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