xref: /original-bsd/sys/kern/kern_descrip.c (revision e58c8952)
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.6 (Berkeley) 04/19/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 file *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, **fpp;
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 		fpp = &fq->f_filef;
568 	else
569 		fpp = &filehead;
570 	p->p_fd->fd_ofiles[i] = fp;
571 	if (fq = *fpp)
572 		fq->f_fileb = &fp->f_filef;
573 	fp->f_filef = fq;
574 	fp->f_fileb = fpp;
575 	*fpp = fp;
576 	fp->f_count = 1;
577 	fp->f_cred = p->p_ucred;
578 	crhold(fp->f_cred);
579 	if (resultfp)
580 		*resultfp = fp;
581 	if (resultfd)
582 		*resultfd = i;
583 	return (0);
584 }
585 
586 /*
587  * Free a file descriptor.
588  */
589 ffree(fp)
590 	register struct file *fp;
591 {
592 	register struct file *fq;
593 
594 	if (fq = fp->f_filef)
595 		fq->f_fileb = fp->f_fileb;
596 	*fp->f_fileb = fq;
597 	crfree(fp->f_cred);
598 #ifdef DIAGNOSTIC
599 	fp->f_filef = NULL;
600 	fp->f_fileb = NULL;
601 	fp->f_count = 0;
602 #endif
603 	nfiles--;
604 	FREE(fp, M_FILE);
605 }
606 
607 /*
608  * Copy a filedesc structure.
609  */
610 struct filedesc *
611 fdcopy(p)
612 	struct proc *p;
613 {
614 	register struct filedesc *newfdp, *fdp = p->p_fd;
615 	register struct file **fpp;
616 	register int i;
617 
618 	MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
619 	    M_FILEDESC, M_WAITOK);
620 	bcopy(fdp, newfdp, sizeof(struct filedesc));
621 	VREF(newfdp->fd_cdir);
622 	if (newfdp->fd_rdir)
623 		VREF(newfdp->fd_rdir);
624 	newfdp->fd_refcnt = 1;
625 
626 	/*
627 	 * If the number of open files fits in the internal arrays
628 	 * of the open file structure, use them, otherwise allocate
629 	 * additional memory for the number of descriptors currently
630 	 * in use.
631 	 */
632 	if (newfdp->fd_lastfile < NDFILE) {
633 		newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
634 		newfdp->fd_ofileflags =
635 		    ((struct filedesc0 *) newfdp)->fd_dfileflags;
636 		i = NDFILE;
637 	} else {
638 		/*
639 		 * Compute the smallest multiple of NDEXTENT needed
640 		 * for the file descriptors currently in use,
641 		 * allowing the table to shrink.
642 		 */
643 		i = newfdp->fd_nfiles;
644 		while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
645 			i /= 2;
646 		MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
647 		    M_FILEDESC, M_WAITOK);
648 		newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
649 	}
650 	newfdp->fd_nfiles = i;
651 	bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
652 	bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
653 	fpp = newfdp->fd_ofiles;
654 	for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
655 		if (*fpp != NULL)
656 			(*fpp)->f_count++;
657 	return (newfdp);
658 }
659 
660 /*
661  * Release a filedesc structure.
662  */
663 void
664 fdfree(p)
665 	struct proc *p;
666 {
667 	register struct filedesc *fdp = p->p_fd;
668 	struct file **fpp;
669 	register int i;
670 
671 	if (--fdp->fd_refcnt > 0)
672 		return;
673 	fpp = fdp->fd_ofiles;
674 	for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
675 		if (*fpp)
676 			(void) closef(*fpp, p);
677 	if (fdp->fd_nfiles > NDFILE)
678 		FREE(fdp->fd_ofiles, M_FILEDESC);
679 	vrele(fdp->fd_cdir);
680 	if (fdp->fd_rdir)
681 		vrele(fdp->fd_rdir);
682 	FREE(fdp, M_FILEDESC);
683 }
684 
685 /*
686  * Internal form of close.
687  * Decrement reference count on file structure.
688  * Note: p may be NULL when closing a file
689  * that was being passed in a message.
690  */
691 closef(fp, p)
692 	register struct file *fp;
693 	register struct proc *p;
694 {
695 	struct vnode *vp;
696 	struct flock lf;
697 	int error;
698 
699 	if (fp == NULL)
700 		return (0);
701 	/*
702 	 * POSIX record locking dictates that any close releases ALL
703 	 * locks owned by this process.  This is handled by setting
704 	 * a flag in the unlock to free ONLY locks obeying POSIX
705 	 * semantics, and not to free BSD-style file locks.
706 	 * If the descriptor was in a message, POSIX-style locks
707 	 * aren't passed with the descriptor.
708 	 */
709 	if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
710 		lf.l_whence = SEEK_SET;
711 		lf.l_start = 0;
712 		lf.l_len = 0;
713 		lf.l_type = F_UNLCK;
714 		vp = (struct vnode *)fp->f_data;
715 		(void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
716 	}
717 	if (--fp->f_count > 0)
718 		return (0);
719 	if (fp->f_count < 0)
720 		panic("closef: count < 0");
721 	if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
722 		lf.l_whence = SEEK_SET;
723 		lf.l_start = 0;
724 		lf.l_len = 0;
725 		lf.l_type = F_UNLCK;
726 		vp = (struct vnode *)fp->f_data;
727 		(void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
728 	}
729 	if (fp->f_ops)
730 		error = (*fp->f_ops->fo_close)(fp, p);
731 	else
732 		error = 0;
733 	ffree(fp);
734 	return (error);
735 }
736 
737 /*
738  * Apply an advisory lock on a file descriptor.
739  *
740  * Just attempt to get a record lock of the requested type on
741  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
742  */
743 struct flock_args {
744 	int	fd;
745 	int	how;
746 };
747 /* ARGSUSED */
748 flock(p, uap, retval)
749 	struct proc *p;
750 	register struct flock_args *uap;
751 	int *retval;
752 {
753 	register struct filedesc *fdp = p->p_fd;
754 	register struct file *fp;
755 	struct vnode *vp;
756 	struct flock lf;
757 
758 	if ((unsigned)uap->fd >= fdp->fd_nfiles ||
759 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
760 		return (EBADF);
761 	if (fp->f_type != DTYPE_VNODE)
762 		return (EOPNOTSUPP);
763 	vp = (struct vnode *)fp->f_data;
764 	lf.l_whence = SEEK_SET;
765 	lf.l_start = 0;
766 	lf.l_len = 0;
767 	if (uap->how & LOCK_UN) {
768 		lf.l_type = F_UNLCK;
769 		fp->f_flag &= ~FHASLOCK;
770 		return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
771 	}
772 	if (uap->how & LOCK_EX)
773 		lf.l_type = F_WRLCK;
774 	else if (uap->how & LOCK_SH)
775 		lf.l_type = F_RDLCK;
776 	else
777 		return (EBADF);
778 	fp->f_flag |= FHASLOCK;
779 	if (uap->how & LOCK_NB)
780 		return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
781 	return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
782 }
783 
784 /*
785  * File Descriptor pseudo-device driver (/dev/fd/).
786  *
787  * Opening minor device N dup()s the file (if any) connected to file
788  * descriptor N belonging to the calling process.  Note that this driver
789  * consists of only the ``open()'' routine, because all subsequent
790  * references to this file will be direct to the other driver.
791  */
792 /* ARGSUSED */
793 fdopen(dev, mode, type, p)
794 	dev_t dev;
795 	int mode, type;
796 	struct proc *p;
797 {
798 
799 	/*
800 	 * XXX Kludge: set curproc->p_dupfd to contain the value of the
801 	 * the file descriptor being sought for duplication. The error
802 	 * return ensures that the vnode for this device will be released
803 	 * by vn_open. Open will detect this special error and take the
804 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
805 	 * will simply report the error.
806 	 */
807 	p->p_dupfd = minor(dev);
808 	return (ENODEV);
809 }
810 
811 /*
812  * Duplicate the specified descriptor to a free descriptor.
813  */
814 dupfdopen(fdp, indx, dfd, mode, error)
815 	register struct filedesc *fdp;
816 	register int indx, dfd;
817 	int mode;
818 	int error;
819 {
820 	register struct file *wfp;
821 	struct file *fp;
822 
823 	/*
824 	 * If the to-be-dup'd fd number is greater than the allowed number
825 	 * of file descriptors, or the fd to be dup'd has already been
826 	 * closed, reject.  Note, check for new == old is necessary as
827 	 * falloc could allocate an already closed to-be-dup'd descriptor
828 	 * as the new descriptor.
829 	 */
830 	fp = fdp->fd_ofiles[indx];
831 	if ((u_int)dfd >= fdp->fd_nfiles ||
832 	    (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
833 		return (EBADF);
834 
835 	/*
836 	 * There are two cases of interest here.
837 	 *
838 	 * For ENODEV simply dup (dfd) to file descriptor
839 	 * (indx) and return.
840 	 *
841 	 * For ENXIO steal away the file structure from (dfd) and
842 	 * store it in (indx).  (dfd) is effectively closed by
843 	 * this operation.
844 	 *
845 	 * Any other error code is just returned.
846 	 */
847 	switch (error) {
848 	case ENODEV:
849 		/*
850 		 * Check that the mode the file is being opened for is a
851 		 * subset of the mode of the existing descriptor.
852 		 */
853 		if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
854 			return (EACCES);
855 		fdp->fd_ofiles[indx] = wfp;
856 		fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
857 		wfp->f_count++;
858 		if (indx > fdp->fd_lastfile)
859 			fdp->fd_lastfile = indx;
860 		return (0);
861 
862 	case ENXIO:
863 		/*
864 		 * Steal away the file pointer from dfd, and stuff it into indx.
865 		 */
866 		fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
867 		fdp->fd_ofiles[dfd] = NULL;
868 		fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
869 		fdp->fd_ofileflags[dfd] = 0;
870 		/*
871 		 * Complete the clean up of the filedesc structure by
872 		 * recomputing the various hints.
873 		 */
874 		if (indx > fdp->fd_lastfile)
875 			fdp->fd_lastfile = indx;
876 		else
877 			while (fdp->fd_lastfile > 0 &&
878 			       fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
879 				fdp->fd_lastfile--;
880 			if (dfd < fdp->fd_freefile)
881 				fdp->fd_freefile = dfd;
882 		return (0);
883 
884 	default:
885 		return (error);
886 	}
887 	/* NOTREACHED */
888 }
889