123367Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 537728Smckusick * Redistribution and use in source and binary forms are permitted 637728Smckusick * provided that the above copyright notice and this paragraph are 737728Smckusick * duplicated in all such forms and that any documentation, 837728Smckusick * advertising materials, and other materials related to such 937728Smckusick * distribution and use acknowledge that the software was developed 1037728Smckusick * by the University of California, Berkeley. The name of the 1137728Smckusick * University may not be used to endorse or promote products derived 1237728Smckusick * from this software without specific prior written permission. 1337728Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437728Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537728Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637728Smckusick * 17*42863Smckusick * @(#)kern_descrip.c 7.12 (Berkeley) 06/04/90 1823367Smckusick */ 197422Sroot 2017089Sbloom #include "param.h" 2117089Sbloom #include "systm.h" 2237728Smckusick #include "syscontext.h" 2317089Sbloom #include "kernel.h" 2437728Smckusick #include "vnode.h" 2517089Sbloom #include "proc.h" 2617089Sbloom #include "file.h" 2717089Sbloom #include "socket.h" 2817089Sbloom #include "socketvar.h" 2917089Sbloom #include "stat.h" 307422Sroot 3117089Sbloom #include "ioctl.h" 327497Sroot 337422Sroot /* 347497Sroot * Descriptor management. 357422Sroot */ 367497Sroot 377497Sroot /* 387497Sroot * System calls on descriptors. 397497Sroot */ 40*42863Smckusick /* ARGSUSED */ 41*42863Smckusick getdtablesize(p, uap, retval) 42*42863Smckusick struct proc *p; 43*42863Smckusick struct args *uap; 44*42863Smckusick int *retval; 457497Sroot { 467497Sroot 47*42863Smckusick *retval = NOFILE; 48*42863Smckusick RETURN (0); 497497Sroot } 507497Sroot 51*42863Smckusick /* 52*42863Smckusick * Duplicate a file descriptor. 53*42863Smckusick */ 54*42863Smckusick /* ARGSUSED */ 55*42863Smckusick dup(p, uap, retval) 56*42863Smckusick struct proc *p; 57*42863Smckusick struct args { 58*42863Smckusick int i; 59*42863Smckusick } *uap; 60*42863Smckusick int *retval; 617422Sroot { 627696Ssam struct file *fp; 63*42863Smckusick int fd, error; 647497Sroot 65*42863Smckusick /* 66*42863Smckusick * XXX Compatibility 67*42863Smckusick */ 68*42863Smckusick if (uap->i &~ 077) { uap->i &= 077; RETURN (dup2(p, uap, retval)); } 697497Sroot 7037728Smckusick if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 7137728Smckusick RETURN (EBADF); 72*42863Smckusick if (error = ufalloc(0, &fd)) 73*42863Smckusick RETURN (error); 74*42863Smckusick u.u_ofile[fd] = fp; 75*42863Smckusick u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE; 76*42863Smckusick fp->f_count++; 77*42863Smckusick if (fd > u.u_lastfile) 78*42863Smckusick u.u_lastfile = fd; 79*42863Smckusick *retval = fd; 80*42863Smckusick RETURN (0); 817497Sroot } 827497Sroot 83*42863Smckusick /* 84*42863Smckusick * Duplicate a file descriptor to a particular value. 85*42863Smckusick */ 86*42863Smckusick /* ARGSUSED */ 87*42863Smckusick dup2(p, uap, retval) 88*42863Smckusick struct proc *p; 89*42863Smckusick register struct args { 90*42863Smckusick int i; 91*42863Smckusick int j; 92*42863Smckusick } *uap; 93*42863Smckusick int *retval; 947497Sroot { 957497Sroot register struct file *fp; 9639354Smckusick int error; 977422Sroot 9837728Smckusick if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 9937728Smckusick RETURN (EBADF); 10039354Smckusick if (uap->j < 0 || uap->j >= NOFILE) 10139354Smckusick RETURN (EBADF); 102*42863Smckusick *retval = uap->j; 1037497Sroot if (uap->i == uap->j) 10439354Smckusick RETURN (0); 1057497Sroot if (u.u_ofile[uap->j]) { 1068945Sroot if (u.u_pofile[uap->j] & UF_MAPPED) 1078945Sroot munmapfd(uap->j); 10839354Smckusick error = closef(u.u_ofile[uap->j]); 1097422Sroot } 110*42863Smckusick u.u_ofile[uap->j] = fp; 111*42863Smckusick u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE; 112*42863Smckusick fp->f_count++; 113*42863Smckusick if (uap->j > u.u_lastfile) 114*42863Smckusick u.u_lastfile = uap->j; 11539354Smckusick /* 11639354Smckusick * dup2() must succeed even though the close had an error. 11739354Smckusick */ 11839354Smckusick error = 0; /* XXX */ 11939354Smckusick RETURN (error); 1207696Ssam } 1217696Ssam 12212748Ssam /* 12312748Ssam * The file control system call. 12412748Ssam */ 125*42863Smckusick /* ARGSUSED */ 126*42863Smckusick fcntl(p, uap, retval) 127*42863Smckusick struct proc *p; 128*42863Smckusick register struct args { 12912748Ssam int fdes; 13012748Ssam int cmd; 13112748Ssam int arg; 132*42863Smckusick } *uap; 133*42863Smckusick int *retval; 134*42863Smckusick { 135*42863Smckusick register struct file *fp; 13612748Ssam register char *pop; 137*42863Smckusick int i, error; 1387497Sroot 13937728Smckusick if ((unsigned)uap->fdes >= NOFILE || 14037728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 14137728Smckusick RETURN (EBADF); 14212748Ssam pop = &u.u_pofile[uap->fdes]; 14312748Ssam switch(uap->cmd) { 14415076Skarels case F_DUPFD: 145*42863Smckusick if (uap->arg < 0 || uap->arg >= NOFILE) 146*42863Smckusick RETURN (EINVAL); 147*42863Smckusick if (error = ufalloc(uap->arg, &i)) 148*42863Smckusick RETURN (error); 149*42863Smckusick u.u_ofile[i] = fp; 150*42863Smckusick u.u_pofile[i] = *pop &~ UF_EXCLOSE; 151*42863Smckusick fp->f_count++; 152*42863Smckusick if (i > u.u_lastfile) 153*42863Smckusick u.u_lastfile = i; 154*42863Smckusick *retval = i; 155*42863Smckusick RETURN (0); 1567497Sroot 15715076Skarels case F_GETFD: 158*42863Smckusick *retval = *pop & 1; 159*42863Smckusick RETURN (0); 1607422Sroot 16115076Skarels case F_SETFD: 16212748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 163*42863Smckusick RETURN (0); 1648145Sroot 16515076Skarels case F_GETFL: 166*42863Smckusick *retval = fp->f_flag + FOPEN; 167*42863Smckusick RETURN (0); 1688145Sroot 16915076Skarels case F_SETFL: 17012748Ssam fp->f_flag &= FCNTLCANT; 17112748Ssam fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; 172*42863Smckusick if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY)) 173*42863Smckusick RETURN (error); 174*42863Smckusick if (error = fset(fp, FASYNC, fp->f_flag & FASYNC)) 17512748Ssam (void) fset(fp, FNDELAY, 0); 176*42863Smckusick RETURN (error); 1777422Sroot 17815076Skarels case F_GETOWN: 179*42863Smckusick RETURN (fgetown(fp, retval)); 1807422Sroot 18115076Skarels case F_SETOWN: 182*42863Smckusick RETURN (fsetown(fp, uap->arg)); 1838115Sroot 18412748Ssam default: 185*42863Smckusick RETURN (EINVAL); 1867422Sroot } 187*42863Smckusick /* NOTREACHED */ 1887422Sroot } 1897422Sroot 19012748Ssam fset(fp, bit, value) 19112748Ssam struct file *fp; 19212748Ssam int bit, value; 1937422Sroot { 1947422Sroot 19512748Ssam if (value) 19612748Ssam fp->f_flag |= bit; 19712748Ssam else 19812748Ssam fp->f_flag &= ~bit; 19912748Ssam return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), 20012748Ssam (caddr_t)&value)); 20112748Ssam } 2027422Sroot 20312748Ssam fgetown(fp, valuep) 20412748Ssam struct file *fp; 20512748Ssam int *valuep; 20612748Ssam { 20712748Ssam int error; 2088115Sroot 20912748Ssam switch (fp->f_type) { 2108115Sroot 21112748Ssam case DTYPE_SOCKET: 21235810Smarc *valuep = ((struct socket *)fp->f_data)->so_pgid; 21312748Ssam return (0); 2147497Sroot 21512748Ssam default: 21612748Ssam error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); 21712748Ssam *valuep = -*valuep; 21812748Ssam return (error); 2197422Sroot } 2207422Sroot } 2217422Sroot 22212748Ssam fsetown(fp, value) 22312748Ssam struct file *fp; 22412748Ssam int value; 2257422Sroot { 22637728Smckusick 22712748Ssam if (fp->f_type == DTYPE_SOCKET) { 22835810Smarc ((struct socket *)fp->f_data)->so_pgid = value; 22912748Ssam return (0); 23012748Ssam } 23112748Ssam if (value > 0) { 23212748Ssam struct proc *p = pfind(value); 23312748Ssam if (p == 0) 23428201Skarels return (ESRCH); 23535810Smarc value = p->p_pgrp->pg_id; 23612748Ssam } else 23712748Ssam value = -value; 23812748Ssam return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); 2397422Sroot } 2407422Sroot 24112748Ssam fioctl(fp, cmd, value) 24212748Ssam struct file *fp; 24312748Ssam int cmd; 24412748Ssam caddr_t value; 2457422Sroot { 2467422Sroot 24712748Ssam return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); 2487422Sroot } 2497422Sroot 250*42863Smckusick /* 251*42863Smckusick * Close a file descriptor. 252*42863Smckusick */ 253*42863Smckusick /* ARGSUSED */ 254*42863Smckusick close(p, uap, retval) 255*42863Smckusick struct proc *p; 256*42863Smckusick struct args { 257*42863Smckusick int fdes; 258*42863Smckusick } *uap; 259*42863Smckusick int *retval; 2608029Sroot { 26112748Ssam register struct file *fp; 26213044Ssam register u_char *pf; 2638029Sroot 26437728Smckusick if ((unsigned)uap->fdes >= NOFILE || 26537728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 26637728Smckusick RETURN (EBADF); 26737728Smckusick pf = (u_char *)&u.u_pofile[uap->fdes]; 26813044Ssam if (*pf & UF_MAPPED) 26937728Smckusick munmapfd(uap->fdes); 27037728Smckusick u.u_ofile[uap->fdes] = NULL; 27121101Skarels while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) 27221101Skarels u.u_lastfile--; 27315550Skarels *pf = 0; 27439354Smckusick RETURN (closef(fp)); 2758029Sroot } 2768029Sroot 277*42863Smckusick /* 278*42863Smckusick * Return status information about a file descriptor. 279*42863Smckusick */ 280*42863Smckusick /* ARGSUSED */ 281*42863Smckusick fstat(p, uap, retval) 282*42863Smckusick struct proc *p; 283*42863Smckusick register struct args { 284*42863Smckusick int fdes; 285*42863Smckusick struct stat *sb; 286*42863Smckusick } *uap; 287*42863Smckusick int *retval; 28813044Ssam { 28913044Ssam register struct file *fp; 29013044Ssam struct stat ub; 291*42863Smckusick int error; 29213044Ssam 29337728Smckusick if ((unsigned)uap->fdes >= NOFILE || 29437728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 29537728Smckusick RETURN (EBADF); 29613044Ssam switch (fp->f_type) { 29713044Ssam 29837728Smckusick case DTYPE_VNODE: 299*42863Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub); 30013044Ssam break; 30113044Ssam 30213044Ssam case DTYPE_SOCKET: 303*42863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 30413044Ssam break; 30513044Ssam 30613044Ssam default: 30713044Ssam panic("fstat"); 30813044Ssam /*NOTREACHED*/ 30913044Ssam } 310*42863Smckusick if (error == 0) 311*42863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 312*42863Smckusick RETURN (error); 31313044Ssam } 31413044Ssam 3157422Sroot /* 3167497Sroot * Allocate a user file descriptor. 3177422Sroot */ 31837728Smckusick ufalloc(want, result) 31937728Smckusick register int want; 32037728Smckusick int *result; 3217422Sroot { 3227497Sroot 32339733Smckusick for (; want < NOFILE; want++) { 32437728Smckusick if (u.u_ofile[want] == NULL) { 32537728Smckusick u.u_pofile[want] = 0; 32637728Smckusick if (want > u.u_lastfile) 32737728Smckusick u.u_lastfile = want; 32839733Smckusick *result = want; 32937728Smckusick return (0); 3307497Sroot } 33139733Smckusick } 33237728Smckusick return (EMFILE); 3337497Sroot } 3347497Sroot 335*42863Smckusick /* 336*42863Smckusick * Check to see if any user file descriptors are available. 337*42863Smckusick */ 33812748Ssam ufavail() 33912748Ssam { 34012748Ssam register int i, avail = 0; 34112748Ssam 34212748Ssam for (i = 0; i < NOFILE; i++) 34312748Ssam if (u.u_ofile[i] == NULL) 34412748Ssam avail++; 34512748Ssam return (avail); 34612748Ssam } 34712748Ssam 3487497Sroot struct file *lastf; 3497497Sroot /* 3507497Sroot * Allocate a user file descriptor 3517497Sroot * and a file structure. 3527497Sroot * Initialize the descriptor 3537497Sroot * to point at the file structure. 3547497Sroot */ 35537728Smckusick falloc(resultfp, resultfd) 35637728Smckusick struct file **resultfp; 35737728Smckusick int *resultfd; 3587497Sroot { 3597422Sroot register struct file *fp; 36037728Smckusick int error, i; 3617422Sroot 36237728Smckusick if (error = ufalloc(0, &i)) 36337728Smckusick return (error); 3647497Sroot if (lastf == 0) 3657497Sroot lastf = file; 3667497Sroot for (fp = lastf; fp < fileNFILE; fp++) 3677497Sroot if (fp->f_count == 0) 3687497Sroot goto slot; 3697497Sroot for (fp = file; fp < lastf; fp++) 3707497Sroot if (fp->f_count == 0) 3717497Sroot goto slot; 3727497Sroot tablefull("file"); 37337728Smckusick return (ENFILE); 3747497Sroot slot: 3757497Sroot u.u_ofile[i] = fp; 37612748Ssam fp->f_count = 1; 37712748Ssam fp->f_data = 0; 3787497Sroot fp->f_offset = 0; 37937728Smckusick fp->f_cred = u.u_cred; 38037728Smckusick crhold(fp->f_cred); 3817497Sroot lastf = fp + 1; 38237728Smckusick if (resultfp) 38337728Smckusick *resultfp = fp; 38437728Smckusick if (resultfd) 38537728Smckusick *resultfd = i; 38637728Smckusick return (0); 3877497Sroot } 38812748Ssam 3897497Sroot /* 3907497Sroot * Internal form of close. 39112748Ssam * Decrement reference count on file structure. 3927497Sroot */ 39313044Ssam closef(fp) 3947497Sroot register struct file *fp; 3957497Sroot { 39639354Smckusick int error; 3977497Sroot 3987422Sroot if (fp == NULL) 39939354Smckusick return (0); 4007497Sroot if (fp->f_count > 1) { 4017497Sroot fp->f_count--; 40239354Smckusick return (0); 4037422Sroot } 40437728Smckusick if (fp->f_count < 1) 40537728Smckusick panic("closef: count < 1"); 40639354Smckusick error = (*fp->f_ops->fo_close)(fp); 40737728Smckusick crfree(fp->f_cred); 4087497Sroot fp->f_count = 0; 40939354Smckusick return (error); 4107422Sroot } 41113044Ssam 41213044Ssam /* 41313044Ssam * Apply an advisory lock on a file descriptor. 41413044Ssam */ 415*42863Smckusick /* ARGSUSED */ 416*42863Smckusick flock(p, uap, retval) 417*42863Smckusick struct proc *p; 418*42863Smckusick register struct args { 41937728Smckusick int fdes; 42013044Ssam int how; 421*42863Smckusick } *uap; 422*42863Smckusick int *retval; 423*42863Smckusick { 42413044Ssam register struct file *fp; 42513044Ssam 42637728Smckusick if ((unsigned)uap->fdes >= NOFILE || 42737728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 42837728Smckusick RETURN (EBADF); 429*42863Smckusick if (fp->f_type != DTYPE_VNODE) 430*42863Smckusick RETURN (EOPNOTSUPP); 43113101Ssam if (uap->how & LOCK_UN) { 43237728Smckusick vn_unlock(fp, FSHLOCK|FEXLOCK); 433*42863Smckusick RETURN (0); 43413044Ssam } 43517434Skarels if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) 436*42863Smckusick RETURN (0); /* error? */ 43717998Skarels if (uap->how & LOCK_EX) 43817998Skarels uap->how &= ~LOCK_SH; 43913101Ssam /* avoid work... */ 44017998Skarels if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || 44117998Skarels (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) 442*42863Smckusick RETURN (0); 443*42863Smckusick RETURN (vn_lock(fp, uap->how)); 44413044Ssam } 44537586Smarc 44637586Smarc /* 44737586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 44837586Smarc * 44937586Smarc * Fred Blonder - U of Maryland 11-Sep-1984 45037586Smarc * 45137586Smarc * Opening minor device N dup()s the file (if any) connected to file 45237586Smarc * descriptor N belonging to the calling process. Note that this driver 45337586Smarc * consists of only the ``open()'' routine, because all subsequent 45437586Smarc * references to this file will be direct to the other driver. 45537586Smarc */ 45637728Smckusick /* ARGSUSED */ 45737728Smckusick fdopen(dev, mode, type) 45837586Smarc dev_t dev; 45937728Smckusick int mode, type; 46037586Smarc { 46137586Smarc struct file *fp, *wfp; 46240873Sbostic int indx, dfd; 46337586Smarc 46437586Smarc /* 46540873Sbostic * XXX 46640873Sbostic * Horrid kludge: u.u_r.r_val1 contains the value of the new file 46740873Sbostic * descriptor, which was set before the call to vn_open() by copen() 46840873Sbostic * in vfs_syscalls.c. 46937586Smarc */ 47040873Sbostic indx = u.u_r.r_val1; 47140873Sbostic fp = u.u_ofile[indx]; 47240873Sbostic 47337586Smarc /* 47440873Sbostic * File system device minor number is the to-be-dup'd fd number. 47540873Sbostic * If it is greater than the allowed number of file descriptors, 47640873Sbostic * or the fd to be dup'd has already been closed, reject. Note, 47740873Sbostic * check for new == old is necessary as u_falloc could allocate 47840873Sbostic * an already closed to-be-dup'd descriptor as the new descriptor. 47937586Smarc */ 48040873Sbostic dfd = minor(dev); 48140873Sbostic if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL || 48240873Sbostic fp == wfp) 48337586Smarc return (EBADF); 48440873Sbostic 48537586Smarc /* 48640873Sbostic * Check that the mode the file is being opened for is a subset 48740873Sbostic * of the mode of the existing descriptor. 48837586Smarc */ 48940873Sbostic if ((mode & (FREAD|FWRITE) | wfp->f_flag) != wfp->f_flag) 49037586Smarc return (EACCES); 491*42863Smckusick u.u_ofile[indx] = wfp; 492*42863Smckusick u.u_pofile[indx] = u.u_pofile[dfd]; 493*42863Smckusick wfp->f_count++; 494*42863Smckusick if (indx > u.u_lastfile) 495*42863Smckusick u.u_lastfile = indx; 49640873Sbostic 49739498Smckusick /* 49840873Sbostic * Delete references to this pseudo-device by returning a special 49940873Sbostic * error (EJUSTRETURN) that will cause all resources to be freed, 50040873Sbostic * then detected and cleared by copen(). 50139498Smckusick */ 50240704Skarels return (EJUSTRETURN); /* XXX */ 50337586Smarc } 504