diff options
Diffstat (limited to 'sys/kern')
63 files changed, 6155 insertions, 2072 deletions
diff --git a/sys/kern/dead_vnops.c b/sys/kern/dead_vnops.c index df66b12f7d13..59cb231c83f2 100644 --- a/sys/kern/dead_vnops.c +++ b/sys/kern/dead_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)dead_vnops.c 7.13 (Berkeley) 4/15/91 - * $Id: dead_vnops.c,v 1.2 1993/10/16 15:23:59 rgrimes Exp $ + * $Id: dead_vnops.c,v 1.5 1993/12/19 00:51:17 wollman Exp $ */ #include "param.h" @@ -42,6 +42,8 @@ #include "namei.h" #include "buf.h" +static int chkvnlock(struct vnode *); + /* * Prototypes for dead operations on vnodes. */ @@ -174,7 +176,7 @@ int dead_bmap __P(( daddr_t *bnp)); int dead_strategy __P(( struct buf *bp)); -int dead_print __P(( +void dead_print __P(( struct vnode *vp)); #define dead_islocked ((int (*) __P(( \ struct vnode *vp))) nullop) @@ -225,6 +227,7 @@ struct vnodeops dead_vnodeops = { * Trivial lookup routine that always fails. */ /* ARGSUSED */ +int dead_lookup(vp, ndp, p) struct vnode *vp; struct nameidata *ndp; @@ -240,6 +243,7 @@ dead_lookup(vp, ndp, p) * Open always fails as if device did not exist. */ /* ARGSUSED */ +int dead_open(vp, mode, cred, p) struct vnode *vp; int mode; @@ -254,6 +258,7 @@ dead_open(vp, mode, cred, p) * Vnode op for read */ /* ARGSUSED */ +int dead_read(vp, uio, ioflag, cred) struct vnode *vp; struct uio *uio; @@ -275,6 +280,7 @@ dead_read(vp, uio, ioflag, cred) * Vnode op for write */ /* ARGSUSED */ +int dead_write(vp, uio, ioflag, cred) register struct vnode *vp; struct uio *uio; @@ -291,6 +297,7 @@ dead_write(vp, uio, ioflag, cred) * Device ioctl operation. */ /* ARGSUSED */ +int dead_ioctl(vp, com, data, fflag, cred, p) struct vnode *vp; register int com; @@ -306,6 +313,7 @@ dead_ioctl(vp, com, data, fflag, cred, p) } /* ARGSUSED */ +int dead_select(vp, which, fflags, cred, p) struct vnode *vp; int which, fflags; @@ -322,6 +330,7 @@ dead_select(vp, which, fflags, cred, p) /* * Just call the device strategy routine */ +int dead_strategy(bp) register struct buf *bp; { @@ -337,6 +346,7 @@ dead_strategy(bp) /* * Wait until the vnode has finished changing state. */ +int dead_lock(vp) struct vnode *vp; { @@ -349,6 +359,7 @@ dead_lock(vp) /* * Wait until the vnode has finished changing state. */ +int dead_bmap(vp, bn, vpp, bnp) struct vnode *vp; daddr_t bn; @@ -365,6 +376,7 @@ dead_bmap(vp, bn, vpp, bnp) * Print out the contents of a dead vnode. */ /* ARGSUSED */ +void dead_print(vp) struct vnode *vp; { @@ -375,6 +387,7 @@ dead_print(vp) /* * Empty vnode failed operation */ +int dead_ebadf() { @@ -384,6 +397,7 @@ dead_ebadf() /* * Empty vnode bad operation */ +int dead_badop() { @@ -394,6 +408,7 @@ dead_badop() /* * Empty vnode null operation */ +int dead_nullop() { @@ -404,6 +419,7 @@ dead_nullop() * We have to wait during times when the vnode is * in a state of change. */ +static int chkvnlock(vp) register struct vnode *vp; { @@ -411,7 +427,7 @@ chkvnlock(vp) while (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - sleep((caddr_t)vp, PINOD); + tsleep((caddr_t)vp, PINOD, "chkvnlk", 0); locked = 1; } return (locked); diff --git a/sys/kern/fifo_vnops.c b/sys/kern/fifo_vnops.c index d51400a2872b..2affc734e213 100644 --- a/sys/kern/fifo_vnops.c +++ b/sys/kern/fifo_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)fifo_vnops.c 7.7 (Berkeley) 4/15/91 - * $Id: fifo_vnops.c,v 1.4 1993/10/16 15:24:02 rgrimes Exp $ + * $Id: fifo_vnops.c,v 1.5 1993/11/25 01:32:44 wollman Exp $ */ #ifdef FIFO @@ -100,6 +100,7 @@ struct vnodeops fifo_vnodeops = { * Trivial lookup routine that always fails. */ /* ARGSUSED */ +int fifo_lookup(vp, ndp, p) struct vnode *vp; struct nameidata *ndp; @@ -116,6 +117,7 @@ fifo_lookup(vp, ndp, p) * to find an active instance of a fifo. */ /* ARGSUSED */ +int fifo_open(vp, mode, cred, p) register struct vnode *vp; int mode; @@ -203,6 +205,7 @@ fifo_open(vp, mode, cred, p) * Vnode op for read */ /* ARGSUSED */ +int fifo_read(vp, uio, ioflag, cred) struct vnode *vp; register struct uio *uio; @@ -222,8 +225,8 @@ fifo_read(vp, uio, ioflag, cred) rso->so_state |= SS_NBIO; startresid = uio->uio_resid; VOP_UNLOCK(vp); - error = soreceive(rso, (struct mbuf **)0, uio, (int *)0, - (struct mbuf **)0, (struct mbuf **)0); + error = soreceive(rso, (struct mbuf **)0, uio, + (struct mbuf **)0, (struct mbuf **)0, (int *)0); VOP_LOCK(vp); /* * Clear EOF indication after first such return. @@ -239,6 +242,7 @@ fifo_read(vp, uio, ioflag, cred) * Vnode op for write */ /* ARGSUSED */ +int fifo_write(vp, uio, ioflag, cred) struct vnode *vp; register struct uio *uio; @@ -266,6 +270,7 @@ fifo_write(vp, uio, ioflag, cred) * Device ioctl operation. */ /* ARGSUSED */ +int fifo_ioctl(vp, com, data, fflag, cred, p) struct vnode *vp; int com; @@ -287,6 +292,7 @@ fifo_ioctl(vp, com, data, fflag, cred, p) } /* ARGSUSED */ +int fifo_select(vp, which, fflag, cred, p) struct vnode *vp; int which, fflag; @@ -306,6 +312,7 @@ fifo_select(vp, which, fflag, cred, p) /* * This is a noop, simply returning what one has been given. */ +int fifo_bmap(vp, bn, vpp, bnp) struct vnode *vp; daddr_t bn; @@ -324,6 +331,7 @@ fifo_bmap(vp, bn, vpp, bnp) * At the moment we do not do any locking. */ /* ARGSUSED */ +int fifo_lock(vp) struct vnode *vp; { @@ -332,6 +340,7 @@ fifo_lock(vp) } /* ARGSUSED */ +int fifo_unlock(vp) struct vnode *vp; { @@ -343,6 +352,7 @@ fifo_unlock(vp) * Device close routine */ /* ARGSUSED */ +int fifo_close(vp, fflag, cred, p) register struct vnode *vp; int fflag; @@ -375,6 +385,7 @@ fifo_close(vp, fflag, cred, p) /* * Print out the contents of a fifo vnode. */ +void fifo_print(vp) struct vnode *vp; { @@ -387,6 +398,7 @@ fifo_print(vp) /* * Print out internal contents of a fifo vnode. */ +void fifo_printinfo(vp) struct vnode *vp; { @@ -399,6 +411,7 @@ fifo_printinfo(vp) /* * Fifo failed operation */ +int fifo_ebadf() { @@ -409,6 +422,7 @@ fifo_ebadf() * Fifo advisory byte-level locks. */ /* ARGSUSED */ +int fifo_advlock(vp, id, op, fl, flags) struct vnode *vp; caddr_t id; @@ -423,6 +437,7 @@ fifo_advlock(vp, id, op, fl, flags) /* * Fifo bad operation */ +int fifo_badop() { diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c new file mode 100644 index 000000000000..8bfb19cfe28d --- /dev/null +++ b/sys/kern/imgact_aout.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1993, David Greenman + * All rights reserved. + * + * 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 David Greenman + * 4. The name of the developer may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + * + * $Id: imgact_aout.c,v 1.3 1993/12/30 01:39:29 davidg Exp $ + */ + +#include "param.h" +#include "systm.h" +#include "resourcevar.h" +#include "exec.h" +#include "mman.h" +#include "imgact.h" +#include "kernel.h" + +#include "vm/vm.h" + +int +exec_aout_imgact(iparams) + struct image_params *iparams; +{ + struct exec *a_out = (struct exec *) iparams->image_header; + struct vmspace *vmspace = iparams->proc->p_vmspace; + unsigned long vmaddr, virtual_offset, file_offset; + unsigned long bss_size; + int error, len; + + /* + * Set file/virtual offset based on a.out variant. + * We do two cases: host byte order and network byte order + * (for NetBSD compatibility) + */ + switch ((int)(a_out->a_magic & 0xffff)) { + case ZMAGIC: + virtual_offset = 0; + if (a_out->a_text) { + file_offset = NBPG; + } else { + /* Bill's "screwball mode" */ + file_offset = 0; + } + break; + case QMAGIC: + virtual_offset = NBPG; + file_offset = 0; + break; + default: + /* NetBSD compatibility */ + switch ((int)(ntohl(a_out->a_magic) & 0xffff)) { + case ZMAGIC: + case QMAGIC: + virtual_offset = NBPG; + file_offset = 0; + break; + default: + return (-1); + } + } + + bss_size = roundup(a_out->a_bss, NBPG); + + /* + * Check various fields in header for validity/bounds. + */ + if (/* entry point must lay with text region */ + a_out->a_entry < virtual_offset || + a_out->a_entry >= virtual_offset + a_out->a_text || + + /* text and data size must each be page rounded */ + a_out->a_text % NBPG || + a_out->a_data % NBPG) + return (-1); + + /* text + data can't exceed file size */ + if (a_out->a_data + a_out->a_text > iparams->attr->va_size) + return (EFAULT); + + /* + * text/data/bss must not exceed limits + */ + if (/* text can't exceed maximum text size */ + a_out->a_text > MAXTSIZ || + + /* data + bss can't exceed maximum data size */ + a_out->a_data + bss_size > MAXDSIZ || + + /* data + bss can't exceed rlimit */ + a_out->a_data + bss_size > + iparams->proc->p_rlimit[RLIMIT_DATA].rlim_cur) + return (ENOMEM); + + /* copy in arguments and/or environment from old process */ + error = exec_extract_strings(iparams); + if (error) + return (error); + + /* + * Destroy old process VM and create a new one (with a new stack) + */ + exec_new_vmspace(iparams); + + /* + * Map text read/execute + */ + vmaddr = virtual_offset; + error = + vm_mmap(&vmspace->vm_map, /* map */ + &vmaddr, /* address */ + a_out->a_text, /* size */ + VM_PROT_READ | VM_PROT_EXECUTE, /* protection */ + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, /* max protection */ + MAP_FILE | MAP_PRIVATE | MAP_FIXED, /* flags */ + iparams->vnodep, /* vnode */ + file_offset); /* offset */ + if (error) + return (error); + + /* + * Map data read/write (if text is 0, assume text is in data area + * [Bill's screwball mode]) + */ + vmaddr = virtual_offset + a_out->a_text; + error = + vm_mmap(&vmspace->vm_map, + &vmaddr, + a_out->a_data, + VM_PROT_READ | VM_PROT_WRITE | (a_out->a_text ? 0 : VM_PROT_EXECUTE), + VM_PROT_READ | VM_PROT_WRITE | (a_out->a_text ? 0 : VM_PROT_EXECUTE), + MAP_FILE | MAP_PRIVATE | MAP_FIXED, + iparams->vnodep, + file_offset + a_out->a_text); + if (error) + return (error); + + /* + * Allocate demand-zeroed area for uninitialized data + * "bss" = 'block started by symbol' - named after the IBM 7090 + * instruction of the same name. + */ + vmaddr = virtual_offset + a_out->a_text + a_out->a_data; + error = vm_allocate(&vmspace->vm_map, &vmaddr, bss_size, FALSE); + if (error) + return (error); + + /* Fill in process VM information */ + vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT; + vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT; + vmspace->vm_taddr = (caddr_t) virtual_offset; + vmspace->vm_daddr = (caddr_t) virtual_offset + a_out->a_text; + + /* Fill in image_params */ + iparams->interpreted = 0; + iparams->entry_addr = a_out->a_entry; + + return (0); +} + +/* + * Tell kern_execve.c about it, with a little help from the linker. + * Since `const' objects end up in the text segment, TEXT_SET is the + * correct directive to use. + */ +static const struct execsw aout_execsw = { exec_aout_imgact }; +TEXT_SET(execsw_set, aout_execsw); + diff --git a/sys/kern/imgact_shell.c b/sys/kern/imgact_shell.c new file mode 100644 index 000000000000..8a7c0545d705 --- /dev/null +++ b/sys/kern/imgact_shell.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1993, David Greenman + * All rights reserved. + * + * 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 David Greenman + * 4. The name of the developer may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + * + * $Id: imgact_shell.c,v 1.2 1993/12/20 19:31:15 wollman Exp $ + */ + +#include "param.h" +#include "systm.h" +#include "resourcevar.h" +#include "imgact.h" +#include "kernel.h" +#include "machine/endian.h" + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SHELLMAGIC 0x2123 /* #! */ +#else +#define SHELLMAGIC 0x2321 +#endif + +#define MAXSHELLCMDLEN 64 + +/* + * Shell interpreter image activator. A interpreter name beginning + * at iparams->stringbase is the minimal successful exit requirement. + */ +int +exec_shell_imgact(iparams) + struct image_params *iparams; +{ + const char *image_header = iparams->image_header; + const char *ihp, *line_endp; + int length; + char *interp; + char **argv; + + /* a shell script? */ + if (((short *) image_header)[0] != SHELLMAGIC) + return(-1); + + /* + * Don't allow a shell script to be the shell for a shell + * script. :-) + */ + if (iparams->interpreted) + return(ENOEXEC); + + iparams->interpreted = 1; + + /* + * Copy shell name and arguments from image_header into string + * buffer. + */ + + /* + * Find end of line; return if the line > MAXSHELLCMDLEN long. + */ + for (ihp = &image_header[2]; *ihp != '\n'; ++ihp) { + if (ihp >= &image_header[MAXSHELLCMDLEN]) + return(ENOEXEC); + } + line_endp = ihp; + + /* reset for another pass */ + ihp = &image_header[2]; + + /* Skip over leading spaces - until the interpreter name */ + while ((*ihp == ' ') || (*ihp == '\t')) ihp++; + + /* copy the interpreter name */ + interp = iparams->interpreter_name; + while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) + *interp++ = *ihp++; + *interp = '\0'; + + /* Disallow a null interpreter filename */ + if (*iparams->interpreter_name == '\0') + return(ENOEXEC); + + /* reset for another pass */ + ihp = &image_header[2]; + + /* copy the interpreter name and arguments */ + while (ihp < line_endp) { + /* Skip over leading spaces */ + while ((*ihp == ' ') || (*ihp == '\t')) ihp++; + + if (ihp < line_endp) { + /* + * Copy to end of token. No need to watch stringspace + * because this is at the front of the string buffer + * and the maximum shell command length is tiny. + */ + while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) { + *iparams->stringp++ = *ihp++; + iparams->stringspace--; + } + + *iparams->stringp++ = 0; + iparams->stringspace--; + + iparams->argc++; + } + } + + /* set argv[0] to point to original file name */ + suword(iparams->uap->argv, (int)iparams->uap->fname); + + return(0); +} + +/* + * Tell kern_execve.c about it, with a little help from the linker. + * Since `const' objects end up in the text segment, TEXT_SET is the + * correct directive to use. + */ +static const struct execsw shell_execsw = { exec_shell_imgact }; +TEXT_SET(execsw_set, shell_execsw); diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 8200ee199c70..ce2f1bf8065f 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)init_main.c 7.41 (Berkeley) 5/15/91 - * $Id: init_main.c,v 1.7 1993/10/08 10:50:42 rgrimes Exp $ + * $Id: init_main.c,v 1.14 1994/01/14 16:24:45 davidg Exp $ */ #include "param.h" @@ -57,7 +57,7 @@ #include "vm/vm.h" -char copyright[] = +const char copyright[] = "Copyright (c) 1989,1990,1991,1992 William F. Jolitz. All rights reserved.\n\ Copyright (c) 1982,1986,1989,1991 The Regents of the University\n\ of California. All rights reserved.\n\n"; @@ -86,24 +86,36 @@ extern int (*mountroot)(); struct vnode *rootvp, *swapdev_vp; int boothowto; +struct proc *updateproc; + #if __GNUC__ >= 2 -__main() {} +void __main() {} #endif /* + * This table is filled in by the linker with functions that need to be + * called to initialize various pseudo-devices and whatnot. + */ +typedef void (*pseudo_func_t)(void); +extern const struct linker_set pseudo_set; +static const pseudo_func_t *pseudos = + (const pseudo_func_t *)&pseudo_set.ls_items[0]; + +/* * System startup; initialize the world, create process 0, * mount root filesystem, and fork to create init and pagedaemon. * Most of the hard work is done in the lower-level initialization * routines including startup(), which does memory initialization * and autoconfiguration. */ +void main() { register int i; register struct proc *p; register struct filedesc0 *fdp; int s, rval[2]; - char *cp; + const char *cp; /* * Initialize curproc before any possible traps/probes @@ -220,21 +232,11 @@ main() * Initialize tables, protocols, and set up well-known inodes. */ mbinit(); -#ifdef SYSVSHM - shminit(); -#endif -#include "sl.h" -#if NSL > 0 - slattach(); /* XXX */ -#endif -#include "ppp.h" -#if NPPP > 0 - pppattach(); /* XXX */ -#endif -#include "loop.h" -#if NLOOP > 0 - loattach(); /* XXX */ -#endif + + while(*pseudos) { + (**pseudos++)(); + } + /* * Block reception of incoming packets * until protocols have been initialized. @@ -249,8 +251,8 @@ main() #endif /* kick off timeout driven events by calling first time */ - roundrobin(); - schedcpu(); + roundrobin(0, 0); + schedcpu(0, 0); enablertclock(); /* enable realtime clock interrupts */ /* @@ -281,22 +283,20 @@ main() * XXX probably should go elsewhere. */ bzero(utsname.sysname, sizeof(utsname.sysname)); - for (cp = version, i= 0; - *cp && *cp != ' ' && i <= sizeof(utsname.sysname); - ) - utsname.sysname[i++] = *cp++; + for (cp = version, i= 0; *cp && *cp != ' ' && i <= sizeof(utsname.sysname);) + utsname.sysname[i++] = *cp++; bzero(utsname.release, sizeof(utsname.release)); for (cp++, i= 0; *cp && *cp != ' ' && i <= sizeof(utsname.release);) - utsname.release[i++] = *cp++; + utsname.release[i++] = *cp++; bzero(utsname.version, sizeof(utsname.version)); for (; *cp != '('; cp++); for (cp++, i= 0; *cp && *cp != ')' && i <= sizeof(utsname.version);) - utsname.version[i++] = *cp++; + utsname.version[i++] = *cp++; for (; *cp != '#'; cp++); if(i <= sizeof(utsname.version)) - utsname.version[i++] = '#'; + utsname.version[i++] = '#'; for (cp++; *cp && *cp != ':' && i <= sizeof(utsname.version);) - utsname.version[i++] = *cp++; + utsname.version[i++] = *cp++; strncpy(utsname.machine, MACHINE, sizeof(utsname.machine)); utsname.machine[sizeof(utsname.machine)-1] = '\0'; @@ -326,6 +326,8 @@ main() if (boothowto&RB_FASTBOOT) *ip++ = 'f'; #endif + if (ip == initflags + 1) + *ip++ = '-'; *ip++ = '\0'; if (vm_allocate(&p->p_vmspace->vm_map, &addr, @@ -363,6 +365,20 @@ main() } /* + * Start update daemon (process 3). + */ + if (fork(p, (void *) NULL, rval)) + panic("fork update"); + if (rval[1]) { + p = curproc; + updateproc = p; + p->p_flag |= SLOAD|SSYS; + bcopy("update", p->p_comm, sizeof("update")); + vfs_update(); + /*NOTREACHED*/ + } + + /* * enter scheduling loop */ sched(); diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 55e428c00fa4..97056b0c3bbc 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * created from $Id: syscalls.master,v 1.5 1993/10/24 06:19:58 paul Exp $ + * created from $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $ */ #include "param.h" @@ -161,10 +161,26 @@ int getfh(); int getdomainname(); int setdomainname(); int uname(); +int sysarch(); +#ifdef SYSVSEM +int semsys(); +#else +#endif +#ifdef SYSVMSG +int msgsys(); +#else +#endif #ifdef SYSVSHM int shmsys(); #else #endif +#ifdef MACHVMCOMPAT +int svm_allocate(); +int svm_deallocate(); +int svm_inherit(); +int svm_protect(); +#else +#endif int setgid(); int setegid(); int seteuid(); @@ -207,9 +223,18 @@ int ogetsockname(); #ifdef NFS #else #endif +#ifdef SYSVSEM +#else +#endif +#ifdef SYSVMSG +#else +#endif #ifdef SYSVSHM #else #endif +#ifdef MACHVMCOMPAT +#else +#endif #else /* COMPAT_43 */ #define compat(n, name) 0, nosys @@ -406,12 +431,20 @@ struct sysent sysent[] = { 2, getdomainname, /* 162 = getdomainname */ 2, setdomainname, /* 163 = setdomainname */ 1, uname, /* 164 = uname */ - 0, nosys, /* 165 = nosys */ + 2, sysarch, /* 165 = sysarch */ 0, nosys, /* 166 = nosys */ 0, nosys, /* 167 = nosys */ 0, nosys, /* 168 = nosys */ +#ifdef SYSVSEM + 5, semsys, /* 169 = semsys */ +#else 0, nosys, /* 169 = nosys */ +#endif +#ifdef SYSVMSG + 6, msgsys, /* 170 = msgsys */ +#else 0, nosys, /* 170 = nosys */ +#endif #ifdef SYSVSHM 4, shmsys, /* 171 = shmsys */ #else @@ -422,10 +455,17 @@ struct sysent sysent[] = { 0, nosys, /* 174 = nosys */ 0, nosys, /* 175 = nosys */ 0, nosys, /* 176 = nosys */ +#ifdef MACHVMCOMPAT + 4, svm_allocate, /* 177 = vm_allocate */ + 3, svm_deallocate, /* 178 = vm_deallocate */ + 4, svm_inherit, /* 179 = vm_inherit */ + 5, svm_protect, /* 180 = vm_protect */ +#else 0, nosys, /* 177 = nosys */ 0, nosys, /* 178 = nosys */ 0, nosys, /* 179 = nosys */ 0, nosys, /* 180 = nosys */ +#endif 1, setgid, /* 181 = setgid */ 1, setegid, /* 182 = setegid */ 1, seteuid, /* 183 = seteuid */ diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c index 05cb3bfb4451..6d2c0e6536c7 100644 --- a/sys/kern/kern_acct.c +++ b/sys/kern/kern_acct.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)kern_acct.c 7.18 (Berkeley) 5/11/91 - * $Id: kern_acct.c,v 1.5 1993/10/19 05:46:05 davidg Exp $ + * $Id: kern_acct.c,v 1.9.2.1 1994/05/04 07:54:32 rgrimes Exp $ */ #include "param.h" @@ -57,10 +64,12 @@ */ int acctsuspend = 2; /* stop accounting when < 2% free space left */ int acctresume = 4; /* resume when free space risen to > 4% */ -struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ +struct timeval chk; /* frequency to check space for accounting */ struct vnode *acctp = NULL; /* file to which to do accounting */ struct vnode *savacctp = NULL; /* file to which to do accounting when space */ +static void acctwatch(caddr_t, int); + /* * Enable or disable process accounting. * @@ -80,6 +89,7 @@ struct sysacct_args { }; /* ARGSUSED */ +int sysacct(p, uap, retval) struct proc *p; struct sysacct_args *uap; @@ -89,7 +99,7 @@ sysacct(p, uap, retval) register struct nameidata *ndp; struct nameidata nd; struct vattr attr; - int rv, acctwatch(); + int rv; if (p->p_ucred->cr_uid != 0) return(EPERM); /* must be root */ @@ -147,8 +157,8 @@ sysacct(p, uap, retval) acctp = nd.ni_vp; savacctp = NULL; - acctwatch(&chk); /* look for full system */ VOP_UNLOCK(acctp); + acctwatch((caddr_t)&chk, 0); /* look for full system */ return(0); /* end successfully */ acct_fail: @@ -161,10 +171,14 @@ acct_fail: * Periodically check the file system to see if accounting * should be turned on or off. */ -acctwatch(resettime) - struct timeval *resettime; +static void +acctwatch(arg1, arg2) + caddr_t arg1; + int arg2; { + struct timeval *resettime = (struct timeval *)arg1; struct statfs sb; + int s; if (savacctp) { (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); @@ -183,6 +197,8 @@ acctwatch(resettime) acctp = NULL; log(LOG_NOTICE, "Accounting suspended\n"); } + s = splhigh(); *resettime = time; splx(s); + resettime->tv_sec += 15; timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); } @@ -193,6 +209,7 @@ acctwatch(resettime) /* Mark Tinguely (tinguely@plains.NoDak.edu) 8/10/93 */ +void acct(p) register struct proc *p; { diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index eca7041a3e35..44a334e00ebc 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_clock.c 7.16 (Berkeley) 5/9/91 - * $Id: kern_clock.c,v 1.6 1993/10/25 02:02:51 davidg Exp $ + * $Id: kern_clock.c,v 1.11 1993/12/19 00:51:20 wollman Exp $ */ #include "param.h" @@ -40,6 +40,7 @@ #include "callout.h" #include "kernel.h" #include "proc.h" +#include "signalvar.h" #include "resourcevar.h" #include "machine/cpu.h" @@ -51,6 +52,12 @@ #include "gprof.h" #endif +static void gatherstats(clockframe *); + +/* From callout.h */ +struct callout *callfree, *callout, calltodo; +int ncallout; + /* * Clock handling routines. * @@ -91,12 +98,13 @@ * If this timer is also being used to gather statistics, * we run through the statistics gathering routine as well. */ +void hardclock(frame) clockframe frame; { register struct callout *p1; register struct proc *p = curproc; - register struct pstats *pstats; + register struct pstats *pstats = 0; register struct rusage *ru; register struct vmspace *vm; register int s; @@ -282,6 +290,7 @@ int dk_ndrive = DK_NDRIVE; * or idle state) for the entire last time interval, and * update statistics accordingly. */ +void gatherstats(framep) clockframe *framep; { @@ -335,6 +344,7 @@ gatherstats(framep) * Run periodic events from timeout queue. */ /*ARGSUSED*/ +void softclock(frame) clockframe frame; { @@ -342,7 +352,7 @@ softclock(frame) for (;;) { register struct callout *p1; register caddr_t arg; - register int (*func)(); + register timeout_func_t func; register int a, s; s = splhigh(); @@ -389,8 +399,9 @@ softclock(frame) /* * Arrange that (*func)(arg) is called in t/hz seconds. */ +void timeout(func, arg, t) - int (*func)(); + timeout_func_t func; caddr_t arg; register int t; { @@ -420,8 +431,9 @@ timeout(func, arg, t) * untimeout is called to remove a function timeout call * from the callout structure. */ +void untimeout(func, arg) - int (*func)(); + timeout_func_t func; caddr_t arg; { register struct callout *p1, *p2; @@ -446,30 +458,60 @@ untimeout(func, arg) * Used to compute third argument to timeout() from an * absolute time. */ + +/* XXX clock_t */ +u_long hzto(tv) struct timeval *tv; { - register long ticks; + register unsigned long ticks; register long sec; - int s = splhigh(); + register long usec; + int s; /* - * 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. + * If the number of usecs in the whole seconds part of the time + * difference fits in a long, then the total number of usecs will + * fit in an unsigned long. Compute the total and convert it to + * ticks, rounding up and adding 1 to allow for the current tick + * to expire. Rounding also depends on unsigned long arithmetic + * to avoid overflow. + * + * Otherwise, if the number of ticks in the whole seconds part of + * the time difference fits in a long, then convert the parts to + * ticks separately and add, using similar rounding methods and + * overflow avoidance. This method would work in the previous + * case but it is slightly slower and assumes that hz is integral. + * + * Otherwise, round the time difference down to the maximum + * representable value. * - * Delta times less than 25 days can be computed ``exactly''. - * Maximum value for any timeout in 10ms ticks is 250 days. + * Maximum value for any timeout in 10ms ticks is 248 days. */ + s = splhigh(); 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) / (tick / 1000); - else if (sec <= 0x7fffffff / hz) - ticks = sec * hz; - else - ticks = 0x7fffffff; + usec = tv->tv_usec - time.tv_usec; splx(s); + if (usec < 0) { + sec--; + usec += 1000000; + } + if (sec < 0) { +#ifdef DIAGNOSTIC + printf("hzto: negative time difference %ld sec %ld usec\n", + sec, usec); +#endif + ticks = 1; + } else if (sec <= LONG_MAX / 1000000) + ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) + / tick + 1; + else if (sec <= LONG_MAX / hz) + ticks = sec * hz + + ((unsigned long)usec + (tick - 1)) / tick + 1; + else + ticks = LONG_MAX; +#define CLOCK_T_MAX INT_MAX /* XXX should be ULONG_MAX */ + if (ticks > CLOCK_T_MAX) + ticks = CLOCK_T_MAX; return (ticks); } diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index f8987ae8611a..d28faac16cbe 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. * All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)kern_descrip.c 7.28 (Berkeley) 6/25/91 - * $Id: kern_descrip.c,v 1.4 1993/10/16 15:24:11 rgrimes Exp $ + * $Id: kern_descrip.c,v 1.6.2.1 1994/05/04 07:54:36 rgrimes Exp $ */ #include "param.h" @@ -50,6 +57,8 @@ #include "syslog.h" #include "resourcevar.h" +#include "vm/vm_user.h" + /* * Descriptor management. */ @@ -61,6 +70,7 @@ extern int maxfdescs; /* maximum number of file descriptors to a process */ * System calls on descriptors. */ /* ARGSUSED */ +int getdtablesize(p, uap, retval) struct proc *p; struct args *uap; @@ -80,6 +90,7 @@ struct dup_args { }; /* ARGSUSED */ +int dup(p, uap, retval) struct proc *p; struct dup_args *uap; @@ -118,6 +129,7 @@ struct dup2_args { }; /* ARGSUSED */ +int dup2(p, uap, retval) struct proc *p; struct dup2_args *uap; @@ -168,6 +180,7 @@ struct fcntl_args { }; /* ARGSUSED */ +int fcntl(p, uap, retval) struct proc *p; register struct fcntl_args *uap; @@ -317,6 +330,7 @@ struct close_args { int fd; }; +int close(p, uap, retval) struct proc *p; struct close_args *uap; @@ -352,6 +366,7 @@ struct fstat_args { }; /* ARGSUSED */ +int fstat(p, uap, retval) struct proc *p; register struct fstat_args *uap; @@ -389,6 +404,7 @@ fstat(p, uap, retval) */ int fdexpand; +int fdalloc(p, want, result) struct proc *p; int want; @@ -457,6 +473,7 @@ fdalloc(p, want, result) * Check to see whether n user file descriptors * are available to the process p. */ +int fdavail(p, n) struct proc *p; register int n; @@ -479,6 +496,7 @@ fdavail(p, n) * Create a new open file structure and allocate * a file decriptor for the process that refers to it. */ +int falloc(p, resultfp, resultfd) register struct proc *p; struct file **resultfp; @@ -526,6 +544,7 @@ falloc(p, resultfp, resultfd) /* * Free a file descriptor. */ +void ffree(fp) register struct file *fp; { @@ -659,6 +678,7 @@ fdcloseexec(p) * Internal form of close. * Decrement reference count on file structure. */ +int closef(fp, p) register struct file *fp; register struct proc *p; @@ -713,6 +733,7 @@ struct flock_args { }; /* ARGSUSED */ +int flock(p, uap, retval) struct proc *p; register struct flock_args *uap; @@ -759,6 +780,7 @@ flock(p, uap, retval) * references to this file will be direct to the other driver. */ /* ARGSUSED */ +int fdopen(dev, mode, type) dev_t dev; int mode, type; @@ -779,6 +801,7 @@ fdopen(dev, mode, type) /* * Duplicate the specified descriptor to a free descriptor. */ +int dupfdopen(fdp, indx, dfd, mode) register struct filedesc *fdp; register int indx, dfd; diff --git a/sys/kern/kern_execve.c b/sys/kern/kern_execve.c index 003b2f768b07..5e0aa6565d3d 100644 --- a/sys/kern/kern_execve.c +++ b/sys/kern/kern_execve.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse + * Copyright (c) 1993, David Greenman * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,31 +12,14 @@ * 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 software is a component of "386BSD" developed by - * William F. Jolitz, TeleMuse. - * 4. Neither the name of the developer nor the name "386BSD" - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * This product includes software developed by David Greenman + * 4. The name of the developer may be used to endorse or promote products + * derived from this software without specific prior written permission. * - * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ - * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS - * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. - * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT - * NOT MAKE USE OF THIS WORK. - * - * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED - * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN - * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES - * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING - * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND - * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE - * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS - * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 DEVELOPER BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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) @@ -45,22 +28,16 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This procedure implements a minimal program execution facility for - * 386BSD. It interfaces to the BSD kernel as the execve system call. - * Significant limitations and lack of compatiblity with POSIX are - * present with this version, to make its basic operation more clear. - * - * $Id: kern_execve.c,v 1.8 1993/10/25 17:26:01 davidg Exp $ + * $Id: kern_execve.c,v 1.15.2.2 1994/03/24 08:57:16 rgrimes Exp $ */ #include "param.h" #include "systm.h" #include "signalvar.h" #include "resourcevar.h" -#include "proc.h" +#include "imgact.h" +#include "kernel.h" #include "mount.h" -#include "namei.h" -#include "vnode.h" #include "file.h" #include "acct.h" #include "exec.h" @@ -68,492 +45,505 @@ #include "wait.h" #include "mman.h" #include "malloc.h" +#include "syslog.h" #include "vm/vm.h" #include "vm/vm_param.h" #include "vm/vm_map.h" #include "vm/vm_kern.h" +#include "vm/vm_user.h" #include "machine/reg.h" -extern int dostacklimits; -#define copyinoutstr copyinstr +int exec_extract_strings __P((struct image_params *)); +int *exec_copyout_strings __P((struct image_params *)); /* - * execve() system call. + * execsw_set is constructed for us by the linker. Each of the items + * is a pointer to a `const struct execsw', hence the double pointer here. */ +extern const struct linker_set execsw_set; +const struct execsw **execsw = (const struct execsw **)&execsw_set.ls_items[0]; -struct execve_args { - char *fname; - char **argp; - char **envp; -}; - -/* ARGSUSED */ +/* + * execve() system call. + */ +int execve(p, uap, retval) struct proc *p; register struct execve_args *uap; int *retval; { - register struct nameidata *ndp; - struct nameidata nd; - char **argbuf, **argbufp, *stringbuf, *stringbufp; - char **vectp, *ep; - int needsenv, limitonargs, stringlen, addr, size, len, - rv, amt, argc, tsize, dsize, bsize, cnt, file_offset, - virtual_offset; + struct nameidata nd, *ndp; + char *stringbase, *stringp; + int *stack_base; + int error, resid, len, i; +#if 0 + char image_header[256]; +#endif + struct image_params image_params, *iparams; + struct vnode *vnodep; struct vattr attr; - struct vmspace *vs; - caddr_t newframe; - char shellname[MAXINTERP]; /* 05 Aug 92*/ - char *shellargs; - union { - char ex_shell[MAXINTERP]; /* #! and interpreter name */ - struct exec ex_hdr; - } exdata; - int indir = 0; + char *image_header; + + iparams = &image_params; + bzero((caddr_t)iparams, sizeof(struct image_params)); + image_header = (char *)0; + + /* + * Initialize a few constants in the common area + */ + iparams->proc = p; + iparams->uap = uap; + iparams->attr = &attr; /* - * Step 1. Lookup filename to see if we have something to execute. + * Allocate temporary demand zeroed space for argument and + * environment strings + */ + error = vm_allocate(kernel_map, (vm_offset_t *)&iparams->stringbase, + ARG_MAX, TRUE); + if (error) { + log(LOG_WARNING, "execve: failed to allocate string space\n"); + return (error); + } + + if (!iparams->stringbase) { + error = ENOMEM; + goto exec_fail; + } + iparams->stringp = iparams->stringbase; + iparams->stringspace = ARG_MAX; + + /* + * Translate the file name. namei() returns a vnode pointer + * in ni_vp amoung other things. */ ndp = &nd; + ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME; ndp->ni_segflg = UIO_USERSPACE; ndp->ni_dirp = uap->fname; -again: /* 05 Aug 92*/ - ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME; - - /* is it there? */ - if (rv = namei(ndp, p)) - return (rv); +interpret: - if (ndp->ni_vp->v_writecount) { /* don't exec if file is busy */ - rv = EBUSY; - goto exec_fail; + error = namei(ndp, p); + if (error) { + vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, + ARG_MAX); + goto exec_fail; } - /* does it have any attributes? */ - rv = VOP_GETATTR(ndp->ni_vp, &attr, p->p_ucred, p); - if (rv) - goto exec_fail; - if (ndp->ni_vp->v_mount->mnt_flag & MNT_NOEXEC) { /* no exec on fs ?*/ - rv = EACCES; - goto exec_fail; - } + iparams->vnodep = vnodep = ndp->ni_vp; - /* is it executable, and a regular file? */ - if ((ndp->ni_vp->v_mount->mnt_flag & MNT_NOEXEC) || /* 29 Jul 92*/ - (VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p)) || - ((attr.va_mode & 0111) == 0) || - (attr.va_type != VREG)) { - rv = EACCES; - goto exec_fail; + if (vnodep == NULL) { + error = ENOEXEC; + goto exec_fail_dealloc; } /* - * Step 2. Does the file contain a format we can - * understand and execute - * - * XXX 05 Aug 92 - * Read in first few bytes of file for segment sizes, magic number: - * ZMAGIC = demand paged RO text - * 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. + * Check file permissions (also 'opens' file) */ - exdata.ex_shell[0] = '\0'; /* for zero length files */ - - rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&exdata, sizeof(exdata), - 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p); + error = exec_check_permissions(iparams); + if (error) + goto exec_fail_dealloc; - /* big enough to hold a header? */ - if (rv) - goto exec_fail; - - if (exdata.ex_hdr.a_text != 0 && (ndp->ni_vp->v_flag & VTEXT) == 0 && - ndp->ni_vp->v_writecount != 0) { - rv = ETXTBSY; - goto exec_fail; +#if 0 + /* + * Read the image header from the file. + */ + error = vn_rdwr(UIO_READ, + vnodep, + image_header, + sizeof(image_header), + 0, + UIO_SYSSPACE, IO_NODELOCKED, + p->p_ucred, + &resid, + p); + if (error) + goto exec_fail_dealloc; + + /* Clear out junk in image_header if a partial read (small file) */ + if (resid) + bzero(image_header + (sizeof(image_header) - resid), resid); +#endif + /* + * Map the image header (first page) of the file into + * kernel address space + */ + error = vm_mmap(kernel_map, /* map */ + (vm_offset_t *)&image_header, /* address */ + NBPG, /* size */ + VM_PROT_READ, /* protection */ + VM_PROT_READ, /* max protection */ + MAP_FILE, /* flags */ + (caddr_t)vnodep, /* vnode */ + 0); /* offset */ + if (error) { + uprintf("mmap failed: %d\n",error); + goto exec_fail_dealloc; } - -#define SHELLMAGIC 0x2123 /* #! */ - - switch (exdata.ex_hdr.a_magic) { - case ZMAGIC: - virtual_offset = 0; - if (exdata.ex_hdr.a_text) { - file_offset = NBPG; - } else { - /* Bill's "screwball mode" */ - file_offset = 0; - } - break; - case QMAGIC: - virtual_offset = NBPG; - file_offset = 0; - break; - default: - if ((exdata.ex_hdr.a_magic & 0xffff) != SHELLMAGIC) { - /* NetBSD compatibility */ - switch (ntohl(exdata.ex_hdr.a_magic) & 0xffff) { - case ZMAGIC: - case QMAGIC: - virtual_offset = NBPG; - file_offset = 0; - break; - default: - rv = ENOEXEC; - goto exec_fail; - } - } else { - char *cp, *sp; - - if (indir) { - rv = ENOEXEC; - goto exec_fail; - } - for (cp = &exdata.ex_shell[2];; ++cp) { - if (cp >= &exdata.ex_shell[MAXINTERP]) { - rv = ENOEXEC; - goto exec_fail; - } - if (*cp == '\n') { - *cp = '\0'; - break; - } - if (*cp == '\t') - *cp = ' '; - } - cp = &exdata.ex_shell[2]; /* get shell interpreter name */ - while (*cp == ' ') - cp++; - - sp = shellname; - while (*cp && *cp != ' ') - *sp++ = *cp++; - *sp = '\0'; - - /* copy the args in the #! line */ - while (*cp == ' ') - cp++; - if (*cp) { - sp++; - shellargs = sp; - while (*cp) - *sp++ = *cp++; - *sp = '\0'; - } else { - shellargs = 0; - } - - indir = 1; /* indicate this is a script file */ + iparams->image_header = image_header; + + /* + * Loop through list of image activators, calling each one. + * If there is no match, the activator returns -1. If there + * is a match, but there was an error during the activation, + * the error is returned. Otherwise 0 means success. If the + * image is interpreted, loop back up and try activating + * the interpreter. + */ + for (i = 0; execsw[i]; ++i) { + if (execsw[i]->ex_imgact) + error = (*execsw[i]->ex_imgact)(iparams); + else + continue; + + if (error == -1) + continue; + if (error) + goto exec_fail_dealloc; + if (iparams->interpreted) { + /* free old vnode and name buffer */ vput(ndp->ni_vp); FREE(ndp->ni_pnbuf, M_NAMEI); + if (vm_deallocate(kernel_map, + (vm_offset_t)image_header, NBPG)) + panic("execve: header dealloc failed (1)"); - ndp->ni_dirp = shellname; /* find shell interpreter */ + /* set new name to that of the interpreter */ ndp->ni_segflg = UIO_SYSSPACE; - goto again; + ndp->ni_dirp = iparams->interpreter_name; + ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME; + goto interpret; } - /* NOT REACHED */ + break; + } + /* If we made it through all the activators and none matched, exit. */ + if (error == -1) { + error = ENOEXEC; + goto exec_fail_dealloc; } - /* sanity check "ain't not such thing as a sanity clause" -groucho */ - rv = ENOMEM; - if (/*exdata.ex_hdr.a_text == 0 || */ exdata.ex_hdr.a_text > MAXTSIZ || - exdata.ex_hdr.a_text % NBPG || exdata.ex_hdr.a_text > attr.va_size) - goto exec_fail; + /* + * Copy out strings (args and env) and initialize stack base + */ + stack_base = exec_copyout_strings(iparams); + p->p_vmspace->vm_minsaddr = (char *)stack_base; - if (exdata.ex_hdr.a_data == 0 || exdata.ex_hdr.a_data > DFLDSIZ - || exdata.ex_hdr.a_data > attr.va_size - || exdata.ex_hdr.a_data + exdata.ex_hdr.a_text > attr.va_size) - goto exec_fail; - if (exdata.ex_hdr.a_bss > MAXDSIZ) - goto exec_fail; - - if (exdata.ex_hdr.a_text + exdata.ex_hdr.a_data + exdata.ex_hdr.a_bss > MAXTSIZ + MAXDSIZ) - goto exec_fail; + /* + * Stuff argument count as first item on stack + */ + *(--stack_base) = iparams->argc; - if (exdata.ex_hdr.a_data + exdata.ex_hdr.a_bss > p->p_rlimit[RLIMIT_DATA].rlim_cur) - goto exec_fail; + /* close files on exec, fixup signals */ + fdcloseexec(p); + execsigs(p); - if (exdata.ex_hdr.a_entry > exdata.ex_hdr.a_text + exdata.ex_hdr.a_data) - goto exec_fail; + /* name this process - nameiexec(p, ndp) */ + len = MIN(ndp->ni_namelen,MAXCOMLEN); + bcopy(ndp->ni_ptr, p->p_comm, len); + p->p_comm[len] = 0; /* - * Step 3. File and header are valid. Now, dig out the strings - * out of the old process image. + * mark as executable, wakeup any process that was vforked and tell + * it that it now has it's own resources back */ + p->p_flag |= SEXEC; + if (p->p_pptr && (p->p_flag & SPPWAIT)) { + p->p_flag &= ~SPPWAIT; + wakeup((caddr_t)p->p_pptr); + } + + /* implement set userid/groupid */ + p->p_flag &= ~SUGID; /* - * We implement a single-pass algorithm that builds a new stack - * frame within the address space of the "old" process image, - * avoiding the second pass entirely. Thus, the new frame is - * in position to be run. This consumes much virtual address space, - * and two pages more of 'real' memory, such are the costs. - * [Also, note the cache wipe that's avoided!] + * Turn off kernel tracing for set-id programs, except for + * root. */ - - /* create anonymous memory region for new stack */ - vs = p->p_vmspace; - if ((unsigned)vs->vm_maxsaddr + MAXSSIZ < USRSTACK) - newframe = (caddr_t) USRSTACK - MAXSSIZ; - else - vs->vm_maxsaddr = newframe = (caddr_t) USRSTACK - 2*MAXSSIZ; - - /* don't do stack limit checking on traps temporarily XXX*/ - dostacklimits = 0; - - rv = vm_allocate(&vs->vm_map, &newframe, MAXSSIZ, FALSE); - if (rv) goto exec_fail; - - /* allocate string buffer and arg buffer */ - argbuf = (char **) (newframe + MAXSSIZ - 3*ARG_MAX); - stringbuf = stringbufp = ((char *)argbuf) + 2*ARG_MAX; - argbufp = argbuf; - - /* first, do args */ - vectp = uap->argp; - needsenv = 1; - limitonargs = ARG_MAX; - cnt = 0; - - /* first, do (shell name if any then) args */ - if (indir) { - ep = shellname; -thrice: - if (ep) { - /* did we outgrow initial argbuf, if so, die */ - if (argbufp >= (char **)stringbuf) { - rv = E2BIG; - goto exec_dealloc; - } - - if (rv = copyoutstr(ep, stringbufp, - (u_int)limitonargs, (u_int *)&stringlen)) { - if (rv == ENAMETOOLONG) - rv = E2BIG; - goto exec_dealloc; - } - suword(argbufp++, (int)stringbufp); - cnt++; - stringbufp += stringlen; - limitonargs -= stringlen; - } - - if (shellargs) { - ep = shellargs; - shellargs = 0; - goto thrice; - } - - if (indir) { - indir = 0; - /* orginal executable is 1st argument with scripts */ - ep = uap->fname; - goto thrice; - } - /* terminate in case no more args to script */ - suword(argbufp, 0); - if (vectp = uap->argp) vectp++; /* manually doing the first - argument with scripts */ + if (p->p_tracep && (attr.va_mode & (VSUID | VSGID)) && + suser(p->p_ucred, &p->p_acflag)) { + p->p_traceflag = 0; + vrele(p->p_tracep); + p->p_tracep = 0; + } + if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) { + p->p_ucred = crcopy(p->p_ucred); + p->p_ucred->cr_uid = attr.va_uid; + p->p_flag |= SUGID; + } + if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) { + p->p_ucred = crcopy(p->p_ucred); + p->p_ucred->cr_groups[0] = attr.va_gid; + p->p_flag |= SUGID; } -do_env_as_well: - if(vectp == 0) goto dont_bother; - - /* for each envp, copy in string */ - do { - /* did we outgrow initial argbuf, if so, die */ - if (argbufp == (char **)stringbuf) { - rv = E2BIG; - goto exec_dealloc; - } - - /* get an string pointer */ - ep = (char *)fuword(vectp++); - if (ep == (char *)-1) { - rv = EFAULT; - goto exec_dealloc; - } - - /* if not a null pointer, copy string */ - if (ep) { - if (rv = copyinoutstr(ep, stringbufp, - (u_int)limitonargs, (u_int *) &stringlen)) { - if (rv == ENAMETOOLONG) - rv = E2BIG; - goto exec_dealloc; - } - suword(argbufp++, (int)stringbufp); - cnt++; - stringbufp += stringlen; - limitonargs -= stringlen; - } else { - suword(argbufp++, 0); - break; - } - } while (limitonargs > 0); + /* + * Implement correct POSIX saved uid behavior. + */ + p->p_cred->p_svuid = p->p_ucred->cr_uid; + p->p_cred->p_svgid = p->p_ucred->cr_gid; -dont_bother: - if (limitonargs <= 0) { - rv = E2BIG; - goto exec_dealloc; - } + /* mark vnode pure text */ + ndp->ni_vp->v_flag |= VTEXT; - /* have we done the environment yet ? */ - if (needsenv) { - /* remember the arg count for later */ - argc = cnt; - vectp = uap->envp; - needsenv = 0; - goto do_env_as_well; - } - - /* At this point, one could optionally implement a - * second pass to condense the strings, arguement vectors, - * and stack to fit the fewest pages. - * - * One might selectively do this when copying was cheaper - * than leaving allocated two more pages per process. + /* + * If tracing the process, trap to debugger so breakpoints + * can be set before the program executes. */ + if (p->p_flag & STRC) + psignal(p, SIGTRAP); - /* stuff arg count on top of "new" stack */ - /* argbuf[-1] = (char *)argc;*/ - suword(argbuf-1,argc); + /* clear "fork but no exec" flag, as we _are_ execing */ + p->p_acflag &= ~AFORK; + + /* Set entry address */ + setregs(p, iparams->entry_addr, stack_base); /* - * Step 4. Build the new processes image. - * - * At this point, we are committed -- destroy old executable! + * free various allocated resources */ + if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, + ARG_MAX)) + panic("execve: string buffer dealloc failed (1)"); + if (vm_deallocate(kernel_map, (vm_offset_t)image_header, NBPG)) + panic("execve: header dealloc failed (2)"); + vput(ndp->ni_vp); + FREE(ndp->ni_pnbuf, M_NAMEI); - /* blow away all address space, except the stack */ - rv = vm_deallocate(&vs->vm_map, 0, USRSTACK - 2*MAXSSIZ); - if (rv) - goto exec_abort; + return (0); - /* destroy "old" stack */ - if ((unsigned)newframe < USRSTACK - MAXSSIZ) { - rv = vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ); - if (rv) - goto exec_abort; +exec_fail_dealloc: + if (iparams->stringbase && iparams->stringbase != (char *)-1) + if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase, + ARG_MAX)) + panic("execve: string buffer dealloc failed (2)"); + if (iparams->image_header && iparams->image_header != (char *)-1) + if (vm_deallocate(kernel_map, + (vm_offset_t)iparams->image_header, NBPG)) + panic("execve: header dealloc failed (3)"); + vput(ndp->ni_vp); + FREE(ndp->ni_pnbuf, M_NAMEI); + +exec_fail: + if (iparams->vmspace_destroyed) { + /* sorry, no more process anymore. exit gracefully */ +#if 0 /* XXX */ + vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ); +#endif + kexit(p, W_EXITCODE(0, SIGABRT)); + /* NOT REACHED */ + return(0); } else { - rv = vm_deallocate(&vs->vm_map, USRSTACK - 2*MAXSSIZ, MAXSSIZ); - if (rv) - goto exec_abort; + return(error); } +} - /* build a new address space */ +/* + * Destroy old address space, and allocate a new stack + * The new stack is only SGROWSIZ large because it is grown + * automatically in trap.c. + */ +int +exec_new_vmspace(iparams) + struct image_params *iparams; +{ + int error; + struct vmspace *vmspace = iparams->proc->p_vmspace; + caddr_t stack_addr = (caddr_t) (USRSTACK - SGROWSIZ); + iparams->vmspace_destroyed = 1; + /* Blow away entire process VM */ + vm_deallocate(&vmspace->vm_map, 0, USRSTACK); - /* treat text, data, and bss in terms of integral page size */ - tsize = roundup(exdata.ex_hdr.a_text, NBPG); - dsize = roundup(exdata.ex_hdr.a_data, NBPG); - bsize = roundup(exdata.ex_hdr.a_bss, NBPG); + /* Allocate a new stack */ + error = vm_allocate(&vmspace->vm_map, (vm_offset_t *)&stack_addr, + SGROWSIZ, FALSE); + if (error) + return(error); - addr = virtual_offset; + vmspace->vm_ssize = SGROWSIZ >> PAGE_SHIFT; - /* map text as being read/execute only and demand paged */ - rv = vm_mmap(&vs->vm_map, &addr, tsize, VM_PROT_READ|VM_PROT_EXECUTE, - VM_PROT_DEFAULT, MAP_FILE|MAP_PRIVATE|MAP_FIXED, - (caddr_t)ndp->ni_vp, file_offset); - if (rv) - goto exec_abort; + /* Initialize maximum stack address */ + vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ; - addr = virtual_offset + tsize; + return(0); +} - /* map data as being read/write and demand paged */ - rv = vm_mmap(&vs->vm_map, &addr, dsize, - VM_PROT_READ | VM_PROT_WRITE | (tsize ? 0 : VM_PROT_EXECUTE), - VM_PROT_DEFAULT, MAP_FILE|MAP_PRIVATE|MAP_FIXED, - (caddr_t)ndp->ni_vp, file_offset + tsize); - if (rv) - goto exec_abort; +/* + * Copy out argument and environment strings from the old process + * address space into the temporary string buffer. + */ +int +exec_extract_strings(iparams) + struct image_params *iparams; +{ + char **argv, **envv; + char *argp, *envp; + int length; - /* create anonymous memory region for bss */ - addr = virtual_offset + tsize + dsize; - rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE); - if (rv) - goto exec_abort; + /* + * extract arguments first + */ + + argv = iparams->uap->argv; + + if (argv) + while (argp = (caddr_t) fuword(argv++)) { + if (argp == (caddr_t) -1) + return (EFAULT); + if (copyinstr(argp, iparams->stringp, iparams->stringspace, + &length) == ENAMETOOLONG) + return(E2BIG); + iparams->stringspace -= length; + iparams->stringp += length; + iparams->argc++; + } /* - * Step 5. Prepare process for execution. + * extract environment strings */ - /* touchup process information -- vm system is unfinished! */ - vs->vm_tsize = tsize/NBPG; /* text size (pages) XXX */ - vs->vm_dsize = (dsize+bsize)/NBPG; /* data size (pages) XXX */ - vs->vm_taddr = (caddr_t) virtual_offset; /* virtual address of text */ - vs->vm_daddr = (caddr_t) virtual_offset + tsize; /* virtual address of data */ - vs->vm_maxsaddr = newframe; /* user VA at max stack growth XXX */ - vs->vm_ssize = ((unsigned)vs->vm_maxsaddr + MAXSSIZ - - (unsigned)argbuf)/ NBPG + 1; /* stack size (pages) */ - dostacklimits = 1; /* allow stack limits to be enforced XXX */ + envv = iparams->uap->envv; + + if (envv) + while (envp = (caddr_t) fuword(envv++)) { + if (envp == (caddr_t) -1) + return (EFAULT); + if (copyinstr(envp, iparams->stringp, iparams->stringspace, + &length) == ENAMETOOLONG) + return(E2BIG); + iparams->stringspace -= length; + iparams->stringp += length; + iparams->envc++; + } - /* close files on exec, fixup signals */ - fdcloseexec(p); - execsigs(p); + return (0); +} - /* name this process - nameiexec(p, ndp) */ - len = MIN(ndp->ni_namelen,MAXCOMLEN); - bcopy(ndp->ni_ptr, p->p_comm, len); - p->p_comm[len] = 0; - - /* mark as executable, wakeup any process that was vforked and tell - * it that it now has it's own resources back */ - p->p_flag |= SEXEC; - if (p->p_pptr && (p->p_flag & SPPWAIT)) { - p->p_flag &= ~SPPWAIT; - wakeup(p->p_pptr); - } - - /* implement set userid/groupid */ - if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) { - p->p_ucred = crcopy(p->p_ucred); - p->p_cred->p_svuid = p->p_ucred->cr_uid = attr.va_uid; +/* + * Copy strings out to the new process address space, constructing + * new arg and env vector tables. Return a pointer to the base + * so that it can be used as the initial stack pointer. + */ +int * +exec_copyout_strings(iparams) + struct image_params *iparams; +{ + int argc, envc; + char **vectp; + char *stringp, *destp; + int *stack_base; + int vect_table_size, string_table_size; + + /* + * Calculate string base and vector table pointers. + */ + destp = (caddr_t) ((caddr_t)USRSTACK - + roundup((ARG_MAX - iparams->stringspace), sizeof(char *))); + /* + * The '+ 2' is for the null pointers at the end of each of the + * arg and env vector sets + */ + vectp = (char **) (destp - + (iparams->argc + iparams->envc + 2) * sizeof(char *)); + + /* + * vectp also becomes our initial stack base + */ + stack_base = (int *)vectp; + + stringp = iparams->stringbase; + argc = iparams->argc; + envc = iparams->envc; + + for (; argc > 0; --argc) { + *(vectp++) = destp; + while (*destp++ = *stringp++); } - if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) { - p->p_ucred = crcopy(p->p_ucred); - p->p_cred->p_svgid = p->p_ucred->cr_groups[0] = attr.va_gid; + + /* a null vector table pointer seperates the argp's from the envp's */ + *(vectp++) = NULL; + + for (; envc > 0; --envc) { + *(vectp++) = destp; + while (*destp++ = *stringp++); } - /* setup initial register state */ - p->p_regs[SP] = (unsigned) (argbuf - 1); - setregs(p, exdata.ex_hdr.a_entry); + /* end of vector table is a null pointer */ + *vectp = NULL; - ndp->ni_vp->v_flag |= VTEXT; /* mark vnode pure text */ + return (stack_base); +} - vput(ndp->ni_vp); - FREE(ndp->ni_pnbuf, M_NAMEI); +/* + * Check permissions of file to execute. + * Return 0 for success or error code on failure. + */ +int +exec_check_permissions(iparams) + struct image_params *iparams; +{ + struct proc *p = iparams->proc; + struct vnode *vnodep = iparams->vnodep; + struct vattr *attr = iparams->attr; + int error; - /* if tracing process, pass control back to debugger so breakpoints - can be set before the program "runs" */ - if (p->p_flag & STRC) - psignal(p, SIGTRAP); - p->p_acflag &= ~AFORK; /* remove fork, but no exec flag */ + /* + * Check number of open-for-writes on the file and deny execution + * if there are any. + */ + if (vnodep->v_writecount) { + return (ETXTBSY); + } - return (0); + /* Get file attributes */ + error = VOP_GETATTR(vnodep, attr, p->p_ucred, p); + if (error) + return (error); -exec_dealloc: - /* remove interim "new" stack frame we were building */ - vm_deallocate(&vs->vm_map, newframe, MAXSSIZ); + /* + * 1) Check if file execution is disabled for the filesystem that this + * file resides on. + * 2) Insure that at least one execute bit is on - otherwise root + * will always succeed, and we don't want to happen unless the + * file really is executable. + * 3) Insure that the file is a regular file. + */ + if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) || + ((attr->va_mode & 0111) == 0) || + (attr->va_type != VREG)) { + return (EACCES); + } -exec_fail: - dostacklimits = 1; - vput(ndp->ni_vp); - FREE(ndp->ni_pnbuf, M_NAMEI); + /* + * Zero length files can't be exec'd + */ + if (attr->va_size == 0) + return (ENOEXEC); - return(rv); + /* + * Disable setuid/setgid if the filesystem prohibits it or if + * the process is being traced. + */ + if ((vnodep->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & STRC)) + attr->va_mode &= ~(VSUID | VSGID); -exec_abort: - /* sorry, no more process anymore. exit gracefully */ - vm_deallocate(&vs->vm_map, newframe, MAXSSIZ); - vput(ndp->ni_vp); - FREE(ndp->ni_pnbuf, M_NAMEI); - kexit(p, W_EXITCODE(0, SIGABRT)); + /* + * Check for execute permission to file based on current credentials. + * Then call filesystem specific open routine (which does nothing + * in the general case). + */ + error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p); + if (error) + return (error); - /* NOTREACHED */ - return(0); + error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p); + if (error) + return (error); + + return (0); } diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6a742b0e160c..e1deb4d855fe 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_exit.c 7.35 (Berkeley) 6/27/91 - * $Id: kern_exit.c,v 1.9 1993/10/19 01:01:20 nate Exp $ + * $Id: kern_exit.c,v 1.14 1994/01/29 04:04:23 davidg Exp $ */ #include "param.h" @@ -48,6 +48,7 @@ #include "vnode.h" #include "syslog.h" #include "malloc.h" +#include "signalvar.h" #include "resourcevar.h" #include "machine/cpu.h" @@ -117,6 +118,10 @@ kexit(p, rv) */ fdfree(p); +#ifdef SYSVSEM + semexit(p); +#endif + /* The next two chunks should probably be moved to vmspace_exit. */ #ifdef SYSVSHM if (p->p_vmspace->vm_shm) @@ -153,7 +158,7 @@ kexit(p, rv) (void) ttywait(sp->s_ttyp); vgoneall(sp->s_ttyvp); } - vrele(sp->s_ttyvp); + vn_close(sp->s_ttyvp, FREAD, p->p_ucred, p); sp->s_ttyvp = NULL; /* * s_ttyp is not zero'd; we use this to indicate @@ -170,19 +175,9 @@ kexit(p, rv) * release trace file */ if (p->p_tracep) - vrele(p->p_tracep); + vn_close(p->p_tracep, FREAD|FWRITE, p->p_ucred, p); #endif - /* current process does not exist, as far as other parts of the - * system (clock) is concerned, since parts of it might not be - * there anymore */ - curproc = NULL; - - if (--p->p_limit->p_refcnt == 0) { - FREE(p->p_limit, M_SUBPROC); - p->p_limit = (struct plimit *) -1; - } - /* * Remove proc from allproc queue and pidhash chain. * Place onto zombproc. Unlink from parent's child list. @@ -246,6 +241,18 @@ done: p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; #endif /* + * current process does not exist, as far as other parts of the + * system (clock) is concerned, since parts of it might not be + * there anymore + */ + curproc = NULL; + + if (--p->p_limit->p_refcnt == 0) { + FREE(p->p_limit, M_SUBPROC); + p->p_limit = (struct plimit *) -1; + } + + /* * Finally, call machine-dependent code to release the remaining * resources including address space, the kernel stack and pcb. * The address space is released by "vmspace_free(p->p_vmspace)"; @@ -258,7 +265,24 @@ done: /* NOTREACHED */ } +/* + * Wait: check child processes to see if any have exited, + * stopped under trace, or (optionally) stopped by a signal. + * Pass back status and deallocate exited child's proc structure. + */ + +struct wait1_args { + int pid; + int *status; + int options; + struct rusage *rusage; #ifdef COMPAT_43 + int compat; +#endif +}; + +#ifdef COMPAT_43 +static int wait1(struct proc *, struct wait1_args *, int *); struct owait_args { int pid; @@ -268,6 +292,7 @@ struct owait_args { int compat; }; +int owait(p, uap, retval) struct proc *p; register struct owait_args *uap; @@ -279,7 +304,7 @@ owait(p, uap, retval) uap->pid = WAIT_ANY; uap->status = 0; uap->compat = 1; - return (wait1(p, uap, retval)); + return (wait1(p, (struct wait1_args *)uap, retval)); } struct wait4_args { @@ -290,6 +315,7 @@ struct wait4_args { int compat; }; +int wait4(p, uap, retval) struct proc *p; struct wait4_args *uap; @@ -297,28 +323,13 @@ wait4(p, uap, retval) { uap->compat = 0; - return (wait1(p, uap, retval)); + return (wait1(p, (struct wait1_args *)uap, retval)); } #else #define wait1 wait4 #endif -/* - * Wait: check child processes to see if any have exited, - * stopped under trace, or (optionally) stopped by a signal. - * Pass back status and deallocate exited child's proc structure. - */ - -struct wait1_args { - int pid; - int *status; - int options; - struct rusage *rusage; -#ifdef COMPAT_43 - int compat; -#endif -}; - +static int wait1(q, uap, retval) register struct proc *q; register struct wait1_args *uap; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index a387af7e9577..5ca1d910f937 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. * All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)kern_fork.c 7.29 (Berkeley) 5/15/91 - * $Id: kern_fork.c,v 1.2 1993/10/16 15:24:17 rgrimes Exp $ + * $Id: kern_fork.c,v 1.6.2.1 1994/05/04 07:54:38 rgrimes Exp $ */ #include "param.h" @@ -47,7 +54,10 @@ #include "ktrace.h" #include "vm/vm.h" +static int fork1(struct proc *, int, int *); + /* ARGSUSED */ +int fork(p, uap, retval) struct proc *p; void *uap; @@ -58,6 +68,7 @@ fork(p, uap, retval) } /* ARGSUSED */ +int vfork(p, uap, retval) struct proc *p; void *uap; @@ -69,6 +80,7 @@ vfork(p, uap, retval) int nprocs = 1; /* process 0 */ +static int fork1(p1, isvfork, retval) register struct proc *p1; int isvfork, retval[]; @@ -156,26 +168,21 @@ again: */ MALLOC(p2, struct proc *, sizeof(struct proc), M_PROC, M_WAITOK); nprocs++; + + /* Initialize all fields to zero */ + bzero((struct proc *)p2, sizeof(struct proc)); + p2->p_nxt = allproc; p2->p_nxt->p_prev = &p2->p_nxt; /* allproc is never NULL */ p2->p_prev = &allproc; allproc = p2; - p2->p_link = NULL; /* shouldn't be necessary */ - p2->p_rlink = NULL; /* shouldn't be necessary */ /* * Make a proc table entry for the new process. - * Start by zeroing the section of proc that is zero-initialized, - * then copy the section that is copied directly from the parent. + * Copy the section that is copied directly from the parent. */ - bzero(&p2->p_startzero, - (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero)); bcopy(&p1->p_startcopy, &p2->p_startcopy, (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy)); - p2->p_spare[0] = 0; /* XXX - should be in zero range */ - p2->p_spare[1] = 0; /* XXX - should be in zero range */ - p2->p_spare[2] = 0; /* XXX - should be in zero range */ - p2->p_spare[3] = 0; /* XXX - should be in zero range */ /* * Duplicate sub-structures as needed. diff --git a/sys/kern/kern_kinfo.c b/sys/kern/kern_kinfo.c index e9c97b6d3a0c..5d6da494162b 100644 --- a/sys/kern/kern_kinfo.c +++ b/sys/kern/kern_kinfo.c @@ -31,10 +31,11 @@ * SUCH DAMAGE. * * from: @(#)kern_kinfo.c 7.17 (Berkeley) 6/26/91 - * $Id: kern_kinfo.c,v 1.3 1993/10/16 15:24:18 rgrimes Exp $ + * $Id: kern_kinfo.c,v 1.9 1993/12/19 00:51:26 wollman Exp $ */ #include "param.h" +#include "systm.h" #include "proc.h" #include "kinfo.h" #include "ioctl.h" @@ -58,6 +59,7 @@ struct getkerninfo_args { }; /* ARGSUSED */ +int getkerninfo(p, uap, retval) struct proc *p; register struct getkerninfo_args *uap; @@ -67,10 +69,6 @@ getkerninfo(p, uap, retval) int bufsize; /* max size of users buffer */ int needed, locked, (*server)(), error = 0; - if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, - sizeof (bufsize))) - goto done; - switch (ki_type(uap->op)) { case KINFO_PROC: @@ -97,9 +95,14 @@ getkerninfo(p, uap, retval) error = (*server)(uap->op, NULL, NULL, uap->arg, &needed); goto done; } + + if (error = copyin((caddr_t)uap->size, (caddr_t)&bufsize, + sizeof (bufsize))) + goto done; + while (kinfo_lock.kl_lock) { kinfo_lock.kl_want++; - sleep(&kinfo_lock, PRIBIO+1); + tsleep((caddr_t)&kinfo_lock, PRIBIO+1, "kinflck", 0); kinfo_lock.kl_want--; kinfo_lock.kl_locked++; } @@ -119,7 +122,7 @@ getkerninfo(p, uap, retval) release: kinfo_lock.kl_lock--; if (kinfo_lock.kl_want) - wakeup(&kinfo_lock); + wakeup((caddr_t)&kinfo_lock); done: if (!error) *retval = needed; @@ -131,14 +134,18 @@ done: */ #define KINFO_PROCSLOP (5 * sizeof (struct kinfo_proc)) +int kinfo_doproc(op, where, acopysize, arg, aneeded) + int op; char *where; - int *acopysize, *aneeded; + int *acopysize; + int arg; + int *aneeded; { register struct proc *p; register struct kinfo_proc *dp = (struct kinfo_proc *)where; - register needed = 0; - int buflen; + register int needed = 0; + int buflen = 0; int doingzomb; struct eproc eproc; int error = 0; @@ -243,8 +250,10 @@ fill_eproc(p, ep) ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0; if (SESS_LEADER(p)) ep->e_flag |= EPROC_SLEADER; - if (p->p_wmesg) + if (p->p_wmesg) { strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); + ep->e_wmesg[WMESGLEN] = 0; /* prevents fault on long wmesg */ + } ep->e_xsize = ep->e_xrssize = 0; ep->e_xccount = ep->e_xswrss = 0; } @@ -252,9 +261,13 @@ fill_eproc(p, ep) /* * Get file structures. */ +int kinfo_file(op, where, acopysize, arg, aneeded) + int op; register char *where; - int *acopysize, *aneeded; + int *acopysize; + int arg; + int *aneeded; { int buflen, needed, error; struct file *fp; diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index 9b218294e33c..42ee4f550928 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_ktrace.c 7.15 (Berkeley) 6/21/91 - * $Id: kern_ktrace.c,v 1.4 1993/10/16 15:24:20 rgrimes Exp $ + * $Id: kern_ktrace.c,v 1.6 1993/12/19 00:51:27 wollman Exp $ */ #ifdef KTRACE @@ -46,8 +46,14 @@ #include "malloc.h" #include "syslog.h" -struct ktr_header * +static void ktrwrite(struct vnode *, struct ktr_header *); +static int ktrops(struct proc *, struct proc *, int, int, struct vnode *); +static int ktrsetchildren(struct proc *, struct proc *, int, int, struct vnode *); +static int ktrcanset(struct proc *, struct proc *); + +static struct ktr_header * ktrgetheader(type) + int type; { register struct ktr_header *kth; struct proc *p = curproc; /* XXX */ @@ -61,6 +67,7 @@ ktrgetheader(type) return (kth); } +void ktrsyscall(vp, code, narg, args) struct vnode *vp; int code, narg, args[]; @@ -83,6 +90,7 @@ ktrsyscall(vp, code, narg, args) FREE(kth, M_TEMP); } +void ktrsysret(vp, code, error, retval) struct vnode *vp; int code, error, retval; @@ -101,6 +109,7 @@ ktrsysret(vp, code, error, retval) FREE(kth, M_TEMP); } +void ktrnamei(vp, path) struct vnode *vp; char *path; @@ -114,11 +123,14 @@ ktrnamei(vp, path) FREE(kth, M_TEMP); } +void ktrgenio(vp, fd, rw, iov, len, error) struct vnode *vp; int fd; enum uio_rw rw; register struct iovec *iov; + int len; + int error; { struct ktr_header *kth = ktrgetheader(KTR_GENIO); register struct ktr_genio *ktp; @@ -150,9 +162,13 @@ done: FREE(ktp, M_TEMP); } +void ktrpsig(vp, sig, action, mask, code) struct vnode *vp; + int sig; sig_t action; + int mask; + int code; { struct ktr_header *kth = ktrgetheader(KTR_PSIG); struct ktr_psig kp; @@ -182,6 +198,7 @@ struct ktrace_args { }; /* ARGSUSED */ +int ktrace(curp, uap, retval) struct proc *curp; register struct ktrace_args *uap; @@ -276,8 +293,11 @@ done: return (error); } +static int ktrops(curp, p, ops, facs, vp) struct proc *curp, *p; + int ops; + int facs; struct vnode *vp; { @@ -311,8 +331,11 @@ ktrops(curp, p, ops, facs, vp) return (1); } +static int ktrsetchildren(curp, top, ops, facs, vp) struct proc *curp, *top; + int ops; + int facs; struct vnode *vp; { register struct proc *p; @@ -345,6 +368,7 @@ ktrsetchildren(curp, top, ops, facs, vp) /*NOTREACHED*/ } +static void ktrwrite(vp, kth) struct vnode *vp; register struct ktr_header *kth; @@ -399,6 +423,7 @@ ktrwrite(vp, kth) * * TODO: check groups. use caller effective gid. */ +static int ktrcanset(callp, targetp) struct proc *callp, *targetp; { diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 1a27d598ffcd..6841827446d0 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -31,16 +31,19 @@ * SUCH DAMAGE. * * from: @(#)kern_malloc.c 7.25 (Berkeley) 5/8/91 - * $Id: kern_malloc.c,v 1.3 1993/10/18 03:46:54 davidg Exp $ + * $Id: kern_malloc.c,v 1.8 1994/02/10 08:04:07 davidg Exp $ */ #include "param.h" +#include "systm.h" #include "proc.h" #include "kernel.h" #include "malloc.h" #include "vm/vm.h" #include "vm/vm_kern.h" +extern int vm_page_count; + struct kmembuckets bucket[MINBUCKET + 16]; struct kmemstats kmemstats[M_LAST]; struct kmemusage *kmemusage; @@ -63,7 +66,7 @@ malloc(size, type, flags) #ifdef KMEMSTATS register struct kmemstats *ksp = &kmemstats[type]; - if (((unsigned long)type) > M_LAST) + if (((unsigned long)type) >= M_LAST) panic("malloc - bogus type"); #endif @@ -224,18 +227,19 @@ free(addr, type) /* * Initialize the kernel memory allocator */ +void kmeminit() { register long indx; int npg; #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) - ERROR!_kmeminit:_MAXALLOCSAVE_too_big +# error "kmeminit: MAXALLOCSAVE too big" #endif #if (MAXALLOCSAVE < CLBYTES-1) - ERROR!_kmeminit:_MAXALLOCSAVE_too_small +# error "kmeminit: MAXALLOCSAVE too small" #endif - npg = VM_KMEM_SIZE/ NBPG; + npg = (VM_KMEM_SIZE + VM_MBUF_SIZE) / NBPG; kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, (vm_size_t)(npg * sizeof(struct kmemusage))); kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, @@ -250,5 +254,8 @@ kmeminit() } for (indx = 0; indx < M_LAST; indx++) kmemstats[indx].ks_limit = npg * NBPG * 6 / 10; + + /* limit the amount of mbuf space to 1/16 of system memory */ + kmemstats[M_MBUF].ks_limit = (vm_page_count * NBPG) / 16; #endif } diff --git a/sys/kern/kern__physio.c b/sys/kern/kern_physio.c index 1e08acd734d1..cf76f80ae202 100644 --- a/sys/kern/kern__physio.c +++ b/sys/kern/kern_physio.c @@ -45,7 +45,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: kern__physio.c,v 1.2 1993/10/16 15:24:06 rgrimes Exp $ + * $Id: kern_physio.c,v 1.1.2.2 1994/05/01 18:59:48 rgrimes Exp $ */ #include "param.h" @@ -58,44 +58,70 @@ #include "vm/vm.h" #include "specdev.h" -static physio(int (*)(), int, int, int, caddr_t, int *, struct proc *); - /* * Driver interface to do "raw" I/O in the address space of a * user process directly for read and write operations.. */ +int rawread(dev, uio) dev_t dev; struct uio *uio; { - return (uioapply(physio, cdevsw[major(dev)].d_strategy, dev, uio)); + return (uioapply(physio, (caddr_t) cdevsw[major(dev)].d_strategy, + (caddr_t) (u_long) dev, uio)); } +int rawwrite(dev, uio) dev_t dev; struct uio *uio; { - return (uioapply(physio, cdevsw[major(dev)].d_strategy, dev, uio)); + return (uioapply(physio, (caddr_t) cdevsw[major(dev)].d_strategy, + (caddr_t) (u_long) dev, uio)); } -static physio(strat, dev, off, rw, base, len, p) - int (*strat)(); + +int physio(strat, dev, bp, off, rw, base, len, p) + d_strategy_t strat; dev_t dev; + struct buf *bp; int rw, off; caddr_t base; int *len; struct proc *p; { - register struct buf *bp; - int amttodo = *len, error, amtdone; + int amttodo = *len; + int error, amtdone; vm_prot_t ftype; - static zero; + vm_offset_t v, lastv; caddr_t adr; + int oldflags; + int s; + + int bp_alloc = (bp == 0); + +/* + * keep the process from being swapped + */ + oldflags = p->p_flag; + p->p_flag |= SPHYSIO; rw = rw == UIO_READ ? B_READ : 0; /* create and build a buffer header for a transfer */ - bp = (struct buf *)malloc(sizeof(*bp), M_TEMP, M_NOWAIT); - bzero((char *)bp, sizeof(*bp)); /* 09 Sep 92*/ + + if (bp_alloc) { + bp = (struct buf *)getpbuf(); + bzero((char *)bp, sizeof(*bp)); /* 09 Sep 92*/ + } else { + s = splbio(); + while (bp->b_flags & B_BUSY) { + bp->b_flags |= B_WANTED; + tsleep((caddr_t)bp, PRIBIO, "physbw", 0); + } + bp->b_flags |= B_BUSY; + splx(s); + } + bp->b_flags = B_BUSY | B_PHYS | rw; bp->b_proc = p; bp->b_dev = dev; @@ -112,12 +138,12 @@ static physio(strat, dev, off, rw, base, len, p) /* first, check if accessible */ if (rw == B_READ && !useracc(base, bp->b_bcount, B_WRITE)) { - free(bp, M_TEMP); - return (EFAULT); + error = EFAULT; + goto errrtn; } if (rw == B_WRITE && !useracc(base, bp->b_bcount, B_READ)) { - free(bp, M_TEMP); - return (EFAULT); + error = EFAULT; + goto errrtn; } /* update referenced and dirty bits, handle copy objects */ @@ -125,21 +151,84 @@ static physio(strat, dev, off, rw, base, len, p) ftype = VM_PROT_READ | VM_PROT_WRITE; else ftype = VM_PROT_READ; -/* 09 Sep 92*/ for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount; + + lastv = 0; + for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount; adr += NBPG) { - vm_fault(&curproc->p_vmspace->vm_map, - adr, ftype, FALSE); - *(int *) adr += zero; + +/* + * make sure that the pde is valid and wired + */ + v = trunc_page(((vm_offset_t)vtopte(adr))); + if (v != lastv) { + vm_map_pageable(&p->p_vmspace->vm_map, v, + round_page(v+1), FALSE); + lastv = v; + } + +/* + * do the vm_fault if needed, do the copy-on-write thing when + * reading stuff off device into memory. + */ + if (ftype & VM_PROT_WRITE) { + /* + * properly handle copy-on-write + */ +#if 0 + *(volatile int *) adr += 0; +#endif + vm_fault(&curproc->p_vmspace->vm_map, + (vm_offset_t) adr, + VM_PROT_READ|VM_PROT_WRITE, FALSE); + } +#if 0 + else { + /* + * this clause is not really necessary because + * vslock does a vm_map_pageable FALSE. + * It is not optimally efficient to reference the + * page with the possiblity of it being paged out, but + * if this page is faulted here, it will be placed on the + * active queue, with the probability of it being paged + * out being very very low. This is here primarily for + * "symmetry". + */ + *(volatile int *) adr; + } +#endif } +/* + * if the process has been blocked by the wiring of the page table pages + * above or faults of other pages, then the vm_map_pageable contained in the + * vslock will fault the pages back in if they have been paged out since + * being referenced in the loop above. (vm_map_pageable calls vm_fault_wire + * which calls vm_fault to get the pages if needed.) + */ - /* lock in core */ + /* lock in core (perform vm_map_pageable, FALSE) */ vslock (base, bp->b_bcount); /* perform transfer */ physstrat(bp, strat, PRIBIO); - /* unlock */ + /* unlock (perform vm_map_pageable, TRUE) */ vsunlock (base, bp->b_bcount, 0); + + lastv = 0; + +/* + * unwire the pde + */ + for (adr = (caddr_t)trunc_page(base); adr < base + bp->b_bcount; + adr += NBPG) { + v = trunc_page(((vm_offset_t)vtopte(adr))); + if (v != lastv) { + vm_map_pageable(&p->p_vmspace->vm_map, v, round_page(v+1), TRUE); + lastv = v; + } + } + + amtdone = bp->b_bcount - bp->b_resid; amttodo -= amtdone; base += amtdone; @@ -147,7 +236,20 @@ static physio(strat, dev, off, rw, base, len, p) } while (amttodo && (bp->b_flags & B_ERROR) == 0 && amtdone > 0); error = bp->b_error; - free(bp, M_TEMP); +errrtn: + if (bp_alloc) { + relpbuf(bp); + } else { + bp->b_flags &= ~B_BUSY; + wakeup((caddr_t)bp); + } *len = amttodo; + +/* + * allow the process to be swapped + */ + p->p_flag &= ~SPHYSIO; + p->p_flag |= (oldflags & SPHYSIO); + return (error); } diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 3dc511da238a..e1f84a331dff 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_proc.c 7.16 (Berkeley) 6/28/91 - * $Id: kern_proc.c,v 1.2 1993/10/16 15:24:23 rgrimes Exp $ + * $Id: kern_proc.c,v 1.4 1993/12/19 00:51:28 wollman Exp $ */ #include "param.h" @@ -49,9 +49,17 @@ #include "ioctl.h" #include "tty.h" +struct prochd qs[NQS]; /* as good a place as any... */ +struct proc *zombproc; +struct proc *allproc; + +static void pgdelete(struct pgrp *); +static void orphanpg(struct pgrp *); + /* * Is p an inferior of the current process? */ +int inferior(p) register struct proc *p; { @@ -66,8 +74,7 @@ inferior(p) * Locate a process by number */ struct proc * -pfind(pid) - register pid; +pfind(int pid) { register struct proc *p = pidhash[PIDHASH(pid)]; @@ -81,8 +88,7 @@ pfind(pid) * Locate a process group by number */ struct pgrp * -pgfind(pgid) - register pid_t pgid; +pgfind(pid_t pgid) { register struct pgrp *pgrp = pgrphash[PIDHASH(pgid)]; @@ -95,9 +101,11 @@ pgfind(pgid) /* * Move p to a new or existing process group (and session) */ +void enterpgrp(p, pgid, mksess) register struct proc *p; pid_t pgid; + int mksess; { register struct pgrp *pgrp = pgfind(pgid); register struct proc **pp; @@ -186,6 +194,7 @@ done: /* * remove process from process group */ +void leavepgrp(p) register struct proc *p; { @@ -206,6 +215,7 @@ done: /* * delete a process group */ +static void pgdelete(pgrp) register struct pgrp *pgrp; { @@ -226,8 +236,6 @@ done: FREE(pgrp, M_PGRP); } -static orphanpg(); - /* * Adjust pgrp jobc counters when specified process changes process group. * We count the number of processes in each process group that "qualify" @@ -238,6 +246,7 @@ static orphanpg(); * entering == 0 => p is leaving specified group. * entering == 1 => p is entering specified group. */ +void fixjobc(p, pgrp, entering) register struct proc *p; register struct pgrp *pgrp; @@ -277,7 +286,7 @@ fixjobc(p, pgrp, entering) * if there are any stopped processes in the group, * hang-up all process in that group. */ -static +static void orphanpg(pg) struct pgrp *pg; { diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index cc76c7c6f406..2d1d7db1ce4e 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989, 1990, 1991 Regents of the University * of California. All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)kern_prot.c 7.21 (Berkeley) 5/3/91 - * $Id: kern_prot.c,v 1.3 1993/10/16 15:24:24 rgrimes Exp $ + * $Id: kern_prot.c,v 1.5.2.2 1994/05/04 07:54:41 rgrimes Exp $ */ /* @@ -39,8 +46,8 @@ */ #include "param.h" -#include "acct.h" #include "systm.h" +#include "acct.h" #include "ucred.h" #include "proc.h" #include "timeb.h" @@ -48,6 +55,7 @@ #include "malloc.h" /* ARGSUSED */ +int getpid(p, uap, retval) struct proc *p; void *uap; @@ -62,6 +70,7 @@ getpid(p, uap, retval) } /* ARGSUSED */ +int getppid(p, uap, retval) struct proc *p; void *uap; @@ -73,6 +82,7 @@ getppid(p, uap, retval) } /* Get process group ID; note that POSIX getpgrp takes no parameter */ +int getpgrp(p, uap, retval) struct proc *p; void *uap; @@ -84,6 +94,7 @@ getpgrp(p, uap, retval) } /* ARGSUSED */ +int getuid(p, uap, retval) struct proc *p; void *uap; @@ -98,6 +109,7 @@ getuid(p, uap, retval) } /* ARGSUSED */ +int geteuid(p, uap, retval) struct proc *p; void *uap; @@ -109,6 +121,7 @@ geteuid(p, uap, retval) } /* ARGSUSED */ +int getgid(p, uap, retval) struct proc *p; void *uap; @@ -128,6 +141,7 @@ getgid(p, uap, retval) * correctly in a library function. */ /* ARGSUSED */ +int getegid(p, uap, retval) struct proc *p; void *uap; @@ -143,6 +157,7 @@ struct getgroups_args { int *gidset; /* XXX not yet POSIX */ }; +int getgroups(p, uap, retval) struct proc *p; register struct getgroups_args *uap; @@ -172,6 +187,7 @@ getgroups(p, uap, retval) } /* ARGSUSED */ +int setsid(p, uap, retval) register struct proc *p; void *uap; @@ -207,6 +223,7 @@ struct setpgid_args { }; /* ARGSUSED */ +int setpgid(curp, uap, retval) struct proc *curp; register struct setpgid_args *uap; @@ -241,6 +258,7 @@ struct setuid_args { }; /* ARGSUSED */ +int setuid(p, uap, retval) struct proc *p; struct setuid_args *uap; @@ -262,6 +280,7 @@ setuid(p, uap, retval) pc->pc_ucred->cr_uid = uid; pc->p_ruid = uid; pc->p_svuid = uid; + p->p_flag |= SUGID; return (0); } @@ -270,6 +289,7 @@ struct seteuid_args { }; /* ARGSUSED */ +int seteuid(p, uap, retval) struct proc *p; struct seteuid_args *uap; @@ -289,6 +309,7 @@ seteuid(p, uap, retval) */ pc->pc_ucred = crcopy(pc->pc_ucred); pc->pc_ucred->cr_uid = euid; + p->p_flag |= SUGID; return (0); } @@ -297,6 +318,7 @@ struct setgid_args { }; /* ARGSUSED */ +int setgid(p, uap, retval) struct proc *p; struct setgid_args *uap; @@ -312,7 +334,8 @@ setgid(p, uap, retval) pc->pc_ucred = crcopy(pc->pc_ucred); pc->pc_ucred->cr_groups[0] = gid; pc->p_rgid = gid; - pc->p_svgid = gid; /* ??? */ + pc->p_svgid = gid; + p->p_flag |= SUGID; return (0); } @@ -321,6 +344,7 @@ struct setegid_args { }; /* ARGSUSED */ +int setegid(p, uap, retval) struct proc *p; struct setegid_args *uap; @@ -336,6 +360,7 @@ setegid(p, uap, retval) return (error); pc->pc_ucred = crcopy(pc->pc_ucred); pc->pc_ucred->cr_groups[0] = egid; + p->p_flag |= SUGID; return (0); } @@ -347,44 +372,37 @@ struct osetreuid_args { }; /* ARGSUSED */ +int osetreuid(p, uap, retval) register struct proc *p; struct osetreuid_args *uap; int *retval; { register struct pcred *pc = p->p_cred; - register uid_t ruid, euid; - int error; + struct seteuid_args e_args; - if (uap->ruid == -1) - ruid = pc->p_ruid; - else - ruid = uap->ruid; - /* - * Allow setting real uid to previous effective, for swapping real and - * effective. This should be: - * - * if (ruid != pc->p_ruid && - * (error = suser(pc->pc_ucred, &p->p_acflag))) - */ - if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && - (error = suser(pc->pc_ucred, &p->p_acflag))) - return (error); - if (uap->euid == -1) - euid = pc->pc_ucred->cr_uid; - else - euid = uap->euid; - if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && - euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) - return (error); /* - * Everything's okay, do it. Copy credentials so other references do - * not see our changes. + * Most calls to setreuid() are done in order to swap real and + * effective uids. In old versions of BSD, this was the only + * way to temporarily renounce privileges and be able to get + * them back. In the presence of the POSIX saved id, however, + * we can do this without modifying the real uid, which could have + * opened up a security hole. So, we implement this: when the user + * attempts to set its real uid, we just check to make sure + * that they will be able to seteuid() back to that id at some + * later time, but don't actually change the real uid. + * Logic taken from 4.4BSD. */ - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_uid = euid; - pc->p_ruid = ruid; - return (0); + if(uap->ruid != -1 && uap->ruid != pc->p_ruid + && uap->ruid != pc->p_svuid) { + return EPERM; + } + + if(uap->euid == -1) { + return 0; + } + e_args.euid = uap->euid; + return seteuid(p, &e_args, retval); } struct osetregid_args { @@ -393,41 +411,29 @@ struct osetregid_args { }; /* ARGSUSED */ +int osetregid(p, uap, retval) register struct proc *p; struct osetregid_args *uap; int *retval; { register struct pcred *pc = p->p_cred; - register gid_t rgid, egid; - int error; + struct setegid_args e_args; - if (uap->rgid == -1) - rgid = pc->p_rgid; - else - rgid = uap->rgid; /* - * Allow setting real gid to previous effective, for swapping real and - * effective. This didn't really work correctly in 4.[23], but is - * preserved so old stuff doesn't fail. This should be: - * - * if (rgid != pc->p_rgid && - * (error = suser(pc->pc_ucred, &p->p_acflag))) + * Same comments as for setreuid() apply here. */ - if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && - (error = suser(pc->pc_ucred, &p->p_acflag))) - return (error); - if (uap->egid == -1) - egid = pc->pc_ucred->cr_groups[0]; - else - egid = uap->egid; - if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && - egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) - return (error); - pc->pc_ucred = crcopy(pc->pc_ucred); - pc->pc_ucred->cr_groups[0] = egid; - pc->p_rgid = rgid; - return (0); + if(uap->rgid != -1 + && uap->rgid != pc->p_rgid + && uap->rgid != pc->p_svgid) { + return EPERM; + } + + if(uap->egid == -1) { + return 0; + } + e_args.egid = uap->egid; + return setegid(p, &e_args, retval); } #endif @@ -437,6 +443,7 @@ struct setgroups_args { }; /* ARGSUSED */ +int setgroups(p, uap, retval) struct proc *p; struct setgroups_args *uap; @@ -466,6 +473,7 @@ setgroups(p, uap, retval) /* * Check if gid is a member of the group set. */ +int groupmember(gid, cred) gid_t gid; register struct ucred *cred; @@ -486,6 +494,7 @@ groupmember(gid, cred) * indicating use of super-powers. * Returns 0 or error. */ +int suser(cred, acflag) struct ucred *cred; u_short *acflag; @@ -516,10 +525,11 @@ crget() * Free a cred structure. * Throws away space when ref count gets to 0. */ +void crfree(cr) struct ucred *cr; { - int s = splimp(); /* ??? */ + int s = splimp(); /* ??? XXX FIXME */ if (--cr->cr_ref != 0) { (void) splx(s); @@ -572,6 +582,7 @@ struct getlogin_args { }; /* ARGSUSED */ +int getlogin(p, uap, retval) struct proc *p; struct getlogin_args *uap; @@ -593,6 +604,7 @@ struct setlogin_args { }; /* ARGSUSED */ +int setlogin(p, uap, retval) struct proc *p; struct setlogin_args *uap; diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index e2f42e706c27..941ead222a34 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1,3 +1,10 @@ +/* + * Copyright (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. + */ /*- * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. * All rights reserved. @@ -31,10 +38,11 @@ * SUCH DAMAGE. * * from: @(#)kern_resource.c 7.13 (Berkeley) 5/9/91 - * $Id: kern_resource.c,v 1.6 1993/10/19 01:02:16 nate Exp $ + * $Id: kern_resource.c,v 1.7.2.1 1994/05/04 07:54:43 rgrimes Exp $ */ #include "param.h" +#include "systm.h" #include "resourcevar.h" #include "malloc.h" #include "proc.h" @@ -50,6 +58,7 @@ struct getpriority_args { int who; }; +int getpriority(curp, uap, retval) struct proc *curp; register struct getpriority_args *uap; @@ -110,6 +119,7 @@ struct setpriority_args { }; /* ARGSUSED */ +int setpriority(curp, uap, retval) struct proc *curp; register struct setpriority_args *uap; @@ -163,6 +173,7 @@ setpriority(curp, uap, retval) return (0); } +int donice(curp, chgp, n) register struct proc *curp, *chgp; register int n; @@ -190,6 +201,7 @@ struct setrlimit_args { }; /* ARGSUSED */ +int setrlimit(p, uap, retval) struct proc *p; register struct setrlimit_args *uap; @@ -273,6 +285,7 @@ struct getrlimit_args { }; /* ARGSUSED */ +int getrlimit(p, uap, retval) struct proc *p; register struct getrlimit_args *uap; @@ -291,6 +304,7 @@ struct getrusage_args { }; /* ARGSUSED */ +int getrusage(p, uap, retval) register struct proc *p; register struct getrusage_args *uap; @@ -322,6 +336,7 @@ getrusage(p, uap, retval) sizeof (struct rusage))); } +void ruadd(ru, ru2) register struct rusage *ru, *ru2; { diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e0e40b77809d..8450e1c2f588 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_sig.c 7.35 (Berkeley) 6/28/91 - * $Id: kern_sig.c,v 1.5 1993/10/16 15:24:27 rgrimes Exp $ + * $Id: kern_sig.c,v 1.9 1993/12/19 00:51:30 wollman Exp $ */ #define SIGPROP /* include signal properties table */ @@ -59,6 +59,11 @@ #include "kinfo_proc.h" #include "user.h" /* for coredump */ +static void setsigvec(struct proc *, int, struct sigaction *); +static void stop(struct proc *); +static void sigexit(struct proc *, int); +static int killpg1(struct proc *, int, int, int); + /* * Can process p, with pcred pc, send the signal signo to process q? */ @@ -77,6 +82,7 @@ struct sigaction_args { }; /* ARGSUSED */ +int sigaction(p, uap, retval) struct proc *p; register struct sigaction_args *uap; @@ -116,6 +122,7 @@ sigaction(p, uap, retval) return (0); } +void setsigvec(p, sig, sa) register struct proc *p; int sig; @@ -229,6 +236,7 @@ struct sigprocmask_args { sigset_t mask; }; +int sigprocmask(p, uap, retval) register struct proc *p; struct sigprocmask_args *uap; @@ -261,6 +269,7 @@ sigprocmask(p, uap, retval) } /* ARGSUSED */ +int sigpending(p, uap, retval) struct proc *p; void *uap; @@ -283,6 +292,7 @@ struct osigvec_args { }; /* ARGSUSED */ +int osigvec(p, uap, retval) struct proc *p; register struct osigvec_args *uap; @@ -327,6 +337,7 @@ struct osigblock_args { int mask; }; +int osigblock(p, uap, retval) register struct proc *p; struct osigblock_args *uap; @@ -344,6 +355,7 @@ struct osigsetmask_args { int mask; }; +int osigsetmask(p, uap, retval) struct proc *p; struct osigsetmask_args *uap; @@ -369,6 +381,7 @@ struct sigsuspend_args { }; /* ARGSUSED */ +int sigsuspend(p, uap, retval) register struct proc *p; struct sigsuspend_args *uap; @@ -397,6 +410,7 @@ struct sigstack_args { }; /* ARGSUSED */ +int sigstack(p, uap, retval) struct proc *p; register struct sigstack_args *uap; @@ -420,6 +434,7 @@ struct kill_args { }; /* ARGSUSED */ +int kill(cp, uap, retval) register struct proc *cp; register struct kill_args *uap; @@ -460,6 +475,7 @@ struct okillpg_args { }; /* ARGSUSED */ +int okillpg(p, uap, retval) struct proc *p; register struct okillpg_args *uap; @@ -476,6 +492,7 @@ okillpg(p, uap, retval) * Common code for kill process group/broadcast kill. * cp is calling process. */ +static int killpg1(cp, signo, pgid, all) register struct proc *cp; int signo, pgid, all; @@ -605,6 +622,10 @@ psignal(p, sig) register sig_t action; int mask; + /* Ignore signals to system (internal) daemons */ + if (p->p_flag & SSYS) + return; + if ((unsigned)sig >= NSIG || sig == 0) panic("psignal sig"); mask = sigmask(sig); @@ -795,6 +816,7 @@ out: * while (sig = CURSIG(curproc)) * psig(sig); */ +int issig(p) register struct proc *p; { @@ -932,6 +954,7 @@ issig(p) * Signals are handled elsewhere. * The process must not be on the run queue. */ +static void stop(p) register struct proc *p; { @@ -1012,6 +1035,7 @@ psig(sig) * If dumping core, save the signal number for the debugger. * Calls exit and does not return. */ +static void sigexit(p, sig) register struct proc *p; int sig; @@ -1037,6 +1061,7 @@ sigexit(p, sig) * or was not produced from the same program, * the link count to the corefile is > 1. */ +int coredump(p) register struct proc *p; { @@ -1061,12 +1086,12 @@ coredump(p) sprintf(name, "%s.core", p->p_comm); nd.ni_dirp = name; nd.ni_segflg = UIO_SYSSPACE; - if ((error = vn_open(&nd, p, FWRITE, 0644)) == 0) + if ((error = vn_open(&nd, p, FWRITE, 0600)) == 0) exists = 1; else exists = 0; if (error == ENOENT) - error = vn_open(&nd, p, O_CREAT | FWRITE, 0644); + error = vn_open(&nd, p, O_CREAT | FWRITE, 0600); if (error) return (error); vp = nd.ni_vp; @@ -1131,6 +1156,7 @@ out: * Flag error in case process won't see signal immediately (blocked or ignored). */ /* ARGSUSED */ +int nosys(p, args, retval) struct proc *p; void *args; diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index 6b9a5aba202d..bb860d2ca6bd 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1991 Regents of the University of California. * All rights reserved. * @@ -31,18 +38,20 @@ * SUCH DAMAGE. * * from: @(#)kern_subr.c 7.7 (Berkeley) 4/15/91 - * $Id: kern_subr.c,v 1.2 1993/10/16 15:24:30 rgrimes Exp $ + * $Id: kern_subr.c,v 1.5.2.1 1994/05/04 07:54:46 rgrimes Exp $ */ #include "param.h" #include "systm.h" #include "proc.h" -uiomove(cp, n, uio) - register caddr_t cp; +int +uiomove(xcp, n, uio) + register void *xcp; register int n; register struct uio *uio; { + caddr_t cp = (caddr_t)xcp; register struct iovec *iov; u_int cnt; int error = 0; @@ -93,8 +102,11 @@ uiomove(cp, n, uio) return (error); } +int uioapply(func, arg1, arg2, uio) int (*func)() ; + caddr_t arg1; + caddr_t arg2; register struct uio *uio; { register struct iovec *iov; @@ -117,7 +129,7 @@ uioapply(func, arg1, arg2, uio) continue; } cnt1 = cnt; - error = (*func)(arg1, arg2, uio->uio_offset, uio->uio_rw, + error = (*func)(arg1, arg2, NULL, uio->uio_offset, uio->uio_rw, iov->iov_base, &cnt1, uio->uio_procp); cnt -= cnt1; iov->iov_base += cnt; @@ -133,6 +145,7 @@ uioapply(func, arg1, arg2, uio) /* * Give next character to user as result of read. */ +int ureadc(c, uio) register int c; register struct uio *uio; @@ -171,32 +184,43 @@ again: return (0); } +char * strcat(src, append) - register char *src, *append; + register char *src; + const char *append; { + char *old = src; for (; *src; ++src) ; while (*src++ = *append++) ; + return old; } +char * strcpy(to, from) - register char *to, *from; + char *to; + const char *from; { - + char *old = to; for (; *to = *from; ++from, ++to) ; + return old; } +char * strncpy(to, from, cnt) - register char *to, *from; - register int cnt; + char *to; + const char *from; + int cnt; { + char *old = to; for (; cnt && (*to = *from); --cnt, ++from, ++to) ; *to = '\0'; + return old; } @@ -215,10 +239,11 @@ strcmp(s1, s2) -#ifndef lint /* unused except by ct.c, other oddities XXX */ +#ifdef notdef /* unused except by ct.c, other oddities XXX */ /* * Get next character written in by user from uio. */ +int uwritec(uio) struct uio *uio; { diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 4b888509b915..554d38b004c4 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * from: @(#)kern_synch.c 7.18 (Berkeley) 6/27/91 - * $Id: kern_synch.c,v 1.2 1993/10/16 15:24:32 rgrimes Exp $ + * $Id: kern_synch.c,v 1.4 1994/02/11 21:14:28 guido Exp $ */ #include "param.h" @@ -45,12 +45,17 @@ #include "machine/cpu.h" +static void endtsleep(caddr_t, int); + u_char curpri; /* usrpri of curproc */ /* * Force switch among equal priority processes every 100ms. */ -roundrobin() +void +roundrobin(dummy1, dummy2) + caddr_t dummy1; + int dummy2; { need_resched(); @@ -145,7 +150,10 @@ fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */ /* * Recompute process priorities, once a second */ -schedcpu() +void +schedcpu(dummy1, dummy2) + caddr_t dummy1; + int dummy2; { register fixpt_t loadfac = loadfactor(averunnable[0]); register struct proc *p; @@ -211,6 +219,7 @@ schedcpu() * For all load averages >= 1 and max p_cpu of 255, sleeping for at least * six times the loadfactor will decay p_cpu to zero. */ +void updatepri(p) register struct proc *p; { @@ -259,18 +268,18 @@ int safepri; * if possible, and EINTR is returned if the system call should * be interrupted by the signal (return EINTR). */ +int tsleep(chan, pri, wmesg, timo) caddr_t chan; int pri; - char *wmesg; + const char *wmesg; int timo; { register struct proc *p = curproc; register struct slpque *qp; register s; - int sig, catch = pri & PCATCH; + int sig = 0, catch = pri & PCATCH; extern int cold; - int endtsleep(); s = splhigh(); if (cold || panicstr) { @@ -326,7 +335,7 @@ tsleep(chan, pri, wmesg, timo) p->p_stats->p_ru.ru_nvcsw++; swtch(); #include "ddb.h" -#ifdef NDDB +#if NDDB > 0 /* handy breakpoint location after process "wakes" */ asm(".globl bpendtsleep ; bpendtsleep:"); #endif @@ -354,9 +363,12 @@ resume: * set timeout flag and undo the sleep. If proc * is stopped, just unsleep so it will remain stopped. */ -endtsleep(p) - register struct proc *p; +void +endtsleep(arg1, dummy) + caddr_t arg1; + int dummy; { + register struct proc *p = (struct proc *)arg1; int s = splhigh(); if (p->p_wchan) { @@ -369,9 +381,11 @@ endtsleep(p) splx(s); } +#if 1 /* XXX this should go away... */ /* * Short-term, non-interruptable sleep. */ +void sleep(chan, pri) caddr_t chan; int pri; @@ -417,17 +431,19 @@ sleep(chan, pri) p->p_stat = SSLEEP; p->p_stats->p_ru.ru_nvcsw++; swtch(); -#ifdef NDDB +#if NDDB > 0 /* handy breakpoint location after process "wakes" */ asm(".globl bpendsleep ; bpendsleep:"); #endif curpri = p->p_usrpri; splx(s); } +#endif /* * Remove a process from its wait queue */ +void unsleep(p) register struct proc *p; { @@ -452,6 +468,7 @@ unsleep(p) * Wakeup on "chan"; set all processes * sleeping on chan to run state. */ +void wakeup(chan) register caddr_t chan; { @@ -501,6 +518,7 @@ restart: * Initialize the (doubly-linked) run queues * to be empty. */ +void rqinit() { register int i; @@ -514,6 +532,7 @@ rqinit() * placing it on the run queue if it is in memory, * and awakening the swapper if it isn't in memory. */ +void setrun(p) register struct proc *p; { @@ -555,6 +574,7 @@ setrun(p) * Arrange to reschedule if the resulting priority * is better than that of the current process. */ +void setpri(p) register struct proc *p; { @@ -567,29 +587,40 @@ setpri(p) need_resched(); } -#ifdef NDDB -#define DDBFUNC(s) ddb_##s +#if NDDB > 0 +#define DDBFUNC(s) db_##s +void DDBFUNC(ps) () { int np; + int nl=0; struct proc *ap, *p, *pp; np = nprocs; p = ap = allproc; - printf(" pid proc addr uid ppid pgrp flag stat comm wchan\n"); + db_printf(" pid proc addr uid ppid pgrp flag stat comm wchan\n"); while (--np >= 0) { + /* + * XXX just take 20 for now... + */ + if(nl++==20) { + db_printf("--More--"); + cngetc(); + db_printf("\b\b\b\b\b\b\b\b"); + nl=0; + } pp = p->p_pptr; if (pp == 0) pp = p; if (p->p_stat) { - printf("%5d %06x %06x %3d %5d %5d %06x %d %s ", + db_printf("%5d %06x %06x %3d %5d %5d %06x %d %s ", p->p_pid, ap, p->p_addr, p->p_cred->p_ruid, pp->p_pid, p->p_pgrp->pg_id, p->p_flag, p->p_stat, p->p_comm); if (p->p_wchan) { if (p->p_wmesg) - printf("%s ", p->p_wmesg); - printf("%x", p->p_wchan); + db_printf("%s ", p->p_wmesg); + db_printf("%x", p->p_wchan); } - printf("\n"); + db_printf("\n"); } ap = p->p_nxt; if (ap == 0 && np > 0) diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index f78786c3668a..a0c4a117bb2f 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -31,10 +31,11 @@ * SUCH DAMAGE. * * from: @(#)kern_time.c 7.15 (Berkeley) 3/17/91 - * $Id: kern_time.c,v 1.3 1993/10/16 15:24:33 rgrimes Exp $ + * $Id: kern_time.c,v 1.4 1993/11/25 01:33:14 wollman Exp $ */ #include "param.h" +#include "systm.h" #include "resourcevar.h" #include "kernel.h" #include "proc.h" @@ -57,6 +58,7 @@ struct gettimeofday_args { }; /* ARGSUSED */ +int gettimeofday(p, uap, retval) struct proc *p; register struct gettimeofday_args *uap; @@ -83,6 +85,7 @@ struct settimeofday_args { }; /* ARGSUSED */ +int settimeofday(p, uap, retval) struct proc *p; struct settimeofday_args *uap; @@ -120,6 +123,7 @@ struct adjtime_args { }; /* ARGSUSED */ +int adjtime(p, uap, retval) struct proc *p; register struct adjtime_args *uap; @@ -185,6 +189,7 @@ struct getitimer_args { }; /* ARGSUSED */ +int getitimer(p, uap, retval) struct proc *p; register struct getitimer_args *uap; @@ -222,6 +227,7 @@ struct setitimer_args { }; /* ARGSUSED */ +int setitimer(p, uap, retval) struct proc *p; register struct setitimer_args *uap; @@ -265,9 +271,10 @@ setitimer(p, uap, retval) * This is where delay in processing this timeout causes multiple * SIGALRM calls to be compressed into one. */ -realitexpire(p) - register struct proc *p; +void +realitexpire(caddr_t arg1, int arg2) { + register struct proc *p = (struct proc *)arg1; int s; psignal(p, SIGALRM); @@ -295,6 +302,7 @@ realitexpire(p) * 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; { @@ -317,6 +325,7 @@ itimerfix(tv) * that it is called in a context where the timers * on which it is operating cannot change in value. */ +int itimerdecr(itp, usec) register struct itimerval *itp; int usec; @@ -356,6 +365,7 @@ expire: * it just gets very confused in this case. * Caveat emptor. */ +void timevaladd(t1, t2) struct timeval *t1, *t2; { @@ -365,6 +375,7 @@ timevaladd(t1, t2) timevalfix(t1); } +void timevalsub(t1, t2) struct timeval *t1, *t2; { @@ -374,6 +385,7 @@ timevalsub(t1, t2) timevalfix(t1); } +void timevalfix(t1) struct timeval *t1; { diff --git a/sys/kern/kern_xxx.c b/sys/kern/kern_xxx.c index d904a8a6af26..e9445e3db512 100644 --- a/sys/kern/kern_xxx.c +++ b/sys/kern/kern_xxx.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)kern_xxx.c 7.17 (Berkeley) 4/20/91 - * $Id: kern_xxx.c,v 1.5 1993/10/24 06:19:56 paul Exp $ + * $Id: kern_xxx.c,v 1.7 1994/01/18 05:28:24 nate Exp $ */ #include "param.h" @@ -42,6 +42,7 @@ #include "utsname.h" /* ARGSUSED */ +int gethostid(p, uap, retval) struct proc *p; void *uap; @@ -57,6 +58,7 @@ struct sethostid_args { }; /* ARGSUSED */ +int sethostid(p, uap, retval) struct proc *p; struct sethostid_args *uap; @@ -76,6 +78,7 @@ struct gethostname_args { }; /* ARGSUSED */ +int gethostname(p, uap, retval) struct proc *p; struct gethostname_args *uap; @@ -93,6 +96,7 @@ struct sethostname_args { }; /* ARGSUSED */ +int sethostname(p, uap, retval) struct proc *p; register struct sethostname_args *uap; @@ -173,6 +177,7 @@ struct reboot_args { }; /* ARGSUSED */ +int reboot(p, uap, retval) struct proc *p; struct reboot_args *uap; @@ -187,9 +192,23 @@ reboot(p, uap, retval) } #ifdef COMPAT_43 +int oquota() { return (ENOSYS); } #endif + + +void +shutdown_nice(void) +{ + register struct proc *p; + + /* Send a signal to init(8) and have it shutdown the world */ + p = pfind(1); + psignal(p, SIGINT); + + return; +} diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 709065445b1a..77f61280c1bd 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -1,6 +1,6 @@ #! /bin/sh - # from: @(#)makesyscalls.sh 7.6 (Berkeley) 4/20/91 -# $Id: makesyscalls.sh,v 1.2 1993/10/16 15:24:36 rgrimes Exp $ +# $Id: makesyscalls.sh,v 1.3 1993/11/07 21:22:30 wollman Exp $ set -e @@ -36,6 +36,8 @@ awk < $1 " infile = \"$1\" "' + printf "#ifndef _SYS_SYSCALL_H_\n" > syshdr + printf "#define _SYS_SYSCALL_H_ 1\n" > syshdr printf "/*\n * System call switch table.\n *\n" > sysdcl printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysdcl @@ -160,6 +162,7 @@ awk < $1 " printf("\n#else /* %s */\n", compat) > syscompat printf("#define compat(n, name) 0, nosys\n") > syscompat printf("#endif /* %s */\n\n", compat) > syscompat + printf("#endif /* _SYS_SYSCALL_H_ */") > syshdr printf("};\n\n") > sysent printf("int\tnsysent = sizeof(sysent) / sizeof(sysent[0]);\n") > sysent @@ -169,4 +172,8 @@ awk < $1 " cat $sysdcl $syscompat $sysent >$syssw -chmod 444 $sysnames $syshdr $syssw +if [ -d CVS ]; then + true +else + chmod 444 $sysnames $syshdr $syssw +fi diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c index d60ea0218fc1..dd7a7c8be283 100644 --- a/sys/kern/spec_vnops.c +++ b/sys/kern/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)spec_vnops.c 7.37 (Berkeley) 5/30/91 - * $Id: spec_vnops.c,v 1.2 1993/10/16 15:24:37 rgrimes Exp $ + * $Id: spec_vnops.c,v 1.3 1993/11/25 01:33:15 wollman Exp $ */ #include "param.h" @@ -52,13 +52,13 @@ #include "disklabel.h" /* symbolic sleep message strings for devices */ -char devopn[] = "devopn"; -char devio[] = "devio"; -char devwait[] = "devwait"; -char devin[] = "devin"; -char devout[] = "devout"; -char devioc[] = "devioc"; -char devcls[] = "devcls"; +const char devopn[] = "devopn"; +const char devio[] = "devio"; +const char devwait[] = "devwait"; +const char devin[] = "devin"; +const char devout[] = "devout"; +const char devioc[] = "devioc"; +const char devcls[] = "devcls"; struct vnodeops spec_vnodeops = { spec_lookup, /* lookup */ @@ -99,6 +99,7 @@ struct vnodeops spec_vnodeops = { /* * Trivial lookup routine that always fails. */ +int spec_lookup(vp, ndp, p) struct vnode *vp; struct nameidata *ndp; @@ -116,6 +117,7 @@ spec_lookup(vp, ndp, p) * Otherwise, call device driver open function. */ /* ARGSUSED */ +int spec_open(vp, mode, cred, p) register struct vnode *vp; int mode; @@ -153,6 +155,7 @@ spec_open(vp, mode, cred, p) * Vnode op for read */ /* ARGSUSED */ +int spec_read(vp, uio, ioflag, cred) register struct vnode *vp; register struct uio *uio; @@ -237,6 +240,7 @@ spec_read(vp, uio, ioflag, cred) * Vnode op for write */ /* ARGSUSED */ +int spec_write(vp, uio, ioflag, cred) register struct vnode *vp; register struct uio *uio; @@ -319,6 +323,7 @@ spec_write(vp, uio, ioflag, cred) * Device ioctl operation. */ /* ARGSUSED */ +int spec_ioctl(vp, com, data, fflag, cred, p) struct vnode *vp; int com; @@ -351,6 +356,7 @@ spec_ioctl(vp, com, data, fflag, cred, p) } /* ARGSUSED */ +int spec_select(vp, which, fflags, cred, p) struct vnode *vp; int which, fflags; @@ -373,6 +379,7 @@ spec_select(vp, which, fflags, cred, p) /* * Just call the device strategy routine */ +int spec_strategy(bp) register struct buf *bp; { @@ -384,6 +391,7 @@ spec_strategy(bp) /* * This is a noop, simply returning what one has been given. */ +int spec_bmap(vp, bn, vpp, bnp) struct vnode *vp; daddr_t bn; @@ -402,6 +410,7 @@ spec_bmap(vp, bn, vpp, bnp) * At the moment we do not do any locking. */ /* ARGSUSED */ +int spec_lock(vp) struct vnode *vp; { @@ -410,6 +419,7 @@ spec_lock(vp) } /* ARGSUSED */ +int spec_unlock(vp) struct vnode *vp; { @@ -421,6 +431,7 @@ spec_unlock(vp) * Device close routine */ /* ARGSUSED */ +int spec_close(vp, flag, cred, p) register struct vnode *vp; int flag; @@ -428,7 +439,7 @@ spec_close(vp, flag, cred, p) struct proc *p; { dev_t dev = vp->v_rdev; - int (*devclose) __P((dev_t, int, int, struct proc *)); + int (*devclose) __P((int /*dev_t*/, int, int, struct proc *)); int mode; switch (vp->v_type) { @@ -479,6 +490,7 @@ spec_close(vp, flag, cred, p) /* * Print out the contents of a special device vnode. */ +void spec_print(vp) struct vnode *vp; { @@ -491,6 +503,7 @@ spec_print(vp) * Special device advisory byte-level locks. */ /* ARGSUSED */ +int spec_advlock(vp, id, op, fl, flags) struct vnode *vp; caddr_t id; @@ -505,6 +518,7 @@ spec_advlock(vp, id, op, fl, flags) /* * Special device failed operation */ +int spec_ebadf() { @@ -514,6 +528,7 @@ spec_ebadf() /* * Special device bad operation */ +int spec_badop() { diff --git a/sys/kern/subr_log.c b/sys/kern/subr_log.c index bc054fcd56dc..dcda60defa3b 100644 --- a/sys/kern/subr_log.c +++ b/sys/kern/subr_log.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)subr_log.c 7.11 (Berkeley) 3/17/91 - * $Id: subr_log.c,v 1.4 1993/10/16 15:24:39 rgrimes Exp $ + * $Id: subr_log.c,v 1.5 1993/11/25 01:33:16 wollman Exp $ */ /* @@ -60,6 +60,7 @@ struct logsoftc { int log_open; /* also used in log() */ /*ARGSUSED*/ +int logopen(dev, flags, mode, p) dev_t dev; int flags, mode; @@ -88,15 +89,19 @@ logopen(dev, flags, mode, p) } /*ARGSUSED*/ +int logclose(dev, flag) dev_t dev; + int flag; { log_open = 0; logsoftc.sc_state = 0; logsoftc.sc_sel = 0; /* 16 Jun 93 */ + return 0; } /*ARGSUSED*/ +int logread(dev, uio, flag) dev_t dev; struct uio *uio; @@ -142,6 +147,7 @@ logread(dev, uio, flag) } /*ARGSUSED*/ +int logselect(dev, rw, p) dev_t dev; int rw; @@ -163,6 +169,7 @@ logselect(dev, rw, p) return (0); } +void logwakeup() { struct proc *p; @@ -186,8 +193,12 @@ logwakeup() } /*ARGSUSED*/ +int logioctl(dev, com, data, flag) + dev_t dev; + int com; caddr_t data; + int flag; { long l; int s; diff --git a/sys/kern/subr_mcount.c b/sys/kern/subr_mcount.c index 7d57dc190c21..e36d21815333 100644 --- a/sys/kern/subr_mcount.c +++ b/sys/kern/subr_mcount.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)subr_mcount.c 7.10 (Berkeley) 5/7/91 - * $Id: subr_mcount.c,v 1.3 1993/10/16 15:24:41 rgrimes Exp $ + * $Id: subr_mcount.c,v 1.6 1993/12/20 16:41:12 davidg Exp $ */ #ifdef GPROF @@ -47,14 +47,16 @@ int profiling = 3; u_short *froms; struct tostruct *tos = 0; long tolimit = 0; -char *s_lowpc = (char *)KERNBASE; -extern char etext; -char *s_highpc = &etext; +extern char btext[]; +char *s_lowpc = btext; +extern char etext[]; +char *s_highpc = etext; u_long s_textsize = 0; int ssiz; u_short *sbuf; u_short *kcount; +void kmstartup() { u_long fromssize, tossize; @@ -107,6 +109,7 @@ kmstartup() kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr)); } +void mcount() { register char *selfpc; /* r11 => r5 */ @@ -167,9 +170,6 @@ mcount() asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ #endif -#if defined(i386) - Fix Me!! -#endif /* i386 */ #if defined(tahoe) asm(" movl -8(fp),r12"); /* selfpc = callf frame */ asm(" movl (fp),r11"); @@ -189,8 +189,12 @@ mcount() asm("movw sr,%0" : "=g" (s)); asm("movw #0x2700,sr"); #else +#if defined(i386) + asm("cli"); +#else s = splhigh(); #endif +#endif /* * Check that frompcindex is a reasonable pc value. * For example: signal catchers get called from the stack, @@ -271,8 +275,12 @@ done: #if defined(hp300) asm("movw %0,sr" : : "g" (s)); #else +#if defined(i386) + asm("sti"); +#else splx(s); #endif +#endif /* and fall through */ out: #if defined(vax) diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index 66c9e13f0c22..6d4a61735965 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -1,3 +1,10 @@ +/* + * Copyright (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. + */ /*- * Copyright (c) 1986, 1988, 1991 The Regents of the University of California. * All rights reserved. @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)subr_prf.c 7.30 (Berkeley) 6/29/91 - * $Id: subr_prf.c,v 1.4.2.1 1993/11/14 18:13:07 rgrimes Exp $ + * $Id: subr_prf.c,v 1.6.2.1 1994/05/04 07:54:49 rgrimes Exp $ */ #include "param.h" @@ -129,7 +136,7 @@ panic(msg) #endif #include "ddb.h" #if NDDB > 0 - Debugger (); + Debugger ("panic"); #endif boot(bootopt); } @@ -139,7 +146,7 @@ panic(msg) */ void tablefull(tab) - char *tab; + const char *tab; { log(LOG_ERR, "%s: table is full\n", tab); @@ -285,12 +292,12 @@ logpri(level) putchar('>', TOLOG, NULL); } -int +void #ifdef __STDC__ addlog(const char *fmt, ...) #else addlog(fmt /*, va_alist */) - char *fmt; + const char *fmt; #endif { register int s; @@ -307,7 +314,6 @@ addlog(fmt /*, va_alist */) va_end(ap); } logwakeup(); - return (0); } int consintr = 1; /* ok to handle console interrupts? */ @@ -317,7 +323,7 @@ int printf(const char *fmt, ...) #else printf(fmt /*, va_alist */) - char *fmt; + const char *fmt; #endif { va_list ap; diff --git a/sys/kern/subr_rlist.c b/sys/kern/subr_rlist.c index 8185be26e30a..de25f048fe9c 100644 --- a/sys/kern/subr_rlist.c +++ b/sys/kern/subr_rlist.c @@ -45,35 +45,96 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: subr_rlist.c,v 1.2 1993/10/16 15:24:44 rgrimes Exp $ + * $Id: subr_rlist.c,v 1.5 1993/12/22 12:51:39 davidg Exp $ */ -#include "sys/param.h" -#include "sys/cdefs.h" -#include "sys/malloc.h" +#include "param.h" +#include "systm.h" +#include "cdefs.h" +#include "malloc.h" #include "rlist.h" +#include "vm/vm.h" +#include "vm/vm_map.h" + +extern vm_map_t kernel_map; /* * Resource lists. */ +#define RLIST_MIN 128 +static int rlist_count=0; +static struct rlist *rlfree; +int rlist_active; + +static struct rlist * +rlist_malloc() +{ + struct rlist *rl; + int i; + while( rlist_count < RLIST_MIN) { + extern vm_map_t kmem_map; + int s = splhigh(); + rl = (struct rlist *)kmem_malloc(kmem_map, NBPG, 0); + splx(s); + if( !rl) + break; + + for(i=0;i<(NBPG/(sizeof *rl));i++) { + rl->rl_next = rlfree; + rlfree = rl; + rlist_count++; + rl++; + } + } + + if( (rl = rlfree) == 0 ) + panic("Cannot get an rlist entry"); + + --rlist_count; + rlfree = rl->rl_next; + return rl; +} + +inline static void +rlist_mfree( struct rlist *rl) +{ + rl->rl_next = rlfree; + rlfree = rl; + ++rlist_count; +} + + /* * Add space to a resource list. Used to either * initialize a list or return free space to it. */ +void rlist_free (rlp, start, end) -register struct rlist **rlp; unsigned start, end; { + register struct rlist **rlp; + unsigned start, end; +{ struct rlist *head; + register struct rlist *olp = 0; + int s; + + s = splhigh(); + while( rlist_active) + tsleep((caddr_t)&rlist_active, PSWP, "rlistf", 0); + rlist_active = 1; + splx(s); head = *rlp; loop: /* if nothing here, insert (tail of list) */ if (*rlp == 0) { - *rlp = (struct rlist *)malloc(sizeof(**rlp), M_TEMP, M_NOWAIT); + *rlp = rlist_malloc(); (*rlp)->rl_start = start; (*rlp)->rl_end = end; (*rlp)->rl_next = 0; + rlist_active = 0; + wakeup((caddr_t)&rlist_active); return; } @@ -100,11 +161,21 @@ loop: if (end < (*rlp)->rl_start) { register struct rlist *nlp; - nlp = (struct rlist *)malloc(sizeof(*nlp), M_TEMP, M_NOWAIT); + nlp = rlist_malloc(); nlp->rl_start = start; nlp->rl_end = end; nlp->rl_next = *rlp; - *rlp = nlp; + /* + * If the new element is in front of the list, + * adjust *rlp, else don't. + */ + if( olp) { + olp->rl_next = nlp; + } else { + *rlp = nlp; + } + rlist_active = 0; + wakeup((caddr_t)&rlist_active); return; } @@ -117,6 +188,7 @@ loop: /* are we after this element */ if (start > (*rlp)->rl_end) { + olp = *rlp; rlp = &((*rlp)->rl_next); goto loop; } else @@ -134,11 +206,13 @@ scan: if (lp->rl_end + 1 == lpn->rl_start) { lp->rl_end = lpn->rl_end; lp->rl_next = lpn->rl_next; - free(lpn, M_TEMP); + rlist_mfree(lpn); } else lp = lp->rl_next; } } + rlist_active = 0; + wakeup((caddr_t)&rlist_active); } /* @@ -148,9 +222,18 @@ scan: * "*loc". (Note: loc can be zero if we don't wish the value) */ int rlist_alloc (rlp, size, loc) -struct rlist **rlp; unsigned size, *loc; { + struct rlist **rlp; + unsigned size, *loc; +{ register struct rlist *lp; + int s; + register struct rlist *olp = 0; + s = splhigh(); + while( rlist_active) + tsleep((caddr_t)&rlist_active, PSWP, "rlista", 0); + rlist_active = 1; + splx(s); /* walk list, allocating first thing that's big enough (first fit) */ for (; *rlp; rlp = &((*rlp)->rl_next)) @@ -163,13 +246,27 @@ struct rlist **rlp; unsigned size, *loc; { /* did we eat this element entirely? */ if ((*rlp)->rl_start > (*rlp)->rl_end) { lp = (*rlp)->rl_next; - free (*rlp, M_TEMP); - *rlp = lp; + rlist_mfree(*rlp); + /* + * if the deleted element was in fromt + * of the list, adjust *rlp, else don't. + */ + if (olp) { + olp->rl_next = lp; + } else { + *rlp = lp; + } } + rlist_active = 0; + wakeup((caddr_t)&rlist_active); return (1); + } else { + olp = *rlp; } + rlist_active = 0; + wakeup((caddr_t)&rlist_active); /* nothing in list that's big enough */ return (0); } @@ -178,14 +275,16 @@ struct rlist **rlp; unsigned size, *loc; { * Finished with this resource list, reclaim all space and * mark it as being empty. */ +void rlist_destroy (rlp) -struct rlist **rlp; { + struct rlist **rlp; +{ struct rlist *lp, *nlp; lp = *rlp; *rlp = 0; for (; lp; lp = nlp) { nlp = lp->rl_next; - free (lp, M_TEMP); + rlist_mfree(lp); } } diff --git a/sys/kern/subr_xxx.c b/sys/kern/subr_xxx.c index e6457a2cd237..1c9cc9afe043 100644 --- a/sys/kern/subr_xxx.c +++ b/sys/kern/subr_xxx.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)subr_xxx.c 7.10 (Berkeley) 4/20/91 - * $Id: subr_xxx.c,v 1.2 1993/10/16 15:24:45 rgrimes Exp $ + * $Id: subr_xxx.c,v 1.3 1993/11/25 01:33:19 wollman Exp $ */ /* @@ -45,6 +45,7 @@ /* * Unsupported device function (e.g. writing to read-only device). */ +int enodev() { @@ -54,6 +55,7 @@ enodev() /* * Unconfigured device function; driver not configured. */ +int enxio() { @@ -63,6 +65,7 @@ enxio() /* * Unsupported ioctl function. */ +int enoioctl() { @@ -74,6 +77,7 @@ enoioctl() * This is used for an otherwise-reasonable operation * that is not supported by the current system binary. */ +int enosys() { @@ -84,6 +88,7 @@ enosys() * Return error for operation not supported * on a specific object or file type. */ +int eopnotsupp() { @@ -93,6 +98,7 @@ eopnotsupp() /* * Generic null operation, always returns success. */ +int nullop() { diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 2a4222496a0f..9f01bd7f3fcf 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)sys_generic.c 7.30 (Berkeley) 5/30/91 - * $Id: sys_generic.c,v 1.4 1993/10/16 15:24:47 rgrimes Exp $ + * $Id: sys_generic.c,v 1.6 1993/12/19 00:51:34 wollman Exp $ */ #include "param.h" @@ -45,6 +45,7 @@ #include "kernel.h" #include "stat.h" #include "malloc.h" +#include "signalvar.h" #ifdef KTRACE #include "ktrace.h" #endif @@ -59,6 +60,7 @@ struct read_args { * Read system call. */ /* ARGSUSED */ +int read(p, uap, retval) struct proc *p; register struct read_args *uap; @@ -117,6 +119,7 @@ struct readv_args { }; /* ARGSUSED */ +int readv(p, uap, retval) struct proc *p; register struct readv_args *uap; @@ -126,7 +129,7 @@ readv(p, uap, retval) register struct filedesc *fdp = p->p_fd; struct uio auio; register struct iovec *iov; - struct iovec *saveiov; + struct iovec *saveiov = 0; struct iovec aiov[UIO_SMALLIOV]; long i, cnt, error = 0; unsigned iovlen; @@ -207,6 +210,7 @@ struct write_args { unsigned count; }; +int write(p, uap, retval) struct proc *p; register struct write_args *uap; @@ -268,6 +272,7 @@ struct writev_args { unsigned iovcnt; }; +int writev(p, uap, retval) struct proc *p; register struct writev_args *uap; @@ -277,7 +282,7 @@ writev(p, uap, retval) register struct filedesc *fdp = p->p_fd; struct uio auio; register struct iovec *iov; - struct iovec *saveiov; + struct iovec *saveiov = 0; struct iovec aiov[UIO_SMALLIOV]; long i, cnt, error = 0; unsigned iovlen; @@ -362,6 +367,7 @@ struct ioctl_args { }; /* ARGSUSED */ +int ioctl(p, uap, retval) struct proc *p; register struct ioctl_args *uap; @@ -500,6 +506,7 @@ struct select_args { struct timeval *tv; }; +int select(p, uap, retval) register struct proc *p; register struct select_args *uap; @@ -605,6 +612,7 @@ selscan(struct proc *p, fd_set *ibits, fd_set *obits, int nfd, int *retval) case 1: flag = FWRITE; break; + default: /* pacify GCC */ case 2: flag = 0; break; } @@ -630,14 +638,14 @@ selscan(struct proc *p, fd_set *ibits, fd_set *obits, int nfd, int *retval) /*ARGSUSED*/ int -seltrue(dev_t dev, int which, struct proc *p) +seltrue(int /*dev_t*/ dev, int which, struct proc *p) { return (1); } void -selwakeup(pid_t pid, int coll) +selwakeup(int /*pid_t*/ pid, int coll) { register struct proc *p; diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index a0717fdc4e63..b129f4f4d5bd 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -31,23 +31,21 @@ * SUCH DAMAGE. * * from: @(#)sys_process.c 7.22 (Berkeley) 5/11/91 - * $Id: sys_process.c,v 1.5 1993/10/16 15:24:48 rgrimes Exp $ + * $Id: sys_process.c,v 1.9.2.2 1994/05/03 20:44:01 rgrimes Exp $ */ -#include <stddef.h> - -#define IPCREG #include "param.h" +#include "systm.h" #include "proc.h" #include "vnode.h" #include "buf.h" #include "ptrace.h" -#include "machine/eflags.h" #include "machine/reg.h" #include "machine/psl.h" #include "vm/vm.h" #include "vm/vm_page.h" +#include "vm/vm_kern.h" #include "user.h" @@ -76,30 +74,165 @@ #define SFTRC 0 #endif -/* - * `ipcreg' defined in <machine/reg.h> - * Should we define a structure with all regs? - */ -int sipcreg[NIPCREG] = - { 0,0,sEDI,sESI,sEBP,sEBX,sEDX,sECX,sEAX,sEIP,sCS,sEFLAGS,sESP,sSS }; - -struct { - int flag; -#define IPC_BUSY 1 -#define IPC_WANT 2 -#define IPC_DONE 4 - int req; /* copy of ptrace request */ - int *addr; /* copy of ptrace address */ - int data; /* copy of ptrace data */ - int error; /* errno from `procxmt' */ - int regs[NIPCREG]; /* PT_[GS]ETREG */ - caddr_t buf; /* PT_BREAD/WRITE */ - int buflen; /* " */ -} ipc; +int +pread (struct proc *procp, unsigned int addr, unsigned int *retval) { + int rv; + vm_map_t map, tmap; + vm_object_t object; + vm_offset_t kva = 0; + int page_offset; /* offset into page */ + vm_offset_t pageno; /* page number */ + vm_map_entry_t out_entry; + vm_prot_t out_prot; + boolean_t wired, single_use; + vm_offset_t off; + + /* Map page into kernel space */ + + map = &procp->p_vmspace->vm_map; + + page_offset = addr - trunc_page(addr); + pageno = trunc_page(addr); + + tmap = map; + rv = vm_map_lookup (&tmap, pageno, VM_PROT_READ, &out_entry, + &object, &off, &out_prot, &wired, &single_use); + + if (rv != KERN_SUCCESS) + return EINVAL; + + vm_map_lookup_done (tmap, out_entry); + + /* Find space in kernel_map for the page we're interested in */ + rv = vm_map_find (kernel_map, object, off, &kva, PAGE_SIZE, 1); + + if (!rv) { + vm_object_reference (object); + + rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, 0); + if (!rv) { + *retval = 0; + bcopy ((caddr_t)(kva + page_offset), retval, + sizeof *retval); + } + vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); + } -/* - * Process debugging system call. - */ + return rv; +} + +int +pwrite (struct proc *procp, unsigned int addr, unsigned int datum) { + int rv; + vm_map_t map, tmap; + vm_object_t object; + vm_offset_t kva = 0; + int page_offset; /* offset into page */ + vm_offset_t pageno; /* page number */ + vm_map_entry_t out_entry; + vm_prot_t out_prot; + boolean_t wired, single_use; + vm_offset_t off; + boolean_t fix_prot = 0; + + /* Map page into kernel space */ + + map = &procp->p_vmspace->vm_map; + + page_offset = addr - trunc_page(addr); + pageno = trunc_page(addr); + + /* + * Check the permissions for the area we're interested in. + */ + + if (vm_map_check_protection (map, pageno, pageno + PAGE_SIZE, + VM_PROT_WRITE) == FALSE) { + /* + * If the page was not writable, we make it so. + * XXX It is possible a page may *not* be read/executable, + * if a process changes that! + */ + fix_prot = 1; + /* The page isn't writable, so let's try making it so... */ + if ((rv = vm_map_protect (map, pageno, pageno + PAGE_SIZE, + VM_PROT_ALL, 0)) != KERN_SUCCESS) + return EFAULT; /* I guess... */ + } + + /* + * Now we need to get the page. out_entry, out_prot, wired, and + * single_use aren't used. One would think the vm code would be + * a *bit* nicer... We use tmap because vm_map_lookup() can + * change the map argument. + */ + + tmap = map; + rv = vm_map_lookup (&tmap, pageno, VM_PROT_WRITE, &out_entry, + &object, &off, &out_prot, &wired, &single_use); + if (rv != KERN_SUCCESS) { + return EINVAL; + } + + /* + * Okay, we've got the page. Let's release tmap. + */ + + vm_map_lookup_done (tmap, out_entry); + + /* + * Fault the page-table-page in... + */ + vm_map_pageable(map, trunc_page(vtopte(pageno)), + trunc_page(vtopte(pageno)) + NBPG, FALSE); + /* + * Fault the page in... + */ + + rv = vm_fault (map, pageno, VM_PROT_WRITE, FALSE); + if (rv != KERN_SUCCESS) { + /* + * release the page table page + */ + vm_map_pageable(map, trunc_page(vtopte(pageno)), + trunc_page(vtopte(pageno)) + NBPG, TRUE); + return EFAULT; + } + + /* + * The page may need to be faulted in again, it seems. + * This covers COW pages, I believe. + */ + + if (!rv) + rv = vm_fault (map, pageno, VM_PROT_WRITE, 0); + + /* Find space in kernel_map for the page we're interested in */ + rv = vm_map_find (kernel_map, object, off, (vm_offset_t *)&kva, + PAGE_SIZE, 1); + + if (!rv) { + vm_object_reference (object); + + rv = vm_map_pageable (kernel_map, kva, kva + PAGE_SIZE, FALSE); + if (!rv) { + bcopy (&datum, (caddr_t)(kva + page_offset), sizeof datum); + } + vm_map_remove (kernel_map, kva, kva + PAGE_SIZE); + } + + if (fix_prot) + vm_map_protect (map, pageno, pageno + PAGE_SIZE, + VM_PROT_READ|VM_PROT_EXECUTE, 0); + + /* + * release the page table page + */ + vm_map_pageable(map, trunc_page(vtopte(pageno)), + trunc_page(vtopte(pageno)) + NBPG, TRUE); + + return rv; +} struct ptrace_args { int req; @@ -108,6 +241,10 @@ struct ptrace_args { int data; }; +/* + * Process debugging system call. + */ +int ptrace(curp, uap, retval) struct proc *curp; register struct ptrace_args *uap; @@ -119,14 +256,13 @@ ptrace(curp, uap, retval) *retval = 0; if (uap->req == PT_TRACE_ME) { curp->p_flag |= STRC; - /*p->p_tptr = p->p_pptr; * What shall we do here ? */ return 0; } if ((p = pfind(uap->pid)) == NULL) { return ESRCH; } -#ifdef notyet +#ifdef PT_ATTACH if (uap->req != PT_ATTACH && ( (p->p_flag & STRC) == 0 || (p->p_tptr && curp != p->p_tptr) || @@ -134,10 +270,25 @@ ptrace(curp, uap, retval) return ESRCH; #endif - - #ifdef PT_ATTACH + if (uap->req != PT_ATTACH) { +#endif + if ((p->p_flag & STRC) == 0) + return EPERM; + if (p->p_stat != SSTOP || (p->p_flag & SWTED) == 0) + return EBUSY; +#ifdef PT_ATTACH + } +#endif + /* + * XXX The PT_ATTACH code is completely broken. It will + * be obsoleted by a /proc filesystem, so is it worth it + * to fix it? (Answer, probably. So that'll be next, + * I guess.) + */ + switch (uap->req) { +#ifdef PT_ATTACH case PT_ATTACH: if (curp->p_ucred->cr_uid != 0 && ( curp->p_ucred->cr_uid != p->p_ucred->cr_uid || @@ -146,7 +297,7 @@ ptrace(curp, uap, retval) p->p_tptr = curp; p->p_flag |= STRC; - psignal(p, SIGTRAP); + psignal(p, SIGSTOP); return 0; case PT_DETACH: @@ -166,346 +317,100 @@ ptrace(curp, uap, retval) splx(s); return 0; -#ifdef PT_INHERIT +# ifdef PT_INHERIT case PT_INHERIT: if ((p->p_flag & STRC) == 0) return ESRCH; p->p_flag |= SFTRC; return 0; -#endif - - default: - break; - } -#endif - - /* Other ptrace calls require target process to be in stopped state */ - if ((p->p_flag & STRC) == 0 || p->p_stat != SSTOP) { - return ESRCH; - } - - /* Acquire the ipc structure */ - while (ipc.flag & IPC_BUSY) { - ipc.flag |= IPC_WANT; - error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0); - if (error) - goto out; - } - - /* Got it, fill it */ - ipc.flag = IPC_BUSY; - ipc.error = 0; - ipc.req = uap->req; - ipc.addr = uap->addr; - ipc.data = uap->data; +# endif /* PT_INHERIT */ +#endif /* PT_ATTACH */ -#ifdef PT_GETREGS - switch (uap->req) { - case PT_SETREGS: - error = copyin((char *)ipc.addr, (char *)ipc.regs, sizeof(ipc.regs)); - if (error) - goto out; - break; - -#ifdef notyet /* requires change in number of args to ptrace syscall */ - case PT_BWRITE_I: - case PT_BWRITE_D: - ipc.buflen = uap->data; - ipc.buf = kmem_alloc_wait(kernelmap, uap->data); - error = copyin((char *)ipc.addr, (char *)ipc.buf, ipc.buflen); - if (error) { - kmem_free_wakeup(kernelmap, ipc.buf, ipc.buflen); - goto out; - } -#endif - default: - break; - } -#endif - - setrun(p); - while ((ipc.flag & IPC_DONE) == 0) { - error = tsleep((caddr_t)&ipc, PWAIT|PCATCH, "ipc", 0); - if (error) - goto out; - } - - *retval = ipc.data; - if (error = ipc.error) - goto out; - -#ifdef PT_GETREGS - switch (uap->req) { - case PT_GETREGS: - error = copyout((char *)ipc.regs, (char *)ipc.addr, sizeof(ipc.regs)); - break; - - case PT_BREAD_I: - case PT_BREAD_D: - /* Not yet */ - default: - break; - } -#endif - -out: - /* Release ipc structure */ - ipc.flag &= ~IPC_BUSY; - if (ipc.flag & IPC_WANT) { - ipc.flag &= ~IPC_WANT; - wakeup((caddr_t)&ipc); - } - return error; -} - -procxmt(p) - register struct proc *p; -{ - int i, *xreg, rv = 0; -#ifdef i386 - int new_eflags, old_cs, old_ds, old_es, old_ss, old_eflags; - int *regs; -#endif - - /* Are we still being traced? */ - if ((p->p_flag & STRC) == 0) - return 1; - - p->p_addr->u_kproc.kp_proc = *p; - fill_eproc(p, &p->p_addr->u_kproc.kp_eproc); - - switch (ipc.req) { case PT_READ_I: case PT_READ_D: - if (!useracc(ipc.addr, sizeof(ipc.data), B_READ)) { - ipc.error = EFAULT; - break; - } - ipc.error = copyin((char *)ipc.addr, (char *)&ipc.data, sizeof(ipc.data)); - break; - - case PT_READ_U: - if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) { - ipc.error = EFAULT; - break; - } - ipc.data = *(int *)((u_int)p->p_addr + (u_int)ipc.addr); - break; - + if (error = pread (p, (unsigned int)uap->addr, retval)) + return error; + return 0; case PT_WRITE_I: - case PT_WRITE_D: { /* 04 Sep 92*/ - vm_prot_t prot; /* current protection of region */ - int cow; /* ensure copy-on-write happens */ - - if (cow = (useracc(ipc.addr, sizeof(ipc.data), B_WRITE) == 0)) { - vm_offset_t addr = (vm_offset_t)ipc.addr; - vm_size_t size; - vm_prot_t max_prot; - vm_inherit_t inh; - boolean_t shared; - vm_object_t object; - vm_offset_t objoff; - - /* - * XXX - the useracc check is stronger than the vm - * checks because the user page tables are in the map. - * Anyway, most of this can be removed now that COW - * works. - */ - if (!useracc(ipc.addr, sizeof(ipc.data), B_READ) || - vm_region(&p->p_vmspace->vm_map, &addr, &size, - &prot, &max_prot, &inh, &shared, - &object, &objoff) != KERN_SUCCESS || - vm_protect(&p->p_vmspace->vm_map, ipc.addr, - sizeof(ipc.data), FALSE, - prot|VM_PROT_WRITE) != KERN_SUCCESS || - vm_fault(&p->p_vmspace->vm_map,trunc_page(ipc.addr), - VM_PROT_WRITE, FALSE) != KERN_SUCCESS) { - - ipc.error = EFAULT; - break; - } - } - ipc.error = copyout((char *)&ipc.data, - (char *)ipc.addr, sizeof(ipc.data)); - if (cow) - if (vm_protect(&p->p_vmspace->vm_map, ipc.addr, - sizeof(ipc.data), FALSE, - prot) != KERN_SUCCESS) - printf("ptrace: oops\n"); - break; - } - - case PT_WRITE_U: -#ifdef i386 - regs = p->p_regs; - /* - * XXX - privileged kernel state is scattered all over the - * user area. Only allow write access to areas known to - * be safe. - */ -#define GO_IF_SAFE(min, size) \ - if ((u_int)ipc.addr >= (min) \ - && (u_int)ipc.addr <= (min) + (size) - sizeof(int)) \ - goto pt_write_u - /* - * Allow writing entire FPU state. - */ - GO_IF_SAFE(offsetof(struct user, u_pcb) - + offsetof(struct pcb, pcb_savefpu), - sizeof(struct save87)); - /* - * Allow writing ordinary registers. Changes to segment - * registers and to some bits in %eflags will be silently - * ignored. Such changes ought to be an error. - */ -/* - * XXX - there is no define for the base of the user area except USRSTACK. - * XXX - USRSTACK is not the base of the user stack. It is the base of the - * user area. - */ -#define USER_OFF(va) ((u_int)(va) - USRSTACK) - GO_IF_SAFE(USER_OFF(regs), - (curpcb->pcb_flags & FM_TRAP ? tSS + 1 : sSS + 1) - * sizeof *regs); - ipc.error = EFAULT; - break; -#else - if ((u_int)ipc.addr > UPAGES * NBPG - sizeof(int)) { - ipc.error = EFAULT; - break; - } -#endif - pt_write_u: -#ifdef i386 - if (curpcb->pcb_flags & FM_TRAP) { - old_cs = regs[tCS]; - old_ds = regs[tES]; - old_es = regs[tES]; - old_ss = regs[tSS]; - old_eflags = regs[tEFLAGS]; - } else { - old_cs = regs[sCS]; - old_ss = regs[sSS]; - old_eflags = regs[sEFLAGS]; - } -#endif - *(int *)((u_int)p->p_addr + (u_int)ipc.addr) = ipc.data; -#ifdef i386 + case PT_WRITE_D: + if (error = pwrite (p, (unsigned int)uap->addr, + (unsigned int)uap->data)) + return error; + return 0; + case PT_STEP: + if (error = ptrace_single_step (p)) + return error; + /* fallthrough */ + case PT_CONTINUE: /* - * Don't allow segment registers to change (although they can - * be changed directly to certain values). - * Don't allow privileged bits in %eflags to change. Users - * have privilege to change TF and NT although although they - * usually shouldn't. - * XXX - fix PT_SETREGS. - * XXX - simplify. Maybe copy through a temporary struct. - * Watch out for problems when ipc.addr is not a multiple - * of the register size. + * Continue at addr uap->addr with signal + * uap->data; if uap->addr is 1, then we just + * let the chips fall where they may. + * + * The only check I'll make right now is for + * uap->data to be larger than NSIG; if so, we return + * EINVAL. */ -#define EFL_UNPRIVILEGED (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF \ - | EFL_TF | EFL_DF | EFL_OF | EFL_NT) - if (curpcb->pcb_flags & FM_TRAP) { - regs[tCS] = old_cs; - regs[tDS] = old_ds; - regs[tES] = old_es; - regs[tSS] = old_es; - new_eflags = regs[tEFLAGS]; - regs[tEFLAGS] - = (new_eflags & EFL_UNPRIVILEGED) - | (old_eflags & ~EFL_UNPRIVILEGED); - } else { - regs[sCS] = old_cs; - regs[sSS] = old_ss; - new_eflags = regs[sEFLAGS]; - regs[sEFLAGS] - = (new_eflags & EFL_UNPRIVILEGED) - | (old_eflags & ~EFL_UNPRIVILEGED); - } -#endif - break; + if (uap->data >= NSIG) + return EINVAL; - case PT_CONTINUE: - if (ipc.addr != (int *)1) { -#ifdef i386 - p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; -#endif + if (uap->addr != (int*)1) { + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + if (error = ptrace_set_pc (p, uap->addr)) + return error; } - p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ - if ((unsigned)ipc.data >= NSIG) { - ipc.error = EINVAL; - } else { - p->p_xstat = ipc.data; - rv = 1; - } - break; - case PT_KILL: - p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ - rv = 2; - break; + p->p_xstat = uap->data; - case PT_STEP: -#ifdef i386 - if (ipc.addr != (int *)1) { - p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; +/* if (p->p_stat == SSTOP) */ + setrun (p); + return 0; + case PT_READ_U: + if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { + return EFAULT; } - p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEFLAGS:sEFLAGS] |= PSL_T; -#endif - p->p_flag &= ~SSTRC; /* Only set by PT_SYSCALL */ - p->p_xstat = 0; - rv = 1; - break; - -#ifdef PT_SYSCALL - case PT_SYSCALL: - if (ipc.addr != (int *)1) { -#ifdef i386 - p->p_regs[(curpcb->pcb_flags&FM_TRAP)?tEIP:sEIP] = (int)ipc.addr; -#endif + p->p_addr->u_kproc.kp_proc = *p; + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + *retval = *(int*)((u_int)p->p_addr + (u_int)uap->addr); + return 0; + case PT_WRITE_U: + if ((u_int)uap->addr > (UPAGES * NBPG - sizeof(int))) { + return EFAULT; } - p->p_flag |= SSTRC; - p->p_xstat = 0; - rv = 1; - break; -#endif + p->p_addr->u_kproc.kp_proc = *p; + fill_eproc (p, &p->p_addr->u_kproc.kp_eproc); + *(int*)((u_int)p->p_addr + (u_int)uap->addr) = uap->data; + return 0; + case PT_KILL: + p->p_xstat = SIGKILL; + setrun(p); + return 0; #ifdef PT_GETREGS case PT_GETREGS: -#ifdef i386 - xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg; -#endif - - for (i = 0; i < NIPCREG; i++) - ipc.regs[i] = p->p_regs[xreg[i]]; - break; - + /* + * copyout the registers into addr. There's no + * size constraint!!! *GRRR* + */ + return ptrace_getregs(p, uap->addr); case PT_SETREGS: -#ifdef i386 - xreg = (curpcb->pcb_flags&FM_TRAP)?ipcreg:sipcreg; -#endif - - for (i = 0; i < NIPCREG; i++) - p->p_regs[xreg[i]] = ipc.regs[i]; - break; -#endif - -#ifdef PT_DUMP - case PT_DUMP: - /* Should be able to specify core file name */ - ipc.error = coredump(p); - break; -#endif - + /* + * copyin the registers from addr. Again, no + * size constraint!!! *GRRRR* + */ + return ptrace_setregs (p, uap->addr); +#endif /* PT_GETREGS */ default: - ipc.error = EINVAL; + break; } - ipc.flag |= IPC_DONE; - wakeup((caddr_t)&ipc); - if (rv == 2) - kexit(p, 0); /*???*/ + return 0; +} - return rv; +int +procxmt(p) + register struct proc *p; +{ + return 1; } /* @@ -520,6 +425,7 @@ struct profil_args { }; /* ARGSUSED */ +int profil(p, uap, retval) struct proc *p; register struct profil_args *uap; @@ -539,9 +445,14 @@ profil(p, uap, retval) * * so we've gotta check to make sure that the info set up for * addupc is set right... it's gotta be writable by the user... + * + * Add a little extra sanity checking so that end profil requests + * don't generate spurious faults. -jkh */ - if (useracc(uap->bufbase,uap->bufsize*sizeof(short),B_WRITE) == 0) + if (uap->bufbase && uap->bufsize && + useracc((caddr_t)uap->bufbase, uap->bufsize * sizeof(short), + B_WRITE) == 0) return EFAULT; p->p_stats->p_prof.pr_base = uap->bufbase; diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c index 247dbc9a2a59..3d59f7fc3f77 100644 --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)sys_socket.c 7.11 (Berkeley) 4/16/91 - * $Id: sys_socket.c,v 1.2 1993/10/16 15:24:50 rgrimes Exp $ + * $Id: sys_socket.c,v 1.4 1993/12/19 00:51:36 wollman Exp $ */ #include "param.h" @@ -51,6 +51,7 @@ struct fileops socketops = { soo_read, soo_write, soo_ioctl, soo_select, soo_close }; /* ARGSUSED */ +int soo_read(fp, uio, cred) struct file *fp; struct uio *uio; @@ -62,6 +63,7 @@ soo_read(fp, uio, cred) } /* ARGSUSED */ +int soo_write(fp, uio, cred) struct file *fp; struct uio *uio; @@ -72,6 +74,7 @@ soo_write(fp, uio, cred) uio, (struct mbuf *)0, (struct mbuf *)0, 0)); } +int soo_ioctl(fp, cmd, data, p) struct file *fp; int cmd; @@ -127,9 +130,11 @@ soo_ioctl(fp, cmd, data, p) if (IOCGROUP(cmd) == 'r') return (rtioctl(cmd, data, p)); return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, - (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0)); + (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0, + (struct mbuf *)0)); } +int soo_select(fp, which, p) struct file *fp; int which; @@ -169,6 +174,7 @@ soo_select(fp, which, p) return (0); } +int soo_stat(so, ub) register struct socket *so; register struct stat *ub; @@ -177,10 +183,11 @@ soo_stat(so, ub) bzero((caddr_t)ub, sizeof (*ub)); return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE, (struct mbuf *)ub, (struct mbuf *)0, - (struct mbuf *)0)); + (struct mbuf *)0, (struct mbuf *)0)); } /* ARGSUSED */ +int soo_close(fp, p) struct file *fp; struct proc *p; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 4fe1c433549c..2f624acebcf7 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -2,7 +2,7 @@ * System call names. * * DO NOT EDIT-- this file is automatically generated. - * created from $Id: syscalls.master,v 1.5 1993/10/24 06:19:58 paul Exp $ + * created from $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $ */ char *syscallnames[] = { @@ -196,12 +196,20 @@ char *syscallnames[] = { "getdomainname", /* 162 = getdomainname */ "setdomainname", /* 163 = setdomainname */ "uname", /* 164 = uname */ - "#165", /* 165 = nosys */ + "sysarch", /* 165 = sysarch */ "#166", /* 166 = nosys */ "#167", /* 167 = nosys */ "#168", /* 168 = nosys */ +#ifdef SYSVSEM + "semsys", /* 169 = semsys */ +#else "#169", /* 169 = nosys */ +#endif +#ifdef SYSVMSG + "msgsys", /* 170 = msgsys */ +#else "#170", /* 170 = nosys */ +#endif #ifdef SYSVSHM "shmsys", /* 171 = shmsys */ #else @@ -212,10 +220,17 @@ char *syscallnames[] = { "#174", /* 174 = nosys */ "#175", /* 175 = nosys */ "#176", /* 176 = nosys */ +#ifdef MACHVMCOMPAT + "vm_allocate", /* 177 = vm_allocate */ + "vm_deallocate", /* 178 = vm_deallocate */ + "vm_inherit", /* 179 = vm_inherit */ + "vm_protect", /* 180 = vm_protect */ +#else "#177", /* 177 = nosys */ "#178", /* 178 = nosys */ "#179", /* 179 = nosys */ "#180", /* 180 = nosys */ +#endif "setgid", /* 181 = setgid */ "setegid", /* 182 = setegid */ "seteuid", /* 183 = seteuid */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index f7470cccbd84..a43845ebd1a4 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $Id: syscalls.master,v 1.5 1993/10/24 06:19:58 paul Exp $ + $Id: syscalls.master,v 1.8 1994/01/31 10:27:25 davidg Exp $ ; from: @(#)syscalls.master 7.26 (Berkeley) 3/25/91 ; System call name/number master file. ; Processed to created init_sysent.c, syscalls.c and syscall.h. @@ -221,12 +221,20 @@ 162 STD 2 getdomainname 163 STD 2 setdomainname 164 STD 1 uname -165 UNIMPL 0 nosys +165 STD 2 sysarch 166 UNIMPL 0 nosys 167 UNIMPL 0 nosys 168 UNIMPL 0 nosys +#ifdef SYSVSEM +169 STD 5 semsys +#else 169 UNIMPL 0 nosys +#endif +#ifdef SYSVMSG +170 STD 6 msgsys +#else 170 UNIMPL 0 nosys +#endif #ifdef SYSVSHM 171 STD 4 shmsys #else @@ -237,10 +245,17 @@ 174 UNIMPL 0 nosys 175 UNIMPL 0 nosys 176 UNIMPL 0 nosys +#ifdef MACHVMCOMPAT +177 STD 4 svm_allocate vm_allocate +178 STD 3 svm_deallocate vm_deallocate +179 STD 4 svm_inherit vm_inherit +180 STD 5 svm_protect vm_protect +#else 177 UNIMPL 0 nosys 178 UNIMPL 0 nosys 179 UNIMPL 0 nosys 180 UNIMPL 0 nosys +#endif ; Syscalls 180-199 are used by/reserved for BSD 181 STD 1 setgid diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c new file mode 100644 index 000000000000..767c1d9ff19b --- /dev/null +++ b/sys/kern/sysv_ipc.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. Originally from University of Wisconsin. + * + * 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. + * + * from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$ + * + * @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91 + */ + +/* + * IPC routines shared by some or all of the SYSV IPC system calls. + */ + +#ifndef SYSVIPC + +#ifdef SYSVSHM +#define SYSVIPC +#endif + +#ifdef SYSVSEM +#define SYSVIPC +#endif + +#ifdef SYSVMSG +#define SYSVIPC +#endif + +#endif + +#ifdef SYSVIPC + +#include "param.h" +#include "systm.h" +#include "kernel.h" +#include "proc.h" +#include "ipc.h" +#include "shm.h" + +/* + * Perform access checking. + */ + +int +ipcaccess(ipc, mode, cred) + register struct ipc_perm *ipc; + int mode; + register struct ucred *cred; +{ + register int m; + + if (cred->cr_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. + */ + mode &= 0700; + m = ipc->mode; + if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) { + m <<= 3; + if (!groupmember(ipc->gid, cred) && + !groupmember(ipc->cgid, cred)) + m <<= 3; + } + if ((mode&m) == mode) + return (0); + return (EACCES); +} +#endif /* SYSVSHM */ diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c new file mode 100644 index 000000000000..f861f53ece52 --- /dev/null +++ b/sys/kern/sysv_msg.c @@ -0,0 +1,1038 @@ +/* + * Implementation of SVID messages + * + * Author: Daniel Boulet + * + * Copyright 1993 Daniel Boulet and RTMX Inc. + * + * This system call was implemented by Daniel Boulet under contract from RTMX. + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#ifdef SYSVMSG + +#include "param.h" +#include "systm.h" +#include "kernel.h" +#include "proc.h" +#include "msg.h" +#include "malloc.h" + +static int msgctl(), msgget(), msgsnd(), msgrcv(); + +int (*msgcalls[])() = { msgctl, msgget, msgsnd, msgrcv }; + +int nfree_msgmaps; /* # of free map entries */ +short free_msgmaps; /* head of linked list of free map entries */ +struct msg *free_msghdrs; /* list of free msg headers */ + +void +msginit() +{ + register int i; + vm_offset_t whocares1, whocares2; + + /* + * msginfo.msgssz should be a power of two for efficiency reasons. + * It is also pretty silly if msginfo.msgssz is less than 8 + * or greater than about 256 so ... + */ + + i = 8; + while ( i < 1024 && i != msginfo.msgssz ) { + i <<= 1; + } + if ( i != msginfo.msgssz ) { + printf("msginfo.msgssz=%d (0x%x)\n",msginfo.msgssz,msginfo.msgssz); + panic("msginfo.msgssz not a small power of 2"); + } + + if ( msginfo.msgseg > 32767 ) { + printf("msginfo.msgseg=%d\n",msginfo.msgseg); + panic("msginfo.msgseg > 32767"); + } + + if ( msgmaps == NULL ) { + panic("msgmaps is NULL"); + } + for ( i = 0; i < msginfo.msgseg; i += 1 ) { + if ( i > 0 ) { + msgmaps[i-1].next = i; + } + msgmaps[i].next = -1; /* implies entry is available */ + } + free_msgmaps = 0; + nfree_msgmaps = msginfo.msgseg; + + if ( msghdrs == NULL ) { + panic("msghdrs is NULL"); + } + for ( i = 0; i < msginfo.msgtql; i += 1 ) { + msghdrs[i].msg_type = 0; + if ( i > 0 ) { + msghdrs[i-1].msg_next = &msghdrs[i]; + } + msghdrs[i].msg_next = NULL; + } + free_msghdrs = &msghdrs[0]; + + if ( msqids == NULL ) { + panic("msqids is NULL"); + } + for ( i = 0; i < msginfo.msgmni; i += 1 ) { + msqids[i].msg_qbytes = 0; /* implies entry is available */ + msqids[i].msg_perm.seq = 0; /* reset to a known value */ + } + +} + +TEXT_SET(pseudo_set, msginit); + +/* + * Entry point for all MSG calls + */ + +struct msgsys_args { + u_int which; +}; + +int +msgsys(p, uap, retval) + struct caller *p; + struct msgsys_args *uap; + int *retval; +{ + if (uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0])) + return (EINVAL); + return ((*msgcalls[uap->which])(p, &uap[1], retval)); +} + +static +void +msg_freehdr(msghdr) +struct msg *msghdr; +{ + while ( msghdr->msg_ts > 0 ) { + short next; + if ( msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg ) { + panic("msghdr->msg_spot out of range"); + } + next = msgmaps[msghdr->msg_spot].next; + msgmaps[msghdr->msg_spot].next = free_msgmaps; + free_msgmaps = msghdr->msg_spot; + nfree_msgmaps += 1; + msghdr->msg_spot = next; + if ( msghdr->msg_ts >= msginfo.msgssz ) { + msghdr->msg_ts -= msginfo.msgssz; + } else { + msghdr->msg_ts = 0; + } + } + if ( msghdr->msg_spot != -1 ) { + panic("msghdr->msg_spot != -1"); + } + msghdr->msg_next = free_msghdrs; + free_msghdrs = msghdr; +} + +struct msgctl_args { + int msqid; + int cmd; + struct msqid_ds *user_msqptr; +}; + +int +msgctl(p, uap, retval) + struct proc *p; + register struct msgctl_args *uap; + int *retval; +{ + int msqid = uap->msqid; + int cmd = uap->cmd; + struct msqid_ds *user_msqptr = uap->user_msqptr; + struct ucred *cred = p->p_ucred; + int i, rval, eval; + struct msqid_ds msqbuf; + register struct msqid_ds *msqptr; + +#ifdef MSG_DEBUG + printf("call to msgctl(%d,%d,0x%x)\n",msqid,cmd,user_msqptr); +#endif + + msqid = IPCID_TO_IX(msqid); + + if ( msqid < 0 || msqid >= msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("msqid (%d) out of range (0<=msqid<%d)\n",msqid,msginfo.msgmni); +#endif + return(EINVAL); + } + + msqptr = &msqids[msqid]; + + if ( msqptr->msg_qbytes == 0 ) { +#ifdef MSG_DEBUG + printf("no such msqid\n"); +#endif + return(EINVAL); + } + if ( msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid) ) { +#ifdef MSG_DEBUG + printf("wrong sequence number\n"); +#endif + return(EINVAL); + } + + eval = 0; + rval = 0; + + switch (cmd) { + + case IPC_RMID: +#ifdef MSG_DEBUG + printf("IPC_RMID\n"); +#endif + { + struct msg *msghdr; + + if ( cred->cr_uid != 0 + && msqptr->msg_perm.cuid != cred->cr_uid + && msqptr->msg_perm.uid != cred->cr_uid ) { + return(EPERM); + } + msghdr = msqptr->msg_first; + + /* Free the message headers */ + + while ( msghdr != NULL ) { + struct msg *msghdr_tmp; + + /* Free the segments of each message */ + + msqptr->msg_cbytes -= msghdr->msg_ts; + msqptr->msg_qnum -= 1; + msghdr_tmp = msghdr; + msghdr = msghdr->msg_next; + msg_freehdr(msghdr_tmp); + + } + + if ( msqptr->msg_cbytes != 0 ) { + panic("msg_cbytes is screwed up"); + } + if ( msqptr->msg_qnum != 0 ) { + panic("msg_qnum is screwed up"); + } + + msqptr->msg_qbytes = 0; /* Mark it as free */ + + /* Make sure that anybody who is waiting notices the deletion */ + + wakeup( (caddr_t)msqptr ); + } + + break; + + case IPC_SET: +#ifdef MSG_DEBUG + printf("IPC_SET\n"); +#endif + if ( cred->cr_uid != 0 + && msqptr->msg_perm.cuid != cred->cr_uid + && msqptr->msg_perm.uid != cred->cr_uid ) { + return(EPERM); + } + if ( (eval = copyin(user_msqptr, &msqbuf, sizeof(msqbuf))) != 0 ) { + return(eval); + } + if ( msqbuf.msg_qbytes > msqptr->msg_qbytes + && cred->cr_uid != 0 ) { + return(EPERM); + } + if ( msqbuf.msg_qbytes > msginfo.msgmnb ) { +#ifdef MSG_DEBUG + printf("can't increase msg_qbytes beyond %d (truncating)\n",msginfo.msgmnb); +#endif + msqbuf.msg_qbytes = msginfo.msgmnb; /* silently restrict qbytes to system limit */ + } + if ( msqbuf.msg_qbytes == 0 ) { +#ifdef MSG_DEBUG + printf("can't reduce msg_qbytes to 0\n"); +#endif + return(EINVAL); /* non-standard errno! */ + } + msqptr->msg_perm.uid = msqbuf.msg_perm.uid; /* change the owner */ + msqptr->msg_perm.gid = msqbuf.msg_perm.gid; /* change the owner */ + msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) + | (msqbuf.msg_perm.mode & 0777); + msqptr->msg_qbytes = msqbuf.msg_qbytes; + msqptr->msg_ctime = time.tv_sec; + break; + + case IPC_STAT: +#ifdef MSG_DEBUG + printf("IPC_STAT\n"); +#endif + if ( (eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred)) ) { +#ifdef MSG_DEBUG + printf("requester doesn't have read access\n"); +#endif + return(eval); + } + rval = 0; + eval = copyout((caddr_t)msqptr, user_msqptr, sizeof(struct msqid_ds)); + break; + + default: +#ifdef MSG_DEBUG + printf("invalid command %d\n",cmd); +#endif + return(EINVAL); + } + + if ( eval == 0 ) { + *retval = rval; + } + return(eval); +} + +struct msgget_args { + key_t key; + int msgflg; +}; + +int +msgget(p, uap, retval) + struct proc *p; + register struct msgget_args *uap; + int *retval; +{ + int msqid, eval; + int key = uap->key; + int msgflg = uap->msgflg; + struct ucred *cred = p->p_ucred; + register struct msqid_ds *msqptr = NULL; + +#ifdef MSG_DEBUG + printf("msgget(0x%x,0%o)\n",key,msgflg); +#endif + + if ( key == IPC_PRIVATE ) { +#ifdef MSG_DEBUG + printf("private key\n"); +#endif + msqid = msginfo.msgmni; + } else { + for ( msqid = 0; msqid < msginfo.msgmni; msqid += 1 ) { + msqptr = &msqids[msqid]; + if ( msqptr->msg_qbytes != 0 && msqptr->msg_perm.key == key ) { + break; + } + } + if ( msqid < msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("found public key\n"); +#endif + if ( (msgflg & IPC_CREAT) && (msgflg & IPC_EXCL) ) { +#ifdef MSG_DEBUG + printf("not exclusive\n"); +#endif + return(EEXIST); + } + if ( (eval = ipcaccess(&msqptr->msg_perm, msgflg & 0700, cred)) ) { +#ifdef MSG_DEBUG + printf("requester doesn't have 0%o access\n",msgflg & 0700); +#endif + return(eval); + } + } else { +#ifdef MSG_DEBUG + printf("didn't find public key\n"); +#endif + } + } + + if ( msqid == msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("need to allocate the msqid_ds\n"); +#endif + if ( key == IPC_PRIVATE || (msgflg & IPC_CREAT) ) { + for ( msqid = 0; msqid < msginfo.msgmni; msqid += 1 ) { + /* + * Look for an unallocated and unlocked msqid_ds. + * msqid_ds's can be locked by msgsnd or msgrcv while they + * are copying the message in/out. We can't re-use the + * entry until they release it. + */ + + msqptr = &msqids[msqid]; + if ( msqptr->msg_qbytes == 0 + && (msqptr->msg_perm.mode & MSG_LOCKED) == 0 ) { + break; + } + } + if ( msqid == msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("no more msqid_ds's available\n"); +#endif + return(ENOSPC); + } +#ifdef MSG_DEBUG + printf("msqid %d is available\n",msqid+1); +#endif + msqptr->msg_perm.key = key; + msqptr->msg_perm.cuid = cred->cr_uid; + msqptr->msg_perm.uid = cred->cr_uid; + msqptr->msg_perm.cgid = cred->cr_gid; + msqptr->msg_perm.gid = cred->cr_gid; + msqptr->msg_perm.mode = (msgflg & 0777); + msqptr->msg_perm.seq += 1; /* Make sure that the returned msqid is unique */ + msqptr->msg_first = NULL; + msqptr->msg_last = NULL; + msqptr->msg_cbytes = 0; + msqptr->msg_qnum = 0; + msqptr->msg_qbytes = msginfo.msgmnb; + msqptr->msg_lspid = 0; + msqptr->msg_lrpid = 0; + msqptr->msg_stime = 0; + msqptr->msg_rtime = 0; + msqptr->msg_ctime = time.tv_sec; + } else { +#ifdef MSG_DEBUG + printf("didn't find it and wasn't asked to create it\n"); +#endif + return(ENOENT); + } + } + + *retval = IXSEQ_TO_IPCID(msqid,msqptr->msg_perm); /* Construct the unique msqid */ + return(0); +} + +struct msgsnd_args { + int msqid; + void *user_msgp; + size_t msgsz; + int msgflg; +}; + +int +msgsnd(p, uap, retval) + struct proc *p; + register struct msgsnd_args *uap; + int *retval; +{ + int msqid = uap->msqid; + void *user_msgp = uap->user_msgp; + size_t msgsz = uap->msgsz; + int msgflg = uap->msgflg; + int segs_needed, eval; + struct ucred *cred = p->p_ucred; + register struct msqid_ds *msqptr; + register struct msg *msghdr; + short next; + +#ifdef MSG_DEBUG + printf("call to msgsnd(%d,0x%x,%d,%d)\n",msqid,user_msgp,msgsz,msgflg); +#endif + + msqid = IPCID_TO_IX(msqid); + + if ( msqid < 0 || msqid >= msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("msqid (%d) out of range (0<=msqid<%d)\n",msqid,msginfo.msgmni); +#endif + return(EINVAL); + } + + msqptr = &msqids[msqid]; + if ( msqptr->msg_qbytes == 0 ) { +#ifdef MSG_DEBUG + printf("no such message queue id\n"); +#endif + return(EINVAL); + } + if ( msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid) ) { +#ifdef MSG_DEBUG + printf("wrong sequence number\n"); +#endif + return(EINVAL); + } + + if ( (eval = ipcaccess(&msqptr->msg_perm, IPC_W, cred)) ) { +#ifdef MSG_DEBUG + printf("requester doesn't have write access\n"); +#endif + return(eval); + } + + segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; +#ifdef MSG_DEBUG + printf("msgsz=%d, msgssz=%d, segs_needed=%d\n",msgsz,msginfo.msgssz,segs_needed); +#endif + while ( 1 ) { + int need_more_resources = 0; + + /* + * check msgsz + * (inside this loop in case msg_qbytes changes while we sleep) + */ + + if ( msgsz > msqptr->msg_qbytes ) { +#ifdef MSG_DEBUG + printf("msgsz > msqptr->msg_qbytes\n"); +#endif + return(EINVAL); + } + + if ( msqptr->msg_perm.mode & MSG_LOCKED ) { +#ifdef MSG_DEBUG + printf("msqid is locked\n"); +#endif + need_more_resources = 1; + } + if ( msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes ) { +#ifdef MSG_DEBUG + printf("msgsz + msg_cbytes > msg_qbytes\n"); +#endif + need_more_resources = 1; + } + if ( segs_needed > nfree_msgmaps ) { +#ifdef MSG_DEBUG + printf("segs_needed > nfree_msgmaps\n"); +#endif + need_more_resources = 1; + } + if ( free_msghdrs == NULL ) { +#ifdef MSG_DEBUG + printf("no more msghdrs\n"); +#endif + need_more_resources = 1; + } + + if ( need_more_resources ) { + + int we_own_it; + + if ( (msgflg & IPC_NOWAIT) != 0 ) { +#ifdef MSG_DEBUG + printf("need more resources but caller doesn't want to wait\n"); +#endif + return(EAGAIN); + } + + if ( (msqptr->msg_perm.mode & MSG_LOCKED) != 0 ) { +#ifdef MSG_DEBUG + printf("we don't own the msqid_ds\n"); +#endif + we_own_it = 0; + } else { + /* Force later arrivals to wait for our request */ +#ifdef MSG_DEBUG + printf("we own the msqid_ds\n"); +#endif + msqptr->msg_perm.mode |= MSG_LOCKED; + we_own_it = 1; + } +#ifdef MSG_DEBUG + printf("goodnight\n"); +#endif + eval = tsleep( (caddr_t)msqptr, (PZERO - 4) | PCATCH, "msg wait", 0 ); +#ifdef MSG_DEBUG + printf("good morning, eval=%d\n",eval); +#endif + if ( we_own_it ) { + msqptr->msg_perm.mode &= ~MSG_LOCKED; + } + if ( eval != 0 ) { +#ifdef MSG_DEBUG + printf("msgsnd: interrupted system call\n"); +#endif + return( EINTR ); + } + + /* + * Make sure that the msq queue still exists + */ + + if ( msqptr->msg_qbytes == 0 ) { +#ifdef MSG_DEBUG + printf("msqid deleted\n"); +#endif + /* The SVID says to return EIDRM. */ +#ifdef EIDRM + return(EIDRM); +#else + /* Unfortunately, BSD doesn't define that code (yet)! */ + return(EINVAL); +#endif + } + + } else { +#ifdef MSG_DEBUG + printf("got all the resources that we need\n"); +#endif + break; + } + + } + + /* + * We have the resources that we need. + * Make sure! + */ + + if ( msqptr->msg_perm.mode & MSG_LOCKED ) { + panic("msg_perm.mode & MSG_LOCKED"); /* bug somewhere */ + } + if ( segs_needed > nfree_msgmaps ) { + panic("segs_needed > nfree_msgmaps"); /* bug somewhere */ + } + if ( msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes ) { + panic("msgsz + msg_cbytes > msg_qbytes"); /* bug somewhere */ + } + if ( free_msghdrs == NULL ) { + panic("no more msghdrs"); /* bug somewhere */ + } + + /* + * Re-lock the msqid_ds in case we page-fault when copying in the message + */ + + if ( (msqptr->msg_perm.mode & MSG_LOCKED) != 0 ) { + panic("msqid_ds is already locked"); + } + msqptr->msg_perm.mode |= MSG_LOCKED; + + /* + * Allocate a message header + */ + + msghdr = free_msghdrs; + free_msghdrs = msghdr->msg_next; + msghdr->msg_spot = -1; + msghdr->msg_ts = msgsz; + + /* + * Allocate space for the message + */ + + while ( segs_needed > 0 ) { + if ( nfree_msgmaps <= 0 ) { + panic("not enough msgmaps"); + } + if ( free_msgmaps == -1 ) { + panic("nil free_msgmaps"); + } + next = free_msgmaps; + if ( next <= -1 ) { + panic("next too low #1"); + } + if ( next >= msginfo.msgseg ) { + panic("next out of range #1"); + } +#ifdef MSG_DEBUG + printf("allocating segment %d to message\n",next); +#endif + free_msgmaps = msgmaps[next].next; + nfree_msgmaps -= 1; + msgmaps[next].next = msghdr->msg_spot; + msghdr->msg_spot = next; + segs_needed -= 1; + } + + /* + * Copy in the message type + */ + + if ( (eval = copyin(user_msgp,&msghdr->msg_type,sizeof(msghdr->msg_type))) != 0 ) { +#ifdef MSG_DEBUG + printf("error %d copying the message type\n",eval); +#endif + msg_freehdr(msghdr); + msqptr->msg_perm.mode &= ~MSG_LOCKED; + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + return(eval); + } + user_msgp += sizeof(msghdr->msg_type); + + /* + * Validate the message type + */ + + if ( msghdr->msg_type < 1 ) { + msg_freehdr(msghdr); + msqptr->msg_perm.mode &= ~MSG_LOCKED; + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ +#ifdef MSG_DEBUG + printf("mtype (%d) < 1\n",msghdr->msg_type); +#endif + return(EINVAL); + } + + /* + * Copy in the message body + */ + + next = msghdr->msg_spot; + while ( msgsz > 0 ) { + size_t tlen; + if ( msgsz > msginfo.msgssz ) { + tlen = msginfo.msgssz; + } else { + tlen = msgsz; + } + if ( next <= -1 ) { + panic("next too low #2"); + } + if ( next >= msginfo.msgseg ) { + panic("next out of range #2"); + } + if ( (eval = copyin(user_msgp, &msgpool[next * msginfo.msgssz], tlen)) != 0 ) { +#ifdef MSG_DEBUG + printf("error %d copying in message segment\n",eval); +#endif + msg_freehdr(msghdr); + msqptr->msg_perm.mode &= ~MSG_LOCKED; + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + return(eval); + } + msgsz -= tlen; + user_msgp += tlen; + next = msgmaps[next].next; + } + if ( next != -1 ) { + panic("didn't use all the msg segments"); + } + + /* + * We've got the message. Unlock the msqid_ds. + */ + + msqptr->msg_perm.mode &= ~MSG_LOCKED; + + /* + * Make sure that the msqid_ds is still allocated. + */ + + if ( msqptr->msg_qbytes == 0 ) { + msg_freehdr(msghdr); + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + /* The SVID says to return EIDRM. */ +#ifdef EIDRM + return(EIDRM); +#else + /* Unfortunately, BSD doesn't define that code (yet)! */ + return(EINVAL); +#endif + } + + /* + * Put the message into the queue + */ + + if ( msqptr->msg_first == NULL ) { + msqptr->msg_first = msghdr; + msqptr->msg_last = msghdr; + } else { + msqptr->msg_last->msg_next = msghdr; + msqptr->msg_last = msghdr; + } + msqptr->msg_last->msg_next = NULL; + + msqptr->msg_cbytes += msghdr->msg_ts; + msqptr->msg_qnum += 1; + msqptr->msg_lspid = p->p_pid; + msqptr->msg_stime = time.tv_sec; + + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + *retval = 0; + return(0); +} + +struct msgrcv_args { + int msqid; + void *msgp; + size_t msgsz; + long msgtyp; + int msgflg; +}; + +int +msgrcv(p, uap, retval) + struct proc *p; + register struct msgrcv_args *uap; + int *retval; +{ + int msqid = uap->msqid; + void *user_msgp = uap->msgp; + size_t msgsz = uap->msgsz; + long msgtyp = uap->msgtyp; + int msgflg = uap->msgflg; + size_t len; + struct ucred *cred = p->p_ucred; + register struct msqid_ds *msqptr; + register struct msg *msghdr; + int eval; + short next; + +#ifdef MSG_DEBUG + printf("call to msgrcv(%d,0x%x,%d,%ld,%d)\n",msqid,user_msgp,msgsz,msgtyp,msgflg); +#endif + + msqid = IPCID_TO_IX(msqid); + + if ( msqid < 0 || msqid >= msginfo.msgmni ) { +#ifdef MSG_DEBUG + printf("msqid (%d) out of range (0<=msqid<%d)\n",msqid,msginfo.msgmni); +#endif + return(EINVAL); + } + + msqptr = &msqids[msqid]; + if ( msqptr->msg_qbytes == 0 ) { +#ifdef MSG_DEBUG + printf("no such message queue id\n"); +#endif + return(EINVAL); + } + if ( msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid) ) { +#ifdef MSG_DEBUG + printf("wrong sequence number\n"); +#endif + return(EINVAL); + } + + if ( (eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred)) ) { +#ifdef MSG_DEBUG + printf("requester doesn't have read access\n"); +#endif + return(eval); + } + + msghdr = NULL; + while ( msghdr == NULL ) { + + if ( msgtyp == 0 ) { + + msghdr = msqptr->msg_first; + if ( msghdr != NULL ) { + if ( msgsz < msghdr->msg_ts && (msgflg & MSG_NOERROR) == 0 ) { +#ifdef MSG_DEBUG + printf("first message on the queue is too big (want %d, got %d)\n",msgsz,msghdr->msg_ts); +#endif + return(E2BIG); + } + if ( msqptr->msg_first == msqptr->msg_last ) { + msqptr->msg_first = NULL; + msqptr->msg_last = NULL; + } else { + msqptr->msg_first = msghdr->msg_next; + if ( msqptr->msg_first == NULL ) { + panic("msg_first/last screwed up #1"); + } + } + } + + } else { + struct msg *previous; + struct msg **prev; + + previous = NULL; + prev = &(msqptr->msg_first); + while ( (msghdr = *prev) != NULL ) { + + /* + * Is this message's type an exact match or is this message's + * type less than or equal to the absolute value of a negative msgtyp? + * Note that the second half of this test can NEVER be true + * if msgtyp is positive since msg_type is always positive! + */ + + if ( msgtyp == msghdr->msg_type || msghdr->msg_type <= -msgtyp ) { +#ifdef MSG_DEBUG + printf("found message type %d, requested %d\n",msghdr->msg_type,msgtyp); +#endif + if ( msgsz < msghdr->msg_ts && (msgflg & MSG_NOERROR) == 0 ) { +#ifdef MSG_DEBUG + printf("requested message on the queue is too big (want %d, got %d)\n",msgsz,msghdr->msg_ts); +#endif + return(E2BIG); + } + *prev = msghdr->msg_next; + if ( msghdr == msqptr->msg_last ) { + if ( previous == NULL ) { + if ( prev != &msqptr->msg_first ) { + panic("msg_first/last screwed up #2"); + } + msqptr->msg_first = NULL; + msqptr->msg_last = NULL; + } else { + if ( prev == &msqptr->msg_first ) { + panic("msg_first/last screwed up #3"); + } + msqptr->msg_last = previous; + } + } + break; + } + previous = msghdr; + prev = &(msghdr->msg_next); + } + + } + + /* + * We've either extracted the msghdr for the appropriate message + * or there isn't one. + * If there is one then bail out of this loop. + */ + + if ( msghdr != NULL ) { + break; + } + + /* + * Hmph! No message found. Does the user want to wait? + */ + + if ( (msgflg & IPC_NOWAIT) != 0 ) { +#ifdef MSG_DEBUG + printf("no appropriate message found (msgtyp=%d)\n",msgtyp); +#endif + /* The SVID says to return ENOMSG. */ +#ifdef ENOMSG + return(ENOMSG); +#else + /* Unfortunately, BSD doesn't define that code (yet)! */ + return(EAGAIN); +#endif + } + + /* + * Wait for something to happen + */ + +#ifdef MSG_DEBUG + printf("msgrcv: goodnight\n"); +#endif + eval = tsleep( (caddr_t)msqptr, (PZERO - 4) | PCATCH, "msg wait", 0 ); +#ifdef MSG_DEBUG + printf("msgrcv: good morning (eval=%d)\n",eval); +#endif + + if ( eval != 0 ) { +#ifdef MSG_DEBUG + printf("msgsnd: interrupted system call\n"); +#endif + return( EINTR ); + } + + /* + * Make sure that the msq queue still exists + */ + + if ( msqptr->msg_qbytes == 0 + || msqptr->msg_perm.seq != IPCID_TO_SEQ(uap->msqid) ) { +#ifdef MSG_DEBUG + printf("msqid deleted\n"); +#endif + /* The SVID says to return EIDRM. */ +#ifdef EIDRM + return(EIDRM); +#else + /* Unfortunately, BSD doesn't define that code (yet)! */ + return(EINVAL); +#endif + } + + } + + /* + * Return the message to the user. + * + * First, do the bookkeeping (before we risk being interrupted). + */ + + msqptr->msg_cbytes -= msghdr->msg_ts; + msqptr->msg_qnum -= 1; + msqptr->msg_lrpid = p->p_pid; + msqptr->msg_rtime = time.tv_sec; + + /* + * Make msgsz the actual amount that we'll be returning. + * Note that this effectively truncates the message if it is too long + * (since msgsz is never increased). + */ + +#ifdef MSG_DEBUG + printf("found a message, msgsz=%d, msg_ts=%d\n",msgsz,msghdr->msg_ts); +#endif + if ( msgsz > msghdr->msg_ts ) { + msgsz = msghdr->msg_ts; + } + + /* + * Return the type to the user. + */ + + eval = copyout((caddr_t)&(msghdr->msg_type), user_msgp, sizeof(msghdr->msg_type)); + if ( eval != 0 ) { +#ifdef MSG_DEBUG + printf("error (%d) copying out message type\n",eval); +#endif + msg_freehdr(msghdr); + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + return(eval); + } + user_msgp += sizeof(msghdr->msg_type); + + /* + * Return the segments to the user + */ + + next = msghdr->msg_spot; + for ( len = 0; len < msgsz; len += msginfo.msgssz ) { + size_t tlen; + if ( msgsz > msginfo.msgssz ) { + tlen = msginfo.msgssz; + } else { + tlen = msgsz; + } + if ( next <= -1 ) { + panic("next too low #3"); + } + if ( next >= msginfo.msgseg ) { + panic("next out of range #3"); + } + eval = copyout((caddr_t)&msgpool[next * msginfo.msgssz], user_msgp, tlen); + if ( eval != 0 ) { +#ifdef MSG_DEBUG + printf("error (%d) copying out message segment\n",eval); +#endif + msg_freehdr(msghdr); + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + return(eval); + } + user_msgp += tlen; + next = msgmaps[next].next; + } + + /* + * Done, return the actual number of bytes copied out. + */ + + msg_freehdr(msghdr); + wakeup( (caddr_t)msqptr ); /* Somebody might care - we should check! */ + *retval = msgsz; + return(0); +} +#endif diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c new file mode 100644 index 000000000000..6344018d9514 --- /dev/null +++ b/sys/kern/sysv_sem.c @@ -0,0 +1,1114 @@ +/* + * Implementation of SVID semaphores + * + * Author: Daniel Boulet + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#ifdef SYSVSEM + +#include "param.h" +#include "systm.h" +#include "kernel.h" +#include "proc.h" +#include "sem.h" +#include "malloc.h" + +static int semctl(), semget(), semop(), semconfig(); +int (*semcalls[])() = { semctl, semget, semop, semconfig }; +int semtot = 0; + +static struct proc *semlock_holder = NULL; + +void +seminit() +{ + register int i; + vm_offset_t whocares1, whocares2; + + if ( sema == NULL ) { + panic("sema is NULL"); + } + for ( i = 0; i < seminfo.semmni; i += 1 ) { + sema[i].sem_base = 0; + sema[i].sem_perm.mode = 0; + } + if ( semu == NULL ) { + panic("semu is NULL"); + } + for ( i = 0; i < seminfo.semmnu; i += 1 ) { + register struct sem_undo *suptr = SEMU(i); + suptr->un_proc = NULL; + } + semu_list = NULL; +} + +TEXT_SET(pseudo_set, seminit); + +/* + * Entry point for all SEM calls + */ + +struct semsys_args { + u_int which; +}; + +int +semsys(p, uap, retval) + struct proc *p; + struct semsys_args *uap; + int *retval; +{ + while ( semlock_holder != NULL && semlock_holder != p ) { + /* printf("semaphore facility locked - sleeping ...\n"); */ + sleep( (caddr_t)&semlock_holder, (PZERO - 4) ); + } + + if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) + return (EINVAL); + return ((*semcalls[uap->which])(p, &uap[1], retval)); +} + +/* + * Lock or unlock the entire semaphore facility. + * + * This will probably eventually evolve into a general purpose semaphore + * facility status enquiry mechanism (I don't like the "read /dev/kmem" + * approach currently taken by ipcs and the amount of info that we want + * to be able to extract for ipcs is probably beyond what the capability + * of the getkerninfo facility. + * + * At the time that the current version of semconfig was written, ipcs is + * the only user of the semconfig facility. It uses it to ensure that the + * semaphore facility data structures remain static while it fishes around + * in /dev/kmem. + */ + +struct semconfig_args { + semconfig_ctl_t flag; +}; + +int +semconfig(p, uap, retval) + struct proc *p; + struct semconfig_args *uap; + int *retval; +{ + int eval = 0; + + switch ( uap->flag ) { + case SEM_CONFIG_FREEZE: + semlock_holder = p; + break; + case SEM_CONFIG_THAW: + semlock_holder = NULL; + wakeup( (caddr_t)&semlock_holder ); + break; + default: + printf("semconfig: unknown flag parameter value (%d) - ignored\n",uap->flag); + eval = EINVAL; + break; + } + + *retval = 0; + return(eval); +} + +/* + * Allocate a new sem_undo structure for a process + * (returns ptr to structure or NULL if no more room) + */ + +struct sem_undo * +semu_alloc(struct proc *p) +{ + register int i; + register struct sem_undo *suptr; + register struct sem_undo **supptr; + int attempt; + + /* + * Try twice to allocate something. + * (we'll purge any empty structures after the first pass so + * two passes are always enough) + */ + + for ( attempt = 0; attempt < 2; attempt += 1 ) { + + /* + * Look for a free structure. + * Fill it in and return it if we find one. + */ + + for ( i = 0; i < seminfo.semmnu; i += 1 ) { + suptr = SEMU(i); + if ( suptr->un_proc == NULL ) { + suptr->un_next = semu_list; + semu_list = suptr; + suptr->un_cnt = 0; + suptr->un_proc = p; + return(suptr); + } + } + + /* + * We didn't find a free one, if this is the first attempt + * then try to free some structures. + */ + + if ( attempt == 0 ) { + + /* All the structures are in use - try to free some */ + + int did_something = 0; + + supptr = &semu_list; + while ( (suptr = *supptr) != NULL ) { + if ( suptr->un_cnt == 0 ) { + suptr->un_proc = NULL; + *supptr = suptr->un_next; + did_something = 1; + } else { + supptr = &(suptr->un_next); + } + } + + /* If we didn't free anything then just give-up */ + + if ( !did_something ) { + return(NULL); + } + + } else { + + /* + * The second pass failed even though we freed + * something after the first pass! + * This is IMPOSSIBLE! + */ + + panic("semu_alloc - second attempt failed"); + + } + + } + + /* NOTREACHED */ + while (1); +} + +/* + * Adjust a particular entry for a particular proc + */ + +int +semundo_adjust(register struct proc *p,struct sem_undo **supptr,int semid,int semnum,int adjval) +{ + register struct sem_undo *suptr; + register struct undo *sunptr; + int i; + + /* Look for and remember the sem_undo if the caller doesn't provide it */ + + suptr = *supptr; + if ( suptr == NULL ) { + /* printf("adjust: need to find suptr\n"); */ + for ( suptr = semu_list; suptr != NULL; suptr = suptr->un_next ) { + if ( suptr->un_proc == p ) { + /* printf("adjust: found suptr @%08x\n",suptr); */ + *supptr = suptr; + break; + } + } + if ( suptr == NULL ) { + if ( adjval == 0 ) { + return(0); /* Don't create it if it doesn't exist */ + } + suptr = semu_alloc(p); + if ( suptr == NULL ) { + return(ENOSPC); + } + /* printf("adjust: allocated suptr @%08x\n",suptr); */ + *supptr = suptr; + } + } + + /* Look for the requested entry and adjust it (delete if adjval becomes 0) */ + + sunptr = &(suptr->un_ent[0]); + for ( i = 0; i < suptr->un_cnt; i += 1, sunptr += 1 ) { + + if ( sunptr->un_id == semid && sunptr->un_num == semnum ) { + + /* Found the right entry - adjust it */ + + if ( adjval == 0 ) { + sunptr->un_adjval = 0; + } else { + /* printf("adjust: %08x %d:%d(%d) += %d\n",suptr->un_proc,semid,semnum,sunptr->un_adjval,adjval); */ + sunptr->un_adjval += adjval; + } + if ( sunptr->un_adjval == 0 ) { + /* printf("adjust: %08x deleting entry %d:%d\n",suptr->un_proc,semid,semnum); */ + suptr->un_cnt -= 1; + if ( i < suptr->un_cnt ) { + suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt]; + } + } + return(0); + + } + } + + /* Didn't find the right entry - create it */ + + if ( adjval == 0 ) { + return(0); + } + if ( suptr->un_cnt == SEMUME ) { + return(EINVAL); + } else { + /* printf("adjust: %08x allocating entry %d as %d:%d(%d)\n",suptr->un_proc,suptr->un_cnt,semid,semnum,adjval); */ + sunptr = &(suptr->un_ent[suptr->un_cnt]); + suptr->un_cnt += 1; + sunptr->un_adjval = adjval; + sunptr->un_id = semid; sunptr->un_num = semnum; + } + return(0); +} + + +void +semundo_clear(int semid,int semnum) +{ + register struct sem_undo *suptr; + + for ( suptr = semu_list; suptr != NULL; suptr = suptr->un_next ) { + + register struct undo *sunptr = &(suptr->un_ent[0]); + register int i = 0; + + while ( i < suptr->un_cnt ) { + int advance = 1; + + if ( sunptr->un_id == semid ) { + if ( semnum == -1 || sunptr->un_num == semnum ) { + /* printf("clear: %08x %d:%d(%d)\n",suptr->un_proc,semid,sunptr->un_num,sunptr->un_adjval); */ + suptr->un_cnt -= 1; + if ( i < suptr->un_cnt ) { + suptr->un_ent[i] = suptr->un_ent[suptr->un_cnt]; + advance = 0; + } + } + if ( semnum != -1 ) { + break; + } + } + + if ( advance ) { + i += 1; + sunptr += 1; + } + + } + + } + +} + +struct semctl_args { + int semid; + int semnum; + int cmd; + union semun *arg; +}; + +int +semctl(p, uap, retval) + struct proc *p; + register struct semctl_args *uap; + int *retval; +{ + int semid = uap->semid; + int semnum = uap->semnum; + int cmd = uap->cmd; + union semun *arg = uap->arg; + union semun real_arg; + struct ucred *cred = p->p_ucred; + int i, rval, eval; + struct semid_ds sbuf; + register struct semid_ds *semaptr; + +#ifdef SEM_DEBUG + printf("call to semctl(%d,%d,%d,0x%x)\n",semid,semnum,cmd,arg); +#endif + + semid = IPCID_TO_IX(semid); + + if ( semid < 0 || semid >= seminfo.semmsl ) { + /* printf("semid out of range (0<=%d<%d)\n",semid,seminfo.semmsl); */ + return(EINVAL); + } + + semaptr = &sema[semid]; + + if ( semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) { + /* printf("invalid sequence number\n"); */ + return(EINVAL); + } + + if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) { + /* printf("no such semaphore id\n"); */ + return(EINVAL); + } + + eval = 0; + rval = 0; + + switch (cmd) { + + case IPC_RMID: + if ( cred->cr_uid != 0 + && semaptr->sem_perm.cuid != cred->cr_uid + && semaptr->sem_perm.uid != cred->cr_uid ) { + return(EPERM); + } + semaptr->sem_perm.cuid = cred->cr_uid; + semaptr->sem_perm.uid = cred->cr_uid; + semtot -= semaptr->sem_nsems; + for ( i = semaptr->sem_base - sem; i < semtot; i += 1 ) { + /* printf("0x%x = 0x%x; ",&sem[i],&sem[i + semaptr->sem_nsems]); */ + sem[i] = sem[i + semaptr->sem_nsems]; + } + /* printf("\n"); */ + for ( i = 0; i < seminfo.semmni; i += 1 ) { + if ( (sema[i].sem_perm.mode & SEM_ALLOC) + && sema[i].sem_base > semaptr->sem_base ) { + /* printf("sema[%d].sem_base was 0x%x",i,sema[i].sem_base); */ + sema[i].sem_base -= semaptr->sem_nsems; + /* printf(", now 0x%x\n",sema[i].sem_base); */ + } + } + semaptr->sem_perm.mode = 0; + + /* Delete any undo entries for this semid */ + + semundo_clear(semid,-1); + + /* Make sure that anybody who is waiting notices the deletion */ + + wakeup( (caddr_t)semaptr ); + + break; + + case IPC_SET: + /* printf("IPC_SET\n"); */ + if ( cred->cr_uid != 0 + && semaptr->sem_perm.cuid != cred->cr_uid + && semaptr->sem_perm.uid != cred->cr_uid ) { + return(EPERM); + } + if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) { + return(eval); + } + if ( (eval = copyin(real_arg.buf, (caddr_t)&sbuf, sizeof(sbuf)) ) != 0 ) { + return(eval); + } + semaptr->sem_perm.uid = sbuf.sem_perm.uid; + semaptr->sem_perm.gid = sbuf.sem_perm.gid; + semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) + | (sbuf.sem_perm.mode & 0777); + semaptr->sem_ctime = time.tv_sec; + break; + + case IPC_STAT: + /* printf("IPC_STAT\n"); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + rval = 0; + if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) { + return(eval); + } + eval = copyout((caddr_t)semaptr, real_arg.buf, sizeof(struct semid_ds)) ; + break; + + case GETNCNT: + /* printf("GETNCNT(%d)\n",semnum); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL); + rval = semaptr->sem_base[semnum].semncnt; + break; + + case GETPID: + /* printf("GETPID(%d)\n",semnum); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL); + rval = semaptr->sem_base[semnum].sempid; + break; + + case GETVAL: + /* printf("GETVAL(%d)\n",semnum); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL); + rval = semaptr->sem_base[semnum].semval; + break; + + case GETALL: + /* printf("GETALL\n"); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + rval = 0; + if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) { + /* printf("initial copyin failed (addr=0x%x)\n",arg); */ + return(eval); + } + /* printf("%d semaphores\n",semaptr->sem_nsems); */ + for ( i = 0; i < semaptr->sem_nsems; i += 1 ) { + /* printf("copyout to 0x%x\n",&real_arg.array[i]); */ + eval = + copyout((caddr_t)&semaptr->sem_base[i].semval, + &real_arg.array[i], + sizeof(real_arg.array[0])); + if ( eval != 0 ) { + /* printf("copyout to 0x%x failed\n",&real_arg.array[i]); */ + break; + } + } + break; + + case GETZCNT: + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)) ) { + return(eval); + } + /* printf("GETZCNT(%d)\n",semnum); */ + if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL); + rval = semaptr->sem_base[semnum].semzcnt; + break; + + case SETVAL: +#ifdef SEM_DEBUG + printf("SETVAL(%d)\n",semnum); +#endif + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) { + return(eval); + } + if ( semnum < 0 || semnum >= semaptr->sem_nsems ) return(EINVAL); + rval = 0; + if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) { + return(eval); + } +#ifdef SEM_DEBUG + printf("semaptr=%x, sem_base=%x, semptr=%x, oldval=%d, ", + semaptr,semaptr->sem_base,&semaptr->sem_base[semnum],semaptr->sem_base[semnum].semval); +#endif + semaptr->sem_base[semnum].semval = real_arg.val; +#ifdef SEM_DEBUG + printf(" newval=%d\n", semaptr->sem_base[semnum].semval); +#endif + semundo_clear(semid,semnum); + wakeup( (caddr_t)semaptr ); /* somebody else might care */ + break; + + case SETALL: + /* printf("SETALL\n"); */ + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) { + return(eval); + } + rval = 0; + if ( (eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0 ) { + return(eval); + } + for ( i = 0; i < semaptr->sem_nsems; i += 1 ) { + eval = + copyin(&real_arg.array[i], + (caddr_t)&semaptr->sem_base[i].semval, + sizeof(real_arg.array[0])); + if ( eval != 0 ) { + break; + } + } + semundo_clear(semid,-1); + wakeup( (caddr_t)semaptr ); /* somebody else might care */ + break; + default: + /* printf("invalid command %d\n",cmd); */ + return(EINVAL); + } + + if ( eval == 0 ) { + *retval = rval; + } + return(eval); +} + +struct semget_args { + key_t key; + int nsems; + int semflg; +}; + +int +semget(p, uap, retval) + struct proc *p; + register struct semget_args *uap; + int *retval; +{ + int semid, eval; + int key = uap->key; + int nsems = uap->nsems; + int semflg = uap->semflg; + struct ucred *cred = p->p_ucred; + +#ifdef SEM_DEBUG + printf("semget(0x%x,%d,0%o)\n",key,nsems,semflg); +#endif + + if ( key == IPC_PRIVATE ) { +#ifdef SEM_DEBUG + printf("private key\n"); +#endif + semid = seminfo.semmni; + } else { + for ( semid = 0; semid < seminfo.semmni; semid += 1 ) { + if ( (sema[semid].sem_perm.mode & SEM_ALLOC) + && sema[semid].sem_perm.key == key ) { + break; + } + } + if ( semid < seminfo.semmni ) { +#ifdef SEM_DEBUG + printf("found public key\n"); +#endif + if ( (eval = ipcaccess(&sema[semid].sem_perm, semflg & 0700, cred)) ) { + return(eval); + } + if ( nsems > 0 && sema[semid].sem_nsems < nsems ) { +#ifdef SEM_DEBUG + printf("too small\n"); +#endif + return(EINVAL); + } + if ( (semflg & IPC_CREAT) && (semflg & IPC_EXCL) ) { +#ifdef SEM_DEBUG + printf("not exclusive\n"); +#endif + return(EEXIST); + } + } else { +#ifdef SEM_DEBUG + printf("didn't find public key\n"); +#endif + } + } + + if ( semid == seminfo.semmni ) { +#ifdef SEM_DEBUG + printf("need to allocate the semid_ds\n"); +#endif + if ( key == IPC_PRIVATE || (semflg & IPC_CREAT) ) { + if ( nsems <= 0 || nsems > seminfo.semmsl ) { +#ifdef SEM_DEBUG + printf("nsems out of range (0<%d<=%d)\n",nsems,seminfo.semmsl); +#endif + return(EINVAL); + } + if ( nsems > seminfo.semmns - semtot ) { +#ifdef SEM_DEBUG + printf("not enough semaphores left (need %d, got %d)\n", + nsems,seminfo.semmns - semtot); +#endif + return(ENOSPC); + } + for ( semid = 0; semid < seminfo.semmni; semid += 1 ) { + if ( (sema[semid].sem_perm.mode & SEM_ALLOC) == 0 ) { + break; + } + } + if ( semid == seminfo.semmni ) { +#ifdef SEM_DEBUG + printf("no more semid_ds's available\n"); +#endif + return(ENOSPC); + } +#ifdef SEM_DEBUG + printf("semid %d is available\n",semid); +#endif + sema[semid].sem_perm.key = key; + sema[semid].sem_perm.cuid = cred->cr_uid; + sema[semid].sem_perm.uid = cred->cr_uid; + sema[semid].sem_perm.cgid = cred->cr_gid; + sema[semid].sem_perm.gid = cred->cr_gid; + sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; + sema[semid].sem_perm.seq = (sema[semid].sem_perm.seq + 1) & 0x7fff; /* avoid semid overflows */ + sema[semid].sem_nsems = nsems; + sema[semid].sem_otime = 0; + sema[semid].sem_ctime = time.tv_sec; + sema[semid].sem_base = &sem[semtot]; + semtot += nsems; + bzero(sema[semid].sem_base,sizeof(sema[semid].sem_base[0])*nsems); +#ifdef SEM_DEBUG + printf("sembase = 0x%x, next = 0x%x\n",sema[semid].sem_base,&sem[semtot]); +#endif + } else { +#ifdef SEM_DEBUG + printf("didn't find it and wasn't asked to create it\n"); +#endif + return(ENOENT); + } + } + + *retval = IXSEQ_TO_IPCID(semid,sema[semid].sem_perm); /* Convert to one origin */ + return(0); +} + +struct semop_args { + int semid; + struct sembuf *sops; + int nsops; +}; + +int +semop(p, uap, retval) + struct proc *p; + register struct semop_args *uap; + int *retval; +{ + int semid = uap->semid; + int nsops = uap->nsops; + struct sembuf sops[MAX_SOPS]; + register struct semid_ds *semaptr; + register struct sembuf *sopptr; + register struct sem *semptr; + struct sem_undo *suptr = NULL; + struct ucred *cred = p->p_ucred; + int i, j, eval; + int all_ok, do_wakeup, do_undos; + +#ifdef SEM_DEBUG + printf("call to semop(%d,0x%x,%d)\n",semid,sops,nsops); +#endif + + semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ + + if ( semid < 0 || semid >= seminfo.semmsl ) { + /* printf("semid out of range (0<=%d<%d)\n",semid,seminfo.semmsl); */ + return(EINVAL); + } + + semaptr = &sema[semid]; + if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) { + /* printf("no such semaphore id\n"); */ + return(EINVAL); + } + + if ( semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) { + /* printf("invalid sequence number\n"); */ + return(EINVAL); + } + + if ( (eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)) ) { +#ifdef SEM_DEBUG + printf("eval = %d from ipaccess\n",eval); +#endif + return(eval); + } + + if ( nsops > MAX_SOPS ) { +#ifdef SEM_DEBUG + printf("too many sops (max=%d, nsops=%d)\n",MAX_SOPS,nsops); +#endif + return(E2BIG); + } + + if ( (eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0 ) { +#ifdef SEM_DEBUG + printf("eval = %d from copyin(%08x, %08x, %d)\n",eval,uap->sops,&sops,nsops * sizeof(sops[0])); +#endif + return(eval); + } + + /* + * Loop trying to satisfy the vector of requests. + * If we reach a point where we must wait, any requests already + * performed are rolled back and we go to sleep until some other + * process wakes us up. At this point, we start all over again. + * + * This ensures that from the perspective of other tasks, a set + * of requests is atomic (never partially satisfied). + */ + + do_undos = 0; + + while (1) { + + do_wakeup = 0; + + for ( i = 0; i < nsops; i += 1 ) { + + sopptr = &sops[i]; + + if ( sopptr->sem_num >= semaptr->sem_nsems ) { + return(EFBIG); + } + + semptr = &semaptr->sem_base[sopptr->sem_num]; + +#ifdef SEM_DEBUG + printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", + semaptr,semaptr->sem_base,semptr, + sopptr->sem_num,semptr->semval,sopptr->sem_op, + (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); +#endif + + if ( sopptr->sem_op < 0 ) { + + if ( semptr->semval + sopptr->sem_op < 0 ) { +#ifdef SEM_DEBUG + printf("semop: can't do it now\n"); +#endif + break; + } else { + semptr->semval += sopptr->sem_op; + if ( semptr->semval == 0 && semptr->semzcnt > 0 ) { + do_wakeup = 1; + } + } + if ( sopptr->sem_flg & SEM_UNDO ) { + do_undos = 1; + } + + } else if ( sopptr->sem_op == 0 ) { + + if ( semptr->semval > 0 ) { +#ifdef SEM_DEBUG + printf("semop: not zero now\n"); +#endif + break; + } + + } else { + + if ( semptr->semncnt > 0 ) { + do_wakeup = 1; + } + semptr->semval += sopptr->sem_op; + if ( sopptr->sem_flg & SEM_UNDO ) { + do_undos = 1; + } + + } + } + + /* + * Did we get through the entire vector? + */ + + if ( i < nsops ) { + + /* + * No ... rollback anything that we've already done + */ + +#ifdef SEM_DEBUG + printf("semop: rollback 0 through %d\n",i-1); +#endif + for ( j = 0; j < i; j += 1 ) { + semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op; + } + + /* + * If the request that we couldn't satisfy has the NOWAIT + * flag set then return with EAGAIN. + */ + + if ( sopptr->sem_flg & IPC_NOWAIT ) { + return(EAGAIN); + } + + if ( sopptr->sem_op == 0 ) { + semptr->semzcnt += 1; + } else { + semptr->semncnt += 1; + } + +#ifdef SEM_DEBUG + printf("semop: good night!\n"); +#endif + eval = tsleep( (caddr_t)semaptr, (PZERO - 4) | PCATCH, "sem wait", 0 ); +#ifdef SEM_DEBUG + printf("semop: good morning (eval=%d)!\n",eval); +#endif + + suptr = NULL; /* The sem_undo may have been reallocated */ + + if ( eval != 0 ) { + /* printf("semop: interrupted system call\n"); */ + return( EINTR ); + } +#ifdef SEM_DEBUG + printf("semop: good morning!\n"); +#endif + + /* + * Make sure that the semaphore still exists + */ + + if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 + || semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid) ) { + + /* printf("semaphore id deleted\n"); */ + /* The man page says to return EIDRM. */ + /* Unfortunately, BSD doesn't define that code! */ +#ifdef EIDRM + return(EIDRM); +#else + return(EINVAL); +#endif + } + + /* + * The semaphore is still alive. Readjust the count of + * waiting processes. + */ + + if ( sopptr->sem_op == 0 ) { + semptr->semzcnt -= 1; + } else { + semptr->semncnt -= 1; + } + + + } else { + + /* + * Yes ... we're done. + * Process any SEM_UNDO requests. + */ + + if ( do_undos ) { + + for ( i = 0; i < nsops; i += 1 ) { + + /* We only need to deal with SEM_UNDO's for non-zero op's */ + int adjval; + + if ( (sops[i].sem_flg & SEM_UNDO) != 0 && (adjval = sops[i].sem_op) != 0 ) { + + eval = semundo_adjust(p,&suptr,semid,sops[i].sem_num,-adjval); + if ( eval != 0 ) { + + /* + * Oh-Oh! We ran out of either sem_undo's or undo's. + * Rollback the adjustments to this point and then + * rollback the semaphore ups and down so we can + * return with an error with all structures restored. + * We rollback the undo's in the exact reverse order that + * we applied them. This guarantees that we won't run + * out of space as we roll things back out. + */ + + for ( j = i - 1; j >= 0; j -= 1 ) { + + if ( (sops[i].sem_flg & SEM_UNDO) != 0 && (adjval = sops[i].sem_op) != 0 ) { + + if ( semundo_adjust(p,&suptr,semid,sops[j].sem_num,adjval) != 0 ) { + + /* This is impossible! */ + panic("semop - can't undo undos"); + + } + } + + } /* loop backwards through sops */ + + for ( j = 0; j < nsops; j += 1 ) { + semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op; + } + +#ifdef SEM_DEBUG + printf("eval = %d from semundo_adjust\n",eval); +#endif + return( eval ); + + } /* semundo_adjust failed */ + + } /* if ( SEM_UNDO && adjval != 0 ) */ + + } /* loop through the sops */ + + } /* if ( do_undos ) */ + + /* We're definitely done - set the sempid's */ + + for ( i = 0; i < nsops; i += 1 ) { + + sopptr = &sops[i]; + semptr = &semaptr->sem_base[sopptr->sem_num]; + semptr->sempid = p->p_pid; + + } + + /* Do a wakeup if any semaphore was up'd. */ + + if ( do_wakeup ) { +#ifdef SEM_DEBUG + printf("semop: doing wakeup\n"); +#ifdef SEM_WAKEUP + sem_wakeup( (caddr_t)semaptr ); +#else + wakeup( (caddr_t)semaptr ); +#endif + printf("semop: back from wakeup\n"); +#else + wakeup( (caddr_t)semaptr ); +#endif + } +#ifdef SEM_DEBUG + printf("semop: done\n"); +#endif + *retval = 0; + return(0); + + } + + } + + panic("semop: how did we get here???"); +} + +/* + * Go through the undo structures for this process and apply the + * adjustments to semaphores. + */ + +void +semexit(p) + struct proc *p; +{ + register struct sem_undo *suptr; + register struct sem_undo **supptr; + int did_something; + + /* + * If somebody else is holding the global semaphore facility lock + * then sleep until it is released. + */ + + while ( semlock_holder != NULL && semlock_holder != p ) { +#ifdef SEM_DEBUG + printf("semaphore facility locked - sleeping ...\n"); +#endif + sleep( (caddr_t)&semlock_holder, (PZERO - 4) ); + } + + did_something = 0; + + /* + * Go through the chain of undo vectors looking for one + * associated with this process. + */ + + for ( supptr = &semu_list; + (suptr = *supptr) != NULL; + supptr = &(suptr->un_next) + ) { + + if ( suptr->un_proc == p ) { + +#ifdef SEM_DEBUG + printf("proc @%08x has undo structure with %d entries\n",p,suptr->un_cnt); +#endif + + /* + * If there are any active undo elements then process them. + */ + + if ( suptr->un_cnt > 0 ) { + + int ix; + + for ( ix = 0; ix < suptr->un_cnt; ix += 1 ) { + + int semid = suptr->un_ent[ix].un_id; + int semnum = suptr->un_ent[ix].un_num; + int adjval = suptr->un_ent[ix].un_adjval; + struct semid_ds *semaptr; + + semaptr = &sema[semid]; + if ( (semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) { + panic("semexit - semid not allocated"); + } + if ( semnum >= semaptr->sem_nsems ) { + panic("semexit - semnum out of range"); + } + +#ifdef SEM_DEBUG + printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n",suptr->un_proc, + suptr->un_ent[ix].un_id,suptr->un_ent[ix].un_num,suptr->un_ent[ix].un_adjval, + semaptr->sem_base[semnum].semval); +#endif + + if ( adjval < 0 ) { + if ( semaptr->sem_base[semnum].semval < -adjval ) { + semaptr->sem_base[semnum].semval = 0; + } else { + semaptr->sem_base[semnum].semval += adjval; + } + } else { + semaptr->sem_base[semnum].semval += adjval; + } + + /* printf("semval now %d\n",semaptr->sem_base[semnum].semval); */ + +#ifdef SEM_WAKEUP + sem_wakeup((caddr_t)semaptr); /* A little sloppy (we should KNOW if anybody is waiting). */ +#else + wakeup((caddr_t)semaptr); /* A little sloppy (we should KNOW if anybody is waiting). */ +#endif +#ifdef SEM_DEBUG + printf("semexit: back from wakeup\n"); +#endif + + } + + } + + /* + * Deallocate the undo vector. + */ + +#ifdef SEM_DEBUG + printf("removing vector\n"); +#endif + suptr->un_proc = NULL; + *supptr = suptr->un_next; + + /* Done. */ + + break; + + + } + + } + + /* + * If the exiting process is holding the global semaphore facility + * lock then release it. + */ + + if ( semlock_holder == p ) { + semlock_holder = NULL; + wakeup( (caddr_t)&semlock_holder ); + } +} +#endif diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index 0e7c3c84db29..00f123f529c5 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -37,7 +37,7 @@ * * from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$ * from: @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91 - * $Id: sysv_shm.c,v 1.4 1993/10/16 15:24:52 rgrimes Exp $ + * $Id: sysv_shm.c,v 1.9 1994/01/21 09:56:31 davidg Exp $ */ /* @@ -59,13 +59,18 @@ #include "vm/vm_kern.h" #include "vm/vm_inherit.h" #include "vm/vm_pager.h" +#include "vm/vm_user.h" #ifdef HPUXCOMPAT #include "hp300/hpux/hpux.h" #endif -int shmat(), shmctl(), shmdt(), shmget(); -int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget }; +/* From shm.h */ +struct shmid_ds *shmsegs; +struct shminfo shminfo; + +int shmat(), shmctl(), shmdt(), shmget(); /* XXX */ +int (*shmcalls[])() = { shmat, shmctl, shmdt, shmget }; /* XXX */ int shmtot = 0; /* @@ -85,8 +90,15 @@ struct shmhandle { caddr_t shmh_id; }; +static int ipcaccess(struct ipc_perm *, int, struct ucred *); +static void shmufree(struct proc *, struct shmdesc *); +static void shmfree(struct shmid_ds *); +static int shmvalid(int); + + vm_map_t shm_map; /* address space for shared memory segments */ +void shminit() { register int i; @@ -102,6 +114,8 @@ shminit() } } +TEXT_SET(pseudo_set, shminit); + /* * Entry point for all SHM calls */ @@ -110,6 +124,7 @@ struct shmsys_args { u_int which; }; +int shmsys(p, uap, retval) struct proc *p; struct shmsys_args *uap; @@ -131,6 +146,7 @@ struct shmget_args { int shmflg; }; +int shmget(p, uap, retval) struct proc *p; register struct shmget_args *uap; @@ -183,7 +199,7 @@ shmget(p, uap, retval) shmh = (struct shmhandle *) malloc(sizeof(struct shmhandle), M_SHM, M_WAITOK); shmh->shmh_kva = 0; - shmh->shmh_id = (caddr_t)(0xc0000000|rval); /* XXX */ + shmh->shmh_id = (caddr_t)(0xc0000000UL|rval); /* XXX */ error = vm_mmap(shm_map, &shmh->shmh_kva, ctob(size), VM_PROT_ALL, VM_PROT_DEFAULT, MAP_ANON, shmh->shmh_id, 0); if (error) { @@ -228,6 +244,7 @@ struct shmctl_args { }; /* ARGSUSED */ +int shmctl(p, uap, retval) struct proc *p; register struct shmctl_args *uap; @@ -299,6 +316,7 @@ struct shmat_args { int shmflg; }; +int shmat(p, uap, retval) struct proc *p; register struct shmat_args *uap; @@ -356,9 +374,11 @@ shmat(p, uap, retval) if (uva) flags |= MAP_FIXED; else - uva = (caddr_t)0x1000000; /* XXX */ - error = vm_mmap(&p->p_vmspace->vm_map, &uva, (vm_size_t)size, prot, VM_PROT_DEFAULT, - flags, ((struct shmhandle *)shp->shm_handle)->shmh_id, 0); + uva = (caddr_t)0x1000000UL; /* XXX */ + error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)&uva, + (vm_size_t)size, prot, VM_PROT_DEFAULT, + flags, ((struct shmhandle *)shp->shm_handle)->shmh_id, + 0); if (error) return(error); shmd->shmd_uva = (vm_offset_t)uva; @@ -382,6 +402,7 @@ struct shmdt_args { }; /* ARGSUSED */ +int shmdt(p, uap, retval) struct proc *p; struct shmdt_args *uap; @@ -399,8 +420,10 @@ shmdt(p, uap, retval) return(EINVAL); shmufree(p, shmd); shmsegs[shmd->shmd_id % SHMMMNI].shm_lpid = p->p_pid; + return 0; } +void shmfork(p1, p2, isvfork) struct proc *p1, *p2; int isvfork; @@ -423,6 +446,7 @@ shmfork(p1, p2, isvfork) shmsegs[shmd->shmd_id % SHMMMNI].shm_nattch++; } +void shmexit(p) struct proc *p; { @@ -437,6 +461,7 @@ shmexit(p) p->p_vmspace->vm_shm = NULL; } +static int shmvalid(id) register int id; { @@ -454,6 +479,7 @@ shmvalid(id) /* * Free user resources associated with a shared memory segment */ +static void shmufree(p, shmd) struct proc *p; struct shmdesc *shmd; @@ -473,6 +499,7 @@ shmufree(p, shmd) /* * Deallocate resources associated with a shared memory segment */ +static void shmfree(shp) register struct shmid_ds *shp; { @@ -500,35 +527,4 @@ shmfree(shp) if ((int)(shp->shm_perm.seq * SHMMMNI) < 0) shp->shm_perm.seq = 0; } - -/* - * XXX This routine would be common to all sysV style IPC - * (if the others were implemented). - */ -ipcaccess(ipc, mode, cred) - register struct ipc_perm *ipc; - int mode; - register struct ucred *cred; -{ - register int m; - - if (cred->cr_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. - */ - mode &= 0700; - m = ipc->mode; - if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) { - m <<= 3; - if (!groupmember(ipc->gid, cred) && - !groupmember(ipc->cgid, cred)) - m <<= 3; - } - if ((mode&m) == mode) - return (0); - return (EACCES); -} #endif /* SYSVSHM */ diff --git a/sys/kern/tty.c b/sys/kern/tty.c index faf8b4d4a1a4..519b910ccfdb 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * from: @(#)tty.c 7.44 (Berkeley) 5/28/91 - * $Id: tty.c,v 1.5 1993/10/16 15:24:54 rgrimes Exp $ + * $Id: tty.c,v 1.19.2.1 1994/03/24 08:19:44 rgrimes Exp $ */ #include "param.h" @@ -49,18 +49,43 @@ #include "kernel.h" #include "vnode.h" #include "syslog.h" - +#include "signalvar.h" #include "vm/vm.h" +#include "kinfo.h" +#include "kinfo_proc.h" + + +/* + * Input control starts when we would not be able to fit the maximum + * contents of the ping-pong buffers and finishes when we would be able + * to fit that much plus 1/8 more. + */ +#define I_HIGH_WATER (TTYHOG - 2 * 256) /* XXX */ +#define I_LOW_WATER ((TTYHOG - 2 * 256) * 7 / 8) /* XXX */ + +/* XXX RB_LEN() is too slow. */ +#define INPUT_LEN(tp) (RB_LEN(&(tp)->t_can) + RB_LEN(&(tp)->t_raw)) +#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */ +#define MAX_INPUT TTYHOG static int proc_compare __P((struct proc *p1, struct proc *p2)); +static void ttyblock __P((struct tty *tp)); +static void ttyecho __P((int c, struct tty *tp)); +static int ttyoutput __P((int c, register struct tty *tp)); +static void ttyoutstr __P((char *cp, struct tty *tp)); +static void ttypend __P((struct tty *tp)); +static void ttyretype __P((struct tty *tp)); +static void ttyrub __P((int c, struct tty *tp)); +static void ttyrubo __P((struct tty *tp, int cnt)); +static void ttyunblock __P((struct tty *tp)); /* symbolic sleep message strings */ -char ttyin[] = "ttyin"; -char ttyout[] = "ttyout"; -char ttopen[] = "ttyopn"; -char ttclos[] = "ttycls"; -char ttybg[] = "ttybg"; -char ttybuf[] = "ttybuf"; +const char ttyin[] = "ttyin"; +const char ttyout[] = "ttyout"; +const char ttopen[] = "ttyopn"; +const char ttclos[] = "ttycls"; +const char ttybg[] = "ttybg"; +const char ttybuf[] = "ttybuf"; /* * Table giving parity for characters and indicating @@ -138,6 +163,7 @@ char partab[] = { #undef CR extern struct tty *constty; /* temporary virtual console */ +extern int nldisp; /* * Is 'c' a line delimiter ("break" character)? @@ -145,6 +171,7 @@ extern struct tty *constty; /* temporary virtual console */ #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) +void ttychars(tp) struct tty *tp; { @@ -155,6 +182,7 @@ ttychars(tp) /* * Flush tty after output has drained. */ +int ttywflush(tp) struct tty *tp; { @@ -168,6 +196,7 @@ ttywflush(tp) /* * Wait for output to drain. */ +int ttywait(tp) register struct tty *tp; { @@ -176,12 +205,33 @@ ttywait(tp) while ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) && (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && tp->t_oproc) { + /* + * XXX temporary fix for deadlock. + * + * If two processes wait for output to drain from the same + * tty, and the amount of output to drain is > 0 and + * <= tp->t_lowat, then the processes will take turns + * uselessly waking each other up until the output drains, + * with cpl higher than spltty() throughout. + * + * The sleep address and TS_ASLEEP flag ought to be different + * for the different events (output done) and (output almost + * done). + */ + tp->t_lowat = 0; + (*tp->t_oproc)(tp); - tp->t_state |= TS_ASLEEP; - if (error = ttysleep(tp, (caddr_t)&tp->t_out, - TTOPRI | PCATCH, ttyout, 0)) + if ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) && + (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL)) { + tp->t_state |= TS_ASLEEP; + if (error = ttysleep(tp, (caddr_t)&tp->t_out, + TTOPRI | PCATCH, "ttywai", 0)) + break; + } else break; } + if (tp->t_lowat == 0) + ttsetwater(tp); splx(s); return (error); } @@ -195,23 +245,26 @@ ttywait(tp) * Flush TTY read and/or write queues, * notifying anyone waiting. */ +void ttyflush(tp, rw) register struct tty *tp; + int rw; { - register s; + register int s; s = spltty(); + if (rw & FWRITE) + tp->t_state &= ~TS_TTSTOP; + (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); if (rw & FREAD) { flushq(&tp->t_can); flushq(&tp->t_raw); tp->t_rocount = 0; tp->t_rocol = 0; - tp->t_state &= ~(TS_LOCAL|TS_TBLOCK); /* XXX - should be TS_RTSBLOCK */ + tp->t_state &= ~TS_LOCAL; ttwakeup(tp); } if (rw & FWRITE) { - tp->t_state &= ~TS_TTSTOP; - (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); flushq(&tp->t_out); wakeup((caddr_t)&tp->t_out); if (tp->t_wsel) { @@ -220,38 +273,74 @@ ttyflush(tp, rw) tp->t_state &= ~TS_WCOLL; } } + if (rw & FREAD) { + if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW) + && INPUT_LEN(tp) < I_LOW_WATER) { + int out_cc; + int t_state; + + /* + * We delayed turning off input flow control in case + * we have to send a start character and the output + * queue was previously full. Sending a start char + * is still tricky because we don't want to add a + * new obstruction to draining the output queue. + */ + out_cc = RB_LEN(&tp->t_out); + t_state = tp->t_state; + ttyunblock(tp); + tp->t_state &= ~TS_TBLOCK; + if (t_state & TS_TBLOCK && RB_LEN(&tp->t_out) != 0) + ttysleep(tp, (caddr_t)&tp->t_out, TTIPRI, + "ttyfls", hz / 10); + if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) { + (*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE); + flushq(&tp->t_out); + } + } + } splx(s); } /* - * Send stop character on input overflow. + * Handle input high water. Send stop character for the IXOFF case. Turn + * on all enabled input flow control bits and propagate the change to the + * driver. */ +static void ttyblock(tp) - register struct tty *tp; + struct tty *tp; { - register x; - int rawcc, cancc; - rawcc = RB_LEN(&tp->t_raw); - cancc = RB_LEN(&tp->t_can); - x = rawcc + cancc; - if (rawcc > TTYHOG) { - ttyflush(tp, FREAD|FWRITE); - } - /* - * Block further input iff: - * Current input > threshold AND input is available to user program - */ - if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && - ((tp->t_lflag&ICANON) == 0) || (cancc > 0)) { - if (tp->t_cc[VSTOP] != _POSIX_VDISABLE) { - putc(tp->t_cc[VSTOP], &tp->t_out); - } - tp->t_state |= TS_TBLOCK; /* XXX - should be TS_RTSBLOCK? */ - ttstart(tp); - } + if ((tp->t_state & TS_TBLOCK) == 0 + && tp->t_cc[VSTOP] != _POSIX_VDISABLE + && putc(tp->t_cc[VSTOP], &tp->t_out) == 0) + tp->t_state |= TS_TBLOCK; + if (tp->t_cflag & CDTR_IFLOW) + tp->t_state |= TS_DTR_IFLOW; + if (tp->t_cflag & CRTS_IFLOW) + tp->t_state |= TS_RTS_IFLOW; + ttstart(tp); } +/* + * Handle input low water. Send start character for the IXOFF case. Turn + * off our input flow control bits and propagate the change to the driver. + */ +static void +ttyunblock(tp) + struct tty *tp; +{ + + if (tp->t_state & TS_TBLOCK + && tp->t_cc[VSTART] != _POSIX_VDISABLE + && putc(tp->t_cc[VSTART], &tp->t_out) == 0) + tp->t_state &= ~TS_TBLOCK; + tp->t_state &= ~TS_HW_IFLOW; + ttstart(tp); +} + +void ttstart(tp) struct tty *tp; { @@ -260,6 +349,8 @@ ttstart(tp) (*tp->t_oproc)(tp); } +#ifdef notused +void ttrstrt(tp) /* XXX */ struct tty *tp; { @@ -271,6 +362,7 @@ ttrstrt(tp) /* XXX */ tp->t_state &= ~TS_TIMEOUT; ttstart(tp); } +#endif /* notused */ /* @@ -280,12 +372,14 @@ ttrstrt(tp) /* XXX */ * and/or reject any of these ioctl commands. */ /*ARGSUSED*/ +int ttioctl(tp, com, data, flag) register struct tty *tp; + int com; caddr_t data; + int flag; { register struct proc *p = curproc; /* XXX */ - extern int nldisp; int s, error; /* @@ -345,9 +439,9 @@ ttioctl(tp, com, data, flag) if (t != tp->t_line) { s = spltty(); (*linesw[tp->t_line].l_close)(tp, flag); - error = (*linesw[t].l_open)(dev, tp); + error = (*linesw[t].l_open)(dev, tp, 0); if (error) { - (void)(*linesw[tp->t_line].l_open)(dev, tp); + (void)(*linesw[tp->t_line].l_open)(dev, tp, 0); splx(s); return (error); } @@ -462,6 +556,22 @@ ttioctl(tp, com, data, flag) splx(s); return (error); } else { + /* + * XXX doubtful. We mostly check both CLOCAL + * and TS_CARR_ON before doing anything, and + * changing TS_ISOPEN here just give another + * flag to worry about, and is probably + * inconsistent with not changing TS_ISOPEN + * when carrier drops or CLOCAL rises. OTOH + * we should maintain a flag to keep track + * of the combination of CLOCAL and TS_CARR_ON. + * This could be just TS_CARR_ON (if we don't + * need to + * + * XXX ttselect() doesn't worry about + * TS_ISOPEN, so it is inconsistent with + * ttread() after TS_ISOPEN gets cleared here. + */ if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) && (t->c_cflag&CLOCAL) == 0) { @@ -586,19 +696,25 @@ ttioctl(tp, com, data, flag) return (0); } +int ttnread(tp) struct tty *tp; { int nread = 0; + /* XXX races. */ if (tp->t_lflag & PENDIN) ttypend(tp); nread = RB_LEN(&tp->t_can); - if ((tp->t_lflag & ICANON) == 0) + if ((tp->t_lflag & ICANON) == 0) { nread += RB_LEN(&tp->t_raw); + if (nread < tp->t_cc[VMIN]) + nread = 0; + } return (nread); } +int ttselect(dev, rw, p) dev_t dev; int rw; @@ -641,9 +757,11 @@ win: /* * Initial open of tty, or (re)entry to standard tty line discipline. */ -ttyopen(dev, tp) +int +ttyopen(dev, tp, dummy) dev_t dev; register struct tty *tp; + int dummy; { tp->t_dev = dev; @@ -662,6 +780,7 @@ ttyopen(dev, tp) /* * "close" a line discipline */ +void ttylclose(tp, flag) struct tty *tp; int flag; @@ -678,6 +797,7 @@ ttylclose(tp, flag) * bumping generation number so that pending read/write calls * can detect recycling of the tty. */ +int ttyclose(tp) register struct tty *tp; { @@ -686,10 +806,6 @@ ttyclose(tp) ttyflush(tp, FREAD|FWRITE); tp->t_session = NULL; tp->t_pgrp = NULL; -/* - * XXX - do we need to send cc[VSTART] or do a ttstart() here in some cases? - * (TS_TBLOCK and TS_RTSBLOCK are being cleared.) - */ tp->t_state = 0; tp->t_gen++; return (0); @@ -700,8 +816,10 @@ ttyclose(tp) * Flag indicates new state of carrier. * Returns 0 if the line should be turned off, otherwise 1. */ +int ttymodem(tp, flag) register struct tty *tp; + int flag; { if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { @@ -709,10 +827,10 @@ ttymodem(tp, flag) * MDMBUF: do flow control according to carrier flag */ if (flag) { - tp->t_state &= ~TS_TTSTOP; + tp->t_state &= ~TS_CAR_OFLOW; ttstart(tp); - } else if ((tp->t_state&TS_TTSTOP) == 0) { - tp->t_state |= TS_TTSTOP; + } else if ((tp->t_state&TS_CAR_OFLOW) == 0) { + tp->t_state |= TS_CAR_OFLOW; (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); } } else if (flag == 0) { @@ -740,6 +858,7 @@ ttymodem(tp, flag) * Default modem control routine (for other line disciplines). * Return argument flag, to turn off device on carrier drop. */ +int nullmodem(tp, flag) register struct tty *tp; int flag; @@ -762,10 +881,10 @@ nullmodem(tp, flag) * reinput pending characters after state switch * call at spltty(). */ +static void ttypend(tp) register struct tty *tp; { - register c; char *hd, *tl; tp->t_lflag &= ~PENDIN; @@ -783,13 +902,14 @@ ttypend(tp) /* * Process input of a single character received on a tty. */ +void ttyinput(c, tp) - register c; + register int c; register struct tty *tp; { - register int iflag = tp->t_iflag; - register int lflag = tp->t_lflag; - register u_char *cc = tp->t_cc; + register tcflag_t iflag = tp->t_iflag; + register tcflag_t lflag = tp->t_lflag; + register cc_t *cc = tp->t_cc; int i, err; /* @@ -809,6 +929,17 @@ ttyinput(c, tp) tp->t_rawcc++; } /* + * If input flow control is enabled and not yet invoked, check the + * high water mark. Block further input iff: + * current input > threshold AND input is available to user program. + * The 3 is slop for PARMRK. + */ + if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0 + || tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0) + && INPUT_LEN(tp) > I_HIGH_WATER - 3 + && ((lflag & ICANON) == 0 || RB_LEN(&tp->t_can) != 0)) + ttyblock(tp); + /* * Handle exceptional conditions (break, parity, framing). */ if (err = (c&TTY_ERRORMASK)) { @@ -826,6 +957,8 @@ ttyinput(c, tp) goto endcase; else if (iflag&PARMRK) { parmrk: + if (INPUT_LEN(tp) > MAX_INPUT - 3) + goto input_overflow; putc(0377|TTY_QUOTE, &tp->t_raw); putc(0|TTY_QUOTE, &tp->t_raw); putc(c|TTY_QUOTE, &tp->t_raw); @@ -834,11 +967,6 @@ parmrk: c = 0; } } - /* - * In tandem mode, check high water mark. - */ - if (iflag&IXOFF) - ttyblock(tp); if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) c &= ~0x80; if ((tp->t_lflag&EXTPROC) == 0) { @@ -878,7 +1006,7 @@ parmrk: else { ttyflush(tp, FWRITE); ttyecho(c, tp); - if (RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can)) + if (INPUT_LEN(tp) != 0) ttyretype(tp); tp->t_lflag |= FLUSHO; } @@ -974,7 +1102,6 @@ parmrk: */ if (CCEQ(cc[VWERASE], c)) { int ctype; - int alt = lflag&ALTWERASE; /* * erase whitespace @@ -991,6 +1118,13 @@ parmrk: c = unputc(&tp->t_raw); if (c == -1) goto endcase; + /* + * Handle one-letter word cases. + */ + if (c == ' ' || c == '\t') { + putc(c, &tp->t_raw); + goto endcase; + } ctype = ISALPHA(c); /* * erase rest of word @@ -1001,7 +1135,8 @@ parmrk: if (c == -1) goto endcase; } while (c != ' ' && c != '\t' && - (alt == 0 || ISALPHA(c) == ctype)); + ((lflag & ALTWERASE) == 0 + || ISALPHA(c) == ctype)); (void) putc(c, &tp->t_raw); goto endcase; } @@ -1025,12 +1160,13 @@ parmrk: /* * Check for input buffer overflow */ - if (RB_LEN(&tp->t_raw)+RB_LEN(&tp->t_can) >= TTYHOG) { + if (INPUT_LEN(tp) >= MAX_INPUT) { +input_overflow: if (iflag&IMAXBEL) { if (RB_LEN(&tp->t_out) < tp->t_hiwat) (void) ttyoutput(CTRL('g'), tp); } else - ttyflush(tp, FREAD | FWRITE); + ttyflush(tp, FREAD); goto endcase; } /* @@ -1062,7 +1198,7 @@ parmrk: /* * Place the cursor over the '^' of the ^D. */ - i = MIN(2, tp->t_col - i); + i = imin(2, tp->t_col - i); while (i > 0) { (void) ttyoutput('\b', tp); i--; @@ -1089,12 +1225,13 @@ startoutput: * Returns < 0 if putc succeeds, otherwise returns char to resend. * Must be recursive. */ +static int ttyoutput(c, tp) - register c; + register int c; register struct tty *tp; { register int col; - register long oflag = tp->t_oflag; + register tcflag_t oflag = tp->t_oflag; if ((oflag&OPOST) == 0) { if (tp->t_lflag&FLUSHO) @@ -1124,11 +1261,11 @@ ttyoutput(c, tp) #ifdef was c -= b_to_q(" ", c, &tp->t_outq); #else - i = min (c, RB_CONTIGPUT(&tp->t_out)); + i = imin(c, RB_CONTIGPUT(&tp->t_out)); bcopy(" ", tp->t_out.rb_tl, i); tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i); - i = min (c-i, RB_CONTIGPUT(&tp->t_out)); + i = imin(c - i, RB_CONTIGPUT(&tp->t_out)); /* off end and still have space? */ if (i) { @@ -1189,16 +1326,20 @@ ttyoutput(c, tp) /* * Process a read call on a tty device. */ +int ttread(tp, uio, flag) register struct tty *tp; struct uio *uio; + int flag; { register struct ringb *qp; register int c; - register long lflag; - register u_char *cc = tp->t_cc; + register tcflag_t lflag; + register cc_t *cc = tp->t_cc; register struct proc *p = curproc; - int s, first, error = 0; + int s, first, error = 0, rblen; + int has_stime = 0, last_cc = 0; + long slp = 0; /* XXX this should be renamed `timo'. */ loop: lflag = tp->t_lflag; @@ -1206,14 +1347,17 @@ loop: /* * take pending input first */ - if (lflag&PENDIN) + if (lflag&PENDIN) { ttypend(tp); - splx(s); + splx(s); /* reduce latency */ + s = spltty(); + } /* * Hang process if it's in the background. */ if (isbackground(p, tp)) { + splx(s); if ((p->p_sigignore & sigmask(SIGTTIN)) || (p->p_sigmask & sigmask(SIGTTIN)) || p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) @@ -1230,16 +1374,100 @@ loop: * else use the raw queue. */ qp = lflag&ICANON ? &tp->t_can : &tp->t_raw; + rblen = RB_LEN(qp); - /* - * If there is no input, sleep on rawq - * awaiting hardware receipt and notification. - * If we have data, we don't need to check for carrier. - */ - s = spltty(); - if (RB_LEN(qp) <= 0) { + if ((lflag & ICANON) == 0) { + int m = cc[VMIN]; + long t = cc[VTIME]; + struct timeval stime, timecopy; + int x; + + /* + * Check each of the four combinations. + * (m > 0 && t == 0) is the normal read case. + * It should be fairly efficient, so we check that and its + * companion case (m == 0 && t == 0) first. + * For the other two cases, we compute the target sleep time + * into slp. + */ + if (t == 0) { + if (rblen < m) + goto sleep; + if (rblen > 0) + goto read; + + /* m, t and rblen are all 0. 0 is enough input. */ + splx(s); + return (0); + } + t *= 100000; /* time in us */ +#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \ + ((t1).tv_usec - (t2).tv_usec)) + if (m > 0) { + if (rblen <= 0) + goto sleep; + if (rblen >= m) + goto read; + x = splclock(); + timecopy = time; + splx(x); + if (!has_stime) { + /* first character, start timer */ + has_stime = 1; + stime = timecopy; + slp = t; + } else if (rblen > last_cc) { + /* got a character, restart timer */ + stime = timecopy; + slp = t; + } else { + /* nothing, check expiration */ + slp = t - diff(timecopy, stime); + if (slp <= 0) + goto read; + } + last_cc = rblen; + } else { /* m == 0 */ + if (rblen > 0) + goto read; + x = splclock(); + timecopy = time; + splx(x); + if (!has_stime) { + has_stime = 1; + stime = timecopy; + slp = t; + } else { + slp = t - diff(timecopy, stime); + if (slp <= 0) { + /* Timed out, but 0 is enough input. */ + splx(s); + return (0); + } + } + } +#undef diff + /* + * Rounding down may make us wake up just short + * of the target, so we round up. + * The formula is ceiling(slp * hz/1000000). + * 32-bit arithmetic is enough for hz < 169. + * XXX see hzto() for how to avoid overflow if hz + * is large (divide by `tick' and/or arrange to + * use hzto() if hz is large). + */ + slp = (long) (((u_long)slp * hz) + 999999) / 1000000; + goto sleep; + } + if (rblen <= 0) { int carrier; +sleep: + /* + * If there is no input, sleep on rawq + * awaiting hardware receipt and notification. + * If we have data, we don't need to check for carrier. + */ carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); if (!carrier && tp->t_state&TS_ISOPEN) { splx(s); @@ -1249,20 +1477,70 @@ loop: splx(s); return (EWOULDBLOCK); } + if (slp) { + /* + * Use plain wakeup() not ttwakeup(). + * XXX why not use the timeout built into tsleep? + */ + timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp); + } error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, carrier ? ttyin : ttopen, 0); + if (slp) { + slp = 0; + untimeout((timeout_func_t)wakeup, (caddr_t)qp); + } splx(s); if (error) return (error); + /* + * XXX what happens if ICANON, MIN or TIME changes or + * another process eats some input while we are asleep + * (not just here)? It would be safest to detect changes + * and reset our state variables (has_stime and last_cc). + */ goto loop; } - splx(s); +read: /* * Input present, check for input mapping and processing. */ first = 1; - while ((c = getc(qp)) >= 0) { + if (lflag & (ICANON | ISIG)) + goto slowcase; + for (;;) { + int rcc; + + rcc = RB_CONTIGGET(qp); + if (rcc > uio->uio_resid) + rcc = uio->uio_resid; + if (rcc <= 0) { + if (first) { + /* queue got flushed (can't happen) */ + splx(s); + goto loop; + } + break; + } + error = uiomove(qp->rb_hd, rcc, uio); + if (error) + break; + qp->rb_hd = RB_ROLLOVER(qp, qp->rb_hd + rcc); + splx(s); + s = spltty(); + first = 0; + } + goto out; +slowcase: + for (;;) { + c = getc(qp); + splx(s); + if (c < 0) { + if (first) + goto loop; + break; + } /* * delayed suspend (^Y) */ @@ -1295,28 +1573,21 @@ loop: */ if (lflag&ICANON && ttbreakc(c)) break; + s = spltty(); first = 0; } + s = spltty(); + /* - * Look to unblock output now that (presumably) + * Look to unblock input now that (presumably) * the input queue has gone down. */ -#if 0 - if (tp->t_state&TS_TBLOCK && RB_LEN(&tp->t_raw) < TTYHOG/5) { - if (cc[VSTART] != _POSIX_VDISABLE && - putc(cc[VSTART], &tp->t_out) == 0) { - tp->t_state &= ~TS_TBLOCK; - ttstart(tp); - } - } -#else -#define TS_RTSBLOCK TS_TBLOCK /* XXX */ -#define RB_I_LOW_WATER ((RBSZ - 2 * 256) * 7 / 8) /* XXX */ - if (tp->t_state&TS_RTSBLOCK && RB_LEN(&tp->t_raw) <= RB_I_LOW_WATER) { - tp->t_state &= ~TS_RTSBLOCK; - ttstart(tp); - } -#endif +out: + if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW) + && INPUT_LEN(tp) <= I_LOW_WATER) + ttyunblock(tp); + + splx(s); return (error); } @@ -1328,12 +1599,12 @@ loop: * Sleeps here are not interruptible, but we return prematurely * if new signals come in. */ +int ttycheckoutq(tp, wait) register struct tty *tp; int wait; { int hiwat, s, oldsig; - extern int wakeup(); hiwat = tp->t_hiwat; s = spltty(); @@ -1348,9 +1619,10 @@ ttycheckoutq(tp, wait) splx(s); return (0); } - timeout(wakeup, (caddr_t)&tp->t_out, hz); + timeout((timeout_func_t)wakeup, (caddr_t)&tp->t_out, + hz); /* XXX */ tp->t_state |= TS_ASLEEP; - sleep((caddr_t)&tp->t_out, PZERO - 1); + tsleep((caddr_t)&tp->t_out, PZERO - 1, "ttchout", 0); } splx(s); return (1); @@ -1359,11 +1631,13 @@ ttycheckoutq(tp, wait) /* * Process a write call on a tty device. */ +int ttwrite(tp, uio, flag) register struct tty *tp; register struct uio *uio; + int flag; { - register char *cp; + register char *cp = NULL; register int cc = 0, ce; register struct proc *p = curproc; int i, hiwat, cnt, error, s; @@ -1420,14 +1694,27 @@ loop: uio->uio_resid = 0; return (0); } - if (RB_LEN(&tp->t_out) > hiwat) + /* + * The output queue may be changed by the interrupt handler: + * (1) certain inputs flush it + * (2) sio hacks on it for output completion. + * The queue length always (?) shrinks so stale counts from + * RB_LEN() are not a problem. However, incorrect counts + * caused by in-between pointers are a problem. The locking + * to fix this is messy because of all the gotos. + */ + s = spltty(); + if (RB_LEN(&tp->t_out) > hiwat) { + splx(s); goto ovhiwat; + } + splx(s); /* * Grab a hunk of data from the user, * unless we have some leftover from last time. */ if (cc == 0) { - cc = min(uio->uio_resid, OBUFSIZ); + cc = imin(uio->uio_resid, OBUFSIZ); cp = obuf; error = uiomove(cp, cc, uio); if (error) { @@ -1459,7 +1746,6 @@ loop: if (ttyoutput(*cp, tp) >= 0) { /* no c-lists, wait a bit */ ttstart(tp); -printf("\nttysleep - no c-lists\n"); /* XXX */ if (error = ttysleep(tp, (caddr_t)&lbolt, TTOPRI | PCATCH, ttybuf, 0)) @@ -1467,9 +1753,13 @@ printf("\nttysleep - no c-lists\n"); /* XXX */ goto loop; } cp++, cc--; + s = spltty(); if ((tp->t_lflag&FLUSHO) || - RB_LEN(&tp->t_out) > hiwat) + RB_LEN(&tp->t_out) > hiwat) { + splx(s); goto ovhiwat; + } + splx(s); continue; } } @@ -1487,7 +1777,8 @@ printf("\nttysleep - no c-lists\n"); /* XXX */ ce -= i; #else i = ce; - ce = min (ce, RB_CONTIGPUT(&tp->t_out)); + s = spltty(); + ce = imin(ce, RB_CONTIGPUT(&tp->t_out)); bcopy(cp, tp->t_out.rb_tl, ce); tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl + ce); @@ -1495,30 +1786,41 @@ printf("\nttysleep - no c-lists\n"); /* XXX */ if (i > 0) { int ii; - ii = min (i, RB_CONTIGPUT(&tp->t_out)); + ii = imin(i, RB_CONTIGPUT(&tp->t_out)); bcopy(cp + ce, tp->t_out.rb_tl, ii); tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl + ii); i -= ii; ce += ii; } + splx(s); #endif tp->t_col += ce; cp += ce, cc -= ce, tk_nout += ce; tp->t_outcc += ce; if (i > 0) { ttstart(tp); - if (RB_CONTIGPUT(&tp->t_out) > 0) + s = spltty(); + if (RB_CONTIGPUT(&tp->t_out) > 0) { + splx(s); goto loop; /* synchronous/fast */ + } /* out of space, wait a bit */ tp->t_state |= TS_ASLEEP; if (error = ttysleep(tp, (caddr_t)&tp->t_out, - TTOPRI | PCATCH, ttybuf, 0)) + TTOPRI | PCATCH, ttybuf, 0)) { + splx(s); break; + } + splx(s); goto loop; } - if (tp->t_lflag&FLUSHO || RB_LEN(&tp->t_out) > hiwat) + s = spltty(); + if (tp->t_lflag&FLUSHO || RB_LEN(&tp->t_out) > hiwat) { + splx(s); break; + } + splx(s); } ttstart(tp); } @@ -1562,8 +1864,9 @@ ovhiwat: * Rubout one character from the rawq of tp * as cleanly as possible. */ +static void ttyrub(c, tp) - register c; + register int c; register struct tty *tp; { char *cp; @@ -1650,6 +1953,7 @@ ttyrub(c, tp) * Crt back over cnt chars perhaps * erasing them. */ +static void ttyrubo(tp, cnt) register struct tty *tp; int cnt; @@ -1663,6 +1967,7 @@ ttyrubo(tp, cnt) * Reprint the rawq line. * We assume c_cc has already been checked. */ +static void ttyretype(tp) register struct tty *tp; { @@ -1690,20 +1995,17 @@ ttyretype(tp) /* * Echo a typed character to the terminal. */ +static void ttyecho(c, tp) - register c; + register int c; register struct tty *tp; { if ((tp->t_state & TS_CNTTB) == 0) tp->t_lflag &= ~FLUSHO; - if (tp->t_lflag & EXTPROC) + if (tp->t_lflag & EXTPROC + || (tp->t_lflag & ECHO) == 0 + && (c != '\n' || (tp->t_lflag & ECHONL) == 0)) return; - if ((tp->t_lflag & ECHO) == 0) { - if ((tp->t_lflag & ECHONL) == 0) - return; - else if (c != '\n') - return; - } if (tp->t_lflag & ECHOCTL) { if ((c & TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || c == 0177) { @@ -1721,6 +2023,7 @@ ttyecho(c, tp) /* * send string cp to tp */ +static void ttyoutstr(cp, tp) register char *cp; register struct tty *tp; @@ -1734,6 +2037,7 @@ ttyoutstr(cp, tp) /* * Wake up any readers on a tty. */ +void ttwakeup(tp) register struct tty *tp; { @@ -1752,7 +2056,9 @@ ttwakeup(tp) * Look up a code for a specified speed in a conversion table; * used by drivers to map software speed values to hardware parameters. */ +int ttspeedtab(speed, table) + int speed; register struct speedtab *table; { @@ -1769,6 +2075,7 @@ ttspeedtab(speed, table) * from hi to low water. * */ +void ttsetwater(tp) struct tty *tp; { @@ -1786,19 +2093,20 @@ ttsetwater(tp) /* * Report on state of foreground process group. */ +void ttyinfo(tp) register struct tty *tp; { register struct proc *p, *pick; struct timeval utime, stime; - int tmp; + int loadtmp; if (ttycheckoutq(tp,0) == 0) return; /* Print load average. */ - tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; - ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); + loadtmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; + ttyprintf(tp, "load: %d.%02d ", loadtmp / 100, loadtmp % 100); if (tp->t_session == NULL) ttyprintf(tp, "not a controlling terminal\n"); @@ -1807,25 +2115,47 @@ ttyinfo(tp) else if ((p = tp->t_pgrp->pg_mem) == NULL) ttyprintf(tp, "empty foreground process group\n"); else { + int kspace; + int s; + pid_t pid; + char wmesg[WMESGLEN+1]; + char comm[MAXCOMLEN+1]; /* Pick interesting process. */ for (pick = NULL; p != NULL; p = p->p_pgrpnxt) if (proc_compare(pick, p)) pick = p; - ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, + if( pick == NULL) { + ttyprintf(tp, "process went away\n"); + goto finish; + } + +#define pgtok(a) (((a) * NBPG) / 1024) + + if( (pick->p_flag & SLOAD) && (pick->p_vmspace)) + kspace = pgtok(pick->p_vmspace->vm_pmap.pm_stats.resident_count); + else + kspace = 0; + strncpy(wmesg, ((pick->p_flag & SLOAD) == 0 ? "swapped": pick->p_stat == SRUN ? "running" : - pick->p_wmesg ? pick->p_wmesg : "iowait"); + pick->p_wmesg ? pick->p_wmesg : "iowait"), WMESGLEN); + wmesg[WMESGLEN] = 0; + + strncpy(comm, pick->p_comm ? pick->p_comm : "", MAXCOMLEN); + comm[MAXCOMLEN] = 0; + + loadtmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT; + + pid = pick->p_pid; /* * Lock out clock if process is running; get user/system * cpu time. */ - if (curproc == pick) - tmp = splclock(); utime = pick->p_utime; stime = pick->p_stime; - if (curproc == pick) - splx(tmp); + + ttyprintf(tp, " cmd: %s %d [%s] ", comm, pid, wmesg); /* Print user time. */ ttyprintf(tp, "%d.%02du ", @@ -1835,12 +2165,10 @@ ttyinfo(tp) ttyprintf(tp, "%d.%02ds ", stime.tv_sec, (stime.tv_usec + 5000) / 10000); -#define pgtok(a) (((a) * NBPG) / 1024) /* Print percentage cpu, resident set size. */ - tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; - ttyprintf(tp, "%d%% %dk\n", - tmp / 100, pgtok(pick->p_vmspace->vm_rssize)); + ttyprintf(tp, "%d%% %dk\n", loadtmp / 100, kspace); } +finish: tp->t_rocount = 0; /* so pending input will be retyped if BS */ } @@ -1923,6 +2251,7 @@ proc_compare(p1, p2) /* * Output char to tty; console putchar style. */ +int tputchar(c, tp) int c; struct tty *tp; @@ -1947,15 +2276,16 @@ tputchar(c, tp) * reported by tsleep. If the tty is revoked, restarting a pending * call will redo validation done at the start of the call. */ +int ttysleep(tp, chan, pri, wmesg, timo) struct tty *tp; caddr_t chan; int pri; - char *wmesg; + const char *wmesg; int timo; { int error; - short gen = tp->t_gen; + int gen = tp->t_gen; if (error = tsleep(chan, pri, wmesg, timo)) return (error); diff --git a/sys/kern/tty_chu.c b/sys/kern/tty_chu.c new file mode 100644 index 000000000000..4615875e77e0 --- /dev/null +++ b/sys/kern/tty_chu.c @@ -0,0 +1,276 @@ +/* tty_chu.c,v 3.1 1993/07/06 01:07:30 jbj Exp + * tty_chu.c - CHU line driver + */ + +#include "chu.h" +#if NCHU > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" + +#include "../h/chudefs.h" + +/* + * Line discipline for receiving CHU time codes. + * Does elementary noise elimination, takes time stamps after + * the arrival of each character, returns a buffer full of the + * received 10 character code and the associated time stamps. + */ +#define NUMCHUBUFS 3 + +struct chudata { + u_char used; /* Set to 1 when structure in use */ + u_char lastindex; /* least recently used buffer */ + u_char curindex; /* buffer to use */ + u_char sleeping; /* set to 1 when we're sleeping on a buffer */ + struct chucode chubuf[NUMCHUBUFS]; +} chu_data[NCHU]; + +/* + * Number of microseconds we allow between + * character arrivals. The speed is 300 baud + * so this should be somewhat more than 30 msec + */ +#define CHUMAXUSEC (50*1000) /* 50 msec */ + +int chu_debug = 0; + +/* + * Open as CHU time discipline. Called when discipline changed + * with ioctl, and changes the interpretation of the information + * in the tty structure. + */ +/*ARGSUSED*/ +chuopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct chudata *chu; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CHULDISC) + return (EBUSY); + ttywflush(tp); + for (chu = chu_data; chu < &chu_data[NCHU]; chu++) + if (!chu->used) + break; + if (chu >= &chu[NCHU]) + return (EBUSY); + chu->used++; + chu->lastindex = chu->curindex = 0; + chu->sleeping = 0; + chu->chubuf[0].ncodechars = 0; + tp->T_LINEP = (caddr_t) chu; + return (0); +} + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +chuclose(tp) + register struct tty *tp; +{ + register int s = spl5(); + + ((struct chudata *) tp->T_LINEP)->used = 0; + tp->t_cp = 0; + tp->t_inbuf = 0; + tp->t_rawq.c_cc = 0; /* clear queues -- paranoid */ + tp->t_canq.c_cc = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + +/* + * Read a CHU buffer. Sleep on the current buffer + */ +churead(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + register struct chudata *chu; + register struct chucode *chucode; + register int s; + + if ((tp->t_state&TS_CARR_ON)==0) + return (EIO); + + chu = (struct chudata *) (tp->T_LINEP); + + s = spl5(); + chucode = &(chu->chubuf[chu->lastindex]); + while (chu->curindex == chu->lastindex) { + chu->sleeping = 1; + sleep((caddr_t)chucode, TTIPRI); + } + chu->sleeping = 0; + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + splx(s); + + return (uiomove((caddr_t)chucode, sizeof(*chucode), UIO_READ, uio)); +} + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +chuinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct chudata *chu = (struct chudata *) tp->T_LINEP; + register struct chucode *chuc; + register int i; + long sec, usec; + struct timeval tv; + + /* + * Do a check on the BSDness of the character. This delays + * the time stamp a bit but saves a fair amount of overhead + * when the static is bad. + */ + if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9) { + chuc = &(chu->chubuf[chu->curindex]); + chuc->ncodechars = 0; /* blow all previous away */ + return; + } + + /* + * Call microtime() to get the current time of day + */ + microtime(&tv); + + /* + * Compute the difference in this character's time stamp + * and the last. If it exceeds the margin, blow away all + * the characters currently in the buffer. + */ + chuc = &(chu->chubuf[chu->curindex]); + i = (int)chuc->ncodechars; + if (i > 0) { + sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec; + usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec; + if (usec < 0) { + sec -= 1; + usec += 1000000; + } + if (sec != 0 || usec > CHUMAXUSEC) { + i = 0; + chuc->ncodechars = 0; + } + } + + /* + * Store the character. If we're done, have to tell someone + */ + chuc->codechars[i] = (u_char)c; + chuc->codetimes[i] = tv; + + if (++i < NCHUCHARS) { + /* + * Not much to do here. Save the count and wait + * for another character. + */ + chuc->ncodechars = (u_char)i; + } else { + /* + * Mark this buffer full and point at next. If the + * next buffer is full we overwrite it by bumping the + * next pointer. + */ + chuc->ncodechars = NCHUCHARS; + if (++(chu->curindex) >= NUMCHUBUFS) + chu->curindex = 0; + if (chu->curindex == chu->lastindex) + if (++(chu->lastindex) >= NUMCHUBUFS) + chu->lastindex = 0; + chu->chubuf[chu->curindex].ncodechars = 0; + + /* + * Wake up anyone sleeping on this. Also wake up + * selectors and/or deliver a SIGIO as required. + */ + if (tp->t_rsel) { + selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); + tp->t_state &= ~TS_RCOLL; + tp->t_rsel = 0; + } + if (tp->t_state & TS_ASYNC) + gsignal(tp->t_pgrp, SIGIO); + if (chu->sleeping) + (void) wakeup((caddr_t)chuc); + } +} + +/* + * Handle ioctls. We reject all tty-style except those that + * change the line discipline. + */ +chuioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + return (-1); + } + return (ENOTTY); /* not quite appropriate */ +} + + +chuselect(dev, rw) + dev_t dev; + int rw; +{ + register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; + struct chudata *chu; + int s = spl5(); + + chu = (struct chudata *) (tp->T_LINEP); + + switch (rw) { + + case FREAD: + if (chu->curindex != chu->lastindex) + goto win; + if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) + tp->t_state |= TS_RCOLL; + else + tp->t_rsel = u.u_procp; + break; + + case FWRITE: + goto win; + } + splx(s); + return (0); +win: + splx(s); + return (1); +} +#endif NCHU diff --git a/sys/kern/tty_clk.c b/sys/kern/tty_clk.c new file mode 100644 index 000000000000..d1b4bbef64b4 --- /dev/null +++ b/sys/kern/tty_clk.c @@ -0,0 +1,303 @@ +/* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp + * tty_clk.c - Generic line driver for receiving radio clock timecodes + */ + +#include "clk.h" +#if NCLK > 0 + +#include "../h/param.h" +#include "../h/types.h" +#include "../h/systm.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/ioctl.h" +#include "../h/tty.h" +#include "../h/proc.h" +#include "../h/file.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/uio.h" +#include "../h/clist.h" + +/* + * This line discipline is intended to provide well performing + * generic support for the reception and time stamping of radio clock + * timecodes. Most radio clock devices return a string where a + * particular character in the code (usually a \r) is on-time + * synchronized with the clock. The idea here is to collect characters + * until (one of) the synchronization character(s) (we allow two) is seen. + * When the magic character arrives we take a timestamp by calling + * microtime() and insert the eight bytes of struct timeval into the + * buffer after the magic character. We then wake up anyone waiting + * for the buffer and return the whole mess on the next read. + * + * To use this the calling program is expected to first open the + * port, and then to set the port into raw mode with the speed + * set appropriately with a TIOCSETP ioctl(), with the erase and kill + * characters set to those to be considered magic (yes, I know this + * is gross, but they were so convenient). If only one character is + * magic you can set then both the same, or perhaps to the alternate + * parity versions of said character. After getting all this set, + * change the line discipline to CLKLDISC and you are on your way. + * + * The only other bit of magic we do in here is to flush the receive + * buffers on writes if the CRMOD flag is set (hack, hack). + */ + +/* + * We run this very much like a raw mode terminal, with the exception + * that we store up characters locally until we hit one of the + * magic ones and then dump it into the rawq all at once. We keep + * the buffered data in clists since we can then often move it to + * the rawq without copying. For sanity we limit the number of + * characters between specials, and the total number of characters + * before we flush the rawq, as follows. + */ +#define CLKLINESIZE (256) +#define NCLKCHARS (CLKLINESIZE*4) + +struct clkdata { + int inuse; + struct clist clkbuf; +}; +#define clk_cc clkbuf.c_cc +#define clk_cf clkbuf.c_cf +#define clk_cl clkbuf.c_cl + +struct clkdata clk_data[NCLK]; + +/* + * Routine for flushing the internal clist + */ +#define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc)) + +int clk_debug = 0; + +/*ARGSUSED*/ +clkopen(dev, tp) + dev_t dev; + register struct tty *tp; +{ + register struct clkdata *clk; + + /* + * Don't allow multiple opens. This will also protect us + * from someone opening /dev/tty + */ + if (tp->t_line == CLKLDISC) + return (EBUSY); + ttywflush(tp); + for (clk = clk_data; clk < &clk_data[NCLK]; clk++) + if (!clk->inuse) + break; + if (clk >= &clk_data[NCLK]) + return (EBUSY); + clk->inuse++; + clk->clk_cc = 0; + clk->clk_cf = clk->clk_cl = NULL; + tp->T_LINEP = (caddr_t) clk; + return (0); +} + + +/* + * Break down... called when discipline changed or from device + * close routine. + */ +clkclose(tp) + register struct tty *tp; +{ + register struct clkdata *clk; + register int s = spltty(); + + clk = (struct clkdata *)tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + clk->inuse = 0; + tp->t_line = 0; /* paranoid: avoid races */ + splx(s); +} + + +/* + * Receive a write request. We pass these requests on to the terminal + * driver, except that if the CRMOD bit is set in the flags we + * first flush the input queues. + */ +clkwrite(tp, uio) + register struct tty *tp; + struct uio *uio; +{ + if (tp->t_flags & CRMOD) { + register struct clkdata *clk; + int s; + + s = spltty(); + if (tp->t_rawq.c_cc > 0) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + (void)splx(s); + } + ttwrite(tp, uio); +} + + +/* + * Low level character input routine. + * If the character looks okay, grab a time stamp. If the stuff in + * the buffer is too old, dump it and start fresh. If the character is + * non-BCDish, everything in the buffer too. + */ +clkinput(c, tp) + register int c; + register struct tty *tp; +{ + register struct clkdata *clk; + register int i; + register long s; + struct timeval tv; + + /* + * Check to see whether this isn't the magic character. If not, + * save the character and return. + */ +#ifdef ultrix + if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) { +#else + if (c != tp->t_erase && c != tp->t_kill) { +#endif + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc >= CLKLINESIZE) + clk_bflush(clk); + if (putc(c, &clk->clkbuf) == -1) { + /* + * Hopeless, no clists. Flush what we have + * and hope things improve. + */ + clk_bflush(clk); + } + return; + } + + /* + * Here we have a magic character. Get a timestamp and store + * everything. + */ + microtime(&tv); + clk = (struct clkdata *) tp->T_LINEP; + + if (putc(c, &clk->clkbuf) == -1) + goto flushout; + + s = tv.tv_sec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } + + s = tv.tv_usec; + for (i = 0; i < sizeof(long); i++) { + if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) + goto flushout; + s <<= 8; + } + + /* + * If the length of the rawq exceeds our sanity limit, dump + * all the old crap in there before copying this in. + */ + if (tp->t_rawq.c_cc > NCLKCHARS) + ndflush(&tp->t_rawq, tp->t_rawq.c_cc); + + /* + * Now copy the buffer in. There is a special case optimization + * here. If there is nothing on the rawq at present we can + * just copy the clists we own over. Otherwise we must concatenate + * the present data on the end. + */ + s = (long)spltty(); + if (tp->t_rawq.c_cc <= 0) { + tp->t_rawq = clk->clkbuf; + clk->clk_cc = 0; + clk->clk_cl = clk->clk_cf = NULL; + (void) splx((int)s); + } else { + (void) splx((int)s); + catq(&clk->clkbuf, &tp->t_rawq); + clk_bflush(clk); + } + + /* + * Tell the world + */ + ttwakeup(tp); + return; + +flushout: + /* + * It would be nice if this never happened. Flush the + * internal clists and hope someone else frees some of them + */ + clk_bflush(clk); + return; +} + + +/* + * Handle ioctls. We reject most tty-style except those that + * change the line discipline and a couple of others.. + */ +clkioctl(tp, cmd, data, flag) + struct tty *tp; + int cmd; + caddr_t data; + int flag; +{ + int flags; + struct sgttyb *sg; + + if ((cmd>>8) != 't') + return (-1); + switch (cmd) { + case TIOCSETD: + case TIOCGETD: + case TIOCGETP: + case TIOCGETC: + case TIOCOUTQ: + return (-1); + + case TIOCSETP: + /* + * He likely wants to set new magic characters in. + * Do this part. + */ + sg = (struct sgttyb *)data; +#ifdef ultrix + tp->t_cc[VERASE] = sg->sg_erase; + tp->t_cc[VKILL] = sg->sg_kill; +#else + tp->t_erase = sg->sg_erase; + tp->t_kill = sg->sg_kill; +#endif + return (0); + + case TIOCFLUSH: + flags = *(int *)data; + if (flags == 0 || (flags & FREAD)) { + register struct clkdata *clk; + + clk = (struct clkdata *) tp->T_LINEP; + if (clk->clk_cc > 0) + clk_bflush(clk); + } + return (-1); + + default: + break; + } + return (ENOTTY); /* not quite appropriate */ +} +#endif NCLK diff --git a/sys/kern/tty_compat.c b/sys/kern/tty_compat.c index a3b92500059c..45994be7ee27 100644 --- a/sys/kern/tty_compat.c +++ b/sys/kern/tty_compat.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)tty_compat.c 7.10 (Berkeley) 5/9/91 - * $Id: tty_compat.c,v 1.2 1993/10/16 15:24:57 rgrimes Exp $ + * $Id: tty_compat.c,v 1.4 1993/12/19 00:51:40 wollman Exp $ */ /* @@ -51,6 +51,10 @@ #include "kernel.h" #include "syslog.h" +static int ttcompatgetflags(struct tty *); +static void ttcompatsetflags(struct tty *, struct termios *); +static void ttcompatsetlflags(struct tty *, struct termios *); + int ttydebug = 0; static struct speedtab compatspeeds[] = { @@ -81,9 +85,12 @@ static int compatspcodes[] = { }; /*ARGSUSED*/ +int ttcompat(tp, com, data, flag) register struct tty *tp; + int com; caddr_t data; + int flag; { switch (com) { @@ -123,7 +130,7 @@ ttcompat(tp, com, data, flag) term.c_ospeed = compatspcodes[speed]; term.c_cc[VERASE] = sg->sg_erase; term.c_cc[VKILL] = sg->sg_kill; - tp->t_flags = tp->t_flags&0xffff0000 | sg->sg_flags&0xffff; + tp->t_flags = tp->t_flags&0xffff0000UL | sg->sg_flags&0xffff; ttcompatsetflags(tp, &term); return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA, (caddr_t)&term, flag)); @@ -189,7 +196,8 @@ ttcompat(tp, com, data, flag) tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16; else { tp->t_flags = - (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff); + (ttcompatgetflags(tp) & 0xffff0000UL) + | (tp->t_flags & 0xffff); if (com == TIOCLBIS) tp->t_flags |= *(int *)data<<16; else @@ -200,7 +208,8 @@ ttcompat(tp, com, data, flag) } case TIOCLGET: tp->t_flags = - (ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff); + (ttcompatgetflags(tp) & 0xffff0000UL) + | (tp->t_flags & 0xffff); *(int *)data = tp->t_flags>>16; if (ttydebug) printf("CLGET: returning %x\n", *(int *)data); @@ -227,6 +236,7 @@ ttcompat(tp, com, data, flag) return (0); } +static int ttcompatgetflags(tp) register struct tty *tp; { @@ -284,6 +294,7 @@ if (ttydebug) return (flags); } +static void ttcompatsetflags(tp, t) register struct tty *tp; register struct termios *t; @@ -356,6 +367,7 @@ ttcompatsetflags(tp, t) t->c_cflag = cflag; } +static void ttcompatsetlflags(tp, t) register struct tty *tp; register struct termios *t; diff --git a/sys/kern/tty_conf.c b/sys/kern/tty_conf.c index 861adfe4b324..6b9ad4917460 100644 --- a/sys/kern/tty_conf.c +++ b/sys/kern/tty_conf.c @@ -1,3 +1,10 @@ +/* + * Copyright (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. + */ /*- * Copyright (c) 1982, 1986, 1991 The Regents of the University of California. * All rights reserved. @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)tty_conf.c 7.6 (Berkeley) 5/9/91 - * $Id: tty_conf.c,v 1.3 1993/10/16 15:24:58 rgrimes Exp $ + * $Id: tty_conf.c,v 1.6.2.1 1994/05/04 07:54:52 rgrimes Exp $ */ #include "param.h" @@ -43,10 +50,12 @@ int enodev(); int nullop(); +static int nullioctl(struct tty *, int, caddr_t, int); -int ttyopen(),ttylclose(),ttread(),ttwrite(),nullioctl(),ttstart(); -int ttymodem(), nullmodem(), ttyinput(); +#define VE(x) ((void (*)())x) /* XXX */ +#define IE(x) ((int (*)())x) /* XXX */ +/* XXX - doesn't work */ #include "tb.h" #if NTB > 0 int tbopen(),tbclose(),tbread(),tbinput(),tbioctl(); @@ -68,31 +77,32 @@ struct linesw linesw[] = ttyopen, ttylclose, ttread, ttwrite, nullioctl, ttyinput, enodev, nullop, ttstart, ttymodem, /* 0- termios */ - enodev, enodev, enodev, enodev, enodev, /* 1- defunct */ - enodev, enodev, enodev, enodev, enodev, + IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev), /* 1- defunct */ + VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev), + + ttyopen, ttylclose, ttread, ttwrite, nullioctl, + ttyinput, enodev, nullop, ttstart, ttymodem, /* 2- NTTYDISC */ - enodev, enodev, enodev, enodev, enodev, /* 2- defunct */ - enodev, enodev, enodev, enodev, enodev, #if NTB > 0 - tbopen, tbclose, tbread, enodev, tbioctl, + tbopen, tbclose, tbread, IE(enodev), tbioctl, tbinput, enodev, nullop, ttstart, nullmodem, /* 3- TABLDISC */ #else - enodev, enodev, enodev, enodev, enodev, - enodev, enodev, enodev, enodev, enodev, + IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev), + VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev), #endif #if NSL > 0 - slopen, slclose, enodev, enodev, sltioctl, - slinput, enodev, nullop, slstart, nullmodem, /* 4- SLIPDISC */ + slopen, VE(slclose), IE(enodev), IE(enodev), sltioctl, + VE(slinput), enodev, nullop, VE(slstart), nullmodem, /* 4- SLIPDISC */ #else - enodev, enodev, enodev, enodev, enodev, - enodev, enodev, enodev, enodev, enodev, + IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev), + VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev), #endif #if NPPP > 0 - pppopen, pppclose, pppread, pppwrite, ppptioctl, - pppinput, enodev, nullop, pppstart, ttymodem, /* 5- PPPDISC */ + pppopen, VE(pppclose), pppread, pppwrite, ppptioctl, + VE(pppinput), enodev, nullop, VE(pppstart), ttymodem, /* 5- PPPDISC */ #else - enodev, enodev, enodev, enodev, enodev, - enodev, enodev, enodev, enodev, enodev, + IE(enodev), VE(enodev), IE(enodev), IE(enodev), IE(enodev), + VE(enodev), IE(enodev), IE(enodev), VE(enodev), IE(enodev), #endif }; @@ -103,8 +113,10 @@ int nldisp = sizeof (linesw) / sizeof (linesw[0]); * discipline specific ioctl command. */ /*ARGSUSED*/ +static int nullioctl(tp, cmd, data, flags) struct tty *tp; + int cmd; char *data; int flags; { diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index b324ca4a1b29..0e99e9329e0a 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)tty_pty.c 7.21 (Berkeley) 5/30/91 - * $Id: tty_pty.c,v 1.4 1993/10/16 15:25:00 rgrimes Exp $ + * $Id: tty_pty.c,v 1.9 1994/01/29 04:04:26 davidg Exp $ */ /* @@ -51,6 +51,7 @@ #include "uio.h" #include "kernel.h" #include "vnode.h" +#include "signalvar.h" #if NPTY == 1 #undef NPTY @@ -59,6 +60,8 @@ #define BUFSIZ 100 /* Chunk size iomoved to/from user */ +static void ptcwakeup(struct tty *, int); + /* * pts == /dev/tty[pqrs]? * ptc == /dev/pty[pqrs]? @@ -81,8 +84,11 @@ int npty = NPTY; /* for pstat -t */ #define PF_UCNTL 0x80 /* user control mode */ /*ARGSUSED*/ +int ptsopen(dev, flag, devtype, p) dev_t dev; + int flag; + int devtype; struct proc *p; { register struct tty *tp; @@ -120,6 +126,7 @@ ptsopen(dev, flag, devtype, p) return (error); } +int ptsclose(dev, flag, mode, p) dev_t dev; int flag, mode; @@ -134,9 +141,11 @@ ptsclose(dev, flag, mode, p) return(0); } +int ptsread(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { struct proc *p = curproc; register struct tty *tp = &pt_tty[minor(dev)]; @@ -185,9 +194,11 @@ again: * Wakeups of controlling tty will happen * indirectly, when tty driver calls ptsstart. */ +int ptswrite(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { register struct tty *tp; @@ -201,6 +212,7 @@ ptswrite(dev, uio, flag) * Start output on pseudo-tty. * Wake up process selecting or sleeping for input from controlling tty. */ +void ptsstart(tp) struct tty *tp; { @@ -215,8 +227,10 @@ ptsstart(tp) ptcwakeup(tp, FREAD); } +static void ptcwakeup(tp, flag) struct tty *tp; + int flag; { struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; @@ -239,8 +253,9 @@ ptcwakeup(tp, flag) } /*ARGSUSED*/ +int #ifdef __STDC__ -ptcopen(dev_t dev, int flag, int devtype, struct proc *p) +ptcopen(int /*dev_t*/ dev, int flag, int devtype, struct proc *p) #else ptcopen(dev, flag, devtype, p) dev_t dev; @@ -267,6 +282,8 @@ ptcopen(dev, flag, devtype, p) } extern struct tty *constty; /* -hv- 06.Oct.92*/ + +int ptcclose(dev) dev_t dev; { @@ -278,16 +295,17 @@ ptcclose(dev) tp->t_oproc = 0; /* mark closed */ tp->t_session = 0; -/* XXX -hv- 6.Oct.92 this prevents the "hanging console bug" with X11 */ if (constty==tp) constty = 0; return (0); } +int ptcread(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { register struct tty *tp = &pt_tty[minor(dev)]; struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; @@ -363,6 +381,7 @@ ptcread(dev, uio, flag) return (error); } +void ptsstop(tp, flush) register struct tty *tp; int flush; @@ -386,6 +405,7 @@ ptsstop(tp, flush) ptcwakeup(tp, flag); } +int ptcselect(dev, rw, p) dev_t dev; int rw; @@ -447,12 +467,14 @@ ptcselect(dev, rw, p) return (0); } +int ptcwrite(dev, uio, flag) dev_t dev; register struct uio *uio; + int flag; { register struct tty *tp = &pt_tty[minor(dev)]; - register u_char *cp; + register u_char *cp = 0; register int cc = 0; u_char locbuf[BUFSIZ]; int cnt = 0; @@ -542,15 +564,17 @@ block: } /*ARGSUSED*/ +int ptyioctl(dev, cmd, data, flag) caddr_t data; + int cmd; dev_t dev; + int flag; { register struct tty *tp = &pt_tty[minor(dev)]; register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; register u_char *cc = tp->t_cc; int stop, error; - extern ttyinput(); /* * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. diff --git a/sys/kern/tty_ring.c b/sys/kern/tty_ring.c index f4149e576214..5c1e1fbcb4fa 100644 --- a/sys/kern/tty_ring.c +++ b/sys/kern/tty_ring.c @@ -45,7 +45,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: tty_ring.c,v 1.2 1993/10/16 15:25:01 rgrimes Exp $ + * $Id: tty_ring.c,v 1.4 1993/12/19 00:51:42 wollman Exp $ */ #include "param.h" @@ -54,12 +54,10 @@ #include "ioctl.h" #include "tty.h" -/* - * XXX - put this in tty.h someday. - */ -size_t rb_write __P((struct ringb *to, char *buf, size_t nfrom)); - -putc(c, rbp) struct ringb *rbp; +int +putc(c, rbp) + int c; + struct ringb *rbp; { char *nxtp; @@ -72,7 +70,9 @@ putc(c, rbp) struct ringb *rbp; return(0); } -getc(rbp) struct ringb *rbp; +int +getc(rbp) + struct ringb *rbp; { u_char c; @@ -85,7 +85,11 @@ getc(rbp) struct ringb *rbp; return (c); } -nextc(cpp, rbp) struct ringb *rbp; char **cpp; { +int +nextc(cpp, rbp) + char **cpp; + struct ringb *rbp; +{ if (*cpp == rbp->rb_tl) return (0); else { char *cp; @@ -95,7 +99,10 @@ nextc(cpp, rbp) struct ringb *rbp; char **cpp; { } } -ungetc(c, rbp) struct ringb *rbp; +int +ungetc(c, rbp) + int c; + struct ringb *rbp; { char *backp; @@ -108,7 +115,9 @@ ungetc(c, rbp) struct ringb *rbp; return(0); } -unputc(rbp) struct ringb *rbp; +int +unputc(rbp) + struct ringb *rbp; { char *backp; int c; @@ -126,7 +135,10 @@ unputc(rbp) struct ringb *rbp; #define peekc(rbp) (*(rbp)->rb_hd) -initrb(rbp) struct ringb *rbp; { +void +initrb(rbp) + struct ringb *rbp; +{ rbp->rb_hd = rbp->rb_tl = rbp->rb_buf; } @@ -157,6 +169,7 @@ initrb(rbp) struct ringb *rbp; { /* * Concatenate ring buffers. */ +void catb(from, to) struct ringb *from, *to; { diff --git a/sys/kern/tty_tty.c b/sys/kern/tty_tty.c index d00e79092680..30fbe19eef73 100644 --- a/sys/kern/tty_tty.c +++ b/sys/kern/tty_tty.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)tty_tty.c 7.15 (Berkeley) 5/28/91 - * $Id: tty_tty.c,v 1.2 1993/10/16 15:25:05 rgrimes Exp $ + * $Id: tty_tty.c,v 1.3 1993/11/25 01:33:30 wollman Exp $ */ /* @@ -49,6 +49,7 @@ #define cttyvp(p) ((p)->p_flag&SCTTY ? (p)->p_session->s_ttyvp : NULL) /*ARGSUSED*/ +int cttyopen(dev, flag, mode, p) dev_t dev; int flag, mode; @@ -69,9 +70,11 @@ cttyopen(dev, flag, mode, p) } /*ARGSUSED*/ +int cttyread(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { register struct vnode *ttyvp = cttyvp(uio->uio_procp); int error; @@ -85,9 +88,11 @@ cttyread(dev, uio, flag) } /*ARGSUSED*/ +int cttywrite(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { register struct vnode *ttyvp = cttyvp(uio->uio_procp); int error; @@ -101,6 +106,7 @@ cttywrite(dev, uio, flag) } /*ARGSUSED*/ +int cttyioctl(dev, cmd, addr, flag, p) dev_t dev; int cmd; @@ -112,7 +118,9 @@ cttyioctl(dev, cmd, addr, flag, p) if (ttyvp == NULL) return (EIO); - if (cmd == TIOCNOTTY) { + if (cmd == TIOCSCTTY) /* don't allow controlling tty to be set */ + return EINVAL; /* to controlling tty - infinite recursion */ + else if (cmd == TIOCNOTTY) { if (!SESS_LEADER(p)) { p->p_flag &= ~SCTTY; return (0); @@ -123,6 +131,7 @@ cttyioctl(dev, cmd, addr, flag, p) } /*ARGSUSED*/ +int cttyselect(dev, flag, p) dev_t dev; int flag; diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index 41a132996202..93a5088a11d8 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -31,11 +31,11 @@ * SUCH DAMAGE. * * from: @(#)uipc_domain.c 7.9 (Berkeley) 3/4/91 - * $Id: uipc_domain.c,v 1.2 1993/10/16 15:25:06 rgrimes Exp $ + * $Id: uipc_domain.c,v 1.5 1993/12/19 00:51:43 wollman Exp $ */ -#include <sys/cdefs.h> #include "param.h" +#include "systm.h" #include "socket.h" #include "protosw.h" #include "domain.h" @@ -43,12 +43,18 @@ #include "time.h" #include "kernel.h" +struct domain *domains; + #define ADDDOMAIN(x) { \ extern struct domain __CONCAT(x,domain); \ __CONCAT(x,domain.dom_next) = domains; \ domains = &__CONCAT(x,domain); \ } +static void pfslowtimo(caddr_t, int); +static void pffasttimo(caddr_t, int); + +void domaininit() { register struct domain *dp; @@ -91,8 +97,8 @@ if (max_linkhdr < 16) /* XXX */ max_linkhdr = 16; max_hdr = max_linkhdr + max_protohdr; max_datalen = MHLEN - max_hdr; - pffasttimo(); - pfslowtimo(); + pffasttimo(0, 0); + pfslowtimo(0, 0); } struct protosw * @@ -139,6 +145,7 @@ found: return (maybe); } +void pfctlinput(cmd, sa) int cmd; struct sockaddr *sa; @@ -152,7 +159,8 @@ pfctlinput(cmd, sa) (*pr->pr_ctlinput)(cmd, sa, (caddr_t) 0); } -pfslowtimo() +static void +pfslowtimo(caddr_t dummy1, int dummy2) { register struct domain *dp; register struct protosw *pr; @@ -164,7 +172,8 @@ pfslowtimo() timeout(pfslowtimo, (caddr_t)0, hz/2); } -pffasttimo() +static void +pffasttimo(caddr_t dummy1, int dummy2) { register struct domain *dp; register struct protosw *pr; diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 552653436890..c0cf7a4c68cd 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91 - * $Id: uipc_mbuf.c,v 1.3 1993/10/16 15:25:07 rgrimes Exp $ + * $Id: uipc_mbuf.c,v 1.6 1993/12/19 00:51:44 wollman Exp $ */ #include "param.h" @@ -46,10 +46,22 @@ #include "protosw.h" #include "vm/vm.h" +/* From sys/mbuf.h */ +struct mbstat mbstat; +int nmbclusters; +union mcluster *mclfree; +int max_linkhdr; +int max_protohdr; +int max_hdr; +int max_datalen; + extern vm_map_t mb_map; struct mbuf *mbutl; char *mclrefcnt; +static void m_reclaim(void); + +void mbinit() { int s; @@ -74,8 +86,10 @@ bad: * Must be called at splimp. */ /* ARGSUSED */ +int m_clalloc(ncl, how) /* 31 Aug 92*/ register int ncl; + int how; { int npg, mbx; register caddr_t p; @@ -136,6 +150,7 @@ m_retryhdr(i, t) return (m); } +static void m_reclaim() { register struct domain *dp; @@ -198,6 +213,7 @@ m_free(m) return (n); } +void m_freem(m) register struct mbuf *m; { @@ -321,6 +337,7 @@ nospace: * Copy data from an mbuf chain starting "off" bytes from the beginning, * continuing for "len" bytes, into the indicated buffer. */ +void m_copydata(m, off, len, cp) register struct mbuf *m; register int off; @@ -356,6 +373,7 @@ m_copydata(m, off, len, cp) * Both chains must be of the same type (e.g. MT_DATA). * Any m_pkthdr is not updated. */ +void m_cat(m, n) register struct mbuf *m, *n; { @@ -376,8 +394,10 @@ m_cat(m, n) } } +void m_adj(mp, req_len) struct mbuf *mp; + int req_len; { register int len = req_len; register struct mbuf *m; @@ -516,3 +536,230 @@ bad: MPFail++; return (0); } + +/* + * Copy data from a buffer back into the indicated mbuf chain, + * starting "off" bytes from the beginning, extending the mbuf + * chain if necessary. + */ +void +m_copyback(m0, off, len, cp) + struct mbuf *m0; + register int off; + register int len; + caddr_t cp; + +{ + register int mlen; + register struct mbuf *m = m0, *n; + int totlen = 0; + + if (m0 == 0) + return; + while (off > (mlen = m->m_len)) { + off -= mlen; + totlen += mlen; + if (m->m_next == 0) { + n = m_getclr(M_DONTWAIT, m->m_type); + if (n == 0) + goto out; + n->m_len = min(MLEN, len + off); + m->m_next = n; + } + m = m->m_next; + } + while (len > 0) { + mlen = min (m->m_len - off, len); + bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); + cp += mlen; + len -= mlen; + mlen += off; + off = 0; + totlen += mlen; + if (len == 0) + break; + if (m->m_next == 0) { + n = m_get(M_DONTWAIT, m->m_type); + if (n == 0) + break; + n->m_len = min(MLEN, len); + m->m_next = n; + } + m = m->m_next; + } +out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) + m->m_pkthdr.len = totlen; +} + +struct mbuf * +m_split (m0, len0, wait) + register struct mbuf *m0; + int len0; + int wait; +{ + register struct mbuf *m, *n; + unsigned len = len0, remain; + + for (m = m0; m && len > m -> m_len; m = m -> m_next) + len -= m -> m_len; + if (m == 0) + return (0); + remain = m -> m_len - len; + if (m0 -> m_flags & M_PKTHDR) { + MGETHDR(n, wait, m0 -> m_type); + if (n == 0) + return (0); + n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif; + n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0; + m0 -> m_pkthdr.len = len0; + if (m -> m_flags & M_EXT) + goto extpacket; + if (remain > MHLEN) { + /* m can't be the lead packet */ + MH_ALIGN(n, 0); + n -> m_next = m_split (m, len, wait); + if (n -> m_next == 0) { + (void) m_free (n); + return (0); + } else + return (n); + } else + MH_ALIGN(n, remain); + } else if (remain == 0) { + n = m -> m_next; + m -> m_next = 0; + return (n); + } else { + MGET(n, wait, m -> m_type); + if (n == 0) + return (0); + M_ALIGN(n, remain); + } +extpacket: + if (m -> m_flags & M_EXT) { + n -> m_flags |= M_EXT; + n -> m_ext = m -> m_ext; + mclrefcnt[mtocl (m -> m_ext.ext_buf)]++; + n -> m_data = m -> m_data + len; + } else { + bcopy (mtod (m, caddr_t) + len, mtod (n, caddr_t), remain); + } + n -> m_len = remain; + m -> m_len = len; + n -> m_next = m -> m_next; + m -> m_next = 0; + return (n); +} + +/* The following taken from netiso/iso_chksum.c */ +struct mbuf * +m_append(head, m) /* XXX */ + struct mbuf *head, *m; +{ + register struct mbuf *n; + + if (m == 0) + return head; + if (head == 0) + return m; + n = head; + while (n->m_next) + n = n->m_next; + n->m_next = m; + return head; +} + +/* + * FUNCTION: m_datalen + * + * PURPOSE: returns length of the mbuf chain. + * used all over the iso code. + * + * RETURNS: integer + * + * SIDE EFFECTS: none + * + * NOTES: + */ +int +m_datalen (morig) /* XXX */ + struct mbuf *morig; +{ + int s = splimp(); + register struct mbuf *n=morig; + register int datalen = 0; + + if( morig == (struct mbuf *)0) + return 0; + for(;;) { + datalen += n->m_len; + if (n->m_next == (struct mbuf *)0 ) { + break; + } + n = n->m_next; + } + splx(s); + return datalen; +} + +int +m_compress(in, out) + register struct mbuf *in, **out; +{ + register int datalen = 0; + int s = splimp(); + + if(!in->m_next) { + *out = in; + splx(s); + return in->m_len; + } + MGET((*out), M_DONTWAIT, MT_DATA); + if(! (*out)) { + *out = in; + splx(s); + return -1; + } + (*out)->m_len = 0; + (*out)->m_act = 0; + + while (in) { + if (in->m_flags & M_EXT) { +#ifdef DEBUG + ASSERT(in->m_len == 0); +#endif + } + if ( in->m_len == 0) { + in = in->m_next; + continue; + } + if (((*out)->m_flags & M_EXT) == 0) { + int len; + + len = M_TRAILINGSPACE(*out); + len = MIN(len, in->m_len); + datalen += len; + + bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len, + (unsigned)len); + + (*out)->m_len += len; + in->m_len -= len; + continue; + } else { + /* (*out) is full */ + if( !((*out)->m_next = m_get(M_DONTWAIT, MT_DATA))) { + m_freem(*out); + *out = in; + splx(s); + return -1; + } + (*out)->m_len = 0; + (*out)->m_act = 0; + *out = (*out)->m_next; + } + } + m_freem(in); + splx(s); + return datalen; +} diff --git a/sys/kern/uipc_proto.c b/sys/kern/uipc_proto.c index 4c25dab81108..881602c3af23 100644 --- a/sys/kern/uipc_proto.c +++ b/sys/kern/uipc_proto.c @@ -31,21 +31,23 @@ * SUCH DAMAGE. * * from: @(#)uipc_proto.c 7.6 (Berkeley) 5/9/91 - * $Id: uipc_proto.c,v 1.2 1993/10/16 15:25:09 rgrimes Exp $ + * $Id: uipc_proto.c,v 1.3 1993/12/19 00:51:45 wollman Exp $ */ #include "param.h" +#include "systm.h" #include "socket.h" #include "protosw.h" #include "domain.h" #include "mbuf.h" +#include "net/raw_cb.h" + /* * Definitions of protocols supported in the UNIX domain. */ int uipc_usrreq(); -int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); extern struct domain unixdomain; /* or at least forward */ struct protosw unixsw[] = { diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 3195bcd3d4c2..8202529d308b 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)uipc_socket.c 7.28 (Berkeley) 5/4/91 - * $Id: uipc_socket.c,v 1.8 1993/10/23 16:23:49 davidg Exp $ + * $Id: uipc_socket.c,v 1.10 1993/12/19 00:51:46 wollman Exp $ */ #include "param.h" @@ -55,7 +55,9 @@ * switching out to the protocol specific routines. */ /*ARGSUSED*/ +int socreate(dom, aso, type, proto) + int dom; struct socket **aso; register int type; int proto; @@ -81,7 +83,8 @@ socreate(dom, aso, type, proto) so->so_proto = prp; error = (*prp->pr_usrreq)(so, PRU_ATTACH, - (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0, + (struct mbuf *)0); if (error) { so->so_state |= SS_NOFDREF; sofree(so); @@ -91,6 +94,7 @@ socreate(dom, aso, type, proto) return (0); } +int sobind(so, nam) struct socket *so; struct mbuf *nam; @@ -100,11 +104,12 @@ sobind(so, nam) error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, - (struct mbuf *)0, nam, (struct mbuf *)0); + (struct mbuf *)0, nam, (struct mbuf *)0, (struct mbuf *)0); splx(s); return (error); } +int solisten(so, backlog) register struct socket *so; int backlog; @@ -113,7 +118,8 @@ solisten(so, backlog) error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0); if (error) { splx(s); return (error); @@ -127,6 +133,7 @@ solisten(so, backlog) return (0); } +void sofree(so) register struct socket *so; { @@ -148,6 +155,7 @@ sofree(so) * Initiate disconnect if connected. * Free socket when disconnect complete. */ +int soclose(so) register struct socket *so; { @@ -182,7 +190,8 @@ drop: if (so->so_pcb) { int error2 = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0); if (error == 0) error = error2; } @@ -198,15 +207,18 @@ discard: /* * Must be called at splnet... */ +int soabort(so) struct socket *so; { return ( (*so->so_proto->pr_usrreq)(so, PRU_ABORT, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0)); } +int soaccept(so, nam) register struct socket *so; struct mbuf *nam; @@ -218,11 +230,12 @@ soaccept(so, nam) panic("soaccept: !NOFDREF"); so->so_state &= ~SS_NOFDREF; error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, - (struct mbuf *)0, nam, (struct mbuf *)0); + (struct mbuf *)0, nam, (struct mbuf *)0, (struct mbuf *)0); splx(s); return (error); } +int soconnect(so, nam) register struct socket *so; struct mbuf *nam; @@ -245,11 +258,12 @@ soconnect(so, nam) error = EISCONN; else error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, - (struct mbuf *)0, nam, (struct mbuf *)0); + (struct mbuf *)0, nam, (struct mbuf *)0, (struct mbuf *)0); splx(s); return (error); } +int soconnect2(so1, so2) register struct socket *so1; struct socket *so2; @@ -258,11 +272,13 @@ soconnect2(so1, so2) int error; error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, - (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0, + (struct mbuf *)0); splx(s); return (error); } +int sodisconnect(so) register struct socket *so; { @@ -278,7 +294,8 @@ sodisconnect(so) goto bad; } error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0); bad: splx(s); return (error); @@ -301,6 +318,7 @@ bad: * must check for short counts if EINTR/ERESTART are returned. * Data and control buffers are freed on return. */ +int sosend(so, addr, uio, top, control, flags) register struct socket *so; struct mbuf *addr; @@ -424,7 +442,7 @@ nopages: s = splnet(); /* XXX */ error = (*so->so_proto->pr_usrreq)(so, (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, - top, addr, control); + top, addr, control, (struct mbuf *)0); splx(s); if (dontroute) so->so_options &= ~SO_DONTROUTE; @@ -463,6 +481,7 @@ out: * an mbuf **mp0 for use in returning the chain. The uio is then used * only for the count in uio_resid. */ +int soreceive(so, paddr, uio, mp0, controlp, flagsp) register struct socket *so; struct mbuf **paddr; @@ -476,7 +495,7 @@ soreceive(so, paddr, uio, mp0, controlp, flagsp) register int flags, len, error, s, offset; struct protosw *pr = so->so_proto; struct mbuf *nextrecord; - int moff, type; + int moff, type = 0; int orig_resid = uio->uio_resid; mp = mp0; @@ -491,7 +510,8 @@ soreceive(so, paddr, uio, mp0, controlp, flagsp) if (flags & MSG_OOB) { m = m_get(M_WAIT, MT_DATA); error = (*pr->pr_usrreq)(so, PRU_RCVOOB, - m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); + m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0, + (struct mbuf *)0); if (error) goto bad; do { @@ -508,7 +528,7 @@ bad: *mp = (struct mbuf *)0; if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, - (struct mbuf *)0, (struct mbuf *)0); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); restart: if (error = sblock(&so->so_rcv)) @@ -759,6 +779,7 @@ release: return (error); } +int soshutdown(so, how) register struct socket *so; register int how; @@ -770,10 +791,12 @@ soshutdown(so, how) sorflush(so); if (how & FWRITE) return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0)); return (0); } +void sorflush(so) register struct socket *so; { @@ -795,6 +818,7 @@ sorflush(so) sbrelease(&asb); } +int sosetopt(so, level, optname, m0) register struct socket *so; int level, optname; @@ -905,6 +929,7 @@ bad: return (error); } +int sogetopt(so, level, optname, mp) register struct socket *so; int level, optname; @@ -988,6 +1013,7 @@ sogetopt(so, level, optname, mp) } } +void sohasoutofband(so) register struct socket *so; { diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 349096aeee29..d6d103466abb 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)uipc_socket2.c 7.17 (Berkeley) 5/4/91 - * $Id: uipc_socket2.c,v 1.2 1993/10/16 15:25:12 rgrimes Exp $ + * $Id: uipc_socket2.c,v 1.4 1993/12/19 00:51:47 wollman Exp $ */ #include "param.h" @@ -50,9 +50,9 @@ */ /* strings for sleep message: */ -char netio[] = "netio"; -char netcon[] = "netcon"; -char netcls[] = "netcls"; +const char netio[] = "netio"; +const char netcon[] = "netcon"; +const char netcls[] = "netcls"; u_long sb_max = SB_MAX; /* patchable */ @@ -86,6 +86,7 @@ u_long sb_max = SB_MAX; /* patchable */ * cause software-interrupt process scheduling. */ +void soisconnecting(so) register struct socket *so; { @@ -94,6 +95,7 @@ soisconnecting(so) so->so_state |= SS_ISCONNECTING; } +void soisconnected(so) register struct socket *so; { @@ -112,6 +114,7 @@ soisconnected(so) } } +void soisdisconnecting(so) register struct socket *so; { @@ -123,6 +126,7 @@ soisdisconnecting(so) sorwakeup(so); } +void soisdisconnected(so) register struct socket *so; { @@ -169,7 +173,8 @@ sonewconn1(head, connstatus) (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); soqinsque(head, so, soqueue); if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, - (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) { + (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0, + (struct mbuf *)0)) { (void) soqremque(so, soqueue); (void) free((caddr_t)so, M_SOCKET); return ((struct socket *)0); @@ -182,6 +187,7 @@ sonewconn1(head, connstatus) return (so); } +void soqinsque(head, so, q) register struct socket *head, *so; int q; @@ -203,6 +209,7 @@ soqinsque(head, so, q) *prev = so; } +int soqremque(so, q) register struct socket *so; int q; @@ -241,6 +248,7 @@ soqremque(so, q) * Data queued for reading in the socket may yet be read. */ +void socantsendmore(so) struct socket *so; { @@ -249,6 +257,7 @@ socantsendmore(so) sowwakeup(so); } +void socantrcvmore(so) struct socket *so; { @@ -264,6 +273,7 @@ socantrcvmore(so) /* * Queue a process for a select on a socket buffer. */ +void sbselqueue(sb, cp) struct sockbuf *sb; struct proc *cp; @@ -281,6 +291,7 @@ sbselqueue(sb, cp) /* * Wait for data to arrive at/drain from a socket buffer. */ +int sbwait(sb) struct sockbuf *sb; { @@ -295,6 +306,7 @@ sbwait(sb) * Lock a sockbuf already known to be locked; * return any error returned from sleep (EINTR). */ +int sb_lock(sb) register struct sockbuf *sb; { @@ -316,6 +328,7 @@ sb_lock(sb) * Do asynchronous notification via SIGIO * if the socket has the SS_ASYNC flag set. */ +void sowakeup(so, sb) register struct socket *so; register struct sockbuf *sb; @@ -371,6 +384,7 @@ sowakeup(so, sb) * should be released by calling sbrelease() when the socket is destroyed. */ +int soreserve(so, sndcc, rcvcc) register struct socket *so; u_long sndcc, rcvcc; @@ -398,6 +412,7 @@ bad: * Attempt to scale mbmax so that mbcnt doesn't become limiting * if buffering efficiency is near the normal case. */ +int sbreserve(sb, cc) struct sockbuf *sb; u_long cc; @@ -415,6 +430,7 @@ sbreserve(sb, cc) /* * Free mbufs held by a socket, and reserved mbuf space. */ +void sbrelease(sb) struct sockbuf *sb; { @@ -454,6 +470,7 @@ sbrelease(sb) * the mbuf chain is recorded in sb. Empty mbufs are * discarded and mbufs are compacted where possible. */ +void sbappend(sb, m) struct sockbuf *sb; struct mbuf *m; @@ -502,6 +519,7 @@ sbcheck(sb) * As above, except the mbuf chain * begins a new record. */ +void sbappendrecord(sb, m0) register struct sockbuf *sb; register struct mbuf *m0; @@ -536,6 +554,7 @@ sbappendrecord(sb, m0) * is inserted at the beginning of the sockbuf, * but after any other OOB data. */ +void sbinsertoob(sb, m0) register struct sockbuf *sb; register struct mbuf *m0; @@ -580,6 +599,7 @@ sbinsertoob(sb, m0) * m0 must include a packet header with total length. * Returns 0 if no space in sockbuf or insufficient mbufs. */ +int sbappendaddr(sb, asa, m0, control) register struct sockbuf *sb; struct sockaddr *asa; @@ -622,6 +642,7 @@ panic("sbappendaddr"); return (1); } +int sbappendcontrol(sb, m0, control) struct sockbuf *sb; struct mbuf *control, *m0; @@ -658,6 +679,7 @@ sbappendcontrol(sb, m0, control) * buffer sb following mbuf n. If n * is null, the buffer is presumed empty. */ +void sbcompress(sb, m, n) register struct sockbuf *sb; register struct mbuf *m, *n; @@ -706,6 +728,7 @@ sbcompress(sb, m, n) * Free all mbufs in a sockbuf. * Check that all resources are reclaimed. */ +void sbflush(sb) register struct sockbuf *sb; { @@ -721,6 +744,7 @@ sbflush(sb) /* * Drop data from (the front of) a sockbuf. */ +void sbdrop(sb, len) register struct sockbuf *sb; register int len; @@ -764,6 +788,7 @@ sbdrop(sb, len) * Drop a record off the front of a sockbuf * and move the next record to the front. */ +void sbdroprecord(sb) register struct sockbuf *sb; { diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index cf82c089a5bc..2f7889d060ca 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -31,10 +31,11 @@ * SUCH DAMAGE. * * from: @(#)uipc_syscalls.c 7.24 (Berkeley) 6/3/91 - * $Id: uipc_syscalls.c,v 1.4 1993/10/16 15:25:14 rgrimes Exp $ + * $Id: uipc_syscalls.c,v 1.6 1993/12/19 00:51:48 wollman Exp $ */ #include "param.h" +#include "systm.h" #include "filedesc.h" #include "proc.h" #include "file.h" @@ -48,6 +49,12 @@ #include "ktrace.h" #endif +/* First two also used by NFS, boooo, hiss! */ +int getsock(struct filedesc *, int, struct file **); +int sockargs(struct mbuf **, caddr_t, int, int); +static int sendit(struct proc *, int, struct msghdr *, int, int *); +static int recvit(struct proc *, int, struct msghdr *, caddr_t, int *); + /* * System call interface to the socket abstraction. */ @@ -60,6 +67,7 @@ struct socket_args { int protocol; }; +int socket(p, uap, retval) struct proc *p; register struct socket_args *uap; @@ -92,6 +100,7 @@ struct bind_args { }; /* ARGSUSED */ +int bind(p, uap, retval) struct proc *p; register struct bind_args *uap; @@ -116,6 +125,7 @@ struct listen_args { }; /* ARGSUSED */ +int listen(p, uap, retval) struct proc *p; register struct listen_args *uap; @@ -129,7 +139,18 @@ listen(p, uap, retval) return (solisten((struct socket *)fp->f_data, uap->backlog)); } +struct accept1_args { + int s; + caddr_t name; + int *anamelen; #ifdef COMPAT_43 + int compat_43; +#endif +}; + +#ifdef COMPAT_43 + +int accept1(struct proc *, struct accept1_args *, int *); struct accept_args { int s; @@ -138,6 +159,7 @@ struct accept_args { int compat_43; }; +int accept(p, uap, retval) struct proc *p; struct accept_args *uap; @@ -145,7 +167,7 @@ accept(p, uap, retval) { uap->compat_43 = 0; - return (accept1(p, uap, retval)); + return (accept1(p, (struct accept1_args *)uap, retval)); } struct oaccept_args { @@ -155,6 +177,7 @@ struct oaccept_args { int compat_43; }; +int oaccept(p, uap, retval) struct proc *p; struct oaccept_args *uap; @@ -162,22 +185,14 @@ oaccept(p, uap, retval) { uap->compat_43 = 1; - return (accept1(p, uap, retval)); + return (accept1(p, (struct accept1_args *)uap, retval)); } #else /* COMPAT_43 */ #define accept1 accept #endif -struct accept1_args { - int s; - caddr_t name; - int *anamelen; -#ifdef COMPAT_43 - int compat_43; -#endif -}; - +int accept1(p, uap, retval) struct proc *p; register struct accept1_args *uap; @@ -261,6 +276,7 @@ struct connect_args { }; /* ARGSUSED */ +int connect(p, uap, retval) struct proc *p; register struct connect_args *uap; @@ -310,6 +326,7 @@ struct socketpair_args { int *rsv; }; +int socketpair(p, uap, retval) struct proc *p; register struct socketpair_args *uap; @@ -373,6 +390,7 @@ struct sendto_args { int tolen; }; +int sendto(p, uap, retval) struct proc *p; register struct sendto_args *uap; @@ -404,6 +422,7 @@ struct osend_args { int flags; }; +int osend(p, uap, retval) struct proc *p; register struct osend_args *uap; @@ -431,6 +450,7 @@ struct osendmsg_args { int flags; }; +int osendmsg(p, uap, retval) struct proc *p; register struct osendmsg_args *uap; @@ -469,6 +489,7 @@ struct sendmsg_args { int flags; }; +int sendmsg(p, uap, retval) struct proc *p; register struct sendmsg_args *uap; @@ -503,6 +524,7 @@ done: return (error); } +static int sendit(p, s, mp, flags, retsize) register struct proc *p; int s; @@ -615,6 +637,7 @@ struct orecvfrom_args { int *fromlenaddr; }; +int orecvfrom(p, uap, retval) struct proc *p; struct orecvfrom_args *uap; @@ -635,6 +658,7 @@ struct recvfrom_args { int *fromlenaddr; }; +int recvfrom(p, uap, retval) struct proc *p; register struct recvfrom_args *uap; @@ -669,6 +693,7 @@ struct orecv_args { int flags; }; +int orecv(p, uap, retval) struct proc *p; register struct orecv_args *uap; @@ -700,6 +725,7 @@ struct orecvmsg_args { int flags; }; +int orecvmsg(p, uap, retval) struct proc *p; register struct orecvmsg_args *uap; @@ -743,6 +769,7 @@ struct recvmsg_args { int flags; }; +int recvmsg(p, uap, retval) struct proc *p; register struct recvmsg_args *uap; @@ -782,6 +809,7 @@ done: return (error); } +int recvit(p, s, mp, namelenp, retsize) register struct proc *p; int s; @@ -918,6 +946,7 @@ struct shutdown_args { }; /* ARGSUSED */ +int shutdown(p, uap, retval) struct proc *p; register struct shutdown_args *uap; @@ -940,6 +969,7 @@ struct setsocketopt_args { }; /* ARGSUSED */ +int setsockopt(p, uap, retval) struct proc *p; register struct setsocketopt_args *uap; @@ -977,6 +1007,7 @@ struct getsockopt_args { }; /* ARGSUSED */ +int getsockopt(p, uap, retval) struct proc *p; register struct getsockopt_args *uap; @@ -1009,6 +1040,7 @@ getsockopt(p, uap, retval) } /* ARGSUSED */ +int pipe(p, uap, retval) struct proc *p; struct args *uap; @@ -1056,8 +1088,19 @@ free1: /* * Get socket name. */ +struct getsockname1_args { + int fdes; + caddr_t asa; + int *alen; +#ifdef COMPAT_43 + int compat_43; +#endif +}; + #ifdef COMPAT_43 +int getsockname1(struct proc *, struct getsockname1_args *, int *); + struct getsockname_args { int fdes; caddr_t asa; @@ -1065,6 +1108,7 @@ struct getsockname_args { int compat_43; }; +int getsockname(p, uap, retval) struct proc *p; struct getsockname_args *uap; @@ -1072,7 +1116,7 @@ getsockname(p, uap, retval) { uap->compat_43 = 0; - return (getsockname1(p, uap, retval)); + return (getsockname1(p, (struct getsockname1_args *)uap, retval)); } struct ogetsockname_args { @@ -1082,6 +1126,7 @@ struct ogetsockname_args { int compat_43; }; +int ogetsockname(p, uap, retval) struct proc *p; struct ogetsockname_args *uap; @@ -1089,23 +1134,15 @@ ogetsockname(p, uap, retval) { uap->compat_43 = 1; - return (getsockname1(p, uap, retval)); + return (getsockname1(p, (struct getsockname1_args *)uap, retval)); } #else /* COMPAT_43 */ #define getsockname1 getsockname #endif -struct getsockname1_args { - int fdes; - caddr_t asa; - int *alen; -#ifdef COMPAT_43 - int compat_43; -#endif -}; - /* ARGSUSED */ +int getsockname1(p, uap, retval) struct proc *p; register struct getsockname1_args *uap; @@ -1124,7 +1161,7 @@ getsockname1(p, uap, retval) m = m_getclr(M_WAIT, MT_SONAME); if (m == NULL) return (ENOBUFS); - if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0)) + if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, 0)) goto bad; if (len > m->m_len) len = m->m_len; @@ -1145,8 +1182,19 @@ bad: /* * Get name of peer for connected socket. */ +struct getpeername1_args { + int fdes; + caddr_t asa; + int *alen; +#ifdef COMPAT_43 + int compat_43; +#endif +}; + #ifdef COMPAT_43 +int getpeername1(struct proc *, struct getpeername1_args *, int *); + struct getpeername_args { int fdes; caddr_t asa; @@ -1154,6 +1202,7 @@ struct getpeername_args { int compat_43; }; +int getpeername(p, uap, retval) struct proc *p; struct getpeername_args *uap; @@ -1161,7 +1210,7 @@ getpeername(p, uap, retval) { uap->compat_43 = 0; - return (getpeername1(p, uap, retval)); + return (getpeername1(p, (struct getpeername1_args *)uap, retval)); } struct ogetpeername_args { @@ -1171,6 +1220,7 @@ struct ogetpeername_args { int compat_43; }; +int ogetpeername(p, uap, retval) struct proc *p; struct ogetpeername_args *uap; @@ -1178,23 +1228,15 @@ ogetpeername(p, uap, retval) { uap->compat_43 = 1; - return (getpeername1(p, uap, retval)); + return (getpeername1(p, (struct getpeername1_args *)uap, retval)); } #else /* COMPAT_43 */ #define getpeername1 getpeername #endif -struct getpeername1_args { - int fdes; - caddr_t asa; - int *alen; -#ifdef COMPAT_43 - int compat_43; -#endif -}; - /* ARGSUSED */ +int getpeername1(p, uap, retval) struct proc *p; register struct getpeername1_args *uap; @@ -1215,7 +1257,7 @@ getpeername1(p, uap, retval) return (ENOBUFS); if (error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len))) return (error); - if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0)) + if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, 0)) goto bad; if (len > m->m_len) len = m->m_len; @@ -1232,6 +1274,7 @@ bad: return (error); } +int sockargs(mp, buf, buflen, type) struct mbuf **mp; caddr_t buf; @@ -1270,6 +1313,7 @@ sockargs(mp, buf, buflen, type) return (0); } +int getsock(fdp, fdes, fpp) struct filedesc *fdp; int fdes; diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 6914ffeac913..a20bfa39bb76 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -31,10 +31,11 @@ * SUCH DAMAGE. * * from: @(#)uipc_usrreq.c 7.26 (Berkeley) 6/3/91 - * $Id: uipc_usrreq.c,v 1.4 1993/10/23 16:34:45 davidg Exp $ + * $Id: uipc_usrreq.c,v 1.5 1993/11/25 01:33:37 wollman Exp $ */ #include "param.h" +#include "systm.h" #include "proc.h" #include "filedesc.h" #include "domain.h" @@ -61,6 +62,7 @@ struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; ino_t unp_ino; /* prototype for fake inode numbers */ /*ARGSUSED*/ +int uipc_usrreq(so, req, m, nam, control) struct socket *so; int req; @@ -313,6 +315,7 @@ u_long unpdg_recvspace = 4*1024; int unp_rights; /* file descriptors in flight */ +int unp_attach(so) struct socket *so; { @@ -330,6 +333,8 @@ unp_attach(so) case SOCK_DGRAM: error = soreserve(so, unpdg_sendspace, unpdg_recvspace); break; + default: + panic("unp_attach"); } if (error) return (error); @@ -343,6 +348,7 @@ unp_attach(so) return (0); } +void unp_detach(unp) register struct unpcb *unp; { @@ -373,6 +379,7 @@ unp_detach(unp) } } +int unp_bind(unp, nam, p) struct unpcb *unp; struct mbuf *nam; @@ -422,6 +429,7 @@ unp_bind(unp, nam, p) return (0); } +int unp_connect(so, nam, p) struct socket *so; struct mbuf *nam; @@ -481,6 +489,7 @@ bad: return (error); } +int unp_connect2(so, so2) register struct socket *so; register struct socket *so2; @@ -512,6 +521,7 @@ unp_connect2(so, so2) return (0); } +void unp_disconnect(unp) struct unpcb *unp; { @@ -557,6 +567,7 @@ unp_abort(unp) } #endif +void unp_shutdown(unp) struct unpcb *unp; { @@ -567,6 +578,7 @@ unp_shutdown(unp) socantrcvmore(so); } +void unp_drop(unp, errno) struct unpcb *unp; int errno; @@ -590,6 +602,7 @@ unp_drain() } #endif +int unp_externalize(rights) struct mbuf *rights; { @@ -621,6 +634,7 @@ unp_externalize(rights) return (0); } +int unp_internalize(control, p) struct mbuf *control; struct proc *p; @@ -655,9 +669,9 @@ unp_internalize(control, p) } int unp_defer, unp_gcing; -int unp_mark(); extern struct domain unixdomain; +void unp_gc() { register struct file *fp; @@ -719,18 +733,18 @@ restart: unp_gcing = 0; } +void unp_dispose(m) struct mbuf *m; { - int unp_discard(); - if (m) unp_scan(m, unp_discard); } +void unp_scan(m0, op) register struct mbuf *m0; - int (*op)(); + void (*op)(struct file *); { register struct mbuf *m; register struct file **rp; @@ -757,6 +771,7 @@ unp_scan(m0, op) } } +void unp_mark(fp) struct file *fp; { @@ -767,6 +782,7 @@ unp_mark(fp) fp->f_flag |= (FMARK|FDEFER); } +void unp_discard(fp) struct file *fp; { diff --git a/sys/kern/vfs__bio.c b/sys/kern/vfs__bio.c index db8c6ad98e73..2ccf2e6126b7 100644 --- a/sys/kern/vfs__bio.c +++ b/sys/kern/vfs__bio.c @@ -45,11 +45,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: vfs__bio.c,v 1.7 1993/10/19 01:06:29 nate Exp $ + * $Id: vfs__bio.c,v 1.15 1994/01/31 05:57:45 davidg Exp $ */ #include "param.h" #include "systm.h" +#include "kernel.h" #include "proc.h" #include "vnode.h" #include "buf.h" @@ -59,6 +60,18 @@ #include "vm/vm.h" #include "resourcevar.h" +/* From sys/buf.h */ +struct buf *buf; /* the buffer pool itself */ +char *buffers; +int nbuf; /* number of buffer headers */ +int bufpages; /* number of memory pages in the buffer pool */ +struct buf *swbuf; /* swap I/O headers */ +int nswbuf; +struct bufhd bufhash[BUFHSZ]; /* heads of hash lists */ +struct buf bfreelist[BQUEUES]; /* heads of available lists */ +struct buf bswlist; /* head of free swap header list */ +struct buf *bclnlist; /* head of cleaned page list */ + static struct buf *getnewbuf(int); extern vm_map_t buffer_map; @@ -283,12 +296,12 @@ brelse(register struct buf *bp) x=splbio(); if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) { (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED; - wakeup(bfreelist); + wakeup((caddr_t)bfreelist); } /* anyone need this very block? */ if (bp->b_flags & B_WANTED) { bp->b_flags &= ~B_WANTED; - wakeup(bp); + wakeup((caddr_t)bp); } if (bp->b_flags & (B_INVAL|B_ERROR)) { @@ -342,14 +355,14 @@ start: /*#define notyet*/ #ifndef notyet - if ((addr = malloc (sz, M_TEMP, M_WAITOK)) == 0) goto tryfree; + if ((addr = malloc (sz, M_IOBUF, M_WAITOK)) == 0) goto tryfree; #else /* notyet */ /* get new memory buffer */ if (round_page(sz) == sz) addr = (caddr_t) kmem_alloc_wired_wait(buffer_map, sz); else - addr = (caddr_t) malloc (sz, M_TEMP, M_WAITOK); - /*if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;*/ + addr = (caddr_t) malloc (sz, M_IOBUF, M_WAITOK); + /*if ((addr = malloc (sz, M_IOBUF, M_NOWAIT)) == 0) goto tryfree;*/ bzero(addr, sz); #endif /* notyet */ freebufspace -= sz; @@ -373,7 +386,7 @@ tryfree: } else { /* wait for a free buffer of any kind */ (bfreelist + BQ_AGE)->b_flags |= B_WANTED; - sleep(bfreelist, PRIBIO); + tsleep((caddr_t)bfreelist, PRIBIO, "newbuf", 0); splx(x); return (0); } @@ -448,33 +461,30 @@ getblk(register struct vnode *vp, daddr_t blkno, int size) struct buf *bp, *bh; int x; - for (;;) { - if (bp = incore(vp, blkno)) { - x = splbio(); - if (bp->b_flags & B_BUSY) { - bp->b_flags |= B_WANTED; - sleep (bp, PRIBIO); - splx(x); - continue; - } - bp->b_flags |= B_BUSY | B_CACHE; - bremfree(bp); - if (size > bp->b_bufsize) - panic("now what do we do?"); - /* if (bp->b_bufsize != size) allocbuf(bp, size); */ - } else { - - if((bp = getnewbuf(size)) == 0) continue; - bp->b_blkno = bp->b_lblkno = blkno; - bgetvp(vp, bp); - x = splbio(); - bh = BUFHASH(vp, blkno); - binshash(bp, bh); - bp->b_flags = B_BUSY; + x = splbio(); +loop: + if (bp = incore(vp, blkno)) { + if (bp->b_flags & B_BUSY) { + bp->b_flags |= B_WANTED; + tsleep ((caddr_t)bp, PRIBIO, "getblk", 0); + goto loop; } - splx(x); - return (bp); + bp->b_flags |= B_BUSY | B_CACHE; + bremfree(bp); + if (size > bp->b_bufsize) + panic("now what do we do?"); + /* if (bp->b_bufsize != size) allocbuf(bp, size); */ + } else { + + if ((bp = getnewbuf(size)) == 0) goto loop; + bp->b_blkno = bp->b_lblkno = blkno; + bgetvp(vp, bp); + bh = BUFHASH(vp, blkno); + binshash(bp, bh); + bp->b_flags = B_BUSY; } + splx(x); + return (bp); } /* @@ -512,12 +522,12 @@ allocbuf(register struct buf *bp, int size) /* get new memory buffer */ #ifndef notyet - newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK); + newcontents = (caddr_t) malloc (size, M_IOBUF, M_WAITOK); #else /* notyet */ if (round_page(size) == size) newcontents = (caddr_t) kmem_alloc_wired_wait(buffer_map, size); else - newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK); + newcontents = (caddr_t) malloc (size, M_IOBUF, M_WAITOK); #endif /* notyet */ /* copy the old into the new, up to the maximum that will fit */ @@ -525,12 +535,12 @@ allocbuf(register struct buf *bp, int size) /* return old contents to free heap */ #ifndef notyet - free (bp->b_un.b_addr, M_TEMP); + free (bp->b_un.b_addr, M_IOBUF); #else /* notyet */ if (round_page(bp->b_bufsize) == bp->b_bufsize) kmem_free_wakeup(buffer_map, bp->b_un.b_addr, bp->b_bufsize); else - free (bp->b_un.b_addr, M_TEMP); + free (bp->b_un.b_addr, M_IOBUF); #endif /* notyet */ /* adjust buffer cache's idea of memory allocated to buffer contents */ @@ -555,7 +565,7 @@ biowait(register struct buf *bp) x = splbio(); while ((bp->b_flags & B_DONE) == 0) - sleep((caddr_t)bp, PRIBIO); + tsleep((caddr_t)bp, PRIBIO, "biowait", 0); if((bp->b_flags & B_ERROR) || bp->b_error) { if ((bp->b_flags & B_INVAL) == 0) { bp->b_flags |= B_INVAL; @@ -575,28 +585,84 @@ biowait(register struct buf *bp) } /* - * Finish up operations on a buffer, calling an optional - * function (if requested), and releasing the buffer if - * marked asynchronous. Then mark this buffer done so that - * others biowait()'ing for it will notice when they are - * woken up from sleep(). + * Finish up operations on a buffer, calling an optional function + * (if requested), and releasing the buffer if marked asynchronous. + * Mark this buffer done so that others biowait()'ing for it will + * notice when they are woken up from sleep(). */ -int +void biodone(register struct buf *bp) { - int x; + bp->b_flags |= B_DONE; - x = splbio(); - if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp); - bp->b_flags &= ~B_CALL; - if ((bp->b_flags & (B_READ|B_DIRTY)) == B_DIRTY) { - bp->b_flags &= ~B_DIRTY; + if ((bp->b_flags & B_READ) == 0) { vwakeup(bp); } - if (bp->b_flags & B_ASYNC) + + /* call optional completion function if requested */ + if (bp->b_flags & B_CALL) { + bp->b_flags &= ~B_CALL; + (*bp->b_iodone)(bp); + return; + } + +/* + * For asynchronous completions, release the buffer now. The brelse + * checks for B_WANTED and will do the wakeup there if necessary - + * so no need to do a wakeup here in the async case. + */ + + if (bp->b_flags & B_ASYNC) { brelse(bp); - bp->b_flags &= ~B_ASYNC; - bp->b_flags |= B_DONE; - wakeup(bp); - splx(x); + } else { + bp->b_flags &= ~B_WANTED; + wakeup((caddr_t) bp); + } +} + +/* + * Internel update daemon, process 3 + * The variable vfs_update_wakeup allows for internal syncs. + */ +int vfs_update_wakeup; + +void +vfs_update() { + (void) spl0(); + while(1) { + tsleep((caddr_t)&vfs_update_wakeup, PRIBIO, "update", hz*30); + vfs_update_wakeup = 0; + sync(curproc, NULL, NULL); + } +} + +/* + * Print out statistics on the current allocation of the buffer pool. + * Can be enabled to print out on every ``sync'' by setting "syncprt" + * in ufs/ufs_vfsops.c. + */ +void +bufstats() +{ + int s, i, j, count; + register struct buf *bp, *dp; + int counts[MAXBSIZE/CLBYTES+1]; + static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; + + for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { + count = 0; + for (j = 0; j <= MAXBSIZE/CLBYTES; j++) + counts[j] = 0; + s = splbio(); + for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { + counts[dp->b_bufsize/CLBYTES]++; + count++; + } + splx(s); + printf("%s: total-%d", bname[i], count); + for (j = 0; j <= MAXBSIZE/CLBYTES; j++) + if (counts[j] != 0) + printf(", %d-%d", j * CLBYTES, counts[j]); + printf("\n"); + } } diff --git a/sys/kern/vfs_bio.old.c b/sys/kern/vfs_bio.old.c deleted file mode 100644 index a791bafcc439..000000000000 --- a/sys/kern/vfs_bio.old.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse - * All rights reserved. - * - * 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 software is a component of "386BSD" developed by - William F. Jolitz, TeleMuse. - * 4. Neither the name of the developer nor the name "386BSD" - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ - * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS - * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. - * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT - * NOT MAKE USE THIS WORK. - * - * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED - * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN - * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES - * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING - * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND - * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE - * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS - * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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. - * - * $Id: vfs_bio.old.c,v 1.2 1993/10/16 15:25:18 rgrimes Exp $ - */ - -#include "param.h" -#include "proc.h" -#include "vnode.h" -#include "buf.h" -#include "specdev.h" -#include "mount.h" -#include "malloc.h" -#ifdef notyet -#include "vm/vm.h" -#include "vm/vm_kern.h" -#endif /* notyet */ -#include "resourcevar.h" - -/* - * Initialize buffer headers and related structures. - */ -void bufinit() -{ - struct bufhd *bh; - struct buf *bp; - - /* first, make a null hash table */ - for(bh = bufhash; bh < bufhash + BUFHSZ; bh++) { - bh->b_flags = 0; - bh->b_forw = (struct buf *)bh; - bh->b_back = (struct buf *)bh; - } - - /* next, make a null set of free lists */ - for(bp = bfreelist; bp < bfreelist + BQUEUES; bp++) { - bp->b_flags = 0; - bp->av_forw = bp; - bp->av_back = bp; - bp->b_forw = bp; - bp->b_back = bp; - } - - /* finally, initialize each buffer header and stick on empty q */ - for(bp = buf; bp < buf + nbuf ; bp++) { - bp->b_flags = B_HEAD | B_INVAL; /* we're just an empty header */ - bp->b_dev = NODEV; - bp->b_vp = 0; - binstailfree(bp, bfreelist + BQ_EMPTY); - binshash(bp, bfreelist + BQ_EMPTY); - } -} - -/* - * Find the block in the buffer pool. - * If the buffer is not present, allocate a new buffer and load - * its contents according to the filesystem fill routine. - */ -bread(vp, blkno, size, cred, bpp) - struct vnode *vp; - daddr_t blkno; - int size; - struct ucred *cred; - struct buf **bpp; -{ - struct buf *bp; - int rv = 0; - - bp = getblk (vp, blkno, size); - - /* if not found in cache, do some I/O */ - if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) { - bp->b_flags |= B_READ; - bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); - bp->b_rcred = cred; - VOP_STRATEGY(bp); - rv = biowait (bp); - } - *bpp = bp; - - return (rv); -} - -/* - * Operates like bread, but also starts I/O on the specified - * read-ahead block. [See page 55 of Bach's Book] - */ -breada(vp, blkno, size, rablkno, rabsize, cred, bpp) - struct vnode *vp; - daddr_t blkno; int size; - daddr_t rablkno; int rabsize; - struct ucred *cred; - struct buf **bpp; -{ - struct buf *bp, *rabp; - int rv = 0, needwait = 0; - - bp = getblk (vp, blkno, size); - - /* if not found in cache, do some I/O */ - if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) { - bp->b_flags |= B_READ; - bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); - bp->b_rcred = cred; - VOP_STRATEGY(bp); - needwait++; - } - - rabp = getblk (vp, rablkno, rabsize); - - /* if not found in cache, do some I/O (overlapped with first) */ - if ((rabp->b_flags & B_CACHE) == 0 || (rabp->b_flags & B_INVAL) != 0) { - rabp->b_flags |= B_READ | B_ASYNC; - rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); - rabp->b_rcred = cred; - VOP_STRATEGY(rabp); - } else - brelse(rabp); - - /* wait for original I/O */ - if (needwait) - rv = biowait (bp); - - *bpp = bp; - return (rv); -} - -/* - * Synchronous write. - * Release buffer on completion. - */ -bwrite(bp) - register struct buf *bp; -{ - int rv; - - if(bp->b_flags & B_INVAL) { - brelse(bp); - return (0); - } else { - int wasdelayed; - - if(!(bp->b_flags & B_BUSY))panic("bwrite: not busy"); - wasdelayed = bp->b_flags & B_DELWRI; - bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_ASYNC|B_DELWRI); - if(wasdelayed) reassignbuf(bp, bp->b_vp); - bp->b_flags |= B_DIRTY; - bp->b_vp->v_numoutput++; - VOP_STRATEGY(bp); - rv = biowait(bp); - brelse(bp); - return (rv); - } -} - -/* - * Delayed write. - * - * The buffer is marked dirty, but is not queued for I/O. - * This routine should be used when the buffer is expected - * to be modified again soon, typically a small write that - * partially fills a buffer. - * - * NB: magnetic tapes cannot be delayed; they must be - * written in the order that the writes are requested. - */ -void bdwrite(bp) - register struct buf *bp; -{ - - if(!(bp->b_flags & B_BUSY))panic("bdwrite: not busy"); - if(bp->b_flags & B_INVAL) { - brelse(bp); - } - if(bp->b_flags & B_TAPE) { - bwrite(bp); - return; - } - bp->b_flags &= ~(B_READ|B_DONE); - bp->b_flags |= B_DIRTY|B_DELWRI; - reassignbuf(bp, bp->b_vp); - brelse(bp); - return; -} - -/* - * Asynchronous write. - * Start I/O on a buffer, but do not wait for it to complete. - * The buffer is released when the I/O completes. - */ -bawrite(bp) - register struct buf *bp; -{ - - if(!(bp->b_flags & B_BUSY))panic("bawrite: not busy"); - if(bp->b_flags & B_INVAL) - brelse(bp); - else { - int wasdelayed; - - wasdelayed = bp->b_flags & B_DELWRI; - bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); - if(wasdelayed) reassignbuf(bp, bp->b_vp); - - bp->b_flags |= B_DIRTY | B_ASYNC; - bp->b_vp->v_numoutput++; - VOP_STRATEGY(bp); - } -} - -/* - * Release a buffer. - * Even if the buffer is dirty, no I/O is started. - */ -brelse(bp) - register struct buf *bp; -{ - int x; - - /* anyone need a "free" block? */ - x=splbio(); - if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) { - (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED; - wakeup(bfreelist); - } - /* anyone need this very block? */ - if (bp->b_flags & B_WANTED) { - bp->b_flags &= ~B_WANTED; - wakeup(bp); - } - - if (bp->b_flags & (B_INVAL|B_ERROR)) { - bp->b_flags |= B_INVAL; - bp->b_flags &= ~(B_DELWRI|B_CACHE); - if(bp->b_vp) - brelvp(bp); - } - - /* enqueue */ - /* just an empty buffer head ... */ - /*if(bp->b_flags & B_HEAD) - binsheadfree(bp, bfreelist + BQ_EMPTY)*/ - /* buffers with junk contents */ - /*else*/ if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE)) - binsheadfree(bp, bfreelist + BQ_AGE) - /* buffers with stale but valid contents */ - else if(bp->b_flags & B_AGE) - binstailfree(bp, bfreelist + BQ_AGE) - /* buffers with valid and quite potentially reuseable contents */ - else - binstailfree(bp, bfreelist + BQ_LRU) - - /* unlock */ - bp->b_flags &= ~B_BUSY; - splx(x); - - return; -} - -int freebufspace; -int allocbufspace; - -/* - * Find a buffer which is available for use. - * If free memory for buffer space and an empty header from the empty list, - * use that. Otherwise, select something from a free list. - * Preference is to AGE list, then LRU list. - */ -struct buf * -getnewbuf(sz) -{ - struct buf *bp; - int x; - - x = splbio(); -start: - /* can we constitute a new buffer? */ - if (freebufspace > sz - && bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) { - caddr_t addr; - -#ifndef notyet - if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree; -#else /* notyet */ - /* get new memory buffer */ - if (round_page(sz) == sz) - addr = (caddr_t) kmem_alloc(buffer_map, sz); - else - addr = (caddr_t) malloc (sz, M_TEMP, M_WAITOK); - /*if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;*/ -#endif /* notyet */ - freebufspace -= sz; - allocbufspace += sz; - - bp = bfreelist[BQ_EMPTY].av_forw; - bp->b_flags = B_BUSY | B_INVAL; - bremfree(bp); -#ifndef notyet - bp->b_un.b_addr = (caddr_t) addr; -#else /* notyet */ - bp->b_un.b_addr = addr; -#endif /* notyet */ - goto fillin; - } - -tryfree: - if (bfreelist[BQ_AGE].av_forw != (struct buf *)bfreelist+BQ_AGE) { - bp = bfreelist[BQ_AGE].av_forw; - bremfree(bp); - } else if (bfreelist[BQ_LRU].av_forw != (struct buf *)bfreelist+BQ_LRU) { - bp = bfreelist[BQ_LRU].av_forw; - bremfree(bp); - } else { - /* wait for a free buffer of any kind */ - (bfreelist + BQ_AGE)->b_flags |= B_WANTED; - sleep(bfreelist, PRIBIO); - splx(x); - return (0); - } - - /* if we are a delayed write, convert to an async write! */ - if (bp->b_flags & B_DELWRI) { - /*bp->b_flags &= ~B_DELWRI;*/ - bp->b_flags |= B_BUSY; - bawrite (bp); - goto start; - } - - /*if (bp->b_flags & (B_INVAL|B_ERROR) == 0) { - bremhash(bp); - }*/ - - if(bp->b_vp) - brelvp(bp); - - /* we are not free, nor do we contain interesting data */ - bp->b_flags = B_BUSY; -fillin: - bremhash(bp); - splx(x); - bp->b_dev = NODEV; - bp->b_vp = NULL; - bp->b_blkno = bp->b_lblkno = 0; - bp->b_iodone = 0; - bp->b_error = 0; - bp->b_wcred = bp->b_rcred = NOCRED; - if (bp->b_bufsize != sz) allocbuf(bp, sz); - bp->b_bcount = bp->b_bufsize = sz; - bp->b_dirtyoff = bp->b_dirtyend = 0; - return (bp); -} - -/* - * Check to see if a block is currently memory resident. - */ -struct buf *incore(vp, blkno) - struct vnode *vp; - daddr_t blkno; -{ - struct buf *bh; - struct buf *bp; - - bh = BUFHASH(vp, blkno); - - /* Search hash chain */ - bp = bh->b_forw; - while (bp != (struct buf *) bh) { - /* hit */ - if (bp->b_lblkno == blkno && bp->b_vp == vp - && (bp->b_flags & B_INVAL) == 0) - return (bp); - bp = bp->b_forw; - } - - return(0); -} - -/* - * Get a block of requested size that is associated with - * a given vnode and block offset. If it is found in the - * block cache, mark it as having been found, make it busy - * and return it. Otherwise, return an empty block of the - * correct size. It is up to the caller to insure that the - * cached blocks be of the correct size. - */ -struct buf * -getblk(vp, blkno, size) - register struct vnode *vp; - daddr_t blkno; - int size; -{ - struct buf *bp, *bh; - int x; - - for (;;) { - if (bp = incore(vp, blkno)) { - x = splbio(); - if (bp->b_flags & B_BUSY) { - bp->b_flags |= B_WANTED; - sleep (bp, PRIBIO); - splx(x); - continue; - } - bp->b_flags |= B_BUSY | B_CACHE; - bremfree(bp); - if (size > bp->b_bufsize) - panic("now what do we do?"); - /* if (bp->b_bufsize != size) allocbuf(bp, size); */ - } else { - - if((bp = getnewbuf(size)) == 0) continue; - bp->b_blkno = bp->b_lblkno = blkno; - bgetvp(vp, bp); - x = splbio(); - bh = BUFHASH(vp, blkno); - binshash(bp, bh); - bp->b_flags = B_BUSY; - } - splx(x); - return (bp); - } -} - -/* - * Get an empty, disassociated buffer of given size. - */ -struct buf * -geteblk(size) - int size; -{ - struct buf *bp; - int x; - - while ((bp = getnewbuf(size)) == 0) - ; - x = splbio(); - binshash(bp, bfreelist + BQ_AGE); - splx(x); - - return (bp); -} - -/* - * Exchange a buffer's underlying buffer storage for one of different - * size, taking care to maintain contents appropriately. When buffer - * increases in size, caller is responsible for filling out additional - * contents. When buffer shrinks in size, data is lost, so caller must - * first return it to backing store before shrinking the buffer, as - * no implied I/O will be done. - * - * Expanded buffer is returned as value. - */ -void -allocbuf(bp, size) - register struct buf *bp; - int size; -{ - caddr_t newcontents; - - /* get new memory buffer */ -#ifndef notyet - newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK); -#else /* notyet */ - if (round_page(size) == size) - newcontents = (caddr_t) kmem_alloc(buffer_map, size); - else - newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK); -#endif /* notyet */ - - /* copy the old into the new, up to the maximum that will fit */ - bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size)); - - /* return old contents to free heap */ -#ifndef notyet - free (bp->b_un.b_addr, M_TEMP); -#else /* notyet */ - if (round_page(bp->b_bufsize) == bp->b_bufsize) - kmem_free(buffer_map, bp->b_un.b_addr, bp->b_bufsize); - else - free (bp->b_un.b_addr, M_TEMP); -#endif /* notyet */ - - /* adjust buffer cache's idea of memory allocated to buffer contents */ - freebufspace -= size - bp->b_bufsize; - allocbufspace += size - bp->b_bufsize; - - /* update buffer header */ - bp->b_un.b_addr = newcontents; - bp->b_bcount = bp->b_bufsize = size; -} - -/* - * Patiently await operations to complete on this buffer. - * When they do, extract error value and return it. - * Extract and return any errors associated with the I/O. - * If an invalid block, force it off the lookup hash chains. - */ -biowait(bp) - register struct buf *bp; -{ - int x; - - x = splbio(); - while ((bp->b_flags & B_DONE) == 0) - sleep((caddr_t)bp, PRIBIO); - if((bp->b_flags & B_ERROR) || bp->b_error) { - if ((bp->b_flags & B_INVAL) == 0) { - bp->b_flags |= B_INVAL; - bremhash(bp); - binshash(bp, bfreelist + BQ_AGE); - } - if (!bp->b_error) - bp->b_error = EIO; - else - bp->b_flags |= B_ERROR; - splx(x); - return (bp->b_error); - } else { - splx(x); - return (0); - } -} - -/* - * Finish up operations on a buffer, calling an optional - * function (if requested), and releasing the buffer if - * marked asynchronous. Then mark this buffer done so that - * others biowait()'ing for it will notice when they are - * woken up from sleep(). - */ -biodone(bp) - register struct buf *bp; -{ - int x; - - x = splbio(); - if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp); - bp->b_flags &= ~B_CALL; - if ((bp->b_flags & (B_READ|B_DIRTY)) == B_DIRTY) { - bp->b_flags &= ~B_DIRTY; - vwakeup(bp); - } - if (bp->b_flags & B_ASYNC) - brelse(bp); - bp->b_flags &= ~B_ASYNC; - bp->b_flags |= B_DONE; - wakeup(bp); - splx(x); -} diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index e34c14a04ba4..1df65b9f395f 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)vfs_cache.c 7.8 (Berkeley) 2/28/91 - * $Id: vfs_cache.c,v 1.2 1993/10/16 15:25:19 rgrimes Exp $ + * $Id: vfs_cache.c,v 1.3 1993/11/25 01:33:40 wollman Exp $ */ #include "param.h" @@ -92,6 +92,7 @@ int doingcache = 1; /* 1 => enable the cache */ * the name does not exist (negative cacheing), a status of ENOENT * is returned. If the lookup fails, a status of zero is returned. */ +int cache_lookup(ndp) register struct nameidata *ndp; { @@ -189,6 +190,7 @@ cache_lookup(ndp) /* * Add an entry to the cache */ +void cache_enter(ndp) register struct nameidata *ndp; { @@ -240,6 +242,7 @@ cache_enter(ndp) /* * Name cache initialization, from vfs_init() when we are booting */ +void nchinit() { register union nchash *nchp; @@ -264,6 +267,7 @@ nchinit() * Cache flush, a particular vnode; called when a vnode is renamed to * hide entries that would now be invalid */ +void cache_purge(vp) struct vnode *vp; { @@ -291,6 +295,7 @@ cache_purge(vp) * if the cache lru chain is modified while we are dumping the * inode. This makes the algorithm O(n^2), but do you think I care? */ +void cache_purgevfs(mp) struct mount *mp; { diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c index 574efd4b8d73..0623ec831a68 100644 --- a/sys/kern/vfs_conf.c +++ b/sys/kern/vfs_conf.c @@ -31,20 +31,14 @@ * SUCH DAMAGE. * * from: @(#)vfs_conf.c 7.3 (Berkeley) 6/28/90 - * $Id: vfs_conf.c,v 1.2 1993/10/16 15:25:21 rgrimes Exp $ + * $Id: vfs_conf.c,v 1.5 1994/01/16 02:26:39 martin Exp $ */ #include "param.h" +#include "systm.h" #include "mount.h" /* - * This specifies the filesystem used to mount the root. - * This specification should be done by /etc/config. - */ -extern int ufs_mountroot(); -int (*mountroot)() = ufs_mountroot; - -/* * These define the root filesystem and device. */ struct mount *rootfs; @@ -72,6 +66,8 @@ extern struct vfsops pcfs_vfsops; extern struct vfsops isofs_vfsops; #endif +extern struct vfsops procfs_vfsops; + struct vfsops *vfssw[] = { (struct vfsops *)0, /* 0 = MOUNT_NONE */ &ufs_vfsops, /* 1 = MOUNT_UFS */ @@ -95,4 +91,5 @@ struct vfsops *vfssw[] = { #else (struct vfsops *)0, #endif + &procfs_vfsops, /* 6 = MOUNT_PROCFS */ }; diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 1202e9de838d..f35002a9460f 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * All rights reserved. * @@ -31,10 +38,11 @@ * SUCH DAMAGE. * * from: @(#)vfs_lookup.c 7.32 (Berkeley) 5/21/91 - * $Id: vfs_lookup.c,v 1.2 1993/10/16 15:25:23 rgrimes Exp $ + * $Id: vfs_lookup.c,v 1.5.2.1 1994/05/04 07:54:56 rgrimes Exp $ */ #include "param.h" +#include "systm.h" #include "syslimits.h" #include "time.h" #include "namei.h" @@ -49,6 +57,8 @@ #include "ktrace.h" #endif +u_long nextvnodeid; + /* * Convert a pathname into a pointer to a locked inode. * @@ -69,6 +79,7 @@ * if symbolic link, massage name in buffer and continue * } */ +int namei(ndp, p) register struct nameidata *ndp; struct proc *p; @@ -91,10 +102,10 @@ namei(ndp, p) MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); if (ndp->ni_segflg == UIO_SYSSPACE) error = copystr(ndp->ni_dirp, ndp->ni_pnbuf, - MAXPATHLEN, &ndp->ni_pathlen); + MAXPATHLEN, (u_int *)&ndp->ni_pathlen); else error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf, - MAXPATHLEN, &ndp->ni_pathlen); + MAXPATHLEN, (u_int *)&ndp->ni_pathlen); if (error) { free(ndp->ni_pnbuf, M_NAMEI); ndp->ni_vp = NULL; @@ -230,6 +241,7 @@ namei(ndp, p) * if LOCKPARENT set, return locked parent in ni_dvp * if WANTPARENT set, return unlocked parent in ni_dvp */ +int lookup(ndp, p) register struct nameidata *ndp; struct proc *p; @@ -399,7 +411,7 @@ mntloop: (ndp->ni_nameiop & NOCROSSMOUNT) == 0) { while(mp->mnt_flag & MNT_MLOCK) { mp->mnt_flag |= MNT_MWAIT; - sleep((caddr_t)mp, PVFS); + tsleep((caddr_t)mp, PVFS, "lookup", 0); goto mntloop; } if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index e0d9d1201431..024c5679000b 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)vfs_subr.c 7.60 (Berkeley) 6/21/91 - * $Id: vfs_subr.c,v 1.4 1993/10/18 14:22:16 davidg Exp $ + * $Id: vfs_subr.c,v 1.7.2.2 1994/05/04 07:55:00 rgrimes Exp $ */ /* @@ -39,6 +46,7 @@ */ #include "param.h" +#include "systm.h" #include "proc.h" #include "mount.h" #include "time.h" @@ -50,6 +58,10 @@ #include "errno.h" #include "malloc.h" +static void insmntque(struct vnode *, struct mount *); + +struct vnode *speclisth[SPECHSZ]; /* device special file vnode hash table */ + /* * Remove a mount point from the list of mounted filesystems. * Unmount of the root is illegal. @@ -71,13 +83,14 @@ vfs_remove(mp) * Lock a filesystem. * Used to prevent access to it while mounting and unmounting. */ +int vfs_lock(mp) register struct mount *mp; { while(mp->mnt_flag & MNT_MLOCK) { mp->mnt_flag |= MNT_MWAIT; - sleep((caddr_t)mp, PVFS); + tsleep((caddr_t)mp, PVFS, "vfslock", 0); } mp->mnt_flag |= MNT_MLOCK; return (0); @@ -105,13 +118,14 @@ vfs_unlock(mp) * Mark a mount point as busy. * Used to synchronize access and to delay unmounting. */ +int vfs_busy(mp) register struct mount *mp; { while(mp->mnt_flag & MNT_MPBUSY) { mp->mnt_flag |= MNT_MPWANT; - sleep((caddr_t)&mp->mnt_flag, PVFS); + tsleep((caddr_t)&mp->mnt_flag, PVFS, "vfsbusy", 0); } if (mp->mnt_flag & MNT_UNMOUNT) return (1); @@ -123,6 +137,7 @@ vfs_busy(mp) * Free a busy filesystem. * Panic if filesystem is not busy. */ +void vfs_unbusy(mp) register struct mount *mp; { @@ -179,13 +194,13 @@ void vattr_null(vap) */ struct vnode *vfreeh, **vfreet; extern struct vnodeops dead_vnodeops, spec_vnodeops; -extern void vclean(); long numvnodes; struct vattr va_null; /* * Initialize the vnode structures and initialize each file system type. */ +void vfsinit() { struct vfsops **vfsp; @@ -208,6 +223,7 @@ vfsinit() /* * Return the next vnode from the free list. */ +int getnewvnode(tag, mp, vops, vpp) enum vtagtype tag; struct mount *mp; @@ -255,6 +271,7 @@ getnewvnode(tag, mp, vops, vpp) /* * Move a vnode from one mount queue to another. */ +static void insmntque(vp, mp) register struct vnode *vp; register struct mount *mp; @@ -289,6 +306,7 @@ insmntque(vp, mp) * Make sure all write-behind blocks associated * with mount point are flushed out (from sync). */ +void mntflushbuf(mountp, flags) struct mount *mountp; int flags; @@ -313,6 +331,7 @@ loop: /* * Flush all dirty buffers associated with a vnode. */ +void vflushbuf(vp, flags) register struct vnode *vp; int flags; @@ -350,7 +369,7 @@ loop: s = splbio(); while (vp->v_numoutput) { vp->v_flag |= VBWAIT; - sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1); + tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vflushbf", 0); } splx(s); if (vp->v_dirtyblkhd) { @@ -362,6 +381,7 @@ loop: /* * Update outstanding I/O count and do wakeup if requested. */ +void vwakeup(bp) register struct buf *bp; { @@ -388,6 +408,7 @@ vwakeup(bp) * filesystem there will be no dirty buffers when we are done. Binval * returns the count of dirty buffers when it is finished. */ +int mntinvalbuf(mountp) struct mount *mountp; { @@ -412,6 +433,7 @@ loop: * Flush out and invalidate all buffers associated with a vnode. * Called with the underlying object locked. */ +int vinvalbuf(vp, save) register struct vnode *vp; int save; @@ -432,7 +454,7 @@ vinvalbuf(vp, save) s = splbio(); if (bp->b_flags & B_BUSY) { bp->b_flags |= B_WANTED; - sleep((caddr_t)bp, PRIBIO + 1); + tsleep((caddr_t)bp, PRIBIO + 1, "vinvalbf", 0); splx(s); break; } @@ -459,6 +481,7 @@ vinvalbuf(vp, save) /* * Associate a buffer with a vnode. */ +void bgetvp(vp, bp) register struct vnode *vp; register struct buf *bp; @@ -487,6 +510,7 @@ bgetvp(vp, bp) /* * Disassociate a buffer from a vnode. */ +void brelvp(bp) register struct buf *bp; { @@ -515,6 +539,7 @@ brelvp(bp) * Used to assign file specific control information * (indirect blocks) to the vnode to which they belong. */ +void reassignbuf(bp, newvp) register struct buf *bp; register struct vnode *newvp; @@ -551,6 +576,7 @@ reassignbuf(bp, newvp) * Used for root filesystem, argdev, and swap areas. * Also used for memory file system special devices. */ +int bdevvp(dev, vpp) dev_t dev; struct vnode **vpp; @@ -644,6 +670,7 @@ loop: * indicate that the vnode is no longer usable (possibly having * been changed to a new file system type). */ +int vget(vp) register struct vnode *vp; { @@ -651,7 +678,7 @@ vget(vp) if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - sleep((caddr_t)vp, PINOD); + tsleep((caddr_t)vp, PINOD, "vget", 0); return (1); } if (vp->v_usecount == 0) { @@ -710,6 +737,7 @@ void vrele(vp) panic("vrele: ref cnt"); } #endif + vp->v_writecount = 0; /* XXX */ if (vfreeh == NULLVP) { /* * insert into empty list @@ -731,6 +759,7 @@ void vrele(vp) /* * Page or buffer structure gets a reference. */ +void vhold(vp) register struct vnode *vp; { @@ -741,6 +770,7 @@ vhold(vp) /* * Page or buffer structure frees a reference. */ +void holdrele(vp) register struct vnode *vp; { @@ -760,6 +790,7 @@ holdrele(vp) */ int busyprt = 0; /* patch to print out busy vnodes */ +int vflush(mp, skipvp, flags) struct mount *mp; struct vnode *skipvp; @@ -902,7 +933,7 @@ void vgoneall(vp) */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - sleep((caddr_t)vp, PINOD); + tsleep((caddr_t)vp, PINOD, "vgoneall", 0); return; } /* @@ -933,11 +964,12 @@ void vgoneall(vp) * Eliminate all activity associated with a vnode * in preparation for reuse. */ -void vgone(vp) +void +vgone(vp) register struct vnode *vp; { register struct vnode *vq; - struct vnode *vx; + struct vnode *vx = 0; long count; /* @@ -946,7 +978,7 @@ void vgone(vp) */ if (vp->v_flag & VXLOCK) { vp->v_flag |= VXWANT; - sleep((caddr_t)vp, PINOD); + tsleep((caddr_t)vp, PINOD, "vgone", 0); return; } /* @@ -1017,6 +1049,7 @@ void vgone(vp) /* * Lookup a vnode by device number. */ +int vfinddev(dev, type, vpp) dev_t dev; enum vtype type; @@ -1036,6 +1069,7 @@ vfinddev(dev, type, vpp) /* * Calculate the total number of references to a special device. */ +int vcount(vp) register struct vnode *vp; { @@ -1066,8 +1100,9 @@ loop: static char *typename[] = { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" }; +void vprint(label, vp) - char *label; + const char *label; register struct vnode *vp; { char buf[64]; @@ -1127,6 +1162,7 @@ int kinfo_vgetfailed; * Copyout address of vnode followed by vnode. */ /* ARGSUSED */ +int kinfo_vnode(op, where, acopysize, arg, aneeded) int op; char *where; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 395dc90e63aa..396bd6326f98 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)vfs_syscalls.c 7.74 (Berkeley) 6/21/91 - * $Id: vfs_syscalls.c,v 1.5 1993/10/23 16:02:54 davidg Exp $ + * $Id: vfs_syscalls.c,v 1.10 1994/01/19 21:09:13 jtc Exp $ */ #include "param.h" @@ -47,6 +47,9 @@ #include "uio.h" #include "malloc.h" +static int getvnode(struct filedesc *, int, struct file **); +static int chdirec(struct nameidata *, struct proc *); + /* * Virtual File System System Calls */ @@ -63,6 +66,7 @@ struct mount_args { }; /* ARGSUSED */ +int mount(p, uap, retval) struct proc *p; register struct mount_args *uap; @@ -71,7 +75,7 @@ mount(p, uap, retval) register struct nameidata *ndp; register struct vnode *vp; register struct mount *mp; - int error, flag; + int error, flag = 0; struct nameidata nd; /* @@ -150,30 +154,10 @@ update: /* * Set the mount level flags. */ - if (uap->flags & MNT_RDONLY) - mp->mnt_flag |= MNT_RDONLY; - else - mp->mnt_flag &= ~MNT_RDONLY; - if (uap->flags & MNT_NOSUID) - mp->mnt_flag |= MNT_NOSUID; - else - mp->mnt_flag &= ~MNT_NOSUID; - if (uap->flags & MNT_NOEXEC) - mp->mnt_flag |= MNT_NOEXEC; - else - mp->mnt_flag &= ~MNT_NOEXEC; - if (uap->flags & MNT_NODEV) - mp->mnt_flag |= MNT_NODEV; - else - mp->mnt_flag &= ~MNT_NODEV; - if (uap->flags & MNT_NOCORE) - mp->mnt_flag |= MNT_NOCORE; - else - mp->mnt_flag &= ~MNT_NOCORE; - if (uap->flags & MNT_SYNCHRONOUS) - mp->mnt_flag |= MNT_SYNCHRONOUS; - else - mp->mnt_flag &= ~MNT_SYNCHRONOUS; + mp->mnt_flag &= + ~(MNT_RDONLY|MNT_NOSUID|MNT_NOEXEC|MNT_NODEV|MNT_SYNCHRONOUS); + mp->mnt_flag |= uap->flags & + (MNT_RDONLY|MNT_NOSUID|MNT_NOEXEC|MNT_NODEV|MNT_SYNCHRONOUS); /* * Mount the filesystem. */ @@ -218,6 +202,7 @@ struct umount_args { }; /* ARGSUSED */ +int unmount(p, uap, retval) struct proc *p; register struct umount_args *uap; @@ -257,6 +242,7 @@ unmount(p, uap, retval) /* * Do an unmount. */ +int dounmount(mp, flags, p) register struct mount *mp; int flags; @@ -293,6 +279,7 @@ dounmount(mp, flags, p) * Sync each mounted filesystem. */ /* ARGSUSED */ +int sync(p, uap, retval) struct proc *p; void *uap; @@ -332,6 +319,7 @@ struct quotactl_args { }; /* ARGSUSED */ +int quotactl(p, uap, retval) struct proc *p; register struct quotactl_args *uap; @@ -363,6 +351,7 @@ struct statfs_args { }; /* ARGSUSED */ +int statfs(p, uap, retval) struct proc *p; register struct statfs_args *uap; @@ -399,6 +388,7 @@ struct fstatfs_args { }; /* ARGSUSED */ +int fstatfs(p, uap, retval) struct proc *p; register struct fstatfs_args *uap; @@ -429,6 +419,7 @@ struct getfsstat_args { int flags; }; +int getfsstat(p, uap, retval) struct proc *p; register struct getfsstat_args *uap; @@ -481,6 +472,7 @@ struct fchdir_args { }; /* ARGSUSED */ +int fchdir(p, uap, retval) struct proc *p; struct fchdir_args *uap; @@ -517,6 +509,7 @@ struct chdir_args { }; /* ARGSUSED */ +int chdir(p, uap, retval) struct proc *p; struct chdir_args *uap; @@ -547,6 +540,7 @@ struct chroot_args { }; /* ARGSUSED */ +int chroot(p, uap, retval) struct proc *p; struct chroot_args *uap; @@ -574,6 +568,7 @@ chroot(p, uap, retval) /* * Common routine for chroot and chdir. */ +static int chdirec(ndp, p) struct nameidata *ndp; struct proc *p; @@ -606,6 +601,7 @@ struct open_args { int crtmode; }; +int open(p, uap, retval) struct proc *p; register struct open_args *uap; @@ -645,6 +641,7 @@ open(p, uap, retval) return (error); } vp = ndp->ni_vp; + VOP_UNLOCK(vp); fp->f_flag = fmode & FMASK; if (fmode & (O_EXLOCK | O_SHLOCK)) { lf.l_whence = SEEK_SET; @@ -658,7 +655,6 @@ open(p, uap, retval) if ((fmode & FNONBLOCK) == 0) type |= F_WAIT; if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { - VOP_UNLOCK(vp); (void) vn_close(vp, fp->f_flag, fp->f_cred, p); ffree(fp); fdp->fd_ofiles[indx] = NULL; @@ -666,7 +662,6 @@ open(p, uap, retval) } fp->f_flag |= FHASLOCK; } - VOP_UNLOCK(vp); fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; @@ -684,6 +679,7 @@ struct ocreat_args { int fmode; }; +int ocreat(p, uap, retval) struct proc *p; register struct ocreat_args *uap; @@ -713,6 +709,7 @@ struct mknod_args { }; /* ARGSUSED */ +int mknod(p, uap, retval) struct proc *p; register struct mknod_args *uap; @@ -780,6 +777,7 @@ struct mkfifo_args { }; /* ARGSUSED */ +int mkfifo(p, uap, retval) struct proc *p; register struct mkfifo_args *uap; @@ -825,6 +823,7 @@ struct link_args { }; /* ARGSUSED */ +int link(p, uap, retval) struct proc *p; register struct link_args *uap; @@ -884,6 +883,7 @@ struct symlink_args { }; /* ARGSUSED */ +int symlink(p, uap, retval) struct proc *p; register struct symlink_args *uap; @@ -931,6 +931,7 @@ struct unlink_args { }; /* ARGSUSED */ +int unlink(p, uap, retval) struct proc *p; struct unlink_args *uap; @@ -983,6 +984,7 @@ struct lseek_args { int sbase; }; +int lseek(p, uap, retval) struct proc *p; register struct lseek_args *uap; @@ -1033,6 +1035,7 @@ struct saccess_args { }; /* ARGSUSED */ +int saccess(p, uap, retval) struct proc *p; register struct saccess_args *uap; @@ -1087,6 +1090,7 @@ struct stat_args { }; /* ARGSUSED */ +int stat(p, uap, retval) struct proc *p; register struct stat_args *uap; @@ -1122,6 +1126,7 @@ struct lstat_args { }; /* ARGSUSED */ +int lstat(p, uap, retval) struct proc *p; register struct lstat_args *uap; @@ -1157,6 +1162,7 @@ struct readlink_args { }; /* ARGSUSED */ +int readlink(p, uap, retval) struct proc *p; register struct readlink_args *uap; @@ -1206,6 +1212,7 @@ struct chflags_args { }; /* ARGSUSED */ +int chflags(p, uap, retval) struct proc *p; register struct chflags_args *uap; @@ -1246,6 +1253,7 @@ struct fdchflags_args { }; /* ARGSUSED */ +int fchflags(p, uap, retval) struct proc *p; register struct fdchflags_args *uap; @@ -1282,6 +1290,7 @@ struct chmod_args { }; /* ARGSUSED */ +int chmod(p, uap, retval) struct proc *p; register struct chmod_args *uap; @@ -1322,6 +1331,7 @@ struct fchmod_args { }; /* ARGSUSED */ +int fchmod(p, uap, retval) struct proc *p; register struct fchmod_args *uap; @@ -1359,6 +1369,7 @@ struct chown_args { }; /* ARGSUSED */ +int chown(p, uap, retval) struct proc *p; register struct chown_args *uap; @@ -1401,6 +1412,7 @@ struct fchown_args { }; /* ARGSUSED */ +int fchown(p, uap, retval) struct proc *p; register struct fchown_args *uap; @@ -1438,6 +1450,7 @@ struct utimes_args { }; /* ARGSUSED */ +int utimes(p, uap, retval) struct proc *p; register struct utimes_args *uap; @@ -1450,7 +1463,12 @@ utimes(p, uap, retval) int error; struct nameidata nd; - if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) + VATTR_NULL(&vattr); + if ((caddr_t)uap->tptr == NULL) { + microtime(&tv[0]); + tv[1] = tv[0]; + vattr.va_vaflags |= VA_UTIMES_NULL; + } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) return (error); ndp = &nd; ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; @@ -1463,7 +1481,6 @@ utimes(p, uap, retval) error = EROFS; goto out; } - VATTR_NULL(&vattr); vattr.va_atime = tv[0]; vattr.va_mtime = tv[1]; error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); @@ -1482,6 +1499,7 @@ struct truncate_args { }; /* ARGSUSED */ +int truncate(p, uap, retval) struct proc *p; register struct truncate_args *uap; @@ -1525,6 +1543,7 @@ struct ftruncate_args { }; /* ARGSUSED */ +int ftruncate(p, uap, retval) struct proc *p; register struct ftruncate_args *uap; @@ -1564,6 +1583,7 @@ struct fsync_args { }; /* ARGSUSED */ +int fsync(p, uap, retval) struct proc *p; struct fsync_args *uap; @@ -1595,6 +1615,7 @@ struct rename_args { }; /* ARGSUSED */ +int rename(p, uap, retval) struct proc *p; register struct rename_args *uap; @@ -1685,6 +1706,7 @@ struct mkdir_args { }; /* ARGSUSED */ +int mkdir(p, uap, retval) struct proc *p; register struct mkdir_args *uap; @@ -1730,6 +1752,7 @@ struct rmdir_args { }; /* ARGSUSED */ +int rmdir(p, uap, retval) struct proc *p; struct rmdir_args *uap; @@ -1788,6 +1811,7 @@ struct getdirentries_args { long *basep; }; +int getdirentries(p, uap, retval) struct proc *p; register struct getdirentries_args *uap; @@ -1858,6 +1882,7 @@ struct revoke_args { }; /* ARGSUSED */ +int revoke(p, uap, retval) struct proc *p; register struct revoke_args *uap; @@ -1895,10 +1920,11 @@ out: /* * Convert a user file descriptor to a kernel file entry. */ +static int getvnode(fdp, fdes, fpp) struct filedesc *fdp; - struct file **fpp; int fdes; + struct file **fpp; { struct file *fp; diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index ed2dc6214a45..b273dc8b3604 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1,4 +1,11 @@ /* + * Copyright (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. + */ +/* * Copyright (c) 1982, 1986, 1989 Regents of the University of California. * All rights reserved. * @@ -31,7 +38,7 @@ * SUCH DAMAGE. * * from: @(#)vfs_vnops.c 7.33 (Berkeley) 6/27/91 - * $Id: vfs_vnops.c,v 1.2 1993/10/16 15:25:29 rgrimes Exp $ + * $Id: vfs_vnops.c,v 1.4.2.2 1994/05/04 07:55:04 rgrimes Exp $ */ #include "param.h" @@ -54,6 +61,7 @@ struct fileops vnops = * Common code for vnode open operations. * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. */ +int vn_open(ndp, p, fmode, cmode) register struct nameidata *ndp; struct proc *p; @@ -139,6 +147,7 @@ bad: * The read-only status of the file system is checked. * Also, prototype text segments cannot be written. */ +int vn_writechk(vp) register struct vnode *vp; { @@ -167,6 +176,7 @@ vn_writechk(vp) /* * Vnode close call */ +int vn_close(vp, flags, cred, p) register struct vnode *vp; int flags; @@ -186,6 +196,7 @@ vn_close(vp, flags, cred, p) * Package up an I/O request on a vnode into a uio and do it. * [internal interface to file i/o for kernel only] */ +int vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) enum uio_rw rw; struct vnode *vp; @@ -230,6 +241,7 @@ vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) /* * File table vnode read routine. */ +int vn_read(fp, uio, cred) struct file *fp; struct uio *uio; @@ -251,6 +263,7 @@ vn_read(fp, uio, cred) /* * File table vnode write routine. */ +int vn_write(fp, uio, cred) struct file *fp; struct uio *uio; @@ -278,6 +291,7 @@ vn_write(fp, uio, cred) /* * File table vnode stat routine. */ +int vn_stat(vp, sb, p) struct vnode *vp; register struct stat *sb; @@ -300,6 +314,7 @@ vn_stat(vp, sb, p) mode = vap->va_mode; switch (vp->v_type) { case VREG: + case VPROC: mode |= S_IFREG; break; case VDIR: @@ -345,6 +360,7 @@ vn_stat(vp, sb, p) /* * File table vnode ioctl routine. */ +int vn_ioctl(fp, com, data, p) struct file *fp; int com; @@ -376,7 +392,7 @@ vn_ioctl(fp, com, data, p) case VCHR: case VBLK: error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); - if (error == 0 && com == TIOCSCTTY) { + if (error == 0 && com == TIOCSCTTY && (p->p_session->s_ttyvp != vp)) { p->p_session->s_ttyvp = vp; VREF(vp); } @@ -387,6 +403,7 @@ vn_ioctl(fp, com, data, p) /* * File table vnode select routine. */ +int vn_select(fp, which, p) struct file *fp; int which; @@ -400,6 +417,7 @@ vn_select(fp, which, p) /* * File table vnode close routine. */ +int vn_closefile(fp, p) struct file *fp; struct proc *p; @@ -415,6 +433,7 @@ vn_closefile(fp, p) * - get vp by calling VFS_FHTOVP() macro * - if lockflag lock it with VOP_LOCK() */ +int vn_fhtovp(fhp, lockflag, vpp) fhandle_t *fhp; int lockflag; |
