xref: /csrg-svn/sys/kern/kern_descrip.c (revision 68301)
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