xref: /freebsd/sys/kern/kern_descrip.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)kern_descrip.c	8.6 (Berkeley) 4/19/94
39  * $Id: kern_descrip.c,v 1.8 1995/02/20 19:42:33 guido Exp $
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/filedesc.h>
45 #include <sys/kernel.h>
46 #include <sys/vnode.h>
47 #include <sys/proc.h>
48 #include <sys/file.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/stat.h>
52 #include <sys/ioctl.h>
53 #include <sys/fcntl.h>
54 #include <sys/malloc.h>
55 #include <sys/syslog.h>
56 #include <sys/unistd.h>
57 #include <sys/resourcevar.h>
58 #include <vm/vm.h>
59 
60 int finishdup(struct filedesc *fdp, int old, int new, int *retval);
61 /*
62  * Descriptor management.
63  */
64 struct file *filehead;	/* head of list of open files */
65 int nfiles;		/* actual number of open files */
66 
67 /*
68  * System calls on descriptors.
69  */
70 struct getdtablesize_args {
71 	int	dummy;
72 };
73 /* ARGSUSED */
74 int
75 getdtablesize(p, uap, retval)
76 	struct proc *p;
77 	struct getdtablesize_args *uap;
78 	int *retval;
79 {
80 
81 	*retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
82 	return (0);
83 }
84 
85 /*
86  * Duplicate a file descriptor to a particular value.
87  */
88 struct dup2_args {
89 	u_int	from;
90 	u_int	to;
91 };
92 /* ARGSUSED */
93 int
94 dup2(p, uap, retval)
95 	struct proc *p;
96 	struct dup2_args *uap;
97 	int *retval;
98 {
99 	register struct filedesc *fdp = p->p_fd;
100 	register u_int old = uap->from, new = uap->to;
101 	int i, error;
102 
103 	if (old >= fdp->fd_nfiles ||
104 	    fdp->fd_ofiles[old] == NULL ||
105 	    new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
106 	    new >= maxfilesperproc)
107 		return (EBADF);
108 	if (old == new) {
109 		*retval = new;
110 		return (0);
111 	}
112 	if (new >= fdp->fd_nfiles) {
113 		if ((error = fdalloc(p, new, &i)))
114 			return (error);
115 		if (new != i)
116 			panic("dup2: fdalloc");
117 	} else if (fdp->fd_ofiles[new]) {
118 		if (fdp->fd_ofileflags[new] & UF_MAPPED)
119 			(void) munmapfd(p, new);
120 		/*
121 		 * dup2() must succeed even if the close has an error.
122 		 */
123 		(void) closef(fdp->fd_ofiles[new], p);
124 	}
125 	return (finishdup(fdp, (int)old, (int)new, retval));
126 }
127 
128 /*
129  * Duplicate a file descriptor.
130  */
131 struct dup_args {
132 	u_int	fd;
133 };
134 /* ARGSUSED */
135 int
136 dup(p, uap, retval)
137 	struct proc *p;
138 	struct dup_args *uap;
139 	int *retval;
140 {
141 	register struct filedesc *fdp;
142 	u_int old;
143 	int new, error;
144 
145 	old = uap->fd;
146 
147 #if 0
148 	/*
149 	 * XXX Compatibility
150 	 */
151 	if (old &~ 077) { uap->fd &= 077; return (dup2(p, uap, retval)); }
152 #endif
153 
154 	fdp = p->p_fd;
155 	if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
156 		return (EBADF);
157 	if ((error = fdalloc(p, 0, &new)))
158 		return (error);
159 	return (finishdup(fdp, (int)old, new, retval));
160 }
161 
162 /*
163  * The file control system call.
164  */
165 struct fcntl_args {
166 	int	fd;
167 	int	cmd;
168 	int	arg;
169 };
170 /* ARGSUSED */
171 int
172 fcntl(p, uap, retval)
173 	struct proc *p;
174 	register struct fcntl_args *uap;
175 	int *retval;
176 {
177 	register struct filedesc *fdp = p->p_fd;
178 	register struct file *fp;
179 	register char *pop;
180 	struct vnode *vp;
181 	int i, tmp, error, flg = F_POSIX;
182 	struct flock fl;
183 	u_int newmin;
184 
185 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
186 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
187 		return (EBADF);
188 	pop = &fdp->fd_ofileflags[uap->fd];
189 	switch (uap->cmd) {
190 
191 	case F_DUPFD:
192 		newmin = uap->arg;
193 		if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
194 		    newmin >= maxfilesperproc)
195 			return (EINVAL);
196 		if ((error = fdalloc(p, newmin, &i)))
197 			return (error);
198 		return (finishdup(fdp, uap->fd, i, retval));
199 
200 	case F_GETFD:
201 		*retval = *pop & 1;
202 		return (0);
203 
204 	case F_SETFD:
205 		*pop = (*pop &~ 1) | (uap->arg & 1);
206 		return (0);
207 
208 	case F_GETFL:
209 		*retval = OFLAGS(fp->f_flag);
210 		return (0);
211 
212 	case F_SETFL:
213 		fp->f_flag &= ~FCNTLFLAGS;
214 		fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
215 		tmp = fp->f_flag & FNONBLOCK;
216 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
217 		if (error)
218 			return (error);
219 		tmp = fp->f_flag & FASYNC;
220 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
221 		if (!error)
222 			return (0);
223 		fp->f_flag &= ~FNONBLOCK;
224 		tmp = 0;
225 		(void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
226 		return (error);
227 
228 	case F_GETOWN:
229 		if (fp->f_type == DTYPE_SOCKET) {
230 			*retval = ((struct socket *)fp->f_data)->so_pgid;
231 			return (0);
232 		}
233 		error = (*fp->f_ops->fo_ioctl)
234 			(fp, (int)TIOCGPGRP, (caddr_t)retval, p);
235 		*retval = -*retval;
236 		return (error);
237 
238 	case F_SETOWN:
239 		if (fp->f_type == DTYPE_SOCKET) {
240 			((struct socket *)fp->f_data)->so_pgid = uap->arg;
241 			return (0);
242 		}
243 		if (uap->arg <= 0) {
244 			uap->arg = -uap->arg;
245 		} else {
246 			struct proc *p1 = pfind(uap->arg);
247 			if (p1 == 0)
248 				return (ESRCH);
249 			uap->arg = p1->p_pgrp->pg_id;
250 		}
251 		return ((*fp->f_ops->fo_ioctl)
252 			(fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
253 
254 	case F_SETLKW:
255 		flg |= F_WAIT;
256 		/* Fall into F_SETLK */
257 
258 	case F_SETLK:
259 		if (fp->f_type != DTYPE_VNODE)
260 			return (EBADF);
261 		vp = (struct vnode *)fp->f_data;
262 		/* Copy in the lock structure */
263 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
264 		if (error)
265 			return (error);
266 		if (fl.l_whence == SEEK_CUR)
267 			fl.l_start += fp->f_offset;
268 		switch (fl.l_type) {
269 
270 		case F_RDLCK:
271 			if ((fp->f_flag & FREAD) == 0)
272 				return (EBADF);
273 			p->p_flag |= P_ADVLOCK;
274 			return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
275 
276 		case F_WRLCK:
277 			if ((fp->f_flag & FWRITE) == 0)
278 				return (EBADF);
279 			p->p_flag |= P_ADVLOCK;
280 			return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
281 
282 		case F_UNLCK:
283 			return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
284 				F_POSIX));
285 
286 		default:
287 			return (EINVAL);
288 		}
289 
290 	case F_GETLK:
291 		if (fp->f_type != DTYPE_VNODE)
292 			return (EBADF);
293 		vp = (struct vnode *)fp->f_data;
294 		/* Copy in the lock structure */
295 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
296 		if (error)
297 			return (error);
298 		if (fl.l_whence == SEEK_CUR)
299 			fl.l_start += fp->f_offset;
300 		if ((error = VOP_ADVLOCK(vp,(caddr_t)p,F_GETLK,&fl,F_POSIX)))
301 			return (error);
302 		return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
303 
304 	default:
305 		return (EINVAL);
306 	}
307 	/* NOTREACHED */
308 }
309 
310 /*
311  * Common code for dup, dup2, and fcntl(F_DUPFD).
312  */
313 int
314 finishdup(fdp, old, new, retval)
315 	register struct filedesc *fdp;
316 	register int old, new, *retval;
317 {
318 	register struct file *fp;
319 
320 	fp = fdp->fd_ofiles[old];
321 	fdp->fd_ofiles[new] = fp;
322 	fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
323 	fp->f_count++;
324 	if (new > fdp->fd_lastfile)
325 		fdp->fd_lastfile = new;
326 	*retval = new;
327 	return (0);
328 }
329 
330 /*
331  * Close a file descriptor.
332  */
333 /* ARGSUSED */
334 int
335 close(p, uap, retval)
336 	struct proc *p;
337 	struct close_args *uap;
338 	int *retval;
339 {
340 	register struct filedesc *fdp = p->p_fd;
341 	register struct file *fp;
342 	register int fd = uap->fd;
343 	register u_char *pf;
344 
345 	if ((unsigned)fd >= fdp->fd_nfiles ||
346 	    (fp = fdp->fd_ofiles[fd]) == NULL)
347 		return (EBADF);
348 	pf = (u_char *)&fdp->fd_ofileflags[fd];
349 	if (*pf & UF_MAPPED)
350 		(void) munmapfd(p, fd);
351 	fdp->fd_ofiles[fd] = NULL;
352 	while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
353 		fdp->fd_lastfile--;
354 	if (fd < fdp->fd_freefile)
355 		fdp->fd_freefile = fd;
356 	*pf = 0;
357 	return (closef(fp, p));
358 }
359 
360 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
361 /*
362  * Return status information about a file descriptor.
363  */
364 struct ofstat_args {
365 	int	fd;
366 	struct	ostat *sb;
367 };
368 /* ARGSUSED */
369 int
370 ofstat(p, uap, retval)
371 	struct proc *p;
372 	register struct ofstat_args *uap;
373 	int *retval;
374 {
375 	register struct filedesc *fdp = p->p_fd;
376 	register struct file *fp;
377 	struct stat ub;
378 	struct ostat oub;
379 	int error;
380 
381 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
382 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
383 		return (EBADF);
384 	switch (fp->f_type) {
385 
386 	case DTYPE_VNODE:
387 		error = vn_stat((struct vnode *)fp->f_data, &ub, p);
388 		break;
389 
390 	case DTYPE_SOCKET:
391 		error = soo_stat((struct socket *)fp->f_data, &ub);
392 		break;
393 
394 	default:
395 		panic("ofstat");
396 		/*NOTREACHED*/
397 	}
398 	cvtstat(&ub, &oub);
399 	if (error == 0)
400 		error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub));
401 	return (error);
402 }
403 #endif /* COMPAT_43 || COMPAT_SUNOS */
404 
405 /*
406  * Return status information about a file descriptor.
407  */
408 struct fstat_args {
409 	int	fd;
410 	struct	stat *sb;
411 };
412 /* ARGSUSED */
413 int
414 fstat(p, uap, retval)
415 	struct proc *p;
416 	register struct fstat_args *uap;
417 	int *retval;
418 {
419 	register struct filedesc *fdp = p->p_fd;
420 	register struct file *fp;
421 	struct stat ub;
422 	int error;
423 
424 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
425 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
426 		return (EBADF);
427 	switch (fp->f_type) {
428 
429 	case DTYPE_VNODE:
430 		error = vn_stat((struct vnode *)fp->f_data, &ub, p);
431 		break;
432 
433 	case DTYPE_SOCKET:
434 		error = soo_stat((struct socket *)fp->f_data, &ub);
435 		break;
436 
437 	default:
438 		panic("fstat");
439 		/*NOTREACHED*/
440 	}
441 	if (error == 0)
442 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
443 	return (error);
444 }
445 
446 /*
447  * Return pathconf information about a file descriptor.
448  */
449 struct fpathconf_args {
450 	int	fd;
451 	int	name;
452 };
453 /* ARGSUSED */
454 int
455 fpathconf(p, uap, retval)
456 	struct proc *p;
457 	register struct fpathconf_args *uap;
458 	int *retval;
459 {
460 	struct filedesc *fdp = p->p_fd;
461 	struct file *fp;
462 	struct vnode *vp;
463 
464 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
465 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
466 		return (EBADF);
467 	switch (fp->f_type) {
468 
469 	case DTYPE_SOCKET:
470 		if (uap->name != _PC_PIPE_BUF)
471 			return (EINVAL);
472 		*retval = PIPE_BUF;
473 		return (0);
474 
475 	case DTYPE_VNODE:
476 		vp = (struct vnode *)fp->f_data;
477 		return (VOP_PATHCONF(vp, uap->name, retval));
478 
479 	default:
480 		panic("fpathconf");
481 	}
482 	/*NOTREACHED*/
483 }
484 
485 /*
486  * Allocate a file descriptor for the process.
487  */
488 int fdexpand;
489 
490 int
491 fdalloc(p, want, result)
492 	struct proc *p;
493 	int want;
494 	int *result;
495 {
496 	register struct filedesc *fdp = p->p_fd;
497 	register int i;
498 	int lim, last, nfiles;
499 	struct file **newofile;
500 	char *newofileflags;
501 
502 	/*
503 	 * Search for a free descriptor starting at the higher
504 	 * of want or fd_freefile.  If that fails, consider
505 	 * expanding the ofile array.
506 	 */
507 	lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
508 	for (;;) {
509 		last = min(fdp->fd_nfiles, lim);
510 		if ((i = want) < fdp->fd_freefile)
511 			i = fdp->fd_freefile;
512 		for (; i < last; i++) {
513 			if (fdp->fd_ofiles[i] == NULL) {
514 				fdp->fd_ofileflags[i] = 0;
515 				if (i > fdp->fd_lastfile)
516 					fdp->fd_lastfile = i;
517 				if (want <= fdp->fd_freefile)
518 					fdp->fd_freefile = i;
519 				*result = i;
520 				return (0);
521 			}
522 		}
523 
524 		/*
525 		 * No space in current array.  Expand?
526 		 */
527 		if (fdp->fd_nfiles >= lim)
528 			return (EMFILE);
529 		if (fdp->fd_nfiles < NDEXTENT)
530 			nfiles = NDEXTENT;
531 		else
532 			nfiles = 2 * fdp->fd_nfiles;
533 		MALLOC(newofile, struct file **, nfiles * OFILESIZE,
534 		    M_FILEDESC, M_WAITOK);
535 		newofileflags = (char *) &newofile[nfiles];
536 		/*
537 		 * Copy the existing ofile and ofileflags arrays
538 		 * and zero the new portion of each array.
539 		 */
540 		bcopy(fdp->fd_ofiles, newofile,
541 			(i = sizeof(struct file *) * fdp->fd_nfiles));
542 		bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
543 		bcopy(fdp->fd_ofileflags, newofileflags,
544 			(i = sizeof(char) * fdp->fd_nfiles));
545 		bzero(newofileflags + i, nfiles * sizeof(char) - i);
546 		if (fdp->fd_nfiles > NDFILE)
547 			FREE(fdp->fd_ofiles, M_FILEDESC);
548 		fdp->fd_ofiles = newofile;
549 		fdp->fd_ofileflags = newofileflags;
550 		fdp->fd_nfiles = nfiles;
551 		fdexpand++;
552 	}
553 	return (0);
554 }
555 
556 /*
557  * Check to see whether n user file descriptors
558  * are available to the process p.
559  */
560 int
561 fdavail(p, n)
562 	struct proc *p;
563 	register int n;
564 {
565 	register struct filedesc *fdp = p->p_fd;
566 	register struct file **fpp;
567 	register int i, lim;
568 
569 	lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
570 	if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
571 		return (1);
572 	fpp = &fdp->fd_ofiles[fdp->fd_freefile];
573 	for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
574 		if (*fpp == NULL && --n <= 0)
575 			return (1);
576 	return (0);
577 }
578 
579 /*
580  * Create a new open file structure and allocate
581  * a file decriptor for the process that refers to it.
582  */
583 int
584 falloc(p, resultfp, resultfd)
585 	register struct proc *p;
586 	struct file **resultfp;
587 	int *resultfd;
588 {
589 	register struct file *fp, *fq, **fpp;
590 	int error, i;
591 
592 	if ((error = fdalloc(p, 0, &i)))
593 		return (error);
594 	if (nfiles >= maxfiles) {
595 		tablefull("file");
596 		return (ENFILE);
597 	}
598 	/*
599 	 * Allocate a new file descriptor.
600 	 * If the process has file descriptor zero open, add to the list
601 	 * of open files at that point, otherwise put it at the front of
602 	 * the list of open files.
603 	 */
604 	nfiles++;
605 	MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
606 	bzero(fp, sizeof(struct file));
607 	if ((fq = p->p_fd->fd_ofiles[0]))
608 		fpp = &fq->f_filef;
609 	else
610 		fpp = &filehead;
611 	p->p_fd->fd_ofiles[i] = fp;
612 	if ((fq = *fpp))
613 		fq->f_fileb = &fp->f_filef;
614 	fp->f_filef = fq;
615 	fp->f_fileb = fpp;
616 	*fpp = fp;
617 	fp->f_count = 1;
618 	fp->f_cred = p->p_ucred;
619 	crhold(fp->f_cred);
620 	if (resultfp)
621 		*resultfp = fp;
622 	if (resultfd)
623 		*resultfd = i;
624 	return (0);
625 }
626 
627 /*
628  * Free a file descriptor.
629  */
630 void
631 ffree(fp)
632 	register struct file *fp;
633 {
634 	register struct file *fq;
635 
636 	if ((fq = fp->f_filef))
637 		fq->f_fileb = fp->f_fileb;
638 	*fp->f_fileb = fq;
639 	crfree(fp->f_cred);
640 #ifdef DIAGNOSTIC
641 	fp->f_filef = NULL;
642 	fp->f_fileb = NULL;
643 	fp->f_count = 0;
644 #endif
645 	nfiles--;
646 	FREE(fp, M_FILE);
647 }
648 
649 /*
650  * Copy a filedesc structure.
651  */
652 struct filedesc *
653 fdcopy(p)
654 	struct proc *p;
655 {
656 	register struct filedesc *newfdp, *fdp = p->p_fd;
657 	register struct file **fpp;
658 	register int i;
659 
660 	MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
661 	    M_FILEDESC, M_WAITOK);
662 	bcopy(fdp, newfdp, sizeof(struct filedesc));
663 	VREF(newfdp->fd_cdir);
664 	if (newfdp->fd_rdir)
665 		VREF(newfdp->fd_rdir);
666 	newfdp->fd_refcnt = 1;
667 
668 	/*
669 	 * If the number of open files fits in the internal arrays
670 	 * of the open file structure, use them, otherwise allocate
671 	 * additional memory for the number of descriptors currently
672 	 * in use.
673 	 */
674 	if (newfdp->fd_lastfile < NDFILE) {
675 		newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
676 		newfdp->fd_ofileflags =
677 		    ((struct filedesc0 *) newfdp)->fd_dfileflags;
678 		i = NDFILE;
679 	} else {
680 		/*
681 		 * Compute the smallest multiple of NDEXTENT needed
682 		 * for the file descriptors currently in use,
683 		 * allowing the table to shrink.
684 		 */
685 		i = newfdp->fd_nfiles;
686 		while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
687 			i /= 2;
688 		MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
689 		    M_FILEDESC, M_WAITOK);
690 		newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
691 	}
692 	newfdp->fd_nfiles = i;
693 	bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
694 	bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
695 	fpp = newfdp->fd_ofiles;
696 	for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
697 		if (*fpp != NULL)
698 			(*fpp)->f_count++;
699 	return (newfdp);
700 }
701 
702 /*
703  * Release a filedesc structure.
704  */
705 void
706 fdfree(p)
707 	struct proc *p;
708 {
709 	register struct filedesc *fdp = p->p_fd;
710 	struct file **fpp;
711 	register int i;
712 
713 	if (--fdp->fd_refcnt > 0)
714 		return;
715 	fpp = fdp->fd_ofiles;
716 	for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
717 		if (*fpp)
718 			(void) closef(*fpp, p);
719 	if (fdp->fd_nfiles > NDFILE)
720 		FREE(fdp->fd_ofiles, M_FILEDESC);
721 	vrele(fdp->fd_cdir);
722 	if (fdp->fd_rdir)
723 		vrele(fdp->fd_rdir);
724 	FREE(fdp, M_FILEDESC);
725 }
726 
727 /*
728  * Close any files on exec?
729  */
730 void
731 fdcloseexec(p)
732 	struct proc *p;
733 {
734 	struct filedesc *fdp = p->p_fd;
735 	struct file **fpp;
736 	char *fdfp;
737 	register int i;
738 
739 	fpp = fdp->fd_ofiles;
740 	fdfp = fdp->fd_ofileflags;
741 	for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
742 		if (*fpp != NULL && (*fdfp & UF_EXCLOSE)) {
743 			if (*fdfp & UF_MAPPED)
744 				(void) munmapfd(p, i);
745 			(void) closef(*fpp, p);
746 			*fpp = NULL;
747 			*fdfp = 0;
748 			if (i < fdp->fd_freefile)
749 				fdp->fd_freefile = i;
750 		}
751 	while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
752 		fdp->fd_lastfile--;
753 }
754 
755 /*
756  * Internal form of close.
757  * Decrement reference count on file structure.
758  * Note: p may be NULL when closing a file
759  * that was being passed in a message.
760  */
761 int
762 closef(fp, p)
763 	register struct file *fp;
764 	register struct proc *p;
765 {
766 	struct vnode *vp;
767 	struct flock lf;
768 	int error;
769 
770 	if (fp == NULL)
771 		return (0);
772 	/*
773 	 * POSIX record locking dictates that any close releases ALL
774 	 * locks owned by this process.  This is handled by setting
775 	 * a flag in the unlock to free ONLY locks obeying POSIX
776 	 * semantics, and not to free BSD-style file locks.
777 	 * If the descriptor was in a message, POSIX-style locks
778 	 * aren't passed with the descriptor.
779 	 */
780 	if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
781 		lf.l_whence = SEEK_SET;
782 		lf.l_start = 0;
783 		lf.l_len = 0;
784 		lf.l_type = F_UNLCK;
785 		vp = (struct vnode *)fp->f_data;
786 		(void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
787 	}
788 	if (--fp->f_count > 0)
789 		return (0);
790 	if (fp->f_count < 0)
791 		panic("closef: count < 0");
792 	if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
793 		lf.l_whence = SEEK_SET;
794 		lf.l_start = 0;
795 		lf.l_len = 0;
796 		lf.l_type = F_UNLCK;
797 		vp = (struct vnode *)fp->f_data;
798 		(void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
799 	}
800 	if (fp->f_ops)
801 		error = (*fp->f_ops->fo_close)(fp, p);
802 	else
803 		error = 0;
804 	ffree(fp);
805 	return (error);
806 }
807 
808 /*
809  * Apply an advisory lock on a file descriptor.
810  *
811  * Just attempt to get a record lock of the requested type on
812  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
813  */
814 struct flock_args {
815 	int	fd;
816 	int	how;
817 };
818 /* ARGSUSED */
819 int
820 flock(p, uap, retval)
821 	struct proc *p;
822 	register struct flock_args *uap;
823 	int *retval;
824 {
825 	register struct filedesc *fdp = p->p_fd;
826 	register struct file *fp;
827 	struct vnode *vp;
828 	struct flock lf;
829 
830 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
831 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
832 		return (EBADF);
833 	if (fp->f_type != DTYPE_VNODE)
834 		return (EOPNOTSUPP);
835 	vp = (struct vnode *)fp->f_data;
836 	lf.l_whence = SEEK_SET;
837 	lf.l_start = 0;
838 	lf.l_len = 0;
839 	if (uap->how & LOCK_UN) {
840 		lf.l_type = F_UNLCK;
841 		fp->f_flag &= ~FHASLOCK;
842 		return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
843 	}
844 	if (uap->how & LOCK_EX)
845 		lf.l_type = F_WRLCK;
846 	else if (uap->how & LOCK_SH)
847 		lf.l_type = F_RDLCK;
848 	else
849 		return (EBADF);
850 	fp->f_flag |= FHASLOCK;
851 	if (uap->how & LOCK_NB)
852 		return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
853 	return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
854 }
855 
856 /*
857  * File Descriptor pseudo-device driver (/dev/fd/).
858  *
859  * Opening minor device N dup()s the file (if any) connected to file
860  * descriptor N belonging to the calling process.  Note that this driver
861  * consists of only the ``open()'' routine, because all subsequent
862  * references to this file will be direct to the other driver.
863  */
864 /* ARGSUSED */
865 int
866 fdopen(dev, mode, type, p)
867 	dev_t dev;
868 	int mode, type;
869 	struct proc *p;
870 {
871 
872 	/*
873 	 * XXX Kludge: set curproc->p_dupfd to contain the value of the
874 	 * the file descriptor being sought for duplication. The error
875 	 * return ensures that the vnode for this device will be released
876 	 * by vn_open. Open will detect this special error and take the
877 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
878 	 * will simply report the error.
879 	 */
880 	p->p_dupfd = minor(dev);
881 	return (ENODEV);
882 }
883 
884 /*
885  * Duplicate the specified descriptor to a free descriptor.
886  */
887 int
888 dupfdopen(fdp, indx, dfd, mode, error)
889 	register struct filedesc *fdp;
890 	register int indx, dfd;
891 	int mode;
892 	int error;
893 {
894 	register struct file *wfp;
895 	struct file *fp;
896 
897 	/*
898 	 * If the to-be-dup'd fd number is greater than the allowed number
899 	 * of file descriptors, or the fd to be dup'd has already been
900 	 * closed, reject.  Note, check for new == old is necessary as
901 	 * falloc could allocate an already closed to-be-dup'd descriptor
902 	 * as the new descriptor.
903 	 */
904 	fp = fdp->fd_ofiles[indx];
905 	if ((u_int)dfd >= fdp->fd_nfiles ||
906 	    (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
907 		return (EBADF);
908 
909 	/*
910 	 * There are two cases of interest here.
911 	 *
912 	 * For ENODEV simply dup (dfd) to file descriptor
913 	 * (indx) and return.
914 	 *
915 	 * For ENXIO steal away the file structure from (dfd) and
916 	 * store it in (indx).  (dfd) is effectively closed by
917 	 * this operation.
918 	 *
919 	 * Any other error code is just returned.
920 	 */
921 	switch (error) {
922 	case ENODEV:
923 		/*
924 		 * Check that the mode the file is being opened for is a
925 		 * subset of the mode of the existing descriptor.
926 		 */
927 		if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
928 			return (EACCES);
929 		fdp->fd_ofiles[indx] = wfp;
930 		fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
931 		wfp->f_count++;
932 		if (indx > fdp->fd_lastfile)
933 			fdp->fd_lastfile = indx;
934 		return (0);
935 
936 	case ENXIO:
937 		/*
938 		 * Steal away the file pointer from dfd, and stuff it into indx.
939 		 */
940 		fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
941 		fdp->fd_ofiles[dfd] = NULL;
942 		fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
943 		fdp->fd_ofileflags[dfd] = 0;
944 		/*
945 		 * Complete the clean up of the filedesc structure by
946 		 * recomputing the various hints.
947 		 */
948 		if (indx > fdp->fd_lastfile)
949 			fdp->fd_lastfile = indx;
950 		else
951 			while (fdp->fd_lastfile > 0 &&
952 			       fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
953 				fdp->fd_lastfile--;
954 			if (dfd < fdp->fd_freefile)
955 				fdp->fd_freefile = dfd;
956 		return (0);
957 
958 	default:
959 		return (error);
960 	}
961 	/* NOTREACHED */
962 }
963