|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1989, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * (c) UNIX System Laboratories, Inc. ! 30: * All or some portions of this file are derived from material licensed ! 31: * to the University of California by American Telephone and Telegraph ! 32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 33: * the permission of UNIX System Laboratories, Inc. ! 34: * ! 35: * Redistribution and use in source and binary forms, with or without ! 36: * modification, are permitted provided that the following conditions ! 37: * are met: ! 38: * 1. Redistributions of source code must retain the above copyright ! 39: * notice, this list of conditions and the following disclaimer. ! 40: * 2. Redistributions in binary form must reproduce the above copyright ! 41: * notice, this list of conditions and the following disclaimer in the ! 42: * documentation and/or other materials provided with the distribution. ! 43: * 3. All advertising materials mentioning features or use of this software ! 44: * must display the following acknowledgement: ! 45: * This product includes software developed by the University of ! 46: * California, Berkeley and its contributors. ! 47: * 4. Neither the name of the University nor the names of its contributors ! 48: * may be used to endorse or promote products derived from this software ! 49: * without specific prior written permission. ! 50: * ! 51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 61: * SUCH DAMAGE. ! 62: * ! 63: * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95 ! 64: */ ! 65: ! 66: #include <mach_nbc.h> ! 67: #include <sys/param.h> ! 68: #include <sys/systm.h> ! 69: #include <sys/namei.h> ! 70: #include <sys/filedesc.h> ! 71: #include <sys/kernel.h> ! 72: #include <sys/file.h> ! 73: #include <sys/stat.h> ! 74: #include <sys/vnode.h> ! 75: #include <sys/mount.h> ! 76: #include <sys/proc.h> ! 77: #include <sys/uio.h> ! 78: #include <sys/malloc.h> ! 79: #include <sys/dirent.h> ! 80: #include <sys/attr.h> ! 81: #include <sys/sysctl.h> ! 82: ! 83: struct lock__bsd__ exchangelock; ! 84: ! 85: static int change_dir __P((struct nameidata *ndp, struct proc *p)); ! 86: static void checkdirs __P((struct vnode *olddp)); ! 87: ! 88: #ifdef NeXT ! 89: unsigned int vfs_nummntops=0; /* counts number of mount and unmount operations */ ! 90: #endif ! 91: ! 92: /* ! 93: * Virtual File System System Calls ! 94: */ ! 95: ! 96: /* ! 97: * Mount a file system. ! 98: */ ! 99: struct mount_args { ! 100: char *type; ! 101: char *path; ! 102: int flags; ! 103: caddr_t data; ! 104: }; ! 105: /* ARGSUSED */ ! 106: int ! 107: mount(p, uap, retval) ! 108: struct proc *p; ! 109: register struct mount_args *uap; ! 110: register_t *retval; ! 111: { ! 112: struct vnode *vp; ! 113: struct mount *mp; ! 114: struct vfsconf *vfsp; ! 115: int error, flag; ! 116: struct vattr va; ! 117: u_long fstypenum; ! 118: struct nameidata nd; ! 119: char fstypename[MFSNAMELEN]; ! 120: ! 121: /* ! 122: * Get vnode to be covered ! 123: */ ! 124: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 125: uap->path, p); ! 126: if (error = namei(&nd)) ! 127: return (error); ! 128: vp = nd.ni_vp; ! 129: if (uap->flags & MNT_UPDATE) { ! 130: if ((vp->v_flag & VROOT) == 0) { ! 131: vput(vp); ! 132: return (EINVAL); ! 133: } ! 134: mp = vp->v_mount; ! 135: flag = mp->mnt_flag; ! 136: /* ! 137: * We only allow the filesystem to be reloaded if it ! 138: * is currently mounted read-only. ! 139: */ ! 140: if ((uap->flags & MNT_RELOAD) && ! 141: ((mp->mnt_flag & MNT_RDONLY) == 0)) { ! 142: vput(vp); ! 143: return (EOPNOTSUPP); /* Needs translation */ ! 144: } ! 145: mp->mnt_flag |= ! 146: uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); ! 147: /* ! 148: * Only root, or the user that did the original mount is ! 149: * permitted to update it. ! 150: */ ! 151: if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && ! 152: (error = suser(p->p_ucred, &p->p_acflag))) { ! 153: vput(vp); ! 154: return (error); ! 155: } ! 156: /* ! 157: * Do not allow NFS export by non-root users. Silently ! 158: * enforce MNT_NOSUID and MNT_NODEV for non-root users. ! 159: */ ! 160: if (p->p_ucred->cr_uid != 0) { ! 161: if (uap->flags & MNT_EXPORTED) { ! 162: vput(vp); ! 163: return (EPERM); ! 164: } ! 165: uap->flags |= MNT_NOSUID | MNT_NODEV; ! 166: } ! 167: if (vfs_busy(mp, LK_NOWAIT, 0, p)) { ! 168: vput(vp); ! 169: return (EBUSY); ! 170: } ! 171: VOP_UNLOCK(vp, 0, p); ! 172: goto update; ! 173: } ! 174: /* ! 175: * If the user is not root, ensure that they own the directory ! 176: * onto which we are attempting to mount. ! 177: */ ! 178: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || ! 179: (va.va_uid != p->p_ucred->cr_uid && ! 180: (error = suser(p->p_ucred, &p->p_acflag)))) { ! 181: vput(vp); ! 182: return (error); ! 183: } ! 184: /* ! 185: * Do not allow NFS export by non-root users. Silently ! 186: * enforce MNT_NOSUID and MNT_NODEV for non-root users. ! 187: */ ! 188: if (p->p_ucred->cr_uid != 0) { ! 189: if (uap->flags & MNT_EXPORTED) { ! 190: vput(vp); ! 191: return (EPERM); ! 192: } ! 193: uap->flags |= MNT_NOSUID | MNT_NODEV; ! 194: } ! 195: if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) { ! 196: vput(vp); ! 197: return (error); ! 198: } ! 199: if (vp->v_type != VDIR) { ! 200: vput(vp); ! 201: return (ENOTDIR); ! 202: } ! 203: #if COMPAT_43 ! 204: /* ! 205: * Historically filesystem types were identified by number. If we ! 206: * get an integer for the filesystem type instead of a string, we ! 207: * check to see if it matches one of the historic filesystem types. ! 208: */ ! 209: fstypenum = (u_long)uap->type; ! 210: if (fstypenum < maxvfsconf) { ! 211: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) ! 212: if (vfsp->vfc_typenum == fstypenum) ! 213: break; ! 214: if (vfsp == NULL) { ! 215: vput(vp); ! 216: return (ENODEV); ! 217: } ! 218: strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); ! 219: } else ! 220: #endif /* COMPAT_43 */ ! 221: if (error = copyinstr(uap->type, fstypename, MFSNAMELEN, NULL)) { ! 222: vput(vp); ! 223: return (error); ! 224: } ! 225: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) ! 226: if (!strcmp(vfsp->vfc_name, fstypename)) ! 227: break; ! 228: if (vfsp == NULL) { ! 229: vput(vp); ! 230: return (ENODEV); ! 231: } ! 232: if (vp->v_mountedhere != NULL) { ! 233: vput(vp); ! 234: return (EBUSY); ! 235: } ! 236: ! 237: /* ! 238: * Allocate and initialize the filesystem. ! 239: */ ! 240: mp = (struct mount *)_MALLOC_ZONE((u_long)sizeof(struct mount), ! 241: M_MOUNT, M_WAITOK); ! 242: bzero((char *)mp, (u_long)sizeof(struct mount)); ! 243: lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); ! 244: (void)vfs_busy(mp, LK_NOWAIT, 0, p); ! 245: mp->mnt_op = vfsp->vfc_vfsops; ! 246: mp->mnt_vfc = vfsp; ! 247: vfsp->vfc_refcount++; ! 248: mp->mnt_stat.f_type = vfsp->vfc_typenum; ! 249: mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; ! 250: strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); ! 251: vp->v_mountedhere = mp; ! 252: mp->mnt_vnodecovered = vp; ! 253: mp->mnt_stat.f_owner = p->p_ucred->cr_uid; ! 254: update: ! 255: /* ! 256: * Set the mount level flags. ! 257: */ ! 258: if (uap->flags & MNT_RDONLY) ! 259: mp->mnt_flag |= MNT_RDONLY; ! 260: else if (mp->mnt_flag & MNT_RDONLY) ! 261: mp->mnt_flag |= MNT_WANTRDWR; ! 262: mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | ! 263: MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); ! 264: mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | ! 265: MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); ! 266: /* ! 267: * Mount the filesystem. ! 268: */ ! 269: error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); ! 270: if (mp->mnt_flag & MNT_UPDATE) { ! 271: vrele(vp); ! 272: if (mp->mnt_flag & MNT_WANTRDWR) ! 273: mp->mnt_flag &= ~MNT_RDONLY; ! 274: mp->mnt_flag &=~ ! 275: (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); ! 276: if (error) ! 277: mp->mnt_flag = flag; ! 278: vfs_unbusy(mp, p); ! 279: return (error); ! 280: } ! 281: /* ! 282: * Put the new filesystem on the mount list after root. ! 283: */ ! 284: cache_purge(vp); ! 285: if (!error) { ! 286: simple_lock(&mountlist_slock); ! 287: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); ! 288: simple_unlock(&mountlist_slock); ! 289: checkdirs(vp); ! 290: VOP_UNLOCK(vp, 0, p); ! 291: vfs_unbusy(mp, p); ! 292: if (error = VFS_START(mp, 0, p)) ! 293: vrele(vp); ! 294: #ifdef NeXT ! 295: /* increment the operations count */ ! 296: if (!error) vfs_nummntops++; ! 297: #endif ! 298: } else { ! 299: mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; ! 300: mp->mnt_vfc->vfc_refcount--; ! 301: vfs_unbusy(mp, p); ! 302: _FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT); ! 303: vput(vp); ! 304: } ! 305: return (error); ! 306: } ! 307: ! 308: /* ! 309: * Scan all active processes to see if any of them have a current ! 310: * or root directory onto which the new filesystem has just been ! 311: * mounted. If so, replace them with the new mount point. ! 312: */ ! 313: static void ! 314: checkdirs(olddp) ! 315: struct vnode *olddp; ! 316: { ! 317: struct filedesc *fdp; ! 318: struct vnode *newdp; ! 319: struct proc *p; ! 320: ! 321: if (olddp->v_usecount == 1) ! 322: return; ! 323: if (VFS_ROOT(olddp->v_mountedhere, &newdp)) ! 324: panic("mount: lost mount"); ! 325: for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { ! 326: fdp = p->p_fd; ! 327: if (fdp->fd_cdir == olddp) { ! 328: vrele(fdp->fd_cdir); ! 329: VREF(newdp); ! 330: fdp->fd_cdir = newdp; ! 331: } ! 332: if (fdp->fd_rdir == olddp) { ! 333: vrele(fdp->fd_rdir); ! 334: VREF(newdp); ! 335: fdp->fd_rdir = newdp; ! 336: } ! 337: } ! 338: if (rootvnode == olddp) { ! 339: vrele(rootvnode); ! 340: VREF(newdp); ! 341: rootvnode = newdp; ! 342: } ! 343: vput(newdp); ! 344: } ! 345: ! 346: /* ! 347: * Unmount a file system. ! 348: * ! 349: * Note: unmount takes a path to the vnode mounted on as argument, ! 350: * not special file (as before). ! 351: */ ! 352: struct unmount_args { ! 353: char *path; ! 354: int flags; ! 355: }; ! 356: /* ARGSUSED */ ! 357: int ! 358: unmount(p, uap, retval) ! 359: struct proc *p; ! 360: register struct unmount_args *uap; ! 361: register_t *retval; ! 362: { ! 363: register struct vnode *vp; ! 364: struct mount *mp; ! 365: int error; ! 366: struct nameidata nd; ! 367: ! 368: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 369: uap->path, p); ! 370: if (error = namei(&nd)) ! 371: return (error); ! 372: vp = nd.ni_vp; ! 373: mp = vp->v_mount; ! 374: ! 375: /* ! 376: * Only root, or the user that did the original mount is ! 377: * permitted to unmount this filesystem. ! 378: */ ! 379: if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && ! 380: (error = suser(p->p_ucred, &p->p_acflag))) { ! 381: vput(vp); ! 382: return (error); ! 383: } ! 384: ! 385: /* ! 386: * Don't allow unmounting the root file system. ! 387: */ ! 388: if (mp->mnt_flag & MNT_ROOTFS) { ! 389: vput(vp); ! 390: return (EINVAL); ! 391: } ! 392: ! 393: /* ! 394: * Must be the root of the filesystem ! 395: */ ! 396: if ((vp->v_flag & VROOT) == 0) { ! 397: vput(vp); ! 398: return (EINVAL); ! 399: } ! 400: vput(vp); ! 401: return (dounmount(mp, uap->flags, p)); ! 402: } ! 403: ! 404: /* ! 405: * Do the actual file system unmount. ! 406: */ ! 407: int ! 408: dounmount(mp, flags, p) ! 409: register struct mount *mp; ! 410: int flags; ! 411: struct proc *p; ! 412: { ! 413: struct vnode *coveredvp; ! 414: int error; ! 415: ! 416: simple_lock(&mountlist_slock); ! 417: mp->mnt_flag |= MNT_UNMOUNT; ! 418: lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); ! 419: mp->mnt_flag &=~ MNT_ASYNC; ! 420: #if MACH_NBC ! 421: mapfs_cache_clear(); ! 422: #endif ! 423: vnode_pager_umount(mp); /* release cached vnodes */ ! 424: #if MACH_NBC ! 425: vm_object_cache_clear(); /* clear the object cache */ ! 426: #endif /* MACH_NBC */ ! 427: cache_purgevfs(mp); /* remove cache entries for this file sys */ ! 428: if (((mp->mnt_flag & MNT_RDONLY) || ! 429: (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || ! 430: (flags & MNT_FORCE)) ! 431: error = VFS_UNMOUNT(mp, flags, p); ! 432: simple_lock(&mountlist_slock); ! 433: if (error) { ! 434: mp->mnt_flag &= ~MNT_UNMOUNT; ! 435: lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, ! 436: &mountlist_slock, p); ! 437: goto out; ! 438: } ! 439: #ifdef NeXT ! 440: /* increment the operations count */ ! 441: if (!error) vfs_nummntops++; ! 442: #endif ! 443: CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); ! 444: if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { ! 445: coveredvp->v_mountedhere = (struct mount *)0; ! 446: simple_unlock(&mountlist_slock); ! 447: vrele(coveredvp); ! 448: simple_lock(&mountlist_slock); ! 449: } ! 450: mp->mnt_vfc->vfc_refcount--; ! 451: if (mp->mnt_vnodelist.lh_first != NULL) ! 452: panic("unmount: dangling vnode"); ! 453: lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); ! 454: out: ! 455: if (mp->mnt_flag & MNT_MWAIT) ! 456: wakeup((caddr_t)mp); ! 457: if (!error) ! 458: _FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT); ! 459: return (error); ! 460: } ! 461: ! 462: /* ! 463: * Sync each mounted filesystem. ! 464: */ ! 465: #if DIAGNOSTIC ! 466: int syncprt = 0; ! 467: struct ctldebug debug0 = { "syncprt", &syncprt }; ! 468: #endif ! 469: ! 470: struct sync_args { ! 471: int dummy; ! 472: }; ! 473: /* ARGSUSED */ ! 474: int ! 475: sync(p, uap, retval) ! 476: struct proc *p; ! 477: struct sync_args *uap; ! 478: register_t *retval; ! 479: { ! 480: register struct mount *mp, *nmp; ! 481: int asyncflag; ! 482: ! 483: #if MACH_NBC ! 484: #if DIAGNOSTIC ! 485: { ! 486: int error = 0; ! 487: error = mapfs_sync(); ! 488: if (error) ! 489: panic("sync: mapfs_sync %d", error); ! 490: } ! 491: #else ! 492: (void)mapfs_sync(); /* Ignore errors! */ ! 493: #endif /* DIAGNOSTIC */ ! 494: #endif /* MACH_NBC */ ! 495: ! 496: simple_lock(&mountlist_slock); ! 497: for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { ! 498: if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { ! 499: nmp = mp->mnt_list.cqe_next; ! 500: continue; ! 501: } ! 502: if ((mp->mnt_flag & MNT_RDONLY) == 0) { ! 503: asyncflag = mp->mnt_flag & MNT_ASYNC; ! 504: mp->mnt_flag &= ~MNT_ASYNC; ! 505: VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); ! 506: if (asyncflag) ! 507: mp->mnt_flag |= MNT_ASYNC; ! 508: } ! 509: simple_lock(&mountlist_slock); ! 510: nmp = mp->mnt_list.cqe_next; ! 511: vfs_unbusy(mp, p); ! 512: } ! 513: simple_unlock(&mountlist_slock); ! 514: #if DIAGNOSTIC ! 515: if (syncprt) ! 516: vfs_bufstats(); ! 517: #endif /* DIAGNOSTIC */ ! 518: return (0); ! 519: } ! 520: ! 521: /* ! 522: * Change filesystem quotas. ! 523: */ ! 524: struct quotactl_args { ! 525: char *path; ! 526: int cmd; ! 527: int uid; ! 528: caddr_t arg; ! 529: }; ! 530: /* ARGSUSED */ ! 531: int ! 532: quotactl(p, uap, retval) ! 533: struct proc *p; ! 534: register struct quotactl_args *uap; ! 535: register_t *retval; ! 536: { ! 537: register struct mount *mp; ! 538: int error; ! 539: struct nameidata nd; ! 540: ! 541: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 542: if (error = namei(&nd)) ! 543: return (error); ! 544: mp = nd.ni_vp->v_mount; ! 545: vrele(nd.ni_vp); ! 546: return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, ! 547: uap->arg, p)); ! 548: } ! 549: ! 550: /* ! 551: * Get filesystem statistics. ! 552: */ ! 553: struct statfs_args { ! 554: char *path; ! 555: struct statfs *buf; ! 556: }; ! 557: /* ARGSUSED */ ! 558: int ! 559: statfs(p, uap, retval) ! 560: struct proc *p; ! 561: register struct statfs_args *uap; ! 562: register_t *retval; ! 563: { ! 564: register struct mount *mp; ! 565: register struct statfs *sp; ! 566: int error; ! 567: struct nameidata nd; ! 568: ! 569: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 570: if (error = namei(&nd)) ! 571: return (error); ! 572: mp = nd.ni_vp->v_mount; ! 573: sp = &mp->mnt_stat; ! 574: vrele(nd.ni_vp); ! 575: if (error = VFS_STATFS(mp, sp, p)) ! 576: return (error); ! 577: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 578: return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); ! 579: } ! 580: ! 581: /* ! 582: * Get filesystem statistics. ! 583: */ ! 584: struct fstatfs_args { ! 585: int fd; ! 586: struct statfs *buf; ! 587: }; ! 588: /* ARGSUSED */ ! 589: int ! 590: fstatfs(p, uap, retval) ! 591: struct proc *p; ! 592: register struct fstatfs_args *uap; ! 593: register_t *retval; ! 594: { ! 595: struct file *fp; ! 596: struct mount *mp; ! 597: register struct statfs *sp; ! 598: int error; ! 599: ! 600: if (error = getvnode(p, uap->fd, &fp)) ! 601: return (error); ! 602: mp = ((struct vnode *)fp->f_data)->v_mount; ! 603: sp = &mp->mnt_stat; ! 604: if (error = VFS_STATFS(mp, sp, p)) ! 605: return (error); ! 606: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 607: return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); ! 608: } ! 609: ! 610: /* ! 611: * Get statistics on all filesystems. ! 612: */ ! 613: struct getfsstat_args { ! 614: struct statfs *buf; ! 615: long bufsize; ! 616: int flags; ! 617: }; ! 618: int ! 619: getfsstat(p, uap, retval) ! 620: struct proc *p; ! 621: register struct getfsstat_args *uap; ! 622: register_t *retval; ! 623: { ! 624: register struct mount *mp, *nmp; ! 625: register struct statfs *sp; ! 626: caddr_t sfsp; ! 627: long count, maxcount, error; ! 628: ! 629: maxcount = uap->bufsize / sizeof(struct statfs); ! 630: sfsp = (caddr_t)uap->buf; ! 631: count = 0; ! 632: simple_lock(&mountlist_slock); ! 633: for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { ! 634: if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { ! 635: nmp = mp->mnt_list.cqe_next; ! 636: continue; ! 637: } ! 638: if (sfsp && count < maxcount) { ! 639: sp = &mp->mnt_stat; ! 640: /* ! 641: * If MNT_NOWAIT is specified, do not refresh the ! 642: * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. ! 643: */ ! 644: if (((uap->flags & MNT_NOWAIT) == 0 || ! 645: (uap->flags & MNT_WAIT)) && ! 646: (error = VFS_STATFS(mp, sp, p))) { ! 647: simple_lock(&mountlist_slock); ! 648: nmp = mp->mnt_list.cqe_next; ! 649: vfs_unbusy(mp, p); ! 650: continue; ! 651: } ! 652: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 653: if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) ! 654: return (error); ! 655: sfsp += sizeof(*sp); ! 656: } ! 657: count++; ! 658: simple_lock(&mountlist_slock); ! 659: nmp = mp->mnt_list.cqe_next; ! 660: vfs_unbusy(mp, p); ! 661: } ! 662: simple_unlock(&mountlist_slock); ! 663: if (sfsp && count > maxcount) ! 664: *retval = maxcount; ! 665: else ! 666: *retval = count; ! 667: return (0); ! 668: } ! 669: ! 670: /* ! 671: * Change current working directory to a given file descriptor. ! 672: */ ! 673: struct fchdir_args { ! 674: int fd; ! 675: }; ! 676: /* ARGSUSED */ ! 677: int ! 678: fchdir(p, uap, retval) ! 679: struct proc *p; ! 680: struct fchdir_args *uap; ! 681: register_t *retval; ! 682: { ! 683: register struct filedesc *fdp = p->p_fd; ! 684: struct vnode *vp, *tdp; ! 685: struct mount *mp; ! 686: struct file *fp; ! 687: int error; ! 688: ! 689: if (error = getvnode(p, uap->fd, &fp)) ! 690: return (error); ! 691: vp = (struct vnode *)fp->f_data; ! 692: VREF(vp); ! 693: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 694: if (vp->v_type != VDIR) ! 695: error = ENOTDIR; ! 696: else ! 697: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); ! 698: while (!error && (mp = vp->v_mountedhere) != NULL) { ! 699: if (vfs_busy(mp, 0, 0, p)) ! 700: continue; ! 701: error = VFS_ROOT(mp, &tdp); ! 702: vfs_unbusy(mp, p); ! 703: if (error) ! 704: break; ! 705: vput(vp); ! 706: vp = tdp; ! 707: } ! 708: if (error) { ! 709: vput(vp); ! 710: return (error); ! 711: } ! 712: VOP_UNLOCK(vp, 0, p); ! 713: vrele(fdp->fd_cdir); ! 714: fdp->fd_cdir = vp; ! 715: return (0); ! 716: } ! 717: ! 718: /* ! 719: * Change current working directory (``.''). ! 720: */ ! 721: struct chdir_args { ! 722: char *path; ! 723: }; ! 724: /* ARGSUSED */ ! 725: int ! 726: chdir(p, uap, retval) ! 727: struct proc *p; ! 728: struct chdir_args *uap; ! 729: register_t *retval; ! 730: { ! 731: register struct filedesc *fdp = p->p_fd; ! 732: int error; ! 733: struct nameidata nd; ! 734: ! 735: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 736: uap->path, p); ! 737: if (error = change_dir(&nd, p)) ! 738: return (error); ! 739: vrele(fdp->fd_cdir); ! 740: fdp->fd_cdir = nd.ni_vp; ! 741: return (0); ! 742: } ! 743: ! 744: /* ! 745: * Change notion of root (``/'') directory. ! 746: */ ! 747: struct chroot_args { ! 748: char *path; ! 749: }; ! 750: /* ARGSUSED */ ! 751: int ! 752: chroot(p, uap, retval) ! 753: struct proc *p; ! 754: struct chroot_args *uap; ! 755: register_t *retval; ! 756: { ! 757: register struct filedesc *fdp = p->p_fd; ! 758: int error; ! 759: struct nameidata nd; ! 760: ! 761: if (error = suser(p->p_ucred, &p->p_acflag)) ! 762: return (error); ! 763: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 764: uap->path, p); ! 765: if (error = change_dir(&nd, p)) ! 766: return (error); ! 767: if (fdp->fd_rdir != NULL) ! 768: vrele(fdp->fd_rdir); ! 769: fdp->fd_rdir = nd.ni_vp; ! 770: return (0); ! 771: } ! 772: ! 773: /* ! 774: * Common routine for chroot and chdir. ! 775: */ ! 776: static int ! 777: change_dir(ndp, p) ! 778: register struct nameidata *ndp; ! 779: struct proc *p; ! 780: { ! 781: struct vnode *vp; ! 782: int error; ! 783: ! 784: if (error = namei(ndp)) ! 785: return (error); ! 786: vp = ndp->ni_vp; ! 787: if (vp->v_type != VDIR) ! 788: error = ENOTDIR; ! 789: else ! 790: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); ! 791: if (error) ! 792: vput(vp); ! 793: else ! 794: VOP_UNLOCK(vp, 0, p); ! 795: return (error); ! 796: } ! 797: ! 798: /* ! 799: * Check permissions, allocate an open file structure, ! 800: * and call the device open routine if any. ! 801: */ ! 802: struct open_args { ! 803: char *path; ! 804: int flags; ! 805: int mode; ! 806: }; ! 807: int ! 808: open(p, uap, retval) ! 809: struct proc *p; ! 810: register struct open_args *uap; ! 811: register_t *retval; ! 812: { ! 813: register struct filedesc *fdp = p->p_fd; ! 814: register struct file *fp; ! 815: register struct vnode *vp; ! 816: int flags, cmode; ! 817: struct file *nfp; ! 818: int type, indx, error; ! 819: struct flock lf; ! 820: struct nameidata nd; ! 821: extern struct fileops vnops; ! 822: ! 823: /* CERT advisory patch applied from FreeBSD */ ! 824: /* Refer to Radar#2262895 A. Ramesh */ ! 825: flags = FFLAGS(uap->flags); ! 826: if ((flags & (FREAD | FWRITE))==0) ! 827: return(EINVAL); ! 828: if (error = falloc(p, &nfp, &indx)) ! 829: return (error); ! 830: fp = nfp; ! 831: cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; ! 832: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 833: p->p_dupfd = -indx - 1; /* XXX check for fdopen */ ! 834: if (error = vn_open(&nd, flags, cmode)) { ! 835: ffree(fp); ! 836: if ((error == ENODEV || error == ENXIO) && ! 837: p->p_dupfd >= 0 && /* XXX from fdopen */ ! 838: (error = ! 839: dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { ! 840: *retval = indx; ! 841: return (0); ! 842: } ! 843: if (error == ERESTART) ! 844: error = EINTR; ! 845: fdrelse(p, indx); ! 846: return (error); ! 847: } ! 848: p->p_dupfd = 0; ! 849: vp = nd.ni_vp; ! 850: fp->f_flag = flags & FMASK; ! 851: fp->f_type = DTYPE_VNODE; ! 852: fp->f_ops = &vnops; ! 853: fp->f_data = (caddr_t)vp; ! 854: if (flags & (O_EXLOCK | O_SHLOCK)) { ! 855: lf.l_whence = SEEK_SET; ! 856: lf.l_start = 0; ! 857: lf.l_len = 0; ! 858: if (flags & O_EXLOCK) ! 859: lf.l_type = F_WRLCK; ! 860: else ! 861: lf.l_type = F_RDLCK; ! 862: type = F_FLOCK; ! 863: if ((flags & FNONBLOCK) == 0) ! 864: type |= F_WAIT; ! 865: VOP_UNLOCK(vp, 0, p); ! 866: if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { ! 867: (void) vn_close(vp, fp->f_flag, fp->f_cred, p); ! 868: ffree(fp); ! 869: fdrelse(p, indx); ! 870: return (error); ! 871: } ! 872: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 873: fp->f_flag |= FHASLOCK; ! 874: } ! 875: VOP_UNLOCK(vp, 0, p); ! 876: *fdflags(p, indx) &= ~UF_RESERVED; ! 877: *retval = indx; ! 878: return (0); ! 879: } ! 880: ! 881: #if COMPAT_43 ! 882: /* ! 883: * Create a file. ! 884: */ ! 885: struct ocreat_args { ! 886: char *path; ! 887: int mode; ! 888: }; ! 889: int ! 890: ocreat(p, uap, retval) ! 891: struct proc *p; ! 892: register struct ocreat_args *uap; ! 893: register_t *retval; ! 894: { ! 895: struct open_args nuap; ! 896: ! 897: nuap.path = uap->path; ! 898: nuap.mode = uap->mode; ! 899: nuap.flags = O_WRONLY | O_CREAT | O_TRUNC; ! 900: return (open(p, &nuap, retval)); ! 901: } ! 902: #endif /* COMPAT_43 */ ! 903: ! 904: /* ! 905: * Create a special file. ! 906: */ ! 907: struct mknod_args { ! 908: char *path; ! 909: int mode; ! 910: int dev; ! 911: }; ! 912: /* ARGSUSED */ ! 913: int ! 914: mknod(p, uap, retval) ! 915: struct proc *p; ! 916: register struct mknod_args *uap; ! 917: register_t *retval; ! 918: { ! 919: register struct vnode *vp; ! 920: struct vattr vattr; ! 921: int error; ! 922: int whiteout; ! 923: struct nameidata nd; ! 924: ! 925: if (error = suser(p->p_ucred, &p->p_acflag)) ! 926: return (error); ! 927: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); ! 928: if (error = namei(&nd)) ! 929: return (error); ! 930: vp = nd.ni_vp; ! 931: if (vp != NULL) ! 932: error = EEXIST; ! 933: else { ! 934: VATTR_NULL(&vattr); ! 935: vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; ! 936: vattr.va_rdev = uap->dev; ! 937: whiteout = 0; ! 938: ! 939: switch (uap->mode & S_IFMT) { ! 940: case S_IFMT: /* used by badsect to flag bad sectors */ ! 941: vattr.va_type = VBAD; ! 942: break; ! 943: case S_IFCHR: ! 944: vattr.va_type = VCHR; ! 945: break; ! 946: case S_IFBLK: ! 947: vattr.va_type = VBLK; ! 948: break; ! 949: case S_IFWHT: ! 950: whiteout = 1; ! 951: break; ! 952: default: ! 953: error = EINVAL; ! 954: break; ! 955: } ! 956: } ! 957: if (!error) { ! 958: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 959: if (whiteout) { ! 960: error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); ! 961: if (error) ! 962: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 963: vput(nd.ni_dvp); ! 964: } else { ! 965: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, ! 966: &nd.ni_cnd, &vattr); ! 967: } ! 968: } else { ! 969: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 970: if (nd.ni_dvp == vp) ! 971: vrele(nd.ni_dvp); ! 972: else ! 973: vput(nd.ni_dvp); ! 974: if (vp) ! 975: vrele(vp); ! 976: } ! 977: return (error); ! 978: } ! 979: ! 980: /* ! 981: * Create a named pipe. ! 982: */ ! 983: struct mkfifo_args { ! 984: char *path; ! 985: int mode; ! 986: }; ! 987: /* ARGSUSED */ ! 988: int ! 989: mkfifo(p, uap, retval) ! 990: struct proc *p; ! 991: register struct mkfifo_args *uap; ! 992: register_t *retval; ! 993: { ! 994: struct vattr vattr; ! 995: int error; ! 996: struct nameidata nd; ! 997: ! 998: #if !FIFO ! 999: return (EOPNOTSUPP); ! 1000: #else ! 1001: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); ! 1002: if (error = namei(&nd)) ! 1003: return (error); ! 1004: if (nd.ni_vp != NULL) { ! 1005: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1006: if (nd.ni_dvp == nd.ni_vp) ! 1007: vrele(nd.ni_dvp); ! 1008: else ! 1009: vput(nd.ni_dvp); ! 1010: vrele(nd.ni_vp); ! 1011: return (EEXIST); ! 1012: } ! 1013: VATTR_NULL(&vattr); ! 1014: vattr.va_type = VFIFO; ! 1015: vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; ! 1016: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 1017: return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); ! 1018: #endif /* FIFO */ ! 1019: } ! 1020: ! 1021: /* ! 1022: * Make a hard file link. ! 1023: */ ! 1024: struct link_args { ! 1025: char *path; ! 1026: char *link; ! 1027: }; ! 1028: /* ARGSUSED */ ! 1029: int ! 1030: link(p, uap, retval) ! 1031: struct proc *p; ! 1032: register struct link_args *uap; ! 1033: register_t *retval; ! 1034: { ! 1035: register struct vnode *vp; ! 1036: struct nameidata nd; ! 1037: int error; ! 1038: ! 1039: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1040: if (error = namei(&nd)) ! 1041: return (error); ! 1042: vp = nd.ni_vp; ! 1043: if (vp->v_type == VDIR) ! 1044: error = EPERM; /* POSIX */ ! 1045: else { ! 1046: nd.ni_cnd.cn_nameiop = CREATE; ! 1047: nd.ni_cnd.cn_flags = LOCKPARENT; ! 1048: nd.ni_dirp = uap->link; ! 1049: if ((error = namei(&nd)) == 0) { ! 1050: if (nd.ni_vp != NULL) ! 1051: error = EEXIST; ! 1052: if (!error) { ! 1053: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, ! 1054: LEASE_WRITE); ! 1055: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1056: error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); ! 1057: } else { ! 1058: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1059: if (nd.ni_dvp == nd.ni_vp) ! 1060: vrele(nd.ni_dvp); ! 1061: else ! 1062: vput(nd.ni_dvp); ! 1063: if (nd.ni_vp) ! 1064: vrele(nd.ni_vp); ! 1065: } ! 1066: } ! 1067: } ! 1068: vrele(vp); ! 1069: return (error); ! 1070: } ! 1071: ! 1072: /* ! 1073: * Make a symbolic link. ! 1074: */ ! 1075: struct symlink_args { ! 1076: char *path; ! 1077: char *link; ! 1078: }; ! 1079: /* ARGSUSED */ ! 1080: int ! 1081: symlink(p, uap, retval) ! 1082: struct proc *p; ! 1083: register struct symlink_args *uap; ! 1084: register_t *retval; ! 1085: { ! 1086: struct vattr vattr; ! 1087: char *path; ! 1088: int error; ! 1089: struct nameidata nd; ! 1090: ! 1091: MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); ! 1092: if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) ! 1093: goto out; ! 1094: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); ! 1095: if (error = namei(&nd)) ! 1096: goto out; ! 1097: if (nd.ni_vp) { ! 1098: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1099: if (nd.ni_dvp == nd.ni_vp) ! 1100: vrele(nd.ni_dvp); ! 1101: else ! 1102: vput(nd.ni_dvp); ! 1103: vrele(nd.ni_vp); ! 1104: error = EEXIST; ! 1105: goto out; ! 1106: } ! 1107: VATTR_NULL(&vattr); ! 1108: vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; ! 1109: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 1110: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); ! 1111: out: ! 1112: FREE_ZONE(path, MAXPATHLEN, M_NAMEI); ! 1113: return (error); ! 1114: } ! 1115: ! 1116: /* ! 1117: * Delete a whiteout from the filesystem. ! 1118: */ ! 1119: struct undelete_args { ! 1120: char *path; ! 1121: }; ! 1122: /* ARGSUSED */ ! 1123: int ! 1124: undelete(p, uap, retval) ! 1125: struct proc *p; ! 1126: register struct undelete_args *uap; ! 1127: register_t *retval; ! 1128: { ! 1129: int error; ! 1130: struct nameidata nd; ! 1131: ! 1132: NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, ! 1133: uap->path, p); ! 1134: error = namei(&nd); ! 1135: if (error) ! 1136: return (error); ! 1137: ! 1138: if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { ! 1139: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1140: if (nd.ni_dvp == nd.ni_vp) ! 1141: vrele(nd.ni_dvp); ! 1142: else ! 1143: vput(nd.ni_dvp); ! 1144: if (nd.ni_vp) ! 1145: vrele(nd.ni_vp); ! 1146: return (EEXIST); ! 1147: } ! 1148: ! 1149: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 1150: if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) ! 1151: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1152: vput(nd.ni_dvp); ! 1153: return (error); ! 1154: } ! 1155: ! 1156: /* ! 1157: * Delete a name from the filesystem. ! 1158: */ ! 1159: struct unlink_args { ! 1160: char *path; ! 1161: }; ! 1162: /* ARGSUSED */ ! 1163: int ! 1164: unlink(p, uap, retval) ! 1165: struct proc *p; ! 1166: struct unlink_args *uap; ! 1167: register_t *retval; ! 1168: { ! 1169: register struct vnode *vp; ! 1170: int error; ! 1171: struct nameidata nd; ! 1172: ! 1173: NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); ! 1174: if (error = namei(&nd)) ! 1175: return (error); ! 1176: vp = nd.ni_vp; ! 1177: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1178: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1179: ! 1180: if (vp->v_type == VDIR) ! 1181: error = EPERM; /* POSIX */ ! 1182: else { ! 1183: /* ! 1184: * The root of a mounted filesystem cannot be deleted. ! 1185: * ! 1186: * XXX: can this only be a VDIR case? ! 1187: */ ! 1188: if (vp->v_flag & VROOT) ! 1189: error = EBUSY; ! 1190: else ! 1191: (void) vnode_uncache(vp); ! 1192: } ! 1193: ! 1194: if (!error) { ! 1195: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 1196: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); ! 1197: } else { ! 1198: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 1199: if (nd.ni_dvp == vp) ! 1200: vrele(nd.ni_dvp); ! 1201: else ! 1202: vput(nd.ni_dvp); ! 1203: if (vp != NULLVP) ! 1204: vput(vp); ! 1205: } ! 1206: return (error); ! 1207: } ! 1208: ! 1209: /* ! 1210: * Reposition read/write file offset. ! 1211: */ ! 1212: struct lseek_args { ! 1213: int fd; ! 1214: #ifdef DOUBLE_ALIGN_PARAMS ! 1215: int pad; ! 1216: #endif ! 1217: off_t offset; ! 1218: int whence; ! 1219: }; ! 1220: int ! 1221: lseek(p, uap, retval) ! 1222: struct proc *p; ! 1223: register struct lseek_args *uap; ! 1224: register_t *retval; ! 1225: { ! 1226: struct ucred *cred = p->p_ucred; ! 1227: struct file *fp; ! 1228: struct vattr vattr; ! 1229: int error; ! 1230: ! 1231: if (error = fdgetf(p, uap->fd, &fp)) ! 1232: return (error); ! 1233: if (fp->f_type != DTYPE_VNODE) ! 1234: return (ESPIPE); ! 1235: switch (uap->whence) { ! 1236: case L_INCR: ! 1237: fp->f_offset += uap->offset; ! 1238: break; ! 1239: case L_XTND: ! 1240: if (error = ! 1241: VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) ! 1242: return (error); ! 1243: fp->f_offset = uap->offset + vattr.va_size; ! 1244: break; ! 1245: case L_SET: ! 1246: fp->f_offset = uap->offset; ! 1247: break; ! 1248: default: ! 1249: return (EINVAL); ! 1250: } ! 1251: *(off_t *)retval = fp->f_offset; ! 1252: return (0); ! 1253: } ! 1254: ! 1255: #if COMPAT_43 ! 1256: /* ! 1257: * Reposition read/write file offset. ! 1258: */ ! 1259: struct olseek_args { ! 1260: int fd; ! 1261: long offset; ! 1262: int whence; ! 1263: }; ! 1264: int ! 1265: olseek(p, uap, retval) ! 1266: struct proc *p; ! 1267: register struct olseek_args *uap; ! 1268: register_t *retval; ! 1269: { ! 1270: struct lseek_args /* { ! 1271: syscallarg(int) fd; ! 1272: #ifdef DOUBLE_ALIGN_PARAMS ! 1273: syscallarg(int) pad; ! 1274: #endif ! 1275: syscallarg(off_t) offset; ! 1276: syscallarg(int) whence; ! 1277: } */ nuap; ! 1278: off_t qret; ! 1279: int error; ! 1280: ! 1281: nuap.fd = uap->fd; ! 1282: nuap.offset = uap->offset; ! 1283: nuap.whence = uap->whence; ! 1284: error = lseek(p, &nuap, &qret); ! 1285: *(long *)retval = qret; ! 1286: return (error); ! 1287: } ! 1288: #endif /* COMPAT_43 */ ! 1289: ! 1290: /* ! 1291: * Check access permissions. ! 1292: */ ! 1293: struct access_args { ! 1294: char *path; ! 1295: int flags; ! 1296: }; ! 1297: int ! 1298: access(p, uap, retval) ! 1299: struct proc *p; ! 1300: register struct access_args *uap; ! 1301: register_t *retval; ! 1302: { ! 1303: register struct ucred *cred = p->p_ucred; ! 1304: register struct vnode *vp; ! 1305: int error, flags, t_gid, t_uid; ! 1306: struct nameidata nd; ! 1307: ! 1308: t_uid = cred->cr_uid; ! 1309: t_gid = cred->cr_groups[0]; ! 1310: cred->cr_uid = p->p_cred->p_ruid; ! 1311: cred->cr_groups[0] = p->p_cred->p_rgid; ! 1312: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1313: uap->path, p); ! 1314: if (error = namei(&nd)) ! 1315: goto out1; ! 1316: vp = nd.ni_vp; ! 1317: ! 1318: /* Flags == 0 means only check for existence. */ ! 1319: if (uap->flags) { ! 1320: flags = 0; ! 1321: if (uap->flags & R_OK) ! 1322: flags |= VREAD; ! 1323: if (uap->flags & W_OK) ! 1324: flags |= VWRITE; ! 1325: if (uap->flags & X_OK) ! 1326: flags |= VEXEC; ! 1327: if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) ! 1328: error = VOP_ACCESS(vp, flags, cred, p); ! 1329: } ! 1330: vput(vp); ! 1331: out1: ! 1332: cred->cr_uid = t_uid; ! 1333: cred->cr_groups[0] = t_gid; ! 1334: return (error); ! 1335: } ! 1336: ! 1337: #if COMPAT_43 ! 1338: /* ! 1339: * Get file status; this version follows links. ! 1340: */ ! 1341: struct ostat_args { ! 1342: char *path; ! 1343: struct ostat *ub; ! 1344: }; ! 1345: /* ARGSUSED */ ! 1346: int ! 1347: ostat(p, uap, retval) ! 1348: struct proc *p; ! 1349: register struct ostat_args *uap; ! 1350: register_t *retval; ! 1351: { ! 1352: struct stat sb; ! 1353: struct ostat osb; ! 1354: int error; ! 1355: struct nameidata nd; ! 1356: ! 1357: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1358: uap->path, p); ! 1359: if (error = namei(&nd)) ! 1360: return (error); ! 1361: error = vn_stat(nd.ni_vp, &sb, p); ! 1362: vput(nd.ni_vp); ! 1363: if (error) ! 1364: return (error); ! 1365: cvtstat(&sb, &osb); ! 1366: error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); ! 1367: return (error); ! 1368: } ! 1369: ! 1370: /* ! 1371: * Get file status; this version does not follow links. ! 1372: */ ! 1373: struct olstat_args { ! 1374: char *path; ! 1375: struct ostat *ub; ! 1376: }; ! 1377: /* ARGSUSED */ ! 1378: int ! 1379: olstat(p, uap, retval) ! 1380: struct proc *p; ! 1381: register struct olstat_args *uap; ! 1382: register_t *retval; ! 1383: { ! 1384: struct vnode *vp, *dvp; ! 1385: struct stat sb, sb1; ! 1386: struct ostat osb; ! 1387: int error; ! 1388: struct nameidata nd; ! 1389: ! 1390: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, ! 1391: uap->path, p); ! 1392: if (error = namei(&nd)) ! 1393: return (error); ! 1394: /* ! 1395: * For symbolic links, always return the attributes of its ! 1396: * containing directory, except for mode, size, and links. ! 1397: */ ! 1398: vp = nd.ni_vp; ! 1399: dvp = nd.ni_dvp; ! 1400: if (vp->v_type != VLNK) { ! 1401: if (dvp == vp) ! 1402: vrele(dvp); ! 1403: else ! 1404: vput(dvp); ! 1405: error = vn_stat(vp, &sb, p); ! 1406: vput(vp); ! 1407: if (error) ! 1408: return (error); ! 1409: } else { ! 1410: error = vn_stat(dvp, &sb, p); ! 1411: vput(dvp); ! 1412: if (error) { ! 1413: vput(vp); ! 1414: return (error); ! 1415: } ! 1416: error = vn_stat(vp, &sb1, p); ! 1417: vput(vp); ! 1418: if (error) ! 1419: return (error); ! 1420: sb.st_mode &= ~S_IFDIR; ! 1421: sb.st_mode |= S_IFLNK; ! 1422: sb.st_nlink = sb1.st_nlink; ! 1423: sb.st_size = sb1.st_size; ! 1424: sb.st_blocks = sb1.st_blocks; ! 1425: } ! 1426: cvtstat(&sb, &osb); ! 1427: error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); ! 1428: return (error); ! 1429: } ! 1430: ! 1431: /* ! 1432: * Convert from an old to a new stat structure. ! 1433: */ ! 1434: void ! 1435: cvtstat(st, ost) ! 1436: struct stat *st; ! 1437: struct ostat *ost; ! 1438: { ! 1439: ! 1440: ost->st_dev = st->st_dev; ! 1441: ost->st_ino = st->st_ino; ! 1442: ost->st_mode = st->st_mode; ! 1443: ost->st_nlink = st->st_nlink; ! 1444: ost->st_uid = st->st_uid; ! 1445: ost->st_gid = st->st_gid; ! 1446: ost->st_rdev = st->st_rdev; ! 1447: if (st->st_size < (quad_t)1 << 32) ! 1448: ost->st_size = st->st_size; ! 1449: else ! 1450: ost->st_size = -2; ! 1451: ost->st_atime = st->st_atime; ! 1452: ost->st_mtime = st->st_mtime; ! 1453: ost->st_ctime = st->st_ctime; ! 1454: ost->st_blksize = st->st_blksize; ! 1455: ost->st_blocks = st->st_blocks; ! 1456: ost->st_flags = st->st_flags; ! 1457: ost->st_gen = st->st_gen; ! 1458: } ! 1459: #endif /* COMPAT_43 */ ! 1460: ! 1461: /* ! 1462: * Get file status; this version follows links. ! 1463: */ ! 1464: struct stat_args { ! 1465: char *path; ! 1466: struct stat *ub; ! 1467: }; ! 1468: /* ARGSUSED */ ! 1469: int ! 1470: stat(p, uap, retval) ! 1471: struct proc *p; ! 1472: register struct stat_args *uap; ! 1473: register_t *retval; ! 1474: { ! 1475: struct stat sb; ! 1476: int error; ! 1477: struct nameidata nd; ! 1478: ! 1479: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1480: uap->path, p); ! 1481: if (error = namei(&nd)) ! 1482: return (error); ! 1483: error = vn_stat(nd.ni_vp, &sb, p); ! 1484: vput(nd.ni_vp); ! 1485: if (error) ! 1486: return (error); ! 1487: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); ! 1488: return (error); ! 1489: } ! 1490: ! 1491: /* ! 1492: * Get file status; this version does not follow links. ! 1493: */ ! 1494: struct lstat_args { ! 1495: char *path; ! 1496: struct stat *ub; ! 1497: }; ! 1498: /* ARGSUSED */ ! 1499: int ! 1500: lstat(p, uap, retval) ! 1501: struct proc *p; ! 1502: register struct lstat_args *uap; ! 1503: register_t *retval; ! 1504: { ! 1505: int error; ! 1506: struct vnode *vp, *dvp; ! 1507: struct stat sb, sb1; ! 1508: struct nameidata nd; ! 1509: ! 1510: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, ! 1511: uap->path, p); ! 1512: if (error = namei(&nd)) ! 1513: return (error); ! 1514: /* ! 1515: * For symbolic links, always return the attributes of its containing ! 1516: * directory, except for mode, size, inode number, and links. ! 1517: */ ! 1518: vp = nd.ni_vp; ! 1519: dvp = nd.ni_dvp; ! 1520: if ((vp->v_type != VLNK) || ((vp->v_type == VLNK) && (vp->v_tag == VT_NFS))) { ! 1521: if (dvp == vp) ! 1522: vrele(dvp); ! 1523: else ! 1524: vput(dvp); ! 1525: error = vn_stat(vp, &sb, p); ! 1526: vput(vp); ! 1527: if (error) ! 1528: return (error); ! 1529: if (vp->v_type == VLNK) ! 1530: sb.st_mode |= S_IFLNK; ! 1531: } else { ! 1532: error = vn_stat(dvp, &sb, p); ! 1533: vput(dvp); ! 1534: if (error) { ! 1535: vput(vp); ! 1536: return (error); ! 1537: } ! 1538: error = vn_stat(vp, &sb1, p); ! 1539: vput(vp); ! 1540: if (error) ! 1541: return (error); ! 1542: sb.st_mode &= ~S_IFDIR; ! 1543: sb.st_mode |= S_IFLNK; ! 1544: sb.st_nlink = sb1.st_nlink; ! 1545: sb.st_size = sb1.st_size; ! 1546: sb.st_blocks = sb1.st_blocks; ! 1547: sb.st_ino = sb1.st_ino; ! 1548: } ! 1549: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); ! 1550: return (error); ! 1551: } ! 1552: ! 1553: /* ! 1554: * Get configurable pathname variables. ! 1555: */ ! 1556: struct pathconf_args { ! 1557: char *path; ! 1558: int name; ! 1559: }; ! 1560: /* ARGSUSED */ ! 1561: int ! 1562: pathconf(p, uap, retval) ! 1563: struct proc *p; ! 1564: register struct pathconf_args *uap; ! 1565: register_t *retval; ! 1566: { ! 1567: int error; ! 1568: struct nameidata nd; ! 1569: ! 1570: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1571: uap->path, p); ! 1572: if (error = namei(&nd)) ! 1573: return (error); ! 1574: error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); ! 1575: vput(nd.ni_vp); ! 1576: return (error); ! 1577: } ! 1578: ! 1579: /* ! 1580: * Return target name of a symbolic link. ! 1581: */ ! 1582: struct readlink_args { ! 1583: char *path; ! 1584: char *buf; ! 1585: int count; ! 1586: }; ! 1587: /* ARGSUSED */ ! 1588: int ! 1589: readlink(p, uap, retval) ! 1590: struct proc *p; ! 1591: register struct readlink_args *uap; ! 1592: register_t *retval; ! 1593: { ! 1594: register struct vnode *vp; ! 1595: struct iovec aiov; ! 1596: struct uio auio; ! 1597: int error; ! 1598: struct nameidata nd; ! 1599: ! 1600: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1601: uap->path, p); ! 1602: if (error = namei(&nd)) ! 1603: return (error); ! 1604: vp = nd.ni_vp; ! 1605: if (vp->v_type != VLNK) ! 1606: error = EINVAL; ! 1607: else { ! 1608: aiov.iov_base = uap->buf; ! 1609: aiov.iov_len = uap->count; ! 1610: auio.uio_iov = &aiov; ! 1611: auio.uio_iovcnt = 1; ! 1612: auio.uio_offset = 0; ! 1613: auio.uio_rw = UIO_READ; ! 1614: auio.uio_segflg = UIO_USERSPACE; ! 1615: auio.uio_procp = p; ! 1616: auio.uio_resid = uap->count; ! 1617: error = VOP_READLINK(vp, &auio, p->p_ucred); ! 1618: } ! 1619: vput(vp); ! 1620: *retval = uap->count - auio.uio_resid; ! 1621: return (error); ! 1622: } ! 1623: ! 1624: /* ! 1625: * Change flags of a file given a path name. ! 1626: */ ! 1627: struct chflags_args { ! 1628: char *path; ! 1629: int flags; ! 1630: }; ! 1631: /* ARGSUSED */ ! 1632: int ! 1633: chflags(p, uap, retval) ! 1634: struct proc *p; ! 1635: register struct chflags_args *uap; ! 1636: register_t *retval; ! 1637: { ! 1638: register struct vnode *vp; ! 1639: struct vattr vattr; ! 1640: int error; ! 1641: struct nameidata nd; ! 1642: ! 1643: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1644: if (error = namei(&nd)) ! 1645: return (error); ! 1646: vp = nd.ni_vp; ! 1647: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1648: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1649: VATTR_NULL(&vattr); ! 1650: vattr.va_flags = uap->flags; ! 1651: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1652: vput(vp); ! 1653: return (error); ! 1654: } ! 1655: ! 1656: /* ! 1657: * Change flags of a file given a file descriptor. ! 1658: */ ! 1659: struct fchflags_args { ! 1660: int fd; ! 1661: int flags; ! 1662: }; ! 1663: /* ARGSUSED */ ! 1664: int ! 1665: fchflags(p, uap, retval) ! 1666: struct proc *p; ! 1667: register struct fchflags_args *uap; ! 1668: register_t *retval; ! 1669: { ! 1670: struct vattr vattr; ! 1671: struct vnode *vp; ! 1672: struct file *fp; ! 1673: int error; ! 1674: ! 1675: if (error = getvnode(p, uap->fd, &fp)) ! 1676: return (error); ! 1677: vp = (struct vnode *)fp->f_data; ! 1678: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1679: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1680: VATTR_NULL(&vattr); ! 1681: vattr.va_flags = uap->flags; ! 1682: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1683: VOP_UNLOCK(vp, 0, p); ! 1684: return (error); ! 1685: } ! 1686: ! 1687: /* ! 1688: * Change mode of a file given path name. ! 1689: */ ! 1690: struct chmod_args { ! 1691: char *path; ! 1692: int mode; ! 1693: }; ! 1694: /* ARGSUSED */ ! 1695: int ! 1696: chmod(p, uap, retval) ! 1697: struct proc *p; ! 1698: register struct chmod_args *uap; ! 1699: register_t *retval; ! 1700: { ! 1701: register struct vnode *vp; ! 1702: struct vattr vattr; ! 1703: int error; ! 1704: struct nameidata nd; ! 1705: ! 1706: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1707: if (error = namei(&nd)) ! 1708: return (error); ! 1709: vp = nd.ni_vp; ! 1710: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1711: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1712: VATTR_NULL(&vattr); ! 1713: vattr.va_mode = uap->mode & ALLPERMS; ! 1714: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1715: vput(vp); ! 1716: return (error); ! 1717: } ! 1718: ! 1719: /* ! 1720: * Change mode of a file given a file descriptor. ! 1721: */ ! 1722: struct fchmod_args { ! 1723: int fd; ! 1724: int mode; ! 1725: }; ! 1726: /* ARGSUSED */ ! 1727: int ! 1728: fchmod(p, uap, retval) ! 1729: struct proc *p; ! 1730: register struct fchmod_args *uap; ! 1731: register_t *retval; ! 1732: { ! 1733: struct vattr vattr; ! 1734: struct vnode *vp; ! 1735: struct file *fp; ! 1736: int error; ! 1737: ! 1738: if (error = getvnode(p, uap->fd, &fp)) ! 1739: return (error); ! 1740: vp = (struct vnode *)fp->f_data; ! 1741: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1742: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1743: VATTR_NULL(&vattr); ! 1744: vattr.va_mode = uap->mode & ALLPERMS; ! 1745: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1746: VOP_UNLOCK(vp, 0, p); ! 1747: return (error); ! 1748: } ! 1749: ! 1750: /* ! 1751: * Set ownership given a path name. ! 1752: */ ! 1753: struct chown_args { ! 1754: char *path; ! 1755: int uid; ! 1756: int gid; ! 1757: }; ! 1758: /* ARGSUSED */ ! 1759: int ! 1760: chown(p, uap, retval) ! 1761: struct proc *p; ! 1762: register struct chown_args *uap; ! 1763: register_t *retval; ! 1764: { ! 1765: register struct vnode *vp; ! 1766: struct vattr vattr; ! 1767: int error; ! 1768: struct nameidata nd; ! 1769: ! 1770: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1771: if (error = namei(&nd)) ! 1772: return (error); ! 1773: vp = nd.ni_vp; ! 1774: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1775: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1776: VATTR_NULL(&vattr); ! 1777: vattr.va_uid = uap->uid; ! 1778: vattr.va_gid = uap->gid; ! 1779: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1780: vput(vp); ! 1781: return (error); ! 1782: } ! 1783: ! 1784: /* ! 1785: * Set ownership given a file descriptor. ! 1786: */ ! 1787: struct fchown_args { ! 1788: int fd; ! 1789: int uid; ! 1790: int gid; ! 1791: }; ! 1792: /* ARGSUSED */ ! 1793: int ! 1794: fchown(p, uap, retval) ! 1795: struct proc *p; ! 1796: register struct fchown_args *uap; ! 1797: register_t *retval; ! 1798: { ! 1799: struct vattr vattr; ! 1800: struct vnode *vp; ! 1801: struct file *fp; ! 1802: int error; ! 1803: ! 1804: if (error = getvnode(p, uap->fd, &fp)) ! 1805: return (error); ! 1806: vp = (struct vnode *)fp->f_data; ! 1807: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1808: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1809: VATTR_NULL(&vattr); ! 1810: vattr.va_uid = uap->uid; ! 1811: vattr.va_gid = uap->gid; ! 1812: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1813: VOP_UNLOCK(vp, 0, p); ! 1814: return (error); ! 1815: } ! 1816: ! 1817: /* ! 1818: * Set the access and modification times of a file. ! 1819: */ ! 1820: struct utimes_args { ! 1821: char *path; ! 1822: struct timeval *tptr; ! 1823: }; ! 1824: /* ARGSUSED */ ! 1825: int ! 1826: utimes(p, uap, retval) ! 1827: struct proc *p; ! 1828: register struct utimes_args *uap; ! 1829: register_t *retval; ! 1830: { ! 1831: register struct vnode *vp; ! 1832: struct timeval tv[2]; ! 1833: struct vattr vattr; ! 1834: int error; ! 1835: struct nameidata nd; ! 1836: ! 1837: VATTR_NULL(&vattr); ! 1838: if (uap->tptr == NULL) { ! 1839: microtime(&tv[0]); ! 1840: tv[1] = tv[0]; ! 1841: vattr.va_vaflags |= VA_UTIMES_NULL; ! 1842: } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, ! 1843: sizeof (tv))) ! 1844: return (error); ! 1845: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1846: if (error = namei(&nd)) ! 1847: return (error); ! 1848: vp = nd.ni_vp; ! 1849: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1850: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1851: vattr.va_atime.tv_sec = tv[0].tv_sec; ! 1852: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; ! 1853: vattr.va_mtime.tv_sec = tv[1].tv_sec; ! 1854: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; ! 1855: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1856: vput(vp); ! 1857: return (error); ! 1858: } ! 1859: ! 1860: /* ! 1861: * Truncate a file given its path name. ! 1862: */ ! 1863: struct truncate_args { ! 1864: char *path; ! 1865: #ifdef DOUBLE_ALIGN_PARAMS ! 1866: int pad; ! 1867: #endif ! 1868: off_t length; ! 1869: }; ! 1870: /* ARGSUSED */ ! 1871: int ! 1872: truncate(p, uap, retval) ! 1873: struct proc *p; ! 1874: register struct truncate_args *uap; ! 1875: register_t *retval; ! 1876: { ! 1877: register struct vnode *vp; ! 1878: struct vattr vattr; ! 1879: int error; ! 1880: struct nameidata nd; ! 1881: ! 1882: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 1883: if (error = namei(&nd)) ! 1884: return (error); ! 1885: vp = nd.ni_vp; ! 1886: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1887: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1888: if (vp->v_type == VDIR) ! 1889: error = EISDIR; ! 1890: else if ((error = vn_writechk(vp)) == 0 && ! 1891: (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { ! 1892: VATTR_NULL(&vattr); ! 1893: vattr.va_size = uap->length; ! 1894: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1895: } ! 1896: vput(vp); ! 1897: return (error); ! 1898: } ! 1899: ! 1900: /* ! 1901: * Truncate a file given a file descriptor. ! 1902: */ ! 1903: struct ftruncate_args { ! 1904: int fd; ! 1905: #ifdef DOUBLE_ALIGN_PARAMS ! 1906: int pad; ! 1907: #endif ! 1908: off_t length; ! 1909: }; ! 1910: /* ARGSUSED */ ! 1911: int ! 1912: ftruncate(p, uap, retval) ! 1913: struct proc *p; ! 1914: register struct ftruncate_args *uap; ! 1915: register_t *retval; ! 1916: { ! 1917: struct vattr vattr; ! 1918: struct vnode *vp; ! 1919: struct file *fp; ! 1920: int error; ! 1921: ! 1922: if (error = getvnode(p, uap->fd, &fp)) ! 1923: return (error); ! 1924: if ((fp->f_flag & FWRITE) == 0) ! 1925: return (EINVAL); ! 1926: vp = (struct vnode *)fp->f_data; ! 1927: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 1928: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1929: if (vp->v_type == VDIR) ! 1930: error = EISDIR; ! 1931: else if ((error = vn_writechk(vp)) == 0) { ! 1932: VATTR_NULL(&vattr); ! 1933: vattr.va_size = uap->length; ! 1934: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); ! 1935: } ! 1936: VOP_UNLOCK(vp, 0, p); ! 1937: return (error); ! 1938: } ! 1939: ! 1940: #if COMPAT_43 ! 1941: /* ! 1942: * Truncate a file given its path name. ! 1943: */ ! 1944: struct otruncate_args { ! 1945: char *path; ! 1946: long length; ! 1947: }; ! 1948: /* ARGSUSED */ ! 1949: int ! 1950: otruncate(p, uap, retval) ! 1951: struct proc *p; ! 1952: register struct otruncate_args *uap; ! 1953: register_t *retval; ! 1954: { ! 1955: struct truncate_args /* { ! 1956: syscallarg(char *) path; ! 1957: #ifdef DOUBLE_ALIGN_PARAMS ! 1958: syscallarg(int) pad; ! 1959: #endif ! 1960: syscallarg(off_t) length; ! 1961: } */ nuap; ! 1962: ! 1963: nuap.path = uap->path; ! 1964: nuap.length = uap->length; ! 1965: return (truncate(p, &nuap, retval)); ! 1966: } ! 1967: ! 1968: /* ! 1969: * Truncate a file given a file descriptor. ! 1970: */ ! 1971: struct oftruncate_args { ! 1972: int fd; ! 1973: long length; ! 1974: }; ! 1975: /* ARGSUSED */ ! 1976: int ! 1977: oftruncate(p, uap, retval) ! 1978: struct proc *p; ! 1979: register struct oftruncate_args *uap; ! 1980: register_t *retval; ! 1981: { ! 1982: struct ftruncate_args /* { ! 1983: syscallarg(int) fd; ! 1984: #ifdef DOUBLE_ALIGN_PARAMS ! 1985: syscallarg(int) pad; ! 1986: #endif ! 1987: syscallarg(off_t) length; ! 1988: } */ nuap; ! 1989: ! 1990: nuap.fd = uap->fd; ! 1991: nuap.length = uap->length; ! 1992: return (ftruncate(p, &nuap, retval)); ! 1993: } ! 1994: #endif /* COMPAT_43 */ ! 1995: ! 1996: /* ! 1997: * Sync an open file. ! 1998: */ ! 1999: struct fsync_args { ! 2000: int fd; ! 2001: }; ! 2002: /* ARGSUSED */ ! 2003: int ! 2004: fsync(p, uap, retval) ! 2005: struct proc *p; ! 2006: struct fsync_args *uap; ! 2007: register_t *retval; ! 2008: { ! 2009: register struct vnode *vp; ! 2010: struct file *fp; ! 2011: int error; ! 2012: ! 2013: if (error = getvnode(p, uap->fd, &fp)) ! 2014: return (error); ! 2015: vp = (struct vnode *)fp->f_data; ! 2016: #if MACH_NBC ! 2017: mapfs_fsync(vp); ! 2018: #endif ! 2019: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 2020: error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); ! 2021: VOP_UNLOCK(vp, 0, p); ! 2022: return (error); ! 2023: } ! 2024: ! 2025: /* ! 2026: * Rename files. Source and destination must either both be directories, ! 2027: * or both not be directories. If target is a directory, it must be empty. ! 2028: */ ! 2029: struct rename_args { ! 2030: char *from; ! 2031: char *to; ! 2032: }; ! 2033: /* ARGSUSED */ ! 2034: int ! 2035: rename(p, uap, retval) ! 2036: struct proc *p; ! 2037: register struct rename_args *uap; ! 2038: register_t *retval; ! 2039: { ! 2040: register struct vnode *tvp, *fvp, *tdvp; ! 2041: struct nameidata fromnd, tond; ! 2042: int error; ! 2043: ! 2044: NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, ! 2045: uap->from, p); ! 2046: if (error = namei(&fromnd)) ! 2047: return (error); ! 2048: fvp = fromnd.ni_vp; ! 2049: NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, ! 2050: UIO_USERSPACE, uap->to, p); ! 2051: if (error = namei(&tond)) { ! 2052: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); ! 2053: vrele(fromnd.ni_dvp); ! 2054: vrele(fvp); ! 2055: goto out1; ! 2056: } ! 2057: tdvp = tond.ni_dvp; ! 2058: tvp = tond.ni_vp; ! 2059: if (tvp != NULL) { ! 2060: if (fvp->v_type == VDIR && tvp->v_type != VDIR) { ! 2061: error = ENOTDIR; ! 2062: goto out; ! 2063: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { ! 2064: error = EISDIR; ! 2065: goto out; ! 2066: } ! 2067: } ! 2068: if (fvp == tdvp) ! 2069: error = EINVAL; ! 2070: /* ! 2071: * If source is the same as the destination (that is the ! 2072: * same inode number) then there is nothing to do. ! 2073: * (fixed to have POSIX semantics - CSM 3/2/98) ! 2074: */ ! 2075: if (fvp == tvp) ! 2076: error = -1; ! 2077: out: ! 2078: if (!error) { ! 2079: VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); ! 2080: if (fromnd.ni_dvp != tdvp) ! 2081: VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 2082: if (tvp) ! 2083: VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); ! 2084: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, ! 2085: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); ! 2086: } else { ! 2087: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); ! 2088: if (tdvp == tvp) ! 2089: vrele(tdvp); ! 2090: else ! 2091: vput(tdvp); ! 2092: if (tvp) ! 2093: vput(tvp); ! 2094: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); ! 2095: vrele(fromnd.ni_dvp); ! 2096: vrele(fvp); ! 2097: } ! 2098: vrele(tond.ni_startdir); ! 2099: FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI); ! 2100: out1: ! 2101: if (fromnd.ni_startdir) ! 2102: vrele(fromnd.ni_startdir); ! 2103: FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI); ! 2104: if (error == -1) ! 2105: return (0); ! 2106: return (error); ! 2107: } ! 2108: ! 2109: /* ! 2110: * Make a directory file. ! 2111: */ ! 2112: struct mkdir_args { ! 2113: char *path; ! 2114: int mode; ! 2115: }; ! 2116: /* ARGSUSED */ ! 2117: int ! 2118: mkdir(p, uap, retval) ! 2119: struct proc *p; ! 2120: register struct mkdir_args *uap; ! 2121: register_t *retval; ! 2122: { ! 2123: register struct vnode *vp; ! 2124: struct vattr vattr; ! 2125: int error; ! 2126: struct nameidata nd; ! 2127: ! 2128: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); ! 2129: if (error = namei(&nd)) ! 2130: return (error); ! 2131: vp = nd.ni_vp; ! 2132: if (vp != NULL) { ! 2133: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 2134: if (nd.ni_dvp == vp) ! 2135: vrele(nd.ni_dvp); ! 2136: else ! 2137: vput(nd.ni_dvp); ! 2138: vrele(vp); ! 2139: return (EEXIST); ! 2140: } ! 2141: VATTR_NULL(&vattr); ! 2142: vattr.va_type = VDIR; ! 2143: vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; ! 2144: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 2145: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); ! 2146: if (!error) ! 2147: vput(nd.ni_vp); ! 2148: return (error); ! 2149: } ! 2150: ! 2151: /* ! 2152: * Remove a directory file. ! 2153: */ ! 2154: struct rmdir_args { ! 2155: char *path; ! 2156: }; ! 2157: /* ARGSUSED */ ! 2158: int ! 2159: rmdir(p, uap, retval) ! 2160: struct proc *p; ! 2161: struct rmdir_args *uap; ! 2162: register_t *retval; ! 2163: { ! 2164: register struct vnode *vp; ! 2165: int error; ! 2166: struct nameidata nd; ! 2167: ! 2168: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, ! 2169: uap->path, p); ! 2170: if (error = namei(&nd)) ! 2171: return (error); ! 2172: vp = nd.ni_vp; ! 2173: if (vp->v_type != VDIR) { ! 2174: error = ENOTDIR; ! 2175: goto out; ! 2176: } ! 2177: /* ! 2178: * No rmdir "." please. ! 2179: */ ! 2180: if (nd.ni_dvp == vp) { ! 2181: error = EINVAL; ! 2182: goto out; ! 2183: } ! 2184: /* ! 2185: * The root of a mounted filesystem cannot be deleted. ! 2186: */ ! 2187: if (vp->v_flag & VROOT) ! 2188: error = EBUSY; ! 2189: out: ! 2190: if (!error) { ! 2191: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); ! 2192: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 2193: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); ! 2194: } else { ! 2195: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); ! 2196: if (nd.ni_dvp == vp) ! 2197: vrele(nd.ni_dvp); ! 2198: else ! 2199: vput(nd.ni_dvp); ! 2200: vput(vp); ! 2201: } ! 2202: return (error); ! 2203: } ! 2204: ! 2205: #if COMPAT_43 ! 2206: /* ! 2207: * Read a block of directory entries in a file system independent format. ! 2208: */ ! 2209: struct ogetdirentries_args { ! 2210: int fd; ! 2211: char *buf; ! 2212: u_int count; ! 2213: long *basep; ! 2214: }; ! 2215: int ! 2216: ogetdirentries(p, uap, retval) ! 2217: struct proc *p; ! 2218: register struct ogetdirentries_args *uap; ! 2219: register_t *retval; ! 2220: { ! 2221: register struct vnode *vp; ! 2222: struct file *fp; ! 2223: struct uio auio, kuio; ! 2224: struct iovec aiov, kiov; ! 2225: struct dirent *dp, *edp; ! 2226: caddr_t dirbuf; ! 2227: int error, eofflag, readcnt; ! 2228: long loff; ! 2229: ! 2230: if (error = getvnode(p, uap->fd, &fp)) ! 2231: return (error); ! 2232: if ((fp->f_flag & FREAD) == 0) ! 2233: return (EBADF); ! 2234: vp = (struct vnode *)fp->f_data; ! 2235: unionread: ! 2236: if (vp->v_type != VDIR) ! 2237: return (EINVAL); ! 2238: aiov.iov_base = uap->buf; ! 2239: aiov.iov_len = uap->count; ! 2240: auio.uio_iov = &aiov; ! 2241: auio.uio_iovcnt = 1; ! 2242: auio.uio_rw = UIO_READ; ! 2243: auio.uio_segflg = UIO_USERSPACE; ! 2244: auio.uio_procp = p; ! 2245: auio.uio_resid = uap->count; ! 2246: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 2247: loff = auio.uio_offset = fp->f_offset; ! 2248: # if (BYTE_ORDER != LITTLE_ENDIAN) ! 2249: if (vp->v_mount->mnt_maxsymlinklen <= 0) { ! 2250: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, ! 2251: (int *)0, (u_long *)0); ! 2252: fp->f_offset = auio.uio_offset; ! 2253: } else ! 2254: # endif ! 2255: { ! 2256: kuio = auio; ! 2257: kuio.uio_iov = &kiov; ! 2258: kuio.uio_segflg = UIO_SYSSPACE; ! 2259: kiov.iov_len = uap->count; ! 2260: MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); ! 2261: kiov.iov_base = dirbuf; ! 2262: error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, ! 2263: (int *)0, (u_long *)0); ! 2264: fp->f_offset = kuio.uio_offset; ! 2265: if (error == 0) { ! 2266: readcnt = uap->count - kuio.uio_resid; ! 2267: edp = (struct dirent *)&dirbuf[readcnt]; ! 2268: for (dp = (struct dirent *)dirbuf; dp < edp; ) { ! 2269: # if (BYTE_ORDER == LITTLE_ENDIAN) ! 2270: /* ! 2271: * The expected low byte of ! 2272: * dp->d_namlen is our dp->d_type. ! 2273: * The high MBZ byte of dp->d_namlen ! 2274: * is our dp->d_namlen. ! 2275: */ ! 2276: dp->d_type = dp->d_namlen; ! 2277: dp->d_namlen = 0; ! 2278: # else ! 2279: /* ! 2280: * The dp->d_type is the high byte ! 2281: * of the expected dp->d_namlen, ! 2282: * so must be zero'ed. ! 2283: */ ! 2284: dp->d_type = 0; ! 2285: # endif ! 2286: if (dp->d_reclen > 0) { ! 2287: dp = (struct dirent *) ! 2288: ((char *)dp + dp->d_reclen); ! 2289: } else { ! 2290: error = EIO; ! 2291: break; ! 2292: } ! 2293: } ! 2294: if (dp >= edp) ! 2295: error = uiomove(dirbuf, readcnt, &auio); ! 2296: } ! 2297: FREE(dirbuf, M_TEMP); ! 2298: } ! 2299: VOP_UNLOCK(vp, 0, p); ! 2300: if (error) ! 2301: return (error); ! 2302: ! 2303: #if UNION ! 2304: { ! 2305: extern int (**union_vnodeop_p)(); ! 2306: extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); ! 2307: ! 2308: if ((uap->count == auio.uio_resid) && ! 2309: (vp->v_op == union_vnodeop_p)) { ! 2310: struct vnode *lvp; ! 2311: ! 2312: lvp = union_dircache(vp, p); ! 2313: if (lvp != NULLVP) { ! 2314: struct vattr va; ! 2315: ! 2316: /* ! 2317: * If the directory is opaque, ! 2318: * then don't show lower entries ! 2319: */ ! 2320: error = VOP_GETATTR(vp, &va, fp->f_cred, p); ! 2321: if (va.va_flags & OPAQUE) { ! 2322: vput(lvp); ! 2323: lvp = NULL; ! 2324: } ! 2325: } ! 2326: ! 2327: if (lvp != NULLVP) { ! 2328: error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); ! 2329: if (error) { ! 2330: vput(lvp); ! 2331: return (error); ! 2332: } ! 2333: VOP_UNLOCK(lvp, 0, p); ! 2334: fp->f_data = (caddr_t) lvp; ! 2335: fp->f_offset = 0; ! 2336: error = vn_close(vp, FREAD, fp->f_cred, p); ! 2337: if (error) ! 2338: return (error); ! 2339: vp = lvp; ! 2340: goto unionread; ! 2341: } ! 2342: } ! 2343: } ! 2344: #endif /* UNION */ ! 2345: ! 2346: if ((uap->count == auio.uio_resid) && ! 2347: (vp->v_flag & VROOT) && ! 2348: (vp->v_mount->mnt_flag & MNT_UNION)) { ! 2349: struct vnode *tvp = vp; ! 2350: vp = vp->v_mount->mnt_vnodecovered; ! 2351: VREF(vp); ! 2352: fp->f_data = (caddr_t) vp; ! 2353: fp->f_offset = 0; ! 2354: vrele(tvp); ! 2355: goto unionread; ! 2356: } ! 2357: error = copyout((caddr_t)&loff, (caddr_t)uap->basep, ! 2358: sizeof(long)); ! 2359: *retval = uap->count - auio.uio_resid; ! 2360: return (error); ! 2361: } ! 2362: #endif /* COMPAT_43 */ ! 2363: ! 2364: /* ! 2365: * Read a block of directory entries in a file system independent format. ! 2366: */ ! 2367: struct getdirentries_args { ! 2368: int fd; ! 2369: char *buf; ! 2370: u_int count; ! 2371: long *basep; ! 2372: }; ! 2373: int ! 2374: getdirentries(p, uap, retval) ! 2375: struct proc *p; ! 2376: register struct getdirentries_args *uap; ! 2377: register_t *retval; ! 2378: { ! 2379: register struct vnode *vp; ! 2380: struct file *fp; ! 2381: struct uio auio; ! 2382: struct iovec aiov; ! 2383: long loff; ! 2384: int error, eofflag; ! 2385: ! 2386: if (error = getvnode(p, uap->fd, &fp)) ! 2387: return (error); ! 2388: if ((fp->f_flag & FREAD) == 0) ! 2389: return (EBADF); ! 2390: vp = (struct vnode *)fp->f_data; ! 2391: unionread: ! 2392: if (vp->v_type != VDIR) ! 2393: return (EINVAL); ! 2394: aiov.iov_base = uap->buf; ! 2395: aiov.iov_len = uap->count; ! 2396: auio.uio_iov = &aiov; ! 2397: auio.uio_iovcnt = 1; ! 2398: auio.uio_rw = UIO_READ; ! 2399: auio.uio_segflg = UIO_USERSPACE; ! 2400: auio.uio_procp = p; ! 2401: auio.uio_resid = uap->count; ! 2402: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 2403: loff = auio.uio_offset = fp->f_offset; ! 2404: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, ! 2405: (int *)0, (u_long *)0); ! 2406: fp->f_offset = auio.uio_offset; ! 2407: VOP_UNLOCK(vp, 0, p); ! 2408: if (error) ! 2409: return (error); ! 2410: ! 2411: #if UNION ! 2412: { ! 2413: extern int (**union_vnodeop_p)(); ! 2414: extern struct vnode *union_dircache __P((struct vnode*, struct proc*)); ! 2415: ! 2416: if ((uap->count == auio.uio_resid) && ! 2417: (vp->v_op == union_vnodeop_p)) { ! 2418: struct vnode *lvp; ! 2419: ! 2420: lvp = union_dircache(vp, p); ! 2421: if (lvp != NULLVP) { ! 2422: struct vattr va; ! 2423: ! 2424: /* ! 2425: * If the directory is opaque, ! 2426: * then don't show lower entries ! 2427: */ ! 2428: error = VOP_GETATTR(vp, &va, fp->f_cred, p); ! 2429: if (va.va_flags & OPAQUE) { ! 2430: vput(lvp); ! 2431: lvp = NULL; ! 2432: } ! 2433: } ! 2434: ! 2435: if (lvp != NULLVP) { ! 2436: error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); ! 2437: if (error) { ! 2438: vput(lvp); ! 2439: return (error); ! 2440: } ! 2441: VOP_UNLOCK(lvp, 0, p); ! 2442: fp->f_data = (caddr_t) lvp; ! 2443: fp->f_offset = 0; ! 2444: error = vn_close(vp, FREAD, fp->f_cred, p); ! 2445: if (error) ! 2446: return (error); ! 2447: vp = lvp; ! 2448: goto unionread; ! 2449: } ! 2450: } ! 2451: } ! 2452: #endif /* UNION */ ! 2453: ! 2454: if ((uap->count == auio.uio_resid) && ! 2455: (vp->v_flag & VROOT) && ! 2456: (vp->v_mount->mnt_flag & MNT_UNION)) { ! 2457: struct vnode *tvp = vp; ! 2458: vp = vp->v_mount->mnt_vnodecovered; ! 2459: VREF(vp); ! 2460: fp->f_data = (caddr_t) vp; ! 2461: fp->f_offset = 0; ! 2462: vrele(tvp); ! 2463: goto unionread; ! 2464: } ! 2465: error = copyout((caddr_t)&loff, (caddr_t)uap->basep, ! 2466: sizeof(long)); ! 2467: *retval = uap->count - auio.uio_resid; ! 2468: return (error); ! 2469: } ! 2470: ! 2471: /* ! 2472: * Set the mode mask for creation of filesystem nodes. ! 2473: */ ! 2474: struct umask_args { ! 2475: int newmask; ! 2476: }; ! 2477: int ! 2478: umask(p, uap, retval) ! 2479: struct proc *p; ! 2480: struct umask_args *uap; ! 2481: register_t *retval; ! 2482: { ! 2483: register struct filedesc *fdp; ! 2484: ! 2485: fdp = p->p_fd; ! 2486: *retval = fdp->fd_cmask; ! 2487: fdp->fd_cmask = uap->newmask & ALLPERMS; ! 2488: return (0); ! 2489: } ! 2490: ! 2491: /* ! 2492: * Void all references to file by ripping underlying filesystem ! 2493: * away from vnode. ! 2494: */ ! 2495: struct revoke_args { ! 2496: char *path; ! 2497: }; ! 2498: /* ARGSUSED */ ! 2499: int ! 2500: revoke(p, uap, retval) ! 2501: struct proc *p; ! 2502: register struct revoke_args *uap; ! 2503: register_t *retval; ! 2504: { ! 2505: register struct vnode *vp; ! 2506: struct vattr vattr; ! 2507: int error; ! 2508: struct nameidata nd; ! 2509: ! 2510: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); ! 2511: if (error = namei(&nd)) ! 2512: return (error); ! 2513: vp = nd.ni_vp; ! 2514: if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) ! 2515: goto out; ! 2516: if (p->p_ucred->cr_uid != vattr.va_uid && ! 2517: (error = suser(p->p_ucred, &p->p_acflag))) ! 2518: goto out; ! 2519: if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) ! 2520: VOP_REVOKE(vp, REVOKEALL); ! 2521: out: ! 2522: vrele(vp); ! 2523: return (error); ! 2524: } ! 2525: ! 2526: /* ! 2527: * Convert a user file descriptor to a kernel file entry. ! 2528: */ ! 2529: int ! 2530: getvnode(p, fd, fpp) ! 2531: struct proc *p; ! 2532: int fd; ! 2533: struct file **fpp; ! 2534: { ! 2535: struct file *fp; ! 2536: int error; ! 2537: ! 2538: if (error = fdgetf(p, fd, &fp)) ! 2539: return (error); ! 2540: if (fp->f_type != DTYPE_VNODE) ! 2541: return (EINVAL); ! 2542: *fpp = fp; ! 2543: return (0); ! 2544: } ! 2545: /* ! 2546: * HFS/HFS PlUS SPECIFIC SYSTEM CALLS ! 2547: * The following 10 system calls are designed to support features ! 2548: * which are specific to the HFS & HFS Plus volume formats ! 2549: */ ! 2550: ! 2551: ! 2552: /* ! 2553: * Make a complex file. A complex file is one with multiple forks (data streams) ! 2554: */ ! 2555: struct mkcomplex_args { ! 2556: const char *path; /* pathname of the file to be created */ ! 2557: mode_t mode; /* access mode for the newly created file */ ! 2558: u_long type; /* format of the complex file */ ! 2559: }; ! 2560: /* ARGSUSED */ ! 2561: int ! 2562: mkcomplex(p,uap,retval) ! 2563: struct proc *p; ! 2564: register struct mkcomplex_args *uap; ! 2565: register_t *retval; ! 2566: ! 2567: { ! 2568: struct vnode *vp; ! 2569: struct vattr vattr; ! 2570: int error; ! 2571: struct nameidata nd; ! 2572: ! 2573: /* mkcomplex wants the directory vnode locked so do that here */ ! 2574: ! 2575: NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_USERSPACE, uap->path, p); ! 2576: if (error = namei(&nd)) ! 2577: return (error); ! 2578: ! 2579: /* Set the attributes as specified by the user */ ! 2580: ! 2581: VATTR_NULL(&vattr); ! 2582: vattr.va_mode = (uap->mode & ACCESSPERMS); ! 2583: error = VOP_MKCOMPLEX(nd.ni_dvp, &vp, &nd.ni_cnd, &vattr, uap->type); ! 2584: ! 2585: /* The mkcomplex call promises to release the parent vnode pointer ! 2586: * even an an error case so don't do it here unless the operation ! 2587: * is not supported. In that case, there isn't anyone to unlock the parent ! 2588: * The vnode pointer to the file will also be released. ! 2589: */ ! 2590: ! 2591: if (error) ! 2592: { ! 2593: if (error == EOPNOTSUPP) ! 2594: vput(nd.ni_dvp); ! 2595: return (error); ! 2596: } ! 2597: ! 2598: return (0); ! 2599: ! 2600: } /* end of mkcomplex system call */ ! 2601: ! 2602: ! 2603: ! 2604: /* ! 2605: * Extended stat call which returns volumeid and vnodeid as well as other info ! 2606: */ ! 2607: struct statv_args { ! 2608: const char *path; /* pathname of the target file */ ! 2609: struct vstat *vsb; /* vstat structure for returned info */ ! 2610: }; ! 2611: /* ARGSUSED */ ! 2612: int ! 2613: statv(p,uap,retval) ! 2614: struct proc *p; ! 2615: register struct statv_args *uap; ! 2616: register_t *retval; ! 2617: ! 2618: { ! 2619: return (EOPNOTSUPP); /* We'll just return an error for now */ ! 2620: ! 2621: } /* end of statv system call */ ! 2622: ! 2623: ! 2624: ! 2625: /* ! 2626: * Extended lstat call which returns volumeid and vnodeid as well as other info ! 2627: */ ! 2628: struct lstatv_args { ! 2629: const char *path; /* pathname of the target file */ ! 2630: struct vstat *vsb; /* vstat structure for returned info */ ! 2631: }; ! 2632: /* ARGSUSED */ ! 2633: int ! 2634: lstatv(p,uap,retval) ! 2635: struct proc *p; ! 2636: register struct lstatv_args *uap; ! 2637: register_t *retval; ! 2638: ! 2639: { ! 2640: return (EOPNOTSUPP); /* We'll just return an error for now */ ! 2641: } /* end of lstatv system call */ ! 2642: ! 2643: ! 2644: ! 2645: /* ! 2646: * Extended fstat call which returns volumeid and vnodeid as well as other info ! 2647: */ ! 2648: struct fstatv_args { ! 2649: int fd; /* file descriptor of the target file */ ! 2650: struct vstat *vsb; /* vstat structure for returned info */ ! 2651: }; ! 2652: /* ARGSUSED */ ! 2653: int ! 2654: fstatv(p,uap,retval) ! 2655: struct proc *p; ! 2656: register struct fstatv_args *uap; ! 2657: register_t *retval; ! 2658: ! 2659: { ! 2660: return (EOPNOTSUPP); /* We'll just return an error for now */ ! 2661: } /* end of fstatv system call */ ! 2662: ! 2663: ! 2664: ! 2665: /* ! 2666: * Obtain attribute information about a file system object ! 2667: */ ! 2668: ! 2669: struct getattrlist_args { ! 2670: const char *path; /* pathname of the target object */ ! 2671: struct attrlist * alist; /* Attributes desired by the user */ ! 2672: void * attributeBuffer; /* buffer to hold returned attributes */ ! 2673: size_t bufferSize; /* size of the return buffer */ ! 2674: }; ! 2675: /* ARGSUSED */ ! 2676: int ! 2677: getattrlist (p,uap,retval) ! 2678: struct proc *p; ! 2679: register struct getattrlist_args *uap; ! 2680: register_t *retval; ! 2681: ! 2682: { ! 2683: int error; ! 2684: struct nameidata nd; ! 2685: struct iovec aiov; ! 2686: struct uio auio; ! 2687: struct attrlist attributelist; ! 2688: ! 2689: /* Get the attributes desire and do our parameter checking */ ! 2690: ! 2691: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist, ! 2692: sizeof (attributelist))) ! 2693: { ! 2694: return(error); ! 2695: } ! 2696: ! 2697: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT ! 2698: #if 0 ! 2699: || attributelist.commonattr & ~ATTR_CMN_VALIDMASK || ! 2700: attributelist.volattr & ~ATTR_VOL_VALIDMASK || ! 2701: attributelist.dirattr & ~ATTR_DIR_VALIDMASK || ! 2702: attributelist.fileattr & ~ATTR_FILE_VALIDMASK || ! 2703: attributelist.forkattr & ~ATTR_FORK_VALIDMASK ! 2704: #endif ! 2705: ) ! 2706: { ! 2707: return (EINVAL); ! 2708: } ! 2709: ! 2710: /* Get the vnode for the file we are getting info on. */ ! 2711: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); ! 2712: ! 2713: if (error = namei(&nd)) ! 2714: return (error); ! 2715: ! 2716: /* Set up the UIO structure for use by the vfs routine */ ! 2717: ! 2718: ! 2719: aiov.iov_base = uap->attributeBuffer; ! 2720: aiov.iov_len = uap->bufferSize; ! 2721: auio.uio_iov = &aiov; ! 2722: auio.uio_iovcnt = 1; ! 2723: auio.uio_offset = 0; ! 2724: auio.uio_rw = UIO_READ; ! 2725: auio.uio_segflg = UIO_USERSPACE; ! 2726: auio.uio_procp = p; ! 2727: auio.uio_resid = uap->bufferSize; ! 2728: ! 2729: ! 2730: error = VOP_GETATTRLIST(nd.ni_vp, &attributelist, &auio, p->p_ucred, p); ! 2731: ! 2732: /* Unlock and release the vnode which will have been locked by namei */ ! 2733: ! 2734: vput(nd.ni_vp); ! 2735: ! 2736: /* return the effort if we got one, otherwise return success */ ! 2737: ! 2738: if (error) ! 2739: { ! 2740: return (error); ! 2741: } ! 2742: ! 2743: return(0); ! 2744: ! 2745: } /* end of getattrlist system call */ ! 2746: ! 2747: ! 2748: ! 2749: /* ! 2750: * Set attribute information about a file system object ! 2751: */ ! 2752: ! 2753: struct setattrlist_args { ! 2754: const char *path; /* pathname of the target object */ ! 2755: struct attrlist * alist; /* Attributes being set by the user */ ! 2756: void * attributeBuffer; /* buffer with attribute values to be set */ ! 2757: size_t bufferSize; /* size of the return buffer */ ! 2758: }; ! 2759: /* ARGSUSED */ ! 2760: int ! 2761: setattrlist (p,uap,retval) ! 2762: struct proc *p; ! 2763: register struct setattrlist_args *uap; ! 2764: register_t *retval; ! 2765: ! 2766: { ! 2767: int error; ! 2768: struct nameidata nd; ! 2769: struct iovec aiov; ! 2770: struct uio auio; ! 2771: struct attrlist attributelist; ! 2772: ! 2773: /* Get the attributes desire and do our parameter checking */ ! 2774: ! 2775: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist, ! 2776: sizeof (attributelist))) ! 2777: { ! 2778: return(error); ! 2779: } ! 2780: ! 2781: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT ! 2782: #if 0 ! 2783: || attributelist.commonattr & ~ATTR_CMN_VALIDMASK || ! 2784: attributelist.volattr & ~ATTR_VOL_VALIDMASK || ! 2785: attributelist.dirattr & ~ATTR_DIR_VALIDMASK || ! 2786: attributelist.fileattr & ~ATTR_FILE_VALIDMASK || ! 2787: attributelist.forkattr & ~ATTR_FORK_VALIDMASK ! 2788: #endif ! 2789: ) ! 2790: { ! 2791: return (EINVAL); ! 2792: } ! 2793: ! 2794: /* Get the vnode for the file we are getting info on. */ ! 2795: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); ! 2796: ! 2797: if (error = namei(&nd)) ! 2798: return (error); ! 2799: ! 2800: /* Set up the UIO structure for use by the vfs routine */ ! 2801: ! 2802: aiov.iov_base = uap->attributeBuffer; ! 2803: aiov.iov_len = uap->bufferSize; ! 2804: auio.uio_iov = &aiov; ! 2805: auio.uio_iovcnt = 1; ! 2806: auio.uio_offset = 0; ! 2807: auio.uio_rw = UIO_WRITE; ! 2808: auio.uio_segflg = UIO_USERSPACE; ! 2809: auio.uio_procp = p; ! 2810: auio.uio_resid = uap->bufferSize; ! 2811: ! 2812: ! 2813: error = VOP_SETATTRLIST(nd.ni_vp,&attributelist, &auio, p->p_ucred, p); ! 2814: ! 2815: /* Unlock and release the vnode which will have been locked by namei */ ! 2816: ! 2817: vput(nd.ni_vp); ! 2818: ! 2819: /* return the error if we got one, otherwise return success */ ! 2820: ! 2821: if (error) ! 2822: { ! 2823: return (error); ! 2824: } ! 2825: ! 2826: return(0); ! 2827: ! 2828: } /* end of setattrlist system call */ ! 2829: ! 2830: ! 2831: /* ! 2832: * Obtain attribute information on objects in a directory while enumerating ! 2833: the directory. This call does not yet support union mounted directories. ! 2834: */ ! 2835: ! 2836: struct getdirentryattr_args { ! 2837: int fd; /* file descriptor */ ! 2838: int *index; /* Cookie from the user */ ! 2839: struct attrlist *alist; /* bit map of requested attributes */ ! 2840: void *attributebuffer; /* buffer to hold returned attribute info */ ! 2841: size_t buffersize; /* size of the return buffer */ ! 2842: }; ! 2843: /* ARGSUSED */ ! 2844: int ! 2845: getdirentryattr (p,uap,retval) ! 2846: struct proc *p; ! 2847: register struct getdirentryattr_args *uap; ! 2848: register_t *retval; ! 2849: ! 2850: { ! 2851: register struct vnode *vp; ! 2852: struct file *fp; ! 2853: struct uio auio; ! 2854: struct iovec aiov; ! 2855: int index; ! 2856: int error, eofflag; ! 2857: struct attrlist attributelist; ! 2858: ! 2859: /* Get the attributes desired and do our parameter checking */ ! 2860: ! 2861: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist, ! 2862: sizeof (attributelist))) ! 2863: { ! 2864: return(error); ! 2865: } ! 2866: ! 2867: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT) ! 2868: { ! 2869: return (EINVAL); ! 2870: } ! 2871: ! 2872: if (error = getvnode(p, uap->fd, &fp)) ! 2873: return (error); ! 2874: ! 2875: if ((fp->f_flag & FREAD) == 0) ! 2876: { ! 2877: return(EBADF); ! 2878: } ! 2879: ! 2880: vp = (struct vnode *)fp->f_data; ! 2881: ! 2882: if (vp->v_type != VDIR) ! 2883: { ! 2884: return(EINVAL); ! 2885: } ! 2886: ! 2887: if (error = copyin((caddr_t) uap->index, (caddr_t) &index, sizeof(index))) ! 2888: return(error); ! 2889: ! 2890: /* set up the uio structure which will contain the users return buffer */ ! 2891: ! 2892: aiov.iov_base = uap->attributebuffer; ! 2893: aiov.iov_len = uap->buffersize; ! 2894: auio.uio_iov = &aiov; ! 2895: auio.uio_iovcnt = 1; ! 2896: auio.uio_rw = UIO_READ; ! 2897: auio.uio_segflg = UIO_USERSPACE; ! 2898: auio.uio_procp = p; ! 2899: auio.uio_resid = uap->buffersize; ! 2900: ! 2901: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 2902: error = VOP_READDIRATTR (vp, &attributelist, &auio, &index, &eofflag,((u_long*)0), ((u_long **)0),fp->f_cred); ! 2903: fp->f_offset = auio.uio_offset; ! 2904: ! 2905: if (error) ! 2906: return (error); ! 2907: ! 2908: VOP_UNLOCK(vp, 0, p); ! 2909: ! 2910: if (error = copyout((caddr_t) &index, (caddr_t) uap->index, sizeof(index))) ! 2911: return(error); ! 2912: ! 2913: return (0); ! 2914: ! 2915: } /* end of getdirentryattr system call */ ! 2916: ! 2917: /* ! 2918: * Exchange data between two files ! 2919: */ ! 2920: ! 2921: struct exchangedata_args { ! 2922: const char *path1; /* pathname of the first swapee */ ! 2923: const char *path2; /* pathname of the second swapee */ ! 2924: }; ! 2925: /* ARGSUSED */ ! 2926: int ! 2927: exchangedata (p,uap,retval) ! 2928: struct proc *p; ! 2929: register struct exchangedata_args *uap; ! 2930: register_t *retval; ! 2931: ! 2932: { ! 2933: ! 2934: struct nameidata fnd, snd; ! 2935: struct vnode *fvp, *svp; ! 2936: int error; ! 2937: ! 2938: /* Global lock, to prevent race condition, only one exchange at a time */ ! 2939: lockmgr(&exchangelock, LK_EXCLUSIVE , (struct slock *)0, p); ! 2940: ! 2941: NDINIT(&fnd, LOOKUP,FOLLOW, UIO_USERSPACE, uap->path1, p); ! 2942: ! 2943: if (error = namei(&fnd)) ! 2944: goto out2; ! 2945: ! 2946: fvp = fnd.ni_vp; ! 2947: ! 2948: NDINIT(&snd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path2, p); ! 2949: ! 2950: if (error = namei(&snd)) { ! 2951: vrele(fvp); ! 2952: goto out2; ! 2953: } ! 2954: ! 2955: svp = snd.ni_vp; ! 2956: ! 2957: /* if the files are the same, return an inval error */ ! 2958: if (svp == fvp) { ! 2959: vrele(fvp); ! 2960: vrele(svp); ! 2961: error = EINVAL; ! 2962: goto out2; ! 2963: } ! 2964: ! 2965: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p); ! 2966: vn_lock(svp, LK_EXCLUSIVE | LK_RETRY, p); ! 2967: ! 2968: error = VOP_ACCESS(fvp, VWRITE, p->p_ucred, p); ! 2969: if (error) goto out; ! 2970: ! 2971: error = VOP_ACCESS(svp, VWRITE, p->p_ucred, p); ! 2972: if (error) goto out; ! 2973: ! 2974: /* Ok, make the call */ ! 2975: error = VOP_EXCHANGE (fvp, svp, p->p_ucred, p); ! 2976: ! 2977: out: ! 2978: vput (svp); ! 2979: vput (fvp); ! 2980: ! 2981: out2: ! 2982: lockmgr(&exchangelock, LK_RELEASE, (struct slock *)0, p); ! 2983: ! 2984: if (error) { ! 2985: return (error); ! 2986: } ! 2987: ! 2988: return (0); ! 2989: ! 2990: } /* end of exchangedata system call */ ! 2991: ! 2992: /* ! 2993: * Check users access to a file ! 2994: */ ! 2995: ! 2996: struct checkuseraccess_args { ! 2997: const char *path; /* pathname of the target file */ ! 2998: uid_t userid; /* user for whom we are checking access */ ! 2999: gid_t *groups; /* Group that we are checking for */ ! 3000: int ngroups; /* Number of groups being checked */ ! 3001: int accessrequired; /* needed access to the file */ ! 3002: }; ! 3003: ! 3004: /* ARGSUSED */ ! 3005: int ! 3006: checkuseraccess (p,uap,retval) ! 3007: struct proc *p; ! 3008: register struct checkuseraccess_args *uap; ! 3009: register_t *retval; ! 3010: ! 3011: { ! 3012: register struct vnode *vp; ! 3013: int error; ! 3014: struct nameidata nd; ! 3015: struct ucred cred; ! 3016: int flags; /*what will actually get passed to access*/ ! 3017: ! 3018: /* Make sure that the number of groups is correct before we do anything */ ! 3019: ! 3020: if (uap->ngroups > NGROUPS) ! 3021: return (EINVAL); ! 3022: ! 3023: /* Verify that the caller is root */ ! 3024: ! 3025: if (error = suser(p->p_ucred, &p->p_acflag)) ! 3026: return(error); ! 3027: ! 3028: /* Fill in the credential structure */ ! 3029: ! 3030: cred.cr_ref = 0; ! 3031: cred.cr_uid = uap->userid; ! 3032: cred.cr_ngroups = uap->ngroups; ! 3033: if (error = copyin((caddr_t) uap->groups, (caddr_t) &(cred.cr_groups), (sizeof(gid_t))*uap->ngroups)) ! 3034: return (error); ! 3035: ! 3036: /* Get our hands on the file */ ! 3037: ! 3038: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); ! 3039: ! 3040: if (error = namei(&nd)) ! 3041: return (error); ! 3042: vp = nd.ni_vp; ! 3043: ! 3044: /* Flags == 0 means only check for existence. */ ! 3045: ! 3046: flags = 0; ! 3047: ! 3048: if (uap->accessrequired) { ! 3049: if (uap->accessrequired & R_OK) ! 3050: flags |= VREAD; ! 3051: if (uap->accessrequired & W_OK) ! 3052: flags |= VWRITE; ! 3053: if (uap->accessrequired & X_OK) ! 3054: flags |= VEXEC; ! 3055: } ! 3056: error = VOP_ACCESS(vp, flags, &cred, p); ! 3057: ! 3058: vput(vp); ! 3059: ! 3060: if (error) ! 3061: return (error); ! 3062: ! 3063: return (0); ! 3064: ! 3065: } /* end of checkuseraccess system call */ ! 3066: ! 3067: ! 3068: struct searchfs_args { ! 3069: const char *path; ! 3070: struct fssearchblock *searchblock; ! 3071: u_long *nummatches; ! 3072: u_long scriptcode; ! 3073: u_long options; ! 3074: struct searchstate *state; ! 3075: }; ! 3076: /* ARGSUSED */ ! 3077: ! 3078: int ! 3079: searchfs (p,uap,retval) ! 3080: struct proc *p; ! 3081: register struct searchfs_args *uap; ! 3082: register_t *retval; ! 3083: ! 3084: { ! 3085: register struct vnode *vp; ! 3086: int error=0; ! 3087: int fserror = 0; ! 3088: struct nameidata nd; ! 3089: struct fssearchblock searchblock; ! 3090: struct searchstate *state; ! 3091: struct attrlist *returnattrs; ! 3092: void *searchparams1,*searchparams2; ! 3093: struct iovec aiov; ! 3094: struct uio auio; ! 3095: u_long nummatches; ! 3096: int mallocsize; ! 3097: ! 3098: ! 3099: /* Start by copying in fsearchblock paramater list */ ! 3100: ! 3101: if (error = copyin((caddr_t) uap->searchblock, (caddr_t) &searchblock,sizeof(struct fssearchblock))) ! 3102: return(error); ! 3103: ! 3104: /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */ ! 3105: /* It all has to do into local memory and it's not that big so we might as well put it all together. */ ! 3106: /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/ ! 3107: /* block. */ ! 3108: ! 3109: mallocsize = searchblock.sizeofsearchparams1+searchblock.sizeofsearchparams2 + ! 3110: sizeof(struct attrlist) + sizeof(struct searchstate); ! 3111: ! 3112: MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK); ! 3113: ! 3114: /* Now set up the various pointers to the correct place in our newly allocated memory */ ! 3115: ! 3116: searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1); ! 3117: returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2); ! 3118: state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist)); ! 3119: ! 3120: /* Now copy in the stuff given our local variables. */ ! 3121: ! 3122: if (error = copyin((caddr_t) searchblock.searchparams1, searchparams1,searchblock.sizeofsearchparams1)) ! 3123: goto freeandexit; ! 3124: ! 3125: if (error = copyin((caddr_t) searchblock.searchparams2, searchparams2,searchblock.sizeofsearchparams2)) ! 3126: goto freeandexit; ! 3127: ! 3128: if (error = copyin((caddr_t) searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist))) ! 3129: goto freeandexit; ! 3130: ! 3131: if (error = copyin((caddr_t) uap->state, (caddr_t) state, sizeof(struct searchstate))) ! 3132: goto freeandexit; ! 3133: ! 3134: /* set up the uio structure which will contain the users return buffer */ ! 3135: ! 3136: aiov.iov_base = searchblock.returnbuffer; ! 3137: aiov.iov_len = searchblock.returnbuffersize; ! 3138: auio.uio_iov = &aiov; ! 3139: auio.uio_iovcnt = 1; ! 3140: auio.uio_rw = UIO_READ; ! 3141: auio.uio_segflg = UIO_USERSPACE; ! 3142: auio.uio_procp = p; ! 3143: auio.uio_resid = searchblock.returnbuffersize; ! 3144: ! 3145: ! 3146: NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_USERSPACE, uap->path, p); ! 3147: ! 3148: if (error = namei(&nd)) ! 3149: goto freeandexit; ! 3150: ! 3151: vp = nd.ni_vp; ! 3152: ! 3153: /* ! 3154: Allright, we have everything we need, so lets make that call. ! 3155: ! 3156: We keep special track of the return value from the file system: ! 3157: EAGAIN is an acceptable error condition that shouldn't keep us ! 3158: from copying out any results... ! 3159: */ ! 3160: ! 3161: fserror = VOP_SEARCHFS(vp, ! 3162: searchparams1, ! 3163: searchparams2, ! 3164: &searchblock.searchattrs, ! 3165: searchblock.maxmatches, ! 3166: &searchblock.timelimit, ! 3167: returnattrs, ! 3168: &nummatches, ! 3169: uap->scriptcode, ! 3170: uap->options, ! 3171: &auio, ! 3172: state); ! 3173: ! 3174: vput(vp); ! 3175: ! 3176: /* Now copy out the stuff that needs copying out. That means the number of matches, the ! 3177: search state. Everything was already put into he return buffer by the vop call. */ ! 3178: ! 3179: if (error = copyout((caddr_t) state, (caddr_t) uap->state, sizeof(struct searchstate))) ! 3180: goto freeandexit; ! 3181: ! 3182: if (error = copyout((caddr_t) &nummatches, (caddr_t) uap->nummatches, sizeof(u_long))) ! 3183: goto freeandexit; ! 3184: ! 3185: error = fserror; ! 3186: ! 3187: freeandexit: ! 3188: ! 3189: FREE(searchparams1,M_TEMP); ! 3190: ! 3191: return(error); ! 3192: ! 3193: ! 3194: } /* end of searchfs system call */ ! 3195: ! 3196:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.