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