Annotation of sys/kern/vfs_syscalls.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: vfs_syscalls.c,v 1.141 2007/08/06 16:58:26 millert Exp $ */
! 2: /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 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: * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/namei.h>
! 43: #include <sys/filedesc.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/file.h>
! 46: #include <sys/stat.h>
! 47: #include <sys/vnode.h>
! 48: #include <sys/mount.h>
! 49: #include <sys/proc.h>
! 50: #include <sys/uio.h>
! 51: #include <sys/malloc.h>
! 52: #include <sys/pool.h>
! 53: #include <sys/dirent.h>
! 54: #include <sys/dkio.h>
! 55: #include <sys/disklabel.h>
! 56:
! 57: #include <sys/syscallargs.h>
! 58:
! 59: #include <uvm/uvm_extern.h>
! 60: #include <sys/sysctl.h>
! 61:
! 62: extern int suid_clear;
! 63: int usermount = 0; /* sysctl: by default, users may not mount */
! 64:
! 65: static int change_dir(struct nameidata *, struct proc *);
! 66:
! 67: void checkdirs(struct vnode *);
! 68:
! 69: int copyout_statfs(struct statfs *, void *, struct proc *);
! 70:
! 71: /*
! 72: * Virtual File System System Calls
! 73: */
! 74:
! 75: /*
! 76: * Mount a file system.
! 77: */
! 78: /* ARGSUSED */
! 79: int
! 80: sys_mount(struct proc *p, void *v, register_t *retval)
! 81: {
! 82: struct sys_mount_args /* {
! 83: syscallarg(const char *) type;
! 84: syscallarg(const char *) path;
! 85: syscallarg(int) flags;
! 86: syscallarg(void *) data;
! 87: } */ *uap = v;
! 88: struct vnode *vp;
! 89: struct mount *mp;
! 90: int error, flag = 0;
! 91: #ifdef COMPAT_43
! 92: u_long fstypenum = 0;
! 93: #endif
! 94: char fstypename[MFSNAMELEN];
! 95: char fspath[MNAMELEN];
! 96: struct vattr va;
! 97: struct nameidata nd;
! 98: struct vfsconf *vfsp;
! 99:
! 100: if (usermount == 0 && (error = suser(p, 0)))
! 101: return (error);
! 102:
! 103: /*
! 104: * Mount points must fit in MNAMELEN, not MAXPATHLEN.
! 105: */
! 106: error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
! 107: if (error)
! 108: return(error);
! 109:
! 110: /*
! 111: * Get vnode to be covered
! 112: */
! 113: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p);
! 114: if ((error = namei(&nd)) != 0)
! 115: return (error);
! 116: vp = nd.ni_vp;
! 117: if (SCARG(uap, flags) & MNT_UPDATE) {
! 118: if ((vp->v_flag & VROOT) == 0) {
! 119: vput(vp);
! 120: return (EINVAL);
! 121: }
! 122: mp = vp->v_mount;
! 123: flag = mp->mnt_flag;
! 124: /*
! 125: * We only allow the filesystem to be reloaded if it
! 126: * is currently mounted read-only.
! 127: */
! 128: if ((SCARG(uap, flags) & MNT_RELOAD) &&
! 129: ((mp->mnt_flag & MNT_RDONLY) == 0)) {
! 130: vput(vp);
! 131: return (EOPNOTSUPP); /* Needs translation */
! 132: }
! 133:
! 134: /*
! 135: * Only root, or the user that did the original mount is
! 136: * permitted to update it.
! 137: */
! 138: if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
! 139: (error = suser(p, 0))) {
! 140: vput(vp);
! 141: return (error);
! 142: }
! 143: /*
! 144: * Do not allow NFS export by non-root users. Silently
! 145: * enforce MNT_NOSUID and MNT_NODEV for non-root users, and
! 146: * inherit MNT_NOEXEC from the mount point.
! 147: */
! 148: if (p->p_ucred->cr_uid != 0) {
! 149: if (SCARG(uap, flags) & MNT_EXPORTED) {
! 150: vput(vp);
! 151: return (EPERM);
! 152: }
! 153: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
! 154: if (flag & MNT_NOEXEC)
! 155: SCARG(uap, flags) |= MNT_NOEXEC;
! 156: }
! 157: if ((error = vfs_busy(mp, VB_READ|VB_NOWAIT)) != 0) {
! 158: vput(vp);
! 159: return (error);
! 160: }
! 161: VOP_UNLOCK(vp, 0, p);
! 162: mp->mnt_flag |= SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE);
! 163: goto update;
! 164: }
! 165: /*
! 166: * If the user is not root, ensure that they own the directory
! 167: * onto which we are attempting to mount.
! 168: */
! 169: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
! 170: (va.va_uid != p->p_ucred->cr_uid &&
! 171: (error = suser(p, 0)))) {
! 172: vput(vp);
! 173: return (error);
! 174: }
! 175: /*
! 176: * Do not allow NFS export by non-root users. Silently
! 177: * enforce MNT_NOSUID and MNT_NODEV for non-root users, and inherit
! 178: * MNT_NOEXEC from the mount point.
! 179: */
! 180: if (p->p_ucred->cr_uid != 0) {
! 181: if (SCARG(uap, flags) & MNT_EXPORTED) {
! 182: vput(vp);
! 183: return (EPERM);
! 184: }
! 185: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
! 186: if (vp->v_mount->mnt_flag & MNT_NOEXEC)
! 187: SCARG(uap, flags) |= MNT_NOEXEC;
! 188: }
! 189: if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
! 190: vput(vp);
! 191: return (error);
! 192: }
! 193: if (vp->v_type != VDIR) {
! 194: vput(vp);
! 195: return (ENOTDIR);
! 196: }
! 197: error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
! 198: if (error) {
! 199: #ifdef COMPAT_43
! 200: /*
! 201: * Historically filesystem types were identified by number.
! 202: * If we get an integer for the filesystem type instead of a
! 203: * string, we check to see if it matches one of the historic
! 204: * filesystem types.
! 205: */
! 206: fstypenum = (u_long)SCARG(uap, type);
! 207:
! 208: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
! 209: if (vfsp->vfc_typenum == fstypenum)
! 210: break;
! 211: if (vfsp == NULL) {
! 212: vput(vp);
! 213: return (ENODEV);
! 214: }
! 215: strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
! 216:
! 217: #else
! 218: vput(vp);
! 219: return (error);
! 220: #endif
! 221: }
! 222: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
! 223: if (!strcmp(vfsp->vfc_name, fstypename))
! 224: break;
! 225: }
! 226:
! 227: if (vfsp == NULL) {
! 228: vput(vp);
! 229: return (EOPNOTSUPP);
! 230: }
! 231:
! 232: if (vp->v_mountedhere != NULL) {
! 233: vput(vp);
! 234: return (EBUSY);
! 235: }
! 236:
! 237: /*
! 238: * Allocate and initialize the file system.
! 239: */
! 240: mp = (struct mount *)malloc((u_long)sizeof(struct mount),
! 241: M_MOUNT, M_WAITOK);
! 242: bzero((char *)mp, (u_long)sizeof(struct mount));
! 243: (void) vfs_busy(mp, VB_READ|VB_NOWAIT);
! 244: mp->mnt_op = vfsp->vfc_vfsops;
! 245: mp->mnt_vfc = vfsp;
! 246: mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK);
! 247: strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
! 248: mp->mnt_vnodecovered = vp;
! 249: mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
! 250: update:
! 251: /*
! 252: * Set the mount level flags.
! 253: */
! 254: if (SCARG(uap, flags) & MNT_RDONLY)
! 255: mp->mnt_flag |= MNT_RDONLY;
! 256: else if (mp->mnt_flag & MNT_RDONLY)
! 257: mp->mnt_flag |= MNT_WANTRDWR;
! 258: mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
! 259: MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME |
! 260: MNT_FORCE);
! 261: mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
! 262: MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP |
! 263: MNT_NOATIME | MNT_FORCE);
! 264: /*
! 265: * Mount the filesystem.
! 266: */
! 267: error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
! 268: if (!error) {
! 269: mp->mnt_stat.f_ctime = time_second;
! 270: }
! 271: if (mp->mnt_flag & MNT_UPDATE) {
! 272: vrele(vp);
! 273: if (mp->mnt_flag & MNT_WANTRDWR)
! 274: mp->mnt_flag &= ~MNT_RDONLY;
! 275: mp->mnt_flag &=~
! 276: (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
! 277: if (error)
! 278: mp->mnt_flag = flag;
! 279:
! 280: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
! 281: if (mp->mnt_syncer == NULL)
! 282: error = vfs_allocate_syncvnode(mp);
! 283: } else {
! 284: if (mp->mnt_syncer != NULL)
! 285: vgone(mp->mnt_syncer);
! 286: mp->mnt_syncer = NULL;
! 287: }
! 288:
! 289: vfs_unbusy(mp);
! 290: return (error);
! 291: }
! 292:
! 293: vp->v_mountedhere = mp;
! 294:
! 295: /*
! 296: * Put the new filesystem on the mount list after root.
! 297: */
! 298: cache_purge(vp);
! 299: if (!error) {
! 300: vfsp->vfc_refcount++;
! 301: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
! 302: checkdirs(vp);
! 303: VOP_UNLOCK(vp, 0, p);
! 304: if ((mp->mnt_flag & MNT_RDONLY) == 0)
! 305: error = vfs_allocate_syncvnode(mp);
! 306: vfs_unbusy(mp);
! 307: (void) VFS_STATFS(mp, &mp->mnt_stat, p);
! 308: if ((error = VFS_START(mp, 0, p)) != 0)
! 309: vrele(vp);
! 310: } else {
! 311: mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
! 312: vfs_unbusy(mp);
! 313: free(mp, M_MOUNT);
! 314: vput(vp);
! 315: }
! 316: return (error);
! 317: }
! 318:
! 319: /*
! 320: * Scan all active processes to see if any of them have a current
! 321: * or root directory onto which the new filesystem has just been
! 322: * mounted. If so, replace them with the new mount point.
! 323: */
! 324: void
! 325: checkdirs(struct vnode *olddp)
! 326: {
! 327: struct filedesc *fdp;
! 328: struct vnode *newdp;
! 329: struct proc *p;
! 330:
! 331: if (olddp->v_usecount == 1)
! 332: return;
! 333: if (VFS_ROOT(olddp->v_mountedhere, &newdp))
! 334: panic("mount: lost mount");
! 335: for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) {
! 336: fdp = p->p_fd;
! 337: if (fdp->fd_cdir == olddp) {
! 338: vrele(fdp->fd_cdir);
! 339: VREF(newdp);
! 340: fdp->fd_cdir = newdp;
! 341: }
! 342: if (fdp->fd_rdir == olddp) {
! 343: vrele(fdp->fd_rdir);
! 344: VREF(newdp);
! 345: fdp->fd_rdir = newdp;
! 346: }
! 347: }
! 348: if (rootvnode == olddp) {
! 349: vrele(rootvnode);
! 350: VREF(newdp);
! 351: rootvnode = newdp;
! 352: }
! 353: vput(newdp);
! 354: }
! 355:
! 356: /*
! 357: * Unmount a file system.
! 358: *
! 359: * Note: unmount takes a path to the vnode mounted on as argument,
! 360: * not special file (as before).
! 361: */
! 362: /* ARGSUSED */
! 363: int
! 364: sys_unmount(struct proc *p, void *v, register_t *retval)
! 365: {
! 366: struct sys_unmount_args /* {
! 367: syscallarg(const char *) path;
! 368: syscallarg(int) flags;
! 369: } */ *uap = v;
! 370: struct vnode *vp;
! 371: struct mount *mp;
! 372: int error;
! 373: struct nameidata nd;
! 374:
! 375: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 376: SCARG(uap, path), p);
! 377: if ((error = namei(&nd)) != 0)
! 378: return (error);
! 379: vp = nd.ni_vp;
! 380: mp = vp->v_mount;
! 381:
! 382: /*
! 383: * Only root, or the user that did the original mount is
! 384: * permitted to unmount this filesystem.
! 385: */
! 386: if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
! 387: (error = suser(p, 0))) {
! 388: vput(vp);
! 389: return (error);
! 390: }
! 391:
! 392: /*
! 393: * Don't allow unmounting the root file system.
! 394: */
! 395: if (mp->mnt_flag & MNT_ROOTFS) {
! 396: vput(vp);
! 397: return (EINVAL);
! 398: }
! 399:
! 400: /*
! 401: * Must be the root of the filesystem
! 402: */
! 403: if ((vp->v_flag & VROOT) == 0) {
! 404: vput(vp);
! 405: return (EINVAL);
! 406: }
! 407: vput(vp);
! 408:
! 409: if (vfs_busy(mp, VB_WRITE|VB_WAIT))
! 410: return (EBUSY);
! 411:
! 412: return (dounmount(mp, SCARG(uap, flags), p, vp));
! 413: }
! 414:
! 415: /*
! 416: * Do the actual file system unmount.
! 417: */
! 418: int
! 419: dounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp)
! 420: {
! 421: struct vnode *coveredvp;
! 422: int error;
! 423: int hadsyncer = 0;
! 424:
! 425: mp->mnt_flag &=~ MNT_ASYNC;
! 426: cache_purgevfs(mp); /* remove cache entries for this file sys */
! 427: if (mp->mnt_syncer != NULL) {
! 428: hadsyncer = 1;
! 429: vgone(mp->mnt_syncer);
! 430: mp->mnt_syncer = NULL;
! 431: }
! 432: if (((mp->mnt_flag & MNT_RDONLY) ||
! 433: (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
! 434: (flags & MNT_FORCE))
! 435: error = VFS_UNMOUNT(mp, flags, p);
! 436:
! 437: if (error && error != EIO && !(flags & MNT_DOOMED)) {
! 438: if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer)
! 439: (void) vfs_allocate_syncvnode(mp);
! 440: vfs_unbusy(mp);
! 441: return (error);
! 442: }
! 443:
! 444: CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
! 445: if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
! 446: coveredvp->v_mountedhere = NULL;
! 447: vrele(coveredvp);
! 448: }
! 449:
! 450: mp->mnt_vfc->vfc_refcount--;
! 451:
! 452: if (!LIST_EMPTY(&mp->mnt_vnodelist))
! 453: panic("unmount: dangling vnode");
! 454:
! 455: vfs_unbusy(mp);
! 456: free(mp, M_MOUNT);
! 457:
! 458: return (0);
! 459: }
! 460:
! 461: /*
! 462: * Sync each mounted filesystem.
! 463: */
! 464: #ifdef DEBUG
! 465: int syncprt = 0;
! 466: struct ctldebug debug0 = { "syncprt", &syncprt };
! 467: #endif
! 468:
! 469: /* ARGSUSED */
! 470: int
! 471: sys_sync(struct proc *p, void *v, register_t *retval)
! 472: {
! 473: struct mount *mp, *nmp;
! 474: int asyncflag;
! 475:
! 476: for (mp = CIRCLEQ_LAST(&mountlist); mp != CIRCLEQ_END(&mountlist);
! 477: mp = nmp) {
! 478: if (vfs_busy(mp, VB_READ|VB_NOWAIT)) {
! 479: nmp = CIRCLEQ_PREV(mp, mnt_list);
! 480: continue;
! 481: }
! 482: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
! 483: asyncflag = mp->mnt_flag & MNT_ASYNC;
! 484: mp->mnt_flag &= ~MNT_ASYNC;
! 485: uvm_vnp_sync(mp);
! 486: VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
! 487: if (asyncflag)
! 488: mp->mnt_flag |= MNT_ASYNC;
! 489: }
! 490: nmp = CIRCLEQ_PREV(mp, mnt_list);
! 491: vfs_unbusy(mp);
! 492: }
! 493:
! 494: #ifdef DEBUG
! 495: if (syncprt)
! 496: vfs_bufstats();
! 497: #endif /* DEBUG */
! 498: return (0);
! 499: }
! 500:
! 501: /*
! 502: * Change filesystem quotas.
! 503: */
! 504: /* ARGSUSED */
! 505: int
! 506: sys_quotactl(struct proc *p, void *v, register_t *retval)
! 507: {
! 508: struct sys_quotactl_args /* {
! 509: syscallarg(const char *) path;
! 510: syscallarg(int) cmd;
! 511: syscallarg(int) uid;
! 512: syscallarg(char *) arg;
! 513: } */ *uap = v;
! 514: struct mount *mp;
! 515: int error;
! 516: struct nameidata nd;
! 517:
! 518: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 519: if ((error = namei(&nd)) != 0)
! 520: return (error);
! 521: mp = nd.ni_vp->v_mount;
! 522: vrele(nd.ni_vp);
! 523: return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
! 524: SCARG(uap, arg), p));
! 525: }
! 526:
! 527: int
! 528: copyout_statfs(struct statfs *sp, void *uaddr, struct proc *p)
! 529: {
! 530: size_t co_sz1 = offsetof(struct statfs, f_fsid);
! 531: size_t co_off2 = co_sz1 + sizeof(fsid_t);
! 532: size_t co_sz2 = sizeof(struct statfs) - co_off2;
! 533: char *s, *d;
! 534: int error;
! 535:
! 536: /* Don't let non-root see filesystem id (for NFS security) */
! 537: if (suser(p, 0)) {
! 538: fsid_t fsid;
! 539:
! 540: s = (char *)sp;
! 541: d = (char *)uaddr;
! 542:
! 543: memset(&fsid, 0, sizeof(fsid));
! 544:
! 545: if ((error = copyout(s, d, co_sz1)) != 0)
! 546: return (error);
! 547: if ((error = copyout(&fsid, d + co_sz1, sizeof(fsid))) != 0)
! 548: return (error);
! 549: return (copyout(s + co_off2, d + co_off2, co_sz2));
! 550: }
! 551:
! 552: return (copyout(sp, uaddr, sizeof(*sp)));
! 553: }
! 554:
! 555: /*
! 556: * Get filesystem statistics.
! 557: */
! 558: /* ARGSUSED */
! 559: int
! 560: sys_statfs(struct proc *p, void *v, register_t *retval)
! 561: {
! 562: struct sys_statfs_args /* {
! 563: syscallarg(const char *) path;
! 564: syscallarg(struct statfs *) buf;
! 565: } */ *uap = v;
! 566: struct mount *mp;
! 567: struct statfs *sp;
! 568: int error;
! 569: struct nameidata nd;
! 570:
! 571: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 572: if ((error = namei(&nd)) != 0)
! 573: return (error);
! 574: mp = nd.ni_vp->v_mount;
! 575: sp = &mp->mnt_stat;
! 576: vrele(nd.ni_vp);
! 577: if ((error = VFS_STATFS(mp, sp, p)) != 0)
! 578: return (error);
! 579: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
! 580: #if notyet
! 581: if (mp->mnt_flag & MNT_SOFTDEP)
! 582: sp->f_eflags = STATFS_SOFTUPD;
! 583: #endif
! 584: return (copyout_statfs(sp, SCARG(uap, buf), p));
! 585: }
! 586:
! 587: /*
! 588: * Get filesystem statistics.
! 589: */
! 590: /* ARGSUSED */
! 591: int
! 592: sys_fstatfs(struct proc *p, void *v, register_t *retval)
! 593: {
! 594: struct sys_fstatfs_args /* {
! 595: syscallarg(int) fd;
! 596: syscallarg(struct statfs *) buf;
! 597: } */ *uap = v;
! 598: struct file *fp;
! 599: struct mount *mp;
! 600: struct statfs *sp;
! 601: int error;
! 602:
! 603: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 604: return (error);
! 605: mp = ((struct vnode *)fp->f_data)->v_mount;
! 606: if (!mp) {
! 607: FRELE(fp);
! 608: return (ENOENT);
! 609: }
! 610: sp = &mp->mnt_stat;
! 611: error = VFS_STATFS(mp, sp, p);
! 612: FRELE(fp);
! 613: if (error)
! 614: return (error);
! 615: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
! 616: #if notyet
! 617: if (mp->mnt_flag & MNT_SOFTDEP)
! 618: sp->f_eflags = STATFS_SOFTUPD;
! 619: #endif
! 620: return (copyout_statfs(sp, SCARG(uap, buf), p));
! 621: }
! 622:
! 623: /*
! 624: * Get statistics on all filesystems.
! 625: */
! 626: int
! 627: sys_getfsstat(struct proc *p, void *v, register_t *retval)
! 628: {
! 629: struct sys_getfsstat_args /* {
! 630: syscallarg(struct statfs *) buf;
! 631: syscallarg(size_t) bufsize;
! 632: syscallarg(int) flags;
! 633: } */ *uap = v;
! 634: struct mount *mp, *nmp;
! 635: struct statfs *sp;
! 636: struct statfs *sfsp;
! 637: size_t count, maxcount;
! 638: int error, flags = SCARG(uap, flags);
! 639:
! 640: maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
! 641: sfsp = SCARG(uap, buf);
! 642: count = 0;
! 643:
! 644: for (mp = CIRCLEQ_FIRST(&mountlist); mp != CIRCLEQ_END(&mountlist);
! 645: mp = nmp) {
! 646: if (vfs_busy(mp, VB_READ|VB_NOWAIT)) {
! 647: nmp = CIRCLEQ_NEXT(mp, mnt_list);
! 648: continue;
! 649: }
! 650: if (sfsp && count < maxcount) {
! 651: sp = &mp->mnt_stat;
! 652:
! 653: /* Refresh stats unless MNT_NOWAIT is specified */
! 654: if (flags != MNT_NOWAIT &&
! 655: flags != MNT_LAZY &&
! 656: (flags == MNT_WAIT ||
! 657: flags == 0) &&
! 658: (error = VFS_STATFS(mp, sp, p))) {
! 659: nmp = CIRCLEQ_NEXT(mp, mnt_list);
! 660: vfs_unbusy(mp);
! 661: continue;
! 662: }
! 663:
! 664: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
! 665: #if notyet
! 666: if (mp->mnt_flag & MNT_SOFTDEP)
! 667: sp->f_eflags = STATFS_SOFTUPD;
! 668: #endif
! 669: error = (copyout_statfs(sp, sfsp, p));
! 670: if (error) {
! 671: vfs_unbusy(mp);
! 672: return (error);
! 673: }
! 674: sfsp++;
! 675: }
! 676: count++;
! 677: nmp = CIRCLEQ_NEXT(mp, mnt_list);
! 678: vfs_unbusy(mp);
! 679: }
! 680:
! 681: if (sfsp && count > maxcount)
! 682: *retval = maxcount;
! 683: else
! 684: *retval = count;
! 685:
! 686: return (0);
! 687: }
! 688:
! 689: /*
! 690: * Change current working directory to a given file descriptor.
! 691: */
! 692: /* ARGSUSED */
! 693: int
! 694: sys_fchdir(struct proc *p, void *v, register_t *retval)
! 695: {
! 696: struct sys_fchdir_args /* {
! 697: syscallarg(int) fd;
! 698: } */ *uap = v;
! 699: struct filedesc *fdp = p->p_fd;
! 700: struct vnode *vp, *tdp;
! 701: struct mount *mp;
! 702: struct file *fp;
! 703: int error;
! 704:
! 705: if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
! 706: return (error);
! 707: vp = (struct vnode *)fp->f_data;
! 708: VREF(vp);
! 709: FRELE(fp);
! 710: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 711: if (vp->v_type != VDIR)
! 712: error = ENOTDIR;
! 713: else
! 714: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
! 715:
! 716: while (!error && (mp = vp->v_mountedhere) != NULL) {
! 717: if (vfs_busy(mp, VB_READ|VB_WAIT))
! 718: continue;
! 719: error = VFS_ROOT(mp, &tdp);
! 720: vfs_unbusy(mp);
! 721: if (error)
! 722: break;
! 723: vput(vp);
! 724: vp = tdp;
! 725: }
! 726: if (error) {
! 727: vput(vp);
! 728: return (error);
! 729: }
! 730: VOP_UNLOCK(vp, 0, p);
! 731: vrele(fdp->fd_cdir);
! 732: fdp->fd_cdir = vp;
! 733: return (0);
! 734: }
! 735:
! 736: /*
! 737: * Change current working directory (``.'').
! 738: */
! 739: /* ARGSUSED */
! 740: int
! 741: sys_chdir(struct proc *p, void *v, register_t *retval)
! 742: {
! 743: struct sys_chdir_args /* {
! 744: syscallarg(const char *) path;
! 745: } */ *uap = v;
! 746: struct filedesc *fdp = p->p_fd;
! 747: int error;
! 748: struct nameidata nd;
! 749:
! 750: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 751: SCARG(uap, path), p);
! 752: if ((error = change_dir(&nd, p)) != 0)
! 753: return (error);
! 754: vrele(fdp->fd_cdir);
! 755: fdp->fd_cdir = nd.ni_vp;
! 756: return (0);
! 757: }
! 758:
! 759: /*
! 760: * Change notion of root (``/'') directory.
! 761: */
! 762: /* ARGSUSED */
! 763: int
! 764: sys_chroot(struct proc *p, void *v, register_t *retval)
! 765: {
! 766: struct sys_chroot_args /* {
! 767: syscallarg(const char *) path;
! 768: } */ *uap = v;
! 769: struct filedesc *fdp = p->p_fd;
! 770: int error;
! 771: struct nameidata nd;
! 772:
! 773: if ((error = suser(p, 0)) != 0)
! 774: return (error);
! 775: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 776: SCARG(uap, path), p);
! 777: if ((error = change_dir(&nd, p)) != 0)
! 778: return (error);
! 779: if (fdp->fd_rdir != NULL) {
! 780: /*
! 781: * A chroot() done inside a changed root environment does
! 782: * an automatic chdir to avoid the out-of-tree experience.
! 783: */
! 784: vrele(fdp->fd_rdir);
! 785: vrele(fdp->fd_cdir);
! 786: VREF(nd.ni_vp);
! 787: fdp->fd_cdir = nd.ni_vp;
! 788: }
! 789: fdp->fd_rdir = nd.ni_vp;
! 790: return (0);
! 791: }
! 792:
! 793: /*
! 794: * Common routine for chroot and chdir.
! 795: */
! 796: static int
! 797: change_dir(struct nameidata *ndp, struct proc *p)
! 798: {
! 799: struct vnode *vp;
! 800: int error;
! 801:
! 802: if ((error = namei(ndp)) != 0)
! 803: return (error);
! 804: vp = ndp->ni_vp;
! 805: if (vp->v_type != VDIR)
! 806: error = ENOTDIR;
! 807: else
! 808: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
! 809: if (error)
! 810: vput(vp);
! 811: else
! 812: VOP_UNLOCK(vp, 0, p);
! 813: return (error);
! 814: }
! 815:
! 816: /*
! 817: * Check permissions, allocate an open file structure,
! 818: * and call the device open routine if any.
! 819: */
! 820: int
! 821: sys_open(struct proc *p, void *v, register_t *retval)
! 822: {
! 823: struct sys_open_args /* {
! 824: syscallarg(const char *) path;
! 825: syscallarg(int) flags;
! 826: syscallarg(mode_t) mode;
! 827: } */ *uap = v;
! 828: struct filedesc *fdp = p->p_fd;
! 829: struct file *fp;
! 830: struct vnode *vp;
! 831: struct vattr vattr;
! 832: int flags, cmode;
! 833: int type, indx, error, localtrunc = 0;
! 834: struct flock lf;
! 835: struct nameidata nd;
! 836:
! 837: fdplock(fdp);
! 838:
! 839: if ((error = falloc(p, &fp, &indx)) != 0)
! 840: goto out;
! 841:
! 842: flags = FFLAGS(SCARG(uap, flags));
! 843: cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
! 844: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 845: p->p_dupfd = -1; /* XXX check for fdopen */
! 846: if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
! 847: localtrunc = 1;
! 848: flags &= ~O_TRUNC; /* Must do truncate ourselves */
! 849: }
! 850: if ((error = vn_open(&nd, flags, cmode)) != 0) {
! 851: if ((error == ENODEV || error == ENXIO) &&
! 852: p->p_dupfd >= 0 && /* XXX from fdopen */
! 853: (error =
! 854: dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
! 855: closef(fp, p);
! 856: *retval = indx;
! 857: goto out;
! 858: }
! 859: if (error == ERESTART)
! 860: error = EINTR;
! 861: fdremove(fdp, indx);
! 862: closef(fp, p);
! 863: goto out;
! 864: }
! 865: p->p_dupfd = 0;
! 866: vp = nd.ni_vp;
! 867: fp->f_flag = flags & FMASK;
! 868: fp->f_type = DTYPE_VNODE;
! 869: fp->f_ops = &vnops;
! 870: fp->f_data = vp;
! 871: if (flags & (O_EXLOCK | O_SHLOCK)) {
! 872: lf.l_whence = SEEK_SET;
! 873: lf.l_start = 0;
! 874: lf.l_len = 0;
! 875: if (flags & O_EXLOCK)
! 876: lf.l_type = F_WRLCK;
! 877: else
! 878: lf.l_type = F_RDLCK;
! 879: type = F_FLOCK;
! 880: if ((flags & FNONBLOCK) == 0)
! 881: type |= F_WAIT;
! 882: VOP_UNLOCK(vp, 0, p);
! 883: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
! 884: if (error) {
! 885: /* closef will vn_close the file for us. */
! 886: fdremove(fdp, indx);
! 887: closef(fp, p);
! 888: goto out;
! 889: }
! 890: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 891: fp->f_flag |= FHASLOCK;
! 892: }
! 893: if (localtrunc) {
! 894: if ((fp->f_flag & FWRITE) == 0)
! 895: error = EACCES;
! 896: else if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 897: error = EROFS;
! 898: else if (vp->v_type == VDIR)
! 899: error = EISDIR;
! 900: else if ((error = vn_writechk(vp)) == 0) {
! 901: VATTR_NULL(&vattr);
! 902: vattr.va_size = 0;
! 903: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
! 904: }
! 905: if (error) {
! 906: VOP_UNLOCK(vp, 0, p);
! 907: /* closef will close the file for us. */
! 908: fdremove(fdp, indx);
! 909: closef(fp, p);
! 910: goto out;
! 911: }
! 912: }
! 913: VOP_UNLOCK(vp, 0, p);
! 914: *retval = indx;
! 915: FILE_SET_MATURE(fp);
! 916: out:
! 917: fdpunlock(fdp);
! 918: return (error);
! 919: }
! 920:
! 921: /*
! 922: * Get file handle system call
! 923: */
! 924: int
! 925: sys_getfh(struct proc *p, void *v, register_t *retval)
! 926: {
! 927: struct sys_getfh_args /* {
! 928: syscallarg(const char *) fname;
! 929: syscallarg(fhandle_t *) fhp;
! 930: } */ *uap = v;
! 931: struct vnode *vp;
! 932: fhandle_t fh;
! 933: int error;
! 934: struct nameidata nd;
! 935:
! 936: /*
! 937: * Must be super user
! 938: */
! 939: error = suser(p, 0);
! 940: if (error)
! 941: return (error);
! 942: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 943: SCARG(uap, fname), p);
! 944: error = namei(&nd);
! 945: if (error)
! 946: return (error);
! 947: vp = nd.ni_vp;
! 948: bzero(&fh, sizeof(fh));
! 949: fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
! 950: error = VFS_VPTOFH(vp, &fh.fh_fid);
! 951: vput(vp);
! 952: if (error)
! 953: return (error);
! 954: error = copyout(&fh, SCARG(uap, fhp), sizeof(fh));
! 955: return (error);
! 956: }
! 957:
! 958: /*
! 959: * Open a file given a file handle.
! 960: *
! 961: * Check permissions, allocate an open file structure,
! 962: * and call the device open routine if any.
! 963: */
! 964: int
! 965: sys_fhopen(struct proc *p, void *v, register_t *retval)
! 966: {
! 967: struct sys_fhopen_args /* {
! 968: syscallarg(const fhandle_t *) fhp;
! 969: syscallarg(int) flags;
! 970: } */ *uap = v;
! 971: struct filedesc *fdp = p->p_fd;
! 972: struct file *fp;
! 973: struct vnode *vp = NULL;
! 974: struct mount *mp;
! 975: struct ucred *cred = p->p_ucred;
! 976: int flags;
! 977: int type, indx, error=0;
! 978: struct flock lf;
! 979: struct vattr va;
! 980: fhandle_t fh;
! 981:
! 982: /*
! 983: * Must be super user
! 984: */
! 985: if ((error = suser(p, 0)))
! 986: return (error);
! 987:
! 988: flags = FFLAGS(SCARG(uap, flags));
! 989: if ((flags & (FREAD | FWRITE)) == 0)
! 990: return (EINVAL);
! 991: if ((flags & O_CREAT))
! 992: return (EINVAL);
! 993:
! 994: fdplock(fdp);
! 995: if ((error = falloc(p, &fp, &indx)) != 0) {
! 996: fp = NULL;
! 997: goto bad;
! 998: }
! 999:
! 1000: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
! 1001: goto bad;
! 1002:
! 1003: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
! 1004: error = ESTALE;
! 1005: goto bad;
! 1006: }
! 1007:
! 1008: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
! 1009: vp = NULL; /* most likely unnecessary sanity for bad: */
! 1010: goto bad;
! 1011: }
! 1012:
! 1013: /* Now do an effective vn_open */
! 1014:
! 1015: if (vp->v_type == VSOCK) {
! 1016: error = EOPNOTSUPP;
! 1017: goto bad;
! 1018: }
! 1019: if (flags & FREAD) {
! 1020: if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
! 1021: goto bad;
! 1022: }
! 1023: if (flags & (FWRITE | O_TRUNC)) {
! 1024: if (vp->v_type == VDIR) {
! 1025: error = EISDIR;
! 1026: goto bad;
! 1027: }
! 1028: if ((error = vn_writechk(vp)) != 0 ||
! 1029: (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
! 1030: goto bad;
! 1031: }
! 1032: if (flags & O_TRUNC) {
! 1033: VATTR_NULL(&va);
! 1034: va.va_size = 0;
! 1035: if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
! 1036: goto bad;
! 1037: }
! 1038: if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
! 1039: goto bad;
! 1040: if (flags & FWRITE)
! 1041: vp->v_writecount++;
! 1042:
! 1043: /* done with modified vn_open, now finish what sys_open does. */
! 1044:
! 1045: fp->f_flag = flags & FMASK;
! 1046: fp->f_type = DTYPE_VNODE;
! 1047: fp->f_ops = &vnops;
! 1048: fp->f_data = vp;
! 1049: if (flags & (O_EXLOCK | O_SHLOCK)) {
! 1050: lf.l_whence = SEEK_SET;
! 1051: lf.l_start = 0;
! 1052: lf.l_len = 0;
! 1053: if (flags & O_EXLOCK)
! 1054: lf.l_type = F_WRLCK;
! 1055: else
! 1056: lf.l_type = F_RDLCK;
! 1057: type = F_FLOCK;
! 1058: if ((flags & FNONBLOCK) == 0)
! 1059: type |= F_WAIT;
! 1060: VOP_UNLOCK(vp, 0, p);
! 1061: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
! 1062: if (error)
! 1063: goto bad;
! 1064: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1065: fp->f_flag |= FHASLOCK;
! 1066: }
! 1067: VOP_UNLOCK(vp, 0, p);
! 1068: *retval = indx;
! 1069: FILE_SET_MATURE(fp);
! 1070:
! 1071: fdpunlock(fdp);
! 1072: return (0);
! 1073:
! 1074: bad:
! 1075: if (fp) {
! 1076: fdremove(fdp, indx);
! 1077: closef(fp, p);
! 1078: if (vp != NULL)
! 1079: vput(vp);
! 1080: }
! 1081: fdpunlock(fdp);
! 1082: return (error);
! 1083: }
! 1084:
! 1085: /* ARGSUSED */
! 1086: int
! 1087: sys_fhstat(struct proc *p, void *v, register_t *retval)
! 1088: {
! 1089: struct sys_fhstat_args /* {
! 1090: syscallarg(const fhandle_t *) fhp;
! 1091: syscallarg(struct stat *) sb;
! 1092: } */ *uap = v;
! 1093: struct stat sb;
! 1094: int error;
! 1095: fhandle_t fh;
! 1096: struct mount *mp;
! 1097: struct vnode *vp;
! 1098:
! 1099: /*
! 1100: * Must be super user
! 1101: */
! 1102: if ((error = suser(p, 0)))
! 1103: return (error);
! 1104:
! 1105: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
! 1106: return (error);
! 1107:
! 1108: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
! 1109: return (ESTALE);
! 1110: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
! 1111: return (error);
! 1112: error = vn_stat(vp, &sb, p);
! 1113: vput(vp);
! 1114: if (error)
! 1115: return (error);
! 1116: error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
! 1117: return (error);
! 1118: }
! 1119:
! 1120: /* ARGSUSED */
! 1121: int
! 1122: sys_fhstatfs(struct proc *p, void *v, register_t *retval)
! 1123: {
! 1124: struct sys_fhstatfs_args /*
! 1125: syscallarg(const fhandle_t *) fhp;
! 1126: syscallarg(struct statfs *) buf;
! 1127: } */ *uap = v;
! 1128: struct statfs *sp;
! 1129: fhandle_t fh;
! 1130: struct mount *mp;
! 1131: struct vnode *vp;
! 1132: int error;
! 1133:
! 1134: /*
! 1135: * Must be super user
! 1136: */
! 1137: if ((error = suser(p, 0)))
! 1138: return (error);
! 1139:
! 1140: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
! 1141: return (error);
! 1142:
! 1143: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
! 1144: return (ESTALE);
! 1145: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
! 1146: return (error);
! 1147: mp = vp->v_mount;
! 1148: sp = &mp->mnt_stat;
! 1149: vput(vp);
! 1150: if ((error = VFS_STATFS(mp, sp, p)) != 0)
! 1151: return (error);
! 1152: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
! 1153: return (copyout(sp, SCARG(uap, buf), sizeof(sp)));
! 1154: }
! 1155:
! 1156: /*
! 1157: * Create a special file.
! 1158: */
! 1159: /* ARGSUSED */
! 1160: int
! 1161: sys_mknod(struct proc *p, void *v, register_t *retval)
! 1162: {
! 1163: struct sys_mknod_args /* {
! 1164: syscallarg(const char *) path;
! 1165: syscallarg(mode_t) mode;
! 1166: syscallarg(int) dev;
! 1167: } */ *uap = v;
! 1168: struct vnode *vp;
! 1169: struct vattr vattr;
! 1170: int error;
! 1171: struct nameidata nd;
! 1172:
! 1173: if ((error = suser(p, 0)) != 0)
! 1174: return (error);
! 1175: if (p->p_fd->fd_rdir)
! 1176: return (EINVAL);
! 1177: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
! 1178: if ((error = namei(&nd)) != 0)
! 1179: return (error);
! 1180: vp = nd.ni_vp;
! 1181: if (vp != NULL)
! 1182: error = EEXIST;
! 1183: else {
! 1184: VATTR_NULL(&vattr);
! 1185: vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
! 1186: vattr.va_rdev = SCARG(uap, dev);
! 1187:
! 1188: switch (SCARG(uap, mode) & S_IFMT) {
! 1189: case S_IFMT: /* used by badsect to flag bad sectors */
! 1190: vattr.va_type = VBAD;
! 1191: break;
! 1192: case S_IFCHR:
! 1193: vattr.va_type = VCHR;
! 1194: break;
! 1195: case S_IFBLK:
! 1196: vattr.va_type = VBLK;
! 1197: break;
! 1198: default:
! 1199: error = EINVAL;
! 1200: break;
! 1201: }
! 1202: }
! 1203: if (!error) {
! 1204: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
! 1205: } else {
! 1206: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1207: if (nd.ni_dvp == vp)
! 1208: vrele(nd.ni_dvp);
! 1209: else
! 1210: vput(nd.ni_dvp);
! 1211: if (vp)
! 1212: vrele(vp);
! 1213: }
! 1214: return (error);
! 1215: }
! 1216:
! 1217: /*
! 1218: * Create a named pipe.
! 1219: */
! 1220: /* ARGSUSED */
! 1221: int
! 1222: sys_mkfifo(struct proc *p, void *v, register_t *retval)
! 1223: {
! 1224: #ifndef FIFO
! 1225: return (EOPNOTSUPP);
! 1226: #else
! 1227: struct sys_mkfifo_args /* {
! 1228: syscallarg(const char *) path;
! 1229: syscallarg(mode_t) mode;
! 1230: } */ *uap = v;
! 1231: struct vattr vattr;
! 1232: int error;
! 1233: struct nameidata nd;
! 1234:
! 1235: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
! 1236: if ((error = namei(&nd)) != 0)
! 1237: return (error);
! 1238: if (nd.ni_vp != NULL) {
! 1239: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1240: if (nd.ni_dvp == nd.ni_vp)
! 1241: vrele(nd.ni_dvp);
! 1242: else
! 1243: vput(nd.ni_dvp);
! 1244: vrele(nd.ni_vp);
! 1245: return (EEXIST);
! 1246: }
! 1247: VATTR_NULL(&vattr);
! 1248: vattr.va_type = VFIFO;
! 1249: vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
! 1250: return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
! 1251: #endif /* FIFO */
! 1252: }
! 1253:
! 1254: /*
! 1255: * Make a hard file link.
! 1256: */
! 1257: /* ARGSUSED */
! 1258: int
! 1259: sys_link(struct proc *p, void *v, register_t *retval)
! 1260: {
! 1261: struct sys_link_args /* {
! 1262: syscallarg(const char *) path;
! 1263: syscallarg(const char *) link;
! 1264: } */ *uap = v;
! 1265: struct vnode *vp;
! 1266: struct nameidata nd;
! 1267: int error;
! 1268: int flags;
! 1269:
! 1270: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1271: if ((error = namei(&nd)) != 0)
! 1272: return (error);
! 1273: vp = nd.ni_vp;
! 1274:
! 1275: flags = LOCKPARENT;
! 1276: if (vp->v_type == VDIR) {
! 1277: flags |= STRIPSLASHES;
! 1278: }
! 1279:
! 1280: NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p);
! 1281: if ((error = namei(&nd)) != 0)
! 1282: goto out;
! 1283: if (nd.ni_vp) {
! 1284: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1285: if (nd.ni_dvp == nd.ni_vp)
! 1286: vrele(nd.ni_dvp);
! 1287: else
! 1288: vput(nd.ni_dvp);
! 1289: vrele(nd.ni_vp);
! 1290: error = EEXIST;
! 1291: goto out;
! 1292: }
! 1293: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
! 1294: out:
! 1295: vrele(vp);
! 1296: return (error);
! 1297: }
! 1298:
! 1299: /*
! 1300: * Make a symbolic link.
! 1301: */
! 1302: /* ARGSUSED */
! 1303: int
! 1304: sys_symlink(struct proc *p, void *v, register_t *retval)
! 1305: {
! 1306: struct sys_symlink_args /* {
! 1307: syscallarg(const char *) path;
! 1308: syscallarg(const char *) link;
! 1309: } */ *uap = v;
! 1310: struct vattr vattr;
! 1311: char *path;
! 1312: int error;
! 1313: struct nameidata nd;
! 1314:
! 1315: path = pool_get(&namei_pool, PR_WAITOK);
! 1316: error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
! 1317: if (error)
! 1318: goto out;
! 1319: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
! 1320: if ((error = namei(&nd)) != 0)
! 1321: goto out;
! 1322: if (nd.ni_vp) {
! 1323: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1324: if (nd.ni_dvp == nd.ni_vp)
! 1325: vrele(nd.ni_dvp);
! 1326: else
! 1327: vput(nd.ni_dvp);
! 1328: vrele(nd.ni_vp);
! 1329: error = EEXIST;
! 1330: goto out;
! 1331: }
! 1332: VATTR_NULL(&vattr);
! 1333: vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
! 1334: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
! 1335: out:
! 1336: pool_put(&namei_pool, path);
! 1337: return (error);
! 1338: }
! 1339:
! 1340: /*
! 1341: * Delete a name from the filesystem.
! 1342: */
! 1343: /* ARGSUSED */
! 1344: int
! 1345: sys_unlink(struct proc *p, void *v, register_t *retval)
! 1346: {
! 1347: struct sys_unlink_args /* {
! 1348: syscallarg(const char *) path;
! 1349: } */ *uap = v;
! 1350: struct vnode *vp;
! 1351: int error;
! 1352: struct nameidata nd;
! 1353:
! 1354: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
! 1355: SCARG(uap, path), p);
! 1356: if ((error = namei(&nd)) != 0)
! 1357: return (error);
! 1358: vp = nd.ni_vp;
! 1359:
! 1360: /*
! 1361: * The root of a mounted filesystem cannot be deleted.
! 1362: */
! 1363: if (vp->v_flag & VROOT) {
! 1364: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 1365: if (nd.ni_dvp == vp)
! 1366: vrele(nd.ni_dvp);
! 1367: else
! 1368: vput(nd.ni_dvp);
! 1369: vput(vp);
! 1370: error = EBUSY;
! 1371: goto out;
! 1372: }
! 1373:
! 1374: (void)uvm_vnp_uncache(vp);
! 1375:
! 1376: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
! 1377: out:
! 1378: return (error);
! 1379: }
! 1380:
! 1381: /*
! 1382: * Reposition read/write file offset.
! 1383: */
! 1384: int
! 1385: sys_lseek(struct proc *p, void *v, register_t *retval)
! 1386: {
! 1387: struct sys_lseek_args /* {
! 1388: syscallarg(int) fd;
! 1389: syscallarg(int) pad;
! 1390: syscallarg(off_t) offset;
! 1391: syscallarg(int) whence;
! 1392: } */ *uap = v;
! 1393: struct ucred *cred = p->p_ucred;
! 1394: struct filedesc *fdp = p->p_fd;
! 1395: struct file *fp;
! 1396: struct vattr vattr;
! 1397: struct vnode *vp;
! 1398: off_t offarg, newoff;
! 1399: int error, special;
! 1400:
! 1401: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
! 1402: return (EBADF);
! 1403: if (fp->f_type != DTYPE_VNODE)
! 1404: return (ESPIPE);
! 1405: vp = (struct vnode *)fp->f_data;
! 1406: if (vp->v_type == VFIFO)
! 1407: return (ESPIPE);
! 1408: if (vp->v_type == VCHR)
! 1409: special = 1;
! 1410: else
! 1411: special = 0;
! 1412: offarg = SCARG(uap, offset);
! 1413:
! 1414: switch (SCARG(uap, whence)) {
! 1415: case SEEK_CUR:
! 1416: newoff = fp->f_offset + offarg;;
! 1417: break;
! 1418: case SEEK_END:
! 1419: error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr,
! 1420: cred, p);
! 1421: if (error)
! 1422: return (error);
! 1423: newoff = offarg + (off_t)vattr.va_size;
! 1424: break;
! 1425: case SEEK_SET:
! 1426: newoff = offarg;
! 1427: break;
! 1428: default:
! 1429: return (EINVAL);
! 1430: }
! 1431: if (!special) {
! 1432: if (newoff < 0)
! 1433: return (EINVAL);
! 1434: } else {
! 1435: /*
! 1436: * Make sure the user don't seek beyond the end of the
! 1437: * partition.
! 1438: */
! 1439: struct partinfo dpart;
! 1440: error = vn_ioctl(fp, DIOCGPART, (void *)&dpart, p);
! 1441: if (!error) {
! 1442: if (newoff >= DL_GETPSIZE(dpart.part) *
! 1443: dpart.disklab->d_secsize)
! 1444: return (EINVAL);
! 1445: }
! 1446: }
! 1447: *(off_t *)retval = fp->f_offset = newoff;
! 1448: fp->f_seek++;
! 1449: return (0);
! 1450: }
! 1451:
! 1452: /*
! 1453: * Check access permissions.
! 1454: */
! 1455: int
! 1456: sys_access(struct proc *p, void *v, register_t *retval)
! 1457: {
! 1458: struct sys_access_args /* {
! 1459: syscallarg(const char *) path;
! 1460: syscallarg(int) flags;
! 1461: } */ *uap = v;
! 1462: struct ucred *cred = p->p_ucred;
! 1463: struct vnode *vp;
! 1464: int error, flags, t_gid, t_uid;
! 1465: struct nameidata nd;
! 1466:
! 1467: if (SCARG(uap, flags) & ~(R_OK | W_OK | X_OK))
! 1468: return (EINVAL);
! 1469: t_uid = cred->cr_uid;
! 1470: t_gid = cred->cr_gid;
! 1471: cred->cr_uid = p->p_cred->p_ruid;
! 1472: cred->cr_gid = p->p_cred->p_rgid;
! 1473: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 1474: SCARG(uap, path), p);
! 1475: if ((error = namei(&nd)) != 0)
! 1476: goto out1;
! 1477: vp = nd.ni_vp;
! 1478:
! 1479: /* Flags == 0 means only check for existence. */
! 1480: if (SCARG(uap, flags)) {
! 1481: flags = 0;
! 1482: if (SCARG(uap, flags) & R_OK)
! 1483: flags |= VREAD;
! 1484: if (SCARG(uap, flags) & W_OK)
! 1485: flags |= VWRITE;
! 1486: if (SCARG(uap, flags) & X_OK)
! 1487: flags |= VEXEC;
! 1488: if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
! 1489: error = VOP_ACCESS(vp, flags, cred, p);
! 1490: }
! 1491: vput(vp);
! 1492: out1:
! 1493: cred->cr_uid = t_uid;
! 1494: cred->cr_gid = t_gid;
! 1495: return (error);
! 1496: }
! 1497:
! 1498: /*
! 1499: * Get file status; this version follows links.
! 1500: */
! 1501: /* ARGSUSED */
! 1502: int
! 1503: sys_stat(struct proc *p, void *v, register_t *retval)
! 1504: {
! 1505: struct sys_stat_args /* {
! 1506: syscallarg(const char *) path;
! 1507: syscallarg(struct stat *) ub;
! 1508: } */ *uap = v;
! 1509: struct stat sb;
! 1510: int error;
! 1511: struct nameidata nd;
! 1512:
! 1513: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 1514: SCARG(uap, path), p);
! 1515: if ((error = namei(&nd)) != 0)
! 1516: return (error);
! 1517: error = vn_stat(nd.ni_vp, &sb, p);
! 1518: vput(nd.ni_vp);
! 1519: if (error)
! 1520: return (error);
! 1521: /* Don't let non-root see generation numbers (for NFS security) */
! 1522: if (suser(p, 0))
! 1523: sb.st_gen = 0;
! 1524: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
! 1525: return (error);
! 1526: }
! 1527:
! 1528: /*
! 1529: * Get file status; this version does not follow links.
! 1530: */
! 1531: /* ARGSUSED */
! 1532: int
! 1533: sys_lstat(struct proc *p, void *v, register_t *retval)
! 1534: {
! 1535: struct sys_lstat_args /* {
! 1536: syscallarg(const char *) path;
! 1537: syscallarg(struct stat *) ub;
! 1538: } */ *uap = v;
! 1539: struct stat sb;
! 1540: int error;
! 1541: struct nameidata nd;
! 1542:
! 1543: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
! 1544: SCARG(uap, path), p);
! 1545: if ((error = namei(&nd)) != 0)
! 1546: return (error);
! 1547: error = vn_stat(nd.ni_vp, &sb, p);
! 1548: vput(nd.ni_vp);
! 1549: if (error)
! 1550: return (error);
! 1551: /* Don't let non-root see generation numbers (for NFS security) */
! 1552: if (suser(p, 0))
! 1553: sb.st_gen = 0;
! 1554: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
! 1555: return (error);
! 1556: }
! 1557:
! 1558: /*
! 1559: * Get configurable pathname variables.
! 1560: */
! 1561: /* ARGSUSED */
! 1562: int
! 1563: sys_pathconf(struct proc *p, void *v, register_t *retval)
! 1564: {
! 1565: struct sys_pathconf_args /* {
! 1566: syscallarg(const char *) path;
! 1567: syscallarg(int) name;
! 1568: } */ *uap = v;
! 1569: int error;
! 1570: struct nameidata nd;
! 1571:
! 1572: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
! 1573: SCARG(uap, path), p);
! 1574: if ((error = namei(&nd)) != 0)
! 1575: return (error);
! 1576: error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
! 1577: vput(nd.ni_vp);
! 1578: return (error);
! 1579: }
! 1580:
! 1581: /*
! 1582: * Return target name of a symbolic link.
! 1583: */
! 1584: /* ARGSUSED */
! 1585: int
! 1586: sys_readlink(struct proc *p, void *v, register_t *retval)
! 1587: {
! 1588: struct sys_readlink_args /* {
! 1589: syscallarg(const char *) path;
! 1590: syscallarg(char *) buf;
! 1591: syscallarg(size_t) count;
! 1592: } */ *uap = v;
! 1593: struct vnode *vp;
! 1594: struct iovec aiov;
! 1595: struct uio auio;
! 1596: int error;
! 1597: struct nameidata nd;
! 1598:
! 1599: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
! 1600: SCARG(uap, path), p);
! 1601: if ((error = namei(&nd)) != 0)
! 1602: return (error);
! 1603: vp = nd.ni_vp;
! 1604: if (vp->v_type != VLNK)
! 1605: error = EINVAL;
! 1606: else {
! 1607: aiov.iov_base = SCARG(uap, buf);
! 1608: aiov.iov_len = SCARG(uap, count);
! 1609: auio.uio_iov = &aiov;
! 1610: auio.uio_iovcnt = 1;
! 1611: auio.uio_offset = 0;
! 1612: auio.uio_rw = UIO_READ;
! 1613: auio.uio_segflg = UIO_USERSPACE;
! 1614: auio.uio_procp = p;
! 1615: auio.uio_resid = SCARG(uap, count);
! 1616: error = VOP_READLINK(vp, &auio, p->p_ucred);
! 1617: }
! 1618: vput(vp);
! 1619: *retval = SCARG(uap, count) - auio.uio_resid;
! 1620: return (error);
! 1621: }
! 1622:
! 1623: /*
! 1624: * Change flags of a file given a path name.
! 1625: */
! 1626: /* ARGSUSED */
! 1627: int
! 1628: sys_chflags(struct proc *p, void *v, register_t *retval)
! 1629: {
! 1630: struct sys_chflags_args /* {
! 1631: syscallarg(const char *) path;
! 1632: syscallarg(u_int) flags;
! 1633: } */ *uap = v;
! 1634: struct vnode *vp;
! 1635: struct vattr vattr;
! 1636: int error;
! 1637: struct nameidata nd;
! 1638:
! 1639: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1640: if ((error = namei(&nd)) != 0)
! 1641: return (error);
! 1642: vp = nd.ni_vp;
! 1643: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1644: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1645: error = EROFS;
! 1646: else if (SCARG(uap, flags) == VNOVAL)
! 1647: error = EINVAL;
! 1648: else {
! 1649: if (suser(p, 0)) {
! 1650: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
! 1651: goto out;
! 1652: if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
! 1653: error = EINVAL;
! 1654: goto out;
! 1655: }
! 1656: }
! 1657: VATTR_NULL(&vattr);
! 1658: vattr.va_flags = SCARG(uap, flags);
! 1659: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1660: }
! 1661: out:
! 1662: vput(vp);
! 1663: return (error);
! 1664: }
! 1665:
! 1666: /*
! 1667: * Change flags of a file given a file descriptor.
! 1668: */
! 1669: /* ARGSUSED */
! 1670: int
! 1671: sys_fchflags(struct proc *p, void *v, register_t *retval)
! 1672: {
! 1673: struct sys_fchflags_args /* {
! 1674: syscallarg(int) fd;
! 1675: syscallarg(u_int) flags;
! 1676: } */ *uap = v;
! 1677: struct vattr vattr;
! 1678: struct vnode *vp;
! 1679: struct file *fp;
! 1680: int error;
! 1681:
! 1682: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 1683: return (error);
! 1684: vp = (struct vnode *)fp->f_data;
! 1685: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1686: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
! 1687: error = EROFS;
! 1688: else if (SCARG(uap, flags) == VNOVAL)
! 1689: error = EINVAL;
! 1690: else {
! 1691: if (suser(p, 0)) {
! 1692: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
! 1693: != 0)
! 1694: goto out;
! 1695: if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
! 1696: error = EINVAL;
! 1697: goto out;
! 1698: }
! 1699: }
! 1700: VATTR_NULL(&vattr);
! 1701: vattr.va_flags = SCARG(uap, flags);
! 1702: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1703: }
! 1704: out:
! 1705: VOP_UNLOCK(vp, 0, p);
! 1706: FRELE(fp);
! 1707: return (error);
! 1708: }
! 1709:
! 1710: /*
! 1711: * Change mode of a file given path name.
! 1712: */
! 1713: /* ARGSUSED */
! 1714: int
! 1715: sys_chmod(struct proc *p, void *v, register_t *retval)
! 1716: {
! 1717: struct sys_chmod_args /* {
! 1718: syscallarg(const char *) path;
! 1719: syscallarg(mode_t) mode;
! 1720: } */ *uap = v;
! 1721: struct vnode *vp;
! 1722: struct vattr vattr;
! 1723: int error;
! 1724: struct nameidata nd;
! 1725:
! 1726: if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
! 1727: return (EINVAL);
! 1728:
! 1729: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1730: if ((error = namei(&nd)) != 0)
! 1731: return (error);
! 1732: vp = nd.ni_vp;
! 1733: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1734: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1735: error = EROFS;
! 1736: else {
! 1737: VATTR_NULL(&vattr);
! 1738: vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
! 1739: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1740: }
! 1741: vput(vp);
! 1742: return (error);
! 1743: }
! 1744:
! 1745: /*
! 1746: * Change mode of a file given a file descriptor.
! 1747: */
! 1748: /* ARGSUSED */
! 1749: int
! 1750: sys_fchmod(struct proc *p, void *v, register_t *retval)
! 1751: {
! 1752: struct sys_fchmod_args /* {
! 1753: syscallarg(int) fd;
! 1754: syscallarg(mode_t) mode;
! 1755: } */ *uap = v;
! 1756: struct vattr vattr;
! 1757: struct vnode *vp;
! 1758: struct file *fp;
! 1759: int error;
! 1760:
! 1761: if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
! 1762: return (EINVAL);
! 1763:
! 1764: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 1765: return (error);
! 1766: vp = (struct vnode *)fp->f_data;
! 1767: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1768: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
! 1769: error = EROFS;
! 1770: else {
! 1771: VATTR_NULL(&vattr);
! 1772: vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
! 1773: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1774: }
! 1775: VOP_UNLOCK(vp, 0, p);
! 1776: FRELE(fp);
! 1777: return (error);
! 1778: }
! 1779:
! 1780: /*
! 1781: * Set ownership given a path name.
! 1782: */
! 1783: /* ARGSUSED */
! 1784: int
! 1785: sys_chown(struct proc *p, void *v, register_t *retval)
! 1786: {
! 1787: struct sys_chown_args /* {
! 1788: syscallarg(const char *) path;
! 1789: syscallarg(uid_t) uid;
! 1790: syscallarg(gid_t) gid;
! 1791: } */ *uap = v;
! 1792: struct vnode *vp;
! 1793: struct vattr vattr;
! 1794: int error;
! 1795: struct nameidata nd;
! 1796: mode_t mode;
! 1797:
! 1798: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1799: if ((error = namei(&nd)) != 0)
! 1800: return (error);
! 1801: vp = nd.ni_vp;
! 1802: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1803: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1804: error = EROFS;
! 1805: else {
! 1806: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
! 1807: (suser(p, 0) || suid_clear)) {
! 1808: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
! 1809: if (error)
! 1810: goto out;
! 1811: mode = vattr.va_mode & ~(VSUID | VSGID);
! 1812: if (mode == vattr.va_mode)
! 1813: mode = VNOVAL;
! 1814: }
! 1815: else
! 1816: mode = VNOVAL;
! 1817: VATTR_NULL(&vattr);
! 1818: vattr.va_uid = SCARG(uap, uid);
! 1819: vattr.va_gid = SCARG(uap, gid);
! 1820: vattr.va_mode = mode;
! 1821: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1822: }
! 1823: out:
! 1824: vput(vp);
! 1825: return (error);
! 1826: }
! 1827:
! 1828: /*
! 1829: * Set ownership given a path name, without following links.
! 1830: */
! 1831: /* ARGSUSED */
! 1832: int
! 1833: sys_lchown(struct proc *p, void *v, register_t *retval)
! 1834: {
! 1835: struct sys_lchown_args /* {
! 1836: syscallarg(const char *) path;
! 1837: syscallarg(uid_t) uid;
! 1838: syscallarg(gid_t) gid;
! 1839: } */ *uap = v;
! 1840: struct vnode *vp;
! 1841: struct vattr vattr;
! 1842: int error;
! 1843: struct nameidata nd;
! 1844: mode_t mode;
! 1845:
! 1846: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1847: if ((error = namei(&nd)) != 0)
! 1848: return (error);
! 1849: vp = nd.ni_vp;
! 1850: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1851: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1852: error = EROFS;
! 1853: else {
! 1854: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
! 1855: (suser(p, 0) || suid_clear)) {
! 1856: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
! 1857: if (error)
! 1858: goto out;
! 1859: mode = vattr.va_mode & ~(VSUID | VSGID);
! 1860: if (mode == vattr.va_mode)
! 1861: mode = VNOVAL;
! 1862: }
! 1863: else
! 1864: mode = VNOVAL;
! 1865: VATTR_NULL(&vattr);
! 1866: vattr.va_uid = SCARG(uap, uid);
! 1867: vattr.va_gid = SCARG(uap, gid);
! 1868: vattr.va_mode = mode;
! 1869: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1870: }
! 1871: out:
! 1872: vput(vp);
! 1873: return (error);
! 1874: }
! 1875:
! 1876: /*
! 1877: * Set ownership given a file descriptor.
! 1878: */
! 1879: /* ARGSUSED */
! 1880: int
! 1881: sys_fchown(struct proc *p, void *v, register_t *retval)
! 1882: {
! 1883: struct sys_fchown_args /* {
! 1884: syscallarg(int) fd;
! 1885: syscallarg(uid_t) uid;
! 1886: syscallarg(gid_t) gid;
! 1887: } */ *uap = v;
! 1888: struct vnode *vp;
! 1889: struct vattr vattr;
! 1890: int error;
! 1891: struct file *fp;
! 1892: mode_t mode;
! 1893:
! 1894: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 1895: return (error);
! 1896: vp = (struct vnode *)fp->f_data;
! 1897: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1898: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1899: error = EROFS;
! 1900: else {
! 1901: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
! 1902: (suser(p, 0) || suid_clear)) {
! 1903: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
! 1904: if (error)
! 1905: goto out;
! 1906: mode = vattr.va_mode & ~(VSUID | VSGID);
! 1907: if (mode == vattr.va_mode)
! 1908: mode = VNOVAL;
! 1909: } else
! 1910: mode = VNOVAL;
! 1911: VATTR_NULL(&vattr);
! 1912: vattr.va_uid = SCARG(uap, uid);
! 1913: vattr.va_gid = SCARG(uap, gid);
! 1914: vattr.va_mode = mode;
! 1915: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1916: }
! 1917: out:
! 1918: VOP_UNLOCK(vp, 0, p);
! 1919: FRELE(fp);
! 1920: return (error);
! 1921: }
! 1922:
! 1923: /*
! 1924: * Set the access and modification times given a path name.
! 1925: */
! 1926: /* ARGSUSED */
! 1927: int
! 1928: sys_utimes(struct proc *p, void *v, register_t *retval)
! 1929: {
! 1930: struct sys_utimes_args /* {
! 1931: syscallarg(const char *) path;
! 1932: syscallarg(const struct timeval *) tptr;
! 1933: } */ *uap = v;
! 1934: struct vnode *vp;
! 1935: struct timeval tv[2];
! 1936: struct vattr vattr;
! 1937: int error;
! 1938: struct nameidata nd;
! 1939:
! 1940: VATTR_NULL(&vattr);
! 1941: if (SCARG(uap, tptr) == NULL) {
! 1942: microtime(&tv[0]);
! 1943: tv[1] = tv[0];
! 1944: vattr.va_vaflags |= VA_UTIMES_NULL;
! 1945: } else {
! 1946: error = copyin(SCARG(uap, tptr), tv,
! 1947: sizeof(tv));
! 1948: if (error)
! 1949: return (error);
! 1950: /* XXX workaround timeval matching the VFS constant VNOVAL */
! 1951: if (tv[0].tv_sec == VNOVAL)
! 1952: tv[0].tv_sec = VNOVAL - 1;
! 1953: if (tv[1].tv_sec == VNOVAL)
! 1954: tv[1].tv_sec = VNOVAL - 1;
! 1955: }
! 1956: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 1957: if ((error = namei(&nd)) != 0)
! 1958: return (error);
! 1959: vp = nd.ni_vp;
! 1960: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 1961: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 1962: error = EROFS;
! 1963: else {
! 1964: vattr.va_atime.tv_sec = tv[0].tv_sec;
! 1965: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
! 1966: vattr.va_mtime.tv_sec = tv[1].tv_sec;
! 1967: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
! 1968: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 1969: }
! 1970: vput(vp);
! 1971: return (error);
! 1972: }
! 1973:
! 1974: /*
! 1975: * Set the access and modification times given a file descriptor.
! 1976: */
! 1977: /* ARGSUSED */
! 1978: int
! 1979: sys_futimes(struct proc *p, void *v, register_t *retval)
! 1980: {
! 1981: struct sys_futimes_args /* {
! 1982: syscallarg(int) fd;
! 1983: syscallarg(const struct timeval *) tptr;
! 1984: } */ *uap = v;
! 1985: struct vnode *vp;
! 1986: struct timeval tv[2];
! 1987: struct vattr vattr;
! 1988: int error;
! 1989: struct file *fp;
! 1990:
! 1991: VATTR_NULL(&vattr);
! 1992: if (SCARG(uap, tptr) == NULL) {
! 1993: microtime(&tv[0]);
! 1994: tv[1] = tv[0];
! 1995: vattr.va_vaflags |= VA_UTIMES_NULL;
! 1996: } else {
! 1997: error = copyin(SCARG(uap, tptr), tv,
! 1998: sizeof(tv));
! 1999: if (error)
! 2000: return (error);
! 2001: /* XXX workaround timeval matching the VFS constant VNOVAL */
! 2002: if (tv[0].tv_sec == VNOVAL)
! 2003: tv[0].tv_sec = VNOVAL - 1;
! 2004: if (tv[1].tv_sec == VNOVAL)
! 2005: tv[1].tv_sec = VNOVAL - 1;
! 2006: }
! 2007: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 2008: return (error);
! 2009: vp = (struct vnode *)fp->f_data;
! 2010: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 2011: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
! 2012: error = EROFS;
! 2013: else {
! 2014: vattr.va_atime.tv_sec = tv[0].tv_sec;
! 2015: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
! 2016: vattr.va_mtime.tv_sec = tv[1].tv_sec;
! 2017: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
! 2018: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 2019: }
! 2020: VOP_UNLOCK(vp, 0, p);
! 2021: FRELE(fp);
! 2022: return (error);
! 2023: }
! 2024:
! 2025: /*
! 2026: * Truncate a file given its path name.
! 2027: */
! 2028: /* ARGSUSED */
! 2029: int
! 2030: sys_truncate(struct proc *p, void *v, register_t *retval)
! 2031: {
! 2032: struct sys_truncate_args /* {
! 2033: syscallarg(const char *) path;
! 2034: syscallarg(int) pad;
! 2035: syscallarg(off_t) length;
! 2036: } */ *uap = v;
! 2037: struct vnode *vp;
! 2038: struct vattr vattr;
! 2039: int error;
! 2040: struct nameidata nd;
! 2041:
! 2042: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 2043: if ((error = namei(&nd)) != 0)
! 2044: return (error);
! 2045: vp = nd.ni_vp;
! 2046: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 2047: if (vp->v_type == VDIR)
! 2048: error = EISDIR;
! 2049: else if ((error = vn_writechk(vp)) == 0 &&
! 2050: (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
! 2051: VATTR_NULL(&vattr);
! 2052: vattr.va_size = SCARG(uap, length);
! 2053: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
! 2054: }
! 2055: vput(vp);
! 2056: return (error);
! 2057: }
! 2058:
! 2059: /*
! 2060: * Truncate a file given a file descriptor.
! 2061: */
! 2062: /* ARGSUSED */
! 2063: int
! 2064: sys_ftruncate(struct proc *p, void *v, register_t *retval)
! 2065: {
! 2066: struct sys_ftruncate_args /* {
! 2067: syscallarg(int) fd;
! 2068: syscallarg(int) pad;
! 2069: syscallarg(off_t) length;
! 2070: } */ *uap = v;
! 2071: struct vattr vattr;
! 2072: struct vnode *vp;
! 2073: struct file *fp;
! 2074: off_t len;
! 2075: int error;
! 2076:
! 2077: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 2078: return (error);
! 2079: len = SCARG(uap, length);
! 2080: if ((fp->f_flag & FWRITE) == 0 || len < 0) {
! 2081: error = EINVAL;
! 2082: goto bad;
! 2083: }
! 2084: vp = (struct vnode *)fp->f_data;
! 2085: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 2086: if (vp->v_type == VDIR)
! 2087: error = EISDIR;
! 2088: else if ((error = vn_writechk(vp)) == 0) {
! 2089: VATTR_NULL(&vattr);
! 2090: vattr.va_size = len;
! 2091: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
! 2092: }
! 2093: VOP_UNLOCK(vp, 0, p);
! 2094: bad:
! 2095: FRELE(fp);
! 2096: return (error);
! 2097: }
! 2098:
! 2099: /*
! 2100: * Sync an open file.
! 2101: */
! 2102: /* ARGSUSED */
! 2103: int
! 2104: sys_fsync(struct proc *p, void *v, register_t *retval)
! 2105: {
! 2106: struct sys_fsync_args /* {
! 2107: syscallarg(int) fd;
! 2108: } */ *uap = v;
! 2109: struct vnode *vp;
! 2110: struct file *fp;
! 2111: int error;
! 2112:
! 2113: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 2114: return (error);
! 2115: vp = (struct vnode *)fp->f_data;
! 2116: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 2117: error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
! 2118: #ifdef FFS_SOFTUPDATES
! 2119: if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
! 2120: error = softdep_fsync(vp);
! 2121: #endif
! 2122:
! 2123: VOP_UNLOCK(vp, 0, p);
! 2124: FRELE(fp);
! 2125: return (error);
! 2126: }
! 2127:
! 2128: /*
! 2129: * Rename files. Source and destination must either both be directories,
! 2130: * or both not be directories. If target is a directory, it must be empty.
! 2131: */
! 2132: /* ARGSUSED */
! 2133: int
! 2134: sys_rename(struct proc *p, void *v, register_t *retval)
! 2135: {
! 2136: struct sys_rename_args /* {
! 2137: syscallarg(const char *) from;
! 2138: syscallarg(const char *) to;
! 2139: } */ *uap = v;
! 2140: struct vnode *tvp, *fvp, *tdvp;
! 2141: struct nameidata fromnd, tond;
! 2142: int error;
! 2143: int flags;
! 2144:
! 2145: NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
! 2146: SCARG(uap, from), p);
! 2147: if ((error = namei(&fromnd)) != 0)
! 2148: return (error);
! 2149: fvp = fromnd.ni_vp;
! 2150:
! 2151: flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
! 2152: /*
! 2153: * rename("foo/", "bar/"); is OK
! 2154: */
! 2155: if (fvp->v_type == VDIR)
! 2156: flags |= STRIPSLASHES;
! 2157:
! 2158: NDINIT(&tond, RENAME, flags,
! 2159: UIO_USERSPACE, SCARG(uap, to), p);
! 2160: if ((error = namei(&tond)) != 0) {
! 2161: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
! 2162: vrele(fromnd.ni_dvp);
! 2163: vrele(fvp);
! 2164: goto out1;
! 2165: }
! 2166: tdvp = tond.ni_dvp;
! 2167: tvp = tond.ni_vp;
! 2168: if (tvp != NULL) {
! 2169: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
! 2170: error = ENOTDIR;
! 2171: goto out;
! 2172: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
! 2173: error = EISDIR;
! 2174: goto out;
! 2175: }
! 2176: }
! 2177: if (fvp == tdvp)
! 2178: error = EINVAL;
! 2179: /*
! 2180: * If source is the same as the destination (that is the
! 2181: * same inode number)
! 2182: */
! 2183: if (fvp == tvp)
! 2184: error = -1;
! 2185: out:
! 2186: if (!error) {
! 2187: if (tvp) {
! 2188: (void)uvm_vnp_uncache(tvp);
! 2189: }
! 2190: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
! 2191: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
! 2192: } else {
! 2193: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
! 2194: if (tdvp == tvp)
! 2195: vrele(tdvp);
! 2196: else
! 2197: vput(tdvp);
! 2198: if (tvp)
! 2199: vput(tvp);
! 2200: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
! 2201: vrele(fromnd.ni_dvp);
! 2202: vrele(fvp);
! 2203: }
! 2204: vrele(tond.ni_startdir);
! 2205: pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
! 2206: out1:
! 2207: if (fromnd.ni_startdir)
! 2208: vrele(fromnd.ni_startdir);
! 2209: pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
! 2210: if (error == -1)
! 2211: return (0);
! 2212: return (error);
! 2213: }
! 2214:
! 2215: /*
! 2216: * Make a directory file.
! 2217: */
! 2218: /* ARGSUSED */
! 2219: int
! 2220: sys_mkdir(struct proc *p, void *v, register_t *retval)
! 2221: {
! 2222: struct sys_mkdir_args /* {
! 2223: syscallarg(const char *) path;
! 2224: syscallarg(mode_t) mode;
! 2225: } */ *uap = v;
! 2226: struct vnode *vp;
! 2227: struct vattr vattr;
! 2228: int error;
! 2229: struct nameidata nd;
! 2230:
! 2231: NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES,
! 2232: UIO_USERSPACE, SCARG(uap, path), p);
! 2233: if ((error = namei(&nd)) != 0)
! 2234: return (error);
! 2235: vp = nd.ni_vp;
! 2236: if (vp != NULL) {
! 2237: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2238: if (nd.ni_dvp == vp)
! 2239: vrele(nd.ni_dvp);
! 2240: else
! 2241: vput(nd.ni_dvp);
! 2242: vrele(vp);
! 2243: return (EEXIST);
! 2244: }
! 2245: VATTR_NULL(&vattr);
! 2246: vattr.va_type = VDIR;
! 2247: vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
! 2248: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
! 2249: if (!error)
! 2250: vput(nd.ni_vp);
! 2251: return (error);
! 2252: }
! 2253:
! 2254: /*
! 2255: * Remove a directory file.
! 2256: */
! 2257: /* ARGSUSED */
! 2258: int
! 2259: sys_rmdir(struct proc *p, void *v, register_t *retval)
! 2260: {
! 2261: struct sys_rmdir_args /* {
! 2262: syscallarg(const char *) path;
! 2263: } */ *uap = v;
! 2264: struct vnode *vp;
! 2265: int error;
! 2266: struct nameidata nd;
! 2267:
! 2268: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
! 2269: SCARG(uap, path), p);
! 2270: if ((error = namei(&nd)) != 0)
! 2271: return (error);
! 2272: vp = nd.ni_vp;
! 2273: if (vp->v_type != VDIR) {
! 2274: error = ENOTDIR;
! 2275: goto out;
! 2276: }
! 2277: /*
! 2278: * No rmdir "." please.
! 2279: */
! 2280: if (nd.ni_dvp == vp) {
! 2281: error = EBUSY;
! 2282: goto out;
! 2283: }
! 2284: /*
! 2285: * The root of a mounted filesystem cannot be deleted.
! 2286: */
! 2287: if (vp->v_flag & VROOT)
! 2288: error = EBUSY;
! 2289: out:
! 2290: if (!error) {
! 2291: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
! 2292: } else {
! 2293: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
! 2294: if (nd.ni_dvp == vp)
! 2295: vrele(nd.ni_dvp);
! 2296: else
! 2297: vput(nd.ni_dvp);
! 2298: vput(vp);
! 2299: }
! 2300: return (error);
! 2301: }
! 2302:
! 2303: /*
! 2304: * Read a block of directory entries in a file system independent format.
! 2305: */
! 2306: int
! 2307: sys_getdirentries(struct proc *p, void *v, register_t *retval)
! 2308: {
! 2309: struct sys_getdirentries_args /* {
! 2310: syscallarg(int) fd;
! 2311: syscallarg(char *) buf;
! 2312: syscallarg(int) count;
! 2313: syscallarg(long *) basep;
! 2314: } */ *uap = v;
! 2315: struct vnode *vp;
! 2316: struct file *fp;
! 2317: struct uio auio;
! 2318: struct iovec aiov;
! 2319: long loff;
! 2320: int error, eofflag;
! 2321:
! 2322: if (SCARG(uap, count) < 0)
! 2323: return EINVAL;
! 2324: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 2325: return (error);
! 2326: if ((fp->f_flag & FREAD) == 0) {
! 2327: error = EBADF;
! 2328: goto bad;
! 2329: }
! 2330: vp = (struct vnode *)fp->f_data;
! 2331: if (vp->v_type != VDIR) {
! 2332: error = EINVAL;
! 2333: goto bad;
! 2334: }
! 2335: aiov.iov_base = SCARG(uap, buf);
! 2336: aiov.iov_len = SCARG(uap, count);
! 2337: auio.uio_iov = &aiov;
! 2338: auio.uio_iovcnt = 1;
! 2339: auio.uio_rw = UIO_READ;
! 2340: auio.uio_segflg = UIO_USERSPACE;
! 2341: auio.uio_procp = p;
! 2342: auio.uio_resid = SCARG(uap, count);
! 2343: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 2344: loff = auio.uio_offset = fp->f_offset;
! 2345: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0);
! 2346: fp->f_offset = auio.uio_offset;
! 2347: VOP_UNLOCK(vp, 0, p);
! 2348: if (error)
! 2349: goto bad;
! 2350: error = copyout(&loff, SCARG(uap, basep),
! 2351: sizeof(long));
! 2352: *retval = SCARG(uap, count) - auio.uio_resid;
! 2353: bad:
! 2354: FRELE(fp);
! 2355: return (error);
! 2356: }
! 2357:
! 2358: /*
! 2359: * Set the mode mask for creation of filesystem nodes.
! 2360: */
! 2361: int
! 2362: sys_umask(struct proc *p, void *v, register_t *retval)
! 2363: {
! 2364: struct sys_umask_args /* {
! 2365: syscallarg(mode_t) newmask;
! 2366: } */ *uap = v;
! 2367: struct filedesc *fdp;
! 2368:
! 2369: fdp = p->p_fd;
! 2370: *retval = fdp->fd_cmask;
! 2371: fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS;
! 2372: return (0);
! 2373: }
! 2374:
! 2375: /*
! 2376: * Void all references to file by ripping underlying filesystem
! 2377: * away from vnode.
! 2378: */
! 2379: /* ARGSUSED */
! 2380: int
! 2381: sys_revoke(struct proc *p, void *v, register_t *retval)
! 2382: {
! 2383: struct sys_revoke_args /* {
! 2384: syscallarg(const char *) path;
! 2385: } */ *uap = v;
! 2386: struct vnode *vp;
! 2387: struct vattr vattr;
! 2388: int error;
! 2389: struct nameidata nd;
! 2390:
! 2391: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
! 2392: if ((error = namei(&nd)) != 0)
! 2393: return (error);
! 2394: vp = nd.ni_vp;
! 2395: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
! 2396: goto out;
! 2397: if (p->p_ucred->cr_uid != vattr.va_uid &&
! 2398: (error = suser(p, 0)))
! 2399: goto out;
! 2400: if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED)))
! 2401: VOP_REVOKE(vp, REVOKEALL);
! 2402: out:
! 2403: vrele(vp);
! 2404: return (error);
! 2405: }
! 2406:
! 2407: /*
! 2408: * Convert a user file descriptor to a kernel file entry.
! 2409: *
! 2410: * On return *fpp is FREF:ed.
! 2411: */
! 2412: int
! 2413: getvnode(struct filedesc *fdp, int fd, struct file **fpp)
! 2414: {
! 2415: struct file *fp;
! 2416: struct vnode *vp;
! 2417:
! 2418: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 2419: return (EBADF);
! 2420:
! 2421: if (fp->f_type != DTYPE_VNODE)
! 2422: return (EINVAL);
! 2423:
! 2424: vp = (struct vnode *)fp->f_data;
! 2425: if (vp->v_type == VBAD)
! 2426: return (EBADF);
! 2427:
! 2428: FREF(fp);
! 2429: *fpp = fp;
! 2430:
! 2431: return (0);
! 2432: }
! 2433:
! 2434: /*
! 2435: * Positional read system call.
! 2436: */
! 2437: int
! 2438: sys_pread(struct proc *p, void *v, register_t *retval)
! 2439: {
! 2440: struct sys_pread_args /* {
! 2441: syscallarg(int) fd;
! 2442: syscallarg(void *) buf;
! 2443: syscallarg(size_t) nbyte;
! 2444: syscallarg(int) pad;
! 2445: syscallarg(off_t) offset;
! 2446: } */ *uap = v;
! 2447: struct filedesc *fdp = p->p_fd;
! 2448: struct file *fp;
! 2449: struct vnode *vp;
! 2450: off_t offset;
! 2451: int fd = SCARG(uap, fd);
! 2452:
! 2453: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 2454: return (EBADF);
! 2455: if ((fp->f_flag & FREAD) == 0)
! 2456: return (EBADF);
! 2457:
! 2458: vp = (struct vnode *)fp->f_data;
! 2459: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
! 2460: return (ESPIPE);
! 2461: }
! 2462:
! 2463: offset = SCARG(uap, offset);
! 2464:
! 2465: FREF(fp);
! 2466:
! 2467: /* dofileread() will FRELE the descriptor for us */
! 2468: return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
! 2469: &offset, retval));
! 2470: }
! 2471:
! 2472: /*
! 2473: * Positional scatter read system call.
! 2474: */
! 2475: int
! 2476: sys_preadv(struct proc *p, void *v, register_t *retval)
! 2477: {
! 2478: struct sys_preadv_args /* {
! 2479: syscallarg(int) fd;
! 2480: syscallarg(const struct iovec *) iovp;
! 2481: syscallarg(int) iovcnt;
! 2482: syscallarg(int) pad;
! 2483: syscallarg(off_t) offset;
! 2484: } */ *uap = v;
! 2485: struct filedesc *fdp = p->p_fd;
! 2486: struct file *fp;
! 2487: struct vnode *vp;
! 2488: off_t offset;
! 2489: int fd = SCARG(uap, fd);
! 2490:
! 2491: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 2492: return (EBADF);
! 2493: if ((fp->f_flag & FREAD) == 0)
! 2494: return (EBADF);
! 2495:
! 2496: vp = (struct vnode *)fp->f_data;
! 2497: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
! 2498: return (ESPIPE);
! 2499: }
! 2500:
! 2501: FREF(fp);
! 2502:
! 2503: offset = SCARG(uap, offset);
! 2504:
! 2505: /* dofilereadv() will FRELE the descriptor for us */
! 2506: return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
! 2507: &offset, retval));
! 2508: }
! 2509:
! 2510: /*
! 2511: * Positional write system call.
! 2512: */
! 2513: int
! 2514: sys_pwrite(struct proc *p, void *v, register_t *retval)
! 2515: {
! 2516: struct sys_pwrite_args /* {
! 2517: syscallarg(int) fd;
! 2518: syscallarg(const void *) buf;
! 2519: syscallarg(size_t) nbyte;
! 2520: syscallarg(int) pad;
! 2521: syscallarg(off_t) offset;
! 2522: } */ *uap = v;
! 2523: struct filedesc *fdp = p->p_fd;
! 2524: struct file *fp;
! 2525: struct vnode *vp;
! 2526: off_t offset;
! 2527: int fd = SCARG(uap, fd);
! 2528:
! 2529: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 2530: return (EBADF);
! 2531: if ((fp->f_flag & FWRITE) == 0)
! 2532: return (EBADF);
! 2533:
! 2534: vp = (struct vnode *)fp->f_data;
! 2535: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
! 2536: return (ESPIPE);
! 2537: }
! 2538:
! 2539: FREF(fp);
! 2540:
! 2541: offset = SCARG(uap, offset);
! 2542:
! 2543: /* dofilewrite() will FRELE the descriptor for us */
! 2544: return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
! 2545: &offset, retval));
! 2546: }
! 2547:
! 2548: /*
! 2549: * Positional gather write system call.
! 2550: */
! 2551: int
! 2552: sys_pwritev(struct proc *p, void *v, register_t *retval)
! 2553: {
! 2554: struct sys_pwritev_args /* {
! 2555: syscallarg(int) fd;
! 2556: syscallarg(const struct iovec *) iovp;
! 2557: syscallarg(int) iovcnt;
! 2558: syscallarg(int) pad;
! 2559: syscallarg(off_t) offset;
! 2560: } */ *uap = v;
! 2561: struct filedesc *fdp = p->p_fd;
! 2562: struct file *fp;
! 2563: struct vnode *vp;
! 2564: off_t offset;
! 2565: int fd = SCARG(uap, fd);
! 2566:
! 2567: if ((fp = fd_getfile(fdp, fd)) == NULL)
! 2568: return (EBADF);
! 2569: if ((fp->f_flag & FWRITE) == 0)
! 2570: return (EBADF);
! 2571:
! 2572: vp = (struct vnode *)fp->f_data;
! 2573: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
! 2574: return (ESPIPE);
! 2575: }
! 2576:
! 2577: FREF(fp);
! 2578:
! 2579: offset = SCARG(uap, offset);
! 2580:
! 2581: /* dofilewritev() will FRELE the descriptor for us */
! 2582: return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
! 2583: &offset, retval));
! 2584: }
CVSweb