386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / kern_descrip.c
CommitLineData
9f5f59e3
WJ
1/*
2 * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)kern_descrip.c 7.28 (Berkeley) 6/25/91
34 */
35static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/kern_descrip.c,v 1.2 92/01/21 21:29:09 william Exp $";
36
37#include "param.h"
38#include "systm.h"
39#include "filedesc.h"
40#include "kernel.h"
41#include "vnode.h"
42#include "proc.h"
43#include "file.h"
44#include "socket.h"
45#include "socketvar.h"
46#include "stat.h"
47#include "ioctl.h"
48#include "fcntl.h"
49#include "malloc.h"
50#include "syslog.h"
51#include "resourcevar.h"
52
53/*
54 * Descriptor management.
55 */
56struct file *filehead; /* head of list of open files */
57int nfiles; /* actual number of open files */
58
59/*
60 * System calls on descriptors.
61 */
62/* ARGSUSED */
63getdtablesize(p, uap, retval)
64 struct proc *p;
65 struct args *uap;
66 int *retval;
67{
68
69 *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
70 return (0);
71}
72
73/*
74 * Duplicate a file descriptor.
75 */
76/* ARGSUSED */
77dup(p, uap, retval)
78 struct proc *p;
79 struct args {
80 int i;
81 } *uap;
82 int *retval;
83{
84 register struct filedesc *fdp = p->p_fd;
85 struct file *fp;
86 int fd, error;
87
88 /*
89 * XXX Compatibility
90 */
91 if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
92
93 if ((unsigned)uap->i >= fdp->fd_nfiles ||
94 (fp = fdp->fd_ofiles[uap->i]) == NULL)
95 return (EBADF);
96 if (error = fdalloc(p, 0, &fd))
97 return (error);
98 fdp->fd_ofiles[fd] = fp;
99 fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
100 fp->f_count++;
101 if (fd > fdp->fd_lastfile)
102 fdp->fd_lastfile = fd;
103 *retval = fd;
104 return (0);
105}
106
107/*
108 * Duplicate a file descriptor to a particular value.
109 */
110/* ARGSUSED */
111dup2(p, uap, retval)
112 struct proc *p;
113 struct args {
114 u_int from;
115 u_int to;
116 } *uap;
117 int *retval;
118{
119 register struct filedesc *fdp = p->p_fd;
120 register struct file *fp;
121 register u_int old = uap->from, new = uap->to;
122 int i, error;
123
124 if (old >= fdp->fd_nfiles ||
125 (fp = fdp->fd_ofiles[old]) == NULL ||
126 new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
127 return (EBADF);
128 *retval = new;
129 if (old == new)
130 return (0);
131 if (new >= fdp->fd_nfiles) {
132 if (error = fdalloc(p, new, &i))
133 return (error);
134 if (new != i)
135 panic("dup2: fdalloc");
136 } else if (fdp->fd_ofiles[new]) {
137 if (fdp->fd_ofileflags[new] & UF_MAPPED)
138 (void) munmapfd(p, new);
139 /*
140 * dup2() must succeed even if the close has an error.
141 */
142 (void) closef(fdp->fd_ofiles[new], p);
143 }
144 fdp->fd_ofiles[new] = fp;
145 fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
146 fp->f_count++;
147 if (new > fdp->fd_lastfile)
148 fdp->fd_lastfile = new;
149 return (0);
150}
151
152/*
153 * The file control system call.
154 */
155/* ARGSUSED */
156fcntl(p, uap, retval)
157 struct proc *p;
158 register struct args {
159 int fd;
160 int cmd;
161 int arg;
162 } *uap;
163 int *retval;
164{
165 register struct filedesc *fdp = p->p_fd;
166 register struct file *fp;
167 register char *pop;
168 struct vnode *vp;
169 int i, tmp, error, flg = F_POSIX;
170 struct flock fl;
171
172 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
173 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
174 return (EBADF);
175 pop = &fdp->fd_ofileflags[uap->fd];
176 switch(uap->cmd) {
177 case F_DUPFD:
178 if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
179 return (EINVAL);
180 if (error = fdalloc(p, uap->arg, &i))
181 return (error);
182 fdp->fd_ofiles[i] = fp;
183 fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE;
184 fp->f_count++;
185 if (i > fdp->fd_lastfile)
186 fdp->fd_lastfile = i;
187 *retval = i;
188 return (0);
189
190 case F_GETFD:
191 *retval = *pop & 1;
192 return (0);
193
194 case F_SETFD:
195 *pop = (*pop &~ 1) | (uap->arg & 1);
196 return (0);
197
198 case F_GETFL:
199 *retval = OFLAGS(fp->f_flag);
200 return (0);
201
202 case F_SETFL:
203 fp->f_flag &= ~FCNTLFLAGS;
204 fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
205 tmp = fp->f_flag & FNONBLOCK;
206 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
207 if (error)
208 return (error);
209 tmp = fp->f_flag & FASYNC;
210 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
211 if (!error)
212 return (0);
213 fp->f_flag &= ~FNONBLOCK;
214 tmp = 0;
215 (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
216 return (error);
217
218 case F_GETOWN:
219 if (fp->f_type == DTYPE_SOCKET) {
220 *retval = ((struct socket *)fp->f_data)->so_pgid;
221 return (0);
222 }
223 error = (*fp->f_ops->fo_ioctl)
224 (fp, (int)TIOCGPGRP, (caddr_t)retval, p);
225 *retval = -*retval;
226 return (error);
227
228 case F_SETOWN:
229 if (fp->f_type == DTYPE_SOCKET) {
230 ((struct socket *)fp->f_data)->so_pgid = uap->arg;
231 return (0);
232 }
233 if (uap->arg <= 0) {
234 uap->arg = -uap->arg;
235 } else {
236 struct proc *p1 = pfind(uap->arg);
237 if (p1 == 0)
238 return (ESRCH);
239 uap->arg = p1->p_pgrp->pg_id;
240 }
241 return ((*fp->f_ops->fo_ioctl)
242 (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
243
244 case F_SETLKW:
245 flg |= F_WAIT;
246 /* Fall into F_SETLK */
247
248 case F_SETLK:
249 if (fp->f_type != DTYPE_VNODE)
250 return (EBADF);
251 vp = (struct vnode *)fp->f_data;
252 /* Copy in the lock structure */
253 error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
254 if (error)
255 return (error);
256 if (fl.l_whence == SEEK_CUR)
257 fl.l_start += fp->f_offset;
258 switch (fl.l_type) {
259
260 case F_RDLCK:
261 if ((fp->f_flag & FREAD) == 0)
262 return (EBADF);
263 p->p_flag |= SADVLCK;
264 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
265
266 case F_WRLCK:
267 if ((fp->f_flag & FWRITE) == 0)
268 return (EBADF);
269 p->p_flag |= SADVLCK;
270 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
271
272 case F_UNLCK:
273 return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
274 F_POSIX));
275
276 default:
277 return (EINVAL);
278 }
279
280 case F_GETLK:
281 if (fp->f_type != DTYPE_VNODE)
282 return (EBADF);
283 vp = (struct vnode *)fp->f_data;
284 /* Copy in the lock structure */
285 error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
286 if (error)
287 return (error);
288 if (fl.l_whence == SEEK_CUR)
289 fl.l_start += fp->f_offset;
290 if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
291 return (error);
292 return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
293
294 default:
295 return (EINVAL);
296 }
297 /* NOTREACHED */
298}
299
300/*
301 * Close a file descriptor.
302 */
303/* ARGSUSED */
304close(p, uap, retval)
305 struct proc *p;
306 struct args {
307 int fd;
308 } *uap;
309 int *retval;
310{
311 register struct filedesc *fdp = p->p_fd;
312 register struct file *fp;
313 register int fd = uap->fd;
314 register u_char *pf;
315
316 if ((unsigned)fd >= fdp->fd_nfiles ||
317 (fp = fdp->fd_ofiles[fd]) == NULL)
318 return (EBADF);
319 pf = (u_char *)&fdp->fd_ofileflags[fd];
320 if (*pf & UF_MAPPED)
321 (void) munmapfd(p, fd);
322 fdp->fd_ofiles[fd] = NULL;
323 while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
324 fdp->fd_lastfile--;
325 if (fd < fdp->fd_freefile)
326 fdp->fd_freefile = fd;
327 *pf = 0;
328 return (closef(fp, p));
329}
330
331/*
332 * Return status information about a file descriptor.
333 */
334/* ARGSUSED */
335fstat(p, uap, retval)
336 struct proc *p;
337 register struct args {
338 int fd;
339 struct stat *sb;
340 } *uap;
341 int *retval;
342{
343 register struct filedesc *fdp = p->p_fd;
344 register struct file *fp;
345 struct stat ub;
346 int error;
347
348 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
349 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
350 return (EBADF);
351 switch (fp->f_type) {
352
353 case DTYPE_VNODE:
354 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
355 break;
356
357 case DTYPE_SOCKET:
358 error = soo_stat((struct socket *)fp->f_data, &ub);
359 break;
360
361 default:
362 panic("fstat");
363 /*NOTREACHED*/
364 }
365 if (error == 0)
366 error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
367 return (error);
368}
369
370/*
371 * Allocate a file descriptor for the process.
372 */
373int fdexpand;
374
375fdalloc(p, want, result)
376 struct proc *p;
377 int want;
378 int *result;
379{
380 register struct filedesc *fdp = p->p_fd;
381 register int i;
382 int lim, last, nfiles;
383 struct file **newofile;
384 char *newofileflags;
385
386 /*
387 * Search for a free descriptor starting at the higher
388 * of want or fd_freefile. If that fails, consider
389 * expanding the ofile array.
390 */
391 lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
392 for (;;) {
393 last = min(fdp->fd_nfiles, lim);
394 if ((i = want) < fdp->fd_freefile)
395 i = fdp->fd_freefile;
396 for (; i < last; i++) {
397 if (fdp->fd_ofiles[i] == NULL) {
398 fdp->fd_ofileflags[i] = 0;
399 if (i > fdp->fd_lastfile)
400 fdp->fd_lastfile = i;
401 if (want <= fdp->fd_freefile)
402 fdp->fd_freefile = i;
403 *result = i;
404 return (0);
405 }
406 }
407
408 /*
409 * No space in current array. Expand?
410 */
411 if (fdp->fd_nfiles >= lim)
412 return (EMFILE);
413 if (fdp->fd_nfiles < NDEXTENT)
414 nfiles = NDEXTENT;
415 else
416 nfiles = 2 * fdp->fd_nfiles;
417 MALLOC(newofile, struct file **, nfiles * OFILESIZE,
418 M_FILEDESC, M_WAITOK);
419 newofileflags = (char *) &newofile[nfiles];
420 /*
421 * Copy the existing ofile and ofileflags arrays
422 * and zero the new portion of each array.
423 */
424 bcopy(fdp->fd_ofiles, newofile,
425 (i = sizeof(struct file *) * fdp->fd_nfiles));
426 bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
427 bcopy(fdp->fd_ofileflags, newofileflags,
428 (i = sizeof(char) * fdp->fd_nfiles));
429 bzero(newofileflags + i, nfiles * sizeof(char) - i);
430 if (fdp->fd_nfiles > NDFILE)
431 FREE(fdp->fd_ofiles, M_FILEDESC);
432 fdp->fd_ofiles = newofile;
433 fdp->fd_ofileflags = newofileflags;
434 fdp->fd_nfiles = nfiles;
435 fdexpand++;
436 }
437}
438
439/*
440 * Check to see whether n user file descriptors
441 * are available to the process p.
442 */
443fdavail(p, n)
444 struct proc *p;
445 register int n;
446{
447 register struct filedesc *fdp = p->p_fd;
448 register struct file **fpp;
449 register int i;
450
451 if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 &&
452 (n -= i) <= 0)
453 return (1);
454 fpp = &fdp->fd_ofiles[fdp->fd_freefile];
455 for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
456 if (*fpp == NULL && --n <= 0)
457 return (1);
458 return (0);
459}
460
461/*
462 * Create a new open file structure and allocate
463 * a file decriptor for the process that refers to it.
464 */
465falloc(p, resultfp, resultfd)
466 register struct proc *p;
467 struct file **resultfp;
468 int *resultfd;
469{
470 register struct file *fp, *fq, **fpp;
471 int error, i;
472
473 if (error = fdalloc(p, 0, &i))
474 return (error);
475 if (nfiles >= maxfiles) {
476 tablefull("file");
477 return (ENFILE);
478 }
479 /*
480 * Allocate a new file descriptor.
481 * If the process has file descriptor zero open, add to the list
482 * of open files at that point, otherwise put it at the front of
483 * the list of open files.
484 */
485 nfiles++;
486 MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
487 if (fq = p->p_fd->fd_ofiles[0])
488 fpp = &fq->f_filef;
489 else
490 fpp = &filehead;
491 p->p_fd->fd_ofiles[i] = fp;
492 if (fq = *fpp)
493 fq->f_fileb = &fp->f_filef;
494 fp->f_filef = fq;
495 fp->f_fileb = fpp;
496 *fpp = fp;
497 fp->f_count = 1;
498 fp->f_msgcount = 0;
499 fp->f_offset = 0;
500 fp->f_cred = p->p_ucred;
501 crhold(fp->f_cred);
502 if (resultfp)
503 *resultfp = fp;
504 if (resultfd)
505 *resultfd = i;
506 return (0);
507}
508
509/*
510 * Free a file descriptor.
511 */
512ffree(fp)
513 register struct file *fp;
514{
515 register struct file *fq;
516
517 if (fq = fp->f_filef)
518 fq->f_fileb = fp->f_fileb;
519 *fp->f_fileb = fq;
520 crfree(fp->f_cred);
521#ifdef DIAGNOSTIC
522 fp->f_filef = NULL;
523 fp->f_fileb = NULL;
524 fp->f_count = 0;
525#endif
526 nfiles--;
527 FREE(fp, M_FILE);
528}
529
530/*
531 * Copy a filedesc structure.
532 */
533struct filedesc *
534fdcopy(p)
535 struct proc *p;
536{
537 register struct filedesc *newfdp, *fdp = p->p_fd;
538 register struct file **fpp;
539 register int i;
540
541 MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
542 M_FILEDESC, M_WAITOK);
543 bcopy(fdp, newfdp, sizeof(struct filedesc));
544 VREF(newfdp->fd_cdir);
545 if (newfdp->fd_rdir)
546 VREF(newfdp->fd_rdir);
547 newfdp->fd_refcnt = 1;
548
549 /*
550 * If the number of open files fits in the internal arrays
551 * of the open file structure, use them, otherwise allocate
552 * additional memory for the number of descriptors currently
553 * in use.
554 */
555 if (newfdp->fd_lastfile < NDFILE) {
556 newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
557 newfdp->fd_ofileflags =
558 ((struct filedesc0 *) newfdp)->fd_dfileflags;
559 i = NDFILE;
560 } else {
561 /*
562 * Compute the smallest multiple of NDEXTENT needed
563 * for the file descriptors currently in use,
564 * allowing the table to shrink.
565 */
566 i = newfdp->fd_nfiles;
567 while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2)
568 i /= 2;
569 MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
570 M_FILEDESC, M_WAITOK);
571 newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
572 }
573 newfdp->fd_nfiles = i;
574 bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
575 bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
576 fpp = newfdp->fd_ofiles;
577 for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
578 if (*fpp != NULL)
579 (*fpp)->f_count++;
580 return (newfdp);
581}
582
583/*
584 * Release a filedesc structure.
585 */
586void
587fdfree(p)
588 struct proc *p;
589{
590 register struct filedesc *fdp = p->p_fd;
591 struct file **fpp;
592 char *fdfp;
593 register int i;
594
595 if (--fdp->fd_refcnt > 0)
596 return;
597 fpp = fdp->fd_ofiles;
598 fdfp = fdp->fd_ofileflags;
599 for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
600 if (*fpp != NULL) {
601 if (*fdfp & UF_MAPPED)
602 (void) munmapfd(p, i);
603 (void) closef(*fpp, p);
604 }
605 if (fdp->fd_nfiles > NDFILE)
606 FREE(fdp->fd_ofiles, M_FILEDESC);
607 vrele(fdp->fd_cdir);
608 if (fdp->fd_rdir)
609 vrele(fdp->fd_rdir);
610 FREE(fdp, M_FILEDESC);
611}
612
613/*
614 * Close any files on exec?
615 */
616void
617fdcloseexec(p)
618 struct proc *p;
619{
620 struct filedesc *fdp = p->p_fd;
621 struct file **fpp;
622 char *fdfp;
623 register int i;
624
625 fpp = fdp->fd_ofiles;
626 fdfp = fdp->fd_ofileflags;
627 for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
628 if (*fpp != NULL && (*fdfp & UF_EXCLOSE)) {
629 if (*fdfp & UF_MAPPED)
630 (void) munmapfd(p, i);
631 (void) closef(*fpp, p);
632 *fpp = NULL;
633 *fdfp = 0;
634 if (i < fdp->fd_freefile)
635 fdp->fd_freefile = i;
636 }
637 while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
638 fdp->fd_lastfile--;
639}
640
641/*
642 * Internal form of close.
643 * Decrement reference count on file structure.
644 */
645closef(fp, p)
646 register struct file *fp;
647 register struct proc *p;
648{
649 struct vnode *vp;
650 struct flock lf;
651 int error;
652
653 if (fp == NULL)
654 return (0);
655 /*
656 * POSIX record locking dictates that any close releases ALL
657 * locks owned by this process. This is handled by setting
658 * a flag in the unlock to free ONLY locks obeying POSIX
659 * semantics, and not to free BSD-style file locks.
660 */
661 if ((p->p_flag & SADVLCK) && fp->f_type == DTYPE_VNODE) {
662 lf.l_whence = SEEK_SET;
663 lf.l_start = 0;
664 lf.l_len = 0;
665 lf.l_type = F_UNLCK;
666 vp = (struct vnode *)fp->f_data;
667 (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
668 }
669 if (--fp->f_count > 0)
670 return (0);
671 if (fp->f_count < 0)
672 panic("closef: count < 0");
673 if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
674 lf.l_whence = SEEK_SET;
675 lf.l_start = 0;
676 lf.l_len = 0;
677 lf.l_type = F_UNLCK;
678 vp = (struct vnode *)fp->f_data;
679 (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
680 }
681 error = (*fp->f_ops->fo_close)(fp, p);
682 ffree(fp);
683 return (error);
684}
685
686/*
687 * Apply an advisory lock on a file descriptor.
688 *
689 * Just attempt to get a record lock of the requested type on
690 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
691 */
692
693/* ARGSUSED */
694flock(p, uap, retval)
695 struct proc *p;
696 register struct args {
697 int fd;
698 int how;
699 } *uap;
700 int *retval;
701{
702 register struct filedesc *fdp = p->p_fd;
703 register struct file *fp;
704 struct vnode *vp;
705 struct flock lf;
706 int error;
707
708 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
709 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
710 return (EBADF);
711 if (fp->f_type != DTYPE_VNODE)
712 return (EOPNOTSUPP);
713 vp = (struct vnode *)fp->f_data;
714 lf.l_whence = SEEK_SET;
715 lf.l_start = 0;
716 lf.l_len = 0;
717 if (uap->how & LOCK_UN) {
718 lf.l_type = F_UNLCK;
719 fp->f_flag &= ~FHASLOCK;
720 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
721 }
722 if (uap->how & LOCK_EX)
723 lf.l_type = F_WRLCK;
724 else if (uap->how & LOCK_SH)
725 lf.l_type = F_RDLCK;
726 else
727 return (EBADF);
728 fp->f_flag |= FHASLOCK;
729 if (uap->how & LOCK_NB)
730 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
731 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
732}
733
734/*
735 * File Descriptor pseudo-device driver (/dev/fd/).
736 *
737 * Opening minor device N dup()s the file (if any) connected to file
738 * descriptor N belonging to the calling process. Note that this driver
739 * consists of only the ``open()'' routine, because all subsequent
740 * references to this file will be direct to the other driver.
741 */
742/* ARGSUSED */
743fdopen(dev, mode, type)
744 dev_t dev;
745 int mode, type;
746{
747
748 /*
749 * XXX Kludge: set curproc->p_dupfd to contain the value of the
750 * the file descriptor being sought for duplication. The error
751 * return ensures that the vnode for this device will be released
752 * by vn_open. Open will detect this special error and take the
753 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
754 * will simply report the error.
755 */
756 curproc->p_dupfd = minor(dev); /* XXX */
757 return (ENODEV);
758}
759
760/*
761 * Duplicate the specified descriptor to a free descriptor.
762 */
763dupfdopen(fdp, indx, dfd, mode)
764 register struct filedesc *fdp;
765 register int indx, dfd;
766 int mode;
767{
768 register struct file *wfp;
769 struct file *fp;
770
771 /*
772 * If the to-be-dup'd fd number is greater than the allowed number
773 * of file descriptors, or the fd to be dup'd has already been
774 * closed, reject. Note, check for new == old is necessary as
775 * falloc could allocate an already closed to-be-dup'd descriptor
776 * as the new descriptor.
777 */
778 fp = fdp->fd_ofiles[indx];
779 if ((u_int)dfd >= fdp->fd_nfiles ||
780 (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
781 return (EBADF);
782
783 /*
784 * Check that the mode the file is being opened for is a subset
785 * of the mode of the existing descriptor.
786 */
787 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
788 return (EACCES);
789 fdp->fd_ofiles[indx] = wfp;
790 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
791 wfp->f_count++;
792 if (indx > fdp->fd_lastfile)
793 fdp->fd_lastfile = indx;
794 return (0);
795}