123367Smckusick /*
263170Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993
363170Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923367Smckusick *
1044431Sbostic * %sccs.include.redist.c%
1137728Smckusick *
12*68301Scgd * @(#)kern_descrip.c 8.8 (Berkeley) 02/14/95
1323367Smckusick */
147422Sroot
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/filedesc.h>
1856517Sbostic #include <sys/kernel.h>
1956517Sbostic #include <sys/vnode.h>
2056517Sbostic #include <sys/proc.h>
2156517Sbostic #include <sys/file.h>
2256517Sbostic #include <sys/socket.h>
2356517Sbostic #include <sys/socketvar.h>
2456517Sbostic #include <sys/stat.h>
2556517Sbostic #include <sys/ioctl.h>
2656517Sbostic #include <sys/fcntl.h>
2756517Sbostic #include <sys/malloc.h>
2856517Sbostic #include <sys/syslog.h>
2960413Smckusick #include <sys/unistd.h>
3056517Sbostic #include <sys/resourcevar.h>
317497Sroot
32*68301Scgd #include <sys/mount.h>
33*68301Scgd #include <sys/syscallargs.h>
34*68301Scgd
357422Sroot /*
367497Sroot * Descriptor management.
377422Sroot */
3867732Smckusick struct filelist filehead; /* head of list of open files */
3967732Smckusick int nfiles; /* actual number of open files */
407497Sroot
417497Sroot /*
427497Sroot * System calls on descriptors.
437497Sroot */
4442863Smckusick /* ARGSUSED */
45*68301Scgd int
getdtablesize(p,uap,retval)4642863Smckusick getdtablesize(p, uap, retval)
4742863Smckusick struct proc *p;
48*68301Scgd void *uap;
49*68301Scgd register_t *retval;
507497Sroot {
517497Sroot
5258775Smckusick *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
5344404Skarels return (0);
547497Sroot }
557497Sroot
5642863Smckusick /*
5742863Smckusick * Duplicate a file descriptor.
5842863Smckusick */
5942863Smckusick /* ARGSUSED */
60*68301Scgd int
dup(p,uap,retval)6142863Smckusick dup(p, uap, retval)
6242863Smckusick struct proc *p;
63*68301Scgd struct dup_args /* {
64*68301Scgd syscallarg(u_int) fd;
65*68301Scgd } */ *uap;
66*68301Scgd register_t *retval;
677422Sroot {
6858775Smckusick register struct filedesc *fdp;
6958775Smckusick u_int old;
7058775Smckusick int new, error;
717497Sroot
72*68301Scgd old = SCARG(uap, fd);
7342863Smckusick /*
7442863Smckusick * XXX Compatibility
7542863Smckusick */
76*68301Scgd if (old &~ 077) {
77*68301Scgd SCARG(uap, fd) &= 077;
78*68301Scgd return (dup2(p, uap, retval));
79*68301Scgd }
807497Sroot
8158775Smckusick fdp = p->p_fd;
8258775Smckusick if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
8344404Skarels return (EBADF);
8458775Smckusick if (error = fdalloc(p, 0, &new))
8544404Skarels return (error);
8658775Smckusick return (finishdup(fdp, (int)old, new, retval));
877497Sroot }
887497Sroot
8942863Smckusick /*
9042863Smckusick * Duplicate a file descriptor to a particular value.
9142863Smckusick */
9242863Smckusick /* ARGSUSED */
93*68301Scgd int
dup2(p,uap,retval)9442863Smckusick dup2(p, uap, retval)
9542863Smckusick struct proc *p;
96*68301Scgd struct dup2_args /* {
97*68301Scgd syscallarg(u_int) from;
98*68301Scgd syscallarg(u_int) to;
99*68301Scgd } */ *uap;
100*68301Scgd register_t *retval;
1017497Sroot {
10245914Smckusick register struct filedesc *fdp = p->p_fd;
103*68301Scgd register int old = SCARG(uap, from), new = SCARG(uap, to);
10445914Smckusick int i, error;
1057422Sroot
10647653Skarels if (old >= fdp->fd_nfiles ||
10758775Smckusick fdp->fd_ofiles[old] == NULL ||
10858656Smckusick new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
10958775Smckusick new >= maxfiles)
11044404Skarels return (EBADF);
11158775Smckusick if (old == new) {
11258775Smckusick *retval = new;
11344404Skarels return (0);
11458775Smckusick }
11547653Skarels if (new >= fdp->fd_nfiles) {
11647653Skarels if (error = fdalloc(p, new, &i))
11745914Smckusick return (error);
11847653Skarels if (new != i)
11947540Skarels panic("dup2: fdalloc");
12047653Skarels } else if (fdp->fd_ofiles[new]) {
12147653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED)
12247653Skarels (void) munmapfd(p, new);
12347653Skarels /*
12447653Skarels * dup2() must succeed even if the close has an error.
12547653Skarels */
12647653Skarels (void) closef(fdp->fd_ofiles[new], p);
1277422Sroot }
12858775Smckusick return (finishdup(fdp, (int)old, (int)new, retval));
1297696Ssam }
1307696Ssam
13112748Ssam /*
13212748Ssam * The file control system call.
13312748Ssam */
13442863Smckusick /* ARGSUSED */
135*68301Scgd int
fcntl(p,uap,retval)13642863Smckusick fcntl(p, uap, retval)
13742863Smckusick struct proc *p;
138*68301Scgd register struct fcntl_args /* {
139*68301Scgd syscallarg(int) fd;
140*68301Scgd syscallarg(int) cmd;
141*68301Scgd syscallarg(void *) arg;
142*68301Scgd } */ *uap;
143*68301Scgd register_t *retval;
14442863Smckusick {
145*68301Scgd int fd = SCARG(uap, fd);
14645914Smckusick register struct filedesc *fdp = p->p_fd;
14742863Smckusick register struct file *fp;
14812748Ssam register char *pop;
14946200Smckusick struct vnode *vp;
15048029Smckusick int i, tmp, error, flg = F_POSIX;
15146200Smckusick struct flock fl;
15258775Smckusick u_int newmin;
1537497Sroot
154*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
155*68301Scgd (fp = fdp->fd_ofiles[fd]) == NULL)
15644404Skarels return (EBADF);
157*68301Scgd pop = &fdp->fd_ofileflags[fd];
158*68301Scgd switch (SCARG(uap, cmd)) {
15958775Smckusick
16015076Skarels case F_DUPFD:
161*68301Scgd newmin = (long)SCARG(uap, arg);
16258775Smckusick if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
16358775Smckusick newmin >= maxfiles)
16444404Skarels return (EINVAL);
16558775Smckusick if (error = fdalloc(p, newmin, &i))
16644404Skarels return (error);
167*68301Scgd return (finishdup(fdp, fd, i, retval));
1687497Sroot
16915076Skarels case F_GETFD:
17042863Smckusick *retval = *pop & 1;
17144404Skarels return (0);
1727422Sroot
17315076Skarels case F_SETFD:
174*68301Scgd *pop = (*pop &~ 1) | ((long)SCARG(uap, arg) & 1);
17544404Skarels return (0);
1768145Sroot
17715076Skarels case F_GETFL:
17846495Skarels *retval = OFLAGS(fp->f_flag);
17944404Skarels return (0);
1808145Sroot
18115076Skarels case F_SETFL:
18246495Skarels fp->f_flag &= ~FCNTLFLAGS;
183*68301Scgd fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
18449940Smckusick tmp = fp->f_flag & FNONBLOCK;
18548029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
18648029Smckusick if (error)
18744404Skarels return (error);
18849940Smckusick tmp = fp->f_flag & FASYNC;
18948029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
19048029Smckusick if (!error)
19148029Smckusick return (0);
19249940Smckusick fp->f_flag &= ~FNONBLOCK;
19348029Smckusick tmp = 0;
19448029Smckusick (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
19544404Skarels return (error);
1967422Sroot
19715076Skarels case F_GETOWN:
19848029Smckusick if (fp->f_type == DTYPE_SOCKET) {
19948029Smckusick *retval = ((struct socket *)fp->f_data)->so_pgid;
20048029Smckusick return (0);
20148029Smckusick }
20248029Smckusick error = (*fp->f_ops->fo_ioctl)
203*68301Scgd (fp, TIOCGPGRP, (caddr_t)retval, p);
20448029Smckusick *retval = -*retval;
20548029Smckusick return (error);
2067422Sroot
20715076Skarels case F_SETOWN:
20848029Smckusick if (fp->f_type == DTYPE_SOCKET) {
209*68301Scgd ((struct socket *)fp->f_data)->so_pgid =
210*68301Scgd (long)SCARG(uap, arg);
21148029Smckusick return (0);
21248029Smckusick }
213*68301Scgd if ((long)SCARG(uap, arg) <= 0) {
214*68301Scgd SCARG(uap, arg) = (void *)(-(long)SCARG(uap, arg));
21548029Smckusick } else {
216*68301Scgd struct proc *p1 = pfind((long)SCARG(uap, arg));
21748029Smckusick if (p1 == 0)
21848029Smckusick return (ESRCH);
219*68301Scgd SCARG(uap, arg) = (void *)(long)p1->p_pgrp->pg_id;
22048029Smckusick }
22148029Smckusick return ((*fp->f_ops->fo_ioctl)
222*68301Scgd (fp, TIOCSPGRP, (caddr_t)&SCARG(uap, arg), p));
2238115Sroot
22446200Smckusick case F_SETLKW:
22548029Smckusick flg |= F_WAIT;
22646200Smckusick /* Fall into F_SETLK */
22746200Smckusick
22846200Smckusick case F_SETLK:
22946200Smckusick if (fp->f_type != DTYPE_VNODE)
23046200Smckusick return (EBADF);
23146200Smckusick vp = (struct vnode *)fp->f_data;
23246200Smckusick /* Copy in the lock structure */
233*68301Scgd error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
234*68301Scgd sizeof (fl));
23546200Smckusick if (error)
23646200Smckusick return (error);
23746200Smckusick if (fl.l_whence == SEEK_CUR)
23846200Smckusick fl.l_start += fp->f_offset;
23946200Smckusick switch (fl.l_type) {
24046200Smckusick
24146200Smckusick case F_RDLCK:
24246200Smckusick if ((fp->f_flag & FREAD) == 0)
24346200Smckusick return (EBADF);
24464593Sbostic p->p_flag |= P_ADVLOCK;
24548029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
24646200Smckusick
24746200Smckusick case F_WRLCK:
24846200Smckusick if ((fp->f_flag & FWRITE) == 0)
24946200Smckusick return (EBADF);
25064593Sbostic p->p_flag |= P_ADVLOCK;
25148029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
25246200Smckusick
25346200Smckusick case F_UNLCK:
25448029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
25548029Smckusick F_POSIX));
25646200Smckusick
25746200Smckusick default:
25846200Smckusick return (EINVAL);
25946200Smckusick }
26046200Smckusick
26146200Smckusick case F_GETLK:
26246200Smckusick if (fp->f_type != DTYPE_VNODE)
26346200Smckusick return (EBADF);
26446200Smckusick vp = (struct vnode *)fp->f_data;
26546200Smckusick /* Copy in the lock structure */
266*68301Scgd error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
267*68301Scgd sizeof (fl));
26846200Smckusick if (error)
26946200Smckusick return (error);
27046765Smckusick if (fl.l_whence == SEEK_CUR)
27146765Smckusick fl.l_start += fp->f_offset;
27248029Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
27346200Smckusick return (error);
274*68301Scgd return (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg),
275*68301Scgd sizeof (fl)));
27646200Smckusick
27712748Ssam default:
27844404Skarels return (EINVAL);
2797422Sroot }
28042863Smckusick /* NOTREACHED */
2817422Sroot }
2827422Sroot
28342863Smckusick /*
28458775Smckusick * Common code for dup, dup2, and fcntl(F_DUPFD).
28558775Smckusick */
28658775Smckusick int
finishdup(fdp,old,new,retval)28758775Smckusick finishdup(fdp, old, new, retval)
28858775Smckusick register struct filedesc *fdp;
289*68301Scgd register int old, new;
290*68301Scgd register_t *retval;
29158775Smckusick {
29258775Smckusick register struct file *fp;
29358775Smckusick
29458775Smckusick fp = fdp->fd_ofiles[old];
29558775Smckusick fdp->fd_ofiles[new] = fp;
29658775Smckusick fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
29758775Smckusick fp->f_count++;
29858775Smckusick if (new > fdp->fd_lastfile)
29958775Smckusick fdp->fd_lastfile = new;
30058775Smckusick *retval = new;
30158775Smckusick return (0);
30258775Smckusick }
30358775Smckusick
30458775Smckusick /*
30542863Smckusick * Close a file descriptor.
30642863Smckusick */
30742863Smckusick /* ARGSUSED */
308*68301Scgd int
close(p,uap,retval)30942863Smckusick close(p, uap, retval)
31042863Smckusick struct proc *p;
311*68301Scgd struct close_args /* {
312*68301Scgd syscallarg(int) fd;
313*68301Scgd } */ *uap;
314*68301Scgd register_t *retval;
3158029Sroot {
316*68301Scgd int fd = SCARG(uap, fd);
31745914Smckusick register struct filedesc *fdp = p->p_fd;
31812748Ssam register struct file *fp;
31913044Ssam register u_char *pf;
3208029Sroot
321*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
32247653Skarels (fp = fdp->fd_ofiles[fd]) == NULL)
32344404Skarels return (EBADF);
32447653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd];
32513044Ssam if (*pf & UF_MAPPED)
32647540Skarels (void) munmapfd(p, fd);
32747653Skarels fdp->fd_ofiles[fd] = NULL;
32847653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
32945914Smckusick fdp->fd_lastfile--;
33047540Skarels if (fd < fdp->fd_freefile)
33147540Skarels fdp->fd_freefile = fd;
33215550Skarels *pf = 0;
33347540Skarels return (closef(fp, p));
3348029Sroot }
3358029Sroot
33654346Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
33742863Smckusick /*
33842863Smckusick * Return status information about a file descriptor.
33942863Smckusick */
34042863Smckusick /* ARGSUSED */
341*68301Scgd int
compat_43_fstat(p,uap,retval)342*68301Scgd compat_43_fstat(p, uap, retval)
34342863Smckusick struct proc *p;
344*68301Scgd register struct compat_43_fstat_args /* {
345*68301Scgd syscallarg(int) fd;
346*68301Scgd syscallarg(struct ostat *) sb;
347*68301Scgd } */ *uap;
348*68301Scgd register_t *retval;
34953466Smckusick {
350*68301Scgd int fd = SCARG(uap, fd);
35153466Smckusick register struct filedesc *fdp = p->p_fd;
35253466Smckusick register struct file *fp;
35353466Smckusick struct stat ub;
35453466Smckusick struct ostat oub;
35553466Smckusick int error;
35653466Smckusick
357*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
358*68301Scgd (fp = fdp->fd_ofiles[fd]) == NULL)
35953466Smckusick return (EBADF);
36053466Smckusick switch (fp->f_type) {
36153466Smckusick
36253466Smckusick case DTYPE_VNODE:
36353466Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p);
36453466Smckusick break;
36553466Smckusick
36653466Smckusick case DTYPE_SOCKET:
36753466Smckusick error = soo_stat((struct socket *)fp->f_data, &ub);
36853466Smckusick break;
36953466Smckusick
37053466Smckusick default:
37154346Smckusick panic("ofstat");
37253466Smckusick /*NOTREACHED*/
37353466Smckusick }
37453466Smckusick cvtstat(&ub, &oub);
37553466Smckusick if (error == 0)
376*68301Scgd error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
377*68301Scgd sizeof (oub));
37853466Smckusick return (error);
37953466Smckusick }
38054346Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
38153466Smckusick
38253466Smckusick /*
38353466Smckusick * Return status information about a file descriptor.
38453466Smckusick */
38553466Smckusick /* ARGSUSED */
386*68301Scgd int
fstat(p,uap,retval)38753758Smckusick fstat(p, uap, retval)
38853466Smckusick struct proc *p;
389*68301Scgd register struct fstat_args /* {
390*68301Scgd syscallarg(int) fd;
391*68301Scgd syscallarg(struct stat *) sb;
392*68301Scgd } */ *uap;
393*68301Scgd register_t *retval;
39413044Ssam {
395*68301Scgd int fd = SCARG(uap, fd);
39645914Smckusick register struct filedesc *fdp = p->p_fd;
39713044Ssam register struct file *fp;
39813044Ssam struct stat ub;
39942863Smckusick int error;
40013044Ssam
401*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
402*68301Scgd (fp = fdp->fd_ofiles[fd]) == NULL)
40344404Skarels return (EBADF);
40413044Ssam switch (fp->f_type) {
40513044Ssam
40637728Smckusick case DTYPE_VNODE:
40748029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p);
40813044Ssam break;
40913044Ssam
41013044Ssam case DTYPE_SOCKET:
41142863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub);
41213044Ssam break;
41313044Ssam
41413044Ssam default:
41513044Ssam panic("fstat");
41613044Ssam /*NOTREACHED*/
41713044Ssam }
41842863Smckusick if (error == 0)
419*68301Scgd error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
420*68301Scgd sizeof (ub));
42144404Skarels return (error);
42213044Ssam }
42313044Ssam
4247422Sroot /*
42560413Smckusick * Return pathconf information about a file descriptor.
42660413Smckusick */
42760413Smckusick /* ARGSUSED */
428*68301Scgd int
fpathconf(p,uap,retval)42960413Smckusick fpathconf(p, uap, retval)
43060413Smckusick struct proc *p;
431*68301Scgd register struct fpathconf_args /* {
432*68301Scgd syscallarg(int) fd;
433*68301Scgd syscallarg(int) name;
434*68301Scgd } */ *uap;
435*68301Scgd register_t *retval;
43660413Smckusick {
437*68301Scgd int fd = SCARG(uap, fd);
43860413Smckusick struct filedesc *fdp = p->p_fd;
43960413Smckusick struct file *fp;
44060413Smckusick struct vnode *vp;
44160413Smckusick
442*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
443*68301Scgd (fp = fdp->fd_ofiles[fd]) == NULL)
44460413Smckusick return (EBADF);
44560413Smckusick switch (fp->f_type) {
44660413Smckusick
44760413Smckusick case DTYPE_SOCKET:
448*68301Scgd if (SCARG(uap, name) != _PC_PIPE_BUF)
44960413Smckusick return (EINVAL);
45060413Smckusick *retval = PIPE_BUF;
45160413Smckusick return (0);
45260413Smckusick
45360413Smckusick case DTYPE_VNODE:
45460413Smckusick vp = (struct vnode *)fp->f_data;
455*68301Scgd return (VOP_PATHCONF(vp, SCARG(uap, name), retval));
45660413Smckusick
45760413Smckusick default:
45860413Smckusick panic("fpathconf");
45960413Smckusick }
46060413Smckusick /*NOTREACHED*/
46160413Smckusick }
46260413Smckusick
46360413Smckusick /*
46447540Skarels * Allocate a file descriptor for the process.
4657422Sroot */
46647540Skarels int fdexpand;
46745914Smckusick
468*68301Scgd int
fdalloc(p,want,result)46947540Skarels fdalloc(p, want, result)
47047540Skarels struct proc *p;
47147540Skarels int want;
47237728Smckusick int *result;
4737422Sroot {
47447540Skarels register struct filedesc *fdp = p->p_fd;
47547540Skarels register int i;
47647540Skarels int lim, last, nfiles;
47745914Smckusick struct file **newofile;
47845914Smckusick char *newofileflags;
4797497Sroot
48047540Skarels /*
48147540Skarels * Search for a free descriptor starting at the higher
48247540Skarels * of want or fd_freefile. If that fails, consider
48347540Skarels * expanding the ofile array.
48447540Skarels */
48558775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
48645914Smckusick for (;;) {
48747540Skarels last = min(fdp->fd_nfiles, lim);
48847540Skarels if ((i = want) < fdp->fd_freefile)
48947540Skarels i = fdp->fd_freefile;
49047540Skarels for (; i < last; i++) {
49147653Skarels if (fdp->fd_ofiles[i] == NULL) {
49247653Skarels fdp->fd_ofileflags[i] = 0;
49347540Skarels if (i > fdp->fd_lastfile)
49447540Skarels fdp->fd_lastfile = i;
49547653Skarels if (want <= fdp->fd_freefile)
49647540Skarels fdp->fd_freefile = i;
49747540Skarels *result = i;
49845914Smckusick return (0);
49945914Smckusick }
5007497Sroot }
50147540Skarels
50247540Skarels /*
50347540Skarels * No space in current array. Expand?
50447540Skarels */
50547540Skarels if (fdp->fd_nfiles >= lim)
50645914Smckusick return (EMFILE);
50747653Skarels if (fdp->fd_nfiles < NDEXTENT)
50847653Skarels nfiles = NDEXTENT;
50947653Skarels else
51047653Skarels nfiles = 2 * fdp->fd_nfiles;
51147540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE,
51247540Skarels M_FILEDESC, M_WAITOK);
51347540Skarels newofileflags = (char *) &newofile[nfiles];
51447540Skarels /*
51547540Skarels * Copy the existing ofile and ofileflags arrays
51647540Skarels * and zero the new portion of each array.
51747540Skarels */
51847540Skarels bcopy(fdp->fd_ofiles, newofile,
51947540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles));
52047540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
52147540Skarels bcopy(fdp->fd_ofileflags, newofileflags,
52247540Skarels (i = sizeof(char) * fdp->fd_nfiles));
52347540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i);
52447653Skarels if (fdp->fd_nfiles > NDFILE)
52547653Skarels FREE(fdp->fd_ofiles, M_FILEDESC);
52647540Skarels fdp->fd_ofiles = newofile;
52747540Skarels fdp->fd_ofileflags = newofileflags;
52847540Skarels fdp->fd_nfiles = nfiles;
52947540Skarels fdexpand++;
53039733Smckusick }
5317497Sroot }
5327497Sroot
53342863Smckusick /*
53447653Skarels * Check to see whether n user file descriptors
53547653Skarels * are available to the process p.
53642863Smckusick */
537*68301Scgd int
fdavail(p,n)53847540Skarels fdavail(p, n)
53947540Skarels struct proc *p;
54047540Skarels register int n;
54112748Ssam {
54247540Skarels register struct filedesc *fdp = p->p_fd;
54347653Skarels register struct file **fpp;
54458775Smckusick register int i, lim;
54512748Ssam
54658775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
54758775Smckusick if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
54847540Skarels return (1);
54947653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile];
55047653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
55147653Skarels if (*fpp == NULL && --n <= 0)
55247540Skarels return (1);
55347540Skarels return (0);
55412748Ssam }
55512748Ssam
5567497Sroot /*
55747540Skarels * Create a new open file structure and allocate
55847540Skarels * a file decriptor for the process that refers to it.
5597497Sroot */
560*68301Scgd int
falloc(p,resultfp,resultfd)56145914Smckusick falloc(p, resultfp, resultfd)
56245914Smckusick register struct proc *p;
56337728Smckusick struct file **resultfp;
56437728Smckusick int *resultfd;
5657497Sroot {
56667732Smckusick register struct file *fp, *fq;
56737728Smckusick int error, i;
5687422Sroot
56947540Skarels if (error = fdalloc(p, 0, &i))
57037728Smckusick return (error);
57149981Smckusick if (nfiles >= maxfiles) {
57249981Smckusick tablefull("file");
57349981Smckusick return (ENFILE);
57449981Smckusick }
57549981Smckusick /*
57649981Smckusick * Allocate a new file descriptor.
57749981Smckusick * If the process has file descriptor zero open, add to the list
57849981Smckusick * of open files at that point, otherwise put it at the front of
57949981Smckusick * the list of open files.
58049981Smckusick */
58149981Smckusick nfiles++;
58249981Smckusick MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
58367007Smckusick bzero(fp, sizeof(struct file));
58467732Smckusick if (fq = p->p_fd->fd_ofiles[0]) {
58567732Smckusick LIST_INSERT_AFTER(fq, fp, f_list);
58667732Smckusick } else {
58767732Smckusick LIST_INSERT_HEAD(&filehead, fp, f_list);
58867732Smckusick }
58950129Smckusick p->p_fd->fd_ofiles[i] = fp;
59012748Ssam fp->f_count = 1;
59147540Skarels fp->f_cred = p->p_ucred;
59237728Smckusick crhold(fp->f_cred);
59337728Smckusick if (resultfp)
59437728Smckusick *resultfp = fp;
59537728Smckusick if (resultfd)
59637728Smckusick *resultfd = i;
59737728Smckusick return (0);
5987497Sroot }
59912748Ssam
6007497Sroot /*
60149981Smckusick * Free a file descriptor.
60249981Smckusick */
603*68301Scgd void
ffree(fp)60449981Smckusick ffree(fp)
60549981Smckusick register struct file *fp;
60649981Smckusick {
60749981Smckusick register struct file *fq;
60849981Smckusick
60967732Smckusick LIST_REMOVE(fp, f_list);
61049981Smckusick crfree(fp->f_cred);
61149981Smckusick #ifdef DIAGNOSTIC
61249981Smckusick fp->f_count = 0;
61349981Smckusick #endif
61449981Smckusick nfiles--;
61549981Smckusick FREE(fp, M_FILE);
61649981Smckusick }
61749981Smckusick
61849981Smckusick /*
61947540Skarels * Copy a filedesc structure.
62045914Smckusick */
62145914Smckusick struct filedesc *
fdcopy(p)62247540Skarels fdcopy(p)
62347540Skarels struct proc *p;
62445914Smckusick {
62547653Skarels register struct filedesc *newfdp, *fdp = p->p_fd;
62647653Skarels register struct file **fpp;
62745914Smckusick register int i;
62845914Smckusick
62947653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
63047653Skarels M_FILEDESC, M_WAITOK);
63147653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc));
63245914Smckusick VREF(newfdp->fd_cdir);
63345914Smckusick if (newfdp->fd_rdir)
63445914Smckusick VREF(newfdp->fd_rdir);
63545914Smckusick newfdp->fd_refcnt = 1;
63647540Skarels
63747540Skarels /*
63847653Skarels * If the number of open files fits in the internal arrays
63947653Skarels * of the open file structure, use them, otherwise allocate
64047653Skarels * additional memory for the number of descriptors currently
64147653Skarels * in use.
64247540Skarels */
64347653Skarels if (newfdp->fd_lastfile < NDFILE) {
64447653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
64547653Skarels newfdp->fd_ofileflags =
64647653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags;
64747653Skarels i = NDFILE;
64847653Skarels } else {
64947653Skarels /*
65047653Skarels * Compute the smallest multiple of NDEXTENT needed
65147653Skarels * for the file descriptors currently in use,
65247653Skarels * allowing the table to shrink.
65347653Skarels */
65447653Skarels i = newfdp->fd_nfiles;
65565547Smckusick while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
65647653Skarels i /= 2;
65747653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
65847653Skarels M_FILEDESC, M_WAITOK);
65947653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
66047653Skarels }
66147540Skarels newfdp->fd_nfiles = i;
66247540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
66347540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
66447653Skarels fpp = newfdp->fd_ofiles;
66547653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
66647653Skarels if (*fpp != NULL)
66747653Skarels (*fpp)->f_count++;
66845914Smckusick return (newfdp);
66945914Smckusick }
67045914Smckusick
67145914Smckusick /*
67245914Smckusick * Release a filedesc structure.
67345914Smckusick */
67447653Skarels void
fdfree(p)67547540Skarels fdfree(p)
67647540Skarels struct proc *p;
67745914Smckusick {
67847540Skarels register struct filedesc *fdp = p->p_fd;
67947653Skarels struct file **fpp;
68045914Smckusick register int i;
68145914Smckusick
68247540Skarels if (--fdp->fd_refcnt > 0)
68345914Smckusick return;
68447653Skarels fpp = fdp->fd_ofiles;
68547653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
68647653Skarels if (*fpp)
68747653Skarels (void) closef(*fpp, p);
68847653Skarels if (fdp->fd_nfiles > NDFILE)
68947653Skarels FREE(fdp->fd_ofiles, M_FILEDESC);
69045914Smckusick vrele(fdp->fd_cdir);
69145914Smckusick if (fdp->fd_rdir)
69245914Smckusick vrele(fdp->fd_rdir);
69347540Skarels FREE(fdp, M_FILEDESC);
69445914Smckusick }
69545914Smckusick
69645914Smckusick /*
6977497Sroot * Internal form of close.
69812748Ssam * Decrement reference count on file structure.
69952034Skarels * Note: p may be NULL when closing a file
70052034Skarels * that was being passed in a message.
7017497Sroot */
702*68301Scgd int
closef(fp,p)70347540Skarels closef(fp, p)
7047497Sroot register struct file *fp;
70549981Smckusick register struct proc *p;
7067497Sroot {
70746200Smckusick struct vnode *vp;
70846200Smckusick struct flock lf;
70939354Smckusick int error;
7107497Sroot
7117422Sroot if (fp == NULL)
71239354Smckusick return (0);
71346200Smckusick /*
71446200Smckusick * POSIX record locking dictates that any close releases ALL
71546200Smckusick * locks owned by this process. This is handled by setting
71646200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX
71746200Smckusick * semantics, and not to free BSD-style file locks.
71852034Skarels * If the descriptor was in a message, POSIX-style locks
71952034Skarels * aren't passed with the descriptor.
72046200Smckusick */
72164593Sbostic if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
72246200Smckusick lf.l_whence = SEEK_SET;
72346200Smckusick lf.l_start = 0;
72446200Smckusick lf.l_len = 0;
72546200Smckusick lf.l_type = F_UNLCK;
72646200Smckusick vp = (struct vnode *)fp->f_data;
72748029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
72846200Smckusick }
72947540Skarels if (--fp->f_count > 0)
73039354Smckusick return (0);
73147540Skarels if (fp->f_count < 0)
73247540Skarels panic("closef: count < 0");
73349951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
73449951Smckusick lf.l_whence = SEEK_SET;
73549951Smckusick lf.l_start = 0;
73649951Smckusick lf.l_len = 0;
73749951Smckusick lf.l_type = F_UNLCK;
73849951Smckusick vp = (struct vnode *)fp->f_data;
73948029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
74049951Smckusick }
74167007Smckusick if (fp->f_ops)
74267007Smckusick error = (*fp->f_ops->fo_close)(fp, p);
74367007Smckusick else
74467007Smckusick error = 0;
74549981Smckusick ffree(fp);
74639354Smckusick return (error);
7477422Sroot }
74813044Ssam
74913044Ssam /*
75013044Ssam * Apply an advisory lock on a file descriptor.
75146200Smckusick *
75246200Smckusick * Just attempt to get a record lock of the requested type on
75346200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
75413044Ssam */
75542863Smckusick /* ARGSUSED */
756*68301Scgd int
flock(p,uap,retval)75742863Smckusick flock(p, uap, retval)
75842863Smckusick struct proc *p;
759*68301Scgd register struct flock_args /* {
760*68301Scgd syscallarg(int) fd;
761*68301Scgd syscallarg(int) how;
762*68301Scgd } */ *uap;
763*68301Scgd register_t *retval;
76442863Smckusick {
765*68301Scgd int fd = SCARG(uap, fd);
766*68301Scgd int how = SCARG(uap, how);
76745914Smckusick register struct filedesc *fdp = p->p_fd;
76813044Ssam register struct file *fp;
76946200Smckusick struct vnode *vp;
77046200Smckusick struct flock lf;
77113044Ssam
772*68301Scgd if ((u_int)fd >= fdp->fd_nfiles ||
773*68301Scgd (fp = fdp->fd_ofiles[fd]) == NULL)
77444404Skarels return (EBADF);
77542863Smckusick if (fp->f_type != DTYPE_VNODE)
77644404Skarels return (EOPNOTSUPP);
77746200Smckusick vp = (struct vnode *)fp->f_data;
77846200Smckusick lf.l_whence = SEEK_SET;
77946200Smckusick lf.l_start = 0;
78046200Smckusick lf.l_len = 0;
781*68301Scgd if (how & LOCK_UN) {
78246200Smckusick lf.l_type = F_UNLCK;
78349951Smckusick fp->f_flag &= ~FHASLOCK;
78448029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
78513044Ssam }
786*68301Scgd if (how & LOCK_EX)
78746200Smckusick lf.l_type = F_WRLCK;
788*68301Scgd else if (how & LOCK_SH)
78946200Smckusick lf.l_type = F_RDLCK;
79046200Smckusick else
79146200Smckusick return (EBADF);
79249951Smckusick fp->f_flag |= FHASLOCK;
793*68301Scgd if (how & LOCK_NB)
79448029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
79548029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
79613044Ssam }
79737586Smarc
79837586Smarc /*
79937586Smarc * File Descriptor pseudo-device driver (/dev/fd/).
80037586Smarc *
80137586Smarc * Opening minor device N dup()s the file (if any) connected to file
80237586Smarc * descriptor N belonging to the calling process. Note that this driver
80337586Smarc * consists of only the ``open()'' routine, because all subsequent
80437586Smarc * references to this file will be direct to the other driver.
80537586Smarc */
80637728Smckusick /* ARGSUSED */
807*68301Scgd int
fdopen(dev,mode,type,p)80852568Smckusick fdopen(dev, mode, type, p)
80937586Smarc dev_t dev;
81037728Smckusick int mode, type;
81152568Smckusick struct proc *p;
81237586Smarc {
81337586Smarc
81437586Smarc /*
81547540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the
81643406Smckusick * the file descriptor being sought for duplication. The error
81743406Smckusick * return ensures that the vnode for this device will be released
81843406Smckusick * by vn_open. Open will detect this special error and take the
81943406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
82043406Smckusick * will simply report the error.
82137586Smarc */
82252568Smckusick p->p_dupfd = minor(dev);
82343406Smckusick return (ENODEV);
82443406Smckusick }
82540873Sbostic
82643406Smckusick /*
82743406Smckusick * Duplicate the specified descriptor to a free descriptor.
82843406Smckusick */
829*68301Scgd int
dupfdopen(fdp,indx,dfd,mode,error)83053826Spendry dupfdopen(fdp, indx, dfd, mode, error)
83145914Smckusick register struct filedesc *fdp;
83243406Smckusick register int indx, dfd;
83343406Smckusick int mode;
83453826Spendry int error;
83543406Smckusick {
83643406Smckusick register struct file *wfp;
83743406Smckusick struct file *fp;
838*68301Scgd
83937586Smarc /*
84043406Smckusick * If the to-be-dup'd fd number is greater than the allowed number
84143406Smckusick * of file descriptors, or the fd to be dup'd has already been
84243406Smckusick * closed, reject. Note, check for new == old is necessary as
84343406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor
84443406Smckusick * as the new descriptor.
84537586Smarc */
84647653Skarels fp = fdp->fd_ofiles[indx];
84747653Skarels if ((u_int)dfd >= fdp->fd_nfiles ||
84847653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
84937586Smarc return (EBADF);
85040873Sbostic
85137586Smarc /*
85253826Spendry * There are two cases of interest here.
85353826Spendry *
85453826Spendry * For ENODEV simply dup (dfd) to file descriptor
85553826Spendry * (indx) and return.
85653826Spendry *
85753826Spendry * For ENXIO steal away the file structure from (dfd) and
85853826Spendry * store it in (indx). (dfd) is effectively closed by
85953826Spendry * this operation.
86053826Spendry *
86153826Spendry * Any other error code is just returned.
86237586Smarc */
86353826Spendry switch (error) {
86453826Spendry case ENODEV:
86553826Spendry /*
86653826Spendry * Check that the mode the file is being opened for is a
86753826Spendry * subset of the mode of the existing descriptor.
86853826Spendry */
86953826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
87053826Spendry return (EACCES);
87153826Spendry fdp->fd_ofiles[indx] = wfp;
87253826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
87353826Spendry wfp->f_count++;
87453826Spendry if (indx > fdp->fd_lastfile)
87553826Spendry fdp->fd_lastfile = indx;
87653826Spendry return (0);
87753826Spendry
87853826Spendry case ENXIO:
87953826Spendry /*
88053826Spendry * Steal away the file pointer from dfd, and stuff it into indx.
88153826Spendry */
88253826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
88353826Spendry fdp->fd_ofiles[dfd] = NULL;
88453826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
88553826Spendry fdp->fd_ofileflags[dfd] = 0;
88653826Spendry /*
88753826Spendry * Complete the clean up of the filedesc structure by
88853826Spendry * recomputing the various hints.
88953826Spendry */
89053826Spendry if (indx > fdp->fd_lastfile)
89153826Spendry fdp->fd_lastfile = indx;
89253826Spendry else
89353826Spendry while (fdp->fd_lastfile > 0 &&
89453826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
89553826Spendry fdp->fd_lastfile--;
89653826Spendry if (dfd < fdp->fd_freefile)
89753826Spendry fdp->fd_freefile = dfd;
89853826Spendry return (0);
89953826Spendry
90053826Spendry default:
90153826Spendry return (error);
90253826Spendry }
90353826Spendry /* NOTREACHED */
90437586Smarc }
905