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