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