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