Initial Import from SVN

This commit is contained in:
Matt Jenkins
2014-04-09 14:27:18 +01:00
parent 8976e834c4
commit 895f96d2f7
3153 changed files with 748589 additions and 0 deletions

341
sys/kernel/init_main.c Normal file
View File

@@ -0,0 +1,341 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "fs.h"
#include "mount.h"
#include "map.h"
#include "proc.h"
#include "ioctl.h"
#include "inode.h"
#include "conf.h"
#include "buf.h"
#include "fcntl.h"
#include "vm.h"
#include "clist.h"
#include "reboot.h"
#include "systm.h"
#include "kernel.h"
#include "namei.h"
#include "stat.h"
#include "rdisk.h"
u_int swapstart, nswap; /* start and size of swap space */
size_t physmem; /* total amount of physical memory */
int boothowto; /* reboot flags, from boot */
/*
* Initialize hash links for buffers.
*/
static void
bhinit()
{
register int i;
register struct bufhd *bp;
for (bp = bufhash, i = 0; i < BUFHSZ; i++, bp++)
bp->b_forw = bp->b_back = (struct buf *)bp;
}
/*
* Initialize the buffer I/O system by freeing
* all buffers and setting all device buffer lists to empty.
*/
static void
binit()
{
register struct buf *bp;
register int i;
caddr_t paddr;
for (bp = bfreelist; bp < &bfreelist[BQUEUES]; bp++)
bp->b_forw = bp->b_back = bp->av_forw = bp->av_back = bp;
paddr = bufdata;
for (i = 0; i < NBUF; i++, paddr += MAXBSIZE) {
bp = &buf[i];
bp->b_dev = NODEV;
bp->b_bcount = 0;
bp->b_addr = paddr;
binshash(bp, &bfreelist[BQ_AGE]);
bp->b_flags = B_BUSY|B_INVAL;
brelse(bp);
}
}
/*
* Initialize clist by freeing all character blocks, then count
* number of character devices. (Once-only routine)
*/
static void
cinit()
{
register int ccp;
register struct cblock *cp;
ccp = (int)cfree;
ccp = (ccp + CROUND) & ~CROUND;
for (cp = (struct cblock *)ccp; cp <= &cfree[NCLIST - 1]; cp++) {
cp->c_next = cfreelist;
cfreelist = cp;
cfreecount += CBSIZE;
}
}
/*
* Initialization code.
* Called from cold start routine as
* soon as a stack and segmentation
* have been established.
* Functions:
* clear and free user core
* turn on clock
* hand craft 0th process
* call all initialization routines
* fork - process 0 to schedule
* - process 1 execute bootstrap
*/
int
main()
{
register struct proc *p;
register int i;
register struct fs *fs = NULL;
char inbuf[4];
char inch;
int s __attribute__((unused));
startup();
printf ("\n%s", version);
cpuidentify();
cnidentify();
/*
* Set up system process 0 (swapper).
*/
p = &proc[0];
p->p_addr = (size_t) &u;
p->p_stat = SRUN;
p->p_flag |= SLOAD | SSYS;
p->p_nice = NZERO;
u.u_procp = p; /* init user structure */
u.u_cmask = CMASK;
u.u_lastfile = -1;
for (i = 1; i < NGROUPS; i++)
u.u_groups[i] = NOGROUP;
for (i = 0; i < sizeof(u.u_rlimit)/sizeof(u.u_rlimit[0]); i++)
u.u_rlimit[i].rlim_cur = u.u_rlimit[i].rlim_max =
RLIM_INFINITY;
/* Initialize signal state for process 0 */
siginit (p);
/*
* Initialize tables, protocols, and set up well-known inodes.
*/
#ifdef LOG_ENABLED
loginit();
#endif
coutinit();
cinit();
pqinit();
ihinit();
bhinit();
binit();
nchinit();
clkstart();
s = spl0();
rdisk_init();
pipedev = rootdev = get_boot_device();
swapdev = get_swap_device();
/* Mount a root filesystem. */
for (;;) {
if(rootdev!=-1)
{
fs = mountfs (rootdev, (boothowto & RB_RDONLY) ? MNT_RDONLY : 0,
(struct inode*) 0);
}
if (fs)
break;
printf ("No root filesystem available!\n");
// rdisk_list_partitions(RDISK_FS);
retry:
printf ("Please enter device to boot from (press ? to list): ");
inch=0;
inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0;
while((inch=cngetc()) != '\r')
{
switch(inch)
{
case '?':
printf("?\n");
rdisk_list_partitions(RDISK_FS);
printf ("Please enter device to boot from (press ? to list): ");
break;
default:
printf("%c",inch);
inbuf[0] = inbuf[1];
inbuf[1] = inbuf[2];
inbuf[2] = inbuf[3];
inbuf[3] = inch;
break;
}
}
inch = 0;
if(inbuf[0]=='r' && inbuf[1]=='d')
{
if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks())
{
if(inbuf[3]>='a' && inbuf[3]<='d')
{
rootdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1);
inch = 1;
}
}
} else if(inbuf[1]=='r' && inbuf[2]=='d') {
if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks())
{
rootdev=makedev(inbuf[3]-'0',0);
inch = 1;
}
} else if(inbuf[3] == 0) {
inch = 1;
}
if(inch==0)
{
printf("\nUnknown device.\n\n");
goto retry;
}
printf ("\n\n");
}
printf ("phys mem = %u kbytes\n", physmem / 1024);
printf ("user mem = %u kbytes\n", MAXMEM / 1024);
if(minor(rootdev)==0)
{
printf ("root dev = rd%d (%d,%d)\n",
major(rootdev),
major(rootdev), minor(rootdev)
);
} else {
printf ("root dev = rd%d%c (%d,%d)\n",
major(rootdev), 'a'+minor(rootdev)-1,
major(rootdev), minor(rootdev)
);
}
printf ("root size = %u kbytes\n", fs->fs_fsize * DEV_BSIZE / 1024);
mount[0].m_inodp = (struct inode*) 1; /* XXX */
mount_updname (fs, "/", "root", 1, 4);
time.tv_sec = fs->fs_time;
boottime = time;
/* Find a swap file. */
swapstart = 1;
while(swapdev == -1)
{
printf("Please enter swap device (press ? to list): ");
inbuf[0] = inbuf[1] = inbuf[2] = inbuf[3] = 0;
while((inch = cngetc())!='\r')
{
switch(inch)
{
case '?':
printf("?\n");
rdisk_list_partitions(RDISK_SWAP);
printf("Please enter swap device (press ? to list): ");
break;
default:
printf("%c",inch);
inbuf[0] = inbuf[1];
inbuf[1] = inbuf[2];
inbuf[2] = inbuf[3];
inbuf[3] = inch;
break;
}
}
inch = 0;
if(inbuf[0]=='r' && inbuf[1]=='d')
{
if(inbuf[2]>='0' && inbuf[2] < '0'+rdisk_num_disks())
{
if(inbuf[3]>='a' && inbuf[3]<='d')
{
swapdev=makedev(inbuf[2]-'0',inbuf[3]-'a'+1);
inch = 1;
}
}
} else if(inbuf[1]=='r' && inbuf[2]=='d') {
if(inbuf[3]>='0' && inbuf[3] < '0'+rdisk_num_disks())
{
swapdev=makedev(inbuf[3]-'0',0);
inch = 1;
}
}
if(minor(swapdev)!=0)
{
if(partition_type(swapdev)!=RDISK_SWAP)
{
printf("\nNot a swap partition!\n\n");
swapdev=-1;
}
}
}
nswap = rdsize(swapdev);
if(minor(swapdev)==0)
{
printf ("swap dev = rd%d (%d,%d)\n",
major(swapdev),
major(swapdev), minor(swapdev)
);
} else {
printf ("swap dev = rd%d%c (%d,%d)\n",
major(swapdev), 'a'+minor(swapdev)-1,
major(swapdev), minor(swapdev)
);
}
(*bdevsw[major(swapdev)].d_open)(swapdev, FREAD|FWRITE, S_IFBLK);
printf ("swap size = %u kbytes\n", nswap * DEV_BSIZE / 1024);
if (nswap <= 0)
panic ("zero swap size"); /* don't want to panic, but what ? */
mfree (swapmap, nswap, swapstart);
/* Kick off timeout driven events by calling first time. */
schedcpu (0);
/* Set up the root file system. */
rootdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO);
iunlock (rootdir);
u.u_cdir = iget (rootdev, &mount[0].m_filsys, (ino_t) ROOTINO);
iunlock (u.u_cdir);
u.u_rdir = NULL;
/*
* Make init process.
*/
if (newproc (0) == 0) {
/* Parent process with pid 0: swapper.
* No return from sched. */
sched();
}
/* Child process with pid 1: init. */
s = splhigh();
p = u.u_procp;
p->p_dsize = icodeend - icode;
p->p_daddr = USER_DATA_START;
p->p_ssize = 1024; /* one kbyte of stack */
p->p_saddr = USER_DATA_END - 1024;
bcopy ((caddr_t) icode, (caddr_t) USER_DATA_START, icodeend - icode);
/*
* return goes to location 0 of user init code
* just copied out.
*/
return 0;
}

211
sys/kernel/init_sysent.c Normal file
View File

@@ -0,0 +1,211 @@
/*
* System call switch table.
*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "glob.h"
#ifdef INET
# define ifnet(narg, name) narg, name
# define errnet(narg, name) narg, name
#else
# define ifnet(narg, name) 0, nosys
# define errnet(narg, name) 0, nonet
#endif
extern void sc_msec();
/*
* Reserved/unimplemented system calls in the range 0-150 inclusive
* are reserved for use in future Berkeley releases.
* Additional system calls implemented in vendor and other
* redistributions should be placed in the reserved range at the end
* of the current calls.
*/
/*
* This table is the switch used to transfer to the appropriate routine for
* processing a system call. Each row contains the number of words of
* arguments expected in registers, how many on the stack, and a pointer to
* the routine.
*
* The maximum number of direct system calls is 255 since system call numbers
* are encoded in the lower byte of the trap instruction -- see trap.c.
*/
const struct sysent sysent[] = {
{ 1, nosys }, /* 0 = out-of-range */
{ 1, rexit }, /* 1 = exit */
{ 0, fork }, /* 2 = fork */
{ 3, read }, /* 3 = read */
{ 3, write }, /* 4 = write */
{ 3, open }, /* 5 = open */
{ 1, close }, /* 6 = close */
{ 4, wait4 }, /* 7 = wait4 */
{ 0, nosys }, /* 8 = (old creat) */
{ 2, link }, /* 9 = link */
{ 1, unlink }, /* 10 = unlink */
{ 2, execv }, /* 11 = execv */
{ 1, chdir }, /* 12 = chdir */
{ 1, fchdir }, /* 13 = fchdir */
{ 3, mknod }, /* 14 = mknod */
{ 2, chmod }, /* 15 = chmod */
{ 3, chown }, /* 16 = chown; now 3 args */
{ 2, chflags }, /* 17 = chflags */
{ 2, fchflags }, /* 18 = fchflags */
{ 4, lseek }, /* 19 = lseek */
{ 0, getpid }, /* 20 = getpid */
{ 3, smount }, /* 21 = mount */
{ 1, umount }, /* 22 = umount */
{ 6, __sysctl }, /* 23 = __sysctl */
{ 0, getuid }, /* 24 = getuid */
{ 0, geteuid }, /* 25 = geteuid */
{ 4, ptrace }, /* 26 = ptrace */
{ 0, getppid }, /* 27 = getppid */
{ 2, statfs }, /* 28 = statfs */
{ 2, fstatfs }, /* 29 = fstatfs */
{ 3, getfsstat }, /* 30 = getfsstat */
{ 4, sigaction }, /* 31 = sigaction */
{ 3, sigprocmask }, /* 32 = sigprocmask */
{ 2, saccess }, /* 33 = access */
{ 1, sigpending }, /* 34 = sigpending */
{ 2, sigaltstack }, /* 35 = sigaltstack */
{ 0, sync }, /* 36 = sync */
{ 2, kill }, /* 37 = kill */
{ 2, stat }, /* 38 = stat */
{ 2, nosys }, /* 39 = getlogin */
{ 2, lstat }, /* 40 = lstat */
{ 1, dup }, /* 41 = dup */
{ 0, pipe }, /* 42 = pipe */
{ 1, nosys }, /* 43 = setlogin */
{ 4, profil }, /* 44 = profil */
{ 1, setuid }, /* 45 = setuid */
{ 1, seteuid }, /* 46 = seteuid */
{ 0, getgid }, /* 47 = getgid */
{ 0, getegid }, /* 48 = getegid */
{ 1, setgid }, /* 49 = setgid */
{ 1, setegid }, /* 50 = setegid */
{ 0, kmemdev }, /* 51 = kmemdev */
{ 3, nosys }, /* 52 = (2.9) set phys addr */
{ 1, nosys }, /* 53 = (2.9) lock in core */
{ 4, ioctl }, /* 54 = ioctl */
{ 1, reboot }, /* 55 = reboot */
{ 2, sigwait }, /* 56 = sigwait */
{ 2, symlink }, /* 57 = symlink */
{ 3, readlink }, /* 58 = readlink */
{ 3, execve }, /* 59 = execve */
{ 1, umask }, /* 60 = umask */
{ 1, chroot }, /* 61 = chroot */
{ 2, fstat }, /* 62 = fstat */
{ 0, nosys }, /* 63 = reserved */
{ 0, nosys }, /* 64 = (old getpagesize) */
{ 6, pselect }, /* 65 = pselect */
{ 0, vfork }, /* 66 = vfork */
{ 0, nosys }, /* 67 = unused */
{ 0, nosys }, /* 68 = unused */
{ 1, brk }, /* 69 = brk */
#ifdef GLOB_ENABLED
{ 1, rdglob }, /* 70 = read from global */
{ 2, wrglob }, /* 71 = write to global */
#else
{ 1, nosys },
{ 2, nosys },
#endif
{ 0, sc_msec }, /* 72 = msec */
{ 0, nosys }, /* 73 = unused */
{ 0, nosys }, /* 74 = unused */
{ 0, nosys }, /* 75 = unused */
{ 0, vhangup }, /* 76 = vhangup */
{ 0, nosys }, /* 77 = unused */
{ 0, nosys }, /* 78 = unused */
{ 2, getgroups }, /* 79 = getgroups */
{ 2, setgroups }, /* 80 = setgroups */
{ 1, getpgrp }, /* 81 = getpgrp */
{ 2, setpgrp }, /* 82 = setpgrp */
{ 3, setitimer }, /* 83 = setitimer */
{ 0, nosys }, /* 84 = (old wait,wait3) */
{ 0, nosys }, /* 85 = unused */
{ 2, getitimer }, /* 86 = getitimer */
{ 0, nosys }, /* 87 = (old gethostname) */
{ 0, nosys }, /* 88 = (old sethostname) */
{ 0, getdtablesize }, /* 89 = getdtablesize */
{ 2, dup2 }, /* 90 = dup2 */
{ 0, nosys }, /* 91 = unused */
{ 3, fcntl }, /* 92 = fcntl */
{ 5, select }, /* 93 = select */
{ 0, nosys }, /* 94 = unused */
{ 1, fsync }, /* 95 = fsync */
{ 3, setpriority }, /* 96 = setpriority */
{ errnet(3, socket) }, /* 97 = socket */
{ ifnet(3, connect) }, /* 98 = connect */
{ ifnet(3, accept) }, /* 99 = accept */
{ 2, getpriority }, /* 100 = getpriority */
{ ifnet(4, send) }, /* 101 = send */
{ ifnet(4, recv) }, /* 102 = recv */
{ 1, sigreturn }, /* 103 = sigreturn */
{ ifnet(3, bind) }, /* 104 = bind */
{ ifnet(5, setsockopt) }, /* 105 = setsockopt */
{ ifnet(2, listen) }, /* 106 = listen */
{ 1, sigsuspend }, /* 107 = sigsuspend */
{ 0, nosys }, /* 108 = (old sigvec) */
{ 0, nosys }, /* 109 = (old sigblock) */
{ 0, nosys }, /* 110 = (old sigsetmask) */
{ 0, nosys }, /* 111 = (old sigpause) */
{ 2, sigstack }, /* 112 = sigstack COMPAT-43 */
{ ifnet(3, recvmsg) }, /* 113 = recvmsg */
{ ifnet(3, sendmsg) }, /* 114 = sendmsg */
{ 0, nosys }, /* 115 = unused */
{ 2, gettimeofday }, /* 116 = gettimeofday */
{ 2, getrusage }, /* 117 = getrusage */
{ ifnet(5, getsockopt) }, /* 118 = getsockopt */
{ 0, nosys }, /* 119 = unused */
{ 3, readv }, /* 120 = readv */
{ 3, writev }, /* 121 = writev */
{ 2, settimeofday }, /* 122 = settimeofday */
{ 3, fchown }, /* 123 = fchown */
{ 2, fchmod }, /* 124 = fchmod */
{ ifnet(6, recvfrom) }, /* 125 = recvfrom */
{ 0, nosys }, /* 126 = (old setreuid) */
{ 0, nosys }, /* 127 = (old setregid) */
{ 2, rename }, /* 128 = rename */
{ 3, truncate }, /* 129 = truncate */
{ 3, ftruncate }, /* 130 = ftruncate */
{ 2, flock }, /* 131 = flock */
{ 0, nosys }, /* 132 = nosys */
{ ifnet(6, sendto) }, /* 133 = sendto */
{ ifnet(2, shutdown) }, /* 134 = shutdown */
{ errnet(4, socketpair) }, /* 135 = socketpair */
{ 2, mkdir }, /* 136 = mkdir */
{ 1, rmdir }, /* 137 = rmdir */
{ 2, utimes }, /* 138 = utimes */
{ 0, nosys }, /* 139 = unused */
{ 2, adjtime }, /* 140 = adjtime */
{ ifnet(3, getpeername) }, /* 141 = getpeername */
{ 0, nosys }, /* 142 = (old gethostid) */
{ 0, nosys }, /* 143 = (old sethostid) */
{ 2, getrlimit }, /* 144 = getrlimit */
{ 2, setrlimit }, /* 145 = setrlimit */
{ 2, killpg }, /* 146 = killpg */
{ 0, nosys }, /* 147 = nosys */
{ 2, nosys }, /* 148 = quota */
{ 4, nosys }, /* 149 = qquota */
{ ifnet(3, getsockname) }, /* 150 = getsockname */
/*
* Syscalls 151-180 inclusive are reserved for vendor-specific
* system calls. (This includes various calls added for compatibity
* with other Unix variants.)
*/
/*
* 2BSD special calls
*/
{ 0, nosys }, /* 151 = unused */
{ 2, ustore }, /* 152 = ustore */
{ 1, ufetch }, /* 153 = ufetch */
{ 4, ucall }, /* 154 = ucall */
{ 0, nosys }, /* 155 = fperr */
};
const int nsysent = sizeof (sysent) / sizeof (sysent[0]);

373
sys/kernel/kern_clock.c Normal file
View File

@@ -0,0 +1,373 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "callout.h"
#include "dk.h"
#include "kernel.h"
#include "systm.h"
int noproc; /* no one is running just now */
struct callout *callfree, calltodo;
#ifdef UCB_METER
int dk_ndrive = DK_NDRIVE;
/*
* Gather statistics on resource utilization.
*
* We make a gross assumption: that the system has been in the
* state it is in (user state, kernel state, interrupt state,
* or idle state) for the entire last time interval, and
* update statistics accordingly.
*/
/*ARGSUSED*/
void
gatherstats(pc, ps)
caddr_t pc;
int ps;
{
register int cpstate;
/*
* Determine what state the cpu is in.
*/
if (USERMODE(ps)) {
/*
* CPU was in user state.
*/
if (u.u_procp->p_nice > NZERO)
cpstate = CP_NICE;
else
cpstate = CP_USER;
} else {
/*
* CPU was in system state. If profiling kernel
* increment a counter. If no process is running
* then this is a system tick if we were running
* at a non-zero IPL (in a driver). If a process is running,
* then we charge it with system time even if we were
* at a non-zero IPL, since the system often runs
* this way during processing of system calls.
* This is approximate, but the lack of true interval
* timers makes doing anything else difficult.
*/
cpstate = CP_SYS;
if (noproc && BASEPRI(ps))
cpstate = CP_IDLE;
}
/*
* We maintain statistics shown by user-level statistics
* programs: the amount of time in each cpu state, and
* the amount of time each of DK_NDRIVE ``drives'' is busy.
*/
cp_time[cpstate]++;
}
#endif /* UCB_METER */
/*
* Software priority level clock interrupt.
* Run periodic events from timeout queue.
*/
void
softclock(pc, ps)
caddr_t pc;
int ps;
{
for (;;) {
register struct callout *p1;
register caddr_t arg;
register void (*func) (caddr_t);
register int s;
s = splhigh();
if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
splx(s);
break;
}
arg = p1->c_arg;
func = p1->c_func;
calltodo.c_next = p1->c_next;
p1->c_next = callfree;
callfree = p1;
splx(s);
(*func) (arg);
}
/*
* If trapped user-mode and profiling, give it
* a profiling tick.
*/
if (USERMODE(ps)) {
register struct proc *p = u.u_procp;
if (u.u_prof.pr_scale)
addupc(pc, &u.u_prof, 1);
/*
* Check to see if process has accumulated
* more than 10 minutes of user time. If so
* reduce priority to give others a chance.
*/
if (p->p_uid && p->p_nice == NZERO &&
u.u_ru.ru_utime > 10L * 60L * hz) {
p->p_nice = NZERO+4;
(void) setpri(p);
}
}
}
/*
* The hz hardware interval timer.
* We update the events relating to real time.
* Also gather statistics.
*
* reprime clock
* implement callouts
* maintain user/system times
* maintain date
* profile
*/
void
hardclock(pc, ps)
caddr_t pc;
int ps;
{
register struct callout *p1;
register struct proc *p;
register int needsoft = 0;
/*
* Update real-time timeout queue.
* At front of queue are some number of events which are ``due''.
* The time to these is <= 0 and if negative represents the
* number of ticks which have passed since it was supposed to happen.
* The rest of the q elements (times > 0) are events yet to happen,
* where the time for each is given as a delta from the previous.
* Decrementing just the first of these serves to decrement the time
* to all events.
*/
p1 = calltodo.c_next;
while (p1) {
if (--p1->c_time > 0)
break;
needsoft = 1;
if (p1->c_time == 0)
break;
p1 = p1->c_next;
}
/*
* Charge the time out based on the mode the cpu is in.
* Here again we fudge for the lack of proper interval timers
* assuming that the current state has been around at least
* one tick.
*/
if (USERMODE(ps)) {
if (u.u_prof.pr_scale)
needsoft = 1;
/*
* CPU was in user state. Increment
* user time counter, and process process-virtual time
* interval timer.
*/
u.u_ru.ru_utime++;
if (u.u_timer[ITIMER_VIRTUAL - 1].it_value &&
!--u.u_timer[ITIMER_VIRTUAL - 1].it_value) {
psignal(u.u_procp, SIGVTALRM);
u.u_timer[ITIMER_VIRTUAL - 1].it_value =
u.u_timer[ITIMER_VIRTUAL - 1].it_interval;
}
} else {
/*
* CPU was in system state.
*/
if (!noproc)
u.u_ru.ru_stime++;
}
/*
* If the cpu is currently scheduled to a process, then
* charge it with resource utilization for a tick, updating
* statistics which run in (user+system) virtual time,
* such as the cpu time limit and profiling timers.
* This assumes that the current process has been running
* the entire last tick.
*/
if (noproc == 0) {
p = u.u_procp;
if (++p->p_cpu == 0)
p->p_cpu--;
if ((u.u_ru.ru_utime+u.u_ru.ru_stime+1) >
u.u_rlimit[RLIMIT_CPU].rlim_cur) {
psignal(p, SIGXCPU);
if (u.u_rlimit[RLIMIT_CPU].rlim_cur <
u.u_rlimit[RLIMIT_CPU].rlim_max)
u.u_rlimit[RLIMIT_CPU].rlim_cur += 5 * hz;
}
if (u.u_timer[ITIMER_PROF - 1].it_value &&
!--u.u_timer[ITIMER_PROF - 1].it_value) {
psignal(p, SIGPROF);
u.u_timer[ITIMER_PROF - 1].it_value =
u.u_timer[ITIMER_PROF - 1].it_interval;
}
}
#ifdef UCB_METER
gatherstats (pc, ps);
#endif
/*
* Increment the time-of-day, process callouts at a very
* low cpu priority, so we don't keep the relatively high
* clock interrupt priority any longer than necessary.
*/
if (adjdelta) {
if (adjdelta > 0) {
++lbolt;
--adjdelta;
} else {
--lbolt;
++adjdelta;
}
}
if (++lbolt >= hz) {
lbolt -= hz;
++time.tv_sec;
}
if (needsoft && BASEPRI(ps)) { /* if ps is high, just return */
// (void) splsoftclock();
softclock (pc, ps);
}
}
/*
* Arrange that (*fun)(arg) is called in t/hz seconds.
*/
void
timeout (fun, arg, t)
void (*fun) (caddr_t);
caddr_t arg;
register int t;
{
register struct callout *p1, *p2, *pnew;
register int s = splclock();
if (t <= 0)
t = 1;
pnew = callfree;
if (pnew == NULL)
panic("timeout table overflow");
callfree = pnew->c_next;
pnew->c_arg = arg;
pnew->c_func = fun;
for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
if (p2->c_time > 0)
t -= p2->c_time;
p1->c_next = pnew;
pnew->c_next = p2;
pnew->c_time = t;
if (p2)
p2->c_time -= t;
splx(s);
}
/*
* untimeout is called to remove a function timeout call
* from the callout structure.
*/
void
untimeout (fun, arg)
void (*fun) (caddr_t);
caddr_t arg;
{
register struct callout *p1, *p2;
register int s;
s = splclock();
for (p1 = &calltodo; (p2 = p1->c_next) != 0; p1 = p2) {
if (p2->c_func == fun && p2->c_arg == arg) {
if (p2->c_next && p2->c_time > 0)
p2->c_next->c_time += p2->c_time;
p1->c_next = p2->c_next;
p2->c_next = callfree;
callfree = p2;
break;
}
}
splx(s);
}
void
profil()
{
register struct a {
unsigned *bufbase;
unsigned bufsize;
unsigned pcoffset;
unsigned pcscale;
} *uap = (struct a*) u.u_arg;
register struct uprof *upp = &u.u_prof;
upp->pr_base = uap->bufbase;
upp->pr_size = uap->bufsize;
upp->pr_off = uap->pcoffset;
upp->pr_scale = uap->pcscale;
}
/*
* Compute number of hz until specified time.
* Used to compute third argument to timeout() from an
* absolute time.
*/
int
hzto(tv)
register struct timeval *tv;
{
register long ticks;
register long sec;
register int s = splhigh();
/*
* If number of milliseconds will fit in 32 bit arithmetic,
* then compute number of milliseconds to time and scale to
* ticks. Otherwise just compute number of hz in time, rounding
* times greater than representible to maximum value.
*
* Delta times less than 25 days can be computed ``exactly''.
* Maximum value for any timeout in 10ms ticks is 250 days.
*/
sec = tv->tv_sec - time.tv_sec;
if (sec <= 0x7fffffff / 1000 - 1000)
ticks = ((tv->tv_sec - time.tv_sec) * 1000 +
(tv->tv_usec - time.tv_usec) / 1000) / (1000/hz);
else if (sec <= 0x7fffffff / hz)
ticks = sec * hz;
else
ticks = 0x7fffffff;
splx(s);
#ifdef pdp11
/* stored in an "int", so 16-bit max */
if (ticks > 0x7fff)
ticks = 0x7fff;
#endif
return ((int)ticks);
}
/*
* Initialize callouts.
*/
void
coutinit()
{
int i;
callfree = callout;
for (i=1; i<NCALL; i++)
callout[i-1].c_next = &callout[i];
}

532
sys/kernel/kern_descrip.c Normal file
View File

@@ -0,0 +1,532 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "file.h"
#include "systm.h"
#include "inode.h"
#include "ioctl.h"
#include "stat.h"
#include "conf.h"
#ifdef INET
#include "socket.h"
#include "socketvar.h"
#endif
#include <syslog.h>
const struct devspec fddevs[] = {
{ 0, "stdin" },
{ 1, "stdout" },
{ 2, "stderr" },
{ 0, 0 }
};
/*
* Descriptor management.
*/
/*
* Allocate a user file descriptor.
*/
static int
ufalloc(i)
register int i;
{
for (; i < NOFILE; i++)
if (u.u_ofile[i] == NULL) {
u.u_rval = i;
u.u_pofile[i] = 0;
if (i > u.u_lastfile)
u.u_lastfile = i;
return (i);
}
u.u_error = EMFILE;
return (-1);
}
/*
* System calls on descriptors.
*/
void
getdtablesize()
{
u.u_rval = NOFILE;
}
static void
dupit(fd, fp, flags)
register int fd;
register struct file *fp;
int flags;
{
u.u_ofile[fd] = fp;
u.u_pofile[fd] = flags;
fp->f_count++;
if (fd > u.u_lastfile)
u.u_lastfile = fd;
}
void
dup()
{
register struct a {
int i;
} *uap = (struct a *) u.u_arg;
register struct file *fp;
register int j;
if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */
GETF(fp, uap->i);
j = ufalloc(0);
if (j < 0)
return;
dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE);
}
void
dup2()
{
register struct a {
int i, j;
} *uap = (struct a *) u.u_arg;
register struct file *fp;
GETF(fp, uap->i);
if (uap->j < 0 || uap->j >= NOFILE) {
u.u_error = EBADF;
return;
}
u.u_rval = uap->j;
if (uap->i == uap->j)
return;
if (u.u_ofile[uap->j])
/*
* dup2 must succeed even if the close has an error.
*/
(void) closef(u.u_ofile[uap->j]);
dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE);
}
/*
* The file control system call.
*/
void
fcntl()
{
register struct file *fp;
register struct a {
int fdes;
int cmd;
int arg;
} *uap;
register int i;
register char *pop;
uap = (struct a *)u.u_arg;
fp = getf(uap->fdes);
if (fp == NULL)
return;
pop = &u.u_pofile[uap->fdes];
switch(uap->cmd) {
case F_DUPFD:
i = uap->arg;
if (i < 0 || i >= NOFILE) {
u.u_error = EINVAL;
return;
}
if ((i = ufalloc(i)) < 0)
return;
dupit(i, fp, *pop &~ UF_EXCLOSE);
break;
case F_GETFD:
u.u_rval = *pop & 1;
break;
case F_SETFD:
*pop = (*pop &~ 1) | (uap->arg & 1);
break;
case F_GETFL:
u.u_rval = OFLAGS(fp->f_flag);
break;
case F_SETFL:
fp->f_flag &= ~FCNTLFLAGS;
fp->f_flag |= (FFLAGS(uap->arg)) & FCNTLFLAGS;
u.u_error = fset (fp, FNONBLOCK, fp->f_flag & FNONBLOCK);
if (u.u_error)
break;
u.u_error = fset (fp, FASYNC, fp->f_flag & FASYNC);
if (u.u_error)
(void) fset (fp, FNONBLOCK, 0);
break;
case F_GETOWN:
u.u_error = fgetown (fp, &u.u_rval);
break;
case F_SETOWN:
u.u_error = fsetown (fp, uap->arg);
break;
default:
u.u_error = EINVAL;
}
}
int
fioctl(fp, cmd, value)
register struct file *fp;
u_int cmd;
caddr_t value;
{
return ((*Fops[fp->f_type]->fo_ioctl)(fp, cmd, value));
}
/*
* Set/clear file flags: nonblock and async.
*/
int
fset (fp, bit, value)
register struct file *fp;
int bit, value;
{
if (value)
fp->f_flag |= bit;
else
fp->f_flag &= ~bit;
return (fioctl(fp, (u_int)(bit == FNONBLOCK ? FIONBIO : FIOASYNC),
(caddr_t)&value));
}
/*
* Get process group id for a file.
*/
int
fgetown(fp, valuep)
register struct file *fp;
register int *valuep;
{
register int error;
#ifdef INET
if (fp->f_type == DTYPE_SOCKET) {
*valuep = mfsd(&fp->f_socket->so_pgrp);
return (0);
}
#endif
error = fioctl(fp, (u_int)TIOCGPGRP, (caddr_t)valuep);
*valuep = -*valuep;
return (error);
}
/*
* Set process group id for a file.
*/
int
fsetown(fp, value)
register struct file *fp;
int value;
{
#ifdef INET
if (fp->f_type == DTYPE_SOCKET) {
mtsd(&fp->f_socket->so_pgrp, value);
return (0);
}
#endif
if (value > 0) {
register struct proc *p = pfind(value);
if (p == 0)
return (ESRCH);
value = p->p_pgrp;
} else
value = -value;
return (fioctl(fp, (u_int)TIOCSPGRP, (caddr_t)&value));
}
void
close()
{
register struct a {
int i;
} *uap = (struct a *)u.u_arg;
register struct file *fp;
GETF(fp, uap->i);
u.u_ofile[uap->i] = NULL;
while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
u.u_lastfile--;
u.u_error = closef(fp);
/* WHAT IF u.u_error ? */
}
void
fstat()
{
register struct file *fp;
register struct a {
int fdes;
struct stat *sb;
} *uap;
struct stat ub;
uap = (struct a *)u.u_arg;
fp = getf(uap->fdes);
if (fp == NULL)
return;
switch (fp->f_type) {
case DTYPE_PIPE:
case DTYPE_INODE:
u.u_error = ino_stat((struct inode *)fp->f_data, &ub);
if (fp->f_type == DTYPE_PIPE)
ub.st_size -= fp->f_offset;
break;
#ifdef INET
case DTYPE_SOCKET:
u.u_error = SOO_STAT(fp->f_socket, &ub);
break;
#endif
default:
u.u_error = EINVAL;
break;
}
if (u.u_error == 0)
u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb,
sizeof (ub));
}
struct file *lastf;
/*
* Allocate a user file descriptor
* and a file structure.
* Initialize the descriptor
* to point at the file structure.
*/
struct file *
falloc()
{
register struct file *fp;
register int i;
i = ufalloc(0);
if (i < 0)
return (NULL);
if (lastf == 0)
lastf = file;
for (fp = lastf; fp < file+NFILE; fp++)
if (fp->f_count == 0)
goto slot;
for (fp = file; fp < lastf; fp++)
if (fp->f_count == 0)
goto slot;
log(LOG_ERR, "file: table full\n");
u.u_error = ENFILE;
return (NULL);
slot:
u.u_ofile[i] = fp;
fp->f_count = 1;
fp->f_data = 0;
fp->f_offset = 0;
lastf = fp + 1;
return (fp);
}
/*
* Convert a user supplied file descriptor into a pointer
* to a file structure. Only task is to check range of the descriptor.
* Critical paths should use the GETF macro unless code size is a
* consideration.
*/
struct file *
getf(f)
register int f;
{
register struct file *fp;
if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
u.u_error = EBADF;
return (NULL);
}
return (fp);
}
/*
* Internal form of close.
* Decrement reference count on file structure.
*/
int
closef(fp)
register struct file *fp;
{
int error;
if (fp == NULL)
return(0);
if (fp->f_count > 1) {
fp->f_count--;
return(0);
}
if ((fp->f_flag & (FSHLOCK|FEXLOCK)) && fp->f_type == DTYPE_INODE)
ino_unlock(fp, FSHLOCK|FEXLOCK);
error = (*Fops[fp->f_type]->fo_close)(fp);
fp->f_count = 0;
return(error);
}
/*
* Apply an advisory lock on a file descriptor.
*/
void
flock()
{
register struct a {
int fd;
int how;
} *uap = (struct a *)u.u_arg;
register struct file *fp;
int error;
if ((fp = getf(uap->fd)) == NULL)
return;
if (fp->f_type != DTYPE_INODE) {
u.u_error = EOPNOTSUPP;
return;
}
if (uap->how & LOCK_UN) {
ino_unlock(fp, FSHLOCK | FEXLOCK);
return;
}
if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
return; /* error? */
if (uap->how & LOCK_EX)
uap->how &= ~LOCK_SH;
/* avoid work... */
if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX))
return;
if ((fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
return;
error = ino_lock(fp, uap->how);
u.u_error = error;
}
/*
* File Descriptor pseudo-device driver (/dev/fd/).
*
* Opening minor device N dup()s the file (if any) connected to file
* descriptor N belonging to the calling process. Note that this driver
* consists of only the ``open()'' routine, because all subsequent
* references to this file will be direct to the other driver.
*/
/* ARGSUSED */
int
fdopen(dev, mode, type)
dev_t dev;
int mode, type;
{
/*
* XXX Kludge: set u.u_dupfd to contain the value of the
* the file descriptor being sought for duplication. The error
* return ensures that the vnode for this device will be released
* by vn_open. Open will detect this special error and take the
* actions in dupfdopen below. Other callers of vn_open will
* simply report the error.
*/
u.u_dupfd = minor(dev);
return(ENODEV);
}
/*
* Duplicate the specified descriptor to a free descriptor.
*/
int
dupfdopen (indx, dfd, mode, error)
register int indx, dfd;
int mode;
int error;
{
register struct file *wfp;
struct file *fp;
/*
* If the to-be-dup'd fd number is greater than the allowed number
* of file descriptors, or the fd to be dup'd has already been
* closed, reject. Note, check for new == old is necessary as
* falloc could allocate an already closed to-be-dup'd descriptor
* as the new descriptor.
*/
fp = u.u_ofile[indx];
if (dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL || fp == wfp)
return(EBADF);
/*
* There are two cases of interest here.
*
* For ENODEV simply dup (dfd) to file descriptor
* (indx) and return.
*
* For ENXIO steal away the file structure from (dfd) and
* store it in (indx). (dfd) is effectively closed by
* this operation.
*
* NOTE: ENXIO only comes out of the 'portal fs' code of 4.4 - since
* 2.11BSD does not implement the portal fs the code is ifdef'd out
* and a short message output.
*
* Any other error code is just returned.
*/
switch (error) {
case ENODEV:
/*
* Check that the mode the file is being opened for is a
* subset of the mode of the existing descriptor.
*/
if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
return(EACCES);
u.u_ofile[indx] = wfp;
u.u_pofile[indx] = u.u_pofile[dfd];
wfp->f_count++;
if (indx > u.u_lastfile)
u.u_lastfile = indx;
return(0);
#ifdef haveportalfs
case ENXIO:
/*
* Steal away the file pointer from dfd, and stuff it into indx.
*/
fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
fdp->fd_ofiles[dfd] = NULL;
fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
fdp->fd_ofileflags[dfd] = 0;
/*
* Complete the clean up of the filedesc structure by
* recomputing the various hints.
*/
if (indx > fdp->fd_lastfile)
fdp->fd_lastfile = indx;
else
while (fdp->fd_lastfile > 0 &&
fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
fdp->fd_lastfile--;
if (dfd < fdp->fd_freefile)
fdp->fd_freefile = dfd;
return (0);
#else
log(LOG_NOTICE, "dupfdopen");
/* FALLTHROUGH */
#endif
default:
return(error);
}
/* NOTREACHED */
}

539
sys/kernel/kern_exec.c Normal file
View File

@@ -0,0 +1,539 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "map.h"
#include "user.h"
#include "proc.h"
#include "buf.h"
#include "inode.h"
#include "namei.h"
#include "fs.h"
#include "mount.h"
#include "file.h"
#include "signalvar.h"
/*
* exec system call, with and without environments.
*/
struct execa {
char *fname;
char **argp;
char **envp;
};
/*
* Reset signals for an exec of the specified process. In 4.4 this function
* was in kern_sig.c but since in 2.11 kern_sig and kern_exec will likely be
* in different overlays placing this here potentially saves a kernel overlay
* switch.
*/
static void
execsigs(p)
register struct proc *p;
{
register int nc;
unsigned long mask;
/*
* Reset caught signals. Held signals remain held
* through p_sigmask (unless they were caught,
* and are now ignored by default).
*/
while (p->p_sigcatch) {
nc = ffs(p->p_sigcatch);
mask = sigmask(nc);
p->p_sigcatch &= ~mask;
if (sigprop[nc] & SA_IGNORE) {
if (nc != SIGCONT)
p->p_sigignore |= mask;
p->p_sig &= ~mask;
}
u.u_signal[nc] = SIG_DFL;
}
/*
* Reset stack state to the user stack (disable the alternate stack).
*/
u.u_sigstk.ss_flags = SA_DISABLE;
u.u_sigstk.ss_size = 0;
u.u_sigstk.ss_base = 0;
u.u_psflags = 0;
}
/*
* Read in and set up memory for executed file.
* u.u_error set on error
*/
static void
getxfile (ip, ep, nargc, uid, gid)
struct inode *ip;
register struct exec *ep;
int nargc, uid, gid;
{
u_int ds, ts, ss;
if (ep->a_magic == OMAGIC) {
ep->a_data += ep->a_text;
ep->a_text = 0;
}
if (ep->a_text != 0 && (ip->i_flag & ITEXT) == 0 &&
ip->i_count != 1) {
register struct file *fp;
for (fp = file; fp < file+NFILE; fp++) {
if (fp->f_type == DTYPE_INODE &&
fp->f_count > 0 &&
(struct inode*)fp->f_data == ip &&
(fp->f_flag & FWRITE)) {
u.u_error = ETXTBSY;
return;
}
}
}
/*
* find text and data sizes try; them out for possible
* overflow of max sizes
*/
ts = ep->a_text;
ds = ep->a_data + ep->a_bss;
ss = SSIZE + nargc;
//printf ("getxfile: size t/d/s = %u/%u/%u\n", ts, ds, ss);
if (ts + ds + ss > MAXMEM) {
u.u_error = ENOMEM;
return;
}
/*
* Allocate core at this point, committed to the new image.
*/
u.u_prof.pr_scale = 0;
if (u.u_procp->p_flag & SVFORK)
endvfork();
u.u_procp->p_dsize = ds;
u.u_procp->p_daddr = USER_DATA_START;
u.u_procp->p_ssize = ss;
u.u_procp->p_saddr = USER_DATA_END - ss;
/* read in text and data */
//printf ("getxfile: read %u bytes at %08x\n", ep->a_data, USER_DATA_START);
rdwri (UIO_READ, ip, (caddr_t) USER_DATA_START, ep->a_data,
sizeof(struct exec) + ep->a_text, IO_UNIT, (int*) 0);
/* clear BSS and stack */
//printf ("getxfile: clear %u bytes at %08x\n", USER_DATA_END - USER_DATA_START - ep->a_data, USER_DATA_START + ep->a_data);
bzero ((void*) (USER_DATA_START + ep->a_data),
USER_DATA_END - USER_DATA_START - ep->a_data);
/*
* set SUID/SGID protections, if no tracing
*/
if ((u.u_procp->p_flag & P_TRACED) == 0) {
u.u_uid = uid;
u.u_procp->p_uid = uid;
u.u_groups[0] = gid;
} else
psignal (u.u_procp, SIGTRAP);
u.u_svuid = u.u_uid;
u.u_svgid = u.u_groups[0];
u.u_tsize = ts;
u.u_dsize = ds;
u.u_ssize = ss;
}
void printmem (unsigned addr, int nbytes)
{
for (; nbytes>0; addr+=16, nbytes-=16) {
unsigned char *p = (unsigned char*) addr;
printf ("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
addr, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
}
}
void
execv()
{
struct execa *arg = (struct execa *)u.u_arg;
arg->envp = NULL;
execve();
}
void
execve()
{
register char *cp;
register struct buf *bp;
struct execa *uap = (struct execa *)u.u_arg;
int nc, na, ne, ucp, ap, indir, uid, gid, resid, error;
register int cc;
unsigned len;
char *sharg;
struct inode *ip;
size_t bno;
char cfname [MAXCOMLEN + 1];
#define SHSIZE 32
char cfarg [SHSIZE];
union {
char ex_shell [SHSIZE]; /* #! and name of interpreter */
struct exec ex_exec;
} exdata;
struct nameidata nd;
register struct nameidata *ndp = &nd;
//printf ("execve ('%s', ['%s', '%s', ...])\n", uap->fname, uap->argp[0], uap->argp[1]);
NDINIT (ndp, LOOKUP, FOLLOW, uap->fname);
ip = namei (ndp);
if (ip == NULL) {
//printf ("execve: file not found\n");
return;
}
bno = 0;
bp = 0;
indir = 0;
uid = u.u_uid;
gid = u.u_groups[0];
if (ip->i_fs->fs_flags & MNT_NOEXEC) {
//printf ("execve: NOEXEC, flags=%o\n", ip->i_fs->fs_flags);
u.u_error = EACCES;
goto done;
}
if ((ip->i_fs->fs_flags & MNT_NOSUID) == 0) {
if (ip->i_mode & ISUID)
uid = ip->i_uid;
if (ip->i_mode & ISGID)
gid = ip->i_gid;
}
again:
if (access (ip, IEXEC)) {
//printf ("execve: no IEXEC\n");
goto done;
}
if ((u.u_procp->p_flag & P_TRACED) && access (ip, IREAD)) {
//printf ("execve: traced, but no IREAD\n");
goto done;
}
if ((ip->i_mode & IFMT) != IFREG ||
(ip->i_mode & (IEXEC | (IEXEC>>3) | (IEXEC>>6))) == 0) {
//printf ("execve: no IEXEC, mode=%o\n", ip->i_mode);
u.u_error = EACCES;
goto done;
}
/*
* Read in first few bytes of file for segment sizes, magic number:
* 407 = plain executable
* Also an ASCII line beginning with #! is
* the file name of a ``shell'' and arguments may be prepended
* to the argument list if given here.
*
* SHELL NAMES ARE LIMITED IN LENGTH.
*
* ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
* THE ASCII LINE.
*/
exdata.ex_shell[0] = '\0'; /* for zero length files */
u.u_error = rdwri (UIO_READ, ip, (caddr_t) &exdata, sizeof(exdata),
(off_t) 0, IO_UNIT, &resid);
if (u.u_error) {
//printf ("execve: rdwri error %d\n", u.u_error);
goto done;
}
if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
exdata.ex_shell[0] != '#') {
//printf ("execve: short read, resid = %d, shell=%.32s\n", resid, exdata.ex_shell);
u.u_error = ENOEXEC;
goto done;
}
//printf ("execve: text=%u, data=%u, bss=%u\n", exdata.ex_exec.a_text, exdata.ex_exec.a_data, exdata.ex_exec.a_bss);
switch ((int) exdata.ex_exec.a_magic) {
case OMAGIC:
case NMAGIC:
break;
default:
if (exdata.ex_shell[0] != '#' ||
exdata.ex_shell[1] != '!' ||
indir) {
//printf ("execve: bad shell=%.32s\n", exdata.ex_shell);
u.u_error = ENOEXEC;
goto done;
}
/*
* If setuid/gid scripts were to be disallowed this is where it would
* have to be done.
* u.u_uid = uid;
* u.u_gid = u_groups[0];
*/
cp = &exdata.ex_shell[2]; /* skip "#!" */
while (cp < &exdata.ex_shell[SHSIZE]) {
if (*cp == '\t')
*cp = ' ';
else if (*cp == '\n') {
*cp = '\0';
break;
}
cp++;
}
if (*cp != '\0') {
u.u_error = ENOEXEC;
goto done;
}
cp = &exdata.ex_shell[2];
while (*cp == ' ')
cp++;
ndp->ni_dirp = cp;
while (*cp && *cp != ' ')
cp++;
cfarg[0] = '\0';
if (*cp) {
*cp++ = '\0';
while (*cp == ' ')
cp++;
if (*cp)
bcopy ((caddr_t) cp, (caddr_t) cfarg, SHSIZE);
}
indir = 1;
iput (ip);
ndp->ni_nameiop = LOOKUP | FOLLOW;
ip = namei (ndp);
if (ip == NULL)
return;
bcopy ((caddr_t) ndp->ni_dent.d_name, (caddr_t) cfname, MAXCOMLEN);
cfname [MAXCOMLEN] = '\0';
goto again;
}
/*
* Collect arguments on "file" in swap space.
*/
na = 0;
ne = 0;
nc = 0;
cc = 0;
cp = 0;
bno = malloc (swapmap, btod (NCARGS + MAXBSIZE));
if (bno == 0) {
u.u_error = ENOMEM;
goto done;
}
/*
* Copy arguments into file in argdev area.
*/
if (uap->argp) for (;;) {
ap = NULL;
sharg = NULL;
if (indir && na == 0) {
sharg = cfname;
ap = (int) sharg;
uap->argp++; /* ignore argv[0] */
} else if (indir && (na == 1 && cfarg[0])) {
sharg = cfarg;
ap = (int) sharg;
} else if (indir && (na == 1 || (na == 2 && cfarg[0])))
ap = (int) uap->fname;
else if (uap->argp) {
ap = *(int*) uap->argp;
uap->argp++;
}
if (ap == NULL && uap->envp) {
uap->argp = NULL;
ap = *(int*) uap->envp;
if (ap != NULL)
uap->envp++, ne++;
}
if (ap == NULL)
break;
na++;
if (ap == -1) {
u.u_error = EFAULT;
break;
}
do {
if (cc <= 0) {
/*
* We depend on NCARGS being a multiple of
* DEV_BSIZE. This way we need only check
* overflow before each buffer allocation.
*/
if (nc >= NCARGS-1) {
//printf ("execve: too many args = %d\n", nc);
error = E2BIG;
break;
}
if (bp) {
bdwrite(bp);
}
cc = DEV_BSIZE;
bp = getblk (swapdev, dbtofsb(bno) + lblkno(nc));
cp = bp->b_addr;
}
if (sharg) {
error = copystr (sharg, cp, (unsigned) cc, &len);
//printf ("execve arg%d=%s: %u bytes from %08x to %08x\n", na-1, sharg, len, sharg, cp);
sharg += len;
} else {
error = copystr ((caddr_t) ap, cp, (unsigned) cc, &len);
//printf ("execve arg%d=%s: %u bytes from %08x to %08x\n", na-1, ap, len, ap, cp);
ap += len;
}
cp += len;
nc += len;
cc -= len;
} while (error == ENOENT);
if (error) {
//printf ("execve: copy arg error = %d\n", error);
u.u_error = error;
if (bp) {
bp->b_flags |= B_AGE;
bp->b_flags &= ~B_DELWRI;
brelse(bp);
}
bp = 0;
goto badarg;
}
}
//printf ("execve: argc=%d, envc=%d, total %d bytes\n", na, ne, nc);
if (bp) {
bdwrite (bp);
}
bp = 0;
nc = (nc + NBPW-1) & ~(NBPW-1);
getxfile (ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
if (u.u_error) {
//printf ("execve: getxfile error = %d\n", u.u_error);
badarg:
for (cc = 0; cc < nc; cc += DEV_BSIZE) {
daddr_t blkno;
blkno = dbtofsb(bno) + lblkno(cc);
if (incore (swapdev, blkno)) {
bp = bread (swapdev, blkno);
bp->b_flags |= B_AGE; /* throw away */
bp->b_flags &= ~B_DELWRI; /* cancel io */
brelse(bp);
bp = 0;
}
}
goto done;
}
iput(ip);
ip = NULL;
/*
* Copy back arglist.
*/
ucp = USER_DATA_END - nc - NBPW;
ap = ucp - na*NBPW - 2*NBPW;
u.u_frame [FRAME_SP] = ap - 16;
u.u_frame [FRAME_R4] = na - ne; /* $a0 := argc */
u.u_frame [FRAME_R5] = ap; /* $a1 := argv */
u.u_frame [FRAME_R6] = ap + (na-ne+1)*NBPW; /* $a2 := env */
*(int*) (USER_DATA_END - NBPW) = ap; /* for /bin/ps */
nc = 0;
cc = 0;
for (;;) {
if (na == ne) {
*(int*) ap = 0;
ap += NBPW;
}
if (--na < 0)
break;
*(int*) ap = ucp;
do {
if (cc <= 0) {
if (bp) {
brelse(bp);
}
cc = DEV_BSIZE;
bp = bread (swapdev, dbtofsb(bno) + lblkno(nc));
bp->b_flags |= B_AGE; /* throw away */
bp->b_flags &= ~B_DELWRI; /* cancel io */
cp = bp->b_addr;
}
error = copystr (cp, (caddr_t) ucp, (unsigned) cc,
&len);
//printf ("execve copy '%s' %u bytes from %08x to %08x\n", cp, len, cp, ucp);
ucp += len;
cp += len;
nc += len;
cc -= len;
} while (error == ENOENT);
if (error == EFAULT)
panic ("exec: EFAULT");
ap += NBPW;
}
*(int*) ap = 0;
if (bp) {
bp->b_flags |= B_AGE;
brelse (bp);
bp = NULL;
}
execsigs (u.u_procp);
for (cp = u.u_pofile, cc = 0; cc <= u.u_lastfile; cc++, cp++) {
if (*cp & UF_EXCLOSE) {
(void) closef (u.u_ofile [cc]);
u.u_ofile [cc] = NULL;
*cp = 0;
}
}
while (u.u_lastfile >= 0 && u.u_ofile [u.u_lastfile] == NULL)
u.u_lastfile--;
/*
* Clear registers.
*/
u.u_frame [FRAME_R1] = 0; /* $at */
u.u_frame [FRAME_R2] = 0; /* $v0 */
u.u_frame [FRAME_R3] = 0; /* $v1 */
u.u_frame [FRAME_R7] = 0; /* $a3 */
u.u_frame [FRAME_R8] = 0; /* $t0 */
u.u_frame [FRAME_R9] = 0; /* $t1 */
u.u_frame [FRAME_R10] = 0; /* $t2 */
u.u_frame [FRAME_R11] = 0; /* $t3 */
u.u_frame [FRAME_R12] = 0; /* $t4 */
u.u_frame [FRAME_R13] = 0; /* $t5 */
u.u_frame [FRAME_R14] = 0; /* $t6 */
u.u_frame [FRAME_R15] = 0; /* $t7 */
u.u_frame [FRAME_R16] = 0; /* $s0 */
u.u_frame [FRAME_R17] = 0; /* $s1 */
u.u_frame [FRAME_R18] = 0; /* $s2 */
u.u_frame [FRAME_R19] = 0; /* $s3 */
u.u_frame [FRAME_R20] = 0; /* $s4 */
u.u_frame [FRAME_R21] = 0; /* $s5 */
u.u_frame [FRAME_R22] = 0; /* $s6 */
u.u_frame [FRAME_R23] = 0; /* $s7 */
u.u_frame [FRAME_R24] = 0; /* $t8 */
u.u_frame [FRAME_R25] = 0; /* $t9 */
u.u_frame [FRAME_FP] = 0;
u.u_frame [FRAME_RA] = 0;
u.u_frame [FRAME_LO] = 0;
u.u_frame [FRAME_HI] = 0;
u.u_frame [FRAME_GP] = 0;
u.u_frame [FRAME_PC] = exdata.ex_exec.a_entry;
/*
* Remember file name for accounting.
*/
bcopy ((caddr_t) (indir ? cfname : ndp->ni_dent.d_name),
(caddr_t) u.u_comm, MAXCOMLEN);
done:
//printf ("execve done: PC=%08x, SP=%08x, R4=%08x, R5=%08x, R6=%08x\n",
// u.u_frame [FRAME_PC], u.u_frame [FRAME_SP],
// u.u_frame [FRAME_R4], u.u_frame [FRAME_R5], u.u_frame [FRAME_R6]);
if (bp) {
bp->b_flags |= B_AGE;
brelse (bp);
}
if (bno)
mfree (swapmap, btod (NCARGS + MAXBSIZE), bno);
if (ip)
iput(ip);
}

280
sys/kernel/kern_exit.c Normal file
View File

@@ -0,0 +1,280 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "map.h"
#include "user.h"
#include "proc.h"
#include "inode.h"
#include "vm.h"
#include "file.h"
#include "wait.h"
#include "kernel.h"
/*
* Notify parent that vfork child is finished with parent's data. Called
* during exit/exec(getxfile). The child
* must be locked in core so it will be in core when the parent runs.
*/
void
endvfork()
{
register struct proc *rip, *rpp;
rpp = u.u_procp;
rip = rpp->p_pptr;
rpp->p_flag &= ~SVFORK;
rpp->p_flag |= SLOCK;
wakeup ((caddr_t) rpp);
while (! (rpp->p_flag & SVFDONE))
sleep ((caddr_t) rip, PZERO-1);
/*
* The parent has taken back our data+stack, set our sizes to 0.
*/
u.u_dsize = rpp->p_dsize = 0;
u.u_ssize = rpp->p_ssize = 0;
rpp->p_flag &= ~(SVFDONE | SLOCK);
}
/*
* Exit: deallocate address space and other resources,
* change proc state to zombie, and unlink proc from allproc
* list. Save exit status and rusage for wait4().
* Check for child processes and orphan them.
*/
void
exit (rv)
int rv;
{
register int i;
register struct proc *p;
struct proc **pp;
p = u.u_procp;
p->p_flag &= ~P_TRACED;
p->p_sigignore = ~0;
p->p_sig = 0;
/*
* 2.11 doesn't need to do this and it gets overwritten anyway.
* p->p_realtimer.it_value = 0;
*/
for (i = 0; i <= u.u_lastfile; i++) {
register struct file *f;
f = u.u_ofile[i];
u.u_ofile[i] = NULL;
u.u_pofile[i] = 0;
(void) closef(f);
}
ilock(u.u_cdir);
iput(u.u_cdir);
if (u.u_rdir) {
ilock(u.u_rdir);
iput(u.u_rdir);
}
u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
if (p->p_flag & SVFORK)
endvfork();
if (p->p_pid == 1)
panic("init died");
if ((*p->p_prev = p->p_nxt) != NULL) /* off allproc queue */
p->p_nxt->p_prev = p->p_prev;
p->p_nxt = zombproc; /* onto zombproc */
if (p->p_nxt != NULL)
p->p_nxt->p_prev = &p->p_nxt;
p->p_prev = &zombproc;
zombproc = p;
p->p_stat = SZOMB;
noproc = 1;
for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
if (*pp == p) {
*pp = p->p_hash;
goto done;
}
panic("exit");
done:
/*
* Overwrite p_alive substructure of proc - better not be anything
* important left!
*/
p->p_xstat = rv;
p->p_ru = u.u_ru;
ruadd(&p->p_ru, &u.u_cru);
{
register struct proc *q;
int doingzomb = 0;
q = allproc;
again:
for(; q; q = q->p_nxt)
if (q->p_pptr == p) {
q->p_pptr = &proc[1];
q->p_ppid = 1;
wakeup((caddr_t)&proc[1]);
if (q->p_flag& P_TRACED) {
q->p_flag &= ~P_TRACED;
psignal(q, SIGKILL);
} else if (q->p_stat == SSTOP) {
psignal(q, SIGHUP);
psignal(q, SIGCONT);
}
}
if (!doingzomb) {
doingzomb = 1;
q = zombproc;
goto again;
}
}
psignal(p->p_pptr, SIGCHLD);
wakeup((caddr_t) p->p_pptr);
wakeup((caddr_t) &runin);
swtch();
/* NOTREACHED */
}
/*
* exit system call: pass back caller's arg
*/
void
rexit()
{
register struct a {
int rval;
} *uap = (struct a*) u.u_arg;
exit (W_EXITCODE (uap->rval, 0));
/* NOTREACHED */
}
struct args {
int pid;
int *status;
int options;
struct rusage *rusage;
};
/*
* Wait: check child processes to see if any have exited,
* stopped under trace or (optionally) stopped by a signal.
* Pass back status and make available for reuse the exited
* child's proc structure.
*/
static int
wait1 (q, uap, retval)
struct proc *q;
register struct args *uap;
int retval[];
{
int nfound, status;
struct rusage ru; /* used for local conversion */
register struct proc *p;
register int error;
if (uap->pid == WAIT_MYPGRP) /* == 0 */
uap->pid = -q->p_pgrp;
loop:
nfound = 0;
/*
* 4.X has child links in the proc structure, so they consolidate
* these two tests into one loop. We only have the zombie chain
* and the allproc chain, so we check for ZOMBIES first, then for
* children that have changed state. We check for ZOMBIES first
* because they are more common, and, as the list is typically small,
* a faster check.
*/
for (p = zombproc; p; p = p->p_nxt) {
if (p->p_pptr != q) /* are we the parent of this process? */
continue;
if (uap->pid != WAIT_ANY &&
p->p_pid != uap->pid && p->p_pgrp != -uap->pid)
continue;
retval[0] = p->p_pid;
retval[1] = p->p_xstat;
if (uap->status && (error = copyout ((caddr_t) &p->p_xstat,
(caddr_t) uap->status, sizeof (uap->status))))
return(error);
if (uap->rusage) {
rucvt(&ru, &p->p_ru);
error = copyout ((caddr_t) &ru, (caddr_t) uap->rusage, sizeof (ru));
if (error)
return(error);
}
ruadd(&u.u_cru, &p->p_ru);
p->p_xstat = 0;
p->p_stat = NULL;
p->p_pid = 0;
p->p_ppid = 0;
if ((*p->p_prev = p->p_nxt) != NULL) /* off zombproc */
p->p_nxt->p_prev = p->p_prev;
p->p_nxt = freeproc; /* onto freeproc */
freeproc = p;
p->p_pptr = 0;
p->p_sig = 0;
p->p_sigcatch = 0;
p->p_sigignore = 0;
p->p_sigmask = 0;
p->p_pgrp = 0;
p->p_flag = 0;
p->p_wchan = 0;
return (0);
}
for (p = allproc; p;p = p->p_nxt) {
if (p->p_pptr != q)
continue;
if (uap->pid != WAIT_ANY &&
p->p_pid != uap->pid && p->p_pgrp != -uap->pid)
continue;
++nfound;
if (p->p_stat == SSTOP && ! (p->p_flag & P_WAITED) &&
(p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
p->p_flag |= P_WAITED;
retval[0] = p->p_pid;
error = 0;
if (uap->status) {
status = W_STOPCODE(p->p_ptracesig);
error = copyout ((caddr_t) &status,
(caddr_t) uap->status, sizeof (status));
}
return (error);
}
}
if (nfound == 0)
return (ECHILD);
if (uap->options&WNOHANG) {
retval[0] = 0;
return (0);
}
error = tsleep ((caddr_t) q, PWAIT|PCATCH, 0);
if (error == 0)
goto loop;
return(error);
}
void
wait4()
{
int retval[2];
register struct args *uap = (struct args*) u.u_arg;
retval[0] = 0;
u.u_error = wait1 (u.u_procp, uap, retval);
if (! u.u_error)
u.u_rval = retval[0];
}
void
reboot()
{
struct a {
int opt;
};
if (suser ())
boot (rootdev, ((struct a*)u.u_arg)->opt);
}

254
sys/kernel/kern_fork.c Normal file
View File

@@ -0,0 +1,254 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "map.h"
#include "user.h"
#include "proc.h"
#include "inode.h"
#include "file.h"
#include "vm.h"
#include "kernel.h"
#include "syslog.h"
int mpid; /* generic for unique process id's */
/*
* Create a new process -- the internal version of system call fork.
* It returns 1 in the new process, 0 in the old.
*/
int
newproc (isvfork)
int isvfork;
{
register struct proc *child, *parent;
register int n;
static int pidchecked = 0;
struct file *fp;
/*
* First, just locate a slot for a process
* and copy the useful info from this process into it.
* The panic "cannot happen" because fork has already
* checked for the existence of a slot.
*/
mpid++;
retry:
if (mpid >= 30000) {
mpid = 100;
pidchecked = 0;
}
if (mpid >= pidchecked) {
int doingzomb = 0;
pidchecked = 30000;
/*
* Scan the proc table to check whether this pid
* is in use. Remember the lowest pid that's greater
* than mpid, so we can avoid checking for a while.
*/
child = allproc;
again:
for (; child != NULL; child = child->p_nxt) {
if (child->p_pid == mpid || child->p_pgrp == mpid) {
mpid++;
if (mpid >= pidchecked)
goto retry;
}
if (child->p_pid > mpid && pidchecked > child->p_pid)
pidchecked = child->p_pid;
if (child->p_pgrp > mpid && pidchecked > child->p_pgrp)
pidchecked = child->p_pgrp;
}
if (!doingzomb) {
doingzomb = 1;
child = zombproc;
goto again;
}
}
child = freeproc;
if (child == NULL)
panic("no procs");
freeproc = child->p_nxt; /* off freeproc */
/*
* Make a proc table entry for the new process.
*/
parent = u.u_procp;
child->p_stat = SIDL;
child->p_realtimer.it_value = 0;
child->p_flag = SLOAD;
child->p_uid = parent->p_uid;
child->p_pgrp = parent->p_pgrp;
child->p_nice = parent->p_nice;
child->p_pid = mpid;
child->p_ppid = parent->p_pid;
child->p_pptr = parent;
child->p_time = 0;
child->p_cpu = 0;
child->p_sigmask = parent->p_sigmask;
child->p_sigcatch = parent->p_sigcatch;
child->p_sigignore = parent->p_sigignore;
/* take along any pending signals like stops? */
#ifdef UCB_METER
if (isvfork) {
forkstat.cntvfork++;
forkstat.sizvfork += (parent->p_dsize + parent->p_ssize) >> 10;
} else {
forkstat.cntfork++;
forkstat.sizfork += (parent->p_dsize + parent->p_ssize) >> 10;
}
#endif
child->p_wchan = 0;
child->p_slptime = 0;
{
struct proc **hash = &pidhash [PIDHASH (child->p_pid)];
child->p_hash = *hash;
*hash = child;
}
/*
* some shuffling here -- in most UNIX kernels, the allproc assign
* is done after grabbing the struct off of the freeproc list. We
* wait so that if the clock interrupts us and vmtotal walks allproc
* the text pointer isn't garbage.
*/
child->p_nxt = allproc; /* onto allproc */
child->p_nxt->p_prev = &child->p_nxt; /* (allproc is never NULL) */
child->p_prev = &allproc;
allproc = child;
/*
* Increase reference counts on shared objects.
*/
for (n = 0; n <= u.u_lastfile; n++) {
fp = u.u_ofile[n];
if (fp == NULL)
continue;
fp->f_count++;
}
u.u_cdir->i_count++;
if (u.u_rdir)
u.u_rdir->i_count++;
/*
* When the longjmp is executed for the new process,
* here's where it will resume.
*/
if (setjmp (&u.u_ssave)) {
return(1);
}
child->p_dsize = parent->p_dsize;
child->p_ssize = parent->p_ssize;
child->p_daddr = parent->p_daddr;
child->p_saddr = parent->p_saddr;
/*
* Partially simulate the environment of the new process so that
* when it is actually created (by copying) it will look right.
*/
u.u_procp = child;
/*
* Swap out the current process to generate the copy.
*/
parent->p_stat = SIDL;
child->p_addr = parent->p_addr;
child->p_stat = SRUN;
swapout (child, X_DONTFREE, X_OLDSIZE, X_OLDSIZE);
child->p_flag |= SSWAP;
parent->p_stat = SRUN;
u.u_procp = parent;
if (isvfork) {
/*
* Wait for the child to finish with it.
* RetroBSD: to make this work, significant
* changes in scheduler are required.
*/
parent->p_dsize = 0;
parent->p_ssize = 0;
child->p_flag |= SVFORK;
parent->p_flag |= SVFPRNT;
while (child->p_flag & SVFORK)
sleep ((caddr_t)child, PSWP+1);
if ((child->p_flag & SLOAD) == 0)
panic ("newproc vfork");
u.u_dsize = parent->p_dsize = child->p_dsize;
parent->p_daddr = child->p_daddr;
child->p_dsize = 0;
u.u_ssize = parent->p_ssize = child->p_ssize;
parent->p_saddr = child->p_saddr;
child->p_ssize = 0;
child->p_flag |= SVFDONE;
wakeup ((caddr_t) parent);
parent->p_flag &= ~SVFPRNT;
}
return(0);
}
static void
fork1 (isvfork)
int isvfork;
{
register int a;
register struct proc *p1, *p2;
a = 0;
if (u.u_uid != 0) {
for (p1 = allproc; p1; p1 = p1->p_nxt)
if (p1->p_uid == u.u_uid)
a++;
for (p1 = zombproc; p1; p1 = p1->p_nxt)
if (p1->p_uid == u.u_uid)
a++;
}
/*
* Disallow if
* No processes at all;
* not su and too many procs owned; or
* not su and would take last slot.
*/
p2 = freeproc;
if (p2==NULL)
log(LOG_ERR, "proc: table full\n");
if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) {
u.u_error = EAGAIN;
return;
}
p1 = u.u_procp;
if (newproc (isvfork)) {
/* Child */
u.u_rval = 0;
u.u_start = time.tv_sec;
bzero(&u.u_ru, sizeof(u.u_ru));
bzero(&u.u_cru, sizeof(u.u_cru));
return;
}
/* Parent */
u.u_rval = p2->p_pid;
}
/*
* fork system call
*/
void
fork()
{
fork1 (0);
}
/*
* vfork system call, fast version of fork
*/
void
vfork()
{
fork1 (1);
}

61
sys/kernel/kern_glob.c Normal file
View File

@@ -0,0 +1,61 @@
/*
* Global memory area system.
*
* Works with two system calls:
*
* byte = rdglob(addr);
* success = wrglob(addr,byte);
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#ifndef GLOBSZ
#define GLOBSZ 256
#endif
unsigned char global_segment[GLOBSZ];
void rdglob()
{
struct a {
int addr;
} *uap = (struct a *)u.u_arg;
// Only root should have access to the shared memory block
if(u.u_uid!=0)
{
u.u_rval = -1;
return;
}
if(uap->addr>=GLOBSZ)
{
u.u_rval = -1;
return;
}
u.u_rval = global_segment[uap->addr];
}
void wrglob()
{
struct a {
int addr;
unsigned char value;
} *uap = (struct a *)u.u_arg;
// Only root should have access to the shared memory block
if(u.u_uid!=0)
{
u.u_rval = -1;
return;
}
if(uap->addr>=GLOBSZ)
{
u.u_rval = -1;
return;
}
u.u_rval = 0;
global_segment[uap->addr] = uap->value;
}

38
sys/kernel/kern_mman.c Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "vm.h"
#include "systm.h"
void
brk()
{
struct a {
int naddr;
};
register int newsize, d;
/* set newsize to new data size */
newsize = ((struct a*)u.u_arg)->naddr - u.u_procp->p_daddr;
if (newsize < 0)
newsize = 0;
if (u.u_tsize + newsize + u.u_ssize > MAXMEM) {
u.u_error = ENOMEM;
return;
}
u.u_procp->p_dsize = newsize;
/* set d to (new - old) */
d = newsize - u.u_dsize;
//printf ("brk: new size %u bytes, incremented by %d\n", newsize, d);
if (d > 0)
bzero ((void*) (u.u_procp->p_daddr + u.u_dsize), d);
u.u_dsize = newsize;
u.u_rval = u.u_procp->p_daddr + u.u_dsize;
}

65
sys/kernel/kern_proc.c Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "systm.h"
/*
* Is p an inferior of the current process?
*/
int
inferior(p)
register struct proc *p;
{
for (; p != u.u_procp; p = p->p_pptr)
if (p->p_ppid == 0)
return (0);
return (1);
}
/*
* Find a process by pid.
*/
struct proc *
pfind (pid)
register int pid;
{
register struct proc *p = pidhash [PIDHASH(pid)];
for (; p; p = p->p_hash)
if (p->p_pid == pid)
return (p);
return ((struct proc *)0);
}
/*
* init the process queues
*/
void
pqinit()
{
register struct proc *p;
/*
* most procs are initially on freequeue
* nb: we place them there in their "natural" order.
*/
freeproc = NULL;
for (p = proc+NPROC; --p > proc; freeproc = p)
p->p_nxt = freeproc;
/*
* but proc[0] is special ...
*/
allproc = p;
p->p_nxt = NULL;
p->p_prev = &allproc;
zombproc = NULL;
}

155
sys/kernel/kern_prot.c Normal file
View File

@@ -0,0 +1,155 @@
/*
* System calls related to processes and protection.
*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "systm.h"
void
getpid()
{
u.u_rval = u.u_procp->p_pid;
}
void
getppid()
{
u.u_rval = u.u_procp->p_ppid;
}
void
getpgrp()
{
register struct a {
int pid;
} *uap = (struct a *)u.u_arg;
register struct proc *p;
if (uap->pid == 0) /* silly... */
uap->pid = u.u_procp->p_pid;
p = pfind(uap->pid);
if (p == 0) {
u.u_error = ESRCH;
return;
}
u.u_rval = p->p_pgrp;
}
void
getuid()
{
u.u_rval = u.u_ruid;
}
void
geteuid()
{
u.u_rval = u.u_uid;
}
void
getgid()
{
u.u_rval = u.u_rgid;
}
void
getegid()
{
u.u_rval = u.u_groups[0];
}
/*
* getgroups and setgroups differ from 4.X because the VAX stores group
* entries in the user structure as shorts and has to convert them to ints.
*/
void
getgroups()
{
register struct a {
u_int gidsetsize;
int *gidset;
} *uap = (struct a *)u.u_arg;
register gid_t *gp;
for (gp = &u.u_groups[NGROUPS]; gp > u.u_groups; gp--)
if (gp[-1] != NOGROUP)
break;
if (uap->gidsetsize < gp - u.u_groups) {
u.u_error = EINVAL;
return;
}
uap->gidsetsize = gp - u.u_groups;
u.u_error = copyout((caddr_t)u.u_groups, (caddr_t)uap->gidset,
uap->gidsetsize * sizeof(u.u_groups[0]));
if (u.u_error)
return;
u.u_rval = uap->gidsetsize;
}
void
setpgrp()
{
register struct proc *p;
register struct a {
int pid;
int pgrp;
} *uap = (struct a *)u.u_arg;
if (uap->pid == 0) /* silly... */
uap->pid = u.u_procp->p_pid;
p = pfind(uap->pid);
if (p == 0) {
u.u_error = ESRCH;
return;
}
/* need better control mechanisms for process groups */
if (p->p_uid != u.u_uid && u.u_uid && !inferior(p)) {
u.u_error = EPERM;
return;
}
p->p_pgrp = uap->pgrp;
}
void
setgroups()
{
register struct a {
u_int gidsetsize;
int *gidset;
} *uap = (struct a *)u.u_arg;
register gid_t *gp;
if (!suser())
return;
if (uap->gidsetsize > sizeof (u.u_groups) / sizeof (u.u_groups[0])) {
u.u_error = EINVAL;
return;
}
u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)u.u_groups,
uap->gidsetsize * sizeof (u.u_groups[0]));
if (u.u_error)
return;
for (gp = &u.u_groups[uap->gidsetsize]; gp < &u.u_groups[NGROUPS]; gp++)
*gp = NOGROUP;
}
/*
* Check if gid is a member of the group set.
*/
int
groupmember(gid)
gid_t gid;
{
register gid_t *gp;
for (gp = u.u_groups; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
if (*gp == gid)
return (1);
return (0);
}

114
sys/kernel/kern_prot2.c Normal file
View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "systm.h"
void
setuid()
{
struct a {
uid_t uid;
} *uap = (struct a*) u.u_arg;
register uid_t uid;
uid = uap->uid;
if (uid != u.u_ruid && ! suser())
return;
/*
* Everything's okay, do it.
*/
u.u_procp->p_uid = uid;
u.u_uid = uid;
u.u_ruid = uid;
u.u_svuid = uid;
u.u_error = 0;
}
void
seteuid()
{
struct a {
uid_t euid;
} *uap = (struct a *)u.u_arg;
register uid_t euid;
euid = uap->euid;
if (euid != u.u_ruid && euid != u.u_svuid && ! suser())
return;
/*
* Everything's okay, do it.
*/
u.u_uid = euid;
u.u_error = 0;
}
void
setgid()
{
struct a {
gid_t gid;
} *uap = (struct a *)u.u_arg;
register gid_t gid;
gid = uap->gid;
if (gid != u.u_rgid && ! suser())
return;
u.u_groups[0] = gid; /* effective gid is u_groups[0] */
u.u_rgid = gid;
u.u_svgid = gid;
u.u_error = 0;
}
void
setegid()
{
struct a {
gid_t egid;
} *uap = (struct a *)u.u_arg;
register gid_t egid;
egid = uap->egid;
if (egid != u.u_rgid && egid != u.u_svgid && ! suser())
return;
u.u_groups[0] = egid;
u.u_error = 0;
}

270
sys/kernel/kern_resource.c Normal file
View File

@@ -0,0 +1,270 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "systm.h"
#include "vm.h"
#include "kernel.h"
/*
* Resource controls and accounting.
*/
void
getpriority()
{
register struct a {
int which;
int who;
} *uap = (struct a *)u.u_arg;
register struct proc *p;
register int low = PRIO_MAX + 1;
switch (uap->which) {
case PRIO_PROCESS:
if (uap->who == 0)
p = u.u_procp;
else
p = pfind(uap->who);
if (p == 0)
break;
low = p->p_nice;
break;
case PRIO_PGRP:
if (uap->who == 0)
uap->who = u.u_procp->p_pgrp;
for (p = allproc; p != NULL; p = p->p_nxt) {
if (p->p_pgrp == uap->who &&
p->p_nice < low)
low = p->p_nice;
}
break;
case PRIO_USER:
if (uap->who == 0)
uap->who = u.u_uid;
for (p = allproc; p != NULL; p = p->p_nxt) {
if (p->p_uid == uap->who &&
p->p_nice < low)
low = p->p_nice;
}
break;
default:
u.u_error = EINVAL;
return;
}
if (low == PRIO_MAX + 1) {
u.u_error = ESRCH;
return;
}
u.u_rval = low;
}
static void
donice(p, n)
register struct proc *p;
register int n;
{
if (u.u_uid && u.u_ruid &&
u.u_uid != p->p_uid && u.u_ruid != p->p_uid) {
u.u_error = EPERM;
return;
}
if (n > PRIO_MAX)
n = PRIO_MAX;
if (n < PRIO_MIN)
n = PRIO_MIN;
if (n < p->p_nice && !suser()) {
u.u_error = EACCES;
return;
}
p->p_nice = n;
}
void
setpriority()
{
register struct a {
int which;
int who;
int prio;
} *uap = (struct a *)u.u_arg;
register struct proc *p;
register int found = 0;
switch (uap->which) {
case PRIO_PROCESS:
if (uap->who == 0)
p = u.u_procp;
else
p = pfind(uap->who);
if (p == 0)
break;
donice(p, uap->prio);
found++;
break;
case PRIO_PGRP:
if (uap->who == 0)
uap->who = u.u_procp->p_pgrp;
for (p = allproc; p != NULL; p = p->p_nxt)
if (p->p_pgrp == uap->who) {
donice(p, uap->prio);
found++;
}
break;
case PRIO_USER:
if (uap->who == 0)
uap->who = u.u_uid;
for (p = allproc; p != NULL; p = p->p_nxt)
if (p->p_uid == uap->who) {
donice(p, uap->prio);
found++;
}
break;
default:
u.u_error = EINVAL;
return;
}
if (found == 0)
u.u_error = ESRCH;
}
void
setrlimit()
{
register struct a {
u_int which;
struct rlimit *lim;
} *uap = (struct a *)u.u_arg;
struct rlimit alim;
register struct rlimit *alimp;
if (uap->which >= RLIM_NLIMITS) {
u.u_error = EINVAL;
return;
}
alimp = &u.u_rlimit[uap->which];
u.u_error = copyin((caddr_t)uap->lim, (caddr_t)&alim,
sizeof (struct rlimit));
if (u.u_error)
return;
if (uap->which == RLIMIT_CPU) {
/*
* 2.11 stores RLIMIT_CPU as ticks to keep from making
* hardclock() do long multiplication/division.
*/
if (alim.rlim_cur >= RLIM_INFINITY / hz)
alim.rlim_cur = RLIM_INFINITY;
else
alim.rlim_cur = alim.rlim_cur * hz;
if (alim.rlim_max >= RLIM_INFINITY / hz)
alim.rlim_max = RLIM_INFINITY;
else
alim.rlim_max = alim.rlim_max * hz;
}
if (alim.rlim_cur > alimp->rlim_max || alim.rlim_max > alimp->rlim_max)
if (!suser())
return;
*alimp = alim;
}
void
getrlimit()
{
register struct a {
u_int which;
struct rlimit *rlp;
} *uap = (struct a *)u.u_arg;
if (uap->which >= RLIM_NLIMITS) {
u.u_error = EINVAL;
return;
}
if (uap->which == RLIMIT_CPU) {
struct rlimit alim;
alim = u.u_rlimit[uap->which];
if (alim.rlim_cur != RLIM_INFINITY)
alim.rlim_cur = alim.rlim_cur / hz;
if (alim.rlim_max != RLIM_INFINITY)
alim.rlim_max = alim.rlim_max / hz;
u.u_error = copyout((caddr_t)&alim,
(caddr_t)uap->rlp,sizeof (struct rlimit));
}
else u.u_error = copyout((caddr_t)&u.u_rlimit[uap->which],
(caddr_t)uap->rlp,sizeof (struct rlimit));
}
void
getrusage()
{
register struct a {
int who;
struct rusage *rusage;
} *uap = (struct a *)u.u_arg;
register struct k_rusage *rup;
struct rusage ru;
switch (uap->who) {
case RUSAGE_SELF:
rup = &u.u_ru;
break;
case RUSAGE_CHILDREN:
rup = &u.u_cru;
break;
default:
u.u_error = EINVAL;
return;
}
rucvt(&ru,rup);
u.u_error = copyout((caddr_t)&ru, (caddr_t)uap->rusage,
sizeof (struct rusage));
}
/*
* Add resource usage data.
*/
void
ruadd(ru, ru2)
struct k_rusage *ru, *ru2;
{
register long *ip, *ip2;
register int i;
/*
* since the kernel timeval structures are single longs,
* fold them into the loop.
*/
ip = &ru->k_ru_first;
ip2 = &ru2->k_ru_first;
for (i = &ru->k_ru_last - &ru->k_ru_first; i >= 0; i--)
*ip++ += *ip2++;
}
/*
* Convert an internal kernel rusage structure into a `real' rusage structure.
*/
void
rucvt (rup, krup)
register struct rusage *rup;
register struct k_rusage *krup;
{
bzero((caddr_t)rup, sizeof(*rup));
rup->ru_utime.tv_sec = krup->ru_utime / hz;
rup->ru_utime.tv_usec = (krup->ru_utime % hz) * usechz;
rup->ru_stime.tv_sec = krup->ru_stime / hz;
rup->ru_stime.tv_usec = (krup->ru_stime % hz) * usechz;
rup->ru_nswap = krup->ru_nswap;
rup->ru_inblock = krup->ru_inblock;
rup->ru_oublock = krup->ru_oublock;
rup->ru_msgsnd = krup->ru_msgsnd;
rup->ru_msgrcv = krup->ru_msgrcv;
rup->ru_nsignals = krup->ru_nsignals;
rup->ru_nvcsw = krup->ru_nvcsw;
rup->ru_nivcsw = krup->ru_nivcsw;
}

664
sys/kernel/kern_sig.c Normal file
View File

@@ -0,0 +1,664 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#include "inode.h"
#include "proc.h"
#include "namei.h"
#include "signalvar.h"
/*
* Can the current process send the signal `signum' to process `q'?
* This is complicated by the need to access the `real uid' of `q'.
* The 'real uid' is in the u area and `q' may be (but usually is not) swapped
* out. Use the routine `fill_from_u' which the sysctl() call uses. See the
* notes in kern_sysctl.c
*
* The previous checks for a process to post a signal to another process
* checked _only_ the effective userid. With the implementation of the
* 'saved id' feature and the ability of a setuid program to assume either
* uid that check was inadequate.
*
* The 'c'urrent process is allowed to send a signal to a 't'arget process if
* 1) either the real or effective user ids match OR 2) if the signal is
* SIGCONT and the target process is a descendant of the current process
*/
static int
cansignal (q, signum)
register struct proc *q;
int signum;
{
register struct proc *curp = u.u_procp;
uid_t ruid;
fill_from_u(q, &ruid, NULL, NULL); /* XXX */
if (curp->p_uid == 0 || /* c effective root */
u.u_ruid == ruid || /* c real = t real */
curp->p_uid == ruid || /* c effective = t real */
u.u_ruid == q->p_uid || /* c real = t effective */
curp->p_uid == q->p_uid || /* c effective = t effective */
(signum == SIGCONT && inferior(q)))
return(1);
return(0);
}
/*
* 4.3 Compatibility
*/
void
sigstack()
{
register struct a {
struct sigstack *nss;
struct sigstack *oss;
} *uap = (struct a*) u.u_arg;
struct sigstack ss;
register int error = 0;
ss.ss_sp = u.u_sigstk.ss_base;
ss.ss_onstack = u.u_sigstk.ss_flags & SA_ONSTACK;
if(uap->oss && (error = copyout ((caddr_t) &ss,
(caddr_t) uap->oss, sizeof (ss))))
goto out;
if (uap->nss && (error = copyin ((caddr_t) uap->nss,
(caddr_t) &ss, sizeof (ss))) == 0) {
u.u_sigstk.ss_base = ss.ss_sp;
u.u_sigstk.ss_size = 0;
u.u_sigstk.ss_flags |= (ss.ss_onstack & SA_ONSTACK);
u.u_psflags |= SAS_ALTSTACK;
}
out:
u.u_error = error;
}
static int
killpg1 (signo, pgrp, all)
int signo, pgrp, all;
{
register struct proc *p;
int f, error = 0;
if (! all && pgrp == 0) {
/*
* Zero process id means send to my process group.
*/
pgrp = u.u_procp->p_pgrp;
if (pgrp == 0)
return (ESRCH);
}
for (f = 0, p = allproc; p != NULL; p = p->p_nxt) {
if ((p->p_pgrp != pgrp && !all) || p->p_ppid == 0 ||
(p->p_flag&SSYS) || (all && p == u.u_procp))
continue;
if (! cansignal (p, signo)) {
if (!all)
error = EPERM;
continue;
}
f++;
if (signo)
psignal(p, signo);
}
return (error ? error : (f == 0 ? ESRCH : 0));
}
void
kill()
{
register struct a {
int pid;
int signo;
} *uap = (struct a *)u.u_arg;
register struct proc *p;
register int error = 0;
/*
* BSD4.3 botches the comparison against NSIG - it's a good thing for
* them psignal catches the error - however, since psignal is the
* kernel's internel signal mechanism and *should be getting correct
* parameters from the rest of the kernel, psignal shouldn't *have*
* to check it's parameters for validity. If you feel differently,
* feel free to clutter up the entire inner kernel with parameter
* checks - start with postsig ...
*/
if (uap->signo < 0 || uap->signo >= NSIG) {
error = EINVAL;
goto out;
}
if (uap->pid > 0) {
/* kill single process */
p = pfind(uap->pid);
if (p == 0) {
error = ESRCH;
goto out;
}
if (! cansignal (p, uap->signo))
error = EPERM;
else if (uap->signo)
psignal (p, uap->signo);
goto out;
}
switch (uap->pid) {
case -1: /* broadcast signal */
error = killpg1 (uap->signo, 0, 1);
break;
case 0: /* signal own process group */
error = killpg1 (uap->signo, 0, 0);
break;
default: /* negative explicit process group */
error = killpg1 (uap->signo, -uap->pid, 0);
break;
}
out:
u.u_error = error;
}
void
killpg()
{
register struct a {
int pgrp;
int signo;
} *uap = (struct a *)u.u_arg;
register int error = 0;
if (uap->signo < 0 || uap->signo >= NSIG) {
error = EINVAL;
goto out;
}
error = killpg1 (uap->signo, uap->pgrp, 0);
out:
u.u_error = error;
}
/*
* Put the argument process into the stopped
* state and notify the parent via wakeup.
* Signals are handled elsewhere.
*/
void
stop(p)
register struct proc *p;
{
p->p_stat = SSTOP;
p->p_flag &= ~P_WAITED;
wakeup((caddr_t)p->p_pptr);
}
/*
* Send the specified signal to
* all processes with 'pgrp' as
* process group.
*/
void
gsignal (pgrp, sig)
register int pgrp;
{
register struct proc *p;
if (pgrp == 0)
return;
for (p = allproc; p != NULL; p = p->p_nxt)
if (p->p_pgrp == pgrp)
psignal(p, sig);
}
/*
* Send the specified signal to
* the specified process.
*/
void
psignal(p, sig)
register struct proc *p;
register int sig;
{
register int s;
sig_t action;
int prop;
long mask;
mask = sigmask(sig);
prop = sigprop[sig];
/*
* If proc is traced, always give parent a chance.
*/
if (p->p_flag & P_TRACED)
action = SIG_DFL;
else {
/*
* If the signal is being ignored,
* then we forget about it immediately.
*/
if (p->p_sigignore & mask)
return;
if (p->p_sigmask & mask)
action = SIG_HOLD;
else if (p->p_sigcatch & mask)
action = SIG_CATCH;
else
action = SIG_DFL;
}
if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&
(p->p_flag & P_TRACED) == 0)
p->p_nice = NZERO;
if (prop & SA_CONT)
p->p_sig &= ~stopsigmask;
if (prop & SA_STOP) {
/*
* If sending a tty stop signal to a member of an orphaned
* process group (i.e. a child of init), discard the signal
* here if the action is default; don't stop the process
* below if sleeping, and don't clear any pending SIGCONT.
*/
if ((prop & SA_TTYSTOP) && (p->p_pptr == &proc[1]) &&
action == SIG_DFL)
return;
p->p_sig &= ~contsigmask;
}
p->p_sig |= mask;
/*
* Defer further processing for signals which are held.
*/
if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP))
return;
s = splhigh();
switch (p->p_stat) {
case SSLEEP:
/*
* If process is sleeping uninterruptibly we can not
* interrupt the sleep... the signal will be noticed
* when the process returns through trap() or syscall().
*/
if ((p->p_flag & P_SINTR) == 0)
goto out;
/*
* Process is sleeping and traced... make it runnable
* so it can discover the signal in issignal() and stop
* for the parent.
*/
if (p->p_flag & P_TRACED)
goto run;
/*
* If SIGCONT is default (or ignored) and process is
* asleep, we are finished; the process should not
* be awakened.
*/
if ((prop & SA_CONT) && action == SIG_DFL) {
p->p_sig &= ~mask;
goto out;
}
/*
* When a sleeping process receives a stop
* signal, process immediately if possible.
* All other (caught or default) signals
* cause the process to run.
*/
if (prop & SA_STOP) {
if (action != SIG_DFL)
goto run;
/*
* If a child holding parent blocked,
* stopping could cause deadlock.
*/
if (p->p_flag & SVFORK)
goto out;
p->p_sig &= ~mask;
p->p_ptracesig = sig;
if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
psignal(p->p_pptr, SIGCHLD);
stop(p);
goto out;
} else
goto run;
/*NOTREACHED*/
case SSTOP:
/*
* If traced process is already stopped,
* then no further action is necessary.
*/
if (p->p_flag & P_TRACED)
goto out;
if (sig == SIGKILL)
goto run;
if (prop & SA_CONT) {
/*
* If SIGCONT is default (or ignored), we continue the
* process but don't leave the signal in p_sig, as
* it has no further action. If SIGCONT is held, we
* continue the process and leave the signal in
* p_sig. If the process catches SIGCONT, let it
* handle the signal itself. If it isn't waiting on
* an event, then it goes back to run state.
* Otherwise, process goes back to sleep state.
*/
if (action == SIG_DFL)
p->p_sig &= ~mask;
if (action == SIG_CATCH || p->p_wchan == 0)
goto run;
p->p_stat = SSLEEP;
goto out;
}
if (prop & SA_STOP) {
/*
* Already stopped, don't need to stop again.
* (If we did the shell could get confused.)
*/
p->p_sig &= ~mask; /* take it away */
goto out;
}
/*
* If process is sleeping interruptibly, then simulate a
* wakeup so that when it is continued, it will be made
* runnable and can look at the signal. But don't make
* the process runnable, leave it stopped.
*/
if (p->p_wchan && (p->p_flag & P_SINTR))
unsleep(p);
goto out;
/*NOTREACHED*/
default:
/*
* SRUN, SIDL, SZOMB do nothing with the signal,
* other than kicking ourselves if we are running.
* It will either never be noticed, or noticed very soon.
*/
goto out;
}
/*NOTREACHED*/
run:
/*
* Raise priority to at least PUSER.
*/
if (p->p_pri > PUSER)
p->p_pri = PUSER;
setrun(p);
out:
splx(s);
}
/*
* If the current process has received a signal (should be caught
* or cause termination, should interrupt current syscall) return the
* signal number. Stop signals with default action are processed
* immediately then cleared; they are not returned. This is checked
* after each entry into the kernel for a syscall of trap (though this
* can usually be done without calling issignal by checking the pending
* signals masks in CURSIG)/ The normal sequence is:
*
* while (signum = CURSIG(u.u_procp))
* postsig(signum);
*/
int
issignal (p)
register struct proc *p;
{
register int sig;
long mask;
int prop;
for (;;) {
mask = p->p_sig & ~p->p_sigmask;
if (p->p_flag&SVFORK)
mask &= ~stopsigmask;
if (mask == 0)
return(0); /* No signals to send */
sig = ffs(mask);
mask = sigmask(sig);
prop = sigprop[sig];
/*
* We should see pending but ignored signals
* only if P_TRACED was on when they were posted.
*/
if ((mask & p->p_sigignore) && ! (p->p_flag & P_TRACED)) {
p->p_sig &= ~mask;
continue;
}
if ((p->p_flag & P_TRACED) && ! (p->p_flag & SVFORK)) {
/*
* If traced, always stop, and stay
* stopped until released by the parent.
*
* Note that we must clear the pending signal
* before we call procxmt since that routine
* might cause a fault, calling sleep and
* leading us back here again with the same signal.
* Then we would be deadlocked because the tracer
* would still be blocked on the ipc struct from
* the initial request.
*/
p->p_sig &= ~mask;
p->p_ptracesig = sig;
psignal(p->p_pptr, SIGCHLD);
do {
stop(p);
swtch();
} while (! procxmt() && (p->p_flag & P_TRACED));
/*
* If parent wants us to take the signal,
* then it will leave it in p->p_ptracesig;
* otherwise we just look for signals again.
*/
sig = p->p_ptracesig;
if (sig == 0)
continue;
/*
* Put the new signal into p_sig. If the
* signal is being masked, look for other signals.
*/
mask = sigmask(sig);
p->p_sig |= mask;
if (p->p_sigmask & mask)
continue;
/*
* If the traced bit got turned off, go back up
* to the top to rescan signals. This ensures
* that p_sig* and u_signal are consistent.
*/
if ((p->p_flag& P_TRACED) == 0)
continue;
prop = sigprop[sig];
}
switch ((int)u.u_signal[sig]) {
case (int)SIG_DFL:
/*
* Don't take default actions on system processes.
*/
if (p->p_pid <= 1) {
#ifdef DIAGNOSTIC
/*
* Are you sure you want to ignore SIGSEGV
* in init? XXX
*/
printf("Process (pid %d) got signal %d\n",
p->p_pid, sig);
#endif
break;
}
/*
* If there is a pending stop signal to process
* with default action, stop here,
* then clear the signal. However,
* if process is member of an orphaned
* process group, ignore tty stop signals.
*/
if (prop & SA_STOP) {
if (p->p_flag & P_TRACED ||
(p->p_pptr == &proc[1] &&
prop & SA_TTYSTOP))
break; /* == ignore */
p->p_ptracesig = sig;
if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
psignal(p->p_pptr, SIGCHLD);
stop(p);
swtch();
break;
} else if (prop & SA_IGNORE) {
/*
* Except for SIGCONT, shouldn't get here.
* Default action is to ignore; drop it.
*/
break; /* == ignore */
} else
return(sig);
/*NOTREACHED*/
case (int)SIG_IGN:
/*
* Masking above should prevent us
* ever trying to take action on a held
* or ignored signal, unless process is traced.
*/
if ((prop & SA_CONT) == 0 &&
(p->p_flag & P_TRACED) == 0)
printf("issig\n");
break; /* == ignore */
default:
/*
* This signal has an action, let postsig process it.
*/
return(sig);
}
p->p_sig &= ~mask; /* take the signal away! */
}
/* NOTREACHED */
}
/*
* Create a core image on the file "core"
* If you are looking for protection glitches,
* there are probably a wealth of them here
* when this occurs to a suid command.
*
* It writes UPAGES (USIZE for pdp11) block of the
* user.h area followed by the entire
* data+stack segments.
*/
static int
core()
{
register struct inode *ip;
struct nameidata nd;
register struct nameidata *ndp = &nd;
register char *np;
char *cp, name[MAXCOMLEN + 6];
/*
* Don't dump if not root.
*/
if (! suser())
return(0);
if (USIZE + u.u_dsize + u.u_ssize >= u.u_rlimit[RLIMIT_CORE].rlim_cur)
return (0);
cp = u.u_comm;
np = name;
while ((*np++ = *cp++))
;
cp = ".core";
np--;
while ((*np++ = *cp++))
;
u.u_error = 0;
NDINIT (ndp, CREATE, FOLLOW, name);
ip = namei(ndp);
if (ip == NULL) {
if (u.u_error)
return (0);
ip = maknode (0644, ndp);
if (ip==NULL)
return (0);
}
if (access(ip, IWRITE) ||
(ip->i_mode&IFMT) != IFREG ||
ip->i_nlink != 1) {
u.u_error = EFAULT;
goto out;
}
itrunc(ip, (u_long)0, 0);
u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) &u,
USIZE, (off_t) 0, IO_UNIT, (int*) 0);
if (u.u_error)
goto out;
u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) USER_DATA_START,
u.u_dsize, (off_t) USIZE, IO_UNIT, (int*) 0);
if (u.u_error)
goto out;
u.u_error = rdwri (UIO_WRITE, ip, (caddr_t) USER_DATA_END - u.u_ssize,
u.u_ssize, (off_t) USIZE + u.u_dsize,
IO_UNIT, (int*) 0);
out:
iput(ip);
return (u.u_error == 0);
}
/*
* Take the action for the specified signal
* from the current set of pending signals.
*/
void
postsig(sig)
int sig;
{
register struct proc *p = u.u_procp;
long mask = sigmask(sig), returnmask;
register sig_t action;
p->p_sig &= ~mask;
action = u.u_signal[sig];
if (action != SIG_DFL) {
#ifdef DIAGNOSTIC
if (action == SIG_IGN || (p->p_sigmask & mask))
panic("postsig action");
#endif
u.u_error = 0; /* XXX - why? */
/*
* Set the new mask value and also defer further
* occurences of this signal.
*
* Special case: user has done a sigsuspend. Here the
* current mask is not of interest, but rather the
* mask from before the sigsuspend is what we want restored
* after the signal processing is completed.
*/
(void) splhigh();
if (u.u_psflags & SAS_OLDMASK) {
returnmask = u.u_oldmask;
u.u_psflags &= ~SAS_OLDMASK;
} else
returnmask = p->p_sigmask;
p->p_sigmask |= u.u_sigmask[sig] | mask;
(void) spl0();
u.u_ru.ru_nsignals++;
sendsig(action, sig, returnmask);
return;
}
if (sigprop[sig] & SA_CORE) {
u.u_arg[0] = sig;
if (core())
sig |= 0200;
}
exit(sig);
}

371
sys/kernel/kern_sig2.c Normal file
View File

@@ -0,0 +1,371 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This module is a hacked down version of kern_sig.c from 4.4BSD. The
* original signal handling code is still present in 2.11's kern_sig.c. This
* was done because large modules are very hard to fit into the kernel's
* overlay structure. A smaller kern_sig2.c fits more easily into an overlaid
* kernel.
*/
#define SIGPROP /* include signal properties table */
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/dir.h>
#include <sys/namei.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/user.h> /* for coredump */
static void
setsigvec(signum, sa)
int signum;
register struct sigaction *sa;
{
unsigned long bit;
register struct proc *p = u.u_procp;
bit = sigmask(signum);
/*
* Change setting atomically.
*/
(void) splhigh();
u.u_signal[signum] = sa->sa_handler;
u.u_sigmask[signum] = sa->sa_mask &~ sigcantmask;
if ((sa->sa_flags & SA_RESTART) == 0)
u.u_sigintr |= bit;
else
u.u_sigintr &= ~bit;
if (sa->sa_flags & SA_ONSTACK)
u.u_sigonstack |= bit;
else
u.u_sigonstack &= ~bit;
if (signum == SIGCHLD) {
if (sa->sa_flags & SA_NOCLDSTOP)
p->p_flag |= P_NOCLDSTOP;
else
p->p_flag &= ~P_NOCLDSTOP;
}
/*
* Set bit in p_sigignore for signals that are set to SIG_IGN,
* and for signals set to SIG_DFL where the default is to ignore.
* However, don't put SIGCONT in p_sigignore,
* as we have to restart the process.
*/
if (sa->sa_handler == SIG_IGN ||
(sigprop[signum] & SA_IGNORE && sa->sa_handler == SIG_DFL)) {
p->p_sig &= ~bit; /* never to be seen again */
if (signum != SIGCONT)
p->p_sigignore |= bit; /* easier in psignal */
p->p_sigcatch &= ~bit;
} else {
p->p_sigignore &= ~bit;
if (sa->sa_handler == SIG_DFL)
p->p_sigcatch &= ~bit;
else
p->p_sigcatch |= bit;
}
(void) spl0();
}
void
sigaction()
{
register struct a {
int signum;
struct sigaction *nsa;
struct sigaction *osa;
u_int sigtramp;
} *uap = (struct a *)u.u_arg;
struct sigaction vec;
register struct sigaction *sa;
register int signum;
u_long bit;
int error = 0;
u.u_sigtramp = uap->sigtramp; /* save trampoline address */
signum = uap->signum;
if (signum <= 0 || signum >= NSIG) {
error = EINVAL;
goto out;
}
if (uap->nsa && (signum == SIGKILL || signum == SIGSTOP)) {
error = EINVAL;
goto out;
}
sa = &vec;
if (uap->osa) {
sa->sa_handler = u.u_signal[signum];
sa->sa_mask = u.u_sigmask[signum];
bit = sigmask(signum);
sa->sa_flags = 0;
if ((u.u_sigonstack & bit) != 0)
sa->sa_flags |= SA_ONSTACK;
if ((u.u_sigintr & bit) == 0)
sa->sa_flags |= SA_RESTART;
if (u.u_procp->p_flag & P_NOCLDSTOP)
sa->sa_flags |= SA_NOCLDSTOP;
error = copyout ((caddr_t) sa, (caddr_t) uap->osa, sizeof(vec));
if (error != 0)
goto out;
}
if (uap->nsa) {
error = copyin ((caddr_t) uap->nsa, (caddr_t) sa, sizeof(vec));
if (error != 0)
goto out;
setsigvec(signum, sa);
}
out:
u.u_error = error;
}
/*
* Kill current process with the specified signal in an uncatchable manner;
* used when process is too confused to continue, or we are unable to
* reconstruct the process state safely.
*/
void
fatalsig(signum)
int signum;
{
unsigned long mask;
register struct proc *p = u.u_procp;
u.u_signal[signum] = SIG_DFL;
mask = sigmask(signum);
p->p_sigignore &= ~mask;
p->p_sigcatch &= ~mask;
p->p_sigmask &= ~mask;
psignal(p, signum);
}
/*
* Initialize signal state for process 0;
* set to ignore signals that are ignored by default.
*/
void
siginit(p)
register struct proc *p;
{
register int i;
for (i = 0; i < NSIG; i++)
if (sigprop[i] & SA_IGNORE && i != SIGCONT)
p->p_sigignore |= sigmask(i);
}
/*
* Manipulate signal mask.
* Unlike 4.4BSD we do not receive a pointer to the new and old mask areas and
* do a copyin/copyout instead of storing indirectly thru a 'retval' parameter.
* This is because we have to return both an error indication (which is 16 bits)
* _AND_ the new mask (which is 32 bits). Can't do both at the same time with
* the 2BSD syscall return mechanism.
*/
void
sigprocmask()
{
register struct a {
int how;
sigset_t *set;
sigset_t *oset;
} *uap = (struct a *)u.u_arg;
int error = 0;
sigset_t oldmask, newmask;
register struct proc *p = u.u_procp;
oldmask = p->p_sigmask;
if (! uap->set) /* No new mask, go possibly return old mask */
goto out;
error = copyin ((caddr_t) uap->set, (caddr_t) &newmask, sizeof (newmask));
if (error)
goto out;
(void) splhigh();
switch (uap->how) {
case SIG_BLOCK:
p->p_sigmask |= (newmask &~ sigcantmask);
break;
case SIG_UNBLOCK:
p->p_sigmask &= ~newmask;
break;
case SIG_SETMASK:
p->p_sigmask = newmask &~ sigcantmask;
break;
default:
error = EINVAL;
break;
}
(void) spl0();
out:
if (error == 0 && uap->oset)
error = copyout ((caddr_t) &oldmask, (caddr_t) uap->oset, sizeof (oldmask));
u.u_error = error;
}
/*
* sigpending and sigsuspend use the standard calling sequence unlike 4.4 which
* used a nonstandard (mask instead of pointer) calling convention.
*/
void
sigpending()
{
register struct a {
struct sigset_t *set;
} *uap = (struct a *)u.u_arg;
register int error = 0;
struct proc *p = u.u_procp;
if (uap->set)
error = copyout((caddr_t)&p->p_sig, (caddr_t)uap->set,
sizeof (p->p_sig));
else
error = EINVAL;
u.u_error = error;
}
/*
* sigsuspend is supposed to always return EINTR so we ignore errors on the
* copyin by assuming a mask of 0.
*/
void
sigsuspend()
{
register struct a {
struct sigset_t *set;
} *uap = (struct a *)u.u_arg;
sigset_t nmask = 0;
struct proc *p = u.u_procp;
int error;
if (uap->set && (error = copyin ((caddr_t) uap->set, (caddr_t) &nmask, sizeof (nmask))))
nmask = 0;
/*
* When returning from sigsuspend, we want the old mask to be restored
* after the signal handler has finished. Thus, we save it here and set
* a flag to indicate this.
*/
u.u_oldmask = p->p_sigmask;
u.u_psflags |= SAS_OLDMASK;
p->p_sigmask = nmask &~ sigcantmask;
while (tsleep((caddr_t)&u, PPAUSE|PCATCH, 0) == 0)
;
/* always return EINTR rather than ERESTART */
u.u_error = EINTR;
}
void
sigaltstack()
{
register struct a {
struct sigaltstack * nss;
struct sigaltstack * oss;
} *uap = (struct a *)u.u_arg;
struct sigaltstack ss;
int error = 0;
if ((u.u_psflags & SAS_ALTSTACK) == 0)
u.u_sigstk.ss_flags |= SA_DISABLE;
if (uap->oss && (error = copyout((caddr_t)&u.u_sigstk,
(caddr_t)uap->oss, sizeof (struct sigaltstack))))
goto out;
if (uap->nss == 0)
goto out;
error = copyin ((caddr_t) uap->nss, (caddr_t) &ss, sizeof(ss));
if (error != 0)
goto out;
if (ss.ss_flags & SA_DISABLE) {
if (u.u_sigstk.ss_flags & SA_ONSTACK)
{
error = EINVAL;
goto out;
}
u.u_psflags &= ~SAS_ALTSTACK;
u.u_sigstk.ss_flags = ss.ss_flags;
goto out;
}
if (ss.ss_size < MINSIGSTKSZ)
{
error = ENOMEM;
goto out;
}
u.u_psflags |= SAS_ALTSTACK;
u.u_sigstk = ss;
out:
u.u_error = error;
}
void
sigwait()
{
register struct a {
sigset_t *set;
int *sig;
} *uap = (struct a *)u.u_arg;
sigset_t wanted, sigsavail;
register struct proc *p = u.u_procp;
int signo, error;
if (uap->set == 0 || uap->sig == 0) {
error = EINVAL;
goto out;
}
error = copyin ((caddr_t) uap->set, (caddr_t) &wanted, sizeof (sigset_t));
if (error)
goto out;
wanted |= sigcantmask;
while ((sigsavail = (wanted & p->p_sig)) == 0)
tsleep ((caddr_t) &u.u_signal[0], PPAUSE | PCATCH, 0);
if (sigsavail & sigcantmask) {
error = EINTR;
goto out;
}
signo = ffs(sigsavail);
p->p_sig &= ~sigmask(signo);
error = copyout ((caddr_t) &signo, (caddr_t) uap->sig, sizeof (int));
out:
u.u_error = error;
}

126
sys/kernel/kern_subr.c Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#include "buf.h"
#include "uio.h"
/*
* Move data to/from user space.
*/
int
uiomove (cp, n, uio)
caddr_t cp;
u_int n;
register struct uio *uio;
{
register struct iovec *iov;
int error = 0;
register u_int cnt;
while (n > 0 && uio->uio_resid) {
iov = uio->uio_iov;
cnt = iov->iov_len;
if (cnt == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
continue;
}
if (cnt > n)
cnt = n;
if (uio->uio_rw == UIO_READ)
bcopy ((caddr_t) cp, iov->iov_base, cnt);
else
bcopy (iov->iov_base, (caddr_t) cp, cnt);
iov->iov_base += cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
uio->uio_offset += cnt;
cp += cnt;
n -= cnt;
}
return (error);
}
/*
* Give next character to user as result of read.
*/
int
ureadc (c, uio)
register int c;
register struct uio *uio;
{
register struct iovec *iov;
again:
if (uio->uio_iovcnt == 0)
panic("ureadc");
iov = uio->uio_iov;
if (iov->iov_len == 0 || uio->uio_resid == 0) {
uio->uio_iovcnt--;
uio->uio_iov++;
goto again;
}
*iov->iov_base = c;
iov->iov_base++;
iov->iov_len--;
uio->uio_resid--;
uio->uio_offset++;
return (0);
}
/*
* Get next character written in by user from uio.
*/
int
uwritec(uio)
register struct uio *uio;
{
register struct iovec *iov;
register int c;
if (uio->uio_resid == 0)
return (-1);
again:
if (uio->uio_iovcnt <= 0)
panic("uwritec");
iov = uio->uio_iov;
if (iov->iov_len == 0) {
uio->uio_iov++;
if (--uio->uio_iovcnt == 0)
return (-1);
goto again;
}
c = (u_char) *iov->iov_base;
iov->iov_base++;
iov->iov_len--;
uio->uio_resid--;
uio->uio_offset++;
return (c & 0377);
}
/*
* Copy bytes to/from the kernel and the user.
*/
int
uiofmove(cp, n, uio, iov)
caddr_t cp;
register int n;
struct uio *uio;
struct iovec *iov;
{
if (uio->uio_rw == UIO_READ) {
/* From kernel to user. */
bcopy(cp, iov->iov_base, n);
} else {
/* From user to kernel. */
bcopy(iov->iov_base, cp, n);
}
return(0);
}

538
sys/kernel/kern_synch.c Normal file
View File

@@ -0,0 +1,538 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "buf.h"
#include "signal.h"
#include "signalvar.h"
#include "vm.h"
#include "kernel.h"
#include "systm.h"
#define SQSIZE 16 /* Must be power of 2 */
#define HASH(x) (((int)x >> 5) & (SQSIZE - 1))
#define SCHMAG 8/10
struct proc *slpque[SQSIZE];
int runrun; /* scheduling flag */
char curpri; /* more scheduling */
/*
* Recompute process priorities, once a second
*/
void
schedcpu (caddr_t arg)
{
register struct proc *p;
register int a;
wakeup((caddr_t)&lbolt);
for (p = allproc; p != NULL; p = p->p_nxt) {
if (p->p_time != 127)
p->p_time++;
/*
* this is where 2.11 does its real time alarms. 4.X uses
* timeouts, since it offers better than second resolution.
* Putting it here allows us to continue using use an int
* to store the number of ticks in the callout structure,
* since the kernel never has a timeout of greater than
* around 9 minutes.
*/
if (p->p_realtimer.it_value && !--p->p_realtimer.it_value) {
psignal(p, SIGALRM);
p->p_realtimer.it_value = p->p_realtimer.it_interval;
}
if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
if (p->p_slptime != 127)
p->p_slptime++;
if (p->p_slptime > 1)
continue;
a = (p->p_cpu & 0377) * SCHMAG + p->p_nice;
if (a < 0)
a = 0;
if (a > 255)
a = 255;
p->p_cpu = a;
if (p->p_pri >= PUSER)
setpri(p);
}
vmmeter();
if (runin != 0) {
runin = 0;
wakeup((caddr_t)&runin);
}
++runrun; /* swtch at least once a second */
timeout (schedcpu, (caddr_t) 0, hz);
}
/*
* Recalculate the priority of a process after it has slept for a while.
*/
void
updatepri(p)
register struct proc *p;
{
register int a = p->p_cpu & 0377;
p->p_slptime--; /* the first time was done in schedcpu */
while (a && --p->p_slptime)
a = (SCHMAG * a) /* + p->p_nice */;
if (a < 0)
a = 0;
if (a > 255)
a = 255;
p->p_cpu = a;
(void) setpri(p);
}
/*
* Implement timeout for tsleep above. If process hasn't been awakened
* (p_wchan non zero) then set timeout flag and undo the sleep. If proc
* is stopped just unsleep so it will remain stopped.
*/
static void
endtsleep (p)
register struct proc *p;
{
register int s;
s = splhigh();
if (p->p_wchan) {
if (p->p_stat == SSLEEP)
setrun(p);
else
unsleep(p);
p->p_flag |= P_TIMEOUT;
}
splx(s);
}
/*
* General sleep call "borrowed" from 4.4BSD - the 'wmesg' parameter was
* removed due to data space concerns. Sleeps at most timo/hz seconds
* 0 means no timeout). NOTE: timeouts in 2.11BSD use a signed int and
* thus can be at most 32767 'ticks' or about 540 seconds in the US with
* 60hz power (~650 seconds if 50hz power is being used).
*
* If 'pri' includes the PCATCH flag signals are checked before and after
* sleeping otherwise signals are not checked. Returns 0 if a wakeup was
* done, EWOULDBLOCK if the timeout expired, ERESTART if the current system
* call should be restarted, and EINTR if the system call should be
* interrupted and EINTR returned to the user process.
*/
int
tsleep (ident, priority, timo)
caddr_t ident;
int priority;
u_int timo;
{
register struct proc *p = u.u_procp;
register struct proc **qp;
int s;
int sig, catch = priority & PCATCH;
s = splhigh();
if (panicstr) {
/*
* After a panic just give interrupts a chance then just return. Don't
* run any other procs (or panic again below) in case this is the idle
* process and already asleep. The splnet should be spl0 if the network
* was being used but for now avoid network interrupts that might cause
* another panic.
*/
(void) splnet();
noop();
splx(s);
return(0);
}
#ifdef DIAGNOSTIC
if (ident == NULL || p->p_stat != SRUN)
panic("tsleep");
#endif
p->p_wchan = ident;
p->p_slptime = 0;
p->p_pri = priority & PRIMASK;
qp = &slpque[HASH(ident)];
p->p_link = *qp;
*qp = p;
if (timo)
timeout (endtsleep, (caddr_t)p, timo);
/*
* We put outselves on the sleep queue and start the timeout before calling
* CURSIG as we could stop there and a wakeup or a SIGCONT (or both) could
* occur while we were stopped. A SIGCONT would cause us to be marked SSLEEP
* without resuming us thus we must be ready for sleep when CURSIG is called.
* If the wakeup happens while we're stopped p->p_wchan will be 0 upon
* return from CURSIG.
*/
if (catch) {
p->p_flag |= P_SINTR;
sig = CURSIG(p);
if (sig) {
if (p->p_wchan)
unsleep(p);
p->p_stat = SRUN;
goto resume;
}
if (p->p_wchan == 0) {
catch = 0;
goto resume;
}
} else
sig = 0;
p->p_stat = SSLEEP;
if (p != &proc[0])
wakeup((caddr_t) &runin);
u.u_ru.ru_nvcsw++;
swtch();
resume:
splx(s);
p->p_flag &= ~P_SINTR;
if (p->p_flag & P_TIMEOUT) {
p->p_flag &= ~P_TIMEOUT;
if (sig == 0)
return(EWOULDBLOCK);
} else if (timo)
untimeout (endtsleep, (caddr_t)p);
if (catch && (sig != 0 || (sig = CURSIG(p)))) {
if (u.u_sigintr & sigmask(sig))
return(EINTR);
return(ERESTART);
}
return(0);
}
/*
* Give up the processor till a wakeup occurs on chan, at which time the
* process enters the scheduling queue at priority pri.
*
* This routine was rewritten to use 'tsleep'. The old behaviour of sleep
* being interruptible (if 'pri>PZERO') is emulated by setting PCATCH and
* then performing the 'longjmp' if the return value of 'tsleep' is
* ERESTART.
*
* Callers of this routine must be prepared for premature return, and check
* that the reason for sleeping has gone away.
*/
void
sleep (chan, pri)
caddr_t chan;
int pri;
{
register int priority = pri;
if (pri > PZERO)
priority |= PCATCH;
u.u_error = tsleep (chan, priority, 0);
/*
* sleep does not return anything. If it was a non-interruptible sleep _or_
* a successful/normal sleep (one for which a wakeup was done) then return.
*/
if ((priority & PCATCH) == 0 || (u.u_error == 0))
return;
/*
* XXX - compatibility uglyness.
*
* The tsleep() above will leave one of the following in u_error:
*
* 0 - a wakeup was done, this is handled above
* EWOULDBLOCK - since no timeout was passed to tsleep we will not see this
* EINTR - put into u_error for trap.c to find (interrupted syscall)
* ERESTART - system call to be restared
*/
longjmp (u.u_procp->p_addr, &u.u_qsave);
/*NOTREACHED*/
}
/*
* Remove a process from its wait queue
*/
void
unsleep (p)
register struct proc *p;
{
register struct proc **hp;
register int s;
s = splhigh();
if (p->p_wchan) {
hp = &slpque[HASH(p->p_wchan)];
while (*hp != p)
hp = &(*hp)->p_link;
*hp = p->p_link;
p->p_wchan = 0;
}
splx(s);
}
/*
* Wake up all processes sleeping on chan.
*/
void
wakeup (chan)
register caddr_t chan;
{
register struct proc *p, **q;
struct proc **qp;
int s;
/*
* Since we are called at interrupt time, must insure normal
* kernel mapping to access proc.
*/
s = splclock();
qp = &slpque[HASH(chan)];
restart:
for (q = qp; (p = *q); ) {
if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
panic("wakeup");
if (p->p_wchan==chan) {
p->p_wchan = 0;
*q = p->p_link;
if (p->p_stat == SSLEEP) {
/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
p->p_stat = SRUN;
if (p->p_flag & SLOAD)
setrq(p);
/*
* Since curpri is a usrpri,
* p->p_pri is always better than curpri.
*/
runrun++;
if (! (p->p_flag & SLOAD)) {
if (runout != 0) {
runout = 0;
wakeup((caddr_t)&runout);
}
}
/* END INLINE EXPANSION */
goto restart;
}
p->p_slptime = 0;
} else
q = &p->p_link;
}
splx(s);
}
/*
* Set the process running;
* arrange for it to be swapped in if necessary.
*/
void
setrun (p)
register struct proc *p;
{
register int s;
s = splhigh();
switch (p->p_stat) {
case 0:
case SWAIT:
case SRUN:
case SZOMB:
default:
panic("setrun");
case SSTOP:
case SSLEEP:
unsleep(p); /* e.g. when sending signals */
break;
case SIDL:
break;
}
if (p->p_slptime > 1)
updatepri(p);
p->p_stat = SRUN;
if (p->p_flag & SLOAD)
setrq(p);
splx(s);
if (p->p_pri < curpri)
runrun++;
if (! (p->p_flag & SLOAD)) {
if (runout != 0) {
runout = 0;
wakeup((caddr_t)&runout);
}
}
}
/*
* Set user priority.
* The rescheduling flag (runrun)
* is set if the priority is better
* than the currently running process.
*/
int
setpri (pp)
register struct proc *pp;
{
register int p;
p = (pp->p_cpu & 0377)/16;
p += PUSER + pp->p_nice;
if (p > 127)
p = 127;
if (p < curpri)
runrun++;
pp->p_pri = p;
return (p);
}
/*
* This routine is called to reschedule the CPU. If the calling process is
* not in RUN state, arrangements for it to restart must have been made
* elsewhere, usually by calling via sleep. There is a race here. A process
* may become ready after it has been examined. In this case, idle() will be
* called and will return in at most 1hz time, e.g. it's not worth putting an
* spl() in.
*/
void
swtch()
{
register struct proc *p, *q;
register int n;
struct proc *pp, *pq;
int s;
#ifdef UCB_METER
cnt.v_swtch++;
#endif
/* If not the idle process, resume the idle process. */
if (u.u_procp != &proc[0]) {
if (setjmp (&u.u_rsave)) {
/* Returned from swapper to user process. */
return;
}
/* Switch from user process to swapper. */
longjmp (proc[0].p_addr, &u.u_qsave);
}
/*
* The first save returns nonzero when proc 0 is resumed
* by another process (above); then the second is not done
* and the process-search loop is entered.
*/
if (setjmp (&u.u_qsave)) {
/* Returned from user process. */
goto loop;
}
/*
* The first save returns 0 when swtch is called in proc 0
* from sched(). The second save returns 0 immediately, so
* in this case too the process-search loop is entered.
* Thus when proc 0 is awakened by being made runnable, it will
* find itself and resume itself at rsave, and return to sched().
*/
if (setjmp (&u.u_rsave)) {
/* Swapper resumed by itself. */
return;
}
loop:
s = splhigh();
noproc = 0;
runrun = 0;
#ifdef DIAGNOSTIC
for (p = qs; p; p = p->p_link)
if (p->p_stat != SRUN)
panic ("swtch SRUN");
#endif
pp = NULL;
q = NULL;
n = 128;
/*
* search for highest-priority runnable process
*/
pq = 0;
for (p = qs; p; p = p->p_link) {
if (p->p_flag & SLOAD && p->p_pri < n) {
pp = p;
pq = q;
n = p->p_pri;
}
q = p;
}
/*
* if no process is runnable, idle.
*/
p = pp;
if (p == NULL) {
idle();
goto loop;
}
if (pq)
pq->p_link = p->p_link;
else
qs = p->p_link;
curpri = n;
splx(s);
/*
* the rsave (ssave) contents are interpreted
* in the new address space
*/
n = p->p_flag & SSWAP;
p->p_flag &= ~SSWAP;
longjmp (p->p_addr, n ? &u.u_ssave : &u.u_rsave);
}
/*
* Put the process into the run queue.
*/
void
setrq (p)
register struct proc *p;
{
register int s;
s = splhigh();
#ifdef DIAGNOSTIC
{ /* see if already on the run queue */
register struct proc *q;
for (q = qs;q != NULL;q = q->p_link)
if (q == p)
panic("setrq");
}
#endif
p->p_link = qs;
qs = p;
splx(s);
}
/*
* Remove runnable job from run queue. This is done when a runnable job
* is swapped out so that it won't be selected in swtch(). It will be
* reinserted in the qs with setrq when it is swapped back in.
*/
void
remrq (p)
register struct proc *p;
{
register struct proc *q;
register int s;
s = splhigh();
if (p == qs)
qs = p->p_link;
else {
for (q = qs; q; q = q->p_link)
if (q->p_link == p) {
q->p_link = p->p_link;
goto done;
}
panic("remrq");
}
done:
splx(s);
}

909
sys/kernel/kern_sysctl.c Normal file
View File

@@ -0,0 +1,909 @@
/*
* sysctl system call.
*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Karels at Berkeley Software Design, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/inode.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/vm.h>
#include <sys/map.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
#include <conf.h>
sysctlfn kern_sysctl;
sysctlfn hw_sysctl;
#ifdef DEBUG
sysctlfn debug_sysctl;
#endif
sysctlfn vm_sysctl;
sysctlfn fs_sysctl;
#ifdef INET
sysctlfn net_sysctl;
#endif
sysctlfn cpu_sysctl;
struct sysctl_args {
int *name;
u_int namelen;
void *old;
size_t *oldlenp;
void *new;
size_t newlen;
};
static int sysctl_clockrate (char *where, size_t *sizep);
static int sysctl_inode (char *where, size_t *sizep);
static int sysctl_file (char *where, size_t *sizep);
static int sysctl_doproc (int *name, u_int namelen, char *where, size_t *sizep);
void
__sysctl()
{
register struct sysctl_args *uap = (struct sysctl_args*) u.u_arg;
int error;
u_int oldlen = 0;
sysctlfn *fn;
int name [CTL_MAXNAME];
if (uap->new != NULL && ! suser())
return;
/*
* all top-level sysctl names are non-terminal
*/
if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) {
u.u_error = EINVAL;
return;
}
error = copyin ((caddr_t) uap->name, (caddr_t) &name, uap->namelen * sizeof(int));
if (error) {
u.u_error = error;
return;
}
switch (name[0]) {
case CTL_KERN:
fn = kern_sysctl;
break;
case CTL_HW:
fn = hw_sysctl;
break;
case CTL_VM:
fn = vm_sysctl;
break;
#ifdef INET
case CTL_NET:
fn = net_sysctl;
break;
#endif
#ifdef notyet
case CTL_FS:
fn = fs_sysctl;
break;
#endif
case CTL_MACHDEP:
fn = cpu_sysctl;
break;
#ifdef DEBUG
case CTL_DEBUG:
fn = debug_sysctl;
break;
#endif
default:
u.u_error = EOPNOTSUPP;
return;
}
if (uap->oldlenp && (error = copyin ((caddr_t) uap->oldlenp,
(caddr_t) &oldlen, sizeof(oldlen)))) {
u.u_error = error;
return;
}
if (uap->old != NULL) {
while (memlock.sl_lock) {
memlock.sl_want = 1;
sleep((caddr_t)&memlock, PRIBIO+1);
memlock.sl_locked++;
}
memlock.sl_lock = 1;
}
error = (*fn) (name + 1, uap->namelen - 1, uap->old, &oldlen,
uap->new, uap->newlen);
if (uap->old != NULL) {
memlock.sl_lock = 0;
if (memlock.sl_want) {
memlock.sl_want = 0;
wakeup((caddr_t)&memlock);
}
}
if (error) {
u.u_error = error;
return;
}
if (uap->oldlenp) {
error = copyout ((caddr_t) &oldlen, (caddr_t) uap->oldlenp, sizeof(oldlen));
if (error) {
u.u_error = error;
return;
}
}
u.u_rval = oldlen;
}
/*
* kernel related system variables.
*/
int
kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
int error, level;
u_long longhostid;
char bsd[10];
/* all sysctl names at this level are terminal */
if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case KERN_OSTYPE:
case KERN_OSRELEASE:
/* code is cheaper than D space */
bsd[0]='2';bsd[1]='.';bsd[2]='1';bsd[3]='1';bsd[4]='B';
bsd[5]='S';bsd[6]='D';bsd[7]='\0';
return (sysctl_rdstring(oldp, oldlenp, newp, bsd));
case KERN_OSREV:
return (sysctl_rdlong(oldp, oldlenp, newp, (long)BSD));
case KERN_VERSION:
return (sysctl_rdstring(oldp, oldlenp, newp, version));
case KERN_MAXINODES:
return(sysctl_rdint(oldp, oldlenp, newp, NINODE));
case KERN_MAXPROC:
return (sysctl_rdint(oldp, oldlenp, newp, NPROC));
case KERN_MAXFILES:
return (sysctl_rdint(oldp, oldlenp, newp, NFILE));
case KERN_ARGMAX:
return (sysctl_rdint(oldp, oldlenp, newp, NCARGS));
case KERN_SECURELVL:
level = securelevel;
if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
newp == NULL)
return (error);
if (level < securelevel && u.u_procp->p_pid != 1)
return (EPERM);
securelevel = level;
return (0);
case KERN_HOSTNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
hostname, sizeof(hostname));
if (newp && !error)
hostnamelen = newlen;
return (error);
case KERN_HOSTID:
longhostid = hostid;
error = sysctl_long(oldp, oldlenp, newp, newlen, (long*) &longhostid);
hostid = longhostid;
return (error);
case KERN_CLOCKRATE:
return (sysctl_clockrate(oldp, oldlenp));
case KERN_BOOTTIME:
return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
sizeof(struct timeval)));
case KERN_INODE:
return (sysctl_inode(oldp, oldlenp));
case KERN_PROC:
return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
case KERN_FILE:
return (sysctl_file(oldp, oldlenp));
#ifdef GPROF
case KERN_PROF:
return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
#endif
case KERN_NGROUPS:
return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS));
case KERN_JOB_CONTROL:
return (sysctl_rdint(oldp, oldlenp, newp, 1));
case KERN_POSIX1:
case KERN_SAVED_IDS:
return (sysctl_rdint(oldp, oldlenp, newp, 0));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
/*
* hardware related system variables.
*/
int
hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
/* all sysctl names at this level are terminal */
if (namelen != 1)
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case HW_MACHINE:
return (sysctl_rdstring(oldp, oldlenp, newp, "pic32"));
case HW_MODEL:
return (sysctl_rdstring(oldp, oldlenp, newp, "mips"));
case HW_NCPU:
return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */
case HW_BYTEORDER:
return (sysctl_rdint(oldp, oldlenp, newp, ENDIAN));
case HW_PHYSMEM:
return (sysctl_rdlong(oldp, oldlenp, newp, physmem));
#ifdef UCB_METER
case HW_USERMEM:
return (sysctl_rdlong(oldp, oldlenp, newp, freemem));
#endif
case HW_PAGESIZE:
return (sysctl_rdint(oldp, oldlenp, newp, DEV_BSIZE));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
#ifdef DEBUG
/*
* Debugging related system variables.
*/
struct ctldebug debug0, debug1, debug2, debug3, debug4;
struct ctldebug debug5, debug6, debug7, debug8, debug9;
struct ctldebug debug10, debug11, debug12, debug13, debug14;
struct ctldebug debug15, debug16, debug17, debug18, debug19;
static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
&debug0, &debug1, &debug2, &debug3, &debug4,
&debug5, &debug6, &debug7, &debug8, &debug9,
&debug10, &debug11, &debug12, &debug13, &debug14,
&debug15, &debug16, &debug17, &debug18, &debug19,
};
int
debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
struct ctldebug *cdp;
/* all sysctl names at this level are name and field */
if (namelen != 2)
return (ENOTDIR); /* overloaded */
cdp = debugvars[name[0]];
if (cdp->debugname == 0)
return (EOPNOTSUPP);
switch (name[1]) {
case CTL_DEBUG_NAME:
return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
case CTL_DEBUG_VALUE:
return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
#endif /* DEBUG */
/*
* Bit of a hack. 2.11 currently uses 'short avenrun[3]' and a fixed scale
* of 256. In order not to break all the applications which nlist() for
* 'avenrun' we build a local 'averunnable' structure here to return to the
* user. Eventually (after all applications which look up the load average
* the old way) have been converted we can change things.
*
* We do not call vmtotal(), that could get rather expensive, rather we rely
* on the 5 second update.
*
* The swapmap case is 2.11BSD extension.
*/
int
vm_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
struct loadavg averunnable; /* loadavg in resource.h */
/* all sysctl names at this level are terminal */
if (namelen != 1)
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case VM_LOADAVG:
averunnable.fscale = 256;
averunnable.ldavg[0] = avenrun[0];
averunnable.ldavg[1] = avenrun[1];
averunnable.ldavg[2] = avenrun[2];
return (sysctl_rdstruct(oldp, oldlenp, newp, &averunnable,
sizeof(averunnable)));
case VM_METER:
#ifdef notsure
vmtotal(); /* could be expensive to do this every time */
#endif
return (sysctl_rdstruct(oldp, oldlenp, newp, &total,
sizeof(total)));
case VM_SWAPMAP:
if (oldp == NULL) {
*oldlenp = (char *)swapmap[0].m_limit -
(char *)swapmap[0].m_map;
return(0);
}
return (sysctl_rdstruct(oldp, oldlenp, newp, swapmap,
(int)swapmap[0].m_limit - (int)swapmap[0].m_map));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
/*
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
*/
int
sysctl_int(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
int *valp;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp && newlen != sizeof(int))
return (EINVAL);
*oldlenp = sizeof(int);
if (oldp)
error = copyout ((caddr_t) valp, (caddr_t) oldp, sizeof(int));
if (error == 0 && newp)
error = copyin ((caddr_t) newp, (caddr_t) valp, sizeof(int));
return (error);
}
/*
* As above, but read-only.
*/
int
sysctl_rdint(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
void *newp;
int val;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(int);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(int));
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for an long-valued sysctl function.
*/
int
sysctl_long(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
long *valp;
{
int error = 0;
if (oldp && *oldlenp < sizeof(long))
return (ENOMEM);
if (newp && newlen != sizeof(long))
return (EINVAL);
*oldlenp = sizeof(long);
if (oldp)
error = copyout ((caddr_t) valp, (caddr_t) oldp, sizeof(long));
if (error == 0 && newp)
error = copyin ((caddr_t) newp, (caddr_t) valp, sizeof(long));
return (error);
}
/*
* As above, but read-only.
*/
int
sysctl_rdlong(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
void *newp;
long val;
{
int error = 0;
if (oldp && *oldlenp < sizeof(long))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(long);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(long));
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for a string-valued sysctl function.
*/
int
sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
char *str;
int maxlen;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout (str, oldp, len);
}
if (error == 0 && newp) {
error = copyin (newp, str, newlen);
str[newlen] = 0;
}
return (error);
}
/*
* As above, but read-only.
*/
int
sysctl_rdstring(oldp, oldlenp, newp, str)
void *oldp;
size_t *oldlenp;
void *newp;
const char *str;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout ((caddr_t) str, oldp, len);
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for a structure oriented sysctl function.
*/
int
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
void *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen > len)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(sp, oldp, len);
}
if (error == 0 && newp)
error = copyin(newp, sp, len);
return (error);
}
/*
* Validate parameters and get old parameters
* for a structure oriented sysctl function.
*/
int
sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
void *oldp;
size_t *oldlenp;
void *newp, *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(sp, oldp, len);
return (error);
}
/*
* Get file structures.
*/
int
sysctl_file(where, sizep)
char *where;
size_t *sizep;
{
int buflen, error;
register struct file *fp;
struct file *fpp;
char *start = where;
register int i;
buflen = *sizep;
if (where == NULL) {
for (i = 0, fp = file; fp < file+NFILE; fp++)
if (fp->f_count) i++;
#define FPTRSZ sizeof (struct file *)
#define FILESZ sizeof (struct file)
/*
* overestimate by 5 files
*/
*sizep = (i + 5) * (FILESZ + FPTRSZ);
return (0);
}
/*
* array of extended file structures: first the address then the
* file structure.
*/
for (fp = file; fp < file+NFILE; fp++) {
if (fp->f_count == 0)
continue;
if (buflen < (FPTRSZ + FILESZ)) {
*sizep = where - start;
return (ENOMEM);
}
fpp = fp;
if ((error = copyout ((caddr_t) &fpp, (caddr_t) where, FPTRSZ)) ||
(error = copyout ((caddr_t) fp, (caddr_t) (where + FPTRSZ), FILESZ)))
return (error);
buflen -= (FPTRSZ + FILESZ);
where += (FPTRSZ + FILESZ);
}
*sizep = where - start;
return (0);
}
/*
* This one is in kern_clock.c in 4.4 but placed here for the reasons
* given earlier (back around line 367).
*/
int
sysctl_clockrate (where, sizep)
char *where;
size_t *sizep;
{
struct clockinfo clkinfo;
/*
* Construct clockinfo structure.
*/
clkinfo.hz = hz;
clkinfo.tick = usechz;
clkinfo.profhz = 0;
clkinfo.stathz = hz;
return(sysctl_rdstruct(where, sizep, NULL, &clkinfo, sizeof (clkinfo)));
}
/*
* Dump inode list (via sysctl).
* Copyout address of inode followed by inode.
*/
/* ARGSUSED */
int
sysctl_inode (where, sizep)
char *where;
size_t *sizep;
{
register struct inode *ip;
register char *bp = where;
struct inode *ipp;
char *ewhere;
int error, numi;
for (numi = 0, ip = inode; ip < inode+NINODE; ip++)
if (ip->i_count) numi++;
#define IPTRSZ sizeof (struct inode *)
#define INODESZ sizeof (struct inode)
if (where == NULL) {
*sizep = (numi + 5) * (IPTRSZ + INODESZ);
return (0);
}
ewhere = where + *sizep;
for (ip = inode; ip < inode+NINODE; ip++) {
if (ip->i_count == 0)
continue;
if (bp + IPTRSZ + INODESZ > ewhere) {
*sizep = bp - where;
return (ENOMEM);
}
ipp = ip;
if ((error = copyout ((caddr_t)&ipp, bp, IPTRSZ)) ||
(error = copyout ((caddr_t)ip, bp + IPTRSZ, INODESZ)))
return (error);
bp += IPTRSZ + INODESZ;
}
*sizep = bp - where;
return (0);
}
/*
* Three pieces of information we need about a process are not kept in
* the proc table: real uid, controlling terminal device, and controlling
* terminal tty struct pointer. For these we must look in either the u
* area or the swap area. If the process is still in memory this is
* easy but if the process has been swapped out we have to read in the
* u area.
*
* XXX - We rely on the fact that u_ttyp, u_ttyd, and u_ruid are all within
* XXX - the first 1kb of the u area. If this ever changes the logic below
* XXX - will break (and badly). At the present time (97/9/2) the u area
* XXX - is 856 bytes long.
*/
void
fill_from_u (p, rup, ttp, tdp)
struct proc *p;
uid_t *rup;
struct tty **ttp;
dev_t *tdp;
{
register struct buf *bp;
dev_t ttyd;
uid_t ruid;
struct tty *ttyp;
struct user *up;
if (p->p_stat == SZOMB) {
ruid = (uid_t)-2;
ttyp = NULL;
ttyd = NODEV;
goto out;
}
if (p->p_flag & SLOAD) {
ttyd = ((struct user *)p->p_addr)->u_ttyd;
ttyp = ((struct user *)p->p_addr)->u_ttyp;
ruid = ((struct user *)p->p_addr)->u_ruid;
} else {
bp = geteblk();
bp->b_dev = swapdev;
bp->b_blkno = (daddr_t)p->p_addr;
bp->b_bcount = DEV_BSIZE; /* XXX */
bp->b_flags = B_READ;
(*bdevsw[major(swapdev)].d_strategy)(bp);
biowait(bp);
if (u.u_error) {
ttyd = NODEV;
ttyp = NULL;
ruid = (uid_t)-2;
} else {
up = (struct user*) bp->b_addr;
ruid = up->u_ruid; /* u_ruid = offset 164 */
ttyd = up->u_ttyd; /* u_ttyd = offset 654 */
ttyp = up->u_ttyp; /* u_ttyp = offset 652 */
}
bp->b_flags |= B_AGE;
brelse(bp);
u.u_error = 0; /* XXX */
}
out:
if (rup)
*rup = ruid;
if (ttp)
*ttp = ttyp;
if (tdp)
*tdp = ttyd;
}
/*
* Fill in an eproc structure for the specified process. Slightly
* inefficient because we have to access the u area again for the
* information not kept in the proc structure itself. Can't afford
* to expand the proc struct so we take a slight speed hit here.
*/
static void
fill_eproc(p, ep)
register struct proc *p;
register struct eproc *ep;
{
struct tty *ttyp;
ep->e_paddr = p;
fill_from_u(p, &ep->e_ruid, &ttyp, &ep->e_tdev);
if (ttyp)
ep->e_tpgid = ttyp->t_pgrp;
else
ep->e_tpgid = 0;
}
/*
* try over estimating by 5 procs
*/
#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
int
sysctl_doproc(name, namelen, where, sizep)
int *name;
u_int namelen;
char *where;
size_t *sizep;
{
register struct proc *p;
register struct kinfo_proc *dp = (struct kinfo_proc *)where;
int needed = 0;
int buflen = where != NULL ? *sizep : 0;
int doingzomb;
struct eproc eproc;
int error = 0;
dev_t ttyd;
uid_t ruid;
struct tty *ttyp;
if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
return (EINVAL);
p = (struct proc *)allproc;
doingzomb = 0;
again:
for (; p != NULL; p = p->p_nxt) {
/*
* Skip embryonic processes.
*/
if (p->p_stat == SIDL)
continue;
/*
* TODO: sysctl_oproc - make more efficient (see notes below).
* do by session.
*/
switch (name[0]) {
case KERN_PROC_PID:
/* could do this with just a lookup */
if (p->p_pid != (pid_t)name[1])
continue;
break;
case KERN_PROC_PGRP:
/* could do this by traversing pgrp */
if (p->p_pgrp != (pid_t)name[1])
continue;
break;
case KERN_PROC_TTY:
fill_from_u(p, &ruid, &ttyp, &ttyd);
if (!ttyp || ttyd != (dev_t)name[1])
continue;
break;
case KERN_PROC_UID:
if (p->p_uid != (uid_t)name[1])
continue;
break;
case KERN_PROC_RUID:
fill_from_u(p, &ruid, &ttyp, &ttyd);
if (ruid != (uid_t)name[1])
continue;
break;
case KERN_PROC_ALL:
break;
default:
return(EINVAL);
}
if (buflen >= sizeof(struct kinfo_proc)) {
fill_eproc(p, &eproc);
error = copyout ((caddr_t) p, (caddr_t) &dp->kp_proc,
sizeof(struct proc));
if (error)
return (error);
error = copyout ((caddr_t)&eproc, (caddr_t) &dp->kp_eproc,
sizeof(eproc));
if (error)
return (error);
dp++;
buflen -= sizeof(struct kinfo_proc);
}
needed += sizeof(struct kinfo_proc);
}
if (doingzomb == 0) {
p = zombproc;
doingzomb++;
goto again;
}
if (where != NULL) {
*sizep = (caddr_t)dp - where;
if (needed > *sizep)
return (ENOMEM);
} else {
needed += KERN_PROCSLOP;
*sizep = needed;
}
return (0);
}

342
sys/kernel/kern_time.c Normal file
View File

@@ -0,0 +1,342 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "kernel.h"
#include "systm.h"
static void
setthetime (tv)
register struct timeval *tv;
{
int s;
if (! suser())
return;
#ifdef NOTNOW
/*
* If the system is secure, we do not allow the time to be set to an
* earlier value. The time may be slowed (using adjtime) but not set back.
*
* NOTE: Can not do this until ntpd is updated to deal with the coarse (50, 60
* hz) clocks. Ntpd wants to adjust time system clock a few microseconds
* at a time (which gets rounded to 0 in adjtime below). If that fails
* ntpd uses settimeofday to step the time backwards which obviously
* will fail if the next 'if' is enabled - all that does is fill up the
* logfiles with "can't set time" messages and the time keeps drifting.
*/
if (securelevel > 0 && timercmp(tv, &time, <)) {
u.u_error = EPERM; /* XXX */
return;
}
#endif
/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
boottime.tv_sec += tv->tv_sec - time.tv_sec;
s = splhigh();
time = *tv;
lbolt = time.tv_usec / usechz;
splx(s);
#ifdef notyet
/*
* if you have a time of day board, use it here
*/
resettodr();
#endif
}
/*
* Time of day and interval timer support.
*
* These routines provide the kernel entry points to get and set
* the time-of-day.
*/
void
gettimeofday()
{
register struct a {
struct timeval *tp;
struct timezone *tzp;
} *uap = (struct a *)u.u_arg;
struct timeval atv;
int s;
register u_int ms;
if (uap->tp) {
/*
* We don't resolve the milliseconds on every clock tick; it's
* easier to do it here. Long casts are out of paranoia.
*/
s = splhigh();
atv = time;
ms = lbolt;
splx(s);
atv.tv_usec = (long)ms * usechz;
u.u_error = copyout ((caddr_t) &atv, (caddr_t) uap->tp,
sizeof(atv));
if (u.u_error)
return;
}
if (uap->tzp)
u.u_error = copyout ((caddr_t) &tz, (caddr_t) uap->tzp,
sizeof (tz));
}
void
settimeofday()
{
register struct a {
struct timeval *tv;
struct timezone *tzp;
} *uap = (struct a *)u.u_arg;
struct timeval atv;
struct timezone atz;
if (uap->tv) {
u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
sizeof (struct timeval));
if (u.u_error)
return;
setthetime(&atv);
if (u.u_error)
return;
}
if (uap->tzp && suser()) {
u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
sizeof (atz));
if (u.u_error == 0)
tz = atz;
}
}
void
adjtime()
{
register struct a {
struct timeval *delta;
struct timeval *olddelta;
} *uap = (struct a *)u.u_arg;
struct timeval atv;
register int s;
long adjust;
if (!suser())
return;
u.u_error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
sizeof (struct timeval));
if (u.u_error)
return;
adjust = (atv.tv_sec * hz) + (atv.tv_usec / usechz);
/* if unstoreable values, just set the clock */
if (adjust > 0x7fff || adjust < 0x8000) {
s = splclock();
time.tv_sec += atv.tv_sec;
lbolt += atv.tv_usec / usechz;
while (lbolt >= hz) {
lbolt -= hz;
++time.tv_sec;
}
splx(s);
if (!uap->olddelta)
return;
atv.tv_sec = atv.tv_usec = 0;
} else {
if (!uap->olddelta) {
adjdelta = adjust;
return;
}
atv.tv_sec = adjdelta / hz;
atv.tv_usec = (adjdelta % hz) * usechz;
adjdelta = adjust;
}
u.u_error = copyout ((caddr_t) &atv, (caddr_t) uap->olddelta,
sizeof (struct timeval));
}
void
getitimer()
{
register struct a {
u_int which;
struct itimerval *itv;
} *uap = (struct a *)u.u_arg;
struct itimerval aitv;
register int s;
if (uap->which > ITIMER_PROF) {
u.u_error = EINVAL;
return;
}
aitv.it_interval.tv_usec = 0;
aitv.it_value.tv_usec = 0;
s = splclock();
if (uap->which == ITIMER_REAL) {
register struct proc *p = u.u_procp;
aitv.it_interval.tv_sec = p->p_realtimer.it_interval;
aitv.it_value.tv_sec = p->p_realtimer.it_value;
} else {
register struct k_itimerval *t = &u.u_timer[uap->which - 1];
aitv.it_interval.tv_sec = t->it_interval / hz;
aitv.it_value.tv_sec = t->it_value / hz;
}
splx(s);
u.u_error = copyout ((caddr_t)&aitv, (caddr_t)uap->itv,
sizeof (struct itimerval));
}
void
setitimer()
{
register struct a {
u_int which;
struct itimerval *itv, *oitv;
} *uap = (struct a *)u.u_arg;
struct itimerval aitv;
register struct itimerval *aitvp;
int s;
if (uap->which > ITIMER_PROF) {
u.u_error = EINVAL;
return;
}
aitvp = uap->itv;
if (uap->oitv) {
uap->itv = uap->oitv;
getitimer();
}
if (aitvp == 0)
return;
u.u_error = copyin((caddr_t)aitvp, (caddr_t)&aitv,
sizeof (struct itimerval));
if (u.u_error)
return;
s = splclock();
if (uap->which == ITIMER_REAL) {
register struct proc *p = u.u_procp;
p->p_realtimer.it_value = aitv.it_value.tv_sec;
if (aitv.it_value.tv_usec)
++p->p_realtimer.it_value;
p->p_realtimer.it_interval = aitv.it_interval.tv_sec;
if (aitv.it_interval.tv_usec)
++p->p_realtimer.it_interval;
} else {
register struct k_itimerval *t = &u.u_timer[uap->which - 1];
t->it_value = aitv.it_value.tv_sec * hz;
if (aitv.it_value.tv_usec)
t->it_value += hz;
t->it_interval = aitv.it_interval.tv_sec * hz;
if (aitv.it_interval.tv_usec)
t->it_interval += hz;
}
splx(s);
}
/*
* Check that a proposed value to load into the .it_value or
* .it_interval part of an interval timer is acceptable, and
* fix it to have at least minimal value (i.e. if it is less
* than the resolution of the clock, round it up.)
*/
int
itimerfix(tv)
struct timeval *tv;
{
if (tv->tv_sec < 0 || tv->tv_sec > 100000000L ||
tv->tv_usec < 0 || tv->tv_usec >= 1000000L)
return (EINVAL);
if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < (1000/hz))
tv->tv_usec = 1000/hz;
return (0);
}
#ifdef NOT_CURRENTLY_IN_USE
/*
* Decrement an interval timer by a specified number
* of microseconds, which must be less than a second,
* i.e. < 1000000. If the timer expires, then reload
* it. In this case, carry over (usec - old value) to
* reducint the value reloaded into the timer so that
* the timer does not drift. This routine assumes
* that it is called in a context where the timers
* on which it is operating cannot change in value.
*/
itimerdecr(itp, usec)
register struct itimerval *itp;
int usec;
{
if (itp->it_value.tv_usec < usec) {
if (itp->it_value.tv_sec == 0) {
/* expired, and already in next interval */
usec -= itp->it_value.tv_usec;
goto expire;
}
itp->it_value.tv_usec += 1000000L;
itp->it_value.tv_sec--;
}
itp->it_value.tv_usec -= usec;
usec = 0;
if (timerisset(&itp->it_value))
return (1);
/* expired, exactly at end of interval */
expire:
if (timerisset(&itp->it_interval)) {
itp->it_value = itp->it_interval;
itp->it_value.tv_usec -= usec;
if (itp->it_value.tv_usec < 0) {
itp->it_value.tv_usec += 1000000L;
itp->it_value.tv_sec--;
}
} else
itp->it_value.tv_usec = 0; /* sec is already 0 */
return (0);
}
#endif /* NOT_CURRENTLY_IN_USE */
static void
tvfix(t1)
struct timeval *t1;
{
if (t1->tv_usec < 0) {
t1->tv_sec--;
t1->tv_usec += 1000000L;
}
if (t1->tv_usec >= 1000000L) {
t1->tv_sec++;
t1->tv_usec -= 1000000L;
}
}
/*
* Add and subtract routines for timevals.
* N.B.: subtract routine doesn't deal with
* results which are before the beginning,
* it just gets very confused in this case.
* Caveat emptor.
*/
void
timevaladd(t1, t2)
struct timeval *t1, *t2;
{
t1->tv_sec += t2->tv_sec;
t1->tv_usec += t2->tv_usec;
tvfix(t1);
}
#ifdef NOT_CURRENTLY_IN_USE
void
timevalsub(t1, t2)
struct timeval *t1, *t2;
{
t1->tv_sec -= t2->tv_sec;
t1->tv_usec -= t2->tv_usec;
tvfix(t1);
}
#endif

336
sys/kernel/subr_log.c Normal file
View File

@@ -0,0 +1,336 @@
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
* logioctl() had the wrong number of arguments. Argh! Apparently this
* driver was overlooked when 'dev' was added to ioctl entry points.
*
* logclose() returned garbage. this went unnoticed because most programs
* don't check status when doing a close.
* Add support for multiple log devices. Minor device 0 is the traditional
* kernel logger (/dev/klog), minor device 1 is reserved for the future device
* error logging daemon.
*/
#define NLOG 1
int nlog = 1;
#include "param.h"
#include "user.h"
#include "proc.h"
#include "ioctl.h"
#include "msgbuf.h"
#include "file.h"
#include "inode.h"
#include "errno.h"
#include "uio.h"
#include "map.h"
#include "systm.h"
#include "conf.h"
const struct devspec logdevs[] = {
{ 0, "klog" },
{ 0, 0 }
};
#define LOG_RDPRI (PZERO + 1)
#define LOG_OPEN 0x01
#define LOG_ASYNC 0x04
#define LOG_RDWAIT 0x08
struct msgbuf msgbuf[NLOG];
static struct logsoftc {
int sc_state; /* see above for possibilities */
struct proc *sc_selp; /* process waiting on select call */
int sc_pgid; /* process/group for async I/O */
int sc_overrun; /* full buffer count */
} logsoftc[NLOG];
/*ARGSUSED*/
int
logopen(dev, mode, unused)
dev_t dev;
int mode;
{
register int unit = minor(dev);
if (unit >= NLOG)
return(ENODEV);
if (logisopen(unit))
return(EBUSY);
if (msgbuf[unit].msg_bufc == 0) /* no buffer allocated */
return(ENOMEM);
logsoftc[unit].sc_state |= LOG_OPEN;
logsoftc[unit].sc_pgid = u.u_procp->p_pid; /* signal process only */
logsoftc[unit].sc_overrun = 0;
return(0);
}
/*ARGSUSED*/
int
logclose(dev, flag, unused)
dev_t dev;
int flag;
{
register int unit = minor(dev);
logsoftc[unit].sc_state = 0;
return(0);
}
/*
* This is a helper function to keep knowledge of this driver's data
* structures away from the rest of the kernel.
*/
int
logisopen(unit)
int unit;
{
if (logsoftc[unit].sc_state & LOG_OPEN)
return(1);
return(0);
}
/*ARGSUSED*/
int
logread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register int l;
register struct logsoftc *lp;
register struct msgbuf *mp;
int s, error = 0;
char buf [128];
l = minor(dev);
lp = &logsoftc[l];
mp = &msgbuf[l];
s = splhigh();
while (mp->msg_bufr == mp->msg_bufx) {
if (flag & IO_NDELAY) {
splx(s);
return(EWOULDBLOCK);
}
lp->sc_state |= LOG_RDWAIT;
sleep((caddr_t)mp, LOG_RDPRI);
}
lp->sc_state &= ~LOG_RDWAIT;
while (uio->uio_resid) {
l = mp->msg_bufx - mp->msg_bufr;
/*
* If the reader and writer are equal then we have caught up and there
* is nothing more to transfer.
*/
if (l == 0)
break;
/*
* If the write pointer is behind the reader then only consider as
* available for now the bytes from the read pointer thru the end of
* the buffer.
*/
if (l < 0) {
l = MSG_BSIZE - mp->msg_bufr;
/*
* If the reader is exactly at the end of the buffer it is
* time to wrap it around to the beginning and recalculate the
* amount of data to transfer.
*/
if (l == 0) {
mp->msg_bufr = 0;
continue;
}
}
l = MIN (l, uio->uio_resid);
l = MIN (l, sizeof buf);
bcopy (&mp->msg_bufc[mp->msg_bufr], buf, l);
error = uiomove (buf, l, uio);
if (error)
break;
mp->msg_bufr += l;
}
splx(s);
return(error);
}
/*ARGSUSED*/
int
logselect(dev, rw)
dev_t dev;
int rw;
{
register int s = splhigh();
int unit = minor(dev);
switch (rw) {
case FREAD:
if (msgbuf[unit].msg_bufr != msgbuf[unit].msg_bufx) {
splx(s);
return(1);
}
logsoftc[unit].sc_selp = u.u_procp;
break;
}
splx(s);
return(0);
}
void
logwakeup(unit)
int unit;
{
register struct proc *p;
register struct logsoftc *lp;
register struct msgbuf *mp;
if (! logisopen(unit))
return;
lp = &logsoftc[unit];
mp = &msgbuf[unit];
if (lp->sc_selp) {
selwakeup(lp->sc_selp, (long) 0);
lp->sc_selp = 0;
}
if (lp->sc_state & LOG_ASYNC && (mp->msg_bufx != mp->msg_bufr)) {
if (lp->sc_pgid < 0)
gsignal(-lp->sc_pgid, SIGIO);
else if ((p = pfind(lp->sc_pgid)))
psignal(p, SIGIO);
}
if (lp->sc_state & LOG_RDWAIT) {
wakeup((caddr_t)mp);
lp->sc_state &= ~LOG_RDWAIT;
}
}
/*ARGSUSED*/
int
logioctl(dev, com, data, flag)
dev_t dev;
u_int com;
caddr_t data;
int flag;
{
long l;
register int s;
int unit;
register struct logsoftc *lp;
register struct msgbuf *mp;
unit = minor(dev);
lp = &logsoftc[unit];
mp = &msgbuf[unit];
switch (com) {
case FIONREAD:
s = splhigh();
l = mp->msg_bufx - mp->msg_bufr;
splx(s);
if (l < 0)
l += MSG_BSIZE;
*(off_t *)data = l;
break;
case FIONBIO:
break;
case FIOASYNC:
if (*(int *)data)
lp->sc_state |= LOG_ASYNC;
else
lp->sc_state &= ~LOG_ASYNC;
break;
case TIOCSPGRP:
lp->sc_pgid = *(int *)data;
break;
case TIOCGPGRP:
*(int *)data = lp->sc_pgid;
break;
default:
return(-1);
}
return(0);
}
/*
* This is inefficient for single character writes. Alas, changing this
* to be buffered would affect the networking code's use of printf.
*/
int
logwrt (buf, len, log)
char *buf;
int len;
int log;
{
register struct msgbuf *mp = &msgbuf[log];
struct logsoftc *lp = &logsoftc[log];
register int infront;
int s, n, writer, err = 0;
if (mp->msg_magic != MSG_MAGIC || (len > MSG_BSIZE))
return(-1);
/*
* Hate to do this but since this can be called from anywhere in the kernel
* we have to hold off any interrupt service routines so they don't change
* things. This looks like a lot of code but it isn't really.
*/
s = splhigh();
while (len) {
again: infront = MSG_BSIZE - mp->msg_bufx;
if (infront <= 0) {
mp->msg_bufx = 0;
infront = MSG_BSIZE - mp->msg_bufr;
}
n = mp->msg_bufr - mp->msg_bufx;
if (n < 0) /* bufr < bufx */
writer = (MSG_BSIZE - mp->msg_bufx) + mp->msg_bufr;
else if (n == 0)
writer = MSG_BSIZE;
else {
writer = n;
infront = n;
}
if (len > writer) {
/*
* won't fit. the total number of bytes to be written is
* greater than the number available. the buffer is full.
* throw away the old data and keep the current data by resetting
* the 'writer' pointer to the current 'reader' position. Bump the
* overrun counter in case anyone wants to look at it for debugging.
*/
lp->sc_overrun++;
mp->msg_bufx = mp->msg_bufr;
goto again;
}
if (infront > len)
infront = len;
bcopy(buf, &mp->msg_bufc[mp->msg_bufx], infront);
mp->msg_bufx += infront;
len -= infront;
buf += infront;
}
splx(s);
return(err);
}
/*
* Initialize the log driver. Called from the system startup code (machdep2.c).
* All buffers are the same (MSG_BSIZE) size.
*/
int
loginit()
{
register struct msgbuf *mp;
for (mp = &msgbuf[0]; mp < &msgbuf[NLOG]; mp++) {
mp->msg_magic = MSG_MAGIC;
mp->msg_bufx = mp->msg_bufr = 0;
}
return(0);
}

565
sys/kernel/subr_prf.c Normal file
View File

@@ -0,0 +1,565 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "buf.h"
#include "msgbuf.h"
#include "conf.h"
#include "ioctl.h"
#include "tty.h"
#include "reboot.h"
#include "systm.h"
#include "syslog.h"
#define TOCONS 0x1
#define TOTTY 0x2
#define TOLOG 0x4
/*
* In case console is off,
* panicstr contains argument to last
* call to panic.
*/
char *panicstr;
/*
* Print a character on console or users terminal.
* If destination is console then the last MSGBUFS characters
* are saved in msgbuf for inspection later.
*/
static void
putchar (c, flags, tp)
int c, flags;
register struct tty *tp;
{
if (flags & TOTTY) {
register int s = spltty();
if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
(TS_CARR_ON | TS_ISOPEN)) {
if (c == '\n')
(void) ttyoutput('\r', tp);
(void) ttyoutput(c, tp);
ttstart(tp);
}
splx(s);
}
#ifdef LOG_ENABLED
if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177) {
char sym = c;
logwrt (&sym, 1, logMSG);
}
#endif
if ((flags & TOCONS) && c != '\0')
cnputc(c);
}
static unsigned
mkhex (unsigned ch)
{
ch &= 15;
if (ch > 9)
return ch + 'a' - 10;
return ch + '0';
}
/*
* Put a NUL-terminated ASCII number (base <= 16) in a buffer in reverse
* order; return an optional length and a pointer to the last character
* written in the buffer (i.e., the first character of the string).
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static char *
ksprintn (char *nbuf, unsigned long ul, int base, int width, int *lenp)
{
char *p;
p = nbuf;
*p = 0;
for (;;) {
*++p = mkhex (ul % base);
ul /= base;
if (--width > 0)
continue;
if (! ul)
break;
}
if (lenp)
*lenp = p - nbuf;
return (p);
}
void puts(char *s, int flags, struct tty *ttyp)
{
while(*s)
putchar(*(s++), flags, ttyp);
}
/*
* Scaled down version of printf(3).
* Two additional formats: %b anf %D.
* Based on FreeBSD sources.
* Heavily rewritten by Serge Vakulenko.
*
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "<base><arg>*");
*
* where <base> is the output base expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
* the first of which gives the bit number to be inspected (origin 1), and
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3<BITTWO,BITONE>
*
* The format %D -- Hexdump, takes a pointer. Sharp flag - use `:' as
* a separator, instead of a space. For example:
*
* ("%6D", ptr) -> XX XX XX XX XX XX
* ("%#*D", len, ptr) -> XX:XX:XX:XX ...
*/
#define PUTC(C) putchar(C,flags,ttyp)
#define HION "\e[1m"
#define HIOFF "\e[0m"
static void
prf (fmt, ap, flags, ttyp)
register char *fmt;
register u_int *ap;
int flags;
struct tty *ttyp;
{
#define va_arg(ap,type) *(type*) (void*) (ap++)
char *q, nbuf [sizeof(long) * 8 + 1];
const char *s;
int c, padding, base, lflag, ladjust, sharpflag, neg, dot, size;
int n, width, dwidth, uppercase, extrazeros, sign;
unsigned long ul;
#ifdef KERNEL_HIGHLIGHT
puts(HION,flags,ttyp);
#endif
if (! fmt)
fmt = "(null)\n";
for (;;) {
while ((c = *fmt++) != '%') {
if (! c) {
#ifdef KERNEL_HIGHLIGHT
puts(HIOFF,flags,ttyp);
#endif
return;
}
PUTC (c);
}
padding = ' ';
width = 0; extrazeros = 0;
lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
sign = 0; dot = 0; uppercase = 0; dwidth = -1;
reswitch: c = *fmt++;
switch (c) {
case '.':
dot = 1;
padding = ' ';
dwidth = 0;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = -1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PUTC (c);
break;
case '*':
if (! dot) {
width = va_arg (ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg (ap, int);
}
goto reswitch;
case '0':
if (! dot) {
padding = '0';
goto reswitch;
}
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n=0; ; ++fmt) {
n = n * 10 + c - '0';
c = *fmt;
if (c < '0' || c > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
ul = va_arg (ap, int);
s = va_arg (ap, const char*);
q = ksprintn (nbuf, ul, *s++, -1, 0);
while (*q)
PUTC (*q--);
if (! ul)
break;
size = 0;
while (*s) {
n = *s++;
if ((char) (ul >> (n-1)) & 1) {
PUTC (size ? ',' : '<');
for (; (n = *s) > ' '; ++s)
PUTC (n);
size = 1;
} else
while (*s > ' ')
++s;
}
if (size)
PUTC ('>');
break;
case 'c':
if (! ladjust && width > 0)
while (width--)
PUTC (' ');
PUTC (va_arg (ap, int));
if (ladjust && width > 0)
while (width--)
PUTC (' ');
break;
case 'D':
s = va_arg (ap, const char*);
if (! width)
width = 16;
if (sharpflag)
padding = ':';
while (width--) {
c = *s++;
PUTC (mkhex (c >> 4));
PUTC (mkhex (c));
if (width)
PUTC (padding);
}
break;
case 'd':
ul = lflag ? va_arg (ap, long) : va_arg (ap, int);
if (! sign) sign = 1;
base = 10;
goto number;
case 'l':
lflag = 1;
goto reswitch;
case 'o':
ul = lflag ? va_arg (ap, unsigned long) :
va_arg (ap, unsigned int);
base = 8;
goto nosign;
case 'p':
ul = (size_t) va_arg (ap, void*);
if (! ul) {
s = "(nil)";
goto const_string;
}
base = 16;
sharpflag = (width == 0);
goto nosign;
case 'n':
ul = lflag ? va_arg (ap, unsigned long) :
sign ? (unsigned long) va_arg (ap, int) :
va_arg (ap, unsigned int);
base = 10;
goto number;
case 's':
s = va_arg (ap, char*);
if (! s)
s = (const char*) "(null)";
const_string:
if (! dot)
n = strlen (s);
else
for (n=0; n<dwidth && s[n]; n++)
continue;
width -= n;
if (! ladjust && width > 0)
while (width--)
PUTC (' ');
while (n--)
PUTC (*s++);
if (ladjust && width > 0)
while (width--)
PUTC (' ');
break;
case 'u':
ul = lflag ? va_arg (ap, unsigned long) :
va_arg (ap, unsigned int);
base = 10;
goto nosign;
case 'x':
case 'X':
ul = lflag ? va_arg (ap, unsigned long) :
va_arg (ap, unsigned int);
base = 16;
uppercase = (c == 'X');
goto nosign;
case 'z':
case 'Z':
ul = lflag ? va_arg (ap, unsigned long) :
sign ? (unsigned long) va_arg (ap, int) :
va_arg (ap, unsigned int);
base = 16;
uppercase = (c == 'Z');
goto number;
nosign: sign = 0;
number: if (sign && ((long) ul != 0L)) {
if ((long) ul < 0L) {
neg = '-';
ul = -(long) ul;
} else if (sign < 0)
neg = '+';
}
if (dwidth >= (int) sizeof(nbuf)) {
extrazeros = dwidth - sizeof(nbuf) + 1;
dwidth = sizeof(nbuf) - 1;
}
s = ksprintn (nbuf, ul, base, dwidth, &size);
if (sharpflag && ul != 0) {
if (base == 8)
size++;
else if (base == 16)
size += 2;
}
if (neg)
size++;
if (! ladjust && width && padding == ' ' &&
(width -= size) > 0)
do {
PUTC (' ');
} while (--width > 0);
if (neg)
PUTC (neg);
if (sharpflag && ul != 0) {
if (base == 8) {
PUTC ('0');
} else if (base == 16) {
PUTC ('0');
PUTC (uppercase ? 'X' : 'x');
}
}
if (extrazeros)
do {
PUTC ('0');
} while (--extrazeros > 0);
if (! ladjust && width && (width -= size) > 0)
do {
PUTC (padding);
} while (--width > 0);
for (; *s; --s) {
if (uppercase && *s>='a' && *s<='z') {
PUTC (*s + 'A' - 'a');
} else {
PUTC (*s);
}
}
if (ladjust && width && (width -= size) > 0)
do {
PUTC (' ');
} while (--width > 0);
break;
default:
PUTC ('%');
if (lflag)
PUTC ('l');
PUTC (c);
break;
}
}
#ifdef KERNEL_HIGHLIGHT
puts(HIOFF,flags,ttyp);
#endif
}
static void
logpri (level)
int level;
{
putchar ('<', TOLOG, (struct tty*) 0);
prf ("%u", &level, TOLOG, (struct tty*) 0);
putchar ('>', TOLOG, (struct tty*) 0);
}
/*
* Scaled down version of C Library printf.
* Used to print diagnostic information directly on console tty.
* Since it is not interrupt driven, all system activities are
* suspended. Printf should not be used for chit-chat.
*
* One additional format: %b is supported to decode error registers.
* Usage is:
* printf("reg=%b\n", regval, "<base><arg>*");
* Where <base> is the output base expressed as a control character,
* e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of
* characters, the first of which gives the bit number to be inspected
* (origin 1), and the next characters (up to a control character, i.e.
* a character <= 32), give the name of the register. Thus
* printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
* would produce output:
* reg=3<BITTWO,BITONE>
*/
void
printf(char *fmt, ...)
{
prf(fmt, &fmt + 1, TOCONS | TOLOG, (struct tty *)0);
}
/*
* Microchip MPLABX C32 compiler generates calls to _printf_s()
* and other strange names.
*/
#ifdef __MPLABX__
void _printf_s(char *fmt, ...)
__attribute__((alias ("printf")));
void _printf_cdnopuxX(char *fmt, ...)
__attribute__((alias ("printf")));
void _printf_cdnopsuxX(char *fmt, ...)
__attribute__((alias ("printf")));
#endif
/*
* Uprintf prints to the current user's terminal,
* guarantees not to sleep (so could be called by interrupt routines;
* but prints on the tty of the current process)
* and does no watermark checking - (so no verbose messages).
* NOTE: with current kernel mapping scheme, the user structure is
* not guaranteed to be accessible at interrupt level (see seg.h);
* a savemap/restormap would be needed here or in putchar if uprintf
* was to be used at interrupt time.
*/
void
uprintf (char *fmt, ...)
{
register struct tty *tp;
tp = u.u_ttyp;
if (tp == NULL)
return;
if (ttycheckoutq (tp, 1))
prf (fmt, &fmt+1, TOTTY, tp);
}
/*
* tprintf prints on the specified terminal (console if none)
* and logs the message. It is designed for error messages from
* single-open devices, and may be called from interrupt level
* (does not sleep).
*/
void
tprintf (register struct tty *tp, char *fmt, ...)
{
int flags = TOTTY | TOLOG;
logpri (LOG_INFO);
if (tp == (struct tty*) NULL)
tp = &cnttys[0];
if (ttycheckoutq (tp, 0) == 0)
flags = TOLOG;
prf (fmt, &fmt + 1, flags, tp);
#ifdef LOG_ENABLED
logwakeup (logMSG);
#endif
}
/*
* Log writes to the log buffer,
* and guarantees not to sleep (so can be called by interrupt routines).
* If there is no process reading the log yet, it writes to the console also.
*/
/*VARARGS2*/
void
log (int level, char *fmt, ...)
{
register int s = splhigh();
logpri(level);
prf(fmt, &fmt + 1, TOLOG, (struct tty *)0);
splx(s);
#ifdef LOG_ENABLED
if (! logisopen(logMSG))
#endif
prf(fmt, &fmt + 1, TOCONS, (struct tty *)0);
#ifdef LOG_ENABLED
logwakeup(logMSG);
#endif
}
/*
* Panic is called on unresolvable fatal errors.
* It prints "panic: mesg", and then reboots.
* If we are called twice, then we avoid trying to
* sync the disks as this often leads to recursive panics.
*/
void
panic(s)
char *s;
{
int bootopt = RB_HALT | RB_DUMP;
if (panicstr) {
bootopt |= RB_NOSYNC;
} else {
panicstr = s;
}
printf ("panic: %s\n", s);
boot (rootdev, bootopt);
}

230
sys/kernel/subr_rmap.c Normal file
View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "map.h"
#include "vm.h"
/*
* Resource map handling routines.
*
* A resource map is an array of structures each of which describes a
* segment of the address space of an available resource. The segments
* are described by their base address and length, and sorted in address
* order. Each resource map has a fixed maximum number of segments
* allowed. Resources are allocated by taking part or all of one of the
* segments of the map.
*
* Returning of resources will require another segment if the returned
* resources are not adjacent in the address space to an existing segment.
* If the return of a segment would require a slot which is not available,
* then one of the resource map segments is discarded after a warning is
* printed.
*
* Returning of resources may also cause the map to collapse by coalescing
* two existing segments and the returned space into a single segment. In
* this case the resource map is made smaller by copying together to fill
* the resultant gap.
*
* N.B.: the current implementation uses a dense array and does not admit
* the value ``0'' as a legal address or size, since that is used as a
* delimiter.
*/
/*
* Allocate 'size' units from the given map. Return the base of the
* allocated space. In a map, the addresses are increasing and the
* list is terminated by a 0 size.
*
* Algorithm is first-fit.
*/
size_t
malloc (mp, size)
struct map *mp;
register size_t size;
{
register struct mapent *bp, *ep;
size_t addr;
if (! size)
panic ("malloc: size = 0");
/*
* Search for a piece of the resource map which has enough
* free space to accomodate the request.
*/
for (bp = mp->m_map; bp->m_size; ++bp)
if (bp->m_size >= size) {
/*
* Allocate from the map. If we allocated the entire
* piece, move the rest of the map to the left.
*/
addr = bp->m_addr;
bp->m_size -= size;
if (bp->m_size)
bp->m_addr += size;
else for (ep = bp;; ++ep) {
*ep = *++bp;
if (!bp->m_size)
break;
}
return(addr);
}
/* no entries big enough */
return 0;
}
/*
* Free the previously allocated size units at addr into the specified
* map. Sort addr into map and combine on one or both ends if possible.
*/
void
mfree (mp, size, addr)
struct map *mp;
size_t size;
register size_t addr;
{
register struct mapent *bp, *ep;
struct mapent *start;
if (! size)
return;
/* the address must not be 0, or the protocol has broken down. */
if (! addr)
panic ("mfree: addr = 0");
/*
* locate the piece of the map which starts after the
* returned space (or the end of the map).
*/
bp = mp->m_map;
/* printf ("mfree (size=%u, addr=%u) m_map = %08x\n", size, addr, bp); */
while (bp->m_size && bp->m_addr <= addr) {
/*printf ("skip m_map[%d]: m_addr %u <= addr %u\n", bp - mp->m_map, bp->m_addr, addr);*/
++bp;
}
/* if there is a piece on the left abutting us, combine with it. */
ep = bp - 1;
if (bp != mp->m_map && ep->m_addr + ep->m_size >= addr) {
#ifdef DIAGNOSTIC
/* any overlap is an internal error */
if (ep->m_addr + ep->m_size > addr)
panic("mfree overlap #1");
#endif
/* add into piece on the left by increasing its size. */
ep->m_size += size;
/*
* if the combined piece abuts the piece on the right now,
* compress it in also, by shifting the remaining pieces
* of the map over.
*/
if (bp->m_size && addr + size >= bp->m_addr) {
#ifdef DIAGNOSTIC
if (addr + size > bp->m_addr)
panic("mfree overlap #2");
#endif
ep->m_size += bp->m_size;
do {
*++ep = *++bp;
} while (bp->m_size);
}
return;
}
/* if doesn't abut on the left, check for abutting on the right. */
if (bp->m_size && addr + size >= bp->m_addr) {
#ifdef DIAGNOSTIC
if (addr + size > bp->m_addr)
panic("mfree overlap #3");
#endif
bp->m_addr = addr;
bp->m_size += size;
return;
}
/* doesn't abut. Make a new entry and check for map overflow. */
for (start = bp; bp->m_size; ++bp);
if (++bp > mp->m_limit)
/*
* too many segments; if this happens, the correct fix
* is to make the map bigger; you can't afford to lose
* chunks of the map. If you need to implement recovery,
* use the above "for" loop to find the smallest entry
* and toss it.
*/
printf("%s: overflow, lost %u clicks at 0%o\n",
mp->m_name, size, addr);
else {
for (ep = bp - 1; ep >= start; *bp-- = *ep--);
start->m_addr = addr;
start->m_size = size;
}
}
/*
* Allocate resources for the three segments of a process (data, stack
* and u.), attempting to minimize the cost of failure part-way through.
* Since the segments are located successively, it is best for the sizes
* to be in decreasing order; generally, data, stack, then u. will be
* best. Returns NULL on failure, address of u. on success.
*/
size_t
malloc3 (mp, d_size, s_size, u_size, a)
struct map *mp;
size_t d_size, s_size, u_size;
size_t a[3];
{
register struct mapent *bp, *remap;
register int next;
struct mapent *madd[3];
size_t sizes[3];
int found;
sizes[0] = d_size;
sizes[1] = s_size;
sizes[2] = u_size;
/*
* note, this has to work for d_size and s_size of zero,
* since init() comes in that way.
*/
madd[0] = madd[1] = madd[2] = remap = NULL;
for (found = 0, bp = mp->m_map; bp->m_size; ++bp)
for (next = 0; next < 3; ++next)
if (!madd[next] && sizes[next] <= bp->m_size) {
madd[next] = bp;
bp->m_size -= sizes[next];
if (!bp->m_size && !remap)
remap = bp;
if (++found == 3)
goto resolve;
}
/* couldn't get it all; restore the old sizes, try again */
for (next = 0; next < 3; ++next)
if (madd[next])
madd[next]->m_size += sizes[next];
return 0;
resolve:
/* got it all, update the addresses. */
for (next = 0; next < 3; ++next) {
bp = madd[next];
a[next] = bp->m_addr;
bp->m_addr += sizes[next];
}
/* remove any entries of size 0; addr of 0 terminates */
if (remap)
for (bp = remap + 1;; ++bp)
if (bp->m_size || !bp->m_addr) {
*remap++ = *bp;
if (!bp->m_addr)
break;
}
return(a[2]);
}

544
sys/kernel/sys_generic.c Normal file
View File

@@ -0,0 +1,544 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "signalvar.h"
#include "inode.h"
#include "file.h"
#include "ioctl.h"
#include "conf.h"
#include "uio.h"
#include "kernel.h"
#include "systm.h"
int selwait;
static void
rwuio (uio)
register struct uio *uio;
{
struct a {
int fdes;
};
register struct file *fp;
register struct iovec *iov;
u_int i, count;
off_t total;
GETF(fp, ((struct a *)u.u_arg)->fdes);
if ((fp->f_flag & (uio->uio_rw == UIO_READ ? FREAD : FWRITE)) == 0) {
u.u_error = EBADF;
return;
}
total = 0;
uio->uio_resid = 0;
for (iov = uio->uio_iov, i = 0; i < uio->uio_iovcnt; i++, iov++)
total += iov->iov_len;
uio->uio_resid = total;
if (uio->uio_resid != total) { /* check wraparound */
u.u_error = EINVAL;
return;
}
count = uio->uio_resid;
if (setjmp (&u.u_qsave)) {
/*
* The ONLY way we can get here is via the longjump in sleep. Thus signals
* have been checked and u_error set accordingly. If no bytes have been
* transferred then all that needs to be done now is 'return'; the system
* call will either be restarted or reported as interrupted. If bytes have
* been transferred then we need to calculate the number of bytes transferred.
*/
if (uio->uio_resid == count)
return;
u.u_error = 0;
} else
u.u_error = (*Fops[fp->f_type]->fo_rw) (fp, uio);
u.u_rval = count - uio->uio_resid;
}
/*
* Read system call.
*/
void
read()
{
register struct a {
int fdes;
char *cbuf;
unsigned count;
} *uap = (struct a *)u.u_arg;
struct uio auio;
struct iovec aiov;
aiov.iov_base = (caddr_t)uap->cbuf;
aiov.iov_len = uap->count;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_rw = UIO_READ;
rwuio (&auio);
}
void
readv()
{
register struct a {
int fdes;
struct iovec *iovp;
unsigned iovcnt;
} *uap = (struct a *)u.u_arg;
struct uio auio;
struct iovec aiov[16]; /* XXX */
if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
u.u_error = EINVAL;
return;
}
auio.uio_iov = aiov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_rw = UIO_READ;
u.u_error = copyin ((caddr_t)uap->iovp, (caddr_t)aiov,
uap->iovcnt * sizeof (struct iovec));
if (u.u_error)
return;
rwuio (&auio);
}
/*
* Write system call
*/
void
write()
{
register struct a {
int fdes;
char *cbuf;
unsigned count;
} *uap = (struct a *)u.u_arg;
struct uio auio;
struct iovec aiov;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_rw = UIO_WRITE;
aiov.iov_base = uap->cbuf;
aiov.iov_len = uap->count;
rwuio (&auio);
}
void
writev()
{
register struct a {
int fdes;
struct iovec *iovp;
unsigned iovcnt;
} *uap = (struct a *)u.u_arg;
struct uio auio;
struct iovec aiov[16]; /* XXX */
if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
u.u_error = EINVAL;
return;
}
auio.uio_iov = aiov;
auio.uio_iovcnt = uap->iovcnt;
auio.uio_rw = UIO_WRITE;
u.u_error = copyin ((caddr_t)uap->iovp, (caddr_t)aiov,
uap->iovcnt * sizeof (struct iovec));
if (u.u_error)
return;
rwuio (&auio);
}
/*
* Ioctl system call
*/
void
ioctl()
{
register struct file *fp;
register struct a {
int fdes;
long cmd;
caddr_t cmarg;
} *uap;
u_int com;
uap = (struct a *)u.u_arg;
fp = getf(uap->fdes);
if (! fp)
return;
if (! (fp->f_flag & (FREAD | FWRITE))) {
u.u_error = EBADF;
return;
}
com = (u_int) uap->cmd;
if (com & (IOC_IN | IOC_OUT)) {
/* Check user address. */
u_int nbytes = (com & ~(IOC_INOUT | IOC_VOID)) >> 16;
if (baduaddr (uap->cmarg) ||
baduaddr (uap->cmarg + nbytes - 1)) {
u.u_error = EFAULT;
return;
}
}
switch (com) {
case FIOCLEX:
u.u_pofile[uap->fdes] |= UF_EXCLOSE;
return;
case FIONCLEX:
u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
return;
case FIONBIO:
u.u_error = fset (fp, FNONBLOCK, *(int*) uap->cmarg);
return;
case FIOASYNC:
u.u_error = fset (fp, FASYNC, *(int*) uap->cmarg);
return;
case FIOSETOWN:
u.u_error = fsetown (fp, *(int*) uap->cmarg);
return;
case FIOGETOWN:
u.u_error = fgetown (fp, (int*) uap->cmarg);
return;
}
u.u_error = (*Fops[fp->f_type]->fo_ioctl) (fp, com, uap->cmarg);
}
int nselcoll;
struct pselect_args {
int nd;
fd_set *in;
fd_set *ou;
fd_set *ex;
struct timespec *ts;
sigset_t *maskp;
};
int
selscan(ibits, obits, nfd, retval)
fd_set *ibits, *obits;
int nfd, *retval;
{
register int i, j, flag;
fd_mask bits;
struct file *fp;
int which, n = 0;
for (which = 0; which < 3; which++) {
switch (which) {
case 0:
flag = FREAD; break;
case 1:
flag = FWRITE; break;
case 2:
flag = 0; break;
}
for (i = 0; i < nfd; i += NFDBITS) {
bits = ibits[which].fds_bits[i/NFDBITS];
while ((j = ffs(bits)) && i + --j < nfd) {
bits &= ~(1L << j);
fp = u.u_ofile[i + j];
if (fp == NULL)
return(EBADF);
if ((*Fops[fp->f_type]->fo_select) (fp, flag)) {
FD_SET(i + j, &obits[which]);
n++;
}
}
}
}
*retval = n;
return(0);
}
/*
* Select helper function common to both select() and pselect()
*/
static int
select1(uap, is_pselect)
register struct pselect_args *uap;
int is_pselect;
{
fd_set ibits[3], obits[3];
struct timeval atv;
sigset_t sigmsk;
unsigned int timo = 0;
register int error, ni;
int ncoll, s;
bzero((caddr_t)ibits, sizeof(ibits));
bzero((caddr_t)obits, sizeof(obits));
if (uap->nd > NOFILE)
uap->nd = NOFILE; /* forgiving, if slightly wrong */
ni = howmany(uap->nd, NFDBITS);
#define getbits(name, x) \
if (uap->name) { \
error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
(unsigned)(ni * sizeof(fd_mask))); \
if (error) \
goto done; \
}
getbits(in, 0);
getbits(ou, 1);
getbits(ex, 2);
#undef getbits
if (uap->maskp) {
error = copyin ((caddr_t) uap->maskp, (caddr_t) &sigmsk, sizeof(sigmsk));
sigmsk &= ~sigcantmask;
if (error)
goto done;
}
if (uap->ts) {
error = copyin ((caddr_t) uap->ts, (caddr_t) &atv, sizeof (atv));
if (error)
goto done;
/*
* nanoseconds ('struct timespec') on a PDP-11 are stupid since a 50 or 60 hz
* clock is all we have. Keeping the names and logic made porting easier
* though.
*/
if (is_pselect) {
struct timespec *ts = (struct timespec *)&atv;
if (ts->tv_sec == 0 && ts->tv_nsec < 1000)
atv.tv_usec = 1;
else
atv.tv_usec = ts->tv_nsec / 1000;
}
if (itimerfix(&atv)) {
error = EINVAL;
goto done;
}
s = splhigh();
time.tv_usec = lbolt * usechz;
timevaladd(&atv, &time);
splx(s);
}
retry:
ncoll = nselcoll;
u.u_procp->p_flag |= P_SELECT;
error = selscan(ibits, obits, uap->nd, &u.u_rval);
if (error || u.u_rval)
goto done;
s = splhigh();
if (uap->ts) {
/* this should be timercmp(&time, &atv, >=) */
if ((time.tv_sec > atv.tv_sec || (time.tv_sec == atv.tv_sec
&& lbolt * usechz >= atv.tv_usec))) {
splx(s);
goto done;
}
timo = hzto(&atv);
if (timo == 0)
timo = 1;
}
if ((u.u_procp->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
u.u_procp->p_flag &= ~P_SELECT;
splx(s);
goto retry;
}
u.u_procp->p_flag &= ~P_SELECT;
/*
* If doing a pselect() need to set a temporary mask while in tsleep.
* Returning from pselect after catching a signal the old mask has to be
* restored. Save it here and set the appropriate flag.
*/
if (uap->maskp) {
u.u_oldmask = u.u_procp->p_sigmask;
u.u_psflags |= SAS_OLDMASK;
u.u_procp->p_sigmask = sigmsk;
}
error = tsleep ((caddr_t) &selwait, PSOCK | PCATCH, timo);
if (uap->maskp)
u.u_procp->p_sigmask = u.u_oldmask;
splx(s);
if (error == 0)
goto retry;
done:
u.u_procp->p_flag &= ~P_SELECT;
/* select is not restarted after signals... */
if (error == ERESTART)
error = EINTR;
if (error == EWOULDBLOCK)
error = 0;
#define putbits(name, x) \
if (uap->name && \
(error2 = copyout ((caddr_t) &obits[x], (caddr_t) uap->name, ni*sizeof(fd_mask)))) \
error = error2;
if (error == 0) {
int error2;
putbits(in, 0);
putbits(ou, 1);
putbits(ex, 2);
#undef putbits
}
return(error);
}
/*
* Select system call.
*/
void
select()
{
struct uap {
int nd;
fd_set *in, *ou, *ex;
struct timeval *tv;
} *uap = (struct uap *)u.u_arg;
register struct pselect_args *pselargs = (struct pselect_args *)uap;
/*
* Fake the 6th parameter of pselect. See the comment below about the
* number of parameters!
*/
pselargs->maskp = 0;
u.u_error = select1 (pselargs, 0);
}
/*
* pselect (posix select)
*
* N.B. There is only room for 6 arguments - see user.h - so pselect() is
* at the maximum! See user.h
*/
void
pselect()
{
register struct pselect_args *uap = (struct pselect_args *)u.u_arg;
u.u_error = select1(uap, 1);
}
/*ARGSUSED*/
int
seltrue(dev, flag)
dev_t dev;
int flag;
{
return (1);
}
void
selwakeup (p, coll)
register struct proc *p;
long coll;
{
if (coll) {
nselcoll++;
wakeup ((caddr_t)&selwait);
}
if (p) {
register int s = splhigh();
if (p->p_wchan == (caddr_t)&selwait) {
if (p->p_stat == SSLEEP)
setrun(p);
else
unsleep(p);
} else if (p->p_flag & P_SELECT)
p->p_flag &= ~P_SELECT;
splx(s);
}
}
int
sorw(fp, uio)
register struct file *fp;
register struct uio *uio;
{
#ifdef INET
if (uio->uio_rw == UIO_READ)
return(SORECEIVE((struct socket *)fp->f_socket, 0, uio, 0, 0));
return(SOSEND((struct socket *)fp->f_socket, 0, uio, 0, 0));
#else
return (EOPNOTSUPP);
#endif
}
int
soctl(fp, com, data)
struct file *fp;
u_int com;
char *data;
{
#ifdef INET
return (SOO_IOCTL(fp, com, data));
#else
return (EOPNOTSUPP);
#endif
}
int
sosel(fp, flag)
struct file *fp;
int flag;
{
#ifdef INET
return (SOO_SELECT(fp, flag));
#else
return (EOPNOTSUPP);
#endif
}
int
socls(fp)
register struct file *fp;
{
register int error = 0;
#ifdef INET
if (fp->f_data)
error = SOCLOSE((struct socket *)fp->f_data);
fp->f_data = 0;
#else
error = EOPNOTSUPP;
#endif
return(error);
}
/*
* this is consolidated here rather than being scattered all over the
* place. the socketops table has to be in kernel space, but since
* networking might not be defined an appropriate error has to be set
*/
const struct fileops socketops = {
sorw, soctl, sosel, socls
};
const struct fileops *const Fops[] = {
NULL, &inodeops, &socketops, &pipeops
};
/*
* Routine placed in illegal entries in the bdevsw and cdevsw tables.
*/
void
nostrategy (bp)
struct buf *bp;
{
/* Empty. */
}
#ifndef INET
/*
* socket(2) and socketpair(2) if networking not available.
*/
void
nonet()
{
u.u_error = EPROTONOSUPPORT;
}
#endif

698
sys/kernel/sys_inode.c Normal file
View File

@@ -0,0 +1,698 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "signalvar.h"
#include "inode.h"
#include "buf.h"
#include "fs.h"
#include "file.h"
#include "stat.h"
#include "mount.h"
#include "conf.h"
#include "uio.h"
#include "ioctl.h"
#include "tty.h"
#include "kernel.h"
#include "systm.h"
#include "syslog.h"
daddr_t rablock; /* block to be read ahead */
int
ino_rw(fp, uio)
struct file *fp;
register struct uio *uio;
{
register struct inode *ip = (struct inode *)fp->f_data;
u_int count, error;
int ioflag;
if ((ip->i_mode&IFMT) != IFCHR)
ILOCK(ip);
uio->uio_offset = fp->f_offset;
count = uio->uio_resid;
if (uio->uio_rw == UIO_READ) {
error = rwip(ip, uio, fp->f_flag & FNONBLOCK ? IO_NDELAY : 0);
fp->f_offset += (count - uio->uio_resid);
} else {
ioflag = 0;
if ((ip->i_mode&IFMT) == IFREG && (fp->f_flag & FAPPEND))
ioflag |= IO_APPEND;
if (fp->f_flag & FNONBLOCK)
ioflag |= IO_NDELAY;
if (fp->f_flag & FFSYNC ||
(ip->i_fs->fs_flags & MNT_SYNCHRONOUS))
ioflag |= IO_SYNC;
error = rwip(ip, uio, ioflag);
if (ioflag & IO_APPEND)
fp->f_offset = uio->uio_offset;
else
fp->f_offset += (count - uio->uio_resid);
}
if ((ip->i_mode&IFMT) != IFCHR)
IUNLOCK(ip);
return (error);
}
int
ino_ioctl(fp, com, data)
register struct file *fp;
register u_int com;
caddr_t data;
{
register struct inode *ip = ((struct inode *)fp->f_data);
dev_t dev;
switch (ip->i_mode & IFMT) {
case IFREG:
case IFDIR:
if (com == FIONREAD) {
if (fp->f_type==DTYPE_PIPE && !(fp->f_flag&FREAD))
*(off_t *)data = 0;
else
*(off_t *)data = ip->i_size - fp->f_offset;
return (0);
}
if (com == FIONBIO || com == FIOASYNC) /* XXX */
return (0); /* XXX */
/* fall into ... */
default:
return (ENOTTY);
case IFCHR:
dev = ip->i_rdev;
u.u_rval = 0;
if (setjmp(&u.u_qsave)) {
/*
* The ONLY way we can get here is via the longjump in sleep. Signals have
* been checked for and u_error set accordingly. All that remains to do
* is 'return'.
*/
return(u.u_error);
}
return((*cdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag));
case IFBLK:
dev = ip->i_rdev;
u.u_rval = 0;
if (setjmp(&u.u_qsave)) {
/*
* The ONLY way we can get here is via the longjump in sleep. Signals have
* been checked for and u_error set accordingly. All that remains to do
* is 'return'.
*/
return(u.u_error);
}
return((*bdevsw[major(dev)].d_ioctl)(dev,com,data,fp->f_flag));
}
}
int
ino_select(fp, which)
struct file *fp;
int which;
{
register struct inode *ip = (struct inode *)fp->f_data;
register dev_t dev;
switch (ip->i_mode & IFMT) {
default:
return (1); /* XXX */
case IFCHR:
dev = ip->i_rdev;
return (*cdevsw[major(dev)].d_select)(dev, which);
}
}
const struct fileops inodeops = {
ino_rw, ino_ioctl, ino_select, vn_closefile
};
int
rdwri (rw, ip, base, len, offset, ioflg, aresid)
enum uio_rw rw;
struct inode *ip;
caddr_t base;
int len;
off_t offset;
int ioflg;
register int *aresid;
{
struct uio auio;
struct iovec aiov;
register int error;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = base;
aiov.iov_len = len;
auio.uio_rw = rw;
auio.uio_resid = len;
auio.uio_offset = offset;
error = rwip(ip, &auio, ioflg);
if (aresid)
*aresid = auio.uio_resid;
else
if (auio.uio_resid)
error = EIO;
return (error);
}
int
rwip (ip, uio, ioflag)
register struct inode *ip;
register struct uio *uio;
int ioflag;
{
dev_t dev = (dev_t)ip->i_rdev;
register struct buf *bp;
off_t osize;
daddr_t lbn, bn;
int n, on, type, resid;
int error = 0;
int flags;
//if (uio->uio_offset < 0)
//return (EINVAL);
type = ip->i_mode & IFMT;
/*
* The write case below checks that i/o is done synchronously to directories
* and that i/o to append only files takes place at the end of file.
* We do not panic on non-sync directory i/o - the sync bit is forced on.
*/
if (uio->uio_rw == UIO_READ) {
if (! (ip->i_fs->fs_flags & MNT_NOATIME))
ip->i_flag |= IACC;
} else {
switch (type) {
case IFREG:
if (ioflag & IO_APPEND)
uio->uio_offset = ip->i_size;
if (ip->i_flags & APPEND && uio->uio_offset != ip->i_size)
return(EPERM);
break;
case IFDIR:
if ((ioflag & IO_SYNC) == 0)
ioflag |= IO_SYNC;
break;
case IFLNK:
case IFBLK:
case IFCHR:
break;
default:
return (EFTYPE);
}
}
/*
* The IO_SYNC flag is turned off here if the 'async' mount flag is on.
* Otherwise directory I/O (which is done by the kernel) would still
* synchronous (because the kernel carefully passes IO_SYNC for all directory
* I/O) even if the fs was mounted with "-o async".
*
* A side effect of this is that if the system administrator mounts a filesystem
* 'async' then the O_FSYNC flag to open() is ignored.
*
* This behaviour should probably be selectable via "sysctl fs.async.dirs" and
* "fs.async.ofsync". A project for a rainy day.
*/
if (type == IFREG || (type == IFDIR && (ip->i_fs->fs_flags & MNT_ASYNC)))
ioflag &= ~IO_SYNC;
if (type == IFCHR) {
if (uio->uio_rw == UIO_READ) {
if (! (ip->i_fs->fs_flags & MNT_NOATIME))
ip->i_flag |= IACC;
error = (*cdevsw[major(dev)].d_read)(dev, uio, ioflag);
} else {
ip->i_flag |= IUPD|ICHG;
error = (*cdevsw[major(dev)].d_write)(dev, uio, ioflag);
}
return (error);
}
if (uio->uio_resid == 0)
return (0);
if (uio->uio_rw == UIO_WRITE && type == IFREG &&
uio->uio_offset + uio->uio_resid >
u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
psignal(u.u_procp, SIGXFSZ);
return (EFBIG);
}
if (type != IFBLK)
dev = ip->i_dev;
resid = uio->uio_resid;
osize = ip->i_size;
flags = ioflag & IO_SYNC ? B_SYNC : 0;
do {
lbn = lblkno(uio->uio_offset);
on = blkoff(uio->uio_offset);
n = MIN((u_int)(DEV_BSIZE - on), uio->uio_resid);
if (type != IFBLK) {
if (uio->uio_rw == UIO_READ) {
off_t diff = ip->i_size - uio->uio_offset;
if (diff <= 0)
return (0);
if (diff < n)
n = diff;
bn = bmap(ip, lbn, B_READ, flags);
} else
bn = bmap(ip,lbn,B_WRITE,
n == DEV_BSIZE ? flags : flags|B_CLRBUF);
if (u.u_error || (uio->uio_rw == UIO_WRITE && (long)bn < 0))
return (u.u_error);
if (uio->uio_rw == UIO_WRITE && uio->uio_offset + n > ip->i_size &&
(type == IFDIR || type == IFREG || type == IFLNK))
ip->i_size = uio->uio_offset + n;
} else {
bn = lbn;
rablock = bn + 1;
}
if (uio->uio_rw == UIO_READ) {
if ((long)bn < 0) {
bp = geteblk();
bzero (bp->b_addr, MAXBSIZE);
} else if (ip->i_lastr + 1 == lbn)
bp = breada (dev, bn, rablock);
else
bp = bread (dev, bn);
ip->i_lastr = lbn;
} else {
if (n == DEV_BSIZE)
bp = getblk (dev, bn);
else
bp = bread (dev, bn);
/*
* 4.3 didn't do this, but 2.10 did. not sure why.
* something about tape drivers don't clear buffers on end-of-tape
* any longer (clrbuf can't be called from interrupt).
*/
if (bp->b_resid == DEV_BSIZE) {
bp->b_resid = 0;
bzero (bp->b_addr, MAXBSIZE);
}
}
n = MIN(n, DEV_BSIZE - bp->b_resid);
if (bp->b_flags & B_ERROR) {
error = EIO;
brelse(bp);
break;
}
u.u_error = uiomove (bp->b_addr + on, n, uio);
if (uio->uio_rw == UIO_READ) {
if (n + on == DEV_BSIZE || uio->uio_offset == ip->i_size) {
bp->b_flags |= B_AGE;
if (ip->i_flag & IPIPE)
bp->b_flags &= ~B_DELWRI;
}
brelse(bp);
} else {
if (ioflag & IO_SYNC)
bwrite(bp);
/*
* The check below interacts _very_ badly with virtual memory tmp files
* such as those used by 'ld'. These files tend to be small and repeatedly
* rewritten in 1kb chunks. The check below causes the device driver to be
* called (and I/O initiated) constantly. Not sure what to do about this yet
* but this comment is being placed here as a reminder.
*/
else if (n + on == DEV_BSIZE && !(ip->i_flag & IPIPE)) {
bp->b_flags |= B_AGE;
bawrite(bp);
} else
bdwrite(bp);
ip->i_flag |= IUPD|ICHG;
if (u.u_ruid != 0)
ip->i_mode &= ~(ISUID|ISGID);
}
} while (u.u_error == 0 && uio->uio_resid && n != 0);
if (error == 0) /* XXX */
error = u.u_error; /* XXX */
if (error && (uio->uio_rw == UIO_WRITE) && (ioflag & IO_UNIT) &&
(type != IFBLK)) {
itrunc(ip, osize, ioflag & IO_SYNC);
uio->uio_offset -= (resid - uio->uio_resid);
uio->uio_resid = resid;
/*
* Should back out the change to the quota here but that would be a lot
* of work for little benefit. Besides we've already made the assumption
* that the entire write would succeed and users can't turn on the IO_UNIT
* bit for their writes anyways.
*/
}
#ifdef whybother
if (! error && (ioflag & IO_SYNC))
IUPDAT(ip, &time, &time, 1);
#endif
return (error);
}
int
ino_stat(ip, sb)
register struct inode *ip;
register struct stat *sb;
{
register struct icommon2 *ic2;
ic2 = &ip->i_ic2;
/*
* inlined ITIMES which takes advantage of the common times pointer.
*/
if (ip->i_flag & (IUPD|IACC|ICHG)) {
ip->i_flag |= IMOD;
if (ip->i_flag & IACC)
ic2->ic_atime = time.tv_sec;
if (ip->i_flag & IUPD)
ic2->ic_mtime = time.tv_sec;
if (ip->i_flag & ICHG)
ic2->ic_ctime = time.tv_sec;
ip->i_flag &= ~(IUPD|IACC|ICHG);
}
sb->st_dev = ip->i_dev;
sb->st_ino = ip->i_number;
sb->st_mode = ip->i_mode;
sb->st_nlink = ip->i_nlink;
sb->st_uid = ip->i_uid;
sb->st_gid = ip->i_gid;
sb->st_rdev = (dev_t)ip->i_rdev;
sb->st_size = ip->i_size;
sb->st_atime = ic2->ic_atime;
sb->st_mtime = ic2->ic_mtime;
sb->st_ctime = ic2->ic_ctime;
sb->st_blksize = MAXBSIZE;
/*
* blocks are too tough to do; it's not worth the effort.
*/
sb->st_blocks = btod (ip->i_size);
sb->st_flags = ip->i_flags;
return (0);
}
/*
* This routine, like its counterpart openi(), calls the device driver for
* special (IBLK, ICHR) files. Normal files simply return early (the default
* case in the switch statement). Pipes and sockets do NOT come here because
* they have their own close routines.
*/
int
closei (ip, flag)
register struct inode *ip;
int flag;
{
register struct mount *mp;
register struct file *fp;
int mode, error;
dev_t dev;
int (*cfunc)();
mode = ip->i_mode & IFMT;
dev = ip->i_rdev;
switch (mode) {
case IFCHR:
cfunc = cdevsw[major(dev)].d_close;
break;
case IFBLK:
/*
* We don't want to really close the device if it is mounted
*/
/* MOUNT TABLE SHOULD HOLD INODE */
for (mp = mount; mp < &mount[NMOUNT]; mp++)
if (mp->m_inodp != NULL && mp->m_dev == dev)
return(0);
cfunc = bdevsw[major(dev)].d_close;
break;
default:
return(0);
}
/*
* Check that another inode for the same device isn't active.
* This is because the same device can be referenced by two
* different inodes.
*/
for (fp = file; fp < file+NFILE; fp++) {
if (fp->f_type != DTYPE_INODE)
continue;
if (fp->f_count && (ip = (struct inode *)fp->f_data) &&
ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
return(0);
}
if (mode == IFBLK) {
/*
* On last close of a block device (that isn't mounted)
* we must invalidate any in core blocks, so that
* we can, for instance, change floppy disks.
*/
bflush(dev);
binval(dev);
}
/*
* NOTE: none of the device drivers appear to either set u_error OR return
* anything meaningful from their close routines. It's a good thing
* programs don't bother checking the error status on close() calls.
* Apparently the only time "errno" is meaningful after a "close" is
* when the process is interrupted.
*/
if (setjmp (&u.u_qsave)) {
/*
* If device close routine is interrupted,
* must return so closef can clean up.
*/
if ((error = u.u_error) == 0)
error = EINTR;
} else
error = (*cfunc)(dev, flag, mode);
return (error);
}
/*
* Place an advisory lock on an inode.
* NOTE: callers of this routine must be prepared to deal with the pseudo
* error return ERESTART.
*/
int
ino_lock(fp, cmd)
register struct file *fp;
int cmd;
{
register int priority = PLOCK;
register struct inode *ip = (struct inode *)fp->f_data;
int error;
if ((cmd & LOCK_EX) == 0)
priority += 4;
/*
* If there's a exclusive lock currently applied to the file then we've
* gotta wait for the lock with everyone else.
*
* NOTE: We can NOT sleep on i_exlockc because it is on an odd byte boundary
* and the low (oddness) bit is reserved for networking/supervisor mode
* sleep channels. Thus we always sleep on i_shlockc and simply check
* the proper bits to see if the lock we want is granted. This may
* mean an extra wakeup/sleep event is done once in a while but
* everything will work correctly.
*/
again:
while (ip->i_flag & IEXLOCK) {
/*
* If we're holding an exclusive
* lock, then release it.
*/
if (fp->f_flag & FEXLOCK) {
ino_unlock(fp, FEXLOCK);
continue;
}
if (cmd & LOCK_NB)
return (EWOULDBLOCK);
ip->i_flag |= ILWAIT;
error = tsleep((caddr_t)&ip->i_shlockc, priority | PCATCH, 0);
if (error)
return(error);
}
if ((cmd & LOCK_EX) && (ip->i_flag & ISHLOCK)) {
/*
* Must wait for any shared locks to finish
* before we try to apply a exclusive lock.
*
* If we're holding a shared
* lock, then release it.
*/
if (fp->f_flag & FSHLOCK) {
ino_unlock(fp, FSHLOCK);
goto again;
}
if (cmd & LOCK_NB)
return (EWOULDBLOCK);
ip->i_flag |= ILWAIT;
error = tsleep((caddr_t)&ip->i_shlockc, PLOCK | PCATCH, 0);
if (error)
return(error);
goto again;
}
if (cmd & LOCK_EX) {
cmd &= ~LOCK_SH;
ip->i_exlockc++;
ip->i_flag |= IEXLOCK;
fp->f_flag |= FEXLOCK;
}
if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
ip->i_shlockc++;
ip->i_flag |= ISHLOCK;
fp->f_flag |= FSHLOCK;
}
return (0);
}
/*
* Unlock a file.
*/
void
ino_unlock(fp, kind)
register struct file *fp;
int kind;
{
register struct inode *ip = (struct inode *)fp->f_data;
register int flags;
kind &= fp->f_flag;
if (ip == NULL || kind == 0)
return;
flags = ip->i_flag;
if (kind & FSHLOCK) {
if (--ip->i_shlockc == 0) {
ip->i_flag &= ~ISHLOCK;
if (flags & ILWAIT)
wakeup((caddr_t)&ip->i_shlockc);
}
fp->f_flag &= ~FSHLOCK;
}
if (kind & FEXLOCK) {
if (--ip->i_exlockc == 0) {
ip->i_flag &= ~(IEXLOCK|ILWAIT);
if (flags & ILWAIT)
wakeup((caddr_t)&ip->i_shlockc);
}
fp->f_flag &= ~FEXLOCK;
}
}
/*
* Openi called to allow handler of special files to initialize and
* validate before actual IO.
*/
int
openi (ip, mode)
register struct inode *ip;
{
register dev_t dev = ip->i_rdev;
register int maj = major(dev);
dev_t bdev;
int error;
switch (ip->i_mode&IFMT) {
case IFCHR:
if (ip->i_fs->fs_flags & MNT_NODEV)
return(ENXIO);
if ((u_int)maj >= nchrdev)
return (ENXIO);
if (mode & FWRITE) {
/*
* When running in very secure mode, do not allow
* opens for writing of any disk character devices.
*/
if (securelevel >= 2 && isdisk(dev, IFCHR))
return(EPERM);
/*
* When running in secure mode, do not allow opens
* for writing of /dev/mem, /dev/kmem, or character
* devices whose corresponding block devices are
* currently mounted.
*/
if (securelevel >= 1) {
if ((bdev = chrtoblk(dev)) != NODEV &&
(error = ufs_mountedon(bdev)))
return(error);
if (iskmemdev(dev))
return(EPERM);
}
}
return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
case IFBLK:
if (ip->i_fs->fs_flags & MNT_NODEV)
return(ENXIO);
if ((u_int)maj >= nblkdev)
return (ENXIO);
/*
* When running in very secure mode, do not allow
* opens for writing of any disk block devices.
*/
if (securelevel >= 2 && (mode & FWRITE) && isdisk(dev, IFBLK))
return(EPERM);
/*
* Do not allow opens of block devices that are
* currently mounted.
*
* 2.11BSD must relax this restriction to allow 'fsck' to
* open the root filesystem (which is always mounted) during
* a reboot. Once in secure or very secure mode the
* above restriction is fully effective. On the otherhand
* fsck should 1) use the raw device, 2) not do sync calls...
*/
if (securelevel > 0 && (error = ufs_mountedon(dev)))
return(error);
return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
}
return (0);
}
static void
forceclose(dev)
register dev_t dev;
{
register struct file *fp;
register struct inode *ip;
for (fp = file; fp < file+NFILE; fp++) {
if (fp->f_count == 0)
continue;
if (fp->f_type != DTYPE_INODE)
continue;
ip = (struct inode *)fp->f_data;
if (ip == 0)
continue;
if ((ip->i_mode & IFMT) != IFCHR)
continue;
if (ip->i_rdev != dev)
continue;
fp->f_flag &= ~(FREAD | FWRITE);
}
}
/*
* Revoke access the current tty by all processes.
* Used only by the super-user in init
* to give ``clean'' terminals at login.
*/
void
vhangup()
{
if (! suser())
return;
if (u.u_ttyp == NULL)
return;
forceclose(u.u_ttyd);
if ((u.u_ttyp->t_state) & TS_ISOPEN)
gsignal(u.u_ttyp->t_pgrp, SIGHUP);
}

307
sys/kernel/sys_pipe.c Normal file
View File

@@ -0,0 +1,307 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#include "proc.h"
#include "inode.h"
#include "file.h"
#include "fs.h"
#include "mount.h"
#include "uio.h"
int
readp (fp, uio, flag)
register struct file *fp;
register struct uio *uio;
int flag;
{
register struct inode *ip;
int error;
ip = (struct inode *)fp->f_data;
loop:
/* Very conservative locking. */
ILOCK(ip);
/* If nothing in the pipe, wait (unless FNONBLOCK is set). */
if (ip->i_size == 0) {
/*
* If there are not both reader and writer active,
* return without satisfying read.
*/
IUNLOCK(ip);
if (ip->i_count != 2)
return (0);
if (fp->f_flag & FNONBLOCK)
return (EWOULDBLOCK);
ip->i_mode |= IREAD;
sleep((caddr_t)ip+4, PPIPE);
goto loop;
}
uio->uio_offset = fp->f_offset;
error = rwip(ip, uio, flag);
fp->f_offset = uio->uio_offset;
/*
* If reader has caught up with writer, reset
* offset and size to 0.
*/
if (fp->f_offset == ip->i_size) {
fp->f_offset = 0;
ip->i_size = 0;
if (ip->i_mode & IWRITE) {
ip->i_mode &= ~IWRITE;
wakeup((caddr_t)ip+2);
}
if (ip->i_wsel) {
selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL));
ip->i_wsel = 0;
ip->i_flag &= ~IWCOLL;
}
}
IUNLOCK(ip);
return (error);
}
int
writep (fp, uio, flag)
struct file *fp;
register struct uio *uio;
int flag;
{
register struct inode *ip;
register int c;
int error = 0;
ip = (struct inode *)fp->f_data;
c = uio->uio_resid;
ILOCK(ip);
if ((fp->f_flag & FNONBLOCK) && ip->i_size + c >= MAXPIPSIZ) {
error = EWOULDBLOCK;
goto done;
}
loop:
/* If all done, return. */
if (c == 0) {
uio->uio_resid = 0;
goto done;
}
/*
* If there are not both read and write sides of the pipe active,
* return error and signal too.
*/
if (ip->i_count != 2) {
psignal(u.u_procp, SIGPIPE);
error = EPIPE;
done: IUNLOCK(ip);
return (error);
}
/*
* If the pipe is full, wait for reads to deplete
* and truncate it.
*/
if (ip->i_size >= MAXPIPSIZ) {
ip->i_mode |= IWRITE;
IUNLOCK(ip);
sleep((caddr_t)ip+2, PPIPE);
ILOCK(ip);
goto loop;
}
/*
* Write what is possible and loop back.
* If writing less than MAXPIPSIZ, it always goes.
* One can therefore get a file > MAXPIPSIZ if write
* sizes do not divide MAXPIPSIZ.
*/
uio->uio_offset = ip->i_size;
uio->uio_resid = MIN((u_int)c, (u_int)MAXPIPSIZ);
c -= uio->uio_resid;
error = rwip(ip, uio, flag);
if (ip->i_mode&IREAD) {
ip->i_mode &= ~IREAD;
wakeup((caddr_t)ip+4);
}
if (ip->i_rsel) {
selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL));
ip->i_rsel = 0;
ip->i_flag &= ~IRCOLL;
}
goto loop;
}
int
pipe_rw (fp, uio, flag)
register struct file *fp;
register struct uio *uio;
int flag;
{
if (uio->uio_rw == UIO_READ)
return (readp(fp, uio, flag));
return (writep(fp, uio, flag));
}
int
pipe_select (fp, which)
struct file *fp;
int which;
{
register struct inode *ip = (struct inode *)fp->f_data;
register struct proc *p;
register int retval = 0;
extern int selwait;
ILOCK(ip);
if (ip->i_count != 2)
retval = 1;
else switch (which) {
case FREAD:
if (ip->i_size) {
retval = 1;
break;
}
if ((p = ip->i_rsel) && p->p_wchan == (caddr_t)&selwait)
ip->i_flag |= IRCOLL;
else
ip->i_rsel = u.u_procp;
break;
case FWRITE:
if (ip->i_size < MAXPIPSIZ) {
retval = 1;
break;
}
if ((p = ip->i_wsel) && p->p_wchan == (caddr_t)&selwait)
ip->i_flag |= IWCOLL;
else
ip->i_wsel = u.u_procp;
break;
}
IUNLOCK(ip);
return(retval);
}
/*
* This routine was pulled out of what used to be called 'ino_close'. Doing
* so saved a test of the inode belonging to a pipe. We know this is a pipe
* because the inode type was DTYPE_PIPE. The dispatch in closef() can come
* directly here instead of the general inode close routine.
*
* This routine frees the inode by calling 'iput'. The inode must be
* unlocked prior to calling this routine because an 'ilock' is done prior
* to the select wakeup processing.
*/
int
pipe_close(fp)
struct file *fp;
{
register struct inode *ip = (struct inode *)fp->f_data;
ilock(ip);
#ifdef DIAGNOSTIC
if ((ip->i_flag & IPIPE) == 0)
panic("pipe_close !IPIPE");
#endif
if (ip->i_rsel) {
selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL));
ip->i_rsel = 0;
ip->i_flag &= ~IRCOLL;
}
if (ip->i_wsel) {
selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL));
ip->i_wsel = 0;
ip->i_flag &= ~IWCOLL;
}
ip->i_mode &= ~(IREAD|IWRITE);
wakeup((caddr_t)ip+2);
wakeup((caddr_t)ip+4);
/*
* And finally decrement the reference count and (likely) release the inode.
*/
iput(ip);
return(0);
}
const struct fileops pipeops = {
pipe_rw, ino_ioctl, pipe_select, pipe_close
};
/*
* The sys-pipe entry.
* Allocate an inode on the root device. Allocate 2
* file structures. Put it all together with flags.
*/
void
pipe()
{
register struct inode *ip;
register struct file *rf, *wf;
static struct mount *mp;
struct inode itmp;
int r;
/*
* if pipedev not yet found, or not available, get it; if can't
* find it, use rootdev. It would be cleaner to wander around
* and fix it so that this and getfs() only check m_dev OR
* m_inodp, but hopefully the mount table isn't scanned enough
* to make it a problem. Besides, 4.3's is just as bad. Basic
* fantasy is that if m_inodp is set, m_dev *will* be okay.
*/
if (! mp || ! mp->m_inodp || mp->m_dev != pipedev) {
for (mp = &mount[0]; ; ++mp) {
if (mp == &mount[NMOUNT]) {
mp = &mount[0]; /* use root */
break;
}
if (mp->m_inodp == NULL || mp->m_dev != pipedev)
continue;
break;
}
if (mp->m_filsys.fs_ronly) {
u.u_error = EROFS;
return;
}
}
itmp.i_fs = &mp->m_filsys;
itmp.i_dev = mp->m_dev;
ip = ialloc (&itmp);
if (ip == NULL)
return;
rf = falloc();
if (rf == NULL) {
iput (ip);
return;
}
r = u.u_rval;
wf = falloc();
if (wf == NULL) {
rf->f_count = 0;
u.u_ofile[r] = NULL;
iput (ip);
return;
}
#ifdef __mips__
/* Move a secondary return value to register $v1. */
u.u_frame [FRAME_R3] = u.u_rval;
#else
#error "pipe return value for unknown architecture"
#endif
u.u_rval = r;
wf->f_flag = FWRITE;
rf->f_flag = FREAD;
rf->f_type = wf->f_type = DTYPE_PIPE;
rf->f_data = wf->f_data = (caddr_t) ip;
ip->i_count = 2;
ip->i_mode = IFREG;
ip->i_flag = IACC | IUPD | ICHG | IPIPE;
}

137
sys/kernel/sys_process.c Normal file
View File

@@ -0,0 +1,137 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#include "proc.h"
#include "inode.h"
#include "vm.h"
#include "ptrace.h"
/*
* sys-trace system call.
*/
void
ptrace()
{
register struct proc *p;
register struct a {
int req;
int pid;
int *addr;
int data;
} *uap;
uap = (struct a *)u.u_arg;
if (uap->req <= 0) {
u.u_procp->p_flag |= P_TRACED;
return;
}
p = pfind(uap->pid);
if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
!(p->p_flag & P_TRACED)) {
u.u_error = ESRCH;
return;
}
while (ipc.ip_lock)
sleep((caddr_t)&ipc, PZERO);
ipc.ip_lock = p->p_pid;
ipc.ip_data = uap->data;
ipc.ip_addr = uap->addr;
ipc.ip_req = uap->req;
p->p_flag &= ~P_WAITED;
setrun(p);
while (ipc.ip_req > 0)
sleep((caddr_t)&ipc, PZERO);
u.u_rval = ipc.ip_data;
if (ipc.ip_req < 0)
u.u_error = EIO;
ipc.ip_lock = 0;
wakeup((caddr_t)&ipc);
}
/*
* Code that the child process
* executes to implement the command
* of the parent process in tracing.
*/
int
procxmt()
{
register int i, *p;
if (ipc.ip_lock != u.u_procp->p_pid)
return(0);
u.u_procp->p_slptime = 0;
i = ipc.ip_req;
ipc.ip_req = 0;
wakeup ((caddr_t)&ipc);
switch (i) {
/* read user I */
case PT_READ_I:
/* read user D */
case PT_READ_D:
if (baduaddr ((caddr_t) ipc.ip_addr))
goto error;
ipc.ip_data = *(int*) ipc.ip_addr;
break;
/* read u */
case PT_READ_U:
i = (int) ipc.ip_addr;
if (i < 0 || i >= USIZE)
goto error;
ipc.ip_data = ((unsigned*)&u) [i/sizeof(int)];
break;
/* write user I */
case PT_WRITE_I:
/* write user D */
case PT_WRITE_D:
if (baduaddr ((caddr_t) ipc.ip_addr))
goto error;
*(int*) ipc.ip_addr = ipc.ip_data;
break;
/* write u */
case PT_WRITE_U:
i = (int)ipc.ip_addr;
p = (int*)&u + i/sizeof(int);
for (i=0; i<FRAME_WORDS; i++)
if (p == &u.u_frame[i])
goto ok;
goto error;
ok:
*p = ipc.ip_data;
break;
/* set signal and continue */
/* one version causes a trace-trap */
case PT_STEP:
/* Use Status.RP bit to indicate a single-step request. */
u.u_frame [FRAME_STATUS] |= ST_RP;
/* FALL THROUGH TO ... */
case PT_CONTINUE:
if ((int)ipc.ip_addr != 1)
u.u_frame [FRAME_PC] = (int)ipc.ip_addr;
if (ipc.ip_data > NSIG)
goto error;
u.u_procp->p_ptracesig = ipc.ip_data;
return(1);
/* force exit */
case PT_KILL:
exit(u.u_procp->p_ptracesig);
/*NOTREACHED*/
default:
error:
ipc.ip_req = -1;
}
return(0);
}

169
sys/kernel/syscalls.c Normal file
View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/*
* System call names.
*/
#ifndef pdp11
const char *const syscallnames[] = {
"indir", /* 0 = indir */
"exit", /* 1 = exit */
"fork", /* 2 = fork */
"read", /* 3 = read */
"write", /* 4 = write */
"open", /* 5 = open */
"close", /* 6 = close */
"wait4", /* 7 = wait4 */
"#8", /* 8 = (old creat) */
"link", /* 9 = link */
"unlink", /* 10 = unlink */
"execv", /* 11 = execv */
"chdir", /* 12 = chdir */
"fchdir", /* 13 = fchdir */
"mknod", /* 14 = mknod */
"chmod", /* 15 = chmod */
"chown", /* 16 = chown; now 3 args */
"chflags", /* 17 = chflags */
"fchflags", /* 18 = fchflags */
"lseek", /* 19 = lseek */
"getpid", /* 20 = getpid */
"mount", /* 21 = mount */
"umount", /* 22 = umount */
"__sysctl", /* 23 = __sysctl */
"getuid", /* 24 = getuid */
"geteuid", /* 25 = geteuid */
"ptrace", /* 26 = ptrace */
"getppid", /* 27 = getppid */
"statfs", /* 28 = statfs */
"fstatfs", /* 29 = fstatfs */
"getfsstat", /* 30 = getfsstat */
"sigaction", /* 31 = sigaction */
"sigprocmask", /* 32 = sigprocmask */
"access", /* 33 = access */
"sigpending", /* 34 = sigpending */
"sigaltstack", /* 35 = sigaltstack */
"sync", /* 36 = sync */
"kill", /* 37 = kill */
"stat", /* 38 = stat */
"getlogin", /* 39 = getlogin */
"lstat", /* 40 = lstat */
"dup", /* 41 = dup */
"pipe", /* 42 = pipe */
"setlogin", /* 43 = setlogin */
"profil", /* 44 = profil */
"setuid", /* 45 = setuid */
"seteuid", /* 46 = seteuid */
"getgid", /* 47 = getgid */
"getegid", /* 48 = getegid */
"setgid", /* 49 = setgid */
"setegid", /* 50 = setegid */
"kmemdev", /* 51 = kmemdev */
"phys", /* 52 = (2.9) set phys addr */
"lock", /* 53 = (2.9) lock in core */
"ioctl", /* 54 = ioctl */
"reboot", /* 55 = reboot */
"sigwait", /* 56 = sigwait */
"symlink", /* 57 = symlink */
"readlink", /* 58 = readlink */
"execve", /* 59 = execve */
"umask", /* 60 = umask */
"chroot", /* 61 = chroot */
"fstat", /* 62 = fstat */
"#63", /* 63 = unused */
"#64", /* 64 = (old getpagesize) */
"pselect", /* 65 = pselect */
"vfork", /* 66 = vfork */
"#67", /* 67 = unused */
"#68", /* 68 = unused */
"brk", /* 69 = brk */
"rdglob", /* 70 = read from global space */
"wrglob", /* 71 = write to global space */
"msec", /* 72 = kticks */
"#73", /* 73 = unused */
"#74", /* 74 = unused */
"#75", /* 75 = unused */
"vhangup", /* 76 = vhangup */
"#77", /* 77 = unused */
"#78", /* 78 = unused */
"getgroups", /* 79 = getgroups */
"setgroups", /* 80 = setgroups */
"getpgrp", /* 81 = getpgrp */
"setpgrp", /* 82 = setpgrp */
"setitimer", /* 83 = setitimer */
"old wait", /* 84 = wait,wait3 COMPAT*/
"#85", /* 85 = unused */
"getitimer", /* 86 = getitimer */
"#87", /* 87 = (old gethostname) */
"#88", /* 88 = (old sethostname) */
"getdtablesize", /* 89 = getdtablesize */
"dup2", /* 90 = dup2 */
"#91", /* 91 = unused */
"fcntl", /* 92 = fcntl */
"select", /* 93 = select */
"#94", /* 94 = unused */
"fsync", /* 95 = fsync */
"setpriority", /* 96 = setpriority */
"socket", /* 97 = socket */
"connect", /* 98 = connect */
"accept", /* 99 = accept */
"getpriority", /* 100 = getpriority */
"send", /* 101 = send */
"recv", /* 102 = recv */
"sigreturn", /* 103 = sigreturn */
"bind", /* 104 = bind */
"setsockopt", /* 105 = setsockopt */
"listen", /* 106 = listen */
"sigsuspend", /* 107 = sigsuspend */
"#108", /* 108 = (old sigvec) */
"#109", /* 109 = (old sigblock) */
"#110", /* 110 = (old sigsetmask) */
"#111", /* 111 = (old sigpause) */
"sigstack", /* 112 = sigstack COMPAT-43 */
"recvmsg", /* 113 = recvmsg */
"sendmsg", /* 114 = sendmsg */
"#115", /* 115 = unused */
"gettimeofday", /* 116 = gettimeofday */
"getrusage", /* 117 = getrusage */
"getsockopt", /* 118 = getsockopt */
"#119", /* 119 = unused */
"readv", /* 120 = readv */
"writev", /* 121 = writev */
"settimeofday", /* 122 = settimeofday */
"fchown", /* 123 = fchown */
"fchmod", /* 124 = fchmod */
"recvfrom", /* 125 = recvfrom */
"#126", /* 126 = (old setreuid) */
"#127", /* 127 = (old setregid) */
"rename", /* 128 = rename */
"truncate", /* 129 = truncate */
"ftruncate", /* 130 = ftruncate */
"flock", /* 131 = flock */
"#132", /* 132 = unused */
"sendto", /* 133 = sendto */
"shutdown", /* 134 = shutdown */
"socketpair", /* 135 = socketpair */
"mkdir", /* 136 = mkdir */
"rmdir", /* 137 = rmdir */
"utimes", /* 138 = utimes */
"#139", /* 139 = unused */
"adjtime", /* 140 = adjtime */
"getpeername", /* 141 = getpeername */
"#142", /* 142 = (old gethostid) */
"#143", /* 143 = (old sethostid) */
"getrlimit", /* 144 = getrlimit */
"setrlimit", /* 145 = setrlimit */
"killpg", /* 146 = killpg */
"#147", /* 147 = unused */
"setquota", /* 148 = setquota */
"quota", /* 149 = quota */
"getsockname", /* 150 = getsockname */
"#151", /* 151 = unused */
"ustore", /* 152 = ustore */
"ufetch", /* 153 = ufetch */
"ucall", /* 154 = ucall */
"#155", /* 155 = unused */
};
#endif

1653
sys/kernel/tty.c Normal file

File diff suppressed because it is too large Load Diff

520
sys/kernel/tty_pty.c Normal file
View File

@@ -0,0 +1,520 @@
/*
* Pseudo-teletype Driver
* (Actually two drivers, requiring two entries in 'cdevsw')
*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "pty.h"
#if NPTY > 0
#include "param.h"
#include "systm.h"
#include "ioctl.h"
#include "tty.h"
#include "user.h"
#include "conf.h"
#include "file.h"
#include "proc.h"
#include "uio.h"
#include "kernel.h"
#include "inode.h"
#include "types.h"
#include "ttydev.h"
const struct devspec ptsdevs[] = {
{ 0, "ttyp0" }, { 1, "ttyp1" }, { 2, "ttyp2" }, { 3, "ttyp3" },
{ 0, 0 }
};
const struct devspec ptcdevs[] = {
{ 0, "ptyp0" }, { 1, "ptyp1" }, { 2, "ptyp2" }, { 3, "ptyp3" },
{ 0, 0 }
};
extern int TTYHOG; /* see tty.c */
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
/*
* pts == /dev/tty[pqrs]?
* ptc == /dev/pty[pqrs]?
*/
struct tty pt_tty[NPTY];
struct pt_ioctl {
int pt_flags;
struct proc *pt_selr, *pt_selw;
u_char pt_send;
u_char pt_ucntl;
} pt_ioctl[NPTY];
int npty = NPTY; /* for pstat -t */
#define PF_RCOLL 0x01
#define PF_WCOLL 0x02
#define PF_PKT 0x08 /* packet mode */
#define PF_STOPPED 0x10 /* user told stopped */
#define PF_REMOTE 0x20 /* remote and flow controlled input */
#define PF_NOSTOP 0x40
#define PF_UCNTL 0x80 /* user control mode */
/*ARGSUSED*/
int ptsopen(dev_t dev, int flag, int mode)
{
register struct tty *tp;
int error;
#ifdef lint
npty = npty;
#endif
if (minor(dev) >= NPTY)
return (ENXIO);
tp = &pt_tty[minor(dev)];
if ((tp->t_state & TS_ISOPEN) == 0) {
ttychars(tp); /* Set up default chars */
tp->t_ispeed = tp->t_ospeed = B115200;
tp->t_flags = 0; /* No features (nor raw mode) */
} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
return (EBUSY);
if (tp->t_oproc) /* Ctrlr still around. */
tp->t_state |= TS_CARR_ON;
while ((tp->t_state & TS_CARR_ON) == 0) {
tp->t_state |= TS_WOPEN;
sleep((caddr_t)&tp->t_rawq, TTIPRI);
}
error = ttyopen(dev, tp);
ptcwakeup (tp, FREAD | FWRITE);
return (error);
}
int ptsclose(dev_t dev, int flag, int mode)
{
register struct tty *tp;
tp = &pt_tty[minor(dev)];
ttyclose(tp);
ptcwakeup(tp, FREAD|FWRITE);
return 0;
}
int ptsread(dev_t dev, register struct uio *uio, int flag)
{
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
again:
if (pti->pt_flags & PF_REMOTE) {
while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
(u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
u.u_procp->p_flag&SVFORK)
return (EIO);
gsignal(u.u_procp->p_pgrp, SIGTTIN);
sleep((caddr_t)&lbolt, TTIPRI);
}
if (tp->t_canq.c_cc == 0) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
sleep((caddr_t)&tp->t_canq, TTIPRI);
goto again;
}
while (tp->t_canq.c_cc > 1 && uio->uio_resid)
if (ureadc(getc(&tp->t_canq), uio) < 0) {
error = EFAULT;
break;
}
if (tp->t_canq.c_cc == 1)
(void) getc(&tp->t_canq);
if (tp->t_canq.c_cc)
return (error);
} else
if (tp->t_oproc)
error = ttread(tp, uio, flag);
ptcwakeup(tp, FWRITE);
return (error);
}
/*
* Write to pseudo-tty.
* Wakeups of controlling tty will happen
* indirectly, when tty driver calls ptsstart.
*/
int ptswrite(dev_t dev, register struct uio *uio, int flag)
{
register struct tty *tp;
tp = &pt_tty[minor(dev)];
if (tp->t_oproc == 0)
return (EIO);
return ttwrite(tp, uio, flag);
}
/*
* Start output on pseudo-tty.
* Wake up process selecting or sleeping for input from controlling tty.
*/
void ptsstart(struct tty *tp)
{
register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
if (tp->t_state & TS_TTSTOP)
return;
if (pti->pt_flags & PF_STOPPED) {
pti->pt_flags &= ~PF_STOPPED;
pti->pt_send = TIOCPKT_START;
}
ptcwakeup(tp, FREAD);
}
void ptcwakeup(struct tty *tp, int flag)
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
if (flag & FREAD) {
if (pti->pt_selr) {
selwakeup(pti->pt_selr, (long)(pti->pt_flags & PF_RCOLL));
pti->pt_selr = 0;
pti->pt_flags &= ~PF_RCOLL;
}
wakeup((caddr_t)&tp->t_outq.c_cf);
}
if (flag & FWRITE) {
if (pti->pt_selw) {
selwakeup(pti->pt_selw, (long)(pti->pt_flags & PF_WCOLL));
pti->pt_selw = 0;
pti->pt_flags &= ~PF_WCOLL;
}
wakeup((caddr_t)&tp->t_rawq.c_cf);
}
}
/*ARGSUSED*/
int ptcopen(dev_t dev, int flag, int mode)
{
register struct tty *tp;
struct pt_ioctl *pti;
if (minor(dev) >= NPTY)
return (ENXIO);
tp = &pt_tty[minor(dev)];
if (tp->t_oproc)
return (EIO);
tp->t_oproc = ptsstart;
ttymodem(tp, 1);
pti = &pt_ioctl[minor(dev)];
pti->pt_flags = 0;
pti->pt_send = 0;
pti->pt_ucntl = 0;
return (0);
}
int ptcclose(dev_t dev, int flag, int mode)
{
register struct tty *tp;
tp = &pt_tty[minor(dev)];
ttymodem(tp, 0);
tp->t_state &= ~TS_CARR_ON;
tp->t_oproc = 0; /* mark closed */
return 0;
}
int ptcread(dev_t dev, register struct uio *uio, int flag)
{
register struct tty *tp = &pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
char buf[BUFSIZ];
int error = 0, cc;
/*
* We want to block until the slave
* is open, and there's something to read;
* but if we lost the slave or we're NBIO,
* then return the appropriate error instead.
*/
for (;;) {
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags&PF_PKT && pti->pt_send) {
error = ureadc((int)pti->pt_send, uio);
if (error)
return (error);
pti->pt_send = 0;
return (0);
}
if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
error = ureadc((int)pti->pt_ucntl, uio);
if (error)
return (error);
pti->pt_ucntl = 0;
return (0);
}
if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
break;
}
if ((tp->t_state&TS_CARR_ON) == 0)
return (0); /* EOF */
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
}
if (pti->pt_flags & (PF_PKT|PF_UCNTL))
error = ureadc(0, uio);
while (uio->uio_resid && error == 0) {
cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
if (cc <= 0)
break;
error = uiomove(buf, cc, uio);
}
if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_outq);
}
if (tp->t_wsel) {
selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
tp->t_wsel = 0;
tp->t_state &= ~TS_WCOLL;
}
}
return (error);
}
void ptsstop(register struct tty *tp, int flush)
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
int flag;
/* note: FLUSHREAD and FLUSHWRITE already ok */
if (flush == 0) {
flush = TIOCPKT_STOP;
pti->pt_flags |= PF_STOPPED;
} else
pti->pt_flags &= ~PF_STOPPED;
pti->pt_send |= flush;
/* change of perspective */
flag = 0;
if (flush & FREAD)
flag |= FWRITE;
if (flush & FWRITE)
flag |= FREAD;
ptcwakeup(tp, flag);
}
int ptcselect(dev_t dev, int rw)
{
register struct tty *tp = &pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
struct proc *p;
int s;
if ((tp->t_state&TS_CARR_ON) == 0)
return (1);
switch (rw) {
case FREAD:
/*
* Need to block timeouts (ttrstart).
*/
s = spltty();
if ((tp->t_state&TS_ISOPEN) &&
tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
splx(s);
return (1);
}
splx(s);
/* FALLTHROUGH */
case 0: /* exceptional */
if ((tp->t_state&TS_ISOPEN) &&
((pti->pt_flags&PF_PKT && pti->pt_send) ||
(pti->pt_flags&PF_UCNTL && pti->pt_ucntl)))
return (1);
if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_RCOLL;
else
pti->pt_selr = u.u_procp;
break;
case FWRITE:
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags & PF_REMOTE) {
if (tp->t_canq.c_cc == 0)
return (1);
} else {
if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
return (1);
if (tp->t_canq.c_cc == 0 &&
(tp->t_flags & (RAW|CBREAK)) == 0)
return (1);
}
}
if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
pti->pt_flags |= PF_WCOLL;
else
pti->pt_selw = u.u_procp;
break;
}
return (0);
}
int ptcwrite(dev_t dev, register struct uio *uio, int flag)
{
register struct tty *tp = &pt_tty[minor(dev)];
register char *cp = NULL;
register int cc = 0;
char locbuf[BUFSIZ];
int cnt = 0;
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
again:
if ((tp->t_state&TS_ISOPEN) == 0)
goto block;
if (pti->pt_flags & PF_REMOTE) {
if (tp->t_canq.c_cc)
goto block;
while (uio->uio_resid && tp->t_canq.c_cc < TTYHOG - 1) {
if (cc == 0) {
cc = MIN(uio->uio_resid, BUFSIZ);
cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
cp = locbuf;
error = uiomove(cp, cc, uio);
if (error)
return (error);
/* check again for safety */
if ((tp->t_state&TS_ISOPEN) == 0)
return (EIO);
}
if (cc)
(void) b_to_q(cp, cc, &tp->t_canq);
cc = 0;
}
(void) putc(0, &tp->t_canq);
ttwakeup(tp);
wakeup((caddr_t)&tp->t_canq);
return (0);
}
while (uio->uio_resid > 0) {
if (cc == 0) {
cc = MIN(uio->uio_resid, BUFSIZ);
cp = locbuf;
error = uiomove(cp, cc, uio);
if (error)
return (error);
/* check again for safety */
if ((tp->t_state&TS_ISOPEN) == 0)
return (EIO);
}
while (cc > 0) {
if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
(tp->t_canq.c_cc > 0 ||
tp->t_flags & (RAW|CBREAK))) {
wakeup((caddr_t)&tp->t_rawq);
goto block;
}
ttyinput(*cp++, tp);
cnt++;
cc--;
}
cc = 0;
}
return (0);
block:
/*
* Come here to wait for slave to open, for space
* in outq, or space in rawq.
*/
if ((tp->t_state&TS_CARR_ON) == 0)
return (EIO);
if (flag & IO_NDELAY) {
/* adjust for data copied in but not written */
uio->uio_resid += cc;
if (cnt == 0)
return (EWOULDBLOCK);
return (0);
}
sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
goto again;
}
int ptyioctl(dev_t dev, u_int cmd, caddr_t data, int flag)
{
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int stop, error;
/*
* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
* ttywflush(tp) will hang if there are characters in the outq.
*/
if (cdevsw[major(dev)].d_open == ptcopen)
switch (cmd) {
case TIOCPKT:
if (*(int *)data) {
if (pti->pt_flags & PF_UCNTL)
return (EINVAL);
pti->pt_flags |= PF_PKT;
} else
pti->pt_flags &= ~PF_PKT;
return (0);
case TIOCUCNTL:
if (*(int *)data) {
if (pti->pt_flags & PF_PKT)
return (EINVAL);
pti->pt_flags |= PF_UCNTL;
} else
pti->pt_flags &= ~PF_UCNTL;
return (0);
case TIOCREMOTE:
if (*(int *)data)
pti->pt_flags |= PF_REMOTE;
else
pti->pt_flags &= ~PF_REMOTE;
ttyflush(tp, FREAD|FWRITE);
return (0);
case TIOCSETP:
case TIOCSETN:
case TIOCSETD:
while (getc(&tp->t_outq) >= 0)
;
break;
}
error = ttioctl (tp, cmd, data, flag);
if (error < 0) {
if (pti->pt_flags & PF_UCNTL &&
(cmd & ~0xff) == UIOCCMD(0)) {
if (cmd & 0xff) {
pti->pt_ucntl = (u_char)cmd;
ptcwakeup(tp, FREAD);
}
return (0);
}
error = ENOTTY;
}
stop = (tp->t_flags & RAW) == 0 &&
tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q');
if (pti->pt_flags & PF_NOSTOP) {
if (stop) {
pti->pt_send &= ~TIOCPKT_NOSTOP;
pti->pt_send |= TIOCPKT_DOSTOP;
pti->pt_flags &= ~PF_NOSTOP;
ptcwakeup(tp, FREAD);
}
} else {
if (!stop) {
pti->pt_send &= ~TIOCPKT_DOSTOP;
pti->pt_send |= TIOCPKT_NOSTOP;
pti->pt_flags |= PF_NOSTOP;
ptcwakeup(tp, FREAD);
}
}
return (error);
}
#endif

406
sys/kernel/tty_subr.c Normal file
View File

@@ -0,0 +1,406 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "clist.h"
#include "ioctl.h"
#include "tty.h"
#include "systm.h"
char cwaiting;
/*
* Character list get/put
*/
int
getc(p)
register struct clist *p;
{
register struct cblock *bp;
register int c, s;
s = spltty();
if (p->c_cc <= 0) {
c = -1;
p->c_cc = 0;
p->c_cf = p->c_cl = NULL;
} else {
c = *p->c_cf++ & 0377;
if (--p->c_cc<=0) {
bp = (struct cblock *)(p->c_cf-1);
bp = (struct cblock *)((int)bp & ~CROUND);
p->c_cf = NULL;
p->c_cl = NULL;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
} else if (((int)p->c_cf & CROUND) == 0){
bp = (struct cblock *)(p->c_cf);
bp--;
p->c_cf = bp->c_next->c_info;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
}
}
splx(s);
return (c);
}
/*
* Copy clist to buffer.
* Return number of bytes moved.
*/
int
q_to_b (q, cp, cc)
register struct clist *q;
char *cp;
{
register struct cblock *bp;
register int nc;
int s;
char *acp;
if (cc <= 0)
return (0);
s = spltty();
if (q->c_cc <= 0) {
q->c_cc = 0;
q->c_cf = q->c_cl = NULL;
splx(s);
return (0);
}
acp = cp;
while (cc) {
nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
nc = MIN(nc, cc);
nc = MIN(nc, q->c_cc);
(void) bcopy(q->c_cf, cp, (unsigned)nc);
q->c_cf += nc;
q->c_cc -= nc;
cc -= nc;
cp += nc;
if (q->c_cc <= 0) {
bp = (struct cblock *)(q->c_cf - 1);
bp = (struct cblock *)((int)bp & ~CROUND);
q->c_cf = q->c_cl = NULL;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
break;
}
if (((int)q->c_cf & CROUND) == 0) {
bp = (struct cblock *)(q->c_cf);
bp--;
q->c_cf = bp->c_next->c_info;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
}
}
splx(s);
return (cp - acp);
}
/*
* Return count of contiguous characters
* in clist starting at q->c_cf.
* Stop counting if flag&character is non-null.
*/
int ndqb (q, flag)
register struct clist *q;
{
int cc;
int s;
s = spltty();
if (q->c_cc <= 0) {
cc = -q->c_cc;
goto out;
}
cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
cc -= (int)q->c_cf;
if (q->c_cc < cc)
cc = q->c_cc;
if (flag) {
register char *p, *end;
p = q->c_cf;
end = p;
end += cc;
while (p < end) {
if (*p & flag) {
cc = (int)p;
cc -= (int)q->c_cf;
break;
}
p++;
}
}
out:
splx(s);
return (cc);
}
/*
* Flush cc bytes from q.
*/
void
ndflush (q, cc)
register struct clist *q;
register int cc;
{
register struct cblock *bp;
char *end;
int rem, s;
s = spltty();
if (q->c_cc <= 0)
goto out;
while (cc>0 && q->c_cc) {
bp = (struct cblock *)((int)q->c_cf & ~CROUND);
if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
end = q->c_cl;
} else {
end = (char *)((int)bp + sizeof (struct cblock));
}
rem = end - q->c_cf;
if (cc >= rem) {
cc -= rem;
q->c_cc -= rem;
q->c_cf = bp->c_next->c_info;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
} else {
q->c_cc -= cc;
q->c_cf += cc;
if (q->c_cc <= 0) {
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
if (cwaiting) {
wakeup (&cwaiting);
cwaiting = 0;
}
}
break;
}
}
if (q->c_cc <= 0) {
q->c_cf = q->c_cl = NULL;
q->c_cc = 0;
}
out:
splx(s);
}
/*
* Put a symbol to a character list.
*/
int
putc (c, p)
register struct clist *p;
{
register struct cblock *bp;
register char *cp;
register int s;
s = spltty();
if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
if ((bp = cfreelist) == NULL) {
splx(s);
return (-1);
}
cfreelist = bp->c_next;
cfreecount -= CBSIZE;
bp->c_next = NULL;
p->c_cf = cp = bp->c_info;
} else if (((int)cp & CROUND) == 0) {
bp = (struct cblock *)cp - 1;
if ((bp->c_next = cfreelist) == NULL) {
splx(s);
return (-1);
}
bp = bp->c_next;
cfreelist = bp->c_next;
cfreecount -= CBSIZE;
bp->c_next = NULL;
cp = bp->c_info;
}
*cp++ = c;
p->c_cc++;
p->c_cl = cp;
splx(s);
return (0);
}
/*
* Copy buffer to clist.
* Return number of bytes not transfered.
*/
int
b_to_q (cp, cc, q)
register char *cp;
struct clist *q;
register int cc;
{
register char *cq;
register struct cblock *bp;
register int s, nc;
int acc;
if (cc <= 0)
return (0);
acc = cc;
s = spltty();
if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
if ((bp = cfreelist) == NULL)
goto out;
cfreelist = bp->c_next;
cfreecount -= CBSIZE;
bp->c_next = NULL;
q->c_cf = cq = bp->c_info;
}
while (cc) {
if (((int)cq & CROUND) == 0) {
bp = (struct cblock *)cq - 1;
if ((bp->c_next = cfreelist) == NULL)
goto out;
bp = bp->c_next;
cfreelist = bp->c_next;
cfreecount -= CBSIZE;
bp->c_next = NULL;
cq = bp->c_info;
}
nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND));
(void) bcopy(cp, cq, (unsigned)nc);
cp += nc;
cq += nc;
cc -= nc;
}
out:
q->c_cl = cq;
q->c_cc += acc - cc;
splx(s);
return (cc);
}
/*
* Given a non-NULL pointter into the list (like c_cf which
* always points to a real character if non-NULL) return the pointer
* to the next character in the list or return NULL if no more chars.
*
* Callers must not allow getc's to happen between nextc's so that the
* pointer becomes invalid. Note that interrupts are NOT masked.
*/
char *
nextc (p, cp)
register struct clist *p;
register char *cp;
{
register char *rcp;
if (p->c_cc && ++cp != p->c_cl) {
if (((int)cp & CROUND) == 0)
rcp = ((struct cblock *)cp)[-1].c_next->c_info;
else
rcp = cp;
} else
rcp = (char *)NULL;
return (rcp);
}
/*
* Remove the last character in the list and return it.
*/
int
unputc (p)
register struct clist *p;
{
register struct cblock *bp;
register int c, s;
struct cblock *obp;
s = spltty();
if (p->c_cc <= 0)
c = -1;
else {
c = *--p->c_cl;
if (--p->c_cc <= 0) {
bp = (struct cblock *)p->c_cl;
bp = (struct cblock *)((int)bp & ~CROUND);
p->c_cl = p->c_cf = NULL;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
} else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
p->c_cl = (char *)((int)p->c_cl & ~CROUND);
bp = (struct cblock *)p->c_cf;
bp = (struct cblock *)((int)bp & ~CROUND);
while (bp->c_next != (struct cblock *)p->c_cl)
bp = bp->c_next;
obp = bp;
p->c_cl = (char *)(bp + 1);
bp = bp->c_next;
bp->c_next = cfreelist;
cfreelist = bp;
cfreecount += CBSIZE;
obp->c_next = NULL;
}
}
splx(s);
return (c);
}
/*
* Put the chars in the from que
* on the end of the to que.
*/
void
catq (from, to)
register struct clist *from, *to;
{
char bbuf [CBSIZE*4];
register int c;
int s;
s = spltty();
if (to->c_cc == 0) {
*to = *from;
from->c_cc = 0;
from->c_cf = NULL;
from->c_cl = NULL;
splx(s);
return;
}
splx(s);
while (from->c_cc > 0) {
c = q_to_b(from, bbuf, sizeof bbuf);
(void) b_to_q(bbuf, c, to);
}
}

90
sys/kernel/tty_tty.c Normal file
View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)tty_tty.c 1.2 (2.11BSD GTE) 11/29/94
*/
/*
* Indirect driver for controlling tty.
*
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "ioctl.h"
#include "tty.h"
#include "conf.h"
const struct devspec sydevs[] = {
{ 0, "tty" },
{ 0, 0 }
};
/*ARGSUSED*/
int
syopen (dev, flag)
dev_t dev;
int flag;
{
if (u.u_ttyp == NULL)
return (ENXIO);
return((*cdevsw[major(u.u_ttyd)].d_open)(u.u_ttyd, flag, 0));
}
/*ARGSUSED*/
int
syread (dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
if (u.u_ttyp == NULL)
return (ENXIO);
return ((*cdevsw[major(u.u_ttyd)].d_read)(u.u_ttyd, uio, flag));
}
/*ARGSUSED*/
int
sywrite (dev, uio, flag)
dev_t dev;
struct uio *uio;
{
if (u.u_ttyp == NULL)
return (ENXIO);
return ((*cdevsw[major(u.u_ttyd)].d_write)(u.u_ttyd, uio, flag));
}
/*ARGSUSED*/
int
syioctl (dev, cmd, addr, flag)
dev_t dev;
u_int cmd;
caddr_t addr;
int flag;
{
if (cmd == TIOCNOTTY) {
u.u_ttyp = 0;
u.u_ttyd = 0;
u.u_procp->p_pgrp = 0;
return (0);
}
if (u.u_ttyp == NULL)
return (ENXIO);
return ((*cdevsw[major(u.u_ttyd)].d_ioctl)(u.u_ttyd, cmd, addr, flag));
}
/*ARGSUSED*/
int
syselect (dev, flag)
dev_t dev;
int flag;
{
if (u.u_ttyp == NULL) {
u.u_error = ENXIO;
return (0);
}
return ((*cdevsw[major(u.u_ttyd)].d_select)(u.u_ttyd, flag));
}

302
sys/kernel/ufs_alloc.c Normal file
View File

@@ -0,0 +1,302 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "fs.h"
#include "dir.h"
#include "inode.h"
#include "buf.h"
#include "user.h"
#include "kernel.h"
#include "mount.h"
#include "proc.h"
#include "systm.h"
typedef struct fblk *FBLKP;
/*
* Allocate a block in the file system.
*
* alloc will obtain the next available free disk block from the
* free list of the specified device. The super block has up to
* NICFREE remembered free blocks; the last of these is read to
* obtain NICFREE more...
*/
struct buf *
balloc(ip, flags)
struct inode *ip;
int flags;
{
register struct fs *fs;
register struct buf *bp;
int async;
daddr_t bno;
fs = ip->i_fs;
async = fs->fs_flags & MNT_ASYNC;
while (fs->fs_flock)
sleep((caddr_t)&fs->fs_flock, PINOD);
do {
if (fs->fs_nfree <= 0)
goto nospace;
if (fs->fs_nfree > NICFREE) {
fserr (fs, "bad free count");
goto nospace;
}
bno = fs->fs_free[--fs->fs_nfree];
if (bno == 0)
goto nospace;
} while (badblock(fs, bno));
if (fs->fs_nfree <= 0) {
fs->fs_flock++;
bp = bread(ip->i_dev, bno);
if (((bp->b_flags&B_ERROR) == 0) && (bp->b_resid==0)) {
register struct fblk *fbp;
fbp = (FBLKP) bp->b_addr;
*((FBLKP)&fs->fs_nfree) = *fbp;
}
brelse(bp);
/*
* Write the superblock back, synchronously if requested,
* so that the free list pointer won't point at garbage.
* We can still end up with dups in free if we then
* use some of the blocks in this freeblock, then crash
* without a sync.
*/
bp = getblk(ip->i_dev, SUPERB);
fs->fs_fmod = 0;
fs->fs_time = time.tv_sec;
{
register struct fs *fps;
fps = (struct fs*) bp->b_addr;
*fps = *fs;
}
if (!async)
bwrite(bp);
else
bdwrite(bp);
fs->fs_flock = 0;
wakeup((caddr_t)&fs->fs_flock);
if (fs->fs_nfree <=0)
goto nospace;
}
bp = getblk(ip->i_dev, bno);
bp->b_resid = 0;
if (flags & B_CLRBUF)
bzero (bp->b_addr, MAXBSIZE);
fs->fs_fmod = 1;
fs->fs_tfree--;
return(bp);
nospace:
fs->fs_nfree = 0;
fs->fs_tfree = 0;
fserr (fs, "file system full");
/*
* THIS IS A KLUDGE...
* SHOULD RATHER SEND A SIGNAL AND SUSPEND THE PROCESS IN A
* STATE FROM WHICH THE SYSTEM CALL WILL RESTART
*/
uprintf("\n%s: write failed, file system full\n", fs->fs_fsmnt);
{
register int i;
for (i = 0; i < 5; i++)
sleep((caddr_t)&lbolt, PRIBIO);
}
u.u_error = ENOSPC;
return(NULL);
}
/*
* Allocate an inode in the file system.
*
* Allocate an unused I node on the specified device. Used with file
* creation. The algorithm keeps up to NICINOD spare I nodes in the
* super block. When this runs out, a linear search through the I list
* is instituted to pick up NICINOD more.
*/
struct inode *
ialloc (pip)
struct inode *pip;
{
register struct fs *fs;
register struct buf *bp;
register struct inode *ip;
int i;
struct dinode *dp;
ino_t ino;
daddr_t adr;
ino_t inobas;
int first;
struct inode *ifind();
char *emsg = "no inodes free";
fs = pip->i_fs;
while (fs->fs_ilock)
sleep((caddr_t)&fs->fs_ilock, PINOD);
loop:
if (fs->fs_ninode > 0) {
ino = fs->fs_inode[--fs->fs_ninode];
if (ino <= ROOTINO)
goto loop;
ip = iget(pip->i_dev, fs, ino);
if (ip == NULL)
return(NULL);
if (ip->i_mode == 0) {
bzero((caddr_t)ip->i_addr,sizeof(ip->i_addr));
ip->i_flags = 0;
fs->fs_fmod = 1;
fs->fs_tinode--;
return(ip);
}
/*
* Inode was allocated after all.
* Look some more.
*/
iput(ip);
goto loop;
}
fs->fs_ilock++;
if (fs->fs_nbehind < 4 * NICINOD) {
first = 1;
ino = fs->fs_lasti;
#ifdef DIAGNOSTIC
if (itoo(ino))
panic("ialloc");
#endif
adr = itod(ino);
} else {
fromtop:
first = 0;
ino = 1;
adr = SUPERB+1;
fs->fs_nbehind = 0;
}
inobas = 0;
for (; adr < fs->fs_isize; adr++) {
inobas = ino;
bp = bread(pip->i_dev, adr);
if ((bp->b_flags & B_ERROR) || bp->b_resid) {
brelse(bp);
ino += INOPB;
continue;
}
dp = (struct dinode*) bp->b_addr;
for (i = 0;i < INOPB;i++) {
if (dp->di_mode != 0)
goto cont;
if (ifind(pip->i_dev, ino))
goto cont;
fs->fs_inode[fs->fs_ninode++] = ino;
if (fs->fs_ninode >= NICINOD)
break;
cont:
ino++;
dp++;
}
brelse(bp);
if (fs->fs_ninode >= NICINOD)
break;
}
if (fs->fs_ninode < NICINOD && first)
goto fromtop;
fs->fs_lasti = inobas;
fs->fs_ilock = 0;
wakeup((caddr_t)&fs->fs_ilock);
if (fs->fs_ninode > 0)
goto loop;
fserr (fs, emsg);
uprintf("\n%s: %s\n", fs->fs_fsmnt, emsg);
u.u_error = ENOSPC;
return(NULL);
}
/*
* Free a block or fragment.
*
* Place the specified disk block back on the free list of the
* specified device.
*/
void
free (ip, bno)
struct inode *ip;
daddr_t bno;
{
register struct fs *fs;
register struct buf *bp;
struct fblk *fbp;
fs = ip->i_fs;
if (badblock (fs, bno)) {
printf("bad block %D, ino %d\n", bno, ip->i_number);
return;
}
while (fs->fs_flock)
sleep((caddr_t)&fs->fs_flock, PINOD);
if (fs->fs_nfree <= 0) {
fs->fs_nfree = 1;
fs->fs_free[0] = 0;
}
if (fs->fs_nfree >= NICFREE) {
fs->fs_flock++;
bp = getblk(ip->i_dev, bno);
fbp = (FBLKP) bp->b_addr;
*fbp = *((FBLKP)&fs->fs_nfree);
fs->fs_nfree = 0;
if (fs->fs_flags & MNT_ASYNC)
bdwrite(bp);
else
bwrite(bp);
fs->fs_flock = 0;
wakeup((caddr_t)&fs->fs_flock);
}
fs->fs_free[fs->fs_nfree++] = bno;
fs->fs_tfree++;
fs->fs_fmod = 1;
}
/*
* Free an inode.
*
* Free the specified I node on the specified device. The algorithm
* stores up to NICINOD I nodes in the super block and throws away any more.
*/
void
ifree (ip, ino)
struct inode *ip;
ino_t ino;
{
register struct fs *fs;
fs = ip->i_fs;
fs->fs_tinode++;
if (fs->fs_ilock)
return;
if (fs->fs_ninode >= NICINOD) {
if (fs->fs_lasti > ino)
fs->fs_nbehind++;
return;
}
fs->fs_inode[fs->fs_ninode++] = ino;
fs->fs_fmod = 1;
}
/*
* Fserr prints the name of a file system with an error diagnostic.
*
* The form of the error message is:
* fs: error message
*/
void
fserr (fp, cp)
struct fs *fp;
char *cp;
{
printf ("%s: %s\n", fp->fs_fsmnt, cp);
}

485
sys/kernel/ufs_bio.c Normal file
View File

@@ -0,0 +1,485 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "buf.h"
#include "user.h"
#include "conf.h"
#include "fs.h"
#include "dk.h"
#include "systm.h"
#include "map.h"
#include "trace.h"
#include "proc.h"
/*
* Read in (if necessary) the block and return a buffer pointer.
*/
struct buf *
bread (dev, blkno)
dev_t dev;
daddr_t blkno;
{
register struct buf *bp;
bp = getblk(dev, blkno);
if (bp->b_flags&(B_DONE|B_DELWRI)) {
trace(TR_BREADHIT);
return (bp);
}
bp->b_flags |= B_READ;
bp->b_bcount = DEV_BSIZE; /* XXX? KB */
(*bdevsw[major(dev)].d_strategy)(bp);
trace(TR_BREADMISS);
u.u_ru.ru_inblock++; /* pay for read */
biowait(bp);
return(bp);
}
/*
* Read in the block, like bread, but also start I/O on the
* read-ahead block (which is not allocated to the caller)
*/
struct buf *
breada(dev, blkno, rablkno)
register dev_t dev;
daddr_t blkno;
daddr_t rablkno;
{
register struct buf *bp, *rabp;
bp = NULL;
/*
* If the block isn't in core, then allocate
* a buffer and initiate i/o (getblk checks
* for a cache hit).
*/
if (! incore (dev, blkno)) {
bp = getblk(dev, blkno);
if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
bp->b_flags |= B_READ;
bp->b_bcount = DEV_BSIZE; /* XXX? KB */
(*bdevsw[major(dev)].d_strategy)(bp);
trace(TR_BREADMISS);
u.u_ru.ru_inblock++; /* pay for read */
}
else
trace(TR_BREADHIT);
}
/*
* If there's a read-ahead block, start i/o
* on it also (as above).
*/
if (rablkno) {
if (! incore (dev, rablkno)) {
rabp = getblk(dev, rablkno);
if (rabp->b_flags & (B_DONE|B_DELWRI)) {
brelse(rabp);
trace(TR_BREADHITRA);
} else {
rabp->b_flags |= B_READ|B_ASYNC;
rabp->b_bcount = DEV_BSIZE; /* XXX? KB */
(*bdevsw[major(dev)].d_strategy)(rabp);
trace(TR_BREADMISSRA);
u.u_ru.ru_inblock++; /* pay in advance */
}
} else
trace(TR_BREADHITRA);
}
/*
* If block was in core, let bread get it.
* If block wasn't in core, then the read was started
* above, and just wait for it.
*/
if (bp == NULL)
return (bread(dev, blkno));
biowait(bp);
return (bp);
}
/*
* Write the buffer, waiting for completion.
* Then release the buffer.
*/
void
bwrite(bp)
register struct buf *bp;
{
register int flag;
flag = bp->b_flags;
bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
if ((flag&B_DELWRI) == 0)
u.u_ru.ru_oublock++; /* noone paid yet */
trace(TR_BWRITE);
bp->b_bcount = DEV_BSIZE; /* XXX? KB */
(*bdevsw[major(bp->b_dev)].d_strategy)(bp);
/*
* If the write was synchronous, then await i/o completion.
* If the write was "delayed", then we put the buffer on
* the q of blocks awaiting i/o completion status.
*/
if ((flag&B_ASYNC) == 0) {
biowait(bp);
brelse(bp);
} else if (flag & B_DELWRI)
bp->b_flags |= B_AGE;
}
/*
* Release the buffer, marking it so that if it is grabbed
* for another purpose it will be written out before being
* given up (e.g. when writing a partial block where it is
* assumed that another write for the same block will soon follow).
* This can't be done for magtape, since writes must be done
* in the same order as requested.
*/
void
bdwrite (bp)
register struct buf *bp;
{
if ((bp->b_flags&B_DELWRI) == 0)
u.u_ru.ru_oublock++; /* noone paid yet */
if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE) {
bawrite(bp);
}
else {
bp->b_flags |= B_DELWRI | B_DONE;
brelse(bp);
}
}
/*
* Release the buffer, with no I/O implied.
*/
void
brelse (bp)
register struct buf *bp;
{
register struct buf *flist;
register int s;
trace(TR_BRELSE);
/*
* If someone's waiting for the buffer, or
* is waiting for a buffer, wake 'em up.
*/
if (bp->b_flags&B_WANTED)
wakeup((caddr_t)bp);
if (bfreelist[0].b_flags&B_WANTED) {
bfreelist[0].b_flags &= ~B_WANTED;
wakeup((caddr_t)bfreelist);
}
if (bp->b_flags&B_ERROR) {
if (bp->b_flags & B_LOCKED)
bp->b_flags &= ~B_ERROR; /* try again later */
else
bp->b_dev = NODEV; /* no assoc */
}
/*
* Stick the buffer back on a free list.
*/
s = splbio();
if (bp->b_flags & (B_ERROR|B_INVAL)) {
/* block has no info ... put at front of most free list */
flist = &bfreelist[BQ_AGE];
binsheadfree(bp, flist);
} else {
if (bp->b_flags & B_LOCKED)
flist = &bfreelist[BQ_LOCKED];
else if (bp->b_flags & B_AGE)
flist = &bfreelist[BQ_AGE];
else
flist = &bfreelist[BQ_LRU];
binstailfree(bp, flist);
}
bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
splx(s);
}
/*
* See if the block is associated with some buffer
* (mainly to avoid getting hung up on a wait in breada)
*/
int
incore (dev, blkno)
register dev_t dev;
daddr_t blkno;
{
register struct buf *bp;
register struct buf *dp;
dp = BUFHASH(dev, blkno);
blkno = fsbtodb(blkno);
for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
if (bp->b_blkno == blkno && bp->b_dev == dev &&
(bp->b_flags & B_INVAL) == 0)
return (1);
return (0);
}
/*
* Find a buffer which is available for use.
* Select something from a free list.
* Preference is to AGE list, then LRU list.
*/
struct buf *
getnewbuf()
{
register struct buf *bp, *dp;
int s;
loop:
s = splbio();
for (dp = &bfreelist[BQ_AGE]; dp > bfreelist; dp--)
if (dp->av_forw != dp)
break;
if (dp == bfreelist) { /* no free blocks */
dp->b_flags |= B_WANTED;
sleep((caddr_t)dp, PRIBIO+1);
splx(s);
goto loop;
}
splx(s);
bp = dp->av_forw;
notavail(bp);
if (bp->b_flags & B_DELWRI) {
bawrite(bp);
goto loop;
}
if(bp->b_flags & (B_RAMREMAP|B_PHYS)) {
#ifdef DIAGNOSTIC
if ((bp < &buf[0]) || (bp >= &buf[NBUF]))
panic("getnewbuf: RAMREMAP bp addr");
#endif
bp->b_addr = bufdata + DEV_BSIZE * (bp - buf);
}
trace(TR_BRELSE);
bp->b_flags = B_BUSY;
return (bp);
}
/*
* Assign a buffer for the given block. If the appropriate
* block is already associated, return it; otherwise search
* for the oldest non-busy buffer and reassign it.
*
* We use splx here because this routine may be called
* on the interrupt stack during a dump, and we don't
* want to lower the ipl back to 0.
*/
struct buf *
getblk(dev, blkno)
register dev_t dev;
daddr_t blkno;
{
register struct buf *bp, *dp;
daddr_t dblkno;
int s;
#ifdef DIAGNOSTIC
if (major(dev) >= nblkdev)
panic("blkdev");
#endif
/*
* Search the cache for the block. If we hit, but
* the buffer is in use for i/o, then we wait until
* the i/o has completed.
*/
dp = BUFHASH(dev, blkno);
dblkno = fsbtodb(blkno);
loop:
for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
if (bp->b_blkno != dblkno || bp->b_dev != dev ||
bp->b_flags&B_INVAL)
continue;
s = splbio();
if (bp->b_flags&B_BUSY) {
bp->b_flags |= B_WANTED;
sleep((caddr_t)bp, PRIBIO+1);
splx(s);
goto loop;
}
splx(s);
notavail(bp);
return (bp);
}
bp = getnewbuf();
bfree(bp);
bremhash(bp);
binshash(bp, dp);
bp->b_dev = dev;
bp->b_blkno = dblkno;
bp->b_error = 0;
return (bp);
}
/*
* get an empty block,
* not assigned to any particular device
*/
struct buf *
geteblk()
{
register struct buf *bp, *flist;
bp = getnewbuf();
bp->b_flags |= B_INVAL;
bfree(bp);
bremhash(bp);
flist = &bfreelist[BQ_AGE];
binshash(bp, flist);
bp->b_dev = (dev_t)NODEV;
bp->b_error = 0;
return (bp);
}
/*
* Wait for I/O completion on the buffer; return errors
* to the user.
*/
void
biowait(bp)
register struct buf *bp;
{
register int s;
s = splbio();
while ((bp->b_flags & B_DONE) == 0)
sleep((caddr_t)bp, PRIBIO);
splx(s);
if (! u.u_error) /* XXX */
u.u_error = geterror(bp);
}
/*
* Mark I/O complete on a buffer.
* Wake up anyone waiting for it.
*/
void
biodone(bp)
register struct buf *bp;
{
if (bp->b_flags & B_DONE)
panic("dup biodone");
bp->b_flags |= B_DONE;
if (bp->b_flags & B_ASYNC)
brelse(bp);
else {
bp->b_flags &= ~B_WANTED;
wakeup((caddr_t)bp);
}
}
/*
* Insure that no part of a specified block is in an incore buffer.
*/
void
blkflush (dev, blkno)
register dev_t dev;
daddr_t blkno;
{
register struct buf *ep;
struct buf *dp;
register int s;
dp = BUFHASH(dev, blkno);
blkno = fsbtodb(blkno);
loop:
for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
if (ep->b_blkno != blkno || ep->b_dev != dev ||
(ep->b_flags&B_INVAL))
continue;
s = splbio();
if (ep->b_flags&B_BUSY) {
ep->b_flags |= B_WANTED;
sleep((caddr_t)ep, PRIBIO+1);
splx(s);
goto loop;
}
if (ep->b_flags & B_DELWRI) {
splx(s);
notavail(ep);
bwrite(ep);
goto loop;
}
splx(s);
}
}
/*
* Make sure all write-behind blocks on dev are flushed out.
* (from umount and sync)
*/
void
bflush(dev)
register dev_t dev;
{
register struct buf *bp;
register struct buf *flist;
int s;
loop:
s = splbio();
for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++) {
for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
if ((bp->b_flags & B_DELWRI) == 0)
continue;
if (dev == bp->b_dev) {
bp->b_flags |= B_ASYNC;
notavail(bp);
bwrite(bp);
splx(s);
goto loop;
}
}
}
splx(s);
}
/*
* Pick up the device's error number and pass it to the user;
* if there is an error but the number is 0 set a generalized code.
*/
int
geterror (bp)
register struct buf *bp;
{
register int error = 0;
if (bp->b_flags&B_ERROR)
if ((error = bp->b_error)==0)
return(EIO);
return (error);
}
/*
* Invalidate in core blocks belonging to closed or umounted filesystem
*
* This is not nicely done at all - the buffer ought to be removed from the
* hash chains & have its dev/blkno fields clobbered, but unfortunately we
* can't do that here, as it is quite possible that the block is still
* being used for i/o. Eventually, all disc drivers should be forced to
* have a close routine, which ought ensure that the queue is empty, then
* properly flush the queues. Until that happy day, this suffices for
* correctness. ... kre
*/
void
binval(dev)
register dev_t dev;
{
register struct buf *bp;
register struct bufhd *hp;
#define dp ((struct buf *)hp)
for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
if (bp->b_dev == dev)
bp->b_flags |= B_INVAL;
}

154
sys/kernel/ufs_bmap.c Normal file
View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "conf.h"
#include "dir.h"
#include "inode.h"
#include "user.h"
#include "buf.h"
#include "fs.h"
#include "mount.h"
#include "uio.h"
/*
* Bmap defines the structure of file system storage
* by returning the physical block number on a device given the
* inode and the logical block number in a file.
* When convenient, it also leaves the physical
* block number of the next block of the file in rablock
* for use in read-ahead.
*/
daddr_t
bmap(ip, bn, rwflg, flags)
register struct inode *ip;
daddr_t bn;
int rwflg, flags;
{
register int i;
register struct buf *bp;
struct buf *nbp;
int j, sh;
daddr_t nb, *bap, ra;
int async = ip->i_fs->fs_flags & MNT_ASYNC;
if (bn < 0) {
u.u_error = EFBIG;
return((daddr_t)0);
}
ra = rablock = 0;
/*
* blocks 0..NADDR-4 are direct blocks
*/
if (bn < NADDR-3) {
i = bn;
nb = ip->i_addr[i];
if (nb == 0) {
if (rwflg == B_READ || (bp = balloc(ip, flags)) == NULL)
return((daddr_t)-1);
nb = dbtofsb(bp->b_blkno);
/*
* directory blocks are usually the only thing written synchronously at this
* point (so they never appear with garbage in them on the disk). This is
* overridden if the filesystem was mounted 'async'.
*/
if (flags & B_SYNC)
bwrite(bp);
else
bdwrite(bp);
ip->i_addr[i] = nb;
ip->i_flag |= IUPD|ICHG;
}
if (i < NADDR-4)
rablock = ip->i_addr[i+1];
return(nb);
}
/*
* addresses NADDR-3, NADDR-2, and NADDR-1
* have single, double, triple indirect blocks.
* the first step is to determine
* how many levels of indirection.
*/
sh = 0;
nb = 1;
bn -= NADDR-3;
for (j = 3;j > 0;j--) {
sh += NSHIFT;
nb <<= NSHIFT;
if (bn < nb)
break;
bn -= nb;
}
if (j == 0) {
u.u_error = EFBIG;
return((daddr_t)0);
}
/*
* fetch the first indirect block
*/
nb = ip->i_addr[NADDR-j];
if (nb == 0) {
if (rwflg == B_READ || (bp = balloc(ip, flags | B_CLRBUF)) == NULL)
return((daddr_t) -1);
nb = dbtofsb(bp->b_blkno);
/*
* Write synchronously if requested so that indirect blocks
* never point at garbage.
*/
if (async)
bdwrite(bp);
else
bwrite(bp);
ip->i_addr[NADDR-j] = nb;
ip->i_flag |= IUPD|ICHG;
}
/*
* fetch through the indirect blocks
*/
for(;j <= 3;j++) {
bp = bread(ip->i_dev, nb);
if ((bp->b_flags & B_ERROR) || bp->b_resid) {
brelse(bp);
return((daddr_t)0);
}
bap = (daddr_t*) bp->b_addr;
sh -= NSHIFT;
i = (bn>>sh) & NMASK;
nb = bap[i];
/*
* calculate read-ahead
*/
if (i < NINDIR-1)
ra = bap[i+1];
if (nb == 0) {
if (rwflg == B_READ || (nbp = balloc(ip, flags | B_CLRBUF)) == NULL) {
brelse(bp);
return((daddr_t) -1);
}
nb = dbtofsb(nbp->b_blkno);
/*
* Write synchronously so indirect blocks never point at garbage and blocks
* in directories never contain garbage. This check used to be based on the
* type of inode, if it was a directory then 'sync' writes were done. See the
* comments earlier about filesystems being mounted 'async'.
*/
if (!async && (j < 3 || (flags & B_SYNC)))
bwrite(nbp);
else
bdwrite(nbp);
bap = (daddr_t*) bp->b_addr;
bap[i] = nb;
bdwrite(bp);
} else
brelse(bp);
}
rablock = ra;
return(nb);
}

84
sys/kernel/ufs_dsort.c Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)ufs_dsort.c 1.1 (2.10BSD Berkeley) 12/1/86
*/
/*
* generalized seek sort for disk
*/
#include "param.h"
#include "systm.h"
#include "buf.h"
#include "dk.h"
void
disksort (dp, bp)
register struct buf *dp, *bp;
{
register struct buf *ap;
struct buf *tp;
ap = dp->b_actf;
if (ap == NULL) {
dp->b_actf = bp;
dp->b_actl = bp;
bp->av_forw = NULL;
return;
}
tp = NULL;
for (; ap != NULL; ap = ap->av_forw) {
if ((bp->b_flags&B_READ) && (ap->b_flags&B_READ) == 0) {
if (tp == NULL)
tp = ap;
break;
}
if ((bp->b_flags&B_READ) == 0 && (ap->b_flags&B_READ))
continue;
if (ap->b_cylin <= bp->b_cylin)
if (tp == NULL || ap->b_cylin >= tp->b_cylin)
tp = ap;
}
if (tp == NULL)
tp = dp->b_actl;
bp->av_forw = tp->av_forw;
tp->av_forw = bp;
if (tp == dp->b_actl)
dp->b_actl = bp;
}
#ifdef UCB_METER
/*
* Allocate iostat disk monitoring slots for a driver. If slots already
* allocated (*dkn >= 0) or not enough slots left to satisfy request simply
* ignore it.
*/
void
dk_alloc (dkn, slots, name)
int *dkn; /* pointer to number for iostat */
int slots; /* number of iostat slots requested */
char *name; /* name of device */
{
int i;
register char **np;
register int *up;
if (*dkn < 0 && dk_n + slots <= DK_NDRIVE) {
/*
* Allocate and initialize the slots
*/
*dkn = dk_n;
np = &dk_name[dk_n];
up = &dk_unit[dk_n];
dk_n += slots;
for (i = 0; i < slots; i++) {
*np++ = name;
*up++ = i;
}
}
}
#endif /* UCB_METER */

186
sys/kernel/ufs_fio.c Normal file
View File

@@ -0,0 +1,186 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "fs.h"
#include "inode.h"
#include "mount.h"
#include "namei.h"
#include "systm.h"
#include "stat.h"
/*
* Check mode permission on inode pointer.
* Mode is READ, WRITE or EXEC.
* In the case of WRITE, the
* read-only status of the file
* system is checked.
* Also in WRITE, prototype text
* segments cannot be written.
* The mode is shifted to select
* the owner/group/other fields.
* The super user is granted all
* permissions.
*/
int
access (ip, mode)
register struct inode *ip;
int mode;
{
register int m;
register gid_t *gp;
m = mode;
if (m == IWRITE) {
if (ip->i_flags & IMMUTABLE) {
u.u_error = EPERM;
return(1);
}
/*
* Disallow write attempts on read-only
* file systems; unless the file is a block
* or character device resident on the
* file system.
*/
if (ip->i_fs->fs_ronly != 0) {
if ((ip->i_mode & IFMT) != IFCHR &&
(ip->i_mode & IFMT) != IFBLK) {
u.u_error = EROFS;
return (1);
}
}
}
/*
* If you're the super-user,
* you always get access.
*/
if (u.u_uid == 0)
return (0);
/*
* Access check is based on only
* one of owner, group, public.
* If not owner, then check group.
* If not a member of the group, then
* check public access.
*/
if (u.u_uid != ip->i_uid) {
m >>= 3;
gp = u.u_groups;
for (; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
if (ip->i_gid == *gp)
goto found;
m >>= 3;
found:
;
}
if ((ip->i_mode&m) != 0)
return (0);
u.u_error = EACCES;
return (1);
}
/* copied, for supervisory networking, to sys_net.c */
/*
* Test if the current user is the
* super user.
*/
int
suser()
{
if (u.u_uid == 0) {
return (1);
}
u.u_error = EPERM;
return (0);
}
/*
* Set the attributes on a file. This was placed here because ufs_syscalls
* is too large already (it will probably be split into two files eventually).
*/
int
ufs_setattr (ip, vap)
register struct inode *ip;
register struct vattr *vap;
{
int error;
struct timeval atimeval, mtimeval;
if (ip->i_fs->fs_ronly) /* can't change anything on a RO fs */
return(EROFS);
if (vap->va_flags != VNOVAL) {
if (u.u_uid != ip->i_uid && !suser())
return(u.u_error);
if (u.u_uid == 0) {
if ((ip->i_flags &
(SF_IMMUTABLE|SF_APPEND)) && securelevel > 0)
return(EPERM);
ip->i_flags = vap->va_flags;
} else {
if (ip->i_flags & (SF_IMMUTABLE|SF_APPEND))
return(EPERM);
ip->i_flags &= SF_SETTABLE;
ip->i_flags |= (vap->va_flags & UF_SETTABLE);
}
ip->i_flag |= ICHG;
if (vap->va_flags & (IMMUTABLE|APPEND))
return(0);
}
if (ip->i_flags & (IMMUTABLE|APPEND))
return(EPERM);
/*
* Go thru the fields (other than 'flags') and update iff not VNOVAL.
*/
if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
error = chown1 (ip, vap->va_uid, vap->va_gid);
if (error)
return(error);
}
if (vap->va_size != (off_t)VNOVAL) {
if ((ip->i_mode & IFMT) == IFDIR)
return(EISDIR);
itrunc(ip, vap->va_size, 0);
if (u.u_error)
return(u.u_error);
}
if (vap->va_atime != (time_t)VNOVAL ||
vap->va_mtime != (time_t)VNOVAL) {
if (u.u_uid != ip->i_uid && !suser() &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
access(ip, IWRITE)))
return(u.u_error);
if (vap->va_atime != (time_t)VNOVAL &&
! (ip->i_fs->fs_flags & MNT_NOATIME))
ip->i_flag |= IACC;
if (vap->va_mtime != (time_t)VNOVAL)
ip->i_flag |= (IUPD|ICHG);
atimeval.tv_sec = vap->va_atime;
mtimeval.tv_sec = vap->va_mtime;
iupdat(ip, &atimeval, &mtimeval, 1);
}
if (vap->va_mode != (mode_t)VNOVAL)
return(chmod1(ip, vap->va_mode));
return(0);
}
/*
* Check that device is mounted somewhere.
* Return EBUSY if mounted, 0 otherwise.
*/
int
ufs_mountedon (dev)
dev_t dev;
{
register struct mount *mp;
for (mp = mount; mp < &mount[NMOUNT]; mp++) {
if (mp->m_inodp == NULL)
continue;
if (mp->m_dev == dev)
return(EBUSY);
}
return(0);
}

695
sys/kernel/ufs_inode.c Normal file
View File

@@ -0,0 +1,695 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "inode.h"
#include "fs.h"
#include "mount.h"
#include "kernel.h"
#include "buf.h"
#include "systm.h"
#include "syslog.h"
#define INOHSZ 16 /* must be power of two */
#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
union ihead { /* inode LRU cache, stolen */
union ihead *ih_head[2];
struct inode *ih_chain[2];
} ihead[INOHSZ];
struct inode *ifreeh, **ifreet;
/*
* Initialize hash links for inodes
* and build inode free list.
*/
void
ihinit()
{
register int i;
register struct inode *ip = inode;
register union ihead *ih = ihead;
for (i = INOHSZ; --i >= 0; ih++) {
ih->ih_head[0] = ih;
ih->ih_head[1] = ih;
}
ifreeh = ip;
ifreet = &ip->i_freef;
ip->i_freeb = &ifreeh;
ip->i_forw = ip;
ip->i_back = ip;
for (i = NINODE; --i > 0; ) {
++ip;
ip->i_forw = ip;
ip->i_back = ip;
*ifreet = ip;
ip->i_freeb = ifreet;
ifreet = &ip->i_freef;
}
ip->i_freef = NULL;
}
/*
* Find an inode if it is incore.
*/
struct inode *
ifind(dev, ino)
register dev_t dev;
register ino_t ino;
{
register struct inode *ip;
union ihead *ih;
ih = &ihead[INOHASH(dev, ino)];
for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
if (ino == ip->i_number && dev == ip->i_dev)
return(ip);
return((struct inode *)NULL);
}
/*
* Look up an inode by device,inumber.
* If it is in core (in the inode structure),
* honor the locking protocol.
* If it is not in core, read it in from the
* specified device.
* If the inode is mounted on, perform
* the indicated indirection.
* In all cases, a pointer to a locked
* inode structure is returned.
*
* panic: no imt -- if the mounted file
* system is not in the mount table.
* "cannot happen"
*/
struct inode *
iget(dev, fs, ino)
dev_t dev;
register struct fs *fs;
ino_t ino;
{
register struct inode *ip;
union ihead *ih;
struct buf *bp;
struct dinode *dp;
loop:
ih = &ihead[INOHASH(dev, ino)];
for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
if (ino == ip->i_number && dev == ip->i_dev) {
/*
* Following is essentially an inline expanded
* copy of igrab(), expanded inline for speed,
* and so that the test for a mounted on inode
* can be deferred until after we are sure that
* the inode isn't busy.
*/
if ((ip->i_flag&ILOCKED) != 0) {
ip->i_flag |= IWANT;
sleep((caddr_t)ip, PINOD);
goto loop;
}
if ((ip->i_flag&IMOUNT) != 0) {
register struct mount *mp;
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if(mp->m_inodp == ip) {
dev = mp->m_dev;
fs = &mp->m_filsys;
ino = ROOTINO;
goto loop;
}
panic("no imt");
}
if (ip->i_count == 0) { /* ino on free list */
register struct inode *iq;
iq = ip->i_freef;
if (iq)
iq->i_freeb = ip->i_freeb;
else
ifreet = ip->i_freeb;
*ip->i_freeb = iq;
ip->i_freef = NULL;
ip->i_freeb = NULL;
}
ip->i_count++;
ip->i_flag |= ILOCKED;
return(ip);
}
ip = ifreeh;
if (ip == NULL) {
log(LOG_ERR, "inode: table full\n");
u.u_error = ENFILE;
return(NULL);
}
if (ip->i_count)
panic("free inode isn't");
{
register struct inode *iq;
iq = ip->i_freef;
if (iq)
iq->i_freeb = &ifreeh;
ifreeh = iq;
}
ip->i_freef = NULL;
ip->i_freeb = NULL;
/*
* Now to take inode off the hash chain it was on
* (initially, or after an iflush, it is on a "hash chain"
* consisting entirely of itself, and pointed to by no-one,
* but that doesn't matter), and put it on the chain for
* its new (ino, dev) pair
*/
remque(ip);
insque(ip, ih);
ip->i_dev = dev;
ip->i_fs = fs;
ip->i_number = ino;
cacheinval(ip);
ip->i_flag = ILOCKED;
ip->i_count++;
ip->i_lastr = 0;
bp = bread(dev, itod(ino));
/*
* Check I/O errors
*/
if ((bp->b_flags&B_ERROR) != 0) {
brelse(bp);
/*
* the inode doesn't contain anything useful, so it would
* be misleading to leave it on its hash chain.
* 'iput' will take care of putting it back on the free list.
*/
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
/*
* we also loose its inumber, just in case (as iput
* doesn't do that any more) - but as it isn't on its
* hash chain, I doubt if this is really necessary .. kre
* (probably the two methods are interchangable)
*/
ip->i_number = 0;
iput(ip);
return(NULL);
}
dp = (struct dinode*) bp->b_addr;
dp += itoo(ino);
ip->i_ic1 = dp->di_ic1;
ip->i_flags = dp->di_flags;
ip->i_ic2 = dp->di_ic2;
bcopy(dp->di_addr, ip->i_addr, NADDR * sizeof (daddr_t));
brelse(bp);
return (ip);
}
/*
* Convert a pointer to an inode into a reference to an inode.
*
* This is basically the internal piece of iget (after the
* inode pointer is located) but without the test for mounted
* filesystems. It is caller's responsibility to check that
* the inode pointer is valid.
*/
void
igrab (ip)
register struct inode *ip;
{
while ((ip->i_flag&ILOCKED) != 0) {
ip->i_flag |= IWANT;
sleep((caddr_t)ip, PINOD);
}
if (ip->i_count == 0) { /* ino on free list */
register struct inode *iq;
iq = ip->i_freef;
if (iq)
iq->i_freeb = ip->i_freeb;
else
ifreet = ip->i_freeb;
*ip->i_freeb = iq;
ip->i_freef = NULL;
ip->i_freeb = NULL;
}
ip->i_count++;
ip->i_flag |= ILOCKED;
}
/*
* Decrement reference count of
* an inode structure.
* On the last reference,
* write the inode out and if necessary,
* truncate and deallocate the file.
*/
void
iput (ip)
register struct inode *ip;
{
#ifdef notnow
/*
* This code requires a lot of workarounds, you have to change
* lots of places to gratuitously lock just so we can unlock it.
* Not worth it. -- KB
*/
if ((ip->i_flag & ILOCKED) == 0)
panic("iput");
#endif
IUNLOCK(ip);
irele(ip);
}
void
irele (ip)
register struct inode *ip;
{
if (ip->i_count == 1) {
ip->i_flag |= ILOCKED;
if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
itrunc (ip, (u_long) 0, 0);
ip->i_mode = 0;
ip->i_rdev = 0;
ip->i_flag |= IUPD|ICHG;
ifree(ip, ip->i_number);
}
IUPDAT(ip, &time, &time, 0);
IUNLOCK(ip);
ip->i_flag = 0;
/*
* Put the inode on the end of the free list.
* Possibly in some cases it would be better to
* put the inode at the head of the free list,
* (eg: where i_mode == 0 || i_number == 0)
* but I will think about that later .. kre
* (i_number is rarely 0 - only after an i/o error in iget,
* where i_mode == 0, the inode will probably be wanted
* again soon for an ialloc, so possibly we should keep it)
*/
if (ifreeh) {
*ifreet = ip;
ip->i_freeb = ifreet;
} else {
ifreeh = ip;
ip->i_freeb = &ifreeh;
}
ip->i_freef = NULL;
ifreet = &ip->i_freef;
} else if (!(ip->i_flag & ILOCKED))
ITIMES(ip, &time, &time);
ip->i_count--;
}
/*
* Check accessed and update flags on
* an inode structure.
* If any are on, update the inode
* with the current time.
* If waitfor set, then must insure
* i/o order so wait for the write to complete.
*/
void
iupdat (ip, ta, tm, waitfor)
struct inode *ip;
struct timeval *ta, *tm;
int waitfor;
{
register struct buf *bp;
register struct dinode *dp;
register struct inode *tip = ip;
if ((tip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
return;
if (tip->i_fs->fs_ronly)
return;
bp = bread(tip->i_dev, itod(tip->i_number));
if (bp->b_flags & B_ERROR) {
brelse(bp);
return;
}
if (tip->i_flag&IACC)
tip->i_atime = ta->tv_sec;
if (tip->i_flag&IUPD)
tip->i_mtime = tm->tv_sec;
if (tip->i_flag&ICHG)
tip->i_ctime = time.tv_sec;
tip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
dp = (struct dinode*) bp->b_addr + itoo (tip->i_number);
dp->di_ic1 = tip->i_ic1;
dp->di_flags = tip->i_flags;
dp->di_ic2 = tip->i_ic2;
bcopy(ip->i_addr, dp->di_addr, NADDR * sizeof (daddr_t));
if (waitfor && ((ip->i_fs->fs_flags & MNT_ASYNC) == 0))
bwrite(bp);
else
bdwrite(bp);
}
#define SINGLE 0 /* index of single indirect block */
#define DOUBLE 1 /* index of double indirect block */
#define TRIPLE 2 /* index of triple indirect block */
static void
trsingle (ip, bp, last, aflags)
register struct inode *ip;
struct buf *bp;
daddr_t last;
int aflags;
{
register const daddr_t *bstart, *bstop;
const daddr_t *blarray = (const daddr_t*) bp->b_addr;
bstart = &blarray[NINDIR - 1];
bstop = &blarray[last];
for (; bstart > bstop; --bstart)
if (*bstart)
free (ip, *bstart);
}
/*
* Release blocks associated with the inode ip and
* stored in the indirect block bn. Blocks are free'd
* in LIFO order up to (but not including) lastbn. If
* level is greater than SINGLE, the block is an indirect
* block and recursive calls to indirtrunc must be used to
* cleanse other indirect blocks.
*
* NB: triple indirect blocks are untested.
*/
void
indirtrunc (ip, bn, lastbn, level, aflags)
struct inode *ip;
daddr_t bn, lastbn;
int level;
int aflags;
{
register struct buf *bp;
daddr_t nb, last;
long factor;
/*
* Calculate index in current block of last
* block to be kept. -1 indicates the entire
* block so we need not calculate the index.
*/
switch (level) {
default:
case SINGLE:
factor = 1;
break;
case DOUBLE:
factor = NINDIR;
break;
case TRIPLE:
factor = NINDIR * NINDIR;
break;
}
last = lastbn;
if (lastbn > 0)
last = last / factor;
/*
* Get buffer of block pointers, zero those
* entries corresponding to blocks to be free'd,
* and update on disk copy first.
*/
{
register daddr_t *bap;
register struct buf *cpy;
bp = bread(ip->i_dev, bn);
if (bp->b_flags&B_ERROR) {
brelse(bp);
return;
}
cpy = geteblk();
bcopy (bp->b_addr, cpy->b_addr, DEV_BSIZE);
bap = (daddr_t*) bp->b_addr;
bzero((caddr_t)&bap[last + 1],
(u_int)(NINDIR - (last + 1)) * sizeof(daddr_t));
if (aflags & B_SYNC)
bwrite(bp);
else
bawrite(bp);
bp = cpy;
}
/*
* Optimized for single indirect blocks, i.e. until a file is
* greater than 4K + 256K you don't have to do a mapin/mapout
* for every entry. The mapin/mapout is required since free()
* may have to map an item in. Have to use another routine
* since it requires 1K of kernel stack to get around the problem
* and that doesn't work well with recursion.
*/
if (level == SINGLE)
trsingle (ip, bp, last, aflags);
else {
register daddr_t *bstart, *bstop;
bstart = (daddr_t*) bp->b_addr;
bstop = &bstart[last];
bstart += NINDIR - 1;
/*
* Recursively free totally unused blocks.
*/
for (;bstart > bstop;--bstart) {
nb = *bstart;
if (nb) {
indirtrunc(ip,nb,(daddr_t)-1, level-1, aflags);
free(ip, nb);
}
}
/*
* Recursively free last partial block.
*/
if (lastbn >= 0) {
nb = *bstop;
last = lastbn % factor;
if (nb != 0)
indirtrunc(ip, nb, last, level - 1, aflags);
}
}
brelse(bp);
}
/*
* Truncate the inode ip to at most
* length size. Free affected disk
* blocks -- the blocks of the file
* are removed in reverse order.
*
* NB: triple indirect blocks are untested.
*/
void
itrunc (oip, length, ioflags)
register struct inode *oip;
u_long length;
int ioflags;
{
daddr_t lastblock;
register int i;
register struct inode *ip;
daddr_t bn, lastiblock[NIADDR];
struct buf *bp;
int offset, level;
struct inode tip;
int aflags;
aflags = B_CLRBUF;
if (ioflags & IO_SYNC)
aflags |= B_SYNC;
/*
* special hack for pipes, since size for them isn't the size of
* the file, it's the amount currently waiting for transfer. It's
* unclear that this will work, though, because pipes can (although
* rarely do) get bigger than MAXPIPSIZ. Don't think it worked
* in V7 either, I don't really understand what's going on.
*/
if (oip->i_flag & IPIPE)
oip->i_size = MAXPIPSIZ;
else if (oip->i_size == length)
goto updret;
/*
* Lengthen the size of the file. We must ensure that the
* last byte of the file is allocated. Since the smallest
* value of osize is 0, length will be at least 1.
*/
if (oip->i_size < length) {
bn = bmap(oip, lblkno(length - 1), B_WRITE, aflags);
if (u.u_error || bn < 0)
return;
oip->i_size = length;
goto doquotaupd;
}
/*
* Calculate index into inode's block list of
* last direct and indirect blocks (if any)
* which we want to keep. Lastblock is -1 when
* the file is truncated to 0.
*/
lastblock = lblkno(length + DEV_BSIZE - 1) - 1;
lastiblock[SINGLE] = lastblock - NDADDR;
lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR;
lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR * NINDIR;
/*
* Update the size of the file. If the file is not being
* truncated to a block boundry, the contents of the
* partial block following the end of the file must be
* zero'ed in case it ever become accessable again because
* of subsequent file growth.
*/
offset = blkoff(length);
if (offset) {
bn = bmap(oip, lblkno(length), B_WRITE, aflags);
if (u.u_error || bn < 0)
return;
bp = bread(oip->i_dev, bn);
if (bp->b_flags & B_ERROR) {
u.u_error = EIO;
brelse(bp);
return;
}
bzero (bp->b_addr + offset, (u_int) (DEV_BSIZE - offset));
bdwrite(bp);
}
/*
* Update file and block pointers
* on disk before we start freeing blocks.
* If we crash before free'ing blocks below,
* the blocks will be returned to the free list.
* lastiblock values are also normalized to -1
* for calls to indirtrunc below.
*/
tip = *oip;
oip->i_size = length;
for (level = TRIPLE; level >= SINGLE; level--)
if (lastiblock[level] < 0) {
oip->i_ib[level] = 0;
lastiblock[level] = -1;
}
for (i = NDADDR - 1; i > lastblock; i--)
oip->i_db[i] = 0;
/*
* Indirect blocks first.
*/
ip = &tip;
for (level = TRIPLE; level >= SINGLE; level--) {
bn = ip->i_ib[level];
if (bn != 0) {
indirtrunc(ip, bn, lastiblock[level], level, aflags);
if (lastiblock[level] < 0) {
ip->i_ib[level] = 0;
free(ip, bn);
}
}
if (lastiblock[level] >= 0)
goto done;
}
/*
* All whole direct blocks.
*/
for (i = NDADDR - 1; i > lastblock; i--) {
bn = ip->i_db[i];
if (bn == 0)
continue;
ip->i_db[i] = 0;
free(ip, bn);
}
if (lastblock < 0)
goto done;
done:
#ifdef DIAGNOSTIC
/* BEGIN PARANOIA */
for (level = SINGLE; level <= TRIPLE; level++)
if (ip->i_ib[level] != oip->i_ib[level])
panic("itrunc1");
for (i = 0; i < NDADDR; i++)
if (ip->i_db[i] != oip->i_db[i])
panic("itrunc2");
/* END PARANOIA */
#endif
doquotaupd:
updret:
oip->i_flag |= ICHG|IUPD;
iupdat(oip, &time, &time, 1);
}
/*
* Remove any inodes in the inode cache belonging to dev.
*
* There should not be any active ones, return error if any are found
* (nb: this is a user error, not a system err)
*
* Also, count the references to dev by block devices - this really
* has nothing to do with the object of the procedure, but as we have
* to scan the inode table here anyway, we might as well get the
* extra benefit.
*
* this is called from sumount() when dev is being unmounted
*/
int
iflush (dev)
dev_t dev;
{
register struct inode *ip;
register int open = 0;
for (ip = inode; ip < inode+NINODE; ip++) {
if (ip->i_dev == dev)
if (ip->i_count)
return(-1);
else {
remque(ip);
ip->i_forw = ip;
ip->i_back = ip;
/*
* as i_count == 0, the inode was on the free
* list already, just leave it there, it will
* fall off the bottom eventually. We could
* perhaps move it to the head of the free
* list, but as umounts are done so
* infrequently, we would gain very little,
* while making the code bigger.
*/
}
else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
ip->i_rdev == dev)
open++;
}
return (open);
}
/*
* Lock an inode. If its already locked, set the WANT bit and sleep.
*/
void
ilock(ip)
register struct inode *ip;
{
ILOCK(ip);
}
/*
* Unlock an inode. If WANT bit is on, wakeup.
*/
void
iunlock(ip)
register struct inode *ip;
{
IUNLOCK(ip);
}

301
sys/kernel/ufs_mount.c Normal file
View File

@@ -0,0 +1,301 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "systm.h"
#include "user.h"
#include "inode.h"
#include "fs.h"
#include "buf.h"
#include "mount.h"
#include "file.h"
#include "namei.h"
#include "conf.h"
#include "stat.h"
#include "ioctl.h"
#include "proc.h"
/*
* Common code for mount and umount.
* Check that the user's argument is a reasonable
* thing on which to mount, otherwise return error.
*/
static int
getmdev (pdev, fname)
caddr_t fname;
dev_t *pdev;
{
register dev_t dev;
register struct inode *ip;
struct nameidata nd;
register struct nameidata *ndp = &nd;
if (!suser())
return (u.u_error);
NDINIT (ndp, LOOKUP, FOLLOW, fname);
ip = namei(ndp);
if (ip == NULL) {
if (u.u_error == ENOENT)
return (ENODEV); /* needs translation */
return (u.u_error);
}
if ((ip->i_mode&IFMT) != IFBLK) {
iput(ip);
return (ENOTBLK);
}
dev = (dev_t)ip->i_rdev;
iput(ip);
if (major(dev) >= nblkdev)
return (ENXIO);
*pdev = dev;
return (0);
}
void
mount_updname (fs, on, from, lenon, lenfrom)
struct fs *fs;
char *on, *from;
int lenon, lenfrom;
{
struct mount *mp;
bzero (fs->fs_fsmnt, sizeof (fs->fs_fsmnt));
bcopy (on, fs->fs_fsmnt, sizeof (fs->fs_fsmnt) - 1);
mp = (struct mount*) ((int) fs - offsetof (struct mount, m_filsys));
bzero (mp->m_mnton, sizeof (mp->m_mnton));
bzero (mp->m_mntfrom, sizeof (mp->m_mntfrom));
bcopy (on, mp->m_mnton, lenon);
bcopy (from, mp->m_mntfrom, lenfrom);
}
void
smount()
{
register struct a {
char *fspec;
char *freg;
int flags;
} *uap = (struct a *)u.u_arg;
dev_t dev = 0;
register struct inode *ip;
register struct fs *fs;
struct nameidata nd;
struct nameidata *ndp = &nd;
struct mount *mp;
u_int lenon, lenfrom;
int error = 0;
char mnton[MNAMELEN], mntfrom[MNAMELEN];
u.u_error = getmdev (&dev, uap->fspec);
if (u.u_error)
return;
NDINIT (ndp, LOOKUP, FOLLOW, uap->freg);
if ((ip = namei(ndp)) == NULL)
return;
if ((ip->i_mode&IFMT) != IFDIR) {
error = ENOTDIR;
goto cmnout;
}
copystr (uap->freg, mnton, sizeof (mnton) - 1, &lenon);
copystr (uap->fspec, mntfrom, sizeof (mntfrom) - 1, &lenfrom);
if (uap->flags & MNT_UPDATE) {
fs = ip->i_fs;
mp = (struct mount *)
((int)fs - offsetof(struct mount, m_filsys));
if (ip->i_number != ROOTINO) {
error = EINVAL; /* Not a mount point */
goto cmnout;
}
/*
* Check that the device passed in is the same one that is in the mount
* table entry for this mount point.
*/
if (dev != mp->m_dev) {
error = EINVAL; /* not right mount point */
goto cmnout;
}
/*
* This is where the RW to RO transformation would be done. It is, for now,
* too much work to port pages of code to do (besides which most
* programs get very upset at having access yanked out from under them).
*/
if (fs->fs_ronly == 0 && (uap->flags & MNT_RDONLY)) {
error = EPERM; /* ! RW to RO updates */
goto cmnout;
}
/*
* However, going from RO to RW is easy. Then merge in the new
* flags (async, sync, nodev, etc) passed in from the program.
*/
if (fs->fs_ronly && ((uap->flags & MNT_RDONLY) == 0)) {
fs->fs_ronly = 0;
mp->m_flags &= ~MNT_RDONLY;
}
#define _MF (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC | MNT_ASYNC | MNT_SYNCHRONOUS | MNT_NOATIME)
mp->m_flags &= ~_MF;
mp->m_flags |= (uap->flags & _MF);
#undef _MF
iput(ip);
u.u_error = 0;
goto updname;
} else {
/*
* This is where a new mount (not an update of an existing mount point) is
* done.
*
* The directory being mounted on can have no other references AND can not
* currently be a mount point. Mount points have an inode number of (you
* guessed it) ROOTINO which is 2.
*/
if (ip->i_count != 1 || (ip->i_number == ROOTINO)) {
error = EBUSY;
goto cmnout;
}
fs = mountfs (dev, uap->flags, ip);
if (fs == 0)
return;
}
/*
* Lastly, both for new mounts and updates of existing mounts, update the
* mounted-on and mounted-from fields.
*/
updname:
mount_updname(fs, mnton, mntfrom, lenon, lenfrom);
return;
cmnout:
iput(ip);
u.u_error = error;
}
/*
* Mount a filesystem on the given directory inode.
*
* this routine has races if running twice
*/
struct fs *
mountfs (dev, flags, ip)
dev_t dev;
int flags;
struct inode *ip;
{
register struct mount *mp = 0;
struct buf *tp = 0;
register struct fs *fs;
register int error;
int ronly = flags & MNT_RDONLY;
int needclose = 0;
error = (*bdevsw[major(dev)].d_open) (dev,
ronly ? FREAD : (FREAD | FWRITE), S_IFBLK);
if (error)
goto out;
needclose = 1;
tp = bread (dev, SUPERB);
if (tp->b_flags & B_ERROR)
goto out;
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if (mp->m_inodp != 0 && dev == mp->m_dev) {
mp = 0;
error = EBUSY;
needclose = 0;
goto out;
}
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if (mp->m_inodp == 0)
goto found;
mp = 0;
error = EMFILE; /* needs translation */
goto out;
found:
mp->m_inodp = ip; /* reserve slot */
mp->m_dev = dev;
fs = &mp->m_filsys;
bcopy (tp->b_addr, (caddr_t)fs, sizeof(struct fs));
brelse (tp);
tp = 0;
if (fs->fs_magic1 != FSMAGIC1 || fs->fs_magic2 != FSMAGIC2) {
error = EINVAL;
goto out;
}
fs->fs_ronly = (ronly != 0);
if (ronly == 0)
fs->fs_fmod = 1;
fs->fs_ilock = 0;
fs->fs_flock = 0;
fs->fs_nbehind = 0;
fs->fs_lasti = 1;
fs->fs_flags = flags;
if (ip) {
ip->i_flag |= IMOUNT;
cacheinval(ip);
IUNLOCK(ip);
}
return (fs);
out:
if (error == 0)
error = EIO;
if (ip)
iput(ip);
if (mp)
mp->m_inodp = 0;
if (tp)
brelse(tp);
if (needclose) {
(*bdevsw[major(dev)].d_close)(dev,
ronly? FREAD : FREAD|FWRITE, S_IFBLK);
binval(dev);
}
u.u_error = error;
return (0);
}
static int
unmount1 (fname)
caddr_t fname;
{
dev_t dev = 0;
register struct mount *mp;
register struct inode *ip;
register int error;
int aflag;
error = getmdev(&dev, fname);
if (error)
return (error);
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
if (mp->m_inodp != NULL && dev == mp->m_dev)
goto found;
return (EINVAL);
found:
nchinval (dev); /* flush the name cache */
aflag = mp->m_flags & MNT_ASYNC;
mp->m_flags &= ~MNT_ASYNC; /* Don't want async when unmounting */
ufs_sync(mp);
if (iflush(dev) < 0) {
mp->m_flags |= aflag;
return (EBUSY);
}
ip = mp->m_inodp;
ip->i_flag &= ~IMOUNT;
irele(ip);
mp->m_inodp = 0;
mp->m_dev = 0;
(*bdevsw[major(dev)].d_close)(dev, 0, S_IFBLK);
binval(dev);
return (0);
}
void
umount()
{
struct a {
char *fspec;
} *uap = (struct a *)u.u_arg;
u.u_error = unmount1 (uap->fspec);
}

1258
sys/kernel/ufs_namei.c Normal file

File diff suppressed because it is too large Load Diff

145
sys/kernel/ufs_subr.c Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "fs.h"
#include "inode.h"
#include "buf.h"
#include "mount.h"
#include "kernel.h"
#include "systm.h"
int updlock; /* lock for sync */
/*
* Go through the mount table looking for filesystems which have been modified.
* For each "dirty" filesystem call 'ufs_sync' to flush changed inodes, data
* blocks and the superblock to disc.
*/
void
sync()
{
register struct mount *mp;
register struct fs *fs;
int async;
if (updlock)
return;
updlock++;
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
if (mp->m_inodp == NULL || mp->m_dev == NODEV)
continue;
fs = &mp->m_filsys;
if (fs->fs_fmod == 0 || fs->fs_ilock || fs->fs_flock)
continue;
async = mp->m_flags & MNT_ASYNC;
mp->m_flags &= ~MNT_ASYNC;
ufs_sync(mp);
mp->m_flags |= async;
}
updlock = 0;
}
/*
* Flush all the blocks associated with an inode.
* There are two strategies based on the size of the file;
* large files are those with more than NBUF/2 blocks.
* Large files
* Walk through the buffer pool and push any dirty pages
* associated with the device on which the file resides.
* Small files
* Look up each block in the file to see if it is in the
* buffer pool writing any that are found to disk.
* Note that we make a more stringent check of
* writing out any block in the buffer pool that may
* overlap the inode. This brings the inode up to
* date with recent mods to the cooked device.
*/
void
syncip(ip)
struct inode *ip;
{
register struct buf *bp;
register struct buf *lastbufp;
long lbn, lastlbn;
register int s;
daddr_t blkno;
lastlbn = howmany(ip->i_size, DEV_BSIZE);
if (lastlbn < NBUF / 2) {
for (lbn = 0; lbn < lastlbn; lbn++) {
blkno = fsbtodb(bmap(ip, lbn, B_READ, 0));
blkflush(ip->i_dev, blkno);
}
} else {
lastbufp = &buf[NBUF];
for (bp = buf; bp < lastbufp; bp++) {
if (bp->b_dev != ip->i_dev ||
(bp->b_flags & B_DELWRI) == 0)
continue;
s = splbio();
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
sleep((caddr_t)bp, PRIBIO+1);
splx(s);
bp--;
continue;
}
splx(s);
notavail(bp);
bwrite(bp);
}
}
ip->i_flag |= ICHG;
iupdat(ip, &time, &time, 1);
}
/*
* Check that a specified block number is in range.
*/
int
badblock (fp, bn)
register struct fs *fp;
daddr_t bn;
{
if (bn < fp->fs_isize || bn >= fp->fs_fsize) {
printf("bad block %D, ",bn);
fserr(fp, "bad block");
return (1);
}
return (0);
}
/*
* Getfs maps a device number into a pointer to the incore super block.
*
* The algorithm is a linear search through the mount table. A
* consistency check of the super block magic number is performed.
*
* panic: no fs -- the device is not mounted.
* this "cannot happen"
*/
struct fs *
getfs(dev)
dev_t dev;
{
register struct mount *mp;
register struct fs *fs;
for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
if (mp->m_inodp == NULL || mp->m_dev != dev)
continue;
fs = &mp->m_filsys;
if (fs->fs_nfree > NICFREE || fs->fs_ninode > NICINOD) {
fserr(fs, "bad count");
fs->fs_nfree = fs->fs_ninode = 0;
}
return(fs);
}
printf("no fs on dev %u/%u\n",major(dev), minor(dev));
return((struct fs *) NULL);
}

1338
sys/kernel/ufs_syscalls.c Normal file

File diff suppressed because it is too large Load Diff

279
sys/kernel/ufs_syscalls2.c Normal file
View File

@@ -0,0 +1,279 @@
/*
* ufs_syscalls was getting too large. Various UFS related system calls were
* relocated to this file.
*/
#include "param.h"
#include "sys/file.h"
#include "user.h"
#include "inode.h"
#include "buf.h"
#include "fs.h"
#include "namei.h"
#include "mount.h"
#include "kernel.h"
#include "systm.h"
#include "proc.h"
static int
statfs1 (mp, sbp)
struct mount *mp;
struct statfs *sbp;
{
struct statfs sfs;
register struct statfs *sfsp;
struct fs *fs = &mp->m_filsys;
sfsp = &sfs;
sfsp->f_type = MOUNT_UFS;
sfsp->f_bsize = MAXBSIZE;
sfsp->f_iosize = MAXBSIZE;
sfsp->f_blocks = fs->fs_fsize - fs->fs_isize;
sfsp->f_bfree = fs->fs_tfree;
sfsp->f_bavail = fs->fs_tfree;
sfsp->f_files = (fs->fs_isize - 1) * INOPB;
sfsp->f_ffree = fs->fs_tinode;
bcopy (mp->m_mnton, sfsp->f_mntonname, MNAMELEN);
bcopy (mp->m_mntfrom, sfsp->f_mntfromname, MNAMELEN);
sfsp->f_flags = mp->m_flags & MNT_VISFLAGMASK;
return copyout ((caddr_t) sfsp, (caddr_t) sbp, sizeof (struct statfs));
}
void
statfs()
{
register struct a {
char *path;
struct statfs *buf;
} *uap = (struct a *)u.u_arg;
register struct inode *ip;
struct nameidata nd;
register struct nameidata *ndp = &nd;
struct mount *mp;
NDINIT (ndp, LOOKUP, FOLLOW, uap->path);
ip = namei(ndp);
if (! ip)
return;
mp = (struct mount *)((int)ip->i_fs - offsetof(struct mount, m_filsys));
iput(ip);
u.u_error = statfs1 (mp, uap->buf);
}
void
fstatfs()
{
register struct a {
int fd;
struct statfs *buf;
} *uap = (struct a *)u.u_arg;
register struct inode *ip;
struct mount *mp;
ip = getinode(uap->fd);
if (! ip)
return;
mp = (struct mount *)((int)ip->i_fs - offsetof(struct mount, m_filsys));
u.u_error = statfs1 (mp, uap->buf);
}
void
getfsstat()
{
register struct a {
struct statfs *buf;
int bufsize;
u_int flags;
} *uap = (struct a *)u.u_arg;
register struct mount *mp;
caddr_t sfsp;
int count, maxcount, error;
maxcount = uap->bufsize / sizeof (struct statfs);
sfsp = (caddr_t)uap->buf;
count = 0;
for (mp = mount; mp < &mount[NMOUNT]; mp++) {
if (mp->m_inodp == NULL)
continue;
if (count < maxcount) {
error = statfs1 (mp, sfsp);
if (error) {
u.u_error = error;
return;
}
sfsp += sizeof (struct statfs);
}
count++;
}
if (sfsp && count > maxcount)
u.u_rval = maxcount;
else
u.u_rval = count;
}
/*
* This is somewhat inefficient in that the inode table is scanned for each
* filesystem but it didn't seem worth a page or two of code on something
* which only happens every 30 seconds.
*/
static void
syncinodes(fs)
struct fs *fs;
{
register struct inode *ip;
/*
* Write back each (modified) inode.
*/
for (ip = inode; ip < inode+NINODE; ip++) {
/*
* Attempt to reduce the overhead by short circuiting the scan if the
* inode is not for the filesystem being processed.
*/
if (ip->i_fs != fs)
continue;
if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 ||
(ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
continue;
ip->i_flag |= ILOCKED;
ip->i_count++;
iupdat(ip, &time, &time, 0);
iput(ip);
}
}
/*
* 'ufs_sync' is the routine which syncs a single filesystem. This was
* created to replace 'update' which 'unmount' called. It seemed silly to
* sync _every_ filesystem when unmounting just one filesystem.
*/
int
ufs_sync(mp)
register struct mount *mp;
{
register struct fs *fs;
struct buf *bp;
int error = 0;
fs = &mp->m_filsys;
if (fs->fs_fmod && (mp->m_flags & MNT_RDONLY)) {
printf("fs = %s\n", fs->fs_fsmnt);
panic("sync: rofs");
}
syncinodes(fs); /* sync the inodes for this filesystem */
bflush(mp->m_dev); /* flush dirty data blocks */
/*
* And lastly the superblock, if the filesystem was modified.
* Write back modified superblocks. Consistency check that the superblock
* of each file system is still in the buffer cache.
*/
if (fs->fs_fmod) {
bp = getblk(mp->m_dev, SUPERB);
fs->fs_fmod = 0;
fs->fs_time = time.tv_sec;
bcopy(fs, bp->b_addr, sizeof (struct fs));
bwrite(bp);
error = geterror(bp);
}
return(error);
}
/*
* mode mask for creation of files
*/
void
umask()
{
register struct a {
int mask;
} *uap = (struct a *)u.u_arg;
u.u_rval = u.u_cmask;
u.u_cmask = uap->mask & 07777;
}
/*
* Seek system call
*/
void
lseek()
{
register struct file *fp;
register struct a {
int fd;
off_t off;
int sbase;
} *uap = (struct a *)u.u_arg;
if ((fp = getf(uap->fd)) == NULL)
return;
if (fp->f_type != DTYPE_INODE) {
u.u_error = ESPIPE;
return;
}
switch (uap->sbase) {
case L_INCR:
fp->f_offset += uap->off;
break;
case L_XTND:
fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
break;
case L_SET:
fp->f_offset = uap->off;
break;
default:
u.u_error = EINVAL;
return;
}
u.u_rval = fp->f_offset;
}
/*
* Synch an open file.
*/
void
fsync()
{
register struct a {
int fd;
} *uap = (struct a *)u.u_arg;
register struct inode *ip;
if ((ip = getinode(uap->fd)) == NULL)
return;
ilock(ip);
syncip(ip);
iunlock(ip);
}
void
utimes()
{
register struct a {
char *fname;
struct timeval *tptr;
} *uap = (struct a *)u.u_arg;
register struct inode *ip;
struct nameidata nd;
register struct nameidata *ndp = &nd;
struct timeval tv[2];
struct vattr vattr;
VATTR_NULL(&vattr);
if (uap->tptr == NULL) {
tv[0].tv_sec = tv[1].tv_sec = time.tv_sec;
vattr.va_vaflags |= VA_UTIMES_NULL;
} else {
u.u_error = copyin ((caddr_t)uap->tptr,(caddr_t)tv,sizeof(tv));
if (u.u_error)
return;
}
NDINIT (ndp, LOOKUP, FOLLOW, uap->fname);
if ((ip = namei(ndp)) == NULL)
return;
vattr.va_atime = tv[0].tv_sec;
vattr.va_mtime = tv[1].tv_sec;
u.u_error = ufs_setattr(ip, &vattr);
iput(ip);
}

212
sys/kernel/vfs_vnops.c Normal file
View File

@@ -0,0 +1,212 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/file.h>
#include <sys/user.h>
#include <sys/namei.h>
#include <sys/inode.h>
#include <sys/stat.h>
#include "systm.h"
/*
* 2.11BSD does not have "vnodes", having instead only old fashioned "inodes".
* The routine names (i.e. vn_open) were retained since the functions them-
* selves were ported over with minimal change. Retaining the 4.4 function
* names also makes it easier to follow the logic flow when reading the 4.4
* sources. Also, changing the names from vn_* to in_* could have caused
* confusion with the networking routines since 'in_' and 'ip_' are frequently
* used in the networking code.
*
* The tab spacing has been altered to be (to me) more readable.
*/
/*
* Common code for vnode open operations.
* Check permissions, and call the VOP_OPEN (openi for 2.11) or VOP_CREATE
* (maknode) routine.
*/
int
vn_open (ndp, fmode, cmode)
register struct nameidata *ndp;
int fmode, cmode;
{
register struct inode *ip;
register int error;
if (fmode & O_CREAT) {
if ((fmode & O_EXCL) == 0)
ndp->ni_nameiop |= (CREATE|FOLLOW);
else
ndp->ni_nameiop = CREATE;
ip = namei(ndp);
if (ip == NULL) {
if (u.u_error) {
goto retuerr;
}
ip = maknode(cmode, ndp);
if (ip == NULL) {
goto retuerr;
}
fmode &= ~O_TRUNC;
} else {
if (fmode & O_EXCL) {
error = EEXIST;
goto bad;
}
fmode &= ~O_CREAT;
}
} else {
ndp->ni_nameiop = LOOKUP | FOLLOW;
ip = namei(ndp);
if (ip == NULL) {
goto retuerr;
}
}
if ((ip->i_mode & IFMT) == IFSOCK) {
error = EOPNOTSUPP;
goto bad;
}
if ((ip->i_flags & APPEND) && (fmode&(FWRITE|O_APPEND)) == FWRITE) {
error = EPERM;
goto bad;
}
if ((fmode & O_CREAT) == 0) {
if (fmode & FREAD) {
if (access(ip, IREAD)) {
error = u.u_error; /* XXX */
goto bad;
}
}
if (fmode & (FWRITE | O_TRUNC)) {
if ((ip->i_mode & IFMT) == IFDIR) {
error = EISDIR;
goto bad;
}
if (access(ip, IWRITE)) {
error = u.u_error;
goto bad;
}
}
}
if (fmode & O_TRUNC)
itrunc(ip, (off_t)0, fmode & O_FSYNC ? IO_SYNC : 0);
/*
* 4.4 returns the vnode locked from vn_open which means that each caller
* has to go and unlock it.
*
* 2.11 returns the inode unlocked (for now).
*/
iunlock(ip); /* because namei returns a locked inode */
if (setjmp(&u.u_qsave)) {
error = EINTR; /* opens are not restarted after signals */
goto lbad;
}
error = openi (ip, fmode);
if (error) {
goto lbad;
}
return(0);
/*
* Gratuitous lock but it does (correctly) implement the earlier behaviour of
* copen (it also avoids a panic in iput).
*/
lbad:
ilock(ip);
bad:
/*
* Do NOT do an 'ilock' here - this tag is to be used only when the inode is
* locked (i.e. from namei).
*/
iput(ip);
return(error);
retuerr:
return(u.u_error); /* XXX - Bletch */
}
/*
* Inode close call. Pipes and sockets do NOT enter here. This routine is
* used by the kernel to close files it opened for itself.
* The kernel does not create sockets or pipes on its own behalf.
*
* The difference between this routine and vn_closefile below is that vn_close
* takes an "inode *" as a first argument and is passed the flags by the caller
* while vn_closefile (called from the closef routine for DTYPE_INODE inodes)
* takes a "file *" and extracts the flags from the file structure.
*/
int
vn_close(ip, flags)
register struct inode *ip;
int flags;
{
register int error;
error = closei(ip, flags);
irele(ip); /* assumes inode is unlocked */
return(error);
}
/*
* File table inode close routine. This is called from 'closef()' via the
* "Fops" table (the 'inodeops' entry).
*
* NOTE: pipes are a special case of inode and have their own 'pipe_close'
* entry in the 'pipeops' table. See sys_pipe.c for pipe_close().
*
* In 4.4BSD this routine called vn_close() but since 2.11 does not do the
* writecheck counting we can skip the overhead of nesting another level down
* and call closei() and irele() ourself.
*/
int
vn_closefile(fp)
register struct file *fp;
{
register struct inode *ip = (struct inode *)fp->f_data;
/*
* Need to clear the inode pointer in the file structure so that the
* inode is not seen during the scan for aliases of character or block
* devices in closei().
*/
fp->f_data = (caddr_t)0; /* XXX */
irele(ip);
return (closei(ip, fp->f_flag));
}

262
sys/kernel/vm_sched.c Normal file
View File

@@ -0,0 +1,262 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "vm.h"
#include "kernel.h"
#include "systm.h"
#include "debug.h"
#define MINFINITY -32767 /* minus infinity */
int maxslp = MAXSLP;
char runin; /* scheduling flag */
char runout; /* scheduling flag */
/*
* The main loop of the scheduling (swapping) process.
* The basic idea is:
* see if anyone wants to be swapped in
* swap out processes until there is room
* swap him in
* repeat
* The runout flag is set whenever someone is swapped out. Sched sleeps on
* it awaiting work. Sched sleeps on runin whenever it cannot find enough
* core (by swapping out or otherwise) to fit the selected swapped process.
* It is awakened when the core situation changes and in any case once per
* second.
*/
void
sched()
{
register struct proc *rp;
struct proc *swapped_out = 0, *in_core = 0;
register int out_time, rptime;
int s __attribute__((unused));
for (;;) {
/* Perform swap-out/swap-in action. */
s=spl0();
if (in_core)
swapout (in_core, X_FREECORE, X_OLDSIZE, X_OLDSIZE);
if (swapped_out)
swapin (swapped_out);
s=splhigh();
in_core = 0;
swapped_out = 0;
/* Find user to swap in; of users ready,
* select one out longest. */
out_time = -20000;
for (rp = allproc; rp; rp = rp->p_nxt) {
if (rp->p_stat != SRUN || (rp->p_flag & SLOAD))
continue;
rptime = rp->p_time - rp->p_nice * 8;
/*
* Always bring in parents ending a vfork,
* to avoid deadlock
*/
if (rptime > out_time || (rp->p_flag & SVFPRNT)) {
swapped_out = rp;
out_time = rptime;
if (rp->p_flag & SVFPRNT)
break;
}
}
/* If there is no one there, wait. */
if (! swapped_out) {
++runout;
//SETVAL(0);
sleep ((caddr_t) &runout, PSWP);
continue;
}
//SETVAL(swapped_out->p_pid);
/*
* Look around for somebody to swap out.
* There may be only one non-system loaded process.
*/
for (rp = allproc; rp != NULL; rp = rp->p_nxt) {
if (rp->p_stat != SZOMB &&
(rp->p_flag & (SSYS | SLOAD)) == SLOAD) {
in_core = rp;
break;
}
}
if (! in_core) {
/* In-core memory is empty. */
continue;
}
/*
* Swap found user out if sleeping interruptibly, or if he has spent at
* least 1 second in core and the swapped-out process has spent at
* least 2 seconds out. Otherwise wait a bit and try again.
*/
if (! (in_core->p_flag & SLOCK) &&
(in_core->p_stat == SSTOP ||
(in_core->p_stat == SSLEEP && (in_core->p_flag & P_SINTR)) ||
((in_core->p_stat == SRUN || in_core->p_stat == SSLEEP) &&
out_time >= 2 &&
in_core->p_time + in_core->p_nice >= 1)))
{
/* Swap out in-core process. */
in_core->p_flag &= ~SLOAD;
if (in_core->p_stat == SRUN)
remrq (in_core);
} else {
/* Nothing to swap in/out. */
in_core = 0;
swapped_out = 0;
++runin;
sleep ((caddr_t) &runin, PSWP);
}
}
}
/*
* Count up various things once a second
*/
void
vmmeter()
{
#ifdef UCB_METER
register u_short *cp, *rp;
register long *sp;
ave(avefree, freemem, 5);
ave(avefree30, freemem, 30);
cp = &cnt.v_first;
rp = &rate.v_first;
sp = &sum.v_first;
while (cp <= &cnt.v_last) {
ave(*rp, *cp, 5);
*sp += *cp;
*cp = 0;
rp++, cp++, sp++;
}
#endif
if (time.tv_sec % 5 == 0) {
vmtotal();
#ifdef UCB_METER
rate.v_swpin = cnt.v_swpin;
sum.v_swpin += cnt.v_swpin;
cnt.v_swpin = 0;
rate.v_swpout = cnt.v_swpout;
sum.v_swpout += cnt.v_swpout;
cnt.v_swpout = 0;
#endif
}
}
/*
* Compute Tenex style load average. This code is adapted from similar code
* by Bill Joy on the Vax system. The major change is that we avoid floating
* point since not all pdp-11's have it. This makes the code quite hard to
* read - it was derived with some algebra.
*
* "floating point" numbers here are stored in a 16 bit short, with 8 bits on
* each side of the decimal point. Some partial products will have 16 bits to
* the right.
*/
static void
loadav (avg, n)
register short *avg;
register int n;
{
register int i;
static const long cexp[3] = {
0353, /* 256 * exp(-1/12) */
0373, /* 256 * exp(-1/60) */
0376, /* 256 * exp(-1/180) */
};
for (i = 0; i < 3; i++)
avg[i] = (cexp[i] * (avg[i]-(n<<8)) + (((long)n)<<16)) >> 8;
}
void
vmtotal()
{
register struct proc *p;
register int nrun = 0;
#ifdef UCB_METER
total.t_vmtxt = 0;
total.t_avmtxt = 0;
total.t_rmtxt = 0;
total.t_armtxt = 0;
total.t_vm = 0;
total.t_avm = 0;
total.t_rm = 0;
total.t_arm = 0;
total.t_rq = 0;
total.t_dw = 0;
total.t_sl = 0;
total.t_sw = 0;
#endif
for (p = allproc; p != NULL; p = p->p_nxt) {
if (p->p_flag & SSYS)
continue;
if (p->p_stat) {
#ifdef UCB_METER
if (p->p_stat != SZOMB) {
total.t_vm += p->p_dsize + p->p_ssize + USIZE;
if (p->p_flag & SLOAD)
total.t_rm += p->p_dsize + p->p_ssize
+ USIZE;
}
#endif
switch (p->p_stat) {
case SSLEEP:
case SSTOP:
if (!(p->p_flag & P_SINTR) && p->p_stat == SSLEEP)
nrun++;
#ifdef UCB_METER
if (p->p_flag & SLOAD) {
if (!(p->p_flag & P_SINTR))
total.t_dw++;
else if (p->p_slptime < maxslp)
total.t_sl++;
} else if (p->p_slptime < maxslp)
total.t_sw++;
if (p->p_slptime < maxslp)
goto active;
#endif
break;
case SRUN:
case SIDL:
nrun++;
#ifdef UCB_METER
if (p->p_flag & SLOAD)
total.t_rq++;
else
total.t_sw++;
active:
total.t_avm += p->p_dsize + p->p_ssize + USIZE;
if (p->p_flag & SLOAD)
total.t_arm += p->p_dsize + p->p_ssize
+ USIZE;
#endif
break;
}
}
}
#ifdef UCB_METER
total.t_vm += total.t_vmtxt;
total.t_avm += total.t_avmtxt;
total.t_rm += total.t_rmtxt;
total.t_arm += total.t_armtxt;
total.t_free = avefree;
#endif
loadav (avenrun, nrun);
}

115
sys/kernel/vm_swap.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "map.h"
#include "buf.h"
#include "systm.h"
#include "vm.h"
/*
* Swap a process in.
* Allocate data and possible text separately. It would be better
* to do largest first. Text, data, and stack are allocated in
* that order, as that is likely to be in order of size.
* U area goes into u0 buffer.
*/
void
swapin (p)
register struct proc *p;
{
size_t daddr = USER_DATA_START;
size_t saddr = USER_DATA_END - p->p_ssize;
size_t uaddr = (size_t) &u0;
if (p->p_dsize) {
swap (p->p_daddr, daddr, p->p_dsize, B_READ);
mfree (swapmap, btod (p->p_dsize), p->p_daddr);
}
if (p->p_ssize) {
swap (p->p_saddr, saddr, p->p_ssize, B_READ);
mfree (swapmap, btod (p->p_ssize), p->p_saddr);
}
swap (p->p_addr, uaddr, USIZE, B_READ);
mfree (swapmap, btod (USIZE), p->p_addr);
p->p_daddr = daddr;
p->p_saddr = saddr;
p->p_addr = uaddr;
if (p->p_stat == SRUN)
setrq (p);
p->p_flag |= SLOAD;
p->p_time = 0;
#ifdef UCB_METER
cnt.v_swpin++;
#endif
}
/*
* Swap out process p.
* odata and ostack are the old data size and the stack size
* of the process, and are supplied during core expansion swaps.
* The freecore flag causes its core to be freed -- it may be
* off when called to create an image for a child process
* in newproc.
*
* panic: out of swap space
*/
void
swapout (p, freecore, odata, ostack)
register struct proc *p;
int freecore;
register u_int odata, ostack;
{
size_t a[3];
if (odata == (u_int) X_OLDSIZE)
odata = p->p_dsize;
if (ostack == (u_int) X_OLDSIZE)
ostack = p->p_ssize;
if (malloc3 (swapmap, btod (p->p_dsize), btod (p->p_ssize),
btod (USIZE), a) == NULL)
panic ("out of swap space");
p->p_flag |= SLOCK;
if (odata) {
swap (a[0], p->p_daddr, odata, B_WRITE);
}
if (ostack) {
swap (a[1], p->p_saddr, ostack, B_WRITE);
}
/*
* Increment u_ru.ru_nswap for process being tossed out of core.
* We can be called to swap out a process other than the current
* process, so we have to map in the victim's u structure briefly.
* Note, savekdsa6 *must* be a static, because we remove the stack
* in the next instruction. The splclock is to prevent the clock
* from coming in and doing accounting for the wrong process, plus
* we don't want to come through here twice. Why are we doing
* this, anyway?
*/
{
int s;
s = splclock();
u.u_ru.ru_nswap++;
splx (s);
}
swap (a[2], p->p_addr, USIZE, B_WRITE);
p->p_daddr = a[0];
p->p_saddr = a[1];
p->p_addr = a[2];
p->p_flag &= ~(SLOAD|SLOCK);
p->p_time = 0;
#ifdef UCB_METER
cnt.v_swpout++;
#endif
if (runout) {
runout = 0;
wakeup ((caddr_t)&runout);
}
}

177
sys/kernel/vm_swp.c Normal file
View File

@@ -0,0 +1,177 @@
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include "param.h"
#include "user.h"
#include "proc.h"
#include "buf.h"
#include "conf.h"
#include "systm.h"
#include "vm.h"
#include "trace.h"
#include "uio.h"
/*
* swap I/O
*/
void
swap (blkno, coreaddr, count, rdflg)
size_t blkno, coreaddr;
register int count;
int rdflg;
{
register struct buf *bp;
int s;
//printf ("swap (%u, %08x, %d, %s)\n", blkno, coreaddr, count, rdflg ? "R" : "W");
#ifdef UCB_METER
if (rdflg) {
cnt.v_kbin += (count + 1023) / 1024;
} else {
cnt.v_kbout += (count + 1023) / 1024;
}
#endif
bp = geteblk(); /* allocate a buffer header */
while (count) {
bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rdflg;
bp->b_dev = swapdev;
bp->b_bcount = count;
bp->b_blkno = blkno;
bp->b_addr = (caddr_t) coreaddr;
trace (TR_SWAPIO);
(*bdevsw[major(swapdev)].d_strategy) (bp);
s = splbio();
while ((bp->b_flags & B_DONE) == 0)
sleep ((caddr_t)bp, PSWP);
splx (s);
if ((bp->b_flags & B_ERROR) || bp->b_resid)
panic ("hard err: swap");
count -= count;
coreaddr += count;
blkno += btod (count);
}
brelse(bp);
}
/*
* Raw I/O. The arguments are
* The strategy routine for the device
* A buffer, which may be a special buffer header
* owned exclusively by the device for this purpose or
* NULL if one is to be allocated.
* The device number
* Read/write flag
* Essentially all the work is computing physical addresses and
* validating them.
*
* rewritten to use the iov/uio mechanism from 4.3bsd. the physbuf routine
* was inlined. essentially the chkphys routine performs the same task
* as the useracc routine on a 4.3 system. 3/90 sms
*
* If the buffer pointer is NULL then one is allocated "dynamically" from
* the system cache. the 'invalid' flag is turned on so that the brelse()
* done later doesn't place the buffer back in the cache. the 'phys' flag
* is left on so that the address of the buffer is recalcuated in getnewbuf().
* The BYTE/WORD stuff began to be removed after testing proved that either
* 1) the underlying hardware gives an error or 2) nothing bad happens.
* besides, 4.3BSD doesn't do the byte/word check and noone could remember
* why the byte/word check was added in the first place - likely historical
* paranoia. chkphys() inlined. 5/91 sms
*
* Refined (and streamlined) the flow by using a 'for' construct
* (a la 4.3Reno). Avoid allocating/freeing the buffer for each iovec
* element (i must have been confused at the time). 6/91-sms
*
* Finished removing the BYTE/WORD code as part of implementing the common
* raw read&write routines , systems had been running fine for several
* months with it ifdef'd out. 9/91-sms
*/
int
physio(strat, bp, dev, rw, uio)
void (*strat) (struct buf*);
register struct buf *bp;
dev_t dev;
int rw;
register struct uio *uio;
{
int error = 0, s, c, allocbuf = 0;
register struct iovec *iov;
if (! bp) {
allocbuf++;
bp = geteblk();
}
u.u_procp->p_flag |= SLOCK;
for ( ; uio->uio_iovcnt; uio->uio_iov++, uio->uio_iovcnt--) {
iov = uio->uio_iov;
if (iov->iov_base >= iov->iov_base + iov->iov_len) {
error = EFAULT;
break;
}
/*
* Check that transfer is either entirely in the
* data or in the stack: that is, either
* the end is in the data or the start is in the stack
* (remember wraparound was already checked).
*/
if (baduaddr (iov->iov_base) ||
baduaddr (iov->iov_base + iov->iov_len - 1)) {
error = EFAULT;
break;
}
if (! allocbuf) {
s = splbio();
while (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
sleep((caddr_t)bp, PRIBIO+1);
}
splx(s);
}
bp->b_error = 0;
while (iov->iov_len) {
bp->b_flags = B_BUSY | B_PHYS | B_INVAL | rw;
bp->b_dev = dev;
bp->b_addr = iov->iov_base;
bp->b_blkno = (unsigned) uio->uio_offset >> DEV_BSHIFT;
bp->b_bcount = iov->iov_len;
c = bp->b_bcount;
(*strat)(bp);
s = splbio();
while ((bp->b_flags & B_DONE) == 0)
sleep((caddr_t)bp, PRIBIO);
if (bp->b_flags & B_WANTED) /* rare */
wakeup((caddr_t)bp);
splx(s);
c -= bp->b_resid;
iov->iov_base += c;
iov->iov_len -= c;
uio->uio_resid -= c;
uio->uio_offset += c;
/* temp kludge for tape drives */
if (bp->b_resid || (bp->b_flags & B_ERROR))
break;
}
bp->b_flags &= ~(B_BUSY | B_WANTED);
error = geterror(bp);
/* temp kludge for tape drives */
if (bp->b_resid || error)
break;
}
if (allocbuf)
brelse(bp);
u.u_procp->p_flag &= ~SLOCK;
return(error);
}
int
rawrw (dev, uio, flag)
dev_t dev;
register struct uio *uio;
int flag;
{
return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, dev,
uio->uio_rw == UIO_READ ? B_READ : B_WRITE, uio));
}