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*43450Smckusick * @(#)vfs_syscalls.c 7.54 (Berkeley) 06/22/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 33*43450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);} 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; 561*43450Smckusick p->p_dupfd = -1; /* XXX check for fdopen */ 56242441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56337741Smckusick crfree(fp->f_cred); 56437741Smckusick fp->f_count--; 56543405Smckusick if (error == ENODEV && /* XXX from fdopen */ 566*43450Smckusick p->p_dupfd >= 0 && 567*43450Smckusick (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) { 56842441Smckusick *retval = indx; 56942441Smckusick RETURN (0); 57042441Smckusick } 57140884Smckusick if (error == ERESTART) 57240884Smckusick error = EINTR; 57342441Smckusick u.u_ofile[indx] = NULL; 57442441Smckusick RETURN (error); 57512756Ssam } 57637741Smckusick fp->f_flag = fmode & FMASK; 57737741Smckusick fp->f_type = DTYPE_VNODE; 57837741Smckusick fp->f_ops = &vnops; 57937741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 58042441Smckusick *retval = indx; 58142441Smckusick RETURN (0); 5826254Sroot } 5836254Sroot 58442955Smckusick #ifdef COMPAT_43 5856254Sroot /* 58642441Smckusick * Creat system call. 5876254Sroot */ 58842955Smckusick ocreat(p, uap, retval) 58942441Smckusick struct proc *p; 59042441Smckusick register struct args { 59142441Smckusick char *fname; 59242441Smckusick int fmode; 59342441Smckusick } *uap; 59442441Smckusick int *retval; 5956254Sroot { 59642441Smckusick struct args { 5976254Sroot char *fname; 59842441Smckusick int mode; 59942441Smckusick int crtmode; 60042441Smckusick } openuap; 60142441Smckusick 60242441Smckusick openuap.fname = uap->fname; 60342441Smckusick openuap.crtmode = uap->fmode; 60442441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60542441Smckusick RETURN (open(p, &openuap, retval)); 60642441Smckusick } 60742955Smckusick #endif /* COMPAT_43 */ 60842441Smckusick 60942441Smckusick /* 61042441Smckusick * Mknod system call 61142441Smckusick */ 61242441Smckusick /* ARGSUSED */ 61342441Smckusick mknod(p, uap, retval) 61442441Smckusick register struct proc *p; 61542441Smckusick register struct args { 61642441Smckusick char *fname; 6176254Sroot int fmode; 6186254Sroot int dev; 61942441Smckusick } *uap; 62042441Smckusick int *retval; 62142441Smckusick { 62242441Smckusick register struct nameidata *ndp = &u.u_nd; 62337741Smckusick register struct vnode *vp; 62437741Smckusick struct vattr vattr; 62537741Smckusick int error; 6266254Sroot 62742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62837741Smckusick RETURN (error); 62937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 63016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 63116694Smckusick ndp->ni_dirp = uap->fname; 63237741Smckusick if (error = namei(ndp)) 63337741Smckusick RETURN (error); 63437741Smckusick vp = ndp->ni_vp; 63537741Smckusick if (vp != NULL) { 63637741Smckusick error = EEXIST; 63712756Ssam goto out; 6386254Sroot } 63941362Smckusick VATTR_NULL(&vattr); 64040635Smckusick switch (uap->fmode & S_IFMT) { 64112756Ssam 64240635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64337741Smckusick vattr.va_type = VBAD; 64437741Smckusick break; 64540635Smckusick case S_IFCHR: 64637741Smckusick vattr.va_type = VCHR; 64737741Smckusick break; 64840635Smckusick case S_IFBLK: 64937741Smckusick vattr.va_type = VBLK; 65037741Smckusick break; 65137741Smckusick default: 65237741Smckusick error = EINVAL; 65337741Smckusick goto out; 6546254Sroot } 65542441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 65637741Smckusick vattr.va_rdev = uap->dev; 6576254Sroot out: 65842465Smckusick if (!error) { 65942465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 66042465Smckusick } else { 66137741Smckusick VOP_ABORTOP(ndp); 66243344Smckusick if (ndp->ni_dvp == vp) 66343344Smckusick vrele(ndp->ni_dvp); 66443344Smckusick else 66543344Smckusick vput(ndp->ni_dvp); 66642465Smckusick if (vp) 66742465Smckusick vrele(vp); 66842465Smckusick } 66937741Smckusick RETURN (error); 6706254Sroot } 6716254Sroot 6726254Sroot /* 67340285Smckusick * Mkfifo system call 67440285Smckusick */ 67542441Smckusick /* ARGSUSED */ 67642441Smckusick mkfifo(p, uap, retval) 67742441Smckusick register struct proc *p; 67842441Smckusick register struct args { 67940285Smckusick char *fname; 68040285Smckusick int fmode; 68142441Smckusick } *uap; 68242441Smckusick int *retval; 68342441Smckusick { 68442441Smckusick register struct nameidata *ndp = &u.u_nd; 68540285Smckusick struct vattr vattr; 68640285Smckusick int error; 68740285Smckusick 68840285Smckusick #ifndef FIFO 68940285Smckusick RETURN (EOPNOTSUPP); 69040285Smckusick #else 69140285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69240285Smckusick ndp->ni_segflg = UIO_USERSPACE; 69340285Smckusick ndp->ni_dirp = uap->fname; 69440285Smckusick if (error = namei(ndp)) 69540285Smckusick RETURN (error); 69640285Smckusick if (ndp->ni_vp != NULL) { 69740285Smckusick VOP_ABORTOP(ndp); 69843344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69943344Smckusick vrele(ndp->ni_dvp); 70043344Smckusick else 70143344Smckusick vput(ndp->ni_dvp); 70242465Smckusick vrele(ndp->ni_vp); 70340285Smckusick RETURN (EEXIST); 70440285Smckusick } else { 70541362Smckusick VATTR_NULL(&vattr); 70640285Smckusick vattr.va_type = VFIFO; 70742441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 70840285Smckusick } 70940285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 71040285Smckusick #endif /* FIFO */ 71140285Smckusick } 71240285Smckusick 71340285Smckusick /* 7146254Sroot * link system call 7156254Sroot */ 71642441Smckusick /* ARGSUSED */ 71742441Smckusick link(p, uap, retval) 71842441Smckusick register struct proc *p; 71942441Smckusick register struct args { 7206254Sroot char *target; 7216254Sroot char *linkname; 72242441Smckusick } *uap; 72342441Smckusick int *retval; 72442441Smckusick { 72542441Smckusick register struct nameidata *ndp = &u.u_nd; 72637741Smckusick register struct vnode *vp, *xp; 72737741Smckusick int error; 7286254Sroot 72916694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 73016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73116694Smckusick ndp->ni_dirp = uap->target; 73237741Smckusick if (error = namei(ndp)) 73337741Smckusick RETURN (error); 73437741Smckusick vp = ndp->ni_vp; 73537741Smckusick if (vp->v_type == VDIR && 73642441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73737741Smckusick goto out1; 73837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73916694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 74037741Smckusick if (error = namei(ndp)) 74137741Smckusick goto out1; 74237741Smckusick xp = ndp->ni_vp; 7436254Sroot if (xp != NULL) { 74437741Smckusick error = EEXIST; 7456254Sroot goto out; 7466254Sroot } 74737741Smckusick xp = ndp->ni_dvp; 74837741Smckusick if (vp->v_mount != xp->v_mount) 74937741Smckusick error = EXDEV; 7506254Sroot out: 75142465Smckusick if (!error) { 75242465Smckusick error = VOP_LINK(vp, ndp); 75342465Smckusick } else { 75437741Smckusick VOP_ABORTOP(ndp); 75543344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 75643344Smckusick vrele(ndp->ni_dvp); 75743344Smckusick else 75843344Smckusick vput(ndp->ni_dvp); 75942465Smckusick if (ndp->ni_vp) 76042465Smckusick vrele(ndp->ni_vp); 76142465Smckusick } 76237741Smckusick out1: 76337741Smckusick vrele(vp); 76437741Smckusick RETURN (error); 7656254Sroot } 7666254Sroot 7676254Sroot /* 7686254Sroot * symlink -- make a symbolic link 7696254Sroot */ 77042441Smckusick /* ARGSUSED */ 77142441Smckusick symlink(p, uap, retval) 77242441Smckusick register struct proc *p; 77342441Smckusick register struct args { 7746254Sroot char *target; 7756254Sroot char *linkname; 77642441Smckusick } *uap; 77742441Smckusick int *retval; 77842441Smckusick { 77942441Smckusick register struct nameidata *ndp = &u.u_nd; 78037741Smckusick struct vattr vattr; 78137741Smckusick char *target; 78237741Smckusick int error; 7836254Sroot 78416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78516694Smckusick ndp->ni_dirp = uap->linkname; 78637741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78737741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 78842465Smckusick goto out; 78937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 79037741Smckusick if (error = namei(ndp)) 79142465Smckusick goto out; 79242465Smckusick if (ndp->ni_vp) { 79342465Smckusick VOP_ABORTOP(ndp); 79443344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 79543344Smckusick vrele(ndp->ni_dvp); 79643344Smckusick else 79743344Smckusick vput(ndp->ni_dvp); 79842465Smckusick vrele(ndp->ni_vp); 79937741Smckusick error = EEXIST; 80037741Smckusick goto out; 8016254Sroot } 80241362Smckusick VATTR_NULL(&vattr); 80342441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 80442465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 80537741Smckusick out: 80637741Smckusick FREE(target, M_NAMEI); 80737741Smckusick RETURN (error); 8086254Sroot } 8096254Sroot 8106254Sroot /* 8116254Sroot * Unlink system call. 8126254Sroot * Hard to avoid races here, especially 8136254Sroot * in unlinking directories. 8146254Sroot */ 81542441Smckusick /* ARGSUSED */ 81642441Smckusick unlink(p, uap, retval) 81742441Smckusick register struct proc *p; 81842441Smckusick struct args { 81942441Smckusick char *fname; 82042441Smckusick } *uap; 82142441Smckusick int *retval; 8226254Sroot { 82342441Smckusick register struct nameidata *ndp = &u.u_nd; 82437741Smckusick register struct vnode *vp; 82537741Smckusick int error; 8266254Sroot 82737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 82816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82916694Smckusick ndp->ni_dirp = uap->fname; 83037741Smckusick if (error = namei(ndp)) 83137741Smckusick RETURN (error); 83237741Smckusick vp = ndp->ni_vp; 83337741Smckusick if (vp->v_type == VDIR && 83442441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8356254Sroot goto out; 8366254Sroot /* 8376254Sroot * Don't unlink a mounted file. 8386254Sroot */ 83937741Smckusick if (vp->v_flag & VROOT) { 84037741Smckusick error = EBUSY; 8416254Sroot goto out; 8426254Sroot } 84337741Smckusick if (vp->v_flag & VTEXT) 84437741Smckusick xrele(vp); /* try once to free text */ 8456254Sroot out: 84642465Smckusick if (!error) { 84742465Smckusick error = VOP_REMOVE(ndp); 84842465Smckusick } else { 84937741Smckusick VOP_ABORTOP(ndp); 85043344Smckusick if (ndp->ni_dvp == vp) 85143344Smckusick vrele(ndp->ni_dvp); 85243344Smckusick else 85343344Smckusick vput(ndp->ni_dvp); 85442465Smckusick vput(vp); 85542465Smckusick } 85637741Smckusick RETURN (error); 8576254Sroot } 8586254Sroot 8596254Sroot /* 8606254Sroot * Seek system call 8616254Sroot */ 86242441Smckusick lseek(p, uap, retval) 86342441Smckusick register struct proc *p; 86442441Smckusick register struct args { 86537741Smckusick int fdes; 8666254Sroot off_t off; 8676254Sroot int sbase; 86842441Smckusick } *uap; 86942441Smckusick off_t *retval; 87042441Smckusick { 87142441Smckusick struct ucred *cred = u.u_nd.ni_cred; 87242441Smckusick register struct file *fp; 87337741Smckusick struct vattr vattr; 87437741Smckusick int error; 8756254Sroot 87637741Smckusick if ((unsigned)uap->fdes >= NOFILE || 87742441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 87837741Smckusick RETURN (EBADF); 87937741Smckusick if (fp->f_type != DTYPE_VNODE) 88037741Smckusick RETURN (ESPIPE); 88113878Ssam switch (uap->sbase) { 88213878Ssam 88313878Ssam case L_INCR: 88413878Ssam fp->f_offset += uap->off; 88513878Ssam break; 88613878Ssam 88713878Ssam case L_XTND: 88837741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 88942441Smckusick &vattr, cred)) 89037741Smckusick RETURN (error); 89137741Smckusick fp->f_offset = uap->off + vattr.va_size; 89213878Ssam break; 89313878Ssam 89413878Ssam case L_SET: 89513878Ssam fp->f_offset = uap->off; 89613878Ssam break; 89713878Ssam 89813878Ssam default: 89937741Smckusick RETURN (EINVAL); 90013878Ssam } 90142441Smckusick *retval = fp->f_offset; 90237741Smckusick RETURN (0); 9036254Sroot } 9046254Sroot 9056254Sroot /* 9066254Sroot * Access system call 9076254Sroot */ 90842441Smckusick /* ARGSUSED */ 90942441Smckusick saccess(p, uap, retval) 91042441Smckusick register struct proc *p; 91142441Smckusick register struct args { 9126254Sroot char *fname; 9136254Sroot int fmode; 91442441Smckusick } *uap; 91542441Smckusick int *retval; 91642441Smckusick { 91742441Smckusick register struct nameidata *ndp = &u.u_nd; 91842441Smckusick register struct ucred *cred = ndp->ni_cred; 91937741Smckusick register struct vnode *vp; 92037741Smckusick int error, mode, svuid, svgid; 9216254Sroot 92242441Smckusick svuid = cred->cr_uid; 92342441Smckusick svgid = cred->cr_groups[0]; 92442441Smckusick cred->cr_uid = p->p_ruid; 92542441Smckusick cred->cr_groups[0] = p->p_rgid; 92637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 92816694Smckusick ndp->ni_dirp = uap->fname; 92937741Smckusick if (error = namei(ndp)) 93037741Smckusick goto out1; 93137741Smckusick vp = ndp->ni_vp; 93237741Smckusick /* 93337741Smckusick * fmode == 0 means only check for exist 93437741Smckusick */ 93537741Smckusick if (uap->fmode) { 93637741Smckusick mode = 0; 93737741Smckusick if (uap->fmode & R_OK) 93837741Smckusick mode |= VREAD; 93937741Smckusick if (uap->fmode & W_OK) 94037741Smckusick mode |= VWRITE; 94137741Smckusick if (uap->fmode & X_OK) 94237741Smckusick mode |= VEXEC; 94339543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 94438399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9456254Sroot } 94637741Smckusick vput(vp); 94737741Smckusick out1: 94842441Smckusick cred->cr_uid = svuid; 94942441Smckusick cred->cr_groups[0] = svgid; 95037741Smckusick RETURN (error); 9516254Sroot } 9526254Sroot 9536254Sroot /* 9546574Smckusic * Stat system call. This version follows links. 95537Sbill */ 95642441Smckusick /* ARGSUSED */ 95742441Smckusick stat(p, uap, retval) 95842441Smckusick register struct proc *p; 95942441Smckusick register struct args { 96042441Smckusick char *fname; 96142441Smckusick struct stat *ub; 96242441Smckusick } *uap; 96342441Smckusick int *retval; 96437Sbill { 96542441Smckusick register struct nameidata *ndp = &u.u_nd; 96642441Smckusick struct stat sb; 96742441Smckusick int error; 96837Sbill 96942441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 97042441Smckusick ndp->ni_segflg = UIO_USERSPACE; 97142441Smckusick ndp->ni_dirp = uap->fname; 97242441Smckusick if (error = namei(ndp)) 97342441Smckusick RETURN (error); 97442441Smckusick error = vn_stat(ndp->ni_vp, &sb); 97542441Smckusick vput(ndp->ni_vp); 97642441Smckusick if (error) 97742441Smckusick RETURN (error); 97842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 97942441Smckusick RETURN (error); 98037Sbill } 98137Sbill 98237Sbill /* 9836574Smckusic * Lstat system call. This version does not follow links. 9845992Swnj */ 98542441Smckusick /* ARGSUSED */ 98642441Smckusick lstat(p, uap, retval) 98742441Smckusick register struct proc *p; 98842441Smckusick register struct args { 9895992Swnj char *fname; 99012756Ssam struct stat *ub; 99142441Smckusick } *uap; 99242441Smckusick int *retval; 99342441Smckusick { 99442441Smckusick register struct nameidata *ndp = &u.u_nd; 99512756Ssam struct stat sb; 99637741Smckusick int error; 9975992Swnj 99842441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 99916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 100016694Smckusick ndp->ni_dirp = uap->fname; 100137741Smckusick if (error = namei(ndp)) 100237741Smckusick RETURN (error); 100337741Smckusick error = vn_stat(ndp->ni_vp, &sb); 100437741Smckusick vput(ndp->ni_vp); 100537741Smckusick if (error) 100637741Smckusick RETURN (error); 100737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 100837741Smckusick RETURN (error); 10095992Swnj } 10105992Swnj 10115992Swnj /* 10125992Swnj * Return target name of a symbolic link 101337Sbill */ 101442441Smckusick /* ARGSUSED */ 101542441Smckusick readlink(p, uap, retval) 101642441Smckusick register struct proc *p; 101742441Smckusick register struct args { 10185992Swnj char *name; 10195992Swnj char *buf; 10205992Swnj int count; 102142441Smckusick } *uap; 102242441Smckusick int *retval; 102342441Smckusick { 102442441Smckusick register struct nameidata *ndp = &u.u_nd; 102537741Smckusick register struct vnode *vp; 102637741Smckusick struct iovec aiov; 102737741Smckusick struct uio auio; 102837741Smckusick int error; 10295992Swnj 103037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 103116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103216694Smckusick ndp->ni_dirp = uap->name; 103337741Smckusick if (error = namei(ndp)) 103437741Smckusick RETURN (error); 103537741Smckusick vp = ndp->ni_vp; 103637741Smckusick if (vp->v_type != VLNK) { 103737741Smckusick error = EINVAL; 10385992Swnj goto out; 10395992Swnj } 104037741Smckusick aiov.iov_base = uap->buf; 104137741Smckusick aiov.iov_len = uap->count; 104237741Smckusick auio.uio_iov = &aiov; 104337741Smckusick auio.uio_iovcnt = 1; 104437741Smckusick auio.uio_offset = 0; 104537741Smckusick auio.uio_rw = UIO_READ; 104637741Smckusick auio.uio_segflg = UIO_USERSPACE; 104737741Smckusick auio.uio_resid = uap->count; 104837741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10495992Swnj out: 105037741Smckusick vput(vp); 105142441Smckusick *retval = uap->count - auio.uio_resid; 105237741Smckusick RETURN (error); 10535992Swnj } 10545992Swnj 10559167Ssam /* 105638259Smckusick * Change flags of a file given path name. 105738259Smckusick */ 105842441Smckusick /* ARGSUSED */ 105942441Smckusick chflags(p, uap, retval) 106042441Smckusick register struct proc *p; 106142441Smckusick register struct args { 106238259Smckusick char *fname; 106338259Smckusick int flags; 106442441Smckusick } *uap; 106542441Smckusick int *retval; 106642441Smckusick { 106742441Smckusick register struct nameidata *ndp = &u.u_nd; 106838259Smckusick register struct vnode *vp; 106938259Smckusick struct vattr vattr; 107038259Smckusick int error; 107138259Smckusick 107238259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 107338259Smckusick ndp->ni_segflg = UIO_USERSPACE; 107438259Smckusick ndp->ni_dirp = uap->fname; 107541362Smckusick VATTR_NULL(&vattr); 107638259Smckusick vattr.va_flags = uap->flags; 107738259Smckusick if (error = namei(ndp)) 107838259Smckusick RETURN (error); 107938259Smckusick vp = ndp->ni_vp; 108041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 108138259Smckusick error = EROFS; 108238259Smckusick goto out; 108338259Smckusick } 108438259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108538259Smckusick out: 108638259Smckusick vput(vp); 108738259Smckusick RETURN (error); 108838259Smckusick } 108938259Smckusick 109038259Smckusick /* 109138259Smckusick * Change flags of a file given a file descriptor. 109238259Smckusick */ 109342441Smckusick /* ARGSUSED */ 109442441Smckusick fchflags(p, uap, retval) 109542441Smckusick register struct proc *p; 109642441Smckusick register struct args { 109738259Smckusick int fd; 109838259Smckusick int flags; 109942441Smckusick } *uap; 110042441Smckusick int *retval; 110142441Smckusick { 110238259Smckusick struct vattr vattr; 110338259Smckusick struct vnode *vp; 110438259Smckusick struct file *fp; 110538259Smckusick int error; 110638259Smckusick 110742441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 110838259Smckusick RETURN (error); 110941362Smckusick VATTR_NULL(&vattr); 111038259Smckusick vattr.va_flags = uap->flags; 111138259Smckusick vp = (struct vnode *)fp->f_data; 111238259Smckusick VOP_LOCK(vp); 111341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111438259Smckusick error = EROFS; 111538259Smckusick goto out; 111638259Smckusick } 111738259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 111838259Smckusick out: 111938259Smckusick VOP_UNLOCK(vp); 112038259Smckusick RETURN (error); 112138259Smckusick } 112238259Smckusick 112338259Smckusick /* 11249167Ssam * Change mode of a file given path name. 11259167Ssam */ 112642441Smckusick /* ARGSUSED */ 112742441Smckusick chmod(p, uap, retval) 112842441Smckusick register struct proc *p; 112942441Smckusick register struct args { 11306254Sroot char *fname; 11316254Sroot int fmode; 113242441Smckusick } *uap; 113342441Smckusick int *retval; 113442441Smckusick { 113542441Smckusick register struct nameidata *ndp = &u.u_nd; 113637741Smckusick register struct vnode *vp; 113737741Smckusick struct vattr vattr; 113837741Smckusick int error; 11395992Swnj 114037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114237741Smckusick ndp->ni_dirp = uap->fname; 114341362Smckusick VATTR_NULL(&vattr); 114437741Smckusick vattr.va_mode = uap->fmode & 07777; 114537741Smckusick if (error = namei(ndp)) 114637741Smckusick RETURN (error); 114737741Smckusick vp = ndp->ni_vp; 114841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114937741Smckusick error = EROFS; 115037741Smckusick goto out; 115137741Smckusick } 115237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115337741Smckusick out: 115437741Smckusick vput(vp); 115537741Smckusick RETURN (error); 11567701Ssam } 11577439Sroot 11589167Ssam /* 11599167Ssam * Change mode of a file given a file descriptor. 11609167Ssam */ 116142441Smckusick /* ARGSUSED */ 116242441Smckusick fchmod(p, uap, retval) 116342441Smckusick register struct proc *p; 116442441Smckusick register struct args { 11657701Ssam int fd; 11667701Ssam int fmode; 116742441Smckusick } *uap; 116842441Smckusick int *retval; 116942441Smckusick { 117037741Smckusick struct vattr vattr; 117137741Smckusick struct vnode *vp; 117237741Smckusick struct file *fp; 117337741Smckusick int error; 11747701Ssam 117542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 117637741Smckusick RETURN (error); 117741362Smckusick VATTR_NULL(&vattr); 117837741Smckusick vattr.va_mode = uap->fmode & 07777; 117937741Smckusick vp = (struct vnode *)fp->f_data; 118037741Smckusick VOP_LOCK(vp); 118141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118237741Smckusick error = EROFS; 118337741Smckusick goto out; 11847439Sroot } 118537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118637741Smckusick out: 118737741Smckusick VOP_UNLOCK(vp); 118837741Smckusick RETURN (error); 11895992Swnj } 11905992Swnj 11919167Ssam /* 11929167Ssam * Set ownership given a path name. 11939167Ssam */ 119442441Smckusick /* ARGSUSED */ 119542441Smckusick chown(p, uap, retval) 119642441Smckusick register struct proc *p; 119742441Smckusick register struct args { 11986254Sroot char *fname; 11996254Sroot int uid; 12006254Sroot int gid; 120142441Smckusick } *uap; 120242441Smckusick int *retval; 120342441Smckusick { 120442441Smckusick register struct nameidata *ndp = &u.u_nd; 120537741Smckusick register struct vnode *vp; 120637741Smckusick struct vattr vattr; 120737741Smckusick int error; 120837Sbill 120937741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 121036614Sbostic ndp->ni_segflg = UIO_USERSPACE; 121136614Sbostic ndp->ni_dirp = uap->fname; 121241362Smckusick VATTR_NULL(&vattr); 121337741Smckusick vattr.va_uid = uap->uid; 121437741Smckusick vattr.va_gid = uap->gid; 121537741Smckusick if (error = namei(ndp)) 121637741Smckusick RETURN (error); 121737741Smckusick vp = ndp->ni_vp; 121841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121937741Smckusick error = EROFS; 122037741Smckusick goto out; 122137741Smckusick } 122237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 122337741Smckusick out: 122437741Smckusick vput(vp); 122537741Smckusick RETURN (error); 12267701Ssam } 12277439Sroot 12289167Ssam /* 12299167Ssam * Set ownership given a file descriptor. 12309167Ssam */ 123142441Smckusick /* ARGSUSED */ 123242441Smckusick fchown(p, uap, retval) 123342441Smckusick register struct proc *p; 123442441Smckusick register struct args { 12357701Ssam int fd; 12367701Ssam int uid; 12377701Ssam int gid; 123842441Smckusick } *uap; 123942441Smckusick int *retval; 124042441Smckusick { 124137741Smckusick struct vattr vattr; 124237741Smckusick struct vnode *vp; 124337741Smckusick struct file *fp; 124437741Smckusick int error; 12457701Ssam 124642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 124737741Smckusick RETURN (error); 124841362Smckusick VATTR_NULL(&vattr); 124937741Smckusick vattr.va_uid = uap->uid; 125037741Smckusick vattr.va_gid = uap->gid; 125137741Smckusick vp = (struct vnode *)fp->f_data; 125237741Smckusick VOP_LOCK(vp); 125341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125437741Smckusick error = EROFS; 125537741Smckusick goto out; 125637741Smckusick } 125737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 125837741Smckusick out: 125937741Smckusick VOP_UNLOCK(vp); 126037741Smckusick RETURN (error); 12617701Ssam } 12627701Ssam 126342441Smckusick /* 126442441Smckusick * Set the access and modification times of a file. 126542441Smckusick */ 126642441Smckusick /* ARGSUSED */ 126742441Smckusick utimes(p, uap, retval) 126842441Smckusick register struct proc *p; 126942441Smckusick register struct args { 127011811Ssam char *fname; 127111811Ssam struct timeval *tptr; 127242441Smckusick } *uap; 127342441Smckusick int *retval; 127442441Smckusick { 127542441Smckusick register struct nameidata *ndp = &u.u_nd; 127637741Smckusick register struct vnode *vp; 127711811Ssam struct timeval tv[2]; 127837741Smckusick struct vattr vattr; 127937741Smckusick int error; 128011811Ssam 128137741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 128237741Smckusick RETURN (error); 128337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 128437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 128537741Smckusick ndp->ni_dirp = uap->fname; 128641362Smckusick VATTR_NULL(&vattr); 128737741Smckusick vattr.va_atime = tv[0]; 128837741Smckusick vattr.va_mtime = tv[1]; 128937741Smckusick if (error = namei(ndp)) 129037741Smckusick RETURN (error); 129137741Smckusick vp = ndp->ni_vp; 129241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129337741Smckusick error = EROFS; 129437741Smckusick goto out; 129521015Smckusick } 129637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129737741Smckusick out: 129837741Smckusick vput(vp); 129937741Smckusick RETURN (error); 130011811Ssam } 130111811Ssam 13029167Ssam /* 13039167Ssam * Truncate a file given its path name. 13049167Ssam */ 130542441Smckusick /* ARGSUSED */ 130642441Smckusick truncate(p, uap, retval) 130742441Smckusick register struct proc *p; 130842441Smckusick register struct args { 13097701Ssam char *fname; 131026473Skarels off_t length; 131142441Smckusick } *uap; 131242441Smckusick int *retval; 131342441Smckusick { 131442441Smckusick register struct nameidata *ndp = &u.u_nd; 131537741Smckusick register struct vnode *vp; 131637741Smckusick struct vattr vattr; 131737741Smckusick int error; 13187701Ssam 131937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 132016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132116694Smckusick ndp->ni_dirp = uap->fname; 132241362Smckusick VATTR_NULL(&vattr); 132337741Smckusick vattr.va_size = uap->length; 132437741Smckusick if (error = namei(ndp)) 132537741Smckusick RETURN (error); 132637741Smckusick vp = ndp->ni_vp; 132737741Smckusick if (vp->v_type == VDIR) { 132837741Smckusick error = EISDIR; 132937741Smckusick goto out; 13307701Ssam } 133138399Smckusick if ((error = vn_writechk(vp)) || 133238399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 133337741Smckusick goto out; 133437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 133537741Smckusick out: 133637741Smckusick vput(vp); 133737741Smckusick RETURN (error); 13387701Ssam } 13397701Ssam 13409167Ssam /* 13419167Ssam * Truncate a file given a file descriptor. 13429167Ssam */ 134342441Smckusick /* ARGSUSED */ 134442441Smckusick ftruncate(p, uap, retval) 134542441Smckusick register struct proc *p; 134642441Smckusick register struct args { 13477701Ssam int fd; 134826473Skarels off_t length; 134942441Smckusick } *uap; 135042441Smckusick int *retval; 135142441Smckusick { 135237741Smckusick struct vattr vattr; 135337741Smckusick struct vnode *vp; 13547701Ssam struct file *fp; 135537741Smckusick int error; 13567701Ssam 135742441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 135837741Smckusick RETURN (error); 135937741Smckusick if ((fp->f_flag & FWRITE) == 0) 136037741Smckusick RETURN (EINVAL); 136141362Smckusick VATTR_NULL(&vattr); 136237741Smckusick vattr.va_size = uap->length; 136337741Smckusick vp = (struct vnode *)fp->f_data; 136437741Smckusick VOP_LOCK(vp); 136537741Smckusick if (vp->v_type == VDIR) { 136637741Smckusick error = EISDIR; 136737741Smckusick goto out; 13687701Ssam } 136938399Smckusick if (error = vn_writechk(vp)) 137037741Smckusick goto out; 137137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 137237741Smckusick out: 137337741Smckusick VOP_UNLOCK(vp); 137437741Smckusick RETURN (error); 13757701Ssam } 13767701Ssam 13779167Ssam /* 13789167Ssam * Synch an open file. 13799167Ssam */ 138042441Smckusick /* ARGSUSED */ 138142441Smckusick fsync(p, uap, retval) 138242441Smckusick register struct proc *p; 138342441Smckusick struct args { 138442441Smckusick int fd; 138542441Smckusick } *uap; 138642441Smckusick int *retval; 13879167Ssam { 138839592Smckusick register struct vnode *vp; 13899167Ssam struct file *fp; 139037741Smckusick int error; 13919167Ssam 139242441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 139337741Smckusick RETURN (error); 139439592Smckusick vp = (struct vnode *)fp->f_data; 139539592Smckusick VOP_LOCK(vp); 139639592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139739592Smckusick VOP_UNLOCK(vp); 139837741Smckusick RETURN (error); 13999167Ssam } 14009167Ssam 14019167Ssam /* 14029167Ssam * Rename system call. 14039167Ssam * 14049167Ssam * Source and destination must either both be directories, or both 14059167Ssam * not be directories. If target is a directory, it must be empty. 14069167Ssam */ 140742441Smckusick /* ARGSUSED */ 140842441Smckusick rename(p, uap, retval) 140942441Smckusick register struct proc *p; 141042441Smckusick register struct args { 14117701Ssam char *from; 14127701Ssam char *to; 141342441Smckusick } *uap; 141442441Smckusick int *retval; 141542441Smckusick { 141637741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141742441Smckusick register struct nameidata *ndp = &u.u_nd; 141837741Smckusick struct nameidata tond; 141937741Smckusick int error; 14207701Ssam 142137741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 142216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142316694Smckusick ndp->ni_dirp = uap->from; 142437741Smckusick if (error = namei(ndp)) 142537741Smckusick RETURN (error); 142637741Smckusick fvp = ndp->ni_vp; 142738266Smckusick nddup(ndp, &tond); 142837741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 142937741Smckusick tond.ni_segflg = UIO_USERSPACE; 143037741Smckusick tond.ni_dirp = uap->to; 143142465Smckusick if (error = namei(&tond)) { 143242465Smckusick VOP_ABORTOP(ndp); 143342465Smckusick vrele(ndp->ni_dvp); 143442465Smckusick vrele(fvp); 143542465Smckusick goto out1; 143642465Smckusick } 143737741Smckusick tdvp = tond.ni_dvp; 143837741Smckusick tvp = tond.ni_vp; 143937741Smckusick if (tvp != NULL) { 144037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 144139242Sbostic error = ENOTDIR; 144237741Smckusick goto out; 144337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 144439242Sbostic error = EISDIR; 144537741Smckusick goto out; 14469167Ssam } 14479167Ssam } 144837741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144937741Smckusick error = EXDEV; 14509167Ssam goto out; 145110051Ssam } 145239286Smckusick if (fvp == tdvp) 145337741Smckusick error = EINVAL; 145439286Smckusick /* 145539286Smckusick * If source is the same as the destination, 145639286Smckusick * then there is nothing to do. 145739286Smckusick */ 145839286Smckusick if (fvp == tvp) 145939286Smckusick error = -1; 146037741Smckusick out: 146142465Smckusick if (!error) { 146242465Smckusick error = VOP_RENAME(ndp, &tond); 146342465Smckusick } else { 146437741Smckusick VOP_ABORTOP(&tond); 146543344Smckusick if (tdvp == tvp) 146643344Smckusick vrele(tdvp); 146743344Smckusick else 146843344Smckusick vput(tdvp); 146942465Smckusick if (tvp) 147042465Smckusick vput(tvp); 147137741Smckusick VOP_ABORTOP(ndp); 147242465Smckusick vrele(ndp->ni_dvp); 147342465Smckusick vrele(fvp); 14749167Ssam } 147537741Smckusick out1: 147638266Smckusick ndrele(&tond); 147739286Smckusick if (error == -1) 147839286Smckusick RETURN (0); 147937741Smckusick RETURN (error); 14807701Ssam } 14817701Ssam 14827535Sroot /* 148312756Ssam * Mkdir system call 148412756Ssam */ 148542441Smckusick /* ARGSUSED */ 148642441Smckusick mkdir(p, uap, retval) 148742441Smckusick register struct proc *p; 148842441Smckusick register struct args { 148912756Ssam char *name; 149012756Ssam int dmode; 149142441Smckusick } *uap; 149242441Smckusick int *retval; 149342441Smckusick { 149442441Smckusick register struct nameidata *ndp = &u.u_nd; 149537741Smckusick register struct vnode *vp; 149637741Smckusick struct vattr vattr; 149737741Smckusick int error; 149812756Ssam 149937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 150016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 150116694Smckusick ndp->ni_dirp = uap->name; 150237741Smckusick if (error = namei(ndp)) 150337741Smckusick RETURN (error); 150437741Smckusick vp = ndp->ni_vp; 150537741Smckusick if (vp != NULL) { 150637741Smckusick VOP_ABORTOP(ndp); 150743344Smckusick if (ndp->ni_dvp == vp) 150843344Smckusick vrele(ndp->ni_dvp); 150943344Smckusick else 151043344Smckusick vput(ndp->ni_dvp); 151142465Smckusick vrele(vp); 151237741Smckusick RETURN (EEXIST); 151312756Ssam } 151441362Smckusick VATTR_NULL(&vattr); 151537741Smckusick vattr.va_type = VDIR; 151642441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 151737741Smckusick error = VOP_MKDIR(ndp, &vattr); 151838145Smckusick if (!error) 151938145Smckusick vput(ndp->ni_vp); 152037741Smckusick RETURN (error); 152112756Ssam } 152212756Ssam 152312756Ssam /* 152412756Ssam * Rmdir system call. 152512756Ssam */ 152642441Smckusick /* ARGSUSED */ 152742441Smckusick rmdir(p, uap, retval) 152842441Smckusick register struct proc *p; 152942441Smckusick struct args { 153042441Smckusick char *name; 153142441Smckusick } *uap; 153242441Smckusick int *retval; 153312756Ssam { 153442441Smckusick register struct nameidata *ndp = &u.u_nd; 153537741Smckusick register struct vnode *vp; 153637741Smckusick int error; 153712756Ssam 153837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 154016694Smckusick ndp->ni_dirp = uap->name; 154137741Smckusick if (error = namei(ndp)) 154237741Smckusick RETURN (error); 154337741Smckusick vp = ndp->ni_vp; 154437741Smckusick if (vp->v_type != VDIR) { 154537741Smckusick error = ENOTDIR; 154612756Ssam goto out; 154712756Ssam } 154812756Ssam /* 154937741Smckusick * No rmdir "." please. 155012756Ssam */ 155137741Smckusick if (ndp->ni_dvp == vp) { 155237741Smckusick error = EINVAL; 155312756Ssam goto out; 155412756Ssam } 155512756Ssam /* 155637741Smckusick * Don't unlink a mounted file. 155712756Ssam */ 155837741Smckusick if (vp->v_flag & VROOT) 155937741Smckusick error = EBUSY; 156012756Ssam out: 156142465Smckusick if (!error) { 156242465Smckusick error = VOP_RMDIR(ndp); 156342465Smckusick } else { 156437741Smckusick VOP_ABORTOP(ndp); 156543344Smckusick if (ndp->ni_dvp == vp) 156643344Smckusick vrele(ndp->ni_dvp); 156743344Smckusick else 156843344Smckusick vput(ndp->ni_dvp); 156942465Smckusick vput(vp); 157042465Smckusick } 157137741Smckusick RETURN (error); 157212756Ssam } 157312756Ssam 157437741Smckusick /* 157537741Smckusick * Read a block of directory entries in a file system independent format 157637741Smckusick */ 157742441Smckusick getdirentries(p, uap, retval) 157842441Smckusick register struct proc *p; 157942441Smckusick register struct args { 158037741Smckusick int fd; 158137741Smckusick char *buf; 158237741Smckusick unsigned count; 158337741Smckusick long *basep; 158442441Smckusick } *uap; 158542441Smckusick int *retval; 158642441Smckusick { 158739592Smckusick register struct vnode *vp; 158816540Ssam struct file *fp; 158937741Smckusick struct uio auio; 159037741Smckusick struct iovec aiov; 159138129Smckusick off_t off; 159240321Smckusick int error, eofflag; 159312756Ssam 159442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 159537741Smckusick RETURN (error); 159637741Smckusick if ((fp->f_flag & FREAD) == 0) 159737741Smckusick RETURN (EBADF); 159839592Smckusick vp = (struct vnode *)fp->f_data; 159939592Smckusick if (vp->v_type != VDIR) 160039592Smckusick RETURN (EINVAL); 160137741Smckusick aiov.iov_base = uap->buf; 160237741Smckusick aiov.iov_len = uap->count; 160337741Smckusick auio.uio_iov = &aiov; 160437741Smckusick auio.uio_iovcnt = 1; 160537741Smckusick auio.uio_rw = UIO_READ; 160637741Smckusick auio.uio_segflg = UIO_USERSPACE; 160737741Smckusick auio.uio_resid = uap->count; 160839592Smckusick VOP_LOCK(vp); 160939592Smckusick auio.uio_offset = off = fp->f_offset; 161040321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 161139592Smckusick fp->f_offset = auio.uio_offset; 161239592Smckusick VOP_UNLOCK(vp); 161339592Smckusick if (error) 161437741Smckusick RETURN (error); 161539592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 161642441Smckusick *retval = uap->count - auio.uio_resid; 161737741Smckusick RETURN (error); 161812756Ssam } 161912756Ssam 162012756Ssam /* 162112756Ssam * mode mask for creation of files 162212756Ssam */ 162342441Smckusick mode_t 162442441Smckusick umask(p, uap, retval) 162542441Smckusick register struct proc *p; 162642441Smckusick struct args { 162742441Smckusick int mask; 162842441Smckusick } *uap; 162942441Smckusick int *retval; 163012756Ssam { 163112756Ssam 163242441Smckusick *retval = u.u_cmask; 163342441Smckusick u.u_cmask = uap->mask & 07777; 163437741Smckusick RETURN (0); 163512756Ssam } 163637741Smckusick 163739566Smarc /* 163839566Smarc * Void all references to file by ripping underlying filesystem 163939566Smarc * away from vnode. 164039566Smarc */ 164142441Smckusick /* ARGSUSED */ 164242441Smckusick revoke(p, uap, retval) 164342441Smckusick register struct proc *p; 164442441Smckusick register struct args { 164539566Smarc char *fname; 164642441Smckusick } *uap; 164742441Smckusick int *retval; 164842441Smckusick { 164942441Smckusick register struct nameidata *ndp = &u.u_nd; 165039566Smarc register struct vnode *vp; 165139566Smarc struct vattr vattr; 165239566Smarc int error; 165339566Smarc 165439566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 165539566Smarc ndp->ni_segflg = UIO_USERSPACE; 165639566Smarc ndp->ni_dirp = uap->fname; 165739566Smarc if (error = namei(ndp)) 165839566Smarc RETURN (error); 165939566Smarc vp = ndp->ni_vp; 166039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 166139566Smarc error = EINVAL; 166239566Smarc goto out; 166339566Smarc } 166442441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 166539566Smarc goto out; 166642955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 166742441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 166839566Smarc goto out; 166939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 167039632Smckusick vgoneall(vp); 167139566Smarc out: 167239566Smarc vrele(vp); 167339566Smarc RETURN (error); 167439566Smarc } 167539566Smarc 167638408Smckusick getvnode(ofile, fdes, fpp) 167738408Smckusick struct file *ofile[]; 167837741Smckusick struct file **fpp; 167937741Smckusick int fdes; 168037741Smckusick { 168137741Smckusick struct file *fp; 168237741Smckusick 168338408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 168437741Smckusick return (EBADF); 168537741Smckusick if (fp->f_type != DTYPE_VNODE) 168637741Smckusick return (EINVAL); 168737741Smckusick *fpp = fp; 168837741Smckusick return (0); 168937741Smckusick } 1690