[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.486

1.486   ! dholland    1: /*     $NetBSD: vfs_syscalls.c,v 1.485 2014/06/26 01:46:03 christos Exp $      */
1.345     ad          2:
                      3: /*-
1.390     ad          4:  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
1.345     ad          5:  * All rights reserved.
                      6:  *
1.390     ad          7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Andrew Doran.
                      9:  *
1.345     ad         10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
1.31      cgd        31:
                     32: /*
                     33:  * Copyright (c) 1989, 1993
                     34:  *     The Regents of the University of California.  All rights reserved.
                     35:  * (c) UNIX System Laboratories, Inc.
                     36:  * All or some portions of this file are derived from material licensed
                     37:  * to the University of California by American Telephone and Telegraph
                     38:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     39:  * the permission of UNIX System Laboratories, Inc.
                     40:  *
                     41:  * Redistribution and use in source and binary forms, with or without
                     42:  * modification, are permitted provided that the following conditions
                     43:  * are met:
                     44:  * 1. Redistributions of source code must retain the above copyright
                     45:  *    notice, this list of conditions and the following disclaimer.
                     46:  * 2. Redistributions in binary form must reproduce the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer in the
                     48:  *    documentation and/or other materials provided with the distribution.
1.191     agc        49:  * 3. Neither the name of the University nor the names of its contributors
1.31      cgd        50:  *    may be used to endorse or promote products derived from this software
                     51:  *    without specific prior written permission.
                     52:  *
                     53:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     54:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     55:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     56:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     57:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     58:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     59:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     60:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     61:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     62:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     63:  * SUCH DAMAGE.
                     64:  *
1.113     fvdl       65:  *     @(#)vfs_syscalls.c      8.42 (Berkeley) 7/31/95
1.31      cgd        66:  */
1.173     lukem      67:
1.420     rmind      68: /*
                     69:  * Virtual File System System Calls
                     70:  */
                     71:
1.173     lukem      72: #include <sys/cdefs.h>
1.486   ! dholland   73: __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.485 2014/06/26 01:46:03 christos Exp $");
1.111     mrg        74:
1.378     ad         75: #ifdef _KERNEL_OPT
1.258     elad       76: #include "opt_fileassoc.h"
1.261     dogcow     77: #include "veriexec.h"
1.378     ad         78: #endif
1.31      cgd        79:
                     80: #include <sys/param.h>
                     81: #include <sys/systm.h>
                     82: #include <sys/namei.h>
                     83: #include <sys/filedesc.h>
                     84: #include <sys/kernel.h>
                     85: #include <sys/file.h>
1.433     manu       86: #include <sys/fcntl.h>
1.31      cgd        87: #include <sys/stat.h>
                     88: #include <sys/vnode.h>
                     89: #include <sys/mount.h>
                     90: #include <sys/proc.h>
                     91: #include <sys/uio.h>
1.248     yamt       92: #include <sys/kmem.h>
1.31      cgd        93: #include <sys/dirent.h>
1.172     simonb     94: #include <sys/sysctl.h>
1.35      cgd        95: #include <sys/syscallargs.h>
1.306     dsl        96: #include <sys/vfs_syscalls.h>
1.444     dholland   97: #include <sys/quota.h>
                     98: #include <sys/quotactl.h>
1.192     drochner   99: #include <sys/ktrace.h>
1.251     elad      100: #ifdef FILEASSOC
                    101: #include <sys/fileassoc.h>
                    102: #endif /* FILEASSOC */
1.430     manu      103: #include <sys/extattr.h>
1.219     blymn     104: #include <sys/verified_exec.h>
1.242     elad      105: #include <sys/kauth.h>
1.346     ad        106: #include <sys/atomic.h>
1.360     ad        107: #include <sys/module.h>
1.380     pooka     108: #include <sys/buf.h>
1.35      cgd       109:
1.148     fvdl      110: #include <miscfs/genfs/genfs.h>
                    111: #include <miscfs/syncfs/syncfs.h>
1.342     ad        112: #include <miscfs/specfs/specdev.h>
1.181     thorpej   113:
1.232     jmmv      114: #include <nfs/rpcv2.h>
                    115: #include <nfs/nfsproto.h>
                    116: #include <nfs/nfs.h>
                    117: #include <nfs/nfs_var.h>
                    118:
1.234     christos  119: static int change_flags(struct vnode *, u_long, struct lwp *);
1.476     njoly     120: static int change_mode(struct vnode *, int, struct lwp *);
1.234     christos  121: static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
1.460     manu      122: static int do_sys_openat(lwp_t *, int, const char *, int, int, int *);
                    123: static int do_sys_mkdirat(struct lwp *l, int, const char *, mode_t,
                    124:     enum uio_seg);
                    125: static int do_sys_mkfifoat(struct lwp *, int, const char *, mode_t);
                    126: static int do_sys_symlinkat(struct lwp *, const char *, int, const char *,
                    127:     enum uio_seg);
                    128: static int do_sys_renameat(struct lwp *l, int, const char *, int, const char *,
                    129:     enum uio_seg, int);
                    130: static int do_sys_readlinkat(struct lwp *, int, const char *, char *,
                    131:     size_t, register_t *);
                    132: static int do_sys_unlinkat(struct lwp *, int, const char *, int, enum uio_seg);
                    133:
                    134: static int fd_nameiat(struct lwp *, int, struct nameidata *);
                    135: static int fd_nameiat_simple_user(struct lwp *, int, const char *,
                    136:     namei_simple_flags_t, struct vnode **);
                    137:
1.63      christos  138:
1.99      thorpej   139: /*
                    140:  * This table is used to maintain compatibility with 4.3BSD
1.378     ad        141:  * and NetBSD 0.9 mount syscalls - and possibly other systems.
                    142:  * Note, the order is important!
1.124     thorpej   143:  *
1.167     jdolecek  144:  * Do not modify this table. It should only contain filesystems
                    145:  * supported by NetBSD 0.9 and 4.3BSD.
1.99      thorpej   146:  */
1.167     jdolecek  147: const char * const mountcompatnames[] = {
1.99      thorpej   148:        NULL,           /* 0 = MOUNT_NONE */
1.167     jdolecek  149:        MOUNT_FFS,      /* 1 = MOUNT_UFS */
1.99      thorpej   150:        MOUNT_NFS,      /* 2 */
                    151:        MOUNT_MFS,      /* 3 */
                    152:        MOUNT_MSDOS,    /* 4 */
1.167     jdolecek  153:        MOUNT_CD9660,   /* 5 = MOUNT_ISOFS */
                    154:        MOUNT_FDESC,    /* 6 */
                    155:        MOUNT_KERNFS,   /* 7 */
                    156:        NULL,           /* 8 = MOUNT_DEVFS */
                    157:        MOUNT_AFS,      /* 9 */
1.99      thorpej   158: };
1.420     rmind     159:
                    160: const int nmountcompatnames = __arraycount(mountcompatnames);
1.99      thorpej   161:
1.460     manu      162: static int
                    163: fd_nameiat(struct lwp *l, int fdat, struct nameidata *ndp)
                    164: {
                    165:        file_t *dfp;
                    166:        int error;
                    167:
                    168:        if (fdat != AT_FDCWD) {
                    169:                if ((error = fd_getvnode(fdat, &dfp)) != 0)
                    170:                        goto out;
                    171:
                    172:                NDAT(ndp, dfp->f_data);
                    173:        }
                    174:
                    175:        error = namei(ndp);
                    176:
                    177:        if (fdat != AT_FDCWD)
                    178:                fd_putfile(fdat);
                    179: out:
                    180:        return error;
                    181: }
                    182:
                    183: static int
                    184: fd_nameiat_simple_user(struct lwp *l, int fdat, const char *path,
                    185:     namei_simple_flags_t sflags, struct vnode **vp_ret)
                    186: {
                    187:        file_t *dfp;
                    188:        struct vnode *dvp;
                    189:        int error;
                    190:
                    191:        if (fdat != AT_FDCWD) {
                    192:                if ((error = fd_getvnode(fdat, &dfp)) != 0)
                    193:                        goto out;
                    194:
                    195:                dvp = dfp->f_data;
                    196:        } else {
                    197:                dvp = NULL;
                    198:        }
                    199:
                    200:        error = nameiat_simple_user(dvp, path, sflags, vp_ret);
                    201:
                    202:        if (fdat != AT_FDCWD)
                    203:                fd_putfile(fdat);
                    204: out:
                    205:        return error;
                    206: }
                    207:
1.285     elad      208: static int
1.422     christos  209: open_setfp(struct lwp *l, file_t *fp, struct vnode *vp, int indx, int flags)
                    210: {
                    211:        int error;
                    212:
                    213:        fp->f_flag = flags & FMASK;
                    214:        fp->f_type = DTYPE_VNODE;
                    215:        fp->f_ops = &vnops;
                    216:        fp->f_data = vp;
                    217:
                    218:        if (flags & (O_EXLOCK | O_SHLOCK)) {
                    219:                struct flock lf;
                    220:                int type;
                    221:
                    222:                lf.l_whence = SEEK_SET;
                    223:                lf.l_start = 0;
                    224:                lf.l_len = 0;
                    225:                if (flags & O_EXLOCK)
                    226:                        lf.l_type = F_WRLCK;
                    227:                else
                    228:                        lf.l_type = F_RDLCK;
                    229:                type = F_FLOCK;
                    230:                if ((flags & FNONBLOCK) == 0)
                    231:                        type |= F_WAIT;
                    232:                VOP_UNLOCK(vp);
                    233:                error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
                    234:                if (error) {
                    235:                        (void) vn_close(vp, fp->f_flag, fp->f_cred);
                    236:                        fd_abort(l->l_proc, fp, indx);
                    237:                        return error;
                    238:                }
                    239:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                    240:                atomic_or_uint(&fp->f_flag, FHASLOCK);
                    241:        }
                    242:        if (flags & O_CLOEXEC)
                    243:                fd_set_exclose(l, indx, true);
                    244:        return 0;
                    245: }
                    246:
                    247: static int
1.283     elad      248: mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324     pooka     249:     void *data, size_t *data_len)
1.56      thorpej   250: {
1.113     fvdl      251:        struct mount *mp;
1.283     elad      252:        int error = 0, saved_flags;
                    253:
                    254:        mp = vp->v_mount;
                    255:        saved_flags = mp->mnt_flag;
                    256:
1.329     ad        257:        /* We can operate only on VV_ROOT nodes. */
                    258:        if ((vp->v_vflag & VV_ROOT) == 0) {
                    259:                error = EINVAL;
                    260:                goto out;
                    261:        }
1.31      cgd       262:
1.218     yamt      263:        /*
1.283     elad      264:         * We only allow the filesystem to be reloaded if it
1.373     ad        265:         * is currently mounted read-only.  Additionally, we
                    266:         * prevent read-write to read-only downgrades.
1.283     elad      267:         */
1.373     ad        268:        if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
1.414     pooka     269:            (mp->mnt_flag & MNT_RDONLY) == 0 &&
                    270:            (mp->mnt_iflag & IMNT_CAN_RWTORO) == 0) {
1.329     ad        271:                error = EOPNOTSUPP;     /* Needs translation */
                    272:                goto out;
                    273:        }
1.292     elad      274:
                    275:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    276:            KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
                    277:        if (error)
1.329     ad        278:                goto out;
1.292     elad      279:
1.358     ad        280:        if (vfs_busy(mp, NULL)) {
1.329     ad        281:                error = EPERM;
                    282:                goto out;
                    283:        }
1.283     elad      284:
1.358     ad        285:        mutex_enter(&mp->mnt_updating);
                    286:
1.286     yamt      287:        mp->mnt_flag &= ~MNT_OP_FLAGS;
1.441     christos  288:        mp->mnt_flag |= flags & MNT_OP_FLAGS;
1.286     yamt      289:
1.283     elad      290:        /*
                    291:         * Set the mount level flags.
                    292:         */
                    293:        if (flags & MNT_RDONLY)
                    294:                mp->mnt_flag |= MNT_RDONLY;
                    295:        else if (mp->mnt_flag & MNT_RDONLY)
                    296:                mp->mnt_iflag |= IMNT_WANTRDWR;
1.441     christos  297:        mp->mnt_flag &= ~MNT_BASIC_FLAGS;
                    298:        mp->mnt_flag |= flags & MNT_BASIC_FLAGS;
1.332     pooka     299:        error = VFS_MOUNT(mp, path, data, data_len);
1.283     elad      300:
1.320     dsl       301:        if (error && data != NULL) {
1.283     elad      302:                int error2;
                    303:
1.378     ad        304:                /*
                    305:                 * Update failed; let's try and see if it was an
1.379     ad        306:                 * export request.  For compat with 3.0 and earlier.
1.378     ad        307:                 */
1.381     ad        308:                error2 = vfs_hooks_reexport(mp, path, data);
1.283     elad      309:
1.381     ad        310:                /*
                    311:                 * Only update error code if the export request was
1.283     elad      312:                 * understood but some problem occurred while
1.381     ad        313:                 * processing it.
                    314:                 */
1.283     elad      315:                if (error2 != EJUSTRETURN)
                    316:                        error = error2;
                    317:        }
1.381     ad        318:
1.283     elad      319:        if (mp->mnt_iflag & IMNT_WANTRDWR)
                    320:                mp->mnt_flag &= ~MNT_RDONLY;
                    321:        if (error)
                    322:                mp->mnt_flag = saved_flags;
1.286     yamt      323:        mp->mnt_flag &= ~MNT_OP_FLAGS;
                    324:        mp->mnt_iflag &= ~IMNT_WANTRDWR;
1.283     elad      325:        if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
                    326:                if (mp->mnt_syncer == NULL)
                    327:                        error = vfs_allocate_syncvnode(mp);
1.125     tls       328:        } else {
1.283     elad      329:                if (mp->mnt_syncer != NULL)
                    330:                        vfs_deallocate_syncvnode(mp);
                    331:        }
1.358     ad        332:        mutex_exit(&mp->mnt_updating);
1.354     ad        333:        vfs_unbusy(mp, false, NULL);
1.283     elad      334:
1.430     manu      335:        if ((error == 0) && !(saved_flags & MNT_EXTATTR) &&
                    336:            (flags & MNT_EXTATTR)) {
1.452     manu      337:                if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_START,
1.430     manu      338:                                   NULL, 0, NULL) != 0) {
                    339:                        printf("%s: failed to start extattr, error = %d",
1.452     manu      340:                               mp->mnt_stat.f_mntonname, error);
1.430     manu      341:                        mp->mnt_flag &= ~MNT_EXTATTR;
                    342:                }
                    343:        }
                    344:
                    345:        if ((error == 0) && (saved_flags & MNT_EXTATTR) &&
                    346:            !(flags & MNT_EXTATTR)) {
1.452     manu      347:                if (VFS_EXTATTRCTL(mp, EXTATTR_CMD_STOP,
1.430     manu      348:                                   NULL, 0, NULL) != 0) {
                    349:                        printf("%s: failed to stop extattr, error = %d",
1.452     manu      350:                               mp->mnt_stat.f_mntonname, error);
1.430     manu      351:                        mp->mnt_flag |= MNT_RDONLY;
                    352:                }
                    353:        }
1.329     ad        354:  out:
1.283     elad      355:        return (error);
                    356: }
                    357:
1.285     elad      358: static int
1.320     dsl       359: mount_get_vfsops(const char *fstype, struct vfsops **vfsops)
1.283     elad      360: {
1.322     christos  361:        char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)];
1.283     elad      362:        int error;
                    363:
1.320     dsl       364:        /* Copy file-system type from userspace.  */
1.322     christos  365:        error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
1.63      christos  366:        if (error) {
1.54      cgd       367:                /*
1.227     jmmv      368:                 * Historically, filesystem types were identified by numbers.
1.54      cgd       369:                 * If we get an integer for the filesystem type instead of a
                    370:                 * string, we check to see if it matches one of the historic
                    371:                 * filesystem types.
1.205     junyoung  372:                 */
1.283     elad      373:                u_long fsindex = (u_long)fstype;
1.99      thorpej   374:                if (fsindex >= nmountcompatnames ||
1.320     dsl       375:                    mountcompatnames[fsindex] == NULL)
                    376:                        return ENODEV;
1.331     pooka     377:                strlcpy(fstypename, mountcompatnames[fsindex],
                    378:                    sizeof(fstypename));
1.31      cgd       379:        }
1.283     elad      380:
1.378     ad        381:        /* Accept `ufs' as an alias for `ffs', for compatibility. */
1.320     dsl       382:        if (strcmp(fstypename, "ufs") == 0)
                    383:                fstypename[0] = 'f';
1.285     elad      384:
1.360     ad        385:        if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                    386:                return 0;
                    387:
                    388:        /* If we can autoload a vfs module, try again */
1.400     martin    389:        (void)module_autoload(fstypename, MODULE_CLASS_VFS);
1.360     ad        390:
                    391:        if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                    392:                return 0;
                    393:
                    394:        return ENODEV;
1.320     dsl       395: }
                    396:
                    397: static int
1.283     elad      398: mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags,
1.324     pooka     399:     void *data, size_t *data_len)
1.283     elad      400: {
                    401:        struct mount *mp;
                    402:        int error;
                    403:
1.289     elad      404:        /* If MNT_GETARGS is specified, it should be the only flag. */
1.320     dsl       405:        if (flags & ~MNT_GETARGS)
                    406:                return EINVAL;
1.289     elad      407:
1.283     elad      408:        mp = vp->v_mount;
                    409:
1.292     elad      410:        /* XXX: probably some notion of "can see" here if we want isolation. */
                    411:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    412:            KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
                    413:        if (error)
1.320     dsl       414:                return error;
1.292     elad      415:
1.329     ad        416:        if ((vp->v_vflag & VV_ROOT) == 0)
1.320     dsl       417:                return EINVAL;
1.283     elad      418:
1.358     ad        419:        if (vfs_busy(mp, NULL))
1.320     dsl       420:                return EPERM;
1.283     elad      421:
1.358     ad        422:        mutex_enter(&mp->mnt_updating);
1.286     yamt      423:        mp->mnt_flag &= ~MNT_OP_FLAGS;
                    424:        mp->mnt_flag |= MNT_GETARGS;
1.332     pooka     425:        error = VFS_MOUNT(mp, path, data, data_len);
1.286     yamt      426:        mp->mnt_flag &= ~MNT_OP_FLAGS;
1.358     ad        427:        mutex_exit(&mp->mnt_updating);
1.283     elad      428:
1.354     ad        429:        vfs_unbusy(mp, false, NULL);
1.283     elad      430:        return (error);
                    431: }
                    432:
1.321     dsl       433: int
1.335     dsl       434: sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
1.321     dsl       435: {
1.335     dsl       436:        /* {
1.321     dsl       437:                syscallarg(const char *) type;
                    438:                syscallarg(const char *) path;
                    439:                syscallarg(int) flags;
                    440:                syscallarg(void *) data;
                    441:                syscallarg(size_t) data_len;
1.335     dsl       442:        } */
1.321     dsl       443:
                    444:        return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
                    445:            SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE,
                    446:            SCARG(uap, data_len), retval);
                    447: }
1.320     dsl       448:
                    449: int
                    450: do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type,
                    451:     const char *path, int flags, void *data, enum uio_seg data_seg,
                    452:     size_t data_len, register_t *retval)
                    453: {
1.283     elad      454:        struct vnode *vp;
1.320     dsl       455:        void *data_buf = data;
1.403     pooka     456:        bool vfsopsrele = false;
1.482     maxv      457:        size_t alloc_sz = 0;
1.283     elad      458:        int error;
                    459:
1.403     pooka     460:        /* XXX: The calling convention of this routine is totally bizarre */
                    461:        if (vfsops)
                    462:                vfsopsrele = true;
                    463:
1.283     elad      464:        /*
                    465:         * Get vnode to be covered
                    466:         */
1.395     dholland  467:        error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
1.403     pooka     468:        if (error != 0) {
                    469:                vp = NULL;
                    470:                goto done;
                    471:        }
1.283     elad      472:
1.320     dsl       473:        if (vfsops == NULL) {
1.361     ad        474:                if (flags & (MNT_GETARGS | MNT_UPDATE)) {
1.320     dsl       475:                        vfsops = vp->v_mount->mnt_op;
1.361     ad        476:                } else {
1.320     dsl       477:                        /* 'type' is userspace */
                    478:                        error = mount_get_vfsops(type, &vfsops);
                    479:                        if (error != 0)
                    480:                                goto done;
1.403     pooka     481:                        vfsopsrele = true;
1.320     dsl       482:                }
                    483:        }
                    484:
1.479     maxv      485:        /*
                    486:         * We allow data to be NULL, even for userspace. Some fs's don't need
                    487:         * it. The others will handle NULL.
                    488:         */
1.320     dsl       489:        if (data != NULL && data_seg == UIO_USERSPACE) {
                    490:                if (data_len == 0) {
                    491:                        /* No length supplied, use default for filesystem */
                    492:                        data_len = vfsops->vfs_min_mount_data;
1.478     maxv      493:
1.378     ad        494:                        /*
                    495:                         * Hopefully a longer buffer won't make copyin() fail.
                    496:                         * For compatibility with 3.0 and earlier.
                    497:                         */
1.320     dsl       498:                        if (flags & MNT_UPDATE
                    499:                            && data_len < sizeof (struct mnt_export_args30))
                    500:                                data_len = sizeof (struct mnt_export_args30);
                    501:                }
1.480     maxv      502:                if ((data_len == 0) || (data_len > VFS_MAX_MOUNT_DATA)) {
1.478     maxv      503:                        error = EINVAL;
                    504:                        goto done;
                    505:                }
1.482     maxv      506:                alloc_sz = data_len;
                    507:                data_buf = kmem_alloc(alloc_sz, KM_SLEEP);
1.283     elad      508:
1.320     dsl       509:                /* NFS needs the buffer even for mnt_getargs .... */
                    510:                error = copyin(data, data_buf, data_len);
                    511:                if (error != 0)
                    512:                        goto done;
                    513:        }
                    514:
                    515:        if (flags & MNT_GETARGS) {
                    516:                if (data_len == 0) {
                    517:                        error = EINVAL;
                    518:                        goto done;
                    519:                }
1.324     pooka     520:                error = mount_getargs(l, vp, path, flags, data_buf, &data_len);
1.320     dsl       521:                if (error != 0)
                    522:                        goto done;
                    523:                if (data_seg == UIO_USERSPACE)
                    524:                        error = copyout(data_buf, data, data_len);
                    525:                *retval = data_len;
                    526:        } else if (flags & MNT_UPDATE) {
1.324     pooka     527:                error = mount_update(l, vp, path, flags, data_buf, &data_len);
1.283     elad      528:        } else {
                    529:                /* Locking is handled internally in mount_domount(). */
1.403     pooka     530:                KASSERT(vfsopsrele == true);
1.320     dsl       531:                error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
1.405     hannken   532:                    &data_len);
1.403     pooka     533:                vfsopsrele = false;
1.283     elad      534:        }
                    535:
1.320     dsl       536:     done:
1.403     pooka     537:        if (vfsopsrele)
                    538:                vfs_delref(vfsops);
1.337     ad        539:        if (vp != NULL) {
1.405     hannken   540:                vrele(vp);
1.337     ad        541:        }
1.320     dsl       542:        if (data_buf != data)
1.482     maxv      543:                kmem_free(data_buf, alloc_sz);
1.31      cgd       544:        return (error);
                    545: }
                    546:
                    547: /*
                    548:  * Unmount a file system.
                    549:  *
                    550:  * Note: unmount takes a path to the vnode mounted on as argument,
                    551:  * not special file (as before).
                    552:  */
                    553: /* ARGSUSED */
1.63      christos  554: int
1.335     dsl       555: sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval)
1.56      thorpej   556: {
1.335     dsl       557:        /* {
1.74      cgd       558:                syscallarg(const char *) path;
1.35      cgd       559:                syscallarg(int) flags;
1.335     dsl       560:        } */
1.155     augustss  561:        struct vnode *vp;
1.31      cgd       562:        struct mount *mp;
                    563:        int error;
1.409     dholland  564:        struct pathbuf *pb;
1.31      cgd       565:        struct nameidata nd;
                    566:
1.409     dholland  567:        error = pathbuf_copyin(SCARG(uap, path), &pb);
                    568:        if (error) {
                    569:                return error;
                    570:        }
                    571:
                    572:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
                    573:        if ((error = namei(&nd)) != 0) {
                    574:                pathbuf_destroy(pb);
                    575:                return error;
                    576:        }
1.31      cgd       577:        vp = nd.ni_vp;
1.409     dholland  578:        pathbuf_destroy(pb);
                    579:
1.43      mycroft   580:        mp = vp->v_mount;
1.358     ad        581:        atomic_inc_uint(&mp->mnt_refcnt);
1.406     hannken   582:        VOP_UNLOCK(vp);
1.31      cgd       583:
1.295     elad      584:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
                    585:            KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
                    586:        if (error) {
1.345     ad        587:                vrele(vp);
1.358     ad        588:                vfs_destroy(mp);
1.31      cgd       589:                return (error);
                    590:        }
                    591:
                    592:        /*
1.47      mycroft   593:         * Don't allow unmounting the root file system.
                    594:         */
                    595:        if (mp->mnt_flag & MNT_ROOTFS) {
1.345     ad        596:                vrele(vp);
1.358     ad        597:                vfs_destroy(mp);
1.47      mycroft   598:                return (EINVAL);
                    599:        }
                    600:
                    601:        /*
1.31      cgd       602:         * Must be the root of the filesystem
                    603:         */
1.329     ad        604:        if ((vp->v_vflag & VV_ROOT) == 0) {
1.345     ad        605:                vrele(vp);
1.358     ad        606:                vfs_destroy(mp);
1.31      cgd       607:                return (EINVAL);
                    608:        }
1.78      fvdl      609:
1.359     ad        610:        vrele(vp);
1.358     ad        611:        error = dounmount(mp, SCARG(uap, flags), l);
1.374     ad        612:        vfs_destroy(mp);
1.358     ad        613:        return error;
1.31      cgd       614: }
                    615:
                    616: /*
                    617:  * Sync each mounted filesystem.
                    618:  */
                    619: #ifdef DEBUG
                    620: int syncprt = 0;
                    621: struct ctldebug debug0 = { "syncprt", &syncprt };
                    622: #endif
                    623:
1.425     dsl       624: void
                    625: do_sys_sync(struct lwp *l)
1.31      cgd       626: {
1.155     augustss  627:        struct mount *mp, *nmp;
1.31      cgd       628:        int asyncflag;
1.257     ad        629:
1.329     ad        630:        mutex_enter(&mountlist_lock);
1.471     christos  631:        for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
1.358     ad        632:                if (vfs_busy(mp, &nmp)) {
1.113     fvdl      633:                        continue;
                    634:                }
1.358     ad        635:                mutex_enter(&mp->mnt_updating);
1.307     hannken   636:                if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1.31      cgd       637:                        asyncflag = mp->mnt_flag & MNT_ASYNC;
                    638:                        mp->mnt_flag &= ~MNT_ASYNC;
1.332     pooka     639:                        VFS_SYNC(mp, MNT_NOWAIT, l->l_cred);
1.31      cgd       640:                        if (asyncflag)
1.113     fvdl      641:                                 mp->mnt_flag |= MNT_ASYNC;
1.31      cgd       642:                }
1.358     ad        643:                mutex_exit(&mp->mnt_updating);
1.354     ad        644:                vfs_unbusy(mp, false, &nmp);
1.31      cgd       645:        }
1.329     ad        646:        mutex_exit(&mountlist_lock);
1.31      cgd       647: #ifdef DEBUG
                    648:        if (syncprt)
                    649:                vfs_bufstats();
                    650: #endif /* DEBUG */
1.425     dsl       651: }
                    652:
                    653: /* ARGSUSED */
                    654: int
                    655: sys_sync(struct lwp *l, const void *v, register_t *retval)
                    656: {
                    657:        do_sys_sync(l);
1.31      cgd       658:        return (0);
                    659: }
                    660:
1.425     dsl       661:
1.31      cgd       662: /*
1.444     dholland  663:  * Access or change filesystem quotas.
                    664:  *
                    665:  * (this is really 14 different calls bundled into one)
1.31      cgd       666:  */
1.444     dholland  667:
                    668: static int
                    669: do_sys_quotactl_stat(struct mount *mp, struct quotastat *info_u)
                    670: {
                    671:        struct quotastat info_k;
                    672:        int error;
                    673:
                    674:        /* ensure any padding bytes are cleared */
                    675:        memset(&info_k, 0, sizeof(info_k));
                    676:
                    677:        error = vfs_quotactl_stat(mp, &info_k);
                    678:        if (error) {
                    679:                return error;
                    680:        }
                    681:
                    682:        return copyout(&info_k, info_u, sizeof(info_k));
                    683: }
                    684:
                    685: static int
                    686: do_sys_quotactl_idtypestat(struct mount *mp, int idtype,
                    687:     struct quotaidtypestat *info_u)
                    688: {
                    689:        struct quotaidtypestat info_k;
                    690:        int error;
                    691:
                    692:        /* ensure any padding bytes are cleared */
                    693:        memset(&info_k, 0, sizeof(info_k));
                    694:
                    695:        error = vfs_quotactl_idtypestat(mp, idtype, &info_k);
                    696:        if (error) {
                    697:                return error;
                    698:        }
                    699:
                    700:        return copyout(&info_k, info_u, sizeof(info_k));
                    701: }
                    702:
                    703: static int
                    704: do_sys_quotactl_objtypestat(struct mount *mp, int objtype,
                    705:     struct quotaobjtypestat *info_u)
                    706: {
                    707:        struct quotaobjtypestat info_k;
                    708:        int error;
                    709:
                    710:        /* ensure any padding bytes are cleared */
                    711:        memset(&info_k, 0, sizeof(info_k));
                    712:
                    713:        error = vfs_quotactl_objtypestat(mp, objtype, &info_k);
                    714:        if (error) {
                    715:                return error;
                    716:        }
                    717:
                    718:        return copyout(&info_k, info_u, sizeof(info_k));
                    719: }
                    720:
                    721: static int
                    722: do_sys_quotactl_get(struct mount *mp, const struct quotakey *key_u,
                    723:     struct quotaval *val_u)
                    724: {
                    725:        struct quotakey key_k;
                    726:        struct quotaval val_k;
                    727:        int error;
                    728:
                    729:        /* ensure any padding bytes are cleared */
                    730:        memset(&val_k, 0, sizeof(val_k));
                    731:
                    732:        error = copyin(key_u, &key_k, sizeof(key_k));
                    733:        if (error) {
                    734:                return error;
                    735:        }
                    736:
                    737:        error = vfs_quotactl_get(mp, &key_k, &val_k);
                    738:        if (error) {
                    739:                return error;
                    740:        }
                    741:
                    742:        return copyout(&val_k, val_u, sizeof(val_k));
                    743: }
                    744:
                    745: static int
                    746: do_sys_quotactl_put(struct mount *mp, const struct quotakey *key_u,
                    747:     const struct quotaval *val_u)
                    748: {
                    749:        struct quotakey key_k;
                    750:        struct quotaval val_k;
                    751:        int error;
                    752:
                    753:        error = copyin(key_u, &key_k, sizeof(key_k));
                    754:        if (error) {
                    755:                return error;
                    756:        }
                    757:
                    758:        error = copyin(val_u, &val_k, sizeof(val_k));
                    759:        if (error) {
                    760:                return error;
                    761:        }
                    762:
                    763:        return vfs_quotactl_put(mp, &key_k, &val_k);
                    764: }
                    765:
                    766: static int
1.486   ! dholland  767: do_sys_quotactl_del(struct mount *mp, const struct quotakey *key_u)
1.444     dholland  768: {
                    769:        struct quotakey key_k;
                    770:        int error;
                    771:
                    772:        error = copyin(key_u, &key_k, sizeof(key_k));
                    773:        if (error) {
                    774:                return error;
                    775:        }
                    776:
1.486   ! dholland  777:        return vfs_quotactl_del(mp, &key_k);
1.444     dholland  778: }
                    779:
                    780: static int
                    781: do_sys_quotactl_cursoropen(struct mount *mp, struct quotakcursor *cursor_u)
                    782: {
                    783:        struct quotakcursor cursor_k;
                    784:        int error;
                    785:
                    786:        /* ensure any padding bytes are cleared */
                    787:        memset(&cursor_k, 0, sizeof(cursor_k));
                    788:
                    789:        error = vfs_quotactl_cursoropen(mp, &cursor_k);
                    790:        if (error) {
                    791:                return error;
                    792:        }
                    793:
                    794:        return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
                    795: }
                    796:
                    797: static int
                    798: do_sys_quotactl_cursorclose(struct mount *mp, struct quotakcursor *cursor_u)
                    799: {
                    800:        struct quotakcursor cursor_k;
                    801:        int error;
                    802:
                    803:        error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
                    804:        if (error) {
                    805:                return error;
                    806:        }
                    807:
                    808:        return vfs_quotactl_cursorclose(mp, &cursor_k);
                    809: }
                    810:
                    811: static int
                    812: do_sys_quotactl_cursorskipidtype(struct mount *mp,
                    813:     struct quotakcursor *cursor_u, int idtype)
                    814: {
                    815:        struct quotakcursor cursor_k;
                    816:        int error;
                    817:
                    818:        error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
                    819:        if (error) {
                    820:                return error;
                    821:        }
                    822:
                    823:        error = vfs_quotactl_cursorskipidtype(mp, &cursor_k, idtype);
                    824:        if (error) {
                    825:                return error;
                    826:        }
                    827:
                    828:        return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
                    829: }
                    830:
                    831: static int
                    832: do_sys_quotactl_cursorget(struct mount *mp, struct quotakcursor *cursor_u,
                    833:     struct quotakey *keys_u, struct quotaval *vals_u, unsigned maxnum,
1.447     dholland  834:     unsigned *ret_u)
1.444     dholland  835: {
                    836: #define CGET_STACK_MAX 8
                    837:        struct quotakcursor cursor_k;
                    838:        struct quotakey stackkeys[CGET_STACK_MAX];
                    839:        struct quotaval stackvals[CGET_STACK_MAX];
                    840:        struct quotakey *keys_k;
                    841:        struct quotaval *vals_k;
1.447     dholland  842:        unsigned ret_k;
1.444     dholland  843:        int error;
                    844:
                    845:        if (maxnum > 128) {
                    846:                maxnum = 128;
                    847:        }
                    848:
                    849:        error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
                    850:        if (error) {
                    851:                return error;
                    852:        }
                    853:
                    854:        if (maxnum <= CGET_STACK_MAX) {
                    855:                keys_k = stackkeys;
                    856:                vals_k = stackvals;
                    857:                /* ensure any padding bytes are cleared */
                    858:                memset(keys_k, 0, maxnum * sizeof(keys_k[0]));
                    859:                memset(vals_k, 0, maxnum * sizeof(vals_k[0]));
                    860:        } else {
                    861:                keys_k = kmem_zalloc(maxnum * sizeof(keys_k[0]), KM_SLEEP);
                    862:                vals_k = kmem_zalloc(maxnum * sizeof(vals_k[0]), KM_SLEEP);
                    863:        }
                    864:
                    865:        error = vfs_quotactl_cursorget(mp, &cursor_k, keys_k, vals_k, maxnum,
                    866:                                       &ret_k);
                    867:        if (error) {
                    868:                goto fail;
                    869:        }
                    870:
                    871:        error = copyout(keys_k, keys_u, ret_k * sizeof(keys_k[0]));
                    872:        if (error) {
                    873:                goto fail;
                    874:        }
                    875:
                    876:        error = copyout(vals_k, vals_u, ret_k * sizeof(vals_k[0]));
                    877:        if (error) {
                    878:                goto fail;
                    879:        }
                    880:
                    881:        error = copyout(&ret_k, ret_u, sizeof(ret_k));
                    882:        if (error) {
                    883:                goto fail;
                    884:        }
                    885:
                    886:        /* do last to maximize the chance of being able to recover a failure */
                    887:        error = copyout(&cursor_k, cursor_u, sizeof(cursor_k));
                    888:
                    889: fail:
                    890:        if (keys_k != stackkeys) {
                    891:                kmem_free(keys_k, maxnum * sizeof(keys_k[0]));
                    892:        }
                    893:        if (vals_k != stackvals) {
                    894:                kmem_free(vals_k, maxnum * sizeof(vals_k[0]));
                    895:        }
                    896:        return error;
                    897: }
                    898:
                    899: static int
                    900: do_sys_quotactl_cursoratend(struct mount *mp, struct quotakcursor *cursor_u,
                    901:     int *ret_u)
                    902: {
                    903:        struct quotakcursor cursor_k;
                    904:        int ret_k;
                    905:        int error;
                    906:
                    907:        error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
                    908:        if (error) {
                    909:                return error;
                    910:        }
                    911:
                    912:        error = vfs_quotactl_cursoratend(mp, &cursor_k, &ret_k);
                    913:        if (error) {
                    914:                return error;
                    915:        }
                    916:
                    917:        error = copyout(&ret_k, ret_u, sizeof(ret_k));
                    918:        if (error) {
                    919:                return error;
                    920:        }
                    921:
                    922:        return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
                    923: }
                    924:
                    925: static int
                    926: do_sys_quotactl_cursorrewind(struct mount *mp, struct quotakcursor *cursor_u)
                    927: {
                    928:        struct quotakcursor cursor_k;
                    929:        int error;
                    930:
                    931:        error = copyin(cursor_u, &cursor_k, sizeof(cursor_k));
                    932:        if (error) {
                    933:                return error;
                    934:        }
                    935:
                    936:        error = vfs_quotactl_cursorrewind(mp, &cursor_k);
                    937:        if (error) {
                    938:                return error;
                    939:        }
                    940:
                    941:        return copyout(&cursor_k, cursor_u, sizeof(cursor_k));
                    942: }
                    943:
                    944: static int
                    945: do_sys_quotactl_quotaon(struct mount *mp, int idtype, const char *path_u)
                    946: {
                    947:        char *path_k;
                    948:        int error;
                    949:
                    950:        /* XXX this should probably be a struct pathbuf */
                    951:        path_k = PNBUF_GET();
                    952:        error = copyin(path_u, path_k, PATH_MAX);
                    953:        if (error) {
                    954:                PNBUF_PUT(path_k);
                    955:                return error;
                    956:        }
                    957:
                    958:        error = vfs_quotactl_quotaon(mp, idtype, path_k);
                    959:
                    960:        PNBUF_PUT(path_k);
                    961:        return error;
                    962: }
                    963:
                    964: static int
                    965: do_sys_quotactl_quotaoff(struct mount *mp, int idtype)
                    966: {
                    967:        return vfs_quotactl_quotaoff(mp, idtype);
                    968: }
                    969:
1.63      christos  970: int
1.445     dholland  971: do_sys_quotactl(const char *path_u, const struct quotactl_args *args)
1.56      thorpej   972: {
1.155     augustss  973:        struct mount *mp;
1.444     dholland  974:        struct vnode *vp;
1.31      cgd       975:        int error;
                    976:
1.445     dholland  977:        error = namei_simple_user(path_u, NSM_FOLLOW_TRYEMULROOT, &vp);
1.395     dholland  978:        if (error != 0)
1.31      cgd       979:                return (error);
1.395     dholland  980:        mp = vp->v_mount;
1.444     dholland  981:
1.445     dholland  982:        switch (args->qc_op) {
1.444     dholland  983:            case QUOTACTL_STAT:
1.446     dholland  984:                error = do_sys_quotactl_stat(mp, args->u.stat.qc_info);
1.444     dholland  985:                break;
                    986:            case QUOTACTL_IDTYPESTAT:
                    987:                error = do_sys_quotactl_idtypestat(mp,
1.445     dholland  988:                                args->u.idtypestat.qc_idtype,
                    989:                                args->u.idtypestat.qc_info);
1.444     dholland  990:                break;
                    991:            case QUOTACTL_OBJTYPESTAT:
                    992:                error = do_sys_quotactl_objtypestat(mp,
1.445     dholland  993:                                args->u.objtypestat.qc_objtype,
                    994:                                args->u.objtypestat.qc_info);
1.444     dholland  995:                break;
                    996:            case QUOTACTL_GET:
                    997:                error = do_sys_quotactl_get(mp,
1.445     dholland  998:                                args->u.get.qc_key,
1.446     dholland  999:                                args->u.get.qc_val);
1.444     dholland 1000:                break;
                   1001:            case QUOTACTL_PUT:
                   1002:                error = do_sys_quotactl_put(mp,
1.445     dholland 1003:                                args->u.put.qc_key,
                   1004:                                args->u.put.qc_val);
1.444     dholland 1005:                break;
1.486   ! dholland 1006:            case QUOTACTL_DEL:
        !          1007:                error = do_sys_quotactl_del(mp, args->u.del.qc_key);
1.444     dholland 1008:                break;
                   1009:            case QUOTACTL_CURSOROPEN:
                   1010:                error = do_sys_quotactl_cursoropen(mp,
1.445     dholland 1011:                                args->u.cursoropen.qc_cursor);
1.444     dholland 1012:                break;
                   1013:            case QUOTACTL_CURSORCLOSE:
                   1014:                error = do_sys_quotactl_cursorclose(mp,
1.445     dholland 1015:                                args->u.cursorclose.qc_cursor);
1.444     dholland 1016:                break;
                   1017:            case QUOTACTL_CURSORSKIPIDTYPE:
                   1018:                error = do_sys_quotactl_cursorskipidtype(mp,
1.445     dholland 1019:                                args->u.cursorskipidtype.qc_cursor,
                   1020:                                args->u.cursorskipidtype.qc_idtype);
1.444     dholland 1021:                break;
                   1022:            case QUOTACTL_CURSORGET:
                   1023:                error = do_sys_quotactl_cursorget(mp,
1.445     dholland 1024:                                args->u.cursorget.qc_cursor,
                   1025:                                args->u.cursorget.qc_keys,
                   1026:                                args->u.cursorget.qc_vals,
                   1027:                                args->u.cursorget.qc_maxnum,
                   1028:                                args->u.cursorget.qc_ret);
1.444     dholland 1029:                break;
                   1030:            case QUOTACTL_CURSORATEND:
                   1031:                error = do_sys_quotactl_cursoratend(mp,
1.445     dholland 1032:                                args->u.cursoratend.qc_cursor,
                   1033:                                args->u.cursoratend.qc_ret);
1.444     dholland 1034:                break;
                   1035:            case QUOTACTL_CURSORREWIND:
                   1036:                error = do_sys_quotactl_cursorrewind(mp,
1.445     dholland 1037:                                args->u.cursorrewind.qc_cursor);
1.444     dholland 1038:                break;
                   1039:            case QUOTACTL_QUOTAON:
                   1040:                error = do_sys_quotactl_quotaon(mp,
1.445     dholland 1041:                                args->u.quotaon.qc_idtype,
                   1042:                                args->u.quotaon.qc_quotafile);
1.444     dholland 1043:                break;
                   1044:            case QUOTACTL_QUOTAOFF:
                   1045:                error = do_sys_quotactl_quotaoff(mp,
1.445     dholland 1046:                                args->u.quotaoff.qc_idtype);
1.444     dholland 1047:                break;
                   1048:            default:
                   1049:                error = EINVAL;
                   1050:                break;
                   1051:        }
                   1052:
1.395     dholland 1053:        vrele(vp);
1.444     dholland 1054:        return error;
1.31      cgd      1055: }
                   1056:
1.445     dholland 1057: /* ARGSUSED */
                   1058: int
                   1059: sys___quotactl(struct lwp *l, const struct sys___quotactl_args *uap,
                   1060:     register_t *retval)
                   1061: {
                   1062:        /* {
                   1063:                syscallarg(const char *) path;
                   1064:                syscallarg(struct quotactl_args *) args;
                   1065:        } */
                   1066:        struct quotactl_args args;
                   1067:        int error;
                   1068:
                   1069:        error = copyin(SCARG(uap, args), &args, sizeof(args));
                   1070:        if (error) {
                   1071:                return error;
                   1072:        }
                   1073:
                   1074:        return do_sys_quotactl(SCARG(uap, path), &args);
                   1075: }
                   1076:
1.206     christos 1077: int
1.234     christos 1078: dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
1.185     christos 1079:     int root)
                   1080: {
1.234     christos 1081:        struct cwdinfo *cwdi = l->l_proc->p_cwdi;
1.185     christos 1082:        int error = 0;
                   1083:
                   1084:        /*
                   1085:         * If MNT_NOWAIT or MNT_LAZY is specified, do not
1.204     dbj      1086:         * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
1.185     christos 1087:         * overrides MNT_NOWAIT.
                   1088:         */
                   1089:        if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
                   1090:            (flags != MNT_WAIT && flags != 0)) {
                   1091:                memcpy(sp, &mp->mnt_stat, sizeof(*sp));
                   1092:                goto done;
                   1093:        }
1.205     junyoung 1094:
1.211     jdolecek 1095:        /* Get the filesystem stats now */
                   1096:        memset(sp, 0, sizeof(*sp));
1.332     pooka    1097:        if ((error = VFS_STATVFS(mp, sp)) != 0) {
1.185     christos 1098:                return error;
                   1099:        }
                   1100:
                   1101:        if (cwdi->cwdi_rdir == NULL)
                   1102:                (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
                   1103: done:
                   1104:        if (cwdi->cwdi_rdir != NULL) {
                   1105:                size_t len;
                   1106:                char *bp;
1.364     christos 1107:                char c;
1.236     yamt     1108:                char *path = PNBUF_GET();
1.185     christos 1109:
                   1110:                bp = path + MAXPATHLEN;
                   1111:                *--bp = '\0';
1.328     ad       1112:                rw_enter(&cwdi->cwdi_lock, RW_READER);
1.185     christos 1113:                error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
1.234     christos 1114:                    MAXPATHLEN / 2, 0, l);
1.328     ad       1115:                rw_exit(&cwdi->cwdi_lock);
1.185     christos 1116:                if (error) {
1.236     yamt     1117:                        PNBUF_PUT(path);
1.185     christos 1118:                        return error;
                   1119:                }
                   1120:                len = strlen(bp);
1.387     christos 1121:                if (len != 1) {
                   1122:                        /*
                   1123:                         * for mount points that are below our root, we can see
                   1124:                         * them, so we fix up the pathname and return them. The
                   1125:                         * rest we cannot see, so we don't allow viewing the
                   1126:                         * data.
                   1127:                         */
                   1128:                        if (strncmp(bp, sp->f_mntonname, len) == 0 &&
                   1129:                            ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
                   1130:                                (void)strlcpy(sp->f_mntonname,
1.388     enami    1131:                                    c == '\0' ? "/" : &sp->f_mntonname[len],
1.187     itojun   1132:                                    sizeof(sp->f_mntonname));
1.387     christos 1133:                        } else {
                   1134:                                if (root)
                   1135:                                        (void)strlcpy(sp->f_mntonname, "/",
                   1136:                                            sizeof(sp->f_mntonname));
                   1137:                                else
                   1138:                                        error = EPERM;
                   1139:                        }
1.185     christos 1140:                }
1.236     yamt     1141:                PNBUF_PUT(path);
1.185     christos 1142:        }
1.206     christos 1143:        sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
1.185     christos 1144:        return error;
                   1145: }
                   1146:
1.31      cgd      1147: /*
1.311     dsl      1148:  * Get filesystem statistics by path.
1.31      cgd      1149:  */
1.311     dsl      1150: int
                   1151: do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb)
                   1152: {
                   1153:        struct mount *mp;
                   1154:        int error;
1.395     dholland 1155:        struct vnode *vp;
1.311     dsl      1156:
1.395     dholland 1157:        error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
                   1158:        if (error != 0)
1.311     dsl      1159:                return error;
1.395     dholland 1160:        mp = vp->v_mount;
1.311     dsl      1161:        error = dostatvfs(mp, sb, l, flags, 1);
1.395     dholland 1162:        vrele(vp);
1.311     dsl      1163:        return error;
                   1164: }
                   1165:
1.31      cgd      1166: /* ARGSUSED */
1.63      christos 1167: int
1.335     dsl      1168: sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval)
1.56      thorpej  1169: {
1.335     dsl      1170:        /* {
1.74      cgd      1171:                syscallarg(const char *) path;
1.206     christos 1172:                syscallarg(struct statvfs *) buf;
                   1173:                syscallarg(int) flags;
1.335     dsl      1174:        } */
1.241     yamt     1175:        struct statvfs *sb;
1.31      cgd      1176:        int error;
                   1177:
1.241     yamt     1178:        sb = STATVFSBUF_GET();
1.311     dsl      1179:        error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb);
                   1180:        if (error == 0)
1.241     yamt     1181:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
                   1182:        STATVFSBUF_PUT(sb);
                   1183:        return error;
1.31      cgd      1184: }
                   1185:
                   1186: /*
1.311     dsl      1187:  * Get filesystem statistics by fd.
1.31      cgd      1188:  */
1.311     dsl      1189: int
                   1190: do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb)
                   1191: {
1.346     ad       1192:        file_t *fp;
1.311     dsl      1193:        struct mount *mp;
                   1194:        int error;
                   1195:
1.346     ad       1196:        /* fd_getvnode() will use the descriptor for us */
                   1197:        if ((error = fd_getvnode(fd, &fp)) != 0)
1.311     dsl      1198:                return (error);
                   1199:        mp = ((struct vnode *)fp->f_data)->v_mount;
1.346     ad       1200:        error = dostatvfs(mp, sb, curlwp, flags, 1);
                   1201:        fd_putfile(fd);
1.311     dsl      1202:        return error;
                   1203: }
                   1204:
1.31      cgd      1205: /* ARGSUSED */
1.63      christos 1206: int
1.335     dsl      1207: sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval)
1.56      thorpej  1208: {
1.335     dsl      1209:        /* {
1.35      cgd      1210:                syscallarg(int) fd;
1.206     christos 1211:                syscallarg(struct statvfs *) buf;
                   1212:                syscallarg(int) flags;
1.335     dsl      1213:        } */
1.241     yamt     1214:        struct statvfs *sb;
1.31      cgd      1215:        int error;
                   1216:
1.241     yamt     1217:        sb = STATVFSBUF_GET();
1.311     dsl      1218:        error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
1.316     dsl      1219:        if (error == 0)
1.311     dsl      1220:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1.241     yamt     1221:        STATVFSBUF_PUT(sb);
1.185     christos 1222:        return error;
1.31      cgd      1223: }
                   1224:
1.185     christos 1225:
1.31      cgd      1226: /*
                   1227:  * Get statistics on all filesystems.
                   1228:  */
1.63      christos 1229: int
1.311     dsl      1230: do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags,
                   1231:     int (*copyfn)(const void *, void *, size_t), size_t entry_sz,
                   1232:     register_t *retval)
1.56      thorpej  1233: {
1.185     christos 1234:        int root = 0;
1.179     thorpej  1235:        struct proc *p = l->l_proc;
1.155     augustss 1236:        struct mount *mp, *nmp;
1.241     yamt     1237:        struct statvfs *sb;
1.206     christos 1238:        size_t count, maxcount;
                   1239:        int error = 0;
1.31      cgd      1240:
1.241     yamt     1241:        sb = STATVFSBUF_GET();
1.311     dsl      1242:        maxcount = bufsize / entry_sz;
1.329     ad       1243:        mutex_enter(&mountlist_lock);
1.113     fvdl     1244:        count = 0;
1.471     christos 1245:        for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
1.358     ad       1246:                if (vfs_busy(mp, &nmp)) {
1.113     fvdl     1247:                        continue;
                   1248:                }
                   1249:                if (sfsp && count < maxcount) {
1.311     dsl      1250:                        error = dostatvfs(mp, sb, l, flags, 0);
1.185     christos 1251:                        if (error) {
1.354     ad       1252:                                vfs_unbusy(mp, false, &nmp);
1.365     christos 1253:                                error = 0;
1.31      cgd      1254:                                continue;
1.113     fvdl     1255:                        }
1.311     dsl      1256:                        error = copyfn(sb, sfsp, entry_sz);
1.133     mycroft  1257:                        if (error) {
1.354     ad       1258:                                vfs_unbusy(mp, false, NULL);
1.241     yamt     1259:                                goto out;
1.133     mycroft  1260:                        }
1.311     dsl      1261:                        sfsp = (char *)sfsp + entry_sz;
1.241     yamt     1262:                        root |= strcmp(sb->f_mntonname, "/") == 0;
1.31      cgd      1263:                }
                   1264:                count++;
1.354     ad       1265:                vfs_unbusy(mp, false, &nmp);
1.31      cgd      1266:        }
1.358     ad       1267:        mutex_exit(&mountlist_lock);
1.331     pooka    1268:
1.185     christos 1269:        if (root == 0 && p->p_cwdi->cwdi_rdir) {
                   1270:                /*
                   1271:                 * fake a root entry
                   1272:                 */
1.331     pooka    1273:                error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount,
                   1274:                    sb, l, flags, 1);
1.311     dsl      1275:                if (error != 0)
1.241     yamt     1276:                        goto out;
1.365     christos 1277:                if (sfsp) {
1.311     dsl      1278:                        error = copyfn(sb, sfsp, entry_sz);
1.365     christos 1279:                        if (error != 0)
                   1280:                                goto out;
                   1281:                }
1.185     christos 1282:                count++;
                   1283:        }
1.31      cgd      1284:        if (sfsp && count > maxcount)
                   1285:                *retval = maxcount;
                   1286:        else
                   1287:                *retval = count;
1.241     yamt     1288: out:
                   1289:        STATVFSBUF_PUT(sb);
1.185     christos 1290:        return error;
1.31      cgd      1291: }
                   1292:
1.311     dsl      1293: int
1.335     dsl      1294: sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval)
1.311     dsl      1295: {
1.335     dsl      1296:        /* {
1.311     dsl      1297:                syscallarg(struct statvfs *) buf;
                   1298:                syscallarg(size_t) bufsize;
                   1299:                syscallarg(int) flags;
1.335     dsl      1300:        } */
1.311     dsl      1301:
                   1302:        return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize),
                   1303:            SCARG(uap, flags), copyout, sizeof (struct statvfs), retval);
                   1304: }
                   1305:
1.31      cgd      1306: /*
                   1307:  * Change current working directory to a given file descriptor.
                   1308:  */
                   1309: /* ARGSUSED */
1.63      christos 1310: int
1.335     dsl      1311: sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval)
1.56      thorpej  1312: {
1.335     dsl      1313:        /* {
1.35      cgd      1314:                syscallarg(int) fd;
1.335     dsl      1315:        } */
1.179     thorpej  1316:        struct proc *p = l->l_proc;
1.328     ad       1317:        struct cwdinfo *cwdi;
1.43      mycroft  1318:        struct vnode *vp, *tdp;
                   1319:        struct mount *mp;
1.346     ad       1320:        file_t *fp;
                   1321:        int error, fd;
1.31      cgd      1322:
1.346     ad       1323:        /* fd_getvnode() will use the descriptor for us */
                   1324:        fd = SCARG(uap, fd);
                   1325:        if ((error = fd_getvnode(fd, &fp)) != 0)
1.31      cgd      1326:                return (error);
1.346     ad       1327:        vp = fp->f_data;
1.131     sommerfe 1328:
1.402     pooka    1329:        vref(vp);
1.113     fvdl     1330:        vn_lock(vp,  LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      1331:        if (vp->v_type != VDIR)
                   1332:                error = ENOTDIR;
                   1333:        else
1.332     pooka    1334:                error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.303     pooka    1335:        if (error) {
                   1336:                vput(vp);
                   1337:                goto out;
                   1338:        }
1.304     pooka    1339:        while ((mp = vp->v_mountedhere) != NULL) {
1.358     ad       1340:                error = vfs_busy(mp, NULL);
1.298     chs      1341:                vput(vp);
1.357     xtraeme  1342:                if (error != 0)
1.356     ad       1343:                        goto out;
1.189     thorpej  1344:                error = VFS_ROOT(mp, &tdp);
1.354     ad       1345:                vfs_unbusy(mp, false, NULL);
1.113     fvdl     1346:                if (error)
1.303     pooka    1347:                        goto out;
1.43      mycroft  1348:                vp = tdp;
                   1349:        }
1.406     hannken  1350:        VOP_UNLOCK(vp);
1.131     sommerfe 1351:
                   1352:        /*
                   1353:         * Disallow changing to a directory not under the process's
                   1354:         * current root directory (if there is one).
                   1355:         */
1.328     ad       1356:        cwdi = p->p_cwdi;
                   1357:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.234     christos 1358:        if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
1.131     sommerfe 1359:                vrele(vp);
1.135     thorpej  1360:                error = EPERM;  /* operation not permitted */
1.328     ad       1361:        } else {
                   1362:                vrele(cwdi->cwdi_cdir);
                   1363:                cwdi->cwdi_cdir = vp;
1.131     sommerfe 1364:        }
1.328     ad       1365:        rw_exit(&cwdi->cwdi_lock);
1.205     junyoung 1366:
1.135     thorpej  1367:  out:
1.346     ad       1368:        fd_putfile(fd);
1.135     thorpej  1369:        return (error);
1.31      cgd      1370: }
                   1371:
                   1372: /*
1.221     thorpej  1373:  * Change this process's notion of the root directory to a given file
                   1374:  * descriptor.
1.131     sommerfe 1375:  */
                   1376: int
1.335     dsl      1377: sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
1.131     sommerfe 1378: {
1.179     thorpej  1379:        struct proc *p = l->l_proc;
1.131     sommerfe 1380:        struct vnode    *vp;
1.346     ad       1381:        file_t  *fp;
                   1382:        int              error, fd = SCARG(uap, fd);
1.131     sommerfe 1383:
1.268     elad     1384:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
                   1385:            KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
1.131     sommerfe 1386:                return error;
1.346     ad       1387:        /* fd_getvnode() will use the descriptor for us */
1.397     bad      1388:        if ((error = fd_getvnode(fd, &fp)) != 0)
1.131     sommerfe 1389:                return error;
1.346     ad       1390:        vp = fp->f_data;
1.131     sommerfe 1391:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   1392:        if (vp->v_type != VDIR)
                   1393:                error = ENOTDIR;
                   1394:        else
1.332     pooka    1395:                error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1.406     hannken  1396:        VOP_UNLOCK(vp);
1.131     sommerfe 1397:        if (error)
1.135     thorpej  1398:                goto out;
1.402     pooka    1399:        vref(vp);
1.131     sommerfe 1400:
1.397     bad      1401:        change_root(p->p_cwdi, vp, l);
1.328     ad       1402:
1.135     thorpej  1403:  out:
1.346     ad       1404:        fd_putfile(fd);
1.135     thorpej  1405:        return (error);
1.131     sommerfe 1406: }
                   1407:
                   1408: /*
1.31      cgd      1409:  * Change current working directory (``.'').
                   1410:  */
                   1411: /* ARGSUSED */
1.63      christos 1412: int
1.335     dsl      1413: sys_chdir(struct lwp *l, const struct sys_chdir_args *uap, register_t *retval)
1.56      thorpej  1414: {
1.335     dsl      1415:        /* {
1.74      cgd      1416:                syscallarg(const char *) path;
1.335     dsl      1417:        } */
1.179     thorpej  1418:        struct proc *p = l->l_proc;
1.328     ad       1419:        struct cwdinfo *cwdi;
1.31      cgd      1420:        int error;
1.397     bad      1421:        struct vnode *vp;
1.31      cgd      1422:
1.397     bad      1423:        if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
                   1424:                                  &vp, l)) != 0)
1.31      cgd      1425:                return (error);
1.328     ad       1426:        cwdi = p->p_cwdi;
                   1427:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  1428:        vrele(cwdi->cwdi_cdir);
1.397     bad      1429:        cwdi->cwdi_cdir = vp;
1.328     ad       1430:        rw_exit(&cwdi->cwdi_lock);
1.31      cgd      1431:        return (0);
                   1432: }
                   1433:
                   1434: /*
                   1435:  * Change notion of root (``/'') directory.
                   1436:  */
                   1437: /* ARGSUSED */
1.63      christos 1438: int
1.335     dsl      1439: sys_chroot(struct lwp *l, const struct sys_chroot_args *uap, register_t *retval)
1.56      thorpej  1440: {
1.335     dsl      1441:        /* {
1.74      cgd      1442:                syscallarg(const char *) path;
1.335     dsl      1443:        } */
1.179     thorpej  1444:        struct proc *p = l->l_proc;
1.397     bad      1445:        int error;
1.131     sommerfe 1446:        struct vnode *vp;
1.31      cgd      1447:
1.268     elad     1448:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
                   1449:            KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
1.31      cgd      1450:                return (error);
1.397     bad      1451:        if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
                   1452:                                  &vp, l)) != 0)
1.31      cgd      1453:                return (error);
1.328     ad       1454:
1.397     bad      1455:        change_root(p->p_cwdi, vp, l);
                   1456:
                   1457:        return (0);
                   1458: }
                   1459:
                   1460: /*
                   1461:  * Common routine for chroot and fchroot.
1.398     bad      1462:  * NB: callers need to properly authorize the change root operation.
1.397     bad      1463:  */
                   1464: void
                   1465: change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l)
                   1466: {
1.457     cheusov  1467:        struct proc *p = l->l_proc;
                   1468:        kauth_cred_t ncred;
                   1469:
                   1470:        ncred = kauth_cred_alloc();
1.397     bad      1471:
1.328     ad       1472:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  1473:        if (cwdi->cwdi_rdir != NULL)
                   1474:                vrele(cwdi->cwdi_rdir);
                   1475:        cwdi->cwdi_rdir = vp;
1.131     sommerfe 1476:
                   1477:        /*
                   1478:         * Prevent escaping from chroot by putting the root under
                   1479:         * the working directory.  Silently chdir to / if we aren't
                   1480:         * already there.
                   1481:         */
1.234     christos 1482:        if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1.131     sommerfe 1483:                /*
                   1484:                 * XXX would be more failsafe to change directory to a
                   1485:                 * deadfs node here instead
                   1486:                 */
1.134     thorpej  1487:                vrele(cwdi->cwdi_cdir);
1.402     pooka    1488:                vref(vp);
1.134     thorpej  1489:                cwdi->cwdi_cdir = vp;
1.131     sommerfe 1490:        }
1.328     ad       1491:        rw_exit(&cwdi->cwdi_lock);
1.457     cheusov  1492:
                   1493:        /* Get a write lock on the process credential. */
                   1494:        proc_crmod_enter();
                   1495:
                   1496:        kauth_cred_clone(p->p_cred, ncred);
                   1497:        kauth_proc_chroot(ncred, p->p_cwdi);
                   1498:
                   1499:        /* Broadcast our credentials to the process and other LWPs. */
                   1500:        proc_crmod_leave(ncred, p->p_cred, true);
1.31      cgd      1501: }
                   1502:
                   1503: /*
                   1504:  * Common routine for chroot and chdir.
1.409     dholland 1505:  * XXX "where" should be enum uio_seg
1.31      cgd      1506:  */
1.397     bad      1507: int
                   1508: chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l)
1.31      cgd      1509: {
1.409     dholland 1510:        struct pathbuf *pb;
1.397     bad      1511:        struct nameidata nd;
1.31      cgd      1512:        int error;
                   1513:
1.409     dholland 1514:        error = pathbuf_maybe_copyin(path, where, &pb);
                   1515:        if (error) {
                   1516:                return error;
                   1517:        }
                   1518:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
                   1519:        if ((error = namei(&nd)) != 0) {
                   1520:                pathbuf_destroy(pb);
                   1521:                return error;
                   1522:        }
1.397     bad      1523:        *vpp = nd.ni_vp;
1.409     dholland 1524:        pathbuf_destroy(pb);
                   1525:
1.397     bad      1526:        if ((*vpp)->v_type != VDIR)
1.31      cgd      1527:                error = ENOTDIR;
                   1528:        else
1.397     bad      1529:                error = VOP_ACCESS(*vpp, VEXEC, l->l_cred);
1.205     junyoung 1530:
1.31      cgd      1531:        if (error)
1.397     bad      1532:                vput(*vpp);
1.113     fvdl     1533:        else
1.406     hannken  1534:                VOP_UNLOCK(*vpp);
1.31      cgd      1535:        return (error);
                   1536: }
                   1537:
                   1538: /*
1.448     martin   1539:  * Internals of sys_open - path has already been converted into a pathbuf
                   1540:  * (so we can easily reuse this function from other parts of the kernel,
                   1541:  * like posix_spawn post-processing).
1.31      cgd      1542:  */
1.474     christos 1543: int
1.460     manu     1544: do_open(lwp_t *l, struct vnode *dvp, struct pathbuf *pb, int open_flags,
                   1545:        int open_mode, int *fd)
1.56      thorpej  1546: {
1.179     thorpej  1547:        struct proc *p = l->l_proc;
1.134     thorpej  1548:        struct cwdinfo *cwdi = p->p_cwdi;
1.346     ad       1549:        file_t *fp;
1.135     thorpej  1550:        struct vnode *vp;
1.31      cgd      1551:        int flags, cmode;
1.422     christos 1552:        int indx, error;
1.31      cgd      1553:        struct nameidata nd;
                   1554:
1.463     dholland 1555:        if (open_flags & O_SEARCH) {
                   1556:                open_flags &= ~(int)O_SEARCH;
                   1557:        }
                   1558:
1.448     martin   1559:        flags = FFLAGS(open_flags);
1.104     mycroft  1560:        if ((flags & (FREAD | FWRITE)) == 0)
1.448     martin   1561:                return EINVAL;
1.409     dholland 1562:
                   1563:        if ((error = fd_allocfile(&fp, &indx)) != 0) {
                   1564:                return error;
                   1565:        }
1.455     rmind    1566:
1.328     ad       1567:        /* We're going to read cwdi->cwdi_cmask unlocked here. */
1.448     martin   1568:        cmode = ((open_mode &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1.409     dholland 1569:        NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, pb);
1.460     manu     1570:        if (dvp != NULL)
                   1571:                NDAT(&nd, dvp);
                   1572:
1.194     jdolecek 1573:        l->l_dupfd = -indx - 1;                 /* XXX check for fdopen */
1.63      christos 1574:        if ((error = vn_open(&nd, flags, cmode)) != 0) {
1.346     ad       1575:                fd_abort(p, fp, indx);
1.213     christos 1576:                if ((error == EDUPFD || error == EMOVEFD) &&
1.194     jdolecek 1577:                    l->l_dupfd >= 0 &&                  /* XXX from fdopen */
1.45      mycroft  1578:                    (error =
1.346     ad       1579:                        fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) {
1.448     martin   1580:                        *fd = indx;
1.455     rmind    1581:                        return 0;
1.45      mycroft  1582:                }
                   1583:                if (error == ERESTART)
1.44      mycroft  1584:                        error = EINTR;
1.448     martin   1585:                return error;
1.31      cgd      1586:        }
1.331     pooka    1587:
1.194     jdolecek 1588:        l->l_dupfd = 0;
1.31      cgd      1589:        vp = nd.ni_vp;
1.409     dholland 1590:
1.422     christos 1591:        if ((error = open_setfp(l, fp, vp, indx, flags)))
                   1592:                return error;
                   1593:
1.406     hannken  1594:        VOP_UNLOCK(vp);
1.448     martin   1595:        *fd = indx;
1.346     ad       1596:        fd_affix(p, fp, indx);
1.448     martin   1597:        return 0;
                   1598: }
                   1599:
                   1600: int
                   1601: fd_open(const char *path, int open_flags, int open_mode, int *fd)
                   1602: {
                   1603:        struct pathbuf *pb;
1.455     rmind    1604:        int error, oflags;
1.448     martin   1605:
1.449     martin   1606:        oflags = FFLAGS(open_flags);
                   1607:        if ((oflags & (FREAD | FWRITE)) == 0)
1.448     martin   1608:                return EINVAL;
                   1609:
                   1610:        pb = pathbuf_create(path);
                   1611:        if (pb == NULL)
                   1612:                return ENOMEM;
                   1613:
1.460     manu     1614:        error = do_open(curlwp, NULL, pb, open_flags, open_mode, fd);
1.455     rmind    1615:        pathbuf_destroy(pb);
                   1616:
                   1617:        return error;
1.448     martin   1618: }
                   1619:
                   1620: /*
                   1621:  * Check permissions, allocate an open file structure,
                   1622:  * and call the device open routine if any.
                   1623:  */
1.460     manu     1624: static int
                   1625: do_sys_openat(lwp_t *l, int fdat, const char *path, int flags,
                   1626:     int mode, int *fd)
                   1627: {
                   1628:        file_t *dfp = NULL;
                   1629:        struct vnode *dvp = NULL;
                   1630:        struct pathbuf *pb;
                   1631:        int error;
                   1632:
1.475     christos 1633: #ifdef COMPAT_10       /* XXX: and perhaps later */
1.477     maxv     1634:        if (path == NULL) {
1.475     christos 1635:                pb = pathbuf_create(".");
1.477     maxv     1636:                if (pb == NULL)
                   1637:                        return ENOMEM;
                   1638:        } else
1.475     christos 1639: #endif
                   1640:        {
                   1641:                error = pathbuf_copyin(path, &pb);
                   1642:                if (error)
                   1643:                        return error;
                   1644:        }
1.460     manu     1645:
                   1646:        if (fdat != AT_FDCWD) {
                   1647:                /* fd_getvnode() will use the descriptor for us */
                   1648:                if ((error = fd_getvnode(fdat, &dfp)) != 0)
                   1649:                        goto out;
                   1650:
                   1651:                dvp = dfp->f_data;
                   1652:        }
                   1653:
                   1654:        error = do_open(l, dvp, pb, flags, mode, fd);
                   1655:
                   1656:        if (dfp != NULL)
                   1657:                fd_putfile(fdat);
                   1658: out:
                   1659:        pathbuf_destroy(pb);
                   1660:        return error;
                   1661: }
                   1662:
1.448     martin   1663: int
                   1664: sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval)
                   1665: {
                   1666:        /* {
                   1667:                syscallarg(const char *) path;
                   1668:                syscallarg(int) flags;
                   1669:                syscallarg(int) mode;
                   1670:        } */
1.460     manu     1671:        int error;
                   1672:        int fd;
1.448     martin   1673:
1.460     manu     1674:        error = do_sys_openat(l, AT_FDCWD, SCARG(uap, path),
                   1675:                              SCARG(uap, flags), SCARG(uap, mode), &fd);
1.448     martin   1676:
1.460     manu     1677:        if (error == 0)
                   1678:                *retval = fd;
1.448     martin   1679:
1.455     rmind    1680:        return error;
1.137     wrstuden 1681: }
                   1682:
1.433     manu     1683: int
                   1684: sys_openat(struct lwp *l, const struct sys_openat_args *uap, register_t *retval)
                   1685: {
                   1686:        /* {
                   1687:                syscallarg(int) fd;
                   1688:                syscallarg(const char *) path;
1.460     manu     1689:                syscallarg(int) oflags;
1.433     manu     1690:                syscallarg(int) mode;
                   1691:        } */
1.460     manu     1692:        int error;
                   1693:        int fd;
                   1694:
                   1695:        error = do_sys_openat(l, SCARG(uap, fd), SCARG(uap, path),
                   1696:                              SCARG(uap, oflags), SCARG(uap, mode), &fd);
                   1697:
                   1698:        if (error == 0)
                   1699:                *retval = fd;
1.433     manu     1700:
1.460     manu     1701:        return error;
1.433     manu     1702: }
                   1703:
1.249     yamt     1704: static void
                   1705: vfs__fhfree(fhandle_t *fhp)
                   1706: {
                   1707:        size_t fhsize;
                   1708:
                   1709:        fhsize = FHANDLE_SIZE(fhp);
                   1710:        kmem_free(fhp, fhsize);
                   1711: }
                   1712:
1.137     wrstuden 1713: /*
1.243     yamt     1714:  * vfs_composefh: compose a filehandle.
                   1715:  */
                   1716:
                   1717: int
1.244     martin   1718: vfs_composefh(struct vnode *vp, fhandle_t *fhp, size_t *fh_size)
1.243     yamt     1719: {
                   1720:        struct mount *mp;
1.250     yamt     1721:        struct fid *fidp;
1.243     yamt     1722:        int error;
1.250     yamt     1723:        size_t needfhsize;
                   1724:        size_t fidsize;
1.243     yamt     1725:
                   1726:        mp = vp->v_mount;
1.250     yamt     1727:        fidp = NULL;
1.252     martin   1728:        if (*fh_size < FHANDLE_SIZE_MIN) {
1.250     yamt     1729:                fidsize = 0;
1.244     martin   1730:        } else {
1.250     yamt     1731:                fidsize = *fh_size - offsetof(fhandle_t, fh_fid);
                   1732:                if (fhp != NULL) {
                   1733:                        memset(fhp, 0, *fh_size);
                   1734:                        fhp->fh_fsid = mp->mnt_stat.f_fsidx;
                   1735:                        fidp = &fhp->fh_fid;
                   1736:                }
1.244     martin   1737:        }
1.250     yamt     1738:        error = VFS_VPTOFH(vp, fidp, &fidsize);
                   1739:        needfhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
                   1740:        if (error == 0 && *fh_size < needfhsize) {
                   1741:                error = E2BIG;
                   1742:        }
                   1743:        *fh_size = needfhsize;
1.243     yamt     1744:        return error;
                   1745: }
                   1746:
1.249     yamt     1747: int
                   1748: vfs_composefh_alloc(struct vnode *vp, fhandle_t **fhpp)
                   1749: {
                   1750:        struct mount *mp;
                   1751:        fhandle_t *fhp;
                   1752:        size_t fhsize;
                   1753:        size_t fidsize;
                   1754:        int error;
                   1755:
                   1756:        mp = vp->v_mount;
1.255     christos 1757:        fidsize = 0;
1.249     yamt     1758:        error = VFS_VPTOFH(vp, NULL, &fidsize);
                   1759:        KASSERT(error != 0);
                   1760:        if (error != E2BIG) {
                   1761:                goto out;
                   1762:        }
1.250     yamt     1763:        fhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1.249     yamt     1764:        fhp = kmem_zalloc(fhsize, KM_SLEEP);
                   1765:        if (fhp == NULL) {
                   1766:                error = ENOMEM;
                   1767:                goto out;
                   1768:        }
                   1769:        fhp->fh_fsid = mp->mnt_stat.f_fsidx;
                   1770:        error = VFS_VPTOFH(vp, &fhp->fh_fid, &fidsize);
                   1771:        if (error == 0) {
                   1772:                KASSERT((FHANDLE_SIZE(fhp) == fhsize &&
                   1773:                    FHANDLE_FILEID(fhp)->fid_len == fidsize));
                   1774:                *fhpp = fhp;
                   1775:        } else {
                   1776:                kmem_free(fhp, fhsize);
                   1777:        }
                   1778: out:
                   1779:        return error;
                   1780: }
                   1781:
                   1782: void
                   1783: vfs_composefh_free(fhandle_t *fhp)
                   1784: {
                   1785:
                   1786:        vfs__fhfree(fhp);
                   1787: }
                   1788:
1.243     yamt     1789: /*
1.248     yamt     1790:  * vfs_fhtovp: lookup a vnode by a filehandle.
                   1791:  */
                   1792:
                   1793: int
                   1794: vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp)
                   1795: {
                   1796:        struct mount *mp;
                   1797:        int error;
                   1798:
                   1799:        *vpp = NULL;
                   1800:        mp = vfs_getvfs(FHANDLE_FSID(fhp));
                   1801:        if (mp == NULL) {
                   1802:                error = ESTALE;
                   1803:                goto out;
                   1804:        }
                   1805:        if (mp->mnt_op->vfs_fhtovp == NULL) {
                   1806:                error = EOPNOTSUPP;
                   1807:                goto out;
                   1808:        }
                   1809:        error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp);
                   1810: out:
                   1811:        return error;
                   1812: }
                   1813:
                   1814: /*
1.265     yamt     1815:  * vfs_copyinfh_alloc: allocate and copyin a filehandle, given
1.263     martin   1816:  * the needed size.
                   1817:  */
                   1818:
                   1819: int
1.265     yamt     1820: vfs_copyinfh_alloc(const void *ufhp, size_t fhsize, fhandle_t **fhpp)
1.263     martin   1821: {
                   1822:        fhandle_t *fhp;
                   1823:        int error;
                   1824:
1.250     yamt     1825:        if (fhsize > FHANDLE_SIZE_MAX) {
                   1826:                return EINVAL;
                   1827:        }
1.265     yamt     1828:        if (fhsize < FHANDLE_SIZE_MIN) {
                   1829:                return EINVAL;
                   1830:        }
1.267     yamt     1831: again:
1.248     yamt     1832:        fhp = kmem_alloc(fhsize, KM_SLEEP);
                   1833:        if (fhp == NULL) {
                   1834:                return ENOMEM;
                   1835:        }
                   1836:        error = copyin(ufhp, fhp, fhsize);
                   1837:        if (error == 0) {
1.265     yamt     1838:                /* XXX this check shouldn't be here */
                   1839:                if (FHANDLE_SIZE(fhp) == fhsize) {
1.263     martin   1840:                        *fhpp = fhp;
                   1841:                        return 0;
1.267     yamt     1842:                } else if (fhsize == NFSX_V2FH && FHANDLE_SIZE(fhp) < fhsize) {
                   1843:                        /*
                   1844:                         * a kludge for nfsv2 padded handles.
                   1845:                         */
                   1846:                        size_t sz;
                   1847:
                   1848:                        sz = FHANDLE_SIZE(fhp);
                   1849:                        kmem_free(fhp, fhsize);
                   1850:                        fhsize = sz;
                   1851:                        goto again;
1.264     yamt     1852:                } else {
1.265     yamt     1853:                        /*
                   1854:                         * userland told us wrong size.
                   1855:                         */
1.263     martin   1856:                        error = EINVAL;
1.264     yamt     1857:                }
1.248     yamt     1858:        }
1.263     martin   1859:        kmem_free(fhp, fhsize);
1.248     yamt     1860:        return error;
                   1861: }
                   1862:
                   1863: void
                   1864: vfs_copyinfh_free(fhandle_t *fhp)
                   1865: {
                   1866:
1.249     yamt     1867:        vfs__fhfree(fhp);
1.248     yamt     1868: }
                   1869:
                   1870: /*
1.137     wrstuden 1871:  * Get file handle system call
                   1872:  */
                   1873: int
1.335     dsl      1874: sys___getfh30(struct lwp *l, const struct sys___getfh30_args *uap, register_t *retval)
1.137     wrstuden 1875: {
1.335     dsl      1876:        /* {
1.137     wrstuden 1877:                syscallarg(char *) fname;
                   1878:                syscallarg(fhandle_t *) fhp;
1.244     martin   1879:                syscallarg(size_t *) fh_size;
1.335     dsl      1880:        } */
1.155     augustss 1881:        struct vnode *vp;
1.244     martin   1882:        fhandle_t *fh;
1.137     wrstuden 1883:        int error;
1.409     dholland 1884:        struct pathbuf *pb;
1.137     wrstuden 1885:        struct nameidata nd;
1.244     martin   1886:        size_t sz;
1.249     yamt     1887:        size_t usz;
1.137     wrstuden 1888:
                   1889:        /*
                   1890:         * Must be super user
                   1891:         */
1.268     elad     1892:        error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
                   1893:            0, NULL, NULL, NULL);
1.137     wrstuden 1894:        if (error)
                   1895:                return (error);
1.409     dholland 1896:
                   1897:        error = pathbuf_copyin(SCARG(uap, fname), &pb);
                   1898:        if (error) {
                   1899:                return error;
                   1900:        }
                   1901:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1.137     wrstuden 1902:        error = namei(&nd);
1.409     dholland 1903:        if (error) {
                   1904:                pathbuf_destroy(pb);
                   1905:                return error;
                   1906:        }
1.137     wrstuden 1907:        vp = nd.ni_vp;
1.409     dholland 1908:        pathbuf_destroy(pb);
                   1909:
1.249     yamt     1910:        error = vfs_composefh_alloc(vp, &fh);
1.247     yamt     1911:        vput(vp);
1.249     yamt     1912:        if (error != 0) {
1.485     christos 1913:                return error;
1.249     yamt     1914:        }
                   1915:        error = copyin(SCARG(uap, fh_size), &usz, sizeof(size_t));
                   1916:        if (error != 0) {
                   1917:                goto out;
                   1918:        }
                   1919:        sz = FHANDLE_SIZE(fh);
                   1920:        error = copyout(&sz, SCARG(uap, fh_size), sizeof(size_t));
                   1921:        if (error != 0) {
                   1922:                goto out;
1.244     martin   1923:        }
1.249     yamt     1924:        if (usz >= sz) {
                   1925:                error = copyout(fh, SCARG(uap, fhp), sz);
                   1926:        } else {
                   1927:                error = E2BIG;
1.244     martin   1928:        }
1.249     yamt     1929: out:
                   1930:        vfs_composefh_free(fh);
1.137     wrstuden 1931:        return (error);
                   1932: }
                   1933:
                   1934: /*
                   1935:  * Open a file given a file handle.
                   1936:  *
                   1937:  * Check permissions, allocate an open file structure,
                   1938:  * and call the device open routine if any.
                   1939:  */
1.265     yamt     1940:
1.137     wrstuden 1941: int
1.265     yamt     1942: dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags,
                   1943:     register_t *retval)
1.137     wrstuden 1944: {
1.346     ad       1945:        file_t *fp;
1.139     wrstuden 1946:        struct vnode *vp = NULL;
1.257     ad       1947:        kauth_cred_t cred = l->l_cred;
1.346     ad       1948:        file_t *nfp;
1.422     christos 1949:        int indx, error = 0;
1.137     wrstuden 1950:        struct vattr va;
1.248     yamt     1951:        fhandle_t *fh;
1.265     yamt     1952:        int flags;
1.346     ad       1953:        proc_t *p;
                   1954:
                   1955:        p = curproc;
1.137     wrstuden 1956:
                   1957:        /*
                   1958:         * Must be super user
                   1959:         */
1.269     elad     1960:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     1961:            0, NULL, NULL, NULL)))
1.137     wrstuden 1962:                return (error);
                   1963:
1.463     dholland 1964:        if (oflags & O_SEARCH) {
                   1965:                oflags &= ~(int)O_SEARCH;
                   1966:        }
                   1967:
1.265     yamt     1968:        flags = FFLAGS(oflags);
1.137     wrstuden 1969:        if ((flags & (FREAD | FWRITE)) == 0)
                   1970:                return (EINVAL);
                   1971:        if ((flags & O_CREAT))
                   1972:                return (EINVAL);
1.346     ad       1973:        if ((error = fd_allocfile(&nfp, &indx)) != 0)
1.137     wrstuden 1974:                return (error);
                   1975:        fp = nfp;
1.265     yamt     1976:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.248     yamt     1977:        if (error != 0) {
1.139     wrstuden 1978:                goto bad;
                   1979:        }
1.248     yamt     1980:        error = vfs_fhtovp(fh, &vp);
1.481     maxv     1981:        vfs_copyinfh_free(fh);
1.248     yamt     1982:        if (error != 0) {
1.139     wrstuden 1983:                goto bad;
                   1984:        }
1.137     wrstuden 1985:
                   1986:        /* Now do an effective vn_open */
                   1987:
                   1988:        if (vp->v_type == VSOCK) {
                   1989:                error = EOPNOTSUPP;
                   1990:                goto bad;
                   1991:        }
1.333     yamt     1992:        error = vn_openchk(vp, cred, flags);
                   1993:        if (error != 0)
                   1994:                goto bad;
1.137     wrstuden 1995:        if (flags & O_TRUNC) {
1.406     hannken  1996:                VOP_UNLOCK(vp);                 /* XXX */
1.137     wrstuden 1997:                vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */
1.402     pooka    1998:                vattr_null(&va);
1.137     wrstuden 1999:                va.va_size = 0;
1.332     pooka    2000:                error = VOP_SETATTR(vp, &va, cred);
1.197     hannken  2001:                if (error)
1.137     wrstuden 2002:                        goto bad;
                   2003:        }
1.332     pooka    2004:        if ((error = VOP_OPEN(vp, flags, cred)) != 0)
1.137     wrstuden 2005:                goto bad;
1.346     ad       2006:        if (flags & FWRITE) {
1.429     rmind    2007:                mutex_enter(vp->v_interlock);
1.137     wrstuden 2008:                vp->v_writecount++;
1.429     rmind    2009:                mutex_exit(vp->v_interlock);
1.346     ad       2010:        }
1.137     wrstuden 2011:
                   2012:        /* done with modified vn_open, now finish what sys_open does. */
1.422     christos 2013:        if ((error = open_setfp(l, fp, vp, indx, flags)))
                   2014:                return error;
1.137     wrstuden 2015:
1.406     hannken  2016:        VOP_UNLOCK(vp);
1.137     wrstuden 2017:        *retval = indx;
1.346     ad       2018:        fd_affix(p, fp, indx);
1.137     wrstuden 2019:        return (0);
1.139     wrstuden 2020:
1.137     wrstuden 2021: bad:
1.346     ad       2022:        fd_abort(p, fp, indx);
1.139     wrstuden 2023:        if (vp != NULL)
                   2024:                vput(vp);
1.137     wrstuden 2025:        return (error);
                   2026: }
                   2027:
                   2028: int
1.335     dsl      2029: sys___fhopen40(struct lwp *l, const struct sys___fhopen40_args *uap, register_t *retval)
1.137     wrstuden 2030: {
1.335     dsl      2031:        /* {
1.263     martin   2032:                syscallarg(const void *) fhp;
                   2033:                syscallarg(size_t) fh_size;
1.265     yamt     2034:                syscallarg(int) flags;
1.335     dsl      2035:        } */
1.265     yamt     2036:
                   2037:        return dofhopen(l, SCARG(uap, fhp), SCARG(uap, fh_size),
                   2038:            SCARG(uap, flags), retval);
                   2039: }
                   2040:
1.306     dsl      2041: int
                   2042: do_fhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sb)
                   2043: {
1.137     wrstuden 2044:        int error;
1.248     yamt     2045:        fhandle_t *fh;
1.137     wrstuden 2046:        struct vnode *vp;
                   2047:
                   2048:        /*
                   2049:         * Must be super user
                   2050:         */
1.268     elad     2051:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     2052:            0, NULL, NULL, NULL)))
1.137     wrstuden 2053:                return (error);
                   2054:
1.265     yamt     2055:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306     dsl      2056:        if (error != 0)
                   2057:                return error;
                   2058:
1.248     yamt     2059:        error = vfs_fhtovp(fh, &vp);
1.306     dsl      2060:        vfs_copyinfh_free(fh);
                   2061:        if (error != 0)
                   2062:                return error;
                   2063:
1.346     ad       2064:        error = vn_stat(vp, sb);
1.137     wrstuden 2065:        vput(vp);
1.248     yamt     2066:        return error;
1.137     wrstuden 2067: }
                   2068:
1.265     yamt     2069:
1.137     wrstuden 2070: /* ARGSUSED */
                   2071: int
1.383     christos 2072: sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval)
1.137     wrstuden 2073: {
1.335     dsl      2074:        /* {
1.265     yamt     2075:                syscallarg(const void *) fhp;
1.263     martin   2076:                syscallarg(size_t) fh_size;
1.265     yamt     2077:                syscallarg(struct stat *) sb;
1.335     dsl      2078:        } */
1.306     dsl      2079:        struct stat sb;
                   2080:        int error;
1.265     yamt     2081:
1.306     dsl      2082:        error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb);
                   2083:        if (error)
                   2084:                return error;
                   2085:        return copyout(&sb, SCARG(uap, sb), sizeof(sb));
1.265     yamt     2086: }
                   2087:
1.306     dsl      2088: int
                   2089: do_fhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *sb,
                   2090:     int flags)
                   2091: {
1.248     yamt     2092:        fhandle_t *fh;
1.137     wrstuden 2093:        struct mount *mp;
                   2094:        struct vnode *vp;
                   2095:        int error;
                   2096:
                   2097:        /*
                   2098:         * Must be super user
                   2099:         */
1.268     elad     2100:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1.270     elad     2101:            0, NULL, NULL, NULL)))
1.206     christos 2102:                return error;
1.137     wrstuden 2103:
1.265     yamt     2104:        error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1.306     dsl      2105:        if (error != 0)
                   2106:                return error;
                   2107:
1.248     yamt     2108:        error = vfs_fhtovp(fh, &vp);
1.306     dsl      2109:        vfs_copyinfh_free(fh);
                   2110:        if (error != 0)
                   2111:                return error;
                   2112:
1.137     wrstuden 2113:        mp = vp->v_mount;
1.306     dsl      2114:        error = dostatvfs(mp, sb, l, flags, 1);
1.137     wrstuden 2115:        vput(vp);
1.241     yamt     2116:        return error;
1.31      cgd      2117: }
                   2118:
1.265     yamt     2119: /* ARGSUSED */
                   2120: int
1.335     dsl      2121: sys___fhstatvfs140(struct lwp *l, const struct sys___fhstatvfs140_args *uap, register_t *retval)
1.265     yamt     2122: {
1.335     dsl      2123:        /* {
1.266     yamt     2124:                syscallarg(const void *) fhp;
1.265     yamt     2125:                syscallarg(size_t) fh_size;
                   2126:                syscallarg(struct statvfs *) buf;
                   2127:                syscallarg(int) flags;
1.335     dsl      2128:        } */
1.306     dsl      2129:        struct statvfs *sb = STATVFSBUF_GET();
                   2130:        int error;
1.265     yamt     2131:
1.306     dsl      2132:        error = do_fhstatvfs(l, SCARG(uap, fhp), SCARG(uap, fh_size), sb,
                   2133:            SCARG(uap, flags));
                   2134:        if (error == 0)
                   2135:                error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
                   2136:        STATVFSBUF_PUT(sb);
                   2137:        return error;
1.265     yamt     2138: }
                   2139:
1.31      cgd      2140: /*
                   2141:  * Create a special file.
                   2142:  */
                   2143: /* ARGSUSED */
1.63      christos 2144: int
1.383     christos 2145: sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap,
                   2146:     register_t *retval)
1.56      thorpej  2147: {
1.335     dsl      2148:        /* {
1.74      cgd      2149:                syscallarg(const char *) path;
1.383     christos 2150:                syscallarg(mode_t) mode;
                   2151:                syscallarg(dev_t) dev;
1.335     dsl      2152:        } */
1.460     manu     2153:        return do_sys_mknodat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
1.399     haad     2154:            SCARG(uap, dev), retval, UIO_USERSPACE);
1.383     christos 2155: }
                   2156:
                   2157: int
1.433     manu     2158: sys_mknodat(struct lwp *l, const struct sys_mknodat_args *uap,
                   2159:     register_t *retval)
                   2160: {
                   2161:        /* {
                   2162:                syscallarg(int) fd;
                   2163:                syscallarg(const char *) path;
                   2164:                syscallarg(mode_t) mode;
1.468     njoly    2165:                syscallarg(int) pad;
                   2166:                syscallarg(dev_t) dev;
1.433     manu     2167:        } */
                   2168:
1.460     manu     2169:        return do_sys_mknodat(l, SCARG(uap, fd), SCARG(uap, path),
                   2170:            SCARG(uap, mode), SCARG(uap, dev), retval, UIO_USERSPACE);
1.433     manu     2171: }
                   2172:
                   2173: int
1.383     christos 2174: do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev,
1.399     haad     2175:     register_t *retval, enum uio_seg seg)
1.383     christos 2176: {
1.460     manu     2177:        return do_sys_mknodat(l, AT_FDCWD, pathname, mode, dev, retval, seg);
                   2178: }
                   2179:
                   2180: int
                   2181: do_sys_mknodat(struct lwp *l, int fdat, const char *pathname, mode_t mode,
                   2182:     dev_t dev, register_t *retval, enum uio_seg seg)
                   2183: {
1.179     thorpej  2184:        struct proc *p = l->l_proc;
1.155     augustss 2185:        struct vnode *vp;
1.31      cgd      2186:        struct vattr vattr;
1.301     pooka    2187:        int error, optype;
1.409     dholland 2188:        struct pathbuf *pb;
1.315     christos 2189:        struct nameidata nd;
1.409     dholland 2190:        const char *pathstring;
1.31      cgd      2191:
1.268     elad     2192:        if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
                   2193:            0, NULL, NULL, NULL)) != 0)
1.31      cgd      2194:                return (error);
1.301     pooka    2195:
                   2196:        optype = VOP_MKNOD_DESCOFFSET;
1.315     christos 2197:
1.409     dholland 2198:        error = pathbuf_maybe_copyin(pathname, seg, &pb);
                   2199:        if (error) {
                   2200:                return error;
                   2201:        }
                   2202:        pathstring = pathbuf_stringcopy_get(pb);
                   2203:        if (pathstring == NULL) {
                   2204:                pathbuf_destroy(pb);
                   2205:                return ENOMEM;
                   2206:        }
1.315     christos 2207:
1.409     dholland 2208:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1.460     manu     2209:
                   2210:        if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.314     christos 2211:                goto out;
1.31      cgd      2212:        vp = nd.ni_vp;
1.409     dholland 2213:
1.43      mycroft  2214:        if (vp != NULL)
1.31      cgd      2215:                error = EEXIST;
1.43      mycroft  2216:        else {
1.402     pooka    2217:                vattr_null(&vattr);
1.328     ad       2218:                /* We will read cwdi->cwdi_cmask unlocked. */
1.383     christos 2219:                vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
                   2220:                vattr.va_rdev = dev;
1.43      mycroft  2221:
1.383     christos 2222:                switch (mode & S_IFMT) {
1.43      mycroft  2223:                case S_IFMT:    /* used by badsect to flag bad sectors */
                   2224:                        vattr.va_type = VBAD;
                   2225:                        break;
                   2226:                case S_IFCHR:
                   2227:                        vattr.va_type = VCHR;
                   2228:                        break;
                   2229:                case S_IFBLK:
                   2230:                        vattr.va_type = VBLK;
                   2231:                        break;
                   2232:                case S_IFWHT:
1.301     pooka    2233:                        optype = VOP_WHITEOUT_DESCOFFSET;
                   2234:                        break;
                   2235:                case S_IFREG:
1.314     christos 2236: #if NVERIEXEC > 0
1.409     dholland 2237:                        error = veriexec_openchk(l, nd.ni_vp, pathstring,
1.314     christos 2238:                            O_CREAT);
                   2239: #endif /* NVERIEXEC > 0 */
1.301     pooka    2240:                        vattr.va_type = VREG;
1.302     pooka    2241:                        vattr.va_rdev = VNOVAL;
1.301     pooka    2242:                        optype = VOP_CREATE_DESCOFFSET;
1.43      mycroft  2243:                        break;
                   2244:                default:
                   2245:                        error = EINVAL;
                   2246:                        break;
                   2247:                }
1.31      cgd      2248:        }
1.432     martin   2249:        if (error == 0 && optype == VOP_MKNOD_DESCOFFSET
                   2250:            && vattr.va_rdev == VNOVAL)
1.431     hannken  2251:                error = EINVAL;
1.43      mycroft  2252:        if (!error) {
1.301     pooka    2253:                switch (optype) {
                   2254:                case VOP_WHITEOUT_DESCOFFSET:
1.43      mycroft  2255:                        error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
                   2256:                        if (error)
                   2257:                                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2258:                        vput(nd.ni_dvp);
1.301     pooka    2259:                        break;
                   2260:
                   2261:                case VOP_MKNOD_DESCOFFSET:
1.43      mycroft  2262:                        error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
                   2263:                                                &nd.ni_cnd, &vattr);
1.168     assar    2264:                        if (error == 0)
1.473     hannken  2265:                                vrele(nd.ni_vp);
1.472     hannken  2266:                        vput(nd.ni_dvp);
1.301     pooka    2267:                        break;
                   2268:
                   2269:                case VOP_CREATE_DESCOFFSET:
                   2270:                        error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp,
                   2271:                                                &nd.ni_cnd, &vattr);
                   2272:                        if (error == 0)
1.473     hannken  2273:                                vrele(nd.ni_vp);
1.472     hannken  2274:                        vput(nd.ni_dvp);
1.301     pooka    2275:                        break;
1.43      mycroft  2276:                }
                   2277:        } else {
                   2278:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2279:                if (nd.ni_dvp == vp)
                   2280:                        vrele(nd.ni_dvp);
                   2281:                else
                   2282:                        vput(nd.ni_dvp);
                   2283:                if (vp)
                   2284:                        vrele(vp);
1.31      cgd      2285:        }
1.314     christos 2286: out:
1.409     dholland 2287:        pathbuf_stringcopy_put(pb, pathstring);
                   2288:        pathbuf_destroy(pb);
1.31      cgd      2289:        return (error);
                   2290: }
                   2291:
                   2292: /*
                   2293:  * Create a named pipe.
                   2294:  */
                   2295: /* ARGSUSED */
1.63      christos 2296: int
1.335     dsl      2297: sys_mkfifo(struct lwp *l, const struct sys_mkfifo_args *uap, register_t *retval)
1.56      thorpej  2298: {
1.335     dsl      2299:        /* {
1.74      cgd      2300:                syscallarg(const char *) path;
1.35      cgd      2301:                syscallarg(int) mode;
1.335     dsl      2302:        } */
1.460     manu     2303:        return do_sys_mkfifoat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode));
                   2304: }
                   2305:
                   2306: int
                   2307: sys_mkfifoat(struct lwp *l, const struct sys_mkfifoat_args *uap,
                   2308:     register_t *retval)
                   2309: {
                   2310:        /* {
                   2311:                syscallarg(int) fd;
                   2312:                syscallarg(const char *) path;
                   2313:                syscallarg(int) mode;
                   2314:        } */
                   2315:
                   2316:        return do_sys_mkfifoat(l, SCARG(uap, fd), SCARG(uap, path),
                   2317:            SCARG(uap, mode));
                   2318: }
                   2319:
                   2320: static int
                   2321: do_sys_mkfifoat(struct lwp *l, int fdat, const char *path, mode_t mode)
                   2322: {
1.179     thorpej  2323:        struct proc *p = l->l_proc;
1.31      cgd      2324:        struct vattr vattr;
                   2325:        int error;
1.409     dholland 2326:        struct pathbuf *pb;
1.31      cgd      2327:        struct nameidata nd;
                   2328:
1.460     manu     2329:        error = pathbuf_copyin(path, &pb);
1.409     dholland 2330:        if (error) {
                   2331:                return error;
                   2332:        }
                   2333:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1.460     manu     2334:
                   2335:        if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409     dholland 2336:                pathbuf_destroy(pb);
                   2337:                return error;
                   2338:        }
1.31      cgd      2339:        if (nd.ni_vp != NULL) {
                   2340:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2341:                if (nd.ni_dvp == nd.ni_vp)
                   2342:                        vrele(nd.ni_dvp);
                   2343:                else
                   2344:                        vput(nd.ni_dvp);
                   2345:                vrele(nd.ni_vp);
1.409     dholland 2346:                pathbuf_destroy(pb);
1.31      cgd      2347:                return (EEXIST);
                   2348:        }
1.402     pooka    2349:        vattr_null(&vattr);
1.31      cgd      2350:        vattr.va_type = VFIFO;
1.328     ad       2351:        /* We will read cwdi->cwdi_cmask unlocked. */
1.460     manu     2352:        vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1.168     assar    2353:        error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
                   2354:        if (error == 0)
1.473     hannken  2355:                vrele(nd.ni_vp);
1.472     hannken  2356:        vput(nd.ni_dvp);
1.409     dholland 2357:        pathbuf_destroy(pb);
1.168     assar    2358:        return (error);
1.31      cgd      2359: }
                   2360:
                   2361: /*
                   2362:  * Make a hard file link.
                   2363:  */
                   2364: /* ARGSUSED */
1.469     chs      2365: int
1.460     manu     2366: do_sys_linkat(struct lwp *l, int fdpath, const char *path, int fdlink,
                   2367:     const char *link, int follow, register_t *retval)
1.56      thorpej  2368: {
1.155     augustss 2369:        struct vnode *vp;
1.409     dholland 2370:        struct pathbuf *linkpb;
1.31      cgd      2371:        struct nameidata nd;
1.460     manu     2372:        namei_simple_flags_t ns_flags;
1.31      cgd      2373:        int error;
                   2374:
1.460     manu     2375:        if (follow & AT_SYMLINK_FOLLOW)
                   2376:                ns_flags = NSM_FOLLOW_TRYEMULROOT;
1.433     manu     2377:        else
1.460     manu     2378:                ns_flags = NSM_NOFOLLOW_TRYEMULROOT;
1.433     manu     2379:
1.460     manu     2380:        error = fd_nameiat_simple_user(l, fdpath, path, ns_flags, &vp);
1.395     dholland 2381:        if (error != 0)
1.31      cgd      2382:                return (error);
1.433     manu     2383:        error = pathbuf_copyin(link, &linkpb);
1.409     dholland 2384:        if (error) {
                   2385:                goto out1;
                   2386:        }
                   2387:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1.460     manu     2388:        if ((error = fd_nameiat(l, fdlink, &nd)) != 0)
1.409     dholland 2389:                goto out2;
1.66      mycroft  2390:        if (nd.ni_vp) {
                   2391:                error = EEXIST;
1.419     yamt     2392:                goto abortop;
                   2393:        }
1.423     rmind    2394:        /* Prevent hard links on directories. */
                   2395:        if (vp->v_type == VDIR) {
                   2396:                error = EPERM;
                   2397:                goto abortop;
                   2398:        }
                   2399:        /* Prevent cross-mount operation. */
1.419     yamt     2400:        if (nd.ni_dvp->v_mount != vp->v_mount) {
                   2401:                error = EXDEV;
                   2402:                goto abortop;
1.31      cgd      2403:        }
1.66      mycroft  2404:        error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1.409     dholland 2405: out2:
                   2406:        pathbuf_destroy(linkpb);
                   2407: out1:
1.31      cgd      2408:        vrele(vp);
                   2409:        return (error);
1.419     yamt     2410: abortop:
                   2411:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2412:        if (nd.ni_dvp == nd.ni_vp)
                   2413:                vrele(nd.ni_dvp);
                   2414:        else
                   2415:                vput(nd.ni_dvp);
                   2416:        if (nd.ni_vp != NULL)
                   2417:                vrele(nd.ni_vp);
                   2418:        goto out2;
1.31      cgd      2419: }
                   2420:
1.63      christos 2421: int
1.433     manu     2422: sys_link(struct lwp *l, const struct sys_link_args *uap, register_t *retval)
                   2423: {
                   2424:        /* {
                   2425:                syscallarg(const char *) path;
                   2426:                syscallarg(const char *) link;
                   2427:        } */
                   2428:        const char *path = SCARG(uap, path);
                   2429:        const char *link = SCARG(uap, link);
                   2430:
1.460     manu     2431:        return do_sys_linkat(l, AT_FDCWD, path, AT_FDCWD, link,
                   2432:            AT_SYMLINK_FOLLOW, retval);
1.433     manu     2433: }
                   2434:
                   2435: int
                   2436: sys_linkat(struct lwp *l, const struct sys_linkat_args *uap,
                   2437:     register_t *retval)
                   2438: {
                   2439:        /* {
                   2440:                syscallarg(int) fd1;
                   2441:                syscallarg(const char *) name1;
                   2442:                syscallarg(int) fd2;
                   2443:                syscallarg(const char *) name2;
                   2444:                syscallarg(int) flags;
                   2445:        } */
1.460     manu     2446:        int fd1 = SCARG(uap, fd1);
1.433     manu     2447:        const char *name1 = SCARG(uap, name1);
1.460     manu     2448:        int fd2 = SCARG(uap, fd2);
1.433     manu     2449:        const char *name2 = SCARG(uap, name2);
                   2450:        int follow;
                   2451:
                   2452:        follow = SCARG(uap, flags) & AT_SYMLINK_FOLLOW;
                   2453:
1.460     manu     2454:        return do_sys_linkat(l, fd1, name1, fd2, name2, follow, retval);
1.433     manu     2455: }
                   2456:
                   2457:
                   2458: int
1.407     pooka    2459: do_sys_symlink(const char *patharg, const char *link, enum uio_seg seg)
1.56      thorpej  2460: {
1.460     manu     2461:        return do_sys_symlinkat(NULL, patharg, AT_FDCWD, link, seg);
                   2462: }
                   2463:
                   2464: static int
                   2465: do_sys_symlinkat(struct lwp *l, const char *patharg, int fdat,
                   2466:     const char *link, enum uio_seg seg)
                   2467: {
1.407     pooka    2468:        struct proc *p = curproc;
1.31      cgd      2469:        struct vattr vattr;
                   2470:        char *path;
                   2471:        int error;
1.409     dholland 2472:        struct pathbuf *linkpb;
1.31      cgd      2473:        struct nameidata nd;
                   2474:
1.460     manu     2475:        KASSERT(l != NULL || fdat == AT_FDCWD);
                   2476:
1.161     thorpej  2477:        path = PNBUF_GET();
1.407     pooka    2478:        if (seg == UIO_USERSPACE) {
                   2479:                if ((error = copyinstr(patharg, path, MAXPATHLEN, NULL)) != 0)
1.409     dholland 2480:                        goto out1;
                   2481:                if ((error = pathbuf_copyin(link, &linkpb)) != 0)
                   2482:                        goto out1;
1.407     pooka    2483:        } else {
                   2484:                KASSERT(strlen(patharg) < MAXPATHLEN);
                   2485:                strcpy(path, patharg);
1.409     dholland 2486:                linkpb = pathbuf_create(link);
                   2487:                if (linkpb == NULL) {
                   2488:                        error = ENOMEM;
                   2489:                        goto out1;
                   2490:                }
1.407     pooka    2491:        }
1.433     manu     2492:        ktrkuser("symlink-target", path, strlen(path));
                   2493:
1.409     dholland 2494:        NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1.460     manu     2495:        if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.409     dholland 2496:                goto out2;
1.31      cgd      2497:        if (nd.ni_vp) {
                   2498:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2499:                if (nd.ni_dvp == nd.ni_vp)
                   2500:                        vrele(nd.ni_dvp);
                   2501:                else
                   2502:                        vput(nd.ni_dvp);
                   2503:                vrele(nd.ni_vp);
                   2504:                error = EEXIST;
1.409     dholland 2505:                goto out2;
1.31      cgd      2506:        }
1.402     pooka    2507:        vattr_null(&vattr);
1.230     jmmv     2508:        vattr.va_type = VLNK;
1.328     ad       2509:        /* We will read cwdi->cwdi_cmask unlocked. */
1.134     thorpej  2510:        vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1.31      cgd      2511:        error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1.168     assar    2512:        if (error == 0)
1.473     hannken  2513:                vrele(nd.ni_vp);
1.472     hannken  2514:        vput(nd.ni_dvp);
1.409     dholland 2515: out2:
                   2516:        pathbuf_destroy(linkpb);
                   2517: out1:
1.161     thorpej  2518:        PNBUF_PUT(path);
1.31      cgd      2519:        return (error);
                   2520: }
                   2521:
                   2522: /*
1.407     pooka    2523:  * Make a symbolic link.
                   2524:  */
                   2525: /* ARGSUSED */
                   2526: int
                   2527: sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)
                   2528: {
                   2529:        /* {
                   2530:                syscallarg(const char *) path;
                   2531:                syscallarg(const char *) link;
                   2532:        } */
                   2533:
1.460     manu     2534:        return do_sys_symlinkat(l, SCARG(uap, path), AT_FDCWD, SCARG(uap, link),
1.407     pooka    2535:            UIO_USERSPACE);
                   2536: }
                   2537:
1.433     manu     2538: int
                   2539: sys_symlinkat(struct lwp *l, const struct sys_symlinkat_args *uap,
                   2540:     register_t *retval)
                   2541: {
                   2542:        /* {
1.460     manu     2543:                syscallarg(const char *) path1;
1.433     manu     2544:                syscallarg(int) fd;
1.460     manu     2545:                syscallarg(const char *) path2;
1.433     manu     2546:        } */
                   2547:
1.460     manu     2548:        return do_sys_symlinkat(l, SCARG(uap, path1), SCARG(uap, fd),
                   2549:            SCARG(uap, path2), UIO_USERSPACE);
1.433     manu     2550: }
                   2551:
1.407     pooka    2552: /*
1.43      mycroft  2553:  * Delete a whiteout from the filesystem.
                   2554:  */
                   2555: /* ARGSUSED */
1.63      christos 2556: int
1.335     dsl      2557: sys_undelete(struct lwp *l, const struct sys_undelete_args *uap, register_t *retval)
1.56      thorpej  2558: {
1.335     dsl      2559:        /* {
1.74      cgd      2560:                syscallarg(const char *) path;
1.335     dsl      2561:        } */
1.43      mycroft  2562:        int error;
1.409     dholland 2563:        struct pathbuf *pb;
1.43      mycroft  2564:        struct nameidata nd;
                   2565:
1.409     dholland 2566:        error = pathbuf_copyin(SCARG(uap, path), &pb);
                   2567:        if (error) {
                   2568:                return error;
                   2569:        }
                   2570:
                   2571:        NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | TRYEMULROOT, pb);
1.43      mycroft  2572:        error = namei(&nd);
1.409     dholland 2573:        if (error) {
                   2574:                pathbuf_destroy(pb);
1.43      mycroft  2575:                return (error);
1.409     dholland 2576:        }
1.43      mycroft  2577:
                   2578:        if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
                   2579:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2580:                if (nd.ni_dvp == nd.ni_vp)
                   2581:                        vrele(nd.ni_dvp);
                   2582:                else
                   2583:                        vput(nd.ni_dvp);
                   2584:                if (nd.ni_vp)
                   2585:                        vrele(nd.ni_vp);
1.409     dholland 2586:                pathbuf_destroy(pb);
1.43      mycroft  2587:                return (EEXIST);
                   2588:        }
1.63      christos 2589:        if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1.43      mycroft  2590:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2591:        vput(nd.ni_dvp);
1.409     dholland 2592:        pathbuf_destroy(pb);
1.43      mycroft  2593:        return (error);
                   2594: }
                   2595:
                   2596: /*
1.31      cgd      2597:  * Delete a name from the filesystem.
                   2598:  */
                   2599: /* ARGSUSED */
1.63      christos 2600: int
1.335     dsl      2601: sys_unlink(struct lwp *l, const struct sys_unlink_args *uap, register_t *retval)
1.56      thorpej  2602: {
1.335     dsl      2603:        /* {
1.74      cgd      2604:                syscallarg(const char *) path;
1.335     dsl      2605:        } */
1.336     ad       2606:
1.460     manu     2607:        return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path), 0, UIO_USERSPACE);
1.336     ad       2608: }
                   2609:
                   2610: int
1.433     manu     2611: sys_unlinkat(struct lwp *l, const struct sys_unlinkat_args *uap,
                   2612:     register_t *retval)
                   2613: {
                   2614:        /* {
                   2615:                syscallarg(int) fd;
                   2616:                syscallarg(const char *) path;
1.460     manu     2617:                syscallarg(int) flag;
1.433     manu     2618:        } */
                   2619:
1.460     manu     2620:        return do_sys_unlinkat(l, SCARG(uap, fd), SCARG(uap, path),
                   2621:            SCARG(uap, flag), UIO_USERSPACE);
1.433     manu     2622: }
                   2623:
                   2624: int
1.336     ad       2625: do_sys_unlink(const char *arg, enum uio_seg seg)
                   2626: {
1.460     manu     2627:        return do_sys_unlinkat(NULL, AT_FDCWD, arg, 0, seg);
                   2628: }
                   2629:
                   2630: static int
                   2631: do_sys_unlinkat(struct lwp *l, int fdat, const char *arg, int flags,
                   2632:     enum uio_seg seg)
                   2633: {
1.155     augustss 2634:        struct vnode *vp;
1.31      cgd      2635:        int error;
1.409     dholland 2636:        struct pathbuf *pb;
1.31      cgd      2637:        struct nameidata nd;
1.409     dholland 2638:        const char *pathstring;
1.31      cgd      2639:
1.460     manu     2640:        KASSERT(l != NULL || fdat == AT_FDCWD);
                   2641:
1.409     dholland 2642:        error = pathbuf_maybe_copyin(arg, seg, &pb);
                   2643:        if (error) {
                   2644:                return error;
                   2645:        }
                   2646:        pathstring = pathbuf_stringcopy_get(pb);
                   2647:        if (pathstring == NULL) {
                   2648:                pathbuf_destroy(pb);
                   2649:                return ENOMEM;
                   2650:        }
1.313     elad     2651:
1.409     dholland 2652:        NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, pb);
1.460     manu     2653:        if ((error = fd_nameiat(l, fdat, &nd)) != 0)
1.313     elad     2654:                goto out;
1.31      cgd      2655:        vp = nd.ni_vp;
                   2656:
1.66      mycroft  2657:        /*
                   2658:         * The root of a mounted filesystem cannot be deleted.
                   2659:         */
1.460     manu     2660:        if ((vp->v_vflag & VV_ROOT) != 0) {
                   2661:                error = EBUSY;
                   2662:                goto abort;
                   2663:        }
                   2664:
                   2665:        if ((vp->v_type == VDIR) && (vp->v_mountedhere != NULL)) {
1.66      mycroft  2666:                error = EBUSY;
1.460     manu     2667:                goto abort;
                   2668:        }
                   2669:
                   2670:        /*
                   2671:         * No rmdir "." please.
                   2672:         */
                   2673:        if (nd.ni_dvp == vp) {
                   2674:                error = EINVAL;
                   2675:                goto abort;
                   2676:        }
                   2677:
                   2678:        /*
                   2679:         * AT_REMOVEDIR is required to remove a directory
                   2680:         */
                   2681:        if (vp->v_type == VDIR) {
                   2682:                if (!(flags & AT_REMOVEDIR)) {
                   2683:                        error = EPERM;
                   2684:                        goto abort;
                   2685:                } else {
                   2686:                        error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
                   2687:                        goto out;
                   2688:                }
                   2689:        }
                   2690:
                   2691:        /*
                   2692:         * Starting here we only deal with non directories.
                   2693:         */
                   2694:        if (flags & AT_REMOVEDIR) {
                   2695:                error = ENOTDIR;
                   2696:                goto abort;
1.31      cgd      2697:        }
1.219     blymn    2698:
1.460     manu     2699:
1.256     elad     2700: #if NVERIEXEC > 0
1.222     elad     2701:        /* Handle remove requests for veriexec entries. */
1.409     dholland 2702:        if ((error = veriexec_removechk(curlwp, nd.ni_vp, pathstring)) != 0) {
1.219     blymn    2703:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2704:                if (nd.ni_dvp == vp)
                   2705:                        vrele(nd.ni_dvp);
                   2706:                else
                   2707:                        vput(nd.ni_dvp);
                   2708:                vput(vp);
                   2709:                goto out;
                   2710:        }
1.256     elad     2711: #endif /* NVERIEXEC > 0 */
                   2712:
1.253     elad     2713: #ifdef FILEASSOC
1.278     elad     2714:        (void)fileassoc_file_delete(vp);
1.253     elad     2715: #endif /* FILEASSOC */
1.66      mycroft  2716:        error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1.460     manu     2717:        goto out;
                   2718:
                   2719: abort:
                   2720:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   2721:        if (nd.ni_dvp == vp)
                   2722:                vrele(nd.ni_dvp);
                   2723:        else
                   2724:                vput(nd.ni_dvp);
                   2725:        vput(vp);
                   2726:
1.66      mycroft  2727: out:
1.409     dholland 2728:        pathbuf_stringcopy_put(pb, pathstring);
                   2729:        pathbuf_destroy(pb);
1.31      cgd      2730:        return (error);
                   2731: }
                   2732:
                   2733: /*
                   2734:  * Reposition read/write file offset.
                   2735:  */
1.63      christos 2736: int
1.335     dsl      2737: sys_lseek(struct lwp *l, const struct sys_lseek_args *uap, register_t *retval)
1.56      thorpej  2738: {
1.335     dsl      2739:        /* {
1.35      cgd      2740:                syscallarg(int) fd;
                   2741:                syscallarg(int) pad;
                   2742:                syscallarg(off_t) offset;
                   2743:                syscallarg(int) whence;
1.335     dsl      2744:        } */
1.257     ad       2745:        kauth_cred_t cred = l->l_cred;
1.346     ad       2746:        file_t *fp;
1.84      kleink   2747:        struct vnode *vp;
1.31      cgd      2748:        struct vattr vattr;
1.155     augustss 2749:        off_t newoff;
1.346     ad       2750:        int error, fd;
                   2751:
                   2752:        fd = SCARG(uap, fd);
1.31      cgd      2753:
1.346     ad       2754:        if ((fp = fd_getfile(fd)) == NULL)
1.31      cgd      2755:                return (EBADF);
1.84      kleink   2756:
1.346     ad       2757:        vp = fp->f_data;
1.135     thorpej  2758:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2759:                error = ESPIPE;
                   2760:                goto out;
                   2761:        }
1.84      kleink   2762:
1.35      cgd      2763:        switch (SCARG(uap, whence)) {
1.92      kleink   2764:        case SEEK_CUR:
1.84      kleink   2765:                newoff = fp->f_offset + SCARG(uap, offset);
1.31      cgd      2766:                break;
1.92      kleink   2767:        case SEEK_END:
1.440     hannken  2768:                vn_lock(vp, LK_SHARED | LK_RETRY);
1.332     pooka    2769:                error = VOP_GETATTR(vp, &vattr, cred);
1.440     hannken  2770:                VOP_UNLOCK(vp);
1.328     ad       2771:                if (error) {
1.135     thorpej  2772:                        goto out;
1.328     ad       2773:                }
1.84      kleink   2774:                newoff = SCARG(uap, offset) + vattr.va_size;
1.31      cgd      2775:                break;
1.92      kleink   2776:        case SEEK_SET:
1.84      kleink   2777:                newoff = SCARG(uap, offset);
1.31      cgd      2778:                break;
                   2779:        default:
1.135     thorpej  2780:                error = EINVAL;
                   2781:                goto out;
1.31      cgd      2782:        }
1.328     ad       2783:        if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) == 0) {
                   2784:                *(off_t *)retval = fp->f_offset = newoff;
                   2785:        }
1.135     thorpej  2786:  out:
1.346     ad       2787:        fd_putfile(fd);
1.135     thorpej  2788:        return (error);
1.120     thorpej  2789: }
                   2790:
                   2791: /*
                   2792:  * Positional read system call.
                   2793:  */
                   2794: int
1.335     dsl      2795: sys_pread(struct lwp *l, const struct sys_pread_args *uap, register_t *retval)
1.120     thorpej  2796: {
1.335     dsl      2797:        /* {
1.120     thorpej  2798:                syscallarg(int) fd;
                   2799:                syscallarg(void *) buf;
                   2800:                syscallarg(size_t) nbyte;
                   2801:                syscallarg(off_t) offset;
1.335     dsl      2802:        } */
1.346     ad       2803:        file_t *fp;
1.120     thorpej  2804:        struct vnode *vp;
                   2805:        off_t offset;
                   2806:        int error, fd = SCARG(uap, fd);
                   2807:
1.346     ad       2808:        if ((fp = fd_getfile(fd)) == NULL)
1.166     thorpej  2809:                return (EBADF);
                   2810:
1.183     pk       2811:        if ((fp->f_flag & FREAD) == 0) {
1.346     ad       2812:                fd_putfile(fd);
1.120     thorpej  2813:                return (EBADF);
1.183     pk       2814:        }
1.120     thorpej  2815:
1.346     ad       2816:        vp = fp->f_data;
1.135     thorpej  2817:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2818:                error = ESPIPE;
                   2819:                goto out;
                   2820:        }
1.120     thorpej  2821:
                   2822:        offset = SCARG(uap, offset);
                   2823:
                   2824:        /*
                   2825:         * XXX This works because no file systems actually
                   2826:         * XXX take any action on the seek operation.
                   2827:         */
                   2828:        if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135     thorpej  2829:                goto out;
1.120     thorpej  2830:
1.135     thorpej  2831:        /* dofileread() will unuse the descriptor for us */
1.328     ad       2832:        return (dofileread(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120     thorpej  2833:            &offset, 0, retval));
1.135     thorpej  2834:
                   2835:  out:
1.346     ad       2836:        fd_putfile(fd);
1.135     thorpej  2837:        return (error);
1.120     thorpej  2838: }
                   2839:
                   2840: /*
                   2841:  * Positional scatter read system call.
                   2842:  */
                   2843: int
1.335     dsl      2844: sys_preadv(struct lwp *l, const struct sys_preadv_args *uap, register_t *retval)
1.120     thorpej  2845: {
1.335     dsl      2846:        /* {
1.120     thorpej  2847:                syscallarg(int) fd;
                   2848:                syscallarg(const struct iovec *) iovp;
                   2849:                syscallarg(int) iovcnt;
                   2850:                syscallarg(off_t) offset;
1.335     dsl      2851:        } */
                   2852:        off_t offset = SCARG(uap, offset);
1.120     thorpej  2853:
1.328     ad       2854:        return do_filereadv(SCARG(uap, fd), SCARG(uap, iovp),
1.335     dsl      2855:            SCARG(uap, iovcnt), &offset, 0, retval);
1.120     thorpej  2856: }
                   2857:
                   2858: /*
                   2859:  * Positional write system call.
                   2860:  */
                   2861: int
1.335     dsl      2862: sys_pwrite(struct lwp *l, const struct sys_pwrite_args *uap, register_t *retval)
1.120     thorpej  2863: {
1.335     dsl      2864:        /* {
1.120     thorpej  2865:                syscallarg(int) fd;
                   2866:                syscallarg(const void *) buf;
                   2867:                syscallarg(size_t) nbyte;
                   2868:                syscallarg(off_t) offset;
1.335     dsl      2869:        } */
1.346     ad       2870:        file_t *fp;
1.120     thorpej  2871:        struct vnode *vp;
                   2872:        off_t offset;
                   2873:        int error, fd = SCARG(uap, fd);
                   2874:
1.346     ad       2875:        if ((fp = fd_getfile(fd)) == NULL)
1.166     thorpej  2876:                return (EBADF);
                   2877:
1.183     pk       2878:        if ((fp->f_flag & FWRITE) == 0) {
1.346     ad       2879:                fd_putfile(fd);
1.120     thorpej  2880:                return (EBADF);
1.183     pk       2881:        }
1.120     thorpej  2882:
1.346     ad       2883:        vp = fp->f_data;
1.135     thorpej  2884:        if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
                   2885:                error = ESPIPE;
                   2886:                goto out;
                   2887:        }
1.120     thorpej  2888:
                   2889:        offset = SCARG(uap, offset);
                   2890:
                   2891:        /*
                   2892:         * XXX This works because no file systems actually
                   2893:         * XXX take any action on the seek operation.
                   2894:         */
                   2895:        if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1.135     thorpej  2896:                goto out;
1.120     thorpej  2897:
1.135     thorpej  2898:        /* dofilewrite() will unuse the descriptor for us */
1.328     ad       2899:        return (dofilewrite(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1.120     thorpej  2900:            &offset, 0, retval));
1.135     thorpej  2901:
                   2902:  out:
1.346     ad       2903:        fd_putfile(fd);
1.135     thorpej  2904:        return (error);
1.120     thorpej  2905: }
                   2906:
                   2907: /*
                   2908:  * Positional gather write system call.
                   2909:  */
                   2910: int
1.335     dsl      2911: sys_pwritev(struct lwp *l, const struct sys_pwritev_args *uap, register_t *retval)
1.120     thorpej  2912: {
1.335     dsl      2913:        /* {
1.120     thorpej  2914:                syscallarg(int) fd;
                   2915:                syscallarg(const struct iovec *) iovp;
                   2916:                syscallarg(int) iovcnt;
                   2917:                syscallarg(off_t) offset;
1.335     dsl      2918:        } */
                   2919:        off_t offset = SCARG(uap, offset);
1.120     thorpej  2920:
1.328     ad       2921:        return do_filewritev(SCARG(uap, fd), SCARG(uap, iovp),
1.335     dsl      2922:            SCARG(uap, iovcnt), &offset, 0, retval);
1.31      cgd      2923: }
                   2924:
                   2925: /*
                   2926:  * Check access permissions.
                   2927:  */
1.63      christos 2928: int
1.335     dsl      2929: sys_access(struct lwp *l, const struct sys_access_args *uap, register_t *retval)
1.56      thorpej  2930: {
1.335     dsl      2931:        /* {
1.74      cgd      2932:                syscallarg(const char *) path;
1.35      cgd      2933:                syscallarg(int) flags;
1.335     dsl      2934:        } */
1.460     manu     2935:
                   2936:        return do_sys_accessat(l, AT_FDCWD, SCARG(uap, path),
                   2937:             SCARG(uap, flags), 0);
                   2938: }
                   2939:
1.469     chs      2940: int
1.460     manu     2941: do_sys_accessat(struct lwp *l, int fdat, const char *path,
                   2942:     int mode, int flags)
                   2943: {
1.242     elad     2944:        kauth_cred_t cred;
1.155     augustss 2945:        struct vnode *vp;
1.460     manu     2946:        int error, nd_flag, vmode;
1.409     dholland 2947:        struct pathbuf *pb;
1.31      cgd      2948:        struct nameidata nd;
                   2949:
1.417     dholland 2950:        CTASSERT(F_OK == 0);
1.460     manu     2951:        if ((mode & ~(R_OK | W_OK | X_OK)) != 0) {
                   2952:                /* nonsense mode */
1.415     dholland 2953:                return EINVAL;
                   2954:        }
                   2955:
1.460     manu     2956:        nd_flag = FOLLOW | LOCKLEAF | TRYEMULROOT;
                   2957:        if (flags & AT_SYMLINK_NOFOLLOW)
                   2958:                nd_flag &= ~FOLLOW;
                   2959:
                   2960:        error = pathbuf_copyin(path, &pb);
                   2961:        if (error)
1.409     dholland 2962:                return error;
1.460     manu     2963:
                   2964:        NDINIT(&nd, LOOKUP, nd_flag, pb);
1.409     dholland 2965:
                   2966:        /* Override default credentials */
1.257     ad       2967:        cred = kauth_cred_dup(l->l_cred);
1.460     manu     2968:        if (!(flags & AT_EACCESS)) {
                   2969:                kauth_cred_seteuid(cred, kauth_cred_getuid(l->l_cred));
                   2970:                kauth_cred_setegid(cred, kauth_cred_getgid(l->l_cred));
                   2971:        }
1.169     christos 2972:        nd.ni_cnd.cn_cred = cred;
1.409     dholland 2973:
1.460     manu     2974:        if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409     dholland 2975:                pathbuf_destroy(pb);
1.169     christos 2976:                goto out;
1.409     dholland 2977:        }
1.31      cgd      2978:        vp = nd.ni_vp;
1.409     dholland 2979:        pathbuf_destroy(pb);
1.31      cgd      2980:
                   2981:        /* Flags == 0 means only check for existence. */
1.460     manu     2982:        if (mode) {
                   2983:                vmode = 0;
                   2984:                if (mode & R_OK)
                   2985:                        vmode |= VREAD;
                   2986:                if (mode & W_OK)
                   2987:                        vmode |= VWRITE;
                   2988:                if (mode & X_OK)
                   2989:                        vmode |= VEXEC;
1.138     is       2990:
1.460     manu     2991:                error = VOP_ACCESS(vp, vmode, cred);
                   2992:                if (!error && (vmode & VWRITE))
1.138     is       2993:                        error = vn_writechk(vp);
1.31      cgd      2994:        }
                   2995:        vput(vp);
1.169     christos 2996: out:
1.242     elad     2997:        kauth_cred_free(cred);
1.31      cgd      2998:        return (error);
                   2999: }
                   3000:
1.433     manu     3001: int
                   3002: sys_faccessat(struct lwp *l, const struct sys_faccessat_args *uap,
                   3003:     register_t *retval)
                   3004: {
                   3005:        /* {
                   3006:                syscallarg(int) fd;
                   3007:                syscallarg(const char *) path;
                   3008:                syscallarg(int) amode;
                   3009:                syscallarg(int) flag;
                   3010:        } */
                   3011:
1.460     manu     3012:        return do_sys_accessat(l, SCARG(uap, fd), SCARG(uap, path),
                   3013:             SCARG(uap, amode), SCARG(uap, flag));
1.433     manu     3014: }
                   3015:
1.31      cgd      3016: /*
1.306     dsl      3017:  * Common code for all sys_stat functions, including compat versions.
                   3018:  */
                   3019: int
1.460     manu     3020: do_sys_stat(const char *userpath, unsigned int nd_flag,
                   3021:     struct stat *sb)
                   3022: {
                   3023:        return do_sys_statat(NULL, AT_FDCWD, userpath, nd_flag, sb);
                   3024: }
                   3025:
1.465     matt     3026: int
1.460     manu     3027: do_sys_statat(struct lwp *l, int fdat, const char *userpath,
                   3028:     unsigned int nd_flag, struct stat *sb)
1.306     dsl      3029: {
                   3030:        int error;
1.409     dholland 3031:        struct pathbuf *pb;
1.306     dsl      3032:        struct nameidata nd;
                   3033:
1.460     manu     3034:        KASSERT(l != NULL || fdat == AT_FDCWD);
                   3035:
1.409     dholland 3036:        error = pathbuf_copyin(userpath, &pb);
                   3037:        if (error) {
                   3038:                return error;
                   3039:        }
1.460     manu     3040:
                   3041:        NDINIT(&nd, LOOKUP, nd_flag | LOCKLEAF | TRYEMULROOT, pb);
                   3042:
                   3043:        error = fd_nameiat(l, fdat, &nd);
1.409     dholland 3044:        if (error != 0) {
                   3045:                pathbuf_destroy(pb);
1.306     dsl      3046:                return error;
1.409     dholland 3047:        }
1.346     ad       3048:        error = vn_stat(nd.ni_vp, sb);
1.306     dsl      3049:        vput(nd.ni_vp);
1.409     dholland 3050:        pathbuf_destroy(pb);
1.306     dsl      3051:        return error;
                   3052: }
                   3053:
                   3054: /*
1.31      cgd      3055:  * Get file status; this version follows links.
                   3056:  */
                   3057: /* ARGSUSED */
1.63      christos 3058: int
1.383     christos 3059: sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval)
1.56      thorpej  3060: {
1.335     dsl      3061:        /* {
1.74      cgd      3062:                syscallarg(const char *) path;
1.35      cgd      3063:                syscallarg(struct stat *) ub;
1.335     dsl      3064:        } */
1.31      cgd      3065:        struct stat sb;
                   3066:        int error;
                   3067:
1.460     manu     3068:        error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), FOLLOW, &sb);
1.31      cgd      3069:        if (error)
1.306     dsl      3070:                return error;
                   3071:        return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31      cgd      3072: }
                   3073:
                   3074: /*
                   3075:  * Get file status; this version does not follow links.
                   3076:  */
                   3077: /* ARGSUSED */
1.63      christos 3078: int
1.383     christos 3079: sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval)
1.56      thorpej  3080: {
1.335     dsl      3081:        /* {
1.74      cgd      3082:                syscallarg(const char *) path;
1.35      cgd      3083:                syscallarg(struct stat *) ub;
1.335     dsl      3084:        } */
1.65      mycroft  3085:        struct stat sb;
1.31      cgd      3086:        int error;
                   3087:
1.460     manu     3088:        error = do_sys_statat(l, AT_FDCWD, SCARG(uap, path), NOFOLLOW, &sb);
1.64      jtc      3089:        if (error)
1.306     dsl      3090:                return error;
                   3091:        return copyout(&sb, SCARG(uap, ub), sizeof(sb));
1.31      cgd      3092: }
                   3093:
1.433     manu     3094: int
                   3095: sys_fstatat(struct lwp *l, const struct sys_fstatat_args *uap,
                   3096:     register_t *retval)
                   3097: {
                   3098:        /* {
                   3099:                syscallarg(int) fd;
                   3100:                syscallarg(const char *) path;
1.460     manu     3101:                syscallarg(struct stat *) buf;
1.433     manu     3102:                syscallarg(int) flag;
                   3103:        } */
1.460     manu     3104:        unsigned int nd_flag;
1.461     martin   3105:        struct stat sb;
                   3106:        int error;
1.433     manu     3107:
1.460     manu     3108:        if (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW)
                   3109:                nd_flag = NOFOLLOW;
                   3110:        else
                   3111:                nd_flag = FOLLOW;
                   3112:
1.461     martin   3113:        error = do_sys_statat(l, SCARG(uap, fd), SCARG(uap, path), nd_flag,
                   3114:            &sb);
                   3115:        if (error)
                   3116:                return error;
                   3117:        return copyout(&sb, SCARG(uap, buf), sizeof(sb));
1.433     manu     3118: }
1.460     manu     3119:
1.31      cgd      3120: /*
                   3121:  * Get configurable pathname variables.
                   3122:  */
                   3123: /* ARGSUSED */
1.63      christos 3124: int
1.335     dsl      3125: sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval)
1.56      thorpej  3126: {
1.335     dsl      3127:        /* {
1.74      cgd      3128:                syscallarg(const char *) path;
1.35      cgd      3129:                syscallarg(int) name;
1.335     dsl      3130:        } */
1.31      cgd      3131:        int error;
1.409     dholland 3132:        struct pathbuf *pb;
1.31      cgd      3133:        struct nameidata nd;
                   3134:
1.409     dholland 3135:        error = pathbuf_copyin(SCARG(uap, path), &pb);
                   3136:        if (error) {
                   3137:                return error;
                   3138:        }
                   3139:        NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
                   3140:        if ((error = namei(&nd)) != 0) {
                   3141:                pathbuf_destroy(pb);
1.31      cgd      3142:                return (error);
1.409     dholland 3143:        }
1.35      cgd      3144:        error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1.31      cgd      3145:        vput(nd.ni_vp);
1.409     dholland 3146:        pathbuf_destroy(pb);
1.31      cgd      3147:        return (error);
                   3148: }
                   3149:
                   3150: /*
                   3151:  * Return target name of a symbolic link.
                   3152:  */
                   3153: /* ARGSUSED */
1.63      christos 3154: int
1.460     manu     3155: sys_readlink(struct lwp *l, const struct sys_readlink_args *uap,
                   3156:     register_t *retval)
1.56      thorpej  3157: {
1.335     dsl      3158:        /* {
1.74      cgd      3159:                syscallarg(const char *) path;
1.35      cgd      3160:                syscallarg(char *) buf;
1.115     kleink   3161:                syscallarg(size_t) count;
1.335     dsl      3162:        } */
1.460     manu     3163:        return do_sys_readlinkat(l, AT_FDCWD, SCARG(uap, path),
                   3164:            SCARG(uap, buf), SCARG(uap, count), retval);
                   3165: }
                   3166:
                   3167: static int
                   3168: do_sys_readlinkat(struct lwp *l, int fdat, const char *path, char *buf,
                   3169:     size_t count, register_t *retval)
                   3170: {
1.155     augustss 3171:        struct vnode *vp;
1.31      cgd      3172:        struct iovec aiov;
                   3173:        struct uio auio;
                   3174:        int error;
1.409     dholland 3175:        struct pathbuf *pb;
1.31      cgd      3176:        struct nameidata nd;
                   3177:
1.460     manu     3178:        error = pathbuf_copyin(path, &pb);
1.409     dholland 3179:        if (error) {
                   3180:                return error;
                   3181:        }
                   3182:        NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1.460     manu     3183:        if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409     dholland 3184:                pathbuf_destroy(pb);
                   3185:                return error;
                   3186:        }
1.31      cgd      3187:        vp = nd.ni_vp;
1.409     dholland 3188:        pathbuf_destroy(pb);
1.31      cgd      3189:        if (vp->v_type != VLNK)
                   3190:                error = EINVAL;
1.106     enami    3191:        else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
1.332     pooka    3192:            (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) {
1.460     manu     3193:                aiov.iov_base = buf;
                   3194:                aiov.iov_len = count;
1.31      cgd      3195:                auio.uio_iov = &aiov;
                   3196:                auio.uio_iovcnt = 1;
                   3197:                auio.uio_offset = 0;
                   3198:                auio.uio_rw = UIO_READ;
1.238     yamt     3199:                KASSERT(l == curlwp);
                   3200:                auio.uio_vmspace = l->l_proc->p_vmspace;
1.460     manu     3201:                auio.uio_resid = count;
1.464     christos 3202:                if ((error = VOP_READLINK(vp, &auio, l->l_cred)) == 0)
                   3203:                        *retval = count - auio.uio_resid;
1.31      cgd      3204:        }
                   3205:        vput(vp);
                   3206:        return (error);
                   3207: }
                   3208:
1.433     manu     3209: int
                   3210: sys_readlinkat(struct lwp *l, const struct sys_readlinkat_args *uap,
                   3211:     register_t *retval)
                   3212: {
                   3213:        /* {
                   3214:                syscallarg(int) fd;
                   3215:                syscallarg(const char *) path;
                   3216:                syscallarg(char *) buf;
1.460     manu     3217:                syscallarg(size_t) bufsize;
1.433     manu     3218:        } */
                   3219:
1.460     manu     3220:        return do_sys_readlinkat(l, SCARG(uap, fd), SCARG(uap, path),
                   3221:            SCARG(uap, buf), SCARG(uap, bufsize), retval);
1.433     manu     3222: }
                   3223:
1.31      cgd      3224: /*
                   3225:  * Change flags of a file given a path name.
                   3226:  */
                   3227: /* ARGSUSED */
1.63      christos 3228: int
1.335     dsl      3229: sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval)
1.56      thorpej  3230: {
1.335     dsl      3231:        /* {
1.74      cgd      3232:                syscallarg(const char *) path;
                   3233:                syscallarg(u_long) flags;
1.335     dsl      3234:        } */
1.155     augustss 3235:        struct vnode *vp;
1.31      cgd      3236:        int error;
                   3237:
1.395     dholland 3238:        error = namei_simple_user(SCARG(uap, path),
                   3239:                                NSM_FOLLOW_TRYEMULROOT, &vp);
                   3240:        if (error != 0)
1.31      cgd      3241:                return (error);
1.234     christos 3242:        error = change_flags(vp, SCARG(uap, flags), l);
1.31      cgd      3243:        vput(vp);
                   3244:        return (error);
                   3245: }
                   3246:
                   3247: /*
                   3248:  * Change flags of a file given a file descriptor.
                   3249:  */
                   3250: /* ARGSUSED */
1.63      christos 3251: int
1.335     dsl      3252: sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval)
1.56      thorpej  3253: {
1.335     dsl      3254:        /* {
1.35      cgd      3255:                syscallarg(int) fd;
1.74      cgd      3256:                syscallarg(u_long) flags;
1.335     dsl      3257:        } */
1.31      cgd      3258:        struct vnode *vp;
1.346     ad       3259:        file_t *fp;
1.31      cgd      3260:        int error;
                   3261:
1.346     ad       3262:        /* fd_getvnode() will use the descriptor for us */
                   3263:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3264:                return (error);
1.346     ad       3265:        vp = fp->f_data;
1.234     christos 3266:        error = change_flags(vp, SCARG(uap, flags), l);
1.406     hannken  3267:        VOP_UNLOCK(vp);
1.346     ad       3268:        fd_putfile(SCARG(uap, fd));
1.156     mrg      3269:        return (error);
                   3270: }
                   3271:
                   3272: /*
1.163     enami    3273:  * Change flags of a file given a path name; this version does
1.156     mrg      3274:  * not follow links.
                   3275:  */
                   3276: int
1.335     dsl      3277: sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval)
1.156     mrg      3278: {
1.335     dsl      3279:        /* {
1.156     mrg      3280:                syscallarg(const char *) path;
                   3281:                syscallarg(u_long) flags;
1.335     dsl      3282:        } */
1.163     enami    3283:        struct vnode *vp;
1.156     mrg      3284:        int error;
                   3285:
1.395     dholland 3286:        error = namei_simple_user(SCARG(uap, path),
                   3287:                                NSM_NOFOLLOW_TRYEMULROOT, &vp);
                   3288:        if (error != 0)
1.156     mrg      3289:                return (error);
1.234     christos 3290:        error = change_flags(vp, SCARG(uap, flags), l);
1.163     enami    3291:        vput(vp);
                   3292:        return (error);
                   3293: }
                   3294:
                   3295: /*
                   3296:  * Common routine to change flags of a file.
                   3297:  */
                   3298: int
1.234     christos 3299: change_flags(struct vnode *vp, u_long flags, struct lwp *l)
1.163     enami    3300: {
                   3301:        struct vattr vattr;
                   3302:        int error;
                   3303:
1.156     mrg      3304:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.450     elad     3305:
1.402     pooka    3306:        vattr_null(&vattr);
1.163     enami    3307:        vattr.va_flags = flags;
1.332     pooka    3308:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.450     elad     3309:
1.31      cgd      3310:        return (error);
                   3311: }
                   3312:
                   3313: /*
1.98      enami    3314:  * Change mode of a file given path name; this version follows links.
1.31      cgd      3315:  */
                   3316: /* ARGSUSED */
1.63      christos 3317: int
1.335     dsl      3318: sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval)
1.56      thorpej  3319: {
1.335     dsl      3320:        /* {
1.74      cgd      3321:                syscallarg(const char *) path;
1.35      cgd      3322:                syscallarg(int) mode;
1.335     dsl      3323:        } */
1.460     manu     3324:        return do_sys_chmodat(l, AT_FDCWD, SCARG(uap, path),
                   3325:                              SCARG(uap, mode), 0);
                   3326: }
                   3327:
1.469     chs      3328: int
1.460     manu     3329: do_sys_chmodat(struct lwp *l, int fdat, const char *path, int mode, int flags)
                   3330: {
1.31      cgd      3331:        int error;
1.395     dholland 3332:        struct vnode *vp;
1.460     manu     3333:        namei_simple_flags_t ns_flag;
                   3334:
                   3335:        if (flags & AT_SYMLINK_NOFOLLOW)
                   3336:                ns_flag = NSM_NOFOLLOW_TRYEMULROOT;
                   3337:        else
                   3338:                ns_flag = NSM_FOLLOW_TRYEMULROOT;
1.31      cgd      3339:
1.460     manu     3340:        error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp);
1.395     dholland 3341:        if (error != 0)
1.460     manu     3342:                return error;
1.97      enami    3343:
1.460     manu     3344:        error = change_mode(vp, mode, l);
1.97      enami    3345:
1.395     dholland 3346:        vrele(vp);
1.460     manu     3347:
1.31      cgd      3348:        return (error);
                   3349: }
                   3350:
                   3351: /*
                   3352:  * Change mode of a file given a file descriptor.
                   3353:  */
                   3354: /* ARGSUSED */
1.63      christos 3355: int
1.335     dsl      3356: sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval)
1.56      thorpej  3357: {
1.335     dsl      3358:        /* {
1.35      cgd      3359:                syscallarg(int) fd;
                   3360:                syscallarg(int) mode;
1.335     dsl      3361:        } */
1.346     ad       3362:        file_t *fp;
1.31      cgd      3363:        int error;
                   3364:
1.346     ad       3365:        /* fd_getvnode() will use the descriptor for us */
                   3366:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3367:                return (error);
1.346     ad       3368:        error = change_mode(fp->f_data, SCARG(uap, mode), l);
                   3369:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  3370:        return (error);
1.97      enami    3371: }
                   3372:
1.433     manu     3373: int
                   3374: sys_fchmodat(struct lwp *l, const struct sys_fchmodat_args *uap,
                   3375:     register_t *retval)
                   3376: {
                   3377:        /* {
                   3378:                syscallarg(int) fd;
                   3379:                syscallarg(const char *) path;
                   3380:                syscallarg(int) mode;
                   3381:                syscallarg(int) flag;
                   3382:        } */
                   3383:
1.460     manu     3384:        return do_sys_chmodat(l, SCARG(uap, fd), SCARG(uap, path),
                   3385:                              SCARG(uap, mode), SCARG(uap, flag));
1.433     manu     3386: }
                   3387:
1.97      enami    3388: /*
1.98      enami    3389:  * Change mode of a file given path name; this version does not follow links.
                   3390:  */
                   3391: /* ARGSUSED */
                   3392: int
1.335     dsl      3393: sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval)
1.98      enami    3394: {
1.335     dsl      3395:        /* {
1.98      enami    3396:                syscallarg(const char *) path;
                   3397:                syscallarg(int) mode;
1.335     dsl      3398:        } */
1.98      enami    3399:        int error;
1.395     dholland 3400:        struct vnode *vp;
1.98      enami    3401:
1.395     dholland 3402:        error = namei_simple_user(SCARG(uap, path),
                   3403:                                NSM_NOFOLLOW_TRYEMULROOT, &vp);
                   3404:        if (error != 0)
1.98      enami    3405:                return (error);
                   3406:
1.395     dholland 3407:        error = change_mode(vp, SCARG(uap, mode), l);
1.98      enami    3408:
1.395     dholland 3409:        vrele(vp);
1.98      enami    3410:        return (error);
                   3411: }
                   3412:
                   3413: /*
1.97      enami    3414:  * Common routine to set mode given a vnode.
                   3415:  */
                   3416: static int
1.234     christos 3417: change_mode(struct vnode *vp, int mode, struct lwp *l)
1.97      enami    3418: {
                   3419:        struct vattr vattr;
                   3420:        int error;
                   3421:
1.113     fvdl     3422:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.402     pooka    3423:        vattr_null(&vattr);
1.113     fvdl     3424:        vattr.va_mode = mode & ALLPERMS;
1.332     pooka    3425:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.406     hannken  3426:        VOP_UNLOCK(vp);
1.31      cgd      3427:        return (error);
                   3428: }
                   3429:
                   3430: /*
1.98      enami    3431:  * Set ownership given a path name; this version follows links.
1.31      cgd      3432:  */
                   3433: /* ARGSUSED */
1.63      christos 3434: int
1.335     dsl      3435: sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval)
1.56      thorpej  3436: {
1.335     dsl      3437:        /* {
1.74      cgd      3438:                syscallarg(const char *) path;
                   3439:                syscallarg(uid_t) uid;
                   3440:                syscallarg(gid_t) gid;
1.335     dsl      3441:        } */
1.460     manu     3442:        return do_sys_chownat(l, AT_FDCWD, SCARG(uap, path), SCARG(uap,uid),
                   3443:                              SCARG(uap, gid), 0);
                   3444: }
                   3445:
1.469     chs      3446: int
1.460     manu     3447: do_sys_chownat(struct lwp *l, int fdat, const char *path, uid_t uid,
                   3448:    gid_t gid, int flags)
                   3449: {
1.31      cgd      3450:        int error;
1.395     dholland 3451:        struct vnode *vp;
1.460     manu     3452:        namei_simple_flags_t ns_flag;
                   3453:
                   3454:        if (flags & AT_SYMLINK_NOFOLLOW)
                   3455:                ns_flag = NSM_NOFOLLOW_TRYEMULROOT;
                   3456:        else
                   3457:                ns_flag = NSM_FOLLOW_TRYEMULROOT;
1.31      cgd      3458:
1.460     manu     3459:        error = fd_nameiat_simple_user(l, fdat, path, ns_flag, &vp);
1.395     dholland 3460:        if (error != 0)
1.460     manu     3461:                return error;
1.86      kleink   3462:
1.460     manu     3463:        error = change_owner(vp, uid, gid, l, 0);
1.112     kleink   3464:
1.395     dholland 3465:        vrele(vp);
1.460     manu     3466:
1.112     kleink   3467:        return (error);
                   3468: }
                   3469:
                   3470: /*
                   3471:  * Set ownership given a path name; this version follows links.
                   3472:  * Provides POSIX semantics.
                   3473:  */
                   3474: /* ARGSUSED */
                   3475: int
1.335     dsl      3476: sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval)
1.112     kleink   3477: {
1.335     dsl      3478:        /* {
1.112     kleink   3479:                syscallarg(const char *) path;
                   3480:                syscallarg(uid_t) uid;
                   3481:                syscallarg(gid_t) gid;
1.335     dsl      3482:        } */
1.112     kleink   3483:        int error;
1.395     dholland 3484:        struct vnode *vp;
1.112     kleink   3485:
1.395     dholland 3486:        error = namei_simple_user(SCARG(uap, path),
                   3487:                                NSM_FOLLOW_TRYEMULROOT, &vp);
                   3488:        if (error != 0)
1.112     kleink   3489:                return (error);
                   3490:
1.395     dholland 3491:        error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.86      kleink   3492:
1.395     dholland 3493:        vrele(vp);
1.31      cgd      3494:        return (error);
                   3495: }
                   3496:
                   3497: /*
                   3498:  * Set ownership given a file descriptor.
                   3499:  */
                   3500: /* ARGSUSED */
1.63      christos 3501: int
1.335     dsl      3502: sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval)
1.56      thorpej  3503: {
1.335     dsl      3504:        /* {
1.35      cgd      3505:                syscallarg(int) fd;
1.74      cgd      3506:                syscallarg(uid_t) uid;
                   3507:                syscallarg(gid_t) gid;
1.335     dsl      3508:        } */
1.71      mycroft  3509:        int error;
1.346     ad       3510:        file_t *fp;
1.31      cgd      3511:
1.346     ad       3512:        /* fd_getvnode() will use the descriptor for us */
                   3513:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3514:                return (error);
1.346     ad       3515:        error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
                   3516:            l, 0);
                   3517:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  3518:        return (error);
1.112     kleink   3519: }
                   3520:
1.433     manu     3521: int
                   3522: sys_fchownat(struct lwp *l, const struct sys_fchownat_args *uap,
                   3523:     register_t *retval)
                   3524: {
                   3525:        /* {
                   3526:                syscallarg(int) fd;
                   3527:                syscallarg(const char *) path;
1.460     manu     3528:                syscallarg(uid_t) owner;
                   3529:                syscallarg(gid_t) group;
1.433     manu     3530:                syscallarg(int) flag;
                   3531:        } */
                   3532:
1.460     manu     3533:        return do_sys_chownat(l, SCARG(uap, fd), SCARG(uap, path),
                   3534:                              SCARG(uap, owner), SCARG(uap, group),
                   3535:                              SCARG(uap, flag));
1.433     manu     3536: }
                   3537:
1.112     kleink   3538: /*
                   3539:  * Set ownership given a file descriptor, providing POSIX/XPG semantics.
                   3540:  */
                   3541: /* ARGSUSED */
                   3542: int
1.335     dsl      3543: sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval)
1.112     kleink   3544: {
1.335     dsl      3545:        /* {
1.112     kleink   3546:                syscallarg(int) fd;
                   3547:                syscallarg(uid_t) uid;
                   3548:                syscallarg(gid_t) gid;
1.335     dsl      3549:        } */
1.112     kleink   3550:        int error;
1.346     ad       3551:        file_t *fp;
1.112     kleink   3552:
1.346     ad       3553:        /* fd_getvnode() will use the descriptor for us */
                   3554:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.112     kleink   3555:                return (error);
1.346     ad       3556:        error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
                   3557:            l, 1);
                   3558:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  3559:        return (error);
1.86      kleink   3560: }
                   3561:
                   3562: /*
1.98      enami    3563:  * Set ownership given a path name; this version does not follow links.
                   3564:  */
                   3565: /* ARGSUSED */
                   3566: int
1.335     dsl      3567: sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval)
1.98      enami    3568: {
1.335     dsl      3569:        /* {
1.98      enami    3570:                syscallarg(const char *) path;
                   3571:                syscallarg(uid_t) uid;
                   3572:                syscallarg(gid_t) gid;
1.335     dsl      3573:        } */
1.98      enami    3574:        int error;
1.395     dholland 3575:        struct vnode *vp;
1.98      enami    3576:
1.395     dholland 3577:        error = namei_simple_user(SCARG(uap, path),
                   3578:                                NSM_NOFOLLOW_TRYEMULROOT, &vp);
                   3579:        if (error != 0)
1.98      enami    3580:                return (error);
                   3581:
1.395     dholland 3582:        error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
1.112     kleink   3583:
1.395     dholland 3584:        vrele(vp);
1.112     kleink   3585:        return (error);
                   3586: }
                   3587:
                   3588: /*
                   3589:  * Set ownership given a path name; this version does not follow links.
                   3590:  * Provides POSIX/XPG semantics.
                   3591:  */
                   3592: /* ARGSUSED */
                   3593: int
1.335     dsl      3594: sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval)
1.112     kleink   3595: {
1.335     dsl      3596:        /* {
1.112     kleink   3597:                syscallarg(const char *) path;
                   3598:                syscallarg(uid_t) uid;
                   3599:                syscallarg(gid_t) gid;
1.335     dsl      3600:        } */
1.112     kleink   3601:        int error;
1.395     dholland 3602:        struct vnode *vp;
1.112     kleink   3603:
1.395     dholland 3604:        error = namei_simple_user(SCARG(uap, path),
                   3605:                                NSM_NOFOLLOW_TRYEMULROOT, &vp);
                   3606:        if (error != 0)
1.112     kleink   3607:                return (error);
                   3608:
1.395     dholland 3609:        error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
1.98      enami    3610:
1.395     dholland 3611:        vrele(vp);
1.98      enami    3612:        return (error);
                   3613: }
                   3614:
                   3615: /*
1.205     junyoung 3616:  * Common routine to set ownership given a vnode.
1.86      kleink   3617:  */
                   3618: static int
1.234     christos 3619: change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l,
1.221     thorpej  3620:     int posix_semantics)
1.86      kleink   3621: {
                   3622:        struct vattr vattr;
1.112     kleink   3623:        mode_t newmode;
1.86      kleink   3624:        int error;
                   3625:
1.113     fvdl     3626:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    3627:        if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
1.86      kleink   3628:                goto out;
                   3629:
1.175     thorpej  3630: #define CHANGED(x) ((int)(x) != -1)
1.112     kleink   3631:        newmode = vattr.va_mode;
                   3632:        if (posix_semantics) {
                   3633:                /*
1.114     kleink   3634:                 * POSIX/XPG semantics: if the caller is not the super-user,
                   3635:                 * clear set-user-id and set-group-id bits.  Both POSIX and
                   3636:                 * the XPG consider the behaviour for calls by the super-user
                   3637:                 * implementation-defined; we leave the set-user-id and set-
                   3638:                 * group-id settings intact in that case.
1.112     kleink   3639:                 */
1.450     elad     3640:                if (vattr.va_mode & S_ISUID) {
1.451     christos 3641:                        if (kauth_authorize_vnode(l->l_cred,
                   3642:                            KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
1.450     elad     3643:                                newmode &= ~S_ISUID;
                   3644:                }
                   3645:                if (vattr.va_mode & S_ISGID) {
1.451     christos 3646:                        if (kauth_authorize_vnode(l->l_cred,
                   3647:                            KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
1.450     elad     3648:                                newmode &= ~S_ISGID;
                   3649:                }
1.112     kleink   3650:        } else {
                   3651:                /*
                   3652:                 * NetBSD semantics: when changing owner and/or group,
                   3653:                 * clear the respective bit(s).
                   3654:                 */
                   3655:                if (CHANGED(uid))
                   3656:                        newmode &= ~S_ISUID;
                   3657:                if (CHANGED(gid))
                   3658:                        newmode &= ~S_ISGID;
                   3659:        }
                   3660:        /* Update va_mode iff altered. */
                   3661:        if (vattr.va_mode == newmode)
                   3662:                newmode = VNOVAL;
1.205     junyoung 3663:
1.402     pooka    3664:        vattr_null(&vattr);
1.175     thorpej  3665:        vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
                   3666:        vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
1.86      kleink   3667:        vattr.va_mode = newmode;
1.332     pooka    3668:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.112     kleink   3669: #undef CHANGED
1.205     junyoung 3670:
1.86      kleink   3671: out:
1.406     hannken  3672:        VOP_UNLOCK(vp);
1.31      cgd      3673:        return (error);
                   3674: }
                   3675:
                   3676: /*
1.98      enami    3677:  * Set the access and modification times given a path name; this
                   3678:  * version follows links.
1.31      cgd      3679:  */
                   3680: /* ARGSUSED */
1.63      christos 3681: int
1.383     christos 3682: sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap,
                   3683:     register_t *retval)
1.56      thorpej  3684: {
1.335     dsl      3685:        /* {
1.74      cgd      3686:                syscallarg(const char *) path;
                   3687:                syscallarg(const struct timeval *) tptr;
1.335     dsl      3688:        } */
1.31      cgd      3689:
1.312     dsl      3690:        return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW,
1.346     ad       3691:            SCARG(uap, tptr), UIO_USERSPACE);
1.71      mycroft  3692: }
                   3693:
                   3694: /*
                   3695:  * Set the access and modification times given a file descriptor.
                   3696:  */
                   3697: /* ARGSUSED */
                   3698: int
1.383     christos 3699: sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap,
                   3700:     register_t *retval)
1.71      mycroft  3701: {
1.335     dsl      3702:        /* {
1.71      mycroft  3703:                syscallarg(int) fd;
1.74      cgd      3704:                syscallarg(const struct timeval *) tptr;
1.335     dsl      3705:        } */
1.71      mycroft  3706:        int error;
1.346     ad       3707:        file_t *fp;
1.71      mycroft  3708:
1.346     ad       3709:        /* fd_getvnode() will use the descriptor for us */
                   3710:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.96      enami    3711:                return (error);
1.346     ad       3712:        error = do_sys_utimes(l, fp->f_data, NULL, 0, SCARG(uap, tptr),
                   3713:            UIO_USERSPACE);
                   3714:        fd_putfile(SCARG(uap, fd));
1.135     thorpej  3715:        return (error);
1.98      enami    3716: }
                   3717:
1.434     manu     3718: int
                   3719: sys_futimens(struct lwp *l, const struct sys_futimens_args *uap,
                   3720:     register_t *retval)
                   3721: {
                   3722:        /* {
                   3723:                syscallarg(int) fd;
                   3724:                syscallarg(const struct timespec *) tptr;
                   3725:        } */
                   3726:        int error;
                   3727:        file_t *fp;
                   3728:
                   3729:        /* fd_getvnode() will use the descriptor for us */
                   3730:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
                   3731:                return (error);
1.460     manu     3732:        error = do_sys_utimensat(l, AT_FDCWD, fp->f_data, NULL, 0,
                   3733:            SCARG(uap, tptr), UIO_USERSPACE);
1.434     manu     3734:        fd_putfile(SCARG(uap, fd));
                   3735:        return (error);
                   3736: }
                   3737:
1.98      enami    3738: /*
                   3739:  * Set the access and modification times given a path name; this
                   3740:  * version does not follow links.
                   3741:  */
                   3742: int
1.383     christos 3743: sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap,
                   3744:     register_t *retval)
1.98      enami    3745: {
1.335     dsl      3746:        /* {
1.98      enami    3747:                syscallarg(const char *) path;
                   3748:                syscallarg(const struct timeval *) tptr;
1.335     dsl      3749:        } */
1.98      enami    3750:
1.312     dsl      3751:        return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW,
1.346     ad       3752:            SCARG(uap, tptr), UIO_USERSPACE);
1.97      enami    3753: }
                   3754:
1.433     manu     3755: int
                   3756: sys_utimensat(struct lwp *l, const struct sys_utimensat_args *uap,
                   3757:     register_t *retval)
                   3758: {
                   3759:        /* {
                   3760:                syscallarg(int) fd;
                   3761:                syscallarg(const char *) path;
                   3762:                syscallarg(const struct timespec *) tptr;
                   3763:                syscallarg(int) flag;
                   3764:        } */
1.434     manu     3765:        int follow;
                   3766:        const struct timespec *tptr;
1.460     manu     3767:        int error;
1.434     manu     3768:
                   3769:        tptr = SCARG(uap, tptr);
                   3770:        follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
                   3771:
1.460     manu     3772:        error = do_sys_utimensat(l, SCARG(uap, fd), NULL,
                   3773:            SCARG(uap, path), follow, tptr, UIO_USERSPACE);
                   3774:
                   3775:        return error;
1.433     manu     3776: }
                   3777:
1.97      enami    3778: /*
                   3779:  * Common routine to set access and modification times given a vnode.
                   3780:  */
1.312     dsl      3781: int
1.434     manu     3782: do_sys_utimens(struct lwp *l, struct vnode *vp, const char *path, int flag,
                   3783:     const struct timespec *tptr, enum uio_seg seg)
1.97      enami    3784: {
1.460     manu     3785:        return do_sys_utimensat(l, AT_FDCWD, vp, path, flag, tptr, seg);
                   3786: }
                   3787:
1.466     matt     3788: int
1.460     manu     3789: do_sys_utimensat(struct lwp *l, int fdat, struct vnode *vp,
                   3790:     const char *path, int flag, const struct timespec *tptr, enum uio_seg seg)
                   3791: {
1.97      enami    3792:        struct vattr vattr;
1.395     dholland 3793:        int error, dorele = 0;
                   3794:        namei_simple_flags_t sflags;
1.367     christos 3795:        bool vanull, setbirthtime;
                   3796:        struct timespec ts[2];
1.97      enami    3797:
1.460     manu     3798:        KASSERT(l != NULL || fdat == AT_FDCWD);
                   3799:
1.395     dholland 3800:        /*
                   3801:         * I have checked all callers and they pass either FOLLOW,
                   3802:         * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW
                   3803:         * is 0. More to the point, they don't pass anything else.
                   3804:         * Let's keep it that way at least until the namei interfaces
                   3805:         * are fully sanitized.
                   3806:         */
                   3807:        KASSERT(flag == NOFOLLOW || flag == FOLLOW);
                   3808:        sflags = (flag == FOLLOW) ?
                   3809:                NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT;
                   3810:
1.97      enami    3811:        if (tptr == NULL) {
1.367     christos 3812:                vanull = true;
                   3813:                nanotime(&ts[0]);
                   3814:                ts[1] = ts[0];
1.71      mycroft  3815:        } else {
1.367     christos 3816:                vanull = false;
1.312     dsl      3817:                if (seg != UIO_SYSSPACE) {
1.434     manu     3818:                        error = copyin(tptr, ts, sizeof (ts));
1.312     dsl      3819:                        if (error != 0)
                   3820:                                return error;
1.437     manu     3821:                } else {
                   3822:                        ts[0] = tptr[0];
                   3823:                        ts[1] = tptr[1];
1.312     dsl      3824:                }
1.71      mycroft  3825:        }
1.312     dsl      3826:
1.438     enami    3827:        if (ts[0].tv_nsec == UTIME_NOW) {
1.434     manu     3828:                nanotime(&ts[0]);
1.438     enami    3829:                if (ts[1].tv_nsec == UTIME_NOW) {
                   3830:                        vanull = true;
                   3831:                        ts[1] = ts[0];
                   3832:                }
                   3833:        } else if (ts[1].tv_nsec == UTIME_NOW)
1.434     manu     3834:                nanotime(&ts[1]);
                   3835:
1.312     dsl      3836:        if (vp == NULL) {
1.395     dholland 3837:                /* note: SEG describes TPTR, not PATH; PATH is always user */
1.460     manu     3838:                error = fd_nameiat_simple_user(l, fdat, path, sflags, &vp);
1.395     dholland 3839:                if (error != 0)
1.367     christos 3840:                        return error;
1.395     dholland 3841:                dorele = 1;
                   3842:        }
1.312     dsl      3843:
1.113     fvdl     3844:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.367     christos 3845:        setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 &&
                   3846:            timespeccmp(&ts[1], &vattr.va_birthtime, <));
1.402     pooka    3847:        vattr_null(&vattr);
1.434     manu     3848:
                   3849:        if (ts[0].tv_nsec != UTIME_OMIT)
                   3850:                vattr.va_atime = ts[0];
                   3851:
                   3852:        if (ts[1].tv_nsec != UTIME_OMIT) {
                   3853:                vattr.va_mtime = ts[1];
                   3854:                if (setbirthtime)
                   3855:                        vattr.va_birthtime = ts[1];
                   3856:        }
                   3857:
1.367     christos 3858:        if (vanull)
1.392     yamt     3859:                vattr.va_vaflags |= VA_UTIMES_NULL;
1.332     pooka    3860:        error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.406     hannken  3861:        VOP_UNLOCK(vp);
1.312     dsl      3862:
1.395     dholland 3863:        if (dorele != 0)
                   3864:                vrele(vp);
1.312     dsl      3865:
1.367     christos 3866:        return error;
1.31      cgd      3867: }
                   3868:
1.434     manu     3869: int
                   3870: do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag,
                   3871:     const struct timeval *tptr, enum uio_seg seg)
                   3872: {
                   3873:        struct timespec ts[2];
                   3874:        struct timespec *tsptr = NULL;
                   3875:        int error;
                   3876:
                   3877:        if (tptr != NULL) {
                   3878:                struct timeval tv[2];
                   3879:
                   3880:                if (seg != UIO_SYSSPACE) {
                   3881:                        error = copyin(tptr, tv, sizeof (tv));
                   3882:                        if (error != 0)
                   3883:                                return error;
                   3884:                        tptr = tv;
                   3885:                }
                   3886:
                   3887:                if ((tv[0].tv_usec == UTIME_NOW) ||
                   3888:                    (tv[0].tv_usec == UTIME_OMIT))
                   3889:                        ts[0].tv_nsec = tv[0].tv_usec;
                   3890:                else
                   3891:                        TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]);
                   3892:
                   3893:                if ((tv[1].tv_usec == UTIME_NOW) ||
                   3894:                    (tv[1].tv_usec == UTIME_OMIT))
                   3895:                        ts[1].tv_nsec = tv[1].tv_usec;
                   3896:                else
                   3897:                        TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]);
                   3898:
                   3899:                tsptr = &ts[0];
                   3900:        }
                   3901:
                   3902:        return do_sys_utimens(l, vp, path, flag, tsptr, UIO_SYSSPACE);
                   3903: }
                   3904:
1.31      cgd      3905: /*
                   3906:  * Truncate a file given its path name.
                   3907:  */
                   3908: /* ARGSUSED */
1.63      christos 3909: int
1.335     dsl      3910: sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval)
1.56      thorpej  3911: {
1.335     dsl      3912:        /* {
1.74      cgd      3913:                syscallarg(const char *) path;
1.35      cgd      3914:                syscallarg(int) pad;
                   3915:                syscallarg(off_t) length;
1.335     dsl      3916:        } */
1.155     augustss 3917:        struct vnode *vp;
1.31      cgd      3918:        struct vattr vattr;
                   3919:        int error;
                   3920:
1.484     njoly    3921:        if (SCARG(uap, length) < 0)
                   3922:                return EINVAL;
                   3923:
1.395     dholland 3924:        error = namei_simple_user(SCARG(uap, path),
                   3925:                                NSM_FOLLOW_TRYEMULROOT, &vp);
                   3926:        if (error != 0)
1.31      cgd      3927:                return (error);
1.113     fvdl     3928:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      3929:        if (vp->v_type == VDIR)
                   3930:                error = EISDIR;
                   3931:        else if ((error = vn_writechk(vp)) == 0 &&
1.332     pooka    3932:            (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {
1.402     pooka    3933:                vattr_null(&vattr);
1.35      cgd      3934:                vattr.va_size = SCARG(uap, length);
1.332     pooka    3935:                error = VOP_SETATTR(vp, &vattr, l->l_cred);
1.31      cgd      3936:        }
                   3937:        vput(vp);
                   3938:        return (error);
                   3939: }
                   3940:
                   3941: /*
                   3942:  * Truncate a file given a file descriptor.
                   3943:  */
                   3944: /* ARGSUSED */
1.63      christos 3945: int
1.335     dsl      3946: sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval)
1.56      thorpej  3947: {
1.335     dsl      3948:        /* {
1.35      cgd      3949:                syscallarg(int) fd;
                   3950:                syscallarg(int) pad;
                   3951:                syscallarg(off_t) length;
1.335     dsl      3952:        } */
1.31      cgd      3953:        struct vattr vattr;
                   3954:        struct vnode *vp;
1.346     ad       3955:        file_t *fp;
1.31      cgd      3956:        int error;
                   3957:
1.484     njoly    3958:        if (SCARG(uap, length) < 0)
                   3959:                return EINVAL;
                   3960:
1.346     ad       3961:        /* fd_getvnode() will use the descriptor for us */
                   3962:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3963:                return (error);
1.135     thorpej  3964:        if ((fp->f_flag & FWRITE) == 0) {
                   3965:                error = EINVAL;
                   3966:                goto out;
                   3967:        }
1.346     ad       3968:        vp = fp->f_data;
1.113     fvdl     3969:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.31      cgd      3970:        if (vp->v_type == VDIR)
                   3971:                error = EISDIR;
                   3972:        else if ((error = vn_writechk(vp)) == 0) {
1.402     pooka    3973:                vattr_null(&vattr);
1.35      cgd      3974:                vattr.va_size = SCARG(uap, length);
1.332     pooka    3975:                error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1.31      cgd      3976:        }
1.406     hannken  3977:        VOP_UNLOCK(vp);
1.135     thorpej  3978:  out:
1.346     ad       3979:        fd_putfile(SCARG(uap, fd));
1.31      cgd      3980:        return (error);
                   3981: }
                   3982:
                   3983: /*
                   3984:  * Sync an open file.
                   3985:  */
                   3986: /* ARGSUSED */
1.63      christos 3987: int
1.335     dsl      3988: sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval)
1.56      thorpej  3989: {
1.335     dsl      3990:        /* {
1.35      cgd      3991:                syscallarg(int) fd;
1.335     dsl      3992:        } */
1.155     augustss 3993:        struct vnode *vp;
1.346     ad       3994:        file_t *fp;
1.31      cgd      3995:        int error;
                   3996:
1.346     ad       3997:        /* fd_getvnode() will use the descriptor for us */
                   3998:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      3999:                return (error);
1.346     ad       4000:        vp = fp->f_data;
1.113     fvdl     4001:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    4002:        error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);
1.406     hannken  4003:        VOP_UNLOCK(vp);
1.346     ad       4004:        fd_putfile(SCARG(uap, fd));
1.201     thorpej  4005:        return (error);
                   4006: }
                   4007:
                   4008: /*
                   4009:  * Sync a range of file data.  API modeled after that found in AIX.
                   4010:  *
                   4011:  * FDATASYNC indicates that we need only save enough metadata to be able
                   4012:  * to re-read the written data.  Note we duplicate AIX's requirement that
                   4013:  * the file be open for writing.
                   4014:  */
                   4015: /* ARGSUSED */
                   4016: int
1.335     dsl      4017: sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval)
1.201     thorpej  4018: {
1.335     dsl      4019:        /* {
1.201     thorpej  4020:                syscallarg(int) fd;
                   4021:                syscallarg(int) flags;
                   4022:                syscallarg(off_t) start;
1.225     cube     4023:                syscallarg(off_t) length;
1.335     dsl      4024:        } */
1.201     thorpej  4025:        struct vnode *vp;
1.346     ad       4026:        file_t *fp;
1.201     thorpej  4027:        int flags, nflags;
                   4028:        off_t s, e, len;
                   4029:        int error;
                   4030:
1.346     ad       4031:        /* fd_getvnode() will use the descriptor for us */
                   4032:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.201     thorpej  4033:                return (error);
                   4034:
                   4035:        if ((fp->f_flag & FWRITE) == 0) {
1.293     wrstuden 4036:                error = EBADF;
                   4037:                goto out;
1.201     thorpej  4038:        }
                   4039:
                   4040:        flags = SCARG(uap, flags);
                   4041:        if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
                   4042:            ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
1.293     wrstuden 4043:                error = EINVAL;
                   4044:                goto out;
1.201     thorpej  4045:        }
                   4046:        /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
                   4047:        if (flags & FDATASYNC)
                   4048:                nflags = FSYNC_DATAONLY | FSYNC_WAIT;
                   4049:        else
                   4050:                nflags = FSYNC_WAIT;
1.216     wrstuden 4051:        if (flags & FDISKSYNC)
                   4052:                nflags |= FSYNC_CACHE;
1.201     thorpej  4053:
                   4054:        len = SCARG(uap, length);
1.424     dsl      4055:        /* If length == 0, we do the whole file, and s = e = 0 will do that */
1.201     thorpej  4056:        if (len) {
                   4057:                s = SCARG(uap, start);
                   4058:                e = s + len;
                   4059:                if (e < s) {
1.293     wrstuden 4060:                        error = EINVAL;
                   4061:                        goto out;
1.201     thorpej  4062:                }
                   4063:        } else {
                   4064:                e = 0;
                   4065:                s = 0;
                   4066:        }
                   4067:
1.346     ad       4068:        vp = fp->f_data;
1.201     thorpej  4069:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    4070:        error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);
1.406     hannken  4071:        VOP_UNLOCK(vp);
1.293     wrstuden 4072: out:
1.346     ad       4073:        fd_putfile(SCARG(uap, fd));
1.31      cgd      4074:        return (error);
                   4075: }
                   4076:
                   4077: /*
1.117     kleink   4078:  * Sync the data of an open file.
                   4079:  */
                   4080: /* ARGSUSED */
                   4081: int
1.335     dsl      4082: sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval)
1.117     kleink   4083: {
1.335     dsl      4084:        /* {
1.117     kleink   4085:                syscallarg(int) fd;
1.335     dsl      4086:        } */
1.117     kleink   4087:        struct vnode *vp;
1.346     ad       4088:        file_t *fp;
1.117     kleink   4089:        int error;
                   4090:
1.346     ad       4091:        /* fd_getvnode() will use the descriptor for us */
                   4092:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.117     kleink   4093:                return (error);
1.199     kleink   4094:        if ((fp->f_flag & FWRITE) == 0) {
1.346     ad       4095:                fd_putfile(SCARG(uap, fd));
1.199     kleink   4096:                return (EBADF);
                   4097:        }
1.346     ad       4098:        vp = fp->f_data;
1.117     kleink   4099:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.332     pooka    4100:        error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);
1.406     hannken  4101:        VOP_UNLOCK(vp);
1.346     ad       4102:        fd_putfile(SCARG(uap, fd));
1.117     kleink   4103:        return (error);
                   4104: }
                   4105:
                   4106: /*
1.90      kleink   4107:  * Rename files, (standard) BSD semantics frontend.
1.31      cgd      4108:  */
                   4109: /* ARGSUSED */
1.63      christos 4110: int
1.335     dsl      4111: sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval)
1.56      thorpej  4112: {
1.335     dsl      4113:        /* {
1.74      cgd      4114:                syscallarg(const char *) from;
                   4115:                syscallarg(const char *) to;
1.335     dsl      4116:        } */
1.90      kleink   4117:
1.460     manu     4118:        return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
                   4119:            SCARG(uap, to), UIO_USERSPACE, 0));
1.90      kleink   4120: }
                   4121:
1.433     manu     4122: int
                   4123: sys_renameat(struct lwp *l, const struct sys_renameat_args *uap,
                   4124:     register_t *retval)
                   4125: {
                   4126:        /* {
                   4127:                syscallarg(int) fromfd;
                   4128:                syscallarg(const char *) from;
                   4129:                syscallarg(int) tofd;
                   4130:                syscallarg(const char *) to;
                   4131:        } */
                   4132:
1.460     manu     4133:        return (do_sys_renameat(l, SCARG(uap, fromfd), SCARG(uap, from),
                   4134:            SCARG(uap, tofd), SCARG(uap, to), UIO_USERSPACE, 0));
1.433     manu     4135: }
                   4136:
1.90      kleink   4137: /*
                   4138:  * Rename files, POSIX semantics frontend.
                   4139:  */
                   4140: /* ARGSUSED */
                   4141: int
1.335     dsl      4142: sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval)
1.90      kleink   4143: {
1.335     dsl      4144:        /* {
1.90      kleink   4145:                syscallarg(const char *) from;
                   4146:                syscallarg(const char *) to;
1.335     dsl      4147:        } */
1.90      kleink   4148:
1.460     manu     4149:        return (do_sys_renameat(l, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
                   4150:            SCARG(uap, to), UIO_USERSPACE, 1));
1.90      kleink   4151: }
                   4152:
                   4153: /*
                   4154:  * Rename files.  Source and destination must either both be directories,
                   4155:  * or both not be directories.  If target is a directory, it must be empty.
                   4156:  * If `from' and `to' refer to the same object, the value of the `retain'
                   4157:  * argument is used to determine whether `from' will be
                   4158:  *
                   4159:  * (retain == 0)       deleted unless `from' and `to' refer to the same
                   4160:  *                     object in the file system's name space (BSD).
                   4161:  * (retain == 1)       always retained (POSIX).
1.458     riastrad 4162:  *
                   4163:  * XXX Synchronize with nfsrv_rename in nfs_serv.c.
1.90      kleink   4164:  */
1.336     ad       4165: int
                   4166: do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain)
1.90      kleink   4167: {
1.460     manu     4168:        return do_sys_renameat(NULL, AT_FDCWD, from, AT_FDCWD, to, seg, retain);
                   4169: }
                   4170:
                   4171: static int
                   4172: do_sys_renameat(struct lwp *l, int fromfd, const char *from, int tofd,
                   4173:     const char *to, enum uio_seg seg, int retain)
                   4174: {
1.458     riastrad 4175:        struct pathbuf *fpb, *tpb;
                   4176:        struct nameidata fnd, tnd;
                   4177:        struct vnode *fdvp, *fvp;
                   4178:        struct vnode *tdvp, *tvp;
                   4179:        struct mount *mp, *tmp;
1.31      cgd      4180:        int error;
                   4181:
1.460     manu     4182:        KASSERT(l != NULL || (fromfd == AT_FDCWD && tofd == AT_FDCWD));
1.458     riastrad 4183:
                   4184:        error = pathbuf_maybe_copyin(from, seg, &fpb);
                   4185:        if (error)
                   4186:                goto out0;
                   4187:        KASSERT(fpb != NULL);
                   4188:
                   4189:        error = pathbuf_maybe_copyin(to, seg, &tpb);
                   4190:        if (error)
                   4191:                goto out1;
                   4192:        KASSERT(tpb != NULL);
                   4193:
                   4194:        /*
                   4195:         * Lookup from.
                   4196:         *
                   4197:         * XXX LOCKPARENT is wrong because we don't actually want it
                   4198:         * locked yet, but (a) namei is insane, and (b) VOP_RENAME is
                   4199:         * insane, so for the time being we need to leave it like this.
                   4200:         */
                   4201:        NDINIT(&fnd, DELETE, (LOCKPARENT | TRYEMULROOT | INRENAME), fpb);
1.460     manu     4202:        if ((error = fd_nameiat(l, fromfd, &fnd)) != 0)
1.458     riastrad 4203:                goto out2;
                   4204:
                   4205:        /*
                   4206:         * Pull out the important results of the lookup, fdvp and fvp.
                   4207:         * Of course, fvp is bogus because we're about to unlock fdvp.
                   4208:         */
                   4209:        fdvp = fnd.ni_dvp;
                   4210:        fvp = fnd.ni_vp;
                   4211:        KASSERT(fdvp != NULL);
                   4212:        KASSERT(fvp != NULL);
                   4213:        KASSERT((fdvp == fvp) || (VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE));
                   4214:
                   4215:        /*
                   4216:         * Make sure neither fdvp nor fvp is locked.
                   4217:         */
                   4218:        if (fdvp != fvp)
                   4219:                VOP_UNLOCK(fdvp);
                   4220:        /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
                   4221:        /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
                   4222:
                   4223:        /*
                   4224:         * Reject renaming `.' and `..'.  Can't do this until after
                   4225:         * namei because we need namei's parsing to find the final
                   4226:         * component name.  (namei should just leave us with the final
                   4227:         * component name and not look it up itself, but anyway...)
                   4228:         *
                   4229:         * This was here before because we used to relookup from
                   4230:         * instead of to and relookup requires the caller to check
                   4231:         * this, but now file systems may depend on this check, so we
                   4232:         * must retain it until the file systems are all rototilled.
                   4233:         */
                   4234:        if (((fnd.ni_cnd.cn_namelen == 1) &&
                   4235:                (fnd.ni_cnd.cn_nameptr[0] == '.')) ||
                   4236:            ((fnd.ni_cnd.cn_namelen == 2) &&
                   4237:                (fnd.ni_cnd.cn_nameptr[0] == '.') &&
                   4238:                (fnd.ni_cnd.cn_nameptr[1] == '.'))) {
                   4239:                error = EINVAL; /* XXX EISDIR?  */
                   4240:                goto abort0;
1.409     dholland 4241:        }
1.458     riastrad 4242:
                   4243:        /*
                   4244:         * Lookup to.
                   4245:         *
                   4246:         * XXX LOCKPARENT is wrong, but...insanity, &c.  Also, using
                   4247:         * fvp here to decide whether to add CREATEDIR is a load of
                   4248:         * bollocks because fvp might be the wrong node by now, since
                   4249:         * fdvp is unlocked.
                   4250:         *
                   4251:         * XXX Why not pass CREATEDIR always?
                   4252:         */
                   4253:        NDINIT(&tnd, RENAME,
                   4254:            (LOCKPARENT | NOCACHE | TRYEMULROOT | INRENAME |
                   4255:                ((fvp->v_type == VDIR)? CREATEDIR : 0)),
                   4256:            tpb);
1.460     manu     4257:        if ((error = fd_nameiat(l, tofd, &tnd)) != 0)
1.458     riastrad 4258:                goto abort0;
                   4259:
                   4260:        /*
                   4261:         * Pull out the important results of the lookup, tdvp and tvp.
                   4262:         * Of course, tvp is bogus because we're about to unlock tdvp.
                   4263:         */
                   4264:        tdvp = tnd.ni_dvp;
                   4265:        tvp = tnd.ni_vp;
                   4266:        KASSERT(tdvp != NULL);
                   4267:        KASSERT((tdvp == tvp) || (VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE));
                   4268:
                   4269:        /*
                   4270:         * Make sure neither tdvp nor tvp is locked.
                   4271:         */
                   4272:        if (tdvp != tvp)
                   4273:                VOP_UNLOCK(tdvp);
                   4274:        /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
                   4275:        /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */
                   4276:
                   4277:        /*
                   4278:         * Reject renaming onto `.' or `..'.  relookup is unhappy with
                   4279:         * these, which is why we must do this here.  Once upon a time
                   4280:         * we relooked up from instead of to, and consequently didn't
                   4281:         * need this check, but now that we relookup to instead of
                   4282:         * from, we need this; and we shall need it forever forward
                   4283:         * until the VOP_RENAME protocol changes, because file systems
                   4284:         * will no doubt begin to depend on this check.
                   4285:         */
                   4286:        if (((tnd.ni_cnd.cn_namelen == 1) &&
                   4287:                (tnd.ni_cnd.cn_nameptr[0] == '.')) ||
                   4288:            ((tnd.ni_cnd.cn_namelen == 2) &&
                   4289:                (tnd.ni_cnd.cn_nameptr[0] == '.') &&
                   4290:                (tnd.ni_cnd.cn_nameptr[1] == '.'))) {
                   4291:                error = EINVAL; /* XXX EISDIR?  */
                   4292:                goto abort1;
1.409     dholland 4293:        }
                   4294:
1.458     riastrad 4295:        /*
                   4296:         * Get the mount point.  If the file system has been unmounted,
                   4297:         * which it may be because we're not holding any vnode locks,
                   4298:         * then v_mount will be NULL.  We're not really supposed to
                   4299:         * read v_mount without holding the vnode lock, but since we
                   4300:         * have fdvp referenced, if fdvp->v_mount changes then at worst
                   4301:         * it will be set to NULL, not changed to another mount point.
                   4302:         * And, of course, since it is up to the file system to
                   4303:         * determine the real lock order, we can't lock both fdvp and
                   4304:         * tdvp at the same time.
                   4305:         */
                   4306:        mp = fdvp->v_mount;
                   4307:        if (mp == NULL) {
                   4308:                error = ENOENT;
                   4309:                goto abort1;
1.344     dholland 4310:        }
                   4311:
                   4312:        /*
1.458     riastrad 4313:         * Make sure the mount points match.  Again, although we don't
                   4314:         * hold any vnode locks, the v_mount fields may change -- but
                   4315:         * at worst they will change to NULL, so this will never become
                   4316:         * a cross-device rename, because we hold vnode references.
1.344     dholland 4317:         *
1.458     riastrad 4318:         * XXX Because nothing is locked and the compiler may reorder
                   4319:         * things here, unmounting the file system at an inopportune
                   4320:         * moment may cause rename to fail with ENXDEV when it really
                   4321:         * should fail with ENOENT.
1.344     dholland 4322:         */
1.458     riastrad 4323:        tmp = tdvp->v_mount;
                   4324:        if (tmp == NULL) {
                   4325:                error = ENOENT;
                   4326:                goto abort1;
1.348     dholland 4327:        }
1.458     riastrad 4328:
                   4329:        if (mp != tmp) {
                   4330:                error = EXDEV;
                   4331:                goto abort1;
1.344     dholland 4332:        }
1.458     riastrad 4333:
                   4334:        /*
                   4335:         * Take the vfs rename lock to avoid cross-directory screw cases.
                   4336:         * Nothing is locked currently, so taking this lock is safe.
                   4337:         */
1.459     riastrad 4338:        error = VFS_RENAMELOCK_ENTER(mp);
                   4339:        if (error)
                   4340:                goto abort1;
1.90      kleink   4341:
1.458     riastrad 4342:        /*
                   4343:         * Now fdvp, fvp, tdvp, and (if nonnull) tvp are referenced,
                   4344:         * and nothing is locked except for the vfs rename lock.
                   4345:         *
                   4346:         * The next step is a little rain dance to conform to the
                   4347:         * insane lock protocol, even though it does nothing to ward
                   4348:         * off race conditions.
                   4349:         *
                   4350:         * We need tdvp and tvp to be locked.  However, because we have
                   4351:         * unlocked tdvp in order to hold no locks while we take the
                   4352:         * vfs rename lock, tvp may be wrong here, and we can't safely
                   4353:         * lock it even if the sensible file systems will just unlock
                   4354:         * it straight away.  Consequently, we must lock tdvp and then
                   4355:         * relookup tvp to get it locked.
                   4356:         *
                   4357:         * Finally, because the VOP_RENAME protocol is brain-damaged
                   4358:         * and various file systems insanely depend on the semantics of
                   4359:         * this brain damage, the lookup of to must be the last lookup
                   4360:         * before VOP_RENAME.
                   4361:         */
                   4362:        vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
                   4363:        error = relookup(tdvp, &tnd.ni_vp, &tnd.ni_cnd, 0);
                   4364:        if (error)
                   4365:                goto abort2;
                   4366:
                   4367:        /*
                   4368:         * Drop the old tvp and pick up the new one -- which might be
                   4369:         * the same, but that doesn't matter to us.  After this, tdvp
                   4370:         * and tvp should both be locked.
                   4371:         */
                   4372:        if (tvp != NULL)
                   4373:                vrele(tvp);
                   4374:        tvp = tnd.ni_vp;
                   4375:        KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
                   4376:        KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
                   4377:
                   4378:        /*
                   4379:         * The old do_sys_rename had various consistency checks here
                   4380:         * involving fvp and tvp.  fvp is bogus already here, and tvp
                   4381:         * will become bogus soon in any sensible file system, so the
                   4382:         * only purpose in putting these checks here is to give lip
                   4383:         * service to these screw cases and to acknowledge that they
                   4384:         * exist, not actually to handle them, but here you go
                   4385:         * anyway...
                   4386:         */
                   4387:
                   4388:        /*
                   4389:         * Acknowledge that directories and non-directories aren't
                   4390:         * suposed to mix.
                   4391:         */
1.31      cgd      4392:        if (tvp != NULL) {
1.458     riastrad 4393:                if ((fvp->v_type == VDIR) && (tvp->v_type != VDIR)) {
1.31      cgd      4394:                        error = ENOTDIR;
1.458     riastrad 4395:                        goto abort3;
                   4396:                } else if ((fvp->v_type != VDIR) && (tvp->v_type == VDIR)) {
1.31      cgd      4397:                        error = EISDIR;
1.458     riastrad 4398:                        goto abort3;
1.31      cgd      4399:                }
                   4400:        }
1.90      kleink   4401:
1.458     riastrad 4402:        /*
                   4403:         * Acknowledge some random screw case, among the dozens that
                   4404:         * might arise.
                   4405:         */
                   4406:        if (fvp == tdvp) {
1.31      cgd      4407:                error = EINVAL;
1.458     riastrad 4408:                goto abort3;
                   4409:        }
1.90      kleink   4410:
1.82      kleink   4411:        /*
1.458     riastrad 4412:         * Acknowledge that POSIX has a wacky screw case.
                   4413:         *
                   4414:         * XXX Eventually the retain flag needs to be passed on to
                   4415:         * VOP_RENAME.
1.82      kleink   4416:         */
1.90      kleink   4417:        if (fvp == tvp) {
1.458     riastrad 4418:                if (retain) {
                   4419:                        error = 0;
                   4420:                        goto abort3;
                   4421:                } else if ((fdvp == tdvp) &&
                   4422:                    (fnd.ni_cnd.cn_namelen == tnd.ni_cnd.cn_namelen) &&
                   4423:                    (0 == memcmp(fnd.ni_cnd.cn_nameptr, tnd.ni_cnd.cn_nameptr,
                   4424:                        fnd.ni_cnd.cn_namelen))) {
                   4425:                        error = 0;
                   4426:                        goto abort3;
                   4427:                }
1.90      kleink   4428:        }
1.458     riastrad 4429:
1.419     yamt     4430:        /*
1.458     riastrad 4431:         * Make sure veriexec can screw us up.  (But a race can screw
                   4432:         * up veriexec, of course -- remember, fvp and (soon) tvp are
                   4433:         * bogus.)
1.419     yamt     4434:         */
1.256     elad     4435: #if NVERIEXEC > 0
1.458     riastrad 4436:        {
1.313     elad     4437:                char *f1, *f2;
1.384     yamt     4438:                size_t f1_len;
                   4439:                size_t f2_len;
1.313     elad     4440:
1.458     riastrad 4441:                f1_len = fnd.ni_cnd.cn_namelen + 1;
1.384     yamt     4442:                f1 = kmem_alloc(f1_len, KM_SLEEP);
1.458     riastrad 4443:                strlcpy(f1, fnd.ni_cnd.cn_nameptr, f1_len);
1.384     yamt     4444:
1.458     riastrad 4445:                f2_len = tnd.ni_cnd.cn_namelen + 1;
1.384     yamt     4446:                f2 = kmem_alloc(f2_len, KM_SLEEP);
1.458     riastrad 4447:                strlcpy(f2, tnd.ni_cnd.cn_nameptr, f2_len);
1.282     elad     4448:
1.428     uebayasi 4449:                error = veriexec_renamechk(curlwp, fvp, f1, tvp, f2);
1.282     elad     4450:
1.384     yamt     4451:                kmem_free(f1, f1_len);
                   4452:                kmem_free(f2, f2_len);
1.458     riastrad 4453:
                   4454:                if (error)
                   4455:                        goto abort3;
1.282     elad     4456:        }
1.256     elad     4457: #endif /* NVERIEXEC > 0 */
1.229     elad     4458:
1.458     riastrad 4459:        /*
                   4460:         * All ready.  Incant the rename vop.
                   4461:         */
                   4462:        /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
                   4463:        /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
                   4464:        KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
                   4465:        KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
                   4466:        error = VOP_RENAME(fdvp, fvp, &fnd.ni_cnd, tdvp, tvp, &tnd.ni_cnd);
                   4467:
                   4468:        /*
                   4469:         * VOP_RENAME releases fdvp, fvp, tdvp, and tvp, and unlocks
                   4470:         * tdvp and tvp.  But we can't assert any of that.
                   4471:         */
                   4472:        /* XXX KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
                   4473:        /* XXX KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
                   4474:        /* XXX KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
                   4475:        /* XXX KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) != LK_EXCLUSIVE)); */
                   4476:
                   4477:        /*
                   4478:         * So all we have left to do is to drop the rename lock and
                   4479:         * destroy the pathbufs.
                   4480:         */
1.459     riastrad 4481:        VFS_RENAMELOCK_EXIT(mp);
1.458     riastrad 4482:        goto out2;
                   4483:
                   4484: abort3:        if ((tvp != NULL) && (tvp != tdvp))
                   4485:                VOP_UNLOCK(tvp);
                   4486: abort2:        VOP_UNLOCK(tdvp);
1.459     riastrad 4487:        VFS_RENAMELOCK_EXIT(mp);
1.458     riastrad 4488: abort1:        VOP_ABORTOP(tdvp, &tnd.ni_cnd);
                   4489:        vrele(tdvp);
                   4490:        if (tvp != NULL)
                   4491:                vrele(tvp);
                   4492: abort0:        VOP_ABORTOP(fdvp, &fnd.ni_cnd);
                   4493:        vrele(fdvp);
                   4494:        vrele(fvp);
                   4495: out2:  pathbuf_destroy(tpb);
                   4496: out1:  pathbuf_destroy(fpb);
                   4497: out0:  return error;
1.31      cgd      4498: }
                   4499:
                   4500: /*
                   4501:  * Make a directory file.
                   4502:  */
                   4503: /* ARGSUSED */
1.63      christos 4504: int
1.335     dsl      4505: sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval)
1.56      thorpej  4506: {
1.335     dsl      4507:        /* {
1.74      cgd      4508:                syscallarg(const char *) path;
1.35      cgd      4509:                syscallarg(int) mode;
1.335     dsl      4510:        } */
1.396     pooka    4511:
1.460     manu     4512:        return do_sys_mkdirat(l, AT_FDCWD, SCARG(uap, path),
                   4513:            SCARG(uap, mode), UIO_USERSPACE);
1.396     pooka    4514: }
                   4515:
                   4516: int
1.433     manu     4517: sys_mkdirat(struct lwp *l, const struct sys_mkdirat_args *uap,
                   4518:     register_t *retval)
                   4519: {
                   4520:        /* {
                   4521:                syscallarg(int) fd;
                   4522:                syscallarg(const char *) path;
                   4523:                syscallarg(int) mode;
                   4524:        } */
                   4525:
1.460     manu     4526:        return do_sys_mkdirat(l, SCARG(uap, fd), SCARG(uap, path),
                   4527:            SCARG(uap, mode), UIO_USERSPACE);
1.433     manu     4528: }
                   4529:
                   4530:
                   4531: int
1.399     haad     4532: do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg)
1.396     pooka    4533: {
1.460     manu     4534:        return do_sys_mkdirat(NULL, AT_FDCWD, path, mode, UIO_USERSPACE);
                   4535: }
                   4536:
                   4537: static int
                   4538: do_sys_mkdirat(struct lwp *l, int fdat, const char *path, mode_t mode,
                   4539:     enum uio_seg seg)
                   4540: {
1.396     pooka    4541:        struct proc *p = curlwp->l_proc;
1.155     augustss 4542:        struct vnode *vp;
1.31      cgd      4543:        struct vattr vattr;
                   4544:        int error;
1.409     dholland 4545:        struct pathbuf *pb;
1.31      cgd      4546:        struct nameidata nd;
                   4547:
1.460     manu     4548:        KASSERT(l != NULL || fdat == AT_FDCWD);
                   4549:
1.409     dholland 4550:        /* XXX bollocks, should pass in a pathbuf */
                   4551:        error = pathbuf_maybe_copyin(path, seg, &pb);
                   4552:        if (error) {
                   4553:                return error;
                   4554:        }
                   4555:
                   4556:        NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, pb);
1.460     manu     4557:
                   4558:        if ((error = fd_nameiat(l, fdat, &nd)) != 0) {
1.409     dholland 4559:                pathbuf_destroy(pb);
1.31      cgd      4560:                return (error);
1.409     dholland 4561:        }
1.31      cgd      4562:        vp = nd.ni_vp;
                   4563:        if (vp != NULL) {
                   4564:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   4565:                if (nd.ni_dvp == vp)
                   4566:                        vrele(nd.ni_dvp);
                   4567:                else
                   4568:                        vput(nd.ni_dvp);
                   4569:                vrele(vp);
1.409     dholland 4570:                pathbuf_destroy(pb);
1.31      cgd      4571:                return (EEXIST);
                   4572:        }
1.402     pooka    4573:        vattr_null(&vattr);
1.31      cgd      4574:        vattr.va_type = VDIR;
1.328     ad       4575:        /* We will read cwdi->cwdi_cmask unlocked. */
1.396     pooka    4576:        vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
1.31      cgd      4577:        error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
                   4578:        if (!error)
1.473     hannken  4579:                vrele(nd.ni_vp);
1.472     hannken  4580:        vput(nd.ni_dvp);
1.409     dholland 4581:        pathbuf_destroy(pb);
1.31      cgd      4582:        return (error);
                   4583: }
                   4584:
                   4585: /*
                   4586:  * Remove a directory file.
                   4587:  */
                   4588: /* ARGSUSED */
1.63      christos 4589: int
1.335     dsl      4590: sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval)
1.56      thorpej  4591: {
1.460     manu     4592:        return do_sys_unlinkat(l, AT_FDCWD, SCARG(uap, path),
                   4593:            AT_REMOVEDIR, UIO_USERSPACE);
1.31      cgd      4594: }
                   4595:
                   4596: /*
                   4597:  * Read a block of directory entries in a file system independent format.
                   4598:  */
1.63      christos 4599: int
1.335     dsl      4600: sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval)
1.56      thorpej  4601: {
1.335     dsl      4602:        /* {
1.35      cgd      4603:                syscallarg(int) fd;
                   4604:                syscallarg(char *) buf;
1.101     fvdl     4605:                syscallarg(size_t) count;
1.335     dsl      4606:        } */
1.346     ad       4607:        file_t *fp;
1.101     fvdl     4608:        int error, done;
1.31      cgd      4609:
1.346     ad       4610:        /* fd_getvnode() will use the descriptor for us */
                   4611:        if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1.31      cgd      4612:                return (error);
1.135     thorpej  4613:        if ((fp->f_flag & FREAD) == 0) {
                   4614:                error = EBADF;
                   4615:                goto out;
                   4616:        }
1.101     fvdl     4617:        error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
1.234     christos 4618:                        SCARG(uap, count), &done, l, 0, 0);
1.325     ad       4619:        ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error);
1.101     fvdl     4620:        *retval = done;
1.135     thorpej  4621:  out:
1.346     ad       4622:        fd_putfile(SCARG(uap, fd));
1.31      cgd      4623:        return (error);
                   4624: }
                   4625:
                   4626: /*
                   4627:  * Set the mode mask for creation of filesystem nodes.
                   4628:  */
1.56      thorpej  4629: int
1.335     dsl      4630: sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval)
1.56      thorpej  4631: {
1.335     dsl      4632:        /* {
1.103     mycroft  4633:                syscallarg(mode_t) newmask;
1.335     dsl      4634:        } */
1.179     thorpej  4635:        struct proc *p = l->l_proc;
1.134     thorpej  4636:        struct cwdinfo *cwdi;
1.31      cgd      4637:
1.328     ad       4638:        /*
                   4639:         * cwdi->cwdi_cmask will be read unlocked elsewhere.  What's
                   4640:         * important is that we serialize changes to the mask.  The
                   4641:         * rw_exit() will issue a write memory barrier on our behalf,
                   4642:         * and force the changes out to other CPUs (as it must use an
                   4643:         * atomic operation, draining the local CPU's store buffers).
                   4644:         */
1.134     thorpej  4645:        cwdi = p->p_cwdi;
1.328     ad       4646:        rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1.134     thorpej  4647:        *retval = cwdi->cwdi_cmask;
                   4648:        cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
1.328     ad       4649:        rw_exit(&cwdi->cwdi_lock);
                   4650:
1.31      cgd      4651:        return (0);
                   4652: }
                   4653:
1.340     elad     4654: int
                   4655: dorevoke(struct vnode *vp, kauth_cred_t cred)
                   4656: {
                   4657:        struct vattr vattr;
1.450     elad     4658:        int error, fs_decision;
1.340     elad     4659:
1.440     hannken  4660:        vn_lock(vp, LK_SHARED | LK_RETRY);
                   4661:        error = VOP_GETATTR(vp, &vattr, cred);
                   4662:        VOP_UNLOCK(vp);
                   4663:        if (error != 0)
1.342     ad       4664:                return error;
1.450     elad     4665:        fs_decision = (kauth_cred_geteuid(cred) == vattr.va_uid) ? 0 : EPERM;
                   4666:        error = kauth_authorize_vnode(cred, KAUTH_VNODE_REVOKE, vp, NULL,
                   4667:            fs_decision);
                   4668:        if (!error)
1.340     elad     4669:                VOP_REVOKE(vp, REVOKEALL);
                   4670:        return (error);
                   4671: }
                   4672:
1.31      cgd      4673: /*
                   4674:  * Void all references to file by ripping underlying filesystem
                   4675:  * away from vnode.
                   4676:  */
                   4677: /* ARGSUSED */
1.63      christos 4678: int
1.335     dsl      4679: sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval)
1.56      thorpej  4680: {
1.335     dsl      4681:        /* {
1.74      cgd      4682:                syscallarg(const char *) path;
1.335     dsl      4683:        } */
1.155     augustss 4684:        struct vnode *vp;
1.31      cgd      4685:        int error;
                   4686:
1.395     dholland 4687:        error = namei_simple_user(SCARG(uap, path),
                   4688:                                NSM_FOLLOW_TRYEMULROOT, &vp);
                   4689:        if (error != 0)
1.31      cgd      4690:                return (error);
1.340     elad     4691:        error = dorevoke(vp, l->l_cred);
1.31      cgd      4692:        vrele(vp);
                   4693:        return (error);
                   4694: }

CVSweb <webmaster@jp.NetBSD.org>