Initial Import from SVN
This commit is contained in:
341
sys/kernel/init_main.c
Normal file
341
sys/kernel/init_main.c
Normal 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
211
sys/kernel/init_sysent.c
Normal 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
373
sys/kernel/kern_clock.c
Normal 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
532
sys/kernel/kern_descrip.c
Normal 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
539
sys/kernel/kern_exec.c
Normal 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
280
sys/kernel/kern_exit.c
Normal 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
254
sys/kernel/kern_fork.c
Normal 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
61
sys/kernel/kern_glob.c
Normal 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
38
sys/kernel/kern_mman.c
Normal 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
65
sys/kernel/kern_proc.c
Normal 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
155
sys/kernel/kern_prot.c
Normal 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
114
sys/kernel/kern_prot2.c
Normal 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
270
sys/kernel/kern_resource.c
Normal 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
664
sys/kernel/kern_sig.c
Normal 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
371
sys/kernel/kern_sig2.c
Normal 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
126
sys/kernel/kern_subr.c
Normal 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
538
sys/kernel/kern_synch.c
Normal 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
909
sys/kernel/kern_sysctl.c
Normal 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
342
sys/kernel/kern_time.c
Normal 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
336
sys/kernel/subr_log.c
Normal 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
565
sys/kernel/subr_prf.c
Normal 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
230
sys/kernel/subr_rmap.c
Normal 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
544
sys/kernel/sys_generic.c
Normal 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
698
sys/kernel/sys_inode.c
Normal 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
307
sys/kernel/sys_pipe.c
Normal 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
137
sys/kernel/sys_process.c
Normal 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
169
sys/kernel/syscalls.c
Normal 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
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
520
sys/kernel/tty_pty.c
Normal 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
406
sys/kernel/tty_subr.c
Normal 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
90
sys/kernel/tty_tty.c
Normal 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
302
sys/kernel/ufs_alloc.c
Normal 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
485
sys/kernel/ufs_bio.c
Normal 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
154
sys/kernel/ufs_bmap.c
Normal 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
84
sys/kernel/ufs_dsort.c
Normal 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
186
sys/kernel/ufs_fio.c
Normal 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
695
sys/kernel/ufs_inode.c
Normal 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
301
sys/kernel/ufs_mount.c
Normal 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
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
145
sys/kernel/ufs_subr.c
Normal 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
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
279
sys/kernel/ufs_syscalls2.c
Normal 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
212
sys/kernel/vfs_vnops.c
Normal 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
262
sys/kernel/vm_sched.c
Normal 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
115
sys/kernel/vm_swap.c
Normal 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
177
sys/kernel/vm_swp.c
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user