123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 537741Smckusick * Redistribution and use in source and binary forms are permitted 637741Smckusick * provided that the above copyright notice and this paragraph are 737741Smckusick * duplicated in all such forms and that any documentation, 837741Smckusick * advertising materials, and other materials related to such 937741Smckusick * distribution and use acknowledge that the software was developed 1037741Smckusick * by the University of California, Berkeley. The name of the 1137741Smckusick * University may not be used to endorse or promote products derived 1237741Smckusick * from this software without specific prior written permission. 1337741Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437741Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537741Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637741Smckusick * 17*43344Smckusick * @(#)vfs_syscalls.c 7.51 (Berkeley) 06/21/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "mount.h" 2817101Sbloom #include "proc.h" 2917101Sbloom #include "uio.h" 3037741Smckusick #include "malloc.h" 3137Sbill 3239797Smckusick #undef RETURN 3342441Smckusick #define RETURN(val) { u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); } 3439797Smckusick 3537741Smckusick /* 3637741Smckusick * Virtual File System System Calls 3737741Smckusick */ 3812756Ssam 399167Ssam /* 4037741Smckusick * mount system call 419167Ssam */ 4242441Smckusick /* ARGSUSED */ 4342441Smckusick mount(p, uap, retval) 4442441Smckusick register struct proc *p; 4542441Smckusick register struct args { 4637741Smckusick int type; 4737741Smckusick char *dir; 4837741Smckusick int flags; 4937741Smckusick caddr_t data; 5042441Smckusick } *uap; 5142441Smckusick int *retval; 5242441Smckusick { 5342441Smckusick register struct nameidata *ndp = &u.u_nd; 5439335Smckusick register struct vnode *vp; 5539335Smckusick register struct mount *mp; 5640111Smckusick int error, flag; 576254Sroot 5837741Smckusick /* 5937741Smckusick * Must be super user 6037741Smckusick */ 6142441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 6237741Smckusick RETURN (error); 6337741Smckusick /* 6437741Smckusick * Get vnode to be covered 6537741Smckusick */ 6637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6837741Smckusick ndp->ni_dirp = uap->dir; 6937741Smckusick if (error = namei(ndp)) 7037741Smckusick RETURN (error); 7137741Smckusick vp = ndp->ni_vp; 7241400Smckusick if (uap->flags & MNT_UPDATE) { 7339335Smckusick if ((vp->v_flag & VROOT) == 0) { 7439335Smckusick vput(vp); 7539335Smckusick RETURN (EINVAL); 7639335Smckusick } 7739335Smckusick mp = vp->v_mount; 7839335Smckusick /* 7939335Smckusick * We allow going from read-only to read-write, 8039335Smckusick * but not from read-write to read-only. 8139335Smckusick */ 8241400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 8341400Smckusick (uap->flags & MNT_RDONLY) != 0) { 8439335Smckusick vput(vp); 8539335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8639335Smckusick } 8741400Smckusick flag = mp->mnt_flag; 8841400Smckusick mp->mnt_flag |= MNT_UPDATE; 8939335Smckusick VOP_UNLOCK(vp); 9039335Smckusick goto update; 9139335Smckusick } 9239665Smckusick vinvalbuf(vp, 1); 9339805Smckusick if (vp->v_usecount != 1) { 9437741Smckusick vput(vp); 9537741Smckusick RETURN (EBUSY); 9637741Smckusick } 9737741Smckusick if (vp->v_type != VDIR) { 9837741Smckusick vput(vp); 9937741Smckusick RETURN (ENOTDIR); 10037741Smckusick } 10139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10337741Smckusick vput(vp); 10437741Smckusick RETURN (ENODEV); 10537741Smckusick } 10637741Smckusick 10737741Smckusick /* 10839335Smckusick * Allocate and initialize the file system. 10937741Smckusick */ 11037741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 11137741Smckusick M_MOUNT, M_WAITOK); 11241400Smckusick mp->mnt_op = vfssw[uap->type]; 11341400Smckusick mp->mnt_flag = 0; 11441400Smckusick mp->mnt_exroot = 0; 11541400Smckusick mp->mnt_mounth = NULLVP; 11639335Smckusick if (error = vfs_lock(mp)) { 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11939335Smckusick RETURN (error); 12039335Smckusick } 12139335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12239335Smckusick vfs_unlock(mp); 12339335Smckusick free((caddr_t)mp, M_MOUNT); 12439335Smckusick vput(vp); 12539335Smckusick RETURN (EBUSY); 12639335Smckusick } 12739335Smckusick vp->v_mountedhere = mp; 12841400Smckusick mp->mnt_vnodecovered = vp; 12939335Smckusick update: 13039335Smckusick /* 13139335Smckusick * Set the mount level flags. 13239335Smckusick */ 13341400Smckusick if (uap->flags & MNT_RDONLY) 13441400Smckusick mp->mnt_flag |= MNT_RDONLY; 13539335Smckusick else 13641400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13741400Smckusick if (uap->flags & MNT_NOSUID) 13841400Smckusick mp->mnt_flag |= MNT_NOSUID; 13939335Smckusick else 14041400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 14141400Smckusick if (uap->flags & MNT_NOEXEC) 14241400Smckusick mp->mnt_flag |= MNT_NOEXEC; 14339335Smckusick else 14441400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 14541400Smckusick if (uap->flags & MNT_NODEV) 14641400Smckusick mp->mnt_flag |= MNT_NODEV; 14739335Smckusick else 14841400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14941400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 15041400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 15139335Smckusick else 15241400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 15339335Smckusick /* 15439335Smckusick * Mount the filesystem. 15539335Smckusick */ 15639335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15741400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15841400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15939335Smckusick vrele(vp); 16040111Smckusick if (error) 16141400Smckusick mp->mnt_flag = flag; 16239335Smckusick RETURN (error); 16339335Smckusick } 16440110Smckusick /* 16540110Smckusick * Put the new filesystem on the mount list after root. 16640110Smckusick */ 16741400Smckusick mp->mnt_next = rootfs->mnt_next; 16841400Smckusick mp->mnt_prev = rootfs; 16941400Smckusick rootfs->mnt_next = mp; 17041400Smckusick mp->mnt_next->mnt_prev = mp; 17137741Smckusick cache_purge(vp); 17237741Smckusick if (!error) { 17339335Smckusick VOP_UNLOCK(vp); 17437741Smckusick vfs_unlock(mp); 17539044Smckusick error = VFS_START(mp, 0); 17637741Smckusick } else { 17737741Smckusick vfs_remove(mp); 17837741Smckusick free((caddr_t)mp, M_MOUNT); 17939335Smckusick vput(vp); 18037741Smckusick } 18137741Smckusick RETURN (error); 1826254Sroot } 1836254Sroot 1849167Ssam /* 18537741Smckusick * Unmount system call. 18637741Smckusick * 18737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18837741Smckusick * not special file (as before). 1899167Ssam */ 19042441Smckusick /* ARGSUSED */ 19142441Smckusick unmount(p, uap, retval) 19242441Smckusick register struct proc *p; 19342441Smckusick register struct args { 19437741Smckusick char *pathp; 19537741Smckusick int flags; 19642441Smckusick } *uap; 19742441Smckusick int *retval; 19842441Smckusick { 19937741Smckusick register struct vnode *vp; 20042441Smckusick register struct nameidata *ndp = &u.u_nd; 20139356Smckusick struct mount *mp; 20237741Smckusick int error; 2036254Sroot 20437741Smckusick /* 20537741Smckusick * Must be super user 20637741Smckusick */ 20742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 20837741Smckusick RETURN (error); 20937741Smckusick 21037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 21137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 21237741Smckusick ndp->ni_dirp = uap->pathp; 21337741Smckusick if (error = namei(ndp)) 21437741Smckusick RETURN (error); 21537741Smckusick vp = ndp->ni_vp; 21637741Smckusick /* 21737741Smckusick * Must be the root of the filesystem 21837741Smckusick */ 21937741Smckusick if ((vp->v_flag & VROOT) == 0) { 22037741Smckusick vput(vp); 22137741Smckusick RETURN (EINVAL); 22237741Smckusick } 22337741Smckusick mp = vp->v_mount; 22437741Smckusick vput(vp); 22539356Smckusick RETURN (dounmount(mp, uap->flags)); 22639356Smckusick } 22739356Smckusick 22839356Smckusick /* 22939356Smckusick * Do an unmount. 23039356Smckusick */ 23139356Smckusick dounmount(mp, flags) 23239356Smckusick register struct mount *mp; 23339356Smckusick int flags; 23439356Smckusick { 23539356Smckusick struct vnode *coveredvp; 23639356Smckusick int error; 23739356Smckusick 23841400Smckusick coveredvp = mp->mnt_vnodecovered; 23941298Smckusick if (vfs_busy(mp)) 24041298Smckusick return (EBUSY); 24141400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 24237741Smckusick if (error = vfs_lock(mp)) 24339356Smckusick return (error); 24437741Smckusick 24537741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24637741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24741676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24841676Smckusick error = VFS_UNMOUNT(mp, flags); 24941400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 25041298Smckusick vfs_unbusy(mp); 25137741Smckusick if (error) { 25237741Smckusick vfs_unlock(mp); 25337741Smckusick } else { 25437741Smckusick vrele(coveredvp); 25537741Smckusick vfs_remove(mp); 25637741Smckusick free((caddr_t)mp, M_MOUNT); 25737741Smckusick } 25839356Smckusick return (error); 2596254Sroot } 2606254Sroot 2619167Ssam /* 26237741Smckusick * Sync system call. 26337741Smckusick * Sync each mounted filesystem. 2649167Ssam */ 26539491Smckusick /* ARGSUSED */ 26642441Smckusick sync(p, uap, retval) 26742441Smckusick register struct proc *p; 26842441Smckusick struct args *uap; 26942441Smckusick int *retval; 2706254Sroot { 27137741Smckusick register struct mount *mp; 27241298Smckusick struct mount *omp; 27337741Smckusick 27437741Smckusick mp = rootfs; 27537741Smckusick do { 27640343Smckusick /* 27740343Smckusick * The lock check below is to avoid races with mount 27840343Smckusick * and unmount. 27940343Smckusick */ 28041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28141298Smckusick !vfs_busy(mp)) { 28237741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28341298Smckusick omp = mp; 28441400Smckusick mp = mp->mnt_next; 28541298Smckusick vfs_unbusy(omp); 28641298Smckusick } else 28741400Smckusick mp = mp->mnt_next; 28837741Smckusick } while (mp != rootfs); 28937741Smckusick } 29037741Smckusick 29137741Smckusick /* 29241298Smckusick * operate on filesystem quotas 29341298Smckusick */ 29442441Smckusick /* ARGSUSED */ 29542441Smckusick quotactl(p, uap, retval) 29642441Smckusick register struct proc *p; 29742441Smckusick register struct args { 29841298Smckusick char *path; 29941298Smckusick int cmd; 30041298Smckusick int uid; 30141298Smckusick caddr_t arg; 30242441Smckusick } *uap; 30342441Smckusick int *retval; 30442441Smckusick { 30541298Smckusick register struct mount *mp; 30642441Smckusick register struct nameidata *ndp = &u.u_nd; 30741298Smckusick int error; 30841298Smckusick 30941298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31041298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31141298Smckusick ndp->ni_dirp = uap->path; 31241298Smckusick if (error = namei(ndp)) 31341298Smckusick RETURN (error); 31441298Smckusick mp = ndp->ni_vp->v_mount; 31541298Smckusick vrele(ndp->ni_vp); 31641298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31741298Smckusick } 31841298Smckusick 31941298Smckusick /* 32037741Smckusick * get filesystem statistics 32137741Smckusick */ 32242441Smckusick /* ARGSUSED */ 32342441Smckusick statfs(p, uap, retval) 32442441Smckusick register struct proc *p; 32542441Smckusick register struct args { 32637741Smckusick char *path; 32737741Smckusick struct statfs *buf; 32842441Smckusick } *uap; 32942441Smckusick int *retval; 33042441Smckusick { 33139464Smckusick register struct mount *mp; 33242441Smckusick register struct nameidata *ndp = &u.u_nd; 33340343Smckusick register struct statfs *sp; 33437741Smckusick int error; 33537741Smckusick 33639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33837741Smckusick ndp->ni_dirp = uap->path; 33937741Smckusick if (error = namei(ndp)) 34037741Smckusick RETURN (error); 34139544Smckusick mp = ndp->ni_vp->v_mount; 34241400Smckusick sp = &mp->mnt_stat; 34339544Smckusick vrele(ndp->ni_vp); 34440343Smckusick if (error = VFS_STATFS(mp, sp)) 34539544Smckusick RETURN (error); 34641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34740343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34837741Smckusick } 34937741Smckusick 35042441Smckusick /* 35142441Smckusick * get filesystem statistics 35242441Smckusick */ 35342441Smckusick /* ARGSUSED */ 35442441Smckusick fstatfs(p, uap, retval) 35542441Smckusick register struct proc *p; 35642441Smckusick register struct args { 35737741Smckusick int fd; 35837741Smckusick struct statfs *buf; 35942441Smckusick } *uap; 36042441Smckusick int *retval; 36142441Smckusick { 36237741Smckusick struct file *fp; 36339464Smckusick struct mount *mp; 36440343Smckusick register struct statfs *sp; 36537741Smckusick int error; 36637741Smckusick 36742441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 36837741Smckusick RETURN (error); 36939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37041400Smckusick sp = &mp->mnt_stat; 37140343Smckusick if (error = VFS_STATFS(mp, sp)) 37237741Smckusick RETURN (error); 37341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37440343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37537741Smckusick } 37637741Smckusick 37737741Smckusick /* 37838270Smckusick * get statistics on all filesystems 37938270Smckusick */ 38042441Smckusick getfsstat(p, uap, retval) 38142441Smckusick register struct proc *p; 38242441Smckusick register struct args { 38338270Smckusick struct statfs *buf; 38438270Smckusick long bufsize; 38540343Smckusick int flags; 38642441Smckusick } *uap; 38742441Smckusick int *retval; 38842441Smckusick { 38938270Smckusick register struct mount *mp; 39040343Smckusick register struct statfs *sp; 39139606Smckusick caddr_t sfsp; 39238270Smckusick long count, maxcount, error; 39338270Smckusick 39438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39539606Smckusick sfsp = (caddr_t)uap->buf; 39638270Smckusick mp = rootfs; 39738270Smckusick count = 0; 39838270Smckusick do { 39941400Smckusick if (sfsp && count < maxcount && 40041400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40141400Smckusick sp = &mp->mnt_stat; 40240343Smckusick /* 40340343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40440343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40540343Smckusick */ 40640343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40740343Smckusick (uap->flags & MNT_WAIT)) && 40840343Smckusick (error = VFS_STATFS(mp, sp))) { 40941400Smckusick mp = mp->mnt_prev; 41039607Smckusick continue; 41139607Smckusick } 41241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41439606Smckusick RETURN (error); 41540343Smckusick sfsp += sizeof(*sp); 41638270Smckusick } 41739606Smckusick count++; 41841400Smckusick mp = mp->mnt_prev; 41938270Smckusick } while (mp != rootfs); 42038270Smckusick if (sfsp && count > maxcount) 42142441Smckusick *retval = maxcount; 42238270Smckusick else 42342441Smckusick *retval = count; 42438270Smckusick RETURN (0); 42538270Smckusick } 42638270Smckusick 42738270Smckusick /* 42838259Smckusick * Change current working directory to a given file descriptor. 42938259Smckusick */ 43042441Smckusick /* ARGSUSED */ 43142441Smckusick fchdir(p, uap, retval) 43242441Smckusick register struct proc *p; 43342441Smckusick struct args { 43442441Smckusick int fd; 43542441Smckusick } *uap; 43642441Smckusick int *retval; 43738259Smckusick { 43842441Smckusick register struct nameidata *ndp = &u.u_nd; 43938259Smckusick register struct vnode *vp; 44038259Smckusick struct file *fp; 44138259Smckusick int error; 44238259Smckusick 44342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 44438259Smckusick RETURN (error); 44538259Smckusick vp = (struct vnode *)fp->f_data; 44638259Smckusick VOP_LOCK(vp); 44738259Smckusick if (vp->v_type != VDIR) 44838259Smckusick error = ENOTDIR; 44938259Smckusick else 45042441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45138259Smckusick VOP_UNLOCK(vp); 45239860Smckusick if (error) 45339860Smckusick RETURN (error); 45439860Smckusick VREF(vp); 45542441Smckusick vrele(ndp->ni_cdir); 45642441Smckusick ndp->ni_cdir = vp; 45739860Smckusick RETURN (0); 45838259Smckusick } 45938259Smckusick 46038259Smckusick /* 46137741Smckusick * Change current working directory (``.''). 46237741Smckusick */ 46342441Smckusick /* ARGSUSED */ 46442441Smckusick chdir(p, uap, retval) 46542441Smckusick register struct proc *p; 46642441Smckusick struct args { 46742441Smckusick char *fname; 46842441Smckusick } *uap; 46942441Smckusick int *retval; 47037741Smckusick { 47142441Smckusick register struct nameidata *ndp = &u.u_nd; 47237741Smckusick int error; 4736254Sroot 47437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47616694Smckusick ndp->ni_dirp = uap->fname; 47737741Smckusick if (error = chdirec(ndp)) 47837741Smckusick RETURN (error); 47942441Smckusick vrele(ndp->ni_cdir); 48042441Smckusick ndp->ni_cdir = ndp->ni_vp; 48137741Smckusick RETURN (0); 48237741Smckusick } 4836254Sroot 48437741Smckusick /* 48537741Smckusick * Change notion of root (``/'') directory. 48637741Smckusick */ 48742441Smckusick /* ARGSUSED */ 48842441Smckusick chroot(p, uap, retval) 48942441Smckusick register struct proc *p; 49042441Smckusick struct args { 49142441Smckusick char *fname; 49242441Smckusick } *uap; 49342441Smckusick int *retval; 49437741Smckusick { 49542441Smckusick register struct nameidata *ndp = &u.u_nd; 49637741Smckusick int error; 49737741Smckusick 49842441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 49937741Smckusick RETURN (error); 50037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50237741Smckusick ndp->ni_dirp = uap->fname; 50337741Smckusick if (error = chdirec(ndp)) 50437741Smckusick RETURN (error); 50542441Smckusick if (ndp->ni_rdir != NULL) 50642441Smckusick vrele(ndp->ni_rdir); 50742441Smckusick ndp->ni_rdir = ndp->ni_vp; 50837741Smckusick RETURN (0); 5096254Sroot } 5106254Sroot 51137Sbill /* 51237741Smckusick * Common routine for chroot and chdir. 51337741Smckusick */ 51437741Smckusick chdirec(ndp) 51537741Smckusick register struct nameidata *ndp; 51637741Smckusick { 51737741Smckusick struct vnode *vp; 51837741Smckusick int error; 51937741Smckusick 52037741Smckusick if (error = namei(ndp)) 52137741Smckusick return (error); 52237741Smckusick vp = ndp->ni_vp; 52337741Smckusick if (vp->v_type != VDIR) 52437741Smckusick error = ENOTDIR; 52537741Smckusick else 52638399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52737741Smckusick VOP_UNLOCK(vp); 52837741Smckusick if (error) 52937741Smckusick vrele(vp); 53037741Smckusick return (error); 53137741Smckusick } 53237741Smckusick 53337741Smckusick /* 5346254Sroot * Open system call. 53542441Smckusick * Check permissions, allocate an open file structure, 53642441Smckusick * and call the device open routine if any. 5376254Sroot */ 53842441Smckusick open(p, uap, retval) 53942441Smckusick register struct proc *p; 54042441Smckusick register struct args { 5416254Sroot char *fname; 5427701Ssam int mode; 54312756Ssam int crtmode; 54442441Smckusick } *uap; 54542441Smckusick int *retval; 5466254Sroot { 54742441Smckusick struct nameidata *ndp = &u.u_nd; 54842441Smckusick register struct file *fp; 54937741Smckusick int fmode, cmode; 55037741Smckusick struct file *nfp; 55137741Smckusick int indx, error; 55237741Smckusick extern struct fileops vnops; 5536254Sroot 55437741Smckusick if (error = falloc(&nfp, &indx)) 55542441Smckusick RETURN (error); 55637741Smckusick fp = nfp; 55742441Smckusick fmode = uap->mode - FOPEN; 55842441Smckusick cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; 55942441Smckusick ndp->ni_segflg = UIO_USERSPACE; 56042441Smckusick ndp->ni_dirp = uap->fname; 56142441Smckusick u.u_r.u_rv.R_val1 = indx; /* XXX for fdopen() */ 56242441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56337741Smckusick crfree(fp->f_cred); 56437741Smckusick fp->f_count--; 56542441Smckusick if (error == EJUSTRETURN) { /* XXX from fdopen */ 56642441Smckusick *retval = indx; 56742441Smckusick RETURN (0); 56842441Smckusick } 56940884Smckusick if (error == ERESTART) 57040884Smckusick error = EINTR; 57142441Smckusick u.u_ofile[indx] = NULL; 57242441Smckusick RETURN (error); 57312756Ssam } 57437741Smckusick fp->f_flag = fmode & FMASK; 57537741Smckusick fp->f_type = DTYPE_VNODE; 57637741Smckusick fp->f_ops = &vnops; 57737741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 57842441Smckusick *retval = indx; 57942441Smckusick RETURN (0); 5806254Sroot } 5816254Sroot 58242955Smckusick #ifdef COMPAT_43 5836254Sroot /* 58442441Smckusick * Creat system call. 5856254Sroot */ 58642955Smckusick ocreat(p, uap, retval) 58742441Smckusick struct proc *p; 58842441Smckusick register struct args { 58942441Smckusick char *fname; 59042441Smckusick int fmode; 59142441Smckusick } *uap; 59242441Smckusick int *retval; 5936254Sroot { 59442441Smckusick struct args { 5956254Sroot char *fname; 59642441Smckusick int mode; 59742441Smckusick int crtmode; 59842441Smckusick } openuap; 59942441Smckusick 60042441Smckusick openuap.fname = uap->fname; 60142441Smckusick openuap.crtmode = uap->fmode; 60242441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60342441Smckusick RETURN (open(p, &openuap, retval)); 60442441Smckusick } 60542955Smckusick #endif /* COMPAT_43 */ 60642441Smckusick 60742441Smckusick /* 60842441Smckusick * Mknod system call 60942441Smckusick */ 61042441Smckusick /* ARGSUSED */ 61142441Smckusick mknod(p, uap, retval) 61242441Smckusick register struct proc *p; 61342441Smckusick register struct args { 61442441Smckusick char *fname; 6156254Sroot int fmode; 6166254Sroot int dev; 61742441Smckusick } *uap; 61842441Smckusick int *retval; 61942441Smckusick { 62042441Smckusick register struct nameidata *ndp = &u.u_nd; 62137741Smckusick register struct vnode *vp; 62237741Smckusick struct vattr vattr; 62337741Smckusick int error; 6246254Sroot 62542441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62637741Smckusick RETURN (error); 62737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62916694Smckusick ndp->ni_dirp = uap->fname; 63037741Smckusick if (error = namei(ndp)) 63137741Smckusick RETURN (error); 63237741Smckusick vp = ndp->ni_vp; 63337741Smckusick if (vp != NULL) { 63437741Smckusick error = EEXIST; 63512756Ssam goto out; 6366254Sroot } 63741362Smckusick VATTR_NULL(&vattr); 63840635Smckusick switch (uap->fmode & S_IFMT) { 63912756Ssam 64040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64137741Smckusick vattr.va_type = VBAD; 64237741Smckusick break; 64340635Smckusick case S_IFCHR: 64437741Smckusick vattr.va_type = VCHR; 64537741Smckusick break; 64640635Smckusick case S_IFBLK: 64737741Smckusick vattr.va_type = VBLK; 64837741Smckusick break; 64937741Smckusick default: 65037741Smckusick error = EINVAL; 65137741Smckusick goto out; 6526254Sroot } 65342441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 65437741Smckusick vattr.va_rdev = uap->dev; 6556254Sroot out: 65642465Smckusick if (!error) { 65742465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 65842465Smckusick } else { 65937741Smckusick VOP_ABORTOP(ndp); 660*43344Smckusick if (ndp->ni_dvp == vp) 661*43344Smckusick vrele(ndp->ni_dvp); 662*43344Smckusick else 663*43344Smckusick vput(ndp->ni_dvp); 66442465Smckusick if (vp) 66542465Smckusick vrele(vp); 66642465Smckusick } 66737741Smckusick RETURN (error); 6686254Sroot } 6696254Sroot 6706254Sroot /* 67140285Smckusick * Mkfifo system call 67240285Smckusick */ 67342441Smckusick /* ARGSUSED */ 67442441Smckusick mkfifo(p, uap, retval) 67542441Smckusick register struct proc *p; 67642441Smckusick register struct args { 67740285Smckusick char *fname; 67840285Smckusick int fmode; 67942441Smckusick } *uap; 68042441Smckusick int *retval; 68142441Smckusick { 68242441Smckusick register struct nameidata *ndp = &u.u_nd; 68340285Smckusick struct vattr vattr; 68440285Smckusick int error; 68540285Smckusick 68640285Smckusick #ifndef FIFO 68740285Smckusick RETURN (EOPNOTSUPP); 68840285Smckusick #else 68940285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69040285Smckusick ndp->ni_segflg = UIO_USERSPACE; 69140285Smckusick ndp->ni_dirp = uap->fname; 69240285Smckusick if (error = namei(ndp)) 69340285Smckusick RETURN (error); 69440285Smckusick if (ndp->ni_vp != NULL) { 69540285Smckusick VOP_ABORTOP(ndp); 696*43344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 697*43344Smckusick vrele(ndp->ni_dvp); 698*43344Smckusick else 699*43344Smckusick vput(ndp->ni_dvp); 70042465Smckusick vrele(ndp->ni_vp); 70140285Smckusick RETURN (EEXIST); 70240285Smckusick } else { 70341362Smckusick VATTR_NULL(&vattr); 70440285Smckusick vattr.va_type = VFIFO; 70542441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 70640285Smckusick } 70740285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 70840285Smckusick #endif /* FIFO */ 70940285Smckusick } 71040285Smckusick 71140285Smckusick /* 7126254Sroot * link system call 7136254Sroot */ 71442441Smckusick /* ARGSUSED */ 71542441Smckusick link(p, uap, retval) 71642441Smckusick register struct proc *p; 71742441Smckusick register struct args { 7186254Sroot char *target; 7196254Sroot char *linkname; 72042441Smckusick } *uap; 72142441Smckusick int *retval; 72242441Smckusick { 72342441Smckusick register struct nameidata *ndp = &u.u_nd; 72437741Smckusick register struct vnode *vp, *xp; 72537741Smckusick int error; 7266254Sroot 72716694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72916694Smckusick ndp->ni_dirp = uap->target; 73037741Smckusick if (error = namei(ndp)) 73137741Smckusick RETURN (error); 73237741Smckusick vp = ndp->ni_vp; 73337741Smckusick if (vp->v_type == VDIR && 73442441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73537741Smckusick goto out1; 73637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73716694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 73837741Smckusick if (error = namei(ndp)) 73937741Smckusick goto out1; 74037741Smckusick xp = ndp->ni_vp; 7416254Sroot if (xp != NULL) { 74237741Smckusick error = EEXIST; 7436254Sroot goto out; 7446254Sroot } 74537741Smckusick xp = ndp->ni_dvp; 74637741Smckusick if (vp->v_mount != xp->v_mount) 74737741Smckusick error = EXDEV; 7486254Sroot out: 74942465Smckusick if (!error) { 75042465Smckusick error = VOP_LINK(vp, ndp); 75142465Smckusick } else { 75237741Smckusick VOP_ABORTOP(ndp); 753*43344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 754*43344Smckusick vrele(ndp->ni_dvp); 755*43344Smckusick else 756*43344Smckusick vput(ndp->ni_dvp); 75742465Smckusick if (ndp->ni_vp) 75842465Smckusick vrele(ndp->ni_vp); 75942465Smckusick } 76037741Smckusick out1: 76137741Smckusick vrele(vp); 76237741Smckusick RETURN (error); 7636254Sroot } 7646254Sroot 7656254Sroot /* 7666254Sroot * symlink -- make a symbolic link 7676254Sroot */ 76842441Smckusick /* ARGSUSED */ 76942441Smckusick symlink(p, uap, retval) 77042441Smckusick register struct proc *p; 77142441Smckusick register struct args { 7726254Sroot char *target; 7736254Sroot char *linkname; 77442441Smckusick } *uap; 77542441Smckusick int *retval; 77642441Smckusick { 77742441Smckusick register struct nameidata *ndp = &u.u_nd; 77837741Smckusick struct vattr vattr; 77937741Smckusick char *target; 78037741Smckusick int error; 7816254Sroot 78216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78316694Smckusick ndp->ni_dirp = uap->linkname; 78437741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78537741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 78642465Smckusick goto out; 78737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78837741Smckusick if (error = namei(ndp)) 78942465Smckusick goto out; 79042465Smckusick if (ndp->ni_vp) { 79142465Smckusick VOP_ABORTOP(ndp); 792*43344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 793*43344Smckusick vrele(ndp->ni_dvp); 794*43344Smckusick else 795*43344Smckusick vput(ndp->ni_dvp); 79642465Smckusick vrele(ndp->ni_vp); 79737741Smckusick error = EEXIST; 79837741Smckusick goto out; 7996254Sroot } 80041362Smckusick VATTR_NULL(&vattr); 80142441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 80242465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 80337741Smckusick out: 80437741Smckusick FREE(target, M_NAMEI); 80537741Smckusick RETURN (error); 8066254Sroot } 8076254Sroot 8086254Sroot /* 8096254Sroot * Unlink system call. 8106254Sroot * Hard to avoid races here, especially 8116254Sroot * in unlinking directories. 8126254Sroot */ 81342441Smckusick /* ARGSUSED */ 81442441Smckusick unlink(p, uap, retval) 81542441Smckusick register struct proc *p; 81642441Smckusick struct args { 81742441Smckusick char *fname; 81842441Smckusick } *uap; 81942441Smckusick int *retval; 8206254Sroot { 82142441Smckusick register struct nameidata *ndp = &u.u_nd; 82237741Smckusick register struct vnode *vp; 82337741Smckusick int error; 8246254Sroot 82537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 82616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82716694Smckusick ndp->ni_dirp = uap->fname; 82837741Smckusick if (error = namei(ndp)) 82937741Smckusick RETURN (error); 83037741Smckusick vp = ndp->ni_vp; 83137741Smckusick if (vp->v_type == VDIR && 83242441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8336254Sroot goto out; 8346254Sroot /* 8356254Sroot * Don't unlink a mounted file. 8366254Sroot */ 83737741Smckusick if (vp->v_flag & VROOT) { 83837741Smckusick error = EBUSY; 8396254Sroot goto out; 8406254Sroot } 84137741Smckusick if (vp->v_flag & VTEXT) 84237741Smckusick xrele(vp); /* try once to free text */ 8436254Sroot out: 84442465Smckusick if (!error) { 84542465Smckusick error = VOP_REMOVE(ndp); 84642465Smckusick } else { 84737741Smckusick VOP_ABORTOP(ndp); 848*43344Smckusick if (ndp->ni_dvp == vp) 849*43344Smckusick vrele(ndp->ni_dvp); 850*43344Smckusick else 851*43344Smckusick vput(ndp->ni_dvp); 85242465Smckusick vput(vp); 85342465Smckusick } 85437741Smckusick RETURN (error); 8556254Sroot } 8566254Sroot 8576254Sroot /* 8586254Sroot * Seek system call 8596254Sroot */ 86042441Smckusick lseek(p, uap, retval) 86142441Smckusick register struct proc *p; 86242441Smckusick register struct args { 86337741Smckusick int fdes; 8646254Sroot off_t off; 8656254Sroot int sbase; 86642441Smckusick } *uap; 86742441Smckusick off_t *retval; 86842441Smckusick { 86942441Smckusick struct ucred *cred = u.u_nd.ni_cred; 87042441Smckusick register struct file *fp; 87137741Smckusick struct vattr vattr; 87237741Smckusick int error; 8736254Sroot 87437741Smckusick if ((unsigned)uap->fdes >= NOFILE || 87542441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 87637741Smckusick RETURN (EBADF); 87737741Smckusick if (fp->f_type != DTYPE_VNODE) 87837741Smckusick RETURN (ESPIPE); 87913878Ssam switch (uap->sbase) { 88013878Ssam 88113878Ssam case L_INCR: 88213878Ssam fp->f_offset += uap->off; 88313878Ssam break; 88413878Ssam 88513878Ssam case L_XTND: 88637741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 88742441Smckusick &vattr, cred)) 88837741Smckusick RETURN (error); 88937741Smckusick fp->f_offset = uap->off + vattr.va_size; 89013878Ssam break; 89113878Ssam 89213878Ssam case L_SET: 89313878Ssam fp->f_offset = uap->off; 89413878Ssam break; 89513878Ssam 89613878Ssam default: 89737741Smckusick RETURN (EINVAL); 89813878Ssam } 89942441Smckusick *retval = fp->f_offset; 90037741Smckusick RETURN (0); 9016254Sroot } 9026254Sroot 9036254Sroot /* 9046254Sroot * Access system call 9056254Sroot */ 90642441Smckusick /* ARGSUSED */ 90742441Smckusick saccess(p, uap, retval) 90842441Smckusick register struct proc *p; 90942441Smckusick register struct args { 9106254Sroot char *fname; 9116254Sroot int fmode; 91242441Smckusick } *uap; 91342441Smckusick int *retval; 91442441Smckusick { 91542441Smckusick register struct nameidata *ndp = &u.u_nd; 91642441Smckusick register struct ucred *cred = ndp->ni_cred; 91737741Smckusick register struct vnode *vp; 91837741Smckusick int error, mode, svuid, svgid; 9196254Sroot 92042441Smckusick svuid = cred->cr_uid; 92142441Smckusick svgid = cred->cr_groups[0]; 92242441Smckusick cred->cr_uid = p->p_ruid; 92342441Smckusick cred->cr_groups[0] = p->p_rgid; 92437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 92616694Smckusick ndp->ni_dirp = uap->fname; 92737741Smckusick if (error = namei(ndp)) 92837741Smckusick goto out1; 92937741Smckusick vp = ndp->ni_vp; 93037741Smckusick /* 93137741Smckusick * fmode == 0 means only check for exist 93237741Smckusick */ 93337741Smckusick if (uap->fmode) { 93437741Smckusick mode = 0; 93537741Smckusick if (uap->fmode & R_OK) 93637741Smckusick mode |= VREAD; 93737741Smckusick if (uap->fmode & W_OK) 93837741Smckusick mode |= VWRITE; 93937741Smckusick if (uap->fmode & X_OK) 94037741Smckusick mode |= VEXEC; 94139543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 94238399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9436254Sroot } 94437741Smckusick vput(vp); 94537741Smckusick out1: 94642441Smckusick cred->cr_uid = svuid; 94742441Smckusick cred->cr_groups[0] = svgid; 94837741Smckusick RETURN (error); 9496254Sroot } 9506254Sroot 9516254Sroot /* 9526574Smckusic * Stat system call. This version follows links. 95337Sbill */ 95442441Smckusick /* ARGSUSED */ 95542441Smckusick stat(p, uap, retval) 95642441Smckusick register struct proc *p; 95742441Smckusick register struct args { 95842441Smckusick char *fname; 95942441Smckusick struct stat *ub; 96042441Smckusick } *uap; 96142441Smckusick int *retval; 96237Sbill { 96342441Smckusick register struct nameidata *ndp = &u.u_nd; 96442441Smckusick struct stat sb; 96542441Smckusick int error; 96637Sbill 96742441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 96842441Smckusick ndp->ni_segflg = UIO_USERSPACE; 96942441Smckusick ndp->ni_dirp = uap->fname; 97042441Smckusick if (error = namei(ndp)) 97142441Smckusick RETURN (error); 97242441Smckusick error = vn_stat(ndp->ni_vp, &sb); 97342441Smckusick vput(ndp->ni_vp); 97442441Smckusick if (error) 97542441Smckusick RETURN (error); 97642441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 97742441Smckusick RETURN (error); 97837Sbill } 97937Sbill 98037Sbill /* 9816574Smckusic * Lstat system call. This version does not follow links. 9825992Swnj */ 98342441Smckusick /* ARGSUSED */ 98442441Smckusick lstat(p, uap, retval) 98542441Smckusick register struct proc *p; 98642441Smckusick register struct args { 9875992Swnj char *fname; 98812756Ssam struct stat *ub; 98942441Smckusick } *uap; 99042441Smckusick int *retval; 99142441Smckusick { 99242441Smckusick register struct nameidata *ndp = &u.u_nd; 99312756Ssam struct stat sb; 99437741Smckusick int error; 9955992Swnj 99642441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 99716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 99816694Smckusick ndp->ni_dirp = uap->fname; 99937741Smckusick if (error = namei(ndp)) 100037741Smckusick RETURN (error); 100137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 100237741Smckusick vput(ndp->ni_vp); 100337741Smckusick if (error) 100437741Smckusick RETURN (error); 100537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 100637741Smckusick RETURN (error); 10075992Swnj } 10085992Swnj 10095992Swnj /* 10105992Swnj * Return target name of a symbolic link 101137Sbill */ 101242441Smckusick /* ARGSUSED */ 101342441Smckusick readlink(p, uap, retval) 101442441Smckusick register struct proc *p; 101542441Smckusick register struct args { 10165992Swnj char *name; 10175992Swnj char *buf; 10185992Swnj int count; 101942441Smckusick } *uap; 102042441Smckusick int *retval; 102142441Smckusick { 102242441Smckusick register struct nameidata *ndp = &u.u_nd; 102337741Smckusick register struct vnode *vp; 102437741Smckusick struct iovec aiov; 102537741Smckusick struct uio auio; 102637741Smckusick int error; 10275992Swnj 102837741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 102916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103016694Smckusick ndp->ni_dirp = uap->name; 103137741Smckusick if (error = namei(ndp)) 103237741Smckusick RETURN (error); 103337741Smckusick vp = ndp->ni_vp; 103437741Smckusick if (vp->v_type != VLNK) { 103537741Smckusick error = EINVAL; 10365992Swnj goto out; 10375992Swnj } 103837741Smckusick aiov.iov_base = uap->buf; 103937741Smckusick aiov.iov_len = uap->count; 104037741Smckusick auio.uio_iov = &aiov; 104137741Smckusick auio.uio_iovcnt = 1; 104237741Smckusick auio.uio_offset = 0; 104337741Smckusick auio.uio_rw = UIO_READ; 104437741Smckusick auio.uio_segflg = UIO_USERSPACE; 104537741Smckusick auio.uio_resid = uap->count; 104637741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10475992Swnj out: 104837741Smckusick vput(vp); 104942441Smckusick *retval = uap->count - auio.uio_resid; 105037741Smckusick RETURN (error); 10515992Swnj } 10525992Swnj 10539167Ssam /* 105438259Smckusick * Change flags of a file given path name. 105538259Smckusick */ 105642441Smckusick /* ARGSUSED */ 105742441Smckusick chflags(p, uap, retval) 105842441Smckusick register struct proc *p; 105942441Smckusick register struct args { 106038259Smckusick char *fname; 106138259Smckusick int flags; 106242441Smckusick } *uap; 106342441Smckusick int *retval; 106442441Smckusick { 106542441Smckusick register struct nameidata *ndp = &u.u_nd; 106638259Smckusick register struct vnode *vp; 106738259Smckusick struct vattr vattr; 106838259Smckusick int error; 106938259Smckusick 107038259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 107138259Smckusick ndp->ni_segflg = UIO_USERSPACE; 107238259Smckusick ndp->ni_dirp = uap->fname; 107341362Smckusick VATTR_NULL(&vattr); 107438259Smckusick vattr.va_flags = uap->flags; 107538259Smckusick if (error = namei(ndp)) 107638259Smckusick RETURN (error); 107738259Smckusick vp = ndp->ni_vp; 107841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 107938259Smckusick error = EROFS; 108038259Smckusick goto out; 108138259Smckusick } 108238259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108338259Smckusick out: 108438259Smckusick vput(vp); 108538259Smckusick RETURN (error); 108638259Smckusick } 108738259Smckusick 108838259Smckusick /* 108938259Smckusick * Change flags of a file given a file descriptor. 109038259Smckusick */ 109142441Smckusick /* ARGSUSED */ 109242441Smckusick fchflags(p, uap, retval) 109342441Smckusick register struct proc *p; 109442441Smckusick register struct args { 109538259Smckusick int fd; 109638259Smckusick int flags; 109742441Smckusick } *uap; 109842441Smckusick int *retval; 109942441Smckusick { 110038259Smckusick struct vattr vattr; 110138259Smckusick struct vnode *vp; 110238259Smckusick struct file *fp; 110338259Smckusick int error; 110438259Smckusick 110542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 110638259Smckusick RETURN (error); 110741362Smckusick VATTR_NULL(&vattr); 110838259Smckusick vattr.va_flags = uap->flags; 110938259Smckusick vp = (struct vnode *)fp->f_data; 111038259Smckusick VOP_LOCK(vp); 111141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111238259Smckusick error = EROFS; 111338259Smckusick goto out; 111438259Smckusick } 111538259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 111638259Smckusick out: 111738259Smckusick VOP_UNLOCK(vp); 111838259Smckusick RETURN (error); 111938259Smckusick } 112038259Smckusick 112138259Smckusick /* 11229167Ssam * Change mode of a file given path name. 11239167Ssam */ 112442441Smckusick /* ARGSUSED */ 112542441Smckusick chmod(p, uap, retval) 112642441Smckusick register struct proc *p; 112742441Smckusick register struct args { 11286254Sroot char *fname; 11296254Sroot int fmode; 113042441Smckusick } *uap; 113142441Smckusick int *retval; 113242441Smckusick { 113342441Smckusick register struct nameidata *ndp = &u.u_nd; 113437741Smckusick register struct vnode *vp; 113537741Smckusick struct vattr vattr; 113637741Smckusick int error; 11375992Swnj 113837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114037741Smckusick ndp->ni_dirp = uap->fname; 114141362Smckusick VATTR_NULL(&vattr); 114237741Smckusick vattr.va_mode = uap->fmode & 07777; 114337741Smckusick if (error = namei(ndp)) 114437741Smckusick RETURN (error); 114537741Smckusick vp = ndp->ni_vp; 114641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114737741Smckusick error = EROFS; 114837741Smckusick goto out; 114937741Smckusick } 115037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115137741Smckusick out: 115237741Smckusick vput(vp); 115337741Smckusick RETURN (error); 11547701Ssam } 11557439Sroot 11569167Ssam /* 11579167Ssam * Change mode of a file given a file descriptor. 11589167Ssam */ 115942441Smckusick /* ARGSUSED */ 116042441Smckusick fchmod(p, uap, retval) 116142441Smckusick register struct proc *p; 116242441Smckusick register struct args { 11637701Ssam int fd; 11647701Ssam int fmode; 116542441Smckusick } *uap; 116642441Smckusick int *retval; 116742441Smckusick { 116837741Smckusick struct vattr vattr; 116937741Smckusick struct vnode *vp; 117037741Smckusick struct file *fp; 117137741Smckusick int error; 11727701Ssam 117342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 117437741Smckusick RETURN (error); 117541362Smckusick VATTR_NULL(&vattr); 117637741Smckusick vattr.va_mode = uap->fmode & 07777; 117737741Smckusick vp = (struct vnode *)fp->f_data; 117837741Smckusick VOP_LOCK(vp); 117941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118037741Smckusick error = EROFS; 118137741Smckusick goto out; 11827439Sroot } 118337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118437741Smckusick out: 118537741Smckusick VOP_UNLOCK(vp); 118637741Smckusick RETURN (error); 11875992Swnj } 11885992Swnj 11899167Ssam /* 11909167Ssam * Set ownership given a path name. 11919167Ssam */ 119242441Smckusick /* ARGSUSED */ 119342441Smckusick chown(p, uap, retval) 119442441Smckusick register struct proc *p; 119542441Smckusick register struct args { 11966254Sroot char *fname; 11976254Sroot int uid; 11986254Sroot int gid; 119942441Smckusick } *uap; 120042441Smckusick int *retval; 120142441Smckusick { 120242441Smckusick register struct nameidata *ndp = &u.u_nd; 120337741Smckusick register struct vnode *vp; 120437741Smckusick struct vattr vattr; 120537741Smckusick int error; 120637Sbill 120737741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 120836614Sbostic ndp->ni_segflg = UIO_USERSPACE; 120936614Sbostic ndp->ni_dirp = uap->fname; 121041362Smckusick VATTR_NULL(&vattr); 121137741Smckusick vattr.va_uid = uap->uid; 121237741Smckusick vattr.va_gid = uap->gid; 121337741Smckusick if (error = namei(ndp)) 121437741Smckusick RETURN (error); 121537741Smckusick vp = ndp->ni_vp; 121641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121737741Smckusick error = EROFS; 121837741Smckusick goto out; 121937741Smckusick } 122037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 122137741Smckusick out: 122237741Smckusick vput(vp); 122337741Smckusick RETURN (error); 12247701Ssam } 12257439Sroot 12269167Ssam /* 12279167Ssam * Set ownership given a file descriptor. 12289167Ssam */ 122942441Smckusick /* ARGSUSED */ 123042441Smckusick fchown(p, uap, retval) 123142441Smckusick register struct proc *p; 123242441Smckusick register struct args { 12337701Ssam int fd; 12347701Ssam int uid; 12357701Ssam int gid; 123642441Smckusick } *uap; 123742441Smckusick int *retval; 123842441Smckusick { 123937741Smckusick struct vattr vattr; 124037741Smckusick struct vnode *vp; 124137741Smckusick struct file *fp; 124237741Smckusick int error; 12437701Ssam 124442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 124537741Smckusick RETURN (error); 124641362Smckusick VATTR_NULL(&vattr); 124737741Smckusick vattr.va_uid = uap->uid; 124837741Smckusick vattr.va_gid = uap->gid; 124937741Smckusick vp = (struct vnode *)fp->f_data; 125037741Smckusick VOP_LOCK(vp); 125141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125237741Smckusick error = EROFS; 125337741Smckusick goto out; 125437741Smckusick } 125537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 125637741Smckusick out: 125737741Smckusick VOP_UNLOCK(vp); 125837741Smckusick RETURN (error); 12597701Ssam } 12607701Ssam 126142441Smckusick /* 126242441Smckusick * Set the access and modification times of a file. 126342441Smckusick */ 126442441Smckusick /* ARGSUSED */ 126542441Smckusick utimes(p, uap, retval) 126642441Smckusick register struct proc *p; 126742441Smckusick register struct args { 126811811Ssam char *fname; 126911811Ssam struct timeval *tptr; 127042441Smckusick } *uap; 127142441Smckusick int *retval; 127242441Smckusick { 127342441Smckusick register struct nameidata *ndp = &u.u_nd; 127437741Smckusick register struct vnode *vp; 127511811Ssam struct timeval tv[2]; 127637741Smckusick struct vattr vattr; 127737741Smckusick int error; 127811811Ssam 127937741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 128037741Smckusick RETURN (error); 128137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 128237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 128337741Smckusick ndp->ni_dirp = uap->fname; 128441362Smckusick VATTR_NULL(&vattr); 128537741Smckusick vattr.va_atime = tv[0]; 128637741Smckusick vattr.va_mtime = tv[1]; 128737741Smckusick if (error = namei(ndp)) 128837741Smckusick RETURN (error); 128937741Smckusick vp = ndp->ni_vp; 129041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129137741Smckusick error = EROFS; 129237741Smckusick goto out; 129321015Smckusick } 129437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129537741Smckusick out: 129637741Smckusick vput(vp); 129737741Smckusick RETURN (error); 129811811Ssam } 129911811Ssam 13009167Ssam /* 13019167Ssam * Truncate a file given its path name. 13029167Ssam */ 130342441Smckusick /* ARGSUSED */ 130442441Smckusick truncate(p, uap, retval) 130542441Smckusick register struct proc *p; 130642441Smckusick register struct args { 13077701Ssam char *fname; 130826473Skarels off_t length; 130942441Smckusick } *uap; 131042441Smckusick int *retval; 131142441Smckusick { 131242441Smckusick register struct nameidata *ndp = &u.u_nd; 131337741Smckusick register struct vnode *vp; 131437741Smckusick struct vattr vattr; 131537741Smckusick int error; 13167701Ssam 131737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 131816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 131916694Smckusick ndp->ni_dirp = uap->fname; 132041362Smckusick VATTR_NULL(&vattr); 132137741Smckusick vattr.va_size = uap->length; 132237741Smckusick if (error = namei(ndp)) 132337741Smckusick RETURN (error); 132437741Smckusick vp = ndp->ni_vp; 132537741Smckusick if (vp->v_type == VDIR) { 132637741Smckusick error = EISDIR; 132737741Smckusick goto out; 13287701Ssam } 132938399Smckusick if ((error = vn_writechk(vp)) || 133038399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 133137741Smckusick goto out; 133237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 133337741Smckusick out: 133437741Smckusick vput(vp); 133537741Smckusick RETURN (error); 13367701Ssam } 13377701Ssam 13389167Ssam /* 13399167Ssam * Truncate a file given a file descriptor. 13409167Ssam */ 134142441Smckusick /* ARGSUSED */ 134242441Smckusick ftruncate(p, uap, retval) 134342441Smckusick register struct proc *p; 134442441Smckusick register struct args { 13457701Ssam int fd; 134626473Skarels off_t length; 134742441Smckusick } *uap; 134842441Smckusick int *retval; 134942441Smckusick { 135037741Smckusick struct vattr vattr; 135137741Smckusick struct vnode *vp; 13527701Ssam struct file *fp; 135337741Smckusick int error; 13547701Ssam 135542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 135637741Smckusick RETURN (error); 135737741Smckusick if ((fp->f_flag & FWRITE) == 0) 135837741Smckusick RETURN (EINVAL); 135941362Smckusick VATTR_NULL(&vattr); 136037741Smckusick vattr.va_size = uap->length; 136137741Smckusick vp = (struct vnode *)fp->f_data; 136237741Smckusick VOP_LOCK(vp); 136337741Smckusick if (vp->v_type == VDIR) { 136437741Smckusick error = EISDIR; 136537741Smckusick goto out; 13667701Ssam } 136738399Smckusick if (error = vn_writechk(vp)) 136837741Smckusick goto out; 136937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 137037741Smckusick out: 137137741Smckusick VOP_UNLOCK(vp); 137237741Smckusick RETURN (error); 13737701Ssam } 13747701Ssam 13759167Ssam /* 13769167Ssam * Synch an open file. 13779167Ssam */ 137842441Smckusick /* ARGSUSED */ 137942441Smckusick fsync(p, uap, retval) 138042441Smckusick register struct proc *p; 138142441Smckusick struct args { 138242441Smckusick int fd; 138342441Smckusick } *uap; 138442441Smckusick int *retval; 13859167Ssam { 138639592Smckusick register struct vnode *vp; 13879167Ssam struct file *fp; 138837741Smckusick int error; 13899167Ssam 139042441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 139137741Smckusick RETURN (error); 139239592Smckusick vp = (struct vnode *)fp->f_data; 139339592Smckusick VOP_LOCK(vp); 139439592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139539592Smckusick VOP_UNLOCK(vp); 139637741Smckusick RETURN (error); 13979167Ssam } 13989167Ssam 13999167Ssam /* 14009167Ssam * Rename system call. 14019167Ssam * 14029167Ssam * Source and destination must either both be directories, or both 14039167Ssam * not be directories. If target is a directory, it must be empty. 14049167Ssam */ 140542441Smckusick /* ARGSUSED */ 140642441Smckusick rename(p, uap, retval) 140742441Smckusick register struct proc *p; 140842441Smckusick register struct args { 14097701Ssam char *from; 14107701Ssam char *to; 141142441Smckusick } *uap; 141242441Smckusick int *retval; 141342441Smckusick { 141437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141542441Smckusick register struct nameidata *ndp = &u.u_nd; 141637741Smckusick struct nameidata tond; 141737741Smckusick int error; 14187701Ssam 141937741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 142016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142116694Smckusick ndp->ni_dirp = uap->from; 142237741Smckusick if (error = namei(ndp)) 142337741Smckusick RETURN (error); 142437741Smckusick fvp = ndp->ni_vp; 142538266Smckusick nddup(ndp, &tond); 142637741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 142737741Smckusick tond.ni_segflg = UIO_USERSPACE; 142837741Smckusick tond.ni_dirp = uap->to; 142942465Smckusick if (error = namei(&tond)) { 143042465Smckusick VOP_ABORTOP(ndp); 143142465Smckusick vrele(ndp->ni_dvp); 143242465Smckusick vrele(fvp); 143342465Smckusick goto out1; 143442465Smckusick } 143537741Smckusick tdvp = tond.ni_dvp; 143637741Smckusick tvp = tond.ni_vp; 143737741Smckusick if (tvp != NULL) { 143837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 143939242Sbostic error = ENOTDIR; 144037741Smckusick goto out; 144137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 144239242Sbostic error = EISDIR; 144337741Smckusick goto out; 14449167Ssam } 14459167Ssam } 144637741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144737741Smckusick error = EXDEV; 14489167Ssam goto out; 144910051Ssam } 145039286Smckusick if (fvp == tdvp) 145137741Smckusick error = EINVAL; 145239286Smckusick /* 145339286Smckusick * If source is the same as the destination, 145439286Smckusick * then there is nothing to do. 145539286Smckusick */ 145639286Smckusick if (fvp == tvp) 145739286Smckusick error = -1; 145837741Smckusick out: 145942465Smckusick if (!error) { 146042465Smckusick error = VOP_RENAME(ndp, &tond); 146142465Smckusick } else { 146237741Smckusick VOP_ABORTOP(&tond); 1463*43344Smckusick if (tdvp == tvp) 1464*43344Smckusick vrele(tdvp); 1465*43344Smckusick else 1466*43344Smckusick vput(tdvp); 146742465Smckusick if (tvp) 146842465Smckusick vput(tvp); 146937741Smckusick VOP_ABORTOP(ndp); 147042465Smckusick vrele(ndp->ni_dvp); 147142465Smckusick vrele(fvp); 14729167Ssam } 147337741Smckusick out1: 147438266Smckusick ndrele(&tond); 147539286Smckusick if (error == -1) 147639286Smckusick RETURN (0); 147737741Smckusick RETURN (error); 14787701Ssam } 14797701Ssam 14807535Sroot /* 148112756Ssam * Mkdir system call 148212756Ssam */ 148342441Smckusick /* ARGSUSED */ 148442441Smckusick mkdir(p, uap, retval) 148542441Smckusick register struct proc *p; 148642441Smckusick register struct args { 148712756Ssam char *name; 148812756Ssam int dmode; 148942441Smckusick } *uap; 149042441Smckusick int *retval; 149142441Smckusick { 149242441Smckusick register struct nameidata *ndp = &u.u_nd; 149337741Smckusick register struct vnode *vp; 149437741Smckusick struct vattr vattr; 149537741Smckusick int error; 149612756Ssam 149737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 149816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 149916694Smckusick ndp->ni_dirp = uap->name; 150037741Smckusick if (error = namei(ndp)) 150137741Smckusick RETURN (error); 150237741Smckusick vp = ndp->ni_vp; 150337741Smckusick if (vp != NULL) { 150437741Smckusick VOP_ABORTOP(ndp); 1505*43344Smckusick if (ndp->ni_dvp == vp) 1506*43344Smckusick vrele(ndp->ni_dvp); 1507*43344Smckusick else 1508*43344Smckusick vput(ndp->ni_dvp); 150942465Smckusick vrele(vp); 151037741Smckusick RETURN (EEXIST); 151112756Ssam } 151241362Smckusick VATTR_NULL(&vattr); 151337741Smckusick vattr.va_type = VDIR; 151442441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 151537741Smckusick error = VOP_MKDIR(ndp, &vattr); 151638145Smckusick if (!error) 151738145Smckusick vput(ndp->ni_vp); 151837741Smckusick RETURN (error); 151912756Ssam } 152012756Ssam 152112756Ssam /* 152212756Ssam * Rmdir system call. 152312756Ssam */ 152442441Smckusick /* ARGSUSED */ 152542441Smckusick rmdir(p, uap, retval) 152642441Smckusick register struct proc *p; 152742441Smckusick struct args { 152842441Smckusick char *name; 152942441Smckusick } *uap; 153042441Smckusick int *retval; 153112756Ssam { 153242441Smckusick register struct nameidata *ndp = &u.u_nd; 153337741Smckusick register struct vnode *vp; 153437741Smckusick int error; 153512756Ssam 153637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 153816694Smckusick ndp->ni_dirp = uap->name; 153937741Smckusick if (error = namei(ndp)) 154037741Smckusick RETURN (error); 154137741Smckusick vp = ndp->ni_vp; 154237741Smckusick if (vp->v_type != VDIR) { 154337741Smckusick error = ENOTDIR; 154412756Ssam goto out; 154512756Ssam } 154612756Ssam /* 154737741Smckusick * No rmdir "." please. 154812756Ssam */ 154937741Smckusick if (ndp->ni_dvp == vp) { 155037741Smckusick error = EINVAL; 155112756Ssam goto out; 155212756Ssam } 155312756Ssam /* 155437741Smckusick * Don't unlink a mounted file. 155512756Ssam */ 155637741Smckusick if (vp->v_flag & VROOT) 155737741Smckusick error = EBUSY; 155812756Ssam out: 155942465Smckusick if (!error) { 156042465Smckusick error = VOP_RMDIR(ndp); 156142465Smckusick } else { 156237741Smckusick VOP_ABORTOP(ndp); 1563*43344Smckusick if (ndp->ni_dvp == vp) 1564*43344Smckusick vrele(ndp->ni_dvp); 1565*43344Smckusick else 1566*43344Smckusick vput(ndp->ni_dvp); 156742465Smckusick vput(vp); 156842465Smckusick } 156937741Smckusick RETURN (error); 157012756Ssam } 157112756Ssam 157237741Smckusick /* 157337741Smckusick * Read a block of directory entries in a file system independent format 157437741Smckusick */ 157542441Smckusick getdirentries(p, uap, retval) 157642441Smckusick register struct proc *p; 157742441Smckusick register struct args { 157837741Smckusick int fd; 157937741Smckusick char *buf; 158037741Smckusick unsigned count; 158137741Smckusick long *basep; 158242441Smckusick } *uap; 158342441Smckusick int *retval; 158442441Smckusick { 158539592Smckusick register struct vnode *vp; 158616540Ssam struct file *fp; 158737741Smckusick struct uio auio; 158837741Smckusick struct iovec aiov; 158938129Smckusick off_t off; 159040321Smckusick int error, eofflag; 159112756Ssam 159242441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 159337741Smckusick RETURN (error); 159437741Smckusick if ((fp->f_flag & FREAD) == 0) 159537741Smckusick RETURN (EBADF); 159639592Smckusick vp = (struct vnode *)fp->f_data; 159739592Smckusick if (vp->v_type != VDIR) 159839592Smckusick RETURN (EINVAL); 159937741Smckusick aiov.iov_base = uap->buf; 160037741Smckusick aiov.iov_len = uap->count; 160137741Smckusick auio.uio_iov = &aiov; 160237741Smckusick auio.uio_iovcnt = 1; 160337741Smckusick auio.uio_rw = UIO_READ; 160437741Smckusick auio.uio_segflg = UIO_USERSPACE; 160537741Smckusick auio.uio_resid = uap->count; 160639592Smckusick VOP_LOCK(vp); 160739592Smckusick auio.uio_offset = off = fp->f_offset; 160840321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 160939592Smckusick fp->f_offset = auio.uio_offset; 161039592Smckusick VOP_UNLOCK(vp); 161139592Smckusick if (error) 161237741Smckusick RETURN (error); 161339592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 161442441Smckusick *retval = uap->count - auio.uio_resid; 161537741Smckusick RETURN (error); 161612756Ssam } 161712756Ssam 161812756Ssam /* 161912756Ssam * mode mask for creation of files 162012756Ssam */ 162142441Smckusick mode_t 162242441Smckusick umask(p, uap, retval) 162342441Smckusick register struct proc *p; 162442441Smckusick struct args { 162542441Smckusick int mask; 162642441Smckusick } *uap; 162742441Smckusick int *retval; 162812756Ssam { 162912756Ssam 163042441Smckusick *retval = u.u_cmask; 163142441Smckusick u.u_cmask = uap->mask & 07777; 163237741Smckusick RETURN (0); 163312756Ssam } 163437741Smckusick 163539566Smarc /* 163639566Smarc * Void all references to file by ripping underlying filesystem 163739566Smarc * away from vnode. 163839566Smarc */ 163942441Smckusick /* ARGSUSED */ 164042441Smckusick revoke(p, uap, retval) 164142441Smckusick register struct proc *p; 164242441Smckusick register struct args { 164339566Smarc char *fname; 164441676Smckusick int flags; 164542441Smckusick } *uap; 164642441Smckusick int *retval; 164742441Smckusick { 164842441Smckusick register struct nameidata *ndp = &u.u_nd; 164939566Smarc register struct vnode *vp; 165039566Smarc struct vattr vattr; 165139566Smarc int error; 165239566Smarc 165339566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 165439566Smarc ndp->ni_segflg = UIO_USERSPACE; 165539566Smarc ndp->ni_dirp = uap->fname; 165639566Smarc if (error = namei(ndp)) 165739566Smarc RETURN (error); 165839566Smarc vp = ndp->ni_vp; 165939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 166039566Smarc error = EINVAL; 166139566Smarc goto out; 166239566Smarc } 166342441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 166439566Smarc goto out; 166542955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 166642441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 166739566Smarc goto out; 166839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 166939632Smckusick vgoneall(vp); 167039566Smarc out: 167139566Smarc vrele(vp); 167239566Smarc RETURN (error); 167339566Smarc } 167439566Smarc 167538408Smckusick getvnode(ofile, fdes, fpp) 167638408Smckusick struct file *ofile[]; 167737741Smckusick struct file **fpp; 167837741Smckusick int fdes; 167937741Smckusick { 168037741Smckusick struct file *fp; 168137741Smckusick 168238408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 168337741Smckusick return (EBADF); 168437741Smckusick if (fp->f_type != DTYPE_VNODE) 168537741Smckusick return (EINVAL); 168637741Smckusick *fpp = fp; 168737741Smckusick return (0); 168837741Smckusick } 1689