[BACK]Return to vfs_syscalls.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/vfs_syscalls.c, Revision 1.389

1.389   ! ad          1: /*     $NetBSD: vfs_syscalls.c,v 1.388 2009/02/15 03:52:49 enami Exp $ */
1.345     ad          2:
                      3: /*-
                      4:  * Copyright (c) 2008 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     17:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     18:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     20:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     22:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     23:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     24:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     25:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
1.31      cgd        28:
                     29: /*
                     30:  * Copyright (c) 1989, 1993
                     31:  *     The Regents of the University of California.  All rights reserved.
                     32:  * (c) UNIX System Laboratories, Inc.
                     33:  * All or some portions of this file are derived from material licensed
                     34:  * to the University of California by American Telephone and Telegraph
                     35:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     36:  * the permission of UNIX System Laboratories, Inc.
                     37:  *
                     38:  * Redistribution and use in source and binary forms, with or without
                     39:  * modification, are permitted provided that the following conditions
                     40:  * are met:
                     41:  * 1. Redistributions of source code must retain the above copyright
                     42:  *    notice, this list of conditions and the following disclaimer.
                     43:  * 2. Redistributions in binary form must reproduce the above copyright
                     44:  *    notice, this list of conditions and the following disclaimer in the
                     45:  *    documentation and/or other materials provided with the distribution.
1.191     agc        46:  * 3. Neither the name of the University nor the names of its contributors
1.31      cgd        47:  *    may be used to endorse or promote products derived from this software
                     48:  *    without specific prior written permission.
                     49:  *
                     50:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     51:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     52:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     53:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     54:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     55:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     56:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     57:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     58:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     59:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     60:  * SUCH DAMAGE.
                     61:  *
1.113     fvdl       62:  *     @(#)vfs_syscalls.c      8.42 (Berkeley) 7/31/95
1.31      cgd        63:  */
1.173     lukem      64:
                     65: #include <sys/cdefs.h>
1.389   ! ad         66: __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.388 2009/02/15 03:52:49 enami Exp $");
1.111     mrg        67:
1.378     ad         68: #ifdef _KERNEL_OPT
1.258     elad       69: #include "opt_fileassoc.h"
1.261     dogcow     70: #include "veriexec.h"
1.378     ad         71: #endif
1.31      cgd        72:
                     73: #include <sys/param.h>
                     74: #include <sys/systm.h>
                     75: #include <sys/namei.h>
                     76: #include <sys/filedesc.h>
                     77: #include <sys/kernel.h>
                     78: #include <sys/file.h>
                     79: #include <sys/stat.h>
                     80: #include <sys/vnode.h>
                     81: #include <sys/mount.h>
                     82: #include <sys/proc.h>
                     83: #include <sys/uio.h>
1.248     yamt       84: #include <sys/kmem.h>
1.31      cgd        85: #include <sys/dirent.h>
1.172     simonb     86: #include <sys/sysctl.h>
1.35      cgd        87: #include <sys/syscallargs.h>
1.306     dsl        88: #include <sys/vfs_syscalls.h>
1.192     drochner   89: #include <sys/ktrace.h>
1.251     elad       90: #ifdef FILEASSOC
                     91: #include <sys/fileassoc.h>
                     92: #endif /* FILEASSOC */
1.219     blymn      93: #include <sys/verified_exec.h>
1.242     elad       94: #include <sys/kauth.h>
1.346     ad         95: #include <sys/atomic.h>
1.360     ad         96: #include <sys/module.h>
1.380     pooka      97: #include <sys/buf.h>
1.35      cgd        98:
1.148     fvdl       99: #include <miscfs/genfs/genfs.h>
                    100: #include <miscfs/syncfs/syncfs.h>
1.342     ad        101: #include <miscfs/specfs/specdev.h>
1.181     thorpej   102:
1.232     jmmv      103: #include <nfs/rpcv2.h>
                    104: #include <nfs/nfsproto.h>
                    105: #include <nfs/nfs.h>
                    106: #include <nfs/nfs_var.h>
                    107:
1.181     thorpej   108: MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
1.110     mrg       109:
1.234     christos  110: static int change_dir(struct nameidata *, struct lwp *);
                    111: static int change_flags(struct vnode *, u_long, struct lwp *);
                    112: static int change_mode(struct vnode *, int, struct lwp *l);
                    113: static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
1.63      christos  114:
1.205     junyoung  115: void checkdirs(struct vnode *);
1.31      cgd       116:
1.150     fvdl      117: int dovfsusermount = 0;
                    118:
1.31      cgd       119: /*
                    120:  * Virtual File System System Calls
                    121:  */
                    122:
                    123: /*
                    124:  * Mount a file system.
                    125:  */
1.99      thorpej   126:
                    127: /*
                    128:  * This table is used to maintain compatibility with 4.3BSD
1.378     ad        129:  * and NetBSD 0.9 mount syscalls - and possibly other systems.
                    130:  * Note, the order is important!
1.124     thorpej   131:  *
1.167     jdolecek  132:  * Do not modify this table. It should only contain filesystems
                    133:  * supported by NetBSD 0.9 and 4.3BSD.
1.99      thorpej   134:  */
1.167     jdolecek  135: const char * const mountcompatnames[] = {
1.99      thorpej   136:        NULL,           /* 0 = MOUNT_NONE */
1.167     jdolecek  137:        MOUNT_FFS,      /* 1 = MOUNT_UFS */
1.99      thorpej   138:        MOUNT_NFS,      /* 2 */
                    139:        MOUNT_MFS,      /* 3 */
                    140:        MOUNT_MSDOS,    /* 4 */
1.167     jdolecek  141:        MOUNT_CD9660,   /* 5 = MOUNT_ISOFS */
                    142:        MOUNT_FDESC,    /* 6 */
                    143:        MOUNT_KERNFS,   /* 7 */
                    144:        NULL,           /* 8 = MOUNT_DEVFS */
                    145:        MOUNT_AFS,      /* 9 */
1.99      thorpej   146: };
1.113     fvdl      147: const int nmountcompatnames = sizeof(mountcompatnames) /
1.99      thorpej   148:     sizeof(mountcompatnames[0]);
                    149:
1.285     elad      150: static int
1.283     elad      151: mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324     pooka     152:     void *data, size_t *data_len)
1.56      thorpej   153: {
1.113     fvdl      154:        struct mount *mp;
1.283     elad      155:        int error = 0, saved_flags;
                    156:
                    157:        mp = vp->v_mount;
                    158:        saved_flags = mp->mnt_flag;
                    159:
1.329     ad        160:        /* We can operate only on VV_ROOT nodes. */
                    161:        if ((vp->v_vflag & VV_ROOT) == 0) {
                    162:                error = EINVAL;
                    163:                goto out;
                    164:        }
1.31      cgd       165:
1.218     yamt      166:        /*
1.283     elad      167:         * We only allow the filesystem to be reloaded if it
1.373     ad        168:         * is currently mounted read-only.  Additionally, we
                    169:         * prevent read-write to read-only downgrades.
1.283     elad      170:         */
1.373     ad        171:        if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
                    172:            (mp->mnt_flag & MNT_RDONLY) == 0) {
1.329     ad        173:                error = EOPNOTSUPP;     /* Needs translation */
                    174:                goto out;
                    175:        }
1.292     elad      176:
                    177:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    178:            KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
                    179:        if (error)
1.329     ad        180:                goto out;
1.292     elad      181:
1.358     ad        182:        if (vfs_busy(mp, NULL)) {
1.329     ad        183:                error = EPERM;
                    184:                goto out;
                    185:        }
1.283     elad      186:
1.358     ad        187:        mutex_enter(&mp->mnt_updating);
                    188:
1.286     yamt      189:        mp->mnt_flag &= ~MNT_OP_FLAGS;
                    190:        mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
                    191:
1.283     elad      192:        /*
                    193:         * Set the mount level flags.
                    194:         */
                    195:        if (flags & MNT_RDONLY)
                    196:                mp->mnt_flag |= MNT_RDONLY;
                    197:        else if (mp->mnt_flag & MNT_RDONLY)
                    198:                mp->mnt_iflag |= IMNT_WANTRDWR;
                    199:        mp->mnt_flag &=
                    200:          ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
                    201:            MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
1.370     simonb    202:            MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
                    203:            MNT_LOG);
1.283     elad      204:        mp->mnt_flag |= flags &
                    205:           (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
                    206:            MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
                    207:            MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
1.370     simonb    208:            MNT_LOG | MNT_IGNORE);
1.283     elad      209:
1.332     pooka     210:        error = VFS_MOUNT(mp, path, data, data_len);
1.283     elad      211:
1.320     dsl       212:        if (error && data != NULL) {
1.283     elad      213:                int error2;
                    214:
1.378     ad        215:                /*
                    216:                 * Update failed; let's try and see if it was an
1.379     ad        217:                 * export request.  For compat with 3.0 and earlier.
1.378     ad        218:                 */
1.381     ad        219:                error2 = vfs_hooks_reexport(mp, path, data);
1.283     elad      220:
1.381     ad        221:                /*
                    222:                 * Only update error code if the export request was
1.283     elad      223:                 * understood but some problem occurred while
1.381     ad        224:                 * processing it.
                    225:                 */
1.283     elad      226:                if (error2 != EJUSTRETURN)
                    227:                        error = error2;
                    228:        }
1.381     ad        229:
1.283     elad      230:        if (mp->mnt_iflag & IMNT_WANTRDWR)
                    231:                mp->mnt_flag &= ~MNT_RDONLY;
                    232:        if (error)
                    233:                mp->mnt_flag = saved_flags;
1.286     yamt      234:        mp->mnt_flag &= ~MNT_OP_FLAGS;
                    235:        mp->mnt_iflag &= ~IMNT_WANTRDWR;
1.283     elad      236:        if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
                    237:                if (mp->mnt_syncer == NULL)
                    238:                        error = vfs_allocate_syncvnode(mp);
1.125     tls       239:        } else {
1.283     elad      240:                if (mp->mnt_syncer != NULL)
                    241:                        vfs_deallocate_syncvnode(mp);
                    242:        }
1.358     ad        243:        mutex_exit(&mp->mnt_updating);
1.354     ad        244:        vfs_unbusy(mp, false, NULL);
1.283     elad      245:
1.329     ad        246:  out:
1.283     elad      247:        return (error);
                    248: }
                    249:
1.285     elad      250: static int
1.320     dsl       251: mount_get_vfsops(const char *fstype, struct vfsops **vfsops)
1.283     elad      252: {
1.322     christos  253:        char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)];
1.283     elad      254:        int error;
                    255:
1.320     dsl       256:        /* Copy file-system type from userspace.  */
1.322     christos  257:        error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
1.63      christos  258:        if (error) {
1.54      cgd       259:                /*
1.227     jmmv      260:                 * Historically, filesystem types were identified by numbers.
1.54      cgd       261:                 * If we get an integer for the filesystem type instead of a
                    262:                 * string, we check to see if it matches one of the historic
                    263:                 * filesystem types.
1.205     junyoung  264:                 */
1.283     elad      265:                u_long fsindex = (u_long)fstype;
1.99      thorpej   266:                if (fsindex >= nmountcompatnames ||
1.320     dsl       267:                    mountcompatnames[fsindex] == NULL)
                    268:                        return ENODEV;
1.331     pooka     269:                strlcpy(fstypename, mountcompatnames[fsindex],
                    270:                    sizeof(fstypename));
1.31      cgd       271:        }
1.283     elad      272:
1.378     ad        273:        /* Accept `ufs' as an alias for `ffs', for compatibility. */
1.320     dsl       274:        if (strcmp(fstypename, "ufs") == 0)
                    275:                fstypename[0] = 'f';
1.285     elad      276:
1.360     ad        277:        if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                    278:                return 0;
                    279:
                    280:        /* If we can autoload a vfs module, try again */
1.376     ad        281:        mutex_enter(&module_lock);
                    282:        (void)module_autoload(fstype, MODULE_CLASS_VFS);
                    283:        mutex_exit(&module_lock);
1.360     ad        284:
                    285:        if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                    286:                return 0;
                    287:
                    288:        return ENODEV;
1.320     dsl       289: }
                    290:
                    291: static int
                    292: mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops,
1.337     ad        293:     const char *path, int flags, void *data, size_t *data_len, u_int recurse)
1.320     dsl       294: {
1.366     simonb    295:        struct mount *mp;
1.320     dsl       296:        struct vnode *vp = *vpp;
                    297:        struct vattr va;
                    298:        int error;
                    299:
                    300:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    301:            KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data);
                    302:        if (error)
                    303:                return error;
                    304:
                    305:        /* Can't make a non-dir a mount-point (from here anyway). */
                    306:        if (vp->v_type != VDIR)
                    307:                return ENOTDIR;
                    308:
                    309:        /*
                    310:         * If the user is not root, ensure that they own the directory
                    311:         * onto which we are attempting to mount.
                    312:         */
1.332     pooka     313:        if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0 ||
1.320     dsl       314:            (va.va_uid != kauth_cred_geteuid(l->l_cred) &&
                    315:            (error = kauth_authorize_generic(l->l_cred,
                    316:            KAUTH_GENERIC_ISSUSER, NULL)) != 0)) {
                    317:                return error;
1.283     elad      318:        }
                    319:
1.320     dsl       320:        if (flags & MNT_EXPORTED)
                    321:                return EINVAL;
                    322:
                    323:        if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
                    324:                return error;
                    325:
1.283     elad      326:        /*
                    327:         * Check if a file-system is not already mounted on this vnode.
                    328:         */
1.320     dsl       329:        if (vp->v_mountedhere != NULL)
                    330:                return EBUSY;
1.283     elad      331:
1.345     ad        332:        mp = kmem_zalloc(sizeof(*mp), KM_SLEEP);
                    333:        if (mp == NULL)
                    334:                return ENOMEM;
1.283     elad      335:
1.320     dsl       336:        mp->mnt_op = vfsops;
1.345     ad        337:        mp->mnt_refcnt = 1;
1.31      cgd       338:
1.296     pooka     339:        TAILQ_INIT(&mp->mnt_vnodelist);
1.358     ad        340:        rw_init(&mp->mnt_unmounting);
1.344     dholland  341:        mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE);
1.358     ad        342:        mutex_init(&mp->mnt_updating, MUTEX_DEFAULT, IPL_NONE);
                    343:        error = vfs_busy(mp, NULL);
                    344:        KASSERT(error == 0);
                    345:        mutex_enter(&mp->mnt_updating);
1.283     elad      346:
1.129     fvdl      347:        mp->mnt_vnodecovered = vp;
1.257     ad        348:        mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred);
1.277     hannken   349:        mount_initspecific(mp);
1.195     thorpej   350:
                    351:        /*
                    352:         * The underlying file system may refuse the mount for
1.198     thorpej   353:         * various reasons.  Allow the user to force it to happen.
1.286     yamt      354:         *
1.284     elad      355:         * Set the mount level flags.
                    356:         */
1.286     yamt      357:        mp->mnt_flag = flags &
                    358:           (MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
1.284     elad      359:            MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
                    360:            MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
1.370     simonb    361:            MNT_LOG | MNT_IGNORE | MNT_RDONLY);
1.284     elad      362:
1.332     pooka     363:        error = VFS_MOUNT(mp, path, data, data_len);
1.286     yamt      364:        mp->mnt_flag &= ~MNT_OP_FLAGS;
1.232     jmmv      365:
1.31      cgd       366:        /*
                    367:         * Put the new filesystem on the mount list after root.
                    368:         */
                    369:        cache_purge(vp);
1.320     dsl       370:        if (error != 0) {
1.283     elad      371:                vp->v_mountedhere = NULL;
1.358     ad        372:                mutex_exit(&mp->mnt_updating);
1.354     ad        373:                vfs_unbusy(mp, false, NULL);
1.358     ad        374:                vfs_destroy(mp);
1.320     dsl       375:                return error;
1.31      cgd       376:        }
1.283     elad      377:
1.320     dsl       378:        mp->mnt_iflag &= ~IMNT_WANTRDWR;
1.345     ad        379:        mutex_enter(&mountlist_lock);
1.320     dsl       380:        vp->v_mountedhere = mp;
                    381:        CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
1.329     ad        382:        mutex_exit(&mountlist_lock);
1.337     ad        383:        vn_restorerecurse(vp, recurse);
1.320     dsl       384:        VOP_UNLOCK(vp, 0);
                    385:        checkdirs(vp);
                    386:        if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
                    387:                error = vfs_allocate_syncvnode(mp);
1.347     ad        388:        /* Hold an additional reference to the mount across VFS_START(). */
1.358     ad        389:        mutex_exit(&mp->mnt_updating);
1.354     ad        390:        vfs_unbusy(mp, true, NULL);
1.332     pooka     391:        (void) VFS_STATVFS(mp, &mp->mnt_stat);
                    392:        error = VFS_START(mp, 0);
1.372     ad        393:        if (error)
1.320     dsl       394:                vrele(vp);
1.347     ad        395:        /* Drop reference held for VFS_START(). */
1.358     ad        396:        vfs_destroy(mp);
1.320     dsl       397:        *vpp = NULL;
                    398:        return error;
1.283     elad      399: }
                    400:
                    401: static int
                    402: mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324     pooka     403:     void *data, size_t *data_len)
1.283     elad      404: {
                    405:        struct mount *mp;
                    406:        int error;
                    407:
1.289     elad      408:        /* If MNT_GETARGS is specified, it should be the only flag. */
1.320     dsl       409:        if (flags & ~MNT_GETARGS)
                    410:                return EINVAL;
1.289     elad      411:
1.283     elad      412:        mp = vp->v_mount;
                    413:
1.292     elad      414:        /* XXX: probably some notion of "can see" here if we want isolation. */
                    415:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    416:            KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
                    417:        if (error)
1.320     dsl       418:                return error;
1.292     elad      419:
1.329     ad        420:        if ((vp->v_vflag & VV_ROOT) == 0)
1.320     dsl       421:                return EINVAL;
1.283     elad      422:
1.358     ad        423:        if (vfs_busy(mp, NULL))
1.320     dsl       424:                return EPERM;
1.283     elad      425:
1.358     ad        426:        mutex_enter(&mp->mnt_updating);
1.286     yamt      427:        mp->mnt_flag &= ~MNT_OP_FLAGS;
                    428:        mp->mnt_flag |= MNT_GETARGS;
1.332     pooka     429:        error = VFS_MOUNT(mp, path, data, data_len);
1.286     yamt      430:        mp->mnt_flag &= ~MNT_OP_FLAGS;
1.358     ad        431:        mutex_exit(&mp->mnt_updating);
1.283     elad      432:
1.354     ad        433:        vfs_unbusy(mp, false, NULL);
1.283     elad      434:        return (error);
                    435: }
                    436:
1.321     dsl       437: int
1.335     dsl       438: sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
1.321     dsl       439: {
1.335     dsl       440:        /* {
1.321     dsl       441:                syscallarg(const char *) type;
                    442:                syscallarg(const char *) path;
                    443:                syscallarg(int) flags;
                    444:                syscallarg(void *) data;
                    445:                syscallarg(size_t) data_len;
1.335     dsl       446:        } */
1.321     dsl       447:
                    448:        return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
                    449:            SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE,
                    450:            SCARG(uap, data_len), retval);
                    451: }
1.320     dsl       452:
                    453: int
                    454: do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type,
                    455:     const char *path, int flags, void *data, enum uio_seg data_seg,
                    456:     size_t data_len, register_t *retval)
                    457: {
1.283     elad      458:        struct vnode *vp;
                    459:        struct nameidata nd;
1.320     dsl       460:        void *data_buf = data;
1.337     ad        461:        u_int recurse;
1.283     elad      462:        int error;
                    463:
                    464:        /*
                    465:         * Get vnode to be covered
                    466:         */
1.334     pooka     467:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);
1.283     elad      468:        if ((error = namei(&nd)) != 0)
                    469:                return (error);
                    470:        vp = nd.ni_vp;
                    471:
                    472:        /*
                    473:         * A lookup in VFS_MOUNT might result in an attempt to
                    474:         * lock this vnode again, so make the lock recursive.
                    475:         */
1.320     dsl       476:        if (vfsops == NULL) {
1.361     ad        477:                if (flags & (MNT_GETARGS | MNT_UPDATE)) {
                    478:                        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    479:                        recurse = vn_setrecurse(vp);
1.320     dsl       480:                        vfsops = vp->v_mount->mnt_op;
1.361     ad        481:                } else {
1.320     dsl       482:                        /* 'type' is userspace */
                    483:                        error = mount_get_vfsops(type, &vfsops);
1.361     ad        484:                        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    485:                        recurse = vn_setrecurse(vp);
1.320     dsl       486:                        if (error != 0)
                    487:                                goto done;
                    488:                }
1.361     ad        489:        } else {
                    490:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    491:                recurse = vn_setrecurse(vp);
1.320     dsl       492:        }
                    493:
                    494:        if (data != NULL && data_seg == UIO_USERSPACE) {
                    495:                if (data_len == 0) {
                    496:                        /* No length supplied, use default for filesystem */
                    497:                        data_len = vfsops->vfs_min_mount_data;
                    498:                        if (data_len > VFS_MAX_MOUNT_DATA) {
                    499:                                error = EINVAL;
                    500:                                goto done;
                    501:                        }
1.378     ad        502:                        /*
                    503:                         * Hopefully a longer buffer won't make copyin() fail.
                    504:                         * For compatibility with 3.0 and earlier.
                    505:                         */
1.320     dsl       506:                        if (flags & MNT_UPDATE
                    507:                            && data_len < sizeof (struct mnt_export_args30))
                    508:                                data_len = sizeof (struct mnt_export_args30);
                    509:                }
1.384     yamt      510:                data_buf = kmem_alloc(data_len, KM_SLEEP);
1.283     elad      511:
1.320     dsl       512:                /* NFS needs the buffer even for mnt_getargs .... */
                    513:                error = copyin(data, data_buf, data_len);
                    514:                if (error != 0)
                    515:                        goto done;
                    516:        }
                    517:
                    518:        if (flags & MNT_GETARGS) {
                    519:                if (data_len == 0) {
                    520:                        error = EINVAL;
                    521:                        goto done;
                    522:                }
1.324     pooka     523:                error = mount_getargs(l, vp, path, flags, data_buf, &data_len);
1.320     dsl       524:                if (error != 0)
                    525:                        goto done;
                    526:                if (data_seg == UIO_USERSPACE)
                    527:                        error = copyout(data_buf, data, data_len);
                    528:                *retval = data_len;
                    529:        } else if (flags & MNT_UPDATE) {
1.324     pooka     530:                error = mount_update(l, vp, path, flags, data_buf, &data_len);
1.283     elad      531:        } else {
                    532:                /* Locking is handled internally in mount_domount(). */
1.320     dsl       533:                error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
1.337     ad        534:                    &data_len, recurse);
1.283     elad      535:        }
                    536:
1.320     dsl       537:     done:
1.337     ad        538:        if (vp != NULL) {
                    539:                vn_restorerecurse(vp, recurse);
                    540:                vput(vp);
                    541:        }
1.320     dsl       542:        if (data_buf != data)
1.384     yamt      543:                kmem_free(data_buf, data_len);
1.31      cgd       544:        return (error);
                    545: }
                    546:
                    547: /*
1.43      mycroft   548:  * Scan all active processes to see if any of them have a current
                    549:  * or root directory onto which the new filesystem has just been
                    550:  * mounted. If so, replace them with the new mount point.
                    551:  */
1.63      christos  552: void
1.221     thorpej   553: checkdirs(struct vnode *olddp)
1.43      mycroft   554: {
1.134     thorpej   555:        struct cwdinfo *cwdi;
1.355     ad        556:        struct vnode *newdp, *rele1, *rele2;
1.43      mycroft   557:        struct proc *p;
1.355     ad        558:        bool retry;
1.43      mycroft   559:
                    560:        if (olddp->v_usecount == 1)
                    561:                return;
1.189     thorpej   562:        if (VFS_ROOT(olddp->v_mountedhere, &newdp))
1.43      mycroft   563:                panic("mount: lost mount");
1.355     ad        564:
                    565:        do {
                    566:                retry = false;
                    567:                mutex_enter(proc_lock);
                    568:                PROCLIST_FOREACH(p, &allproc) {
                    569:                        if ((p->p_flag & PK_MARKER) != 0)
                    570:                                continue;
                    571:                        if ((cwdi = p->p_cwdi) == NULL)
                    572:                                continue;
                    573:                        /*
                    574:                         * Can't change to the old directory any more,
                    575:                         * so even if we see a stale value it's not a
                    576:                         * problem.
                    577:                         */
                    578:                        if (cwdi->cwdi_cdir != olddp &&
                    579:                            cwdi->cwdi_rdir != olddp)
                    580:                                continue;
                    581:                        retry = true;
                    582:                        rele1 = NULL;
                    583:                        rele2 = NULL;
                    584:                        atomic_inc_uint(&cwdi->cwdi_refcnt);
                    585:                        mutex_exit(proc_lock);
                    586:                        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
                    587:                        if (cwdi->cwdi_cdir == olddp) {
                    588:                                rele1 = cwdi->cwdi_cdir;
                    589:                                VREF(newdp);
                    590:                                cwdi->cwdi_cdir = newdp;
                    591:                        }
                    592:                        if (cwdi->cwdi_rdir == olddp) {
                    593:                                rele2 = cwdi->cwdi_rdir;
                    594:                                VREF(newdp);
                    595:                                cwdi->cwdi_rdir = newdp;
                    596:                        }
                    597:                        rw_exit(&cwdi->cwdi_lock);
                    598:                        cwdfree(cwdi);
                    599:                        if (rele1 != NULL)
                    600:                                vrele(rele1);
                    601:                        if (rele2 != NULL)
                    602:                                vrele(rele2);
                    603:                        mutex_enter(proc_lock);
                    604:                        break;
1.43      mycroft   605:                }
1.355     ad        606:                mutex_exit(proc_lock);
                    607:        } while (retry);
                    608:
1.43      mycroft   609:        if (rootvnode == olddp) {
                    610:                vrele(rootvnode);
                    611:                VREF(newdp);
                    612:                rootvnode = newdp;
                    613:        }
                    614:        vput(newdp);
                    615: }
                    616:
                    617: /*
1.31      cgd       618:  * Unmount a file system.
                    619:  *
                    620:  * Note: unmount takes a path to the vnode mounted on as argument,
                    621:  * not special file (as before).
                    622:  */
                    623: /* ARGSUSED */
1.63      christos  624: int
1.335     dsl       625: sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval)
1.56      thorpej   626: {
1.335     dsl       627:        /* {
1.74      cgd       628:                syscallarg(const char *) path;
1.35      cgd       629:                syscallarg(int) flags;
1.335     dsl       630:        } */
1.155     augustss  631:        struct vnode *vp;
1.31      cgd       632:        struct mount *mp;
                    633:        int error;
                    634:        struct nameidata nd;
                    635:
1.310     dsl       636:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka     637:            SCARG(uap, path));
1.63      christos  638:        if ((error = namei(&nd)) != 0)
1.31      cgd       639:                return (error);
                    640:        vp = nd.ni_vp;
1.43      mycroft   641:        mp = vp->v_mount;
1.358     ad        642:        atomic_inc_uint(&mp->mnt_refcnt);
1.345     ad        643:        VOP_UNLOCK(vp, 0);
1.31      cgd       644:
1.295     elad      645:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    646:            KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
                    647:        if (error) {
1.345     ad        648:                vrele(vp);
1.358     ad        649:                vfs_destroy(mp);
1.31      cgd       650:                return (error);
                    651:        }
                    652:
                    653:        /*
1.47      mycroft   654:         * Don't allow unmounting the root file system.
                    655:         */
                    656:        if (mp->mnt_flag & MNT_ROOTFS) {
1.345     ad        657:                vrele(vp);
1.358     ad        658:                vfs_destroy(mp);
1.47      mycroft   659:                return (EINVAL);
                    660:        }
                    661:
                    662:        /*
1.31      cgd       663:         * Must be the root of the filesystem
                    664:         */
1.329     ad        665:        if ((vp->v_vflag & VV_ROOT) == 0) {
1.345     ad        666:                vrele(vp);
1.358     ad        667:                vfs_destroy(mp);
1.31      cgd       668:                return (EINVAL);
                    669:        }
1.78      fvdl      670:
1.359     ad        671:        vrele(vp);
1.358     ad        672:        error = dounmount(mp, SCARG(uap, flags), l);
1.374     ad        673:        vfs_destroy(mp);
1.358     ad        674:        return error;
1.31      cgd       675: }
                    676:
                    677: /*
1.358     ad        678:  * Do the actual file system unmount.  File system is assumed to have
                    679:  * been locked by the caller.
                    680:  *
1.375     wiz       681:  * => Caller hold reference to the mount, explicitly for dounmount().
1.31      cgd       682:  */
1.63      christos  683: int
1.234     christos  684: dounmount(struct mount *mp, int flags, struct lwp *l)
1.31      cgd       685: {
                    686:        struct vnode *coveredvp;
                    687:        int error;
1.140     sommerfe  688:        int async;
1.162     fvdl      689:        int used_syncer;
1.31      cgd       690:
1.256     elad      691: #if NVERIEXEC > 0
1.279     elad      692:        error = veriexec_unmountchk(mp);
                    693:        if (error)
                    694:                return (error);
1.256     elad      695: #endif /* NVERIEXEC > 0 */
1.251     elad      696:
1.358     ad        697:        /*
                    698:         * XXX Freeze syncer.  Must do this before locking the
                    699:         * mount point.  See dounmount() for details.
                    700:         */
                    701:        mutex_enter(&syncer_mutex);
                    702:        rw_enter(&mp->mnt_unmounting, RW_WRITER);
                    703:        if ((mp->mnt_iflag & IMNT_GONE) != 0) {
                    704:                rw_exit(&mp->mnt_unmounting);
                    705:                mutex_exit(&syncer_mutex);
                    706:                return ENOENT;
                    707:        }
                    708:
1.162     fvdl      709:        used_syncer = (mp->mnt_syncer != NULL);
                    710:
1.148     fvdl      711:        /*
1.165     thorpej   712:         * XXX Syncer must be frozen when we get here.  This should really
                    713:         * be done on a per-mountpoint basis, but especially the softdep
1.227     jmmv      714:         * code possibly called from the syncer doesn't exactly work on a
1.165     thorpej   715:         * per-mountpoint basis, so the softdep code would become a maze
                    716:         * of vfs_busy() calls.
                    717:         *
1.300     ad        718:         * The caller of dounmount() must acquire syncer_mutex because
                    719:         * the syncer itself acquires locks in syncer_mutex -> vfs_busy
1.165     thorpej   720:         * order, and we must preserve that order to avoid deadlock.
                    721:         *
                    722:         * So, if the file system did not use the syncer, now is
1.300     ad        723:         * the time to release the syncer_mutex.
1.148     fvdl      724:         */
1.165     thorpej   725:        if (used_syncer == 0)
1.300     ad        726:                mutex_exit(&syncer_mutex);
1.148     fvdl      727:
1.196     dbj       728:        mp->mnt_iflag |= IMNT_UNMOUNT;
1.141     sommerfe  729:        async = mp->mnt_flag & MNT_ASYNC;
1.151     mycroft   730:        mp->mnt_flag &= ~MNT_ASYNC;
1.31      cgd       731:        cache_purgevfs(mp);     /* remove cache entries for this file sys */
1.160     mycroft   732:        if (mp->mnt_syncer != NULL)
                    733:                vfs_deallocate_syncvnode(mp);
1.209     hannken   734:        error = 0;
                    735:        if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1.371     hannken   736:                error = VFS_SYNC(mp, MNT_WAIT, l->l_cred);
1.209     hannken   737:        }
1.342     ad        738:        vfs_scrubvnlist(mp);
1.209     hannken   739:        if (error == 0 || (flags & MNT_FORCE))
1.332     pooka     740:                error = VFS_UNMOUNT(mp, flags);
1.31      cgd       741:        if (error) {
1.151     mycroft   742:                if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
1.148     fvdl      743:                        (void) vfs_allocate_syncvnode(mp);
1.196     dbj       744:                mp->mnt_iflag &= ~IMNT_UNMOUNT;
1.140     sommerfe  745:                mp->mnt_flag |= async;
1.358     ad        746:                rw_exit(&mp->mnt_unmounting);
1.162     fvdl      747:                if (used_syncer)
1.300     ad        748:                        mutex_exit(&syncer_mutex);
1.142     sommerfe  749:                return (error);
1.113     fvdl      750:        }
1.338     ad        751:        vfs_scrubvnlist(mp);
1.358     ad        752:        mutex_enter(&mountlist_lock);
1.297     hannken   753:        if ((coveredvp = mp->mnt_vnodecovered) != NULLVP)
1.113     fvdl      754:                coveredvp->v_mountedhere = NULL;
1.358     ad        755:        CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
                    756:        mp->mnt_iflag |= IMNT_GONE;
                    757:        mutex_exit(&mountlist_lock);
1.273     reinoud   758:        if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL)
1.113     fvdl      759:                panic("unmount: dangling vnode");
1.162     fvdl      760:        if (used_syncer)
1.300     ad        761:                mutex_exit(&syncer_mutex);
1.231     jmmv      762:        vfs_hooks_unmount(mp);
1.358     ad        763:        rw_exit(&mp->mnt_unmounting);
1.374     ad        764:        vfs_destroy(mp);        /* reference from mount() */
1.345     ad        765:        if (coveredvp != NULLVP)
                    766:                vrele(coveredvp);
1.113     fvdl      767:        return (0);
1.31      cgd       768: }
                    769:
                    770: /*
                    771:  * Sync each mounted filesystem.
                    772:  */
                    773: #ifdef DEBUG
                    774: int syncprt = 0;
                    775: struct ctldebug debug0 = { "syncprt", &syncprt };
                    776: #endif
                    777:
                    778: /* ARGSUSED */
1.63      christos  779: int
1.335     dsl       780: sys_sync(struct lwp *l, const void *v, register_t *retval)
1.31      cgd       781: {
1.155     augustss  782:        struct mount *mp, *nmp;
1.31      cgd       783:        int asyncflag;
1.257     ad        784:
                    785:        if (l == NULL)
                    786:                l = &lwp0;
1.31      cgd       787:
1.329     ad        788:        mutex_enter(&mountlist_lock);
1.353     ad        789:        for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
                    790:             mp = nmp) {
1.358     ad        791:                if (vfs_busy(mp, &nmp)) {
1.113     fvdl      792:                        continue;
                    793:                }
1.358     ad        794:                mutex_enter(&mp->mnt_updating);
1.307     hannken   795:                if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1.31      cgd       796:                        asyncflag = mp->mnt_flag & MNT_ASYNC;
                    797:                        mp->mnt_flag &= ~MNT_ASYNC;
1.332     pooka     798:                        VFS_SYNC(mp, MNT_NOWAIT, l->l_cred);
1.31      cgd       799:                        if (asyncflag)
1.113     fvdl      800:                                 mp->mnt_flag |= MNT_ASYNC;
1.31      cgd       801:                }
1.358     ad        802:                mutex_exit(&mp->mnt_updating);
1.354     ad        803:                vfs_unbusy(mp, false, &nmp);
1.31      cgd       804:        }
1.329     ad        805:        mutex_exit(&mountlist_lock);
1.31      cgd       806: #ifdef DEBUG
                    807:        if (syncprt)
                    808:                vfs_bufstats();
                    809: #endif /* DEBUG */
                    810:        return (0);
                    811: }
                    812:
                    813: /*
                    814:  * Change filesystem quotas.
                    815:  */
                    816: /* ARGSUSED */
1.63      christos  817: int
1.335     dsl       818: sys_quotactl(struct lwp *l, const struct sys_quotactl_args *uap, register_t *retval)
1.56      thorpej   819: {
1.335     dsl       820:        /* {
1.74      cgd       821:                syscallarg(const char *) path;
1.35      cgd       822:                syscallarg(int) cmd;
                    823:                syscallarg(int) uid;
1.272     christos  824:                syscallarg(void *) arg;
1.335     dsl       825:        } */
1.155     augustss  826:        struct mount *mp;
1.31      cgd       827:        int error;
                    828:        struct nameidata nd;
                    829:
1.326     pooka     830:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka     831:            SCARG(uap, path));
1.63      christos  832:        if ((error = namei(&nd)) != 0)
1.31      cgd       833:                return (error);
1.307     hannken   834:        mp = nd.ni_vp->v_mount;
1.197     hannken   835:        error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
1.332     pooka     836:            SCARG(uap, arg));
1.326     pooka     837:        vrele(nd.ni_vp);
1.197     hannken   838:        return (error);
1.31      cgd       839: }
                    840:
1.206     christos  841: int
1.234     christos  842: dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
1.185     christos  843:     int root)
                    844: {
1.234     christos  845:        struct cwdinfo *cwdi = l->l_proc->p_cwdi;
1.185     christos  846:        int error = 0;
                    847:
                    848:        /*
                    849:         * If MNT_NOWAIT or MNT_LAZY is specified, do not
1.204     dbj       850:         * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
1.185     christos  851:         * overrides MNT_NOWAIT.
                    852:         */
                    853:        if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
                    854:            (flags != MNT_WAIT && flags != 0)) {
                    855:                memcpy(sp, &mp->mnt_stat, sizeof(*sp));
                    856:                goto done;
                    857:        }
1.205     junyoung  858:
1.211     jdolecek  859:        /* Get the filesystem stats now */
                    860:        memset(sp, 0, sizeof(*sp));
1.332     pooka     861:        if ((error = VFS_STATVFS(mp, sp)) != 0) {
1.185     christos  862:                return error;
                    863:        }
                    864:
                    865:        if (cwdi->cwdi_rdir == NULL)
                    866:                (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
                    867: done:
                    868:        if (cwdi->cwdi_rdir != NULL) {
                    869:                size_t len;
                    870:                char *bp;
1.364     christos  871:                char c;
1.236     yamt      872:                char *path = PNBUF_GET();
1.185     christos  873:
                    874:                bp = path + MAXPATHLEN;
                    875:                *--bp = '\0';
1.328     ad        876:                rw_enter(&cwdi->cwdi_lock, RW_READER);
1.185     christos  877:                error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
1.234     christos  878:                    MAXPATHLEN / 2, 0, l);
1.328     ad        879:                rw_exit(&cwdi->cwdi_lock);
1.185     christos  880:                if (error) {
1.236     yamt      881:                        PNBUF_PUT(path);
1.185     christos  882:                        return error;
                    883:                }
                    884:                len = strlen(bp);
1.387     christos  885:                if (len != 1) {
                    886:                        /*
                    887:                         * for mount points that are below our root, we can see
                    888:                         * them, so we fix up the pathname and return them. The
                    889:                         * rest we cannot see, so we don't allow viewing the
                    890:                         * data.
                    891:                         */
                    892:                        if (strncmp(bp, sp->f_mntonname, len) == 0 &&
                    893:                            ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
                    894:                                (void)strlcpy(sp->f_mntonname,
1.388     enami     895:                                    c == '\0' ? "/" : &sp->f_mntonname[len],
1.187     itojun    896:                                    sizeof(sp->f_mntonname));
1.387     christos  897:                        } else {
                    898:                                if (root)
                    899:                                        (void)strlcpy(sp->f_mntonname, "/",
                    900:                                            sizeof(sp->f_mntonname));
                    901:                                else
                    902:                                        error = EPERM;
                    903:                        }
1.185     christos  904:                }
1.236     yamt      905:                PNBUF_PUT(path);
1.185     christos  906:        }
1.206     christos  907:        sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
1.185     christos  908:        return error;
                    909: }
                    910:
1.31      cgd       911: /*
1.311     dsl       912:  * Get filesystem statistics by path.
1.31      cgd       913:  */
1.311     dsl       914: int
                    915: do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb)
                    916: {
                    917:        struct mount *mp;
                    918:        int error;
                    919:        struct nameidata nd;
                    920:
1.334     pooka     921:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);
1.311     dsl       922:        if ((error = namei(&nd)) != 0)
                    923:                return error;
                    924:        mp = nd.ni_vp->v_mount;
                    925:        error = dostatvfs(mp, sb, l, flags, 1);
                    926:        vrele(nd.ni_vp);
                    927:        return error;
                    928: }
                    929:
1.31      cgd       930: /* ARGSUSED */
1.63      christos  931: int
1.335     dsl       932: sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval)
1.56      thorpej   933: {
1.335     dsl       934:        /* {
1.74      cgd       935:                syscallarg(const char *) path;
1.206     christos  936:                syscallarg(struct statvfs *) buf;
                    937:                syscallarg(int) flags;
1.335     dsl       938:        } */
1.241     yamt      939:        struct statvfs *sb;
1.31      cgd       940:        int error;
                    941:
1.241     yamt      942:        sb = STATVFSBUF_GET();
1.311     dsl       943:        error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb);
                    944:        if (error == 0)
1.241     yamt      945:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
                    946:        STATVFSBUF_PUT(sb);
                    947:        return error;
1.31      cgd       948: }
                    949:
                    950: /*
1.311     dsl       951:  * Get filesystem statistics by fd.
1.31      cgd       952:  */
1.311     dsl       953: int
                    954: do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb)
                    955: {
1.346     ad        956:        file_t *fp;
1.311     dsl       957:        struct mount *mp;
                    958:        int error;
                    959:
1.346     ad        960:        /* fd_getvnode() will use the descriptor for us */
                    961:        if ((error = fd_getvnode(fd, &fp)) != 0)
1.311     dsl       962:                return (error);
                    963:        mp = ((struct vnode *)fp->f_data)->v_mount;
1.346     ad        964:        error = dostatvfs(mp, sb, curlwp, flags, 1);
                    965:        fd_putfile(fd);
1.311     dsl       966:        return error;
                    967: }
                    968:
1.31      cgd       969: /* ARGSUSED */
1.63      christos  970: int
1.335     dsl       971: sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval)
1.56      thorpej   972: {
1.335     dsl       973:        /* {
1.35      cgd       974:                syscallarg(int) fd;
1.206     christos  975:                syscallarg(struct statvfs *) buf;
                    976:                syscallarg(int) flags;
1.335     dsl       977:        } */
1.241     yamt      978:        struct statvfs *sb;
1.31      cgd       979:        int error;
                    980:
1.241     yamt      981:        sb = STATVFSBUF_GET();
1.311     dsl       982:        error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
1.316     dsl       983:        if (error == 0)
1.311     dsl       984:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1.241     yamt      985:        STATVFSBUF_PUT(sb);
1.185     christos  986:        return error;
1.31      cgd       987: }
                    988:
1.185     christos  989:
1.31      cgd       990: /*
                    991:  * Get statistics on all filesystems.
                    992:  */
1.63      christos  993: int
1.311     dsl       994: do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags,
                    995:     int (*copyfn)(const void *, void *, size_t), size_t entry_sz,
                    996:     register_t *retval)
1.56      thorpej   997: {
1.185     christos  998:        int root = 0;
1.179     thorpej   999:        struct proc *p = l->l_proc;
1.155     augustss 1000:        struct mount *mp, *nmp;
1.241     yamt     1001:        struct statvfs *sb;
1.206     christos 1002:        size_t count, maxcount;
                   1003:        int error = 0;
1.31      cgd      1004:
1.241     yamt     1005:        sb = STATVFSBUF_GET();
1.311     dsl      1006:        maxcount = bufsize / entry_sz;
1.329     ad       1007:        mutex_enter(&mountlist_lock);
1.113     fvdl     1008:        count = 0;
1.176     matt     1009:        for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
                   1010:             mp = nmp) {
1.358     ad       1011:                if (vfs_busy(mp, &nmp)) {
1.113     fvdl     1012:                        continue;
                   1013:                }
                   1014:                if (sfsp && count < maxcount) {
1.311     dsl      1015:                        error = dostatvfs(mp, sb, l, flags, 0);
1.185     christos 1016:                        if (error) {
1.354     ad       1017:                                vfs_unbusy(mp, false, &nmp);
1.365     christos 1018:                                error = 0;
1.31      cgd      1019:                                continue;
1.113     fvdl     1020:                        }
1.311     dsl      1021:                        error = copyfn(sb, sfsp, entry_sz);
1.133     mycroft  1022:                        if (error) {
1.354     ad       1023:                                vfs_unbusy(mp, false, NULL);
1.241     yamt     1024:                                goto out;
1.133     mycroft  1025:                        }
1.311     dsl      1026:                        sfsp = (char *)sfsp + entry_sz;
1.241     yamt     1027:                        root |= strcmp(sb->f_mntonname, "/") == 0;
1.31      cgd      1028:                }
                   1029:                count++;
1.354     ad       1030:                vfs_unbusy(mp, false, &nmp);
1.31      cgd      1031:        }
1.358     ad       1032:        mutex_exit(&mountlist_lock);
1.331     pooka    1033:
1.185     christos 1034:        if (root == 0 && p->p_cwdi->cwdi_rdir) {
                   1035:                /*
                   1036:                 * fake a root entry
                   1037:                 */
1.331     pooka    1038:                error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount,
                   1039:                    sb, l, flags, 1);
1.311     dsl      1040:                if (error != 0)
1.241     yamt     1041:                        goto out;
1.365     christos 1042:                if (sfsp) {
1.311     dsl      1043:                        error = copyfn(sb, sfsp, entry_sz);
1.365     christos 1044:                        if (error != 0)
                   1045:                                goto out;
                   1046:                }
1.185     christos 1047:                count++;
                   1048:        }
1.31      cgd      1049:        if (sfsp && count > maxcount)
                   1050:                *retval = maxcount;
                   1051:        else
                   1052:                *retval = count;
1.241     yamt     1053: out:
                   1054:        STATVFSBUF_PUT(sb);
1.185     christos 1055:        return error;
1.31      cgd      1056: }
                   1057:
1.311     dsl      1058: int
1.335     dsl      1059: sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval)
1.311     dsl      1060: {
1.335     dsl      1061:        /* {
1.311     dsl      1062:                syscallarg(struct statvfs *) buf;
                   1063:                syscallarg(size_t) bufsize;
                   1064:                syscallarg(int) flags;
1.335     dsl      1065:        } */
1.311     dsl      1066:
                   1067:        return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize),
                   1068:            SCARG(uap, flags), copyout, sizeof (struct statvfs), retval);
                   1069: }
                   1070:
1.31      cgd      1071: /*
                   1072:  * Change current working directory to a given file descriptor.
                   1073:  */
                   1074: /* ARGSUSED */
1.63      christos 1075: int
1.335     dsl      1076: sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval)
1.56      thorpej  1077: {
1.335     dsl      1078:        /* {
1.35      cgd      1079:                syscallarg(int) fd;
1.335     dsl      1080:        } */
1.179     thorpej  1081:        struct proc *p = l->l_proc;
1.328     ad       1082:        struct cwdinfo *cwdi;
1.43      mycroft  1083:        struct vnode *vp, *tdp;
                   1084:        struct mount *mp;
1.346     ad       1085:        file_t *fp;
                   1086:        int error, fd;
1.31      cgd      1087:
1.346     ad       1088:        /* fd_getvnode() will use the descriptor for us */
                   1089:        fd = SCARG(uap, fd);
                   1090:        if ((error = fd_getvnode(fd, &fp)) != 0)
1.31      cgd      1091:                return (error);
1.346     ad       1092:        vp = fp->f_data;
1.131     sommerfe 1093:
1.43      mycroft  1094:        VREF(vp);
1.113     fvdl     1095:        vn_lock(vp,  LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      1096:        if (vp->v_type != VDIR)
                   1097:                error = ENOTDIR;
                   1098:        else
1.332     pooka    1099:                error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.303     pooka    1100:        if (error) {
                   1101:                vput(vp);
                   1102:                goto out;
                   1103:        }
1.304     pooka    1104:        while ((mp = vp->v_mountedhere) != NULL) {
1.358     ad       1105:                error = vfs_busy(mp, NULL);
1.298     chs      1106:                vput(vp);
1.357     xtraeme  1107:                if (error != 0)
1.356     ad       1108:                        goto out;
1.189     thorpej  1109:                error = VFS_ROOT(mp, &tdp);
1.354     ad       1110:                vfs_unbusy(mp, false, NULL);
1.113     fvdl     1111:                if (error)
1.303     pooka    1112:                        goto out;
1.43      mycroft  1113:                vp = tdp;
                   1114:        }
1.113     fvdl     1115:        VOP_UNLOCK(vp, 0);
1.131     sommerfe 1116:
                   1117:        /*
                   1118:         * Disallow changing to a directory not under the process's
                   1119:         * current root directory (if there is one).
                   1120:         */
1.328     ad       1121:        cwdi = p->p_cwdi;
                   1122:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.234     christos 1123:        if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
1.131     sommerfe 1124:                vrele(vp);
1.135     thorpej  1125:                error = EPERM;  /* operation not permitted */
1.328     ad       1126:        } else {
                   1127:                vrele(cwdi->cwdi_cdir);
                   1128:                cwdi->cwdi_cdir = vp;
1.131     sommerfe 1129:        }
1.328     ad       1130:        rw_exit(&cwdi->cwdi_lock);
1.205     junyoung 1131:
1.135     thorpej  1132:  out:
1.346     ad       1133:        fd_putfile(fd);
1.135     thorpej  1134:        return (error);
1.31      cgd      1135: }
                   1136:
                   1137: /*
1.221     thorpej  1138:  * Change this process's notion of the root directory to a given file
                   1139:  * descriptor.
1.131     sommerfe 1140:  */
                   1141: int
1.335     dsl      1142: sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
1.131     sommerfe 1143: {
1.179     thorpej  1144:        struct proc *p = l->l_proc;
1.328     ad       1145:        struct cwdinfo *cwdi;
1.131     sommerfe 1146:        struct vnode    *vp;
1.346     ad       1147:        file_t  *fp;
                   1148:        int              error, fd = SCARG(uap, fd);
1.131     sommerfe 1149:
1.268     elad     1150:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
                   1151:            KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
1.131     sommerfe 1152:                return error;
1.346     ad       1153:        /* fd_getvnode() will use the descriptor for us */
                   1154:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.131     sommerfe 1155:                return error;
1.346     ad       1156:        vp = fp->f_data;
1.131     sommerfe 1157:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   1158:        if (vp->v_type != VDIR)
                   1159:                error = ENOTDIR;
                   1160:        else
1.332     pooka    1161:                error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.131     sommerfe 1162:        VOP_UNLOCK(vp, 0);
                   1163:        if (error)
1.135     thorpej  1164:                goto out;
1.131     sommerfe 1165:        VREF(vp);
                   1166:
                   1167:        /*
                   1168:         * Prevent escaping from chroot by putting the root under
                   1169:         * the working directory.  Silently chdir to / if we aren't
                   1170:         * already there.
                   1171:         */
1.328     ad       1172:        cwdi = p->p_cwdi;
                   1173:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.234     christos 1174:        if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131     sommerfe 1175:                /*
                   1176:                 * XXX would be more failsafe to change directory to a
                   1177:                 * deadfs node here instead
                   1178:                 */
1.134     thorpej  1179:                vrele(cwdi->cwdi_cdir);
1.131     sommerfe 1180:                VREF(vp);
1.134     thorpej  1181:                cwdi->cwdi_cdir = vp;
1.131     sommerfe 1182:        }
1.205     junyoung 1183:
1.134     thorpej  1184:        if (cwdi->cwdi_rdir != NULL)
                   1185:                vrele(cwdi->cwdi_rdir);
                   1186:        cwdi->cwdi_rdir = vp;
1.328     ad       1187:        rw_exit(&cwdi->cwdi_lock);
                   1188:
1.135     thorpej  1189:  out:
1.346     ad       1190:        fd_putfile(fd);
1.135     thorpej  1191:        return (error);
1.131     sommerfe 1192: }
                   1193:
                   1194: /*
1.31      cgd      1195:  * Change current working directory (``.'').
                   1196:  */
                   1197: /* ARGSUSED */
1.63      christos 1198: int
1.335     dsl      1199: sys_chdir(struct lwp *l, const struct sys_chdir_args *uap, register_t *retval)
1.56      thorpej  1200: {
1.335     dsl      1201:        /* {
1.74      cgd      1202:                syscallarg(const char *) path;
1.335     dsl      1203:        } */
1.179     thorpej  1204:        struct proc *p = l->l_proc;
1.328     ad       1205:        struct cwdinfo *cwdi;
1.31      cgd      1206:        int error;
                   1207:        struct nameidata nd;
                   1208:
1.310     dsl      1209:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    1210:            SCARG(uap, path));
1.234     christos 1211:        if ((error = change_dir(&nd, l)) != 0)
1.31      cgd      1212:                return (error);
1.328     ad       1213:        cwdi = p->p_cwdi;
                   1214:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  1215:        vrele(cwdi->cwdi_cdir);
                   1216:        cwdi->cwdi_cdir = nd.ni_vp;
1.328     ad       1217:        rw_exit(&cwdi->cwdi_lock);
1.31      cgd      1218:        return (0);
                   1219: }
                   1220:
                   1221: /*
                   1222:  * Change notion of root (``/'') directory.
                   1223:  */
                   1224: /* ARGSUSED */
1.63      christos 1225: int
1.335     dsl      1226: sys_chroot(struct lwp *l, const struct sys_chroot_args *uap, register_t *retval)
1.56      thorpej  1227: {
1.335     dsl      1228:        /* {
1.74      cgd      1229:                syscallarg(const char *) path;
1.335     dsl      1230:        } */
1.179     thorpej  1231:        struct proc *p = l->l_proc;
1.328     ad       1232:        struct cwdinfo *cwdi;
1.131     sommerfe 1233:        struct vnode *vp;
1.31      cgd      1234:        int error;
                   1235:        struct nameidata nd;
                   1236:
1.268     elad     1237:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
                   1238:            KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
1.31      cgd      1239:                return (error);
1.310     dsl      1240:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    1241:            SCARG(uap, path));
1.234     christos 1242:        if ((error = change_dir(&nd, l)) != 0)
1.31      cgd      1243:                return (error);
1.328     ad       1244:
                   1245:        cwdi = p->p_cwdi;
                   1246:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  1247:        if (cwdi->cwdi_rdir != NULL)
                   1248:                vrele(cwdi->cwdi_rdir);
1.131     sommerfe 1249:        vp = nd.ni_vp;
1.134     thorpej  1250:        cwdi->cwdi_rdir = vp;
1.131     sommerfe 1251:
                   1252:        /*
                   1253:         * Prevent escaping from chroot by putting the root under
                   1254:         * the working directory.  Silently chdir to / if we aren't
                   1255:         * already there.
                   1256:         */
1.234     christos 1257:        if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131     sommerfe 1258:                /*
                   1259:                 * XXX would be more failsafe to change directory to a
                   1260:                 * deadfs node here instead
                   1261:                 */
1.134     thorpej  1262:                vrele(cwdi->cwdi_cdir);
1.131     sommerfe 1263:                VREF(vp);
1.134     thorpej  1264:                cwdi->cwdi_cdir = vp;
1.131     sommerfe 1265:        }
1.328     ad       1266:        rw_exit(&cwdi->cwdi_lock);
1.205     junyoung 1267:
1.31      cgd      1268:        return (0);
                   1269: }
                   1270:
                   1271: /*
                   1272:  * Common routine for chroot and chdir.
                   1273:  */
                   1274: static int
1.234     christos 1275: change_dir(struct nameidata *ndp, struct lwp *l)
1.31      cgd      1276: {
                   1277:        struct vnode *vp;
                   1278:        int error;
                   1279:
1.63      christos 1280:        if ((error = namei(ndp)) != 0)
1.31      cgd      1281:                return (error);
                   1282:        vp = ndp->ni_vp;
                   1283:        if (vp->v_type != VDIR)
                   1284:                error = ENOTDIR;
                   1285:        else
1.332     pooka    1286:                error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.205     junyoung 1287:
1.31      cgd      1288:        if (error)
1.113     fvdl     1289:                vput(vp);
                   1290:        else
                   1291:                VOP_UNLOCK(vp, 0);
1.31      cgd      1292:        return (error);
                   1293: }
                   1294:
                   1295: /*
                   1296:  * Check permissions, allocate an open file structure,
                   1297:  * and call the device open routine if any.
                   1298:  */
1.63      christos 1299: int
1.335     dsl      1300: sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval)
1.56      thorpej  1301: {
1.335     dsl      1302:        /* {
1.74      cgd      1303:                syscallarg(const char *) path;
1.35      cgd      1304:                syscallarg(int) flags;
                   1305:                syscallarg(int) mode;
1.335     dsl      1306:        } */
1.179     thorpej  1307:        struct proc *p = l->l_proc;
1.134     thorpej  1308:        struct cwdinfo *cwdi = p->p_cwdi;
1.346     ad       1309:        file_t *fp;
1.135     thorpej  1310:        struct vnode *vp;
1.31      cgd      1311:        int flags, cmode;
                   1312:        int type, indx, error;
                   1313:        struct flock lf;
                   1314:        struct nameidata nd;
                   1315:
1.104     mycroft  1316:        flags = FFLAGS(SCARG(uap, flags));
                   1317:        if ((flags & (FREAD | FWRITE)) == 0)
                   1318:                return (EINVAL);
1.346     ad       1319:        if ((error = fd_allocfile(&fp, &indx)) != 0)
1.31      cgd      1320:                return (error);
1.328     ad       1321:        /* We're going to read cwdi->cwdi_cmask unlocked here. */
1.134     thorpej  1322:        cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1.331     pooka    1323:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    1324:            SCARG(uap, path));
1.194     jdolecek 1325:        l->l_dupfd = -indx - 1;                 /* XXX check for fdopen */
1.63      christos 1326:        if ((error = vn_open(&nd, flags, cmode)) != 0) {
1.346     ad       1327:                fd_abort(p, fp, indx);
1.213     christos 1328:                if ((error == EDUPFD || error == EMOVEFD) &&
1.194     jdolecek 1329:                    l->l_dupfd >= 0 &&                  /* XXX from fdopen */
1.45      mycroft  1330:                    (error =
1.346     ad       1331:                        fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) {
1.45      mycroft  1332:                        *retval = indx;
                   1333:                        return (0);
                   1334:                }
                   1335:                if (error == ERESTART)
1.44      mycroft  1336:                        error = EINTR;
1.31      cgd      1337:                return (error);
                   1338:        }
1.331     pooka    1339:
1.194     jdolecek 1340:        l->l_dupfd = 0;
1.31      cgd      1341:        vp = nd.ni_vp;
                   1342:        fp->f_flag = flags & FMASK;
                   1343:        fp->f_type = DTYPE_VNODE;
                   1344:        fp->f_ops = &vnops;
1.184     dsl      1345:        fp->f_data = vp;
1.31      cgd      1346:        if (flags & (O_EXLOCK | O_SHLOCK)) {
                   1347:                lf.l_whence = SEEK_SET;
                   1348:                lf.l_start = 0;
                   1349:                lf.l_len = 0;
                   1350:                if (flags & O_EXLOCK)
                   1351:                        lf.l_type = F_WRLCK;
                   1352:                else
                   1353:                        lf.l_type = F_RDLCK;
                   1354:                type = F_FLOCK;
                   1355:                if ((flags & FNONBLOCK) == 0)
                   1356:                        type |= F_WAIT;
1.113     fvdl     1357:                VOP_UNLOCK(vp, 0);
1.184     dsl      1358:                error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1.63      christos 1359:                if (error) {
1.346     ad       1360:                        (void) vn_close(vp, fp->f_flag, fp->f_cred);
                   1361:                        fd_abort(p, fp, indx);
1.31      cgd      1362:                        return (error);
                   1363:                }
1.113     fvdl     1364:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.346     ad       1365:                atomic_or_uint(&fp->f_flag, FHASLOCK);
1.31      cgd      1366:        }
1.113     fvdl     1367:        VOP_UNLOCK(vp, 0);
1.31      cgd      1368:        *retval = indx;
1.346     ad       1369:        fd_affix(p, fp, indx);
1.31      cgd      1370:        return (0);
1.137     wrstuden 1371: }
                   1372:
1.249     yamt     1373: static void
                   1374: vfs__fhfree(fhandle_t *fhp)
                   1375: {
                   1376:        size_t fhsize;
                   1377:
                   1378:        if (fhp == NULL) {
                   1379:                return;
                   1380:        }
                   1381:        fhsize = FHANDLE_SIZE(fhp);
                   1382:        kmem_free(fhp, fhsize);
                   1383: }
                   1384:
1.137     wrstuden 1385: /*
1.243     yamt     1386:  * vfs_composefh: compose a filehandle.
                   1387:  */
                   1388:
                   1389: int
1.244     martin   1390: vfs_composefh(struct vnode *vp, fhandle_t *fhp, size_t *fh_size)
1.243     yamt     1391: {
                   1392:        struct mount *mp;
1.250     yamt     1393:        struct fid *fidp;
1.243     yamt     1394:        int error;
1.250     yamt     1395:        size_t needfhsize;
                   1396:        size_t fidsize;
1.243     yamt     1397:
                   1398:        mp = vp->v_mount;
1.250     yamt     1399:        fidp = NULL;
1.252     martin   1400:        if (*fh_size < FHANDLE_SIZE_MIN) {
1.250     yamt     1401:                fidsize = 0;
1.244     martin   1402:        } else {
1.250     yamt     1403:                fidsize = *fh_size - offsetof(fhandle_t, fh_fid);
                   1404:                if (fhp != NULL) {
                   1405:                        memset(fhp, 0, *fh_size);
                   1406:                        fhp->fh_fsid = mp->mnt_stat.f_fsidx;
                   1407:                        fidp = &fhp->fh_fid;
                   1408:                }
1.244     martin   1409:        }
1.250     yamt     1410:        error = VFS_VPTOFH(vp, fidp, &fidsize);
                   1411:        needfhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
                   1412:        if (error == 0 && *fh_size < needfhsize) {
                   1413:                error = E2BIG;
                   1414:        }
                   1415:        *fh_size = needfhsize;
1.243     yamt     1416:        return error;
                   1417: }
                   1418:
1.249     yamt     1419: int
                   1420: vfs_composefh_alloc(struct vnode *vp, fhandle_t **fhpp)
                   1421: {
                   1422:        struct mount *mp;
                   1423:        fhandle_t *fhp;
                   1424:        size_t fhsize;
                   1425:        size_t fidsize;
                   1426:        int error;
                   1427:
                   1428:        *fhpp = NULL;
                   1429:        mp = vp->v_mount;
1.255     christos 1430:        fidsize = 0;
1.249     yamt     1431:        error = VFS_VPTOFH(vp, NULL, &fidsize);
                   1432:        KASSERT(error != 0);
                   1433:        if (error != E2BIG) {
                   1434:                goto out;
                   1435:        }
1.250     yamt     1436:        fhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1.249     yamt     1437:        fhp = kmem_zalloc(fhsize, KM_SLEEP);
                   1438:        if (fhp == NULL) {
                   1439:                error = ENOMEM;
                   1440:                goto out;
                   1441:        }
                   1442:        fhp->fh_fsid = mp->mnt_stat.f_fsidx;
                   1443:        error = VFS_VPTOFH(vp, &fhp->fh_fid, &fidsize);
                   1444:        if (error == 0) {
                   1445:                KASSERT((FHANDLE_SIZE(fhp) == fhsize &&
                   1446:                    FHANDLE_FILEID(fhp)->fid_len == fidsize));
                   1447:                *fhpp = fhp;
                   1448:        } else {
                   1449:                kmem_free(fhp, fhsize);
                   1450:        }
                   1451: out:
                   1452:        return error;
                   1453: }
                   1454:
                   1455: void
                   1456: vfs_composefh_free(fhandle_t *fhp)
                   1457: {
                   1458:
                   1459:        vfs__fhfree(fhp);
                   1460: }
                   1461:
1.243     yamt     1462: /*
1.248     yamt     1463:  * vfs_fhtovp: lookup a vnode by a filehandle.
                   1464:  */
                   1465:
                   1466: int
                   1467: vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp)
                   1468: {
                   1469:        struct mount *mp;
                   1470:        int error;
                   1471:
                   1472:        *vpp = NULL;
                   1473:        mp = vfs_getvfs(FHANDLE_FSID(fhp));
                   1474:        if (mp == NULL) {
                   1475:                error = ESTALE;
                   1476:                goto out;
                   1477:        }
                   1478:        if (mp->mnt_op->vfs_fhtovp == NULL) {
                   1479:                error = EOPNOTSUPP;
                   1480:                goto out;
                   1481:        }
                   1482:        error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp);
                   1483: out:
                   1484:        return error;
                   1485: }
                   1486:
                   1487: /*
1.265     yamt     1488:  * vfs_copyinfh_alloc: allocate and copyin a filehandle, given
1.263     martin   1489:  * the needed size.
                   1490:  */
                   1491:
                   1492: int
1.265     yamt     1493: vfs_copyinfh_alloc(const void *ufhp, size_t fhsize, fhandle_t **fhpp)
1.263     martin   1494: {
                   1495:        fhandle_t *fhp;
                   1496:        int error;
                   1497:
                   1498:        *fhpp = NULL;
1.250     yamt     1499:        if (fhsize > FHANDLE_SIZE_MAX) {
                   1500:                return EINVAL;
                   1501:        }
1.265     yamt     1502:        if (fhsize < FHANDLE_SIZE_MIN) {
                   1503:                return EINVAL;
                   1504:        }
1.267     yamt     1505: again:
1.248     yamt     1506:        fhp = kmem_alloc(fhsize, KM_SLEEP);
                   1507:        if (fhp == NULL) {
                   1508:                return ENOMEM;
                   1509:        }
                   1510:        error = copyin(ufhp, fhp, fhsize);
                   1511:        if (error == 0) {
1.265     yamt     1512:                /* XXX this check shouldn't be here */
                   1513:                if (FHANDLE_SIZE(fhp) == fhsize) {
1.263     martin   1514:                        *fhpp = fhp;
                   1515:                        return 0;
1.267     yamt     1516:                } else if (fhsize == NFSX_V2FH && FHANDLE_SIZE(fhp) < fhsize) {
                   1517:                        /*
                   1518:                         * a kludge for nfsv2 padded handles.
                   1519:                         */
                   1520:                        size_t sz;
                   1521:
                   1522:                        sz = FHANDLE_SIZE(fhp);
                   1523:                        kmem_free(fhp, fhsize);
                   1524:                        fhsize = sz;
                   1525:                        goto again;
1.264     yamt     1526:                } else {
1.265     yamt     1527:                        /*
                   1528:                         * userland told us wrong size.
                   1529:                         */
1.263     martin   1530:                        error = EINVAL;
1.264     yamt     1531:                }
1.248     yamt     1532:        }
1.263     martin   1533:        kmem_free(fhp, fhsize);
1.248     yamt     1534:        return error;
                   1535: }
                   1536:
                   1537: void
                   1538: vfs_copyinfh_free(fhandle_t *fhp)
                   1539: {
                   1540:
1.249     yamt     1541:        vfs__fhfree(fhp);
1.248     yamt     1542: }
                   1543:
                   1544: /*
1.137     wrstuden 1545:  * Get file handle system call
                   1546:  */
                   1547: int
1.335     dsl      1548: sys___getfh30(struct lwp *l, const struct sys___getfh30_args *uap, register_t *retval)
1.137     wrstuden 1549: {
1.335     dsl      1550:        /* {
1.137     wrstuden 1551:                syscallarg(char *) fname;
                   1552:                syscallarg(fhandle_t *) fhp;
1.244     martin   1553:                syscallarg(size_t *) fh_size;
1.335     dsl      1554:        } */
1.155     augustss 1555:        struct vnode *vp;
1.244     martin   1556:        fhandle_t *fh;
1.137     wrstuden 1557:        int error;
                   1558:        struct nameidata nd;
1.244     martin   1559:        size_t sz;
1.249     yamt     1560:        size_t usz;
1.137     wrstuden 1561:
                   1562:        /*
                   1563:         * Must be super user
                   1564:         */
1.268     elad     1565:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
                   1566:            0, NULL, NULL, NULL);
1.137     wrstuden 1567:        if (error)
                   1568:                return (error);
1.310     dsl      1569:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    1570:            SCARG(uap, fname));
1.137     wrstuden 1571:        error = namei(&nd);
                   1572:        if (error)
                   1573:                return (error);
                   1574:        vp = nd.ni_vp;
1.249     yamt     1575:        error = vfs_composefh_alloc(vp, &fh);
1.247     yamt     1576:        vput(vp);
1.249     yamt     1577:        if (error != 0) {
                   1578:                goto out;
                   1579:        }
                   1580:        error = copyin(SCARG(uap, fh_size), &usz, sizeof(size_t));
                   1581:        if (error != 0) {
                   1582:                goto out;
                   1583:        }
                   1584:        sz = FHANDLE_SIZE(fh);
                   1585:        error = copyout(&sz, SCARG(uap, fh_size), sizeof(size_t));
                   1586:        if (error != 0) {
                   1587:                goto out;
1.244     martin   1588:        }
1.249     yamt     1589:        if (usz >= sz) {
                   1590:                error = copyout(fh, SCARG(uap, fhp), sz);
                   1591:        } else {
                   1592:                error = E2BIG;
1.244     martin   1593:        }
1.249     yamt     1594: out:
                   1595:        vfs_composefh_free(fh);
1.137     wrstuden 1596:        return (error);
                   1597: }
                   1598:
                   1599: /*
                   1600:  * Open a file given a file handle.
                   1601:  *
                   1602:  * Check permissions, allocate an open file structure,
                   1603:  * and call the device open routine if any.
                   1604:  */
1.265     yamt     1605:
1.137     wrstuden 1606: int
1.265     yamt     1607: dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags,
                   1608:     register_t *retval)
1.137     wrstuden 1609: {
1.346     ad       1610:        file_t *fp;
1.139     wrstuden 1611:        struct vnode *vp = NULL;
1.257     ad       1612:        kauth_cred_t cred = l->l_cred;
1.346     ad       1613:        file_t *nfp;
1.137     wrstuden 1614:        int type, indx, error=0;
                   1615:        struct flock lf;
                   1616:        struct vattr va;
1.248     yamt     1617:        fhandle_t *fh;
1.265     yamt     1618:        int flags;
1.346     ad       1619:        proc_t *p;
                   1620:
                   1621:        p = curproc;
1.137     wrstuden 1622:
                   1623:        /*
                   1624:         * Must be super user
                   1625:         */
1.269     elad     1626:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     1627:            0, NULL, NULL, NULL)))
1.137     wrstuden 1628:                return (error);
                   1629:
1.265     yamt     1630:        flags = FFLAGS(oflags);
1.137     wrstuden 1631:        if ((flags & (FREAD | FWRITE)) == 0)
                   1632:                return (EINVAL);
                   1633:        if ((flags & O_CREAT))
                   1634:                return (EINVAL);
1.346     ad       1635:        if ((error = fd_allocfile(&nfp, &indx)) != 0)
1.137     wrstuden 1636:                return (error);
                   1637:        fp = nfp;
1.265     yamt     1638:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248     yamt     1639:        if (error != 0) {
1.139     wrstuden 1640:                goto bad;
                   1641:        }
1.248     yamt     1642:        error = vfs_fhtovp(fh, &vp);
                   1643:        if (error != 0) {
1.139     wrstuden 1644:                goto bad;
                   1645:        }
1.137     wrstuden 1646:
                   1647:        /* Now do an effective vn_open */
                   1648:
                   1649:        if (vp->v_type == VSOCK) {
                   1650:                error = EOPNOTSUPP;
                   1651:                goto bad;
                   1652:        }
1.333     yamt     1653:        error = vn_openchk(vp, cred, flags);
                   1654:        if (error != 0)
                   1655:                goto bad;
1.137     wrstuden 1656:        if (flags & O_TRUNC) {
                   1657:                VOP_UNLOCK(vp, 0);                      /* XXX */
                   1658:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */
                   1659:                VATTR_NULL(&va);
                   1660:                va.va_size = 0;
1.332     pooka    1661:                error = VOP_SETATTR(vp, &va, cred);
1.197     hannken  1662:                if (error)
1.137     wrstuden 1663:                        goto bad;
                   1664:        }
1.332     pooka    1665:        if ((error = VOP_OPEN(vp, flags, cred)) != 0)
1.137     wrstuden 1666:                goto bad;
1.346     ad       1667:        if (flags & FWRITE) {
                   1668:                mutex_enter(&vp->v_interlock);
1.137     wrstuden 1669:                vp->v_writecount++;
1.346     ad       1670:                mutex_exit(&vp->v_interlock);
                   1671:        }
1.137     wrstuden 1672:
                   1673:        /* done with modified vn_open, now finish what sys_open does. */
                   1674:
                   1675:        fp->f_flag = flags & FMASK;
                   1676:        fp->f_type = DTYPE_VNODE;
                   1677:        fp->f_ops = &vnops;
1.184     dsl      1678:        fp->f_data = vp;
1.137     wrstuden 1679:        if (flags & (O_EXLOCK | O_SHLOCK)) {
                   1680:                lf.l_whence = SEEK_SET;
                   1681:                lf.l_start = 0;
                   1682:                lf.l_len = 0;
                   1683:                if (flags & O_EXLOCK)
                   1684:                        lf.l_type = F_WRLCK;
                   1685:                else
                   1686:                        lf.l_type = F_RDLCK;
                   1687:                type = F_FLOCK;
                   1688:                if ((flags & FNONBLOCK) == 0)
                   1689:                        type |= F_WAIT;
                   1690:                VOP_UNLOCK(vp, 0);
1.184     dsl      1691:                error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1.137     wrstuden 1692:                if (error) {
1.346     ad       1693:                        (void) vn_close(vp, fp->f_flag, fp->f_cred);
                   1694:                        fd_abort(p, fp, indx);
1.137     wrstuden 1695:                        return (error);
                   1696:                }
                   1697:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.346     ad       1698:                atomic_or_uint(&fp->f_flag, FHASLOCK);
1.137     wrstuden 1699:        }
                   1700:        VOP_UNLOCK(vp, 0);
                   1701:        *retval = indx;
1.346     ad       1702:        fd_affix(p, fp, indx);
1.248     yamt     1703:        vfs_copyinfh_free(fh);
1.137     wrstuden 1704:        return (0);
1.139     wrstuden 1705:
1.137     wrstuden 1706: bad:
1.346     ad       1707:        fd_abort(p, fp, indx);
1.139     wrstuden 1708:        if (vp != NULL)
                   1709:                vput(vp);
1.248     yamt     1710:        vfs_copyinfh_free(fh);
1.137     wrstuden 1711:        return (error);
                   1712: }
                   1713:
                   1714: int
1.335     dsl      1715: sys___fhopen40(struct lwp *l, const struct sys___fhopen40_args *uap, register_t *retval)
1.137     wrstuden 1716: {
1.335     dsl      1717:        /* {
1.263     martin   1718:                syscallarg(const void *) fhp;
                   1719:                syscallarg(size_t) fh_size;
1.265     yamt     1720:                syscallarg(int) flags;
1.335     dsl      1721:        } */
1.265     yamt     1722:
                   1723:        return dofhopen(l, SCARG(uap, fhp), SCARG(uap, fh_size),
                   1724:            SCARG(uap, flags), retval);
                   1725: }
                   1726:
1.306     dsl      1727: int
                   1728: do_fhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sb)
                   1729: {
1.137     wrstuden 1730:        int error;
1.248     yamt     1731:        fhandle_t *fh;
1.137     wrstuden 1732:        struct vnode *vp;
                   1733:
                   1734:        /*
                   1735:         * Must be super user
                   1736:         */
1.268     elad     1737:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     1738:            0, NULL, NULL, NULL)))
1.137     wrstuden 1739:                return (error);
                   1740:
1.265     yamt     1741:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306     dsl      1742:        if (error != 0)
                   1743:                return error;
                   1744:
1.248     yamt     1745:        error = vfs_fhtovp(fh, &vp);
1.306     dsl      1746:        vfs_copyinfh_free(fh);
                   1747:        if (error != 0)
                   1748:                return error;
                   1749:
1.346     ad       1750:        error = vn_stat(vp, sb);
1.137     wrstuden 1751:        vput(vp);
1.248     yamt     1752:        return error;
1.137     wrstuden 1753: }
                   1754:
1.265     yamt     1755:
1.137     wrstuden 1756: /* ARGSUSED */
                   1757: int
1.383     christos 1758: sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval)
1.137     wrstuden 1759: {
1.335     dsl      1760:        /* {
1.265     yamt     1761:                syscallarg(const void *) fhp;
1.263     martin   1762:                syscallarg(size_t) fh_size;
1.265     yamt     1763:                syscallarg(struct stat *) sb;
1.335     dsl      1764:        } */
1.306     dsl      1765:        struct stat sb;
                   1766:        int error;
1.265     yamt     1767:
1.306     dsl      1768:        error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb);
                   1769:        if (error)
                   1770:                return error;
                   1771:        return copyout(&sb, SCARG(uap, sb), sizeof(sb));
1.265     yamt     1772: }
                   1773:
1.306     dsl      1774: int
                   1775: do_fhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *sb,
                   1776:     int flags)
                   1777: {
1.248     yamt     1778:        fhandle_t *fh;
1.137     wrstuden 1779:        struct mount *mp;
                   1780:        struct vnode *vp;
                   1781:        int error;
                   1782:
                   1783:        /*
                   1784:         * Must be super user
                   1785:         */
1.268     elad     1786:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     1787:            0, NULL, NULL, NULL)))
1.206     christos 1788:                return error;
1.137     wrstuden 1789:
1.265     yamt     1790:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306     dsl      1791:        if (error != 0)
                   1792:                return error;
                   1793:
1.248     yamt     1794:        error = vfs_fhtovp(fh, &vp);
1.306     dsl      1795:        vfs_copyinfh_free(fh);
                   1796:        if (error != 0)
                   1797:                return error;
                   1798:
1.137     wrstuden 1799:        mp = vp->v_mount;
1.306     dsl      1800:        error = dostatvfs(mp, sb, l, flags, 1);
1.137     wrstuden 1801:        vput(vp);
1.241     yamt     1802:        return error;
1.31      cgd      1803: }
                   1804:
1.265     yamt     1805: /* ARGSUSED */
                   1806: int
1.335     dsl      1807: sys___fhstatvfs140(struct lwp *l, const struct sys___fhstatvfs140_args *uap, register_t *retval)
1.265     yamt     1808: {
1.335     dsl      1809:        /* {
1.266     yamt     1810:                syscallarg(const void *) fhp;
1.265     yamt     1811:                syscallarg(size_t) fh_size;
                   1812:                syscallarg(struct statvfs *) buf;
                   1813:                syscallarg(int) flags;
1.335     dsl      1814:        } */
1.306     dsl      1815:        struct statvfs *sb = STATVFSBUF_GET();
                   1816:        int error;
1.265     yamt     1817:
1.306     dsl      1818:        error = do_fhstatvfs(l, SCARG(uap, fhp), SCARG(uap, fh_size), sb,
                   1819:            SCARG(uap, flags));
                   1820:        if (error == 0)
                   1821:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
                   1822:        STATVFSBUF_PUT(sb);
                   1823:        return error;
1.265     yamt     1824: }
                   1825:
1.31      cgd      1826: /*
                   1827:  * Create a special file.
                   1828:  */
                   1829: /* ARGSUSED */
1.63      christos 1830: int
1.383     christos 1831: sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap,
                   1832:     register_t *retval)
1.56      thorpej  1833: {
1.335     dsl      1834:        /* {
1.74      cgd      1835:                syscallarg(const char *) path;
1.383     christos 1836:                syscallarg(mode_t) mode;
                   1837:                syscallarg(dev_t) dev;
1.335     dsl      1838:        } */
1.383     christos 1839:        return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode),
                   1840:            SCARG(uap, dev), retval);
                   1841: }
                   1842:
                   1843: int
                   1844: do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev,
                   1845:     register_t *retval)
                   1846: {
1.179     thorpej  1847:        struct proc *p = l->l_proc;
1.155     augustss 1848:        struct vnode *vp;
1.31      cgd      1849:        struct vattr vattr;
1.301     pooka    1850:        int error, optype;
1.315     christos 1851:        struct nameidata nd;
1.314     christos 1852:        char *path;
1.315     christos 1853:        const char *cpath;
                   1854:        enum uio_seg seg = UIO_USERSPACE;
1.31      cgd      1855:
1.268     elad     1856:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
                   1857:            0, NULL, NULL, NULL)) != 0)
1.31      cgd      1858:                return (error);
1.301     pooka    1859:
                   1860:        optype = VOP_MKNOD_DESCOFFSET;
1.315     christos 1861:
1.383     christos 1862:        VERIEXEC_PATH_GET(pathname, seg, cpath, path);
1.334     pooka    1863:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, cpath);
1.315     christos 1864:
1.63      christos 1865:        if ((error = namei(&nd)) != 0)
1.314     christos 1866:                goto out;
1.31      cgd      1867:        vp = nd.ni_vp;
1.43      mycroft  1868:        if (vp != NULL)
1.31      cgd      1869:                error = EEXIST;
1.43      mycroft  1870:        else {
                   1871:                VATTR_NULL(&vattr);
1.328     ad       1872:                /* We will read cwdi->cwdi_cmask unlocked. */
1.383     christos 1873:                vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
                   1874:                vattr.va_rdev = dev;
1.43      mycroft  1875:
1.383     christos 1876:                switch (mode & S_IFMT) {
1.43      mycroft  1877:                case S_IFMT:    /* used by badsect to flag bad sectors */
                   1878:                        vattr.va_type = VBAD;
                   1879:                        break;
                   1880:                case S_IFCHR:
                   1881:                        vattr.va_type = VCHR;
                   1882:                        break;
                   1883:                case S_IFBLK:
                   1884:                        vattr.va_type = VBLK;
                   1885:                        break;
                   1886:                case S_IFWHT:
1.301     pooka    1887:                        optype = VOP_WHITEOUT_DESCOFFSET;
                   1888:                        break;
                   1889:                case S_IFREG:
1.314     christos 1890: #if NVERIEXEC > 0
                   1891:                        error = veriexec_openchk(l, nd.ni_vp, nd.ni_dirp,
                   1892:                            O_CREAT);
                   1893: #endif /* NVERIEXEC > 0 */
1.301     pooka    1894:                        vattr.va_type = VREG;
1.302     pooka    1895:                        vattr.va_rdev = VNOVAL;
1.301     pooka    1896:                        optype = VOP_CREATE_DESCOFFSET;
1.43      mycroft  1897:                        break;
                   1898:                default:
                   1899:                        error = EINVAL;
                   1900:                        break;
                   1901:                }
1.31      cgd      1902:        }
1.43      mycroft  1903:        if (!error) {
1.301     pooka    1904:                switch (optype) {
                   1905:                case VOP_WHITEOUT_DESCOFFSET:
1.43      mycroft  1906:                        error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
                   1907:                        if (error)
                   1908:                                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1909:                        vput(nd.ni_dvp);
1.301     pooka    1910:                        break;
                   1911:
                   1912:                case VOP_MKNOD_DESCOFFSET:
1.43      mycroft  1913:                        error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
                   1914:                                                &nd.ni_cnd, &vattr);
1.168     assar    1915:                        if (error == 0)
                   1916:                                vput(nd.ni_vp);
1.301     pooka    1917:                        break;
                   1918:
                   1919:                case VOP_CREATE_DESCOFFSET:
                   1920:                        error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp,
                   1921:                                                &nd.ni_cnd, &vattr);
                   1922:                        if (error == 0)
                   1923:                                vput(nd.ni_vp);
                   1924:                        break;
1.43      mycroft  1925:                }
                   1926:        } else {
                   1927:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1928:                if (nd.ni_dvp == vp)
                   1929:                        vrele(nd.ni_dvp);
                   1930:                else
                   1931:                        vput(nd.ni_dvp);
                   1932:                if (vp)
                   1933:                        vrele(vp);
1.31      cgd      1934:        }
1.314     christos 1935: out:
1.315     christos 1936:        VERIEXEC_PATH_PUT(path);
1.31      cgd      1937:        return (error);
                   1938: }
                   1939:
                   1940: /*
                   1941:  * Create a named pipe.
                   1942:  */
                   1943: /* ARGSUSED */
1.63      christos 1944: int
1.335     dsl      1945: sys_mkfifo(struct lwp *l, const struct sys_mkfifo_args *uap, register_t *retval)
1.56      thorpej  1946: {
1.335     dsl      1947:        /* {
1.74      cgd      1948:                syscallarg(const char *) path;
1.35      cgd      1949:                syscallarg(int) mode;
1.335     dsl      1950:        } */
1.179     thorpej  1951:        struct proc *p = l->l_proc;
1.31      cgd      1952:        struct vattr vattr;
                   1953:        int error;
                   1954:        struct nameidata nd;
                   1955:
1.334     pooka    1956:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,
                   1957:            SCARG(uap, path));
1.63      christos 1958:        if ((error = namei(&nd)) != 0)
1.31      cgd      1959:                return (error);
                   1960:        if (nd.ni_vp != NULL) {
                   1961:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1962:                if (nd.ni_dvp == nd.ni_vp)
                   1963:                        vrele(nd.ni_dvp);
                   1964:                else
                   1965:                        vput(nd.ni_dvp);
                   1966:                vrele(nd.ni_vp);
                   1967:                return (EEXIST);
                   1968:        }
                   1969:        VATTR_NULL(&vattr);
                   1970:        vattr.va_type = VFIFO;
1.328     ad       1971:        /* We will read cwdi->cwdi_cmask unlocked. */
1.134     thorpej  1972:        vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1.168     assar    1973:        error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
                   1974:        if (error == 0)
                   1975:                vput(nd.ni_vp);
                   1976:        return (error);
1.31      cgd      1977: }
                   1978:
                   1979: /*
                   1980:  * Make a hard file link.
                   1981:  */
                   1982: /* ARGSUSED */
1.63      christos 1983: int
1.335     dsl      1984: sys_link(struct lwp *l, const struct sys_link_args *uap, register_t *retval)
1.56      thorpej  1985: {
1.335     dsl      1986:        /* {
1.74      cgd      1987:                syscallarg(const char *) path;
                   1988:                syscallarg(const char *) link;
1.335     dsl      1989:        } */
1.155     augustss 1990:        struct vnode *vp;
1.31      cgd      1991:        struct nameidata nd;
                   1992:        int error;
                   1993:
1.331     pooka    1994:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    1995:            SCARG(uap, path));
1.63      christos 1996:        if ((error = namei(&nd)) != 0)
1.31      cgd      1997:                return (error);
                   1998:        vp = nd.ni_vp;
1.331     pooka    1999:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2000:            SCARG(uap, link));
1.66      mycroft  2001:        if ((error = namei(&nd)) != 0)
                   2002:                goto out;
                   2003:        if (nd.ni_vp) {
                   2004:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2005:                if (nd.ni_dvp == nd.ni_vp)
                   2006:                        vrele(nd.ni_dvp);
                   2007:                else
                   2008:                        vput(nd.ni_dvp);
                   2009:                vrele(nd.ni_vp);
                   2010:                error = EEXIST;
                   2011:                goto out;
1.31      cgd      2012:        }
1.66      mycroft  2013:        error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
                   2014: out:
1.31      cgd      2015:        vrele(vp);
                   2016:        return (error);
                   2017: }
                   2018:
                   2019: /*
                   2020:  * Make a symbolic link.
                   2021:  */
                   2022: /* ARGSUSED */
1.63      christos 2023: int
1.335     dsl      2024: sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)
1.56      thorpej  2025: {
1.335     dsl      2026:        /* {
1.74      cgd      2027:                syscallarg(const char *) path;
                   2028:                syscallarg(const char *) link;
1.335     dsl      2029:        } */
1.179     thorpej  2030:        struct proc *p = l->l_proc;
1.31      cgd      2031:        struct vattr vattr;
                   2032:        char *path;
                   2033:        int error;
                   2034:        struct nameidata nd;
                   2035:
1.161     thorpej  2036:        path = PNBUF_GET();
1.63      christos 2037:        error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
                   2038:        if (error)
1.43      mycroft  2039:                goto out;
1.331     pooka    2040:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2041:            SCARG(uap, link));
1.63      christos 2042:        if ((error = namei(&nd)) != 0)
1.43      mycroft  2043:                goto out;
1.31      cgd      2044:        if (nd.ni_vp) {
                   2045:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2046:                if (nd.ni_dvp == nd.ni_vp)
                   2047:                        vrele(nd.ni_dvp);
                   2048:                else
                   2049:                        vput(nd.ni_dvp);
                   2050:                vrele(nd.ni_vp);
                   2051:                error = EEXIST;
1.43      mycroft  2052:                goto out;
1.31      cgd      2053:        }
                   2054:        VATTR_NULL(&vattr);
1.230     jmmv     2055:        vattr.va_type = VLNK;
1.328     ad       2056:        /* We will read cwdi->cwdi_cmask unlocked. */
1.134     thorpej  2057:        vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1.31      cgd      2058:        error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1.168     assar    2059:        if (error == 0)
                   2060:                vput(nd.ni_vp);
1.43      mycroft  2061: out:
1.161     thorpej  2062:        PNBUF_PUT(path);
1.31      cgd      2063:        return (error);
                   2064: }
                   2065:
                   2066: /*
1.43      mycroft  2067:  * Delete a whiteout from the filesystem.
                   2068:  */
                   2069: /* ARGSUSED */
1.63      christos 2070: int
1.335     dsl      2071: sys_undelete(struct lwp *l, const struct sys_undelete_args *uap, register_t *retval)
1.56      thorpej  2072: {
1.335     dsl      2073:        /* {
1.74      cgd      2074:                syscallarg(const char *) path;
1.335     dsl      2075:        } */
1.43      mycroft  2076:        int error;
                   2077:        struct nameidata nd;
                   2078:
1.331     pooka    2079:        NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | TRYEMULROOT,
1.334     pooka    2080:            UIO_USERSPACE, SCARG(uap, path));
1.43      mycroft  2081:        error = namei(&nd);
                   2082:        if (error)
                   2083:                return (error);
                   2084:
                   2085:        if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
                   2086:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2087:                if (nd.ni_dvp == nd.ni_vp)
                   2088:                        vrele(nd.ni_dvp);
                   2089:                else
                   2090:                        vput(nd.ni_dvp);
                   2091:                if (nd.ni_vp)
                   2092:                        vrele(nd.ni_vp);
                   2093:                return (EEXIST);
                   2094:        }
1.63      christos 2095:        if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1.43      mycroft  2096:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2097:        vput(nd.ni_dvp);
                   2098:        return (error);
                   2099: }
                   2100:
                   2101: /*
1.31      cgd      2102:  * Delete a name from the filesystem.
                   2103:  */
                   2104: /* ARGSUSED */
1.63      christos 2105: int
1.335     dsl      2106: sys_unlink(struct lwp *l, const struct sys_unlink_args *uap, register_t *retval)
1.56      thorpej  2107: {
1.335     dsl      2108:        /* {
1.74      cgd      2109:                syscallarg(const char *) path;
1.335     dsl      2110:        } */
1.336     ad       2111:
                   2112:        return do_sys_unlink(SCARG(uap, path), UIO_USERSPACE);
                   2113: }
                   2114:
                   2115: int
                   2116: do_sys_unlink(const char *arg, enum uio_seg seg)
                   2117: {
1.155     augustss 2118:        struct vnode *vp;
1.31      cgd      2119:        int error;
                   2120:        struct nameidata nd;
1.336     ad       2121:        kauth_cred_t cred;
1.315     christos 2122:        char *path;
                   2123:        const char *cpath;
1.31      cgd      2124:
1.336     ad       2125:        VERIEXEC_PATH_GET(arg, seg, cpath, path);
1.334     pooka    2126:        NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, seg, cpath);
1.313     elad     2127:
1.63      christos 2128:        if ((error = namei(&nd)) != 0)
1.313     elad     2129:                goto out;
1.31      cgd      2130:        vp = nd.ni_vp;
                   2131:
1.66      mycroft  2132:        /*
                   2133:         * The root of a mounted filesystem cannot be deleted.
                   2134:         */
1.329     ad       2135:        if (vp->v_vflag & VV_ROOT) {
1.43      mycroft  2136:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2137:                if (nd.ni_dvp == vp)
                   2138:                        vrele(nd.ni_dvp);
                   2139:                else
                   2140:                        vput(nd.ni_dvp);
1.66      mycroft  2141:                vput(vp);
                   2142:                error = EBUSY;
                   2143:                goto out;
1.31      cgd      2144:        }
1.219     blymn    2145:
1.256     elad     2146: #if NVERIEXEC > 0
1.222     elad     2147:        /* Handle remove requests for veriexec entries. */
1.336     ad       2148:        if ((error = veriexec_removechk(curlwp, nd.ni_vp, nd.ni_dirp)) != 0) {
1.219     blymn    2149:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2150:                if (nd.ni_dvp == vp)
                   2151:                        vrele(nd.ni_dvp);
                   2152:                else
                   2153:                        vput(nd.ni_dvp);
                   2154:                vput(vp);
                   2155:                goto out;
                   2156:        }
1.256     elad     2157: #endif /* NVERIEXEC > 0 */
                   2158:
1.336     ad       2159:        cred = kauth_cred_get();
1.253     elad     2160: #ifdef FILEASSOC
1.278     elad     2161:        (void)fileassoc_file_delete(vp);
1.253     elad     2162: #endif /* FILEASSOC */
1.66      mycroft  2163:        error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
                   2164: out:
1.315     christos 2165:        VERIEXEC_PATH_PUT(path);
1.31      cgd      2166:        return (error);
                   2167: }
                   2168:
                   2169: /*
                   2170:  * Reposition read/write file offset.
                   2171:  */
1.63      christos 2172: int
1.335     dsl      2173: sys_lseek(struct lwp *l, const struct sys_lseek_args *uap, register_t *retval)
1.56      thorpej  2174: {
1.335     dsl      2175:        /* {
1.35      cgd      2176:                syscallarg(int) fd;
                   2177:                syscallarg(int) pad;
                   2178:                syscallarg(off_t) offset;
                   2179:                syscallarg(int) whence;
1.335     dsl      2180:        } */
1.257     ad       2181:        kauth_cred_t cred = l->l_cred;
1.346     ad       2182:        file_t *fp;
1.84      kleink   2183:        struct vnode *vp;
1.31      cgd      2184:        struct vattr vattr;
1.155     augustss 2185:        off_t newoff;
1.346     ad       2186:        int error, fd;
                   2187:
                   2188:        fd = SCARG(uap, fd);
1.31      cgd      2189:
1.346     ad       2190:        if ((fp = fd_getfile(fd)) == NULL)
1.31      cgd      2191:                return (EBADF);
1.84      kleink   2192:
1.346     ad       2193:        vp = fp->f_data;
1.135     thorpej  2194:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2195:                error = ESPIPE;
                   2196:                goto out;
                   2197:        }
1.84      kleink   2198:
1.35      cgd      2199:        switch (SCARG(uap, whence)) {
1.92      kleink   2200:        case SEEK_CUR:
1.84      kleink   2201:                newoff = fp->f_offset + SCARG(uap, offset);
1.31      cgd      2202:                break;
1.92      kleink   2203:        case SEEK_END:
1.332     pooka    2204:                error = VOP_GETATTR(vp, &vattr, cred);
1.328     ad       2205:                if (error) {
1.135     thorpej  2206:                        goto out;
1.328     ad       2207:                }
1.84      kleink   2208:                newoff = SCARG(uap, offset) + vattr.va_size;
1.31      cgd      2209:                break;
1.92      kleink   2210:        case SEEK_SET:
1.84      kleink   2211:                newoff = SCARG(uap, offset);
1.31      cgd      2212:                break;
                   2213:        default:
1.135     thorpej  2214:                error = EINVAL;
                   2215:                goto out;
1.31      cgd      2216:        }
1.328     ad       2217:        if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) == 0) {
                   2218:                *(off_t *)retval = fp->f_offset = newoff;
                   2219:        }
1.135     thorpej  2220:  out:
1.346     ad       2221:        fd_putfile(fd);
1.135     thorpej  2222:        return (error);
1.120     thorpej  2223: }
                   2224:
                   2225: /*
                   2226:  * Positional read system call.
                   2227:  */
                   2228: int
1.335     dsl      2229: sys_pread(struct lwp *l, const struct sys_pread_args *uap, register_t *retval)
1.120     thorpej  2230: {
1.335     dsl      2231:        /* {
1.120     thorpej  2232:                syscallarg(int) fd;
                   2233:                syscallarg(void *) buf;
                   2234:                syscallarg(size_t) nbyte;
                   2235:                syscallarg(off_t) offset;
1.335     dsl      2236:        } */
1.346     ad       2237:        file_t *fp;
1.120     thorpej  2238:        struct vnode *vp;
                   2239:        off_t offset;
                   2240:        int error, fd = SCARG(uap, fd);
                   2241:
1.346     ad       2242:        if ((fp = fd_getfile(fd)) == NULL)
1.166     thorpej  2243:                return (EBADF);
                   2244:
1.183     pk       2245:        if ((fp->f_flag & FREAD) == 0) {
1.346     ad       2246:                fd_putfile(fd);
1.120     thorpej  2247:                return (EBADF);
1.183     pk       2248:        }
1.120     thorpej  2249:
1.346     ad       2250:        vp = fp->f_data;
1.135     thorpej  2251:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2252:                error = ESPIPE;
                   2253:                goto out;
                   2254:        }
1.120     thorpej  2255:
                   2256:        offset = SCARG(uap, offset);
                   2257:
                   2258:        /*
                   2259:         * XXX This works because no file systems actually
                   2260:         * XXX take any action on the seek operation.
                   2261:         */
                   2262:        if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135     thorpej  2263:                goto out;
1.120     thorpej  2264:
1.135     thorpej  2265:        /* dofileread() will unuse the descriptor for us */
1.328     ad       2266:        return (dofileread(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120     thorpej  2267:            &offset, 0, retval));
1.135     thorpej  2268:
                   2269:  out:
1.346     ad       2270:        fd_putfile(fd);
1.135     thorpej  2271:        return (error);
1.120     thorpej  2272: }
                   2273:
                   2274: /*
                   2275:  * Positional scatter read system call.
                   2276:  */
                   2277: int
1.335     dsl      2278: sys_preadv(struct lwp *l, const struct sys_preadv_args *uap, register_t *retval)
1.120     thorpej  2279: {
1.335     dsl      2280:        /* {
1.120     thorpej  2281:                syscallarg(int) fd;
                   2282:                syscallarg(const struct iovec *) iovp;
                   2283:                syscallarg(int) iovcnt;
                   2284:                syscallarg(off_t) offset;
1.335     dsl      2285:        } */
                   2286:        off_t offset = SCARG(uap, offset);
1.120     thorpej  2287:
1.328     ad       2288:        return do_filereadv(SCARG(uap, fd), SCARG(uap, iovp),
1.335     dsl      2289:            SCARG(uap, iovcnt), &offset, 0, retval);
1.120     thorpej  2290: }
                   2291:
                   2292: /*
                   2293:  * Positional write system call.
                   2294:  */
                   2295: int
1.335     dsl      2296: sys_pwrite(struct lwp *l, const struct sys_pwrite_args *uap, register_t *retval)
1.120     thorpej  2297: {
1.335     dsl      2298:        /* {
1.120     thorpej  2299:                syscallarg(int) fd;
                   2300:                syscallarg(const void *) buf;
                   2301:                syscallarg(size_t) nbyte;
                   2302:                syscallarg(off_t) offset;
1.335     dsl      2303:        } */
1.346     ad       2304:        file_t *fp;
1.120     thorpej  2305:        struct vnode *vp;
                   2306:        off_t offset;
                   2307:        int error, fd = SCARG(uap, fd);
                   2308:
1.346     ad       2309:        if ((fp = fd_getfile(fd)) == NULL)
1.166     thorpej  2310:                return (EBADF);
                   2311:
1.183     pk       2312:        if ((fp->f_flag & FWRITE) == 0) {
1.346     ad       2313:                fd_putfile(fd);
1.120     thorpej  2314:                return (EBADF);
1.183     pk       2315:        }
1.120     thorpej  2316:
1.346     ad       2317:        vp = fp->f_data;
1.135     thorpej  2318:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2319:                error = ESPIPE;
                   2320:                goto out;
                   2321:        }
1.120     thorpej  2322:
                   2323:        offset = SCARG(uap, offset);
                   2324:
                   2325:        /*
                   2326:         * XXX This works because no file systems actually
                   2327:         * XXX take any action on the seek operation.
                   2328:         */
                   2329:        if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135     thorpej  2330:                goto out;
1.120     thorpej  2331:
1.135     thorpej  2332:        /* dofilewrite() will unuse the descriptor for us */
1.328     ad       2333:        return (dofilewrite(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120     thorpej  2334:            &offset, 0, retval));
1.135     thorpej  2335:
                   2336:  out:
1.346     ad       2337:        fd_putfile(fd);
1.135     thorpej  2338:        return (error);
1.120     thorpej  2339: }
                   2340:
                   2341: /*
                   2342:  * Positional gather write system call.
                   2343:  */
                   2344: int
1.335     dsl      2345: sys_pwritev(struct lwp *l, const struct sys_pwritev_args *uap, register_t *retval)
1.120     thorpej  2346: {
1.335     dsl      2347:        /* {
1.120     thorpej  2348:                syscallarg(int) fd;
                   2349:                syscallarg(const struct iovec *) iovp;
                   2350:                syscallarg(int) iovcnt;
                   2351:                syscallarg(off_t) offset;
1.335     dsl      2352:        } */
                   2353:        off_t offset = SCARG(uap, offset);
1.120     thorpej  2354:
1.328     ad       2355:        return do_filewritev(SCARG(uap, fd), SCARG(uap, iovp),
1.335     dsl      2356:            SCARG(uap, iovcnt), &offset, 0, retval);
1.31      cgd      2357: }
                   2358:
                   2359: /*
                   2360:  * Check access permissions.
                   2361:  */
1.63      christos 2362: int
1.335     dsl      2363: sys_access(struct lwp *l, const struct sys_access_args *uap, register_t *retval)
1.56      thorpej  2364: {
1.335     dsl      2365:        /* {
1.74      cgd      2366:                syscallarg(const char *) path;
1.35      cgd      2367:                syscallarg(int) flags;
1.335     dsl      2368:        } */
1.242     elad     2369:        kauth_cred_t cred;
1.155     augustss 2370:        struct vnode *vp;
1.169     christos 2371:        int error, flags;
1.31      cgd      2372:        struct nameidata nd;
                   2373:
1.257     ad       2374:        cred = kauth_cred_dup(l->l_cred);
                   2375:        kauth_cred_seteuid(cred, kauth_cred_getuid(l->l_cred));
                   2376:        kauth_cred_setegid(cred, kauth_cred_getgid(l->l_cred));
1.310     dsl      2377:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2378:            SCARG(uap, path));
1.169     christos 2379:        /* Override default credentials */
                   2380:        nd.ni_cnd.cn_cred = cred;
1.63      christos 2381:        if ((error = namei(&nd)) != 0)
1.169     christos 2382:                goto out;
1.31      cgd      2383:        vp = nd.ni_vp;
                   2384:
                   2385:        /* Flags == 0 means only check for existence. */
1.35      cgd      2386:        if (SCARG(uap, flags)) {
1.31      cgd      2387:                flags = 0;
1.35      cgd      2388:                if (SCARG(uap, flags) & R_OK)
1.31      cgd      2389:                        flags |= VREAD;
1.35      cgd      2390:                if (SCARG(uap, flags) & W_OK)
1.31      cgd      2391:                        flags |= VWRITE;
1.89      mycroft  2392:                if (SCARG(uap, flags) & X_OK)
                   2393:                        flags |= VEXEC;
1.138     is       2394:
1.332     pooka    2395:                error = VOP_ACCESS(vp, flags, cred);
1.138     is       2396:                if (!error && (flags & VWRITE))
                   2397:                        error = vn_writechk(vp);
1.31      cgd      2398:        }
                   2399:        vput(vp);
1.169     christos 2400: out:
1.242     elad     2401:        kauth_cred_free(cred);
1.31      cgd      2402:        return (error);
                   2403: }
                   2404:
                   2405: /*
1.306     dsl      2406:  * Common code for all sys_stat functions, including compat versions.
                   2407:  */
                   2408: int
1.346     ad       2409: do_sys_stat(const char *path, unsigned int nd_flags, struct stat *sb)
1.306     dsl      2410: {
                   2411:        int error;
                   2412:        struct nameidata nd;
                   2413:
1.331     pooka    2414:        NDINIT(&nd, LOOKUP, nd_flags | LOCKLEAF | TRYEMULROOT,
1.334     pooka    2415:            UIO_USERSPACE, path);
1.306     dsl      2416:        error = namei(&nd);
                   2417:        if (error != 0)
                   2418:                return error;
1.346     ad       2419:        error = vn_stat(nd.ni_vp, sb);
1.306     dsl      2420:        vput(nd.ni_vp);
                   2421:        return error;
                   2422: }
                   2423:
                   2424: /*
1.31      cgd      2425:  * Get file status; this version follows links.
                   2426:  */
                   2427: /* ARGSUSED */
1.63      christos 2428: int
1.383     christos 2429: sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval)
1.56      thorpej  2430: {
1.335     dsl      2431:        /* {
1.74      cgd      2432:                syscallarg(const char *) path;
1.35      cgd      2433:                syscallarg(struct stat *) ub;
1.335     dsl      2434:        } */
1.31      cgd      2435:        struct stat sb;
                   2436:        int error;
                   2437:
1.346     ad       2438:        error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
1.31      cgd      2439:        if (error)
1.306     dsl      2440:                return error;
                   2441:        return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31      cgd      2442: }
                   2443:
                   2444: /*
                   2445:  * Get file status; this version does not follow links.
                   2446:  */
                   2447: /* ARGSUSED */
1.63      christos 2448: int
1.383     christos 2449: sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval)
1.56      thorpej  2450: {
1.335     dsl      2451:        /* {
1.74      cgd      2452:                syscallarg(const char *) path;
1.35      cgd      2453:                syscallarg(struct stat *) ub;
1.335     dsl      2454:        } */
1.65      mycroft  2455:        struct stat sb;
1.31      cgd      2456:        int error;
                   2457:
1.346     ad       2458:        error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb);
1.64      jtc      2459:        if (error)
1.306     dsl      2460:                return error;
                   2461:        return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31      cgd      2462: }
                   2463:
                   2464: /*
                   2465:  * Get configurable pathname variables.
                   2466:  */
                   2467: /* ARGSUSED */
1.63      christos 2468: int
1.335     dsl      2469: sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval)
1.56      thorpej  2470: {
1.335     dsl      2471:        /* {
1.74      cgd      2472:                syscallarg(const char *) path;
1.35      cgd      2473:                syscallarg(int) name;
1.335     dsl      2474:        } */
1.31      cgd      2475:        int error;
                   2476:        struct nameidata nd;
                   2477:
1.310     dsl      2478:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2479:            SCARG(uap, path));
1.63      christos 2480:        if ((error = namei(&nd)) != 0)
1.31      cgd      2481:                return (error);
1.35      cgd      2482:        error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1.31      cgd      2483:        vput(nd.ni_vp);
                   2484:        return (error);
                   2485: }
                   2486:
                   2487: /*
                   2488:  * Return target name of a symbolic link.
                   2489:  */
                   2490: /* ARGSUSED */
1.63      christos 2491: int
1.335     dsl      2492: sys_readlink(struct lwp *l, const struct sys_readlink_args *uap, register_t *retval)
1.56      thorpej  2493: {
1.335     dsl      2494:        /* {
1.74      cgd      2495:                syscallarg(const char *) path;
1.35      cgd      2496:                syscallarg(char *) buf;
1.115     kleink   2497:                syscallarg(size_t) count;
1.335     dsl      2498:        } */
1.155     augustss 2499:        struct vnode *vp;
1.31      cgd      2500:        struct iovec aiov;
                   2501:        struct uio auio;
                   2502:        int error;
                   2503:        struct nameidata nd;
                   2504:
1.310     dsl      2505:        NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2506:            SCARG(uap, path));
1.63      christos 2507:        if ((error = namei(&nd)) != 0)
1.31      cgd      2508:                return (error);
                   2509:        vp = nd.ni_vp;
                   2510:        if (vp->v_type != VLNK)
                   2511:                error = EINVAL;
1.106     enami    2512:        else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
1.332     pooka    2513:            (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) {
1.35      cgd      2514:                aiov.iov_base = SCARG(uap, buf);
                   2515:                aiov.iov_len = SCARG(uap, count);
1.31      cgd      2516:                auio.uio_iov = &aiov;
                   2517:                auio.uio_iovcnt = 1;
                   2518:                auio.uio_offset = 0;
                   2519:                auio.uio_rw = UIO_READ;
1.238     yamt     2520:                KASSERT(l == curlwp);
                   2521:                auio.uio_vmspace = l->l_proc->p_vmspace;
1.35      cgd      2522:                auio.uio_resid = SCARG(uap, count);
1.257     ad       2523:                error = VOP_READLINK(vp, &auio, l->l_cred);
1.31      cgd      2524:        }
                   2525:        vput(vp);
1.35      cgd      2526:        *retval = SCARG(uap, count) - auio.uio_resid;
1.31      cgd      2527:        return (error);
                   2528: }
                   2529:
                   2530: /*
                   2531:  * Change flags of a file given a path name.
                   2532:  */
                   2533: /* ARGSUSED */
1.63      christos 2534: int
1.335     dsl      2535: sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval)
1.56      thorpej  2536: {
1.335     dsl      2537:        /* {
1.74      cgd      2538:                syscallarg(const char *) path;
                   2539:                syscallarg(u_long) flags;
1.335     dsl      2540:        } */
1.155     augustss 2541:        struct vnode *vp;
1.31      cgd      2542:        int error;
                   2543:        struct nameidata nd;
                   2544:
1.331     pooka    2545:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2546:            SCARG(uap, path));
1.63      christos 2547:        if ((error = namei(&nd)) != 0)
1.31      cgd      2548:                return (error);
                   2549:        vp = nd.ni_vp;
1.234     christos 2550:        error = change_flags(vp, SCARG(uap, flags), l);
1.31      cgd      2551:        vput(vp);
                   2552:        return (error);
                   2553: }
                   2554:
                   2555: /*
                   2556:  * Change flags of a file given a file descriptor.
                   2557:  */
                   2558: /* ARGSUSED */
1.63      christos 2559: int
1.335     dsl      2560: sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval)
1.56      thorpej  2561: {
1.335     dsl      2562:        /* {
1.35      cgd      2563:                syscallarg(int) fd;
1.74      cgd      2564:                syscallarg(u_long) flags;
1.335     dsl      2565:        } */
1.31      cgd      2566:        struct vnode *vp;
1.346     ad       2567:        file_t *fp;
1.31      cgd      2568:        int error;
                   2569:
1.346     ad       2570:        /* fd_getvnode() will use the descriptor for us */
                   2571:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      2572:                return (error);
1.346     ad       2573:        vp = fp->f_data;
1.234     christos 2574:        error = change_flags(vp, SCARG(uap, flags), l);
1.113     fvdl     2575:        VOP_UNLOCK(vp, 0);
1.346     ad       2576:        fd_putfile(SCARG(uap, fd));
1.156     mrg      2577:        return (error);
                   2578: }
                   2579:
                   2580: /*
1.163     enami    2581:  * Change flags of a file given a path name; this version does
1.156     mrg      2582:  * not follow links.
                   2583:  */
                   2584: int
1.335     dsl      2585: sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval)
1.156     mrg      2586: {
1.335     dsl      2587:        /* {
1.156     mrg      2588:                syscallarg(const char *) path;
                   2589:                syscallarg(u_long) flags;
1.335     dsl      2590:        } */
1.163     enami    2591:        struct vnode *vp;
1.156     mrg      2592:        int error;
                   2593:        struct nameidata nd;
                   2594:
1.331     pooka    2595:        NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2596:            SCARG(uap, path));
1.156     mrg      2597:        if ((error = namei(&nd)) != 0)
                   2598:                return (error);
                   2599:        vp = nd.ni_vp;
1.234     christos 2600:        error = change_flags(vp, SCARG(uap, flags), l);
1.163     enami    2601:        vput(vp);
                   2602:        return (error);
                   2603: }
                   2604:
                   2605: /*
                   2606:  * Common routine to change flags of a file.
                   2607:  */
                   2608: int
1.234     christos 2609: change_flags(struct vnode *vp, u_long flags, struct lwp *l)
1.163     enami    2610: {
                   2611:        struct vattr vattr;
                   2612:        int error;
                   2613:
1.156     mrg      2614:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.163     enami    2615:        /*
                   2616:         * Non-superusers cannot change the flags on devices, even if they
                   2617:         * own them.
                   2618:         */
1.294     elad     2619:        if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1.332     pooka    2620:                if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
1.156     mrg      2621:                        goto out;
                   2622:                if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
                   2623:                        error = EINVAL;
                   2624:                        goto out;
                   2625:                }
                   2626:        }
                   2627:        VATTR_NULL(&vattr);
1.163     enami    2628:        vattr.va_flags = flags;
1.332     pooka    2629:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.156     mrg      2630: out:
1.31      cgd      2631:        return (error);
                   2632: }
                   2633:
                   2634: /*
1.98      enami    2635:  * Change mode of a file given path name; this version follows links.
1.31      cgd      2636:  */
                   2637: /* ARGSUSED */
1.63      christos 2638: int
1.335     dsl      2639: sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval)
1.56      thorpej  2640: {
1.335     dsl      2641:        /* {
1.74      cgd      2642:                syscallarg(const char *) path;
1.35      cgd      2643:                syscallarg(int) mode;
1.335     dsl      2644:        } */
1.31      cgd      2645:        int error;
                   2646:        struct nameidata nd;
                   2647:
1.331     pooka    2648:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2649:            SCARG(uap, path));
1.63      christos 2650:        if ((error = namei(&nd)) != 0)
1.31      cgd      2651:                return (error);
1.97      enami    2652:
1.234     christos 2653:        error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
1.97      enami    2654:
                   2655:        vrele(nd.ni_vp);
1.31      cgd      2656:        return (error);
                   2657: }
                   2658:
                   2659: /*
                   2660:  * Change mode of a file given a file descriptor.
                   2661:  */
                   2662: /* ARGSUSED */
1.63      christos 2663: int
1.335     dsl      2664: sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval)
1.56      thorpej  2665: {
1.335     dsl      2666:        /* {
1.35      cgd      2667:                syscallarg(int) fd;
                   2668:                syscallarg(int) mode;
1.335     dsl      2669:        } */
1.346     ad       2670:        file_t *fp;
1.31      cgd      2671:        int error;
                   2672:
1.346     ad       2673:        /* fd_getvnode() will use the descriptor for us */
                   2674:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      2675:                return (error);
1.346     ad       2676:        error = change_mode(fp->f_data, SCARG(uap, mode), l);
                   2677:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  2678:        return (error);
1.97      enami    2679: }
                   2680:
                   2681: /*
1.98      enami    2682:  * Change mode of a file given path name; this version does not follow links.
                   2683:  */
                   2684: /* ARGSUSED */
                   2685: int
1.335     dsl      2686: sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval)
1.98      enami    2687: {
1.335     dsl      2688:        /* {
1.98      enami    2689:                syscallarg(const char *) path;
                   2690:                syscallarg(int) mode;
1.335     dsl      2691:        } */
1.98      enami    2692:        int error;
                   2693:        struct nameidata nd;
                   2694:
1.331     pooka    2695:        NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2696:            SCARG(uap, path));
1.98      enami    2697:        if ((error = namei(&nd)) != 0)
                   2698:                return (error);
                   2699:
1.234     christos 2700:        error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
1.98      enami    2701:
                   2702:        vrele(nd.ni_vp);
                   2703:        return (error);
                   2704: }
                   2705:
                   2706: /*
1.97      enami    2707:  * Common routine to set mode given a vnode.
                   2708:  */
                   2709: static int
1.234     christos 2710: change_mode(struct vnode *vp, int mode, struct lwp *l)
1.97      enami    2711: {
                   2712:        struct vattr vattr;
                   2713:        int error;
                   2714:
1.113     fvdl     2715:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   2716:        VATTR_NULL(&vattr);
                   2717:        vattr.va_mode = mode & ALLPERMS;
1.332     pooka    2718:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.113     fvdl     2719:        VOP_UNLOCK(vp, 0);
1.31      cgd      2720:        return (error);
                   2721: }
                   2722:
                   2723: /*
1.98      enami    2724:  * Set ownership given a path name; this version follows links.
1.31      cgd      2725:  */
                   2726: /* ARGSUSED */
1.63      christos 2727: int
1.335     dsl      2728: sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval)
1.56      thorpej  2729: {
1.335     dsl      2730:        /* {
1.74      cgd      2731:                syscallarg(const char *) path;
                   2732:                syscallarg(uid_t) uid;
                   2733:                syscallarg(gid_t) gid;
1.335     dsl      2734:        } */
1.31      cgd      2735:        int error;
                   2736:        struct nameidata nd;
                   2737:
1.331     pooka    2738:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2739:            SCARG(uap, path));
1.63      christos 2740:        if ((error = namei(&nd)) != 0)
1.31      cgd      2741:                return (error);
1.86      kleink   2742:
1.234     christos 2743:        error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112     kleink   2744:
                   2745:        vrele(nd.ni_vp);
                   2746:        return (error);
                   2747: }
                   2748:
                   2749: /*
                   2750:  * Set ownership given a path name; this version follows links.
                   2751:  * Provides POSIX semantics.
                   2752:  */
                   2753: /* ARGSUSED */
                   2754: int
1.335     dsl      2755: sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval)
1.112     kleink   2756: {
1.335     dsl      2757:        /* {
1.112     kleink   2758:                syscallarg(const char *) path;
                   2759:                syscallarg(uid_t) uid;
                   2760:                syscallarg(gid_t) gid;
1.335     dsl      2761:        } */
1.112     kleink   2762:        int error;
                   2763:        struct nameidata nd;
                   2764:
1.331     pooka    2765:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2766:            SCARG(uap, path));
1.112     kleink   2767:        if ((error = namei(&nd)) != 0)
                   2768:                return (error);
                   2769:
1.234     christos 2770:        error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.86      kleink   2771:
                   2772:        vrele(nd.ni_vp);
1.31      cgd      2773:        return (error);
                   2774: }
                   2775:
                   2776: /*
                   2777:  * Set ownership given a file descriptor.
                   2778:  */
                   2779: /* ARGSUSED */
1.63      christos 2780: int
1.335     dsl      2781: sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval)
1.56      thorpej  2782: {
1.335     dsl      2783:        /* {
1.35      cgd      2784:                syscallarg(int) fd;
1.74      cgd      2785:                syscallarg(uid_t) uid;
                   2786:                syscallarg(gid_t) gid;
1.335     dsl      2787:        } */
1.71      mycroft  2788:        int error;
1.346     ad       2789:        file_t *fp;
1.31      cgd      2790:
1.346     ad       2791:        /* fd_getvnode() will use the descriptor for us */
                   2792:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      2793:                return (error);
1.346     ad       2794:        error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
                   2795:            l, 0);
                   2796:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  2797:        return (error);
1.112     kleink   2798: }
                   2799:
                   2800: /*
                   2801:  * Set ownership given a file descriptor, providing POSIX/XPG semantics.
                   2802:  */
                   2803: /* ARGSUSED */
                   2804: int
1.335     dsl      2805: sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval)
1.112     kleink   2806: {
1.335     dsl      2807:        /* {
1.112     kleink   2808:                syscallarg(int) fd;
                   2809:                syscallarg(uid_t) uid;
                   2810:                syscallarg(gid_t) gid;
1.335     dsl      2811:        } */
1.112     kleink   2812:        int error;
1.346     ad       2813:        file_t *fp;
1.112     kleink   2814:
1.346     ad       2815:        /* fd_getvnode() will use the descriptor for us */
                   2816:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.112     kleink   2817:                return (error);
1.346     ad       2818:        error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
                   2819:            l, 1);
                   2820:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  2821:        return (error);
1.86      kleink   2822: }
                   2823:
                   2824: /*
1.98      enami    2825:  * Set ownership given a path name; this version does not follow links.
                   2826:  */
                   2827: /* ARGSUSED */
                   2828: int
1.335     dsl      2829: sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval)
1.98      enami    2830: {
1.335     dsl      2831:        /* {
1.98      enami    2832:                syscallarg(const char *) path;
                   2833:                syscallarg(uid_t) uid;
                   2834:                syscallarg(gid_t) gid;
1.335     dsl      2835:        } */
1.98      enami    2836:        int error;
                   2837:        struct nameidata nd;
                   2838:
1.331     pooka    2839:        NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2840:            SCARG(uap, path));
1.98      enami    2841:        if ((error = namei(&nd)) != 0)
                   2842:                return (error);
                   2843:
1.234     christos 2844:        error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112     kleink   2845:
                   2846:        vrele(nd.ni_vp);
                   2847:        return (error);
                   2848: }
                   2849:
                   2850: /*
                   2851:  * Set ownership given a path name; this version does not follow links.
                   2852:  * Provides POSIX/XPG semantics.
                   2853:  */
                   2854: /* ARGSUSED */
                   2855: int
1.335     dsl      2856: sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval)
1.112     kleink   2857: {
1.335     dsl      2858:        /* {
1.112     kleink   2859:                syscallarg(const char *) path;
                   2860:                syscallarg(uid_t) uid;
                   2861:                syscallarg(gid_t) gid;
1.335     dsl      2862:        } */
1.112     kleink   2863:        int error;
                   2864:        struct nameidata nd;
                   2865:
1.331     pooka    2866:        NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    2867:            SCARG(uap, path));
1.112     kleink   2868:        if ((error = namei(&nd)) != 0)
                   2869:                return (error);
                   2870:
1.234     christos 2871:        error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.98      enami    2872:
                   2873:        vrele(nd.ni_vp);
                   2874:        return (error);
                   2875: }
                   2876:
                   2877: /*
1.205     junyoung 2878:  * Common routine to set ownership given a vnode.
1.86      kleink   2879:  */
                   2880: static int
1.234     christos 2881: change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l,
1.221     thorpej  2882:     int posix_semantics)
1.86      kleink   2883: {
                   2884:        struct vattr vattr;
1.112     kleink   2885:        mode_t newmode;
1.86      kleink   2886:        int error;
                   2887:
1.113     fvdl     2888:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    2889:        if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
1.86      kleink   2890:                goto out;
                   2891:
1.175     thorpej  2892: #define CHANGED(x) ((int)(x) != -1)
1.112     kleink   2893:        newmode = vattr.va_mode;
                   2894:        if (posix_semantics) {
                   2895:                /*
1.114     kleink   2896:                 * POSIX/XPG semantics: if the caller is not the super-user,
                   2897:                 * clear set-user-id and set-group-id bits.  Both POSIX and
                   2898:                 * the XPG consider the behaviour for calls by the super-user
                   2899:                 * implementation-defined; we leave the set-user-id and set-
                   2900:                 * group-id settings intact in that case.
1.112     kleink   2901:                 */
1.257     ad       2902:                if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
1.242     elad     2903:                                      NULL) != 0)
1.112     kleink   2904:                        newmode &= ~(S_ISUID | S_ISGID);
                   2905:        } else {
                   2906:                /*
                   2907:                 * NetBSD semantics: when changing owner and/or group,
                   2908:                 * clear the respective bit(s).
                   2909:                 */
                   2910:                if (CHANGED(uid))
                   2911:                        newmode &= ~S_ISUID;
                   2912:                if (CHANGED(gid))
                   2913:                        newmode &= ~S_ISGID;
                   2914:        }
                   2915:        /* Update va_mode iff altered. */
                   2916:        if (vattr.va_mode == newmode)
                   2917:                newmode = VNOVAL;
1.205     junyoung 2918:
1.86      kleink   2919:        VATTR_NULL(&vattr);
1.175     thorpej  2920:        vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
                   2921:        vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
1.86      kleink   2922:        vattr.va_mode = newmode;
1.332     pooka    2923:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.112     kleink   2924: #undef CHANGED
1.205     junyoung 2925:
1.86      kleink   2926: out:
1.113     fvdl     2927:        VOP_UNLOCK(vp, 0);
1.31      cgd      2928:        return (error);
                   2929: }
                   2930:
                   2931: /*
1.98      enami    2932:  * Set the access and modification times given a path name; this
                   2933:  * version follows links.
1.31      cgd      2934:  */
                   2935: /* ARGSUSED */
1.63      christos 2936: int
1.383     christos 2937: sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap,
                   2938:     register_t *retval)
1.56      thorpej  2939: {
1.335     dsl      2940:        /* {
1.74      cgd      2941:                syscallarg(const char *) path;
                   2942:                syscallarg(const struct timeval *) tptr;
1.335     dsl      2943:        } */
1.31      cgd      2944:
1.312     dsl      2945:        return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW,
1.346     ad       2946:            SCARG(uap, tptr), UIO_USERSPACE);
1.71      mycroft  2947: }
                   2948:
                   2949: /*
                   2950:  * Set the access and modification times given a file descriptor.
                   2951:  */
                   2952: /* ARGSUSED */
                   2953: int
1.383     christos 2954: sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap,
                   2955:     register_t *retval)
1.71      mycroft  2956: {
1.335     dsl      2957:        /* {
1.71      mycroft  2958:                syscallarg(int) fd;
1.74      cgd      2959:                syscallarg(const struct timeval *) tptr;
1.335     dsl      2960:        } */
1.71      mycroft  2961:        int error;
1.346     ad       2962:        file_t *fp;
1.71      mycroft  2963:
1.346     ad       2964:        /* fd_getvnode() will use the descriptor for us */
                   2965:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.96      enami    2966:                return (error);
1.346     ad       2967:        error = do_sys_utimes(l, fp->f_data, NULL, 0, SCARG(uap, tptr),
                   2968:            UIO_USERSPACE);
                   2969:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  2970:        return (error);
1.98      enami    2971: }
                   2972:
                   2973: /*
                   2974:  * Set the access and modification times given a path name; this
                   2975:  * version does not follow links.
                   2976:  */
                   2977: int
1.383     christos 2978: sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap,
                   2979:     register_t *retval)
1.98      enami    2980: {
1.335     dsl      2981:        /* {
1.98      enami    2982:                syscallarg(const char *) path;
                   2983:                syscallarg(const struct timeval *) tptr;
1.335     dsl      2984:        } */
1.98      enami    2985:
1.312     dsl      2986:        return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW,
1.346     ad       2987:            SCARG(uap, tptr), UIO_USERSPACE);
1.97      enami    2988: }
                   2989:
                   2990: /*
                   2991:  * Common routine to set access and modification times given a vnode.
                   2992:  */
1.312     dsl      2993: int
                   2994: do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag,
                   2995:     const struct timeval *tptr, enum uio_seg seg)
1.97      enami    2996: {
                   2997:        struct vattr vattr;
1.312     dsl      2998:        struct nameidata nd;
1.97      enami    2999:        int error;
1.367     christos 3000:        bool vanull, setbirthtime;
                   3001:        struct timespec ts[2];
1.97      enami    3002:
                   3003:        if (tptr == NULL) {
1.367     christos 3004:                vanull = true;
                   3005:                nanotime(&ts[0]);
                   3006:                ts[1] = ts[0];
1.71      mycroft  3007:        } else {
1.233     yamt     3008:                struct timeval tv[2];
                   3009:
1.367     christos 3010:                vanull = false;
1.312     dsl      3011:                if (seg != UIO_SYSSPACE) {
1.383     christos 3012:                        error = copyin(tptr, tv, sizeof (tv));
1.312     dsl      3013:                        if (error != 0)
                   3014:                                return error;
                   3015:                        tptr = tv;
                   3016:                }
1.367     christos 3017:                TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]);
                   3018:                TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]);
1.71      mycroft  3019:        }
1.312     dsl      3020:
                   3021:        if (vp == NULL) {
1.334     pooka    3022:                NDINIT(&nd, LOOKUP, flag | TRYEMULROOT, UIO_USERSPACE, path);
1.312     dsl      3023:                if ((error = namei(&nd)) != 0)
1.367     christos 3024:                        return error;
1.312     dsl      3025:                vp = nd.ni_vp;
                   3026:        } else
                   3027:                nd.ni_vp = NULL;
                   3028:
1.113     fvdl     3029:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.367     christos 3030:        setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 &&
                   3031:            timespeccmp(&ts[1], &vattr.va_birthtime, <));
                   3032:        VATTR_NULL(&vattr);
1.368     christos 3033:        vattr.va_atime = ts[0];
                   3034:        vattr.va_mtime = ts[1];
1.367     christos 3035:        if (setbirthtime)
                   3036:                vattr.va_birthtime = ts[1];
                   3037:        if (vanull)
                   3038:                vattr.va_flags |= VA_UTIMES_NULL;
1.332     pooka    3039:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.113     fvdl     3040:        VOP_UNLOCK(vp, 0);
1.312     dsl      3041:
                   3042:        if (nd.ni_vp != NULL)
                   3043:                vrele(nd.ni_vp);
                   3044:
1.367     christos 3045:        return error;
1.31      cgd      3046: }
                   3047:
                   3048: /*
                   3049:  * Truncate a file given its path name.
                   3050:  */
                   3051: /* ARGSUSED */
1.63      christos 3052: int
1.335     dsl      3053: sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval)
1.56      thorpej  3054: {
1.335     dsl      3055:        /* {
1.74      cgd      3056:                syscallarg(const char *) path;
1.35      cgd      3057:                syscallarg(int) pad;
                   3058:                syscallarg(off_t) length;
1.335     dsl      3059:        } */
1.155     augustss 3060:        struct vnode *vp;
1.31      cgd      3061:        struct vattr vattr;
                   3062:        int error;
                   3063:        struct nameidata nd;
                   3064:
1.331     pooka    3065:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    3066:            SCARG(uap, path));
1.63      christos 3067:        if ((error = namei(&nd)) != 0)
1.31      cgd      3068:                return (error);
                   3069:        vp = nd.ni_vp;
1.113     fvdl     3070:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      3071:        if (vp->v_type == VDIR)
                   3072:                error = EISDIR;
                   3073:        else if ((error = vn_writechk(vp)) == 0 &&
1.332     pooka    3074:            (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {
1.31      cgd      3075:                VATTR_NULL(&vattr);
1.35      cgd      3076:                vattr.va_size = SCARG(uap, length);
1.332     pooka    3077:                error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.31      cgd      3078:        }
                   3079:        vput(vp);
                   3080:        return (error);
                   3081: }
                   3082:
                   3083: /*
                   3084:  * Truncate a file given a file descriptor.
                   3085:  */
                   3086: /* ARGSUSED */
1.63      christos 3087: int
1.335     dsl      3088: sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval)
1.56      thorpej  3089: {
1.335     dsl      3090:        /* {
1.35      cgd      3091:                syscallarg(int) fd;
                   3092:                syscallarg(int) pad;
                   3093:                syscallarg(off_t) length;
1.335     dsl      3094:        } */
1.31      cgd      3095:        struct vattr vattr;
                   3096:        struct vnode *vp;
1.346     ad       3097:        file_t *fp;
1.31      cgd      3098:        int error;
                   3099:
1.346     ad       3100:        /* fd_getvnode() will use the descriptor for us */
                   3101:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3102:                return (error);
1.135     thorpej  3103:        if ((fp->f_flag & FWRITE) == 0) {
                   3104:                error = EINVAL;
                   3105:                goto out;
                   3106:        }
1.346     ad       3107:        vp = fp->f_data;
1.113     fvdl     3108:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      3109:        if (vp->v_type == VDIR)
                   3110:                error = EISDIR;
                   3111:        else if ((error = vn_writechk(vp)) == 0) {
                   3112:                VATTR_NULL(&vattr);
1.35      cgd      3113:                vattr.va_size = SCARG(uap, length);
1.332     pooka    3114:                error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1.31      cgd      3115:        }
1.113     fvdl     3116:        VOP_UNLOCK(vp, 0);
1.135     thorpej  3117:  out:
1.346     ad       3118:        fd_putfile(SCARG(uap, fd));
1.31      cgd      3119:        return (error);
                   3120: }
                   3121:
                   3122: /*
                   3123:  * Sync an open file.
                   3124:  */
                   3125: /* ARGSUSED */
1.63      christos 3126: int
1.335     dsl      3127: sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval)
1.56      thorpej  3128: {
1.335     dsl      3129:        /* {
1.35      cgd      3130:                syscallarg(int) fd;
1.335     dsl      3131:        } */
1.155     augustss 3132:        struct vnode *vp;
1.346     ad       3133:        file_t *fp;
1.31      cgd      3134:        int error;
                   3135:
1.346     ad       3136:        /* fd_getvnode() will use the descriptor for us */
                   3137:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3138:                return (error);
1.346     ad       3139:        vp = fp->f_data;
1.113     fvdl     3140:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    3141:        error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);
1.113     fvdl     3142:        VOP_UNLOCK(vp, 0);
1.346     ad       3143:        fd_putfile(SCARG(uap, fd));
1.201     thorpej  3144:        return (error);
                   3145: }
                   3146:
                   3147: /*
                   3148:  * Sync a range of file data.  API modeled after that found in AIX.
                   3149:  *
                   3150:  * FDATASYNC indicates that we need only save enough metadata to be able
                   3151:  * to re-read the written data.  Note we duplicate AIX's requirement that
                   3152:  * the file be open for writing.
                   3153:  */
                   3154: /* ARGSUSED */
                   3155: int
1.335     dsl      3156: sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval)
1.201     thorpej  3157: {
1.335     dsl      3158:        /* {
1.201     thorpej  3159:                syscallarg(int) fd;
                   3160:                syscallarg(int) flags;
                   3161:                syscallarg(off_t) start;
1.225     cube     3162:                syscallarg(off_t) length;
1.335     dsl      3163:        } */
1.201     thorpej  3164:        struct vnode *vp;
1.346     ad       3165:        file_t *fp;
1.201     thorpej  3166:        int flags, nflags;
                   3167:        off_t s, e, len;
                   3168:        int error;
                   3169:
1.346     ad       3170:        /* fd_getvnode() will use the descriptor for us */
                   3171:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.201     thorpej  3172:                return (error);
                   3173:
                   3174:        if ((fp->f_flag & FWRITE) == 0) {
1.293     wrstuden 3175:                error = EBADF;
                   3176:                goto out;
1.201     thorpej  3177:        }
                   3178:
                   3179:        flags = SCARG(uap, flags);
                   3180:        if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
                   3181:            ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
1.293     wrstuden 3182:                error = EINVAL;
                   3183:                goto out;
1.201     thorpej  3184:        }
                   3185:        /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
                   3186:        if (flags & FDATASYNC)
                   3187:                nflags = FSYNC_DATAONLY | FSYNC_WAIT;
                   3188:        else
                   3189:                nflags = FSYNC_WAIT;
1.216     wrstuden 3190:        if (flags & FDISKSYNC)
                   3191:                nflags |= FSYNC_CACHE;
1.201     thorpej  3192:
                   3193:        len = SCARG(uap, length);
                   3194:        /* If length == 0, we do the whole file, and s = l = 0 will do that */
                   3195:        if (len) {
                   3196:                s = SCARG(uap, start);
                   3197:                e = s + len;
                   3198:                if (e < s) {
1.293     wrstuden 3199:                        error = EINVAL;
                   3200:                        goto out;
1.201     thorpej  3201:                }
                   3202:        } else {
                   3203:                e = 0;
                   3204:                s = 0;
                   3205:        }
                   3206:
1.346     ad       3207:        vp = fp->f_data;
1.201     thorpej  3208:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    3209:        error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);
1.201     thorpej  3210:        VOP_UNLOCK(vp, 0);
1.293     wrstuden 3211: out:
1.346     ad       3212:        fd_putfile(SCARG(uap, fd));
1.31      cgd      3213:        return (error);
                   3214: }
                   3215:
                   3216: /*
1.117     kleink   3217:  * Sync the data of an open file.
                   3218:  */
                   3219: /* ARGSUSED */
                   3220: int
1.335     dsl      3221: sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval)
1.117     kleink   3222: {
1.335     dsl      3223:        /* {
1.117     kleink   3224:                syscallarg(int) fd;
1.335     dsl      3225:        } */
1.117     kleink   3226:        struct vnode *vp;
1.346     ad       3227:        file_t *fp;
1.117     kleink   3228:        int error;
                   3229:
1.346     ad       3230:        /* fd_getvnode() will use the descriptor for us */
                   3231:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.117     kleink   3232:                return (error);
1.199     kleink   3233:        if ((fp->f_flag & FWRITE) == 0) {
1.346     ad       3234:                fd_putfile(SCARG(uap, fd));
1.199     kleink   3235:                return (EBADF);
                   3236:        }
1.346     ad       3237:        vp = fp->f_data;
1.117     kleink   3238:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    3239:        error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);
1.117     kleink   3240:        VOP_UNLOCK(vp, 0);
1.346     ad       3241:        fd_putfile(SCARG(uap, fd));
1.117     kleink   3242:        return (error);
                   3243: }
                   3244:
                   3245: /*
1.90      kleink   3246:  * Rename files, (standard) BSD semantics frontend.
1.31      cgd      3247:  */
                   3248: /* ARGSUSED */
1.63      christos 3249: int
1.335     dsl      3250: sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval)
1.56      thorpej  3251: {
1.335     dsl      3252:        /* {
1.74      cgd      3253:                syscallarg(const char *) from;
                   3254:                syscallarg(const char *) to;
1.335     dsl      3255:        } */
1.90      kleink   3256:
1.336     ad       3257:        return (do_sys_rename(SCARG(uap, from), SCARG(uap, to), UIO_USERSPACE, 0));
1.90      kleink   3258: }
                   3259:
                   3260: /*
                   3261:  * Rename files, POSIX semantics frontend.
                   3262:  */
                   3263: /* ARGSUSED */
                   3264: int
1.335     dsl      3265: sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval)
1.90      kleink   3266: {
1.335     dsl      3267:        /* {
1.90      kleink   3268:                syscallarg(const char *) from;
                   3269:                syscallarg(const char *) to;
1.335     dsl      3270:        } */
1.90      kleink   3271:
1.336     ad       3272:        return (do_sys_rename(SCARG(uap, from), SCARG(uap, to), UIO_USERSPACE, 1));
1.90      kleink   3273: }
                   3274:
                   3275: /*
                   3276:  * Rename files.  Source and destination must either both be directories,
                   3277:  * or both not be directories.  If target is a directory, it must be empty.
                   3278:  * If `from' and `to' refer to the same object, the value of the `retain'
                   3279:  * argument is used to determine whether `from' will be
                   3280:  *
                   3281:  * (retain == 0)       deleted unless `from' and `to' refer to the same
                   3282:  *                     object in the file system's name space (BSD).
                   3283:  * (retain == 1)       always retained (POSIX).
                   3284:  */
1.336     ad       3285: int
                   3286: do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain)
1.90      kleink   3287: {
1.155     augustss 3288:        struct vnode *tvp, *fvp, *tdvp;
1.31      cgd      3289:        struct nameidata fromnd, tond;
1.344     dholland 3290:        struct mount *fs;
1.336     ad       3291:        struct lwp *l = curlwp;
1.234     christos 3292:        struct proc *p;
1.344     dholland 3293:        uint32_t saveflag;
1.31      cgd      3294:        int error;
                   3295:
1.331     pooka    3296:        NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT,
1.336     ad       3297:            seg, from);
1.63      christos 3298:        if ((error = namei(&fromnd)) != 0)
1.31      cgd      3299:                return (error);
1.291     pooka    3300:        if (fromnd.ni_dvp != fromnd.ni_vp)
                   3301:                VOP_UNLOCK(fromnd.ni_dvp, 0);
1.31      cgd      3302:        fvp = fromnd.ni_vp;
1.344     dholland 3303:
                   3304:        fs = fvp->v_mount;
                   3305:        error = VFS_RENAMELOCK_ENTER(fs);
                   3306:        if (error) {
                   3307:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                   3308:                vrele(fromnd.ni_dvp);
                   3309:                vrele(fvp);
                   3310:                goto out1;
                   3311:        }
                   3312:
                   3313:        /*
                   3314:         * close, partially, yet another race - ideally we should only
                   3315:         * go as far as getting fromnd.ni_dvp before getting the per-fs
                   3316:         * lock, and then continue to get fromnd.ni_vp, but we can't do
                   3317:         * that with namei as it stands.
                   3318:         *
                   3319:         * This still won't prevent rmdir from nuking fromnd.ni_vp
                   3320:         * under us. The real fix is to get the locks in the right
                   3321:         * order and do the lookups in the right places, but that's a
                   3322:         * major rototill.
                   3323:         *
                   3324:         * Preserve the SAVESTART in cn_flags, because who knows what
                   3325:         * might happen if we don't.
                   3326:         *
                   3327:         * Note: this logic (as well as this whole function) is cloned
                   3328:         * in nfs_serv.c. Proceed accordingly.
                   3329:         */
                   3330:        vrele(fvp);
1.348     dholland 3331:        if ((fromnd.ni_cnd.cn_namelen == 1 &&
                   3332:             fromnd.ni_cnd.cn_nameptr[0] == '.') ||
                   3333:            (fromnd.ni_cnd.cn_namelen == 2 &&
                   3334:             fromnd.ni_cnd.cn_nameptr[0] == '.' &&
                   3335:             fromnd.ni_cnd.cn_nameptr[1] == '.')) {
                   3336:                error = EINVAL;
                   3337:                VFS_RENAMELOCK_EXIT(fs);
                   3338:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                   3339:                vrele(fromnd.ni_dvp);
                   3340:                goto out1;
                   3341:        }
1.344     dholland 3342:        saveflag = fromnd.ni_cnd.cn_flags & SAVESTART;
                   3343:        fromnd.ni_cnd.cn_flags &= ~SAVESTART;
                   3344:        vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
                   3345:        error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd);
                   3346:        fromnd.ni_cnd.cn_flags |= saveflag;
                   3347:        if (error) {
                   3348:                VOP_UNLOCK(fromnd.ni_dvp, 0);
                   3349:                VFS_RENAMELOCK_EXIT(fs);
                   3350:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                   3351:                vrele(fromnd.ni_dvp);
                   3352:                goto out1;
                   3353:        }
                   3354:        VOP_UNLOCK(fromnd.ni_vp, 0);
                   3355:        if (fromnd.ni_dvp != fromnd.ni_vp)
                   3356:                VOP_UNLOCK(fromnd.ni_dvp, 0);
                   3357:        fvp = fromnd.ni_vp;
                   3358:
1.331     pooka    3359:        NDINIT(&tond, RENAME,
                   3360:            LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT
                   3361:              | (fvp->v_type == VDIR ? CREATEDIR : 0),
1.336     ad       3362:            seg, to);
1.63      christos 3363:        if ((error = namei(&tond)) != 0) {
1.344     dholland 3364:                VFS_RENAMELOCK_EXIT(fs);
1.31      cgd      3365:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                   3366:                vrele(fromnd.ni_dvp);
                   3367:                vrele(fvp);
                   3368:                goto out1;
                   3369:        }
                   3370:        tdvp = tond.ni_dvp;
                   3371:        tvp = tond.ni_vp;
1.90      kleink   3372:
1.31      cgd      3373:        if (tvp != NULL) {
                   3374:                if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
                   3375:                        error = ENOTDIR;
                   3376:                        goto out;
                   3377:                } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
                   3378:                        error = EISDIR;
                   3379:                        goto out;
                   3380:                }
                   3381:        }
1.90      kleink   3382:
1.31      cgd      3383:        if (fvp == tdvp)
                   3384:                error = EINVAL;
1.90      kleink   3385:
1.82      kleink   3386:        /*
1.90      kleink   3387:         * Source and destination refer to the same object.
1.82      kleink   3388:         */
1.90      kleink   3389:        if (fvp == tvp) {
                   3390:                if (retain)
                   3391:                        error = -1;
                   3392:                else if (fromnd.ni_dvp == tdvp &&
                   3393:                    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1.123     perry    3394:                    !memcmp(fromnd.ni_cnd.cn_nameptr,
1.90      kleink   3395:                          tond.ni_cnd.cn_nameptr,
                   3396:                          fromnd.ni_cnd.cn_namelen))
1.82      kleink   3397:                error = -1;
1.90      kleink   3398:        }
                   3399:
1.256     elad     3400: #if NVERIEXEC > 0
1.282     elad     3401:        if (!error) {
1.313     elad     3402:                char *f1, *f2;
1.384     yamt     3403:                size_t f1_len;
                   3404:                size_t f2_len;
1.313     elad     3405:
1.384     yamt     3406:                f1_len = fromnd.ni_cnd.cn_namelen + 1;
                   3407:                f1 = kmem_alloc(f1_len, KM_SLEEP);
                   3408:                strlcpy(f1, fromnd.ni_cnd.cn_nameptr, f1_len);
                   3409:
                   3410:                f2_len = tond.ni_cnd.cn_namelen + 1;
                   3411:                f2 = kmem_alloc(f2_len, KM_SLEEP);
                   3412:                strlcpy(f2, tond.ni_cnd.cn_nameptr, f2_len);
1.282     elad     3413:
1.315     christos 3414:                error = veriexec_renamechk(l, fvp, f1, tvp, f2);
1.282     elad     3415:
1.384     yamt     3416:                kmem_free(f1, f1_len);
                   3417:                kmem_free(f2, f2_len);
1.282     elad     3418:        }
1.256     elad     3419: #endif /* NVERIEXEC > 0 */
1.229     elad     3420:
1.31      cgd      3421: out:
1.234     christos 3422:        p = l->l_proc;
1.31      cgd      3423:        if (!error) {
                   3424:                error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
                   3425:                                   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1.344     dholland 3426:                VFS_RENAMELOCK_EXIT(fs);
1.31      cgd      3427:        } else {
                   3428:                VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
                   3429:                if (tdvp == tvp)
                   3430:                        vrele(tdvp);
                   3431:                else
                   3432:                        vput(tdvp);
                   3433:                if (tvp)
                   3434:                        vput(tvp);
1.344     dholland 3435:                VFS_RENAMELOCK_EXIT(fs);
1.31      cgd      3436:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                   3437:                vrele(fromnd.ni_dvp);
                   3438:                vrele(fvp);
                   3439:        }
                   3440:        vrele(tond.ni_startdir);
1.161     thorpej  3441:        PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
1.31      cgd      3442: out1:
                   3443:        if (fromnd.ni_startdir)
                   3444:                vrele(fromnd.ni_startdir);
1.161     thorpej  3445:        PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
1.80      kleink   3446:        return (error == -1 ? 0 : error);
1.31      cgd      3447: }
                   3448:
                   3449: /*
                   3450:  * Make a directory file.
                   3451:  */
                   3452: /* ARGSUSED */
1.63      christos 3453: int
1.335     dsl      3454: sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval)
1.56      thorpej  3455: {
1.335     dsl      3456:        /* {
1.74      cgd      3457:                syscallarg(const char *) path;
1.35      cgd      3458:                syscallarg(int) mode;
1.335     dsl      3459:        } */
1.179     thorpej  3460:        struct proc *p = l->l_proc;
1.155     augustss 3461:        struct vnode *vp;
1.31      cgd      3462:        struct vattr vattr;
                   3463:        int error;
                   3464:        struct nameidata nd;
                   3465:
1.310     dsl      3466:        NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    3467:            SCARG(uap, path));
1.63      christos 3468:        if ((error = namei(&nd)) != 0)
1.31      cgd      3469:                return (error);
                   3470:        vp = nd.ni_vp;
                   3471:        if (vp != NULL) {
                   3472:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   3473:                if (nd.ni_dvp == vp)
                   3474:                        vrele(nd.ni_dvp);
                   3475:                else
                   3476:                        vput(nd.ni_dvp);
                   3477:                vrele(vp);
                   3478:                return (EEXIST);
                   3479:        }
                   3480:        VATTR_NULL(&vattr);
                   3481:        vattr.va_type = VDIR;
1.328     ad       3482:        /* We will read cwdi->cwdi_cmask unlocked. */
1.134     thorpej  3483:        vattr.va_mode =
                   3484:            (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
1.31      cgd      3485:        error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
                   3486:        if (!error)
                   3487:                vput(nd.ni_vp);
                   3488:        return (error);
                   3489: }
                   3490:
                   3491: /*
                   3492:  * Remove a directory file.
                   3493:  */
                   3494: /* ARGSUSED */
1.63      christos 3495: int
1.335     dsl      3496: sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval)
1.56      thorpej  3497: {
1.335     dsl      3498:        /* {
1.74      cgd      3499:                syscallarg(const char *) path;
1.335     dsl      3500:        } */
1.155     augustss 3501:        struct vnode *vp;
1.31      cgd      3502:        int error;
                   3503:        struct nameidata nd;
                   3504:
1.310     dsl      3505:        NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    3506:            SCARG(uap, path));
1.63      christos 3507:        if ((error = namei(&nd)) != 0)
1.31      cgd      3508:                return (error);
                   3509:        vp = nd.ni_vp;
                   3510:        if (vp->v_type != VDIR) {
                   3511:                error = ENOTDIR;
                   3512:                goto out;
                   3513:        }
                   3514:        /*
                   3515:         * No rmdir "." please.
                   3516:         */
                   3517:        if (nd.ni_dvp == vp) {
                   3518:                error = EINVAL;
                   3519:                goto out;
                   3520:        }
                   3521:        /*
                   3522:         * The root of a mounted filesystem cannot be deleted.
                   3523:         */
1.350     joerg    3524:        if ((vp->v_vflag & VV_ROOT) != 0 || vp->v_mountedhere != NULL) {
1.31      cgd      3525:                error = EBUSY;
1.197     hannken  3526:                goto out;
                   3527:        }
                   3528:        error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
                   3529:        return (error);
                   3530:
                   3531: out:
                   3532:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   3533:        if (nd.ni_dvp == vp)
                   3534:                vrele(nd.ni_dvp);
                   3535:        else
                   3536:                vput(nd.ni_dvp);
                   3537:        vput(vp);
1.31      cgd      3538:        return (error);
                   3539: }
                   3540:
                   3541: /*
                   3542:  * Read a block of directory entries in a file system independent format.
                   3543:  */
1.63      christos 3544: int
1.335     dsl      3545: sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval)
1.56      thorpej  3546: {
1.335     dsl      3547:        /* {
1.35      cgd      3548:                syscallarg(int) fd;
                   3549:                syscallarg(char *) buf;
1.101     fvdl     3550:                syscallarg(size_t) count;
1.335     dsl      3551:        } */
1.346     ad       3552:        file_t *fp;
1.101     fvdl     3553:        int error, done;
1.31      cgd      3554:
1.346     ad       3555:        /* fd_getvnode() will use the descriptor for us */
                   3556:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3557:                return (error);
1.135     thorpej  3558:        if ((fp->f_flag & FREAD) == 0) {
                   3559:                error = EBADF;
                   3560:                goto out;
                   3561:        }
1.101     fvdl     3562:        error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
1.234     christos 3563:                        SCARG(uap, count), &done, l, 0, 0);
1.325     ad       3564:        ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error);
1.101     fvdl     3565:        *retval = done;
1.135     thorpej  3566:  out:
1.346     ad       3567:        fd_putfile(SCARG(uap, fd));
1.31      cgd      3568:        return (error);
                   3569: }
                   3570:
                   3571: /*
                   3572:  * Set the mode mask for creation of filesystem nodes.
                   3573:  */
1.56      thorpej  3574: int
1.335     dsl      3575: sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval)
1.56      thorpej  3576: {
1.335     dsl      3577:        /* {
1.103     mycroft  3578:                syscallarg(mode_t) newmask;
1.335     dsl      3579:        } */
1.179     thorpej  3580:        struct proc *p = l->l_proc;
1.134     thorpej  3581:        struct cwdinfo *cwdi;
1.31      cgd      3582:
1.328     ad       3583:        /*
                   3584:         * cwdi->cwdi_cmask will be read unlocked elsewhere.  What's
                   3585:         * important is that we serialize changes to the mask.  The
                   3586:         * rw_exit() will issue a write memory barrier on our behalf,
                   3587:         * and force the changes out to other CPUs (as it must use an
                   3588:         * atomic operation, draining the local CPU's store buffers).
                   3589:         */
1.134     thorpej  3590:        cwdi = p->p_cwdi;
1.328     ad       3591:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  3592:        *retval = cwdi->cwdi_cmask;
                   3593:        cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
1.328     ad       3594:        rw_exit(&cwdi->cwdi_lock);
                   3595:
1.31      cgd      3596:        return (0);
                   3597: }
                   3598:
1.340     elad     3599: int
                   3600: dorevoke(struct vnode *vp, kauth_cred_t cred)
                   3601: {
                   3602:        struct vattr vattr;
                   3603:        int error;
                   3604:
                   3605:        if ((error = VOP_GETATTR(vp, &vattr, cred)) != 0)
1.342     ad       3606:                return error;
1.385     enami    3607:        if (kauth_cred_geteuid(cred) == vattr.va_uid ||
1.340     elad     3608:            (error = kauth_authorize_generic(cred,
1.342     ad       3609:            KAUTH_GENERIC_ISSUSER, NULL)) == 0)
1.340     elad     3610:                VOP_REVOKE(vp, REVOKEALL);
                   3611:        return (error);
                   3612: }
                   3613:
1.31      cgd      3614: /*
                   3615:  * Void all references to file by ripping underlying filesystem
                   3616:  * away from vnode.
                   3617:  */
                   3618: /* ARGSUSED */
1.63      christos 3619: int
1.335     dsl      3620: sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval)
1.56      thorpej  3621: {
1.335     dsl      3622:        /* {
1.74      cgd      3623:                syscallarg(const char *) path;
1.335     dsl      3624:        } */
1.155     augustss 3625:        struct vnode *vp;
1.31      cgd      3626:        int error;
                   3627:        struct nameidata nd;
                   3628:
1.331     pooka    3629:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
1.334     pooka    3630:            SCARG(uap, path));
1.63      christos 3631:        if ((error = namei(&nd)) != 0)
1.31      cgd      3632:                return (error);
                   3633:        vp = nd.ni_vp;
1.340     elad     3634:        error = dorevoke(vp, l->l_cred);
1.31      cgd      3635:        vrele(vp);
                   3636:        return (error);
                   3637: }

CVSweb <webmaster@jp.NetBSD.org>