1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-28 16:43:09 +00:00

Import 4.4BSD-Lite2 onto the vendor branch, note that in the kernel, all

files are off the vendor branch, so this should not change anything.

A "U" marker generally means that the file was not changed in between
the 4.4Lite and Lite-2 releases, and does not need a merge.  "C" generally
means that there was a change.
[note new unused (in this form) syscalls.conf, to be 'cvs rm'ed]
This commit is contained in:
Peter Wemm 1996-03-11 20:02:06 +00:00
parent 8169788f40
commit edbfedac86
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=14567
53 changed files with 28580 additions and 0 deletions

19
sys/kern/Make.tags.inc Normal file
View File

@ -0,0 +1,19 @@
# @(#)Make.tags.inc 8.2 (Berkeley) 11/23/94
# Common files for "make tags".
# Included by the Makefile for each architecture.
# Put the ../sys stuff near the end so that subroutine definitions win when
# there is a struct tag with the same name (eg., vmmeter). The real
# solution would probably be for ctags to generate "struct vmmeter" tags.
COMM= /sys/conf/*.[ch] \
/sys/dev/*.[ch] /sys/dev/scsi/*.[ch] \
/sys/isofs/*/*.[ch] \
/sys/kern/*.[ch] /sys/libkern/*.[ch] \
/sys/miscfs/*/*.[ch] \
/sys/net/*.[ch] /sys/netccitt/*.[ch] /sys/netinet/*.[ch] \
/sys/netiso/*.[ch] /sys/netns/*.[ch] \
/sys/nfs/*.[ch] /sys/sys/*.[ch] \
/sys/ufs/*/*.[ch] \
/sys/vm/*.[ch]

50
sys/kern/Makefile Normal file
View File

@ -0,0 +1,50 @@
# @(#)Makefile 8.3 (Berkeley) 2/14/95
# Makefile for kernel tags files, init_sysent, etc.
ARCH= hp300 i386 luna68k news3400 pmax sparc tahoe vax
all:
@echo "make tags, make links or init_sysent.c only"
init_sysent.c syscalls.c ../sys/syscall.h ../sys/syscallargs.h: makesyscalls.sh syscalls.master
-mv -f init_sysent.c init_sysent.c.bak
-mv -f syscalls.c syscalls.c.bak
-mv -f ../sys/syscall.h ../sys/syscall.h.bak
sh makesyscalls.sh syscalls.conf syscalls.master
# Kernel tags:
# Tags files are built in the top-level directory for each architecture,
# with a makefile listing the architecture-dependent files, etc. The list
# of common files is in ./Make.tags.inc. Links to the correct tags file
# are placed in each source directory. We need to have links to tags files
# from the generic directories that are relative to the machine type, even
# via remote mounts; therefore we use symlinks to $SYSTAGS, which points at
# ${SYSDIR}/${MACHINE}/tags.
SYSTAGS=/var/db/sys_tags
SYSDIR=/sys
# Directories in which to place tags links (other than machine-dependent)
DGEN= conf \
dev dev/scsi \
hp hp/dev hp/hpux \
kern libkern \
miscfs miscfs/deadfs miscfs/fdesc miscfs/fifofs miscfs/kernfs \
miscfs/lofs miscfs/nullfs miscfs/portal miscfs/procfs \
miscfs/specfs miscfs/umapfs miscfs/union \
net netccitt netinet netiso netns nfs scripts sys \
ufs ufs/ffs ufs/lfs ufs/mfs ufs/ufs \
vm
tags::
-for i in ${ARCH}; do \
(cd ../$$i && make ${MFLAGS} tags); done
links::
rm -f ${SYSTAGS}
ln -s ${SYSDIR}/${MACHINE}/tags ${SYSTAGS}
-for i in ${DGEN}; do \
(cd ../$$i && { rm -f tags; ln -s ${SYSTAGS} tags; }) done
-for i in ${ARCH}; do \
(cd ../$$i && make ${MFLAGS} SYSTAGS=${SYSTAGS} links); done

412
sys/kern/init_main.c Normal file
View File

@ -0,0 +1,412 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)init_main.c 8.16 (Berkeley) 5/14/95
*/
#include <sys/param.h>
#include <sys/filedesc.h>
#include <sys/errno.h>
#include <sys/exec.h>
#include <sys/kernel.h>
#include <sys/mount.h>
#include <sys/map.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/systm.h>
#include <sys/vnode.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/clist.h>
#include <sys/device.h>
#include <sys/protosw.h>
#include <sys/reboot.h>
#include <sys/user.h>
#include <sys/syscallargs.h>
#include <ufs/ufs/quota.h>
#include <machine/cpu.h>
#include <vm/vm.h>
#ifdef HPFPLIB
char copyright[] =
"Copyright (c) 1982, 1986, 1989, 1991, 1993\n\tThe Regents of the University of California.\nCopyright (c) 1992 Hewlett-Packard Company\nCopyright (c) 1992 Motorola Inc.\nAll rights reserved.\n\n";
#else
char copyright[] =
"Copyright (c) 1982, 1986, 1989, 1991, 1993\n\tThe Regents of the University of California. All rights reserved.\n\n";
#endif
/* Components of the first process -- never freed. */
struct session session0;
struct pgrp pgrp0;
struct proc proc0;
struct pcred cred0;
struct filedesc0 filedesc0;
struct plimit limit0;
struct vmspace vmspace0;
struct proc *curproc = &proc0;
struct proc *initproc, *pageproc;
int cmask = CMASK;
extern struct user *proc0paddr;
struct vnode *rootvp, *swapdev_vp;
int boothowto;
struct timeval boottime;
struct timeval runtime;
static void start_init __P((struct proc *p, void *framep));
/*
* 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.
*/
main(framep)
void *framep;
{
register struct proc *p;
register struct filedesc0 *fdp;
register struct pdevinit *pdev;
register int i;
int s;
register_t rval[2];
extern struct pdevinit pdevinit[];
extern void roundrobin __P((void *));
extern void schedcpu __P((void *));
/*
* Initialize the current process pointer (curproc) before
* any possible traps/probes to simplify trap processing.
*/
p = &proc0;
curproc = p;
/*
* Attempt to find console and initialize
* in case of early panic or other messages.
*/
consinit();
printf(copyright);
vm_mem_init();
kmeminit();
cpu_startup();
/*
* Initialize process and pgrp structures.
*/
procinit();
/*
* Create process 0 (the swapper).
*/
LIST_INSERT_HEAD(&allproc, p, p_list);
p->p_pgrp = &pgrp0;
LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash);
LIST_INIT(&pgrp0.pg_members);
LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist);
pgrp0.pg_session = &session0;
session0.s_count = 1;
session0.s_leader = p;
p->p_flag = P_INMEM | P_SYSTEM;
p->p_stat = SRUN;
p->p_nice = NZERO;
bcopy("swapper", p->p_comm, sizeof ("swapper"));
/* Create credentials. */
cred0.p_refcnt = 1;
p->p_cred = &cred0;
p->p_ucred = crget();
p->p_ucred->cr_ngroups = 1; /* group 0 */
/* Create the file descriptor table. */
fdp = &filedesc0;
p->p_fd = &fdp->fd_fd;
fdp->fd_fd.fd_refcnt = 1;
fdp->fd_fd.fd_cmask = cmask;
fdp->fd_fd.fd_ofiles = fdp->fd_dfiles;
fdp->fd_fd.fd_ofileflags = fdp->fd_dfileflags;
fdp->fd_fd.fd_nfiles = NDFILE;
/* Create the limits structures. */
p->p_limit = &limit0;
for (i = 0; i < sizeof(p->p_rlimit)/sizeof(p->p_rlimit[0]); i++)
limit0.pl_rlimit[i].rlim_cur =
limit0.pl_rlimit[i].rlim_max = RLIM_INFINITY;
limit0.pl_rlimit[RLIMIT_NOFILE].rlim_cur = NOFILE;
limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = MAXUPRC;
i = ptoa(cnt.v_free_count);
limit0.pl_rlimit[RLIMIT_RSS].rlim_max = i;
limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i;
limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3;
limit0.p_refcnt = 1;
/* Allocate a prototype map so we have something to fork. */
p->p_vmspace = &vmspace0;
vmspace0.vm_refcnt = 1;
pmap_pinit(&vmspace0.vm_pmap);
vm_map_init(&p->p_vmspace->vm_map, round_page(VM_MIN_ADDRESS),
trunc_page(VM_MAX_ADDRESS), TRUE);
vmspace0.vm_map.pmap = &vmspace0.vm_pmap;
p->p_addr = proc0paddr; /* XXX */
/*
* We continue to place resource usage info and signal
* actions in the user struct so they're pageable.
*/
p->p_stats = &p->p_addr->u_stats;
p->p_sigacts = &p->p_addr->u_sigacts;
/*
* Charge root for one process.
*/
(void)chgproccnt(0, 1);
rqinit();
/* Configure virtual memory system, set vm rlimits. */
vm_init_limits(p);
/* Initialize the file systems. */
vfsinit();
/* Start real time and statistics clocks. */
initclocks();
/* Initialize mbuf's. */
mbinit();
/* Initialize clists. */
clist_init();
#ifdef SYSVSHM
/* Initialize System V style shared memory. */
shminit();
#endif
/* Attach pseudo-devices. */
for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
(*pdev->pdev_attach)(pdev->pdev_count);
/*
* Initialize protocols. Block reception of incoming packets
* until everything is ready.
*/
s = splimp();
ifinit();
domaininit();
splx(s);
#ifdef GPROF
/* Initialize kernel profiling. */
kmstartup();
#endif
/* Kick off timeout driven events by calling first time. */
roundrobin(NULL);
schedcpu(NULL);
/* Mount the root file system. */
if (vfs_mountroot())
panic("cannot mount root");
mountlist.cqh_first->mnt_flag |= MNT_ROOTFS;
/* Get the vnode for '/'. Set fdp->fd_fd.fd_cdir to reference it. */
if (VFS_ROOT(mountlist.cqh_first, &rootvnode))
panic("cannot find root vnode");
fdp->fd_fd.fd_cdir = rootvnode;
VREF(fdp->fd_fd.fd_cdir);
VOP_UNLOCK(rootvnode, 0, p);
fdp->fd_fd.fd_rdir = NULL;
swapinit();
/*
* Now can look at time, having had a chance to verify the time
* from the file system. Reset p->p_rtime as it may have been
* munched in mi_switch() after the time got set.
*/
p->p_stats->p_start = runtime = mono_time = boottime = time;
p->p_rtime.tv_sec = p->p_rtime.tv_usec = 0;
/* Initialize signal state for process 0. */
siginit(p);
/* Create process 1 (init(8)). */
if (fork(p, NULL, rval))
panic("fork init");
if (rval[1]) {
start_init(curproc, framep);
return;
}
/* Create process 2 (the pageout daemon). */
if (fork(p, NULL, rval))
panic("fork pager");
if (rval[1]) {
/*
* Now in process 2.
*/
p = curproc;
pageproc = p;
p->p_flag |= P_INMEM | P_SYSTEM; /* XXX */
bcopy("pagedaemon", curproc->p_comm, sizeof ("pagedaemon"));
vm_pageout();
/* NOTREACHED */
}
/* The scheduler is an infinite loop. */
scheduler();
/* NOTREACHED */
}
/*
* List of paths to try when searching for "init".
*/
static char *initpaths[] = {
"/sbin/init",
"/sbin/oinit",
"/sbin/init.bak",
NULL,
};
/*
* Start the initial user process; try exec'ing each pathname in "initpaths".
* The program is invoked with one argument containing the boot flags.
*/
static void
start_init(p, framep)
struct proc *p;
void *framep;
{
vm_offset_t addr;
struct execve_args /* {
syscallarg(char *) path;
syscallarg(char **) argp;
syscallarg(char **) envp;
} */ args;
int options, i, error;
register_t retval[2];
char flags[4] = "-", *flagsp;
char **pathp, *path, *ucp, **uap, *arg0, *arg1;
initproc = p;
/*
* We need to set the system call frame as if we were entered through
* a syscall() so that when we call execve() below, it will be able
* to set the entry point (see setregs) when it tries to exec. The
* startup code in "locore.s" has allocated space for the frame and
* passed a pointer to that space as main's argument.
*/
cpu_set_init_frame(p, framep);
/*
* Need just enough stack to hold the faked-up "execve()" arguments.
*/
addr = trunc_page(VM_MAX_ADDRESS - PAGE_SIZE);
if (vm_allocate(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, FALSE) != 0)
panic("init: couldn't allocate argument space");
p->p_vmspace->vm_maxsaddr = (caddr_t)addr;
for (pathp = &initpaths[0]; (path = *pathp) != NULL; pathp++) {
/*
* Construct the boot flag argument.
*/
options = 0;
flagsp = flags + 1;
ucp = (char *)USRSTACK;
if (boothowto & RB_SINGLE) {
*flagsp++ = 's';
options = 1;
}
#ifdef notyet
if (boothowto & RB_FASTBOOT) {
*flagsp++ = 'f';
options = 1;
}
#endif
/*
* Move out the flags (arg 1), if necessary.
*/
if (options != 0) {
*flagsp++ = '\0';
i = flagsp - flags;
(void)copyout((caddr_t)flags, (caddr_t)(ucp -= i), i);
arg1 = ucp;
}
/*
* Move out the file name (also arg 0).
*/
i = strlen(path) + 1;
(void)copyout((caddr_t)path, (caddr_t)(ucp -= i), i);
arg0 = ucp;
/*
* Move out the arg pointers.
*/
uap = (char **)((long)ucp & ~ALIGNBYTES);
(void)suword((caddr_t)--uap, 0); /* terminator */
if (options != 0)
(void)suword((caddr_t)--uap, (long)arg1);
(void)suword((caddr_t)--uap, (long)arg0);
/*
* Point at the arguments.
*/
SCARG(&args, path) = arg0;
SCARG(&args, argp) = uap;
SCARG(&args, envp) = NULL;
/*
* Now try to exec the program. If can't for any reason
* other than it doesn't exist, complain.
*/
if ((error = execve(p, &args, retval)) == 0)
return;
if (error != ENOENT)
printf("exec %s: error %d\n", path, error);
}
printf("init: not found\n");
panic("no init");
}

767
sys/kern/init_sysent.c Normal file
View File

@ -0,0 +1,767 @@
/*
* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
* created from @(#)syscalls.master 8.6 (Berkeley) 3/30/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signal.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
int nosys();
int exit();
int fork();
int read();
int write();
int open();
int close();
int wait4();
int link();
int unlink();
int chdir();
int fchdir();
int mknod();
int chmod();
int chown();
int obreak();
int getfsstat();
int getpid();
int mount();
int unmount();
int setuid();
int getuid();
int geteuid();
int ptrace();
int recvmsg();
int sendmsg();
int recvfrom();
int accept();
int getpeername();
int getsockname();
int access();
int chflags();
int fchflags();
int sync();
int kill();
int getppid();
int dup();
int pipe();
int getegid();
int profil();
#ifdef KTRACE
int ktrace();
#else
#endif
int sigaction();
int getgid();
int sigprocmask();
int getlogin();
int setlogin();
int acct();
int sigpending();
int sigaltstack();
int ioctl();
int reboot();
int revoke();
int symlink();
int readlink();
int execve();
int umask();
int chroot();
int msync();
int vfork();
int sbrk();
int sstk();
int ovadvise();
int munmap();
int mprotect();
int madvise();
int mincore();
int getgroups();
int setgroups();
int getpgrp();
int setpgid();
int setitimer();
int swapon();
int getitimer();
int getdtablesize();
int dup2();
int fcntl();
int select();
int fsync();
int setpriority();
int socket();
int connect();
int getpriority();
int sigreturn();
int bind();
int setsockopt();
int listen();
int sigsuspend();
#ifdef TRACE
int vtrace();
#else
#endif
int gettimeofday();
int getrusage();
int getsockopt();
#ifdef vax
int resuba();
#else
#endif
int readv();
int writev();
int settimeofday();
int fchown();
int fchmod();
int rename();
int flock();
int mkfifo();
int sendto();
int shutdown();
int socketpair();
int mkdir();
int rmdir();
int utimes();
int adjtime();
int setsid();
int quotactl();
#ifdef NFS
int nfssvc();
#else
#endif
int statfs();
int fstatfs();
#ifdef NFS
int getfh();
#else
#endif
#if defined(SYSVSHM) && !defined(alpha)
#else
#endif
int setgid();
int setegid();
int seteuid();
#ifdef LFS
int lfs_bmapv();
int lfs_markv();
int lfs_segclean();
int lfs_segwait();
#else
#endif
int stat();
int fstat();
int lstat();
int pathconf();
int fpathconf();
int getrlimit();
int setrlimit();
int getdirentries();
int mmap();
int nosys();
int lseek();
int truncate();
int ftruncate();
int __sysctl();
int mlock();
int munlock();
int undelete();
#if defined(SYSVSHM) && 0
int shmat();
int shmctl();
int shmdt();
int shmget();
#else
#endif
#ifdef COMPAT_43
#define compat_43(func) __CONCAT(compat_43_,func)
int compat_43(creat)();
int compat_43(lseek)();
int compat_43(stat)();
int compat_43(lstat)();
#ifdef KTRACE
#else
#endif
int compat_43(fstat)();
int compat_43(getkerninfo)();
int compat_43(getpagesize)();
int compat_43(mmap)();
int compat_43(wait)();
int compat_43(gethostname)();
int compat_43(sethostname)();
int compat_43(accept)();
int compat_43(send)();
int compat_43(recv)();
int compat_43(sigvec)();
int compat_43(sigblock)();
int compat_43(sigsetmask)();
int compat_43(sigstack)();
int compat_43(recvmsg)();
int compat_43(sendmsg)();
#ifdef TRACE
#else
#endif
#ifdef vax
#else
#endif
int compat_43(recvfrom)();
int compat_43(setreuid)();
int compat_43(setregid)();
int compat_43(truncate)();
int compat_43(ftruncate)();
int compat_43(getpeername)();
int compat_43(gethostid)();
int compat_43(sethostid)();
int compat_43(getrlimit)();
int compat_43(setrlimit)();
int compat_43(killpg)();
int compat_43(quota)();
int compat_43(getsockname)();
#ifdef NFS
#else
#endif
int compat_43(getdirentries)();
#ifdef NFS
#else
#endif
#if defined(SYSVSHM) && !defined(alpha)
int compat_43(shmsys)();
#else
#endif
#ifdef LFS
#else
#endif
#if defined(SYSVSHM) && 0
#else
#endif
#else /* COMPAT_43 */
#define compat_43(func) nosys
#endif /* COMPAT_43 */
#define s(type) sizeof(type)
struct sysent sysent[] = {
{ 0, 0,
nosys }, /* 0 = syscall */
{ 1, s(struct exit_args),
exit }, /* 1 = exit */
{ 0, 0,
fork }, /* 2 = fork */
{ 3, s(struct read_args),
read }, /* 3 = read */
{ 3, s(struct write_args),
write }, /* 4 = write */
{ 3, s(struct open_args),
open }, /* 5 = open */
{ 1, s(struct close_args),
close }, /* 6 = close */
{ 4, s(struct wait4_args),
wait4 }, /* 7 = wait4 */
{ 2, s(struct compat_43_creat_args),
compat_43(creat) }, /* 8 = compat_43 creat */
{ 2, s(struct link_args),
link }, /* 9 = link */
{ 1, s(struct unlink_args),
unlink }, /* 10 = unlink */
{ 0, 0,
nosys }, /* 11 = obsolete execv */
{ 1, s(struct chdir_args),
chdir }, /* 12 = chdir */
{ 1, s(struct fchdir_args),
fchdir }, /* 13 = fchdir */
{ 3, s(struct mknod_args),
mknod }, /* 14 = mknod */
{ 2, s(struct chmod_args),
chmod }, /* 15 = chmod */
{ 3, s(struct chown_args),
chown }, /* 16 = chown */
{ 1, s(struct obreak_args),
obreak }, /* 17 = break */
{ 3, s(struct getfsstat_args),
getfsstat }, /* 18 = getfsstat */
{ 3, s(struct compat_43_lseek_args),
compat_43(lseek) }, /* 19 = compat_43 lseek */
{ 0, 0,
getpid }, /* 20 = getpid */
{ 4, s(struct mount_args),
mount }, /* 21 = mount */
{ 2, s(struct unmount_args),
unmount }, /* 22 = unmount */
{ 1, s(struct setuid_args),
setuid }, /* 23 = setuid */
{ 0, 0,
getuid }, /* 24 = getuid */
{ 0, 0,
geteuid }, /* 25 = geteuid */
{ 4, s(struct ptrace_args),
ptrace }, /* 26 = ptrace */
{ 3, s(struct recvmsg_args),
recvmsg }, /* 27 = recvmsg */
{ 3, s(struct sendmsg_args),
sendmsg }, /* 28 = sendmsg */
{ 6, s(struct recvfrom_args),
recvfrom }, /* 29 = recvfrom */
{ 3, s(struct accept_args),
accept }, /* 30 = accept */
{ 3, s(struct getpeername_args),
getpeername }, /* 31 = getpeername */
{ 3, s(struct getsockname_args),
getsockname }, /* 32 = getsockname */
{ 2, s(struct access_args),
access }, /* 33 = access */
{ 2, s(struct chflags_args),
chflags }, /* 34 = chflags */
{ 2, s(struct fchflags_args),
fchflags }, /* 35 = fchflags */
{ 0, 0,
sync }, /* 36 = sync */
{ 2, s(struct kill_args),
kill }, /* 37 = kill */
{ 2, s(struct compat_43_stat_args),
compat_43(stat) }, /* 38 = compat_43 stat */
{ 0, 0,
getppid }, /* 39 = getppid */
{ 2, s(struct compat_43_lstat_args),
compat_43(lstat) }, /* 40 = compat_43 lstat */
{ 1, s(struct dup_args),
dup }, /* 41 = dup */
{ 0, 0,
pipe }, /* 42 = pipe */
{ 0, 0,
getegid }, /* 43 = getegid */
{ 4, s(struct profil_args),
profil }, /* 44 = profil */
#ifdef KTRACE
{ 4, s(struct ktrace_args),
ktrace }, /* 45 = ktrace */
#else
{ 0, 0,
nosys }, /* 45 = unimplemented ktrace */
#endif
{ 3, s(struct sigaction_args),
sigaction }, /* 46 = sigaction */
{ 0, 0,
getgid }, /* 47 = getgid */
{ 2, s(struct sigprocmask_args),
sigprocmask }, /* 48 = sigprocmask */
{ 2, s(struct getlogin_args),
getlogin }, /* 49 = getlogin */
{ 1, s(struct setlogin_args),
setlogin }, /* 50 = setlogin */
{ 1, s(struct acct_args),
acct }, /* 51 = acct */
{ 0, 0,
sigpending }, /* 52 = sigpending */
{ 2, s(struct sigaltstack_args),
sigaltstack }, /* 53 = sigaltstack */
{ 3, s(struct ioctl_args),
ioctl }, /* 54 = ioctl */
{ 1, s(struct reboot_args),
reboot }, /* 55 = reboot */
{ 1, s(struct revoke_args),
revoke }, /* 56 = revoke */
{ 2, s(struct symlink_args),
symlink }, /* 57 = symlink */
{ 3, s(struct readlink_args),
readlink }, /* 58 = readlink */
{ 3, s(struct execve_args),
execve }, /* 59 = execve */
{ 1, s(struct umask_args),
umask }, /* 60 = umask */
{ 1, s(struct chroot_args),
chroot }, /* 61 = chroot */
{ 2, s(struct compat_43_fstat_args),
compat_43(fstat) }, /* 62 = compat_43 fstat */
{ 4, s(struct compat_43_getkerninfo_args),
compat_43(getkerninfo) }, /* 63 = compat_43 getkerninfo */
{ 0, 0,
compat_43(getpagesize) }, /* 64 = compat_43 getpagesize */
{ 2, s(struct msync_args),
msync }, /* 65 = msync */
{ 0, 0,
vfork }, /* 66 = vfork */
{ 0, 0,
nosys }, /* 67 = obsolete vread */
{ 0, 0,
nosys }, /* 68 = obsolete vwrite */
{ 1, s(struct sbrk_args),
sbrk }, /* 69 = sbrk */
{ 1, s(struct sstk_args),
sstk }, /* 70 = sstk */
{ 6, s(struct compat_43_mmap_args),
compat_43(mmap) }, /* 71 = compat_43 mmap */
{ 1, s(struct ovadvise_args),
ovadvise }, /* 72 = vadvise */
{ 2, s(struct munmap_args),
munmap }, /* 73 = munmap */
{ 3, s(struct mprotect_args),
mprotect }, /* 74 = mprotect */
{ 3, s(struct madvise_args),
madvise }, /* 75 = madvise */
{ 0, 0,
nosys }, /* 76 = obsolete vhangup */
{ 0, 0,
nosys }, /* 77 = obsolete vlimit */
{ 3, s(struct mincore_args),
mincore }, /* 78 = mincore */
{ 2, s(struct getgroups_args),
getgroups }, /* 79 = getgroups */
{ 2, s(struct setgroups_args),
setgroups }, /* 80 = setgroups */
{ 0, 0,
getpgrp }, /* 81 = getpgrp */
{ 2, s(struct setpgid_args),
setpgid }, /* 82 = setpgid */
{ 3, s(struct setitimer_args),
setitimer }, /* 83 = setitimer */
{ 0, 0,
compat_43(wait) }, /* 84 = compat_43 wait */
{ 1, s(struct swapon_args),
swapon }, /* 85 = swapon */
{ 2, s(struct getitimer_args),
getitimer }, /* 86 = getitimer */
{ 2, s(struct compat_43_gethostname_args),
compat_43(gethostname) }, /* 87 = compat_43 gethostname */
{ 2, s(struct compat_43_sethostname_args),
compat_43(sethostname) }, /* 88 = compat_43 sethostname */
{ 0, 0,
getdtablesize }, /* 89 = getdtablesize */
{ 2, s(struct dup2_args),
dup2 }, /* 90 = dup2 */
{ 0, 0,
nosys }, /* 91 = unimplemented getdopt */
{ 3, s(struct fcntl_args),
fcntl }, /* 92 = fcntl */
{ 5, s(struct select_args),
select }, /* 93 = select */
{ 0, 0,
nosys }, /* 94 = unimplemented setdopt */
{ 1, s(struct fsync_args),
fsync }, /* 95 = fsync */
{ 3, s(struct setpriority_args),
setpriority }, /* 96 = setpriority */
{ 3, s(struct socket_args),
socket }, /* 97 = socket */
{ 3, s(struct connect_args),
connect }, /* 98 = connect */
{ 3, s(struct compat_43_accept_args),
compat_43(accept) }, /* 99 = compat_43 accept */
{ 2, s(struct getpriority_args),
getpriority }, /* 100 = getpriority */
{ 4, s(struct compat_43_send_args),
compat_43(send) }, /* 101 = compat_43 send */
{ 4, s(struct compat_43_recv_args),
compat_43(recv) }, /* 102 = compat_43 recv */
{ 1, s(struct sigreturn_args),
sigreturn }, /* 103 = sigreturn */
{ 3, s(struct bind_args),
bind }, /* 104 = bind */
{ 5, s(struct setsockopt_args),
setsockopt }, /* 105 = setsockopt */
{ 2, s(struct listen_args),
listen }, /* 106 = listen */
{ 0, 0,
nosys }, /* 107 = obsolete vtimes */
{ 3, s(struct compat_43_sigvec_args),
compat_43(sigvec) }, /* 108 = compat_43 sigvec */
{ 1, s(struct compat_43_sigblock_args),
compat_43(sigblock) }, /* 109 = compat_43 sigblock */
{ 1, s(struct compat_43_sigsetmask_args),
compat_43(sigsetmask) }, /* 110 = compat_43 sigsetmask */
{ 1, s(struct sigsuspend_args),
sigsuspend }, /* 111 = sigsuspend */
{ 2, s(struct compat_43_sigstack_args),
compat_43(sigstack) }, /* 112 = compat_43 sigstack */
{ 3, s(struct compat_43_recvmsg_args),
compat_43(recvmsg) }, /* 113 = compat_43 recvmsg */
{ 3, s(struct compat_43_sendmsg_args),
compat_43(sendmsg) }, /* 114 = compat_43 sendmsg */
#ifdef TRACE
{ 2, s(struct vtrace_args),
vtrace }, /* 115 = vtrace */
#else
{ 0, 0,
nosys }, /* 115 = obsolete vtrace */
#endif
{ 2, s(struct gettimeofday_args),
gettimeofday }, /* 116 = gettimeofday */
{ 2, s(struct getrusage_args),
getrusage }, /* 117 = getrusage */
{ 5, s(struct getsockopt_args),
getsockopt }, /* 118 = getsockopt */
#ifdef vax
{ 1, s(struct resuba_args),
resuba }, /* 119 = resuba */
#else
{ 0, 0,
nosys }, /* 119 = unimplemented resuba */
#endif
{ 3, s(struct readv_args),
readv }, /* 120 = readv */
{ 3, s(struct writev_args),
writev }, /* 121 = writev */
{ 2, s(struct settimeofday_args),
settimeofday }, /* 122 = settimeofday */
{ 3, s(struct fchown_args),
fchown }, /* 123 = fchown */
{ 2, s(struct fchmod_args),
fchmod }, /* 124 = fchmod */
{ 6, s(struct compat_43_recvfrom_args),
compat_43(recvfrom) }, /* 125 = compat_43 recvfrom */
{ 2, s(struct compat_43_setreuid_args),
compat_43(setreuid) }, /* 126 = compat_43 setreuid */
{ 2, s(struct compat_43_setregid_args),
compat_43(setregid) }, /* 127 = compat_43 setregid */
{ 2, s(struct rename_args),
rename }, /* 128 = rename */
{ 2, s(struct compat_43_truncate_args),
compat_43(truncate) }, /* 129 = compat_43 truncate */
{ 2, s(struct compat_43_ftruncate_args),
compat_43(ftruncate) }, /* 130 = compat_43 ftruncate */
{ 2, s(struct flock_args),
flock }, /* 131 = flock */
{ 2, s(struct mkfifo_args),
mkfifo }, /* 132 = mkfifo */
{ 6, s(struct sendto_args),
sendto }, /* 133 = sendto */
{ 2, s(struct shutdown_args),
shutdown }, /* 134 = shutdown */
{ 4, s(struct socketpair_args),
socketpair }, /* 135 = socketpair */
{ 2, s(struct mkdir_args),
mkdir }, /* 136 = mkdir */
{ 1, s(struct rmdir_args),
rmdir }, /* 137 = rmdir */
{ 2, s(struct utimes_args),
utimes }, /* 138 = utimes */
{ 0, 0,
nosys }, /* 139 = obsolete 4.2 sigreturn */
{ 2, s(struct adjtime_args),
adjtime }, /* 140 = adjtime */
{ 3, s(struct compat_43_getpeername_args),
compat_43(getpeername) }, /* 141 = compat_43 getpeername */
{ 0, 0,
compat_43(gethostid) }, /* 142 = compat_43 gethostid */
{ 1, s(struct compat_43_sethostid_args),
compat_43(sethostid) }, /* 143 = compat_43 sethostid */
{ 2, s(struct compat_43_getrlimit_args),
compat_43(getrlimit) }, /* 144 = compat_43 getrlimit */
{ 2, s(struct compat_43_setrlimit_args),
compat_43(setrlimit) }, /* 145 = compat_43 setrlimit */
{ 2, s(struct compat_43_killpg_args),
compat_43(killpg) }, /* 146 = compat_43 killpg */
{ 0, 0,
setsid }, /* 147 = setsid */
{ 4, s(struct quotactl_args),
quotactl }, /* 148 = quotactl */
{ 0, 0,
compat_43(quota) }, /* 149 = compat_43 quota */
{ 3, s(struct compat_43_getsockname_args),
compat_43(getsockname) }, /* 150 = compat_43 getsockname */
{ 0, 0,
nosys }, /* 151 = unimplemented */
{ 0, 0,
nosys }, /* 152 = unimplemented */
{ 0, 0,
nosys }, /* 153 = unimplemented */
{ 0, 0,
nosys }, /* 154 = unimplemented */
#ifdef NFS
{ 2, s(struct nfssvc_args),
nfssvc }, /* 155 = nfssvc */
#else
{ 0, 0,
nosys }, /* 155 = unimplemented nfssvc */
#endif
{ 4, s(struct compat_43_getdirentries_args),
compat_43(getdirentries) }, /* 156 = compat_43 getdirentries */
{ 2, s(struct statfs_args),
statfs }, /* 157 = statfs */
{ 2, s(struct fstatfs_args),
fstatfs }, /* 158 = fstatfs */
{ 0, 0,
nosys }, /* 159 = unimplemented */
{ 0, 0,
nosys }, /* 160 = unimplemented */
#ifdef NFS
{ 2, s(struct getfh_args),
getfh }, /* 161 = getfh */
#else
{ 0, 0,
nosys }, /* 161 = unimplemented getfh */
#endif
{ 0, 0,
nosys }, /* 162 = unimplemented getdomainname */
{ 0, 0,
nosys }, /* 163 = unimplemented setdomainname */
{ 0, 0,
nosys }, /* 164 = unimplemented */
{ 0, 0,
nosys }, /* 165 = unimplemented */
{ 0, 0,
nosys }, /* 166 = unimplemented */
{ 0, 0,
nosys }, /* 167 = unimplemented */
{ 0, 0,
nosys }, /* 168 = unimplemented */
{ 0, 0,
nosys }, /* 169 = unimplemented semsys */
{ 0, 0,
nosys }, /* 170 = unimplemented msgsys */
#if defined(SYSVSHM) && !defined(alpha)
{ 4, s(struct compat_43_shmsys_args),
compat_43(shmsys) }, /* 171 = compat_43 shmsys */
#else
{ 0, 0,
nosys }, /* 171 = unimplemented shmsys */
#endif
{ 0, 0,
nosys }, /* 172 = unimplemented */
{ 0, 0,
nosys }, /* 173 = unimplemented */
{ 0, 0,
nosys }, /* 174 = unimplemented */
{ 0, 0,
nosys }, /* 175 = unimplemented */
{ 0, 0,
nosys }, /* 176 = unimplemented */
{ 0, 0,
nosys }, /* 177 = unimplemented */
{ 0, 0,
nosys }, /* 178 = unimplemented */
{ 0, 0,
nosys }, /* 179 = unimplemented */
{ 0, 0,
nosys }, /* 180 = unimplemented */
{ 1, s(struct setgid_args),
setgid }, /* 181 = setgid */
{ 1, s(struct setegid_args),
setegid }, /* 182 = setegid */
{ 1, s(struct seteuid_args),
seteuid }, /* 183 = seteuid */
#ifdef LFS
{ 3, s(struct lfs_bmapv_args),
lfs_bmapv }, /* 184 = lfs_bmapv */
{ 3, s(struct lfs_markv_args),
lfs_markv }, /* 185 = lfs_markv */
{ 2, s(struct lfs_segclean_args),
lfs_segclean }, /* 186 = lfs_segclean */
{ 2, s(struct lfs_segwait_args),
lfs_segwait }, /* 187 = lfs_segwait */
#else
{ 0, 0,
nosys }, /* 184 = unimplemented lfs_bmapv */
{ 0, 0,
nosys }, /* 185 = unimplemented lfs_markv */
{ 0, 0,
nosys }, /* 186 = unimplemented lfs_segclean */
{ 0, 0,
nosys }, /* 187 = unimplemented lfs_segwait */
#endif
{ 2, s(struct stat_args),
stat }, /* 188 = stat */
{ 2, s(struct fstat_args),
fstat }, /* 189 = fstat */
{ 2, s(struct lstat_args),
lstat }, /* 190 = lstat */
{ 2, s(struct pathconf_args),
pathconf }, /* 191 = pathconf */
{ 2, s(struct fpathconf_args),
fpathconf }, /* 192 = fpathconf */
{ 0, 0,
nosys }, /* 193 = unimplemented */
{ 2, s(struct getrlimit_args),
getrlimit }, /* 194 = getrlimit */
{ 2, s(struct setrlimit_args),
setrlimit }, /* 195 = setrlimit */
{ 4, s(struct getdirentries_args),
getdirentries }, /* 196 = getdirentries */
{ 7, s(struct mmap_args),
mmap }, /* 197 = mmap */
{ 0, 0,
nosys }, /* 198 = __syscall */
{ 4, s(struct lseek_args),
lseek }, /* 199 = lseek */
{ 3, s(struct truncate_args),
truncate }, /* 200 = truncate */
{ 3, s(struct ftruncate_args),
ftruncate }, /* 201 = ftruncate */
{ 6, s(struct __sysctl_args),
__sysctl }, /* 202 = __sysctl */
{ 2, s(struct mlock_args),
mlock }, /* 203 = mlock */
{ 2, s(struct munlock_args),
munlock }, /* 204 = munlock */
{ 1, s(struct undelete_args),
undelete }, /* 205 = undelete */
{ 0, 0,
nosys }, /* 206 = unimplemented */
{ 0, 0,
nosys }, /* 207 = unimplemented */
{ 0, 0,
nosys }, /* 208 = unimplemented */
{ 0, 0,
nosys }, /* 209 = unimplemented */
{ 0, 0,
nosys }, /* 210 = unimplemented */
{ 0, 0,
nosys }, /* 211 = unimplemented */
{ 0, 0,
nosys }, /* 212 = unimplemented */
{ 0, 0,
nosys }, /* 213 = unimplemented */
{ 0, 0,
nosys }, /* 214 = unimplemented */
{ 0, 0,
nosys }, /* 215 = unimplemented */
{ 0, 0,
nosys }, /* 216 = unimplemented */
{ 0, 0,
nosys }, /* 217 = unimplemented */
{ 0, 0,
nosys }, /* 218 = unimplemented */
{ 0, 0,
nosys }, /* 219 = unimplemented */
{ 0, 0,
nosys }, /* 220 = unimplemented semctl */
{ 0, 0,
nosys }, /* 221 = unimplemented semget */
{ 0, 0,
nosys }, /* 222 = unimplemented semop */
{ 0, 0,
nosys }, /* 223 = unimplemented semconfig */
{ 0, 0,
nosys }, /* 224 = unimplemented msgctl */
{ 0, 0,
nosys }, /* 225 = unimplemented msgget */
{ 0, 0,
nosys }, /* 226 = unimplemented msgsnd */
{ 0, 0,
nosys }, /* 227 = unimplemented msgrcv */
#if defined(SYSVSHM) && 0
{ 3, s(struct shmat_args),
shmat }, /* 228 = shmat */
{ 3, s(struct shmctl_args),
shmctl }, /* 229 = shmctl */
{ 1, s(struct shmdt_args),
shmdt }, /* 230 = shmdt */
{ 3, s(struct shmget_args),
shmget }, /* 231 = shmget */
#else
{ 0, 0,
nosys }, /* 228 = unimplemented shmat */
{ 0, 0,
nosys }, /* 229 = unimplemented shmctl */
{ 0, 0,
nosys }, /* 230 = unimplemented shmdt */
{ 0, 0,
nosys }, /* 231 = unimplemented shmget */
#endif
};
int nsysent= sizeof(sysent) / sizeof(sysent[0]);

127
sys/kern/kern_acct.c Normal file
View File

@ -0,0 +1,127 @@
/*-
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)kern_acct.c 8.8 (Berkeley) 5/14/95
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/syslog.h>
#include <sys/kernel.h>
acct(a1, a2, a3)
struct proc *a1;
struct acct_args /* {
syscallarg(char *) path;
} */ *a2;
int *a3;
{
/*
* Body deleted.
*/
return (ENOSYS);
}
acct_process(a1)
struct proc *a1;
{
/*
* Body deleted.
*/
return;
}
/*
* Periodically check the file system to see if accounting
* should be turned on or off. Beware the case where the vnode
* has been vgone()'d out from underneath us, e.g. when the file
* system containing the accounting file has been forcibly unmounted.
*/
/*
* Values associated with enabling and disabling accounting
*/
int acctsuspend = 2; /* stop accounting when < 2% free space left */
int acctresume = 4; /* resume when free space risen to > 4% */
int acctchkfreq = 15; /* frequency (in seconds) to check space */
/*
* SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
*/
struct vnode *acctp;
struct vnode *savacctp;
/* ARGSUSED */
void
acctwatch(a)
void *a;
{
struct statfs sb;
if (savacctp) {
if (savacctp->v_type == VBAD) {
(void) vn_close(savacctp, FWRITE, NOCRED, NULL);
savacctp = NULL;
return;
}
(void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
acctp = savacctp;
savacctp = NULL;
log(LOG_NOTICE, "Accounting resumed\n");
}
} else {
if (acctp == NULL)
return;
if (acctp->v_type == VBAD) {
(void) vn_close(acctp, FWRITE, NOCRED, NULL);
acctp = NULL;
return;
}
(void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
savacctp = acctp;
acctp = NULL;
log(LOG_NOTICE, "Accounting suspended\n");
}
}
timeout(acctwatch, NULL, acctchkfreq * hz);
}

930
sys/kern/kern_descrip.c Normal file
View File

@ -0,0 +1,930 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/filedesc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/unistd.h>
#include <sys/resourcevar.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
/*
* Descriptor management.
*/
struct filelist filehead; /* head of list of open files */
int nfiles; /* actual number of open files */
/*
* System calls on descriptors.
*/
/* ARGSUSED */
int
getdtablesize(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
return (0);
}
/*
* Duplicate a file descriptor.
*/
/* ARGSUSED */
int
dup(p, uap, retval)
struct proc *p;
struct dup_args /* {
syscallarg(u_int) fd;
} */ *uap;
register_t *retval;
{
register struct filedesc *fdp;
u_int old;
int new, error;
old = SCARG(uap, fd);
/*
* XXX Compatibility
*/
if (old &~ 077) {
SCARG(uap, fd) &= 077;
return (dup2(p, uap, retval));
}
fdp = p->p_fd;
if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
return (EBADF);
if (error = fdalloc(p, 0, &new))
return (error);
return (finishdup(fdp, (int)old, new, retval));
}
/*
* Duplicate a file descriptor to a particular value.
*/
/* ARGSUSED */
int
dup2(p, uap, retval)
struct proc *p;
struct dup2_args /* {
syscallarg(u_int) from;
syscallarg(u_int) to;
} */ *uap;
register_t *retval;
{
register struct filedesc *fdp = p->p_fd;
register int old = SCARG(uap, from), new = SCARG(uap, to);
int i, error;
if (old >= fdp->fd_nfiles ||
fdp->fd_ofiles[old] == NULL ||
new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
new >= maxfiles)
return (EBADF);
if (old == new) {
*retval = new;
return (0);
}
if (new >= fdp->fd_nfiles) {
if (error = fdalloc(p, new, &i))
return (error);
if (new != i)
panic("dup2: fdalloc");
} else if (fdp->fd_ofiles[new]) {
if (fdp->fd_ofileflags[new] & UF_MAPPED)
(void) munmapfd(p, new);
/*
* dup2() must succeed even if the close has an error.
*/
(void) closef(fdp->fd_ofiles[new], p);
}
return (finishdup(fdp, (int)old, (int)new, retval));
}
/*
* The file control system call.
*/
/* ARGSUSED */
int
fcntl(p, uap, retval)
struct proc *p;
register struct fcntl_args /* {
syscallarg(int) fd;
syscallarg(int) cmd;
syscallarg(void *) arg;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
register char *pop;
struct vnode *vp;
int i, tmp, error, flg = F_POSIX;
struct flock fl;
u_int newmin;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
pop = &fdp->fd_ofileflags[fd];
switch (SCARG(uap, cmd)) {
case F_DUPFD:
newmin = (long)SCARG(uap, arg);
if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
newmin >= maxfiles)
return (EINVAL);
if (error = fdalloc(p, newmin, &i))
return (error);
return (finishdup(fdp, fd, i, retval));
case F_GETFD:
*retval = *pop & 1;
return (0);
case F_SETFD:
*pop = (*pop &~ 1) | ((long)SCARG(uap, arg) & 1);
return (0);
case F_GETFL:
*retval = OFLAGS(fp->f_flag);
return (0);
case F_SETFL:
fp->f_flag &= ~FCNTLFLAGS;
fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
tmp = fp->f_flag & FNONBLOCK;
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
if (error)
return (error);
tmp = fp->f_flag & FASYNC;
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
if (!error)
return (0);
fp->f_flag &= ~FNONBLOCK;
tmp = 0;
(void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
return (error);
case F_GETOWN:
if (fp->f_type == DTYPE_SOCKET) {
*retval = ((struct socket *)fp->f_data)->so_pgid;
return (0);
}
error = (*fp->f_ops->fo_ioctl)
(fp, TIOCGPGRP, (caddr_t)retval, p);
*retval = -*retval;
return (error);
case F_SETOWN:
if (fp->f_type == DTYPE_SOCKET) {
((struct socket *)fp->f_data)->so_pgid =
(long)SCARG(uap, arg);
return (0);
}
if ((long)SCARG(uap, arg) <= 0) {
SCARG(uap, arg) = (void *)(-(long)SCARG(uap, arg));
} else {
struct proc *p1 = pfind((long)SCARG(uap, arg));
if (p1 == 0)
return (ESRCH);
SCARG(uap, arg) = (void *)(long)p1->p_pgrp->pg_id;
}
return ((*fp->f_ops->fo_ioctl)
(fp, TIOCSPGRP, (caddr_t)&SCARG(uap, arg), p));
case F_SETLKW:
flg |= F_WAIT;
/* Fall into F_SETLK */
case F_SETLK:
if (fp->f_type != DTYPE_VNODE)
return (EBADF);
vp = (struct vnode *)fp->f_data;
/* Copy in the lock structure */
error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
sizeof (fl));
if (error)
return (error);
if (fl.l_whence == SEEK_CUR)
fl.l_start += fp->f_offset;
switch (fl.l_type) {
case F_RDLCK:
if ((fp->f_flag & FREAD) == 0)
return (EBADF);
p->p_flag |= P_ADVLOCK;
return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
case F_WRLCK:
if ((fp->f_flag & FWRITE) == 0)
return (EBADF);
p->p_flag |= P_ADVLOCK;
return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
case F_UNLCK:
return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
F_POSIX));
default:
return (EINVAL);
}
case F_GETLK:
if (fp->f_type != DTYPE_VNODE)
return (EBADF);
vp = (struct vnode *)fp->f_data;
/* Copy in the lock structure */
error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
sizeof (fl));
if (error)
return (error);
if (fl.l_whence == SEEK_CUR)
fl.l_start += fp->f_offset;
if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
return (error);
return (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg),
sizeof (fl)));
default:
return (EINVAL);
}
/* NOTREACHED */
}
/*
* Common code for dup, dup2, and fcntl(F_DUPFD).
*/
int
finishdup(fdp, old, new, retval)
register struct filedesc *fdp;
register int old, new;
register_t *retval;
{
register struct file *fp;
fp = fdp->fd_ofiles[old];
fdp->fd_ofiles[new] = fp;
fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
fp->f_count++;
if (new > fdp->fd_lastfile)
fdp->fd_lastfile = new;
*retval = new;
return (0);
}
/*
* Close a file descriptor.
*/
/* ARGSUSED */
int
close(p, uap, retval)
struct proc *p;
struct close_args /* {
syscallarg(int) fd;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
register u_char *pf;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
pf = (u_char *)&fdp->fd_ofileflags[fd];
if (*pf & UF_MAPPED)
(void) munmapfd(p, fd);
fdp->fd_ofiles[fd] = NULL;
while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
fdp->fd_lastfile--;
if (fd < fdp->fd_freefile)
fdp->fd_freefile = fd;
*pf = 0;
return (closef(fp, p));
}
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
/*
* Return status information about a file descriptor.
*/
/* ARGSUSED */
int
compat_43_fstat(p, uap, retval)
struct proc *p;
register struct compat_43_fstat_args /* {
syscallarg(int) fd;
syscallarg(struct ostat *) sb;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
struct stat ub;
struct ostat oub;
int error;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
switch (fp->f_type) {
case DTYPE_VNODE:
error = vn_stat((struct vnode *)fp->f_data, &ub, p);
break;
case DTYPE_SOCKET:
error = soo_stat((struct socket *)fp->f_data, &ub);
break;
default:
panic("ofstat");
/*NOTREACHED*/
}
cvtstat(&ub, &oub);
if (error == 0)
error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
sizeof (oub));
return (error);
}
#endif /* COMPAT_43 || COMPAT_SUNOS */
/*
* Return status information about a file descriptor.
*/
/* ARGSUSED */
int
fstat(p, uap, retval)
struct proc *p;
register struct fstat_args /* {
syscallarg(int) fd;
syscallarg(struct stat *) sb;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
struct stat ub;
int error;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
switch (fp->f_type) {
case DTYPE_VNODE:
error = vn_stat((struct vnode *)fp->f_data, &ub, p);
break;
case DTYPE_SOCKET:
error = soo_stat((struct socket *)fp->f_data, &ub);
break;
default:
panic("fstat");
/*NOTREACHED*/
}
if (error == 0)
error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
sizeof (ub));
return (error);
}
/*
* Return pathconf information about a file descriptor.
*/
/* ARGSUSED */
int
fpathconf(p, uap, retval)
struct proc *p;
register struct fpathconf_args /* {
syscallarg(int) fd;
syscallarg(int) name;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
struct filedesc *fdp = p->p_fd;
struct file *fp;
struct vnode *vp;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
switch (fp->f_type) {
case DTYPE_SOCKET:
if (SCARG(uap, name) != _PC_PIPE_BUF)
return (EINVAL);
*retval = PIPE_BUF;
return (0);
case DTYPE_VNODE:
vp = (struct vnode *)fp->f_data;
return (VOP_PATHCONF(vp, SCARG(uap, name), retval));
default:
panic("fpathconf");
}
/*NOTREACHED*/
}
/*
* Allocate a file descriptor for the process.
*/
int fdexpand;
int
fdalloc(p, want, result)
struct proc *p;
int want;
int *result;
{
register struct filedesc *fdp = p->p_fd;
register int i;
int lim, last, nfiles;
struct file **newofile;
char *newofileflags;
/*
* Search for a free descriptor starting at the higher
* of want or fd_freefile. If that fails, consider
* expanding the ofile array.
*/
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
for (;;) {
last = min(fdp->fd_nfiles, lim);
if ((i = want) < fdp->fd_freefile)
i = fdp->fd_freefile;
for (; i < last; i++) {
if (fdp->fd_ofiles[i] == NULL) {
fdp->fd_ofileflags[i] = 0;
if (i > fdp->fd_lastfile)
fdp->fd_lastfile = i;
if (want <= fdp->fd_freefile)
fdp->fd_freefile = i;
*result = i;
return (0);
}
}
/*
* No space in current array. Expand?
*/
if (fdp->fd_nfiles >= lim)
return (EMFILE);
if (fdp->fd_nfiles < NDEXTENT)
nfiles = NDEXTENT;
else
nfiles = 2 * fdp->fd_nfiles;
MALLOC(newofile, struct file **, nfiles * OFILESIZE,
M_FILEDESC, M_WAITOK);
newofileflags = (char *) &newofile[nfiles];
/*
* Copy the existing ofile and ofileflags arrays
* and zero the new portion of each array.
*/
bcopy(fdp->fd_ofiles, newofile,
(i = sizeof(struct file *) * fdp->fd_nfiles));
bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
bcopy(fdp->fd_ofileflags, newofileflags,
(i = sizeof(char) * fdp->fd_nfiles));
bzero(newofileflags + i, nfiles * sizeof(char) - i);
if (fdp->fd_nfiles > NDFILE)
FREE(fdp->fd_ofiles, M_FILEDESC);
fdp->fd_ofiles = newofile;
fdp->fd_ofileflags = newofileflags;
fdp->fd_nfiles = nfiles;
fdexpand++;
}
}
/*
* Check to see whether n user file descriptors
* are available to the process p.
*/
int
fdavail(p, n)
struct proc *p;
register int n;
{
register struct filedesc *fdp = p->p_fd;
register struct file **fpp;
register int i, lim;
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
return (1);
fpp = &fdp->fd_ofiles[fdp->fd_freefile];
for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
if (*fpp == NULL && --n <= 0)
return (1);
return (0);
}
/*
* 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;
int *resultfd;
{
register struct file *fp, *fq;
int error, i;
if (error = fdalloc(p, 0, &i))
return (error);
if (nfiles >= maxfiles) {
tablefull("file");
return (ENFILE);
}
/*
* Allocate a new file descriptor.
* If the process has file descriptor zero open, add to the list
* of open files at that point, otherwise put it at the front of
* the list of open files.
*/
nfiles++;
MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
bzero(fp, sizeof(struct file));
if (fq = p->p_fd->fd_ofiles[0]) {
LIST_INSERT_AFTER(fq, fp, f_list);
} else {
LIST_INSERT_HEAD(&filehead, fp, f_list);
}
p->p_fd->fd_ofiles[i] = fp;
fp->f_count = 1;
fp->f_cred = p->p_ucred;
crhold(fp->f_cred);
if (resultfp)
*resultfp = fp;
if (resultfd)
*resultfd = i;
return (0);
}
/*
* Free a file descriptor.
*/
void
ffree(fp)
register struct file *fp;
{
register struct file *fq;
LIST_REMOVE(fp, f_list);
crfree(fp->f_cred);
#ifdef DIAGNOSTIC
fp->f_count = 0;
#endif
nfiles--;
FREE(fp, M_FILE);
}
/*
* Copy a filedesc structure.
*/
struct filedesc *
fdcopy(p)
struct proc *p;
{
register struct filedesc *newfdp, *fdp = p->p_fd;
register struct file **fpp;
register int i;
MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
M_FILEDESC, M_WAITOK);
bcopy(fdp, newfdp, sizeof(struct filedesc));
VREF(newfdp->fd_cdir);
if (newfdp->fd_rdir)
VREF(newfdp->fd_rdir);
newfdp->fd_refcnt = 1;
/*
* If the number of open files fits in the internal arrays
* of the open file structure, use them, otherwise allocate
* additional memory for the number of descriptors currently
* in use.
*/
if (newfdp->fd_lastfile < NDFILE) {
newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
newfdp->fd_ofileflags =
((struct filedesc0 *) newfdp)->fd_dfileflags;
i = NDFILE;
} else {
/*
* Compute the smallest multiple of NDEXTENT needed
* for the file descriptors currently in use,
* allowing the table to shrink.
*/
i = newfdp->fd_nfiles;
while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
i /= 2;
MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
M_FILEDESC, M_WAITOK);
newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
}
newfdp->fd_nfiles = i;
bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
fpp = newfdp->fd_ofiles;
for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
if (*fpp != NULL)
(*fpp)->f_count++;
return (newfdp);
}
/*
* Release a filedesc structure.
*/
void
fdfree(p)
struct proc *p;
{
register struct filedesc *fdp = p->p_fd;
struct file **fpp;
register int i;
if (--fdp->fd_refcnt > 0)
return;
fpp = fdp->fd_ofiles;
for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
if (*fpp)
(void) closef(*fpp, p);
if (fdp->fd_nfiles > NDFILE)
FREE(fdp->fd_ofiles, M_FILEDESC);
vrele(fdp->fd_cdir);
if (fdp->fd_rdir)
vrele(fdp->fd_rdir);
FREE(fdp, M_FILEDESC);
}
/*
* Internal form of close.
* Decrement reference count on file structure.
* Note: p may be NULL when closing a file
* that was being passed in a message.
*/
int
closef(fp, p)
register struct file *fp;
register struct proc *p;
{
struct vnode *vp;
struct flock lf;
int error;
if (fp == NULL)
return (0);
/*
* POSIX record locking dictates that any close releases ALL
* locks owned by this process. This is handled by setting
* a flag in the unlock to free ONLY locks obeying POSIX
* semantics, and not to free BSD-style file locks.
* If the descriptor was in a message, POSIX-style locks
* aren't passed with the descriptor.
*/
if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_UNLCK;
vp = (struct vnode *)fp->f_data;
(void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
}
if (--fp->f_count > 0)
return (0);
if (fp->f_count < 0)
panic("closef: count < 0");
if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_UNLCK;
vp = (struct vnode *)fp->f_data;
(void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
}
if (fp->f_ops)
error = (*fp->f_ops->fo_close)(fp, p);
else
error = 0;
ffree(fp);
return (error);
}
/*
* Apply an advisory lock on a file descriptor.
*
* Just attempt to get a record lock of the requested type on
* the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
*/
/* ARGSUSED */
int
flock(p, uap, retval)
struct proc *p;
register struct flock_args /* {
syscallarg(int) fd;
syscallarg(int) how;
} */ *uap;
register_t *retval;
{
int fd = SCARG(uap, fd);
int how = SCARG(uap, how);
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
struct vnode *vp;
struct flock lf;
if ((u_int)fd >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
if (fp->f_type != DTYPE_VNODE)
return (EOPNOTSUPP);
vp = (struct vnode *)fp->f_data;
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
if (how & LOCK_UN) {
lf.l_type = F_UNLCK;
fp->f_flag &= ~FHASLOCK;
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
}
if (how & LOCK_EX)
lf.l_type = F_WRLCK;
else if (how & LOCK_SH)
lf.l_type = F_RDLCK;
else
return (EBADF);
fp->f_flag |= FHASLOCK;
if (how & LOCK_NB)
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
}
/*
* File Descriptor pseudo-device driver (/dev/fd/).
*
* Opening minor device N dup()s the file (if any) connected to file
* descriptor N belonging to the calling process. Note that this driver
* consists of only the ``open()'' routine, because all subsequent
* references to this file will be direct to the other driver.
*/
/* ARGSUSED */
int
fdopen(dev, mode, type, p)
dev_t dev;
int mode, type;
struct proc *p;
{
/*
* XXX Kludge: set curproc->p_dupfd to contain the value of the
* the file descriptor being sought for duplication. The error
* return ensures that the vnode for this device will be released
* by vn_open. Open will detect this special error and take the
* actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
* will simply report the error.
*/
p->p_dupfd = minor(dev);
return (ENODEV);
}
/*
* Duplicate the specified descriptor to a free descriptor.
*/
int
dupfdopen(fdp, indx, dfd, mode, error)
register struct filedesc *fdp;
register int indx, dfd;
int mode;
int error;
{
register struct file *wfp;
struct file *fp;
/*
* If the to-be-dup'd fd number is greater than the allowed number
* of file descriptors, or the fd to be dup'd has already been
* closed, reject. Note, check for new == old is necessary as
* falloc could allocate an already closed to-be-dup'd descriptor
* as the new descriptor.
*/
fp = fdp->fd_ofiles[indx];
if ((u_int)dfd >= fdp->fd_nfiles ||
(wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
return (EBADF);
/*
* There are two cases of interest here.
*
* For ENODEV simply dup (dfd) to file descriptor
* (indx) and return.
*
* For ENXIO steal away the file structure from (dfd) and
* store it in (indx). (dfd) is effectively closed by
* this operation.
*
* Any other error code is just returned.
*/
switch (error) {
case ENODEV:
/*
* Check that the mode the file is being opened for is a
* subset of the mode of the existing descriptor.
*/
if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
return (EACCES);
fdp->fd_ofiles[indx] = wfp;
fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
wfp->f_count++;
if (indx > fdp->fd_lastfile)
fdp->fd_lastfile = indx;
return (0);
case ENXIO:
/*
* Steal away the file pointer from dfd, and stuff it into indx.
*/
fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
fdp->fd_ofiles[dfd] = NULL;
fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
fdp->fd_ofileflags[dfd] = 0;
/*
* Complete the clean up of the filedesc structure by
* recomputing the various hints.
*/
if (indx > fdp->fd_lastfile)
fdp->fd_lastfile = indx;
else
while (fdp->fd_lastfile > 0 &&
fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
fdp->fd_lastfile--;
if (dfd < fdp->fd_freefile)
fdp->fd_freefile = dfd;
return (0);
default:
return (error);
}
/* NOTREACHED */
}

453
sys/kern/kern_exit.c Normal file
View File

@ -0,0 +1,453 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_exit.c 8.10 (Berkeley) 2/23/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <sys/vnode.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/resourcevar.h>
#include <sys/ptrace.h>
#include <machine/cpu.h>
#ifdef COMPAT_43
#include <machine/reg.h>
#include <machine/psl.h>
#endif
#include <vm/vm.h>
#include <vm/vm_kern.h>
__dead void cpu_exit __P((struct proc *));
__dead void exit1 __P((struct proc *, int));
/*
* exit --
* Death of process.
*/
struct rexit_args {
int rval;
};
__dead void
exit(p, uap, retval)
struct proc *p;
struct rexit_args *uap;
int *retval;
{
exit1(p, W_EXITCODE(uap->rval, 0));
/* NOTREACHED */
}
/*
* Exit: deallocate address space and other resources, change proc state
* to zombie, and unlink proc from allproc and parent's lists. Save exit
* status and rusage for wait(). Check for child processes and orphan them.
*/
__dead void
exit1(p, rv)
register struct proc *p;
int rv;
{
register struct proc *q, *nq;
register struct proc **pp;
register struct vmspace *vm;
if (p->p_pid == 1)
panic("init died (signal %d, exit %d)",
WTERMSIG(rv), WEXITSTATUS(rv));
#ifdef PGINPROF
vmsizmon();
#endif
if (p->p_flag & P_PROFIL)
stopprofclock(p);
MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
M_ZOMBIE, M_WAITOK);
/*
* If parent is waiting for us to exit or exec,
* P_PPWAIT is set; we will wakeup the parent below.
*/
p->p_flag &= ~(P_TRACED | P_PPWAIT);
p->p_flag |= P_WEXIT;
p->p_sigignore = ~0;
p->p_siglist = 0;
untimeout(realitexpire, (caddr_t)p);
/*
* Close open files and release open-file table.
* This may block!
*/
fdfree(p);
/* The next two chunks should probably be moved to vmspace_exit. */
vm = p->p_vmspace;
#ifdef SYSVSHM
if (vm->vm_shm)
shmexit(p);
#endif
/*
* Release user portion of address space.
* This releases references to vnodes,
* which could cause I/O if the file has been unlinked.
* Need to do this early enough that we can still sleep.
* Can't free the entire vmspace as the kernel stack
* may be mapped within that space also.
*/
if (vm->vm_refcnt == 1)
(void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS);
if (SESS_LEADER(p)) {
register struct session *sp = p->p_session;
if (sp->s_ttyvp) {
/*
* Controlling process.
* Signal foreground pgrp,
* drain controlling terminal
* and revoke access to controlling terminal.
*/
if (sp->s_ttyp->t_session == sp) {
if (sp->s_ttyp->t_pgrp)
pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
(void) ttywait(sp->s_ttyp);
/*
* The tty could have been revoked
* if we blocked.
*/
if (sp->s_ttyvp)
VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
}
if (sp->s_ttyvp)
vrele(sp->s_ttyvp);
sp->s_ttyvp = NULL;
/*
* s_ttyp is not zero'd; we use this to indicate
* that the session once had a controlling terminal.
* (for logging and informational purposes)
*/
}
sp->s_leader = NULL;
}
fixjobc(p, p->p_pgrp, 0);
p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
(void)acct_process(p);
#ifdef KTRACE
/*
* release trace file
*/
p->p_traceflag = 0; /* don't trace the vrele() */
if (p->p_tracep)
vrele(p->p_tracep);
#endif
/*
* Remove proc from allproc queue and pidhash chain.
* Place onto zombproc. Unlink from parent's child list.
*/
LIST_REMOVE(p, p_list);
LIST_INSERT_HEAD(&zombproc, p, p_list);
p->p_stat = SZOMB;
LIST_REMOVE(p, p_hash);
q = p->p_children.lh_first;
if (q) /* only need this if any child is S_ZOMB */
wakeup((caddr_t) initproc);
for (; q != 0; q = nq) {
nq = q->p_sibling.le_next;
LIST_REMOVE(q, p_sibling);
LIST_INSERT_HEAD(&initproc->p_children, q, p_sibling);
q->p_pptr = initproc;
/*
* Traced processes are killed
* since their existence means someone is screwing up.
*/
if (q->p_flag & P_TRACED) {
q->p_flag &= ~P_TRACED;
psignal(q, SIGKILL);
}
}
/*
* Save exit status and final rusage info, adding in child rusage
* info and self times.
*/
p->p_xstat = rv;
*p->p_ru = p->p_stats->p_ru;
calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
ruadd(p->p_ru, &p->p_stats->p_cru);
/*
* Notify parent that we're gone.
*/
psignal(p->p_pptr, SIGCHLD);
wakeup((caddr_t)p->p_pptr);
#if defined(tahoe)
/* move this to cpu_exit */
p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
#endif
/*
* Clear curproc after we've done all operations
* that could block, and before tearing down the rest
* of the process state that might be used from clock, etc.
* Also, can't clear curproc while we're still runnable,
* as we're not on a run queue (we are current, just not
* a proper proc any longer!).
*
* Other substructures are freed from wait().
*/
curproc = NULL;
if (--p->p_limit->p_refcnt == 0)
FREE(p->p_limit, M_SUBPROC);
/*
* 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)";
* This is machine-dependent, as we may have to change stacks
* or ensure that the current one isn't reallocated before we
* finish. cpu_exit will end with a call to cpu_swtch(), finishing
* our execution (pun intended).
*/
cpu_exit(p);
}
struct wait_args {
int pid;
int *status;
int options;
struct rusage *rusage;
#ifdef COMPAT_43
int compat; /* pseudo */
#endif
};
#ifdef COMPAT_43
#if defined(hp300) || defined(luna68k)
#include <machine/frame.h>
#define GETPS(rp) ((struct frame *)(rp))->f_sr
#else
#define GETPS(rp) (rp)[PS]
#endif
compat_43_wait(p, uap, retval)
struct proc *p;
register struct wait_args *uap;
int *retval;
{
#ifdef PSL_ALLCC
if ((GETPS(p->p_md.md_regs) & PSL_ALLCC) != PSL_ALLCC) {
uap->options = 0;
uap->rusage = NULL;
} else {
uap->options = p->p_md.md_regs[R0];
uap->rusage = (struct rusage *)p->p_md.md_regs[R1];
}
#else
uap->options = 0;
uap->rusage = NULL;
#endif
uap->pid = WAIT_ANY;
uap->status = NULL;
uap->compat = 1;
return (wait1(p, uap, retval));
}
wait4(p, uap, retval)
struct proc *p;
struct wait_args *uap;
int *retval;
{
uap->compat = 0;
return (wait1(p, uap, retval));
}
#else
#define wait1 wait4
#endif
int
wait1(q, uap, retval)
register struct proc *q;
register struct wait_args *uap;
int retval[];
{
register int nfound;
register struct proc *p, *t;
int status, error;
if (uap->pid == 0)
uap->pid = -q->p_pgid;
#ifdef notyet
if (uap->options &~ (WUNTRACED|WNOHANG))
return (EINVAL);
#endif
loop:
nfound = 0;
for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) {
if (uap->pid != WAIT_ANY &&
p->p_pid != uap->pid && p->p_pgid != -uap->pid)
continue;
nfound++;
if (p->p_stat == SZOMB) {
retval[0] = p->p_pid;
#ifdef COMPAT_43
if (uap->compat)
retval[1] = p->p_xstat;
else
#endif
if (uap->status) {
status = p->p_xstat; /* convert to int */
if (error = copyout((caddr_t)&status,
(caddr_t)uap->status, sizeof(status)))
return (error);
}
if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
(caddr_t)uap->rusage, sizeof (struct rusage))))
return (error);
/*
* If we got the child via a ptrace 'attach',
* we need to give it back to the old parent.
*/
if (p->p_oppid && (t = pfind(p->p_oppid))) {
p->p_oppid = 0;
proc_reparent(p, t);
psignal(t, SIGCHLD);
wakeup((caddr_t)t);
return (0);
}
p->p_xstat = 0;
ruadd(&q->p_stats->p_cru, p->p_ru);
FREE(p->p_ru, M_ZOMBIE);
/*
* Decrement the count of procs running with this uid.
*/
(void)chgproccnt(p->p_cred->p_ruid, -1);
/*
* Free up credentials.
*/
if (--p->p_cred->p_refcnt == 0) {
crfree(p->p_cred->pc_ucred);
FREE(p->p_cred, M_SUBPROC);
}
/*
* Release reference to text vnode
*/
if (p->p_textvp)
vrele(p->p_textvp);
/*
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
*/
leavepgrp(p);
LIST_REMOVE(p, p_list); /* off zombproc */
LIST_REMOVE(p, p_sibling);
/*
* Give machine-dependent layer a chance
* to free anything that cpu_exit couldn't
* release while still running in process context.
*/
cpu_wait(p);
FREE(p, M_PROC);
nprocs--;
return (0);
}
if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
(p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
p->p_flag |= P_WAITED;
retval[0] = p->p_pid;
#ifdef COMPAT_43
if (uap->compat) {
retval[1] = W_STOPCODE(p->p_xstat);
error = 0;
} else
#endif
if (uap->status) {
status = W_STOPCODE(p->p_xstat);
error = copyout((caddr_t)&status,
(caddr_t)uap->status, sizeof(status));
} else
error = 0;
return (error);
}
}
if (nfound == 0)
return (ECHILD);
if (uap->options & WNOHANG) {
retval[0] = 0;
return (0);
}
if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
return (error);
goto loop;
}
/*
* make process 'parent' the new parent of process 'child'.
*/
void
proc_reparent(child, parent)
register struct proc *child;
register struct proc *parent;
{
if (child->p_pptr == parent)
return;
LIST_REMOVE(child, p_sibling);
LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
child->p_pptr = parent;
}

287
sys/kern/kern_fork.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_fork.c 8.8 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/filedesc.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/acct.h>
#include <sys/ktrace.h>
/* ARGSUSED */
fork(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
return (fork1(p, 0, retval));
}
/* ARGSUSED */
vfork(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
return (fork1(p, 1, retval));
}
int nprocs = 1; /* process 0 */
fork1(p1, isvfork, retval)
register struct proc *p1;
int isvfork;
register_t *retval;
{
register struct proc *p2;
register uid_t uid;
struct proc *newproc;
struct proc **hash;
int count;
static int nextpid, pidchecked = 0;
/*
* Although process entries are dynamically created, we still keep
* a global limit on the maximum number we will create. Don't allow
* a nonprivileged user to use the last process; don't let root
* exceed the limit. The variable nprocs is the current number of
* processes, maxproc is the limit.
*/
uid = p1->p_cred->p_ruid;
if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) {
tablefull("proc");
return (EAGAIN);
}
/*
* Increment the count of procs running with this uid. Don't allow
* a nonprivileged user to exceed their current limit.
*/
count = chgproccnt(uid, 1);
if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) {
(void)chgproccnt(uid, -1);
return (EAGAIN);
}
/* Allocate new proc. */
MALLOC(newproc, struct proc *, sizeof(struct proc), M_PROC, M_WAITOK);
/*
* Find an unused process ID. We remember a range of unused IDs
* ready to use (from nextpid+1 through pidchecked-1).
*/
nextpid++;
retry:
/*
* If the process ID prototype has wrapped around,
* restart somewhat above 0, as the low-numbered procs
* tend to include daemons that don't exit.
*/
if (nextpid >= PID_MAX) {
nextpid = 100;
pidchecked = 0;
}
if (nextpid >= pidchecked) {
int doingzomb = 0;
pidchecked = PID_MAX;
/*
* Scan the active and zombie procs to check whether this pid
* is in use. Remember the lowest pid that's greater
* than nextpid, so we can avoid checking for a while.
*/
p2 = allproc.lh_first;
again:
for (; p2 != 0; p2 = p2->p_list.le_next) {
while (p2->p_pid == nextpid ||
p2->p_pgrp->pg_id == nextpid) {
nextpid++;
if (nextpid >= pidchecked)
goto retry;
}
if (p2->p_pid > nextpid && pidchecked > p2->p_pid)
pidchecked = p2->p_pid;
if (p2->p_pgrp->pg_id > nextpid &&
pidchecked > p2->p_pgrp->pg_id)
pidchecked = p2->p_pgrp->pg_id;
}
if (!doingzomb) {
doingzomb = 1;
p2 = zombproc.lh_first;
goto again;
}
}
nprocs++;
p2 = newproc;
p2->p_stat = SIDL; /* protect against others */
p2->p_pid = nextpid;
LIST_INSERT_HEAD(&allproc, p2, p_list);
p2->p_forw = p2->p_back = NULL; /* shouldn't be necessary */
LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
/*
* 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.
*/
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));
/*
* Duplicate sub-structures as needed.
* Increase reference counts on shared objects.
* The p_stats and p_sigacts substructs are set in vm_fork.
*/
p2->p_flag = P_INMEM;
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
MALLOC(p2->p_cred, struct pcred *, sizeof(struct pcred),
M_SUBPROC, M_WAITOK);
bcopy(p1->p_cred, p2->p_cred, sizeof(*p2->p_cred));
p2->p_cred->p_refcnt = 1;
crhold(p1->p_ucred);
/* bump references to the text vnode (for procfs) */
p2->p_textvp = p1->p_textvp;
if (p2->p_textvp)
VREF(p2->p_textvp);
p2->p_fd = fdcopy(p1);
/*
* If p_limit is still copy-on-write, bump refcnt,
* otherwise get a copy that won't be modified.
* (If PL_SHAREMOD is clear, the structure is shared
* copy-on-write.)
*/
if (p1->p_limit->p_lflags & PL_SHAREMOD)
p2->p_limit = limcopy(p1->p_limit);
else {
p2->p_limit = p1->p_limit;
p2->p_limit->p_refcnt++;
}
if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
p2->p_flag |= P_CONTROLT;
if (isvfork)
p2->p_flag |= P_PPWAIT;
LIST_INSERT_AFTER(p1, p2, p_pglist);
p2->p_pptr = p1;
LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
LIST_INIT(&p2->p_children);
#ifdef KTRACE
/*
* Copy traceflag and tracefile if enabled.
* If not inherited, these were zeroed above.
*/
if (p1->p_traceflag&KTRFAC_INHERIT) {
p2->p_traceflag = p1->p_traceflag;
if ((p2->p_tracep = p1->p_tracep) != NULL)
VREF(p2->p_tracep);
}
#endif
/*
* This begins the section where we must prevent the parent
* from being swapped.
*/
p1->p_flag |= P_NOSWAP;
/*
* Set return values for child before vm_fork,
* so they can be copied to child stack.
* We return parent pid, and mark as child in retval[1].
* NOTE: the kernel stack may be at a different location in the child
* process, and thus addresses of automatic variables (including retval)
* may be invalid after vm_fork returns in the child process.
*/
retval[0] = p1->p_pid;
retval[1] = 1;
if (vm_fork(p1, p2, isvfork)) {
/*
* Child process. Set start time and get to work.
*/
(void) splclock();
p2->p_stats->p_start = time;
(void) spl0();
p2->p_acflag = AFORK;
return (0);
}
/*
* Make child runnable and add to run queue.
*/
(void) splhigh();
p2->p_stat = SRUN;
setrunqueue(p2);
(void) spl0();
/*
* Now can be swapped.
*/
p1->p_flag &= ~P_NOSWAP;
/*
* Preserve synchronization semantics of vfork. If waiting for
* child to exec or exit, set P_PPWAIT on child, and sleep on our
* proc (in case of exit).
*/
if (isvfork)
while (p2->p_flag & P_PPWAIT)
tsleep(p1, PWAIT, "ppwait", 0);
/*
* Return child pid to parent process,
* marking us as parent via retval[1].
*/
retval[0] = p2->p_pid;
retval[1] = 0;
return (0);
}

475
sys/kern/kern_ktrace.c Normal file
View File

@ -0,0 +1,475 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. 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 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.
*
* @(#)kern_ktrace.c 8.5 (Berkeley) 5/14/95
*/
#ifdef KTRACE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/ktrace.h>
#include <sys/malloc.h>
#include <sys/syslog.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
struct ktr_header *
ktrgetheader(type)
int type;
{
register struct ktr_header *kth;
struct proc *p = curproc; /* XXX */
MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
M_TEMP, M_WAITOK);
kth->ktr_type = type;
microtime(&kth->ktr_time);
kth->ktr_pid = p->p_pid;
bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
return (kth);
}
void
ktrsyscall(vp, code, argsize, args)
struct vnode *vp;
int code, argsize;
register_t args[];
{
struct ktr_header *kth;
struct ktr_syscall *ktp;
register len = sizeof(struct ktr_syscall) + argsize;
struct proc *p = curproc; /* XXX */
register_t *argp;
int i;
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_SYSCALL);
MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK);
ktp->ktr_code = code;
ktp->ktr_argsize = argsize;
argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
for (i = 0; i < (argsize / sizeof *argp); i++)
*argp++ = args[i];
kth->ktr_buf = (caddr_t)ktp;
kth->ktr_len = len;
ktrwrite(vp, kth);
FREE(ktp, M_TEMP);
FREE(kth, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
void
ktrsysret(vp, code, error, retval)
struct vnode *vp;
int code, error, retval;
{
struct ktr_header *kth;
struct ktr_sysret ktp;
struct proc *p = curproc; /* XXX */
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_SYSRET);
ktp.ktr_code = code;
ktp.ktr_error = error;
ktp.ktr_retval = retval; /* what about val2 ? */
kth->ktr_buf = (caddr_t)&ktp;
kth->ktr_len = sizeof(struct ktr_sysret);
ktrwrite(vp, kth);
FREE(kth, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
void
ktrnamei(vp, path)
struct vnode *vp;
char *path;
{
struct ktr_header *kth;
struct proc *p = curproc; /* XXX */
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_NAMEI);
kth->ktr_len = strlen(path);
kth->ktr_buf = path;
ktrwrite(vp, kth);
FREE(kth, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
void
ktrgenio(vp, fd, rw, iov, len, error)
struct vnode *vp;
int fd;
enum uio_rw rw;
register struct iovec *iov;
int len, error;
{
struct ktr_header *kth;
register struct ktr_genio *ktp;
register caddr_t cp;
register int resid = len, cnt;
struct proc *p = curproc; /* XXX */
if (error)
return;
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_GENIO);
MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len,
M_TEMP, M_WAITOK);
ktp->ktr_fd = fd;
ktp->ktr_rw = rw;
cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
while (resid > 0) {
if ((cnt = iov->iov_len) > resid)
cnt = resid;
if (copyin(iov->iov_base, cp, (unsigned)cnt))
goto done;
cp += cnt;
resid -= cnt;
iov++;
}
kth->ktr_buf = (caddr_t)ktp;
kth->ktr_len = sizeof (struct ktr_genio) + len;
ktrwrite(vp, kth);
done:
FREE(kth, M_TEMP);
FREE(ktp, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
void
ktrpsig(vp, sig, action, mask, code)
struct vnode *vp;
int sig;
sig_t action;
int mask, code;
{
struct ktr_header *kth;
struct ktr_psig kp;
struct proc *p = curproc; /* XXX */
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_PSIG);
kp.signo = (char)sig;
kp.action = action;
kp.mask = mask;
kp.code = code;
kth->ktr_buf = (caddr_t)&kp;
kth->ktr_len = sizeof (struct ktr_psig);
ktrwrite(vp, kth);
FREE(kth, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
void
ktrcsw(vp, out, user)
struct vnode *vp;
int out, user;
{
struct ktr_header *kth;
struct ktr_csw kc;
struct proc *p = curproc; /* XXX */
p->p_traceflag |= KTRFAC_ACTIVE;
kth = ktrgetheader(KTR_CSW);
kc.out = out;
kc.user = user;
kth->ktr_buf = (caddr_t)&kc;
kth->ktr_len = sizeof (struct ktr_csw);
ktrwrite(vp, kth);
FREE(kth, M_TEMP);
p->p_traceflag &= ~KTRFAC_ACTIVE;
}
/* Interface and common routines */
/*
* ktrace system call
*/
/* ARGSUSED */
int
ktrace(curp, uap, retval)
struct proc *curp;
register struct ktrace_args /* {
syscallarg(char *) fname;
syscallarg(int) ops;
syscallarg(int) facs;
syscallarg(int) pid;
} */ *uap;
register_t *retval;
{
register struct vnode *vp = NULL;
register struct proc *p;
struct pgrp *pg;
int facs = SCARG(uap, facs) & ~KTRFAC_ROOT;
int ops = KTROP(SCARG(uap, ops));
int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
int ret = 0;
int error = 0;
struct nameidata nd;
curp->p_traceflag |= KTRFAC_ACTIVE;
if (ops != KTROP_CLEAR) {
/*
* an operation which requires a file argument.
*/
NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
curp);
if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
curp->p_traceflag &= ~KTRFAC_ACTIVE;
return (error);
}
vp = nd.ni_vp;
VOP_UNLOCK(vp, 0, p);
if (vp->v_type != VREG) {
(void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
curp->p_traceflag &= ~KTRFAC_ACTIVE;
return (EACCES);
}
}
/*
* Clear all uses of the tracefile
*/
if (ops == KTROP_CLEARFILE) {
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
if (p->p_tracep == vp) {
if (ktrcanset(curp, p)) {
p->p_tracep = NULL;
p->p_traceflag = 0;
(void) vn_close(vp, FREAD|FWRITE,
p->p_ucred, p);
} else
error = EPERM;
}
}
goto done;
}
/*
* need something to (un)trace (XXX - why is this here?)
*/
if (!facs) {
error = EINVAL;
goto done;
}
/*
* do it
*/
if (SCARG(uap, pid) < 0) {
/*
* by process group
*/
pg = pgfind(-SCARG(uap, pid));
if (pg == NULL) {
error = ESRCH;
goto done;
}
for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next)
if (descend)
ret |= ktrsetchildren(curp, p, ops, facs, vp);
else
ret |= ktrops(curp, p, ops, facs, vp);
} else {
/*
* by pid
*/
p = pfind(SCARG(uap, pid));
if (p == NULL) {
error = ESRCH;
goto done;
}
if (descend)
ret |= ktrsetchildren(curp, p, ops, facs, vp);
else
ret |= ktrops(curp, p, ops, facs, vp);
}
if (!ret)
error = EPERM;
done:
if (vp != NULL)
(void) vn_close(vp, FWRITE, curp->p_ucred, curp);
curp->p_traceflag &= ~KTRFAC_ACTIVE;
return (error);
}
int
ktrops(curp, p, ops, facs, vp)
struct proc *p, *curp;
int ops, facs;
struct vnode *vp;
{
if (!ktrcanset(curp, p))
return (0);
if (ops == KTROP_SET) {
if (p->p_tracep != vp) {
/*
* if trace file already in use, relinquish
*/
if (p->p_tracep != NULL)
vrele(p->p_tracep);
VREF(vp);
p->p_tracep = vp;
}
p->p_traceflag |= facs;
if (curp->p_ucred->cr_uid == 0)
p->p_traceflag |= KTRFAC_ROOT;
} else {
/* KTROP_CLEAR */
if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
/* no more tracing */
p->p_traceflag = 0;
if (p->p_tracep != NULL) {
vrele(p->p_tracep);
p->p_tracep = NULL;
}
}
}
return (1);
}
ktrsetchildren(curp, top, ops, facs, vp)
struct proc *curp, *top;
int ops, facs;
struct vnode *vp;
{
register struct proc *p;
register int ret = 0;
p = top;
for (;;) {
ret |= ktrops(curp, p, ops, facs, vp);
/*
* If this process has children, descend to them next,
* otherwise do any siblings, and if done with this level,
* follow back up the tree (but not past top).
*/
if (p->p_children.lh_first)
p = p->p_children.lh_first;
else for (;;) {
if (p == top)
return (ret);
if (p->p_sibling.le_next) {
p = p->p_sibling.le_next;
break;
}
p = p->p_pptr;
}
}
/*NOTREACHED*/
}
ktrwrite(vp, kth)
struct vnode *vp;
register struct ktr_header *kth;
{
struct uio auio;
struct iovec aiov[2];
register struct proc *p = curproc; /* XXX */
int error;
if (vp == NULL)
return;
auio.uio_iov = &aiov[0];
auio.uio_offset = 0;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_WRITE;
aiov[0].iov_base = (caddr_t)kth;
aiov[0].iov_len = sizeof(struct ktr_header);
auio.uio_resid = sizeof(struct ktr_header);
auio.uio_iovcnt = 1;
auio.uio_procp = (struct proc *)0;
if (kth->ktr_len > 0) {
auio.uio_iovcnt++;
aiov[1].iov_base = kth->ktr_buf;
aiov[1].iov_len = kth->ktr_len;
auio.uio_resid += kth->ktr_len;
}
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
VOP_UNLOCK(vp, 0, p);
if (!error)
return;
/*
* If error encountered, give up tracing on this vnode.
*/
log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
error);
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
if (p->p_tracep == vp) {
p->p_tracep = NULL;
p->p_traceflag = 0;
vrele(vp);
}
}
}
/*
* Return true if caller has permission to set the ktracing state
* of target. Essentially, the target can't possess any
* more permissions than the caller. KTRFAC_ROOT signifies that
* root previously set the tracing status on the target process, and
* so, only root may further change it.
*
* TODO: check groups. use caller effective gid.
*/
ktrcanset(callp, targetp)
struct proc *callp, *targetp;
{
register struct pcred *caller = callp->p_cred;
register struct pcred *target = targetp->p_cred;
if ((caller->pc_ucred->cr_uid == target->p_ruid &&
target->p_ruid == target->p_svuid &&
caller->p_rgid == target->p_rgid && /* XXX */
target->p_rgid == target->p_svgid &&
(targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
caller->pc_ucred->cr_uid == 0)
return (1);
return (0);
}
#endif

396
sys/kern/kern_malloc.c Normal file
View File

@ -0,0 +1,396 @@
/*
* Copyright (c) 1987, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/map.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <vm/vm.h>
#include <vm/vm_kern.h>
struct kmembuckets bucket[MINBUCKET + 16];
struct kmemstats kmemstats[M_LAST];
struct kmemusage *kmemusage;
char *kmembase, *kmemlimit;
char *memname[] = INITKMEMNAMES;
#ifdef DIAGNOSTIC
/*
* This structure provides a set of masks to catch unaligned frees.
*/
long addrmask[] = { 0,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
};
/*
* The WEIRD_ADDR is used as known text to copy into free objects so
* that modifications after frees can be detected.
*/
#define WEIRD_ADDR 0xdeadbeef
#define MAX_COPY 32
/*
* Normally the first word of the structure is used to hold the list
* pointer for free objects. However, when running with diagnostics,
* we use the third and fourth fields, so as to catch modifications
* in the most commonly trashed first two words.
*/
struct freelist {
long spare0;
short type;
long spare1;
caddr_t next;
};
#else /* !DIAGNOSTIC */
struct freelist {
caddr_t next;
};
#endif /* DIAGNOSTIC */
/*
* Allocate a block of memory
*/
void *
malloc(size, type, flags)
unsigned long size;
int type, flags;
{
register struct kmembuckets *kbp;
register struct kmemusage *kup;
register struct freelist *freep;
long indx, npg, allocsize;
int s;
caddr_t va, cp, savedlist;
#ifdef DIAGNOSTIC
long *end, *lp;
int copysize;
char *savedtype;
#endif
#ifdef DEBUG
extern int simplelockrecurse;
#endif
#ifdef KMEMSTATS
register struct kmemstats *ksp = &kmemstats[type];
if (((unsigned long)type) > M_LAST)
panic("malloc - bogus type");
#endif
indx = BUCKETINDX(size);
kbp = &bucket[indx];
s = splimp();
#ifdef KMEMSTATS
while (ksp->ks_memuse >= ksp->ks_limit) {
if (flags & M_NOWAIT) {
splx(s);
return ((void *) NULL);
}
if (ksp->ks_limblocks < 65535)
ksp->ks_limblocks++;
tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
}
ksp->ks_size |= 1 << indx;
#endif
#ifdef DIAGNOSTIC
copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
#endif
#ifdef DEBUG
if (flags & M_NOWAIT)
simplelockrecurse++;
#endif
if (kbp->kb_next == NULL) {
kbp->kb_last = NULL;
if (size > MAXALLOCSAVE)
allocsize = roundup(size, CLBYTES);
else
allocsize = 1 << indx;
npg = clrnd(btoc(allocsize));
va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg),
!(flags & M_NOWAIT));
if (va == NULL) {
splx(s);
#ifdef DEBUG
if (flags & M_NOWAIT)
simplelockrecurse--;
#endif
return ((void *) NULL);
}
#ifdef KMEMSTATS
kbp->kb_total += kbp->kb_elmpercl;
#endif
kup = btokup(va);
kup->ku_indx = indx;
if (allocsize > MAXALLOCSAVE) {
if (npg > 65535)
panic("malloc: allocation too large");
kup->ku_pagecnt = npg;
#ifdef KMEMSTATS
ksp->ks_memuse += allocsize;
#endif
goto out;
}
#ifdef KMEMSTATS
kup->ku_freecnt = kbp->kb_elmpercl;
kbp->kb_totalfree += kbp->kb_elmpercl;
#endif
/*
* Just in case we blocked while allocating memory,
* and someone else also allocated memory for this
* bucket, don't assume the list is still empty.
*/
savedlist = kbp->kb_next;
kbp->kb_next = cp = va + (npg * NBPG) - allocsize;
for (;;) {
freep = (struct freelist *)cp;
#ifdef DIAGNOSTIC
/*
* Copy in known text to detect modification
* after freeing.
*/
end = (long *)&cp[copysize];
for (lp = (long *)cp; lp < end; lp++)
*lp = WEIRD_ADDR;
freep->type = M_FREE;
#endif /* DIAGNOSTIC */
if (cp <= va)
break;
cp -= allocsize;
freep->next = cp;
}
freep->next = savedlist;
if (kbp->kb_last == NULL)
kbp->kb_last = (caddr_t)freep;
}
va = kbp->kb_next;
kbp->kb_next = ((struct freelist *)va)->next;
#ifdef DIAGNOSTIC
freep = (struct freelist *)va;
savedtype = (unsigned)freep->type < M_LAST ?
memname[freep->type] : "???";
if (kbp->kb_next &&
!kernacc(kbp->kb_next, sizeof(struct freelist), 0)) {
printf("%s of object 0x%x size %d %s %s (invalid addr 0x%x)\n",
"Data modified on freelist: word 2.5", va, size,
"previous type", savedtype, kbp->kb_next);
kbp->kb_next = NULL;
}
#if BYTE_ORDER == BIG_ENDIAN
freep->type = WEIRD_ADDR >> 16;
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
freep->type = (short)WEIRD_ADDR;
#endif
if (((long)(&freep->next)) & 0x2)
freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
else
freep->next = (caddr_t)WEIRD_ADDR;
end = (long *)&va[copysize];
for (lp = (long *)va; lp < end; lp++) {
if (*lp == WEIRD_ADDR)
continue;
printf("%s %d of object 0x%x size %d %s %s (0x%x != 0x%x)\n",
"Data modified on freelist: word", lp - (long *)va,
va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
break;
}
freep->spare0 = 0;
#endif /* DIAGNOSTIC */
#ifdef KMEMSTATS
kup = btokup(va);
if (kup->ku_indx != indx)
panic("malloc: wrong bucket");
if (kup->ku_freecnt == 0)
panic("malloc: lost data");
kup->ku_freecnt--;
kbp->kb_totalfree--;
ksp->ks_memuse += 1 << indx;
out:
kbp->kb_calls++;
ksp->ks_inuse++;
ksp->ks_calls++;
if (ksp->ks_memuse > ksp->ks_maxused)
ksp->ks_maxused = ksp->ks_memuse;
#else
out:
#endif
splx(s);
#ifdef DEBUG
if (flags & M_NOWAIT)
simplelockrecurse--;
#endif
return ((void *) va);
}
/*
* Free a block of memory allocated by malloc.
*/
void
free(addr, type)
void *addr;
int type;
{
register struct kmembuckets *kbp;
register struct kmemusage *kup;
register struct freelist *freep;
long size;
int s;
#ifdef DIAGNOSTIC
caddr_t cp;
long *end, *lp, alloc, copysize;
#endif
#ifdef KMEMSTATS
register struct kmemstats *ksp = &kmemstats[type];
#endif
kup = btokup(addr);
size = 1 << kup->ku_indx;
kbp = &bucket[kup->ku_indx];
s = splimp();
#ifdef DIAGNOSTIC
/*
* Check for returns of data that do not point to the
* beginning of the allocation.
*/
if (size > NBPG * CLSIZE)
alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)];
else
alloc = addrmask[kup->ku_indx];
if (((u_long)addr & alloc) != 0)
panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n",
addr, size, memname[type], alloc);
#endif /* DIAGNOSTIC */
if (size > MAXALLOCSAVE) {
kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
#ifdef KMEMSTATS
size = kup->ku_pagecnt << PGSHIFT;
ksp->ks_memuse -= size;
kup->ku_indx = 0;
kup->ku_pagecnt = 0;
if (ksp->ks_memuse + size >= ksp->ks_limit &&
ksp->ks_memuse < ksp->ks_limit)
wakeup((caddr_t)ksp);
ksp->ks_inuse--;
kbp->kb_total -= 1;
#endif
splx(s);
return;
}
freep = (struct freelist *)addr;
#ifdef DIAGNOSTIC
/*
* Check for multiple frees. Use a quick check to see if
* it looks free before laboriously searching the freelist.
*/
if (freep->spare0 == WEIRD_ADDR) {
for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) {
if (addr != cp)
continue;
printf("multiply freed item 0x%x\n", addr);
panic("free: duplicated free");
}
}
/*
* Copy in known text to detect modification after freeing
* and to make it look free. Also, save the type being freed
* so we can list likely culprit if modification is detected
* when the object is reallocated.
*/
copysize = size < MAX_COPY ? size : MAX_COPY;
end = (long *)&((caddr_t)addr)[copysize];
for (lp = (long *)addr; lp < end; lp++)
*lp = WEIRD_ADDR;
freep->type = type;
#endif /* DIAGNOSTIC */
#ifdef KMEMSTATS
kup->ku_freecnt++;
if (kup->ku_freecnt >= kbp->kb_elmpercl)
if (kup->ku_freecnt > kbp->kb_elmpercl)
panic("free: multiple frees");
else if (kbp->kb_totalfree > kbp->kb_highwat)
kbp->kb_couldfree++;
kbp->kb_totalfree++;
ksp->ks_memuse -= size;
if (ksp->ks_memuse + size >= ksp->ks_limit &&
ksp->ks_memuse < ksp->ks_limit)
wakeup((caddr_t)ksp);
ksp->ks_inuse--;
#endif
if (kbp->kb_next == NULL)
kbp->kb_next = addr;
else
((struct freelist *)kbp->kb_last)->next = addr;
freep->next = NULL;
kbp->kb_last = addr;
splx(s);
}
/*
* Initialize the kernel memory allocator
*/
kmeminit()
{
register long indx;
int npg;
#if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
#endif
#if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
ERROR!_kmeminit:_MAXALLOCSAVE_too_big
#endif
#if (MAXALLOCSAVE < CLBYTES)
ERROR!_kmeminit:_MAXALLOCSAVE_too_small
#endif
npg = VM_KMEM_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,
(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE);
#ifdef KMEMSTATS
for (indx = 0; indx < MINBUCKET + 16; indx++) {
if (1 << indx >= CLBYTES)
bucket[indx].kb_elmpercl = 1;
else
bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
}
for (indx = 0; indx < M_LAST; indx++)
kmemstats[indx].ks_limit = npg * NBPG * 6 / 10;
#endif
}

374
sys/kern/kern_proc.c Normal file
View File

@ -0,0 +1,374 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)kern_proc.c 8.7 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/acct.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <ufs/ufs/quota.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
/*
* Structure associated with user cacheing.
*/
struct uidinfo {
LIST_ENTRY(uidinfo) ui_hash;
uid_t ui_uid;
long ui_proccnt;
};
#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
u_long uihash; /* size of hash table - 1 */
/*
* Other process lists
*/
struct pidhashhead *pidhashtbl;
u_long pidhash;
struct pgrphashhead *pgrphashtbl;
u_long pgrphash;
struct proclist allproc;
struct proclist zombproc;
/*
* Initialize global process hashing structures.
*/
void
procinit()
{
LIST_INIT(&allproc);
LIST_INIT(&zombproc);
pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
}
/*
* Change the count associated with number of processes
* a given user is using.
*/
int
chgproccnt(uid, diff)
uid_t uid;
int diff;
{
register struct uidinfo *uip;
register struct uihashhead *uipp;
uipp = UIHASH(uid);
for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
if (uip->ui_uid == uid)
break;
if (uip) {
uip->ui_proccnt += diff;
if (uip->ui_proccnt > 0)
return (uip->ui_proccnt);
if (uip->ui_proccnt < 0)
panic("chgproccnt: procs < 0");
LIST_REMOVE(uip, ui_hash);
FREE(uip, M_PROC);
return (0);
}
if (diff <= 0) {
if (diff == 0)
return(0);
panic("chgproccnt: lost user");
}
MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
LIST_INSERT_HEAD(uipp, uip, ui_hash);
uip->ui_uid = uid;
uip->ui_proccnt = diff;
return (diff);
}
/*
* Is p an inferior of the current process?
*/
inferior(p)
register struct proc *p;
{
for (; p != curproc; p = p->p_pptr)
if (p->p_pid == 0)
return (0);
return (1);
}
/*
* Locate a process by number
*/
struct proc *
pfind(pid)
register pid_t pid;
{
register struct proc *p;
for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
if (p->p_pid == pid)
return (p);
return (NULL);
}
/*
* Locate a process group by number
*/
struct pgrp *
pgfind(pgid)
register pid_t pgid;
{
register struct pgrp *pgrp;
for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0;
pgrp = pgrp->pg_hash.le_next)
if (pgrp->pg_id == pgid)
return (pgrp);
return (NULL);
}
/*
* Move p to a new or existing process group (and session)
*/
int
enterpgrp(p, pgid, mksess)
register struct proc *p;
pid_t pgid;
int mksess;
{
register struct pgrp *pgrp = pgfind(pgid);
#ifdef DIAGNOSTIC
if (pgrp != NULL && mksess) /* firewalls */
panic("enterpgrp: setsid into non-empty pgrp");
if (SESS_LEADER(p))
panic("enterpgrp: session leader attempted setpgrp");
#endif
if (pgrp == NULL) {
pid_t savepid = p->p_pid;
struct proc *np;
/*
* new process group
*/
#ifdef DIAGNOSTIC
if (p->p_pid != pgid)
panic("enterpgrp: new pgrp and pid != pgid");
#endif
MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
M_WAITOK);
if ((np = pfind(savepid)) == NULL || np != p)
return (ESRCH);
if (mksess) {
register struct session *sess;
/*
* new session
*/
MALLOC(sess, struct session *, sizeof(struct session),
M_SESSION, M_WAITOK);
sess->s_leader = p;
sess->s_count = 1;
sess->s_ttyvp = NULL;
sess->s_ttyp = NULL;
bcopy(p->p_session->s_login, sess->s_login,
sizeof(sess->s_login));
p->p_flag &= ~P_CONTROLT;
pgrp->pg_session = sess;
#ifdef DIAGNOSTIC
if (p != curproc)
panic("enterpgrp: mksession and p != curproc");
#endif
} else {
pgrp->pg_session = p->p_session;
pgrp->pg_session->s_count++;
}
pgrp->pg_id = pgid;
LIST_INIT(&pgrp->pg_members);
LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
pgrp->pg_jobc = 0;
} else if (pgrp == p->p_pgrp)
return (0);
/*
* Adjust eligibility of affected pgrps to participate in job control.
* Increment eligibility counts before decrementing, otherwise we
* could reach 0 spuriously during the first call.
*/
fixjobc(p, pgrp, 1);
fixjobc(p, p->p_pgrp, 0);
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
pgdelete(p->p_pgrp);
p->p_pgrp = pgrp;
LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
return (0);
}
/*
* remove process from process group
*/
int
leavepgrp(p)
register struct proc *p;
{
LIST_REMOVE(p, p_pglist);
if (p->p_pgrp->pg_members.lh_first == 0)
pgdelete(p->p_pgrp);
p->p_pgrp = 0;
return (0);
}
/*
* delete a process group
*/
void
pgdelete(pgrp)
register struct pgrp *pgrp;
{
if (pgrp->pg_session->s_ttyp != NULL &&
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
LIST_REMOVE(pgrp, pg_hash);
if (--pgrp->pg_session->s_count == 0)
FREE(pgrp->pg_session, M_SESSION);
FREE(pgrp, M_PGRP);
}
static void orphanpg();
/*
* Adjust pgrp jobc counters when specified process changes process group.
* We count the number of processes in each process group that "qualify"
* the group for terminal job control (those with a parent in a different
* process group of the same session). If that count reaches zero, the
* process group becomes orphaned. Check both the specified process'
* process group and that of its children.
* 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;
int entering;
{
register struct pgrp *hispgrp;
register struct session *mysession = pgrp->pg_session;
/*
* Check p's parent to see whether p qualifies its own process
* group; if so, adjust count for p's process group.
*/
if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession)
if (entering)
pgrp->pg_jobc++;
else if (--pgrp->pg_jobc == 0)
orphanpg(pgrp);
/*
* Check this process' children to see whether they qualify
* their process groups; if so, adjust counts for children's
* process groups.
*/
for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
if ((hispgrp = p->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession &&
p->p_stat != SZOMB)
if (entering)
hispgrp->pg_jobc++;
else if (--hispgrp->pg_jobc == 0)
orphanpg(hispgrp);
}
/*
* A process group has become orphaned;
* if there are any stopped processes in the group,
* hang-up all process in that group.
*/
static void
orphanpg(pg)
struct pgrp *pg;
{
register struct proc *p;
for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
if (p->p_stat == SSTOP) {
for (p = pg->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
psignal(p, SIGHUP);
psignal(p, SIGCONT);
}
return;
}
}
}
#ifdef DEBUG
pgrpdump()
{
register struct pgrp *pgrp;
register struct proc *p;
register i;
for (i = 0; i <= pgrphash; i++) {
if (pgrp = pgrphashtbl[i].lh_first) {
printf("\tindx %d\n", i);
for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
pgrp, pgrp->pg_id, pgrp->pg_session,
pgrp->pg_session->s_count,
pgrp->pg_members.lh_first);
for (p = pgrp->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
printf("\t\tpid %d addr %x pgrp %x\n",
p->p_pid, p, p->p_pgrp);
}
}
}
}
}
#endif /* DEBUG */

601
sys/kern/kern_prot.c Normal file
View File

@ -0,0 +1,601 @@
/*
* Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_prot.c 8.9 (Berkeley) 2/14/95
*/
/*
* System calls related to processes and protection
*/
#include <sys/param.h>
#include <sys/acct.h>
#include <sys/systm.h>
#include <sys/ucred.h>
#include <sys/proc.h>
#include <sys/timeb.h>
#include <sys/times.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
/* ARGSUSED */
int
getpid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pid;
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
retval[1] = p->p_pptr->p_pid;
#endif
return (0);
}
/* ARGSUSED */
int
getppid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pptr->p_pid;
return (0);
}
/* Get process group ID; note that POSIX getpgrp takes no parameter */
int
getpgrp(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_pgrp->pg_id;
return (0);
}
/* ARGSUSED */
int
getuid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_cred->p_ruid;
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
retval[1] = p->p_ucred->cr_uid;
#endif
return (0);
}
/* ARGSUSED */
int
geteuid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_ucred->cr_uid;
return (0);
}
/* ARGSUSED */
int
getgid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_cred->p_rgid;
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
retval[1] = p->p_ucred->cr_groups[0];
#endif
return (0);
}
/*
* Get effective group ID. The "egid" is groups[0], and could be obtained
* via getgroups. This syscall exists because it is somewhat painful to do
* correctly in a library function.
*/
/* ARGSUSED */
int
getegid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*retval = p->p_ucred->cr_groups[0];
return (0);
}
int
getgroups(p, uap, retval)
struct proc *p;
register struct getgroups_args /* {
syscallarg(u_int) gidsetsize;
syscallarg(gid_t *) gidset;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register u_int ngrp;
int error;
if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
*retval = pc->pc_ucred->cr_ngroups;
return (0);
}
if (ngrp < pc->pc_ucred->cr_ngroups)
return (EINVAL);
ngrp = pc->pc_ucred->cr_ngroups;
if (error = copyout((caddr_t)pc->pc_ucred->cr_groups,
(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)))
return (error);
*retval = ngrp;
return (0);
}
/* ARGSUSED */
int
setsid(p, uap, retval)
register struct proc *p;
void *uap;
register_t *retval;
{
if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
return (EPERM);
} else {
(void)enterpgrp(p, p->p_pid, 1);
*retval = p->p_pid;
return (0);
}
}
/*
* set process group (setpgid/old setpgrp)
*
* caller does setpgid(targpid, targpgid)
*
* pid must be caller or child of caller (ESRCH)
* if a child
* pid must be in same session (EPERM)
* pid can't have done an exec (EACCES)
* if pgid != pid
* there must exist some pid in same session having pgid (EPERM)
* pid must not be session leader (EPERM)
*/
/* ARGSUSED */
int
setpgid(curp, uap, retval)
struct proc *curp;
register struct setpgid_args /* {
syscallarg(int) pid;
syscallarg(int) pgid;
} */ *uap;
register_t *retval;
{
register struct proc *targp; /* target process */
register struct pgrp *pgrp; /* target pgrp */
if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
return (ESRCH);
if (targp->p_session != curp->p_session)
return (EPERM);
if (targp->p_flag & P_EXEC)
return (EACCES);
} else
targp = curp;
if (SESS_LEADER(targp))
return (EPERM);
if (SCARG(uap, pgid) == 0)
SCARG(uap, pgid) = targp->p_pid;
else if (SCARG(uap, pgid) != targp->p_pid)
if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
pgrp->pg_session != curp->p_session)
return (EPERM);
return (enterpgrp(targp, SCARG(uap, pgid), 0));
}
/* ARGSUSED */
int
setuid(p, uap, retval)
struct proc *p;
struct setuid_args /* {
syscallarg(uid_t) uid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register uid_t uid;
int error;
uid = SCARG(uap, uid);
if (uid != pc->p_ruid &&
(error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
/*
* Everything's okay, do it.
* Transfer proc count to new user.
* Copy credentials so other references do not see our changes.
*/
(void)chgproccnt(pc->p_ruid, -1);
(void)chgproccnt(uid, 1);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_uid = uid;
pc->p_ruid = uid;
pc->p_svuid = uid;
p->p_flag |= P_SUGID;
return (0);
}
/* ARGSUSED */
int
seteuid(p, uap, retval)
struct proc *p;
struct seteuid_args /* {
syscallarg(uid_t) euid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register uid_t euid;
int error;
euid = SCARG(uap, euid);
if (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.
*/
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_uid = euid;
p->p_flag |= P_SUGID;
return (0);
}
/* ARGSUSED */
int
setgid(p, uap, retval)
struct proc *p;
struct setgid_args /* {
syscallarg(gid_t) gid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register gid_t gid;
int error;
gid = SCARG(uap, gid);
if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
return (error);
pc->pc_ucred = crcopy(pc->pc_ucred);
pc->pc_ucred->cr_groups[0] = gid;
pc->p_rgid = gid;
pc->p_svgid = gid; /* ??? */
p->p_flag |= P_SUGID;
return (0);
}
/* ARGSUSED */
int
setegid(p, uap, retval)
struct proc *p;
struct setegid_args /* {
syscallarg(gid_t) egid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register gid_t egid;
int error;
egid = SCARG(uap, egid);
if (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;
p->p_flag |= P_SUGID;
return (0);
}
/* ARGSUSED */
int
setgroups(p, uap, retval)
struct proc *p;
struct setgroups_args /* {
syscallarg(u_int) gidsetsize;
syscallarg(gid_t *) gidset;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
register u_int ngrp;
int error;
if (error = suser(pc->pc_ucred, &p->p_acflag))
return (error);
ngrp = SCARG(uap, gidsetsize);
if (ngrp < 1 || ngrp > NGROUPS)
return (EINVAL);
pc->pc_ucred = crcopy(pc->pc_ucred);
if (error = copyin((caddr_t)SCARG(uap, gidset),
(caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t)))
return (error);
pc->pc_ucred->cr_ngroups = ngrp;
p->p_flag |= P_SUGID;
return (0);
}
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
/* ARGSUSED */
int
compat_43_setreuid(p, uap, retval)
register struct proc *p;
struct compat_43_setreuid_args /* {
syscallarg(int) ruid;
syscallarg(int) euid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
union {
struct setuid_args sa;
struct seteuid_args ea;
} args;
/*
* If ruid == euid then setreuid is being used to emulate setuid,
* just do it.
*/
if (SCARG(uap, ruid) != -1 && SCARG(uap, ruid) == SCARG(uap, euid)) {
SCARG(&args.sa, uid) = SCARG(uap, ruid);
return (setuid(p, &args.sa, retval));
}
/*
* Otherwise we assume that the intent of setting ruid is to be
* able to get back ruid priviledge (i.e. swapping ruid and euid).
* So we make sure that we will be able to do so, but do not
* actually set the ruid.
*/
if (SCARG(uap, ruid) != (uid_t)-1 && SCARG(uap, ruid) != pc->p_ruid &&
SCARG(uap, ruid) != pc->p_svuid)
return (EPERM);
if (SCARG(uap, euid) == (uid_t)-1)
return (0);
SCARG(&args.ea, euid) = SCARG(uap, euid);
return (seteuid(p, &args.ea, retval));
}
/* ARGSUSED */
int
compat_43_setregid(p, uap, retval)
register struct proc *p;
struct compat_43_setregid_args /* {
syscallarg(int) rgid;
syscallarg(int) egid;
} */ *uap;
register_t *retval;
{
register struct pcred *pc = p->p_cred;
union {
struct setgid_args sa;
struct setegid_args ea;
} args;
/*
* If rgid == egid then setreuid is being used to emulate setgid,
* just do it.
*/
if (SCARG(uap, rgid) != -1 && SCARG(uap, rgid) == SCARG(uap, egid)) {
SCARG(&args.sa, gid) = SCARG(uap, rgid);
return (setgid(p, &args.sa, retval));
}
/*
* Otherwise we assume that the intent of setting rgid is to be
* able to get back rgid priviledge (i.e. swapping rgid and egid).
* So we make sure that we will be able to do so, but do not
* actually set the rgid.
*/
if (SCARG(uap, rgid) != (gid_t)-1 && SCARG(uap, rgid) != pc->p_rgid &&
SCARG(uap, rgid) != pc->p_svgid)
return (EPERM);
if (SCARG(uap, egid) == (gid_t)-1)
return (0);
SCARG(&args.ea, egid) = SCARG(uap, egid);
return (setegid(p, &args.ea, retval));
}
#endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */
/*
* Check if gid is a member of the group set.
*/
int
groupmember(gid, cred)
gid_t gid;
register struct ucred *cred;
{
register gid_t *gp;
gid_t *egp;
egp = &(cred->cr_groups[cred->cr_ngroups]);
for (gp = cred->cr_groups; gp < egp; gp++)
if (*gp == gid)
return (1);
return (0);
}
/*
* Test whether the specified credentials imply "super-user"
* privilege; if so, and we have accounting info, set the flag
* indicating use of super-powers.
* Returns 0 or error.
*/
int
suser(cred, acflag)
struct ucred *cred;
u_short *acflag;
{
if (cred->cr_uid == 0) {
if (acflag)
*acflag |= ASU;
return (0);
}
return (EPERM);
}
/*
* Allocate a zeroed cred structure.
*/
struct ucred *
crget()
{
register struct ucred *cr;
MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
bzero((caddr_t)cr, sizeof(*cr));
cr->cr_ref = 1;
return (cr);
}
/*
* Free a cred structure.
* Throws away space when ref count gets to 0.
*/
void
crfree(cr)
struct ucred *cr;
{
int s;
s = splimp(); /* ??? */
if (--cr->cr_ref == 0)
FREE((caddr_t)cr, M_CRED);
(void) splx(s);
}
/*
* Copy cred structure to a new one and free the old one.
*/
struct ucred *
crcopy(cr)
struct ucred *cr;
{
struct ucred *newcr;
if (cr->cr_ref == 1)
return (cr);
newcr = crget();
*newcr = *cr;
crfree(cr);
newcr->cr_ref = 1;
return (newcr);
}
/*
* Dup cred struct to a new held one.
*/
struct ucred *
crdup(cr)
struct ucred *cr;
{
struct ucred *newcr;
newcr = crget();
*newcr = *cr;
newcr->cr_ref = 1;
return (newcr);
}
/*
* Get login name, if available.
*/
/* ARGSUSED */
int
getlogin(p, uap, retval)
struct proc *p;
struct getlogin_args /* {
syscallarg(char *) namebuf;
syscallarg(u_int) namelen;
} */ *uap;
register_t *retval;
{
if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
(caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
}
/*
* Set login name.
*/
/* ARGSUSED */
int
setlogin(p, uap, retval)
struct proc *p;
struct setlogin_args /* {
syscallarg(char *) namebuf;
} */ *uap;
register_t *retval;
{
int error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
error = copyinstr((caddr_t) SCARG(uap, namebuf),
(caddr_t) p->p_pgrp->pg_session->s_login,
sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
if (error == ENAMETOOLONG)
error = EINVAL;
return (error);
}

489
sys/kern/kern_resource.c Normal file
View File

@ -0,0 +1,489 @@
/*-
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_resource.c 8.8 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/resourcevar.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <vm/vm.h>
int donice __P((struct proc *curp, struct proc *chgp, int n));
int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
/*
* Resource controls and accounting.
*/
int
getpriority(curp, uap, retval)
struct proc *curp;
register struct getpriority_args /* {
syscallarg(int) which;
syscallarg(int) who;
} */ *uap;
register_t *retval;
{
register struct proc *p;
register int low = PRIO_MAX + 1;
switch (SCARG(uap, which)) {
case PRIO_PROCESS:
if (SCARG(uap, who) == 0)
p = curp;
else
p = pfind(SCARG(uap, who));
if (p == 0)
break;
low = p->p_nice;
break;
case PRIO_PGRP: {
register struct pgrp *pg;
if (SCARG(uap, who) == 0)
pg = curp->p_pgrp;
else if ((pg = pgfind(SCARG(uap, who))) == NULL)
break;
for (p = pg->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
if (p->p_nice < low)
low = p->p_nice;
}
break;
}
case PRIO_USER:
if (SCARG(uap, who) == 0)
SCARG(uap, who) = curp->p_ucred->cr_uid;
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
if (p->p_ucred->cr_uid == SCARG(uap, who) &&
p->p_nice < low)
low = p->p_nice;
break;
default:
return (EINVAL);
}
if (low == PRIO_MAX + 1)
return (ESRCH);
*retval = low;
return (0);
}
/* ARGSUSED */
int
setpriority(curp, uap, retval)
struct proc *curp;
register struct setpriority_args /* {
syscallarg(int) which;
syscallarg(int) who;
syscallarg(int) prio;
} */ *uap;
register_t *retval;
{
register struct proc *p;
int found = 0, error = 0;
switch (SCARG(uap, which)) {
case PRIO_PROCESS:
if (SCARG(uap, who) == 0)
p = curp;
else
p = pfind(SCARG(uap, who));
if (p == 0)
break;
error = donice(curp, p, SCARG(uap, prio));
found++;
break;
case PRIO_PGRP: {
register struct pgrp *pg;
if (SCARG(uap, who) == 0)
pg = curp->p_pgrp;
else if ((pg = pgfind(SCARG(uap, who))) == NULL)
break;
for (p = pg->pg_members.lh_first; p != 0;
p = p->p_pglist.le_next) {
error = donice(curp, p, SCARG(uap, prio));
found++;
}
break;
}
case PRIO_USER:
if (SCARG(uap, who) == 0)
SCARG(uap, who) = curp->p_ucred->cr_uid;
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
if (p->p_ucred->cr_uid == SCARG(uap, who)) {
error = donice(curp, p, SCARG(uap, prio));
found++;
}
break;
default:
return (EINVAL);
}
if (found == 0)
return (ESRCH);
return (error);
}
int
donice(curp, chgp, n)
register struct proc *curp, *chgp;
register int n;
{
register struct pcred *pcred = curp->p_cred;
if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
pcred->p_ruid != chgp->p_ucred->cr_uid)
return (EPERM);
if (n > PRIO_MAX)
n = PRIO_MAX;
if (n < PRIO_MIN)
n = PRIO_MIN;
if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
return (EACCES);
chgp->p_nice = n;
(void)resetpriority(chgp);
return (0);
}
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
/* ARGSUSED */
int
compat_43_setrlimit(p, uap, retval)
struct proc *p;
struct compat_43_setrlimit_args /* {
syscallarg(u_int) which;
syscallarg(struct ogetrlimit *) rlp;
} */ *uap;
register_t *retval;
{
struct orlimit olim;
struct rlimit lim;
int error;
if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&olim,
sizeof (struct orlimit)))
return (error);
lim.rlim_cur = olim.rlim_cur;
lim.rlim_max = olim.rlim_max;
return (dosetrlimit(p, SCARG(uap, which), &lim));
}
/* ARGSUSED */
int
compat_43_getrlimit(p, uap, retval)
struct proc *p;
register struct compat_43_getrlimit_args /* {
syscallarg(u_int) which;
syscallarg(struct ogetrlimit *) rlp;
} */ *uap;
register_t *retval;
{
struct orlimit olim;
if (SCARG(uap, which) >= RLIM_NLIMITS)
return (EINVAL);
olim.rlim_cur = p->p_rlimit[SCARG(uap, which)].rlim_cur;
if (olim.rlim_cur == -1)
olim.rlim_cur = 0x7fffffff;
olim.rlim_max = p->p_rlimit[SCARG(uap, which)].rlim_max;
if (olim.rlim_max == -1)
olim.rlim_max = 0x7fffffff;
return (copyout((caddr_t)&olim, (caddr_t)SCARG(uap, rlp),
sizeof(olim)));
}
#endif /* COMPAT_43 || COMPAT_SUNOS */
/* ARGSUSED */
int
setrlimit(p, uap, retval)
struct proc *p;
register struct setrlimit_args /* {
syscallarg(u_int) which;
syscallarg(struct rlimit *) rlp;
} */ *uap;
register_t *retval;
{
struct rlimit alim;
int error;
if (error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
sizeof (struct rlimit)))
return (error);
return (dosetrlimit(p, SCARG(uap, which), &alim));
}
int
dosetrlimit(p, which, limp)
struct proc *p;
u_int which;
struct rlimit *limp;
{
register struct rlimit *alimp;
extern unsigned maxdmap;
int error;
if (which >= RLIM_NLIMITS)
return (EINVAL);
alimp = &p->p_rlimit[which];
if (limp->rlim_cur > alimp->rlim_max ||
limp->rlim_max > alimp->rlim_max)
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (limp->rlim_cur > limp->rlim_max)
limp->rlim_cur = limp->rlim_max;
if (p->p_limit->p_refcnt > 1 &&
(p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
p->p_limit->p_refcnt--;
p->p_limit = limcopy(p->p_limit);
alimp = &p->p_rlimit[which];
}
switch (which) {
case RLIMIT_DATA:
if (limp->rlim_cur > maxdmap)
limp->rlim_cur = maxdmap;
if (limp->rlim_max > maxdmap)
limp->rlim_max = maxdmap;
break;
case RLIMIT_STACK:
if (limp->rlim_cur > maxdmap)
limp->rlim_cur = maxdmap;
if (limp->rlim_max > maxdmap)
limp->rlim_max = maxdmap;
/*
* Stack is allocated to the max at exec time with only
* "rlim_cur" bytes accessible. If stack limit is going
* up make more accessible, if going down make inaccessible.
*/
if (limp->rlim_cur != alimp->rlim_cur) {
vm_offset_t addr;
vm_size_t size;
vm_prot_t prot;
if (limp->rlim_cur > alimp->rlim_cur) {
prot = VM_PROT_ALL;
size = limp->rlim_cur - alimp->rlim_cur;
addr = USRSTACK - limp->rlim_cur;
} else {
prot = VM_PROT_NONE;
size = alimp->rlim_cur - limp->rlim_cur;
addr = USRSTACK - alimp->rlim_cur;
}
addr = trunc_page(addr);
size = round_page(size);
(void) vm_map_protect(&p->p_vmspace->vm_map,
addr, addr+size, prot, FALSE);
}
break;
case RLIMIT_NOFILE:
if (limp->rlim_cur > maxfiles)
limp->rlim_cur = maxfiles;
if (limp->rlim_max > maxfiles)
limp->rlim_max = maxfiles;
break;
case RLIMIT_NPROC:
if (limp->rlim_cur > maxproc)
limp->rlim_cur = maxproc;
if (limp->rlim_max > maxproc)
limp->rlim_max = maxproc;
break;
}
*alimp = *limp;
return (0);
}
/* ARGSUSED */
int
getrlimit(p, uap, retval)
struct proc *p;
register struct getrlimit_args /* {
syscallarg(u_int) which;
syscallarg(struct rlimit *) rlp;
} */ *uap;
register_t *retval;
{
if (SCARG(uap, which) >= RLIM_NLIMITS)
return (EINVAL);
return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
(caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
}
/*
* Transform the running time and tick information in proc p into user,
* system, and interrupt time usage.
*/
void
calcru(p, up, sp, ip)
register struct proc *p;
register struct timeval *up;
register struct timeval *sp;
register struct timeval *ip;
{
register u_quad_t u, st, ut, it, tot;
register u_long sec, usec;
register int s;
struct timeval tv;
s = splstatclock();
st = p->p_sticks;
ut = p->p_uticks;
it = p->p_iticks;
splx(s);
tot = st + ut + it;
if (tot == 0) {
up->tv_sec = up->tv_usec = 0;
sp->tv_sec = sp->tv_usec = 0;
if (ip != NULL)
ip->tv_sec = ip->tv_usec = 0;
return;
}
sec = p->p_rtime.tv_sec;
usec = p->p_rtime.tv_usec;
if (p == curproc) {
/*
* Adjust for the current time slice. This is actually fairly
* important since the error here is on the order of a time
* quantum, which is much greater than the sampling error.
*/
microtime(&tv);
sec += tv.tv_sec - runtime.tv_sec;
usec += tv.tv_usec - runtime.tv_usec;
}
u = sec * 1000000 + usec;
st = (u * st) / tot;
sp->tv_sec = st / 1000000;
sp->tv_usec = st % 1000000;
ut = (u * ut) / tot;
up->tv_sec = ut / 1000000;
up->tv_usec = ut % 1000000;
if (ip != NULL) {
it = (u * it) / tot;
ip->tv_sec = it / 1000000;
ip->tv_usec = it % 1000000;
}
}
/* ARGSUSED */
int
getrusage(p, uap, retval)
register struct proc *p;
register struct getrusage_args /* {
syscallarg(int) who;
syscallarg(struct rusage *) rusage;
} */ *uap;
register_t *retval;
{
register struct rusage *rup;
switch (SCARG(uap, who)) {
case RUSAGE_SELF:
rup = &p->p_stats->p_ru;
calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
break;
case RUSAGE_CHILDREN:
rup = &p->p_stats->p_cru;
break;
default:
return (EINVAL);
}
return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
sizeof (struct rusage)));
}
void
ruadd(ru, ru2)
register struct rusage *ru, *ru2;
{
register long *ip, *ip2;
register int i;
timevaladd(&ru->ru_utime, &ru2->ru_utime);
timevaladd(&ru->ru_stime, &ru2->ru_stime);
if (ru->ru_maxrss < ru2->ru_maxrss)
ru->ru_maxrss = ru2->ru_maxrss;
ip = &ru->ru_first; ip2 = &ru2->ru_first;
for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
*ip++ += *ip2++;
}
/*
* Make a copy of the plimit structure.
* We share these structures copy-on-write after fork,
* and copy when a limit is changed.
*/
struct plimit *
limcopy(lim)
struct plimit *lim;
{
register struct plimit *copy;
MALLOC(copy, struct plimit *, sizeof(struct plimit),
M_SUBPROC, M_WAITOK);
bcopy(lim->pl_rlimit, copy->pl_rlimit,
sizeof(struct rlimit) * RLIM_NLIMITS);
copy->p_lflags = 0;
copy->p_refcnt = 1;
return (copy);
}

1219
sys/kern/kern_sig.c Normal file

File diff suppressed because it is too large Load Diff

215
sys/kern/kern_subr.c Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/queue.h>
int
uiomove(cp, n, uio)
register caddr_t cp;
register int n;
register struct uio *uio;
{
register struct iovec *iov;
u_int cnt;
int error = 0;
#ifdef DIAGNOSTIC
if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
panic("uiomove: mode");
if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
panic("uiomove proc");
#endif
while (n > 0 && uio->uio_resid) {
iov = uio->uio_iov;
cnt = iov->iov_len;
if (cnt == 0) {
uio->uio_iov++;
uio->uio_iovcnt--;
continue;
}
if (cnt > n)
cnt = n;
switch (uio->uio_segflg) {
case UIO_USERSPACE:
case UIO_USERISPACE:
if (uio->uio_rw == UIO_READ)
error = copyout(cp, iov->iov_base, cnt);
else
error = copyin(iov->iov_base, cp, cnt);
if (error)
return (error);
break;
case UIO_SYSSPACE:
if (uio->uio_rw == UIO_READ)
bcopy((caddr_t)cp, iov->iov_base, cnt);
else
bcopy(iov->iov_base, (caddr_t)cp, cnt);
break;
}
iov->iov_base += cnt;
iov->iov_len -= cnt;
uio->uio_resid -= cnt;
uio->uio_offset += cnt;
cp += cnt;
n -= cnt;
}
return (error);
}
/*
* Give next character to user as result of read.
*/
int
ureadc(c, uio)
register int c;
register struct uio *uio;
{
register struct iovec *iov;
if (uio->uio_resid <= 0)
panic("ureadc: non-positive resid");
again:
if (uio->uio_iovcnt <= 0)
panic("ureadc: non-positive iovcnt");
iov = uio->uio_iov;
if (iov->iov_len <= 0) {
uio->uio_iovcnt--;
uio->uio_iov++;
goto again;
}
switch (uio->uio_segflg) {
case UIO_USERSPACE:
if (subyte(iov->iov_base, c) < 0)
return (EFAULT);
break;
case UIO_SYSSPACE:
*iov->iov_base = c;
break;
case UIO_USERISPACE:
if (suibyte(iov->iov_base, c) < 0)
return (EFAULT);
break;
}
iov->iov_base++;
iov->iov_len--;
uio->uio_resid--;
uio->uio_offset++;
return (0);
}
#ifdef vax /* unused except by ct.c, other oddities XXX */
/*
* Get next character written in by user from uio.
*/
int
uwritec(uio)
struct uio *uio;
{
register struct iovec *iov;
register int c;
if (uio->uio_resid <= 0)
return (-1);
again:
if (uio->uio_iovcnt <= 0)
panic("uwritec: non-positive iovcnt");
iov = uio->uio_iov;
if (iov->iov_len == 0) {
uio->uio_iov++;
if (--uio->uio_iovcnt == 0)
return (-1);
goto again;
}
switch (uio->uio_segflg) {
case UIO_USERSPACE:
c = fubyte(iov->iov_base);
break;
case UIO_SYSSPACE:
c = *(u_char *) iov->iov_base;
break;
case UIO_USERISPACE:
c = fuibyte(iov->iov_base);
break;
}
if (c < 0)
return (-1);
iov->iov_base++;
iov->iov_len--;
uio->uio_resid--;
uio->uio_offset++;
return (c);
}
#endif /* vax */
/*
* General routine to allocate a hash table.
*/
void *
hashinit(elements, type, hashmask)
int elements, type;
u_long *hashmask;
{
long hashsize;
LIST_HEAD(generic, generic) *hashtbl;
int i;
if (elements <= 0)
panic("hashinit: bad cnt");
for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
continue;
hashsize >>= 1;
hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
for (i = 0; i < hashsize; i++)
LIST_INIT(&hashtbl[i]);
*hashmask = hashsize - 1;
return (hashtbl);
}

671
sys/kern/kern_synch.c Normal file
View File

@ -0,0 +1,671 @@
/*-
* Copyright (c) 1982, 1986, 1990, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_synch.c 8.9 (Berkeley) 5/19/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/signalvar.h>
#include <sys/resourcevar.h>
#include <sys/vmmeter.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#include <machine/cpu.h>
u_char curpriority; /* usrpri of curproc */
int lbolt; /* once a second sleep address */
/*
* Force switch among equal priority processes every 100ms.
*/
/* ARGSUSED */
void
roundrobin(arg)
void *arg;
{
need_resched();
timeout(roundrobin, NULL, hz / 10);
}
/*
* Constants for digital decay and forget:
* 90% of (p_estcpu) usage in 5 * loadav time
* 95% of (p_pctcpu) usage in 60 seconds (load insensitive)
* Note that, as ps(1) mentions, this can let percentages
* total over 100% (I've seen 137.9% for 3 processes).
*
* Note that hardclock updates p_estcpu and p_cpticks independently.
*
* We wish to decay away 90% of p_estcpu in (5 * loadavg) seconds.
* That is, the system wants to compute a value of decay such
* that the following for loop:
* for (i = 0; i < (5 * loadavg); i++)
* p_estcpu *= decay;
* will compute
* p_estcpu *= 0.1;
* for all values of loadavg:
*
* Mathematically this loop can be expressed by saying:
* decay ** (5 * loadavg) ~= .1
*
* The system computes decay as:
* decay = (2 * loadavg) / (2 * loadavg + 1)
*
* We wish to prove that the system's computation of decay
* will always fulfill the equation:
* decay ** (5 * loadavg) ~= .1
*
* If we compute b as:
* b = 2 * loadavg
* then
* decay = b / (b + 1)
*
* We now need to prove two things:
* 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1)
* 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg)
*
* Facts:
* For x close to zero, exp(x) =~ 1 + x, since
* exp(x) = 0! + x**1/1! + x**2/2! + ... .
* therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b.
* For x close to zero, ln(1+x) =~ x, since
* ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1
* therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1).
* ln(.1) =~ -2.30
*
* Proof of (1):
* Solve (factor)**(power) =~ .1 given power (5*loadav):
* solving for factor,
* ln(factor) =~ (-2.30/5*loadav), or
* factor =~ exp(-1/((5/2.30)*loadav)) =~ exp(-1/(2*loadav)) =
* exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED
*
* Proof of (2):
* Solve (factor)**(power) =~ .1 given factor == (b/(b+1)):
* solving for power,
* power*ln(b/(b+1)) =~ -2.30, or
* power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED
*
* Actual power values for the implemented algorithm are as follows:
* loadav: 1 2 3 4
* power: 5.68 10.32 14.94 19.55
*/
/* calculations for digital decay to forget 90% of usage in 5*loadav sec */
#define loadfactor(loadav) (2 * (loadav))
#define decay_cpu(loadfac, cpu) (((loadfac) * (cpu)) / ((loadfac) + FSCALE))
/* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */
fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */
/*
* If `ccpu' is not equal to `exp(-1/20)' and you still want to use the
* faster/more-accurate formula, you'll have to estimate CCPU_SHIFT below
* and possibly adjust FSHIFT in "param.h" so that (FSHIFT >= CCPU_SHIFT).
*
* To estimate CCPU_SHIFT for exp(-1/20), the following formula was used:
* 1 - exp(-1/20) ~= 0.0487 ~= 0.0488 == 1 (fixed pt, *11* bits).
*
* If you dont want to bother with the faster/more-accurate formula, you
* can set CCPU_SHIFT to (FSHIFT + 1) which will use a slower/less-accurate
* (more general) method of calculating the %age of CPU used by a process.
*/
#define CCPU_SHIFT 11
/*
* Recompute process priorities, every hz ticks.
*/
/* ARGSUSED */
void
schedcpu(arg)
void *arg;
{
register fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
register struct proc *p;
register int s;
register unsigned int newcpu;
wakeup((caddr_t)&lbolt);
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
/*
* Increment time in/out of memory and sleep time
* (if sleeping). We ignore overflow; with 16-bit int's
* (remember them?) overflow takes 45 days.
*/
p->p_swtime++;
if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
p->p_slptime++;
p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
/*
* If the process has slept the entire second,
* stop recalculating its priority until it wakes up.
*/
if (p->p_slptime > 1)
continue;
s = splstatclock(); /* prevent state changes */
/*
* p_pctcpu is only for ps.
*/
#if (FSHIFT >= CCPU_SHIFT)
p->p_pctcpu += (hz == 100)?
((fixpt_t) p->p_cpticks) << (FSHIFT - CCPU_SHIFT):
100 * (((fixpt_t) p->p_cpticks)
<< (FSHIFT - CCPU_SHIFT)) / hz;
#else
p->p_pctcpu += ((FSCALE - ccpu) *
(p->p_cpticks * FSCALE / hz)) >> FSHIFT;
#endif
p->p_cpticks = 0;
newcpu = (u_int) decay_cpu(loadfac, p->p_estcpu) + p->p_nice;
p->p_estcpu = min(newcpu, UCHAR_MAX);
resetpriority(p);
if (p->p_priority >= PUSER) {
#define PPQ (128 / NQS) /* priorities per queue */
if ((p != curproc) &&
p->p_stat == SRUN &&
(p->p_flag & P_INMEM) &&
(p->p_priority / PPQ) != (p->p_usrpri / PPQ)) {
remrq(p);
p->p_priority = p->p_usrpri;
setrunqueue(p);
} else
p->p_priority = p->p_usrpri;
}
splx(s);
}
vmmeter();
if (bclnlist != NULL)
wakeup((caddr_t)pageproc);
timeout(schedcpu, (void *)0, hz);
}
/*
* Recalculate the priority of a process after it has slept for a while.
* For all load averages >= 1 and max p_estcpu of 255, sleeping for at
* least six times the loadfactor will decay p_estcpu to zero.
*/
void
updatepri(p)
register struct proc *p;
{
register unsigned int newcpu = p->p_estcpu;
register fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
if (p->p_slptime > 5 * loadfac)
p->p_estcpu = 0;
else {
p->p_slptime--; /* the first time was done in schedcpu */
while (newcpu && --p->p_slptime)
newcpu = (int) decay_cpu(loadfac, newcpu);
p->p_estcpu = min(newcpu, UCHAR_MAX);
}
resetpriority(p);
}
/*
* We're only looking at 7 bits of the address; everything is
* aligned to 4, lots of things are aligned to greater powers
* of 2. Shift right by 8, i.e. drop the bottom 256 worth.
*/
#define TABLESIZE 128
#define LOOKUP(x) (((long)(x) >> 8) & (TABLESIZE - 1))
struct slpque {
struct proc *sq_head;
struct proc **sq_tailp;
} slpque[TABLESIZE];
/*
* During autoconfiguration or after a panic, a sleep will simply
* lower the priority briefly to allow interrupts, then return.
* The priority to be used (safepri) is machine-dependent, thus this
* value is initialized and maintained in the machine-dependent layers.
* This priority will typically be 0, or the lowest priority
* that is safe for use on the interrupt stack; it can be made
* higher to block network software interrupts after panics.
*/
int safepri;
/*
* General sleep call. Suspends the current process until a wakeup is
* performed on the specified identifier. The process will then be made
* runnable with the specified priority. Sleeps at most timo/hz seconds
* (0 means no timeout). If pri includes PCATCH flag, signals are checked
* before and after sleeping, else signals are not checked. Returns 0 if
* awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
* signal needs to be delivered, ERESTART is returned if the current system
* call should be restarted if possible, and EINTR is returned if the system
* call should be interrupted by the signal (return EINTR).
*/
int
tsleep(ident, priority, wmesg, timo)
void *ident;
int priority, timo;
char *wmesg;
{
register struct proc *p = curproc;
register struct slpque *qp;
register s;
int sig, catch = priority & PCATCH;
extern int cold;
void endtsleep __P((void *));
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 1, 0);
#endif
s = splhigh();
if (cold || panicstr) {
/*
* After a panic, or during autoconfiguration,
* just give interrupts a chance, then just return;
* don't run any other procs or panic below,
* in case this is the idle process and already asleep.
*/
splx(safepri);
splx(s);
return (0);
}
#ifdef DIAGNOSTIC
if (ident == NULL || p->p_stat != SRUN || p->p_back)
panic("tsleep");
#endif
p->p_wchan = ident;
p->p_wmesg = wmesg;
p->p_slptime = 0;
p->p_priority = priority & PRIMASK;
qp = &slpque[LOOKUP(ident)];
if (qp->sq_head == 0)
qp->sq_head = p;
else
*qp->sq_tailp = p;
*(qp->sq_tailp = &p->p_forw) = 0;
if (timo)
timeout(endtsleep, (void *)p, timo);
/*
* We put ourselves on the sleep queue and start our timeout
* before calling CURSIG, as we could stop there, and a wakeup
* or a SIGCONT (or both) could occur while we were stopped.
* A SIGCONT would cause us to be marked as SSLEEP
* without resuming us, thus we must be ready for sleep
* when CURSIG is called. If the wakeup happens while we're
* stopped, p->p_wchan will be 0 upon return from CURSIG.
*/
if (catch) {
p->p_flag |= P_SINTR;
if (sig = CURSIG(p)) {
if (p->p_wchan)
unsleep(p);
p->p_stat = SRUN;
goto resume;
}
if (p->p_wchan == 0) {
catch = 0;
goto resume;
}
} else
sig = 0;
p->p_stat = SSLEEP;
p->p_stats->p_ru.ru_nvcsw++;
mi_switch();
resume:
curpriority = p->p_usrpri;
splx(s);
p->p_flag &= ~P_SINTR;
if (p->p_flag & P_TIMEOUT) {
p->p_flag &= ~P_TIMEOUT;
if (sig == 0) {
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 0, 0);
#endif
return (EWOULDBLOCK);
}
} else if (timo)
untimeout(endtsleep, (void *)p);
if (catch && (sig != 0 || (sig = CURSIG(p)))) {
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 0, 0);
#endif
if (p->p_sigacts->ps_sigintr & sigmask(sig))
return (EINTR);
return (ERESTART);
}
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 0, 0);
#endif
return (0);
}
/*
* Implement timeout for tsleep.
* If process hasn't been awakened (wchan non-zero),
* set timeout flag and undo the sleep. If proc
* is stopped, just unsleep so it will remain stopped.
*/
void
endtsleep(arg)
void *arg;
{
register struct proc *p;
int s;
p = (struct proc *)arg;
s = splhigh();
if (p->p_wchan) {
if (p->p_stat == SSLEEP)
setrunnable(p);
else
unsleep(p);
p->p_flag |= P_TIMEOUT;
}
splx(s);
}
/*
* Short-term, non-interruptable sleep.
*/
void
sleep(ident, priority)
void *ident;
int priority;
{
register struct proc *p = curproc;
register struct slpque *qp;
register s;
extern int cold;
#ifdef DIAGNOSTIC
if (priority > PZERO) {
printf("sleep called with priority %d > PZERO, wchan: %x\n",
priority, ident);
panic("old sleep");
}
#endif
s = splhigh();
if (cold || panicstr) {
/*
* After a panic, or during autoconfiguration,
* just give interrupts a chance, then just return;
* don't run any other procs or panic below,
* in case this is the idle process and already asleep.
*/
splx(safepri);
splx(s);
return;
}
#ifdef DIAGNOSTIC
if (ident == NULL || p->p_stat != SRUN || p->p_back)
panic("sleep");
#endif
p->p_wchan = ident;
p->p_wmesg = NULL;
p->p_slptime = 0;
p->p_priority = priority;
qp = &slpque[LOOKUP(ident)];
if (qp->sq_head == 0)
qp->sq_head = p;
else
*qp->sq_tailp = p;
*(qp->sq_tailp = &p->p_forw) = 0;
p->p_stat = SSLEEP;
p->p_stats->p_ru.ru_nvcsw++;
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 1, 0);
#endif
mi_switch();
#ifdef KTRACE
if (KTRPOINT(p, KTR_CSW))
ktrcsw(p->p_tracep, 0, 0);
#endif
curpriority = p->p_usrpri;
splx(s);
}
/*
* Remove a process from its wait queue
*/
void
unsleep(p)
register struct proc *p;
{
register struct slpque *qp;
register struct proc **hp;
int s;
s = splhigh();
if (p->p_wchan) {
hp = &(qp = &slpque[LOOKUP(p->p_wchan)])->sq_head;
while (*hp != p)
hp = &(*hp)->p_forw;
*hp = p->p_forw;
if (qp->sq_tailp == &p->p_forw)
qp->sq_tailp = hp;
p->p_wchan = 0;
}
splx(s);
}
/*
* Make all processes sleeping on the specified identifier runnable.
*/
void
wakeup(ident)
register void *ident;
{
register struct slpque *qp;
register struct proc *p, **q;
int s;
s = splhigh();
qp = &slpque[LOOKUP(ident)];
restart:
for (q = &qp->sq_head; p = *q; ) {
#ifdef DIAGNOSTIC
if (p->p_back || p->p_stat != SSLEEP && p->p_stat != SSTOP)
panic("wakeup");
#endif
if (p->p_wchan == ident) {
p->p_wchan = 0;
*q = p->p_forw;
if (qp->sq_tailp == &p->p_forw)
qp->sq_tailp = q;
if (p->p_stat == SSLEEP) {
/* OPTIMIZED EXPANSION OF setrunnable(p); */
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
p->p_stat = SRUN;
if (p->p_flag & P_INMEM)
setrunqueue(p);
/*
* Since curpriority is a user priority,
* p->p_priority is always better than
* curpriority.
*/
if ((p->p_flag & P_INMEM) == 0)
wakeup((caddr_t)&proc0);
else
need_resched();
/* END INLINE EXPANSION */
goto restart;
}
} else
q = &p->p_forw;
}
splx(s);
}
/*
* The machine independent parts of mi_switch().
* Must be called at splstatclock() or higher.
*/
void
mi_switch()
{
register struct proc *p = curproc; /* XXX */
register struct rlimit *rlim;
register long s, u;
struct timeval tv;
#ifdef DEBUG
if (p->p_simple_locks)
panic("sleep: holding simple lock");
#endif
/*
* Compute the amount of time during which the current
* process was running, and add that to its total so far.
*/
microtime(&tv);
u = p->p_rtime.tv_usec + (tv.tv_usec - runtime.tv_usec);
s = p->p_rtime.tv_sec + (tv.tv_sec - runtime.tv_sec);
if (u < 0) {
u += 1000000;
s--;
} else if (u >= 1000000) {
u -= 1000000;
s++;
}
p->p_rtime.tv_usec = u;
p->p_rtime.tv_sec = s;
/*
* Check if the process exceeds its cpu resource allocation.
* If over max, kill it. In any case, if it has run for more
* than 10 minutes, reduce priority to give others a chance.
*/
rlim = &p->p_rlimit[RLIMIT_CPU];
if (s >= rlim->rlim_cur) {
if (s >= rlim->rlim_max)
psignal(p, SIGKILL);
else {
psignal(p, SIGXCPU);
if (rlim->rlim_cur < rlim->rlim_max)
rlim->rlim_cur += 5;
}
}
if (s > 10 * 60 && p->p_ucred->cr_uid && p->p_nice == NZERO) {
p->p_nice = NZERO + 4;
resetpriority(p);
}
/*
* Pick a new current process and record its start time.
*/
cnt.v_swtch++;
cpu_switch(p);
microtime(&runtime);
}
/*
* Initialize the (doubly-linked) run queues
* to be empty.
*/
void
rqinit()
{
register int i;
for (i = 0; i < NQS; i++)
qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
}
/*
* Change process state to be runnable,
* placing it on the run queue if it is in memory,
* and awakening the swapper if it isn't in memory.
*/
void
setrunnable(p)
register struct proc *p;
{
register int s;
s = splhigh();
switch (p->p_stat) {
case 0:
case SRUN:
case SZOMB:
default:
panic("setrunnable");
case SSTOP:
case SSLEEP:
unsleep(p); /* e.g. when sending signals */
break;
case SIDL:
break;
}
p->p_stat = SRUN;
if (p->p_flag & P_INMEM)
setrunqueue(p);
splx(s);
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
if ((p->p_flag & P_INMEM) == 0)
wakeup((caddr_t)&proc0);
else if (p->p_priority < curpriority)
need_resched();
}
/*
* Compute the priority of a process when running in user mode.
* Arrange to reschedule if the resulting priority is better
* than that of the current process.
*/
void
resetpriority(p)
register struct proc *p;
{
register unsigned int newpriority;
newpriority = PUSER + p->p_estcpu / 4 + 2 * p->p_nice;
newpriority = min(newpriority, MAXPRI);
p->p_usrpri = newpriority;
if (newpriority < curpriority)
need_resched();
}

793
sys/kern/kern_sysctl.c Normal file
View File

@ -0,0 +1,793 @@
/*-
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Karels at Berkeley Software Design, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_sysctl.c 8.9 (Berkeley) 5/20/95
*/
/*
* sysctl system call.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/vnode.h>
#include <sys/unistd.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
sysctlfn kern_sysctl;
sysctlfn hw_sysctl;
#ifdef DEBUG
sysctlfn debug_sysctl;
#endif
extern sysctlfn vm_sysctl;
extern sysctlfn vfs_sysctl;
extern sysctlfn net_sysctl;
extern sysctlfn cpu_sysctl;
/*
* Locking and stats
*/
static struct sysctl_lock {
int sl_lock;
int sl_want;
int sl_locked;
} memlock;
int
__sysctl(p, uap, retval)
struct proc *p;
register struct __sysctl_args /* {
syscallarg(int *) name;
syscallarg(u_int) namelen;
syscallarg(void *) old;
syscallarg(size_t *) oldlenp;
syscallarg(void *) new;
syscallarg(size_t) newlen;
} */ *uap;
register_t *retval;
{
int error, dolock = 1;
size_t savelen, oldlen = 0;
sysctlfn *fn;
int name[CTL_MAXNAME];
if (SCARG(uap, new) != NULL &&
(error = suser(p->p_ucred, &p->p_acflag)))
return (error);
/*
* all top-level sysctl names are non-terminal
*/
if (SCARG(uap, namelen) > CTL_MAXNAME || SCARG(uap, namelen) < 2)
return (EINVAL);
if (error =
copyin(SCARG(uap, name), &name, SCARG(uap, namelen) * sizeof(int)))
return (error);
switch (name[0]) {
case CTL_KERN:
fn = kern_sysctl;
if (name[2] == KERN_VNODE) /* XXX */
dolock = 0;
break;
case CTL_HW:
fn = hw_sysctl;
break;
case CTL_VM:
fn = vm_sysctl;
break;
case CTL_NET:
fn = net_sysctl;
break;
case CTL_VFS:
fn = vfs_sysctl;
break;
case CTL_MACHDEP:
fn = cpu_sysctl;
break;
#ifdef DEBUG
case CTL_DEBUG:
fn = debug_sysctl;
break;
#endif
default:
return (EOPNOTSUPP);
}
if (SCARG(uap, oldlenp) &&
(error = copyin(SCARG(uap, oldlenp), &oldlen, sizeof(oldlen))))
return (error);
if (SCARG(uap, old) != NULL) {
if (!useracc(SCARG(uap, old), oldlen, B_WRITE))
return (EFAULT);
while (memlock.sl_lock) {
memlock.sl_want = 1;
sleep((caddr_t)&memlock, PRIBIO+1);
memlock.sl_locked++;
}
memlock.sl_lock = 1;
if (dolock)
vslock(SCARG(uap, old), oldlen);
savelen = oldlen;
}
error = (*fn)(name + 1, SCARG(uap, namelen) - 1, SCARG(uap, old),
&oldlen, SCARG(uap, new), SCARG(uap, newlen), p);
if (SCARG(uap, old) != NULL) {
if (dolock)
vsunlock(SCARG(uap, old), savelen, B_WRITE);
memlock.sl_lock = 0;
if (memlock.sl_want) {
memlock.sl_want = 0;
wakeup((caddr_t)&memlock);
}
}
if (error)
return (error);
if (SCARG(uap, oldlenp))
error = copyout(&oldlen, SCARG(uap, oldlenp), sizeof(oldlen));
*retval = oldlen;
return (0);
}
/*
* Attributes stored in the kernel.
*/
char hostname[MAXHOSTNAMELEN];
int hostnamelen;
long hostid;
int securelevel;
/*
* kernel related system variables.
*/
kern_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
struct proc *p;
{
int error, level, inthostid;
extern char ostype[], osrelease[], version[];
/* all sysctl names at this level are terminal */
if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case KERN_OSTYPE:
return (sysctl_rdstring(oldp, oldlenp, newp, ostype));
case KERN_OSRELEASE:
return (sysctl_rdstring(oldp, oldlenp, newp, osrelease));
case KERN_OSREV:
return (sysctl_rdint(oldp, oldlenp, newp, BSD));
case KERN_VERSION:
return (sysctl_rdstring(oldp, oldlenp, newp, version));
case KERN_MAXVNODES:
return(sysctl_int(oldp, oldlenp, newp, newlen, &desiredvnodes));
case KERN_MAXPROC:
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxproc));
case KERN_MAXFILES:
return (sysctl_int(oldp, oldlenp, newp, newlen, &maxfiles));
case KERN_ARGMAX:
return (sysctl_rdint(oldp, oldlenp, newp, ARG_MAX));
case KERN_SECURELVL:
level = securelevel;
if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
newp == NULL)
return (error);
if (level < securelevel && p->p_pid != 1)
return (EPERM);
securelevel = level;
return (0);
case KERN_HOSTNAME:
error = sysctl_string(oldp, oldlenp, newp, newlen,
hostname, sizeof(hostname));
if (newp && !error)
hostnamelen = newlen;
return (error);
case KERN_HOSTID:
inthostid = hostid; /* XXX assumes sizeof long <= sizeof int */
error = sysctl_int(oldp, oldlenp, newp, newlen, &inthostid);
hostid = inthostid;
return (error);
case KERN_CLOCKRATE:
return (sysctl_clockrate(oldp, oldlenp));
case KERN_BOOTTIME:
return (sysctl_rdstruct(oldp, oldlenp, newp, &boottime,
sizeof(struct timeval)));
case KERN_VNODE:
return (sysctl_vnode(oldp, oldlenp, p));
case KERN_PROC:
return (sysctl_doproc(name + 1, namelen - 1, oldp, oldlenp));
case KERN_FILE:
return (sysctl_file(oldp, oldlenp));
#ifdef GPROF
case KERN_PROF:
return (sysctl_doprof(name + 1, namelen - 1, oldp, oldlenp,
newp, newlen));
#endif
case KERN_POSIX1:
return (sysctl_rdint(oldp, oldlenp, newp, _POSIX_VERSION));
case KERN_NGROUPS:
return (sysctl_rdint(oldp, oldlenp, newp, NGROUPS_MAX));
case KERN_JOB_CONTROL:
return (sysctl_rdint(oldp, oldlenp, newp, 1));
case KERN_SAVED_IDS:
#ifdef _POSIX_SAVED_IDS
return (sysctl_rdint(oldp, oldlenp, newp, 1));
#else
return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
/*
* hardware related system variables.
*/
hw_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
struct proc *p;
{
extern char machine[], cpu_model[];
/* all sysctl names at this level are terminal */
if (namelen != 1)
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case HW_MACHINE:
return (sysctl_rdstring(oldp, oldlenp, newp, machine));
case HW_MODEL:
return (sysctl_rdstring(oldp, oldlenp, newp, cpu_model));
case HW_NCPU:
return (sysctl_rdint(oldp, oldlenp, newp, 1)); /* XXX */
case HW_BYTEORDER:
return (sysctl_rdint(oldp, oldlenp, newp, BYTE_ORDER));
case HW_PHYSMEM:
return (sysctl_rdint(oldp, oldlenp, newp, ctob(physmem)));
case HW_USERMEM:
return (sysctl_rdint(oldp, oldlenp, newp,
ctob(physmem - cnt.v_wire_count)));
case HW_PAGESIZE:
return (sysctl_rdint(oldp, oldlenp, newp, PAGE_SIZE));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
#ifdef DEBUG
/*
* Debugging related system variables.
*/
struct ctldebug debug0, debug1, debug2, debug3, debug4;
struct ctldebug debug5, debug6, debug7, debug8, debug9;
struct ctldebug debug10, debug11, debug12, debug13, debug14;
struct ctldebug debug15, debug16, debug17, debug18, debug19;
static struct ctldebug *debugvars[CTL_DEBUG_MAXID] = {
&debug0, &debug1, &debug2, &debug3, &debug4,
&debug5, &debug6, &debug7, &debug8, &debug9,
&debug10, &debug11, &debug12, &debug13, &debug14,
&debug15, &debug16, &debug17, &debug18, &debug19,
};
int
debug_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
struct proc *p;
{
struct ctldebug *cdp;
/* all sysctl names at this level are name and field */
if (namelen != 2)
return (ENOTDIR); /* overloaded */
cdp = debugvars[name[0]];
if (name[0] >= CTL_DEBUG_MAXID || cdp->debugname == 0)
return (EOPNOTSUPP);
switch (name[1]) {
case CTL_DEBUG_NAME:
return (sysctl_rdstring(oldp, oldlenp, newp, cdp->debugname));
case CTL_DEBUG_VALUE:
return (sysctl_int(oldp, oldlenp, newp, newlen, cdp->debugvar));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
#endif /* DEBUG */
/*
* Validate parameters and get old / set new parameters
* for an integer-valued sysctl function.
*/
sysctl_int(oldp, oldlenp, newp, newlen, valp)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
int *valp;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp && newlen != sizeof(int))
return (EINVAL);
*oldlenp = sizeof(int);
if (oldp)
error = copyout(valp, oldp, sizeof(int));
if (error == 0 && newp)
error = copyin(newp, valp, sizeof(int));
return (error);
}
/*
* As above, but read-only.
*/
sysctl_rdint(oldp, oldlenp, newp, val)
void *oldp;
size_t *oldlenp;
void *newp;
int val;
{
int error = 0;
if (oldp && *oldlenp < sizeof(int))
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = sizeof(int);
if (oldp)
error = copyout((caddr_t)&val, oldp, sizeof(int));
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for a string-valued sysctl function.
*/
sysctl_string(oldp, oldlenp, newp, newlen, str, maxlen)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
char *str;
int maxlen;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen >= maxlen)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(str, oldp, len);
}
if (error == 0 && newp) {
error = copyin(newp, str, newlen);
str[newlen] = 0;
}
return (error);
}
/*
* As above, but read-only.
*/
sysctl_rdstring(oldp, oldlenp, newp, str)
void *oldp;
size_t *oldlenp;
void *newp;
char *str;
{
int len, error = 0;
len = strlen(str) + 1;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(str, oldp, len);
return (error);
}
/*
* Validate parameters and get old / set new parameters
* for a structure oriented sysctl function.
*/
sysctl_struct(oldp, oldlenp, newp, newlen, sp, len)
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
void *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp && newlen > len)
return (EINVAL);
if (oldp) {
*oldlenp = len;
error = copyout(sp, oldp, len);
}
if (error == 0 && newp)
error = copyin(newp, sp, len);
return (error);
}
/*
* Validate parameters and get old parameters
* for a structure oriented sysctl function.
*/
sysctl_rdstruct(oldp, oldlenp, newp, sp, len)
void *oldp;
size_t *oldlenp;
void *newp, *sp;
int len;
{
int error = 0;
if (oldp && *oldlenp < len)
return (ENOMEM);
if (newp)
return (EPERM);
*oldlenp = len;
if (oldp)
error = copyout(sp, oldp, len);
return (error);
}
/*
* Get file structures.
*/
sysctl_file(where, sizep)
char *where;
size_t *sizep;
{
int buflen, error;
struct file *fp;
char *start = where;
buflen = *sizep;
if (where == NULL) {
/*
* overestimate by 10 files
*/
*sizep = sizeof(filehead) + (nfiles + 10) * sizeof(struct file);
return (0);
}
/*
* first copyout filehead
*/
if (buflen < sizeof(filehead)) {
*sizep = 0;
return (0);
}
if (error = copyout((caddr_t)&filehead, where, sizeof(filehead)))
return (error);
buflen -= sizeof(filehead);
where += sizeof(filehead);
/*
* followed by an array of file structures
*/
for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
if (buflen < sizeof(struct file)) {
*sizep = where - start;
return (ENOMEM);
}
if (error = copyout((caddr_t)fp, where, sizeof (struct file)))
return (error);
buflen -= sizeof(struct file);
where += sizeof(struct file);
}
*sizep = where - start;
return (0);
}
/*
* try over estimating by 5 procs
*/
#define KERN_PROCSLOP (5 * sizeof (struct kinfo_proc))
sysctl_doproc(name, namelen, where, sizep)
int *name;
u_int namelen;
char *where;
size_t *sizep;
{
register struct proc *p;
register struct kinfo_proc *dp = (struct kinfo_proc *)where;
register int needed = 0;
int buflen = where != NULL ? *sizep : 0;
int doingzomb;
struct eproc eproc;
int error = 0;
if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
return (EINVAL);
p = allproc.lh_first;
doingzomb = 0;
again:
for (; p != 0; p = p->p_list.le_next) {
/*
* Skip embryonic processes.
*/
if (p->p_stat == SIDL)
continue;
/*
* TODO - make more efficient (see notes below).
* do by session.
*/
switch (name[0]) {
case KERN_PROC_PID:
/* could do this with just a lookup */
if (p->p_pid != (pid_t)name[1])
continue;
break;
case KERN_PROC_PGRP:
/* could do this by traversing pgrp */
if (p->p_pgrp->pg_id != (pid_t)name[1])
continue;
break;
case KERN_PROC_TTY:
if ((p->p_flag & P_CONTROLT) == 0 ||
p->p_session->s_ttyp == NULL ||
p->p_session->s_ttyp->t_dev != (dev_t)name[1])
continue;
break;
case KERN_PROC_UID:
if (p->p_ucred->cr_uid != (uid_t)name[1])
continue;
break;
case KERN_PROC_RUID:
if (p->p_cred->p_ruid != (uid_t)name[1])
continue;
break;
}
if (buflen >= sizeof(struct kinfo_proc)) {
fill_eproc(p, &eproc);
if (error = copyout((caddr_t)p, &dp->kp_proc,
sizeof(struct proc)))
return (error);
if (error = copyout((caddr_t)&eproc, &dp->kp_eproc,
sizeof(eproc)))
return (error);
dp++;
buflen -= sizeof(struct kinfo_proc);
}
needed += sizeof(struct kinfo_proc);
}
if (doingzomb == 0) {
p = zombproc.lh_first;
doingzomb++;
goto again;
}
if (where != NULL) {
*sizep = (caddr_t)dp - where;
if (needed > *sizep)
return (ENOMEM);
} else {
needed += KERN_PROCSLOP;
*sizep = needed;
}
return (0);
}
/*
* Fill in an eproc structure for the specified process.
*/
void
fill_eproc(p, ep)
register struct proc *p;
register struct eproc *ep;
{
register struct tty *tp;
ep->e_paddr = p;
ep->e_sess = p->p_pgrp->pg_session;
ep->e_pcred = *p->p_cred;
ep->e_ucred = *p->p_ucred;
if (p->p_stat == SIDL || p->p_stat == SZOMB) {
ep->e_vm.vm_rssize = 0;
ep->e_vm.vm_tsize = 0;
ep->e_vm.vm_dsize = 0;
ep->e_vm.vm_ssize = 0;
#ifndef sparc
/* ep->e_vm.vm_pmap = XXX; */
#endif
} else {
register struct vmspace *vm = p->p_vmspace;
#ifdef pmap_resident_count
ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
#else
ep->e_vm.vm_rssize = vm->vm_rssize;
#endif
ep->e_vm.vm_tsize = vm->vm_tsize;
ep->e_vm.vm_dsize = vm->vm_dsize;
ep->e_vm.vm_ssize = vm->vm_ssize;
#ifndef sparc
ep->e_vm.vm_pmap = vm->vm_pmap;
#endif
}
if (p->p_pptr)
ep->e_ppid = p->p_pptr->p_pid;
else
ep->e_ppid = 0;
ep->e_pgid = p->p_pgrp->pg_id;
ep->e_jobc = p->p_pgrp->pg_jobc;
if ((p->p_flag & P_CONTROLT) &&
(tp = ep->e_sess->s_ttyp)) {
ep->e_tdev = tp->t_dev;
ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
ep->e_tsess = tp->t_session;
} else
ep->e_tdev = NODEV;
ep->e_flag = ep->e_sess->s_ttyvp ? EPROC_CTTY : 0;
if (SESS_LEADER(p))
ep->e_flag |= EPROC_SLEADER;
if (p->p_wmesg)
strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
ep->e_xsize = ep->e_xrssize = 0;
ep->e_xccount = ep->e_xswrss = 0;
}
#ifdef COMPAT_43
#include <sys/socket.h>
#define KINFO_PROC (0<<8)
#define KINFO_RT (1<<8)
#define KINFO_VNODE (2<<8)
#define KINFO_FILE (3<<8)
#define KINFO_METER (4<<8)
#define KINFO_LOADAVG (5<<8)
#define KINFO_CLOCKRATE (6<<8)
compat_43_getkerninfo(p, uap, retval)
struct proc *p;
register struct compat_43_getkerninfo_args /* {
syscallarg(int) op;
syscallarg(char *) where;
syscallarg(int *) size;
syscallarg(int) arg;
} */ *uap;
register_t *retval;
{
int error, name[5];
size_t size;
if (SCARG(uap, size) && (error = copyin((caddr_t)SCARG(uap, size),
(caddr_t)&size, sizeof(size))))
return (error);
switch (SCARG(uap, op) & 0xff00) {
case KINFO_RT:
name[0] = PF_ROUTE;
name[1] = 0;
name[2] = (SCARG(uap, op) & 0xff0000) >> 16;
name[3] = SCARG(uap, op) & 0xff;
name[4] = SCARG(uap, arg);
error =
net_sysctl(name, 5, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_VNODE:
name[0] = KERN_VNODE;
error =
kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_PROC:
name[0] = KERN_PROC;
name[1] = SCARG(uap, op) & 0xff;
name[2] = SCARG(uap, arg);
error =
kern_sysctl(name, 3, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_FILE:
name[0] = KERN_FILE;
error =
kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_METER:
name[0] = VM_METER;
error =
vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_LOADAVG:
name[0] = VM_LOADAVG;
error =
vm_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
break;
case KINFO_CLOCKRATE:
name[0] = KERN_CLOCKRATE;
error =
kern_sysctl(name, 1, SCARG(uap, where), &size, NULL, 0, p);
break;
default:
return (EOPNOTSUPP);
}
if (error)
return (error);
*retval = size;
if (SCARG(uap, size))
error = copyout((caddr_t)&size, (caddr_t)SCARG(uap, size),
sizeof(size));
return (error);
}
#endif /* COMPAT_43 */

433
sys/kern/kern_time.c Normal file
View File

@ -0,0 +1,433 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. 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 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.
*
* @(#)kern_time.c 8.4 (Berkeley) 5/26/95
*/
#include <sys/param.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <machine/cpu.h>
/*
* Time of day and interval timer support.
*
* These routines provide the kernel entry points to get and set
* the time-of-day and per-process interval timers. Subroutines
* here provide support for adding and subtracting timeval structures
* and decrementing interval timers, optionally reloading the interval
* timers when they expire.
*/
/* ARGSUSED */
int
gettimeofday(p, uap, retval)
struct proc *p;
register struct gettimeofday_args /* {
syscallarg(struct timeval *) tp;
syscallarg(struct timezone *) tzp;
} */ *uap;
register_t *retval;
{
struct timeval atv;
int error = 0;
if (SCARG(uap, tp)) {
microtime(&atv);
if (error = copyout((caddr_t)&atv, (caddr_t)SCARG(uap, tp),
sizeof (atv)))
return (error);
}
if (SCARG(uap, tzp))
error = copyout((caddr_t)&tz, (caddr_t)SCARG(uap, tzp),
sizeof (tz));
return (error);
}
/* ARGSUSED */
int
settimeofday(p, uap, retval)
struct proc *p;
struct settimeofday_args /* {
syscallarg(struct timeval *) tv;
syscallarg(struct timezone *) tzp;
} */ *uap;
register_t *retval;
{
struct timeval atv, delta;
struct timezone atz;
int error, s;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
/* Verify all parameters before changing time. */
if (SCARG(uap, tv) && (error = copyin((caddr_t)SCARG(uap, tv),
(caddr_t)&atv, sizeof(atv))))
return (error);
if (SCARG(uap, tzp) && (error = copyin((caddr_t)SCARG(uap, tzp),
(caddr_t)&atz, sizeof(atz))))
return (error);
if (SCARG(uap, tv)) {
/*
* If the system is secure, we do not allow the time to be
* set to an earlier value (it may be slowed using adjtime,
* but not set back). This feature prevent interlopers from
* setting arbitrary time stamps on files.
*/
if (securelevel > 0 && timercmp(&atv, &time, <))
return (EPERM);
/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
s = splclock();
/* nb. delta.tv_usec may be < 0, but this is OK here */
delta.tv_sec = atv.tv_sec - time.tv_sec;
delta.tv_usec = atv.tv_usec - time.tv_usec;
time = atv;
(void) splsoftclock();
timevaladd(&boottime, &delta);
timevalfix(&boottime);
timevaladd(&runtime, &delta);
timevalfix(&runtime);
# ifdef NFS
lease_updatetime(delta.tv_sec);
# endif
splx(s);
resettodr();
}
if (SCARG(uap, tzp))
tz = atz;
return (0);
}
extern int tickadj; /* "standard" clock skew, us./tick */
int tickdelta; /* current clock skew, us. per tick */
long timedelta; /* unapplied time correction, us. */
long bigadj = 1000000; /* use 10x skew above bigadj us. */
/* ARGSUSED */
int
adjtime(p, uap, retval)
struct proc *p;
register struct adjtime_args /* {
syscallarg(struct timeval *) delta;
syscallarg(struct timeval *) olddelta;
} */ *uap;
register_t *retval;
{
struct timeval atv;
register long ndelta, ntickdelta, odelta;
int s, error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
if (error = copyin((caddr_t)SCARG(uap, delta), (caddr_t)&atv,
sizeof(struct timeval)))
return (error);
/*
* Compute the total correction and the rate at which to apply it.
* Round the adjustment down to a whole multiple of the per-tick
* delta, so that after some number of incremental changes in
* hardclock(), tickdelta will become zero, lest the correction
* overshoot and start taking us away from the desired final time.
*/
ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
if (ndelta > bigadj)
ntickdelta = 10 * tickadj;
else
ntickdelta = tickadj;
if (ndelta % ntickdelta)
ndelta = ndelta / ntickdelta * ntickdelta;
/*
* To make hardclock()'s job easier, make the per-tick delta negative
* if we want time to run slower; then hardclock can simply compute
* tick + tickdelta, and subtract tickdelta from timedelta.
*/
if (ndelta < 0)
ntickdelta = -ntickdelta;
s = splclock();
odelta = timedelta;
timedelta = ndelta;
tickdelta = ntickdelta;
splx(s);
if (SCARG(uap, olddelta)) {
atv.tv_sec = odelta / 1000000;
atv.tv_usec = odelta % 1000000;
(void) copyout((caddr_t)&atv, (caddr_t)SCARG(uap, olddelta),
sizeof(struct timeval));
}
return (0);
}
/*
* Get value of an interval timer. The process virtual and
* profiling virtual time timers are kept in the p_stats area, since
* they can be swapped out. These are kept internally in the
* way they are specified externally: in time until they expire.
*
* The real time interval timer is kept in the process table slot
* for the process, and its value (it_value) is kept as an
* absolute time rather than as a delta, so that it is easy to keep
* periodic real-time signals from drifting.
*
* Virtual time timers are processed in the hardclock() routine of
* kern_clock.c. The real time timer is processed by a timeout
* routine, called from the softclock() routine. Since a callout
* may be delayed in real time due to interrupt processing in the system,
* it is possible for the real time timeout routine (realitexpire, given below),
* to be delayed in real time past when it is supposed to occur. It
* does not suffice, therefore, to reload the real timer .it_value from the
* real time timers .it_interval. Rather, we compute the next time in
* absolute time the timer should go off.
*/
/* ARGSUSED */
int
getitimer(p, uap, retval)
struct proc *p;
register struct getitimer_args /* {
syscallarg(u_int) which;
syscallarg(struct itimerval *) itv;
} */ *uap;
register_t *retval;
{
struct itimerval aitv;
int s;
if (SCARG(uap, which) > ITIMER_PROF)
return (EINVAL);
s = splclock();
if (SCARG(uap, which) == ITIMER_REAL) {
/*
* Convert from absolute to relative time in .it_value
* part of real time timer. If time for real time timer
* has passed return 0, else return difference between
* current time and time for the timer to go off.
*/
aitv = p->p_realtimer;
if (timerisset(&aitv.it_value))
if (timercmp(&aitv.it_value, &time, <))
timerclear(&aitv.it_value);
else
timevalsub(&aitv.it_value,
(struct timeval *)&time);
} else
aitv = p->p_stats->p_timer[SCARG(uap, which)];
splx(s);
return (copyout((caddr_t)&aitv, (caddr_t)SCARG(uap, itv),
sizeof (struct itimerval)));
}
/* ARGSUSED */
int
setitimer(p, uap, retval)
struct proc *p;
register struct setitimer_args /* {
syscallarg(u_int) which;
syscallarg(struct itimerval *) itv;
syscallarg(struct itimerval *) oitv;
} */ *uap;
register_t *retval;
{
struct itimerval aitv;
register struct itimerval *itvp;
int s, error;
if (SCARG(uap, which) > ITIMER_PROF)
return (EINVAL);
itvp = SCARG(uap, itv);
if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
sizeof(struct itimerval))))
return (error);
if ((SCARG(uap, itv) = SCARG(uap, oitv)) &&
(error = getitimer(p, uap, retval)))
return (error);
if (itvp == 0)
return (0);
if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
return (EINVAL);
s = splclock();
if (SCARG(uap, which) == ITIMER_REAL) {
untimeout(realitexpire, (caddr_t)p);
if (timerisset(&aitv.it_value)) {
timevaladd(&aitv.it_value, (struct timeval *)&time);
timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
}
p->p_realtimer = aitv;
} else
p->p_stats->p_timer[SCARG(uap, which)] = aitv;
splx(s);
return (0);
}
/*
* Real interval timer expired:
* send process whose timer expired an alarm signal.
* If time is not set up to reload, then just return.
* Else compute next time timer should go off which is > current time.
* This is where delay in processing this timeout causes multiple
* SIGALRM calls to be compressed into one.
*/
void
realitexpire(arg)
void *arg;
{
register struct proc *p;
int s;
p = (struct proc *)arg;
psignal(p, SIGALRM);
if (!timerisset(&p->p_realtimer.it_interval)) {
timerclear(&p->p_realtimer.it_value);
return;
}
for (;;) {
s = splclock();
timevaladd(&p->p_realtimer.it_value,
&p->p_realtimer.it_interval);
if (timercmp(&p->p_realtimer.it_value, &time, >)) {
timeout(realitexpire, (caddr_t)p,
hzto(&p->p_realtimer.it_value));
splx(s);
return;
}
splx(s);
}
}
/*
* Check that a proposed value to load into the .it_value or
* .it_interval part of an interval timer is acceptable, and
* fix it to have at least minimal value (i.e. if it is less
* than the resolution of the clock, round it up.)
*/
int
itimerfix(tv)
struct timeval *tv;
{
if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
tv->tv_usec < 0 || tv->tv_usec >= 1000000)
return (EINVAL);
if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
tv->tv_usec = tick;
return (0);
}
/*
* Decrement an interval timer by a specified number
* of microseconds, which must be less than a second,
* i.e. < 1000000. If the timer expires, then reload
* it. In this case, carry over (usec - old value) to
* reduce the value reloaded into the timer so that
* the timer does not drift. This routine assumes
* that it is called in a context where the timers
* on which it is operating cannot change in value.
*/
int
itimerdecr(itp, usec)
register struct itimerval *itp;
int usec;
{
if (itp->it_value.tv_usec < usec) {
if (itp->it_value.tv_sec == 0) {
/* expired, and already in next interval */
usec -= itp->it_value.tv_usec;
goto expire;
}
itp->it_value.tv_usec += 1000000;
itp->it_value.tv_sec--;
}
itp->it_value.tv_usec -= usec;
usec = 0;
if (timerisset(&itp->it_value))
return (1);
/* expired, exactly at end of interval */
expire:
if (timerisset(&itp->it_interval)) {
itp->it_value = itp->it_interval;
itp->it_value.tv_usec -= usec;
if (itp->it_value.tv_usec < 0) {
itp->it_value.tv_usec += 1000000;
itp->it_value.tv_sec--;
}
} else
itp->it_value.tv_usec = 0; /* sec is already 0 */
return (0);
}
/*
* Add and subtract routines for timevals.
* N.B.: subtract routine doesn't deal with
* results which are before the beginning,
* it just gets very confused in this case.
* Caveat emptor.
*/
timevaladd(t1, t2)
struct timeval *t1, *t2;
{
t1->tv_sec += t2->tv_sec;
t1->tv_usec += t2->tv_usec;
timevalfix(t1);
}
timevalsub(t1, t2)
struct timeval *t1, *t2;
{
t1->tv_sec -= t2->tv_sec;
t1->tv_usec -= t2->tv_usec;
timevalfix(t1);
}
timevalfix(t1)
struct timeval *t1;
{
if (t1->tv_usec < 0) {
t1->tv_sec--;
t1->tv_usec += 1000000;
}
if (t1->tv_usec >= 1000000) {
t1->tv_sec++;
t1->tv_usec -= 1000000;
}
}

143
sys/kern/kern_xxx.c Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. 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 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.
*
* @(#)kern_xxx.c 8.3 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
/* ARGSUSED */
int
reboot(p, uap, retval)
struct proc *p;
struct reboot_args /* {
syscallarg(int) opt;
} */ *uap;
register_t *retval;
{
int error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
boot(SCARG(uap, opt));
return (0);
}
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
/* ARGSUSED */
int
compat_43_gethostname(p, uap, retval)
struct proc *p;
struct compat_43_gethostname_args /* {
syscallarg(char *) hostname;
syscallarg(u_int) len;
} */ *uap;
register_t *retval;
{
int name;
name = KERN_HOSTNAME;
return (kern_sysctl(&name, 1, SCARG(uap, hostname), &SCARG(uap, len),
0, 0));
}
/* ARGSUSED */
int
compat_43_sethostname(p, uap, retval)
struct proc *p;
register struct compat_43_sethostname_args /* {
syscallarg(char *) hostname;
syscallarg(u_int) len;
} */ *uap;
register_t *retval;
{
int name;
int error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
name = KERN_HOSTNAME;
return (kern_sysctl(&name, 1, 0, 0, SCARG(uap, hostname),
SCARG(uap, len)));
}
/* ARGSUSED */
int
compat_43_gethostid(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
*(int32_t *)retval = hostid;
return (0);
}
#endif /* COMPAT_43 || COMPAT_SUNOS */
#ifdef COMPAT_43
/* ARGSUSED */
int
compat_43_sethostid(p, uap, retval)
struct proc *p;
struct compat_43_sethostid_args /* {
syscallarg(int32_t) hostid;
} */ *uap;
register_t *retval;
{
int error;
if (error = suser(p->p_ucred, &p->p_acflag))
return (error);
hostid = SCARG(uap, hostid);
return (0);
}
int
compat_43_quota(p, uap, retval)
struct proc *p;
void *uap;
register_t *retval;
{
return (ENOSYS);
}
#endif /* COMPAT_43 */

365
sys/kern/makesyscalls.sh Normal file
View File

@ -0,0 +1,365 @@
#! /bin/sh -
#
# @(#)makesyscalls.sh 8.2 (Berkeley) 2/14/95
set -e
case $# in
2) ;;
*) echo "Usage: $0 config-file input-file" 1>&2
exit 1
;;
esac
# source the config file.
. $1
# the config file sets the following variables:
# sysnames the syscall names file
# sysnumhdr the syscall numbers file
# syssw the syscall switch file
# sysarghdr the syscall argument struct definitions
# compatopts those syscall types that are for 'compat' syscalls
# switchname the name for the 'struct sysent' we define
# namesname the name for the 'char *[]' we define
# constprefix the prefix for the system call constants
#
# NOTE THAT THIS makesyscalls.sh DOES NOT SUPPORT 'LIBCOMPAT'.
# tmp files:
sysdcl="sysent.dcl"
syscompat_pref="sysent."
sysent="sysent.switch"
syscompat_files=""
for file in $compatopts; do
syscompat_files="$syscompat_files $syscompat_pref$file"
done
trap "rm $sysdcl $syscompat_files $sysent" 0
# Awk program (must support nawk extensions)
# Use "awk" at Berkeley, "nawk" or "gawk" elsewhere.
awk=${AWK:-awk}
# Does this awk have a "toupper" function? (i.e. is it GNU awk)
isgawk=`$awk 'BEGIN { print toupper("true"); exit; }' 2>/dev/null`
# If this awk does not define "toupper" then define our own.
if [ "$isgawk" = TRUE ] ; then
# GNU awk provides it.
toupper=
else
# Provide our own toupper()
toupper='
function toupper(str) {
_toupper_cmd = "echo "str" |tr a-z A-Z"
_toupper_cmd | getline _toupper_str;
close(_toupper_cmd);
return _toupper_str;
}'
fi
# before handing it off to awk, make a few adjustments:
# (1) insert spaces around {, }, (, ), *, and commas.
# (2) get rid of any and all dollar signs (so that rcs id use safe)
#
# The awk script will deal with blank lines and lines that
# start with the comment character (';').
sed -e '
s/\$//g
:join
/\\$/{a\
N
s/\\\n//
b join
}
2,${
/^#/!s/\([{}()*,]\)/ \1 /g
}
' < $2 | $awk "
$toupper
BEGIN {
sysnames = \"$sysnames\"
sysnumhdr = \"$sysnumhdr\"
sysarghdr = \"$sysarghdr\"
switchname = \"$switchname\"
namesname = \"$namesname\"
constprefix = \"$constprefix\"
sysdcl = \"$sysdcl\"
syscompat_pref = \"$syscompat_pref\"
sysent = \"$sysent\"
infile = \"$2\"
compatopts = \"$compatopts\"
"'
printf "/*\n * System call switch table.\n *\n" > sysdcl
printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysdcl
ncompat = split(compatopts,compat)
for (i = 1; i <= ncompat; i++) {
compat_upper[i] = toupper(compat[i])
compat_file[i] = sprintf("%s%s", syscompat_pref, compat[i])
printf "\n#ifdef %s\n", compat_upper[i] > compat_file[i]
printf "#define %s(func) __CONCAT(%s_,func)\n\n", \
compat[i], compat[i] > compat_file[i]
}
printf "/*\n * System call names.\n *\n" > sysnames
printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysnames
printf "/*\n * System call numbers.\n *\n" > sysnumhdr
printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysnumhdr
printf "/*\n * System call argument lists.\n *\n" > sysarghdr
printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysarghdr
}
NR == 1 {
printf " * created from%s\n */\n\n", $0 > sysdcl
printf "#define\ts(type)\tsizeof(type)\n\n" > sysent
printf "struct sysent %s[] = {\n",switchname > sysent
printf " * created from%s\n */\n\n", $0 > sysnames
printf "char *%s[] = {\n",namesname > sysnames
printf " * created from%s\n */\n\n", $0 > sysnumhdr
printf " * created from%s\n */\n\n", $0 > sysarghdr
printf "#define\tsyscallarg(x)\tunion { x datum; register_t pad; }\n" \
> sysarghdr
next
}
NF == 0 || $1 ~ /^;/ {
next
}
$1 ~ /^#[ ]*include/ {
print > sysdcl
next
}
$1 ~ /^#[ ]*if/ {
print > sysent
print > sysdcl
for (i = 1; i <= ncompat; i++)
print > compat_file[i]
print > sysnames
savesyscall = syscall
next
}
$1 ~ /^#[ ]*else/ {
print > sysent
print > sysdcl
for (i = 1; i <= ncompat; i++)
print > compat_file[i]
print > sysnames
syscall = savesyscall
next
}
$1 ~ /^#/ {
print > sysent
print > sysdcl
for (i = 1; i <= ncompat; i++)
print > compat_file[i]
print > sysnames
next
}
syscall != $1 {
printf "%s: line %d: syscall number out of sync at %d\n", \
infile, NR, syscall
printf "line is:\n"
print
exit 1
}
function parserr(was, wanted) {
printf "%s: line %d: unexpected %s (expected %s)\n", \
infile, NR, was, wanted
exit 1
}
function parseline() {
f=3 # toss number and type
if ($NF != "}") {
funcalias=$NF
end=NF-1
} else {
funcalias=""
end=NF
}
if ($f != "{")
parserr($f, "{")
f++
if ($end != "}")
parserr($end, "}")
end--
if ($end != ";")
parserr($end, ";")
end--
if ($end != ")")
parserr($end, ")")
end--
f++ # toss return type
funcname=$f
if (funcalias == "")
funcalias=funcname
f++
if ($f != "(")
parserr($f, ")")
f++
argc= 0;
if (f == end) {
if ($f != "void")
parserr($f, "argument definition")
return
}
while (f <= end) {
argc++
argtype[argc]=""
oldf=""
while (f < end && $(f+1) != ",") {
if (argtype[argc] != "" && oldf != "*")
argtype[argc] = argtype[argc]" ";
argtype[argc] = argtype[argc]$f;
oldf = $f;
f++
}
if (argtype[argc] == "")
parserr($f, "argument definition")
argname[argc]=$f;
f += 2; # skip name, and any comma
}
}
function putent(nodefs, declfile, compatwrap) {
# output syscall declaration for switch table
if (compatwrap == "")
printf("int\t%s();\n", funcname) > declfile
else
printf("int\t%s(%s)();\n", compatwrap, funcname) > declfile
# output syscall switch entry
# printf("\t{ { %d", argc) > sysent
# for (i = 1; i <= argc; i++) {
# if (i == 5) # wrap the line
# printf(",\n\t ") > sysent
# else
# printf(", ") > sysent
# printf("s(%s)", argtypenospc[i]) > sysent
# }
printf("\t{ %d, ", argc) > sysent
if (argc == 0)
printf("0") > sysent
else if (compatwrap == "")
printf("s(struct %s_args)", funcname) > sysent
else
printf("s(struct %s_%s_args)", compatwrap, funcname) > sysent
if (compatwrap == "")
wfn = sprintf("%s", funcname);
else
wfn = sprintf("%s(%s)", compatwrap, funcname);
printf(",\n\t %s },", wfn) > sysent
for (i = 0; i < (33 - length(wfn)) / 8; i++)
printf("\t") > sysent
if (compatwrap == "")
printf("/* %d = %s */\n", syscall, funcalias) > sysent
else
printf("/* %d = %s %s */\n", syscall, compatwrap,
funcalias) > sysent
# output syscall name for names table
if (compatwrap == "")
printf("\t\"%s\",\t\t\t/* %d = %s */\n", funcalias, syscall,
funcalias) > sysnames
else
printf("\t\"%s_%s\",\t/* %d = %s %s */\n", compatwrap,
funcalias, syscall, compatwrap, funcalias) > sysnames
# output syscall number of header, if appropriate
if (nodefs == "" || nodefs == "NOARGS")
printf("#define\t%s%s\t%d\n", constprefix, funcalias,
syscall) > sysnumhdr
else if (nodefs != "NODEF")
printf("\t\t\t\t/* %d is %s %s */\n", syscall,
compatwrap, funcalias) > sysnumhdr
# output syscall argument structure, if it has arguments
if (argc != 0 && nodefs != "NOARGS") {
if (compatwrap == "")
printf("\nstruct %s_args {\n", funcname) > sysarghdr
else
printf("\nstruct %s_%s_args {\n", compatwrap,
funcname) > sysarghdr
for (i = 1; i <= argc; i++)
printf("\tsyscallarg(%s) %s;\n", argtype[i],
argname[i]) > sysarghdr
printf("};\n") > sysarghdr
}
}
$2 == "STD" {
parseline()
putent("", sysdcl, "")
syscall++
next
}
$2 == "NODEF" || $2 == "NOARGS" {
parseline()
putent($2, sysdcl, "")
syscall++
next
}
$2 == "OBSOL" || $2 == "UNIMPL" {
if ($2 == "OBSOL")
comment="obsolete"
else
comment="unimplemented"
for (i = 3; i <= NF; i++)
comment=comment " " $i
printf("\t{ 0, 0,\n\t nosys },\t\t\t\t/* %d = %s */\n", \
syscall, comment) > sysent
printf("\t\"#%d (%s)\",\t\t/* %d = %s */\n", \
syscall, comment, syscall, comment) > sysnames
if ($2 != "UNIMPL")
printf("\t\t\t\t/* %d is %s */\n", syscall, comment) > sysnumhdr
syscall++
next
}
{
for (i = 1; i <= ncompat; i++) {
if ($2 == compat_upper[i]) {
parseline();
putent("COMMENT", compat_file[i], compat[i])
syscall++
next
}
}
printf "%s: line %d: unrecognized keyword %s\n", infile, NR, $2
exit 1
}
END {
printf "\n#undef\tsyscallarg\n" > sysarghdr
for (i = 1; i <= ncompat; i++) {
printf("\n#else /* %s */\n", compat_upper[i]) > compat_file[i]
printf("#define %s(func) nosys\n", compat[i]) > \
compat_file[i]
printf("#endif /* %s */\n\n", compat_upper[i]) > compat_file[i]
}
printf("};\n\n") > sysent
printf("int\tn%s= sizeof(%s) / sizeof(%s[0]);\n", switchname,
switchname, switchname) > sysent
printf("};\n") > sysnames
} '
cat $sysdcl $syscompat_files $sysent > $syssw
#chmod 444 $sysnames $syshdr $syssw

345
sys/kern/subr_autoconf.c Normal file
View File

@ -0,0 +1,345 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* 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, Lawrence Berkeley Laboratories.
*
* 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.
*
* @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
*
* from: $Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp $ (LBL)
*/
#include <sys/param.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <libkern/libkern.h>
/*
* Autoconfiguration subroutines.
*/
/*
* ioconf.c exports exactly two names: cfdata and cfroots. All system
* devices and drivers are found via these tables.
*/
extern struct cfdata cfdata[];
extern short cfroots[];
#define ROOT ((struct device *)NULL)
struct matchinfo {
cfmatch_t fn;
struct device *parent;
void *aux;
struct cfdata *match;
int pri;
};
/*
* Apply the matching function and choose the best. This is used
* a few times and we want to keep the code small.
*/
static void
mapply(m, cf)
register struct matchinfo *m;
register struct cfdata *cf;
{
register int pri;
if (m->fn != NULL)
pri = (*m->fn)(m->parent, cf, m->aux);
else
pri = (*cf->cf_driver->cd_match)(m->parent, cf, m->aux);
if (pri > m->pri) {
m->match = cf;
m->pri = pri;
}
}
/*
* Iterate over all potential children of some device, calling the given
* function (default being the child's match function) for each one.
* Nonzero returns are matches; the highest value returned is considered
* the best match. Return the `found child' if we got a match, or NULL
* otherwise. The `aux' pointer is simply passed on through.
*
* Note that this function is designed so that it can be used to apply
* an arbitrary function to all potential children (its return value
* can be ignored).
*/
struct cfdata *
config_search(fn, parent, aux)
cfmatch_t fn;
register struct device *parent;
void *aux;
{
register struct cfdata *cf;
register short *p;
struct matchinfo m;
m.fn = fn;
m.parent = parent;
m.aux = aux;
m.match = NULL;
m.pri = 0;
for (cf = cfdata; cf->cf_driver; cf++) {
/*
* Skip cf if no longer eligible, otherwise scan through
* parents for one matching `parent', and try match function.
*/
if (cf->cf_fstate == FSTATE_FOUND)
continue;
for (p = cf->cf_parents; *p >= 0; p++)
if (parent->dv_cfdata == &cfdata[*p])
mapply(&m, cf);
}
return (m.match);
}
/*
* Find the given root device.
* This is much like config_search, but there is no parent.
*/
struct cfdata *
config_rootsearch(fn, rootname, aux)
register cfmatch_t fn;
register char *rootname;
register void *aux;
{
register struct cfdata *cf;
register short *p;
struct matchinfo m;
m.fn = fn;
m.parent = ROOT;
m.aux = aux;
m.match = NULL;
m.pri = 0;
/*
* Look at root entries for matching name. We do not bother
* with found-state here since only one root should ever be
* searched (and it must be done first).
*/
for (p = cfroots; *p >= 0; p++) {
cf = &cfdata[*p];
if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
mapply(&m, cf);
}
return (m.match);
}
static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
/*
* The given `aux' argument describes a device that has been found
* on the given parent, but not necessarily configured. Locate the
* configuration data for that device (using the cd_match configuration
* driver function) and attach it, and return true. If the device was
* not configured, call the given `print' function and return 0.
*/
int
config_found(parent, aux, print)
struct device *parent;
void *aux;
cfprint_t print;
{
struct cfdata *cf;
if ((cf = config_search((cfmatch_t)NULL, parent, aux)) != NULL) {
config_attach(parent, cf, aux, print);
return (1);
}
printf(msgs[(*print)(aux, parent->dv_xname)]);
return (0);
}
/*
* As above, but for root devices.
*/
int
config_rootfound(rootname, aux)
char *rootname;
void *aux;
{
struct cfdata *cf;
if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL) {
config_attach(ROOT, cf, aux, (cfprint_t)NULL);
return (1);
}
printf("root device %s not configured\n", rootname);
return (0);
}
/* just like sprintf(buf, "%d") except that it works from the end */
static char *
number(ep, n)
register char *ep;
register int n;
{
*--ep = 0;
while (n >= 10) {
*--ep = (n % 10) + '0';
n /= 10;
}
*--ep = n + '0';
return (ep);
}
/*
* Attach a found device. Allocates memory for device variables.
*/
void
config_attach(parent, cf, aux, print)
register struct device *parent;
register struct cfdata *cf;
register void *aux;
cfprint_t print;
{
register struct device *dev;
register struct cfdriver *cd;
register size_t lname, lunit;
register char *xunit;
int myunit;
char num[10];
static struct device **nextp = &alldevs;
cd = cf->cf_driver;
if (cd->cd_devsize < sizeof(struct device))
panic("config_attach");
myunit = cf->cf_unit;
if (cf->cf_fstate == FSTATE_NOTFOUND)
cf->cf_fstate = FSTATE_FOUND;
else
cf->cf_unit++;
/* compute length of name and decimal expansion of unit number */
lname = strlen(cd->cd_name);
xunit = number(&num[sizeof num], myunit);
lunit = &num[sizeof num] - xunit;
if (lname + lunit >= sizeof(dev->dv_xname))
panic("config_attach: device name too long");
/* get memory for all device vars */
dev = (struct device *)malloc(cd->cd_devsize, M_DEVBUF, M_WAITOK);
/* XXX cannot wait! */
bzero(dev, cd->cd_devsize);
*nextp = dev; /* link up */
nextp = &dev->dv_next;
dev->dv_class = cd->cd_class;
dev->dv_cfdata = cf;
dev->dv_unit = myunit;
bcopy(cd->cd_name, dev->dv_xname, lname);
bcopy(xunit, dev->dv_xname + lname, lunit);
dev->dv_parent = parent;
if (parent == ROOT)
printf("%s (root)", dev->dv_xname);
else {
printf("%s at %s", dev->dv_xname, parent->dv_xname);
(void) (*print)(aux, (char *)0);
}
/* put this device in the devices array */
if (dev->dv_unit >= cd->cd_ndevs) {
/*
* Need to expand the array.
*/
int old = cd->cd_ndevs, oldbytes, new, newbytes;
void **nsp;
if (old == 0) {
new = max(MINALLOCSIZE / sizeof(void *),
dev->dv_unit + 1);
newbytes = new * sizeof(void *);
nsp = malloc(newbytes, M_DEVBUF, M_WAITOK); /*XXX*/
bzero(nsp, newbytes);
} else {
new = cd->cd_ndevs;
do {
new *= 2;
} while (new <= dev->dv_unit);
oldbytes = old * sizeof(void *);
newbytes = new * sizeof(void *);
nsp = malloc(newbytes, M_DEVBUF, M_WAITOK); /*XXX*/
bcopy(cd->cd_devs, nsp, oldbytes);
bzero(&nsp[old], newbytes - oldbytes);
free(cd->cd_devs, M_DEVBUF);
}
cd->cd_ndevs = new;
cd->cd_devs = nsp;
}
if (cd->cd_devs[dev->dv_unit])
panic("config_attach: duplicate %s", dev->dv_xname);
cd->cd_devs[dev->dv_unit] = dev;
/*
* Before attaching, clobber any unfound devices that are
* otherwise identical.
*/
for (cf = cfdata; cf->cf_driver; cf++)
if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit &&
cf->cf_fstate == FSTATE_NOTFOUND)
cf->cf_fstate = FSTATE_FOUND;
(*cd->cd_attach)(parent, dev, aux);
}
/*
* Attach an event. These must come from initially-zero space (see
* commented-out assignments below), but that occurs naturally for
* device instance variables.
*/
void
evcnt_attach(dev, name, ev)
struct device *dev;
const char *name;
struct evcnt *ev;
{
static struct evcnt **nextp = &allevents;
#ifdef DIAGNOSTIC
if (strlen(name) >= sizeof(ev->ev_name))
panic("evcnt_attach");
#endif
/* ev->ev_next = NULL; */
ev->ev_dev = dev;
/* ev->ev_count = 0; */
strcpy(ev->ev_name, name);
*nextp = ev;
nextp = &ev->ev_next;
}

238
sys/kern/subr_log.c Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. 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 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.
*
* @(#)subr_log.c 8.3 (Berkeley) 2/14/95
*/
/*
* Error log buffer for kernel printf's.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/ioctl.h>
#include <sys/msgbuf.h>
#include <sys/file.h>
#define LOG_RDPRI (PZERO + 1)
#define LOG_ASYNC 0x04
#define LOG_RDWAIT 0x08
struct logsoftc {
int sc_state; /* see above for possibilities */
struct selinfo sc_selp; /* process waiting on select call */
int sc_pgid; /* process/group for async I/O */
} logsoftc;
int log_open; /* also used in log() */
/*ARGSUSED*/
int
logopen(dev, flags, mode, p)
dev_t dev;
int flags, mode;
struct proc *p;
{
register struct msgbuf *mbp = msgbufp;
if (log_open)
return (EBUSY);
log_open = 1;
logsoftc.sc_pgid = p->p_pid; /* signal process only */
/*
* Potential race here with putchar() but since putchar should be
* called by autoconf, msg_magic should be initialized by the time
* we get here.
*/
if (mbp->msg_magic != MSG_MAGIC) {
register int i;
mbp->msg_magic = MSG_MAGIC;
mbp->msg_bufx = mbp->msg_bufr = 0;
for (i=0; i < MSG_BSIZE; i++)
mbp->msg_bufc[i] = 0;
}
return (0);
}
/*ARGSUSED*/
int
logclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
log_open = 0;
logsoftc.sc_state = 0;
return (0);
}
/*ARGSUSED*/
int
logread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register struct msgbuf *mbp = msgbufp;
register long l;
register int s;
int error = 0;
s = splhigh();
while (mbp->msg_bufr == mbp->msg_bufx) {
if (flag & IO_NDELAY) {
splx(s);
return (EWOULDBLOCK);
}
logsoftc.sc_state |= LOG_RDWAIT;
if (error = tsleep((caddr_t)mbp, LOG_RDPRI | PCATCH,
"klog", 0)) {
splx(s);
return (error);
}
}
splx(s);
logsoftc.sc_state &= ~LOG_RDWAIT;
while (uio->uio_resid > 0) {
l = mbp->msg_bufx - mbp->msg_bufr;
if (l < 0)
l = MSG_BSIZE - mbp->msg_bufr;
l = min(l, uio->uio_resid);
if (l == 0)
break;
error = uiomove((caddr_t)&mbp->msg_bufc[mbp->msg_bufr],
(int)l, uio);
if (error)
break;
mbp->msg_bufr += l;
if (mbp->msg_bufr < 0 || mbp->msg_bufr >= MSG_BSIZE)
mbp->msg_bufr = 0;
}
return (error);
}
/*ARGSUSED*/
int
logselect(dev, rw, p)
dev_t dev;
int rw;
struct proc *p;
{
int s = splhigh();
switch (rw) {
case FREAD:
if (msgbufp->msg_bufr != msgbufp->msg_bufx) {
splx(s);
return (1);
}
selrecord(p, &logsoftc.sc_selp);
break;
}
splx(s);
return (0);
}
void
logwakeup()
{
struct proc *p;
if (!log_open)
return;
selwakeup(&logsoftc.sc_selp);
if (logsoftc.sc_state & LOG_ASYNC) {
if (logsoftc.sc_pgid < 0)
gsignal(-logsoftc.sc_pgid, SIGIO);
else if (p = pfind(logsoftc.sc_pgid))
psignal(p, SIGIO);
}
if (logsoftc.sc_state & LOG_RDWAIT) {
wakeup((caddr_t)msgbufp);
logsoftc.sc_state &= ~LOG_RDWAIT;
}
}
/*ARGSUSED*/
int
logioctl(dev, com, data, flag, p)
dev_t dev;
u_long com;
caddr_t data;
int flag;
struct proc *p;
{
long l;
int s;
switch (com) {
/* return number of characters immediately available */
case FIONREAD:
s = splhigh();
l = msgbufp->msg_bufx - msgbufp->msg_bufr;
splx(s);
if (l < 0)
l += MSG_BSIZE;
*(int *)data = l;
break;
case FIONBIO:
break;
case FIOASYNC:
if (*(int *)data)
logsoftc.sc_state |= LOG_ASYNC;
else
logsoftc.sc_state &= ~LOG_ASYNC;
break;
case TIOCSPGRP:
logsoftc.sc_pgid = *(int *)data;
break;
case TIOCGPGRP:
*(int *)data = logsoftc.sc_pgid;
break;
default:
return (-1);
}
return (0);
}

606
sys/kern/subr_prf.c Normal file
View File

@ -0,0 +1,606 @@
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)subr_prf.c 8.4 (Berkeley) 5/4/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/reboot.h>
#include <sys/msgbuf.h>
#include <sys/proc.h>
#include <sys/ioctl.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/tty.h>
#include <sys/tprintf.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
/*
* Note that stdarg.h and the ANSI style va_start macro is used for both
* ANSI and traditional C compilers.
*/
#include <machine/stdarg.h>
#ifdef KADB
#include <machine/kdbparam.h>
#endif
#define TOCONS 0x01
#define TOTTY 0x02
#define TOLOG 0x04
struct tty *constty; /* pointer to console "window" tty */
extern cnputc(); /* standard console putc */
int (*v_putc)() = cnputc; /* routine to putc on virtual console */
void logpri __P((int level));
static void putchar __P((int ch, int flags, struct tty *tp));
static char *ksprintn __P((u_long num, int base, int *len));
void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
int consintr = 1; /* Ok to handle console interrupts? */
/*
* Variable panicstr contains argument to first call to panic; used as flag
* to indicate that the kernel has already called panic.
*/
const char *panicstr;
/*
* Panic is called on unresolvable fatal errors. It prints "panic: mesg",
* and then reboots. If we are called twice, then we avoid trying to sync
* the disks as this often leads to recursive panics.
*/
#ifdef __GNUC__
volatile void boot(int flags); /* boot() does not return */
volatile /* panic() does not return */
#endif
void
#ifdef __STDC__
panic(const char *fmt, ...)
#else
panic(fmt, va_alist)
char *fmt;
#endif
{
int bootopt;
va_list ap;
bootopt = RB_AUTOBOOT | RB_DUMP;
if (panicstr)
bootopt |= RB_NOSYNC;
else
panicstr = fmt;
va_start(ap, fmt);
printf("panic: %r\n", fmt, ap);
va_end(ap);
#ifdef KGDB
kgdb_panic();
#endif
#ifdef KADB
if (boothowto & RB_KDB)
kdbpanic();
#endif
boot(bootopt);
}
/*
* Warn that a system table is full.
*/
void
tablefull(tab)
const char *tab;
{
log(LOG_ERR, "%s: table is full\n", tab);
}
/*
* Uprintf prints to the controlling terminal for the current process.
* It may block if the tty queue is overfull. No message is printed if
* the queue does not clear in a reasonable time.
*/
void
#ifdef __STDC__
uprintf(const char *fmt, ...)
#else
uprintf(fmt, va_alist)
char *fmt;
#endif
{
register struct proc *p = curproc;
va_list ap;
if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
va_start(ap, fmt);
kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
va_end(ap);
}
}
tpr_t
tprintf_open(p)
register struct proc *p;
{
if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
SESSHOLD(p->p_session);
return ((tpr_t) p->p_session);
}
return ((tpr_t) NULL);
}
void
tprintf_close(sess)
tpr_t sess;
{
if (sess)
SESSRELE((struct session *) sess);
}
/*
* tprintf prints on the controlling terminal associated
* with the given session.
*/
void
#ifdef __STDC__
tprintf(tpr_t tpr, const char *fmt, ...)
#else
tprintf(tpr, fmt, va_alist)
tpr_t tpr;
char *fmt;
#endif
{
register struct session *sess = (struct session *)tpr;
struct tty *tp = NULL;
int flags = TOLOG;
va_list ap;
logpri(LOG_INFO);
if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
flags |= TOTTY;
tp = sess->s_ttyp;
}
va_start(ap, fmt);
kprintf(fmt, flags, tp, ap);
va_end(ap);
logwakeup();
}
/*
* Ttyprintf displays a message on a tty; it should be used only by
* the tty driver, or anything that knows the underlying tty will not
* be revoke(2)'d away. Other callers should use tprintf.
*/
void
#ifdef __STDC__
ttyprintf(struct tty *tp, const char *fmt, ...)
#else
ttyprintf(tp, fmt, va_alist)
struct tty *tp;
char *fmt;
#endif
{
va_list ap;
va_start(ap, fmt);
kprintf(fmt, TOTTY, tp, ap);
va_end(ap);
}
extern int log_open;
/*
* Log writes to the log buffer, and guarantees not to sleep (so can be
* called by interrupt routines). If there is no process reading the
* log yet, it writes to the console also.
*/
void
#ifdef __STDC__
log(int level, const char *fmt, ...)
#else
log(level, fmt, va_alist)
int level;
char *fmt;
#endif
{
register int s;
va_list ap;
s = splhigh();
logpri(level);
va_start(ap, fmt);
kprintf(fmt, TOLOG, NULL, ap);
splx(s);
va_end(ap);
if (!log_open) {
va_start(ap, fmt);
kprintf(fmt, TOCONS, NULL, ap);
va_end(ap);
}
logwakeup();
}
void
logpri(level)
int level;
{
register int ch;
register char *p;
putchar('<', TOLOG, NULL);
for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
putchar(ch, TOLOG, NULL);
putchar('>', TOLOG, NULL);
}
void
#ifdef __STDC__
addlog(const char *fmt, ...)
#else
addlog(fmt, va_alist)
char *fmt;
#endif
{
register int s;
va_list ap;
s = splhigh();
va_start(ap, fmt);
kprintf(fmt, TOLOG, NULL, ap);
splx(s);
va_end(ap);
if (!log_open) {
va_start(ap, fmt);
kprintf(fmt, TOCONS, NULL, ap);
va_end(ap);
}
logwakeup();
}
void
#ifdef __STDC__
printf(const char *fmt, ...)
#else
printf(fmt, va_alist)
char *fmt;
#endif
{
va_list ap;
register int savintr;
savintr = consintr; /* disable interrupts */
consintr = 0;
va_start(ap, fmt);
kprintf(fmt, TOCONS | TOLOG, NULL, ap);
va_end(ap);
if (!panicstr)
logwakeup();
consintr = savintr; /* reenable interrupts */
}
/*
* Scaled down version of printf(3).
*
* Two additional formats:
*
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "<base><arg>*");
*
* where <base> is the output base expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
* the first of which gives the bit number to be inspected (origin 1), and
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3<BITTWO,BITONE>
*
* The format %r passes an additional format string and argument list
* recursively. Its usage is:
*
* fn(char *fmt, ...)
* {
* va_list ap;
* va_start(ap, fmt);
* printf("prefix: %r: suffix\n", fmt, ap);
* va_end(ap);
* }
*
* Space or zero padding and a field width are supported for the numeric
* formats only.
*/
void
kprintf(fmt, flags, tp, ap)
register const char *fmt;
int flags;
struct tty *tp;
va_list ap;
{
register char *p, *q;
register int ch, n;
u_long ul;
int base, lflag, tmp, width;
char padc;
for (;;) {
padc = ' ';
width = 0;
while ((ch = *(u_char *)fmt++) != '%') {
if (ch == '\0')
return;
putchar(ch, flags, tp);
}
lflag = 0;
reswitch: switch (ch = *(u_char *)fmt++) {
case '0':
padc = '0';
goto reswitch;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (width = 0;; ++fmt) {
width = width * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
goto reswitch;
case 'l':
lflag = 1;
goto reswitch;
case 'b':
ul = va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
putchar(ch, flags, tp);
if (!ul)
break;
for (tmp = 0; n = *p++;) {
if (ul & (1 << (n - 1))) {
putchar(tmp ? ',' : '<', flags, tp);
for (; (n = *p) > ' '; ++p)
putchar(n, flags, tp);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
putchar('>', flags, tp);
break;
case 'c':
putchar(va_arg(ap, int), flags, tp);
break;
case 'r':
p = va_arg(ap, char *);
kprintf(p, flags, tp, va_arg(ap, va_list));
break;
case 's':
p = va_arg(ap, char *);
while (ch = *p++)
putchar(ch, flags, tp);
break;
case 'd':
ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
if ((long)ul < 0) {
putchar('-', flags, tp);
ul = -(long)ul;
}
base = 10;
goto number;
case 'o':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 8;
goto number;
case 'u':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 10;
goto number;
case 'x':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 16;
number: p = ksprintn(ul, base, &tmp);
if (width && (width -= tmp) > 0)
while (width--)
putchar(padc, flags, tp);
while (ch = *p--)
putchar(ch, flags, tp);
break;
default:
putchar('%', flags, tp);
if (lflag)
putchar('l', flags, tp);
/* FALLTHROUGH */
case '%':
putchar(ch, flags, tp);
}
}
}
/*
* Print a character on console or users terminal. If destination is
* the console then the last MSGBUFS characters are saved in msgbuf for
* inspection later.
*/
static void
putchar(c, flags, tp)
register int c;
int flags;
struct tty *tp;
{
extern int msgbufmapped;
register struct msgbuf *mbp;
if (panicstr)
constty = NULL;
if ((flags & TOCONS) && tp == NULL && constty) {
tp = constty;
flags |= TOTTY;
}
if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
(flags & TOCONS) && tp == constty)
constty = NULL;
if ((flags & TOLOG) &&
c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
mbp = msgbufp;
if (mbp->msg_magic != MSG_MAGIC) {
bzero((caddr_t)mbp, sizeof(*mbp));
mbp->msg_magic = MSG_MAGIC;
}
mbp->msg_bufc[mbp->msg_bufx++] = c;
if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
mbp->msg_bufx = 0;
/* If the buffer is full, keep the most recent data. */
if (mbp->msg_bufr == mbp->msg_bufx) {
if (++mbp->msg_bufr >= MSG_BSIZE)
mbp->msg_bufr = 0;
}
}
if ((flags & TOCONS) && constty == NULL && c != '\0')
(*v_putc)(c);
}
/*
* Scaled down version of sprintf(3).
*/
#ifdef __STDC__
sprintf(char *buf, const char *cfmt, ...)
#else
sprintf(buf, cfmt, va_alist)
char *buf, *cfmt;
#endif
{
register const char *fmt = cfmt;
register char *p, *bp;
register int ch, base;
u_long ul;
int lflag;
va_list ap;
va_start(ap, cfmt);
for (bp = buf; ; ) {
while ((ch = *(u_char *)fmt++) != '%')
if ((*bp++ = ch) == '\0')
return ((bp - buf) - 1);
lflag = 0;
reswitch: switch (ch = *(u_char *)fmt++) {
case 'l':
lflag = 1;
goto reswitch;
case 'c':
*bp++ = va_arg(ap, int);
break;
case 's':
p = va_arg(ap, char *);
while (*bp++ = *p++)
continue;
--bp;
break;
case 'd':
ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
if ((long)ul < 0) {
*bp++ = '-';
ul = -(long)ul;
}
base = 10;
goto number;
break;
case 'o':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 8;
goto number;
break;
case 'u':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 10;
goto number;
break;
case 'x':
ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
base = 16;
number: for (p = ksprintn(ul, base, NULL); ch = *p--;)
*bp++ = ch;
break;
default:
*bp++ = '%';
if (lflag)
*bp++ = 'l';
/* FALLTHROUGH */
case '%':
*bp++ = ch;
}
}
va_end(ap);
}
/*
* Put a number (base <= 16) in a buffer in reverse order; return an
* optional length and a pointer to the NULL terminated (preceded?)
* buffer.
*/
static char *
ksprintn(ul, base, lenp)
register u_long ul;
register int base, *lenp;
{ /* A long in base 8, plus NULL. */
static char buf[sizeof(long) * NBBY / 3 + 2];
register char *p;
p = buf;
do {
*++p = "0123456789abcdef"[ul % base];
} while (ul /= base);
if (lenp)
*lenp = p - buf;
return (p);
}

262
sys/kern/subr_prof.c Normal file
View File

@ -0,0 +1,262 @@
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. 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 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.
*
* @(#)subr_prof.c 8.4 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <machine/cpu.h>
#ifdef GPROF
#include <sys/malloc.h>
#include <sys/gmon.h>
/*
* Froms is actually a bunch of unsigned shorts indexing tos
*/
struct gmonparam _gmonparam = { GMON_PROF_OFF };
extern char etext[];
void
kmstartup()
{
char *cp;
struct gmonparam *p = &_gmonparam;
/*
* Round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
*/
p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
p->textsize = p->highpc - p->lowpc;
printf("Profiling kernel, textsize=%d [%x..%x]\n",
p->textsize, p->lowpc, p->highpc);
p->kcountsize = p->textsize / HISTFRACTION;
p->hashfraction = HASHFRACTION;
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
if (p->tolimit < MINARCS)
p->tolimit = MINARCS;
else if (p->tolimit > MAXARCS)
p->tolimit = MAXARCS;
p->tossize = p->tolimit * sizeof(struct tostruct);
cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
M_GPROF, M_NOWAIT);
if (cp == 0) {
printf("No memory for profiling.\n");
return;
}
bzero(cp, p->kcountsize + p->tossize + p->fromssize);
p->tos = (struct tostruct *)cp;
cp += p->tossize;
p->kcount = (u_short *)cp;
cp += p->kcountsize;
p->froms = (u_short *)cp;
}
/*
* Return kernel profiling information.
*/
int
sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
{
struct gmonparam *gp = &_gmonparam;
int error;
/* all sysctl names at this level are terminal */
if (namelen != 1)
return (ENOTDIR); /* overloaded */
switch (name[0]) {
case GPROF_STATE:
error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
if (error)
return (error);
if (gp->state == GMON_PROF_OFF)
stopprofclock(&proc0);
else
startprofclock(&proc0);
return (0);
case GPROF_COUNT:
return (sysctl_struct(oldp, oldlenp, newp, newlen,
gp->kcount, gp->kcountsize));
case GPROF_FROMS:
return (sysctl_struct(oldp, oldlenp, newp, newlen,
gp->froms, gp->fromssize));
case GPROF_TOS:
return (sysctl_struct(oldp, oldlenp, newp, newlen,
gp->tos, gp->tossize));
case GPROF_GMONPARAM:
return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
default:
return (EOPNOTSUPP);
}
/* NOTREACHED */
}
#endif /* GPROF */
/*
* Profiling system call.
*
* The scale factor is a fixed point number with 16 bits of fraction, so that
* 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
*/
/* ARGSUSED */
int
profil(p, uap, retval)
struct proc *p;
register struct profil_args /* {
syscallarg(caddr_t) samples;
syscallarg(u_int) size;
syscallarg(u_int) offset;
syscallarg(u_int) scale;
} */ *uap;
register_t *retval;
{
register struct uprof *upp;
int s;
if (SCARG(uap, scale) > (1 << 16))
return (EINVAL);
if (SCARG(uap, scale) == 0) {
stopprofclock(p);
return (0);
}
upp = &p->p_stats->p_prof;
/* Block profile interrupts while changing state. */
s = splstatclock();
upp->pr_off = SCARG(uap, offset);
upp->pr_scale = SCARG(uap, scale);
upp->pr_base = SCARG(uap, samples);
upp->pr_size = SCARG(uap, size);
startprofclock(p);
splx(s);
return (0);
}
/*
* Scale is a fixed-point number with the binary point 16 bits
* into the value, and is <= 1.0. pc is at most 32 bits, so the
* intermediate result is at most 48 bits.
*/
#define PC_TO_INDEX(pc, prof) \
((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
(u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
/*
* Collect user-level profiling statistics; called on a profiling tick,
* when a process is running in user-mode. This routine may be called
* from an interrupt context. We try to update the user profiling buffers
* cheaply with fuswintr() and suswintr(). If that fails, we revert to
* an AST that will vector us to trap() with a context in which copyin
* and copyout will work. Trap will then call addupc_task().
*
* Note that we may (rarely) not get around to the AST soon enough, and
* lose profile ticks when the next tick overwrites this one, but in this
* case the system is overloaded and the profile is probably already
* inaccurate.
*/
void
addupc_intr(p, pc, ticks)
register struct proc *p;
register u_long pc;
u_int ticks;
{
register struct uprof *prof;
register caddr_t addr;
register u_int i;
register int v;
if (ticks == 0)
return;
prof = &p->p_stats->p_prof;
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
return; /* out of range; ignore */
addr = prof->pr_base + i;
if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
prof->pr_addr = pc;
prof->pr_ticks = ticks;
need_proftick(p);
}
}
/*
* Much like before, but we can afford to take faults here. If the
* update fails, we simply turn off profiling.
*/
void
addupc_task(p, pc, ticks)
register struct proc *p;
register u_long pc;
u_int ticks;
{
register struct uprof *prof;
register caddr_t addr;
register u_int i;
u_short v;
/* Testing P_PROFIL may be unnecessary, but is certainly safe. */
if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
return;
prof = &p->p_stats->p_prof;
if (pc < prof->pr_off ||
(i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
return;
addr = prof->pr_base + i;
if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
v += ticks;
if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
return;
}
stopprofclock(p);
}

117
sys/kern/subr_xxx.c Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)subr_xxx.c 8.3 (Berkeley) 3/29/95
*/
/*
* Miscellaneous trivial functions, including many
* that are often inline-expanded or done in assembler.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <machine/cpu.h>
/*
* Unsupported device function (e.g. writing to read-only device).
*/
int
enodev()
{
return (ENODEV);
}
/*
* Unconfigured device function; driver not configured.
*/
int
enxio()
{
return (ENXIO);
}
/*
* Unsupported ioctl function.
*/
int
enoioctl()
{
return (ENOTTY);
}
/*
* Unsupported system function.
* This is used for an otherwise-reasonable operation
* that is not supported by the current system binary.
*/
int
enosys()
{
return (ENOSYS);
}
/*
* Return error for operation not supported
* on a specific object or file type.
*/
int
eopnotsupp()
{
return (EOPNOTSUPP);
}
/*
* Return error for an inval operation
* on a specific object or file type.
*/
int
einval()
{
return (EINVAL);
}
/*
* Generic null operation, always returns success.
*/
int
nullop()
{
return (0);
}

690
sys/kern/sys_generic.c Normal file
View File

@ -0,0 +1,690 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)sys_generic.c 8.9 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/filedesc.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/proc.h>
#include <sys/socketvar.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#include <sys/mount.h>
#include <sys/syscallargs.h>
/*
* Read system call.
*/
/* ARGSUSED */
int
read(p, uap, retval)
struct proc *p;
register struct read_args /* {
syscallarg(int) fd;
syscallarg(char *) buf;
syscallarg(u_int) nbyte;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp = p->p_fd;
struct uio auio;
struct iovec aiov;
long cnt, error = 0;
#ifdef KTRACE
struct iovec ktriov;
#endif
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
(fp->f_flag & FREAD) == 0)
return (EBADF);
aiov.iov_base = (caddr_t)SCARG(uap, buf);
aiov.iov_len = SCARG(uap, nbyte);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = SCARG(uap, nbyte);
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
#ifdef KTRACE
/*
* if tracing, save a copy of iovec
*/
if (KTRPOINT(p, KTR_GENIO))
ktriov = aiov;
#endif
cnt = SCARG(uap, nbyte);
if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
if (auio.uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
cnt -= auio.uio_resid;
#ifdef KTRACE
if (KTRPOINT(p, KTR_GENIO) && error == 0)
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov,
cnt, error);
#endif
*retval = cnt;
return (error);
}
/*
* Scatter read system call.
*/
int
readv(p, uap, retval)
struct proc *p;
register struct readv_args /* {
syscallarg(int) fd;
syscallarg(struct iovec *) iovp;
syscallarg(u_int) iovcnt;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp = p->p_fd;
struct uio auio;
register struct iovec *iov;
struct iovec *needfree;
struct iovec aiov[UIO_SMALLIOV];
long i, cnt, error = 0;
u_int iovlen;
#ifdef KTRACE
struct iovec *ktriov = NULL;
#endif
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
(fp->f_flag & FREAD) == 0)
return (EBADF);
/* note: can't use iovlen until iovcnt is validated */
iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
if (SCARG(uap, iovcnt) > UIO_MAXIOV)
return (EINVAL);
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else {
iov = aiov;
needfree = NULL;
}
auio.uio_iov = iov;
auio.uio_iovcnt = SCARG(uap, iovcnt);
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
goto done;
auio.uio_resid = 0;
for (i = 0; i < SCARG(uap, iovcnt); i++) {
if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
#ifdef KTRACE
/*
* if tracing, save a copy of iovec
*/
if (KTRPOINT(p, KTR_GENIO)) {
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
}
#endif
cnt = auio.uio_resid;
if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
if (auio.uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
cnt -= auio.uio_resid;
#ifdef KTRACE
if (ktriov != NULL) {
if (error == 0)
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov,
cnt, error);
FREE(ktriov, M_TEMP);
}
#endif
*retval = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
return (error);
}
/*
* Write system call
*/
int
write(p, uap, retval)
struct proc *p;
register struct write_args /* {
syscallarg(int) fd;
syscallarg(char *) buf;
syscallarg(u_int) nbyte;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp = p->p_fd;
struct uio auio;
struct iovec aiov;
long cnt, error = 0;
#ifdef KTRACE
struct iovec ktriov;
#endif
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
(fp->f_flag & FWRITE) == 0)
return (EBADF);
aiov.iov_base = (caddr_t)SCARG(uap, buf);
aiov.iov_len = SCARG(uap, nbyte);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = SCARG(uap, nbyte);
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
#ifdef KTRACE
/*
* if tracing, save a copy of iovec
*/
if (KTRPOINT(p, KTR_GENIO))
ktriov = aiov;
#endif
cnt = SCARG(uap, nbyte);
if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
if (auio.uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
if (error == EPIPE)
psignal(p, SIGPIPE);
}
cnt -= auio.uio_resid;
#ifdef KTRACE
if (KTRPOINT(p, KTR_GENIO) && error == 0)
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
&ktriov, cnt, error);
#endif
*retval = cnt;
return (error);
}
/*
* Gather write system call
*/
int
writev(p, uap, retval)
struct proc *p;
register struct writev_args /* {
syscallarg(int) fd;
syscallarg(struct iovec *) iovp;
syscallarg(u_int) iovcnt;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp = p->p_fd;
struct uio auio;
register struct iovec *iov;
struct iovec *needfree;
struct iovec aiov[UIO_SMALLIOV];
long i, cnt, error = 0;
u_int iovlen;
#ifdef KTRACE
struct iovec *ktriov = NULL;
#endif
if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
(fp->f_flag & FWRITE) == 0)
return (EBADF);
/* note: can't use iovlen until iovcnt is validated */
iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
if (SCARG(uap, iovcnt) > UIO_MAXIOV)
return (EINVAL);
MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
needfree = iov;
} else {
iov = aiov;
needfree = NULL;
}
auio.uio_iov = iov;
auio.uio_iovcnt = SCARG(uap, iovcnt);
auio.uio_rw = UIO_WRITE;
auio.uio_segflg = UIO_USERSPACE;
auio.uio_procp = p;
if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
goto done;
auio.uio_resid = 0;
for (i = 0; i < SCARG(uap, iovcnt); i++) {
if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
error = EINVAL;
goto done;
}
auio.uio_resid += iov->iov_len;
iov++;
}
#ifdef KTRACE
/*
* if tracing, save a copy of iovec
*/
if (KTRPOINT(p, KTR_GENIO)) {
MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
}
#endif
cnt = auio.uio_resid;
if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
if (auio.uio_resid != cnt && (error == ERESTART ||
error == EINTR || error == EWOULDBLOCK))
error = 0;
if (error == EPIPE)
psignal(p, SIGPIPE);
}
cnt -= auio.uio_resid;
#ifdef KTRACE
if (ktriov != NULL) {
if (error == 0)
ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
ktriov, cnt, error);
FREE(ktriov, M_TEMP);
}
#endif
*retval = cnt;
done:
if (needfree)
FREE(needfree, M_IOV);
return (error);
}
/*
* Ioctl system call
*/
/* ARGSUSED */
int
ioctl(p, uap, retval)
struct proc *p;
register struct ioctl_args /* {
syscallarg(int) fd;
syscallarg(u_long) com;
syscallarg(caddr_t) data;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp;
register u_long com;
register int error;
register u_int size;
caddr_t data, memp;
int tmp;
#define STK_PARAMS 128
char stkbuf[STK_PARAMS];
fdp = p->p_fd;
if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
return (EBADF);
if ((fp->f_flag & (FREAD | FWRITE)) == 0)
return (EBADF);
switch (com = SCARG(uap, com)) {
case FIONCLEX:
fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
return (0);
case FIOCLEX:
fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
return (0);
}
/*
* Interpret high order word to find amount of data to be
* copied to/from the user's address space.
*/
size = IOCPARM_LEN(com);
if (size > IOCPARM_MAX)
return (ENOTTY);
memp = NULL;
if (size > sizeof (stkbuf)) {
memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
data = memp;
} else
data = stkbuf;
if (com&IOC_IN) {
if (size) {
error = copyin(SCARG(uap, data), data, (u_int)size);
if (error) {
if (memp)
free(memp, M_IOCTLOPS);
return (error);
}
} else
*(caddr_t *)data = SCARG(uap, data);
} else if ((com&IOC_OUT) && size)
/*
* Zero the buffer so the user always
* gets back something deterministic.
*/
bzero(data, size);
else if (com&IOC_VOID)
*(caddr_t *)data = SCARG(uap, data);
switch (com) {
case FIONBIO:
if (tmp = *(int *)data)
fp->f_flag |= FNONBLOCK;
else
fp->f_flag &= ~FNONBLOCK;
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
break;
case FIOASYNC:
if (tmp = *(int *)data)
fp->f_flag |= FASYNC;
else
fp->f_flag &= ~FASYNC;
error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
break;
case FIOSETOWN:
tmp = *(int *)data;
if (fp->f_type == DTYPE_SOCKET) {
((struct socket *)fp->f_data)->so_pgid = tmp;
error = 0;
break;
}
if (tmp <= 0) {
tmp = -tmp;
} else {
struct proc *p1 = pfind(tmp);
if (p1 == 0) {
error = ESRCH;
break;
}
tmp = p1->p_pgrp->pg_id;
}
error = (*fp->f_ops->fo_ioctl)
(fp, TIOCSPGRP, (caddr_t)&tmp, p);
break;
case FIOGETOWN:
if (fp->f_type == DTYPE_SOCKET) {
error = 0;
*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
break;
}
error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
*(int *)data = -*(int *)data;
break;
default:
error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
/*
* Copy any data to user, size was
* already set and checked above.
*/
if (error == 0 && (com&IOC_OUT) && size)
error = copyout(data, SCARG(uap, data), (u_int)size);
break;
}
if (memp)
free(memp, M_IOCTLOPS);
return (error);
}
int selwait, nselcoll;
/*
* Select system call.
*/
int
select(p, uap, retval)
register struct proc *p;
register struct select_args /* {
syscallarg(u_int) nd;
syscallarg(fd_set *) in;
syscallarg(fd_set *) ou;
syscallarg(fd_set *) ex;
syscallarg(struct timeval *) tv;
} */ *uap;
register_t *retval;
{
fd_set ibits[3], obits[3];
struct timeval atv;
int s, ncoll, error, timo = 0;
u_int ni;
bzero((caddr_t)ibits, sizeof(ibits));
bzero((caddr_t)obits, sizeof(obits));
if (SCARG(uap, nd) > FD_SETSIZE)
return (EINVAL);
if (SCARG(uap, nd) > p->p_fd->fd_nfiles) {
/* forgiving; slightly wrong */
SCARG(uap, nd) = p->p_fd->fd_nfiles;
}
ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask);
#define getbits(name, x) \
if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
(caddr_t)&ibits[x], ni))) \
goto done;
getbits(in, 0);
getbits(ou, 1);
getbits(ex, 2);
#undef getbits
if (SCARG(uap, tv)) {
error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv,
sizeof (atv));
if (error)
goto done;
if (itimerfix(&atv)) {
error = EINVAL;
goto done;
}
s = splclock();
timevaladd(&atv, (struct timeval *)&time);
splx(s);
}
retry:
ncoll = nselcoll;
p->p_flag |= P_SELECT;
error = selscan(p, ibits, obits, SCARG(uap, nd), retval);
if (error || *retval)
goto done;
s = splhigh();
if (SCARG(uap, tv)) {
if (timercmp(&time, &atv, >=)) {
splx(s);
goto done;
}
/*
* If poll wait was tiny, this could be zero; we will
* have to round it up to avoid sleeping forever. If
* we retry below, the timercmp above will get us out.
* Note that if wait was 0, the timercmp will prevent
* us from getting here the first time.
*/
timo = hzto(&atv);
if (timo == 0)
timo = 1;
}
if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
splx(s);
goto retry;
}
p->p_flag &= ~P_SELECT;
error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
splx(s);
if (error == 0)
goto retry;
done:
p->p_flag &= ~P_SELECT;
/* select is not restarted after signals... */
if (error == ERESTART)
error = EINTR;
if (error == EWOULDBLOCK)
error = 0;
#define putbits(name, x) \
if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
(caddr_t)SCARG(uap, name), ni))) \
error = error2;
if (error == 0) {
int error2;
putbits(in, 0);
putbits(ou, 1);
putbits(ex, 2);
#undef putbits
}
return (error);
}
int
selscan(p, ibits, obits, nfd, retval)
struct proc *p;
fd_set *ibits, *obits;
int nfd;
register_t *retval;
{
register struct filedesc *fdp = p->p_fd;
register int msk, i, j, fd;
register fd_mask bits;
struct file *fp;
int n = 0;
static int flag[3] = { FREAD, FWRITE, 0 };
for (msk = 0; msk < 3; msk++) {
for (i = 0; i < nfd; i += NFDBITS) {
bits = ibits[msk].fds_bits[i/NFDBITS];
while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
bits &= ~(1 << j);
fp = fdp->fd_ofiles[fd];
if (fp == NULL)
return (EBADF);
if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
FD_SET(fd, &obits[msk]);
n++;
}
}
}
}
*retval = n;
return (0);
}
/*ARGSUSED*/
int
seltrue(dev, flag, p)
dev_t dev;
int flag;
struct proc *p;
{
return (1);
}
/*
* Record a select request.
*/
void
selrecord(selector, sip)
struct proc *selector;
struct selinfo *sip;
{
struct proc *p;
pid_t mypid;
mypid = selector->p_pid;
if (sip->si_pid == mypid)
return;
if (sip->si_pid && (p = pfind(sip->si_pid)) &&
p->p_wchan == (caddr_t)&selwait)
sip->si_flags |= SI_COLL;
else
sip->si_pid = mypid;
}
/*
* Do a wakeup when a selectable event occurs.
*/
void
selwakeup(sip)
register struct selinfo *sip;
{
register struct proc *p;
int s;
if (sip->si_pid == 0)
return;
if (sip->si_flags & SI_COLL) {
nselcoll++;
sip->si_flags &= ~SI_COLL;
wakeup((caddr_t)&selwait);
}
p = pfind(sip->si_pid);
sip->si_pid = 0;
if (p != NULL) {
s = splhigh();
if (p->p_wchan == (caddr_t)&selwait) {
if (p->p_stat == SSLEEP)
setrunnable(p);
else
unsleep(p);
} else if (p->p_flag & P_SELECT)
p->p_flag &= ~P_SELECT;
splx(s);
}
}

203
sys/kern/sys_socket.c Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 1982, 1986, 1990, 1993
* The Regents of the University of California. 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 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.
*
* @(#)sys_socket.c 8.3 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <net/if.h>
#include <net/route.h>
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;
struct ucred *cred;
{
return (soreceive((struct socket *)fp->f_data, (struct mbuf **)0,
uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
}
/* ARGSUSED */
int
soo_write(fp, uio, cred)
struct file *fp;
struct uio *uio;
struct ucred *cred;
{
return (sosend((struct socket *)fp->f_data, (struct mbuf *)0,
uio, (struct mbuf *)0, (struct mbuf *)0, 0));
}
int
soo_ioctl(fp, cmd, data, p)
struct file *fp;
u_long cmd;
register caddr_t data;
struct proc *p;
{
register struct socket *so = (struct socket *)fp->f_data;
switch (cmd) {
case FIONBIO:
if (*(int *)data)
so->so_state |= SS_NBIO;
else
so->so_state &= ~SS_NBIO;
return (0);
case FIOASYNC:
if (*(int *)data) {
so->so_state |= SS_ASYNC;
so->so_rcv.sb_flags |= SB_ASYNC;
so->so_snd.sb_flags |= SB_ASYNC;
} else {
so->so_state &= ~SS_ASYNC;
so->so_rcv.sb_flags &= ~SB_ASYNC;
so->so_snd.sb_flags &= ~SB_ASYNC;
}
return (0);
case FIONREAD:
*(int *)data = so->so_rcv.sb_cc;
return (0);
case SIOCSPGRP:
so->so_pgid = *(int *)data;
return (0);
case SIOCGPGRP:
*(int *)data = so->so_pgid;
return (0);
case SIOCATMARK:
*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
return (0);
}
/*
* Interface/routing/protocol specific ioctls:
* interface and routing ioctls should have a
* different entry since a socket's unnecessary
*/
if (IOCGROUP(cmd) == 'i')
return (ifioctl(so, 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));
}
int
soo_select(fp, which, p)
struct file *fp;
int which;
struct proc *p;
{
register struct socket *so = (struct socket *)fp->f_data;
register int s = splnet();
switch (which) {
case FREAD:
if (soreadable(so)) {
splx(s);
return (1);
}
selrecord(p, &so->so_rcv.sb_sel);
so->so_rcv.sb_flags |= SB_SEL;
break;
case FWRITE:
if (sowriteable(so)) {
splx(s);
return (1);
}
selrecord(p, &so->so_snd.sb_sel);
so->so_snd.sb_flags |= SB_SEL;
break;
case 0:
if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) {
splx(s);
return (1);
}
selrecord(p, &so->so_rcv.sb_sel);
so->so_rcv.sb_flags |= SB_SEL;
break;
}
splx(s);
return (0);
}
int
soo_stat(so, ub)
register struct socket *so;
register struct stat *ub;
{
bzero((caddr_t)ub, sizeof (*ub));
ub->st_mode = S_IFSOCK;
return ((*so->so_proto->pr_usrreq)(so, PRU_SENSE,
(struct mbuf *)ub, (struct mbuf *)0,
(struct mbuf *)0));
}
/* ARGSUSED */
int
soo_close(fp, p)
struct file *fp;
struct proc *p;
{
int error = 0;
if (fp->f_data)
error = soclose((struct socket *)fp->f_data);
fp->f_data = 0;
return (error);
}

279
sys/kern/syscalls.c Normal file
View File

@ -0,0 +1,279 @@
/*
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
* created from @(#)syscalls.master 8.6 (Berkeley) 3/30/95
*/
char *syscallnames[] = {
"syscall", /* 0 = syscall */
"exit", /* 1 = exit */
"fork", /* 2 = fork */
"read", /* 3 = read */
"write", /* 4 = write */
"open", /* 5 = open */
"close", /* 6 = close */
"wait4", /* 7 = wait4 */
"compat_43_creat", /* 8 = compat_43 creat */
"link", /* 9 = link */
"unlink", /* 10 = unlink */
"#11 (obsolete execv)", /* 11 = obsolete execv */
"chdir", /* 12 = chdir */
"fchdir", /* 13 = fchdir */
"mknod", /* 14 = mknod */
"chmod", /* 15 = chmod */
"chown", /* 16 = chown */
"break", /* 17 = break */
"getfsstat", /* 18 = getfsstat */
"compat_43_lseek", /* 19 = compat_43 lseek */
"getpid", /* 20 = getpid */
"mount", /* 21 = mount */
"unmount", /* 22 = unmount */
"setuid", /* 23 = setuid */
"getuid", /* 24 = getuid */
"geteuid", /* 25 = geteuid */
"ptrace", /* 26 = ptrace */
"recvmsg", /* 27 = recvmsg */
"sendmsg", /* 28 = sendmsg */
"recvfrom", /* 29 = recvfrom */
"accept", /* 30 = accept */
"getpeername", /* 31 = getpeername */
"getsockname", /* 32 = getsockname */
"access", /* 33 = access */
"chflags", /* 34 = chflags */
"fchflags", /* 35 = fchflags */
"sync", /* 36 = sync */
"kill", /* 37 = kill */
"compat_43_stat", /* 38 = compat_43 stat */
"getppid", /* 39 = getppid */
"compat_43_lstat", /* 40 = compat_43 lstat */
"dup", /* 41 = dup */
"pipe", /* 42 = pipe */
"getegid", /* 43 = getegid */
"profil", /* 44 = profil */
#ifdef KTRACE
"ktrace", /* 45 = ktrace */
#else
"#45 (unimplemented ktrace)", /* 45 = unimplemented ktrace */
#endif
"sigaction", /* 46 = sigaction */
"getgid", /* 47 = getgid */
"sigprocmask", /* 48 = sigprocmask */
"getlogin", /* 49 = getlogin */
"setlogin", /* 50 = setlogin */
"acct", /* 51 = acct */
"sigpending", /* 52 = sigpending */
"sigaltstack", /* 53 = sigaltstack */
"ioctl", /* 54 = ioctl */
"reboot", /* 55 = reboot */
"revoke", /* 56 = revoke */
"symlink", /* 57 = symlink */
"readlink", /* 58 = readlink */
"execve", /* 59 = execve */
"umask", /* 60 = umask */
"chroot", /* 61 = chroot */
"compat_43_fstat", /* 62 = compat_43 fstat */
"compat_43_getkerninfo", /* 63 = compat_43 getkerninfo */
"compat_43_getpagesize", /* 64 = compat_43 getpagesize */
"msync", /* 65 = msync */
"vfork", /* 66 = vfork */
"#67 (obsolete vread)", /* 67 = obsolete vread */
"#68 (obsolete vwrite)", /* 68 = obsolete vwrite */
"sbrk", /* 69 = sbrk */
"sstk", /* 70 = sstk */
"compat_43_mmap", /* 71 = compat_43 mmap */
"vadvise", /* 72 = vadvise */
"munmap", /* 73 = munmap */
"mprotect", /* 74 = mprotect */
"madvise", /* 75 = madvise */
"#76 (obsolete vhangup)", /* 76 = obsolete vhangup */
"#77 (obsolete vlimit)", /* 77 = obsolete vlimit */
"mincore", /* 78 = mincore */
"getgroups", /* 79 = getgroups */
"setgroups", /* 80 = setgroups */
"getpgrp", /* 81 = getpgrp */
"setpgid", /* 82 = setpgid */
"setitimer", /* 83 = setitimer */
"compat_43_wait", /* 84 = compat_43 wait */
"swapon", /* 85 = swapon */
"getitimer", /* 86 = getitimer */
"compat_43_gethostname", /* 87 = compat_43 gethostname */
"compat_43_sethostname", /* 88 = compat_43 sethostname */
"getdtablesize", /* 89 = getdtablesize */
"dup2", /* 90 = dup2 */
"#91 (unimplemented getdopt)", /* 91 = unimplemented getdopt */
"fcntl", /* 92 = fcntl */
"select", /* 93 = select */
"#94 (unimplemented setdopt)", /* 94 = unimplemented setdopt */
"fsync", /* 95 = fsync */
"setpriority", /* 96 = setpriority */
"socket", /* 97 = socket */
"connect", /* 98 = connect */
"compat_43_accept", /* 99 = compat_43 accept */
"getpriority", /* 100 = getpriority */
"compat_43_send", /* 101 = compat_43 send */
"compat_43_recv", /* 102 = compat_43 recv */
"sigreturn", /* 103 = sigreturn */
"bind", /* 104 = bind */
"setsockopt", /* 105 = setsockopt */
"listen", /* 106 = listen */
"#107 (obsolete vtimes)", /* 107 = obsolete vtimes */
"compat_43_sigvec", /* 108 = compat_43 sigvec */
"compat_43_sigblock", /* 109 = compat_43 sigblock */
"compat_43_sigsetmask", /* 110 = compat_43 sigsetmask */
"sigsuspend", /* 111 = sigsuspend */
"compat_43_sigstack", /* 112 = compat_43 sigstack */
"compat_43_recvmsg", /* 113 = compat_43 recvmsg */
"compat_43_sendmsg", /* 114 = compat_43 sendmsg */
#ifdef TRACE
"vtrace", /* 115 = vtrace */
#else
"#115 (obsolete vtrace)", /* 115 = obsolete vtrace */
#endif
"gettimeofday", /* 116 = gettimeofday */
"getrusage", /* 117 = getrusage */
"getsockopt", /* 118 = getsockopt */
#ifdef vax
"resuba", /* 119 = resuba */
#else
"#119 (unimplemented resuba)", /* 119 = unimplemented resuba */
#endif
"readv", /* 120 = readv */
"writev", /* 121 = writev */
"settimeofday", /* 122 = settimeofday */
"fchown", /* 123 = fchown */
"fchmod", /* 124 = fchmod */
"compat_43_recvfrom", /* 125 = compat_43 recvfrom */
"compat_43_setreuid", /* 126 = compat_43 setreuid */
"compat_43_setregid", /* 127 = compat_43 setregid */
"rename", /* 128 = rename */
"compat_43_truncate", /* 129 = compat_43 truncate */
"compat_43_ftruncate", /* 130 = compat_43 ftruncate */
"flock", /* 131 = flock */
"mkfifo", /* 132 = mkfifo */
"sendto", /* 133 = sendto */
"shutdown", /* 134 = shutdown */
"socketpair", /* 135 = socketpair */
"mkdir", /* 136 = mkdir */
"rmdir", /* 137 = rmdir */
"utimes", /* 138 = utimes */
"#139 (obsolete 4.2 sigreturn)", /* 139 = obsolete 4.2 sigreturn */
"adjtime", /* 140 = adjtime */
"compat_43_getpeername", /* 141 = compat_43 getpeername */
"compat_43_gethostid", /* 142 = compat_43 gethostid */
"compat_43_sethostid", /* 143 = compat_43 sethostid */
"compat_43_getrlimit", /* 144 = compat_43 getrlimit */
"compat_43_setrlimit", /* 145 = compat_43 setrlimit */
"compat_43_killpg", /* 146 = compat_43 killpg */
"setsid", /* 147 = setsid */
"quotactl", /* 148 = quotactl */
"compat_43_quota", /* 149 = compat_43 quota */
"compat_43_getsockname", /* 150 = compat_43 getsockname */
"#151 (unimplemented)", /* 151 = unimplemented */
"#152 (unimplemented)", /* 152 = unimplemented */
"#153 (unimplemented)", /* 153 = unimplemented */
"#154 (unimplemented)", /* 154 = unimplemented */
#ifdef NFS
"nfssvc", /* 155 = nfssvc */
#else
"#155 (unimplemented nfssvc)", /* 155 = unimplemented nfssvc */
#endif
"compat_43_getdirentries", /* 156 = compat_43 getdirentries */
"statfs", /* 157 = statfs */
"fstatfs", /* 158 = fstatfs */
"#159 (unimplemented)", /* 159 = unimplemented */
"#160 (unimplemented)", /* 160 = unimplemented */
#ifdef NFS
"getfh", /* 161 = getfh */
#else
"#161 (unimplemented getfh)", /* 161 = unimplemented getfh */
#endif
"#162 (unimplemented getdomainname)", /* 162 = unimplemented getdomainname */
"#163 (unimplemented setdomainname)", /* 163 = unimplemented setdomainname */
"#164 (unimplemented)", /* 164 = unimplemented */
"#165 (unimplemented)", /* 165 = unimplemented */
"#166 (unimplemented)", /* 166 = unimplemented */
"#167 (unimplemented)", /* 167 = unimplemented */
"#168 (unimplemented)", /* 168 = unimplemented */
"#169 (unimplemented semsys)", /* 169 = unimplemented semsys */
"#170 (unimplemented msgsys)", /* 170 = unimplemented msgsys */
#if defined(SYSVSHM) && !defined(alpha)
"compat_43_shmsys", /* 171 = compat_43 shmsys */
#else
"#171 (unimplemented shmsys)", /* 171 = unimplemented shmsys */
#endif
"#172 (unimplemented)", /* 172 = unimplemented */
"#173 (unimplemented)", /* 173 = unimplemented */
"#174 (unimplemented)", /* 174 = unimplemented */
"#175 (unimplemented)", /* 175 = unimplemented */
"#176 (unimplemented)", /* 176 = unimplemented */
"#177 (unimplemented)", /* 177 = unimplemented */
"#178 (unimplemented)", /* 178 = unimplemented */
"#179 (unimplemented)", /* 179 = unimplemented */
"#180 (unimplemented)", /* 180 = unimplemented */
"setgid", /* 181 = setgid */
"setegid", /* 182 = setegid */
"seteuid", /* 183 = seteuid */
#ifdef LFS
"lfs_bmapv", /* 184 = lfs_bmapv */
"lfs_markv", /* 185 = lfs_markv */
"lfs_segclean", /* 186 = lfs_segclean */
"lfs_segwait", /* 187 = lfs_segwait */
#else
"#184 (unimplemented lfs_bmapv)", /* 184 = unimplemented lfs_bmapv */
"#185 (unimplemented lfs_markv)", /* 185 = unimplemented lfs_markv */
"#186 (unimplemented lfs_segclean)", /* 186 = unimplemented lfs_segclean */
"#187 (unimplemented lfs_segwait)", /* 187 = unimplemented lfs_segwait */
#endif
"stat", /* 188 = stat */
"fstat", /* 189 = fstat */
"lstat", /* 190 = lstat */
"pathconf", /* 191 = pathconf */
"fpathconf", /* 192 = fpathconf */
"#193 (unimplemented)", /* 193 = unimplemented */
"getrlimit", /* 194 = getrlimit */
"setrlimit", /* 195 = setrlimit */
"getdirentries", /* 196 = getdirentries */
"mmap", /* 197 = mmap */
"__syscall", /* 198 = __syscall */
"lseek", /* 199 = lseek */
"truncate", /* 200 = truncate */
"ftruncate", /* 201 = ftruncate */
"__sysctl", /* 202 = __sysctl */
"mlock", /* 203 = mlock */
"munlock", /* 204 = munlock */
"undelete", /* 205 = undelete */
"#206 (unimplemented)", /* 206 = unimplemented */
"#207 (unimplemented)", /* 207 = unimplemented */
"#208 (unimplemented)", /* 208 = unimplemented */
"#209 (unimplemented)", /* 209 = unimplemented */
"#210 (unimplemented)", /* 210 = unimplemented */
"#211 (unimplemented)", /* 211 = unimplemented */
"#212 (unimplemented)", /* 212 = unimplemented */
"#213 (unimplemented)", /* 213 = unimplemented */
"#214 (unimplemented)", /* 214 = unimplemented */
"#215 (unimplemented)", /* 215 = unimplemented */
"#216 (unimplemented)", /* 216 = unimplemented */
"#217 (unimplemented)", /* 217 = unimplemented */
"#218 (unimplemented)", /* 218 = unimplemented */
"#219 (unimplemented)", /* 219 = unimplemented */
"#220 (unimplemented semctl)", /* 220 = unimplemented semctl */
"#221 (unimplemented semget)", /* 221 = unimplemented semget */
"#222 (unimplemented semop)", /* 222 = unimplemented semop */
"#223 (unimplemented semconfig)", /* 223 = unimplemented semconfig */
"#224 (unimplemented msgctl)", /* 224 = unimplemented msgctl */
"#225 (unimplemented msgget)", /* 225 = unimplemented msgget */
"#226 (unimplemented msgsnd)", /* 226 = unimplemented msgsnd */
"#227 (unimplemented msgrcv)", /* 227 = unimplemented msgrcv */
#if defined(SYSVSHM) && 0
"shmat", /* 228 = shmat */
"shmctl", /* 229 = shmctl */
"shmdt", /* 230 = shmdt */
"shmget", /* 231 = shmget */
#else
"#228 (unimplemented shmat)", /* 228 = unimplemented shmat */
"#229 (unimplemented shmctl)", /* 229 = unimplemented shmctl */
"#230 (unimplemented shmdt)", /* 230 = unimplemented shmdt */
"#231 (unimplemented shmget)", /* 231 = unimplemented shmget */
#endif
};

12
sys/kern/syscalls.conf Normal file
View File

@ -0,0 +1,12 @@
# @(#)syscalls.conf 8.1 (Berkeley) 2/14/95
sysnames="syscalls.c"
sysnumhdr="../sys/syscall.h"
syssw="init_sysent.c"
sysarghdr="../sys/syscallargs.h"
compatopts="compat_43"
libcompatopts=""
switchname="sysent"
namesname="syscallnames"
constprefix="SYS_"

355
sys/kern/syscalls.master Normal file
View File

@ -0,0 +1,355 @@
@(#)syscalls.master 8.6 (Berkeley) 3/30/95
; System call name/number "master" file.
; (See syscalls.conf to see what it is processed into.)
;
; Fields: number type [type-dependent ...]
; number system call number, must be in order
; type one of STD, OBSOL, UNIMPL, NODEF, NOARGS, or one of
; the compatibility options defined in syscalls.conf.
;
; types:
; STD always included
; OBSOL obsolete, not included in system
; UNIMPL unimplemented, not included in system
; NODEF included, but don't define the syscall number
; NOARGS included, but don't define the syscall args structure
;
; The compat options are defined in the syscalls.conf file, and the
; compat option name is prefixed to the syscall name. Other than
; that, they're like NODEF (for 'compat' options), or STD (for
; 'libcompat' options).
;
; The type-dependent arguments are as follows:
; For STD, NODEF, NOARGS, and compat syscalls:
; { pseudo-proto } [alias]
; For other syscalls:
; [comment]
;
; #ifdef's, etc. may be included, and are copied to the output files.
; #include's are copied to the syscall switch definition file only.
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signal.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
; Reserved/unimplemented system calls in the range 0-150 inclusive
; are reserved for use in future Berkeley releases.
; Additional system calls implemented in vendor and other
; redistributions should be placed in the reserved range at the end
; of the current calls.
0 STD { int nosys(void); } syscall
1 STD { int exit(int rval); }
2 STD { int fork(void); }
3 STD { int read(int fd, char *buf, u_int nbyte); }
4 STD { int write(int fd, char *buf, u_int nbyte); }
5 STD { int open(char *path, int flags, int mode); }
6 STD { int close(int fd); }
7 STD { int wait4(int pid, int *status, int options, \
struct rusage *rusage); }
8 COMPAT_43 { int creat(char *path, int mode); }
9 STD { int link(char *path, char *link); }
10 STD { int unlink(char *path); }
11 OBSOL execv
12 STD { int chdir(char *path); }
13 STD { int fchdir(int fd); }
14 STD { int mknod(char *path, int mode, int dev); }
15 STD { int chmod(char *path, int mode); }
16 STD { int chown(char *path, int uid, int gid); }
17 STD { int obreak(char *nsize); } break
18 STD { int getfsstat(struct statfs *buf, long bufsize, \
int flags); }
19 COMPAT_43 { long lseek(int fd, long offset, int whence); }
20 STD { pid_t getpid(void); }
21 STD { int mount(char *type, char *path, int flags, \
caddr_t data); }
22 STD { int unmount(char *path, int flags); }
23 STD { int setuid(uid_t uid); }
24 STD { uid_t getuid(void); }
25 STD { uid_t geteuid(void); }
26 STD { int ptrace(int req, pid_t pid, caddr_t addr, \
int data); }
27 STD { int recvmsg(int s, struct msghdr *msg, int flags); }
28 STD { int sendmsg(int s, caddr_t msg, int flags); }
29 STD { int recvfrom(int s, caddr_t buf, size_t len, \
int flags, caddr_t from, int *fromlenaddr); }
30 STD { int accept(int s, caddr_t name, int *anamelen); }
31 STD { int getpeername(int fdes, caddr_t asa, int *alen); }
32 STD { int getsockname(int fdes, caddr_t asa, int *alen); }
33 STD { int access(char *path, int flags); }
34 STD { int chflags(char *path, int flags); }
35 STD { int fchflags(int fd, int flags); }
36 STD { int sync(void); }
37 STD { int kill(int pid, int signum); }
38 COMPAT_43 { int stat(char *path, struct ostat *ub); }
39 STD { pid_t getppid(void); }
40 COMPAT_43 { int lstat(char *path, struct ostat *ub); }
41 STD { int dup(u_int fd); }
42 STD { int pipe(void); }
43 STD { gid_t getegid(void); }
44 STD { int profil(caddr_t samples, u_int size, \
u_int offset, u_int scale); }
#ifdef KTRACE
45 STD { int ktrace(char *fname, int ops, int facs, \
int pid); }
#else
45 UNIMPL ktrace
#endif
46 STD { int sigaction(int signum, struct sigaction *nsa, \
struct sigaction *osa); }
47 STD { gid_t getgid(void); }
48 STD { int sigprocmask(int how, sigset_t mask); }
49 STD { int getlogin(char *namebuf, u_int namelen); }
50 STD { int setlogin(char *namebuf); }
51 STD { int acct(char *path); }
52 STD { int sigpending(void); }
53 STD { int sigaltstack(struct sigaltstack *nss, \
struct sigaltstack *oss); }
54 STD { int ioctl(int fd, u_long com, caddr_t data); }
55 STD { int reboot(int opt); }
56 STD { int revoke(char *path); }
57 STD { int symlink(char *path, char *link); }
58 STD { int readlink(char *path, char *buf, int count); }
59 STD { int execve(char *path, char **argp, char **envp); }
60 STD { int umask(int newmask); }
61 STD { int chroot(char *path); }
62 COMPAT_43 { int fstat(int fd, struct ostat *sb); }
63 COMPAT_43 { int getkerninfo(int op, char *where, int *size, \
int arg); }
64 COMPAT_43 { int getpagesize(void); }
65 STD { int msync(caddr_t addr, int len); }
66 STD { int vfork(void); }
67 OBSOL vread
68 OBSOL vwrite
69 STD { int sbrk(int incr); }
70 STD { int sstk(int incr); }
71 COMPAT_43 { int mmap(caddr_t addr, int len, int prot, \
int flags, int fd, long pos); }
72 STD { int ovadvise(int anom); } vadvise
73 STD { int munmap(caddr_t addr, int len); }
74 STD { int mprotect(caddr_t addr, int len, int prot); }
75 STD { int madvise(caddr_t addr, int len, int behav); }
76 OBSOL vhangup
77 OBSOL vlimit
78 STD { int mincore(caddr_t addr, int len, char *vec); }
79 STD { int getgroups(u_int gidsetsize, gid_t *gidset); }
80 STD { int setgroups(u_int gidsetsize, gid_t *gidset); }
81 STD { int getpgrp(void); }
82 STD { int setpgid(int pid, int pgid); }
83 STD { int setitimer(u_int which, struct itimerval *itv, \
struct itimerval *oitv); }
84 COMPAT_43 { int wait(void); }
85 STD { int swapon(char *name); }
86 STD { int getitimer(u_int which, struct itimerval *itv); }
87 COMPAT_43 { int gethostname(char *hostname, u_int len); }
88 COMPAT_43 { int sethostname(char *hostname, u_int len); }
89 STD { int getdtablesize(void); }
90 STD { int dup2(u_int from, u_int to); }
91 UNIMPL getdopt
92 STD { int fcntl(int fd, int cmd, void *arg); }
93 STD { int select(u_int nd, fd_set *in, fd_set *ou, \
fd_set *ex, struct timeval *tv); }
94 UNIMPL setdopt
95 STD { int fsync(int fd); }
96 STD { int setpriority(int which, int who, int prio); }
97 STD { int socket(int domain, int type, int protocol); }
98 STD { int connect(int s, caddr_t name, int namelen); }
99 COMPAT_43 { int accept(int s, caddr_t name, int *anamelen); }
100 STD { int getpriority(int which, int who); }
101 COMPAT_43 { int send(int s, caddr_t buf, int len, int flags); }
102 COMPAT_43 { int recv(int s, caddr_t buf, int len, int flags); }
103 STD { int sigreturn(struct sigcontext *sigcntxp); }
104 STD { int bind(int s, caddr_t name, int namelen); }
105 STD { int setsockopt(int s, int level, int name, \
caddr_t val, int valsize); }
106 STD { int listen(int s, int backlog); }
107 OBSOL vtimes
108 COMPAT_43 { int sigvec(int signum, struct sigvec *nsv, \
struct sigvec *osv); }
109 COMPAT_43 { int sigblock(int mask); }
110 COMPAT_43 { int sigsetmask(int mask); }
111 STD { int sigsuspend(int mask); }
112 COMPAT_43 { int sigstack(struct sigstack *nss, \
struct sigstack *oss); }
113 COMPAT_43 { int recvmsg(int s, struct omsghdr *msg, int flags); }
114 COMPAT_43 { int sendmsg(int s, caddr_t msg, int flags); }
#ifdef TRACE
115 STD { int vtrace(int request, int value); }
#else
115 OBSOL vtrace
#endif
116 STD { int gettimeofday(struct timeval *tp, \
struct timezone *tzp); }
117 STD { int getrusage(int who, struct rusage *rusage); }
118 STD { int getsockopt(int s, int level, int name, \
caddr_t val, int *avalsize); }
#ifdef vax
119 STD { int resuba(int value); }
#else
119 UNIMPL resuba
#endif
120 STD { int readv(int fd, struct iovec *iovp, u_int iovcnt); }
121 STD { int writev(int fd, struct iovec *iovp, \
u_int iovcnt); }
122 STD { int settimeofday(struct timeval *tv, \
struct timezone *tzp); }
123 STD { int fchown(int fd, int uid, int gid); }
124 STD { int fchmod(int fd, int mode); }
125 COMPAT_43 { int recvfrom(int s, caddr_t buf, size_t len, \
int flags, caddr_t from, int *fromlenaddr); }
126 COMPAT_43 { int setreuid(int ruid, int euid); }
127 COMPAT_43 { int setregid(int rgid, int egid); }
128 STD { int rename(char *from, char *to); }
129 COMPAT_43 { int truncate(char *path, long length); }
130 COMPAT_43 { int ftruncate(int fd, long length); }
131 STD { int flock(int fd, int how); }
132 STD { int mkfifo(char *path, int mode); }
133 STD { int sendto(int s, caddr_t buf, size_t len, \
int flags, caddr_t to, int tolen); }
134 STD { int shutdown(int s, int how); }
135 STD { int socketpair(int domain, int type, int protocol, \
int *rsv); }
136 STD { int mkdir(char *path, int mode); }
137 STD { int rmdir(char *path); }
138 STD { int utimes(char *path, struct timeval *tptr); }
139 OBSOL 4.2 sigreturn
140 STD { int adjtime(struct timeval *delta, \
struct timeval *olddelta); }
141 COMPAT_43 { int getpeername(int fdes, caddr_t asa, int *alen); }
142 COMPAT_43 { int32_t gethostid(void); }
143 COMPAT_43 { int sethostid(int32_t hostid); }
144 COMPAT_43 { int getrlimit(u_int which, struct ogetrlimit *rlp); }
145 COMPAT_43 { int setrlimit(u_int which, struct ogetrlimit *rlp); }
146 COMPAT_43 { int killpg(int pgid, int signum); }
147 STD { int setsid(void); }
148 STD { int quotactl(char *path, int cmd, int uid, \
caddr_t arg); }
149 COMPAT_43 { int quota(void); }
150 COMPAT_43 { int getsockname(int fdec, caddr_t asa, int *alen); }
; Syscalls 151-180 inclusive are reserved for vendor-specific
; system calls. (This includes various calls added for compatibity
; with other Unix variants.)
; Some of these calls are now supported by BSD...
151 UNIMPL
152 UNIMPL
153 UNIMPL
154 UNIMPL
#ifdef NFS
155 STD { int nfssvc(int flag, caddr_t argp); }
#else
155 UNIMPL nfssvc
#endif
156 COMPAT_43 { int getdirentries(int fd, char *buf, u_int count, \
long *basep); }
157 STD { int statfs(char *path, struct statfs *buf); }
158 STD { int fstatfs(int fd, struct statfs *buf); }
159 UNIMPL
160 UNIMPL
#ifdef NFS
161 STD { int getfh(char *fname, fhandle_t *fhp); }
#else
161 UNIMPL getfh
#endif
162 UNIMPL getdomainname
163 UNIMPL setdomainname
164 UNIMPL
165 UNIMPL
166 UNIMPL
167 UNIMPL
168 UNIMPL
169 UNIMPL semsys
170 UNIMPL msgsys
; XXX more generally, never on machines where sizeof(void *) != sizeof(int)
#if defined(SYSVSHM) && !defined(alpha)
171 COMPAT_43 { int shmsys(int which, int a2, int a3, int a4); }
#else
171 UNIMPL shmsys
#endif
172 UNIMPL
173 UNIMPL
174 UNIMPL
175 UNIMPL
176 UNIMPL
177 UNIMPL
178 UNIMPL
179 UNIMPL
180 UNIMPL
; Syscalls 180-209 are used by/reserved for BSD
181 STD { int setgid(gid_t gid); }
182 STD { int setegid(gid_t egid); }
183 STD { int seteuid(uid_t euid); }
#ifdef LFS
184 STD { int lfs_bmapv(fsid_t *fsidp, \
struct block_info *blkiov, int blkcnt); }
185 STD { int lfs_markv(fsid_t *fsidp, \
struct block_info *blkiov, int blkcnt); }
186 STD { int lfs_segclean(fsid_t *fsidp, u_long segment); }
187 STD { int lfs_segwait(fsid_t *fsidp, struct timeval *tv); }
#else
184 UNIMPL lfs_bmapv
185 UNIMPL lfs_markv
186 UNIMPL lfs_segclean
187 UNIMPL lfs_segwait
#endif
188 STD { int stat(char *path, struct stat *ub); }
189 STD { int fstat(int fd, struct stat *sb); }
190 STD { int lstat(char *path, struct stat *ub); }
191 STD { int pathconf(char *path, int name); }
192 STD { int fpathconf(int fd, int name); }
193 UNIMPL
194 STD { int getrlimit(u_int which, struct rlimit *rlp); }
195 STD { int setrlimit(u_int which, struct rlimit *rlp); }
196 STD { int getdirentries(int fd, char *buf, u_int count, \
long *basep); }
197 STD { caddr_t mmap(caddr_t addr, size_t len, int prot, \
int flags, int fd, long pad, off_t pos); }
198 STD { int nosys(void); } __syscall
199 STD { off_t lseek(int fd, int pad, off_t offset, \
int whence); }
200 STD { int truncate(char *path, int pad, off_t length); }
201 STD { int ftruncate(int fd, int pad, off_t length); }
202 STD { int __sysctl(int *name, u_int namelen, void *old, \
size_t *oldlenp, void *new, size_t newlen); }
203 STD { int mlock(caddr_t addr, size_t len); }
204 STD { int munlock(caddr_t addr, size_t len); }
205 STD { int undelete(char *path); }
206 UNIMPL
207 UNIMPL
208 UNIMPL
209 UNIMPL
; Syscalls 210-219 are used by/reserved for vendor-specific system calls
210 UNIMPL
211 UNIMPL
212 UNIMPL
213 UNIMPL
214 UNIMPL
215 UNIMPL
216 UNIMPL
217 UNIMPL
218 UNIMPL
219 UNIMPL
; System calls 220-240 are reserved for use by BSD
220 UNIMPL semctl
221 UNIMPL semget
222 UNIMPL semop
223 UNIMPL semconfig
224 UNIMPL msgctl
225 UNIMPL msgget
226 UNIMPL msgsnd
227 UNIMPL msgrcv
#if defined(SYSVSHM) && 0
228 STD { int shmat(int shmid, void *shmaddr, int shmflg); }
229 STD { int shmctl(int shmid, int cmd, \
struct shmid_ds *buf); }
230 STD { int shmdt(void *shmaddr); }
231 STD { int shmget(key_t key, int size, int shmflg); }
#else
228 UNIMPL shmat
229 UNIMPL shmctl
230 UNIMPL shmdt
231 UNIMPL shmget
#endif

1927
sys/kern/tty.c Normal file

File diff suppressed because it is too large Load Diff

411
sys/kern/tty_compat.c Normal file
View File

@ -0,0 +1,411 @@
/*-
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)tty_compat.c 8.2 (Berkeley) 1/9/95
*/
/*
* mapping routines for old line discipline (yuck)
*/
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/termios.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
int ttydebug = 0;
static struct speedtab compatspeeds[] = {
{ 38400, 15 },
{ 19200, 14 },
{ 9600, 13 },
{ 4800, 12 },
{ 2400, 11 },
{ 1800, 10 },
{ 1200, 9 },
{ 600, 8 },
{ 300, 7 },
{ 200, 6 },
{ 150, 5 },
{ 134, 4 },
{ 110, 3 },
{ 75, 2 },
{ 50, 1 },
{ 0, 0 },
{ -1, -1 },
};
static int compatspcodes[16] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
1800, 2400, 4800, 9600, 19200, 38400,
};
/*ARGSUSED*/
ttcompat(tp, com, data, flag)
register struct tty *tp;
u_long com;
caddr_t data;
int flag;
{
switch (com) {
case TIOCGETP: {
register struct sgttyb *sg = (struct sgttyb *)data;
register u_char *cc = tp->t_cc;
register speed;
speed = ttspeedtab(tp->t_ospeed, compatspeeds);
sg->sg_ospeed = (speed == -1) ? 15 : speed;
if (tp->t_ispeed == 0)
sg->sg_ispeed = sg->sg_ospeed;
else {
speed = ttspeedtab(tp->t_ispeed, compatspeeds);
sg->sg_ispeed = (speed == -1) ? 15 : speed;
}
sg->sg_erase = cc[VERASE];
sg->sg_kill = cc[VKILL];
sg->sg_flags = ttcompatgetflags(tp);
break;
}
case TIOCSETP:
case TIOCSETN: {
register struct sgttyb *sg = (struct sgttyb *)data;
struct termios term;
int speed;
term = tp->t_termios;
if ((speed = sg->sg_ispeed) > 15 || speed < 0)
term.c_ispeed = speed;
else
term.c_ispeed = compatspcodes[speed];
if ((speed = sg->sg_ospeed) > 15 || speed < 0)
term.c_ospeed = speed;
else
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;
ttcompatsetflags(tp, &term);
return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA,
&term, flag));
}
case TIOCGETC: {
struct tchars *tc = (struct tchars *)data;
register u_char *cc = tp->t_cc;
tc->t_intrc = cc[VINTR];
tc->t_quitc = cc[VQUIT];
tc->t_startc = cc[VSTART];
tc->t_stopc = cc[VSTOP];
tc->t_eofc = cc[VEOF];
tc->t_brkc = cc[VEOL];
break;
}
case TIOCSETC: {
struct tchars *tc = (struct tchars *)data;
register u_char *cc = tp->t_cc;
cc[VINTR] = tc->t_intrc;
cc[VQUIT] = tc->t_quitc;
cc[VSTART] = tc->t_startc;
cc[VSTOP] = tc->t_stopc;
cc[VEOF] = tc->t_eofc;
cc[VEOL] = tc->t_brkc;
if (tc->t_brkc == -1)
cc[VEOL2] = _POSIX_VDISABLE;
break;
}
case TIOCSLTC: {
struct ltchars *ltc = (struct ltchars *)data;
register u_char *cc = tp->t_cc;
cc[VSUSP] = ltc->t_suspc;
cc[VDSUSP] = ltc->t_dsuspc;
cc[VREPRINT] = ltc->t_rprntc;
cc[VDISCARD] = ltc->t_flushc;
cc[VWERASE] = ltc->t_werasc;
cc[VLNEXT] = ltc->t_lnextc;
break;
}
case TIOCGLTC: {
struct ltchars *ltc = (struct ltchars *)data;
register u_char *cc = tp->t_cc;
ltc->t_suspc = cc[VSUSP];
ltc->t_dsuspc = cc[VDSUSP];
ltc->t_rprntc = cc[VREPRINT];
ltc->t_flushc = cc[VDISCARD];
ltc->t_werasc = cc[VWERASE];
ltc->t_lnextc = cc[VLNEXT];
break;
}
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET: {
struct termios term;
term = tp->t_termios;
if (com == TIOCLSET)
tp->t_flags = (tp->t_flags&0xffff) | *(int *)data<<16;
else {
tp->t_flags =
(ttcompatgetflags(tp)&0xffff0000)|(tp->t_flags&0xffff);
if (com == TIOCLBIS)
tp->t_flags |= *(int *)data<<16;
else
tp->t_flags &= ~(*(int *)data<<16);
}
ttcompatsetlflags(tp, &term);
return (ttioctl(tp, TIOCSETA, &term, flag));
}
case TIOCLGET:
*(int *)data = ttcompatgetflags(tp)>>16;
if (ttydebug)
printf("CLGET: returning %x\n", *(int *)data);
break;
case OTIOCGETD:
*(int *)data = tp->t_line ? tp->t_line : 2;
break;
case OTIOCSETD: {
int ldisczero = 0;
return (ttioctl(tp, TIOCSETD,
*(int *)data == 2 ? (caddr_t)&ldisczero : data, flag));
}
case OTIOCCONS:
*(int *)data = 1;
return (ttioctl(tp, TIOCCONS, data, flag));
default:
return (-1);
}
return (0);
}
ttcompatgetflags(tp)
register struct tty *tp;
{
register long iflag = tp->t_iflag;
register long lflag = tp->t_lflag;
register long oflag = tp->t_oflag;
register long cflag = tp->t_cflag;
register flags = 0;
if (iflag&IXOFF)
flags |= TANDEM;
if (iflag&ICRNL || oflag&ONLCR)
flags |= CRMOD;
if (cflag&PARENB) {
if (iflag&INPCK) {
if (cflag&PARODD)
flags |= ODDP;
else
flags |= EVENP;
} else
flags |= EVENP | ODDP;
} else {
if ((tp->t_flags&LITOUT) && !(oflag&OPOST))
flags |= LITOUT;
if (tp->t_flags&PASS8)
flags |= PASS8;
}
if ((lflag&ICANON) == 0) {
/* fudge */
if (iflag&IXON || lflag&ISIG || lflag&IEXTEN || cflag&PARENB)
flags |= CBREAK;
else
flags |= RAW;
}
if (cflag&MDMBUF)
flags |= MDMBUF;
if ((cflag&HUPCL) == 0)
flags |= NOHANG;
if (oflag&OXTABS)
flags |= XTABS;
if (lflag&ECHOE)
flags |= CRTERA|CRTBS;
if (lflag&ECHOKE)
flags |= CRTKIL|CRTBS;
if (lflag&ECHOPRT)
flags |= PRTERA;
if (lflag&ECHOCTL)
flags |= CTLECH;
if ((iflag&IXANY) == 0)
flags |= DECCTQ;
flags |= lflag&(ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH);
if (ttydebug)
printf("getflags: %x\n", flags);
return (flags);
}
ttcompatsetflags(tp, t)
register struct tty *tp;
register struct termios *t;
{
register flags = tp->t_flags;
register long iflag = t->c_iflag;
register long oflag = t->c_oflag;
register long lflag = t->c_lflag;
register long cflag = t->c_cflag;
if (flags & RAW) {
iflag &= IXOFF;
oflag &= ~OPOST;
lflag &= ~(ECHOCTL|ISIG|ICANON|IEXTEN);
} else {
iflag |= BRKINT|IXON|IMAXBEL;
oflag |= OPOST;
lflag |= ISIG|IEXTEN|ECHOCTL; /* XXX was echoctl on ? */
if (flags & XTABS)
oflag |= OXTABS;
else
oflag &= ~OXTABS;
if (flags & CBREAK)
lflag &= ~ICANON;
else
lflag |= ICANON;
if (flags&CRMOD) {
iflag |= ICRNL;
oflag |= ONLCR;
} else {
iflag &= ~ICRNL;
oflag &= ~ONLCR;
}
}
if (flags&ECHO)
lflag |= ECHO;
else
lflag &= ~ECHO;
if (flags&(RAW|LITOUT|PASS8)) {
cflag &= ~(CSIZE|PARENB);
cflag |= CS8;
if ((flags&(RAW|PASS8)) == 0)
iflag |= ISTRIP;
else
iflag &= ~ISTRIP;
} else {
cflag &= ~CSIZE;
cflag |= CS7|PARENB;
iflag |= ISTRIP;
}
if ((flags&(EVENP|ODDP)) == EVENP) {
iflag |= INPCK;
cflag &= ~PARODD;
} else if ((flags&(EVENP|ODDP)) == ODDP) {
iflag |= INPCK;
cflag |= PARODD;
} else
iflag &= ~INPCK;
if (flags&LITOUT)
oflag &= ~OPOST; /* move earlier ? */
if (flags&TANDEM)
iflag |= IXOFF;
else
iflag &= ~IXOFF;
t->c_iflag = iflag;
t->c_oflag = oflag;
t->c_lflag = lflag;
t->c_cflag = cflag;
}
ttcompatsetlflags(tp, t)
register struct tty *tp;
register struct termios *t;
{
register flags = tp->t_flags;
register long iflag = t->c_iflag;
register long oflag = t->c_oflag;
register long lflag = t->c_lflag;
register long cflag = t->c_cflag;
if (flags&CRTERA)
lflag |= ECHOE;
else
lflag &= ~ECHOE;
if (flags&CRTKIL)
lflag |= ECHOKE;
else
lflag &= ~ECHOKE;
if (flags&PRTERA)
lflag |= ECHOPRT;
else
lflag &= ~ECHOPRT;
if (flags&CTLECH)
lflag |= ECHOCTL;
else
lflag &= ~ECHOCTL;
if ((flags&DECCTQ) == 0)
iflag |= IXANY;
else
iflag &= ~IXANY;
if (flags & MDMBUF)
cflag |= MDMBUF;
else
cflag &= ~MDMBUF;
if (flags&NOHANG)
cflag &= ~HUPCL;
else
cflag |= HUPCL;
lflag &= ~(TOSTOP|FLUSHO|PENDIN|NOFLSH);
lflag |= flags&(TOSTOP|FLUSHO|PENDIN|NOFLSH);
if (flags&(LITOUT|PASS8)) {
iflag &= ~ISTRIP;
cflag &= ~(CSIZE|PARENB);
cflag |= CS8;
if (flags&LITOUT)
oflag &= ~OPOST;
if ((flags&(PASS8|RAW)) == 0)
iflag |= ISTRIP;
} else if ((flags&RAW) == 0) {
cflag &= ~CSIZE;
cflag |= CS7|PARENB;
oflag |= OPOST;
}
t->c_iflag = iflag;
t->c_oflag = oflag;
t->c_lflag = lflag;
t->c_cflag = cflag;
}
#endif /* COMPAT_43 || COMPAT_SUNOS */

126
sys/kern/tty_conf.c Normal file
View File

@ -0,0 +1,126 @@
/*-
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tty_conf.c 8.5 (Berkeley) 1/9/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/conf.h>
#define ttynodisc ((int (*) __P((dev_t, struct tty *)))enodev)
#define ttyerrclose ((int (*) __P((struct tty *, int flags)))enodev)
#define ttyerrio ((int (*) __P((struct tty *, struct uio *, int)))enodev)
#define ttyerrinput ((int (*) __P((int c, struct tty *)))enodev)
#define ttyerrstart ((int (*) __P((struct tty *)))enodev)
int nullioctl __P((struct tty *tp, u_long cmd, caddr_t data,
int flag, struct proc *p));
#include "tb.h"
#if NTB > 0
int tbopen __P((dev_t dev, struct tty *tp));
int tbclose __P((struct tty *tp, int flags));
int tbread __P((struct tty *, struct uio *, int flags));
int tbioctl __P((struct tty *tp, u_long cmd, caddr_t data,
int flag, struct proc *p));
int tbinput __P((int c, struct tty *tp));
#endif
#include "sl.h"
#if NSL > 0
int slopen __P((dev_t dev, struct tty *tp));
int slclose __P((struct tty *tp, int flags));
int sltioctl __P((struct tty *tp, u_long cmd, caddr_t data,
int flag, struct proc *p));
int slinput __P((int c, struct tty *tp));
int slstart __P((struct tty *tp));
#endif
struct linesw linesw[] =
{
{ ttyopen, ttylclose, ttread, ttwrite, nullioctl,
ttyinput, ttstart, ttymodem }, /* 0- termios */
{ ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
ttyerrinput, ttyerrstart, nullmodem }, /* 1- defunct */
{ ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
ttyerrinput, ttyerrstart, nullmodem }, /* 2- defunct */
#if NTB > 0
{ tbopen, tbclose, tbread, enodev, tbioctl,
tbinput, ttstart, nullmodem }, /* 3- TABLDISC */
#else
{ ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
ttyerrinput, ttyerrstart, nullmodem },
#endif
#if NSL > 0
{ slopen, slclose, ttyerrio, ttyerrio, sltioctl,
slinput, slstart, nullmodem }, /* 4- SLIPDISC */
#else
{ ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
ttyerrinput, ttyerrstart, nullmodem },
#endif
};
int nlinesw = sizeof (linesw) / sizeof (linesw[0]);
/*
* Do nothing specific version of line
* discipline specific ioctl command.
*/
/*ARGSUSED*/
nullioctl(tp, cmd, data, flags, p)
struct tty *tp;
u_long cmd;
char *data;
int flags;
struct proc *p;
{
#ifdef lint
tp = tp; data = data; flags = flags; p = p;
#endif
return (-1);
}

691
sys/kern/tty_pty.c Normal file
View File

@ -0,0 +1,691 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. 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 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.
*
* @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
*/
/*
* Pseudo-teletype Driver
* (Actually two drivers, requiring two entries in 'cdevsw')
*/
#include "pty.h" /* XXX */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#if NPTY == 1
#undef NPTY
#define NPTY 32 /* crude XXX */
#endif
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
/*
* pts == /dev/tty[pqrs]?
* ptc == /dev/pty[pqrs]?
*/
struct tty pt_tty[NPTY]; /* XXX */
struct pt_ioctl {
int pt_flags;
struct selinfo pt_selr, pt_selw;
u_char pt_send;
u_char pt_ucntl;
} pt_ioctl[NPTY]; /* XXX */
int npty = NPTY; /* for pstat -t */
#define PF_PKT 0x08 /* packet mode */
#define PF_STOPPED 0x10 /* user told stopped */
#define PF_REMOTE 0x20 /* remote and flow controlled input */
#define PF_NOSTOP 0x40
#define PF_UCNTL 0x80 /* user control mode */
void ptsstop __P((struct tty *, int));
/*
* Establish n (or default if n is 1) ptys in the system.
*
* XXX cdevsw & pstat require the array `pty[]' to be an array
*/
void
ptyattach(n)
int n;
{
#ifdef notyet
char *mem;
register u_long ntb;
#define DEFAULT_NPTY 32
/* maybe should allow 0 => none? */
if (n <= 1)
n = DEFAULT_NPTY;
ntb = n * sizeof(struct tty);
mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
M_DEVBUF, M_WAITOK);
pt_tty = (struct tty *)mem;
mem = (char *)ALIGN(mem + ntb);
pt_ioctl = (struct pt_ioctl *)mem;
npty = n;
#endif
}
/*ARGSUSED*/
ptsopen(dev, flag, devtype, p)
dev_t dev;
int flag, devtype;
struct proc *p;
{
register struct tty *tp;
int error;
if (minor(dev) >= npty)
return (ENXIO);
tp = &pt_tty[minor(dev)];
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_state |= TS_WOPEN;
ttychars(tp); /* Set up default chars */
tp->t_iflag = TTYDEF_IFLAG;
tp->t_oflag = TTYDEF_OFLAG;
tp->t_lflag = TTYDEF_LFLAG;
tp->t_cflag = TTYDEF_CFLAG;
tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
ttsetwater(tp); /* would be done in xxparam() */
} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
return (EBUSY);
if (tp->t_oproc) /* Ctrlr still around. */
tp->t_state |= TS_CARR_ON;
while ((tp->t_state & TS_CARR_ON) == 0) {
tp->t_state |= TS_WOPEN;
if (flag&FNONBLOCK)
break;
if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
ttopen, 0))
return (error);
}
error = (*linesw[tp->t_line].l_open)(dev, tp);
ptcwakeup(tp, FREAD|FWRITE);
return (error);
}
ptsclose(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
register struct tty *tp;
int err;
tp = &pt_tty[minor(dev)];
err = (*linesw[tp->t_line].l_close)(tp, flag);
err |= ttyclose(tp);
ptcwakeup(tp, FREAD|FWRITE);
return (err);
}
ptsread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct proc *p = curproc;
register struct tty *tp = &pt_tty[minor(dev)];
register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
again:
if (pti->pt_flags & PF_REMOTE) {
while (isbackground(p, tp)) {
if ((p->p_sigignore & sigmask(SIGTTIN)) ||
(p->p_sigmask & sigmask(SIGTTIN)) ||
p->p_pgrp->pg_jobc == 0 ||
p->p_flag & P_PPWAIT)
return (EIO);
pgsignal(p->p_pgrp, SIGTTIN, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt,
TTIPRI | PCATCH, ttybg, 0))
return (error);
}
if (tp->t_canq.c_cc == 0) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
TTIPRI | PCATCH, ttyin, 0))
return (error);
goto again;
}
while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
if (ureadc(getc(&tp->t_canq), uio) < 0) {
error = EFAULT;
break;
}
if (tp->t_canq.c_cc == 1)
(void) getc(&tp->t_canq);
if (tp->t_canq.c_cc)
return (error);
} else
if (tp->t_oproc)
error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
ptcwakeup(tp, FWRITE);
return (error);
}
/*
* Write to pseudo-tty.
* Wakeups of controlling tty will happen
* indirectly, when tty driver calls ptsstart.
*/
ptswrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
register struct tty *tp;
tp = &pt_tty[minor(dev)];
if (tp->t_oproc == 0)
return (EIO);
return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
}
/*
* Start output on pseudo-tty.
* Wake up process selecting or sleeping for input from controlling tty.
*/
void
ptsstart(tp)
struct tty *tp;
{
register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
if (tp->t_state & TS_TTSTOP)
return;
if (pti->pt_flags & PF_STOPPED) {
pti->pt_flags &= ~PF_STOPPED;
pti->pt_send = TIOCPKT_START;
}
ptcwakeup(tp, FREAD);
}
ptcwakeup(tp, flag)
struct tty *tp;
int flag;
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
if (flag & FREAD) {
selwakeup(&pti->pt_selr);
wakeup((caddr_t)&tp->t_outq.c_cf);
}
if (flag & FWRITE) {
selwakeup(&pti->pt_selw);
wakeup((caddr_t)&tp->t_rawq.c_cf);
}
}
/*ARGSUSED*/
#ifdef __STDC__
ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
#else
ptcopen(dev, flag, devtype, p)
dev_t dev;
int flag, devtype;
struct proc *p;
#endif
{
register struct tty *tp;
struct pt_ioctl *pti;
if (minor(dev) >= npty)
return (ENXIO);
tp = &pt_tty[minor(dev)];
if (tp->t_oproc)
return (EIO);
tp->t_oproc = ptsstart;
#ifdef sun4c
tp->t_stop = ptsstop;
#endif
(void)(*linesw[tp->t_line].l_modem)(tp, 1);
tp->t_lflag &= ~EXTPROC;
pti = &pt_ioctl[minor(dev)];
pti->pt_flags = 0;
pti->pt_send = 0;
pti->pt_ucntl = 0;
return (0);
}
ptcclose(dev)
dev_t dev;
{
register struct tty *tp;
tp = &pt_tty[minor(dev)];
(void)(*linesw[tp->t_line].l_modem)(tp, 0);
tp->t_state &= ~TS_CARR_ON;
tp->t_oproc = 0; /* mark closed */
tp->t_session = 0;
return (0);
}
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)];
char buf[BUFSIZ];
int error = 0, cc;
/*
* We want to block until the slave
* is open, and there's something to read;
* but if we lost the slave or we're NBIO,
* then return the appropriate error instead.
*/
for (;;) {
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags&PF_PKT && pti->pt_send) {
error = ureadc((int)pti->pt_send, uio);
if (error)
return (error);
if (pti->pt_send & TIOCPKT_IOCTL) {
cc = min(uio->uio_resid,
sizeof(tp->t_termios));
uiomove(&tp->t_termios, cc, uio);
}
pti->pt_send = 0;
return (0);
}
if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
error = ureadc((int)pti->pt_ucntl, uio);
if (error)
return (error);
pti->pt_ucntl = 0;
return (0);
}
if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
break;
}
if ((tp->t_state&TS_CARR_ON) == 0)
return (0); /* EOF */
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
ttyin, 0))
return (error);
}
if (pti->pt_flags & (PF_PKT|PF_UCNTL))
error = ureadc(0, uio);
while (uio->uio_resid > 0 && error == 0) {
cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
if (cc <= 0)
break;
error = uiomove(buf, cc, uio);
}
if (tp->t_outq.c_cc <= tp->t_lowat) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_outq);
}
selwakeup(&tp->t_wsel);
}
return (error);
}
void
ptsstop(tp, flush)
register struct tty *tp;
int flush;
{
struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
int flag;
/* note: FLUSHREAD and FLUSHWRITE already ok */
if (flush == 0) {
flush = TIOCPKT_STOP;
pti->pt_flags |= PF_STOPPED;
} else
pti->pt_flags &= ~PF_STOPPED;
pti->pt_send |= flush;
/* change of perspective */
flag = 0;
if (flush & FREAD)
flag |= FWRITE;
if (flush & FWRITE)
flag |= FREAD;
ptcwakeup(tp, flag);
}
ptcselect(dev, rw, p)
dev_t dev;
int rw;
struct proc *p;
{
register struct tty *tp = &pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int s;
if ((tp->t_state&TS_CARR_ON) == 0)
return (1);
switch (rw) {
case FREAD:
/*
* Need to block timeouts (ttrstart).
*/
s = spltty();
if ((tp->t_state&TS_ISOPEN) &&
tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
splx(s);
return (1);
}
splx(s);
/* FALLTHROUGH */
case 0: /* exceptional */
if ((tp->t_state&TS_ISOPEN) &&
(pti->pt_flags&PF_PKT && pti->pt_send ||
pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
return (1);
selrecord(p, &pti->pt_selr);
break;
case FWRITE:
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags & PF_REMOTE) {
if (tp->t_canq.c_cc == 0)
return (1);
} else {
if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
return (1);
if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
return (1);
}
}
selrecord(p, &pti->pt_selw);
break;
}
return (0);
}
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 int cc = 0;
u_char locbuf[BUFSIZ];
int cnt = 0;
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
int error = 0;
again:
if ((tp->t_state&TS_ISOPEN) == 0)
goto block;
if (pti->pt_flags & PF_REMOTE) {
if (tp->t_canq.c_cc)
goto block;
while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
if (cc == 0) {
cc = min(uio->uio_resid, BUFSIZ);
cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
cp = locbuf;
error = uiomove((caddr_t)cp, cc, uio);
if (error)
return (error);
/* check again for safety */
if ((tp->t_state&TS_ISOPEN) == 0)
return (EIO);
}
if (cc)
(void) b_to_q((char *)cp, cc, &tp->t_canq);
cc = 0;
}
(void) putc(0, &tp->t_canq);
ttwakeup(tp);
wakeup((caddr_t)&tp->t_canq);
return (0);
}
while (uio->uio_resid > 0) {
if (cc == 0) {
cc = min(uio->uio_resid, BUFSIZ);
cp = locbuf;
error = uiomove((caddr_t)cp, cc, uio);
if (error)
return (error);
/* check again for safety */
if ((tp->t_state&TS_ISOPEN) == 0)
return (EIO);
}
while (cc > 0) {
if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
(tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
wakeup((caddr_t)&tp->t_rawq);
goto block;
}
(*linesw[tp->t_line].l_rint)(*cp++, tp);
cnt++;
cc--;
}
cc = 0;
}
return (0);
block:
/*
* Come here to wait for slave to open, for space
* in outq, or space in rawq.
*/
if ((tp->t_state&TS_CARR_ON) == 0)
return (EIO);
if (flag & IO_NDELAY) {
/* adjust for data copied in but not written */
uio->uio_resid += cc;
if (cnt == 0)
return (EWOULDBLOCK);
return (0);
}
if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
ttyout, 0)) {
/* adjust for data copied in but not written */
uio->uio_resid += cc;
return (error);
}
goto again;
}
/*ARGSUSED*/
ptyioctl(dev, cmd, data, flag, p)
dev_t dev;
u_long cmd;
caddr_t data;
int flag;
struct proc *p;
{
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;
/*
* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
* ttywflush(tp) will hang if there are characters in the outq.
*/
if (cmd == TIOCEXT) {
/*
* When the EXTPROC bit is being toggled, we need
* to send an TIOCPKT_IOCTL if the packet driver
* is turned on.
*/
if (*(int *)data) {
if (pti->pt_flags & PF_PKT) {
pti->pt_send |= TIOCPKT_IOCTL;
ptcwakeup(tp, FREAD);
}
tp->t_lflag |= EXTPROC;
} else {
if ((tp->t_lflag & EXTPROC) &&
(pti->pt_flags & PF_PKT)) {
pti->pt_send |= TIOCPKT_IOCTL;
ptcwakeup(tp, FREAD);
}
tp->t_lflag &= ~EXTPROC;
}
return(0);
} else
if (cdevsw[major(dev)].d_open == ptcopen)
switch (cmd) {
case TIOCGPGRP:
/*
* We aviod calling ttioctl on the controller since,
* in that case, tp must be the controlling terminal.
*/
*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
return (0);
case TIOCPKT:
if (*(int *)data) {
if (pti->pt_flags & PF_UCNTL)
return (EINVAL);
pti->pt_flags |= PF_PKT;
} else
pti->pt_flags &= ~PF_PKT;
return (0);
case TIOCUCNTL:
if (*(int *)data) {
if (pti->pt_flags & PF_PKT)
return (EINVAL);
pti->pt_flags |= PF_UCNTL;
} else
pti->pt_flags &= ~PF_UCNTL;
return (0);
case TIOCREMOTE:
if (*(int *)data)
pti->pt_flags |= PF_REMOTE;
else
pti->pt_flags &= ~PF_REMOTE;
ttyflush(tp, FREAD|FWRITE);
return (0);
#ifdef COMPAT_43
case TIOCSETP:
case TIOCSETN:
#endif
case TIOCSETD:
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF:
ndflush(&tp->t_outq, tp->t_outq.c_cc);
break;
case TIOCSIG:
if (*(unsigned int *)data >= NSIG)
return(EINVAL);
if ((tp->t_lflag&NOFLSH) == 0)
ttyflush(tp, FREAD|FWRITE);
pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
if ((*(unsigned int *)data == SIGINFO) &&
((tp->t_lflag&NOKERNINFO) == 0))
ttyinfo(tp);
return(0);
}
error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
if (error < 0)
error = ttioctl(tp, cmd, data, flag);
if (error < 0) {
if (pti->pt_flags & PF_UCNTL &&
(cmd & ~0xff) == UIOCCMD(0)) {
if (cmd & 0xff) {
pti->pt_ucntl = (u_char)cmd;
ptcwakeup(tp, FREAD);
}
return (0);
}
error = ENOTTY;
}
/*
* If external processing and packet mode send ioctl packet.
*/
if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
switch(cmd) {
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF:
#ifdef COMPAT_43
case TIOCSETP:
case TIOCSETN:
#endif
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
case TIOCSETC:
case TIOCSLTC:
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
#endif
pti->pt_send |= TIOCPKT_IOCTL;
ptcwakeup(tp, FREAD);
default:
break;
}
}
stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
&& CCEQ(cc[VSTART], CTRL('q'));
if (pti->pt_flags & PF_NOSTOP) {
if (stop) {
pti->pt_send &= ~TIOCPKT_NOSTOP;
pti->pt_send |= TIOCPKT_DOSTOP;
pti->pt_flags &= ~PF_NOSTOP;
ptcwakeup(tp, FREAD);
}
} else {
if (!stop) {
pti->pt_send &= ~TIOCPKT_DOSTOP;
pti->pt_send |= TIOCPKT_NOSTOP;
pti->pt_flags |= PF_NOSTOP;
ptcwakeup(tp, FREAD);
}
}
return (error);
}

368
sys/kern/tty_tb.c Normal file
View File

@ -0,0 +1,368 @@
/*-
* Copyright (c) 1982, 1986, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)tty_tb.c 8.2 (Berkeley) 1/9/95
*/
#include "tb.h"
#if NTB > 0
/*
* Line discipline for RS232 tablets;
* supplies binary coordinate data.
*/
#include <sys/param.h>
#include <sys/tablet.h>
#include <sys/tty.h>
/*
* Tablet configuration table.
*/
struct tbconf {
short tbc_recsize; /* input record size in bytes */
short tbc_uiosize; /* size of data record returned user */
int tbc_sync; /* mask for finding sync byte/bit */
int (*tbc_decode)();/* decoding routine */
char *tbc_run; /* enter run mode sequence */
char *tbc_point; /* enter point mode sequence */
char *tbc_stop; /* stop sequence */
char *tbc_start; /* start/restart sequence */
int tbc_flags;
#define TBF_POL 0x1 /* polhemus hack */
#define TBF_INPROX 0x2 /* tablet has proximity info */
};
static int tbdecode(), gtcodecode(), poldecode();
static int tblresdecode(), tbhresdecode();
struct tbconf tbconf[TBTYPE] = {
{ 0 },
{ 5, sizeof (struct tbpos), 0200, tbdecode, "6", "4" },
{ 5, sizeof (struct tbpos), 0200, tbdecode, "\1CN", "\1RT", "\2", "\4" },
{ 8, sizeof (struct gtcopos), 0200, gtcodecode },
{17, sizeof (struct polpos), 0200, poldecode, 0, 0, "\21", "\5\22\2\23",
TBF_POL },
{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CN", "\1PT", "\2", "\4",
TBF_INPROX },
{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CN", "\1PT", "\2", "\4",
TBF_INPROX },
{ 5, sizeof (struct tbpos), 0100, tblresdecode, "\1CL\33", "\1PT\33", 0, 0},
{ 6, sizeof (struct tbpos), 0200, tbhresdecode, "\1CL\33", "\1PT\33", 0, 0},
};
/*
* Tablet state
*/
struct tb {
int tbflags; /* mode & type bits */
#define TBMAXREC 17 /* max input record size */
char cbuf[TBMAXREC]; /* input buffer */
union {
struct tbpos tbpos;
struct gtcopos gtcopos;
struct polpos polpos;
} rets; /* processed state */
#define NTBS 16
} tb[NTBS];
/*
* Open as tablet discipline; called on discipline change.
*/
/*ARGSUSED*/
tbopen(dev, tp)
dev_t dev;
register struct tty *tp;
{
register struct tb *tbp;
if (tp->t_line == TABLDISC)
return (ENODEV);
ttywflush(tp);
for (tbp = tb; tbp < &tb[NTBS]; tbp++)
if (tbp->tbflags == 0)
break;
if (tbp >= &tb[NTBS])
return (EBUSY);
tbp->tbflags = TBTIGER|TBPOINT; /* default */
tp->t_cp = tbp->cbuf;
tp->t_inbuf = 0;
bzero((caddr_t)&tbp->rets, sizeof (tbp->rets));
tp->T_LINEP = (caddr_t)tbp;
tp->t_flags |= LITOUT;
return (0);
}
/*
* Line discipline change or last device close.
*/
tbclose(tp)
register struct tty *tp;
{
register int s;
int modebits = TBPOINT|TBSTOP;
tbioctl(tp, BIOSMODE, &modebits, 0);
s = spltty();
((struct tb *)tp->T_LINEP)->tbflags = 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 from a tablet line.
* Characters have been buffered in a buffer and decoded.
*/
tbread(tp, uio)
register struct tty *tp;
struct uio *uio;
{
register struct tb *tbp = (struct tb *)tp->T_LINEP;
register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
int ret;
if ((tp->t_state&TS_CARR_ON) == 0)
return (EIO);
ret = uiomove(&tbp->rets, tc->tbc_uiosize, uio);
if (tc->tbc_flags&TBF_POL)
tbp->rets.polpos.p_key = ' ';
return (ret);
}
/*
* Low level character input routine.
* Stuff the character in the buffer, and decode
* if all the chars are there.
*
* This routine could be expanded in-line in the receiver
* interrupt routine to make it run as fast as possible.
*/
tbinput(c, tp)
register int c;
register struct tty *tp;
{
register struct tb *tbp = (struct tb *)tp->T_LINEP;
register struct tbconf *tc = &tbconf[tbp->tbflags & TBTYPE];
if (tc->tbc_recsize == 0 || tc->tbc_decode == 0) /* paranoid? */
return;
/*
* Locate sync bit/byte or reset input buffer.
*/
if (c&tc->tbc_sync || tp->t_inbuf == tc->tbc_recsize) {
tp->t_cp = tbp->cbuf;
tp->t_inbuf = 0;
}
*tp->t_cp++ = c&0177;
/*
* Call decode routine only if a full record has been collected.
*/
if (++tp->t_inbuf == tc->tbc_recsize)
(*tc->tbc_decode)(tc, tbp->cbuf, &tbp->rets);
}
/*
* Decode GTCO 8 byte format (high res, tilt, and pressure).
*/
static
gtcodecode(tc, cp, tbpos)
struct tbconf *tc;
register char *cp;
register struct gtcopos *tbpos;
{
tbpos->pressure = *cp >> 2;
tbpos->status = (tbpos->pressure > 16) | TBINPROX; /* half way down */
tbpos->xpos = (*cp++ & 03) << 14;
tbpos->xpos |= *cp++ << 7;
tbpos->xpos |= *cp++;
tbpos->ypos = (*cp++ & 03) << 14;
tbpos->ypos |= *cp++ << 7;
tbpos->ypos |= *cp++;
tbpos->xtilt = *cp++;
tbpos->ytilt = *cp++;
tbpos->scount++;
}
/*
* Decode old Hitachi 5 byte format (low res).
*/
static
tbdecode(tc, cp, tbpos)
struct tbconf *tc;
register char *cp;
register struct tbpos *tbpos;
{
register char byte;
byte = *cp++;
tbpos->status = (byte&0100) ? TBINPROX : 0;
byte &= ~0100;
if (byte > 036)
tbpos->status |= 1 << ((byte-040)/2);
tbpos->xpos = *cp++ << 7;
tbpos->xpos |= *cp++;
if (tbpos->xpos < 256) /* tablet wraps around at 256 */
tbpos->status &= ~TBINPROX; /* make it out of proximity */
tbpos->ypos = *cp++ << 7;
tbpos->ypos |= *cp++;
tbpos->scount++;
}
/*
* Decode new Hitach 5-byte format (low res).
*/
static
tblresdecode(tc, cp, tbpos)
struct tbconf *tc;
register char *cp;
register struct tbpos *tbpos;
{
*cp &= ~0100; /* mask sync bit */
tbpos->status = (*cp++ >> 2) | TBINPROX;
if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
tbpos->status &= ~(020|TBINPROX);
tbpos->xpos = *cp++;
tbpos->xpos |= *cp++ << 6;
tbpos->ypos = *cp++;
tbpos->ypos |= *cp++ << 6;
tbpos->scount++;
}
/*
* Decode new Hitach 6-byte format (high res).
*/
static
tbhresdecode(tc, cp, tbpos)
struct tbconf *tc;
register char *cp;
register struct tbpos *tbpos;
{
char byte;
byte = *cp++;
tbpos->xpos = (byte & 03) << 14;
tbpos->xpos |= *cp++ << 7;
tbpos->xpos |= *cp++;
tbpos->ypos = *cp++ << 14;
tbpos->ypos |= *cp++ << 7;
tbpos->ypos |= *cp++;
tbpos->status = (byte >> 2) | TBINPROX;
if (tc->tbc_flags&TBF_INPROX && tbpos->status&020)
tbpos->status &= ~(020|TBINPROX);
tbpos->scount++;
}
/*
* Polhemus decode.
*/
static
poldecode(tc, cp, polpos)
struct tbconf *tc;
register char *cp;
register struct polpos *polpos;
{
polpos->p_x = cp[4] | cp[3]<<7 | (cp[9] & 0x03) << 14;
polpos->p_y = cp[6] | cp[5]<<7 | (cp[9] & 0x0c) << 12;
polpos->p_z = cp[8] | cp[7]<<7 | (cp[9] & 0x30) << 10;
polpos->p_azi = cp[11] | cp[10]<<7 | (cp[16] & 0x03) << 14;
polpos->p_pit = cp[13] | cp[12]<<7 | (cp[16] & 0x0c) << 12;
polpos->p_rol = cp[15] | cp[14]<<7 | (cp[16] & 0x30) << 10;
polpos->p_stat = cp[1] | cp[0]<<7;
if (cp[2] != ' ')
polpos->p_key = cp[2];
}
/*ARGSUSED*/
tbioctl(tp, cmd, data, flag)
struct tty *tp;
u_long cmd;
caddr_t data;
int flag;
{
register struct tb *tbp = (struct tb *)tp->T_LINEP;
switch (cmd) {
case BIOGMODE:
*(int *)data = tbp->tbflags & TBMODE;
break;
case BIOSTYPE:
if (tbconf[*(int *)data & TBTYPE].tbc_recsize == 0 ||
tbconf[*(int *)data & TBTYPE].tbc_decode == 0)
return (EINVAL);
tbp->tbflags &= ~TBTYPE;
tbp->tbflags |= *(int *)data & TBTYPE;
/* fall thru... to set mode bits */
case BIOSMODE: {
register struct tbconf *tc;
tbp->tbflags &= ~TBMODE;
tbp->tbflags |= *(int *)data & TBMODE;
tc = &tbconf[tbp->tbflags & TBTYPE];
if (tbp->tbflags&TBSTOP) {
if (tc->tbc_stop)
ttyout(tc->tbc_stop, tp);
} else if (tc->tbc_start)
ttyout(tc->tbc_start, tp);
if (tbp->tbflags&TBPOINT) {
if (tc->tbc_point)
ttyout(tc->tbc_point, tp);
} else if (tc->tbc_run)
ttyout(tc->tbc_run, tp);
ttstart(tp);
break;
}
case BIOGTYPE:
*(int *)data = tbp->tbflags & TBTYPE;
break;
case TIOCSETD:
case TIOCGETD:
case TIOCGETP:
case TIOCGETC:
return (-1); /* pass thru... */
default:
return (ENOTTY);
}
return (0);
}
#endif

149
sys/kern/tty_tty.c Normal file
View File

@ -0,0 +1,149 @@
/*-
* Copyright (c) 1982, 1986, 1991, 1993, 1995
* The Regents of the University of California. 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 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.
*
* @(#)tty_tty.c 8.4 (Berkeley) 5/14/95
*/
/*
* Indirect driver for controlling tty.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/ioctl.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/vnode.h>
#include <sys/file.h>
#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
/*ARGSUSED*/
cttyopen(dev, flag, mode, p)
dev_t dev;
int flag, mode;
struct proc *p;
{
struct vnode *ttyvp = cttyvp(p);
int error;
if (ttyvp == NULL)
return (ENXIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p);
#ifdef PARANOID
/*
* Since group is tty and mode is 620 on most terminal lines
* and since sessions protect terminals from processes outside
* your session, this check is probably no longer necessary.
* Since it inhibits setuid root programs that later switch
* to another user from accessing /dev/tty, we have decided
* to delete this test. (mckusick 5/93)
*/
error = VOP_ACCESS(ttyvp,
(flag&FREAD ? VREAD : 0) | (flag&FWRITE ? VWRITE : 0), p->p_ucred, p);
if (!error)
#endif /* PARANOID */
error = VOP_OPEN(ttyvp, flag, NOCRED, p);
VOP_UNLOCK(ttyvp, 0, p);
return (error);
}
/*ARGSUSED*/
cttyread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct proc *p = uio->uio_procp;
register struct vnode *ttyvp = cttyvp(p);
int error;
if (ttyvp == NULL)
return (EIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_READ(ttyvp, uio, flag, NOCRED);
VOP_UNLOCK(ttyvp, 0, p);
return (error);
}
/*ARGSUSED*/
cttywrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct proc *p = uio->uio_procp;
struct vnode *ttyvp = cttyvp(uio->uio_procp);
int error;
if (ttyvp == NULL)
return (EIO);
vn_lock(ttyvp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_WRITE(ttyvp, uio, flag, NOCRED);
VOP_UNLOCK(ttyvp, 0, p);
return (error);
}
/*ARGSUSED*/
cttyioctl(dev, cmd, addr, flag, p)
dev_t dev;
u_long cmd;
caddr_t addr;
int flag;
struct proc *p;
{
struct vnode *ttyvp = cttyvp(p);
if (ttyvp == NULL)
return (EIO);
if (cmd == TIOCNOTTY) {
if (!SESS_LEADER(p)) {
p->p_flag &= ~P_CONTROLT;
return (0);
} else
return (EINVAL);
}
return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, p));
}
/*ARGSUSED*/
cttyselect(dev, flag, p)
dev_t dev;
int flag;
struct proc *p;
{
struct vnode *ttyvp = cttyvp(p);
if (ttyvp == NULL)
return (1); /* try operation to get EOF/failure */
return (VOP_SELECT(ttyvp, flag, FREAD|FWRITE, NOCRED, p));
}

223
sys/kern/uipc_domain.c Normal file
View File

@ -0,0 +1,223 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. 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 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.
*
* @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <vm/vm.h>
#include <sys/sysctl.h>
void pffasttimo __P((void *));
void pfslowtimo __P((void *));
#define ADDDOMAIN(x) { \
extern struct domain __CONCAT(x,domain); \
__CONCAT(x,domain.dom_next) = domains; \
domains = &__CONCAT(x,domain); \
}
void
domaininit()
{
register struct domain *dp;
register struct protosw *pr;
#undef unix
#ifndef lint
ADDDOMAIN(unix);
ADDDOMAIN(route);
#ifdef INET
ADDDOMAIN(inet);
#endif
#ifdef NS
ADDDOMAIN(ns);
#endif
#ifdef ISO
ADDDOMAIN(iso);
#endif
#ifdef CCITT
ADDDOMAIN(ccitt);
#endif
#include "imp.h"
#if NIMP > 0
ADDDOMAIN(imp);
#endif
#endif
for (dp = domains; dp; dp = dp->dom_next) {
if (dp->dom_init)
(*dp->dom_init)();
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_init)
(*pr->pr_init)();
}
if (max_linkhdr < 16) /* XXX */
max_linkhdr = 16;
max_hdr = max_linkhdr + max_protohdr;
max_datalen = MHLEN - max_hdr;
timeout(pffasttimo, NULL, 1);
timeout(pfslowtimo, NULL, 1);
}
struct protosw *
pffindtype(family, type)
int family, type;
{
register struct domain *dp;
register struct protosw *pr;
for (dp = domains; dp; dp = dp->dom_next)
if (dp->dom_family == family)
goto found;
return (0);
found:
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_type && pr->pr_type == type)
return (pr);
return (0);
}
struct protosw *
pffindproto(family, protocol, type)
int family, protocol, type;
{
register struct domain *dp;
register struct protosw *pr;
struct protosw *maybe = 0;
if (family == 0)
return (0);
for (dp = domains; dp; dp = dp->dom_next)
if (dp->dom_family == family)
goto found;
return (0);
found:
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
if ((pr->pr_protocol == protocol) && (pr->pr_type == type))
return (pr);
if (type == SOCK_RAW && pr->pr_type == SOCK_RAW &&
pr->pr_protocol == 0 && maybe == (struct protosw *)0)
maybe = pr;
}
return (maybe);
}
int
net_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
struct proc *p;
{
register struct domain *dp;
register struct protosw *pr;
int family, protocol;
/*
* All sysctl names at this level are nonterminal;
* next two components are protocol family and protocol number,
* then at least one addition component.
*/
if (namelen < 3)
return (EISDIR); /* overloaded */
family = name[0];
protocol = name[1];
if (family == 0)
return (0);
for (dp = domains; dp; dp = dp->dom_next)
if (dp->dom_family == family)
goto found;
return (ENOPROTOOPT);
found:
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_protocol == protocol && pr->pr_sysctl)
return ((*pr->pr_sysctl)(name + 2, namelen - 2,
oldp, oldlenp, newp, newlen));
return (ENOPROTOOPT);
}
void
pfctlinput(cmd, sa)
int cmd;
struct sockaddr *sa;
{
register struct domain *dp;
register struct protosw *pr;
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_ctlinput)
(*pr->pr_ctlinput)(cmd, sa, (caddr_t)0);
}
void
pfslowtimo(arg)
void *arg;
{
register struct domain *dp;
register struct protosw *pr;
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_slowtimo)
(*pr->pr_slowtimo)();
timeout(pfslowtimo, NULL, hz/2);
}
void
pffasttimo(arg)
void *arg;
{
register struct domain *dp;
register struct protosw *pr;
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_fasttimo)
(*pr->pr_fasttimo)();
timeout(pffasttimo, NULL, hz/5);
}

660
sys/kern/uipc_mbuf.c Normal file
View File

@ -0,0 +1,660 @@
/*
* Copyright (c) 1982, 1986, 1988, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/map.h>
#define MBTYPES
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/syslog.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <vm/vm.h>
extern vm_map_t mb_map;
struct mbuf *mbutl;
char *mclrefcnt;
void
mbinit()
{
int s;
s = splimp();
if (m_clalloc(max(4096/CLBYTES, 1), M_DONTWAIT) == 0)
goto bad;
splx(s);
return;
bad:
panic("mbinit");
}
/*
* Allocate some number of mbuf clusters
* and place on cluster free list.
* Must be called at splimp.
*/
/* ARGSUSED */
int
m_clalloc(ncl, nowait)
register int ncl;
int nowait;
{
static int logged;
register caddr_t p;
register int i;
int npg;
npg = ncl * CLSIZE;
p = (caddr_t)kmem_malloc(mb_map, ctob(npg), !nowait);
if (p == NULL) {
if (logged == 0) {
logged++;
log(LOG_ERR, "mb_map full\n");
}
return (0);
}
ncl = ncl * CLBYTES / MCLBYTES;
for (i = 0; i < ncl; i++) {
((union mcluster *)p)->mcl_next = mclfree;
mclfree = (union mcluster *)p;
p += MCLBYTES;
mbstat.m_clfree++;
}
mbstat.m_clusters += ncl;
return (1);
}
/*
* When MGET failes, ask protocols to free space when short of memory,
* then re-attempt to allocate an mbuf.
*/
struct mbuf *
m_retry(i, t)
int i, t;
{
register struct mbuf *m;
m_reclaim();
#define m_retry(i, t) (struct mbuf *)0
MGET(m, i, t);
#undef m_retry
return (m);
}
/*
* As above; retry an MGETHDR.
*/
struct mbuf *
m_retryhdr(i, t)
int i, t;
{
register struct mbuf *m;
m_reclaim();
#define m_retryhdr(i, t) (struct mbuf *)0
MGETHDR(m, i, t);
#undef m_retryhdr
return (m);
}
void
m_reclaim()
{
register struct domain *dp;
register struct protosw *pr;
int s = splimp();
for (dp = domains; dp; dp = dp->dom_next)
for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
if (pr->pr_drain)
(*pr->pr_drain)();
splx(s);
mbstat.m_drain++;
}
/*
* Space allocation routines.
* These are also available as macros
* for critical paths.
*/
struct mbuf *
m_get(nowait, type)
int nowait, type;
{
register struct mbuf *m;
MGET(m, nowait, type);
return (m);
}
struct mbuf *
m_gethdr(nowait, type)
int nowait, type;
{
register struct mbuf *m;
MGETHDR(m, nowait, type);
return (m);
}
struct mbuf *
m_getclr(nowait, type)
int nowait, type;
{
register struct mbuf *m;
MGET(m, nowait, type);
if (m == 0)
return (0);
bzero(mtod(m, caddr_t), MLEN);
return (m);
}
struct mbuf *
m_free(m)
struct mbuf *m;
{
register struct mbuf *n;
MFREE(m, n);
return (n);
}
void
m_freem(m)
register struct mbuf *m;
{
register struct mbuf *n;
if (m == NULL)
return;
do {
MFREE(m, n);
} while (m = n);
}
/*
* Mbuffer utility routines.
*/
/*
* Lesser-used path for M_PREPEND:
* allocate new mbuf to prepend to chain,
* copy junk along.
*/
struct mbuf *
m_prepend(m, len, how)
register struct mbuf *m;
int len, how;
{
struct mbuf *mn;
MGET(mn, how, m->m_type);
if (mn == (struct mbuf *)NULL) {
m_freem(m);
return ((struct mbuf *)NULL);
}
if (m->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(mn, m);
m->m_flags &= ~M_PKTHDR;
}
mn->m_next = m;
m = mn;
if (len < MHLEN)
MH_ALIGN(m, len);
m->m_len = len;
return (m);
}
/*
* Make a copy of an mbuf chain starting "off0" bytes from the beginning,
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
*/
int MCFail;
struct mbuf *
m_copym(m, off0, len, wait)
register struct mbuf *m;
int off0, wait;
register int len;
{
register struct mbuf *n, **np;
register int off = off0;
struct mbuf *top;
int copyhdr = 0;
if (off < 0 || len < 0)
panic("m_copym");
if (off == 0 && m->m_flags & M_PKTHDR)
copyhdr = 1;
while (off > 0) {
if (m == 0)
panic("m_copym");
if (off < m->m_len)
break;
off -= m->m_len;
m = m->m_next;
}
np = &top;
top = 0;
while (len > 0) {
if (m == 0) {
if (len != M_COPYALL)
panic("m_copym");
break;
}
MGET(n, wait, m->m_type);
*np = n;
if (n == 0)
goto nospace;
if (copyhdr) {
M_COPY_PKTHDR(n, m);
if (len == M_COPYALL)
n->m_pkthdr.len -= off0;
else
n->m_pkthdr.len = len;
copyhdr = 0;
}
n->m_len = min(len, m->m_len - off);
if (m->m_flags & M_EXT) {
n->m_data = m->m_data + off;
mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
n->m_ext = m->m_ext;
n->m_flags |= M_EXT;
} else
bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
(unsigned)n->m_len);
if (len != M_COPYALL)
len -= n->m_len;
off = 0;
m = m->m_next;
np = &n->m_next;
}
if (top == 0)
MCFail++;
return (top);
nospace:
m_freem(top);
MCFail++;
return (0);
}
/*
* 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;
register int len;
caddr_t cp;
{
register unsigned count;
if (off < 0 || len < 0)
panic("m_copydata");
while (off > 0) {
if (m == 0)
panic("m_copydata");
if (off < m->m_len)
break;
off -= m->m_len;
m = m->m_next;
}
while (len > 0) {
if (m == 0)
panic("m_copydata");
count = min(m->m_len - off, len);
bcopy(mtod(m, caddr_t) + off, cp, count);
len -= count;
cp += count;
off = 0;
m = m->m_next;
}
}
/*
* Concatenate mbuf chain n to m.
* 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;
{
while (m->m_next)
m = m->m_next;
while (n) {
if (m->m_flags & M_EXT ||
m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
/* just join the two chains */
m->m_next = n;
return;
}
/* splat the data from one into the other */
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
(u_int)n->m_len);
m->m_len += n->m_len;
n = m_free(n);
}
}
void
m_adj(mp, req_len)
struct mbuf *mp;
int req_len;
{
register int len = req_len;
register struct mbuf *m;
register count;
if ((m = mp) == NULL)
return;
if (len >= 0) {
/*
* Trim from head.
*/
while (m != NULL && len > 0) {
if (m->m_len <= len) {
len -= m->m_len;
m->m_len = 0;
m = m->m_next;
} else {
m->m_len -= len;
m->m_data += len;
len = 0;
}
}
m = mp;
if (mp->m_flags & M_PKTHDR)
m->m_pkthdr.len -= (req_len - len);
} else {
/*
* Trim from tail. Scan the mbuf chain,
* calculating its length and finding the last mbuf.
* If the adjustment only affects this mbuf, then just
* adjust and return. Otherwise, rescan and truncate
* after the remaining size.
*/
len = -len;
count = 0;
for (;;) {
count += m->m_len;
if (m->m_next == (struct mbuf *)0)
break;
m = m->m_next;
}
if (m->m_len >= len) {
m->m_len -= len;
if (mp->m_flags & M_PKTHDR)
mp->m_pkthdr.len -= len;
return;
}
count -= len;
if (count < 0)
count = 0;
/*
* Correct length for chain is "count".
* Find the mbuf with last data, adjust its length,
* and toss data from remaining mbufs on chain.
*/
m = mp;
if (m->m_flags & M_PKTHDR)
m->m_pkthdr.len = count;
for (; m; m = m->m_next) {
if (m->m_len >= count) {
m->m_len = count;
break;
}
count -= m->m_len;
}
while (m = m->m_next)
m->m_len = 0;
}
}
/*
* Rearange an mbuf chain so that len bytes are contiguous
* and in the data area of an mbuf (so that mtod and dtom
* will work for a structure of size len). Returns the resulting
* mbuf chain on success, frees it and returns null on failure.
* If there is room, it will add up to max_protohdr-len extra bytes to the
* contiguous region in an attempt to avoid being called next time.
*/
int MPFail;
struct mbuf *
m_pullup(n, len)
register struct mbuf *n;
int len;
{
register struct mbuf *m;
register int count;
int space;
/*
* If first mbuf has no cluster, and has room for len bytes
* without shifting current data, pullup into it,
* otherwise allocate a new mbuf to prepend to the chain.
*/
if ((n->m_flags & M_EXT) == 0 &&
n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
if (n->m_len >= len)
return (n);
m = n;
n = n->m_next;
len -= m->m_len;
} else {
if (len > MHLEN)
goto bad;
MGET(m, M_DONTWAIT, n->m_type);
if (m == 0)
goto bad;
m->m_len = 0;
if (n->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(m, n);
n->m_flags &= ~M_PKTHDR;
}
}
space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
do {
count = min(min(max(len, max_protohdr), space), n->m_len);
bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
(unsigned)count);
len -= count;
m->m_len += count;
n->m_len -= count;
space -= count;
if (n->m_len)
n->m_data += count;
else
n = m_free(n);
} while (len > 0 && n);
if (len > 0) {
(void) m_free(m);
goto bad;
}
m->m_next = n;
return (m);
bad:
m_freem(n);
MPFail++;
return (0);
}
/*
* Partition an mbuf chain in two pieces, returning the tail --
* all but the first len0 bytes. In case of failure, it returns NULL and
* attempts to restore the chain to its original state.
*/
struct mbuf *
m_split(m0, len0, wait)
register struct mbuf *m0;
int len0, 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)]++;
m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
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);
}
/*
* Routine to copy from device local memory into mbufs.
*/
struct mbuf *
m_devget(buf, totlen, off0, ifp, copy)
char *buf;
int totlen, off0;
struct ifnet *ifp;
void (*copy)();
{
register struct mbuf *m;
struct mbuf *top = 0, **mp = &top;
register int off = off0, len;
register char *cp;
char *epkt;
cp = buf;
epkt = cp + totlen;
if (off) {
/*
* If 'off' is non-zero, packet is trailer-encapsulated,
* so we have to skip the type and length fields.
*/
cp += off + 2 * sizeof(u_int16_t);
totlen -= 2 * sizeof(u_int16_t);
}
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0)
return (0);
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
m->m_len = MHLEN;
while (totlen > 0) {
if (top) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
m_freem(top);
return (0);
}
m->m_len = MLEN;
}
len = min(totlen, epkt - cp);
if (len >= MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT)
m->m_len = len = min(len, MCLBYTES);
else
len = m->m_len;
} else {
/*
* Place initial small packet/header at end of mbuf.
*/
if (len < m->m_len) {
if (top == 0 && len + max_linkhdr <= m->m_len)
m->m_data += max_linkhdr;
m->m_len = len;
} else
len = m->m_len;
}
if (copy)
copy(cp, mtod(m, caddr_t), (unsigned)len);
else
bcopy(cp, mtod(m, caddr_t), (unsigned)len);
cp += len;
*mp = m;
mp = &m->m_next;
totlen -= len;
if (cp == epkt)
cp = buf;
}
return (top);
}

72
sys/kern/uipc_proto.c Normal file
View File

@ -0,0 +1,72 @@
/*-
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. 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 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.
*
* @(#)uipc_proto.c 8.2 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
/*
* Definitions of protocols supported in the UNIX domain.
*/
int uipc_usrreq(), raw_usrreq();
void raw_init(), raw_input(), raw_ctlinput();
extern struct domain unixdomain; /* or at least forward */
struct protosw unixsw[] = {
{ SOCK_STREAM, &unixdomain, 0, PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS,
0, 0, 0, 0,
uipc_usrreq,
0, 0, 0, 0,
},
{ SOCK_DGRAM, &unixdomain, 0, PR_ATOMIC|PR_ADDR|PR_RIGHTS,
0, 0, 0, 0,
uipc_usrreq,
0, 0, 0, 0,
},
{ 0, 0, 0, 0,
raw_input, 0, raw_ctlinput, 0,
raw_usrreq,
raw_init, 0, 0, 0,
}
};
int unp_externalize(), unp_dispose();
struct domain unixdomain =
{ AF_UNIX, "unix", 0, unp_externalize, unp_dispose,
unixsw, &unixsw[sizeof(unixsw)/sizeof(unixsw[0])] };

1040
sys/kern/uipc_socket.c Normal file

File diff suppressed because it is too large Load Diff

779
sys/kern/uipc_socket2.c Normal file
View File

@ -0,0 +1,779 @@
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
* The Regents of the University of California. 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 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.
*
* @(#)uipc_socket2.c 8.2 (Berkeley) 2/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
/*
* Primitive routines for operating on sockets and socket buffers
*/
/* strings for sleep message: */
char netio[] = "netio";
char netcon[] = "netcon";
char netcls[] = "netcls";
u_long sb_max = SB_MAX; /* patchable */
/*
* Procedures to manipulate state flags of socket
* and do appropriate wakeups. Normal sequence from the
* active (originating) side is that soisconnecting() is
* called during processing of connect() call,
* resulting in an eventual call to soisconnected() if/when the
* connection is established. When the connection is torn down
* soisdisconnecting() is called during processing of disconnect() call,
* and soisdisconnected() is called when the connection to the peer
* is totally severed. The semantics of these routines are such that
* connectionless protocols can call soisconnected() and soisdisconnected()
* only, bypassing the in-progress calls when setting up a ``connection''
* takes no time.
*
* From the passive side, a socket is created with
* two queues of sockets: so_q0 for connections in progress
* and so_q for connections already made and awaiting user acceptance.
* As a protocol is preparing incoming connections, it creates a socket
* structure queued on so_q0 by calling sonewconn(). When the connection
* is established, soisconnected() is called, and transfers the
* socket structure to so_q, making it available to accept().
*
* If a socket is closed with sockets on either
* so_q0 or so_q, these sockets are dropped.
*
* If higher level protocols are implemented in
* the kernel, the wakeups done here will sometimes
* cause software-interrupt process scheduling.
*/
void
soisconnecting(so)
register struct socket *so;
{
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISCONNECTING;
}
void
soisconnected(so)
register struct socket *so;
{
register struct socket *head = so->so_head;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && soqremque(so, 0)) {
soqinsque(head, so, 1);
sorwakeup(head);
wakeup((caddr_t)&head->so_timeo);
} else {
wakeup((caddr_t)&so->so_timeo);
sorwakeup(so);
sowwakeup(so);
}
}
void
soisdisconnecting(so)
register struct socket *so;
{
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
wakeup((caddr_t)&so->so_timeo);
sowwakeup(so);
sorwakeup(so);
}
void
soisdisconnected(so)
register struct socket *so;
{
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
wakeup((caddr_t)&so->so_timeo);
sowwakeup(so);
sorwakeup(so);
}
/*
* When an attempt at a new connection is noted on a socket
* which accepts connections, sonewconn is called. If the
* connection is possible (subject to space constraints, etc.)
* then we allocate a new structure, propoerly linked into the
* data structure of the original socket, and return this.
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
*
* Currently, sonewconn() is defined as sonewconn1() in socketvar.h
* to catch calls that are missing the (new) second parameter.
*/
struct socket *
sonewconn1(head, connstatus)
register struct socket *head;
int connstatus;
{
register struct socket *so;
int soqueue = connstatus ? 1 : 0;
if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2)
return ((struct socket *)0);
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT);
if (so == NULL)
return ((struct socket *)0);
bzero((caddr_t)so, sizeof(*so));
so->so_type = head->so_type;
so->so_options = head->so_options &~ SO_ACCEPTCONN;
so->so_linger = head->so_linger;
so->so_state = head->so_state | SS_NOFDREF;
so->so_proto = head->so_proto;
so->so_timeo = head->so_timeo;
so->so_pgid = head->so_pgid;
(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)) {
(void) soqremque(so, soqueue);
(void) free((caddr_t)so, M_SOCKET);
return ((struct socket *)0);
}
if (connstatus) {
sorwakeup(head);
wakeup((caddr_t)&head->so_timeo);
so->so_state |= connstatus;
}
return (so);
}
void
soqinsque(head, so, q)
register struct socket *head, *so;
int q;
{
register struct socket **prev;
so->so_head = head;
if (q == 0) {
head->so_q0len++;
so->so_q0 = 0;
for (prev = &(head->so_q0); *prev; )
prev = &((*prev)->so_q0);
} else {
head->so_qlen++;
so->so_q = 0;
for (prev = &(head->so_q); *prev; )
prev = &((*prev)->so_q);
}
*prev = so;
}
int
soqremque(so, q)
register struct socket *so;
int q;
{
register struct socket *head, *prev, *next;
head = so->so_head;
prev = head;
for (;;) {
next = q ? prev->so_q : prev->so_q0;
if (next == so)
break;
if (next == 0)
return (0);
prev = next;
}
if (q == 0) {
prev->so_q0 = next->so_q0;
head->so_q0len--;
} else {
prev->so_q = next->so_q;
head->so_qlen--;
}
next->so_q0 = next->so_q = 0;
next->so_head = 0;
return (1);
}
/*
* Socantsendmore indicates that no more data will be sent on the
* socket; it would normally be applied to a socket when the user
* informs the system that no more data is to be sent, by the protocol
* code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data
* will be received, and will normally be applied to the socket by a
* protocol when it detects that the peer will send no more data.
* Data queued for reading in the socket may yet be read.
*/
void
socantsendmore(so)
struct socket *so;
{
so->so_state |= SS_CANTSENDMORE;
sowwakeup(so);
}
void
socantrcvmore(so)
struct socket *so;
{
so->so_state |= SS_CANTRCVMORE;
sorwakeup(so);
}
/*
* Wait for data to arrive at/drain from a socket buffer.
*/
int
sbwait(sb)
struct sockbuf *sb;
{
sb->sb_flags |= SB_WAIT;
return (tsleep((caddr_t)&sb->sb_cc,
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, netio,
sb->sb_timeo));
}
/*
* Lock a sockbuf already known to be locked;
* return any error returned from sleep (EINTR).
*/
int
sb_lock(sb)
register struct sockbuf *sb;
{
int error;
while (sb->sb_flags & SB_LOCK) {
sb->sb_flags |= SB_WANT;
if (error = tsleep((caddr_t)&sb->sb_flags,
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH,
netio, 0))
return (error);
}
sb->sb_flags |= SB_LOCK;
return (0);
}
/*
* Wakeup processes waiting on a socket buffer.
* 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;
{
struct proc *p;
selwakeup(&sb->sb_sel);
sb->sb_flags &= ~SB_SEL;
if (sb->sb_flags & SB_WAIT) {
sb->sb_flags &= ~SB_WAIT;
wakeup((caddr_t)&sb->sb_cc);
}
if (so->so_state & SS_ASYNC) {
if (so->so_pgid < 0)
gsignal(-so->so_pgid, SIGIO);
else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
psignal(p, SIGIO);
}
}
/*
* Socket buffer (struct sockbuf) utility routines.
*
* Each socket contains two socket buffers: one for sending data and
* one for receiving data. Each buffer contains a queue of mbufs,
* information about the number of mbufs and amount of data in the
* queue, and other fields allowing select() statements and notification
* on data availability to be implemented.
*
* Data stored in a socket buffer is maintained as a list of records.
* Each record is a list of mbufs chained together with the m_next
* field. Records are chained together with the m_nextpkt field. The upper
* level routine soreceive() expects the following conventions to be
* observed when placing information in the receive buffer:
*
* 1. If the protocol requires each message be preceded by the sender's
* name, then a record containing that name must be present before
* any associated data (mbuf's must be of type MT_SONAME).
* 2. If the protocol supports the exchange of ``access rights'' (really
* just additional data associated with the message), and there are
* ``rights'' to be received, then a record containing this data
* should be present (mbuf's must be of type MT_RIGHTS).
* 3. If a name or rights record exists, then it must be followed by
* a data record, perhaps of zero length.
*
* Before using a new socket structure it is first necessary to reserve
* buffer space to the socket, by calling sbreserve(). This should commit
* some of the available buffer space in the system buffer pool for the
* socket (currently, it does nothing but enforce limits). The space
* should be released by calling sbrelease() when the socket is destroyed.
*/
int
soreserve(so, sndcc, rcvcc)
register struct socket *so;
u_long sndcc, rcvcc;
{
if (sbreserve(&so->so_snd, sndcc) == 0)
goto bad;
if (sbreserve(&so->so_rcv, rcvcc) == 0)
goto bad2;
if (so->so_rcv.sb_lowat == 0)
so->so_rcv.sb_lowat = 1;
if (so->so_snd.sb_lowat == 0)
so->so_snd.sb_lowat = MCLBYTES;
if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
return (0);
bad2:
sbrelease(&so->so_snd);
bad:
return (ENOBUFS);
}
/*
* Allot mbufs to a sockbuf.
* 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;
{
if (cc > sb_max * MCLBYTES / (MSIZE + MCLBYTES))
return (0);
sb->sb_hiwat = cc;
sb->sb_mbmax = min(cc * 2, sb_max);
if (sb->sb_lowat > sb->sb_hiwat)
sb->sb_lowat = sb->sb_hiwat;
return (1);
}
/*
* Free mbufs held by a socket, and reserved mbuf space.
*/
void
sbrelease(sb)
struct sockbuf *sb;
{
sbflush(sb);
sb->sb_hiwat = sb->sb_mbmax = 0;
}
/*
* Routines to add and remove
* data from an mbuf queue.
*
* The routines sbappend() or sbappendrecord() are normally called to
* append new mbufs to a socket buffer, after checking that adequate
* space is available, comparing the function sbspace() with the amount
* of data to be added. sbappendrecord() differs from sbappend() in
* that data supplied is treated as the beginning of a new record.
* To place a sender's address, optional access rights, and data in a
* socket receive buffer, sbappendaddr() should be used. To place
* access rights and data in a socket receive buffer, sbappendrights()
* should be used. In either case, the new data begins a new record.
* Note that unlike sbappend() and sbappendrecord(), these routines check
* for the caller that there will be enough space to store the data.
* Each fails if there is not enough space, or if it cannot find mbufs
* to store additional information in.
*
* Reliable protocols may use the socket send buffer to hold data
* awaiting acknowledgement. Data is normally copied from a socket
* send buffer in a protocol with m_copy for output to a peer,
* and then removing the data from the socket buffer with sbdrop()
* or sbdroprecord() when the data is acknowledged by the peer.
*/
/*
* Append mbuf chain m to the last record in the
* socket buffer sb. The additional space associated
* 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;
{
register struct mbuf *n;
if (m == 0)
return;
if (n = sb->sb_mb) {
while (n->m_nextpkt)
n = n->m_nextpkt;
do {
if (n->m_flags & M_EOR) {
sbappendrecord(sb, m); /* XXXXXX!!!! */
return;
}
} while (n->m_next && (n = n->m_next));
}
sbcompress(sb, m, n);
}
#ifdef SOCKBUF_DEBUG
void
sbcheck(sb)
register struct sockbuf *sb;
{
register struct mbuf *m;
register int len = 0, mbcnt = 0;
for (m = sb->sb_mb; m; m = m->m_next) {
len += m->m_len;
mbcnt += MSIZE;
if (m->m_flags & M_EXT)
mbcnt += m->m_ext.ext_size;
if (m->m_nextpkt)
panic("sbcheck nextpkt");
}
if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
printf("cc %d != %d || mbcnt %d != %d\n", len, sb->sb_cc,
mbcnt, sb->sb_mbcnt);
panic("sbcheck");
}
}
#endif
/*
* As above, except the mbuf chain
* begins a new record.
*/
void
sbappendrecord(sb, m0)
register struct sockbuf *sb;
register struct mbuf *m0;
{
register struct mbuf *m;
if (m0 == 0)
return;
if (m = sb->sb_mb)
while (m->m_nextpkt)
m = m->m_nextpkt;
/*
* Put the first mbuf on the queue.
* Note this permits zero length records.
*/
sballoc(sb, m0);
if (m)
m->m_nextpkt = m0;
else
sb->sb_mb = m0;
m = m0->m_next;
m0->m_next = 0;
if (m && (m0->m_flags & M_EOR)) {
m0->m_flags &= ~M_EOR;
m->m_flags |= M_EOR;
}
sbcompress(sb, m, m0);
}
/*
* As above except that OOB data
* 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;
{
register struct mbuf *m;
register struct mbuf **mp;
if (m0 == 0)
return;
for (mp = &sb->sb_mb; m = *mp; mp = &((*mp)->m_nextpkt)) {
again:
switch (m->m_type) {
case MT_OOBDATA:
continue; /* WANT next train */
case MT_CONTROL:
if (m = m->m_next)
goto again; /* inspect THIS train further */
}
break;
}
/*
* Put the first mbuf on the queue.
* Note this permits zero length records.
*/
sballoc(sb, m0);
m0->m_nextpkt = *mp;
*mp = m0;
m = m0->m_next;
m0->m_next = 0;
if (m && (m0->m_flags & M_EOR)) {
m0->m_flags &= ~M_EOR;
m->m_flags |= M_EOR;
}
sbcompress(sb, m, m0);
}
/*
* Append address and data, and optionally, control (ancillary) data
* to the receive queue of a socket. If present,
* 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;
struct mbuf *m0, *control;
{
register struct mbuf *m, *n;
int space = asa->sa_len;
if (m0 && (m0->m_flags & M_PKTHDR) == 0)
panic("sbappendaddr");
if (m0)
space += m0->m_pkthdr.len;
for (n = control; n; n = n->m_next) {
space += n->m_len;
if (n->m_next == 0) /* keep pointer to last control buf */
break;
}
if (space > sbspace(sb))
return (0);
if (asa->sa_len > MLEN)
return (0);
MGET(m, M_DONTWAIT, MT_SONAME);
if (m == 0)
return (0);
m->m_len = asa->sa_len;
bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len);
if (n)
n->m_next = m0; /* concatenate data to control */
else
control = m0;
m->m_next = control;
for (n = m; n; n = n->m_next)
sballoc(sb, n);
if (n = sb->sb_mb) {
while (n->m_nextpkt)
n = n->m_nextpkt;
n->m_nextpkt = m;
} else
sb->sb_mb = m;
return (1);
}
int
sbappendcontrol(sb, m0, control)
struct sockbuf *sb;
struct mbuf *m0, *control;
{
register struct mbuf *m, *n;
int space = 0;
if (control == 0)
panic("sbappendcontrol");
for (m = control; ; m = m->m_next) {
space += m->m_len;
if (m->m_next == 0)
break;
}
n = m; /* save pointer to last control buffer */
for (m = m0; m; m = m->m_next)
space += m->m_len;
if (space > sbspace(sb))
return (0);
n->m_next = m0; /* concatenate data to control */
for (m = control; m; m = m->m_next)
sballoc(sb, m);
if (n = sb->sb_mb) {
while (n->m_nextpkt)
n = n->m_nextpkt;
n->m_nextpkt = control;
} else
sb->sb_mb = control;
return (1);
}
/*
* Compress mbuf chain m into the socket
* 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;
{
register int eor = 0;
register struct mbuf *o;
while (m) {
eor |= m->m_flags & M_EOR;
if (m->m_len == 0 &&
(eor == 0 ||
(((o = m->m_next) || (o = n)) &&
o->m_type == m->m_type))) {
m = m_free(m);
continue;
}
if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 &&
(n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] &&
n->m_type == m->m_type) {
bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
(unsigned)m->m_len);
n->m_len += m->m_len;
sb->sb_cc += m->m_len;
m = m_free(m);
continue;
}
if (n)
n->m_next = m;
else
sb->sb_mb = m;
sballoc(sb, m);
n = m;
m->m_flags &= ~M_EOR;
m = m->m_next;
n->m_next = 0;
}
if (eor) {
if (n)
n->m_flags |= eor;
else
printf("semi-panic: sbcompress\n");
}
}
/*
* Free all mbufs in a sockbuf.
* Check that all resources are reclaimed.
*/
void
sbflush(sb)
register struct sockbuf *sb;
{
if (sb->sb_flags & SB_LOCK)
panic("sbflush");
while (sb->sb_mbcnt)
sbdrop(sb, (int)sb->sb_cc);
if (sb->sb_cc || sb->sb_mb)
panic("sbflush 2");
}
/*
* Drop data from (the front of) a sockbuf.
*/
void
sbdrop(sb, len)
register struct sockbuf *sb;
register int len;
{
register struct mbuf *m, *mn;
struct mbuf *next;
next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
while (len > 0) {
if (m == 0) {
if (next == 0)
panic("sbdrop");
m = next;
next = m->m_nextpkt;
continue;
}
if (m->m_len > len) {
m->m_len -= len;
m->m_data += len;
sb->sb_cc -= len;
break;
}
len -= m->m_len;
sbfree(sb, m);
MFREE(m, mn);
m = mn;
}
while (m && m->m_len == 0) {
sbfree(sb, m);
MFREE(m, mn);
m = mn;
}
if (m) {
sb->sb_mb = m;
m->m_nextpkt = next;
} else
sb->sb_mb = next;
}
/*
* Drop a record off the front of a sockbuf
* and move the next record to the front.
*/
void
sbdroprecord(sb)
register struct sockbuf *sb;
{
register struct mbuf *m, *mn;
m = sb->sb_mb;
if (m) {
sb->sb_mb = m->m_nextpkt;
do {
sbfree(sb, m);
MFREE(m, mn);
} while (m = mn);
}
}

1263
sys/kern/uipc_syscalls.c Normal file

File diff suppressed because it is too large Load Diff

839
sys/kern/uipc_usrreq.c Normal file
View File

@ -0,0 +1,839 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. 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 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.
*
* @(#)uipc_usrreq.c 8.9 (Berkeley) 5/14/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/unpcb.h>
#include <sys/un.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/mbuf.h>
/*
* Unix communications domain.
*
* TODO:
* SEQPACKET, RDM
* rethink name space problems
* need a proper out-of-band
*/
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;
struct mbuf *m, *nam, *control;
{
struct unpcb *unp = sotounpcb(so);
register struct socket *so2;
register int error = 0;
struct proc *p = curproc; /* XXX */
if (req == PRU_CONTROL)
return (EOPNOTSUPP);
if (req != PRU_SEND && control && control->m_len) {
error = EOPNOTSUPP;
goto release;
}
if (unp == 0 && req != PRU_ATTACH) {
error = EINVAL;
goto release;
}
switch (req) {
case PRU_ATTACH:
if (unp) {
error = EISCONN;
break;
}
error = unp_attach(so);
break;
case PRU_DETACH:
unp_detach(unp);
break;
case PRU_BIND:
error = unp_bind(unp, nam, p);
break;
case PRU_LISTEN:
if (unp->unp_vnode == 0)
error = EINVAL;
break;
case PRU_CONNECT:
error = unp_connect(so, nam, p);
break;
case PRU_CONNECT2:
error = unp_connect2(so, (struct socket *)nam);
break;
case PRU_DISCONNECT:
unp_disconnect(unp);
break;
case PRU_ACCEPT:
/*
* Pass back name of connected socket,
* if it was bound and we are still connected
* (our peer may have closed already!).
*/
if (unp->unp_conn && unp->unp_conn->unp_addr) {
nam->m_len = unp->unp_conn->unp_addr->m_len;
bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
mtod(nam, caddr_t), (unsigned)nam->m_len);
} else {
nam->m_len = sizeof(sun_noname);
*(mtod(nam, struct sockaddr *)) = sun_noname;
}
break;
case PRU_SHUTDOWN:
socantsendmore(so);
unp_shutdown(unp);
break;
case PRU_RCVD:
switch (so->so_type) {
case SOCK_DGRAM:
panic("uipc 1");
/*NOTREACHED*/
case SOCK_STREAM:
#define rcv (&so->so_rcv)
#define snd (&so2->so_snd)
if (unp->unp_conn == 0)
break;
so2 = unp->unp_conn->unp_socket;
/*
* Adjust backpressure on sender
* and wakeup any waiting to write.
*/
snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
unp->unp_mbcnt = rcv->sb_mbcnt;
snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
unp->unp_cc = rcv->sb_cc;
sowwakeup(so2);
#undef snd
#undef rcv
break;
default:
panic("uipc 2");
}
break;
case PRU_SEND:
if (control && (error = unp_internalize(control, p)))
break;
switch (so->so_type) {
case SOCK_DGRAM: {
struct sockaddr *from;
if (nam) {
if (unp->unp_conn) {
error = EISCONN;
break;
}
error = unp_connect(so, nam, p);
if (error)
break;
} else {
if (unp->unp_conn == 0) {
error = ENOTCONN;
break;
}
}
so2 = unp->unp_conn->unp_socket;
if (unp->unp_addr)
from = mtod(unp->unp_addr, struct sockaddr *);
else
from = &sun_noname;
if (sbappendaddr(&so2->so_rcv, from, m, control)) {
sorwakeup(so2);
m = 0;
control = 0;
} else
error = ENOBUFS;
if (nam)
unp_disconnect(unp);
break;
}
case SOCK_STREAM:
#define rcv (&so2->so_rcv)
#define snd (&so->so_snd)
if (so->so_state & SS_CANTSENDMORE) {
error = EPIPE;
break;
}
if (unp->unp_conn == 0)
panic("uipc 3");
so2 = unp->unp_conn->unp_socket;
/*
* Send to paired receive port, and then reduce
* send buffer hiwater marks to maintain backpressure.
* Wake up readers.
*/
if (control) {
if (sbappendcontrol(rcv, m, control))
control = 0;
} else
sbappend(rcv, m);
snd->sb_mbmax -=
rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
unp->unp_conn->unp_cc = rcv->sb_cc;
sorwakeup(so2);
m = 0;
#undef snd
#undef rcv
break;
default:
panic("uipc 4");
}
break;
case PRU_ABORT:
unp_drop(unp, ECONNABORTED);
break;
case PRU_SENSE:
((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
so2 = unp->unp_conn->unp_socket;
((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
}
((struct stat *) m)->st_dev = NODEV;
if (unp->unp_ino == 0)
unp->unp_ino = unp_ino++;
((struct stat *) m)->st_ino = unp->unp_ino;
return (0);
case PRU_RCVOOB:
return (EOPNOTSUPP);
case PRU_SENDOOB:
error = EOPNOTSUPP;
break;
case PRU_SOCKADDR:
if (unp->unp_addr) {
nam->m_len = unp->unp_addr->m_len;
bcopy(mtod(unp->unp_addr, caddr_t),
mtod(nam, caddr_t), (unsigned)nam->m_len);
} else
nam->m_len = 0;
break;
case PRU_PEERADDR:
if (unp->unp_conn && unp->unp_conn->unp_addr) {
nam->m_len = unp->unp_conn->unp_addr->m_len;
bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
mtod(nam, caddr_t), (unsigned)nam->m_len);
} else
nam->m_len = 0;
break;
case PRU_SLOWTIMO:
break;
default:
panic("piusrreq");
}
release:
if (control)
m_freem(control);
if (m)
m_freem(m);
return (error);
}
/*
* Both send and receive buffers are allocated PIPSIZ bytes of buffering
* for stream sockets, although the total for sender and receiver is
* actually only PIPSIZ.
* Datagram sockets really use the sendspace as the maximum datagram size,
* and don't really want to reserve the sendspace. Their recvspace should
* be large enough for at least one max-size datagram plus address.
*/
#define PIPSIZ 4096
u_long unpst_sendspace = PIPSIZ;
u_long unpst_recvspace = PIPSIZ;
u_long unpdg_sendspace = 2*1024; /* really max datagram size */
u_long unpdg_recvspace = 4*1024;
int unp_rights; /* file descriptors in flight */
int
unp_attach(so)
struct socket *so;
{
register struct mbuf *m;
register struct unpcb *unp;
int error;
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
switch (so->so_type) {
case SOCK_STREAM:
error = soreserve(so, unpst_sendspace, unpst_recvspace);
break;
case SOCK_DGRAM:
error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
break;
default:
panic("unp_attach");
}
if (error)
return (error);
}
m = m_getclr(M_DONTWAIT, MT_PCB);
if (m == NULL)
return (ENOBUFS);
unp = mtod(m, struct unpcb *);
so->so_pcb = (caddr_t)unp;
unp->unp_socket = so;
return (0);
}
void
unp_detach(unp)
register struct unpcb *unp;
{
if (unp->unp_vnode) {
unp->unp_vnode->v_socket = 0;
vrele(unp->unp_vnode);
unp->unp_vnode = 0;
}
if (unp->unp_conn)
unp_disconnect(unp);
while (unp->unp_refs)
unp_drop(unp->unp_refs, ECONNRESET);
soisdisconnected(unp->unp_socket);
unp->unp_socket->so_pcb = 0;
m_freem(unp->unp_addr);
(void) m_free(dtom(unp));
if (unp_rights) {
/*
* Normally the receive buffer is flushed later,
* in sofree, but if our receive buffer holds references
* to descriptors that are now garbage, we will dispose
* of those descriptor references after the garbage collector
* gets them (resulting in a "panic: closef: count < 0").
*/
sorflush(unp->unp_socket);
unp_gc();
}
}
int
unp_bind(unp, nam, p)
struct unpcb *unp;
struct mbuf *nam;
struct proc *p;
{
struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
register struct vnode *vp;
struct vattr vattr;
int error;
struct nameidata nd;
NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
soun->sun_path, p);
if (unp->unp_vnode != NULL)
return (EINVAL);
if (nam->m_len == MLEN) {
if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
return (EINVAL);
} else
*(mtod(nam, caddr_t) + nam->m_len) = 0;
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
if (error = namei(&nd))
return (error);
vp = nd.ni_vp;
if (vp != NULL) {
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
vrele(vp);
return (EADDRINUSE);
}
VATTR_NULL(&vattr);
vattr.va_type = VSOCK;
vattr.va_mode = ACCESSPERMS;
VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
return (error);
vp = nd.ni_vp;
vp->v_socket = unp->unp_socket;
unp->unp_vnode = vp;
unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
VOP_UNLOCK(vp, 0, p);
return (0);
}
int
unp_connect(so, nam, p)
struct socket *so;
struct mbuf *nam;
struct proc *p;
{
register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
register struct vnode *vp;
register struct socket *so2, *so3;
struct unpcb *unp2, *unp3;
int error;
struct nameidata nd;
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */
if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
return (EMSGSIZE);
} else
*(mtod(nam, caddr_t) + nam->m_len) = 0;
if (error = namei(&nd))
return (error);
vp = nd.ni_vp;
if (vp->v_type != VSOCK) {
error = ENOTSOCK;
goto bad;
}
if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
goto bad;
so2 = vp->v_socket;
if (so2 == 0) {
error = ECONNREFUSED;
goto bad;
}
if (so->so_type != so2->so_type) {
error = EPROTOTYPE;
goto bad;
}
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
(so3 = sonewconn(so2, 0)) == 0) {
error = ECONNREFUSED;
goto bad;
}
unp2 = sotounpcb(so2);
unp3 = sotounpcb(so3);
if (unp2->unp_addr)
unp3->unp_addr =
m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
so2 = so3;
}
error = unp_connect2(so, so2);
bad:
vput(vp);
return (error);
}
int
unp_connect2(so, so2)
register struct socket *so;
register struct socket *so2;
{
register struct unpcb *unp = sotounpcb(so);
register struct unpcb *unp2;
if (so2->so_type != so->so_type)
return (EPROTOTYPE);
unp2 = sotounpcb(so2);
unp->unp_conn = unp2;
switch (so->so_type) {
case SOCK_DGRAM:
unp->unp_nextref = unp2->unp_refs;
unp2->unp_refs = unp;
soisconnected(so);
break;
case SOCK_STREAM:
unp2->unp_conn = unp;
soisconnected(so);
soisconnected(so2);
break;
default:
panic("unp_connect2");
}
return (0);
}
void
unp_disconnect(unp)
struct unpcb *unp;
{
register struct unpcb *unp2 = unp->unp_conn;
if (unp2 == 0)
return;
unp->unp_conn = 0;
switch (unp->unp_socket->so_type) {
case SOCK_DGRAM:
if (unp2->unp_refs == unp)
unp2->unp_refs = unp->unp_nextref;
else {
unp2 = unp2->unp_refs;
for (;;) {
if (unp2 == 0)
panic("unp_disconnect");
if (unp2->unp_nextref == unp)
break;
unp2 = unp2->unp_nextref;
}
unp2->unp_nextref = unp->unp_nextref;
}
unp->unp_nextref = 0;
unp->unp_socket->so_state &= ~SS_ISCONNECTED;
break;
case SOCK_STREAM:
soisdisconnected(unp->unp_socket);
unp2->unp_conn = 0;
soisdisconnected(unp2->unp_socket);
break;
}
}
#ifdef notdef
void
unp_abort(unp)
struct unpcb *unp;
{
unp_detach(unp);
}
#endif
void
unp_shutdown(unp)
struct unpcb *unp;
{
struct socket *so;
if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
(so = unp->unp_conn->unp_socket))
socantrcvmore(so);
}
void
unp_drop(unp, errno)
struct unpcb *unp;
int errno;
{
struct socket *so = unp->unp_socket;
so->so_error = errno;
unp_disconnect(unp);
if (so->so_head) {
so->so_pcb = (caddr_t) 0;
m_freem(unp->unp_addr);
(void) m_free(dtom(unp));
sofree(so);
}
}
#ifdef notdef
unp_drain()
{
}
#endif
int
unp_externalize(rights)
struct mbuf *rights;
{
struct proc *p = curproc; /* XXX */
register int i;
register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
register struct file **rp = (struct file **)(cm + 1);
register struct file *fp;
int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
int f;
if (!fdavail(p, newfds)) {
for (i = 0; i < newfds; i++) {
fp = *rp;
unp_discard(fp);
*rp++ = 0;
}
return (EMSGSIZE);
}
for (i = 0; i < newfds; i++) {
if (fdalloc(p, 0, &f))
panic("unp_externalize");
fp = *rp;
p->p_fd->fd_ofiles[f] = fp;
fp->f_msgcount--;
unp_rights--;
*(int *)rp++ = f;
}
return (0);
}
int
unp_internalize(control, p)
struct mbuf *control;
struct proc *p;
{
struct filedesc *fdp = p->p_fd;
register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
register struct file **rp;
register struct file *fp;
register int i, fd;
int oldfds;
if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
cm->cmsg_len != control->m_len)
return (EINVAL);
oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
rp = (struct file **)(cm + 1);
for (i = 0; i < oldfds; i++) {
fd = *(int *)rp++;
if ((unsigned)fd >= fdp->fd_nfiles ||
fdp->fd_ofiles[fd] == NULL)
return (EBADF);
}
rp = (struct file **)(cm + 1);
for (i = 0; i < oldfds; i++) {
fp = fdp->fd_ofiles[*(int *)rp];
*rp++ = fp;
fp->f_count++;
fp->f_msgcount++;
unp_rights++;
}
return (0);
}
int unp_defer, unp_gcing;
extern struct domain unixdomain;
void
unp_gc()
{
register struct file *fp, *nextfp;
register struct socket *so;
struct file **extra_ref, **fpp;
int nunref, i;
if (unp_gcing)
return;
unp_gcing = 1;
unp_defer = 0;
for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next)
fp->f_flag &= ~(FMARK|FDEFER);
do {
for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
if (fp->f_count == 0)
continue;
if (fp->f_flag & FDEFER) {
fp->f_flag &= ~FDEFER;
unp_defer--;
} else {
if (fp->f_flag & FMARK)
continue;
if (fp->f_count == fp->f_msgcount)
continue;
fp->f_flag |= FMARK;
}
if (fp->f_type != DTYPE_SOCKET ||
(so = (struct socket *)fp->f_data) == 0)
continue;
if (so->so_proto->pr_domain != &unixdomain ||
(so->so_proto->pr_flags&PR_RIGHTS) == 0)
continue;
#ifdef notdef
if (so->so_rcv.sb_flags & SB_LOCK) {
/*
* This is problematical; it's not clear
* we need to wait for the sockbuf to be
* unlocked (on a uniprocessor, at least),
* and it's also not clear what to do
* if sbwait returns an error due to receipt
* of a signal. If sbwait does return
* an error, we'll go into an infinite
* loop. Delete all of this for now.
*/
(void) sbwait(&so->so_rcv);
goto restart;
}
#endif
unp_scan(so->so_rcv.sb_mb, unp_mark);
}
} while (unp_defer);
/*
* We grab an extra reference to each of the file table entries
* that are not otherwise accessible and then free the rights
* that are stored in messages on them.
*
* The bug in the orginal code is a little tricky, so I'll describe
* what's wrong with it here.
*
* It is incorrect to simply unp_discard each entry for f_msgcount
* times -- consider the case of sockets A and B that contain
* references to each other. On a last close of some other socket,
* we trigger a gc since the number of outstanding rights (unp_rights)
* is non-zero. If during the sweep phase the gc code un_discards,
* we end up doing a (full) closef on the descriptor. A closef on A
* results in the following chain. Closef calls soo_close, which
* calls soclose. Soclose calls first (through the switch
* uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply
* returns because the previous instance had set unp_gcing, and
* we return all the way back to soclose, which marks the socket
* with SS_NOFDREF, and then calls sofree. Sofree calls sorflush
* to free up the rights that are queued in messages on the socket A,
* i.e., the reference on B. The sorflush calls via the dom_dispose
* switch unp_dispose, which unp_scans with unp_discard. This second
* instance of unp_discard just calls closef on B.
*
* Well, a similar chain occurs on B, resulting in a sorflush on B,
* which results in another closef on A. Unfortunately, A is already
* being closed, and the descriptor has already been marked with
* SS_NOFDREF, and soclose panics at this point.
*
* Here, we first take an extra reference to each inaccessible
* descriptor. Then, we call sorflush ourself, since we know
* it is a Unix domain socket anyhow. After we destroy all the
* rights carried in messages, we do a last closef to get rid
* of our extra reference. This is the last close, and the
* unp_detach etc will shut down the socket.
*
* 91/09/19, bsy@cs.cmu.edu
*/
extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0;
fp = nextfp) {
nextfp = fp->f_list.le_next;
if (fp->f_count == 0)
continue;
if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
*fpp++ = fp;
nunref++;
fp->f_count++;
}
}
for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
sorflush((struct socket *)(*fpp)->f_data);
for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
closef(*fpp, (struct proc *)NULL);
free((caddr_t)extra_ref, M_FILE);
unp_gcing = 0;
}
void
unp_dispose(m)
struct mbuf *m;
{
if (m)
unp_scan(m, unp_discard);
}
void
unp_scan(m0, op)
register struct mbuf *m0;
void (*op) __P((struct file *));
{
register struct mbuf *m;
register struct file **rp;
register struct cmsghdr *cm;
register int i;
int qfds;
while (m0) {
for (m = m0; m; m = m->m_next)
if (m->m_type == MT_CONTROL &&
m->m_len >= sizeof(*cm)) {
cm = mtod(m, struct cmsghdr *);
if (cm->cmsg_level != SOL_SOCKET ||
cm->cmsg_type != SCM_RIGHTS)
continue;
qfds = (cm->cmsg_len - sizeof *cm)
/ sizeof (struct file *);
rp = (struct file **)(cm + 1);
for (i = 0; i < qfds; i++)
(*op)(*rp++);
break; /* XXX, but saves time */
}
m0 = m0->m_act;
}
}
void
unp_mark(fp)
struct file *fp;
{
if (fp->f_flag & FMARK)
return;
unp_defer++;
fp->f_flag |= (FMARK|FDEFER);
}
void
unp_discard(fp)
struct file *fp;
{
fp->f_msgcount--;
unp_rights--;
(void) closef(fp, (struct proc *)NULL);
}

320
sys/kern/vfs_cache.c Normal file
View File

@ -0,0 +1,320 @@
/*
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Poul-Henning Kamp of the FreeBSD Project.
*
* 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: vfs_cache.c,v 1.11 1995/03/12 02:01:20 phk Exp $
*
* @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/namei.h>
#include <sys/errno.h>
#include <sys/malloc.h>
/*
* Name caching works as follows:
*
* Names found by directory scans are retained in a cache
* for future reference. It is managed LRU, so frequently
* used names will hang around. Cache is indexed by hash value
* obtained from (vp, name) where vp refers to the directory
* containing name.
*
* If it is a "negative" entry, (i.e. for a name that is known NOT to
* exist) the vnode pointer will be NULL.
*
* For simplicity (and economy of storage), names longer than
* a maximum length of NCHNAMLEN are not cached; they occur
* infrequently in any case, and are almost never of interest.
*
* Upon reaching the last segment of a path, if the reference
* is for DELETE, or NOCACHE is set (rewrite), and the
* name is located in the cache, it will be dropped.
*/
/*
* Structures associated with name cacheing.
*/
#define NCHHASH(dvp, cnp) \
(&nchashtbl[((dvp)->v_id + (cnp)->cn_hash) & nchash])
LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */
u_long nchash; /* size of hash table - 1 */
long numcache; /* number of cache entries allocated */
TAILQ_HEAD(, namecache) nclruhead; /* LRU chain */
struct nchstats nchstats; /* cache effectiveness statistics */
int doingcache = 1; /* 1 => enable the cache */
/*
* Delete an entry from its hash list and move it to the front
* of the LRU list for immediate reuse.
*/
#define PURGE(ncp) { \
LIST_REMOVE(ncp, nc_hash); \
ncp->nc_hash.le_prev = 0; \
TAILQ_REMOVE(&nclruhead, ncp, nc_lru); \
TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); \
}
/*
* Move an entry that has been used to the tail of the LRU list
* so that it will be preserved for future use.
*/
#define TOUCH(ncp) { \
if (ncp->nc_lru.tqe_next != 0) { \
TAILQ_REMOVE(&nclruhead, ncp, nc_lru); \
TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru); \
} \
}
/*
* Lookup an entry in the cache
*
* We don't do this if the segment name is long, simply so the cache
* can avoid holding long names (which would either waste space, or
* add greatly to the complexity).
*
* Lookup is called with dvp pointing to the directory to search,
* cnp pointing to the name of the entry being sought. If the lookup
* succeeds, the vnode is returned in *vpp, and a status of -1 is
* returned. If the lookup determines that 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(dvp, vpp, cnp)
struct vnode *dvp;
struct vnode **vpp;
struct componentname *cnp;
{
register struct namecache *ncp, *nnp;
register struct nchashhead *ncpp;
if (!doingcache) {
cnp->cn_flags &= ~MAKEENTRY;
return (0);
}
if (cnp->cn_namelen > NCHNAMLEN) {
nchstats.ncs_long++;
cnp->cn_flags &= ~MAKEENTRY;
return (0);
}
ncpp = NCHHASH(dvp, cnp);
for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) {
nnp = ncp->nc_hash.le_next;
/* If one of the vp's went stale, don't bother anymore. */
if ((ncp->nc_dvpid != ncp->nc_dvp->v_id) ||
(ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id)) {
nchstats.ncs_falsehits++;
PURGE(ncp);
continue;
}
/* Now that we know the vp's to be valid, is it ours ? */
if (ncp->nc_dvp == dvp &&
ncp->nc_nlen == cnp->cn_namelen &&
!bcmp(ncp->nc_name, cnp->cn_nameptr, (u_int)ncp->nc_nlen))
break;
}
/* We failed to find an entry */
if (ncp == 0) {
nchstats.ncs_miss++;
return (0);
}
/* We don't want to have an entry, so dump it */
if ((cnp->cn_flags & MAKEENTRY) == 0) {
nchstats.ncs_badhits++;
PURGE(ncp);
return (0);
}
/* We found a "positive" match, return the vnode */
if (ncp->nc_vp) {
nchstats.ncs_goodhits++;
TOUCH(ncp);
*vpp = ncp->nc_vp;
return (-1);
}
/* We found a negative match, and want to create it, so purge */
if (cnp->cn_nameiop == CREATE) {
nchstats.ncs_badhits++;
PURGE(ncp);
return (0);
}
/*
* We found a "negative" match, ENOENT notifies client of this match.
* The nc_vpid field records whether this is a whiteout.
*/
nchstats.ncs_neghits++;
TOUCH(ncp);
cnp->cn_flags |= ncp->nc_vpid;
return (ENOENT);
}
/*
* Add an entry to the cache.
*/
void
cache_enter(dvp, vp, cnp)
struct vnode *dvp;
struct vnode *vp;
struct componentname *cnp;
{
register struct namecache *ncp;
register struct nchashhead *ncpp;
if (!doingcache)
return;
#ifdef DIAGNOSTIC
if (cnp->cn_namelen > NCHNAMLEN)
panic("cache_enter: name too long");
#endif
/*
* We allocate a new entry if we are less than the maximum
* allowed and the one at the front of the LRU list is in use.
* Otherwise we use the one at the front of the LRU list.
*/
if (numcache < desiredvnodes &&
((ncp = nclruhead.tqh_first) == NULL ||
ncp->nc_hash.le_prev != 0)) {
/* Add one more entry */
ncp = (struct namecache *)
malloc((u_long)sizeof *ncp, M_CACHE, M_WAITOK);
bzero((char *)ncp, sizeof *ncp);
numcache++;
} else if (ncp = nclruhead.tqh_first) {
/* reuse an old entry */
TAILQ_REMOVE(&nclruhead, ncp, nc_lru);
if (ncp->nc_hash.le_prev != 0) {
LIST_REMOVE(ncp, nc_hash);
ncp->nc_hash.le_prev = 0;
}
} else {
/* give up */
return;
}
/*
* Fill in cache info, if vp is NULL this is a "negative" cache entry.
* For negative entries, we have to record whether it is a whiteout.
* the whiteout flag is stored in the nc_vpid field which is
* otherwise unused.
*/
ncp->nc_vp = vp;
if (vp)
ncp->nc_vpid = vp->v_id;
else
ncp->nc_vpid = cnp->cn_flags & ISWHITEOUT;
ncp->nc_dvp = dvp;
ncp->nc_dvpid = dvp->v_id;
ncp->nc_nlen = cnp->cn_namelen;
bcopy(cnp->cn_nameptr, ncp->nc_name, (unsigned)ncp->nc_nlen);
TAILQ_INSERT_TAIL(&nclruhead, ncp, nc_lru);
ncpp = NCHHASH(dvp, cnp);
LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
}
/*
* Name cache initialization, from vfs_init() when we are booting
*/
void
nchinit()
{
TAILQ_INIT(&nclruhead);
nchashtbl = hashinit(desiredvnodes, M_CACHE, &nchash);
}
/*
* Invalidate a all entries to particular vnode.
*
* We actually just increment the v_id, that will do it. The entries will
* be purged by lookup as they get found. If the v_id wraps around, we
* need to ditch the entire cache, to avoid confusion. No valid vnode will
* ever have (v_id == 0).
*/
void
cache_purge(vp)
struct vnode *vp;
{
struct namecache *ncp;
struct nchashhead *ncpp;
vp->v_id = ++nextvnodeid;
if (nextvnodeid != 0)
return;
for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
while (ncp = ncpp->lh_first)
PURGE(ncp);
}
vp->v_id = ++nextvnodeid;
}
/*
* Flush all entries referencing a particular filesystem.
*
* Since we need to check it anyway, we will flush all the invalid
* entriess at the same time.
*/
void
cache_purgevfs(mp)
struct mount *mp;
{
struct nchashhead *ncpp;
struct namecache *ncp, *nnp;
/* Scan hash tables for applicable entries */
for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
for (ncp = ncpp->lh_first; ncp != 0; ncp = nnp) {
nnp = ncp->nc_hash.le_next;
if (ncp->nc_dvpid != ncp->nc_dvp->v_id ||
(ncp->nc_vp && ncp->nc_vpid != ncp->nc_vp->v_id) ||
ncp->nc_dvp->v_mount == mp) {
PURGE(ncp);
}
}
}
}

756
sys/kern/vfs_cluster.c Normal file
View File

@ -0,0 +1,756 @@
/*-
* Copyright (c) 1993
* The Regents of the University of California. 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 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.
*
* @(#)vfs_cluster.c 8.10 (Berkeley) 3/28/95
*/
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/trace.h>
#include <sys/malloc.h>
#include <sys/resourcevar.h>
#include <libkern/libkern.h>
/*
* Local declarations
*/
struct buf *cluster_newbuf __P((struct vnode *, struct buf *, long, daddr_t,
daddr_t, long, int));
struct buf *cluster_rbuild __P((struct vnode *, u_quad_t, struct buf *,
daddr_t, daddr_t, long, int, long));
void cluster_wbuild __P((struct vnode *, struct buf *, long,
daddr_t, int, daddr_t));
struct cluster_save *cluster_collectbufs __P((struct vnode *, struct buf *));
#ifdef DIAGNOSTIC
/*
* Set to 1 if reads of block zero should cause readahead to be done.
* Set to 0 treats a read of block zero as a non-sequential read.
*
* Setting to one assumes that most reads of block zero of files are due to
* sequential passes over the files (e.g. cat, sum) where additional blocks
* will soon be needed. Setting to zero assumes that the majority are
* surgical strikes to get particular info (e.g. size, file) where readahead
* blocks will not be used and, in fact, push out other potentially useful
* blocks from the cache. The former seems intuitive, but some quick tests
* showed that the latter performed better from a system-wide point of view.
*/
int doclusterraz = 0;
#define ISSEQREAD(vp, blk) \
(((blk) != 0 || doclusterraz) && \
((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
#else
#define ISSEQREAD(vp, blk) \
((blk) != 0 && ((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
#endif
/*
* This replaces bread. If this is a bread at the beginning of a file and
* lastr is 0, we assume this is the first read and we'll read up to two
* blocks if they are sequential. After that, we'll do regular read ahead
* in clustered chunks.
*
* There are 4 or 5 cases depending on how you count:
* Desired block is in the cache:
* 1 Not sequential access (0 I/Os).
* 2 Access is sequential, do read-ahead (1 ASYNC).
* Desired block is not in cache:
* 3 Not sequential access (1 SYNC).
* 4 Sequential access, next block is contiguous (1 SYNC).
* 5 Sequential access, next block is not contiguous (1 SYNC, 1 ASYNC)
*
* There are potentially two buffers that require I/O.
* bp is the block requested.
* rbp is the read-ahead block.
* If either is NULL, then you don't have to do the I/O.
*/
cluster_read(vp, filesize, lblkno, size, cred, bpp)
struct vnode *vp;
u_quad_t filesize;
daddr_t lblkno;
long size;
struct ucred *cred;
struct buf **bpp;
{
struct buf *bp, *rbp;
daddr_t blkno, ioblkno;
long flags;
int error, num_ra, alreadyincore;
#ifdef DIAGNOSTIC
if (size == 0)
panic("cluster_read: size = 0");
#endif
error = 0;
flags = B_READ;
*bpp = bp = getblk(vp, lblkno, size, 0, 0);
if (bp->b_flags & B_CACHE) {
/*
* Desired block is in cache; do any readahead ASYNC.
* Case 1, 2.
*/
trace(TR_BREADHIT, pack(vp, size), lblkno);
flags |= B_ASYNC;
ioblkno = lblkno + (vp->v_ralen ? vp->v_ralen : 1);
alreadyincore = incore(vp, ioblkno) != NULL;
bp = NULL;
} else {
/* Block wasn't in cache, case 3, 4, 5. */
trace(TR_BREADMISS, pack(vp, size), lblkno);
bp->b_flags |= B_READ;
ioblkno = lblkno;
alreadyincore = 0;
curproc->p_stats->p_ru.ru_inblock++; /* XXX */
}
/*
* XXX
* Replace 1 with a window size based on some permutation of
* maxcontig and rot_delay. This will let you figure out how
* many blocks you should read-ahead (case 2, 4, 5).
*
* If the access isn't sequential, reset the window to 1.
* Note that a read to the same block is considered sequential.
* This catches the case where the file is being read sequentially,
* but at smaller than the filesystem block size.
*/
rbp = NULL;
if (!ISSEQREAD(vp, lblkno)) {
vp->v_ralen = 0;
vp->v_maxra = lblkno;
} else if ((ioblkno + 1) * size <= filesize && !alreadyincore &&
!(error = VOP_BMAP(vp, ioblkno, NULL, &blkno, &num_ra)) &&
blkno != -1) {
/*
* Reading sequentially, and the next block is not in the
* cache. We are going to try reading ahead.
*/
if (num_ra) {
/*
* If our desired readahead block had been read
* in a previous readahead but is no longer in
* core, then we may be reading ahead too far
* or are not using our readahead very rapidly.
* In this case we scale back the window.
*/
if (!alreadyincore && ioblkno <= vp->v_maxra)
vp->v_ralen = max(vp->v_ralen >> 1, 1);
/*
* There are more sequential blocks than our current
* window allows, scale up. Ideally we want to get
* in sync with the filesystem maxcontig value.
*/
else if (num_ra > vp->v_ralen && lblkno != vp->v_lastr)
vp->v_ralen = vp->v_ralen ?
min(num_ra, vp->v_ralen << 1) : 1;
if (num_ra > vp->v_ralen)
num_ra = vp->v_ralen;
}
if (num_ra) /* case 2, 4 */
rbp = cluster_rbuild(vp, filesize,
bp, ioblkno, blkno, size, num_ra, flags);
else if (ioblkno == lblkno) {
bp->b_blkno = blkno;
/* Case 5: check how many blocks to read ahead */
++ioblkno;
if ((ioblkno + 1) * size > filesize ||
incore(vp, ioblkno) || (error = VOP_BMAP(vp,
ioblkno, NULL, &blkno, &num_ra)) || blkno == -1)
goto skip_readahead;
/*
* Adjust readahead as above.
* Don't check alreadyincore, we know it is 0 from
* the previous conditional.
*/
if (num_ra) {
if (ioblkno <= vp->v_maxra)
vp->v_ralen = max(vp->v_ralen >> 1, 1);
else if (num_ra > vp->v_ralen &&
lblkno != vp->v_lastr)
vp->v_ralen = vp->v_ralen ?
min(num_ra,vp->v_ralen<<1) : 1;
if (num_ra > vp->v_ralen)
num_ra = vp->v_ralen;
}
flags |= B_ASYNC;
if (num_ra)
rbp = cluster_rbuild(vp, filesize,
NULL, ioblkno, blkno, size, num_ra, flags);
else {
rbp = getblk(vp, ioblkno, size, 0, 0);
rbp->b_flags |= flags;
rbp->b_blkno = blkno;
}
} else {
/* case 2; read ahead single block */
rbp = getblk(vp, ioblkno, size, 0, 0);
rbp->b_flags |= flags;
rbp->b_blkno = blkno;
}
if (rbp == bp) /* case 4 */
rbp = NULL;
else if (rbp) { /* case 2, 5 */
trace(TR_BREADMISSRA,
pack(vp, (num_ra + 1) * size), ioblkno);
curproc->p_stats->p_ru.ru_inblock++; /* XXX */
}
}
/* XXX Kirk, do we need to make sure the bp has creds? */
skip_readahead:
if (bp)
if (bp->b_flags & (B_DONE | B_DELWRI))
panic("cluster_read: DONE bp");
else
error = VOP_STRATEGY(bp);
if (rbp)
if (error || rbp->b_flags & (B_DONE | B_DELWRI)) {
rbp->b_flags &= ~(B_ASYNC | B_READ);
brelse(rbp);
} else
(void) VOP_STRATEGY(rbp);
/*
* Recalculate our maximum readahead
*/
if (rbp == NULL)
rbp = bp;
if (rbp)
vp->v_maxra = rbp->b_lblkno + (rbp->b_bufsize / size) - 1;
if (bp)
return(biowait(bp));
return(error);
}
/*
* If blocks are contiguous on disk, use this to provide clustered
* read ahead. We will read as many blocks as possible sequentially
* and then parcel them up into logical blocks in the buffer hash table.
*/
struct buf *
cluster_rbuild(vp, filesize, bp, lbn, blkno, size, run, flags)
struct vnode *vp;
u_quad_t filesize;
struct buf *bp;
daddr_t lbn;
daddr_t blkno;
long size;
int run;
long flags;
{
struct cluster_save *b_save;
struct buf *tbp;
daddr_t bn;
int i, inc;
#ifdef DIAGNOSTIC
if (size != vp->v_mount->mnt_stat.f_iosize)
panic("cluster_rbuild: size %d != filesize %d\n",
size, vp->v_mount->mnt_stat.f_iosize);
#endif
if (size * (lbn + run + 1) > filesize)
--run;
if (run == 0) {
if (!bp) {
bp = getblk(vp, lbn, size, 0, 0);
bp->b_blkno = blkno;
bp->b_flags |= flags;
}
return(bp);
}
bp = cluster_newbuf(vp, bp, flags, blkno, lbn, size, run + 1);
if (bp->b_flags & (B_DONE | B_DELWRI))
return (bp);
b_save = malloc(sizeof(struct buf *) * run + sizeof(struct cluster_save),
M_SEGMENT, M_WAITOK);
b_save->bs_bufsize = b_save->bs_bcount = size;
b_save->bs_nchildren = 0;
b_save->bs_children = (struct buf **)(b_save + 1);
b_save->bs_saveaddr = bp->b_saveaddr;
bp->b_saveaddr = (caddr_t) b_save;
inc = btodb(size);
for (bn = blkno + inc, i = 1; i <= run; ++i, bn += inc) {
/*
* A component of the cluster is already in core,
* terminate the cluster early.
*/
if (incore(vp, lbn + i))
break;
tbp = getblk(vp, lbn + i, 0, 0, 0);
/*
* getblk may return some memory in the buffer if there were
* no empty buffers to shed it to. If there is currently
* memory in the buffer, we move it down size bytes to make
* room for the valid pages that cluster_callback will insert.
* We do this now so we don't have to do it at interrupt time
* in the callback routine.
*/
if (tbp->b_bufsize != 0) {
caddr_t bdata = (char *)tbp->b_data;
/*
* No room in the buffer to add another page,
* terminate the cluster early.
*/
if (tbp->b_bufsize + size > MAXBSIZE) {
#ifdef DIAGNOSTIC
if (tbp->b_bufsize != MAXBSIZE)
panic("cluster_rbuild: too much memory");
#endif
brelse(tbp);
break;
}
if (tbp->b_bufsize > size) {
/*
* XXX if the source and destination regions
* overlap we have to copy backward to avoid
* clobbering any valid pages (i.e. pagemove
* implementations typically can't handle
* overlap).
*/
bdata += tbp->b_bufsize;
while (bdata > (char *)tbp->b_data) {
bdata -= CLBYTES;
pagemove(bdata, bdata + size, CLBYTES);
}
} else
pagemove(bdata, bdata + size, tbp->b_bufsize);
}
tbp->b_blkno = bn;
tbp->b_flags |= flags | B_READ | B_ASYNC;
++b_save->bs_nchildren;
b_save->bs_children[i - 1] = tbp;
}
/*
* The cluster may have been terminated early, adjust the cluster
* buffer size accordingly. If no cluster could be formed,
* deallocate the cluster save info.
*/
if (i <= run) {
if (i == 1) {
bp->b_saveaddr = b_save->bs_saveaddr;
bp->b_flags &= ~B_CALL;
bp->b_iodone = NULL;
free(b_save, M_SEGMENT);
}
allocbuf(bp, size * i);
}
return(bp);
}
/*
* Either get a new buffer or grow the existing one.
*/
struct buf *
cluster_newbuf(vp, bp, flags, blkno, lblkno, size, run)
struct vnode *vp;
struct buf *bp;
long flags;
daddr_t blkno;
daddr_t lblkno;
long size;
int run;
{
if (!bp) {
bp = getblk(vp, lblkno, size, 0, 0);
if (bp->b_flags & (B_DONE | B_DELWRI)) {
bp->b_blkno = blkno;
return(bp);
}
}
allocbuf(bp, run * size);
bp->b_blkno = blkno;
bp->b_iodone = cluster_callback;
bp->b_flags |= flags | B_CALL;
return(bp);
}
/*
* Cleanup after a clustered read or write.
* This is complicated by the fact that any of the buffers might have
* extra memory (if there were no empty buffer headers at allocbuf time)
* that we will need to shift around.
*/
void
cluster_callback(bp)
struct buf *bp;
{
struct cluster_save *b_save;
struct buf **bpp, *tbp;
long bsize;
caddr_t cp;
int error = 0;
/*
* Must propogate errors to all the components.
*/
if (bp->b_flags & B_ERROR)
error = bp->b_error;
b_save = (struct cluster_save *)(bp->b_saveaddr);
bp->b_saveaddr = b_save->bs_saveaddr;
bsize = b_save->bs_bufsize;
cp = (char *)bp->b_data + bsize;
/*
* Move memory from the large cluster buffer into the component
* buffers and mark IO as done on these.
*/
for (bpp = b_save->bs_children; b_save->bs_nchildren--; ++bpp) {
tbp = *bpp;
pagemove(cp, tbp->b_data, bsize);
tbp->b_bufsize += bsize;
tbp->b_bcount = bsize;
if (error) {
tbp->b_flags |= B_ERROR;
tbp->b_error = error;
}
biodone(tbp);
bp->b_bufsize -= bsize;
cp += bsize;
}
/*
* If there was excess memory in the cluster buffer,
* slide it up adjacent to the remaining valid data.
*/
if (bp->b_bufsize != bsize) {
if (bp->b_bufsize < bsize)
panic("cluster_callback: too little memory");
pagemove(cp, (char *)bp->b_data + bsize, bp->b_bufsize - bsize);
}
bp->b_bcount = bsize;
bp->b_iodone = NULL;
free(b_save, M_SEGMENT);
if (bp->b_flags & B_ASYNC)
brelse(bp);
else {
bp->b_flags &= ~B_WANTED;
wakeup((caddr_t)bp);
}
}
/*
* Do clustered write for FFS.
*
* Three cases:
* 1. Write is not sequential (write asynchronously)
* Write is sequential:
* 2. beginning of cluster - begin cluster
* 3. middle of a cluster - add to cluster
* 4. end of a cluster - asynchronously write cluster
*/
void
cluster_write(bp, filesize)
struct buf *bp;
u_quad_t filesize;
{
struct vnode *vp;
daddr_t lbn;
int maxclen, cursize;
vp = bp->b_vp;
lbn = bp->b_lblkno;
/* Initialize vnode to beginning of file. */
if (lbn == 0)
vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
if (vp->v_clen == 0 || lbn != vp->v_lastw + 1 ||
(bp->b_blkno != vp->v_lasta + btodb(bp->b_bcount))) {
maxclen = MAXBSIZE / vp->v_mount->mnt_stat.f_iosize - 1;
if (vp->v_clen != 0) {
/*
* Next block is not sequential.
*
* If we are not writing at end of file, the process
* seeked to another point in the file since its
* last write, or we have reached our maximum
* cluster size, then push the previous cluster.
* Otherwise try reallocating to make it sequential.
*/
cursize = vp->v_lastw - vp->v_cstart + 1;
if ((lbn + 1) * bp->b_bcount != filesize ||
lbn != vp->v_lastw + 1 || vp->v_clen <= cursize) {
cluster_wbuild(vp, NULL, bp->b_bcount,
vp->v_cstart, cursize, lbn);
} else {
struct buf **bpp, **endbp;
struct cluster_save *buflist;
buflist = cluster_collectbufs(vp, bp);
endbp = &buflist->bs_children
[buflist->bs_nchildren - 1];
if (VOP_REALLOCBLKS(vp, buflist)) {
/*
* Failed, push the previous cluster.
*/
for (bpp = buflist->bs_children;
bpp < endbp; bpp++)
brelse(*bpp);
free(buflist, M_SEGMENT);
cluster_wbuild(vp, NULL, bp->b_bcount,
vp->v_cstart, cursize, lbn);
} else {
/*
* Succeeded, keep building cluster.
*/
for (bpp = buflist->bs_children;
bpp <= endbp; bpp++)
bdwrite(*bpp);
free(buflist, M_SEGMENT);
vp->v_lastw = lbn;
vp->v_lasta = bp->b_blkno;
return;
}
}
}
/*
* Consider beginning a cluster.
* If at end of file, make cluster as large as possible,
* otherwise find size of existing cluster.
*/
if ((lbn + 1) * bp->b_bcount != filesize &&
(VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen) ||
bp->b_blkno == -1)) {
bawrite(bp);
vp->v_clen = 0;
vp->v_lasta = bp->b_blkno;
vp->v_cstart = lbn + 1;
vp->v_lastw = lbn;
return;
}
vp->v_clen = maxclen;
if (maxclen == 0) { /* I/O not contiguous */
vp->v_cstart = lbn + 1;
bawrite(bp);
} else { /* Wait for rest of cluster */
vp->v_cstart = lbn;
bdwrite(bp);
}
} else if (lbn == vp->v_cstart + vp->v_clen) {
/*
* At end of cluster, write it out.
*/
cluster_wbuild(vp, bp, bp->b_bcount, vp->v_cstart,
vp->v_clen + 1, lbn);
vp->v_clen = 0;
vp->v_cstart = lbn + 1;
} else
/*
* In the middle of a cluster, so just delay the
* I/O for now.
*/
bdwrite(bp);
vp->v_lastw = lbn;
vp->v_lasta = bp->b_blkno;
}
/*
* This is an awful lot like cluster_rbuild...wish they could be combined.
* The last lbn argument is the current block on which I/O is being
* performed. Check to see that it doesn't fall in the middle of
* the current block (if last_bp == NULL).
*/
void
cluster_wbuild(vp, last_bp, size, start_lbn, len, lbn)
struct vnode *vp;
struct buf *last_bp;
long size;
daddr_t start_lbn;
int len;
daddr_t lbn;
{
struct cluster_save *b_save;
struct buf *bp, *tbp;
caddr_t cp;
int i, s;
#ifdef DIAGNOSTIC
if (size != vp->v_mount->mnt_stat.f_iosize)
panic("cluster_wbuild: size %d != filesize %d\n",
size, vp->v_mount->mnt_stat.f_iosize);
#endif
redo:
while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
++start_lbn;
--len;
}
/* Get more memory for current buffer */
if (len <= 1) {
if (last_bp) {
bawrite(last_bp);
} else if (len) {
bp = getblk(vp, start_lbn, size, 0, 0);
bawrite(bp);
}
return;
}
bp = getblk(vp, start_lbn, size, 0, 0);
if (!(bp->b_flags & B_DELWRI)) {
++start_lbn;
--len;
brelse(bp);
goto redo;
}
/*
* Extra memory in the buffer, punt on this buffer.
* XXX we could handle this in most cases, but we would have to
* push the extra memory down to after our max possible cluster
* size and then potentially pull it back up if the cluster was
* terminated prematurely--too much hassle.
*/
if (bp->b_bcount != bp->b_bufsize) {
++start_lbn;
--len;
bawrite(bp);
goto redo;
}
--len;
b_save = malloc(sizeof(struct buf *) * len + sizeof(struct cluster_save),
M_SEGMENT, M_WAITOK);
b_save->bs_bcount = bp->b_bcount;
b_save->bs_bufsize = bp->b_bufsize;
b_save->bs_nchildren = 0;
b_save->bs_children = (struct buf **)(b_save + 1);
b_save->bs_saveaddr = bp->b_saveaddr;
bp->b_saveaddr = (caddr_t) b_save;
bp->b_flags |= B_CALL;
bp->b_iodone = cluster_callback;
cp = (char *)bp->b_data + size;
for (++start_lbn, i = 0; i < len; ++i, ++start_lbn) {
/*
* Block is not in core or the non-sequential block
* ending our cluster was part of the cluster (in which
* case we don't want to write it twice).
*/
if (!incore(vp, start_lbn) ||
last_bp == NULL && start_lbn == lbn)
break;
/*
* Get the desired block buffer (unless it is the final
* sequential block whose buffer was passed in explictly
* as last_bp).
*/
if (last_bp == NULL || start_lbn != lbn) {
tbp = getblk(vp, start_lbn, size, 0, 0);
if (!(tbp->b_flags & B_DELWRI)) {
brelse(tbp);
break;
}
} else
tbp = last_bp;
++b_save->bs_nchildren;
/* Move memory from children to parent */
if (tbp->b_blkno != (bp->b_blkno + btodb(bp->b_bufsize))) {
printf("Clustered Block: %d addr %x bufsize: %d\n",
bp->b_lblkno, bp->b_blkno, bp->b_bufsize);
printf("Child Block: %d addr: %x\n", tbp->b_lblkno,
tbp->b_blkno);
panic("Clustered write to wrong blocks");
}
pagemove(tbp->b_data, cp, size);
bp->b_bcount += size;
bp->b_bufsize += size;
tbp->b_bufsize -= size;
tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
tbp->b_flags |= (B_ASYNC | B_AGE);
s = splbio();
reassignbuf(tbp, tbp->b_vp); /* put on clean list */
++tbp->b_vp->v_numoutput;
splx(s);
b_save->bs_children[i] = tbp;
cp += size;
}
if (i == 0) {
/* None to cluster */
bp->b_saveaddr = b_save->bs_saveaddr;
bp->b_flags &= ~B_CALL;
bp->b_iodone = NULL;
free(b_save, M_SEGMENT);
}
bawrite(bp);
if (i < len) {
len -= i + 1;
start_lbn += 1;
goto redo;
}
}
/*
* Collect together all the buffers in a cluster.
* Plus add one additional buffer.
*/
struct cluster_save *
cluster_collectbufs(vp, last_bp)
struct vnode *vp;
struct buf *last_bp;
{
struct cluster_save *buflist;
daddr_t lbn;
int i, len;
len = vp->v_lastw - vp->v_cstart + 1;
buflist = malloc(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
M_SEGMENT, M_WAITOK);
buflist->bs_nchildren = 0;
buflist->bs_children = (struct buf **)(buflist + 1);
for (lbn = vp->v_cstart, i = 0; i < len; lbn++, i++)
(void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
&buflist->bs_children[i]);
buflist->bs_children[i] = last_bp;
buflist->bs_nchildren = i + 1;
return (buflist);
}

248
sys/kern/vfs_conf.c Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. 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 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.
*
* @(#)vfs_conf.c 8.11 (Berkeley) 5/10/95
*/
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/vnode.h>
/*
* These define the root filesystem, device, and root filesystem type.
*/
struct mount *rootfs;
struct vnode *rootvnode;
int (*mountroot)() = NULL;
/*
* Set up the initial array of known filesystem types.
*/
extern struct vfsops ufs_vfsops;
extern int ffs_mountroot();
extern struct vfsops lfs_vfsops;
extern int lfs_mountroot();
extern struct vfsops mfs_vfsops;
extern int mfs_mountroot();
extern struct vfsops cd9660_vfsops;
extern int cd9660_mountroot();
extern struct vfsops msdos_vfsops;
extern struct vfsops adosfs_vfsops;
extern struct vfsops nfs_vfsops;
extern int nfs_mountroot();
extern struct vfsops afs_vfsops;
extern struct vfsops procfs_vfsops;
extern struct vfsops null_vfsops;
extern struct vfsops union_vfsops;
extern struct vfsops umap_vfsops;
extern struct vfsops portal_vfsops;
extern struct vfsops fdesc_vfsops;
extern struct vfsops kernfs_vfsops;
/*
* Set up the filesystem operations for vnodes.
*/
static struct vfsconf vfsconflist[] = {
/* Fast Filesystem */
#ifdef FFS
{ &ufs_vfsops, "ufs", 1, 0, MNT_LOCAL, ffs_mountroot, NULL },
#endif
/* Log-based Filesystem */
#ifdef LFS
{ &lfs_vfsops, "lfs", 5, 0, MNT_LOCAL, lfs_mountroot, NULL },
#endif
/* Memory-based Filesystem */
#ifdef MFS
{ &mfs_vfsops, "mfs", 3, 0, MNT_LOCAL, mfs_mountroot, NULL },
#endif
/* ISO9660 (aka CDROM) Filesystem */
#ifdef CD9660
{ &cd9660_vfsops, "cd9660", 14, 0, MNT_LOCAL, cd9660_mountroot, NULL },
#endif
/* MSDOS Filesystem */
#ifdef MSDOS
{ &msdos_vfsops, "msdos", 4, 0, MNT_LOCAL, NULL, NULL },
#endif
/* AmigaDOS Filesystem */
#ifdef ADOSFS
{ &adosfs_vfsops, "adosfs", 16, 0, MNT_LOCAL, NULL, NULL },
#endif
/* Sun-compatible Network Filesystem */
#ifdef NFS
{ &nfs_vfsops, "nfs", 2, 0, 0, nfs_mountroot, NULL },
#endif
/* Andrew Filesystem */
#ifdef AFS
{ &afs_vfsops, "andrewfs", 13, 0, 0, afs_mountroot, NULL },
#endif
/* /proc Filesystem */
#ifdef PROCFS
{ &procfs_vfsops, "procfs", 12, 0, 0, NULL, NULL },
#endif
/* Loopback (Minimal) Filesystem Layer */
#ifdef NULLFS
{ &null_vfsops, "loopback", 9, 0, 0, NULL, NULL },
#endif
/* Union (translucent) Filesystem */
#ifdef UNION
{ &union_vfsops, "union", 15, 0, 0, NULL, NULL },
#endif
/* User/Group Identifer Remapping Filesystem */
#ifdef UMAPFS
{ &umap_vfsops, "umap", 10, 0, 0, NULL, NULL },
#endif
/* Portal Filesystem */
#ifdef PORTAL
{ &portal_vfsops, "portal", 8, 0, 0, NULL, NULL },
#endif
/* File Descriptor Filesystem */
#ifdef FDESC
{ &fdesc_vfsops, "fdesc", 7, 0, 0, NULL, NULL },
#endif
/* Kernel Information Filesystem */
#ifdef KERNFS
{ &kernfs_vfsops, "kernfs", 11, 0, 0, NULL, NULL },
#endif
};
/*
* Initially the size of the list, vfs_init will set maxvfsconf
* to the highest defined type number.
*/
int maxvfsconf = sizeof(vfsconflist) / sizeof (struct vfsconf);
struct vfsconf *vfsconf = vfsconflist;
/*
*
* vfs_opv_descs enumerates the list of vnode classes, each with it's own
* vnode operation vector. It is consulted at system boot to build operation
* vectors. It is NULL terminated.
*
*/
extern struct vnodeopv_desc ffs_vnodeop_opv_desc;
extern struct vnodeopv_desc ffs_specop_opv_desc;
extern struct vnodeopv_desc ffs_fifoop_opv_desc;
extern struct vnodeopv_desc lfs_vnodeop_opv_desc;
extern struct vnodeopv_desc lfs_specop_opv_desc;
extern struct vnodeopv_desc lfs_fifoop_opv_desc;
extern struct vnodeopv_desc mfs_vnodeop_opv_desc;
extern struct vnodeopv_desc dead_vnodeop_opv_desc;
extern struct vnodeopv_desc fifo_vnodeop_opv_desc;
extern struct vnodeopv_desc spec_vnodeop_opv_desc;
extern struct vnodeopv_desc nfsv2_vnodeop_opv_desc;
extern struct vnodeopv_desc spec_nfsv2nodeop_opv_desc;
extern struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc;
extern struct vnodeopv_desc fdesc_vnodeop_opv_desc;
extern struct vnodeopv_desc portal_vnodeop_opv_desc;
extern struct vnodeopv_desc null_vnodeop_opv_desc;
extern struct vnodeopv_desc umap_vnodeop_opv_desc;
extern struct vnodeopv_desc kernfs_vnodeop_opv_desc;
extern struct vnodeopv_desc procfs_vnodeop_opv_desc;
extern struct vnodeopv_desc cd9660_vnodeop_opv_desc;
extern struct vnodeopv_desc cd9660_specop_opv_desc;
extern struct vnodeopv_desc cd9660_fifoop_opv_desc;
extern struct vnodeopv_desc union_vnodeop_opv_desc;
struct vnodeopv_desc *vfs_opv_descs[] = {
&ffs_vnodeop_opv_desc,
&ffs_specop_opv_desc,
#ifdef FIFO
&ffs_fifoop_opv_desc,
#endif
&dead_vnodeop_opv_desc,
#ifdef FIFO
&fifo_vnodeop_opv_desc,
#endif
&spec_vnodeop_opv_desc,
#ifdef LFS
&lfs_vnodeop_opv_desc,
&lfs_specop_opv_desc,
#ifdef FIFO
&lfs_fifoop_opv_desc,
#endif
#endif
#ifdef MFS
&mfs_vnodeop_opv_desc,
#endif
#ifdef NFS
&nfsv2_vnodeop_opv_desc,
&spec_nfsv2nodeop_opv_desc,
#ifdef FIFO
&fifo_nfsv2nodeop_opv_desc,
#endif
#endif
#ifdef FDESC
&fdesc_vnodeop_opv_desc,
#endif
#ifdef PORTAL
&portal_vnodeop_opv_desc,
#endif
#ifdef NULLFS
&null_vnodeop_opv_desc,
#endif
#ifdef UMAPFS
&umap_vnodeop_opv_desc,
#endif
#ifdef KERNFS
&kernfs_vnodeop_opv_desc,
#endif
#ifdef PROCFS
&procfs_vnodeop_opv_desc,
#endif
#ifdef CD9660
&cd9660_vnodeop_opv_desc,
&cd9660_specop_opv_desc,
#ifdef FIFO
&cd9660_fifoop_opv_desc,
#endif
#endif
#ifdef UNION
&union_vnodeop_opv_desc,
#endif
NULL
};

251
sys/kern/vfs_init.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed
* to Berkeley by John Heidemann of the UCLA Ficus project.
*
* Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
*
* 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.
*
* @(#)vfs_init.c 8.5 (Berkeley) 5/11/95
*/
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/stat.h>
#include <sys/namei.h>
#include <sys/ucred.h>
#include <sys/buf.h>
#include <sys/errno.h>
#include <sys/malloc.h>
/*
* Sigh, such primitive tools are these...
*/
#if 0
#define DODEBUG(A) A
#else
#define DODEBUG(A)
#endif
extern struct vnodeopv_desc *vfs_opv_descs[];
/* a list of lists of vnodeops defns */
extern struct vnodeop_desc *vfs_op_descs[];
/* and the operations they perform */
/*
* This code doesn't work if the defn is **vnodop_defns with cc.
* The problem is because of the compiler sometimes putting in an
* extra level of indirection for arrays. It's an interesting
* "feature" of C.
*/
int vfs_opv_numops;
typedef (*PFI)(); /* the standard Pointer to a Function returning an Int */
/*
* A miscellaneous routine.
* A generic "default" routine that just returns an error.
*/
int
vn_default_error()
{
return (EOPNOTSUPP);
}
/*
* vfs_init.c
*
* Allocate and fill in operations vectors.
*
* An undocumented feature of this approach to defining operations is that
* there can be multiple entries in vfs_opv_descs for the same operations
* vector. This allows third parties to extend the set of operations
* supported by another layer in a binary compatibile way. For example,
* assume that NFS needed to be modified to support Ficus. NFS has an entry
* (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
* default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
* listing those new operations Ficus adds to NFS, all without modifying the
* NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
* that is a(whole)nother story.) This is a feature.
*/
void
vfs_opv_init()
{
int i, j, k;
int (***opv_desc_vector_p)();
int (**opv_desc_vector)();
struct vnodeopv_entry_desc *opve_descp;
/*
* Allocate the dynamic vectors and fill them in.
*/
for (i=0; vfs_opv_descs[i]; i++) {
opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
/*
* Allocate and init the vector, if it needs it.
* Also handle backwards compatibility.
*/
if (*opv_desc_vector_p == NULL) {
/* XXX - shouldn't be M_VNODE */
MALLOC(*opv_desc_vector_p, PFI*,
vfs_opv_numops*sizeof(PFI), M_VNODE, M_WAITOK);
bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
DODEBUG(printf("vector at %x allocated\n",
opv_desc_vector_p));
}
opv_desc_vector = *opv_desc_vector_p;
for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
/*
* Sanity check: is this operation listed
* in the list of operations? We check this
* by seeing if its offest is zero. Since
* the default routine should always be listed
* first, it should be the only one with a zero
* offset. Any other operation with a zero
* offset is probably not listed in
* vfs_op_descs, and so is probably an error.
*
* A panic here means the layer programmer
* has committed the all-too common bug
* of adding a new operation to the layer's
* list of vnode operations but
* not adding the operation to the system-wide
* list of supported operations.
*/
if (opve_descp->opve_op->vdesc_offset == 0 &&
opve_descp->opve_op->vdesc_offset !=
VOFFSET(vop_default)) {
printf("operation %s not listed in %s.\n",
opve_descp->opve_op->vdesc_name,
"vfs_op_descs");
panic ("vfs_opv_init: bad operation");
}
/*
* Fill in this entry.
*/
opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
opve_descp->opve_impl;
}
}
/*
* Finally, go back and replace unfilled routines
* with their default. (Sigh, an O(n^3) algorithm. I
* could make it better, but that'd be work, and n is small.)
*/
for (i = 0; vfs_opv_descs[i]; i++) {
opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
/*
* Force every operations vector to have a default routine.
*/
if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
panic("vfs_opv_init: operation vector without default routine.");
}
for (k = 0; k<vfs_opv_numops; k++)
if (opv_desc_vector[k] == NULL)
opv_desc_vector[k] =
opv_desc_vector[VOFFSET(vop_default)];
}
}
/*
* Initialize known vnode operations vectors.
*/
void
vfs_op_init()
{
int i;
DODEBUG(printf("Vnode_interface_init.\n"));
/*
* Set all vnode vectors to a well known value.
*/
for (i = 0; vfs_opv_descs[i]; i++)
*(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
/*
* Figure out how many ops there are by counting the table,
* and assign each its offset.
*/
for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
vfs_opv_numops++;
}
DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
}
/*
* Routines having to do with the management of the vnode table.
*/
extern struct vnodeops dead_vnodeops;
extern struct vnodeops spec_vnodeops;
struct vattr va_null;
/*
* Initialize the vnode structures and initialize each file system type.
*/
vfsinit()
{
struct vfsconf *vfsp;
int i, maxtypenum;
/*
* Initialize the vnode table
*/
vntblinit();
/*
* Initialize the vnode name cache
*/
nchinit();
/*
* Build vnode operation vectors.
*/
vfs_op_init();
vfs_opv_init(); /* finish the job */
/*
* Initialize each file system type.
*/
vattr_null(&va_null);
maxtypenum = 0;
for (vfsp = vfsconf, i = 1; i <= maxvfsconf; i++, vfsp++) {
if (i < maxvfsconf)
vfsp->vfc_next = vfsp + 1;
if (maxtypenum <= vfsp->vfc_typenum)
maxtypenum = vfsp->vfc_typenum + 1;
(*vfsp->vfc_vfsops->vfs_init)(vfsp);
}
/* next vfc_typenum to be used */
maxvfsconf = maxtypenum;
}

645
sys/kern/vfs_lookup.c Normal file
View File

@ -0,0 +1,645 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)vfs_lookup.c 8.10 (Berkeley) 5/27/95
*/
#include <sys/param.h>
#include <sys/syslimits.h>
#include <sys/time.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/errno.h>
#include <sys/malloc.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
/*
* Convert a pathname into a pointer to a locked inode.
*
* The FOLLOW flag is set when symbolic links are to be followed
* when they occur at the end of the name translation process.
* Symbolic links are always followed for all other pathname
* components other than the last.
*
* The segflg defines whether the name is to be copied from user
* space or kernel space.
*
* Overall outline of namei:
*
* copy in name
* get starting directory
* while (!done && !error) {
* call lookup to search path.
* if symbolic link, massage name in buffer and continue
* }
*/
int
namei(ndp)
register struct nameidata *ndp;
{
register struct filedesc *fdp; /* pointer to file descriptor state */
register char *cp; /* pointer into pathname argument */
register struct vnode *dp; /* the directory we are searching */
struct iovec aiov; /* uio for reading symbolic links */
struct uio auio;
int error, linklen;
struct componentname *cnp = &ndp->ni_cnd;
struct proc *p = cnp->cn_proc;
ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
#ifdef DIAGNOSTIC
if (!cnp->cn_cred || !cnp->cn_proc)
panic ("namei: bad cred/proc");
if (cnp->cn_nameiop & (~OPMASK))
panic ("namei: nameiop contaminated with flags");
if (cnp->cn_flags & OPMASK)
panic ("namei: flags contaminated with nameiops");
#endif
fdp = cnp->cn_proc->p_fd;
/*
* Get a buffer for the name to be translated, and copy the
* name into the buffer.
*/
if ((cnp->cn_flags & HASBUF) == 0)
MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
if (ndp->ni_segflg == UIO_SYSSPACE)
error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
MAXPATHLEN, &ndp->ni_pathlen);
else
error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
MAXPATHLEN, &ndp->ni_pathlen);
if (error) {
free(cnp->cn_pnbuf, M_NAMEI);
ndp->ni_vp = NULL;
return (error);
}
ndp->ni_loopcnt = 0;
#ifdef KTRACE
if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
#endif
/*
* Get starting point for the translation.
*/
if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
ndp->ni_rootdir = rootvnode;
dp = fdp->fd_cdir;
VREF(dp);
for (;;) {
/*
* Check if root directory should replace current directory.
* Done at start of translation and after symbolic link.
*/
cnp->cn_nameptr = cnp->cn_pnbuf;
if (*(cnp->cn_nameptr) == '/') {
vrele(dp);
while (*(cnp->cn_nameptr) == '/') {
cnp->cn_nameptr++;
ndp->ni_pathlen--;
}
dp = ndp->ni_rootdir;
VREF(dp);
}
ndp->ni_startdir = dp;
if (error = lookup(ndp)) {
FREE(cnp->cn_pnbuf, M_NAMEI);
return (error);
}
/*
* Check for symbolic link
*/
if ((cnp->cn_flags & ISSYMLINK) == 0) {
if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
FREE(cnp->cn_pnbuf, M_NAMEI);
else
cnp->cn_flags |= HASBUF;
return (0);
}
if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
VOP_UNLOCK(ndp->ni_dvp, 0, p);
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
error = ELOOP;
break;
}
if (ndp->ni_pathlen > 1)
MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
else
cp = cnp->cn_pnbuf;
aiov.iov_base = cp;
aiov.iov_len = MAXPATHLEN;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = 0;
auio.uio_rw = UIO_READ;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_procp = (struct proc *)0;
auio.uio_resid = MAXPATHLEN;
if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) {
if (ndp->ni_pathlen > 1)
free(cp, M_NAMEI);
break;
}
linklen = MAXPATHLEN - auio.uio_resid;
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
if (ndp->ni_pathlen > 1)
free(cp, M_NAMEI);
error = ENAMETOOLONG;
break;
}
if (ndp->ni_pathlen > 1) {
bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
FREE(cnp->cn_pnbuf, M_NAMEI);
cnp->cn_pnbuf = cp;
} else
cnp->cn_pnbuf[linklen] = '\0';
ndp->ni_pathlen += linklen;
vput(ndp->ni_vp);
dp = ndp->ni_dvp;
}
FREE(cnp->cn_pnbuf, M_NAMEI);
vrele(ndp->ni_dvp);
vput(ndp->ni_vp);
ndp->ni_vp = NULL;
return (error);
}
/*
* Search a pathname.
* This is a very central and rather complicated routine.
*
* The pathname is pointed to by ni_ptr and is of length ni_pathlen.
* The starting directory is taken from ni_startdir. The pathname is
* descended until done, or a symbolic link is encountered. The variable
* ni_more is clear if the path is completed; it is set to one if a
* symbolic link needing interpretation is encountered.
*
* The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
* whether the name is to be looked up, created, renamed, or deleted.
* When CREATE, RENAME, or DELETE is specified, information usable in
* creating, renaming, or deleting a directory entry may be calculated.
* If flag has LOCKPARENT or'ed into it, the parent directory is returned
* locked. If flag has WANTPARENT or'ed into it, the parent directory is
* returned unlocked. Otherwise the parent directory is not returned. If
* the target of the pathname exists and LOCKLEAF is or'ed into the flag
* the target is returned locked, otherwise it is returned unlocked.
* When creating or renaming and LOCKPARENT is specified, the target may not
* be ".". When deleting and LOCKPARENT is specified, the target may be ".".
*
* Overall outline of lookup:
*
* dirloop:
* identify next component of name at ndp->ni_ptr
* handle degenerate case where name is null string
* if .. and crossing mount points and on mounted filesys, find parent
* call VOP_LOOKUP routine for next component name
* directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
* component vnode returned in ni_vp (if it exists), locked.
* if result vnode is mounted on and crossing mount points,
* find mounted on vnode
* if more components of name, do next level at dirloop
* return the answer in ni_vp, locked if LOCKLEAF set
* if LOCKPARENT set, return locked parent in ni_dvp
* if WANTPARENT set, return unlocked parent in ni_dvp
*/
int
lookup(ndp)
register struct nameidata *ndp;
{
register char *cp; /* pointer into pathname argument */
register struct vnode *dp = 0; /* the directory we are searching */
struct vnode *tdp; /* saved dp */
struct mount *mp; /* mount table entry */
int docache; /* == 0 do not cache last component */
int wantparent; /* 1 => wantparent or lockparent flag */
int rdonly; /* lookup read-only flag bit */
int error = 0;
struct componentname *cnp = &ndp->ni_cnd;
struct proc *p = cnp->cn_proc;
/*
* Setup: break out flag bits into variables.
*/
wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
if (cnp->cn_nameiop == DELETE ||
(wantparent && cnp->cn_nameiop != CREATE))
docache = 0;
rdonly = cnp->cn_flags & RDONLY;
ndp->ni_dvp = NULL;
cnp->cn_flags &= ~ISSYMLINK;
dp = ndp->ni_startdir;
ndp->ni_startdir = NULLVP;
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
dirloop:
/*
* Search a new directory.
*
* The cn_hash value is for use by vfs_cache.
* The last component of the filename is left accessible via
* cnp->cn_nameptr for callers that need the name. Callers needing
* the name set the SAVENAME flag. When done, they assume
* responsibility for freeing the pathname buffer.
*/
cnp->cn_consume = 0;
cnp->cn_hash = 0;
for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
cnp->cn_hash += (unsigned char)*cp;
cnp->cn_namelen = cp - cnp->cn_nameptr;
if (cnp->cn_namelen > NAME_MAX) {
error = ENAMETOOLONG;
goto bad;
}
#ifdef NAMEI_DIAGNOSTIC
{ char c = *cp;
*cp = '\0';
printf("{%s}: ", cnp->cn_nameptr);
*cp = c; }
#endif
ndp->ni_pathlen -= cnp->cn_namelen;
ndp->ni_next = cp;
cnp->cn_flags |= MAKEENTRY;
if (*cp == '\0' && docache == 0)
cnp->cn_flags &= ~MAKEENTRY;
if (cnp->cn_namelen == 2 &&
cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
cnp->cn_flags |= ISDOTDOT;
else
cnp->cn_flags &= ~ISDOTDOT;
if (*ndp->ni_next == 0)
cnp->cn_flags |= ISLASTCN;
else
cnp->cn_flags &= ~ISLASTCN;
/*
* Check for degenerate name (e.g. / or "")
* which is a way of talking about a directory,
* e.g. like "/." or ".".
*/
if (cnp->cn_nameptr[0] == '\0') {
if (dp->v_type != VDIR) {
error = ENOTDIR;
goto bad;
}
if (cnp->cn_nameiop != LOOKUP) {
error = EISDIR;
goto bad;
}
if (wantparent) {
ndp->ni_dvp = dp;
VREF(dp);
}
ndp->ni_vp = dp;
if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF)))
VOP_UNLOCK(dp, 0, p);
if (cnp->cn_flags & SAVESTART)
panic("lookup: SAVESTART");
return (0);
}
/*
* Handle "..": two special cases.
* 1. If at root directory (e.g. after chroot)
* or at absolute root directory
* then ignore it so can't get out.
* 2. If this vnode is the root of a mounted
* filesystem, then replace it with the
* vnode which was mounted on so we take the
* .. in the other file system.
*/
if (cnp->cn_flags & ISDOTDOT) {
for (;;) {
if (dp == ndp->ni_rootdir || dp == rootvnode) {
ndp->ni_dvp = dp;
ndp->ni_vp = dp;
VREF(dp);
goto nextname;
}
if ((dp->v_flag & VROOT) == 0 ||
(cnp->cn_flags & NOCROSSMOUNT))
break;
tdp = dp;
dp = dp->v_mount->mnt_vnodecovered;
vput(tdp);
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
}
}
/*
* We now have a segment name to search for, and a directory to search.
*/
unionlookup:
ndp->ni_dvp = dp;
ndp->ni_vp = NULL;
if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
#ifdef DIAGNOSTIC
if (ndp->ni_vp != NULL)
panic("leaf should be empty");
#endif
#ifdef NAMEI_DIAGNOSTIC
printf("not found\n");
#endif
if ((error == ENOENT) &&
(dp->v_flag & VROOT) &&
(dp->v_mount->mnt_flag & MNT_UNION)) {
tdp = dp;
dp = dp->v_mount->mnt_vnodecovered;
vput(tdp);
VREF(dp);
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
goto unionlookup;
}
if (error != EJUSTRETURN)
goto bad;
/*
* If creating and at end of pathname, then can consider
* allowing file to be created.
*/
if (rdonly) {
error = EROFS;
goto bad;
}
/*
* We return with ni_vp NULL to indicate that the entry
* doesn't currently exist, leaving a pointer to the
* (possibly locked) directory inode in ndp->ni_dvp.
*/
if (cnp->cn_flags & SAVESTART) {
ndp->ni_startdir = ndp->ni_dvp;
VREF(ndp->ni_startdir);
}
return (0);
}
#ifdef NAMEI_DIAGNOSTIC
printf("found\n");
#endif
/*
* Take into account any additional components consumed by
* the underlying filesystem.
*/
if (cnp->cn_consume > 0) {
cnp->cn_nameptr += cnp->cn_consume;
ndp->ni_next += cnp->cn_consume;
ndp->ni_pathlen -= cnp->cn_consume;
cnp->cn_consume = 0;
}
dp = ndp->ni_vp;
/*
* Check to see if the vnode has been mounted on;
* if so find the root of the mounted file system.
*/
while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
(cnp->cn_flags & NOCROSSMOUNT) == 0) {
if (vfs_busy(mp, 0, 0, p))
continue;
error = VFS_ROOT(mp, &tdp);
vfs_unbusy(mp, p);
if (error)
goto bad2;
vput(dp);
ndp->ni_vp = dp = tdp;
}
/*
* Check for symbolic link
*/
if ((dp->v_type == VLNK) &&
((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
cnp->cn_flags |= ISSYMLINK;
return (0);
}
nextname:
/*
* Not a symbolic link. If more pathname,
* continue at next component, else return.
*/
if (*ndp->ni_next == '/') {
cnp->cn_nameptr = ndp->ni_next;
while (*cnp->cn_nameptr == '/') {
cnp->cn_nameptr++;
ndp->ni_pathlen--;
}
vrele(ndp->ni_dvp);
goto dirloop;
}
/*
* Disallow directory write attempts on read-only file systems.
*/
if (rdonly &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
error = EROFS;
goto bad2;
}
if (cnp->cn_flags & SAVESTART) {
ndp->ni_startdir = ndp->ni_dvp;
VREF(ndp->ni_startdir);
}
if (!wantparent)
vrele(ndp->ni_dvp);
if ((cnp->cn_flags & LOCKLEAF) == 0)
VOP_UNLOCK(dp, 0, p);
return (0);
bad2:
if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
VOP_UNLOCK(ndp->ni_dvp, 0, p);
vrele(ndp->ni_dvp);
bad:
vput(dp);
ndp->ni_vp = NULL;
return (error);
}
/*
* relookup - lookup a path name component
* Used by lookup to re-aquire things.
*/
int
relookup(dvp, vpp, cnp)
struct vnode *dvp, **vpp;
struct componentname *cnp;
{
struct proc *p = cnp->cn_proc;
struct vnode *dp = 0; /* the directory we are searching */
int docache; /* == 0 do not cache last component */
int wantparent; /* 1 => wantparent or lockparent flag */
int rdonly; /* lookup read-only flag bit */
int error = 0;
#ifdef NAMEI_DIAGNOSTIC
int newhash; /* DEBUG: check name hash */
char *cp; /* DEBUG: check name ptr/len */
#endif
/*
* Setup: break out flag bits into variables.
*/
wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
if (cnp->cn_nameiop == DELETE ||
(wantparent && cnp->cn_nameiop != CREATE))
docache = 0;
rdonly = cnp->cn_flags & RDONLY;
cnp->cn_flags &= ~ISSYMLINK;
dp = dvp;
vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, p);
/* dirloop: */
/*
* Search a new directory.
*
* The cn_hash value is for use by vfs_cache.
* The last component of the filename is left accessible via
* cnp->cn_nameptr for callers that need the name. Callers needing
* the name set the SAVENAME flag. When done, they assume
* responsibility for freeing the pathname buffer.
*/
#ifdef NAMEI_DIAGNOSTIC
for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
newhash += (unsigned char)*cp;
if (newhash != cnp->cn_hash)
panic("relookup: bad hash");
if (cnp->cn_namelen != cp - cnp->cn_nameptr)
panic ("relookup: bad len");
if (*cp != 0)
panic("relookup: not last component");
printf("{%s}: ", cnp->cn_nameptr);
#endif
/*
* Check for degenerate name (e.g. / or "")
* which is a way of talking about a directory,
* e.g. like "/." or ".".
*/
if (cnp->cn_nameptr[0] == '\0') {
if (cnp->cn_nameiop != LOOKUP || wantparent) {
error = EISDIR;
goto bad;
}
if (dp->v_type != VDIR) {
error = ENOTDIR;
goto bad;
}
if (!(cnp->cn_flags & LOCKLEAF))
VOP_UNLOCK(dp, 0, p);
*vpp = dp;
if (cnp->cn_flags & SAVESTART)
panic("lookup: SAVESTART");
return (0);
}
if (cnp->cn_flags & ISDOTDOT)
panic ("relookup: lookup on dot-dot");
/*
* We now have a segment name to search for, and a directory to search.
*/
if (error = VOP_LOOKUP(dp, vpp, cnp)) {
#ifdef DIAGNOSTIC
if (*vpp != NULL)
panic("leaf should be empty");
#endif
if (error != EJUSTRETURN)
goto bad;
/*
* If creating and at end of pathname, then can consider
* allowing file to be created.
*/
if (rdonly) {
error = EROFS;
goto bad;
}
/* ASSERT(dvp == ndp->ni_startdir) */
if (cnp->cn_flags & SAVESTART)
VREF(dvp);
/*
* We return with ni_vp NULL to indicate that the entry
* doesn't currently exist, leaving a pointer to the
* (possibly locked) directory inode in ndp->ni_dvp.
*/
return (0);
}
dp = *vpp;
#ifdef DIAGNOSTIC
/*
* Check for symbolic link
*/
if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
panic ("relookup: symlink found.\n");
#endif
/*
* Disallow directory write attempts on read-only file systems.
*/
if (rdonly &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
error = EROFS;
goto bad2;
}
/* ASSERT(dvp == ndp->ni_startdir) */
if (cnp->cn_flags & SAVESTART)
VREF(dvp);
if (!wantparent)
vrele(dvp);
if ((cnp->cn_flags & LOCKLEAF) == 0)
VOP_UNLOCK(dp, 0, p);
return (0);
bad2:
if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
VOP_UNLOCK(dvp, 0, p);
vrele(dvp);
bad:
vput(dp);
*vpp = NULL;
return (error);
}

1782
sys/kern/vfs_subr.c Normal file

File diff suppressed because it is too large Load Diff

2417
sys/kern/vfs_syscalls.c Normal file

File diff suppressed because it is too large Load Diff

449
sys/kern/vfs_vnops.c Normal file
View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 1982, 1986, 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <vm/vm.h>
struct fileops vnops =
{ vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
/*
* Common code for vnode open operations.
* Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
*/
vn_open(ndp, fmode, cmode)
register struct nameidata *ndp;
int fmode, cmode;
{
register struct vnode *vp;
register struct proc *p = ndp->ni_cnd.cn_proc;
register struct ucred *cred = p->p_ucred;
struct vattr vat;
struct vattr *vap = &vat;
int error;
if (fmode & O_CREAT) {
ndp->ni_cnd.cn_nameiop = CREATE;
ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
if ((fmode & O_EXCL) == 0)
ndp->ni_cnd.cn_flags |= FOLLOW;
if (error = namei(ndp))
return (error);
if (ndp->ni_vp == NULL) {
VATTR_NULL(vap);
vap->va_type = VREG;
vap->va_mode = cmode;
if (fmode & O_EXCL)
vap->va_vaflags |= VA_EXCLUSIVE;
VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
&ndp->ni_cnd, vap))
return (error);
fmode &= ~O_TRUNC;
vp = ndp->ni_vp;
} else {
VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
if (ndp->ni_dvp == ndp->ni_vp)
vrele(ndp->ni_dvp);
else
vput(ndp->ni_dvp);
ndp->ni_dvp = NULL;
vp = ndp->ni_vp;
if (fmode & O_EXCL) {
error = EEXIST;
goto bad;
}
fmode &= ~O_CREAT;
}
} else {
ndp->ni_cnd.cn_nameiop = LOOKUP;
ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
if (error = namei(ndp))
return (error);
vp = ndp->ni_vp;
}
if (vp->v_type == VSOCK) {
error = EOPNOTSUPP;
goto bad;
}
if ((fmode & O_CREAT) == 0) {
if (fmode & FREAD) {
if (error = VOP_ACCESS(vp, VREAD, cred, p))
goto bad;
}
if (fmode & (FWRITE | O_TRUNC)) {
if (vp->v_type == VDIR) {
error = EISDIR;
goto bad;
}
if ((error = vn_writechk(vp)) ||
(error = VOP_ACCESS(vp, VWRITE, cred, p)))
goto bad;
}
}
if (fmode & O_TRUNC) {
VOP_UNLOCK(vp, 0, p); /* XXX */
VOP_LEASE(vp, p, cred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
VATTR_NULL(vap);
vap->va_size = 0;
if (error = VOP_SETATTR(vp, vap, cred, p))
goto bad;
}
if (error = VOP_OPEN(vp, fmode, cred, p))
goto bad;
if (fmode & FWRITE)
vp->v_writecount++;
return (0);
bad:
vput(vp);
return (error);
}
/*
* Check for write permissions on the specified vnode.
* Prototype text segments cannot be written.
*/
vn_writechk(vp)
register struct vnode *vp;
{
/*
* If there's shared text associated with
* the vnode, try to free it up once. If
* we fail, we can't allow writing.
*/
if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
return (ETXTBSY);
return (0);
}
/*
* Vnode close call
*/
vn_close(vp, flags, cred, p)
register struct vnode *vp;
int flags;
struct ucred *cred;
struct proc *p;
{
int error;
if (flags & FWRITE)
vp->v_writecount--;
error = VOP_CLOSE(vp, flags, cred, p);
vrele(vp);
return (error);
}
/*
* Package up an I/O request on a vnode into a uio and do it.
*/
vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
enum uio_rw rw;
struct vnode *vp;
caddr_t base;
int len;
off_t offset;
enum uio_seg segflg;
int ioflg;
struct ucred *cred;
int *aresid;
struct proc *p;
{
struct uio auio;
struct iovec aiov;
int error;
if ((ioflg & IO_NODELOCKED) == 0)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
aiov.iov_base = base;
aiov.iov_len = len;
auio.uio_resid = len;
auio.uio_offset = offset;
auio.uio_segflg = segflg;
auio.uio_rw = rw;
auio.uio_procp = p;
if (rw == UIO_READ) {
error = VOP_READ(vp, &auio, ioflg, cred);
} else {
error = VOP_WRITE(vp, &auio, ioflg, cred);
}
if (aresid)
*aresid = auio.uio_resid;
else
if (auio.uio_resid && error == 0)
error = EIO;
if ((ioflg & IO_NODELOCKED) == 0)
VOP_UNLOCK(vp, 0, p);
return (error);
}
/*
* File table vnode read routine.
*/
vn_read(fp, uio, cred)
struct file *fp;
struct uio *uio;
struct ucred *cred;
{
struct vnode *vp = (struct vnode *)fp->f_data;
struct proc *p = uio->uio_procp;
int count, error;
VOP_LEASE(vp, p, cred, LEASE_READ);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
uio->uio_offset = fp->f_offset;
count = uio->uio_resid;
error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
cred);
fp->f_offset += count - uio->uio_resid;
VOP_UNLOCK(vp, 0, p);
return (error);
}
/*
* File table vnode write routine.
*/
vn_write(fp, uio, cred)
struct file *fp;
struct uio *uio;
struct ucred *cred;
{
struct vnode *vp = (struct vnode *)fp->f_data;
struct proc *p = uio->uio_procp;
int count, error, ioflag = IO_UNIT;
if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
ioflag |= IO_APPEND;
if (fp->f_flag & FNONBLOCK)
ioflag |= IO_NDELAY;
if ((fp->f_flag & O_FSYNC) ||
(vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
ioflag |= IO_SYNC;
VOP_LEASE(vp, p, cred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
uio->uio_offset = fp->f_offset;
count = uio->uio_resid;
error = VOP_WRITE(vp, uio, ioflag, cred);
if (ioflag & IO_APPEND)
fp->f_offset = uio->uio_offset;
else
fp->f_offset += count - uio->uio_resid;
VOP_UNLOCK(vp, 0, p);
return (error);
}
/*
* File table vnode stat routine.
*/
vn_stat(vp, sb, p)
struct vnode *vp;
register struct stat *sb;
struct proc *p;
{
struct vattr vattr;
register struct vattr *vap;
int error;
u_short mode;
vap = &vattr;
error = VOP_GETATTR(vp, vap, p->p_ucred, p);
if (error)
return (error);
/*
* Copy from vattr table
*/
sb->st_dev = vap->va_fsid;
sb->st_ino = vap->va_fileid;
mode = vap->va_mode;
switch (vp->v_type) {
case VREG:
mode |= S_IFREG;
break;
case VDIR:
mode |= S_IFDIR;
break;
case VBLK:
mode |= S_IFBLK;
break;
case VCHR:
mode |= S_IFCHR;
break;
case VLNK:
mode |= S_IFLNK;
break;
case VSOCK:
mode |= S_IFSOCK;
break;
case VFIFO:
mode |= S_IFIFO;
break;
default:
return (EBADF);
};
sb->st_mode = mode;
sb->st_nlink = vap->va_nlink;
sb->st_uid = vap->va_uid;
sb->st_gid = vap->va_gid;
sb->st_rdev = vap->va_rdev;
sb->st_size = vap->va_size;
sb->st_atimespec = vap->va_atime;
sb->st_mtimespec = vap->va_mtime;
sb->st_ctimespec = vap->va_ctime;
sb->st_blksize = vap->va_blocksize;
sb->st_flags = vap->va_flags;
sb->st_gen = vap->va_gen;
sb->st_blocks = vap->va_bytes / S_BLKSIZE;
return (0);
}
/*
* File table vnode ioctl routine.
*/
vn_ioctl(fp, com, data, p)
struct file *fp;
u_long com;
caddr_t data;
struct proc *p;
{
register struct vnode *vp = ((struct vnode *)fp->f_data);
struct vattr vattr;
int error;
switch (vp->v_type) {
case VREG:
case VDIR:
if (com == FIONREAD) {
if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
return (error);
*(int *)data = vattr.va_size - fp->f_offset;
return (0);
}
if (com == FIONBIO || com == FIOASYNC) /* XXX */
return (0); /* XXX */
/* fall into ... */
default:
return (ENOTTY);
case VFIFO:
case VCHR:
case VBLK:
error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
if (error == 0 && com == TIOCSCTTY) {
if (p->p_session->s_ttyvp)
vrele(p->p_session->s_ttyvp);
p->p_session->s_ttyvp = vp;
VREF(vp);
}
return (error);
}
}
/*
* File table vnode select routine.
*/
vn_select(fp, which, p)
struct file *fp;
int which;
struct proc *p;
{
return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
fp->f_cred, p));
}
/*
* Check that the vnode is still valid, and if so
* acquire requested lock.
*/
int
vn_lock(vp, flags, p)
struct vnode *vp;
int flags;
struct proc *p;
{
int error;
do {
if ((flags & LK_INTERLOCK) == 0)
simple_lock(&vp->v_interlock);
if (vp->v_flag & VXLOCK) {
vp->v_flag |= VXWANT;
simple_unlock(&vp->v_interlock);
tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
error = ENOENT;
} else {
error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
if (error == 0)
return (error);
}
flags &= ~LK_INTERLOCK;
} while (flags & LK_RETRY);
return (error);
}
/*
* File table vnode close routine.
*/
vn_closefile(fp, p)
struct file *fp;
struct proc *p;
{
return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
fp->f_cred, p));
}

344
sys/kern/vnode_if.sh Normal file
View File

@ -0,0 +1,344 @@
#!/bin/sh -
copyright='
/*
* Copyright (c) 1992, 1993, 1994, 1995
* The Regents of the University of California. 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 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: NetBSD: vnode_if.sh,v 1.7 1994/08/25 03:04:28 cgd Exp $
*/
'
SCRIPT_ID='@(#)vnode_if.sh 8.7 (Berkeley) 5/11/95'
# Script to produce VFS front-end sugar.
#
# usage: vnode_if.sh srcfile
# (where srcfile is currently /sys/kern/vnode_if.src)
#
if [ $# -ne 1 ] ; then
echo 'usage: vnode_if.sh srcfile'
exit 1
fi
# Name of the source file.
src=$1
# Names of the created files.
out_c=vnode_if.c
out_h=vnode_if.h
# Awk program (must support nawk extensions)
# Use "awk" at Berkeley, "nawk" or "gawk" elsewhere.
awk=${AWK:-awk}
# Does this awk have a "toupper" function? (i.e. is it GNU awk)
isgawk=`$awk 'BEGIN { print toupper("true"); exit; }' 2>/dev/null`
# If this awk does not define "toupper" then define our own.
if [ "$isgawk" = TRUE ] ; then
# GNU awk provides it.
toupper=
else
# Provide our own toupper()
toupper='
function toupper(str) {
_toupper_cmd = "echo "str" |tr a-z A-Z"
_toupper_cmd | getline _toupper_str;
close(_toupper_cmd);
return _toupper_str;
}'
fi
#
# This is the common part of all awk programs that read $src
# This parses the input for one function into the arrays:
# argdir, argtype, argname, willrele
# and calls "doit()" to generate output for the function.
#
# Input to this parser is pre-processed slightly by sed
# so this awk parser doesn't have to work so hard. The
# changes done by the sed pre-processing step are:
# insert a space beween * and pointer name
# replace semicolons with spaces
#
sed_prep='s:\*\([^\*/]\):\* \1:g
s/;/ /'
awk_parser='
# Comment line
/^#/ { next; }
# First line of description
/^vop_/ {
name=$1;
argc=0;
next;
}
# Last line of description
/^}/ {
doit();
next;
}
# Middle lines of description
{
argdir[argc] = $1; i=2;
if ($2 == "WILLRELE") {
willrele[argc] = 1;
i++;
} else
willrele[argc] = 0;
argtype[argc] = $i; i++;
while (i < NF) {
argtype[argc] = argtype[argc]" "$i;
i++;
}
argname[argc] = $i;
argc++;
next;
}
'
# This is put after the copyright on each generated file.
warning="
/*
* Warning: This file is generated automatically.
* (Modifications made here may easily be lost!)
*
* Created by the script:
* ${SCRIPT_ID}
*/
"
# Get rid of ugly spaces
space_elim='s:\([^/]\*\) :\1:g'
#
# Redirect stdout to the H file.
#
echo "$0: Creating $out_h" 1>&2
exec > $out_h
# Begin stuff
echo "$copyright"
echo "$warning"
echo '
extern struct vnodeop_desc vop_default_desc;
'
# Body stuff
# This awk program needs toupper() so define it if necessary.
sed -e "$sed_prep" $src | $awk "$toupper"'
function doit() {
# Declare arg struct, descriptor.
printf("\nstruct %s_args {\n", name);
printf("\tstruct vnodeop_desc * a_desc;\n");
for (i=0; i<argc; i++) {
printf("\t%s a_%s;\n", argtype[i], argname[i]);
}
printf("};\n");
printf("extern struct vnodeop_desc %s_desc;\n", name);
# Define inline function.
printf("#define %s(", toupper(name));
for (i=0; i<argc; i++) {
printf("%s", argname[i]);
if (i < (argc-1)) printf(", ");
}
printf(") _%s(", toupper(name));
for (i=0; i<argc; i++) {
printf("%s", argname[i]);
if (i < (argc-1)) printf(", ");
}
printf(")\n");
printf("static __inline int _%s(", toupper(name));
for (i=0; i<argc; i++) {
printf("%s", argname[i]);
if (i < (argc-1)) printf(", ");
}
printf(")\n");
for (i=0; i<argc; i++) {
printf("\t%s %s;\n", argtype[i], argname[i]);
}
printf("{\n\tstruct %s_args a;\n", name);
printf("\ta.a_desc = VDESC(%s);\n", name);
for (i=0; i<argc; i++) {
printf("\ta.a_%s = %s;\n", argname[i], argname[i]);
}
printf("\treturn (VCALL(%s%s, VOFFSET(%s), &a));\n}\n",
argname[0], arg0special, name);
}
BEGIN {
arg0special="";
}
END {
printf("\n/* Special cases: */\n#include <sys/buf.h>\n");
argc=1;
argtype[0]="struct buf *";
argname[0]="bp";
arg0special="->b_vp";
name="vop_strategy";
doit();
name="vop_bwrite";
doit();
}
'"$awk_parser" | sed -e "$space_elim"
# End stuff
echo '
/* End of special cases. */'
#
# Redirect stdout to the C file.
#
echo "$0: Creating $out_c" 1>&2
exec > $out_c
# Begin stuff
echo "$copyright"
echo "$warning"
echo '
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/vnode.h>
struct vnodeop_desc vop_default_desc = {
0,
"default",
0,
NULL,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
VDESC_NO_OFFSET,
NULL,
};
'
# Body stuff
sed -e "$sed_prep" $src | $awk '
function do_offset(typematch) {
for (i=0; i<argc; i++) {
if (argtype[i] == typematch) {
printf("\tVOPARG_OFFSETOF(struct %s_args, a_%s),\n",
name, argname[i]);
return i;
};
};
print "\tVDESC_NO_OFFSET,";
return -1;
}
function doit() {
# Define offsets array
printf("\nint %s_vp_offsets[] = {\n", name);
for (i=0; i<argc; i++) {
if (argtype[i] == "struct vnode *") {
printf ("\tVOPARG_OFFSETOF(struct %s_args,a_%s),\n",
name, argname[i]);
}
}
print "\tVDESC_NO_OFFSET";
print "};";
# Define F_desc
printf("struct vnodeop_desc %s_desc = {\n", name);
# offset
printf ("\t0,\n");
# printable name
printf ("\t\"%s\",\n", name);
# flags
printf("\t0");
vpnum = 0;
for (i=0; i<argc; i++) {
if (willrele[i]) {
if (argdir[i] ~ /OUT/) {
printf(" | VDESC_VPP_WILLRELE");
} else {
printf(" | VDESC_VP%s_WILLRELE", vpnum);
};
vpnum++;
}
}
print ",";
# vp offsets
printf ("\t%s_vp_offsets,\n", name);
# vpp (if any)
do_offset("struct vnode **");
# cred (if any)
do_offset("struct ucred *");
# proc (if any)
do_offset("struct proc *");
# componentname
do_offset("struct componentname *");
# transport layer information
printf ("\tNULL,\n};\n");
}
END {
printf("\n/* Special cases: */\n");
argc=1;
argdir[0]="IN";
argtype[0]="struct buf *";
argname[0]="bp";
willrele[0]=0;
name="vop_strategy";
doit();
name="vop_bwrite";
doit();
}
'"$awk_parser" | sed -e "$space_elim"
# End stuff
echo '
/* End of special cases. */'
# Add the vfs_op_descs array to the C file.
# Begin stuff
echo '
struct vnodeop_desc *vfs_op_descs[] = {
&vop_default_desc, /* MUST BE FIRST */
&vop_strategy_desc, /* XXX: SPECIAL CASE */
&vop_bwrite_desc, /* XXX: SPECIAL CASE */
'
# Body stuff
sed -e "$sed_prep" $src | $awk '
function doit() {
printf("\t&%s_desc,\n", name);
}
'"$awk_parser"
# End stuff
echo ' NULL
};
'
exit 0
# Local Variables:
# tab-width: 4
# End:

494
sys/kern/vnode_if.src Normal file
View File

@ -0,0 +1,494 @@
#
# Copyright (c) 1992, 1993
# The Regents of the University of California. 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 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.
#
# @(#)vnode_if.src 8.12 (Berkeley) 5/14/95
#
#
# Above each of the vop descriptors is a specification of the locking
# protocol used by each vop call. The first column is the name of
# the variable, the remaining three columns are in, out and error
# respectively. The "in" column defines the lock state on input,
# the "out" column defines the state on succesful return, and the
# "error" column defines the locking state on error exit.
#
# The locking value can take the following values:
# L: locked.
# U: unlocked/
# -: not applicable. vnode does not yet (or no longer) exists.
# =: the same on input and output, may be either L or U.
# X: locked if not nil.
#
#
#% lookup dvp L ? ?
#% lookup vpp - L -
#
# XXX - the lookup locking protocol defies simple description and depends
# on the flags and operation fields in the (cnp) structure. Note
# especially that *vpp may equal dvp and both may be locked.
#
vop_lookup {
IN struct vnode *dvp;
INOUT struct vnode **vpp;
IN struct componentname *cnp;
};
#
#% create dvp L U U
#% create vpp - L -
#
vop_create {
IN WILLRELE struct vnode *dvp;
OUT struct vnode **vpp;
IN struct componentname *cnp;
IN struct vattr *vap;
};
#
#% whiteout dvp L L L
#% whiteout cnp - - -
#% whiteout flag - - -
#
vop_whiteout {
IN WILLRELE struct vnode *dvp;
IN struct componentname *cnp;
IN int flags;
};
#
#% mknod dvp L U U
#% mknod vpp - X -
#
vop_mknod {
IN WILLRELE struct vnode *dvp;
OUT WILLRELE struct vnode **vpp;
IN struct componentname *cnp;
IN struct vattr *vap;
};
#
#% open vp L L L
#
vop_open {
IN struct vnode *vp;
IN int mode;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% close vp U U U
#
vop_close {
IN struct vnode *vp;
IN int fflag;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% access vp L L L
#
vop_access {
IN struct vnode *vp;
IN int mode;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% getattr vp = = =
#
vop_getattr {
IN struct vnode *vp;
IN struct vattr *vap;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% setattr vp L L L
#
vop_setattr {
IN struct vnode *vp;
IN struct vattr *vap;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% read vp L L L
#
vop_read {
IN struct vnode *vp;
INOUT struct uio *uio;
IN int ioflag;
IN struct ucred *cred;
};
#
#% write vp L L L
#
vop_write {
IN struct vnode *vp;
INOUT struct uio *uio;
IN int ioflag;
IN struct ucred *cred;
};
#
#% lease vp = = =
#
vop_lease {
IN struct vnode *vp;
IN struct proc *p;
IN struct ucred *cred;
IN int flag;
};
#
#% ioctl vp U U U
#
vop_ioctl {
IN struct vnode *vp;
IN u_long command;
IN caddr_t data;
IN int fflag;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% select vp U U U
#
# Needs work? (fflags)
#
vop_select {
IN struct vnode *vp;
IN int which;
IN int fflags;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% revoke vp U U U
#
vop_revoke {
IN struct vnode *vp;
IN int flags;
};
#
# XXX - not used
#
vop_mmap {
IN struct vnode *vp;
IN int fflags;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% fsync vp L L L
#
vop_fsync {
IN struct vnode *vp;
IN struct ucred *cred;
IN int waitfor;
IN struct proc *p;
};
#
# XXX - not used
# Needs work: Is newoff right? What's it mean?
#
vop_seek {
IN struct vnode *vp;
IN off_t oldoff;
IN off_t newoff;
IN struct ucred *cred;
};
#
#% remove dvp L U U
#% remove vp L U U
#
vop_remove {
IN WILLRELE struct vnode *dvp;
IN WILLRELE struct vnode *vp;
IN struct componentname *cnp;
};
#
#% link vp U U U
#% link tdvp L U U
#
vop_link {
IN WILLRELE struct vnode *vp;
IN struct vnode *tdvp;
IN struct componentname *cnp;
};
#
#% rename fdvp U U U
#% rename fvp U U U
#% rename tdvp L U U
#% rename tvp X U U
#
vop_rename {
IN WILLRELE struct vnode *fdvp;
IN WILLRELE struct vnode *fvp;
IN struct componentname *fcnp;
IN WILLRELE struct vnode *tdvp;
IN WILLRELE struct vnode *tvp;
IN struct componentname *tcnp;
};
#
#% mkdir dvp L U U
#% mkdir vpp - L -
#
vop_mkdir {
IN WILLRELE struct vnode *dvp;
OUT struct vnode **vpp;
IN struct componentname *cnp;
IN struct vattr *vap;
};
#
#% rmdir dvp L U U
#% rmdir vp L U U
#
vop_rmdir {
IN WILLRELE struct vnode *dvp;
IN WILLRELE struct vnode *vp;
IN struct componentname *cnp;
};
#
#% symlink dvp L U U
#% symlink vpp - U -
#
# XXX - note that the return vnode has already been VRELE'ed
# by the filesystem layer. To use it you must use vget,
# possibly with a further namei.
#
vop_symlink {
IN WILLRELE struct vnode *dvp;
OUT WILLRELE struct vnode **vpp;
IN struct componentname *cnp;
IN struct vattr *vap;
IN char *target;
};
#
#% readdir vp L L L
#
vop_readdir {
IN struct vnode *vp;
INOUT struct uio *uio;
IN struct ucred *cred;
INOUT int *eofflag;
OUT int *ncookies;
INOUT u_long **cookies;
};
#
#% readlink vp L L L
#
vop_readlink {
IN struct vnode *vp;
INOUT struct uio *uio;
IN struct ucred *cred;
};
#
#% abortop dvp = = =
#
vop_abortop {
IN struct vnode *dvp;
IN struct componentname *cnp;
};
#
#% inactive vp L U U
#
vop_inactive {
IN struct vnode *vp;
IN struct proc *p;
};
#
#% reclaim vp U U U
#
vop_reclaim {
IN struct vnode *vp;
IN struct proc *p;
};
#
#% lock vp U L U
#
vop_lock {
IN struct vnode *vp;
IN int flags;
IN struct proc *p;
};
#
#% unlock vp L U L
#
vop_unlock {
IN struct vnode *vp;
IN int flags;
IN struct proc *p;
};
#
#% bmap vp L L L
#% bmap vpp - U -
#
vop_bmap {
IN struct vnode *vp;
IN daddr_t bn;
OUT struct vnode **vpp;
IN daddr_t *bnp;
OUT int *runp;
};
#
# Needs work: no vp?
#
#vop_strategy {
# IN struct buf *bp;
#};
#
#% print vp = = =
#
vop_print {
IN struct vnode *vp;
};
#
#% islocked vp = = =
#
vop_islocked {
IN struct vnode *vp;
};
#
#% pathconf vp L L L
#
vop_pathconf {
IN struct vnode *vp;
IN int name;
OUT register_t *retval;
};
#
#% advlock vp U U U
#
vop_advlock {
IN struct vnode *vp;
IN caddr_t id;
IN int op;
IN struct flock *fl;
IN int flags;
};
#
#% blkatoff vp L L L
#
vop_blkatoff {
IN struct vnode *vp;
IN off_t offset;
OUT char **res;
OUT struct buf **bpp;
};
#
#% valloc pvp L L L
#
vop_valloc {
IN struct vnode *pvp;
IN int mode;
IN struct ucred *cred;
OUT struct vnode **vpp;
};
#
#% reallocblks vp L L L
#
vop_reallocblks {
IN struct vnode *vp;
IN struct cluster_save *buflist;
};
#
#% vfree pvp L L L
#
vop_vfree {
IN struct vnode *pvp;
IN ino_t ino;
IN int mode;
};
#
#% truncate vp L L L
#
vop_truncate {
IN struct vnode *vp;
IN off_t length;
IN int flags;
IN struct ucred *cred;
IN struct proc *p;
};
#
#% update vp L L L
#
vop_update {
IN struct vnode *vp;
IN struct timeval *access;
IN struct timeval *modify;
IN int waitfor;
};
#
# Needs work: no vp?
#
#vop_bwrite {
# IN struct buf *bp;
#};