xref: /csrg-svn/sys/kern/kern_descrip.c (revision 47653)
123367Smckusick /*
2*47653Skarels  * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
337728Smckusick  * All rights reserved.
423367Smckusick  *
544431Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*47653Skarels  *	@(#)kern_descrip.c	7.22 (Berkeley) 03/25/91
823367Smckusick  */
97422Sroot 
1017089Sbloom #include "param.h"
1117089Sbloom #include "systm.h"
1245914Smckusick #include "filedesc.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"
2146200Smckusick #include "fcntl.h"
2245914Smckusick #include "malloc.h"
2345914Smckusick #include "syslog.h"
24*47653Skarels #include "resourcevar.h"
257497Sroot 
267422Sroot /*
277497Sroot  * Descriptor management.
287422Sroot  */
297497Sroot 
307497Sroot /*
317497Sroot  * System calls on descriptors.
327497Sroot  */
3342863Smckusick /* ARGSUSED */
3442863Smckusick getdtablesize(p, uap, retval)
3542863Smckusick 	struct proc *p;
3642863Smckusick 	struct args *uap;
3742863Smckusick 	int *retval;
387497Sroot {
397497Sroot 
4047540Skarels 	*retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
4144404Skarels 	return (0);
427497Sroot }
437497Sroot 
4442863Smckusick /*
4542863Smckusick  * Duplicate a file descriptor.
4642863Smckusick  */
4742863Smckusick /* ARGSUSED */
4842863Smckusick dup(p, uap, retval)
4942863Smckusick 	struct proc *p;
5042863Smckusick 	struct args {
5142863Smckusick 		int	i;
5242863Smckusick 	} *uap;
5342863Smckusick 	int *retval;
547422Sroot {
5545914Smckusick 	register struct filedesc *fdp = p->p_fd;
567696Ssam 	struct file *fp;
5742863Smckusick 	int fd, error;
587497Sroot 
5942863Smckusick 	/*
6042863Smckusick 	 * XXX Compatibility
6142863Smckusick 	 */
6244404Skarels 	if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
637497Sroot 
6447540Skarels 	if ((unsigned)uap->i >= fdp->fd_nfiles ||
65*47653Skarels 	    (fp = fdp->fd_ofiles[uap->i]) == NULL)
6644404Skarels 		return (EBADF);
6747540Skarels 	if (error = fdalloc(p, 0, &fd))
6844404Skarels 		return (error);
69*47653Skarels 	fdp->fd_ofiles[fd] = fp;
70*47653Skarels 	fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
7142863Smckusick 	fp->f_count++;
7245914Smckusick 	if (fd > fdp->fd_lastfile)
7345914Smckusick 		fdp->fd_lastfile = fd;
7442863Smckusick 	*retval = fd;
7544404Skarels 	return (0);
767497Sroot }
777497Sroot 
7842863Smckusick /*
7942863Smckusick  * Duplicate a file descriptor to a particular value.
8042863Smckusick  */
8142863Smckusick /* ARGSUSED */
8242863Smckusick dup2(p, uap, retval)
8342863Smckusick 	struct proc *p;
84*47653Skarels 	struct args {
85*47653Skarels 		u_int	from;
86*47653Skarels 		u_int	to;
8742863Smckusick 	} *uap;
8842863Smckusick 	int *retval;
897497Sroot {
9045914Smckusick 	register struct filedesc *fdp = p->p_fd;
917497Sroot 	register struct file *fp;
92*47653Skarels 	register u_int old = uap->from, new = uap->to;
9345914Smckusick 	int i, error;
947422Sroot 
95*47653Skarels 	if (old >= fdp->fd_nfiles ||
96*47653Skarels 	    (fp = fdp->fd_ofiles[old]) == NULL ||
97*47653Skarels 	    new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
9844404Skarels 		return (EBADF);
99*47653Skarels 	*retval = new;
100*47653Skarels 	if (old == new)
10144404Skarels 		return (0);
102*47653Skarels 	if (new >= fdp->fd_nfiles) {
103*47653Skarels 		if (error = fdalloc(p, new, &i))
10445914Smckusick 			return (error);
105*47653Skarels 		if (new != i)
10647540Skarels 			panic("dup2: fdalloc");
107*47653Skarels 	} else if (fdp->fd_ofiles[new]) {
108*47653Skarels 		if (fdp->fd_ofileflags[new] & UF_MAPPED)
109*47653Skarels 			(void) munmapfd(p, new);
110*47653Skarels 		/*
111*47653Skarels 		 * dup2() must succeed even if the close has an error.
112*47653Skarels 		 */
113*47653Skarels 		(void) closef(fdp->fd_ofiles[new], p);
1147422Sroot 	}
115*47653Skarels 	fdp->fd_ofiles[new] = fp;
116*47653Skarels 	fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
11742863Smckusick 	fp->f_count++;
118*47653Skarels 	if (new > fdp->fd_lastfile)
119*47653Skarels 		fdp->fd_lastfile = new;
120*47653Skarels 	return (0);
1217696Ssam }
1227696Ssam 
12312748Ssam /*
12412748Ssam  * The file control system call.
12512748Ssam  */
12642863Smckusick /* ARGSUSED */
12742863Smckusick fcntl(p, uap, retval)
12842863Smckusick 	struct proc *p;
12942863Smckusick 	register struct args {
13047540Skarels 		int	fd;
13112748Ssam 		int	cmd;
13212748Ssam 		int	arg;
13342863Smckusick 	} *uap;
13442863Smckusick 	int *retval;
13542863Smckusick {
13645914Smckusick 	register struct filedesc *fdp = p->p_fd;
13742863Smckusick 	register struct file *fp;
13812748Ssam 	register char *pop;
13946200Smckusick 	struct vnode *vp;
14046200Smckusick 	int i, error, flags = F_POSIX;
14146200Smckusick 	struct flock fl;
1427497Sroot 
14347540Skarels 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
144*47653Skarels 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
14544404Skarels 		return (EBADF);
146*47653Skarels 	pop = &fdp->fd_ofileflags[uap->fd];
14712748Ssam 	switch(uap->cmd) {
14815076Skarels 	case F_DUPFD:
14947540Skarels 		if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
15044404Skarels 			return (EINVAL);
15147540Skarels 		if (error = fdalloc(p, uap->arg, &i))
15244404Skarels 			return (error);
153*47653Skarels 		fdp->fd_ofiles[i] = fp;
154*47653Skarels 		fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE;
15542863Smckusick 		fp->f_count++;
15645914Smckusick 		if (i > fdp->fd_lastfile)
15745914Smckusick 			fdp->fd_lastfile = i;
15842863Smckusick 		*retval = i;
15944404Skarels 		return (0);
1607497Sroot 
16115076Skarels 	case F_GETFD:
16242863Smckusick 		*retval = *pop & 1;
16344404Skarels 		return (0);
1647422Sroot 
16515076Skarels 	case F_SETFD:
16612748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
16744404Skarels 		return (0);
1688145Sroot 
16915076Skarels 	case F_GETFL:
17046495Skarels 		*retval = OFLAGS(fp->f_flag);
17144404Skarels 		return (0);
1728145Sroot 
17315076Skarels 	case F_SETFL:
17446495Skarels 		fp->f_flag &= ~FCNTLFLAGS;
17546495Skarels 		fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
17642863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
17744404Skarels 			return (error);
17842863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
17912748Ssam 			(void) fset(fp, FNDELAY, 0);
18044404Skarels 		return (error);
1817422Sroot 
18215076Skarels 	case F_GETOWN:
18344404Skarels 		return (fgetown(fp, retval));
1847422Sroot 
18515076Skarels 	case F_SETOWN:
18644404Skarels 		return (fsetown(fp, uap->arg));
1878115Sroot 
18846200Smckusick 	case F_SETLKW:
18946200Smckusick 		flags |= F_WAIT;
19046200Smckusick 		/* Fall into F_SETLK */
19146200Smckusick 
19246200Smckusick 	case F_SETLK:
19346200Smckusick 		if (fp->f_type != DTYPE_VNODE)
19446200Smckusick 			return (EBADF);
19546200Smckusick 		vp = (struct vnode *)fp->f_data;
19646200Smckusick 		/* Copy in the lock structure */
19746200Smckusick 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
19846200Smckusick 		if (error)
19946200Smckusick 			return (error);
20046200Smckusick 		if (fl.l_whence == SEEK_CUR)
20146200Smckusick 			fl.l_start += fp->f_offset;
20246200Smckusick 		switch (fl.l_type) {
20346200Smckusick 
20446200Smckusick 		case F_RDLCK:
20546200Smckusick 			if ((fp->f_flag & FREAD) == 0)
20646200Smckusick 				return (EBADF);
20746200Smckusick 			return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
20846200Smckusick 
20946200Smckusick 		case F_WRLCK:
21046200Smckusick 			if ((fp->f_flag & FWRITE) == 0)
21146200Smckusick 				return (EBADF);
21246200Smckusick 			return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
21346200Smckusick 
21446200Smckusick 		case F_UNLCK:
21546200Smckusick 			return (VOP_ADVLOCK(vp, p, F_UNLCK, &fl, F_POSIX));
21646200Smckusick 
21746200Smckusick 		default:
21846200Smckusick 			return (EINVAL);
21946200Smckusick 		}
22046200Smckusick 
22146200Smckusick 	case F_GETLK:
22246200Smckusick 		if (fp->f_type != DTYPE_VNODE)
22346200Smckusick 			return (EBADF);
22446200Smckusick 		vp = (struct vnode *)fp->f_data;
22546200Smckusick 		/* Copy in the lock structure */
22646200Smckusick 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
22746200Smckusick 		if (error)
22846200Smckusick 			return (error);
22946765Smckusick 		if (fl.l_whence == SEEK_CUR)
23046765Smckusick 			fl.l_start += fp->f_offset;
23146200Smckusick 		if (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX))
23246200Smckusick 			return (error);
23346200Smckusick 		return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
23446200Smckusick 
23512748Ssam 	default:
23644404Skarels 		return (EINVAL);
2377422Sroot 	}
23842863Smckusick 	/* NOTREACHED */
2397422Sroot }
2407422Sroot 
24112748Ssam fset(fp, bit, value)
24212748Ssam 	struct file *fp;
24312748Ssam 	int bit, value;
2447422Sroot {
2457422Sroot 
24612748Ssam 	if (value)
24712748Ssam 		fp->f_flag |= bit;
24812748Ssam 	else
24912748Ssam 		fp->f_flag &= ~bit;
25012748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
25112748Ssam 	    (caddr_t)&value));
25212748Ssam }
2537422Sroot 
25412748Ssam fgetown(fp, valuep)
25512748Ssam 	struct file *fp;
25612748Ssam 	int *valuep;
25712748Ssam {
25812748Ssam 	int error;
2598115Sroot 
26012748Ssam 	switch (fp->f_type) {
2618115Sroot 
26212748Ssam 	case DTYPE_SOCKET:
26335810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
26412748Ssam 		return (0);
2657497Sroot 
26612748Ssam 	default:
26712748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
26812748Ssam 		*valuep = -*valuep;
26912748Ssam 		return (error);
2707422Sroot 	}
2717422Sroot }
2727422Sroot 
27312748Ssam fsetown(fp, value)
27412748Ssam 	struct file *fp;
27512748Ssam 	int value;
2767422Sroot {
27737728Smckusick 
27812748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
27935810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
28012748Ssam 		return (0);
28112748Ssam 	}
28212748Ssam 	if (value > 0) {
28312748Ssam 		struct proc *p = pfind(value);
28412748Ssam 		if (p == 0)
28528201Skarels 			return (ESRCH);
28635810Smarc 		value = p->p_pgrp->pg_id;
28712748Ssam 	} else
28812748Ssam 		value = -value;
28912748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2907422Sroot }
2917422Sroot 
29212748Ssam fioctl(fp, cmd, value)
29312748Ssam 	struct file *fp;
29412748Ssam 	int cmd;
29512748Ssam 	caddr_t value;
2967422Sroot {
2977422Sroot 
29812748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2997422Sroot }
3007422Sroot 
30142863Smckusick /*
30242863Smckusick  * Close a file descriptor.
30342863Smckusick  */
30442863Smckusick /* ARGSUSED */
30542863Smckusick close(p, uap, retval)
30642863Smckusick 	struct proc *p;
30742863Smckusick 	struct args {
30847540Skarels 		int	fd;
30942863Smckusick 	} *uap;
31042863Smckusick 	int *retval;
3118029Sroot {
31245914Smckusick 	register struct filedesc *fdp = p->p_fd;
31312748Ssam 	register struct file *fp;
31447540Skarels 	register int fd = uap->fd;
31513044Ssam 	register u_char *pf;
3168029Sroot 
31747540Skarels 	if ((unsigned)fd >= fdp->fd_nfiles ||
318*47653Skarels 	    (fp = fdp->fd_ofiles[fd]) == NULL)
31944404Skarels 		return (EBADF);
320*47653Skarels 	pf = (u_char *)&fdp->fd_ofileflags[fd];
32113044Ssam 	if (*pf & UF_MAPPED)
32247540Skarels 		(void) munmapfd(p, fd);
323*47653Skarels 	fdp->fd_ofiles[fd] = NULL;
324*47653Skarels 	while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
32545914Smckusick 		fdp->fd_lastfile--;
32647540Skarels 	if (fd < fdp->fd_freefile)
32747540Skarels 		fdp->fd_freefile = fd;
32815550Skarels 	*pf = 0;
32947540Skarels 	return (closef(fp, p));
3308029Sroot }
3318029Sroot 
33242863Smckusick /*
33342863Smckusick  * Return status information about a file descriptor.
33442863Smckusick  */
33542863Smckusick /* ARGSUSED */
33642863Smckusick fstat(p, uap, retval)
33742863Smckusick 	struct proc *p;
33842863Smckusick 	register struct args {
33947540Skarels 		int	fd;
34042863Smckusick 		struct	stat *sb;
34142863Smckusick 	} *uap;
34242863Smckusick 	int *retval;
34313044Ssam {
34445914Smckusick 	register struct filedesc *fdp = p->p_fd;
34513044Ssam 	register struct file *fp;
34613044Ssam 	struct stat ub;
34742863Smckusick 	int error;
34813044Ssam 
34947540Skarels 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
350*47653Skarels 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
35144404Skarels 		return (EBADF);
35213044Ssam 	switch (fp->f_type) {
35313044Ssam 
35437728Smckusick 	case DTYPE_VNODE:
35542863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
35613044Ssam 		break;
35713044Ssam 
35813044Ssam 	case DTYPE_SOCKET:
35942863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
36013044Ssam 		break;
36113044Ssam 
36213044Ssam 	default:
36313044Ssam 		panic("fstat");
36413044Ssam 		/*NOTREACHED*/
36513044Ssam 	}
36642863Smckusick 	if (error == 0)
36742863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
36844404Skarels 	return (error);
36913044Ssam }
37013044Ssam 
3717422Sroot /*
37247540Skarels  * Allocate a file descriptor for the process.
3737422Sroot  */
37447540Skarels int fdexpand;
37545914Smckusick 
37647540Skarels fdalloc(p, want, result)
37747540Skarels 	struct proc *p;
37847540Skarels 	int want;
37937728Smckusick 	int *result;
3807422Sroot {
38147540Skarels 	register struct filedesc *fdp = p->p_fd;
38247540Skarels 	register int i;
38347540Skarels 	int lim, last, nfiles;
38445914Smckusick 	struct file **newofile;
38545914Smckusick 	char *newofileflags;
3867497Sroot 
38747540Skarels 	/*
38847540Skarels 	 * Search for a free descriptor starting at the higher
38947540Skarels 	 * of want or fd_freefile.  If that fails, consider
39047540Skarels 	 * expanding the ofile array.
39147540Skarels 	 */
39247540Skarels 	lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
39345914Smckusick 	for (;;) {
39447540Skarels 		last = min(fdp->fd_nfiles, lim);
39547540Skarels 		if ((i = want) < fdp->fd_freefile)
39647540Skarels 			i = fdp->fd_freefile;
39747540Skarels 		for (; i < last; i++) {
398*47653Skarels 			if (fdp->fd_ofiles[i] == NULL) {
399*47653Skarels 				fdp->fd_ofileflags[i] = 0;
40047540Skarels 				if (i > fdp->fd_lastfile)
40147540Skarels 					fdp->fd_lastfile = i;
402*47653Skarels 				if (want <= fdp->fd_freefile)
40347540Skarels 					fdp->fd_freefile = i;
40447540Skarels 				*result = i;
40545914Smckusick 				return (0);
40645914Smckusick 			}
4077497Sroot 		}
40847540Skarels 
40947540Skarels 		/*
41047540Skarels 		 * No space in current array.  Expand?
41147540Skarels 		 */
41247540Skarels 		if (fdp->fd_nfiles >= lim)
41345914Smckusick 			return (EMFILE);
414*47653Skarels 		if (fdp->fd_nfiles < NDEXTENT)
415*47653Skarels 			nfiles = NDEXTENT;
416*47653Skarels 		else
417*47653Skarels 			nfiles = 2 * fdp->fd_nfiles;
41847540Skarels 		MALLOC(newofile, struct file **, nfiles * OFILESIZE,
41947540Skarels 		    M_FILEDESC, M_WAITOK);
42047540Skarels 		newofileflags = (char *) &newofile[nfiles];
42147540Skarels 		/*
42247540Skarels 		 * Copy the existing ofile and ofileflags arrays
42347540Skarels 		 * and zero the new portion of each array.
42447540Skarels 		 */
42547540Skarels 		bcopy(fdp->fd_ofiles, newofile,
42647540Skarels 			(i = sizeof(struct file *) * fdp->fd_nfiles));
42747540Skarels 		bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
42847540Skarels 		bcopy(fdp->fd_ofileflags, newofileflags,
42947540Skarels 			(i = sizeof(char) * fdp->fd_nfiles));
43047540Skarels 		bzero(newofileflags + i, nfiles * sizeof(char) - i);
431*47653Skarels 		if (fdp->fd_nfiles > NDFILE)
432*47653Skarels 			FREE(fdp->fd_ofiles, M_FILEDESC);
43347540Skarels 		fdp->fd_ofiles = newofile;
43447540Skarels 		fdp->fd_ofileflags = newofileflags;
43547540Skarels 		fdp->fd_nfiles = nfiles;
43647540Skarels 		fdexpand++;
43739733Smckusick 	}
4387497Sroot }
4397497Sroot 
44042863Smckusick /*
441*47653Skarels  * Check to see whether n user file descriptors
442*47653Skarels  * are available to the process p.
44342863Smckusick  */
44447540Skarels fdavail(p, n)
44547540Skarels 	struct proc *p;
44647540Skarels 	register int n;
44712748Ssam {
44847540Skarels 	register struct filedesc *fdp = p->p_fd;
449*47653Skarels 	register struct file **fpp;
45047540Skarels 	register int i;
45112748Ssam 
45247540Skarels 	if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 &&
45347540Skarels 	    (n -= i) <= 0)
45447540Skarels 		return (1);
455*47653Skarels 	fpp = &fdp->fd_ofiles[fdp->fd_freefile];
456*47653Skarels 	for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
457*47653Skarels 		if (*fpp == NULL && --n <= 0)
45847540Skarels 			return (1);
45947540Skarels 	return (0);
46012748Ssam }
46112748Ssam 
4627497Sroot struct	file *lastf;
4637497Sroot /*
46447540Skarels  * Create a new open file structure and allocate
46547540Skarels  * a file decriptor for the process that refers to it.
4667497Sroot  */
46745914Smckusick falloc(p, resultfp, resultfd)
46845914Smckusick 	register struct proc *p;
46937728Smckusick 	struct file **resultfp;
47037728Smckusick 	int *resultfd;
4717497Sroot {
4727422Sroot 	register struct file *fp;
47337728Smckusick 	int error, i;
4747422Sroot 
47547540Skarels 	if (error = fdalloc(p, 0, &i))
47637728Smckusick 		return (error);
4777497Sroot 	if (lastf == 0)
4787497Sroot 		lastf = file;
4797497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
4807497Sroot 		if (fp->f_count == 0)
4817497Sroot 			goto slot;
4827497Sroot 	for (fp = file; fp < lastf; fp++)
4837497Sroot 		if (fp->f_count == 0)
4847497Sroot 			goto slot;
4857497Sroot 	tablefull("file");
48637728Smckusick 	return (ENFILE);
4877497Sroot slot:
488*47653Skarels 	p->p_fd->fd_ofiles[i] = fp;
48912748Ssam 	fp->f_count = 1;
49012748Ssam 	fp->f_data = 0;
4917497Sroot 	fp->f_offset = 0;
49247540Skarels 	fp->f_cred = p->p_ucred;
49337728Smckusick 	crhold(fp->f_cred);
4947497Sroot 	lastf = fp + 1;
49537728Smckusick 	if (resultfp)
49637728Smckusick 		*resultfp = fp;
49737728Smckusick 	if (resultfd)
49837728Smckusick 		*resultfd = i;
49937728Smckusick 	return (0);
5007497Sroot }
50112748Ssam 
5027497Sroot /*
50347540Skarels  * Copy a filedesc structure.
50445914Smckusick  */
50545914Smckusick struct filedesc *
50647540Skarels fdcopy(p)
50747540Skarels 	struct proc *p;
50845914Smckusick {
509*47653Skarels 	register struct filedesc *newfdp, *fdp = p->p_fd;
510*47653Skarels 	register struct file **fpp;
51145914Smckusick 	register int i;
51245914Smckusick 
513*47653Skarels 	MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
514*47653Skarels 	    M_FILEDESC, M_WAITOK);
515*47653Skarels 	bcopy(fdp, newfdp, sizeof(struct filedesc));
51645914Smckusick 	VREF(newfdp->fd_cdir);
51745914Smckusick 	if (newfdp->fd_rdir)
51845914Smckusick 		VREF(newfdp->fd_rdir);
51945914Smckusick 	newfdp->fd_refcnt = 1;
52047540Skarels 
52147540Skarels 	/*
522*47653Skarels 	 * If the number of open files fits in the internal arrays
523*47653Skarels 	 * of the open file structure, use them, otherwise allocate
524*47653Skarels 	 * additional memory for the number of descriptors currently
525*47653Skarels 	 * in use.
52647540Skarels 	 */
527*47653Skarels 	if (newfdp->fd_lastfile < NDFILE) {
528*47653Skarels 		newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
529*47653Skarels 		newfdp->fd_ofileflags =
530*47653Skarels 		    ((struct filedesc0 *) newfdp)->fd_dfileflags;
531*47653Skarels 		i = NDFILE;
532*47653Skarels 	} else {
533*47653Skarels 		/*
534*47653Skarels 		 * Compute the smallest multiple of NDEXTENT needed
535*47653Skarels 		 * for the file descriptors currently in use,
536*47653Skarels 		 * allowing the table to shrink.
537*47653Skarels 		 */
538*47653Skarels 		i = newfdp->fd_nfiles;
539*47653Skarels 		while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2)
540*47653Skarels 			i /= 2;
541*47653Skarels 		MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
542*47653Skarels 		    M_FILEDESC, M_WAITOK);
543*47653Skarels 		newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
544*47653Skarels 	}
54547540Skarels 	newfdp->fd_nfiles = i;
54647540Skarels 	bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
54747540Skarels 	bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
548*47653Skarels 	fpp = newfdp->fd_ofiles;
549*47653Skarels 	for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
550*47653Skarels 		if (*fpp != NULL)
551*47653Skarels 			(*fpp)->f_count++;
55245914Smckusick 	return (newfdp);
55345914Smckusick }
55445914Smckusick 
55545914Smckusick /*
55645914Smckusick  * Release a filedesc structure.
55745914Smckusick  */
558*47653Skarels void
55947540Skarels fdfree(p)
56047540Skarels 	struct proc *p;
56145914Smckusick {
56247540Skarels 	register struct filedesc *fdp = p->p_fd;
563*47653Skarels 	struct file **fpp;
56445914Smckusick 	register int i;
56545914Smckusick 
56647540Skarels 	if (--fdp->fd_refcnt > 0)
56745914Smckusick 		return;
568*47653Skarels 	fpp = fdp->fd_ofiles;
569*47653Skarels 	for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
570*47653Skarels 		if (*fpp)
571*47653Skarels 			(void) closef(*fpp, p);
572*47653Skarels 	if (fdp->fd_nfiles > NDFILE)
573*47653Skarels 		FREE(fdp->fd_ofiles, M_FILEDESC);
57445914Smckusick 	vrele(fdp->fd_cdir);
57545914Smckusick 	if (fdp->fd_rdir)
57645914Smckusick 		vrele(fdp->fd_rdir);
57747540Skarels 	FREE(fdp, M_FILEDESC);
57845914Smckusick }
57945914Smckusick 
58045914Smckusick /*
5817497Sroot  * Internal form of close.
58212748Ssam  * Decrement reference count on file structure.
5837497Sroot  */
58447540Skarels closef(fp, p)
5857497Sroot 	register struct file *fp;
58647540Skarels 	struct proc *p;
5877497Sroot {
58846200Smckusick 	struct vnode *vp;
58946200Smckusick 	struct flock lf;
59039354Smckusick 	int error;
5917497Sroot 
5927422Sroot 	if (fp == NULL)
59339354Smckusick 		return (0);
59446200Smckusick 	/*
59546200Smckusick 	 * POSIX record locking dictates that any close releases ALL
59646200Smckusick 	 * locks owned by this process.  This is handled by setting
59746200Smckusick 	 * a flag in the unlock to free ONLY locks obeying POSIX
59846200Smckusick 	 * semantics, and not to free BSD-style file locks.
59946200Smckusick 	 */
60046200Smckusick 	if (fp->f_type == DTYPE_VNODE) {
60146200Smckusick 		lf.l_whence = SEEK_SET;
60246200Smckusick 		lf.l_start = 0;
60346200Smckusick 		lf.l_len = 0;
60446200Smckusick 		lf.l_type = F_UNLCK;
60546200Smckusick 		vp = (struct vnode *)fp->f_data;
60646200Smckusick 		(void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX);
60746200Smckusick 	}
60847540Skarels 	if (--fp->f_count > 0)
60939354Smckusick 		return (0);
61047540Skarels 	if (fp->f_count < 0)
61147540Skarels 		panic("closef: count < 0");
61246200Smckusick 	if (fp->f_type == DTYPE_VNODE)
61346200Smckusick 		(void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK);
61439354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
61537728Smckusick 	crfree(fp->f_cred);
6167497Sroot 	fp->f_count = 0;
61739354Smckusick 	return (error);
6187422Sroot }
61913044Ssam 
62013044Ssam /*
62113044Ssam  * Apply an advisory lock on a file descriptor.
62246200Smckusick  *
62346200Smckusick  * Just attempt to get a record lock of the requested type on
62446200Smckusick  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
62513044Ssam  */
62646200Smckusick 
62742863Smckusick /* ARGSUSED */
62842863Smckusick flock(p, uap, retval)
62942863Smckusick 	struct proc *p;
63042863Smckusick 	register struct args {
63147540Skarels 		int	fd;
63213044Ssam 		int	how;
63342863Smckusick 	} *uap;
63442863Smckusick 	int *retval;
63542863Smckusick {
63645914Smckusick 	register struct filedesc *fdp = p->p_fd;
63713044Ssam 	register struct file *fp;
63846200Smckusick 	struct vnode *vp;
63946200Smckusick 	struct flock lf;
64046200Smckusick 	int error;
64113044Ssam 
64247540Skarels 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
643*47653Skarels 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
64444404Skarels 		return (EBADF);
64542863Smckusick 	if (fp->f_type != DTYPE_VNODE)
64644404Skarels 		return (EOPNOTSUPP);
64746200Smckusick 	vp = (struct vnode *)fp->f_data;
64846200Smckusick 	lf.l_whence = SEEK_SET;
64946200Smckusick 	lf.l_start = 0;
65046200Smckusick 	lf.l_len = 0;
65113101Ssam 	if (uap->how & LOCK_UN) {
65246200Smckusick 		lf.l_type = F_UNLCK;
65346200Smckusick 		return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK));
65413044Ssam 	}
65517998Skarels 	if (uap->how & LOCK_EX)
65646200Smckusick 		lf.l_type = F_WRLCK;
65746200Smckusick 	else if (uap->how & LOCK_SH)
65846200Smckusick 		lf.l_type = F_RDLCK;
65946200Smckusick 	else
66046200Smckusick 		return (EBADF);
66146200Smckusick 	if (uap->how & LOCK_NB)
66246200Smckusick 		return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK));
66346200Smckusick 	return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
66413044Ssam }
66537586Smarc 
66637586Smarc /*
66737586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
66837586Smarc  *
66937586Smarc  * Opening minor device N dup()s the file (if any) connected to file
67037586Smarc  * descriptor N belonging to the calling process.  Note that this driver
67137586Smarc  * consists of only the ``open()'' routine, because all subsequent
67237586Smarc  * references to this file will be direct to the other driver.
67337586Smarc  */
67437728Smckusick /* ARGSUSED */
67537728Smckusick fdopen(dev, mode, type)
67637586Smarc 	dev_t dev;
67737728Smckusick 	int mode, type;
67837586Smarc {
67937586Smarc 
68037586Smarc 	/*
68147540Skarels 	 * XXX Kludge: set curproc->p_dupfd to contain the value of the
68243406Smckusick 	 * the file descriptor being sought for duplication. The error
68343406Smckusick 	 * return ensures that the vnode for this device will be released
68443406Smckusick 	 * by vn_open. Open will detect this special error and take the
68543406Smckusick 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
68643406Smckusick 	 * will simply report the error.
68737586Smarc 	 */
68847540Skarels 	curproc->p_dupfd = minor(dev);		/* XXX */
68943406Smckusick 	return (ENODEV);
69043406Smckusick }
69140873Sbostic 
69243406Smckusick /*
69343406Smckusick  * Duplicate the specified descriptor to a free descriptor.
69443406Smckusick  */
69545914Smckusick dupfdopen(fdp, indx, dfd, mode)
69645914Smckusick 	register struct filedesc *fdp;
69743406Smckusick 	register int indx, dfd;
69843406Smckusick 	int mode;
69943406Smckusick {
70043406Smckusick 	register struct file *wfp;
70143406Smckusick 	struct file *fp;
70243406Smckusick 
70337586Smarc 	/*
70443406Smckusick 	 * If the to-be-dup'd fd number is greater than the allowed number
70543406Smckusick 	 * of file descriptors, or the fd to be dup'd has already been
70643406Smckusick 	 * closed, reject.  Note, check for new == old is necessary as
70743406Smckusick 	 * falloc could allocate an already closed to-be-dup'd descriptor
70843406Smckusick 	 * as the new descriptor.
70937586Smarc 	 */
710*47653Skarels 	fp = fdp->fd_ofiles[indx];
711*47653Skarels 	if ((u_int)dfd >= fdp->fd_nfiles ||
712*47653Skarels 	    (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
71337586Smarc 		return (EBADF);
71440873Sbostic 
71537586Smarc 	/*
71640873Sbostic 	 * Check that the mode the file is being opened for is a subset
71740873Sbostic 	 * of the mode of the existing descriptor.
71837586Smarc 	 */
71943406Smckusick 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
72037586Smarc 		return (EACCES);
721*47653Skarels 	fdp->fd_ofiles[indx] = wfp;
722*47653Skarels 	fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
72342863Smckusick 	wfp->f_count++;
72445914Smckusick 	if (indx > fdp->fd_lastfile)
72545914Smckusick 		fdp->fd_lastfile = indx;
72643406Smckusick 	return (0);
72737586Smarc }
728