123367Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 5*44431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*44431Sbostic * @(#)kern_descrip.c 7.16 (Berkeley) 06/28/90 823367Smckusick */ 97422Sroot 1017089Sbloom #include "param.h" 1117089Sbloom #include "systm.h" 1244404Skarels #include "user.h" 1317089Sbloom #include "kernel.h" 1437728Smckusick #include "vnode.h" 1517089Sbloom #include "proc.h" 1617089Sbloom #include "file.h" 1717089Sbloom #include "socket.h" 1817089Sbloom #include "socketvar.h" 1917089Sbloom #include "stat.h" 2017089Sbloom #include "ioctl.h" 217497Sroot 227422Sroot /* 237497Sroot * Descriptor management. 247422Sroot */ 257497Sroot 267497Sroot /* 277497Sroot * System calls on descriptors. 287497Sroot */ 2942863Smckusick /* ARGSUSED */ 3042863Smckusick getdtablesize(p, uap, retval) 3142863Smckusick struct proc *p; 3242863Smckusick struct args *uap; 3342863Smckusick int *retval; 347497Sroot { 357497Sroot 3642863Smckusick *retval = NOFILE; 3744404Skarels return (0); 387497Sroot } 397497Sroot 4042863Smckusick /* 4142863Smckusick * Duplicate a file descriptor. 4242863Smckusick */ 4342863Smckusick /* ARGSUSED */ 4442863Smckusick dup(p, uap, retval) 4542863Smckusick struct proc *p; 4642863Smckusick struct args { 4742863Smckusick int i; 4842863Smckusick } *uap; 4942863Smckusick int *retval; 507422Sroot { 517696Ssam struct file *fp; 5242863Smckusick int fd, error; 537497Sroot 5442863Smckusick /* 5542863Smckusick * XXX Compatibility 5642863Smckusick */ 5744404Skarels if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); } 587497Sroot 5937728Smckusick if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 6044404Skarels return (EBADF); 6142863Smckusick if (error = ufalloc(0, &fd)) 6244404Skarels return (error); 6342863Smckusick u.u_ofile[fd] = fp; 6442863Smckusick u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE; 6542863Smckusick fp->f_count++; 6642863Smckusick if (fd > u.u_lastfile) 6742863Smckusick u.u_lastfile = fd; 6842863Smckusick *retval = fd; 6944404Skarels return (0); 707497Sroot } 717497Sroot 7242863Smckusick /* 7342863Smckusick * Duplicate a file descriptor to a particular value. 7442863Smckusick */ 7542863Smckusick /* ARGSUSED */ 7642863Smckusick dup2(p, uap, retval) 7742863Smckusick struct proc *p; 7842863Smckusick register struct args { 7942863Smckusick int i; 8042863Smckusick int j; 8142863Smckusick } *uap; 8242863Smckusick int *retval; 837497Sroot { 847497Sroot register struct file *fp; 8539354Smckusick int error; 867422Sroot 8737728Smckusick if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) 8844404Skarels return (EBADF); 8939354Smckusick if (uap->j < 0 || uap->j >= NOFILE) 9044404Skarels return (EBADF); 9142863Smckusick *retval = uap->j; 927497Sroot if (uap->i == uap->j) 9344404Skarels return (0); 947497Sroot if (u.u_ofile[uap->j]) { 958945Sroot if (u.u_pofile[uap->j] & UF_MAPPED) 968945Sroot munmapfd(uap->j); 9739354Smckusick error = closef(u.u_ofile[uap->j]); 987422Sroot } 9942863Smckusick u.u_ofile[uap->j] = fp; 10042863Smckusick u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE; 10142863Smckusick fp->f_count++; 10242863Smckusick if (uap->j > u.u_lastfile) 10342863Smckusick u.u_lastfile = uap->j; 10439354Smckusick /* 10539354Smckusick * dup2() must succeed even though the close had an error. 10639354Smckusick */ 10739354Smckusick error = 0; /* XXX */ 10844404Skarels return (error); 1097696Ssam } 1107696Ssam 11112748Ssam /* 11212748Ssam * The file control system call. 11312748Ssam */ 11442863Smckusick /* ARGSUSED */ 11542863Smckusick fcntl(p, uap, retval) 11642863Smckusick struct proc *p; 11742863Smckusick register struct args { 11812748Ssam int fdes; 11912748Ssam int cmd; 12012748Ssam int arg; 12142863Smckusick } *uap; 12242863Smckusick int *retval; 12342863Smckusick { 12442863Smckusick register struct file *fp; 12512748Ssam register char *pop; 12642863Smckusick int i, error; 1277497Sroot 12837728Smckusick if ((unsigned)uap->fdes >= NOFILE || 12937728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 13044404Skarels return (EBADF); 13112748Ssam pop = &u.u_pofile[uap->fdes]; 13212748Ssam switch(uap->cmd) { 13315076Skarels case F_DUPFD: 13442863Smckusick if (uap->arg < 0 || uap->arg >= NOFILE) 13544404Skarels return (EINVAL); 13642863Smckusick if (error = ufalloc(uap->arg, &i)) 13744404Skarels return (error); 13842863Smckusick u.u_ofile[i] = fp; 13942863Smckusick u.u_pofile[i] = *pop &~ UF_EXCLOSE; 14042863Smckusick fp->f_count++; 14142863Smckusick if (i > u.u_lastfile) 14242863Smckusick u.u_lastfile = i; 14342863Smckusick *retval = i; 14444404Skarels return (0); 1457497Sroot 14615076Skarels case F_GETFD: 14742863Smckusick *retval = *pop & 1; 14844404Skarels return (0); 1497422Sroot 15015076Skarels case F_SETFD: 15112748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 15244404Skarels return (0); 1538145Sroot 15415076Skarels case F_GETFL: 15542863Smckusick *retval = fp->f_flag + FOPEN; 15644404Skarels return (0); 1578145Sroot 15815076Skarels case F_SETFL: 15912748Ssam fp->f_flag &= FCNTLCANT; 16012748Ssam fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; 16142863Smckusick if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY)) 16244404Skarels return (error); 16342863Smckusick if (error = fset(fp, FASYNC, fp->f_flag & FASYNC)) 16412748Ssam (void) fset(fp, FNDELAY, 0); 16544404Skarels return (error); 1667422Sroot 16715076Skarels case F_GETOWN: 16844404Skarels return (fgetown(fp, retval)); 1697422Sroot 17015076Skarels case F_SETOWN: 17144404Skarels return (fsetown(fp, uap->arg)); 1728115Sroot 17312748Ssam default: 17444404Skarels return (EINVAL); 1757422Sroot } 17642863Smckusick /* NOTREACHED */ 1777422Sroot } 1787422Sroot 17912748Ssam fset(fp, bit, value) 18012748Ssam struct file *fp; 18112748Ssam int bit, value; 1827422Sroot { 1837422Sroot 18412748Ssam if (value) 18512748Ssam fp->f_flag |= bit; 18612748Ssam else 18712748Ssam fp->f_flag &= ~bit; 18812748Ssam return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), 18912748Ssam (caddr_t)&value)); 19012748Ssam } 1917422Sroot 19212748Ssam fgetown(fp, valuep) 19312748Ssam struct file *fp; 19412748Ssam int *valuep; 19512748Ssam { 19612748Ssam int error; 1978115Sroot 19812748Ssam switch (fp->f_type) { 1998115Sroot 20012748Ssam case DTYPE_SOCKET: 20135810Smarc *valuep = ((struct socket *)fp->f_data)->so_pgid; 20212748Ssam return (0); 2037497Sroot 20412748Ssam default: 20512748Ssam error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); 20612748Ssam *valuep = -*valuep; 20712748Ssam return (error); 2087422Sroot } 2097422Sroot } 2107422Sroot 21112748Ssam fsetown(fp, value) 21212748Ssam struct file *fp; 21312748Ssam int value; 2147422Sroot { 21537728Smckusick 21612748Ssam if (fp->f_type == DTYPE_SOCKET) { 21735810Smarc ((struct socket *)fp->f_data)->so_pgid = value; 21812748Ssam return (0); 21912748Ssam } 22012748Ssam if (value > 0) { 22112748Ssam struct proc *p = pfind(value); 22212748Ssam if (p == 0) 22328201Skarels return (ESRCH); 22435810Smarc value = p->p_pgrp->pg_id; 22512748Ssam } else 22612748Ssam value = -value; 22712748Ssam return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); 2287422Sroot } 2297422Sroot 23012748Ssam fioctl(fp, cmd, value) 23112748Ssam struct file *fp; 23212748Ssam int cmd; 23312748Ssam caddr_t value; 2347422Sroot { 2357422Sroot 23612748Ssam return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); 2377422Sroot } 2387422Sroot 23942863Smckusick /* 24042863Smckusick * Close a file descriptor. 24142863Smckusick */ 24242863Smckusick /* ARGSUSED */ 24342863Smckusick close(p, uap, retval) 24442863Smckusick struct proc *p; 24542863Smckusick struct args { 24642863Smckusick int fdes; 24742863Smckusick } *uap; 24842863Smckusick int *retval; 2498029Sroot { 25012748Ssam register struct file *fp; 25113044Ssam register u_char *pf; 2528029Sroot 25337728Smckusick if ((unsigned)uap->fdes >= NOFILE || 25437728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 25544404Skarels return (EBADF); 25637728Smckusick pf = (u_char *)&u.u_pofile[uap->fdes]; 25713044Ssam if (*pf & UF_MAPPED) 25837728Smckusick munmapfd(uap->fdes); 25937728Smckusick u.u_ofile[uap->fdes] = NULL; 26021101Skarels while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) 26121101Skarels u.u_lastfile--; 26215550Skarels *pf = 0; 26344404Skarels return (closef(fp)); 2648029Sroot } 2658029Sroot 26642863Smckusick /* 26742863Smckusick * Return status information about a file descriptor. 26842863Smckusick */ 26942863Smckusick /* ARGSUSED */ 27042863Smckusick fstat(p, uap, retval) 27142863Smckusick struct proc *p; 27242863Smckusick register struct args { 27342863Smckusick int fdes; 27442863Smckusick struct stat *sb; 27542863Smckusick } *uap; 27642863Smckusick int *retval; 27713044Ssam { 27813044Ssam register struct file *fp; 27913044Ssam struct stat ub; 28042863Smckusick int error; 28113044Ssam 28237728Smckusick if ((unsigned)uap->fdes >= NOFILE || 28337728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 28444404Skarels return (EBADF); 28513044Ssam switch (fp->f_type) { 28613044Ssam 28737728Smckusick case DTYPE_VNODE: 28842863Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub); 28913044Ssam break; 29013044Ssam 29113044Ssam case DTYPE_SOCKET: 29242863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 29313044Ssam break; 29413044Ssam 29513044Ssam default: 29613044Ssam panic("fstat"); 29713044Ssam /*NOTREACHED*/ 29813044Ssam } 29942863Smckusick if (error == 0) 30042863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 30144404Skarels return (error); 30213044Ssam } 30313044Ssam 3047422Sroot /* 3057497Sroot * Allocate a user file descriptor. 3067422Sroot */ 30737728Smckusick ufalloc(want, result) 30837728Smckusick register int want; 30937728Smckusick int *result; 3107422Sroot { 3117497Sroot 31239733Smckusick for (; want < NOFILE; want++) { 31337728Smckusick if (u.u_ofile[want] == NULL) { 31437728Smckusick u.u_pofile[want] = 0; 31537728Smckusick if (want > u.u_lastfile) 31637728Smckusick u.u_lastfile = want; 31739733Smckusick *result = want; 31837728Smckusick return (0); 3197497Sroot } 32039733Smckusick } 32137728Smckusick return (EMFILE); 3227497Sroot } 3237497Sroot 32442863Smckusick /* 32542863Smckusick * Check to see if any user file descriptors are available. 32642863Smckusick */ 32712748Ssam ufavail() 32812748Ssam { 32912748Ssam register int i, avail = 0; 33012748Ssam 33112748Ssam for (i = 0; i < NOFILE; i++) 33212748Ssam if (u.u_ofile[i] == NULL) 33312748Ssam avail++; 33412748Ssam return (avail); 33512748Ssam } 33612748Ssam 3377497Sroot struct file *lastf; 3387497Sroot /* 3397497Sroot * Allocate a user file descriptor 3407497Sroot * and a file structure. 3417497Sroot * Initialize the descriptor 3427497Sroot * to point at the file structure. 3437497Sroot */ 34437728Smckusick falloc(resultfp, resultfd) 34537728Smckusick struct file **resultfp; 34637728Smckusick int *resultfd; 3477497Sroot { 3487422Sroot register struct file *fp; 34937728Smckusick int error, i; 3507422Sroot 35137728Smckusick if (error = ufalloc(0, &i)) 35237728Smckusick return (error); 3537497Sroot if (lastf == 0) 3547497Sroot lastf = file; 3557497Sroot for (fp = lastf; fp < fileNFILE; fp++) 3567497Sroot if (fp->f_count == 0) 3577497Sroot goto slot; 3587497Sroot for (fp = file; fp < lastf; fp++) 3597497Sroot if (fp->f_count == 0) 3607497Sroot goto slot; 3617497Sroot tablefull("file"); 36237728Smckusick return (ENFILE); 3637497Sroot slot: 3647497Sroot u.u_ofile[i] = fp; 36512748Ssam fp->f_count = 1; 36612748Ssam fp->f_data = 0; 3677497Sroot fp->f_offset = 0; 36837728Smckusick fp->f_cred = u.u_cred; 36937728Smckusick crhold(fp->f_cred); 3707497Sroot lastf = fp + 1; 37137728Smckusick if (resultfp) 37237728Smckusick *resultfp = fp; 37337728Smckusick if (resultfd) 37437728Smckusick *resultfd = i; 37537728Smckusick return (0); 3767497Sroot } 37712748Ssam 3787497Sroot /* 3797497Sroot * Internal form of close. 38012748Ssam * Decrement reference count on file structure. 3817497Sroot */ 38213044Ssam closef(fp) 3837497Sroot register struct file *fp; 3847497Sroot { 38539354Smckusick int error; 3867497Sroot 3877422Sroot if (fp == NULL) 38839354Smckusick return (0); 3897497Sroot if (fp->f_count > 1) { 3907497Sroot fp->f_count--; 39139354Smckusick return (0); 3927422Sroot } 39337728Smckusick if (fp->f_count < 1) 39437728Smckusick panic("closef: count < 1"); 39539354Smckusick error = (*fp->f_ops->fo_close)(fp); 39637728Smckusick crfree(fp->f_cred); 3977497Sroot fp->f_count = 0; 39839354Smckusick return (error); 3997422Sroot } 40013044Ssam 40113044Ssam /* 40213044Ssam * Apply an advisory lock on a file descriptor. 40313044Ssam */ 40442863Smckusick /* ARGSUSED */ 40542863Smckusick flock(p, uap, retval) 40642863Smckusick struct proc *p; 40742863Smckusick register struct args { 40837728Smckusick int fdes; 40913044Ssam int how; 41042863Smckusick } *uap; 41142863Smckusick int *retval; 41242863Smckusick { 41313044Ssam register struct file *fp; 41413044Ssam 41537728Smckusick if ((unsigned)uap->fdes >= NOFILE || 41637728Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 41744404Skarels return (EBADF); 41842863Smckusick if (fp->f_type != DTYPE_VNODE) 41944404Skarels return (EOPNOTSUPP); 42013101Ssam if (uap->how & LOCK_UN) { 42137728Smckusick vn_unlock(fp, FSHLOCK|FEXLOCK); 42244404Skarels return (0); 42313044Ssam } 42417434Skarels if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) 42544404Skarels return (0); /* error? */ 42617998Skarels if (uap->how & LOCK_EX) 42717998Skarels uap->how &= ~LOCK_SH; 42813101Ssam /* avoid work... */ 42917998Skarels if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || 43017998Skarels (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) 43144404Skarels return (0); 43244404Skarels return (vn_lock(fp, uap->how)); 43313044Ssam } 43437586Smarc 43537586Smarc /* 43637586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 43737586Smarc * 43837586Smarc * Opening minor device N dup()s the file (if any) connected to file 43937586Smarc * descriptor N belonging to the calling process. Note that this driver 44037586Smarc * consists of only the ``open()'' routine, because all subsequent 44137586Smarc * references to this file will be direct to the other driver. 44237586Smarc */ 44337728Smckusick /* ARGSUSED */ 44437728Smckusick fdopen(dev, mode, type) 44537586Smarc dev_t dev; 44637728Smckusick int mode, type; 44737586Smarc { 44843406Smckusick struct proc *p = u.u_procp; /* XXX */ 44937586Smarc 45037586Smarc /* 45143449Smckusick * XXX Kludge: set p->p_dupfd to contain the value of the 45243406Smckusick * the file descriptor being sought for duplication. The error 45343406Smckusick * return ensures that the vnode for this device will be released 45443406Smckusick * by vn_open. Open will detect this special error and take the 45543406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 45643406Smckusick * will simply report the error. 45737586Smarc */ 45843449Smckusick p->p_dupfd = minor(dev); 45943406Smckusick return (ENODEV); 46043406Smckusick } 46140873Sbostic 46243406Smckusick /* 46343406Smckusick * Duplicate the specified descriptor to a free descriptor. 46443406Smckusick */ 46543406Smckusick dupfdopen(indx, dfd, mode) 46643406Smckusick register int indx, dfd; 46743406Smckusick int mode; 46843406Smckusick { 46943406Smckusick register struct file *wfp; 47043406Smckusick struct file *fp; 47143406Smckusick 47237586Smarc /* 47343406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 47443406Smckusick * of file descriptors, or the fd to be dup'd has already been 47543406Smckusick * closed, reject. Note, check for new == old is necessary as 47643406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 47743406Smckusick * as the new descriptor. 47837586Smarc */ 47943406Smckusick fp = u.u_ofile[indx]; 48040873Sbostic if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL || 48140873Sbostic fp == wfp) 48237586Smarc return (EBADF); 48340873Sbostic 48437586Smarc /* 48540873Sbostic * Check that the mode the file is being opened for is a subset 48640873Sbostic * of the mode of the existing descriptor. 48737586Smarc */ 48843406Smckusick if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 48937586Smarc return (EACCES); 49042863Smckusick u.u_ofile[indx] = wfp; 49142863Smckusick u.u_pofile[indx] = u.u_pofile[dfd]; 49242863Smckusick wfp->f_count++; 49342863Smckusick if (indx > u.u_lastfile) 49442863Smckusick u.u_lastfile = indx; 49543406Smckusick return (0); 49637586Smarc } 497