LCOV - code coverage report
Current view: top level - kern - vfs_syscalls.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1626 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 88 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: vfs_syscalls.c,v 1.305 2018/09/01 17:02:12 deraadt Exp $      */
       2             : /*      $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $        */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1989, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  * (c) UNIX System Laboratories, Inc.
       8             :  * All or some portions of this file are derived from material licensed
       9             :  * to the University of California by American Telephone and Telegraph
      10             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      11             :  * the permission of UNIX System Laboratories, Inc.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  * 3. Neither the name of the University nor the names of its contributors
      22             :  *    may be used to endorse or promote products derived from this software
      23             :  *    without specific prior written permission.
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      26             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      27             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      28             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      29             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      30             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      31             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      33             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      34             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      35             :  * SUCH DAMAGE.
      36             :  *
      37             :  *      @(#)vfs_syscalls.c      8.28 (Berkeley) 12/10/94
      38             :  */
      39             : 
      40             : #include <sys/param.h>
      41             : #include <sys/systm.h>
      42             : #include <sys/namei.h>
      43             : #include <sys/filedesc.h>
      44             : #include <sys/kernel.h>
      45             : #include <sys/conf.h>
      46             : #include <sys/sysctl.h>
      47             : #include <sys/fcntl.h>
      48             : #include <sys/file.h>
      49             : #include <sys/stat.h>
      50             : #include <sys/lock.h>
      51             : #include <sys/vnode.h>
      52             : #include <sys/mount.h>
      53             : #include <sys/proc.h>
      54             : #include <sys/pledge.h>
      55             : #include <sys/uio.h>
      56             : #include <sys/malloc.h>
      57             : #include <sys/pool.h>
      58             : #include <sys/dkio.h>
      59             : #include <sys/disklabel.h>
      60             : #include <sys/ktrace.h>
      61             : #include <sys/unistd.h>
      62             : #include <sys/specdev.h>
      63             : 
      64             : #include <sys/syscallargs.h>
      65             : 
      66             : extern int suid_clear;
      67             : 
      68             : static int change_dir(struct nameidata *, struct proc *);
      69             : 
      70             : void checkdirs(struct vnode *);
      71             : 
      72             : int copyout_statfs(struct statfs *, void *, struct proc *);
      73             : 
      74             : int doopenat(struct proc *, int, const char *, int, mode_t, register_t *);
      75             : int domknodat(struct proc *, int, const char *, mode_t, dev_t);
      76             : int dolinkat(struct proc *, int, const char *, int, const char *, int);
      77             : int dosymlinkat(struct proc *, const char *, int, const char *);
      78             : int dounlinkat(struct proc *, int, const char *, int);
      79             : int dofaccessat(struct proc *, int, const char *, int, int);
      80             : int dofstatat(struct proc *, int, const char *, struct stat *, int);
      81             : int doreadlinkat(struct proc *, int, const char *, char *, size_t,
      82             :     register_t *);
      83             : int dochflagsat(struct proc *, int, const char *, u_int, int);
      84             : int dovchflags(struct proc *, struct vnode *, u_int);
      85             : int dofchmodat(struct proc *, int, const char *, mode_t, int);
      86             : int dofchownat(struct proc *, int, const char *, uid_t, gid_t, int);
      87             : int dorenameat(struct proc *, int, const char *, int, const char *);
      88             : int domkdirat(struct proc *, int, const char *, mode_t);
      89             : int doutimensat(struct proc *, int, const char *, struct timespec [2], int);
      90             : int dovutimens(struct proc *, struct vnode *, struct timespec [2]);
      91             : int dofutimens(struct proc *, int, struct timespec [2]);
      92             : int dounmount_leaf(struct mount *, int, struct proc *);
      93             : int unveil_add(struct proc *, struct nameidata *, const char *);
      94             : void unveil_removevnode(struct vnode *vp);
      95             : 
      96             : /*
      97             :  * Virtual File System System Calls
      98             :  */
      99             : 
     100             : /*
     101             :  * Mount a file system.
     102             :  */
     103             : int
     104           0 : sys_mount(struct proc *p, void *v, register_t *retval)
     105             : {
     106             :         struct sys_mount_args /* {
     107             :                 syscallarg(const char *) type;
     108             :                 syscallarg(const char *) path;
     109             :                 syscallarg(int) flags;
     110             :                 syscallarg(void *) data;
     111           0 :         } */ *uap = v;
     112             :         struct vnode *vp;
     113             :         struct mount *mp;
     114             :         int error, mntflag = 0;
     115           0 :         char fstypename[MFSNAMELEN];
     116           0 :         char fspath[MNAMELEN];
     117           0 :         struct nameidata nd;
     118             :         struct vfsconf *vfsp;
     119           0 :         int flags = SCARG(uap, flags);
     120             :         void *args = NULL;
     121             : 
     122           0 :         if ((error = suser(p)))
     123           0 :                 return (error);
     124             : 
     125             :         /*
     126             :          * Mount points must fit in MNAMELEN, not MAXPATHLEN.
     127             :          */
     128           0 :         error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
     129           0 :         if (error)
     130           0 :                 return(error);
     131             : 
     132             :         /*
     133             :          * Get vnode to be covered
     134             :          */
     135           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p);
     136           0 :         if ((error = namei(&nd)) != 0)
     137             :                 goto fail;
     138           0 :         vp = nd.ni_vp;
     139           0 :         if (flags & MNT_UPDATE) {
     140           0 :                 if ((vp->v_flag & VROOT) == 0) {
     141           0 :                         vput(vp);
     142             :                         error = EINVAL;
     143           0 :                         goto fail;
     144             :                 }
     145           0 :                 mp = vp->v_mount;
     146           0 :                 vfsp = mp->mnt_vfc;
     147             : 
     148           0 :                 args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO);
     149           0 :                 error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize);
     150           0 :                 if (error) {
     151           0 :                         vput(vp);
     152           0 :                         goto fail;
     153             :                 }
     154             : 
     155           0 :                 mntflag = mp->mnt_flag;
     156             :                 /*
     157             :                  * We only allow the filesystem to be reloaded if it
     158             :                  * is currently mounted read-only.
     159             :                  */
     160           0 :                 if ((flags & MNT_RELOAD) &&
     161           0 :                     ((mp->mnt_flag & MNT_RDONLY) == 0)) {
     162           0 :                         vput(vp);
     163             :                         error = EOPNOTSUPP;     /* Needs translation */
     164           0 :                         goto fail;
     165             :                 }
     166             : 
     167           0 :                 if ((error = vfs_busy(mp, VB_READ|VB_NOWAIT)) != 0) {
     168           0 :                         vput(vp);
     169           0 :                         goto fail;
     170             :                 }
     171           0 :                 mp->mnt_flag |= flags & (MNT_RELOAD | MNT_UPDATE);
     172           0 :                 goto update;
     173             :         }
     174             :         /*
     175             :          * Do not allow disabling of permission checks unless exec and access to
     176             :          * device files is disabled too.
     177             :          */
     178           0 :         if ((flags & MNT_NOPERM) &&
     179           0 :             (flags & (MNT_NODEV | MNT_NOEXEC)) != (MNT_NODEV | MNT_NOEXEC)) {
     180           0 :                 vput(vp);
     181             :                 error = EPERM;
     182           0 :                 goto fail;
     183             :         }
     184           0 :         if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
     185           0 :                 vput(vp);
     186           0 :                 goto fail;
     187             :         }
     188           0 :         if (vp->v_type != VDIR) {
     189           0 :                 vput(vp);
     190           0 :                 goto fail;
     191             :         }
     192           0 :         error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
     193           0 :         if (error) {
     194           0 :                 vput(vp);
     195           0 :                 goto fail;
     196             :         }
     197           0 :         for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
     198           0 :                 if (!strcmp(vfsp->vfc_name, fstypename))
     199             :                         break;
     200             :         }
     201             : 
     202           0 :         if (vfsp == NULL) {
     203           0 :                 vput(vp);
     204             :                 error = EOPNOTSUPP;
     205           0 :                 goto fail;
     206             :         }
     207             : 
     208           0 :         args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO);
     209           0 :         error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize);
     210           0 :         if (error) {
     211           0 :                 vput(vp);
     212           0 :                 goto fail;
     213             :         }
     214             : 
     215           0 :         if (vp->v_mountedhere != NULL) {
     216           0 :                 vput(vp);
     217             :                 error = EBUSY;
     218           0 :                 goto fail;
     219             :         }
     220             : 
     221             :         /*
     222             :          * Allocate and initialize the file system.
     223             :          */
     224           0 :         mp = malloc(sizeof(*mp), M_MOUNT, M_WAITOK|M_ZERO);
     225           0 :         (void) vfs_busy(mp, VB_READ|VB_NOWAIT);
     226           0 :         mp->mnt_op = vfsp->vfc_vfsops;
     227           0 :         mp->mnt_vfc = vfsp;
     228           0 :         mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK);
     229           0 :         strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
     230           0 :         mp->mnt_vnodecovered = vp;
     231           0 :         mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
     232             : 
     233             : update:
     234             :         /* Ensure that the parent mountpoint does not get unmounted. */
     235           0 :         error = vfs_busy(vp->v_mount, VB_READ|VB_NOWAIT|VB_DUPOK);
     236           0 :         if (error) {
     237           0 :                 if (mp->mnt_flag & MNT_UPDATE) {
     238           0 :                         mp->mnt_flag = mntflag;
     239           0 :                         vfs_unbusy(mp);
     240           0 :                 } else {
     241           0 :                         vfs_unbusy(mp);
     242           0 :                         free(mp, M_MOUNT, sizeof(*mp));
     243             :                 }
     244           0 :                 vput(vp);
     245           0 :                 goto fail;
     246             :         }
     247             : 
     248             :         /*
     249             :          * Set the mount level flags.
     250             :          */
     251           0 :         if (flags & MNT_RDONLY)
     252           0 :                 mp->mnt_flag |= MNT_RDONLY;
     253           0 :         else if (mp->mnt_flag & MNT_RDONLY)
     254           0 :                 mp->mnt_flag |= MNT_WANTRDWR;
     255           0 :         mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV |
     256             :             MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME |
     257             :             MNT_NOPERM | MNT_FORCE);
     258           0 :         mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED |
     259             :             MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP |
     260             :             MNT_NOATIME | MNT_NOPERM | MNT_FORCE);
     261             :         /*
     262             :          * Mount the filesystem.
     263             :          */
     264           0 :         error = VFS_MOUNT(mp, fspath, args, &nd, p);
     265           0 :         if (!error) {
     266           0 :                 mp->mnt_stat.f_ctime = time_second;
     267           0 :         }
     268           0 :         if (mp->mnt_flag & MNT_UPDATE) {
     269           0 :                 vfs_unbusy(vp->v_mount);
     270           0 :                 vput(vp);
     271           0 :                 if (mp->mnt_flag & MNT_WANTRDWR)
     272           0 :                         mp->mnt_flag &= ~MNT_RDONLY;
     273           0 :                 mp->mnt_flag &=~
     274             :                     (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
     275           0 :                 if (error)
     276           0 :                         mp->mnt_flag = mntflag;
     277             : 
     278           0 :                 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
     279           0 :                         if (mp->mnt_syncer == NULL)
     280           0 :                                 error = vfs_allocate_syncvnode(mp);
     281             :                 } else {
     282           0 :                         if (mp->mnt_syncer != NULL)
     283           0 :                                 vgone(mp->mnt_syncer);
     284           0 :                         mp->mnt_syncer = NULL;
     285             :                 }
     286             : 
     287           0 :                 vfs_unbusy(mp);
     288           0 :                 goto fail;
     289             :         }
     290             : 
     291           0 :         vp->v_mountedhere = mp;
     292             : 
     293             :         /*
     294             :          * Put the new filesystem on the mount list after root.
     295             :          */
     296           0 :         cache_purge(vp);
     297           0 :         if (!error) {
     298           0 :                 vfsp->vfc_refcount++;
     299           0 :                 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
     300           0 :                 checkdirs(vp);
     301           0 :                 vfs_unbusy(vp->v_mount);
     302           0 :                 VOP_UNLOCK(vp);
     303           0 :                 if ((mp->mnt_flag & MNT_RDONLY) == 0)
     304           0 :                         error = vfs_allocate_syncvnode(mp);
     305           0 :                 vfs_unbusy(mp);
     306           0 :                 (void) VFS_STATFS(mp, &mp->mnt_stat, p);
     307           0 :                 if ((error = VFS_START(mp, 0, p)) != 0)
     308           0 :                         vrele(vp);
     309             :         } else {
     310           0 :                 mp->mnt_vnodecovered->v_mountedhere = NULL;
     311           0 :                 vfs_unbusy(mp);
     312           0 :                 free(mp, M_MOUNT, sizeof(*mp));
     313           0 :                 vfs_unbusy(vp->v_mount);
     314           0 :                 vput(vp);
     315             :         }
     316             : fail:
     317           0 :         if (args)
     318           0 :                 free(args, M_TEMP, vfsp->vfc_datasize);
     319           0 :         return (error);
     320           0 : }
     321             : 
     322             : /*
     323             :  * Scan all active processes to see if any of them have a current
     324             :  * or root directory onto which the new filesystem has just been
     325             :  * mounted. If so, replace them with the new mount point, keeping
     326             :  * track of how many were replaced.  That's the number of references
     327             :  * the old vnode had that we've replaced, so finish by vrele()'ing
     328             :  * it that many times.  This puts off any possible sleeping until
     329             :  * we've finished walking the allprocess list.
     330             :  */
     331             : void
     332           0 : checkdirs(struct vnode *olddp)
     333             : {
     334             :         struct filedesc *fdp;
     335           0 :         struct vnode *newdp;
     336             :         struct process *pr;
     337             :         u_int  free_count = 0;
     338             : 
     339           0 :         if (olddp->v_usecount == 1)
     340           0 :                 return;
     341           0 :         if (VFS_ROOT(olddp->v_mountedhere, &newdp))
     342           0 :                 panic("mount: lost mount");
     343           0 :         LIST_FOREACH(pr, &allprocess, ps_list) {
     344           0 :                 fdp = pr->ps_fd;
     345           0 :                 if (fdp->fd_cdir == olddp) {
     346           0 :                         free_count++;
     347           0 :                         vref(newdp);
     348           0 :                         fdp->fd_cdir = newdp;
     349           0 :                 }
     350           0 :                 if (fdp->fd_rdir == olddp) {
     351           0 :                         free_count++;
     352           0 :                         vref(newdp);
     353           0 :                         fdp->fd_rdir = newdp;
     354           0 :                 }
     355           0 :                 pr->ps_uvpcwd = NULL;
     356             :                 /* XXX */
     357           0 :                 pr->ps_uvpcwdgone = 1;
     358             :         }
     359           0 :         if (rootvnode == olddp) {
     360           0 :                 free_count++;
     361           0 :                 vref(newdp);
     362           0 :                 rootvnode = newdp;
     363           0 :         }
     364           0 :         while (free_count-- > 0)
     365           0 :                 vrele(olddp);
     366           0 :         vput(newdp);
     367           0 : }
     368             : 
     369             : /*
     370             :  * Unmount a file system.
     371             :  *
     372             :  * Note: unmount takes a path to the vnode mounted on as argument,
     373             :  * not special file (as before).
     374             :  */
     375             : int
     376           0 : sys_unmount(struct proc *p, void *v, register_t *retval)
     377             : {
     378             :         struct sys_unmount_args /* {
     379             :                 syscallarg(const char *) path;
     380             :                 syscallarg(int) flags;
     381           0 :         } */ *uap = v;
     382             :         struct vnode *vp;
     383             :         struct mount *mp;
     384             :         int error;
     385           0 :         struct nameidata nd;
     386             : 
     387           0 :         if ((error = suser(p)) != 0)
     388           0 :                 return (error);
     389             : 
     390           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
     391             :             SCARG(uap, path), p);
     392           0 :         if ((error = namei(&nd)) != 0)
     393           0 :                 return (error);
     394           0 :         vp = nd.ni_vp;
     395           0 :         mp = vp->v_mount;
     396             : 
     397             :         /*
     398             :          * Don't allow unmounting the root file system.
     399             :          */
     400           0 :         if (mp->mnt_flag & MNT_ROOTFS) {
     401           0 :                 vput(vp);
     402           0 :                 return (EINVAL);
     403             :         }
     404             : 
     405             :         /*
     406             :          * Must be the root of the filesystem
     407             :          */
     408           0 :         if ((vp->v_flag & VROOT) == 0) {
     409             :                 vput(vp);
     410           0 :                 return (EINVAL);
     411             :         }
     412             :         vput(vp);
     413             : 
     414           0 :         if (vfs_busy(mp, VB_WRITE|VB_WAIT))
     415           0 :                 return (EBUSY);
     416             : 
     417           0 :         return (dounmount(mp, SCARG(uap, flags) & MNT_FORCE, p));
     418           0 : }
     419             : 
     420             : /*
     421             :  * Do the actual file system unmount.
     422             :  */
     423             : int
     424           0 : dounmount(struct mount *mp, int flags, struct proc *p)
     425             : {
     426             :         SLIST_HEAD(, mount) mplist;
     427             :         struct mount *nmp;
     428             :         int error;
     429             : 
     430             :         SLIST_INIT(&mplist);
     431           0 :         SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount);
     432             : 
     433             :         /*
     434             :          * Collect nested mount points. This takes advantage of the mount list
     435             :          * being ordered - nested mount points come after their parent.
     436             :          */
     437           0 :         while ((mp = TAILQ_NEXT(mp, mnt_list)) != NULL) {
     438           0 :                 SLIST_FOREACH(nmp, &mplist, mnt_dounmount) {
     439           0 :                         if (mp->mnt_vnodecovered == NULLVP ||
     440           0 :                             mp->mnt_vnodecovered->v_mount != nmp)
     441             :                                 continue;
     442             : 
     443           0 :                         if ((flags & MNT_FORCE) == 0) {
     444             :                                 error = EBUSY;
     445           0 :                                 goto err;
     446             :                         }
     447           0 :                         error = vfs_busy(mp, VB_WRITE|VB_WAIT|VB_DUPOK);
     448           0 :                         if (error) {
     449           0 :                                 if ((flags & MNT_DOOMED)) {
     450             :                                         /*
     451             :                                          * If the mount point was busy due to 
     452             :                                          * being unmounted, it has been removed
     453             :                                          * from the mount list already.
     454             :                                          * Restart the iteration from the last 
     455             :                                          * collected busy entry.
     456             :                                          */
     457             :                                         mp = SLIST_FIRST(&mplist);
     458           0 :                                         break;
     459             :                                 }
     460             :                                 goto err;
     461             :                         }
     462           0 :                         SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount);
     463           0 :                         break;
     464             :                 }
     465             :         }
     466             : 
     467             :         /* 
     468             :          * Nested mount points cannot appear during this loop as mounting
     469             :          * requires a read lock for the parent mount point.
     470             :          */
     471           0 :         while ((mp = SLIST_FIRST(&mplist)) != NULL) {
     472           0 :                 SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount);
     473           0 :                 error = dounmount_leaf(mp, flags, p);
     474           0 :                 if (error)
     475             :                         goto err;
     476             :         }
     477           0 :         return (0);
     478             : 
     479             : err:
     480           0 :         while ((mp = SLIST_FIRST(&mplist)) != NULL) {
     481           0 :                 SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount);
     482           0 :                 vfs_unbusy(mp);
     483             :         }
     484           0 :         return (error);
     485           0 : }
     486             : 
     487             : int
     488           0 : dounmount_leaf(struct mount *mp, int flags, struct proc *p)
     489             : {
     490             :         struct vnode *coveredvp;
     491             :         struct vnode *vp, *nvp;
     492             :         int error;
     493             :         int hadsyncer = 0;
     494             : 
     495           0 :         mp->mnt_flag &=~ MNT_ASYNC;
     496           0 :         cache_purgevfs(mp);     /* remove cache entries for this file sys */
     497           0 :         if (mp->mnt_syncer != NULL) {
     498             :                 hadsyncer = 1;
     499           0 :                 vgone(mp->mnt_syncer);
     500           0 :                 mp->mnt_syncer = NULL;
     501           0 :         }
     502             : 
     503             :         /*
     504             :          * Before calling file system unmount, make sure
     505             :          * all unveils to vnodes in here are dropped.
     506             :          */
     507           0 :         LIST_FOREACH_SAFE(vp , &mp->mnt_vnodelist, v_mntvnodes, nvp) {
     508           0 :                 unveil_removevnode(vp);
     509             :         }
     510             : 
     511           0 :         if (((mp->mnt_flag & MNT_RDONLY) ||
     512           0 :             (error = VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p)) == 0) ||
     513           0 :             (flags & MNT_FORCE))
     514           0 :                 error = VFS_UNMOUNT(mp, flags, p);
     515             : 
     516           0 :         if (error && !(flags & MNT_DOOMED)) {
     517           0 :                 if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer)
     518           0 :                         (void) vfs_allocate_syncvnode(mp);
     519           0 :                 vfs_unbusy(mp);
     520           0 :                 return (error);
     521             :         }
     522             : 
     523           0 :         TAILQ_REMOVE(&mountlist, mp, mnt_list);
     524           0 :         if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
     525           0 :                 coveredvp->v_mountedhere = NULL;
     526           0 :                 vrele(coveredvp);
     527           0 :         }
     528             : 
     529           0 :         mp->mnt_vfc->vfc_refcount--;
     530             : 
     531           0 :         if (!LIST_EMPTY(&mp->mnt_vnodelist))
     532           0 :                 panic("unmount: dangling vnode");
     533             : 
     534           0 :         vfs_unbusy(mp);
     535           0 :         free(mp, M_MOUNT, sizeof(*mp));
     536             : 
     537           0 :         return (0);
     538           0 : }
     539             : 
     540             : /*
     541             :  * Sync each mounted filesystem.
     542             :  */
     543             : #ifdef DEBUG
     544             : int syncprt = 0;
     545             : struct ctldebug debug0 = { "syncprt", &syncprt };
     546             : #endif
     547             : 
     548             : int
     549           0 : sys_sync(struct proc *p, void *v, register_t *retval)
     550             : {
     551             :         struct mount *mp;
     552             :         int asyncflag;
     553             : 
     554           0 :         TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
     555           0 :                 if (vfs_busy(mp, VB_READ|VB_NOWAIT))
     556             :                         continue;
     557           0 :                 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
     558           0 :                         asyncflag = mp->mnt_flag & MNT_ASYNC;
     559           0 :                         mp->mnt_flag &= ~MNT_ASYNC;
     560           0 :                         uvm_vnp_sync(mp);
     561           0 :                         VFS_SYNC(mp, MNT_NOWAIT, 0, p->p_ucred, p);
     562           0 :                         if (asyncflag)
     563           0 :                                 mp->mnt_flag |= MNT_ASYNC;
     564             :                 }
     565           0 :                 vfs_unbusy(mp);
     566           0 :         }
     567             : 
     568           0 :         return (0);
     569             : }
     570             : 
     571             : /*
     572             :  * Change filesystem quotas.
     573             :  */
     574             : int
     575           0 : sys_quotactl(struct proc *p, void *v, register_t *retval)
     576             : {
     577             :         struct sys_quotactl_args /* {
     578             :                 syscallarg(const char *) path;
     579             :                 syscallarg(int) cmd;
     580             :                 syscallarg(int) uid;
     581             :                 syscallarg(char *) arg;
     582           0 :         } */ *uap = v;
     583             :         struct mount *mp;
     584             :         int error;
     585           0 :         struct nameidata nd;
     586             : 
     587           0 :         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
     588           0 :         if ((error = namei(&nd)) != 0)
     589           0 :                 return (error);
     590           0 :         mp = nd.ni_vp->v_mount;
     591           0 :         vrele(nd.ni_vp);
     592           0 :         return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
     593             :             SCARG(uap, arg), p));
     594           0 : }
     595             : 
     596             : int
     597           0 : copyout_statfs(struct statfs *sp, void *uaddr, struct proc *p)
     598             : {
     599             :         size_t co_sz1 = offsetof(struct statfs, f_fsid);
     600             :         size_t co_off2 = co_sz1 + sizeof(fsid_t);
     601             :         size_t co_sz2 = sizeof(struct statfs) - co_off2;
     602             :         char *s, *d;
     603             :         int error;
     604             : 
     605             :         /* Don't let non-root see filesystem id (for NFS security) */
     606           0 :         if (suser(p)) {
     607           0 :                 fsid_t fsid;
     608             : 
     609           0 :                 s = (char *)sp;
     610             :                 d = (char *)uaddr;
     611             : 
     612           0 :                 memset(&fsid, 0, sizeof(fsid));
     613             : 
     614           0 :                 if ((error = copyout(s, d, co_sz1)) != 0)
     615           0 :                         return (error);
     616           0 :                 if ((error = copyout(&fsid, d + co_sz1, sizeof(fsid))) != 0)
     617           0 :                         return (error);
     618           0 :                 return (copyout(s + co_off2, d + co_off2, co_sz2));
     619           0 :         }
     620             : 
     621           0 :         return (copyout(sp, uaddr, sizeof(*sp)));
     622           0 : }
     623             : 
     624             : /*
     625             :  * Get filesystem statistics.
     626             :  */
     627             : int
     628           0 : sys_statfs(struct proc *p, void *v, register_t *retval)
     629             : {
     630             :         struct sys_statfs_args /* {
     631             :                 syscallarg(const char *) path;
     632             :                 syscallarg(struct statfs *) buf;
     633           0 :         } */ *uap = v;
     634             :         struct mount *mp;
     635             :         struct statfs *sp;
     636             :         int error;
     637           0 :         struct nameidata nd;
     638             : 
     639           0 :         NDINIT(&nd, LOOKUP, FOLLOW | BYPASSUNVEIL, UIO_USERSPACE,
     640             :             SCARG(uap, path), p);
     641           0 :         nd.ni_pledge = PLEDGE_RPATH;
     642           0 :         nd.ni_unveil = UNVEIL_READ;
     643           0 :         if ((error = namei(&nd)) != 0)
     644           0 :                 return (error);
     645           0 :         mp = nd.ni_vp->v_mount;
     646           0 :         sp = &mp->mnt_stat;
     647           0 :         vrele(nd.ni_vp);
     648           0 :         if ((error = VFS_STATFS(mp, sp, p)) != 0)
     649           0 :                 return (error);
     650           0 :         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
     651             : 
     652           0 :         return (copyout_statfs(sp, SCARG(uap, buf), p));
     653           0 : }
     654             : 
     655             : /*
     656             :  * Get filesystem statistics.
     657             :  */
     658             : int
     659           0 : sys_fstatfs(struct proc *p, void *v, register_t *retval)
     660             : {
     661             :         struct sys_fstatfs_args /* {
     662             :                 syscallarg(int) fd;
     663             :                 syscallarg(struct statfs *) buf;
     664           0 :         } */ *uap = v;
     665           0 :         struct file *fp;
     666             :         struct mount *mp;
     667             :         struct statfs *sp;
     668             :         int error;
     669             : 
     670           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
     671           0 :                 return (error);
     672           0 :         mp = ((struct vnode *)fp->f_data)->v_mount;
     673           0 :         if (!mp) {
     674           0 :                 FRELE(fp, p);
     675           0 :                 return (ENOENT);
     676             :         }
     677           0 :         sp = &mp->mnt_stat;
     678           0 :         error = VFS_STATFS(mp, sp, p);
     679           0 :         FRELE(fp, p);
     680           0 :         if (error)
     681           0 :                 return (error);
     682           0 :         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
     683             : 
     684           0 :         return (copyout_statfs(sp, SCARG(uap, buf), p));
     685           0 : }
     686             : 
     687             : /*
     688             :  * Get statistics on all filesystems.
     689             :  */
     690             : int
     691           0 : sys_getfsstat(struct proc *p, void *v, register_t *retval)
     692             : {
     693             :         struct sys_getfsstat_args /* {
     694             :                 syscallarg(struct statfs *) buf;
     695             :                 syscallarg(size_t) bufsize;
     696             :                 syscallarg(int) flags;
     697           0 :         } */ *uap = v;
     698             :         struct mount *mp;
     699             :         struct statfs *sp;
     700             :         struct statfs *sfsp;
     701             :         size_t count, maxcount;
     702           0 :         int error, flags = SCARG(uap, flags);
     703             : 
     704           0 :         maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
     705           0 :         sfsp = SCARG(uap, buf);
     706             :         count = 0;
     707             : 
     708           0 :         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
     709           0 :                 if (vfs_busy(mp, VB_READ|VB_NOWAIT))
     710             :                         continue;
     711           0 :                 if (sfsp && count < maxcount) {
     712           0 :                         sp = &mp->mnt_stat;
     713             : 
     714             :                         /* Refresh stats unless MNT_NOWAIT is specified */
     715           0 :                         if (flags != MNT_NOWAIT &&
     716           0 :                             flags != MNT_LAZY &&
     717           0 :                             (flags == MNT_WAIT ||
     718           0 :                             flags == 0) &&
     719           0 :                             (error = VFS_STATFS(mp, sp, p))) {
     720           0 :                                 vfs_unbusy(mp);
     721           0 :                                 continue;
     722             :                         }
     723             : 
     724           0 :                         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
     725             : #if notyet
     726             :                         if (mp->mnt_flag & MNT_SOFTDEP)
     727             :                                 sp->f_eflags = STATFS_SOFTUPD;
     728             : #endif
     729           0 :                         error = (copyout_statfs(sp, sfsp, p));
     730           0 :                         if (error) {
     731           0 :                                 vfs_unbusy(mp);
     732           0 :                                 return (error);
     733             :                         }
     734           0 :                         sfsp++;
     735           0 :                 }
     736           0 :                 count++;
     737           0 :                 vfs_unbusy(mp);
     738           0 :         }
     739             : 
     740           0 :         if (sfsp && count > maxcount)
     741           0 :                 *retval = maxcount;
     742             :         else
     743           0 :                 *retval = count;
     744             : 
     745           0 :         return (0);
     746           0 : }
     747             : 
     748             : /*
     749             :  * Change current working directory to a given file descriptor.
     750             :  */
     751             : int
     752           0 : sys_fchdir(struct proc *p, void *v, register_t *retval)
     753             : {
     754             :         struct sys_fchdir_args /* {
     755             :                 syscallarg(int) fd;
     756           0 :         } */ *uap = v;
     757           0 :         struct filedesc *fdp = p->p_fd;
     758           0 :         struct vnode *vp, *tdp, *old_cdir;
     759             :         struct mount *mp;
     760             :         struct file *fp;
     761             :         int error;
     762             : 
     763           0 :         if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
     764           0 :                 return (EBADF);
     765           0 :         vp = fp->f_data;
     766           0 :         if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) {
     767           0 :                 FRELE(fp, p);
     768           0 :                 return (ENOTDIR);
     769             :         }
     770           0 :         vref(vp);
     771           0 :         FRELE(fp, p);
     772           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
     773           0 :         error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
     774             : 
     775           0 :         while (!error && (mp = vp->v_mountedhere) != NULL) {
     776           0 :                 if (vfs_busy(mp, VB_READ|VB_WAIT))
     777           0 :                         continue;
     778           0 :                 error = VFS_ROOT(mp, &tdp);
     779           0 :                 vfs_unbusy(mp);
     780           0 :                 if (error)
     781             :                         break;
     782           0 :                 vput(vp);
     783           0 :                 vp = tdp;
     784             :         }
     785           0 :         if (error) {
     786           0 :                 vput(vp);
     787           0 :                 return (error);
     788             :         }
     789           0 :         VOP_UNLOCK(vp);
     790           0 :         old_cdir = fdp->fd_cdir;
     791           0 :         fdp->fd_cdir = vp;
     792           0 :         vrele(old_cdir);
     793           0 :         return (0);
     794           0 : }
     795             : 
     796             : /*
     797             :  * Change current working directory (``.'').
     798             :  */
     799             : int
     800           0 : sys_chdir(struct proc *p, void *v, register_t *retval)
     801             : {
     802             :         struct sys_chdir_args /* {
     803             :                 syscallarg(const char *) path;
     804           0 :         } */ *uap = v;
     805           0 :         struct filedesc *fdp = p->p_fd;
     806             :         struct vnode *old_cdir;
     807             :         int error;
     808           0 :         struct nameidata nd;
     809             : 
     810           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
     811             :             SCARG(uap, path), p);
     812           0 :         nd.ni_pledge = PLEDGE_RPATH;
     813           0 :         nd.ni_unveil = UNVEIL_READ;
     814           0 :         if ((error = change_dir(&nd, p)) != 0)
     815           0 :                 return (error);
     816           0 :         p->p_p->ps_uvpcwd = nd.ni_unveil_match;
     817           0 :         p->p_p->ps_uvpcwdgone = 0;
     818           0 :         old_cdir = fdp->fd_cdir;
     819           0 :         fdp->fd_cdir = nd.ni_vp;
     820           0 :         vrele(old_cdir);
     821           0 :         return (0);
     822           0 : }
     823             : 
     824             : /*
     825             :  * Change notion of root (``/'') directory.
     826             :  */
     827             : int
     828           0 : sys_chroot(struct proc *p, void *v, register_t *retval)
     829             : {
     830             :         struct sys_chroot_args /* {
     831             :                 syscallarg(const char *) path;
     832           0 :         } */ *uap = v;
     833           0 :         struct filedesc *fdp = p->p_fd;
     834             :         struct vnode *old_cdir, *old_rdir;
     835             :         int error;
     836           0 :         struct nameidata nd;
     837             : 
     838           0 :         if ((error = suser(p)) != 0)
     839           0 :                 return (error);
     840           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
     841             :             SCARG(uap, path), p);
     842           0 :         if ((error = change_dir(&nd, p)) != 0)
     843           0 :                 return (error);
     844           0 :         if (fdp->fd_rdir != NULL) {
     845             :                 /*
     846             :                  * A chroot() done inside a changed root environment does
     847             :                  * an automatic chdir to avoid the out-of-tree experience.
     848             :                  */
     849           0 :                 vref(nd.ni_vp);
     850           0 :                 old_rdir = fdp->fd_rdir;
     851           0 :                 old_cdir = fdp->fd_cdir;
     852           0 :                 fdp->fd_rdir = fdp->fd_cdir = nd.ni_vp;
     853           0 :                 vrele(old_rdir);
     854           0 :                 vrele(old_cdir);
     855           0 :         } else
     856           0 :                 fdp->fd_rdir = nd.ni_vp;
     857           0 :         return (0);
     858           0 : }
     859             : 
     860             : /*
     861             :  * Common routine for chroot and chdir.
     862             :  */
     863             : static int
     864           0 : change_dir(struct nameidata *ndp, struct proc *p)
     865             : {
     866             :         struct vnode *vp;
     867             :         int error;
     868             : 
     869           0 :         if ((error = namei(ndp)) != 0)
     870           0 :                 return (error);
     871           0 :         vp = ndp->ni_vp;
     872           0 :         if (vp->v_type != VDIR)
     873           0 :                 error = ENOTDIR;
     874             :         else
     875           0 :                 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
     876           0 :         if (error)
     877           0 :                 vput(vp);
     878             :         else
     879           0 :                 VOP_UNLOCK(vp);
     880           0 :         return (error);
     881           0 : }
     882             : 
     883             : int
     884           0 : sys_unveil(struct proc *p, void *v, register_t *retval)
     885             : {
     886             :         struct sys_unveil_args /* {
     887             :                 syscallarg(const char *) path;
     888             :                 syscallarg(const char *) permissions;
     889           0 :         } */ *uap = v;
     890           0 :         char pathname[MAXPATHLEN];
     891           0 :         struct nameidata nd;
     892           0 :         size_t pathlen;
     893           0 :         char permissions[5];
     894             :         int error;
     895             : 
     896           0 :         if (SCARG(uap, path) == NULL && SCARG(uap, permissions) == NULL) {
     897           0 :                 p->p_p->ps_uvdone = 1;
     898           0 :                 return (0);
     899             :         }
     900             : 
     901           0 :         if (p->p_p->ps_uvdone != 0)
     902           0 :                 return EPERM;
     903             : 
     904           0 :         error = copyinstr(SCARG(uap, permissions), permissions,
     905             :             sizeof(permissions), NULL);
     906           0 :         if (error)
     907           0 :                 return(error);
     908           0 :         error = copyinstr(SCARG(uap, path), pathname, sizeof(pathname), &pathlen);
     909           0 :         if (error)
     910           0 :                 return(error);
     911             : 
     912             : #ifdef KTRACE
     913           0 :         if (KTRPOINT(p, KTR_STRUCT))
     914           0 :                 ktrstruct(p, "unveil", permissions, strlen(permissions));
     915             : #endif
     916           0 :         if (pathlen < 2)
     917           0 :                 return EINVAL;
     918             : 
     919           0 :         if (pathlen == 2 && pathname[0] == '/')
     920           0 :                 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME,
     921             :                     UIO_SYSSPACE, pathname, p);
     922             :         else
     923           0 :                 NDINIT(&nd, CREATE, FOLLOW | LOCKLEAF | LOCKPARENT | SAVENAME,
     924             :                     UIO_SYSSPACE, pathname, p);
     925             : 
     926           0 :         nd.ni_pledge = PLEDGE_UNVEIL;
     927           0 :         if ((error = namei(&nd)) != 0)
     928           0 :                 return (error);
     929             : 
     930             :         /*
     931             :          * XXX Any access to the file or directory will allow us to
     932             :          * pledge path it
     933             :          */
     934           0 :         if ((nd.ni_vp &&
     935           0 :             (VOP_ACCESS(nd.ni_vp, VREAD, p->p_ucred, p) == 0 ||
     936           0 :             VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p) == 0 ||
     937           0 :             VOP_ACCESS(nd.ni_vp, VEXEC, p->p_ucred, p) == 0)) ||
     938           0 :             VOP_ACCESS(nd.ni_dvp, VREAD, p->p_ucred, p) == 0 ||
     939           0 :             VOP_ACCESS(nd.ni_dvp, VWRITE, p->p_ucred, p) == 0 ||
     940           0 :             VOP_ACCESS(nd.ni_dvp, VEXEC, p->p_ucred, p) == 0)
     941           0 :                 error = unveil_add(p, &nd, permissions);
     942             :         else
     943             :                 error = EPERM;
     944             : 
     945             :         /* release vref and lock from namei, but not vref from ppath_add */
     946           0 :         if (nd.ni_vp)
     947           0 :                 vput(nd.ni_vp);
     948           0 :         if (nd.ni_dvp && nd.ni_dvp != nd.ni_vp)
     949           0 :                 vput(nd.ni_dvp);
     950           0 :         return (error);
     951           0 : }
     952             : 
     953             : /*
     954             :  * Check permissions, allocate an open file structure,
     955             :  * and call the device open routine if any.
     956             :  */
     957             : int
     958           0 : sys_open(struct proc *p, void *v, register_t *retval)
     959             : {
     960             :         struct sys_open_args /* {
     961             :                 syscallarg(const char *) path;
     962             :                 syscallarg(int) flags;
     963             :                 syscallarg(mode_t) mode;
     964           0 :         } */ *uap = v;
     965             : 
     966           0 :         return (doopenat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags),
     967           0 :             SCARG(uap, mode), retval));
     968             : }
     969             : 
     970             : int
     971           0 : sys_openat(struct proc *p, void *v, register_t *retval)
     972             : {
     973             :         struct sys_openat_args /* {
     974             :                 syscallarg(int) fd;
     975             :                 syscallarg(const char *) path;
     976             :                 syscallarg(int) flags;
     977             :                 syscallarg(mode_t) mode;
     978           0 :         } */ *uap = v;
     979             : 
     980           0 :         return (doopenat(p, SCARG(uap, fd), SCARG(uap, path),
     981           0 :             SCARG(uap, flags), SCARG(uap, mode), retval));
     982             : }
     983             : 
     984             : int
     985           0 : doopenat(struct proc *p, int fd, const char *path, int oflags, mode_t mode,
     986             :     register_t *retval)
     987             : {
     988           0 :         struct filedesc *fdp = p->p_fd;
     989           0 :         struct file *fp;
     990             :         struct vnode *vp;
     991           0 :         struct vattr vattr;
     992             :         int flags, cloexec, cmode;
     993           0 :         int type, indx, error, localtrunc = 0;
     994           0 :         struct flock lf;
     995           0 :         struct nameidata nd;
     996             :         uint64_t ni_pledge = 0;
     997             :         u_char ni_unveil = 0;
     998             : 
     999           0 :         if (oflags & (O_EXLOCK | O_SHLOCK)) {
    1000           0 :                 error = pledge_flock(p);
    1001           0 :                 if (error != 0)
    1002           0 :                         return (error);
    1003             :         }
    1004             : 
    1005           0 :         cloexec = (oflags & O_CLOEXEC) ? UF_EXCLOSE : 0;
    1006             : 
    1007           0 :         fdplock(fdp);
    1008           0 :         if ((error = falloc(p, &fp, &indx)) != 0)
    1009             :                 goto out;
    1010           0 :         fdpunlock(fdp);
    1011             : 
    1012           0 :         flags = FFLAGS(oflags);
    1013           0 :         if (flags & FREAD) {
    1014             :                 ni_pledge |= PLEDGE_RPATH;
    1015             :                 ni_unveil |= UNVEIL_READ;
    1016           0 :         }
    1017           0 :         if (flags & FWRITE) {
    1018           0 :                 ni_pledge |= PLEDGE_WPATH;
    1019           0 :                 ni_unveil |= UNVEIL_WRITE;
    1020           0 :         }
    1021           0 :         if (oflags & O_CREAT) {
    1022           0 :                 ni_pledge |= PLEDGE_CPATH;
    1023           0 :                 ni_unveil |= UNVEIL_CREATE;
    1024           0 :         }
    1025             : 
    1026           0 :         cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
    1027           0 :         if ((p->p_p->ps_flags & PS_PLEDGE))
    1028           0 :                 cmode &= ACCESSPERMS;
    1029           0 :         NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
    1030           0 :         nd.ni_pledge = ni_pledge;
    1031           0 :         nd.ni_unveil = ni_unveil;
    1032           0 :         p->p_dupfd = -1;                     /* XXX check for fdopen */
    1033           0 :         if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
    1034             :                 localtrunc = 1;
    1035           0 :                 flags &= ~O_TRUNC;  /* Must do truncate ourselves */
    1036           0 :         }
    1037           0 :         if ((error = vn_open(&nd, flags, cmode)) != 0) {
    1038           0 :                 fdplock(fdp);
    1039           0 :                 if (error == ENODEV &&
    1040           0 :                     p->p_dupfd >= 0 &&                    /* XXX from fdopen */
    1041             :                     (error =
    1042           0 :                         dupfdopen(p, indx, flags)) == 0) {
    1043           0 :                         closef(fp, p);
    1044           0 :                         *retval = indx;
    1045           0 :                         goto out;
    1046             :                 }
    1047           0 :                 if (error == ERESTART)
    1048           0 :                         error = EINTR;
    1049           0 :                 fdremove(fdp, indx);
    1050           0 :                 closef(fp, p);
    1051           0 :                 goto out;
    1052             :         }
    1053           0 :         p->p_dupfd = 0;
    1054           0 :         vp = nd.ni_vp;
    1055           0 :         fp->f_flag = flags & FMASK;
    1056           0 :         fp->f_type = DTYPE_VNODE;
    1057           0 :         fp->f_ops = &vnops;
    1058           0 :         fp->f_data = vp;
    1059           0 :         if (flags & (O_EXLOCK | O_SHLOCK)) {
    1060           0 :                 lf.l_whence = SEEK_SET;
    1061           0 :                 lf.l_start = 0;
    1062           0 :                 lf.l_len = 0;
    1063           0 :                 if (flags & O_EXLOCK)
    1064           0 :                         lf.l_type = F_WRLCK;
    1065             :                 else
    1066           0 :                         lf.l_type = F_RDLCK;
    1067             :                 type = F_FLOCK;
    1068           0 :                 if ((flags & FNONBLOCK) == 0)
    1069           0 :                         type |= F_WAIT;
    1070           0 :                 VOP_UNLOCK(vp);
    1071           0 :                 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
    1072           0 :                 if (error) {
    1073           0 :                         fdplock(fdp);
    1074             :                         /* closef will vn_close the file for us. */
    1075           0 :                         fdremove(fdp, indx);
    1076           0 :                         closef(fp, p);
    1077           0 :                         goto out;
    1078             :                 }
    1079           0 :                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    1080           0 :                 fp->f_iflags |= FIF_HASLOCK;
    1081           0 :         }
    1082           0 :         if (localtrunc) {
    1083           0 :                 if ((fp->f_flag & FWRITE) == 0)
    1084           0 :                         error = EACCES;
    1085           0 :                 else if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY))
    1086           0 :                         error = EROFS;
    1087           0 :                 else if (vp->v_type == VDIR)
    1088           0 :                         error = EISDIR;
    1089           0 :                 else if ((error = vn_writechk(vp)) == 0) {
    1090           0 :                         VATTR_NULL(&vattr);
    1091           0 :                         vattr.va_size = 0;
    1092           0 :                         error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
    1093           0 :                 }
    1094           0 :                 if (error) {
    1095           0 :                         VOP_UNLOCK(vp);
    1096           0 :                         fdplock(fdp);
    1097             :                         /* closef will close the file for us. */
    1098           0 :                         fdremove(fdp, indx);
    1099           0 :                         closef(fp, p);
    1100           0 :                         goto out;
    1101             :                 }
    1102             :         }
    1103           0 :         VOP_UNLOCK(vp);
    1104           0 :         *retval = indx;
    1105           0 :         fdplock(fdp);
    1106           0 :         fdinsert(fdp, indx, cloexec, fp);
    1107           0 :         FRELE(fp, p);
    1108             : out:
    1109           0 :         fdpunlock(fdp);
    1110           0 :         return (error);
    1111           0 : }
    1112             : 
    1113             : /*
    1114             :  * Get file handle system call
    1115             :  */
    1116             : int
    1117           0 : sys_getfh(struct proc *p, void *v, register_t *retval)
    1118             : {
    1119             :         struct sys_getfh_args /* {
    1120             :                 syscallarg(const char *) fname;
    1121             :                 syscallarg(fhandle_t *) fhp;
    1122           0 :         } */ *uap = v;
    1123             :         struct vnode *vp;
    1124           0 :         fhandle_t fh;
    1125             :         int error;
    1126           0 :         struct nameidata nd;
    1127             : 
    1128             :         /*
    1129             :          * Must be super user
    1130             :          */
    1131           0 :         error = suser(p);
    1132           0 :         if (error)
    1133           0 :                 return (error);
    1134           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
    1135             :             SCARG(uap, fname), p);
    1136           0 :         error = namei(&nd);
    1137           0 :         if (error)
    1138           0 :                 return (error);
    1139           0 :         vp = nd.ni_vp;
    1140           0 :         memset(&fh, 0, sizeof(fh));
    1141           0 :         fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
    1142           0 :         error = VFS_VPTOFH(vp, &fh.fh_fid);
    1143           0 :         vput(vp);
    1144           0 :         if (error)
    1145           0 :                 return (error);
    1146           0 :         error = copyout(&fh, SCARG(uap, fhp), sizeof(fh));
    1147           0 :         return (error);
    1148           0 : }
    1149             : 
    1150             : /*
    1151             :  * Open a file given a file handle.
    1152             :  *
    1153             :  * Check permissions, allocate an open file structure,
    1154             :  * and call the device open routine if any.
    1155             :  */
    1156             : int
    1157           0 : sys_fhopen(struct proc *p, void *v, register_t *retval)
    1158             : {
    1159             :         struct sys_fhopen_args /* {
    1160             :                 syscallarg(const fhandle_t *) fhp;
    1161             :                 syscallarg(int) flags;
    1162           0 :         } */ *uap = v;
    1163           0 :         struct filedesc *fdp = p->p_fd;
    1164           0 :         struct file *fp;
    1165           0 :         struct vnode *vp = NULL;
    1166             :         struct mount *mp;
    1167           0 :         struct ucred *cred = p->p_ucred;
    1168             :         int flags, cloexec;
    1169           0 :         int type, indx, error=0;
    1170           0 :         struct flock lf;
    1171           0 :         struct vattr va;
    1172           0 :         fhandle_t fh;
    1173             : 
    1174             :         /*
    1175             :          * Must be super user
    1176             :          */
    1177           0 :         if ((error = suser(p)))
    1178           0 :                 return (error);
    1179             : 
    1180           0 :         flags = FFLAGS(SCARG(uap, flags));
    1181           0 :         if ((flags & (FREAD | FWRITE)) == 0)
    1182           0 :                 return (EINVAL);
    1183           0 :         if ((flags & O_CREAT))
    1184           0 :                 return (EINVAL);
    1185             : 
    1186           0 :         cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0;
    1187             : 
    1188           0 :         fdplock(fdp);
    1189           0 :         if ((error = falloc(p, &fp, &indx)) != 0) {
    1190           0 :                 fp = NULL;
    1191           0 :                 goto bad;
    1192             :         }
    1193             : 
    1194           0 :         if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
    1195             :                 goto bad;
    1196             : 
    1197           0 :         if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
    1198             :                 error = ESTALE;
    1199           0 :                 goto bad;
    1200             :         }
    1201             : 
    1202           0 :         if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
    1203           0 :                 vp = NULL;      /* most likely unnecessary sanity for bad: */
    1204           0 :                 goto bad;
    1205             :         }
    1206             : 
    1207             :         /* Now do an effective vn_open */
    1208             : 
    1209           0 :         if (vp->v_type == VSOCK) {
    1210             :                 error = EOPNOTSUPP;
    1211           0 :                 goto bad;
    1212             :         }
    1213           0 :         if ((flags & O_DIRECTORY) && vp->v_type != VDIR) {
    1214             :                 error = ENOTDIR;
    1215           0 :                 goto bad;
    1216             :         }
    1217           0 :         if (flags & FREAD) {
    1218           0 :                 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
    1219             :                         goto bad;
    1220             :         }
    1221           0 :         if (flags & (FWRITE | O_TRUNC)) {
    1222           0 :                 if (vp->v_type == VDIR) {
    1223             :                         error = EISDIR;
    1224           0 :                         goto bad;
    1225             :                 }
    1226           0 :                 if ((error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0 ||
    1227           0 :                     (error = vn_writechk(vp)) != 0)
    1228             :                         goto bad;
    1229             :         }
    1230           0 :         if (flags & O_TRUNC) {
    1231           0 :                 VATTR_NULL(&va);
    1232           0 :                 va.va_size = 0;
    1233           0 :                 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
    1234             :                         goto bad;
    1235             :         }
    1236           0 :         if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
    1237             :                 goto bad;
    1238           0 :         if (flags & FWRITE)
    1239           0 :                 vp->v_writecount++;
    1240             : 
    1241             :         /* done with modified vn_open, now finish what sys_open does. */
    1242             : 
    1243           0 :         fp->f_flag = flags & FMASK;
    1244           0 :         fp->f_type = DTYPE_VNODE;
    1245           0 :         fp->f_ops = &vnops;
    1246           0 :         fp->f_data = vp;
    1247           0 :         if (flags & (O_EXLOCK | O_SHLOCK)) {
    1248           0 :                 lf.l_whence = SEEK_SET;
    1249           0 :                 lf.l_start = 0;
    1250           0 :                 lf.l_len = 0;
    1251           0 :                 if (flags & O_EXLOCK)
    1252           0 :                         lf.l_type = F_WRLCK;
    1253             :                 else
    1254           0 :                         lf.l_type = F_RDLCK;
    1255             :                 type = F_FLOCK;
    1256           0 :                 if ((flags & FNONBLOCK) == 0)
    1257           0 :                         type |= F_WAIT;
    1258           0 :                 VOP_UNLOCK(vp);
    1259           0 :                 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
    1260           0 :                 if (error) {
    1261           0 :                         vp = NULL;      /* closef will vn_close the file */
    1262           0 :                         goto bad;
    1263             :                 }
    1264           0 :                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    1265           0 :                 fp->f_iflags |= FIF_HASLOCK;
    1266           0 :         }
    1267           0 :         VOP_UNLOCK(vp);
    1268           0 :         *retval = indx;
    1269           0 :         fdinsert(fdp, indx, cloexec, fp);
    1270           0 :         fdpunlock(fdp);
    1271           0 :         FRELE(fp, p);
    1272           0 :         return (0);
    1273             : 
    1274             : bad:
    1275           0 :         if (fp) {
    1276           0 :                 fdremove(fdp, indx);
    1277           0 :                 closef(fp, p);
    1278           0 :                 if (vp != NULL)
    1279           0 :                         vput(vp);
    1280             :         }
    1281           0 :         fdpunlock(fdp);
    1282           0 :         return (error);
    1283           0 : }
    1284             : 
    1285             : int
    1286           0 : sys_fhstat(struct proc *p, void *v, register_t *retval)
    1287             : {
    1288             :         struct sys_fhstat_args /* {
    1289             :                 syscallarg(const fhandle_t *) fhp;
    1290             :                 syscallarg(struct stat *) sb;
    1291           0 :         } */ *uap = v;
    1292           0 :         struct stat sb;
    1293             :         int error;
    1294           0 :         fhandle_t fh;
    1295             :         struct mount *mp;
    1296           0 :         struct vnode *vp;
    1297             : 
    1298             :         /*
    1299             :          * Must be super user
    1300             :          */
    1301           0 :         if ((error = suser(p)))
    1302           0 :                 return (error);
    1303             : 
    1304           0 :         if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
    1305           0 :                 return (error);
    1306             : 
    1307           0 :         if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
    1308           0 :                 return (ESTALE);
    1309           0 :         if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
    1310           0 :                 return (error);
    1311           0 :         error = vn_stat(vp, &sb, p);
    1312           0 :         vput(vp);
    1313           0 :         if (error)
    1314           0 :                 return (error);
    1315           0 :         error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
    1316           0 :         return (error);
    1317           0 : }
    1318             : 
    1319             : int
    1320           0 : sys_fhstatfs(struct proc *p, void *v, register_t *retval)
    1321             : {
    1322             :         struct sys_fhstatfs_args /* {
    1323             :                 syscallarg(const fhandle_t *) fhp;
    1324             :                 syscallarg(struct statfs *) buf;
    1325           0 :         } */ *uap = v;
    1326             :         struct statfs *sp;
    1327           0 :         fhandle_t fh;
    1328             :         struct mount *mp;
    1329           0 :         struct vnode *vp;
    1330             :         int error;
    1331             : 
    1332             :         /*
    1333             :          * Must be super user
    1334             :          */
    1335           0 :         if ((error = suser(p)))
    1336           0 :                 return (error);
    1337             : 
    1338           0 :         if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
    1339           0 :                 return (error);
    1340             : 
    1341           0 :         if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
    1342           0 :                 return (ESTALE);
    1343           0 :         if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
    1344           0 :                 return (error);
    1345           0 :         mp = vp->v_mount;
    1346           0 :         sp = &mp->mnt_stat;
    1347           0 :         vput(vp);
    1348           0 :         if ((error = VFS_STATFS(mp, sp, p)) != 0)
    1349           0 :                 return (error);
    1350           0 :         sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
    1351           0 :         return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
    1352           0 : }
    1353             : 
    1354             : /*
    1355             :  * Create a special file or named pipe.
    1356             :  */
    1357             : int
    1358           0 : sys_mknod(struct proc *p, void *v, register_t *retval)
    1359             : {
    1360             :         struct sys_mknod_args /* {
    1361             :                 syscallarg(const char *) path;
    1362             :                 syscallarg(mode_t) mode;
    1363             :                 syscallarg(int) dev;
    1364           0 :         } */ *uap = v;
    1365             : 
    1366           0 :         return (domknodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
    1367           0 :             SCARG(uap, dev)));
    1368             : }
    1369             : 
    1370             : int
    1371           0 : sys_mknodat(struct proc *p, void *v, register_t *retval)
    1372             : {
    1373             :         struct sys_mknodat_args /* {
    1374             :                 syscallarg(int) fd;
    1375             :                 syscallarg(const char *) path;
    1376             :                 syscallarg(mode_t) mode;
    1377             :                 syscallarg(dev_t) dev;
    1378           0 :         } */ *uap = v;
    1379             : 
    1380           0 :         return (domknodat(p, SCARG(uap, fd), SCARG(uap, path),
    1381           0 :             SCARG(uap, mode), SCARG(uap, dev)));
    1382             : }
    1383             : 
    1384             : int
    1385           0 : domknodat(struct proc *p, int fd, const char *path, mode_t mode, dev_t dev)
    1386             : {
    1387             :         struct vnode *vp;
    1388           0 :         struct vattr vattr;
    1389             :         int error;
    1390           0 :         struct nameidata nd;
    1391             : 
    1392           0 :         if (dev == VNOVAL)
    1393           0 :                 return (EINVAL);
    1394           0 :         NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, path, p);
    1395           0 :         nd.ni_pledge = PLEDGE_DPATH;
    1396           0 :         nd.ni_unveil = UNVEIL_CREATE;
    1397           0 :         if ((error = namei(&nd)) != 0)
    1398           0 :                 return (error);
    1399           0 :         vp = nd.ni_vp;
    1400           0 :         if (!S_ISFIFO(mode) || dev != 0) {
    1401           0 :                 if ((nd.ni_dvp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
    1402           0 :                     (error = suser(p)) != 0)
    1403             :                         goto out;
    1404           0 :                 if (p->p_fd->fd_rdir) {
    1405             :                         error = EINVAL;
    1406           0 :                         goto out;
    1407             :                 }
    1408             :         }
    1409           0 :         if (vp != NULL)
    1410           0 :                 error = EEXIST;
    1411             :         else {
    1412           0 :                 VATTR_NULL(&vattr);
    1413           0 :                 vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
    1414           0 :                 if ((p->p_p->ps_flags & PS_PLEDGE))
    1415           0 :                         vattr.va_mode &= ACCESSPERMS;
    1416           0 :                 vattr.va_rdev = dev;
    1417             : 
    1418           0 :                 switch (mode & S_IFMT) {
    1419             :                 case S_IFMT:    /* used by badsect to flag bad sectors */
    1420           0 :                         vattr.va_type = VBAD;
    1421           0 :                         break;
    1422             :                 case S_IFCHR:
    1423           0 :                         vattr.va_type = VCHR;
    1424           0 :                         break;
    1425             :                 case S_IFBLK:
    1426           0 :                         vattr.va_type = VBLK;
    1427           0 :                         break;
    1428             :                 case S_IFIFO:
    1429             : #ifndef FIFO
    1430             :                         error = EOPNOTSUPP;
    1431             :                         break;
    1432             : #else
    1433           0 :                         if (dev == 0) {
    1434           0 :                                 vattr.va_type = VFIFO;
    1435           0 :                                 break;
    1436             :                         }
    1437             :                         /* FALLTHROUGH */
    1438             : #endif /* FIFO */
    1439             :                 default:
    1440             :                         error = EINVAL;
    1441           0 :                         break;
    1442             :                 }
    1443             :         }
    1444             : out:
    1445           0 :         if (!error) {
    1446           0 :                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
    1447           0 :                 vput(nd.ni_dvp);
    1448           0 :         } else {
    1449           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    1450           0 :                 if (nd.ni_dvp == vp)
    1451           0 :                         vrele(nd.ni_dvp);
    1452             :                 else
    1453           0 :                         vput(nd.ni_dvp);
    1454           0 :                 if (vp)
    1455           0 :                         vrele(vp);
    1456             :         }
    1457           0 :         return (error);
    1458           0 : }
    1459             : 
    1460             : /*
    1461             :  * Create a named pipe.
    1462             :  */
    1463             : int
    1464           0 : sys_mkfifo(struct proc *p, void *v, register_t *retval)
    1465             : {
    1466             :         struct sys_mkfifo_args /* {
    1467             :                 syscallarg(const char *) path;
    1468             :                 syscallarg(mode_t) mode;
    1469           0 :         } */ *uap = v;
    1470             : 
    1471           0 :         return (domknodat(p, AT_FDCWD, SCARG(uap, path),
    1472           0 :             (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0));
    1473             : }
    1474             : 
    1475             : int
    1476           0 : sys_mkfifoat(struct proc *p, void *v, register_t *retval)
    1477             : {
    1478             :         struct sys_mkfifoat_args /* {
    1479             :                 syscallarg(int) fd;
    1480             :                 syscallarg(const char *) path;
    1481             :                 syscallarg(mode_t) mode;
    1482           0 :         } */ *uap = v;
    1483             : 
    1484           0 :         return (domknodat(p, SCARG(uap, fd), SCARG(uap, path),
    1485           0 :             (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0));
    1486             : }
    1487             : 
    1488             : /*
    1489             :  * Make a hard file link.
    1490             :  */
    1491             : int
    1492           0 : sys_link(struct proc *p, void *v, register_t *retval)
    1493             : {
    1494             :         struct sys_link_args /* {
    1495             :                 syscallarg(const char *) path;
    1496             :                 syscallarg(const char *) link;
    1497           0 :         } */ *uap = v;
    1498             : 
    1499           0 :         return (dolinkat(p, AT_FDCWD, SCARG(uap, path), AT_FDCWD,
    1500           0 :             SCARG(uap, link), AT_SYMLINK_FOLLOW));
    1501             : }
    1502             : 
    1503             : int
    1504           0 : sys_linkat(struct proc *p, void *v, register_t *retval)
    1505             : {
    1506             :         struct sys_linkat_args /* {
    1507             :                 syscallarg(int) fd1;
    1508             :                 syscallarg(const char *) path1;
    1509             :                 syscallarg(int) fd2;
    1510             :                 syscallarg(const char *) path2;
    1511             :                 syscallarg(int) flag;
    1512           0 :         } */ *uap = v;
    1513             : 
    1514           0 :         return (dolinkat(p, SCARG(uap, fd1), SCARG(uap, path1),
    1515           0 :             SCARG(uap, fd2), SCARG(uap, path2), SCARG(uap, flag)));
    1516             : }
    1517             : 
    1518             : int
    1519           0 : dolinkat(struct proc *p, int fd1, const char *path1, int fd2,
    1520             :     const char *path2, int flag)
    1521             : {
    1522             :         struct vnode *vp;
    1523           0 :         struct nameidata nd;
    1524             :         int error, follow;
    1525             :         int flags;
    1526             : 
    1527           0 :         if (flag & ~AT_SYMLINK_FOLLOW)
    1528           0 :                 return (EINVAL);
    1529             : 
    1530           0 :         follow = (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW;
    1531           0 :         NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd1, path1, p);
    1532           0 :         nd.ni_pledge = PLEDGE_RPATH;
    1533           0 :         nd.ni_unveil = UNVEIL_READ;
    1534           0 :         if ((error = namei(&nd)) != 0)
    1535           0 :                 return (error);
    1536           0 :         vp = nd.ni_vp;
    1537             : 
    1538             :         flags = LOCKPARENT;
    1539           0 :         if (vp->v_type == VDIR) {
    1540             :                 flags |= STRIPSLASHES;
    1541           0 :         }
    1542             : 
    1543           0 :         NDINITAT(&nd, CREATE, flags, UIO_USERSPACE, fd2, path2, p);
    1544           0 :         nd.ni_pledge = PLEDGE_CPATH;
    1545           0 :         nd.ni_unveil = UNVEIL_CREATE;
    1546           0 :         if ((error = namei(&nd)) != 0)
    1547             :                 goto out;
    1548           0 :         if (nd.ni_vp) {
    1549           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    1550           0 :                 if (nd.ni_dvp == nd.ni_vp)
    1551           0 :                         vrele(nd.ni_dvp);
    1552             :                 else
    1553           0 :                         vput(nd.ni_dvp);
    1554           0 :                 vrele(nd.ni_vp);
    1555             :                 error = EEXIST;
    1556           0 :                 goto out;
    1557             :         }
    1558           0 :         error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
    1559             : out:
    1560           0 :         vrele(vp);
    1561           0 :         return (error);
    1562           0 : }
    1563             : 
    1564             : /*
    1565             :  * Make a symbolic link.
    1566             :  */
    1567             : int
    1568           0 : sys_symlink(struct proc *p, void *v, register_t *retval)
    1569             : {
    1570             :         struct sys_symlink_args /* {
    1571             :                 syscallarg(const char *) path;
    1572             :                 syscallarg(const char *) link;
    1573           0 :         } */ *uap = v;
    1574             : 
    1575           0 :         return (dosymlinkat(p, SCARG(uap, path), AT_FDCWD, SCARG(uap, link)));
    1576             : }
    1577             : 
    1578             : int
    1579           0 : sys_symlinkat(struct proc *p, void *v, register_t *retval)
    1580             : {
    1581             :         struct sys_symlinkat_args /* {
    1582             :                 syscallarg(const char *) path;
    1583             :                 syscallarg(int) fd;
    1584             :                 syscallarg(const char *) link;
    1585           0 :         } */ *uap = v;
    1586             : 
    1587           0 :         return (dosymlinkat(p, SCARG(uap, path), SCARG(uap, fd),
    1588           0 :             SCARG(uap, link)));
    1589             : }
    1590             : 
    1591             : int
    1592           0 : dosymlinkat(struct proc *p, const char *upath, int fd, const char *link)
    1593             : {
    1594           0 :         struct vattr vattr;
    1595             :         char *path;
    1596             :         int error;
    1597           0 :         struct nameidata nd;
    1598             : 
    1599           0 :         path = pool_get(&namei_pool, PR_WAITOK);
    1600           0 :         error = copyinstr(upath, path, MAXPATHLEN, NULL);
    1601           0 :         if (error)
    1602             :                 goto out;
    1603           0 :         NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, link, p);
    1604           0 :         nd.ni_pledge = PLEDGE_CPATH;
    1605           0 :         nd.ni_unveil = UNVEIL_CREATE;
    1606           0 :         if ((error = namei(&nd)) != 0)
    1607             :                 goto out;
    1608           0 :         if (nd.ni_vp) {
    1609           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    1610           0 :                 if (nd.ni_dvp == nd.ni_vp)
    1611           0 :                         vrele(nd.ni_dvp);
    1612             :                 else
    1613           0 :                         vput(nd.ni_dvp);
    1614           0 :                 vrele(nd.ni_vp);
    1615             :                 error = EEXIST;
    1616           0 :                 goto out;
    1617             :         }
    1618           0 :         VATTR_NULL(&vattr);
    1619           0 :         vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
    1620           0 :         error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
    1621             : out:
    1622           0 :         pool_put(&namei_pool, path);
    1623           0 :         return (error);
    1624           0 : }
    1625             : 
    1626             : /*
    1627             :  * Delete a name from the filesystem.
    1628             :  */
    1629             : int
    1630           0 : sys_unlink(struct proc *p, void *v, register_t *retval)
    1631             : {
    1632             :         struct sys_unlink_args /* {
    1633             :                 syscallarg(const char *) path;
    1634           0 :         } */ *uap = v;
    1635             : 
    1636           0 :         return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), 0));
    1637             : }
    1638             : 
    1639             : int
    1640           0 : sys_unlinkat(struct proc *p, void *v, register_t *retval)
    1641             : {
    1642             :         struct sys_unlinkat_args /* {
    1643             :                 syscallarg(int) fd;
    1644             :                 syscallarg(const char *) path;
    1645             :                 syscallarg(int) flag;
    1646           0 :         } */ *uap = v;
    1647             : 
    1648           0 :         return (dounlinkat(p, SCARG(uap, fd), SCARG(uap, path),
    1649           0 :             SCARG(uap, flag)));
    1650             : }
    1651             : 
    1652             : int
    1653           0 : dounlinkat(struct proc *p, int fd, const char *path, int flag)
    1654             : {
    1655             :         struct vnode *vp;
    1656             :         int error;
    1657           0 :         struct nameidata nd;
    1658             : 
    1659           0 :         if (flag & ~AT_REMOVEDIR)
    1660           0 :                 return (EINVAL);
    1661             : 
    1662           0 :         NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
    1663             :             fd, path, p);
    1664           0 :         nd.ni_pledge = PLEDGE_CPATH;
    1665           0 :         nd.ni_unveil = UNVEIL_CREATE;
    1666           0 :         if ((error = namei(&nd)) != 0)
    1667           0 :                 return (error);
    1668           0 :         vp = nd.ni_vp;
    1669             : 
    1670           0 :         if (flag & AT_REMOVEDIR) {
    1671           0 :                 if (vp->v_type != VDIR) {
    1672             :                         error = ENOTDIR;
    1673           0 :                         goto out;
    1674             :                 }
    1675             :                 /*
    1676             :                  * No rmdir "." please.
    1677             :                  */
    1678           0 :                 if (nd.ni_dvp == vp) {
    1679             :                         error = EINVAL;
    1680           0 :                         goto out;
    1681             :                 }
    1682             :                 /*
    1683             :                  * A mounted on directory cannot be deleted.
    1684             :                  */
    1685           0 :                 if (vp->v_mountedhere != NULL) {
    1686             :                         error = EBUSY;
    1687           0 :                         goto out;
    1688             :                 }
    1689             :         }
    1690             : 
    1691             :         /*
    1692             :          * The root of a mounted filesystem cannot be deleted.
    1693             :          */
    1694           0 :         if (vp->v_flag & VROOT)
    1695           0 :                 error = EBUSY;
    1696             : out:
    1697           0 :         if (!error) {
    1698           0 :                 if (flag & AT_REMOVEDIR) {
    1699           0 :                         error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
    1700           0 :                 } else {
    1701           0 :                         (void)uvm_vnp_uncache(vp);
    1702           0 :                         error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
    1703             :                 }
    1704             :         } else {
    1705           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    1706           0 :                 if (nd.ni_dvp == vp)
    1707           0 :                         vrele(nd.ni_dvp);
    1708             :                 else
    1709           0 :                         vput(nd.ni_dvp);
    1710           0 :                 vput(vp);
    1711             :         }
    1712           0 :         return (error);
    1713           0 : }
    1714             : 
    1715             : /*
    1716             :  * Reposition read/write file offset.
    1717             :  */
    1718             : int
    1719           0 : sys_lseek(struct proc *p, void *v, register_t *retval)
    1720             : {
    1721             :         struct sys_lseek_args /* {
    1722             :                 syscallarg(int) fd;
    1723             :                 syscallarg(int) pad;
    1724             :                 syscallarg(off_t) offset;
    1725             :                 syscallarg(int) whence;
    1726           0 :         } */ *uap = v;
    1727           0 :         struct filedesc *fdp = p->p_fd;
    1728             :         struct file *fp;
    1729           0 :         off_t offset;
    1730             :         int error;
    1731             : 
    1732           0 :         if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
    1733           0 :                 return (EBADF);
    1734           0 :         if (fp->f_ops->fo_seek == NULL) {
    1735             :                 error = ESPIPE;
    1736           0 :                 goto bad;
    1737             :         }
    1738           0 :         offset = SCARG(uap, offset);
    1739             : 
    1740           0 :         error = (*fp->f_ops->fo_seek)(fp, &offset, SCARG(uap, whence), p);
    1741           0 :         if (error)
    1742             :                 goto bad;
    1743             : 
    1744           0 :         *(off_t *)retval = offset;
    1745           0 :         mtx_enter(&fp->f_mtx);
    1746           0 :         fp->f_seek++;
    1747           0 :         mtx_leave(&fp->f_mtx);
    1748           0 :         error = 0;
    1749             :  bad:
    1750           0 :         FRELE(fp, p);
    1751           0 :         return (error);
    1752           0 : }
    1753             : 
    1754             : /*
    1755             :  * Check access permissions.
    1756             :  */
    1757             : int
    1758           0 : sys_access(struct proc *p, void *v, register_t *retval)
    1759             : {
    1760             :         struct sys_access_args /* {
    1761             :                 syscallarg(const char *) path;
    1762             :                 syscallarg(int) amode;
    1763           0 :         } */ *uap = v;
    1764             : 
    1765           0 :         return (dofaccessat(p, AT_FDCWD, SCARG(uap, path),
    1766           0 :             SCARG(uap, amode), 0));
    1767             : }
    1768             : 
    1769             : int
    1770           0 : sys_faccessat(struct proc *p, void *v, register_t *retval)
    1771             : {
    1772             :         struct sys_faccessat_args /* {
    1773             :                 syscallarg(int) fd;
    1774             :                 syscallarg(const char *) path;
    1775             :                 syscallarg(int) amode;
    1776             :                 syscallarg(int) flag;
    1777           0 :         } */ *uap = v;
    1778             : 
    1779           0 :         return (dofaccessat(p, SCARG(uap, fd), SCARG(uap, path),
    1780           0 :             SCARG(uap, amode), SCARG(uap, flag)));
    1781             : }
    1782             : 
    1783             : int
    1784           0 : dofaccessat(struct proc *p, int fd, const char *path, int amode, int flag)
    1785             : {
    1786             :         struct vnode *vp;
    1787             :         struct ucred *newcred, *oldcred;
    1788           0 :         struct nameidata nd;
    1789             :         int error;
    1790             : 
    1791           0 :         if (amode & ~(R_OK | W_OK | X_OK))
    1792           0 :                 return (EINVAL);
    1793           0 :         if (flag & ~AT_EACCESS)
    1794           0 :                 return (EINVAL);
    1795             : 
    1796             :         newcred = NULL;
    1797           0 :         oldcred = p->p_ucred;
    1798             : 
    1799             :         /*
    1800             :          * If access as real ids was requested and they really differ,
    1801             :          * give the thread new creds with them reset
    1802             :          */
    1803           0 :         if ((flag & AT_EACCESS) == 0 &&
    1804           0 :             (oldcred->cr_uid != oldcred->cr_ruid ||
    1805           0 :             (oldcred->cr_gid != oldcred->cr_rgid))) {
    1806           0 :                 p->p_ucred = newcred = crdup(oldcred);
    1807           0 :                 newcred->cr_uid = newcred->cr_ruid;
    1808           0 :                 newcred->cr_gid = newcred->cr_rgid;
    1809           0 :         }
    1810             : 
    1811           0 :         NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
    1812           0 :         nd.ni_pledge = PLEDGE_RPATH;
    1813           0 :         nd.ni_unveil = UNVEIL_INSPECT;
    1814           0 :         if ((error = namei(&nd)) != 0)
    1815             :                 goto out;
    1816           0 :         vp = nd.ni_vp;
    1817             : 
    1818             :         /* Flags == 0 means only check for existence. */
    1819           0 :         if (amode) {
    1820             :                 int vflags = 0;
    1821             : 
    1822           0 :                 if (amode & R_OK)
    1823           0 :                         vflags |= VREAD;
    1824           0 :                 if (amode & W_OK)
    1825           0 :                         vflags |= VWRITE;
    1826           0 :                 if (amode & X_OK)
    1827           0 :                         vflags |= VEXEC;
    1828             : 
    1829           0 :                 error = VOP_ACCESS(vp, vflags, p->p_ucred, p);
    1830           0 :                 if (!error && (vflags & VWRITE))
    1831           0 :                         error = vn_writechk(vp);
    1832           0 :         }
    1833           0 :         vput(vp);
    1834             : out:
    1835           0 :         if (newcred != NULL) {
    1836           0 :                 p->p_ucred = oldcred;
    1837           0 :                 crfree(newcred);
    1838           0 :         }
    1839           0 :         return (error);
    1840           0 : }
    1841             : 
    1842             : /*
    1843             :  * Get file status; this version follows links.
    1844             :  */
    1845             : int
    1846           0 : sys_stat(struct proc *p, void *v, register_t *retval)
    1847             : {
    1848             :         struct sys_stat_args /* {
    1849             :                 syscallarg(const char *) path;
    1850             :                 syscallarg(struct stat *) ub;
    1851           0 :         } */ *uap = v;
    1852             : 
    1853           0 :         return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub), 0));
    1854             : }
    1855             : 
    1856             : int
    1857           0 : sys_fstatat(struct proc *p, void *v, register_t *retval)
    1858             : {
    1859             :         struct sys_fstatat_args /* {
    1860             :                 syscallarg(int) fd;
    1861             :                 syscallarg(const char *) path;
    1862             :                 syscallarg(struct stat *) buf;
    1863             :                 syscallarg(int) flag;
    1864           0 :         } */ *uap = v;
    1865             : 
    1866           0 :         return (dofstatat(p, SCARG(uap, fd), SCARG(uap, path),
    1867           0 :             SCARG(uap, buf), SCARG(uap, flag)));
    1868             : }
    1869             : 
    1870             : int
    1871           0 : dofstatat(struct proc *p, int fd, const char *path, struct stat *buf, int flag)
    1872             : {
    1873           0 :         struct stat sb;
    1874             :         int error, follow;
    1875           0 :         struct nameidata nd;
    1876             : 
    1877           0 :         if (flag & ~AT_SYMLINK_NOFOLLOW)
    1878           0 :                 return (EINVAL);
    1879             : 
    1880             : 
    1881           0 :         follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
    1882           0 :         NDINITAT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fd, path, p);
    1883           0 :         nd.ni_pledge = PLEDGE_RPATH;
    1884           0 :         nd.ni_unveil = UNVEIL_INSPECT;
    1885           0 :         if ((error = namei(&nd)) != 0)
    1886           0 :                 return (error);
    1887           0 :         error = vn_stat(nd.ni_vp, &sb, p);
    1888           0 :         vput(nd.ni_vp);
    1889           0 :         if (error)
    1890           0 :                 return (error);
    1891           0 :         if (nd.ni_pledge & PLEDGE_STATLIE) {
    1892           0 :                 if (S_ISDIR(sb.st_mode) || S_ISLNK(sb.st_mode)) {
    1893           0 :                         if (sb.st_uid >= 1000) {
    1894           0 :                                 sb.st_uid = p->p_ucred->cr_uid;
    1895           0 :                                 sb.st_gid = p->p_ucred->cr_gid;;
    1896           0 :                         }
    1897           0 :                         sb.st_gen = 0;
    1898             :                 } else
    1899           0 :                         return (ENOENT);
    1900           0 :         }
    1901             :         /* Don't let non-root see generation numbers (for NFS security) */
    1902           0 :         if (suser(p))
    1903           0 :                 sb.st_gen = 0;
    1904           0 :         error = copyout(&sb, buf, sizeof(sb));
    1905             : #ifdef KTRACE
    1906           0 :         if (error == 0 && KTRPOINT(p, KTR_STRUCT))
    1907           0 :                 ktrstat(p, &sb);
    1908             : #endif
    1909           0 :         return (error);
    1910           0 : }
    1911             : 
    1912             : /*
    1913             :  * Get file status; this version does not follow links.
    1914             :  */
    1915             : int
    1916           0 : sys_lstat(struct proc *p, void *v, register_t *retval)
    1917             : {
    1918             :         struct sys_lstat_args /* {
    1919             :                 syscallarg(const char *) path;
    1920             :                 syscallarg(struct stat *) ub;
    1921           0 :         } */ *uap = v;
    1922             : 
    1923           0 :         return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub),
    1924             :             AT_SYMLINK_NOFOLLOW));
    1925             : }
    1926             : 
    1927             : /*
    1928             :  * Get configurable pathname variables.
    1929             :  */
    1930             : int
    1931           0 : sys_pathconf(struct proc *p, void *v, register_t *retval)
    1932             : {
    1933             :         struct sys_pathconf_args /* {
    1934             :                 syscallarg(const char *) path;
    1935             :                 syscallarg(int) name;
    1936           0 :         } */ *uap = v;
    1937             :         int error;
    1938           0 :         struct nameidata nd;
    1939             : 
    1940           0 :         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
    1941             :             SCARG(uap, path), p);
    1942           0 :         nd.ni_pledge = PLEDGE_RPATH;
    1943           0 :         nd.ni_unveil = UNVEIL_READ;
    1944           0 :         if ((error = namei(&nd)) != 0)
    1945           0 :                 return (error);
    1946           0 :         error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
    1947           0 :         vput(nd.ni_vp);
    1948           0 :         return (error);
    1949           0 : }
    1950             : 
    1951             : /*
    1952             :  * Return target name of a symbolic link.
    1953             :  */
    1954             : int
    1955           0 : sys_readlink(struct proc *p, void *v, register_t *retval)
    1956             : {
    1957             :         struct sys_readlink_args /* {
    1958             :                 syscallarg(const char *) path;
    1959             :                 syscallarg(char *) buf;
    1960             :                 syscallarg(size_t) count;
    1961           0 :         } */ *uap = v;
    1962             : 
    1963           0 :         return (doreadlinkat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, buf),
    1964           0 :             SCARG(uap, count), retval));
    1965             : }
    1966             : 
    1967             : int
    1968           0 : sys_readlinkat(struct proc *p, void *v, register_t *retval)
    1969             : {
    1970             :         struct sys_readlinkat_args /* {
    1971             :                 syscallarg(int) fd;
    1972             :                 syscallarg(const char *) path;
    1973             :                 syscallarg(char *) buf;
    1974             :                 syscallarg(size_t) count;
    1975           0 :         } */ *uap = v;
    1976             : 
    1977           0 :         return (doreadlinkat(p, SCARG(uap, fd), SCARG(uap, path),
    1978           0 :             SCARG(uap, buf), SCARG(uap, count), retval));
    1979             : }
    1980             : 
    1981             : int
    1982           0 : doreadlinkat(struct proc *p, int fd, const char *path, char *buf,
    1983             :     size_t count, register_t *retval)
    1984             : {
    1985             :         struct vnode *vp;
    1986           0 :         struct iovec aiov;
    1987           0 :         struct uio auio;
    1988             :         int error;
    1989           0 :         struct nameidata nd;
    1990             : 
    1991           0 :         NDINITAT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
    1992           0 :         nd.ni_pledge = PLEDGE_RPATH;
    1993           0 :         nd.ni_unveil = UNVEIL_INSPECT;
    1994           0 :         if ((error = namei(&nd)) != 0)
    1995           0 :                 return (error);
    1996           0 :         vp = nd.ni_vp;
    1997           0 :         if (vp->v_type != VLNK)
    1998           0 :                 error = EINVAL;
    1999             :         else {
    2000           0 :                 aiov.iov_base = buf;
    2001           0 :                 aiov.iov_len = count;
    2002           0 :                 auio.uio_iov = &aiov;
    2003           0 :                 auio.uio_iovcnt = 1;
    2004           0 :                 auio.uio_offset = 0;
    2005           0 :                 auio.uio_rw = UIO_READ;
    2006           0 :                 auio.uio_segflg = UIO_USERSPACE;
    2007           0 :                 auio.uio_procp = p;
    2008           0 :                 auio.uio_resid = count;
    2009           0 :                 error = VOP_READLINK(vp, &auio, p->p_ucred);
    2010           0 :                 *retval = count - auio.uio_resid;
    2011             :         }
    2012           0 :         vput(vp);
    2013           0 :         return (error);
    2014           0 : }
    2015             : 
    2016             : /*
    2017             :  * Change flags of a file given a path name.
    2018             :  */
    2019             : int
    2020           0 : sys_chflags(struct proc *p, void *v, register_t *retval)
    2021             : {
    2022             :         struct sys_chflags_args /* {
    2023             :                 syscallarg(const char *) path;
    2024             :                 syscallarg(u_int) flags;
    2025           0 :         } */ *uap = v;
    2026             : 
    2027           0 :         return (dochflagsat(p, AT_FDCWD, SCARG(uap, path),
    2028           0 :             SCARG(uap, flags), 0));
    2029             : }
    2030             : 
    2031             : int
    2032           0 : sys_chflagsat(struct proc *p, void *v, register_t *retval)
    2033             : {
    2034             :         struct sys_chflagsat_args /* {
    2035             :                 syscallarg(int) fd;
    2036             :                 syscallarg(const char *) path;
    2037             :                 syscallarg(u_int) flags;
    2038             :                 syscallarg(int) atflags;
    2039           0 :         } */ *uap = v;
    2040             : 
    2041           0 :         return (dochflagsat(p, SCARG(uap, fd), SCARG(uap, path),
    2042           0 :             SCARG(uap, flags), SCARG(uap, atflags)));
    2043             : }
    2044             : 
    2045             : int
    2046           0 : dochflagsat(struct proc *p, int fd, const char *path, u_int flags, int atflags)
    2047             : {
    2048           0 :         struct nameidata nd;
    2049             :         int error, follow;
    2050             : 
    2051           0 :         if (atflags & ~AT_SYMLINK_NOFOLLOW)
    2052           0 :                 return (EINVAL);
    2053             : 
    2054           0 :         follow = (atflags & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
    2055           0 :         NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
    2056           0 :         nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
    2057           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2058           0 :         if ((error = namei(&nd)) != 0)
    2059           0 :                 return (error);
    2060           0 :         return (dovchflags(p, nd.ni_vp, flags));
    2061           0 : }
    2062             : 
    2063             : /*
    2064             :  * Change flags of a file given a file descriptor.
    2065             :  */
    2066             : int
    2067           0 : sys_fchflags(struct proc *p, void *v, register_t *retval)
    2068             : {
    2069             :         struct sys_fchflags_args /* {
    2070             :                 syscallarg(int) fd;
    2071             :                 syscallarg(u_int) flags;
    2072           0 :         } */ *uap = v;
    2073           0 :         struct file *fp;
    2074             :         struct vnode *vp;
    2075             :         int error;
    2076             : 
    2077           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2078           0 :                 return (error);
    2079           0 :         vp = fp->f_data;
    2080           0 :         vref(vp);
    2081           0 :         FRELE(fp, p);
    2082           0 :         return (dovchflags(p, vp, SCARG(uap, flags)));
    2083           0 : }
    2084             : 
    2085             : int
    2086           0 : dovchflags(struct proc *p, struct vnode *vp, u_int flags)
    2087             : {
    2088           0 :         struct vattr vattr;
    2089             :         int error;
    2090             : 
    2091           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2092           0 :         if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
    2093           0 :                 error = EROFS;
    2094           0 :         else if (flags == VNOVAL)
    2095           0 :                 error = EINVAL;
    2096             :         else {
    2097           0 :                 if (suser(p)) {
    2098           0 :                         if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
    2099           0 :                             != 0)
    2100             :                                 goto out;
    2101           0 :                         if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
    2102             :                                 error = EINVAL;
    2103           0 :                                 goto out;
    2104             :                         }
    2105             :                 }
    2106           0 :                 VATTR_NULL(&vattr);
    2107           0 :                 vattr.va_flags = flags;
    2108           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2109             :         }
    2110             : out:
    2111           0 :         vput(vp);
    2112           0 :         return (error);
    2113           0 : }
    2114             : 
    2115             : /*
    2116             :  * Change mode of a file given path name.
    2117             :  */
    2118             : int
    2119           0 : sys_chmod(struct proc *p, void *v, register_t *retval)
    2120             : {
    2121             :         struct sys_chmod_args /* {
    2122             :                 syscallarg(const char *) path;
    2123             :                 syscallarg(mode_t) mode;
    2124           0 :         } */ *uap = v;
    2125             : 
    2126           0 :         return (dofchmodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), 0));
    2127             : }
    2128             : 
    2129             : int
    2130           0 : sys_fchmodat(struct proc *p, void *v, register_t *retval)
    2131             : {
    2132             :         struct sys_fchmodat_args /* {
    2133             :                 syscallarg(int) fd;
    2134             :                 syscallarg(const char *) path;
    2135             :                 syscallarg(mode_t) mode;
    2136             :                 syscallarg(int) flag;
    2137           0 :         } */ *uap = v;
    2138             : 
    2139           0 :         return (dofchmodat(p, SCARG(uap, fd), SCARG(uap, path),
    2140           0 :             SCARG(uap, mode), SCARG(uap, flag)));
    2141             : }
    2142             : 
    2143             : int
    2144           0 : dofchmodat(struct proc *p, int fd, const char *path, mode_t mode, int flag)
    2145             : {
    2146             :         struct vnode *vp;
    2147           0 :         struct vattr vattr;
    2148             :         int error, follow;
    2149           0 :         struct nameidata nd;
    2150             : 
    2151           0 :         if (mode & ~(S_IFMT | ALLPERMS))
    2152           0 :                 return (EINVAL);
    2153           0 :         if ((p->p_p->ps_flags & PS_PLEDGE))
    2154           0 :                 mode &= ACCESSPERMS;
    2155           0 :         if (flag & ~AT_SYMLINK_NOFOLLOW)
    2156           0 :                 return (EINVAL);
    2157             : 
    2158           0 :         follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
    2159           0 :         NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
    2160           0 :         nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
    2161           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2162           0 :         if ((error = namei(&nd)) != 0)
    2163           0 :                 return (error);
    2164           0 :         vp = nd.ni_vp;
    2165           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2166           0 :         if (vp->v_mount->mnt_flag & MNT_RDONLY)
    2167           0 :                 error = EROFS;
    2168             :         else {
    2169           0 :                 VATTR_NULL(&vattr);
    2170           0 :                 vattr.va_mode = mode & ALLPERMS;
    2171           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2172             :         }
    2173           0 :         vput(vp);
    2174           0 :         return (error);
    2175           0 : }
    2176             : 
    2177             : /*
    2178             :  * Change mode of a file given a file descriptor.
    2179             :  */
    2180             : int
    2181           0 : sys_fchmod(struct proc *p, void *v, register_t *retval)
    2182             : {
    2183             :         struct sys_fchmod_args /* {
    2184             :                 syscallarg(int) fd;
    2185             :                 syscallarg(mode_t) mode;
    2186           0 :         } */ *uap = v;
    2187           0 :         struct vattr vattr;
    2188             :         struct vnode *vp;
    2189           0 :         struct file *fp;
    2190           0 :         mode_t mode = SCARG(uap, mode);
    2191             :         int error;
    2192             : 
    2193           0 :         if (mode & ~(S_IFMT | ALLPERMS))
    2194           0 :                 return (EINVAL);
    2195           0 :         if ((p->p_p->ps_flags & PS_PLEDGE))
    2196           0 :                 mode &= ACCESSPERMS;
    2197             : 
    2198           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2199           0 :                 return (error);
    2200           0 :         vp = fp->f_data;
    2201           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2202           0 :         if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
    2203           0 :                 error = EROFS;
    2204             :         else {
    2205           0 :                 VATTR_NULL(&vattr);
    2206           0 :                 vattr.va_mode = mode & ALLPERMS;
    2207           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2208             :         }
    2209           0 :         VOP_UNLOCK(vp);
    2210           0 :         FRELE(fp, p);
    2211           0 :         return (error);
    2212           0 : }
    2213             : 
    2214             : /*
    2215             :  * Set ownership given a path name.
    2216             :  */
    2217             : int
    2218           0 : sys_chown(struct proc *p, void *v, register_t *retval)
    2219             : {
    2220             :         struct sys_chown_args /* {
    2221             :                 syscallarg(const char *) path;
    2222             :                 syscallarg(uid_t) uid;
    2223             :                 syscallarg(gid_t) gid;
    2224           0 :         } */ *uap = v;
    2225             : 
    2226           0 :         return (dofchownat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, uid),
    2227           0 :             SCARG(uap, gid), 0));
    2228             : }
    2229             : 
    2230             : int
    2231           0 : sys_fchownat(struct proc *p, void *v, register_t *retval)
    2232             : {
    2233             :         struct sys_fchownat_args /* {
    2234             :                 syscallarg(int) fd;
    2235             :                 syscallarg(const char *) path;
    2236             :                 syscallarg(uid_t) uid;
    2237             :                 syscallarg(gid_t) gid;
    2238             :                 syscallarg(int) flag;
    2239           0 :         } */ *uap = v;
    2240             : 
    2241           0 :         return (dofchownat(p, SCARG(uap, fd), SCARG(uap, path),
    2242           0 :             SCARG(uap, uid), SCARG(uap, gid), SCARG(uap, flag)));
    2243             : }
    2244             : 
    2245             : int
    2246           0 : dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid,
    2247             :     int flag)
    2248             : {
    2249             :         struct vnode *vp;
    2250           0 :         struct vattr vattr;
    2251             :         int error, follow;
    2252           0 :         struct nameidata nd;
    2253             :         mode_t mode;
    2254             : 
    2255           0 :         if (flag & ~AT_SYMLINK_NOFOLLOW)
    2256           0 :                 return (EINVAL);
    2257             : 
    2258           0 :         follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
    2259           0 :         NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
    2260           0 :         nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH;
    2261           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2262           0 :         if ((error = namei(&nd)) != 0)
    2263           0 :                 return (error);
    2264           0 :         vp = nd.ni_vp;
    2265           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2266           0 :         if (vp->v_mount->mnt_flag & MNT_RDONLY)
    2267           0 :                 error = EROFS;
    2268             :         else {
    2269           0 :                 if ((error = pledge_chown(p, uid, gid)))
    2270             :                         goto out;
    2271           0 :                 if ((uid != -1 || gid != -1) &&
    2272           0 :                     (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
    2273           0 :                     (suser(p) || suid_clear)) {
    2274           0 :                         error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
    2275           0 :                         if (error)
    2276             :                                 goto out;
    2277           0 :                         mode = vattr.va_mode & ~(VSUID | VSGID);
    2278           0 :                         if (mode == vattr.va_mode)
    2279             :                                 mode = VNOVAL;
    2280           0 :                 } else
    2281             :                         mode = VNOVAL;
    2282           0 :                 VATTR_NULL(&vattr);
    2283           0 :                 vattr.va_uid = uid;
    2284           0 :                 vattr.va_gid = gid;
    2285           0 :                 vattr.va_mode = mode;
    2286           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2287             :         }
    2288             : out:
    2289           0 :         vput(vp);
    2290           0 :         return (error);
    2291           0 : }
    2292             : 
    2293             : /*
    2294             :  * Set ownership given a path name, without following links.
    2295             :  */
    2296             : int
    2297           0 : sys_lchown(struct proc *p, void *v, register_t *retval)
    2298             : {
    2299             :         struct sys_lchown_args /* {
    2300             :                 syscallarg(const char *) path;
    2301             :                 syscallarg(uid_t) uid;
    2302             :                 syscallarg(gid_t) gid;
    2303           0 :         } */ *uap = v;
    2304             :         struct vnode *vp;
    2305           0 :         struct vattr vattr;
    2306             :         int error;
    2307           0 :         struct nameidata nd;
    2308             :         mode_t mode;
    2309           0 :         uid_t uid = SCARG(uap, uid);
    2310           0 :         gid_t gid = SCARG(uap, gid);
    2311             : 
    2312           0 :         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
    2313           0 :         nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH;
    2314           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2315           0 :         if ((error = namei(&nd)) != 0)
    2316           0 :                 return (error);
    2317           0 :         vp = nd.ni_vp;
    2318           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2319           0 :         if (vp->v_mount->mnt_flag & MNT_RDONLY)
    2320           0 :                 error = EROFS;
    2321             :         else {
    2322           0 :                 if ((error = pledge_chown(p, uid, gid)))
    2323             :                         goto out;
    2324           0 :                 if ((uid != -1 || gid != -1) &&
    2325           0 :                     (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
    2326           0 :                     (suser(p) || suid_clear)) {
    2327           0 :                         error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
    2328           0 :                         if (error)
    2329             :                                 goto out;
    2330           0 :                         mode = vattr.va_mode & ~(VSUID | VSGID);
    2331           0 :                         if (mode == vattr.va_mode)
    2332             :                                 mode = VNOVAL;
    2333           0 :                 } else
    2334             :                         mode = VNOVAL;
    2335           0 :                 VATTR_NULL(&vattr);
    2336           0 :                 vattr.va_uid = uid;
    2337           0 :                 vattr.va_gid = gid;
    2338           0 :                 vattr.va_mode = mode;
    2339           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2340             :         }
    2341             : out:
    2342           0 :         vput(vp);
    2343           0 :         return (error);
    2344           0 : }
    2345             : 
    2346             : /*
    2347             :  * Set ownership given a file descriptor.
    2348             :  */
    2349             : int
    2350           0 : sys_fchown(struct proc *p, void *v, register_t *retval)
    2351             : {
    2352             :         struct sys_fchown_args /* {
    2353             :                 syscallarg(int) fd;
    2354             :                 syscallarg(uid_t) uid;
    2355             :                 syscallarg(gid_t) gid;
    2356           0 :         } */ *uap = v;
    2357             :         struct vnode *vp;
    2358           0 :         struct vattr vattr;
    2359             :         int error;
    2360           0 :         struct file *fp;
    2361             :         mode_t mode;
    2362           0 :         uid_t uid = SCARG(uap, uid);
    2363           0 :         gid_t gid = SCARG(uap, gid);
    2364             : 
    2365           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2366           0 :                 return (error);
    2367           0 :         vp = fp->f_data;
    2368           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2369           0 :         if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY))
    2370           0 :                 error = EROFS;
    2371             :         else {
    2372           0 :                 if ((error = pledge_chown(p, uid, gid)))
    2373             :                         goto out;
    2374           0 :                 if ((uid != -1 || gid != -1) &&
    2375           0 :                     (vp->v_mount &&
    2376           0 :                      (vp->v_mount->mnt_flag & MNT_NOPERM) == 0) &&
    2377           0 :                     (suser(p) || suid_clear)) {
    2378           0 :                         error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
    2379           0 :                         if (error)
    2380             :                                 goto out;
    2381           0 :                         mode = vattr.va_mode & ~(VSUID | VSGID);
    2382           0 :                         if (mode == vattr.va_mode)
    2383             :                                 mode = VNOVAL;
    2384           0 :                 } else
    2385             :                         mode = VNOVAL;
    2386           0 :                 VATTR_NULL(&vattr);
    2387           0 :                 vattr.va_uid = uid;
    2388           0 :                 vattr.va_gid = gid;
    2389           0 :                 vattr.va_mode = mode;
    2390           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2391             :         }
    2392             : out:
    2393           0 :         VOP_UNLOCK(vp);
    2394           0 :         FRELE(fp, p);
    2395           0 :         return (error);
    2396           0 : }
    2397             : 
    2398             : /*
    2399             :  * Set the access and modification times given a path name.
    2400             :  */
    2401             : int
    2402           0 : sys_utimes(struct proc *p, void *v, register_t *retval)
    2403             : {
    2404             :         struct sys_utimes_args /* {
    2405             :                 syscallarg(const char *) path;
    2406             :                 syscallarg(const struct timeval *) tptr;
    2407           0 :         } */ *uap = v;
    2408             : 
    2409           0 :         struct timespec ts[2];
    2410           0 :         struct timeval tv[2];
    2411             :         const struct timeval *tvp;
    2412             :         int error;
    2413             : 
    2414           0 :         tvp = SCARG(uap, tptr);
    2415           0 :         if (tvp != NULL) {
    2416           0 :                 error = copyin(tvp, tv, sizeof(tv));
    2417           0 :                 if (error)
    2418           0 :                         return (error);
    2419           0 :                 TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]);
    2420           0 :                 TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]);
    2421           0 :         } else
    2422           0 :                 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
    2423             : 
    2424           0 :         return (doutimensat(p, AT_FDCWD, SCARG(uap, path), ts, 0));
    2425           0 : }
    2426             : 
    2427             : int
    2428           0 : sys_utimensat(struct proc *p, void *v, register_t *retval)
    2429             : {
    2430             :         struct sys_utimensat_args /* {
    2431             :                 syscallarg(int) fd;
    2432             :                 syscallarg(const char *) path;
    2433             :                 syscallarg(const struct timespec *) times;
    2434             :                 syscallarg(int) flag;
    2435           0 :         } */ *uap = v;
    2436             : 
    2437           0 :         struct timespec ts[2];
    2438             :         const struct timespec *tsp;
    2439             :         int error;
    2440             : 
    2441           0 :         tsp = SCARG(uap, times);
    2442           0 :         if (tsp != NULL) {
    2443           0 :                 error = copyin(tsp, ts, sizeof(ts));
    2444           0 :                 if (error)
    2445           0 :                         return (error);
    2446             :         } else
    2447           0 :                 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
    2448             : 
    2449           0 :         return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), ts,
    2450           0 :             SCARG(uap, flag)));
    2451           0 : }
    2452             : 
    2453             : int
    2454           0 : doutimensat(struct proc *p, int fd, const char *path,
    2455             :     struct timespec ts[2], int flag)
    2456             : {
    2457             :         struct vnode *vp;
    2458             :         int error, follow;
    2459           0 :         struct nameidata nd;
    2460             : 
    2461           0 :         if (flag & ~AT_SYMLINK_NOFOLLOW)
    2462           0 :                 return (EINVAL);
    2463             : 
    2464           0 :         follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
    2465           0 :         NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
    2466           0 :         nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
    2467           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2468           0 :         if ((error = namei(&nd)) != 0)
    2469           0 :                 return (error);
    2470           0 :         vp = nd.ni_vp;
    2471             : 
    2472           0 :         return (dovutimens(p, vp, ts));
    2473           0 : }
    2474             : 
    2475             : int
    2476           0 : dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2])
    2477             : {
    2478           0 :         struct vattr vattr;
    2479           0 :         struct timespec now;
    2480             :         int error;
    2481             : 
    2482             : #ifdef KTRACE
    2483             :         /* if they're both UTIME_NOW, then don't report either */
    2484           0 :         if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) &&
    2485           0 :             KTRPOINT(p, KTR_STRUCT)) {
    2486           0 :                 ktrabstimespec(p, &ts[0]);
    2487           0 :                 ktrabstimespec(p, &ts[1]);
    2488           0 :         }
    2489             : #endif
    2490             : 
    2491           0 :         VATTR_NULL(&vattr);
    2492             : 
    2493             :         /*  make sure ctime is updated even if neither mtime nor atime is */
    2494           0 :         vattr.va_vaflags = VA_UTIMES_CHANGE;
    2495             : 
    2496           0 :         if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
    2497           0 :                 if (ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW)
    2498           0 :                         vattr.va_vaflags |= VA_UTIMES_NULL;
    2499             : 
    2500           0 :                 getnanotime(&now);
    2501           0 :                 if (ts[0].tv_nsec == UTIME_NOW)
    2502           0 :                         ts[0] = now;
    2503           0 :                 if (ts[1].tv_nsec == UTIME_NOW)
    2504           0 :                         ts[1] = now;
    2505             :         }
    2506             : 
    2507           0 :         if (ts[0].tv_nsec != UTIME_OMIT) {
    2508           0 :                 if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= 1000000000) {
    2509           0 :                         vrele(vp);
    2510           0 :                         return (EINVAL);
    2511             :                 }
    2512           0 :                 vattr.va_atime = ts[0];
    2513           0 :         }
    2514           0 :         if (ts[1].tv_nsec != UTIME_OMIT) {
    2515           0 :                 if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= 1000000000) {
    2516           0 :                         vrele(vp);
    2517           0 :                         return (EINVAL);
    2518             :                 }
    2519           0 :                 vattr.va_mtime = ts[1];
    2520           0 :         }
    2521             : 
    2522           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2523           0 :         if (vp->v_mount->mnt_flag & MNT_RDONLY)
    2524           0 :                 error = EROFS;
    2525             :         else
    2526           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2527           0 :         vput(vp);
    2528           0 :         return (error);
    2529           0 : }
    2530             : 
    2531             : /*
    2532             :  * Set the access and modification times given a file descriptor.
    2533             :  */
    2534             : int
    2535           0 : sys_futimes(struct proc *p, void *v, register_t *retval)
    2536             : {
    2537             :         struct sys_futimes_args /* {
    2538             :                 syscallarg(int) fd;
    2539             :                 syscallarg(const struct timeval *) tptr;
    2540           0 :         } */ *uap = v;
    2541           0 :         struct timeval tv[2];
    2542           0 :         struct timespec ts[2];
    2543             :         const struct timeval *tvp;
    2544             :         int error;
    2545             : 
    2546           0 :         tvp = SCARG(uap, tptr);
    2547           0 :         if (tvp != NULL) {
    2548           0 :                 error = copyin(tvp, tv, sizeof(tv));
    2549           0 :                 if (error)
    2550           0 :                         return (error);
    2551           0 :                 TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]);
    2552           0 :                 TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]);
    2553           0 :         } else
    2554           0 :                 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
    2555             : 
    2556           0 :         return (dofutimens(p, SCARG(uap, fd), ts));
    2557           0 : }
    2558             : 
    2559             : int
    2560           0 : sys_futimens(struct proc *p, void *v, register_t *retval)
    2561             : {
    2562             :         struct sys_futimens_args /* {
    2563             :                 syscallarg(int) fd;
    2564             :                 syscallarg(const struct timespec *) times;
    2565           0 :         } */ *uap = v;
    2566           0 :         struct timespec ts[2];
    2567             :         const struct timespec *tsp;
    2568             :         int error;
    2569             : 
    2570           0 :         tsp = SCARG(uap, times);
    2571           0 :         if (tsp != NULL) {
    2572           0 :                 error = copyin(tsp, ts, sizeof(ts));
    2573           0 :                 if (error)
    2574           0 :                         return (error);
    2575             :         } else
    2576           0 :                 ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
    2577             : 
    2578           0 :         return (dofutimens(p, SCARG(uap, fd), ts));
    2579           0 : }
    2580             : 
    2581             : int
    2582           0 : dofutimens(struct proc *p, int fd, struct timespec ts[2])
    2583             : {
    2584           0 :         struct file *fp;
    2585             :         struct vnode *vp;
    2586             :         int error;
    2587             : 
    2588           0 :         if ((error = getvnode(p, fd, &fp)) != 0)
    2589           0 :                 return (error);
    2590           0 :         vp = fp->f_data;
    2591           0 :         vref(vp);
    2592           0 :         FRELE(fp, p);
    2593             : 
    2594           0 :         return (dovutimens(p, vp, ts));
    2595           0 : }
    2596             : 
    2597             : /*
    2598             :  * Truncate a file given its path name.
    2599             :  */
    2600             : int
    2601           0 : sys_truncate(struct proc *p, void *v, register_t *retval)
    2602             : {
    2603             :         struct sys_truncate_args /* {
    2604             :                 syscallarg(const char *) path;
    2605             :                 syscallarg(int) pad;
    2606             :                 syscallarg(off_t) length;
    2607           0 :         } */ *uap = v;
    2608             :         struct vnode *vp;
    2609           0 :         struct vattr vattr;
    2610             :         int error;
    2611           0 :         struct nameidata nd;
    2612             : 
    2613           0 :         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
    2614           0 :         nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
    2615           0 :         nd.ni_unveil = UNVEIL_WRITE;
    2616           0 :         if ((error = namei(&nd)) != 0)
    2617           0 :                 return (error);
    2618           0 :         vp = nd.ni_vp;
    2619           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2620           0 :         if (vp->v_type == VDIR)
    2621           0 :                 error = EISDIR;
    2622           0 :         else if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0 &&
    2623           0 :             (error = vn_writechk(vp)) == 0) {
    2624           0 :                 VATTR_NULL(&vattr);
    2625           0 :                 vattr.va_size = SCARG(uap, length);
    2626           0 :                 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
    2627           0 :         }
    2628           0 :         vput(vp);
    2629           0 :         return (error);
    2630           0 : }
    2631             : 
    2632             : /*
    2633             :  * Truncate a file given a file descriptor.
    2634             :  */
    2635             : int
    2636           0 : sys_ftruncate(struct proc *p, void *v, register_t *retval)
    2637             : {
    2638             :         struct sys_ftruncate_args /* {
    2639             :                 syscallarg(int) fd;
    2640             :                 syscallarg(int) pad;
    2641             :                 syscallarg(off_t) length;
    2642           0 :         } */ *uap = v;
    2643           0 :         struct vattr vattr;
    2644             :         struct vnode *vp;
    2645           0 :         struct file *fp;
    2646             :         off_t len;
    2647             :         int error;
    2648             : 
    2649           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2650           0 :                 return (error);
    2651           0 :         len = SCARG(uap, length);
    2652           0 :         if ((fp->f_flag & FWRITE) == 0 || len < 0) {
    2653             :                 error = EINVAL;
    2654           0 :                 goto bad;
    2655             :         }
    2656           0 :         vp = fp->f_data;
    2657           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2658           0 :         if (vp->v_type == VDIR)
    2659           0 :                 error = EISDIR;
    2660           0 :         else if ((error = vn_writechk(vp)) == 0) {
    2661           0 :                 VATTR_NULL(&vattr);
    2662           0 :                 vattr.va_size = len;
    2663           0 :                 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
    2664           0 :         }
    2665           0 :         VOP_UNLOCK(vp);
    2666             : bad:
    2667           0 :         FRELE(fp, p);
    2668           0 :         return (error);
    2669           0 : }
    2670             : 
    2671             : /*
    2672             :  * Sync an open file.
    2673             :  */
    2674             : int
    2675           0 : sys_fsync(struct proc *p, void *v, register_t *retval)
    2676             : {
    2677             :         struct sys_fsync_args /* {
    2678             :                 syscallarg(int) fd;
    2679           0 :         } */ *uap = v;
    2680             :         struct vnode *vp;
    2681           0 :         struct file *fp;
    2682             :         int error;
    2683             : 
    2684           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2685           0 :                 return (error);
    2686           0 :         vp = fp->f_data;
    2687           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2688           0 :         error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
    2689             : #ifdef FFS_SOFTUPDATES
    2690           0 :         if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
    2691           0 :                 error = softdep_fsync(vp);
    2692             : #endif
    2693             : 
    2694           0 :         VOP_UNLOCK(vp);
    2695           0 :         FRELE(fp, p);
    2696           0 :         return (error);
    2697           0 : }
    2698             : 
    2699             : /*
    2700             :  * Rename files.  Source and destination must either both be directories,
    2701             :  * or both not be directories.  If target is a directory, it must be empty.
    2702             :  */
    2703             : int
    2704           0 : sys_rename(struct proc *p, void *v, register_t *retval)
    2705             : {
    2706             :         struct sys_rename_args /* {
    2707             :                 syscallarg(const char *) from;
    2708             :                 syscallarg(const char *) to;
    2709           0 :         } */ *uap = v;
    2710             : 
    2711           0 :         return (dorenameat(p, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
    2712           0 :             SCARG(uap, to)));
    2713             : }
    2714             : 
    2715             : int
    2716           0 : sys_renameat(struct proc *p, void *v, register_t *retval)
    2717             : {
    2718             :         struct sys_renameat_args /* {
    2719             :                 syscallarg(int) fromfd;
    2720             :                 syscallarg(const char *) from;
    2721             :                 syscallarg(int) tofd;
    2722             :                 syscallarg(const char *) to;
    2723           0 :         } */ *uap = v;
    2724             : 
    2725           0 :         return (dorenameat(p, SCARG(uap, fromfd), SCARG(uap, from),
    2726           0 :             SCARG(uap, tofd), SCARG(uap, to)));
    2727             : }
    2728             : 
    2729             : int
    2730           0 : dorenameat(struct proc *p, int fromfd, const char *from, int tofd,
    2731             :     const char *to)
    2732             : {
    2733             :         struct vnode *tvp, *fvp, *tdvp;
    2734           0 :         struct nameidata fromnd, tond;
    2735             :         int error;
    2736             :         int flags;
    2737             : 
    2738           0 :         NDINITAT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
    2739             :             fromfd, from, p);
    2740           0 :         fromnd.ni_pledge = PLEDGE_RPATH | PLEDGE_CPATH;
    2741           0 :         fromnd.ni_unveil = UNVEIL_READ | UNVEIL_CREATE;
    2742           0 :         if ((error = namei(&fromnd)) != 0)
    2743           0 :                 return (error);
    2744           0 :         fvp = fromnd.ni_vp;
    2745             : 
    2746             :         flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
    2747             :         /*
    2748             :          * rename("foo/", "bar/");  is  OK
    2749             :          */
    2750           0 :         if (fvp->v_type == VDIR)
    2751           0 :                 flags |= STRIPSLASHES;
    2752             : 
    2753           0 :         NDINITAT(&tond, RENAME, flags, UIO_USERSPACE, tofd, to, p);
    2754           0 :         tond.ni_pledge = PLEDGE_CPATH;
    2755           0 :         tond.ni_unveil = UNVEIL_CREATE;
    2756           0 :         if ((error = namei(&tond)) != 0) {
    2757           0 :                 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
    2758           0 :                 vrele(fromnd.ni_dvp);
    2759           0 :                 vrele(fvp);
    2760           0 :                 goto out1;
    2761             :         }
    2762           0 :         tdvp = tond.ni_dvp;
    2763           0 :         tvp = tond.ni_vp;
    2764           0 :         if (tvp != NULL) {
    2765           0 :                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
    2766             :                         error = ENOTDIR;
    2767           0 :                         goto out;
    2768           0 :                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
    2769             :                         error = EISDIR;
    2770           0 :                         goto out;
    2771             :                 }
    2772             :         }
    2773           0 :         if (fvp == tdvp)
    2774           0 :                 error = EINVAL;
    2775             :         /*
    2776             :          * If source is the same as the destination (that is the
    2777             :          * same inode number)
    2778             :          */
    2779           0 :         if (fvp == tvp)
    2780           0 :                 error = -1;
    2781             : out:
    2782           0 :         if (!error) {
    2783           0 :                 if (tvp) {
    2784           0 :                         (void)uvm_vnp_uncache(tvp);
    2785           0 :                 }
    2786           0 :                 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
    2787           0 :                                    tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
    2788           0 :         } else {
    2789           0 :                 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
    2790           0 :                 if (tdvp == tvp)
    2791           0 :                         vrele(tdvp);
    2792             :                 else
    2793           0 :                         vput(tdvp);
    2794           0 :                 if (tvp)
    2795           0 :                         vput(tvp);
    2796           0 :                 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
    2797           0 :                 vrele(fromnd.ni_dvp);
    2798           0 :                 vrele(fvp);
    2799             :         }
    2800           0 :         vrele(tond.ni_startdir);
    2801           0 :         pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
    2802             : out1:
    2803           0 :         if (fromnd.ni_startdir)
    2804           0 :                 vrele(fromnd.ni_startdir);
    2805           0 :         pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
    2806           0 :         if (error == -1)
    2807           0 :                 return (0);
    2808           0 :         return (error);
    2809           0 : }
    2810             : 
    2811             : /*
    2812             :  * Make a directory file.
    2813             :  */
    2814             : int
    2815           0 : sys_mkdir(struct proc *p, void *v, register_t *retval)
    2816             : {
    2817             :         struct sys_mkdir_args /* {
    2818             :                 syscallarg(const char *) path;
    2819             :                 syscallarg(mode_t) mode;
    2820           0 :         } */ *uap = v;
    2821             : 
    2822           0 :         return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode)));
    2823             : }
    2824             : 
    2825             : int
    2826           0 : sys_mkdirat(struct proc *p, void *v, register_t *retval)
    2827             : {
    2828             :         struct sys_mkdirat_args /* {
    2829             :                 syscallarg(int) fd;
    2830             :                 syscallarg(const char *) path;
    2831             :                 syscallarg(mode_t) mode;
    2832           0 :         } */ *uap = v;
    2833             : 
    2834           0 :         return (domkdirat(p, SCARG(uap, fd), SCARG(uap, path),
    2835           0 :             SCARG(uap, mode)));
    2836             : }
    2837             : 
    2838             : int
    2839           0 : domkdirat(struct proc *p, int fd, const char *path, mode_t mode)
    2840             : {
    2841             :         struct vnode *vp;
    2842           0 :         struct vattr vattr;
    2843             :         int error;
    2844           0 :         struct nameidata nd;
    2845             : 
    2846           0 :         NDINITAT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, UIO_USERSPACE,
    2847             :             fd, path, p);
    2848           0 :         nd.ni_pledge = PLEDGE_CPATH;
    2849           0 :         nd.ni_unveil = UNVEIL_CREATE;
    2850           0 :         if ((error = namei(&nd)) != 0)
    2851           0 :                 return (error);
    2852           0 :         vp = nd.ni_vp;
    2853           0 :         if (vp != NULL) {
    2854           0 :                 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    2855           0 :                 if (nd.ni_dvp == vp)
    2856           0 :                         vrele(nd.ni_dvp);
    2857             :                 else
    2858           0 :                         vput(nd.ni_dvp);
    2859           0 :                 vrele(vp);
    2860           0 :                 return (EEXIST);
    2861             :         }
    2862           0 :         VATTR_NULL(&vattr);
    2863           0 :         vattr.va_type = VDIR;
    2864           0 :         vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
    2865           0 :         error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
    2866           0 :         if (!error)
    2867           0 :                 vput(nd.ni_vp);
    2868           0 :         return (error);
    2869           0 : }
    2870             : 
    2871             : /*
    2872             :  * Remove a directory file.
    2873             :  */
    2874             : int
    2875           0 : sys_rmdir(struct proc *p, void *v, register_t *retval)
    2876             : {
    2877             :         struct sys_rmdir_args /* {
    2878             :                 syscallarg(const char *) path;
    2879           0 :         } */ *uap = v;
    2880             : 
    2881           0 :         return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR));
    2882             : }
    2883             : 
    2884             : /*
    2885             :  * Read a block of directory entries in a file system independent format.
    2886             :  */
    2887             : int
    2888           0 : sys_getdents(struct proc *p, void *v, register_t *retval)
    2889             : {
    2890             :         struct sys_getdents_args /* {
    2891             :                 syscallarg(int) fd;
    2892             :                 syscallarg(void *) buf;
    2893             :                 syscallarg(size_t) buflen;
    2894           0 :         } */ *uap = v;
    2895             :         struct vnode *vp;
    2896           0 :         struct file *fp;
    2897           0 :         struct uio auio;
    2898           0 :         struct iovec aiov;
    2899             :         size_t buflen;
    2900           0 :         int error, eofflag;
    2901             : 
    2902           0 :         buflen = SCARG(uap, buflen);
    2903             : 
    2904           0 :         if (buflen > INT_MAX)
    2905           0 :                 return EINVAL;
    2906           0 :         if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
    2907           0 :                 return (error);
    2908           0 :         if ((fp->f_flag & FREAD) == 0) {
    2909             :                 error = EBADF;
    2910           0 :                 goto bad;
    2911             :         }
    2912           0 :         if (fp->f_offset < 0) {
    2913             :                 error = EINVAL;
    2914           0 :                 goto bad;
    2915             :         }
    2916           0 :         vp = fp->f_data;
    2917           0 :         if (vp->v_type != VDIR) {
    2918             :                 error = EINVAL;
    2919           0 :                 goto bad;
    2920             :         }
    2921           0 :         aiov.iov_base = SCARG(uap, buf);
    2922           0 :         aiov.iov_len = buflen;
    2923           0 :         auio.uio_iov = &aiov;
    2924           0 :         auio.uio_iovcnt = 1;
    2925           0 :         auio.uio_rw = UIO_READ;
    2926           0 :         auio.uio_segflg = UIO_USERSPACE;
    2927           0 :         auio.uio_procp = p;
    2928           0 :         auio.uio_resid = buflen;
    2929           0 :         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    2930           0 :         auio.uio_offset = fp->f_offset;
    2931           0 :         error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
    2932           0 :         fp->f_offset = auio.uio_offset;
    2933           0 :         VOP_UNLOCK(vp);
    2934           0 :         if (error)
    2935             :                 goto bad;
    2936           0 :         *retval = buflen - auio.uio_resid;
    2937             : bad:
    2938           0 :         FRELE(fp, p);
    2939           0 :         return (error);
    2940           0 : }
    2941             : 
    2942             : /*
    2943             :  * Set the mode mask for creation of filesystem nodes.
    2944             :  */
    2945             : int
    2946           0 : sys_umask(struct proc *p, void *v, register_t *retval)
    2947             : {
    2948             :         struct sys_umask_args /* {
    2949             :                 syscallarg(mode_t) newmask;
    2950           0 :         } */ *uap = v;
    2951             :         struct filedesc *fdp;
    2952             : 
    2953           0 :         fdp = p->p_fd;
    2954           0 :         *retval = fdp->fd_cmask;
    2955           0 :         fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS;
    2956           0 :         return (0);
    2957             : }
    2958             : 
    2959             : /*
    2960             :  * Void all references to file by ripping underlying filesystem
    2961             :  * away from vnode.
    2962             :  */
    2963             : int
    2964           0 : sys_revoke(struct proc *p, void *v, register_t *retval)
    2965             : {
    2966             :         struct sys_revoke_args /* {
    2967             :                 syscallarg(const char *) path;
    2968           0 :         } */ *uap = v;
    2969             :         struct vnode *vp;
    2970           0 :         struct vattr vattr;
    2971             :         int error;
    2972           0 :         struct nameidata nd;
    2973             : 
    2974           0 :         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
    2975           0 :         nd.ni_pledge = PLEDGE_RPATH | PLEDGE_TTY;
    2976           0 :         nd.ni_unveil = UNVEIL_READ;
    2977           0 :         if ((error = namei(&nd)) != 0)
    2978           0 :                 return (error);
    2979           0 :         vp = nd.ni_vp;
    2980           0 :         if (vp->v_type != VCHR || (u_int)major(vp->v_rdev) >= nchrdev ||
    2981           0 :             cdevsw[major(vp->v_rdev)].d_type != D_TTY) {
    2982             :                 error = ENOTTY;
    2983           0 :                 goto out;
    2984             :         }
    2985           0 :         if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
    2986             :                 goto out;
    2987           0 :         if (p->p_ucred->cr_uid != vattr.va_uid &&
    2988           0 :             (error = suser(p)))
    2989             :                 goto out;
    2990           0 :         if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED)))
    2991           0 :                 VOP_REVOKE(vp, REVOKEALL);
    2992             : out:
    2993           0 :         vrele(vp);
    2994           0 :         return (error);
    2995           0 : }
    2996             : 
    2997             : /*
    2998             :  * Convert a user file descriptor to a kernel file entry.
    2999             :  *
    3000             :  * On return *fpp is FREF:ed.
    3001             :  */
    3002             : int
    3003           0 : getvnode(struct proc *p, int fd, struct file **fpp)
    3004             : {
    3005             :         struct file *fp;
    3006             :         struct vnode *vp;
    3007             : 
    3008           0 :         if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
    3009           0 :                 return (EBADF);
    3010             : 
    3011           0 :         if (fp->f_type != DTYPE_VNODE) {
    3012           0 :                 FRELE(fp, p);
    3013           0 :                 return (EINVAL);
    3014             :         }
    3015             : 
    3016           0 :         vp = fp->f_data;
    3017           0 :         if (vp->v_type == VBAD) {
    3018           0 :                 FRELE(fp, p);
    3019           0 :                 return (EBADF);
    3020             :         }
    3021             : 
    3022           0 :         *fpp = fp;
    3023             : 
    3024           0 :         return (0);
    3025           0 : }
    3026             : 
    3027             : /*
    3028             :  * Positional read system call.
    3029             :  */
    3030             : int
    3031           0 : sys_pread(struct proc *p, void *v, register_t *retval)
    3032             : {
    3033             :         struct sys_pread_args /* {
    3034             :                 syscallarg(int) fd;
    3035             :                 syscallarg(void *) buf;
    3036             :                 syscallarg(size_t) nbyte;
    3037             :                 syscallarg(int) pad;
    3038             :                 syscallarg(off_t) offset;
    3039           0 :         } */ *uap = v;
    3040           0 :         struct iovec iov;
    3041           0 :         struct uio auio;
    3042             : 
    3043           0 :         iov.iov_base = SCARG(uap, buf);
    3044           0 :         iov.iov_len = SCARG(uap, nbyte);
    3045           0 :         if (iov.iov_len > SSIZE_MAX)
    3046           0 :                 return (EINVAL);
    3047             : 
    3048           0 :         auio.uio_iov = &iov;
    3049           0 :         auio.uio_iovcnt = 1;
    3050           0 :         auio.uio_resid = iov.iov_len;
    3051           0 :         auio.uio_offset = SCARG(uap, offset);
    3052             : 
    3053           0 :         return (dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval));
    3054           0 : }
    3055             : 
    3056             : /*
    3057             :  * Positional scatter read system call.
    3058             :  */
    3059             : int
    3060           0 : sys_preadv(struct proc *p, void *v, register_t *retval)
    3061             : {
    3062             :         struct sys_preadv_args /* {
    3063             :                 syscallarg(int) fd;
    3064             :                 syscallarg(const struct iovec *) iovp;
    3065             :                 syscallarg(int) iovcnt;
    3066             :                 syscallarg(int) pad;
    3067             :                 syscallarg(off_t) offset;
    3068           0 :         } */ *uap = v;
    3069           0 :         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
    3070           0 :         int error, iovcnt = SCARG(uap, iovcnt);
    3071           0 :         struct uio auio;
    3072           0 :         size_t resid;
    3073             : 
    3074           0 :         error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid);
    3075           0 :         if (error)
    3076             :                 goto done;
    3077             : 
    3078           0 :         auio.uio_iov = iov;
    3079           0 :         auio.uio_iovcnt = iovcnt;
    3080           0 :         auio.uio_resid = resid;
    3081           0 :         auio.uio_offset = SCARG(uap, offset);
    3082             : 
    3083           0 :         error = dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval);
    3084             :  done:
    3085           0 :         iovec_free(iov, iovcnt);
    3086           0 :         return (error);
    3087           0 : }
    3088             : 
    3089             : /*
    3090             :  * Positional write system call.
    3091             :  */
    3092             : int
    3093           0 : sys_pwrite(struct proc *p, void *v, register_t *retval)
    3094             : {
    3095             :         struct sys_pwrite_args /* {
    3096             :                 syscallarg(int) fd;
    3097             :                 syscallarg(const void *) buf;
    3098             :                 syscallarg(size_t) nbyte;
    3099             :                 syscallarg(int) pad;
    3100             :                 syscallarg(off_t) offset;
    3101           0 :         } */ *uap = v;
    3102           0 :         struct iovec iov;
    3103           0 :         struct uio auio;
    3104             : 
    3105           0 :         iov.iov_base = (void *)SCARG(uap, buf);
    3106           0 :         iov.iov_len = SCARG(uap, nbyte);
    3107           0 :         if (iov.iov_len > SSIZE_MAX)
    3108           0 :                 return (EINVAL);
    3109             : 
    3110           0 :         auio.uio_iov = &iov;
    3111           0 :         auio.uio_iovcnt = 1;
    3112           0 :         auio.uio_resid = iov.iov_len;
    3113           0 :         auio.uio_offset = SCARG(uap, offset);
    3114             : 
    3115           0 :         return (dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval));
    3116           0 : }
    3117             : 
    3118             : /*
    3119             :  * Positional gather write system call.
    3120             :  */
    3121             : int
    3122           0 : sys_pwritev(struct proc *p, void *v, register_t *retval)
    3123             : {
    3124             :         struct sys_pwritev_args /* {
    3125             :                 syscallarg(int) fd;
    3126             :                 syscallarg(const struct iovec *) iovp;
    3127             :                 syscallarg(int) iovcnt;
    3128             :                 syscallarg(int) pad;
    3129             :                 syscallarg(off_t) offset;
    3130           0 :         } */ *uap = v;
    3131           0 :         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
    3132           0 :         int error, iovcnt = SCARG(uap, iovcnt);
    3133           0 :         struct uio auio;
    3134           0 :         size_t resid;
    3135             : 
    3136           0 :         error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid);
    3137           0 :         if (error)
    3138             :                 goto done;
    3139             : 
    3140           0 :         auio.uio_iov = iov;
    3141           0 :         auio.uio_iovcnt = iovcnt;
    3142           0 :         auio.uio_resid = resid;
    3143           0 :         auio.uio_offset = SCARG(uap, offset);
    3144             : 
    3145           0 :         error = dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval);
    3146             :  done:
    3147           0 :         iovec_free(iov, iovcnt);
    3148           0 :         return (error);
    3149           0 : }

Generated by: LCOV version 1.13