This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[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 *
78ed81a3 33 * from: @(#)kern_descrip.c 7.28 (Berkeley) 6/25/91
34 * $Id$
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
53/*
54 * Descriptor management.
55 */
56struct file *filehead; /* head of list of open files */
57int nfiles; /* actual number of open files */
78ed81a3 58extern int maxfdescs; /* maximum number of file descriptors to a process */
15637ed4
RG
59
60/*
61 * System calls on descriptors.
62 */
63/* ARGSUSED */
64getdtablesize(p, uap, retval)
65 struct proc *p;
66 struct args *uap;
67 int *retval;
68{
69
70 *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
71 return (0);
72}
73
74/*
75 * Duplicate a file descriptor.
76 */
78ed81a3 77
78struct dup_args {
79 int i;
80};
81
15637ed4
RG
82/* ARGSUSED */
83dup(p, uap, retval)
84 struct proc *p;
78ed81a3 85 struct dup_args *uap;
15637ed4
RG
86 int *retval;
87{
88 register struct filedesc *fdp = p->p_fd;
89 struct file *fp;
90 int fd, error;
91
92 /*
93 * XXX Compatibility
94 */
95 if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
96
97 if ((unsigned)uap->i >= fdp->fd_nfiles ||
98 (fp = fdp->fd_ofiles[uap->i]) == NULL)
99 return (EBADF);
100 if (error = fdalloc(p, 0, &fd))
101 return (error);
102 fdp->fd_ofiles[fd] = fp;
103 fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
104 fp->f_count++;
105 if (fd > fdp->fd_lastfile)
106 fdp->fd_lastfile = fd;
107 *retval = fd;
108 return (0);
109}
110
111/*
112 * Duplicate a file descriptor to a particular value.
113 */
78ed81a3 114
115struct dup2_args {
116 u_int from;
117 u_int to;
118};
119
15637ed4
RG
120/* ARGSUSED */
121dup2(p, uap, retval)
122 struct proc *p;
78ed81a3 123 struct dup2_args *uap;
15637ed4
RG
124 int *retval;
125{
126 register struct filedesc *fdp = p->p_fd;
127 register struct file *fp;
128 register u_int old = uap->from, new = uap->to;
129 int i, error;
130
131 if (old >= fdp->fd_nfiles ||
132 (fp = fdp->fd_ofiles[old]) == NULL ||
78ed81a3 133 new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur ||
134 new >= maxfdescs)
15637ed4
RG
135 return (EBADF);
136 *retval = new;
137 if (old == new)
138 return (0);
139 if (new >= fdp->fd_nfiles) {
140 if (error = fdalloc(p, new, &i))
141 return (error);
142 if (new != i)
143 panic("dup2: fdalloc");
144 } else if (fdp->fd_ofiles[new]) {
145 if (fdp->fd_ofileflags[new] & UF_MAPPED)
146 (void) munmapfd(p, new);
147 /*
148 * dup2() must succeed even if the close has an error.
149 */
150 (void) closef(fdp->fd_ofiles[new], p);
151 }
152 fdp->fd_ofiles[new] = fp;
153 fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
154 fp->f_count++;
155 if (new > fdp->fd_lastfile)
156 fdp->fd_lastfile = new;
157 return (0);
158}
159
160/*
161 * The file control system call.
162 */
78ed81a3 163
164struct fcntl_args {
165 int fd;
166 int cmd;
167 int arg;
168};
169
15637ed4
RG
170/* ARGSUSED */
171fcntl(p, uap, retval)
172 struct proc *p;
78ed81a3 173 register struct fcntl_args *uap;
15637ed4
RG
174 int *retval;
175{
176 register struct filedesc *fdp = p->p_fd;
177 register struct file *fp;
178 register char *pop;
179 struct vnode *vp;
180 int i, tmp, error, flg = F_POSIX;
181 struct flock fl;
182
183 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
184 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
185 return (EBADF);
186 pop = &fdp->fd_ofileflags[uap->fd];
187 switch(uap->cmd) {
188 case F_DUPFD:
78ed81a3 189 if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur ||
190 ((unsigned)uap->arg >= maxfdescs))
15637ed4
RG
191 return (EINVAL);
192 if (error = fdalloc(p, uap->arg, &i))
193 return (error);
194 fdp->fd_ofiles[i] = fp;
195 fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE;
196 fp->f_count++;
197 if (i > fdp->fd_lastfile)
198 fdp->fd_lastfile = i;
199 *retval = i;
200 return (0);
201
202 case F_GETFD:
203 *retval = *pop & 1;
204 return (0);
205
206 case F_SETFD:
207 *pop = (*pop &~ 1) | (uap->arg & 1);
208 return (0);
209
210 case F_GETFL:
211 *retval = OFLAGS(fp->f_flag);
212 return (0);
213
214 case F_SETFL:
215 fp->f_flag &= ~FCNTLFLAGS;
216 fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
217 tmp = fp->f_flag & FNONBLOCK;
218 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
219 if (error)
220 return (error);
221 tmp = fp->f_flag & FASYNC;
222 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
223 if (!error)
224 return (0);
225 fp->f_flag &= ~FNONBLOCK;
226 tmp = 0;
227 (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
228 return (error);
229
230 case F_GETOWN:
231 if (fp->f_type == DTYPE_SOCKET) {
232 *retval = ((struct socket *)fp->f_data)->so_pgid;
233 return (0);
234 }
235 error = (*fp->f_ops->fo_ioctl)
236 (fp, (int)TIOCGPGRP, (caddr_t)retval, p);
237 *retval = -*retval;
238 return (error);
239
240 case F_SETOWN:
241 if (fp->f_type == DTYPE_SOCKET) {
242 ((struct socket *)fp->f_data)->so_pgid = uap->arg;
243 return (0);
244 }
245 if (uap->arg <= 0) {
246 uap->arg = -uap->arg;
247 } else {
248 struct proc *p1 = pfind(uap->arg);
249 if (p1 == 0)
250 return (ESRCH);
251 uap->arg = p1->p_pgrp->pg_id;
252 }
253 return ((*fp->f_ops->fo_ioctl)
254 (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
255
256 case F_SETLKW:
257 flg |= F_WAIT;
258 /* Fall into F_SETLK */
259
260 case F_SETLK:
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 switch (fl.l_type) {
271
272 case F_RDLCK:
273 if ((fp->f_flag & FREAD) == 0)
274 return (EBADF);
275 p->p_flag |= SADVLCK;
276 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
277
278 case F_WRLCK:
279 if ((fp->f_flag & FWRITE) == 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_UNLCK:
285 return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
286 F_POSIX));
287
288 default:
289 return (EINVAL);
290 }
291
292 case F_GETLK:
293 if (fp->f_type != DTYPE_VNODE)
294 return (EBADF);
295 vp = (struct vnode *)fp->f_data;
296 /* Copy in the lock structure */
297 error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
298 if (error)
299 return (error);
300 if (fl.l_whence == SEEK_CUR)
301 fl.l_start += fp->f_offset;
302 if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
303 return (error);
304 return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
305
306 default:
307 return (EINVAL);
308 }
309 /* NOTREACHED */
310}
311
312/*
313 * Close a file descriptor.
314 */
315/* ARGSUSED */
78ed81a3 316struct close_args {
317 int fd;
318};
319
15637ed4
RG
320close(p, uap, retval)
321 struct proc *p;
78ed81a3 322 struct close_args *uap;
15637ed4
RG
323 int *retval;
324{
325 register struct filedesc *fdp = p->p_fd;
326 register struct file *fp;
327 register int fd = uap->fd;
328 register u_char *pf;
329
330 if ((unsigned)fd >= fdp->fd_nfiles ||
331 (fp = fdp->fd_ofiles[fd]) == NULL)
332 return (EBADF);
333 pf = (u_char *)&fdp->fd_ofileflags[fd];
334 if (*pf & UF_MAPPED)
335 (void) munmapfd(p, fd);
336 fdp->fd_ofiles[fd] = NULL;
337 while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
338 fdp->fd_lastfile--;
339 if (fd < fdp->fd_freefile)
340 fdp->fd_freefile = fd;
341 *pf = 0;
342 return (closef(fp, p));
343}
344
345/*
346 * Return status information about a file descriptor.
347 */
78ed81a3 348
349struct fstat_args {
350 int fd;
351 struct stat *sb;
352};
353
15637ed4
RG
354/* ARGSUSED */
355fstat(p, uap, retval)
356 struct proc *p;
78ed81a3 357 register struct fstat_args *uap;
15637ed4
RG
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 */
390int fdexpand;
391
392fdalloc(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 */
460fdavail(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 */
482falloc(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 */
529ffree(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 */
550struct filedesc *
551fdcopy(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 */
603void
604fdfree(p)
605 struct proc *p;
606{
607 register struct filedesc *fdp = p->p_fd;
608 struct file **fpp;
609 char *fdfp;
610 register int i;
611
612 if (--fdp->fd_refcnt > 0)
613 return;
614 fpp = fdp->fd_ofiles;
615 fdfp = fdp->fd_ofileflags;
616 for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
617 if (*fpp != NULL) {
618 if (*fdfp & UF_MAPPED)
619 (void) munmapfd(p, i);
620 (void) closef(*fpp, p);
621 }
622 if (fdp->fd_nfiles > NDFILE)
623 FREE(fdp->fd_ofiles, M_FILEDESC);
624 vrele(fdp->fd_cdir);
625 if (fdp->fd_rdir)
626 vrele(fdp->fd_rdir);
627 FREE(fdp, M_FILEDESC);
628}
629
630/*
631 * Close any files on exec?
632 */
633void
634fdcloseexec(p)
635 struct proc *p;
636{
637 struct filedesc *fdp = p->p_fd;
638 struct file **fpp;
639 char *fdfp;
640 register int i;
641
642 fpp = fdp->fd_ofiles;
643 fdfp = fdp->fd_ofileflags;
644 for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
645 if (*fpp != NULL && (*fdfp & UF_EXCLOSE)) {
646 if (*fdfp & UF_MAPPED)
647 (void) munmapfd(p, i);
648 (void) closef(*fpp, p);
649 *fpp = NULL;
650 *fdfp = 0;
651 if (i < fdp->fd_freefile)
652 fdp->fd_freefile = i;
653 }
654 while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
655 fdp->fd_lastfile--;
656}
657
658/*
659 * Internal form of close.
660 * Decrement reference count on file structure.
661 */
662closef(fp, p)
663 register struct file *fp;
664 register struct proc *p;
665{
666 struct vnode *vp;
667 struct flock lf;
668 int error;
669
670 if (fp == NULL)
671 return (0);
672 /*
673 * POSIX record locking dictates that any close releases ALL
674 * locks owned by this process. This is handled by setting
675 * a flag in the unlock to free ONLY locks obeying POSIX
676 * semantics, and not to free BSD-style file locks.
677 */
678 if ((p->p_flag & SADVLCK) && fp->f_type == DTYPE_VNODE) {
679 lf.l_whence = SEEK_SET;
680 lf.l_start = 0;
681 lf.l_len = 0;
682 lf.l_type = F_UNLCK;
683 vp = (struct vnode *)fp->f_data;
684 (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
685 }
686 if (--fp->f_count > 0)
687 return (0);
688 if (fp->f_count < 0)
689 panic("closef: count < 0");
690 if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
691 lf.l_whence = SEEK_SET;
692 lf.l_start = 0;
693 lf.l_len = 0;
694 lf.l_type = F_UNLCK;
695 vp = (struct vnode *)fp->f_data;
696 (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
697 }
698 error = (*fp->f_ops->fo_close)(fp, p);
699 ffree(fp);
700 return (error);
701}
702
703/*
704 * Apply an advisory lock on a file descriptor.
705 *
706 * Just attempt to get a record lock of the requested type on
707 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
708 */
709
78ed81a3 710struct flock_args {
711 int fd;
712 int how;
713};
714
15637ed4
RG
715/* ARGSUSED */
716flock(p, uap, retval)
717 struct proc *p;
78ed81a3 718 register struct flock_args *uap;
15637ed4
RG
719 int *retval;
720{
721 register struct filedesc *fdp = p->p_fd;
722 register struct file *fp;
723 struct vnode *vp;
724 struct flock lf;
725 int error;
726
727 if ((unsigned)uap->fd >= fdp->fd_nfiles ||
728 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
729 return (EBADF);
730 if (fp->f_type != DTYPE_VNODE)
731 return (EOPNOTSUPP);
732 vp = (struct vnode *)fp->f_data;
733 lf.l_whence = SEEK_SET;
734 lf.l_start = 0;
735 lf.l_len = 0;
736 if (uap->how & LOCK_UN) {
737 lf.l_type = F_UNLCK;
738 fp->f_flag &= ~FHASLOCK;
739 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
740 }
741 if (uap->how & LOCK_EX)
742 lf.l_type = F_WRLCK;
743 else if (uap->how & LOCK_SH)
744 lf.l_type = F_RDLCK;
745 else
746 return (EBADF);
747 fp->f_flag |= FHASLOCK;
748 if (uap->how & LOCK_NB)
749 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
750 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
751}
752
753/*
754 * File Descriptor pseudo-device driver (/dev/fd/).
755 *
756 * Opening minor device N dup()s the file (if any) connected to file
757 * descriptor N belonging to the calling process. Note that this driver
758 * consists of only the ``open()'' routine, because all subsequent
759 * references to this file will be direct to the other driver.
760 */
761/* ARGSUSED */
762fdopen(dev, mode, type)
763 dev_t dev;
764 int mode, type;
765{
766
767 /*
768 * XXX Kludge: set curproc->p_dupfd to contain the value of the
769 * the file descriptor being sought for duplication. The error
770 * return ensures that the vnode for this device will be released
771 * by vn_open. Open will detect this special error and take the
772 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
773 * will simply report the error.
774 */
775 curproc->p_dupfd = minor(dev); /* XXX */
776 return (ENODEV);
777}
778
779/*
780 * Duplicate the specified descriptor to a free descriptor.
781 */
782dupfdopen(fdp, indx, dfd, mode)
783 register struct filedesc *fdp;
784 register int indx, dfd;
785 int mode;
786{
787 register struct file *wfp;
788 struct file *fp;
789
790 /*
791 * If the to-be-dup'd fd number is greater than the allowed number
792 * of file descriptors, or the fd to be dup'd has already been
793 * closed, reject. Note, check for new == old is necessary as
794 * falloc could allocate an already closed to-be-dup'd descriptor
795 * as the new descriptor.
796 */
797 fp = fdp->fd_ofiles[indx];
798 if ((u_int)dfd >= fdp->fd_nfiles ||
799 (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
800 return (EBADF);
801
802 /*
803 * Check that the mode the file is being opened for is a subset
804 * of the mode of the existing descriptor.
805 */
806 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
807 return (EACCES);
808 fdp->fd_ofiles[indx] = wfp;
809 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
810 wfp->f_count++;
811 if (indx > fdp->fd_lastfile)
812 fdp->fd_lastfile = indx;
813 return (0);
814}