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