📄 kern_descrip.c
字号:
/* $Id: kern_descrip.c,v 1.3 2002/05/05 21:30:13 patrik Exp $ *//* $OpenBSD: kern_descrip.c,v 1.18 1999/07/13 15:17:50 provos Exp $ *//* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ *//* * 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.6 (Berkeley) 4/19/94 */#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/ucred.h>#include <sys/unistd.h>#include <sys/resourcevar.h>#include <sys/conf.h>#if 0#include <sys/mount.h>#endif#include <sys/syscallargs.h>#include <vm/vm.h>#ifdef NOTUSED_BY_PMON#include <sys/pipe.h>#endif#ifdef PMON#include <fcntl.h>#endif/* * Descriptor management. */struct filelist filehead; /* head of list of open files */int nfiles; /* actual number of open files */static __inline void fd_used __P((struct filedesc *, int));static __inline void fd_unused __P((struct filedesc *, int));int finishdup __P((struct filedesc *, int, int, register_t *));static __inline voidfd_used(fdp, fd) register struct filedesc *fdp; register int fd;{ if (fd > fdp->fd_lastfile) fdp->fd_lastfile = fd;}static __inline voidfd_unused(fdp, fd) register struct filedesc *fdp; register int fd;{ if (fd < fdp->fd_freefile) fdp->fd_freefile = fd;#ifdef DIAGNOSTIC if (fd > fdp->fd_lastfile) panic("fd_unused: fd_lastfile inconsistent");#endif if (fd == fdp->fd_lastfile) { do { fd--; } while (fd >= 0 && fdp->fd_ofiles[fd] == NULL); fdp->fd_lastfile = fd; }}/* * System calls on descriptors. *//* * Duplicate a file descriptor. *//* ARGSUSED */intsys_dup(p, v, retval) struct proc *p; void *v; register_t *retval;{ struct sys_dup_args /* { syscallarg(u_int) fd; } */ *uap = v; register struct filedesc *fdp = p->p_fd; register int old = SCARG(uap, fd); int new; int error; if ((u_int)old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL) return (EBADF); if ((error = fdalloc(p, 0, &new)) != 0) return (error); return (finishdup(fdp, old, new, retval));}/* * Duplicate a file descriptor to a particular value. *//* ARGSUSED */intsys_dup2(p, v, retval) struct proc *p; void *v; register_t *retval;{ struct sys_dup2_args /* { syscallarg(u_int) from; syscallarg(u_int) to; } */ *uap = v; register struct filedesc *fdp = p->p_fd; register int old = SCARG(uap, from), new = SCARG(uap, to); int i, error; if ((u_int)old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL ||#ifdef NOTUSED_BY_PMON (u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||#endif (u_int)new >= maxfiles) return (EBADF); if (old == new) { *retval = new; return (0); } if (new >= fdp->fd_nfiles) { if ((error = fdalloc(p, new, &i)) != 0) return (error); if (new != i) panic("dup2: fdalloc"); } else { (void) fdrelease(p, new); } return (finishdup(fdp, old, new, retval));}/* * The file control system call. *//* ARGSUSED */intsys_fcntl(p, v, retval) struct proc *p; void *v; register_t *retval;{ register struct sys_fcntl_args /* { syscallarg(int) fd; syscallarg(int) cmd; syscallarg(void *) arg; } */ *uap = v; int fd = SCARG(uap, fd); register struct filedesc *fdp = p->p_fd; register struct file *fp; int i, tmp, error;#ifndef PMON struct vnode *vp; int flg = F_POSIX; struct flock fl;#endif int newmin; if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) return (EBADF); switch (SCARG(uap, cmd)) { case F_DUPFD: newmin = (long)SCARG(uap, arg);#ifdef NOTUSED_BY_PMON if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||#else if (#endif (u_int)newmin >= maxfiles) return (EINVAL); if ((error = fdalloc(p, newmin, &i)) != 0) return (error); return (finishdup(fdp, fd, i, retval)); case F_GETFD: *retval = fdp->fd_ofileflags[fd] & UF_EXCLOSE ? 1 : 0; return (0); case F_SETFD: if ((long)SCARG(uap, arg) & 1) fdp->fd_ofileflags[fd] |= UF_EXCLOSE; else fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE; 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);#ifdef NOTUSED_BY_PMON case F_SETOWN: if (fp->f_type == DTYPE_SOCKET) { struct socket *so = (struct socket *)fp->f_data; so->so_pgid = (long)SCARG(uap, arg); so->so_siguid = p->p_cred->p_ruid; so->so_sigeuid = p->p_ucred->cr_uid; 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; else if (fl.l_whence != SEEK_END && fl.l_whence != SEEK_SET && fl.l_whence != 0) return (EINVAL); if (fl.l_start < 0) return (EINVAL); if (fl.l_type != F_RDLCK && fl.l_type != F_WRLCK && fl.l_type != F_UNLCK && fl.l_type != 0) return (EINVAL); error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX); if (error) return (error); return (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg), sizeof (fl)));#endif default: return (EINVAL); } /* NOTREACHED */}/* * Common code for dup, dup2, and fcntl(F_DUPFD). */intfinishdup(fdp, old, new, retval) register struct filedesc *fdp; register int old, new; register_t *retval;{ register struct file *fp; fp = fdp->fd_ofiles[old]; if (fp->f_count == LONG_MAX-2) return (EDEADLK); fdp->fd_ofiles[new] = fp; fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; fp->f_count++; fd_used(fdp, new); *retval = new; return (0);}voidfdremove(fdp, fd) struct filedesc *fdp; int fd;{ fdp->fd_ofiles[fd] = NULL; fd_unused(fdp, fd);}intfdrelease(p, fd) struct proc *p; int fd;{ register struct filedesc *fdp = p->p_fd; register struct file **fpp, *fp; register char *pf; fpp = &fdp->fd_ofiles[fd]; fp = *fpp; if (fp == NULL) return (EBADF); pf = &fdp->fd_ofileflags[fd];#ifndef PMON#if defined(UVM) if (*pf & UF_MAPPED) { /* XXX: USELESS? XXXCDC check it */ p->p_fd->fd_ofileflags[fd] &= ~UF_MAPPED; }#else if (*pf & UF_MAPPED) (void) munmapfd(p, fd);#endif#endif *fpp = NULL; *pf = 0; fd_unused(fdp, fd); return (closef(fp, p));}/* * Close a file descriptor. *//* ARGSUSED */intsys_close(p, v, retval) struct proc *p; void *v; register_t *retval;{ struct sys_close_args /* { syscallarg(int) fd; } */ *uap = v; int fd = SCARG(uap, fd); register struct filedesc *fdp = p->p_fd; if ((u_int)fd >= fdp->fd_nfiles) return (EBADF); return (fdrelease(p, fd));}/* * Return status information about a file descriptor. *//* ARGSUSED */intsys_fstat(p, v, retval) struct proc *p; void *v; register_t *retval;{ register struct sys_fstat_args /* { syscallarg(int) fd; syscallarg(struct stat *) sb; } */ *uap = v; 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) {#ifndef PMON case DTYPE_VNODE: error = vn_stat((struct vnode *)fp->f_data, &ub, p); break;#endif case DTYPE_SOCKET: error = soo_stat((struct socket *)fp->f_data, &ub); break;#ifdef NOTUSED_BY_PMON#ifndef OLD_PIPE case DTYPE_PIPE: error = pipe_stat((struct pipe *)fp->f_data, &ub); break;#endif#endif default: panic("fstat"); /*NOTREACHED*/ } if (error == 0) { /* Don't let non-root see generation numbers (for NFS security) */ if (suser(p->p_ucred, &p->p_acflag)) ub.st_gen = 0; error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb), sizeof (ub)); } return (error);}/* * Return pathconf information about a file descriptor. *//* ARGSUSED */intsys_fpathconf(p, v, retval) struct proc *p; void *v; register_t *retval;{ register struct sys_fpathconf_args /* { syscallarg(int) fd; syscallarg(int) name; } */ *uap = v; int fd = SCARG(uap, fd); struct filedesc *fdp = p->p_fd; struct file *fp;#ifndef PMON struct vnode *vp;#endif if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) return (EBADF); switch (fp->f_type) {#ifndef OLD_PIPE case DTYPE_PIPE:#endif case DTYPE_SOCKET: if (SCARG(uap, name) != _PC_PIPE_BUF) return (EINVAL); *retval = PIPE_BUF; return (0);#ifndef PMON case DTYPE_VNODE: vp = (struct vnode *)fp->f_data; return (VOP_PATHCONF(vp, SCARG(uap, name), retval));#endif default: panic("fpathconf"); } /*NOTREACHED*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -