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