Annotation of sys/kern/kern_descrip.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_descrip.c,v 1.76 2007/03/15 10:22:30 art Exp $ */
! 2: /* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989, 1991, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: * (c) UNIX System Laboratories, Inc.
! 8: * All or some portions of this file are derived from material licensed
! 9: * to the University of California by American Telephone and Telegraph
! 10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 11: * the permission of UNIX System Laboratories, Inc.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/filedesc.h>
! 43: #include <sys/kernel.h>
! 44: #include <sys/vnode.h>
! 45: #include <sys/proc.h>
! 46: #include <sys/file.h>
! 47: #include <sys/socket.h>
! 48: #include <sys/socketvar.h>
! 49: #include <sys/stat.h>
! 50: #include <sys/ioctl.h>
! 51: #include <sys/fcntl.h>
! 52: #include <sys/malloc.h>
! 53: #include <sys/syslog.h>
! 54: #include <sys/ucred.h>
! 55: #include <sys/unistd.h>
! 56: #include <sys/resourcevar.h>
! 57: #include <sys/conf.h>
! 58: #include <sys/mount.h>
! 59: #include <sys/syscallargs.h>
! 60: #include <sys/event.h>
! 61: #include <sys/pool.h>
! 62:
! 63: #include <uvm/uvm_extern.h>
! 64:
! 65: #include <sys/pipe.h>
! 66:
! 67: /*
! 68: * Descriptor management.
! 69: */
! 70: struct filelist filehead; /* head of list of open files */
! 71: int nfiles; /* actual number of open files */
! 72:
! 73: static __inline void fd_used(struct filedesc *, int);
! 74: static __inline void fd_unused(struct filedesc *, int);
! 75: static __inline int find_next_zero(u_int *, int, u_int);
! 76: int finishdup(struct proc *, struct file *, int, int, register_t *);
! 77: int find_last_set(struct filedesc *, int);
! 78:
! 79: struct pool file_pool;
! 80: struct pool fdesc_pool;
! 81:
! 82: void
! 83: filedesc_init(void)
! 84: {
! 85: pool_init(&file_pool, sizeof(struct file), 0, 0, 0, "filepl",
! 86: &pool_allocator_nointr);
! 87: pool_init(&fdesc_pool, sizeof(struct filedesc0), 0, 0, 0, "fdescpl",
! 88: &pool_allocator_nointr);
! 89: LIST_INIT(&filehead);
! 90: }
! 91:
! 92: static __inline int
! 93: find_next_zero (u_int *bitmap, int want, u_int bits)
! 94: {
! 95: int i, off, maxoff;
! 96: u_int sub;
! 97:
! 98: if (want > bits)
! 99: return -1;
! 100:
! 101: off = want >> NDENTRYSHIFT;
! 102: i = want & NDENTRYMASK;
! 103: if (i) {
! 104: sub = bitmap[off] | ((u_int)~0 >> (NDENTRIES - i));
! 105: if (sub != ~0)
! 106: goto found;
! 107: off++;
! 108: }
! 109:
! 110: maxoff = NDLOSLOTS(bits);
! 111: while (off < maxoff) {
! 112: if ((sub = bitmap[off]) != ~0)
! 113: goto found;
! 114: off++;
! 115: }
! 116:
! 117: return -1;
! 118:
! 119: found:
! 120: return (off << NDENTRYSHIFT) + ffs(~sub) - 1;
! 121: }
! 122:
! 123: int
! 124: find_last_set(struct filedesc *fd, int last)
! 125: {
! 126: int off, i;
! 127: struct file **ofiles = fd->fd_ofiles;
! 128: u_int *bitmap = fd->fd_lomap;
! 129:
! 130: off = (last - 1) >> NDENTRYSHIFT;
! 131:
! 132: while (off >= 0 && !bitmap[off])
! 133: off--;
! 134: if (off < 0)
! 135: return 0;
! 136:
! 137: i = ((off + 1) << NDENTRYSHIFT) - 1;
! 138: if (i >= last)
! 139: i = last - 1;
! 140:
! 141: while (i > 0 && ofiles[i] == NULL)
! 142: i--;
! 143: return i;
! 144: }
! 145:
! 146: static __inline void
! 147: fd_used(struct filedesc *fdp, int fd)
! 148: {
! 149: u_int off = fd >> NDENTRYSHIFT;
! 150:
! 151: fdp->fd_lomap[off] |= 1 << (fd & NDENTRYMASK);
! 152: if (fdp->fd_lomap[off] == ~0)
! 153: fdp->fd_himap[off >> NDENTRYSHIFT] |= 1 << (off & NDENTRYMASK);
! 154:
! 155: if (fd > fdp->fd_lastfile)
! 156: fdp->fd_lastfile = fd;
! 157: }
! 158:
! 159: static __inline void
! 160: fd_unused(struct filedesc *fdp, int fd)
! 161: {
! 162: u_int off = fd >> NDENTRYSHIFT;
! 163:
! 164: if (fd < fdp->fd_freefile)
! 165: fdp->fd_freefile = fd;
! 166:
! 167: if (fdp->fd_lomap[off] == ~0)
! 168: fdp->fd_himap[off >> NDENTRYSHIFT] &= ~(1 << (off & NDENTRYMASK));
! 169: fdp->fd_lomap[off] &= ~(1 << (fd & NDENTRYMASK));
! 170:
! 171: #ifdef DIAGNOSTIC
! 172: if (fd > fdp->fd_lastfile)
! 173: panic("fd_unused: fd_lastfile inconsistent");
! 174: #endif
! 175: if (fd == fdp->fd_lastfile)
! 176: fdp->fd_lastfile = find_last_set(fdp, fd);
! 177: }
! 178:
! 179: struct file *
! 180: fd_getfile(struct filedesc *fdp, int fd)
! 181: {
! 182: struct file *fp;
! 183:
! 184: if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
! 185: return (NULL);
! 186:
! 187: if (!FILE_IS_USABLE(fp))
! 188: return (NULL);
! 189:
! 190: return (fp);
! 191: }
! 192:
! 193: /*
! 194: * System calls on descriptors.
! 195: */
! 196:
! 197: /*
! 198: * Duplicate a file descriptor.
! 199: */
! 200: /* ARGSUSED */
! 201: int
! 202: sys_dup(struct proc *p, void *v, register_t *retval)
! 203: {
! 204: struct sys_dup_args /* {
! 205: syscallarg(int) fd;
! 206: } */ *uap = v;
! 207: struct filedesc *fdp = p->p_fd;
! 208: int old = SCARG(uap, fd);
! 209: struct file *fp;
! 210: int new;
! 211: int error;
! 212:
! 213: restart:
! 214: if ((fp = fd_getfile(fdp, old)) == NULL)
! 215: return (EBADF);
! 216: FREF(fp);
! 217: fdplock(fdp);
! 218: if ((error = fdalloc(p, 0, &new)) != 0) {
! 219: FRELE(fp);
! 220: if (error == ENOSPC) {
! 221: fdexpand(p);
! 222: fdpunlock(fdp);
! 223: goto restart;
! 224: }
! 225: goto out;
! 226: }
! 227: error = finishdup(p, fp, old, new, retval);
! 228:
! 229: out:
! 230: fdpunlock(fdp);
! 231: return (error);
! 232: }
! 233:
! 234: /*
! 235: * Duplicate a file descriptor to a particular value.
! 236: */
! 237: /* ARGSUSED */
! 238: int
! 239: sys_dup2(struct proc *p, void *v, register_t *retval)
! 240: {
! 241: struct sys_dup2_args /* {
! 242: syscallarg(int) from;
! 243: syscallarg(int) to;
! 244: } */ *uap = v;
! 245: int old = SCARG(uap, from), new = SCARG(uap, to);
! 246: struct filedesc *fdp = p->p_fd;
! 247: struct file *fp;
! 248: int i, error;
! 249:
! 250: restart:
! 251: if ((fp = fd_getfile(fdp, old)) == NULL)
! 252: return (EBADF);
! 253: if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
! 254: (u_int)new >= maxfiles)
! 255: return (EBADF);
! 256: if (old == new) {
! 257: /*
! 258: * NOTE! This doesn't clear the close-on-exec flag. This might
! 259: * or might not be the intended behavior from the start, but
! 260: * this is what everyone else does.
! 261: */
! 262: *retval = new;
! 263: return (0);
! 264: }
! 265: FREF(fp);
! 266: fdplock(fdp);
! 267: if (new >= fdp->fd_nfiles) {
! 268: if ((error = fdalloc(p, new, &i)) != 0) {
! 269: FRELE(fp);
! 270: if (error == ENOSPC) {
! 271: fdexpand(p);
! 272: fdpunlock(fdp);
! 273: goto restart;
! 274: }
! 275: goto out;
! 276: }
! 277: if (new != i)
! 278: panic("dup2: fdalloc");
! 279: }
! 280: /* finishdup() does FRELE */
! 281: error = finishdup(p, fp, old, new, retval);
! 282:
! 283: out:
! 284: fdpunlock(fdp);
! 285: return (error);
! 286: }
! 287:
! 288: /*
! 289: * The file control system call.
! 290: */
! 291: /* ARGSUSED */
! 292: int
! 293: sys_fcntl(struct proc *p, void *v, register_t *retval)
! 294: {
! 295: struct sys_fcntl_args /* {
! 296: syscallarg(int) fd;
! 297: syscallarg(int) cmd;
! 298: syscallarg(void *) arg;
! 299: } */ *uap = v;
! 300: int fd = SCARG(uap, fd);
! 301: struct filedesc *fdp = p->p_fd;
! 302: struct file *fp;
! 303: struct vnode *vp;
! 304: int i, tmp, newmin, flg = F_POSIX;
! 305: struct flock fl;
! 306: int error = 0;
! 307:
! 308: restart:
! 309: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 310: return (EBADF);
! 311: FREF(fp);
! 312: switch (SCARG(uap, cmd)) {
! 313:
! 314: case F_DUPFD:
! 315: newmin = (long)SCARG(uap, arg);
! 316: if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
! 317: (u_int)newmin >= maxfiles) {
! 318: error = EINVAL;
! 319: break;
! 320: }
! 321: fdplock(fdp);
! 322: if ((error = fdalloc(p, newmin, &i)) != 0) {
! 323: if (error == ENOSPC) {
! 324: fdexpand(p);
! 325: FRELE(fp);
! 326: fdpunlock(fdp);
! 327: goto restart;
! 328: }
! 329: }
! 330: /* finishdup will FRELE for us. */
! 331: if (!error)
! 332: error = finishdup(p, fp, fd, i, retval);
! 333: else
! 334: FRELE(fp);
! 335:
! 336: fdpunlock(fdp);
! 337: return (error);
! 338:
! 339: case F_GETFD:
! 340: *retval = fdp->fd_ofileflags[fd] & UF_EXCLOSE ? 1 : 0;
! 341: break;
! 342:
! 343: case F_SETFD:
! 344: if ((long)SCARG(uap, arg) & 1)
! 345: fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
! 346: else
! 347: fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
! 348: break;
! 349:
! 350: case F_GETFL:
! 351: *retval = OFLAGS(fp->f_flag);
! 352: break;
! 353:
! 354: case F_SETFL:
! 355: fp->f_flag &= ~FCNTLFLAGS;
! 356: fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
! 357: tmp = fp->f_flag & FNONBLOCK;
! 358: error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
! 359: if (error)
! 360: break;
! 361: tmp = fp->f_flag & FASYNC;
! 362: error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
! 363: if (!error)
! 364: break;
! 365: fp->f_flag &= ~FNONBLOCK;
! 366: tmp = 0;
! 367: (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
! 368: break;
! 369:
! 370: case F_GETOWN:
! 371: if (fp->f_type == DTYPE_SOCKET) {
! 372: *retval = ((struct socket *)fp->f_data)->so_pgid;
! 373: break;
! 374: }
! 375: error = (*fp->f_ops->fo_ioctl)
! 376: (fp, TIOCGPGRP, (caddr_t)&tmp, p);
! 377: *retval = -tmp;
! 378: break;
! 379:
! 380: case F_SETOWN:
! 381: if (fp->f_type == DTYPE_SOCKET) {
! 382: struct socket *so = (struct socket *)fp->f_data;
! 383:
! 384: so->so_pgid = (long)SCARG(uap, arg);
! 385: so->so_siguid = p->p_cred->p_ruid;
! 386: so->so_sigeuid = p->p_ucred->cr_uid;
! 387: break;
! 388: }
! 389: if ((long)SCARG(uap, arg) <= 0) {
! 390: SCARG(uap, arg) = (void *)(-(long)SCARG(uap, arg));
! 391: } else {
! 392: struct proc *p1 = pfind((long)SCARG(uap, arg));
! 393: if (p1 == 0) {
! 394: error = ESRCH;
! 395: break;
! 396: }
! 397: SCARG(uap, arg) = (void *)(long)p1->p_pgrp->pg_id;
! 398: }
! 399: error = ((*fp->f_ops->fo_ioctl)
! 400: (fp, TIOCSPGRP, (caddr_t)&SCARG(uap, arg), p));
! 401: break;
! 402:
! 403: case F_SETLKW:
! 404: flg |= F_WAIT;
! 405: /* FALLTHROUGH */
! 406:
! 407: case F_SETLK:
! 408: if (fp->f_type != DTYPE_VNODE) {
! 409: error = EBADF;
! 410: break;
! 411: }
! 412: vp = (struct vnode *)fp->f_data;
! 413: /* Copy in the lock structure */
! 414: error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
! 415: sizeof (fl));
! 416: if (error)
! 417: break;
! 418: if (fl.l_whence == SEEK_CUR) {
! 419: if (fl.l_start == 0 && fl.l_len < 0) {
! 420: /* lockf(3) compliance hack */
! 421: fl.l_len = -fl.l_len;
! 422: fl.l_start = fp->f_offset - fl.l_len;
! 423: } else
! 424: fl.l_start += fp->f_offset;
! 425: }
! 426: switch (fl.l_type) {
! 427:
! 428: case F_RDLCK:
! 429: if ((fp->f_flag & FREAD) == 0) {
! 430: error = EBADF;
! 431: goto out;
! 432: }
! 433: atomic_setbits_int(&p->p_flag, P_ADVLOCK);
! 434: error = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
! 435: goto out;
! 436:
! 437: case F_WRLCK:
! 438: if ((fp->f_flag & FWRITE) == 0) {
! 439: error = EBADF;
! 440: goto out;
! 441: }
! 442: atomic_setbits_int(&p->p_flag, P_ADVLOCK);
! 443: error = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
! 444: goto out;
! 445:
! 446: case F_UNLCK:
! 447: error = (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
! 448: F_POSIX));
! 449: goto out;
! 450:
! 451: default:
! 452: error = EINVAL;
! 453: goto out;
! 454: }
! 455:
! 456: case F_GETLK:
! 457: if (fp->f_type != DTYPE_VNODE) {
! 458: error = EBADF;
! 459: break;
! 460: }
! 461: vp = (struct vnode *)fp->f_data;
! 462: /* Copy in the lock structure */
! 463: error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
! 464: sizeof (fl));
! 465: if (error)
! 466: break;
! 467: if (fl.l_whence == SEEK_CUR) {
! 468: if (fl.l_start == 0 && fl.l_len < 0) {
! 469: /* lockf(3) compliance hack */
! 470: fl.l_len = -fl.l_len;
! 471: fl.l_start = fp->f_offset - fl.l_len;
! 472: } else
! 473: fl.l_start += fp->f_offset;
! 474: }
! 475: if (fl.l_type != F_RDLCK &&
! 476: fl.l_type != F_WRLCK &&
! 477: fl.l_type != F_UNLCK &&
! 478: fl.l_type != 0) {
! 479: error = EINVAL;
! 480: break;
! 481: }
! 482: error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX);
! 483: if (error)
! 484: break;
! 485: error = (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg),
! 486: sizeof (fl)));
! 487: break;
! 488:
! 489: default:
! 490: error = EINVAL;
! 491: break;
! 492: }
! 493: out:
! 494: FRELE(fp);
! 495: return (error);
! 496: }
! 497:
! 498: /*
! 499: * Common code for dup, dup2, and fcntl(F_DUPFD).
! 500: */
! 501: int
! 502: finishdup(struct proc *p, struct file *fp, int old, int new, register_t *retval)
! 503: {
! 504: struct file *oldfp;
! 505: struct filedesc *fdp = p->p_fd;
! 506:
! 507: if (fp->f_count == LONG_MAX-2) {
! 508: FRELE(fp);
! 509: return (EDEADLK);
! 510: }
! 511:
! 512: /*
! 513: * Don't fd_getfile here. We want to closef LARVAL files and
! 514: * closef can deal with that.
! 515: */
! 516: oldfp = fdp->fd_ofiles[new];
! 517: if (oldfp != NULL)
! 518: FREF(oldfp);
! 519:
! 520: fdp->fd_ofiles[new] = fp;
! 521: fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE;
! 522: fp->f_count++;
! 523: FRELE(fp);
! 524: if (oldfp == NULL)
! 525: fd_used(fdp, new);
! 526: *retval = new;
! 527:
! 528: if (oldfp != NULL) {
! 529: if (new < fdp->fd_knlistsize)
! 530: knote_fdclose(p, new);
! 531: closef(oldfp, p);
! 532: }
! 533:
! 534: return (0);
! 535: }
! 536:
! 537: void
! 538: fdremove(struct filedesc *fdp, int fd)
! 539: {
! 540: fdp->fd_ofiles[fd] = NULL;
! 541: fd_unused(fdp, fd);
! 542: }
! 543:
! 544: int
! 545: fdrelease(struct proc *p, int fd)
! 546: {
! 547: struct filedesc *fdp = p->p_fd;
! 548: struct file **fpp, *fp;
! 549:
! 550: /*
! 551: * Don't fd_getfile here. We want to closef LARVAL files and closef
! 552: * can deal with that.
! 553: */
! 554: fpp = &fdp->fd_ofiles[fd];
! 555: fp = *fpp;
! 556: if (fp == NULL)
! 557: return (EBADF);
! 558: FREF(fp);
! 559: *fpp = NULL;
! 560: fdp->fd_ofileflags[fd] = 0;
! 561: fd_unused(fdp, fd);
! 562: if (fd < fdp->fd_knlistsize)
! 563: knote_fdclose(p, fd);
! 564: return (closef(fp, p));
! 565: }
! 566:
! 567: /*
! 568: * Close a file descriptor.
! 569: */
! 570: /* ARGSUSED */
! 571: int
! 572: sys_close(struct proc *p, void *v, register_t *retval)
! 573: {
! 574: struct sys_close_args /* {
! 575: syscallarg(int) fd;
! 576: } */ *uap = v;
! 577: int fd = SCARG(uap, fd), error;
! 578: struct filedesc *fdp = p->p_fd;
! 579:
! 580: if (fd_getfile(fdp, fd) == NULL)
! 581: return (EBADF);
! 582: fdplock(fdp);
! 583: error = fdrelease(p, fd);
! 584: fdpunlock(fdp);
! 585:
! 586: return (error);
! 587: }
! 588:
! 589: /*
! 590: * Return status information about a file descriptor.
! 591: */
! 592: /* ARGSUSED */
! 593: int
! 594: sys_fstat(struct proc *p, void *v, register_t *retval)
! 595: {
! 596: struct sys_fstat_args /* {
! 597: syscallarg(int) fd;
! 598: syscallarg(struct stat *) sb;
! 599: } */ *uap = v;
! 600: int fd = SCARG(uap, fd);
! 601: struct filedesc *fdp = p->p_fd;
! 602: struct file *fp;
! 603: struct stat ub;
! 604: int error;
! 605:
! 606: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 607: return (EBADF);
! 608: FREF(fp);
! 609: error = (*fp->f_ops->fo_stat)(fp, &ub, p);
! 610: FRELE(fp);
! 611: if (error == 0) {
! 612: /*
! 613: * Don't let non-root see generation numbers
! 614: * (for NFS security)
! 615: */
! 616: if (suser(p, 0))
! 617: ub.st_gen = 0;
! 618: error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
! 619: sizeof (ub));
! 620: }
! 621: return (error);
! 622: }
! 623:
! 624: /*
! 625: * Return pathconf information about a file descriptor.
! 626: */
! 627: /* ARGSUSED */
! 628: int
! 629: sys_fpathconf(struct proc *p, void *v, register_t *retval)
! 630: {
! 631: struct sys_fpathconf_args /* {
! 632: syscallarg(int) fd;
! 633: syscallarg(int) name;
! 634: } */ *uap = v;
! 635: int fd = SCARG(uap, fd);
! 636: struct filedesc *fdp = p->p_fd;
! 637: struct file *fp;
! 638: struct vnode *vp;
! 639: int error;
! 640:
! 641: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 642: return (EBADF);
! 643: FREF(fp);
! 644: switch (fp->f_type) {
! 645: case DTYPE_PIPE:
! 646: case DTYPE_SOCKET:
! 647: if (SCARG(uap, name) != _PC_PIPE_BUF) {
! 648: error = EINVAL;
! 649: break;
! 650: }
! 651: *retval = PIPE_BUF;
! 652: error = 0;
! 653: break;
! 654:
! 655: case DTYPE_VNODE:
! 656: vp = (struct vnode *)fp->f_data;
! 657: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 658: error = VOP_PATHCONF(vp, SCARG(uap, name), retval);
! 659: VOP_UNLOCK(vp, 0, p);
! 660: break;
! 661:
! 662: default:
! 663: error = EOPNOTSUPP;
! 664: break;
! 665: }
! 666: FRELE(fp);
! 667: return (error);
! 668: }
! 669:
! 670: /*
! 671: * Allocate a file descriptor for the process.
! 672: */
! 673: int
! 674: fdalloc(struct proc *p, int want, int *result)
! 675: {
! 676: struct filedesc *fdp = p->p_fd;
! 677: int lim, last, i;
! 678: u_int new, off;
! 679:
! 680: /*
! 681: * Search for a free descriptor starting at the higher
! 682: * of want or fd_freefile. If that fails, consider
! 683: * expanding the ofile array.
! 684: */
! 685: restart:
! 686: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
! 687: last = min(fdp->fd_nfiles, lim);
! 688: if ((i = want) < fdp->fd_freefile)
! 689: i = fdp->fd_freefile;
! 690: off = i >> NDENTRYSHIFT;
! 691: new = find_next_zero(fdp->fd_himap, off,
! 692: (last + NDENTRIES - 1) >> NDENTRYSHIFT);
! 693: if (new != -1) {
! 694: i = find_next_zero(&fdp->fd_lomap[new],
! 695: new > off ? 0 : i & NDENTRYMASK,
! 696: NDENTRIES);
! 697: if (i == -1) {
! 698: /*
! 699: * Free file descriptor in this block was
! 700: * below want, try again with higher want.
! 701: */
! 702: want = (new + 1) << NDENTRYSHIFT;
! 703: goto restart;
! 704: }
! 705: i += (new << NDENTRYSHIFT);
! 706: if (i < last) {
! 707: fd_used(fdp, i);
! 708: if (want <= fdp->fd_freefile)
! 709: fdp->fd_freefile = i;
! 710: *result = i;
! 711: return (0);
! 712: }
! 713: }
! 714: if (fdp->fd_nfiles >= lim)
! 715: return (EMFILE);
! 716:
! 717: return (ENOSPC);
! 718: }
! 719:
! 720: void
! 721: fdexpand(struct proc *p)
! 722: {
! 723: struct filedesc *fdp = p->p_fd;
! 724: int nfiles, i;
! 725: struct file **newofile;
! 726: char *newofileflags;
! 727: u_int *newhimap, *newlomap;
! 728:
! 729: /*
! 730: * No space in current array.
! 731: */
! 732: if (fdp->fd_nfiles < NDEXTENT)
! 733: nfiles = NDEXTENT;
! 734: else
! 735: nfiles = 2 * fdp->fd_nfiles;
! 736:
! 737: newofile = malloc(nfiles * OFILESIZE, M_FILEDESC, M_WAITOK);
! 738: newofileflags = (char *) &newofile[nfiles];
! 739:
! 740: /*
! 741: * Copy the existing ofile and ofileflags arrays
! 742: * and zero the new portion of each array.
! 743: */
! 744: bcopy(fdp->fd_ofiles, newofile,
! 745: (i = sizeof(struct file *) * fdp->fd_nfiles));
! 746: bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
! 747: bcopy(fdp->fd_ofileflags, newofileflags,
! 748: (i = sizeof(char) * fdp->fd_nfiles));
! 749: bzero(newofileflags + i, nfiles * sizeof(char) - i);
! 750:
! 751: if (fdp->fd_nfiles > NDFILE)
! 752: free(fdp->fd_ofiles, M_FILEDESC);
! 753:
! 754: if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
! 755: newhimap = malloc(NDHISLOTS(nfiles) * sizeof(u_int),
! 756: M_FILEDESC, M_WAITOK);
! 757: newlomap = malloc(NDLOSLOTS(nfiles) * sizeof(u_int),
! 758: M_FILEDESC, M_WAITOK);
! 759:
! 760: bcopy(fdp->fd_himap, newhimap,
! 761: (i = NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int)));
! 762: bzero((char *)newhimap + i,
! 763: NDHISLOTS(nfiles) * sizeof(u_int) - i);
! 764:
! 765: bcopy(fdp->fd_lomap, newlomap,
! 766: (i = NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int)));
! 767: bzero((char *)newlomap + i,
! 768: NDLOSLOTS(nfiles) * sizeof(u_int) - i);
! 769:
! 770: if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
! 771: free(fdp->fd_himap, M_FILEDESC);
! 772: free(fdp->fd_lomap, M_FILEDESC);
! 773: }
! 774: fdp->fd_himap = newhimap;
! 775: fdp->fd_lomap = newlomap;
! 776: }
! 777: fdp->fd_ofiles = newofile;
! 778: fdp->fd_ofileflags = newofileflags;
! 779: fdp->fd_nfiles = nfiles;
! 780: }
! 781:
! 782: /*
! 783: * Create a new open file structure and allocate
! 784: * a file descriptor for the process that refers to it.
! 785: */
! 786: int
! 787: falloc(struct proc *p, struct file **resultfp, int *resultfd)
! 788: {
! 789: struct file *fp, *fq;
! 790: int error, i;
! 791:
! 792: restart:
! 793: if ((error = fdalloc(p, 0, &i)) != 0) {
! 794: if (error == ENOSPC) {
! 795: fdexpand(p);
! 796: goto restart;
! 797: }
! 798: return (error);
! 799: }
! 800: if (nfiles >= maxfiles) {
! 801: fd_unused(p->p_fd, i);
! 802: tablefull("file");
! 803: return (ENFILE);
! 804: }
! 805: /*
! 806: * Allocate a new file descriptor.
! 807: * If the process has file descriptor zero open, add to the list
! 808: * of open files at that point, otherwise put it at the front of
! 809: * the list of open files.
! 810: */
! 811: nfiles++;
! 812: fp = pool_get(&file_pool, PR_WAITOK);
! 813: bzero(fp, sizeof(struct file));
! 814: fp->f_iflags = FIF_LARVAL;
! 815: if ((fq = p->p_fd->fd_ofiles[0]) != NULL) {
! 816: LIST_INSERT_AFTER(fq, fp, f_list);
! 817: } else {
! 818: LIST_INSERT_HEAD(&filehead, fp, f_list);
! 819: }
! 820: p->p_fd->fd_ofiles[i] = fp;
! 821: fp->f_count = 1;
! 822: fp->f_cred = p->p_ucred;
! 823: crhold(fp->f_cred);
! 824: if (resultfp)
! 825: *resultfp = fp;
! 826: if (resultfd)
! 827: *resultfd = i;
! 828: FREF(fp);
! 829: return (0);
! 830: }
! 831:
! 832: /*
! 833: * Build a new filedesc structure.
! 834: */
! 835: struct filedesc *
! 836: fdinit(struct proc *p)
! 837: {
! 838: struct filedesc0 *newfdp;
! 839: extern int cmask;
! 840:
! 841: newfdp = pool_get(&fdesc_pool, PR_WAITOK);
! 842: bzero(newfdp, sizeof(struct filedesc0));
! 843: if (p != NULL) {
! 844: struct filedesc *fdp = p->p_fd;
! 845:
! 846: newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
! 847: VREF(newfdp->fd_fd.fd_cdir);
! 848: newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
! 849: if (newfdp->fd_fd.fd_rdir)
! 850: VREF(newfdp->fd_fd.fd_rdir);
! 851: }
! 852: rw_init(&newfdp->fd_fd.fd_lock, "fdlock");
! 853:
! 854: /* Create the file descriptor table. */
! 855: newfdp->fd_fd.fd_refcnt = 1;
! 856: newfdp->fd_fd.fd_cmask = cmask;
! 857: newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
! 858: newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
! 859: newfdp->fd_fd.fd_nfiles = NDFILE;
! 860: newfdp->fd_fd.fd_himap = newfdp->fd_dhimap;
! 861: newfdp->fd_fd.fd_lomap = newfdp->fd_dlomap;
! 862: newfdp->fd_fd.fd_knlistsize = -1;
! 863:
! 864: newfdp->fd_fd.fd_freefile = 0;
! 865: newfdp->fd_fd.fd_lastfile = 0;
! 866:
! 867: return (&newfdp->fd_fd);
! 868: }
! 869:
! 870: /*
! 871: * Share a filedesc structure.
! 872: */
! 873: struct filedesc *
! 874: fdshare(struct proc *p)
! 875: {
! 876: p->p_fd->fd_refcnt++;
! 877: return (p->p_fd);
! 878: }
! 879:
! 880: /*
! 881: * Copy a filedesc structure.
! 882: */
! 883: struct filedesc *
! 884: fdcopy(struct proc *p)
! 885: {
! 886: struct filedesc *newfdp, *fdp = p->p_fd;
! 887: struct file **fpp;
! 888: int i;
! 889:
! 890: newfdp = pool_get(&fdesc_pool, PR_WAITOK);
! 891: bcopy(fdp, newfdp, sizeof(struct filedesc));
! 892: if (newfdp->fd_cdir)
! 893: VREF(newfdp->fd_cdir);
! 894: if (newfdp->fd_rdir)
! 895: VREF(newfdp->fd_rdir);
! 896: newfdp->fd_refcnt = 1;
! 897:
! 898: /*
! 899: * If the number of open files fits in the internal arrays
! 900: * of the open file structure, use them, otherwise allocate
! 901: * additional memory for the number of descriptors currently
! 902: * in use.
! 903: */
! 904: if (newfdp->fd_lastfile < NDFILE) {
! 905: newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
! 906: newfdp->fd_ofileflags =
! 907: ((struct filedesc0 *) newfdp)->fd_dfileflags;
! 908: i = NDFILE;
! 909: } else {
! 910: /*
! 911: * Compute the smallest multiple of NDEXTENT needed
! 912: * for the file descriptors currently in use,
! 913: * allowing the table to shrink.
! 914: */
! 915: i = newfdp->fd_nfiles;
! 916: while (i >= 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
! 917: i /= 2;
! 918: newfdp->fd_ofiles = malloc(i * OFILESIZE, M_FILEDESC, M_WAITOK);
! 919: newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
! 920: }
! 921: if (NDHISLOTS(i) <= NDHISLOTS(NDFILE)) {
! 922: newfdp->fd_himap =
! 923: ((struct filedesc0 *) newfdp)->fd_dhimap;
! 924: newfdp->fd_lomap =
! 925: ((struct filedesc0 *) newfdp)->fd_dlomap;
! 926: } else {
! 927: newfdp->fd_himap = malloc(NDHISLOTS(i) * sizeof(u_int),
! 928: M_FILEDESC, M_WAITOK);
! 929: newfdp->fd_lomap = malloc(NDLOSLOTS(i) * sizeof(u_int),
! 930: M_FILEDESC, M_WAITOK);
! 931: }
! 932: newfdp->fd_nfiles = i;
! 933: bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
! 934: bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
! 935: bcopy(fdp->fd_himap, newfdp->fd_himap, NDHISLOTS(i) * sizeof(u_int));
! 936: bcopy(fdp->fd_lomap, newfdp->fd_lomap, NDLOSLOTS(i) * sizeof(u_int));
! 937:
! 938: /*
! 939: * kq descriptors cannot be copied.
! 940: */
! 941: if (newfdp->fd_knlistsize != -1) {
! 942: fpp = newfdp->fd_ofiles;
! 943: for (i = 0; i <= newfdp->fd_lastfile; i++, fpp++)
! 944: if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE)
! 945: fdremove(newfdp, i);
! 946: newfdp->fd_knlist = NULL;
! 947: newfdp->fd_knlistsize = -1;
! 948: newfdp->fd_knhash = NULL;
! 949: newfdp->fd_knhashmask = 0;
! 950: }
! 951:
! 952: fpp = newfdp->fd_ofiles;
! 953: for (i = 0; i <= newfdp->fd_lastfile; i++, fpp++)
! 954: if (*fpp != NULL) {
! 955: /*
! 956: * XXX Gruesome hack. If count gets too high, fail
! 957: * to copy an fd, since fdcopy()'s callers do not
! 958: * permit it to indicate failure yet.
! 959: */
! 960: if ((*fpp)->f_count == LONG_MAX-2)
! 961: fdremove(newfdp, i);
! 962: else
! 963: (*fpp)->f_count++;
! 964: }
! 965: return (newfdp);
! 966: }
! 967:
! 968: /*
! 969: * Release a filedesc structure.
! 970: */
! 971: void
! 972: fdfree(struct proc *p)
! 973: {
! 974: struct filedesc *fdp = p->p_fd;
! 975: struct file **fpp, *fp;
! 976: int i;
! 977:
! 978: if (--fdp->fd_refcnt > 0)
! 979: return;
! 980: fpp = fdp->fd_ofiles;
! 981: for (i = fdp->fd_lastfile; i >= 0; i--, fpp++) {
! 982: fp = *fpp;
! 983: if (fp != NULL) {
! 984: FREF(fp);
! 985: *fpp = NULL;
! 986: (void) closef(fp, p);
! 987: }
! 988: }
! 989: p->p_fd = NULL;
! 990: if (fdp->fd_nfiles > NDFILE)
! 991: free(fdp->fd_ofiles, M_FILEDESC);
! 992: if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
! 993: free(fdp->fd_himap, M_FILEDESC);
! 994: free(fdp->fd_lomap, M_FILEDESC);
! 995: }
! 996: if (fdp->fd_cdir)
! 997: vrele(fdp->fd_cdir);
! 998: if (fdp->fd_rdir)
! 999: vrele(fdp->fd_rdir);
! 1000: if (fdp->fd_knlist)
! 1001: FREE(fdp->fd_knlist, M_TEMP);
! 1002: if (fdp->fd_knhash)
! 1003: FREE(fdp->fd_knhash, M_TEMP);
! 1004: pool_put(&fdesc_pool, fdp);
! 1005: }
! 1006:
! 1007: /*
! 1008: * Internal form of close.
! 1009: * Decrement reference count on file structure.
! 1010: * Note: p may be NULL when closing a file
! 1011: * that was being passed in a message.
! 1012: *
! 1013: * The fp must have its usecount bumped and will be FRELEd here.
! 1014: */
! 1015: int
! 1016: closef(struct file *fp, struct proc *p)
! 1017: {
! 1018: struct vnode *vp;
! 1019: struct flock lf;
! 1020: int error;
! 1021:
! 1022: if (fp == NULL)
! 1023: return (0);
! 1024:
! 1025: /*
! 1026: * POSIX record locking dictates that any close releases ALL
! 1027: * locks owned by this process. This is handled by setting
! 1028: * a flag in the unlock to free ONLY locks obeying POSIX
! 1029: * semantics, and not to free BSD-style file locks.
! 1030: * If the descriptor was in a message, POSIX-style locks
! 1031: * aren't passed with the descriptor.
! 1032: */
! 1033: if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
! 1034: lf.l_whence = SEEK_SET;
! 1035: lf.l_start = 0;
! 1036: lf.l_len = 0;
! 1037: lf.l_type = F_UNLCK;
! 1038: vp = (struct vnode *)fp->f_data;
! 1039: (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
! 1040: }
! 1041:
! 1042: /*
! 1043: * Some files passed to this function could be accessed
! 1044: * without a FILE_IS_USABLE check (and in some cases it's perfectly
! 1045: * legal), we must beware of files where someone already won the
! 1046: * race to FIF_WANTCLOSE.
! 1047: */
! 1048: if ((fp->f_iflags & FIF_WANTCLOSE) != 0) {
! 1049: FRELE(fp);
! 1050: return (0);
! 1051: }
! 1052:
! 1053: if (--fp->f_count > 0) {
! 1054: FRELE(fp);
! 1055: return (0);
! 1056: }
! 1057:
! 1058: #ifdef DIAGNOSTIC
! 1059: if (fp->f_count < 0)
! 1060: panic("closef: count < 0");
! 1061: #endif
! 1062:
! 1063: /* Wait for the last usecount to drain. */
! 1064: fp->f_iflags |= FIF_WANTCLOSE;
! 1065: while (fp->f_usecount > 1)
! 1066: tsleep(&fp->f_usecount, PRIBIO, "closef", 0);
! 1067:
! 1068: if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
! 1069: lf.l_whence = SEEK_SET;
! 1070: lf.l_start = 0;
! 1071: lf.l_len = 0;
! 1072: lf.l_type = F_UNLCK;
! 1073: vp = (struct vnode *)fp->f_data;
! 1074: (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
! 1075: }
! 1076: if (fp->f_ops)
! 1077: error = (*fp->f_ops->fo_close)(fp, p);
! 1078: else
! 1079: error = 0;
! 1080:
! 1081: /* Free fp */
! 1082: LIST_REMOVE(fp, f_list);
! 1083: crfree(fp->f_cred);
! 1084: #ifdef DIAGNOSTIC
! 1085: if (fp->f_count != 0 || fp->f_usecount != 1)
! 1086: panic("closef: count: %d/%d", fp->f_count, fp->f_usecount);
! 1087: #endif
! 1088: nfiles--;
! 1089: pool_put(&file_pool, fp);
! 1090:
! 1091: return (error);
! 1092: }
! 1093:
! 1094: /*
! 1095: * Apply an advisory lock on a file descriptor.
! 1096: *
! 1097: * Just attempt to get a record lock of the requested type on
! 1098: * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
! 1099: */
! 1100: /* ARGSUSED */
! 1101: int
! 1102: sys_flock(struct proc *p, void *v, register_t *retval)
! 1103: {
! 1104: struct sys_flock_args /* {
! 1105: syscallarg(int) fd;
! 1106: syscallarg(int) how;
! 1107: } */ *uap = v;
! 1108: int fd = SCARG(uap, fd);
! 1109: int how = SCARG(uap, how);
! 1110: struct filedesc *fdp = p->p_fd;
! 1111: struct file *fp;
! 1112: struct vnode *vp;
! 1113: struct flock lf;
! 1114: int error;
! 1115:
! 1116: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 1117: return (EBADF);
! 1118: if (fp->f_type != DTYPE_VNODE)
! 1119: return (EOPNOTSUPP);
! 1120: vp = (struct vnode *)fp->f_data;
! 1121: lf.l_whence = SEEK_SET;
! 1122: lf.l_start = 0;
! 1123: lf.l_len = 0;
! 1124: if (how & LOCK_UN) {
! 1125: lf.l_type = F_UNLCK;
! 1126: fp->f_flag &= ~FHASLOCK;
! 1127: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
! 1128: goto out;
! 1129: }
! 1130: if (how & LOCK_EX)
! 1131: lf.l_type = F_WRLCK;
! 1132: else if (how & LOCK_SH)
! 1133: lf.l_type = F_RDLCK;
! 1134: else {
! 1135: error = EINVAL;
! 1136: goto out;
! 1137: }
! 1138: fp->f_flag |= FHASLOCK;
! 1139: if (how & LOCK_NB)
! 1140: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK);
! 1141: else
! 1142: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT);
! 1143: out:
! 1144: return (error);
! 1145: }
! 1146:
! 1147: /*
! 1148: * File Descriptor pseudo-device driver (/dev/fd/).
! 1149: *
! 1150: * Opening minor device N dup()s the file (if any) connected to file
! 1151: * descriptor N belonging to the calling process. Note that this driver
! 1152: * consists of only the ``open()'' routine, because all subsequent
! 1153: * references to this file will be direct to the other driver.
! 1154: */
! 1155: /* ARGSUSED */
! 1156: int
! 1157: filedescopen(dev_t dev, int mode, int type, struct proc *p)
! 1158: {
! 1159:
! 1160: /*
! 1161: * XXX Kludge: set curproc->p_dupfd to contain the value of the
! 1162: * the file descriptor being sought for duplication. The error
! 1163: * return ensures that the vnode for this device will be released
! 1164: * by vn_open. Open will detect this special error and take the
! 1165: * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
! 1166: * will simply report the error.
! 1167: */
! 1168: p->p_dupfd = minor(dev);
! 1169: return (ENODEV);
! 1170: }
! 1171:
! 1172: /*
! 1173: * Duplicate the specified descriptor to a free descriptor.
! 1174: */
! 1175: int
! 1176: dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode, int error)
! 1177: {
! 1178: struct file *wfp;
! 1179:
! 1180: /*
! 1181: * Assume that the filename was user-specified; applications do
! 1182: * not tend to open /dev/fd/# when they can just call dup()
! 1183: */
! 1184: if ((curproc->p_flag & (P_SUGIDEXEC | P_SUGID))) {
! 1185: if (curproc->p_descfd == 255)
! 1186: return (EPERM);
! 1187: if (curproc->p_descfd != curproc->p_dupfd)
! 1188: return (EPERM);
! 1189: }
! 1190:
! 1191: /*
! 1192: * If the to-be-dup'd fd number is greater than the allowed number
! 1193: * of file descriptors, or the fd to be dup'd has already been
! 1194: * closed, reject. Note, there is no need to check for new == old
! 1195: * because fd_getfile will return NULL if the file at indx is
! 1196: * newly created by falloc (FIF_LARVAL).
! 1197: */
! 1198: if ((wfp = fd_getfile(fdp, dfd)) == NULL)
! 1199: return (EBADF);
! 1200:
! 1201: /*
! 1202: * There are two cases of interest here.
! 1203: *
! 1204: * For ENODEV simply dup (dfd) to file descriptor
! 1205: * (indx) and return.
! 1206: *
! 1207: * For ENXIO steal away the file structure from (dfd) and
! 1208: * store it in (indx). (dfd) is effectively closed by
! 1209: * this operation.
! 1210: *
! 1211: * Any other error code is just returned.
! 1212: */
! 1213: switch (error) {
! 1214: case ENODEV:
! 1215: /*
! 1216: * Check that the mode the file is being opened for is a
! 1217: * subset of the mode of the existing descriptor.
! 1218: */
! 1219: if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
! 1220: return (EACCES);
! 1221: if (wfp->f_count == LONG_MAX-2)
! 1222: return (EDEADLK);
! 1223: fdp->fd_ofiles[indx] = wfp;
! 1224: fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
! 1225: wfp->f_count++;
! 1226: fd_used(fdp, indx);
! 1227: return (0);
! 1228:
! 1229: case ENXIO:
! 1230: /*
! 1231: * Steal away the file pointer from dfd, and stuff it into indx.
! 1232: */
! 1233: fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
! 1234: fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
! 1235: fdp->fd_ofiles[dfd] = NULL;
! 1236: fdp->fd_ofileflags[dfd] = 0;
! 1237: /*
! 1238: * Complete the clean up of the filedesc structure by
! 1239: * recomputing the various hints.
! 1240: */
! 1241: fd_used(fdp, indx);
! 1242: fd_unused(fdp, dfd);
! 1243: return (0);
! 1244:
! 1245: default:
! 1246: return (error);
! 1247: }
! 1248: /* NOTREACHED */
! 1249: }
! 1250:
! 1251: /*
! 1252: * Close any files on exec?
! 1253: */
! 1254: void
! 1255: fdcloseexec(struct proc *p)
! 1256: {
! 1257: struct filedesc *fdp = p->p_fd;
! 1258: int fd;
! 1259:
! 1260: for (fd = 0; fd <= fdp->fd_lastfile; fd++)
! 1261: if (fdp->fd_ofileflags[fd] & UF_EXCLOSE)
! 1262: (void) fdrelease(p, fd);
! 1263: }
! 1264:
! 1265: int
! 1266: sys_closefrom(struct proc *p, void *v, register_t *retval)
! 1267: {
! 1268: struct sys_closefrom_args *uap = v;
! 1269: struct filedesc *fdp = p->p_fd;
! 1270: u_int startfd, i;
! 1271:
! 1272: startfd = SCARG(uap, fd);
! 1273: fdplock(fdp);
! 1274:
! 1275: if (startfd > fdp->fd_lastfile) {
! 1276: fdpunlock(fdp);
! 1277: return (EBADF);
! 1278: }
! 1279:
! 1280: for (i = startfd; i <= fdp->fd_lastfile; i++)
! 1281: fdrelease(p, i);
! 1282:
! 1283: fdpunlock(fdp);
! 1284: return (0);
! 1285: }
CVSweb