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*43405Smckusick * @(#)vfs_syscalls.c 7.53 (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 32*43405Smckusick #define p_devtmp p_logname[11] 33*43405Smckusick 3439797Smckusick #undef RETURN 3542441Smckusick #define RETURN(val) { u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); } 3639797Smckusick 3737741Smckusick /* 3837741Smckusick * Virtual File System System Calls 3937741Smckusick */ 4012756Ssam 419167Ssam /* 4237741Smckusick * mount system call 439167Ssam */ 4442441Smckusick /* ARGSUSED */ 4542441Smckusick mount(p, uap, retval) 4642441Smckusick register struct proc *p; 4742441Smckusick register struct args { 4837741Smckusick int type; 4937741Smckusick char *dir; 5037741Smckusick int flags; 5137741Smckusick caddr_t data; 5242441Smckusick } *uap; 5342441Smckusick int *retval; 5442441Smckusick { 5542441Smckusick register struct nameidata *ndp = &u.u_nd; 5639335Smckusick register struct vnode *vp; 5739335Smckusick register struct mount *mp; 5840111Smckusick int error, flag; 596254Sroot 6037741Smckusick /* 6137741Smckusick * Must be super user 6237741Smckusick */ 6342441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 6437741Smckusick RETURN (error); 6537741Smckusick /* 6637741Smckusick * Get vnode to be covered 6737741Smckusick */ 6837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 7037741Smckusick ndp->ni_dirp = uap->dir; 7137741Smckusick if (error = namei(ndp)) 7237741Smckusick RETURN (error); 7337741Smckusick vp = ndp->ni_vp; 7441400Smckusick if (uap->flags & MNT_UPDATE) { 7539335Smckusick if ((vp->v_flag & VROOT) == 0) { 7639335Smckusick vput(vp); 7739335Smckusick RETURN (EINVAL); 7839335Smckusick } 7939335Smckusick mp = vp->v_mount; 8039335Smckusick /* 8139335Smckusick * We allow going from read-only to read-write, 8239335Smckusick * but not from read-write to read-only. 8339335Smckusick */ 8441400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 8541400Smckusick (uap->flags & MNT_RDONLY) != 0) { 8639335Smckusick vput(vp); 8739335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8839335Smckusick } 8941400Smckusick flag = mp->mnt_flag; 9041400Smckusick mp->mnt_flag |= MNT_UPDATE; 9139335Smckusick VOP_UNLOCK(vp); 9239335Smckusick goto update; 9339335Smckusick } 9439665Smckusick vinvalbuf(vp, 1); 9539805Smckusick if (vp->v_usecount != 1) { 9637741Smckusick vput(vp); 9737741Smckusick RETURN (EBUSY); 9837741Smckusick } 9937741Smckusick if (vp->v_type != VDIR) { 10037741Smckusick vput(vp); 10137741Smckusick RETURN (ENOTDIR); 10237741Smckusick } 10339741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10437741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10537741Smckusick vput(vp); 10637741Smckusick RETURN (ENODEV); 10737741Smckusick } 10837741Smckusick 10937741Smckusick /* 11039335Smckusick * Allocate and initialize the file system. 11137741Smckusick */ 11237741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 11337741Smckusick M_MOUNT, M_WAITOK); 11441400Smckusick mp->mnt_op = vfssw[uap->type]; 11541400Smckusick mp->mnt_flag = 0; 11641400Smckusick mp->mnt_exroot = 0; 11741400Smckusick mp->mnt_mounth = NULLVP; 11839335Smckusick if (error = vfs_lock(mp)) { 11939335Smckusick free((caddr_t)mp, M_MOUNT); 12039335Smckusick vput(vp); 12139335Smckusick RETURN (error); 12239335Smckusick } 12339335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12439335Smckusick vfs_unlock(mp); 12539335Smckusick free((caddr_t)mp, M_MOUNT); 12639335Smckusick vput(vp); 12739335Smckusick RETURN (EBUSY); 12839335Smckusick } 12939335Smckusick vp->v_mountedhere = mp; 13041400Smckusick mp->mnt_vnodecovered = vp; 13139335Smckusick update: 13239335Smckusick /* 13339335Smckusick * Set the mount level flags. 13439335Smckusick */ 13541400Smckusick if (uap->flags & MNT_RDONLY) 13641400Smckusick mp->mnt_flag |= MNT_RDONLY; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13941400Smckusick if (uap->flags & MNT_NOSUID) 14041400Smckusick mp->mnt_flag |= MNT_NOSUID; 14139335Smckusick else 14241400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 14341400Smckusick if (uap->flags & MNT_NOEXEC) 14441400Smckusick mp->mnt_flag |= MNT_NOEXEC; 14539335Smckusick else 14641400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 14741400Smckusick if (uap->flags & MNT_NODEV) 14841400Smckusick mp->mnt_flag |= MNT_NODEV; 14939335Smckusick else 15041400Smckusick mp->mnt_flag &= ~MNT_NODEV; 15141400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 15241400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 15339335Smckusick else 15441400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 15539335Smckusick /* 15639335Smckusick * Mount the filesystem. 15739335Smckusick */ 15839335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15941400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 16041400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 16139335Smckusick vrele(vp); 16240111Smckusick if (error) 16341400Smckusick mp->mnt_flag = flag; 16439335Smckusick RETURN (error); 16539335Smckusick } 16640110Smckusick /* 16740110Smckusick * Put the new filesystem on the mount list after root. 16840110Smckusick */ 16941400Smckusick mp->mnt_next = rootfs->mnt_next; 17041400Smckusick mp->mnt_prev = rootfs; 17141400Smckusick rootfs->mnt_next = mp; 17241400Smckusick mp->mnt_next->mnt_prev = mp; 17337741Smckusick cache_purge(vp); 17437741Smckusick if (!error) { 17539335Smckusick VOP_UNLOCK(vp); 17637741Smckusick vfs_unlock(mp); 17739044Smckusick error = VFS_START(mp, 0); 17837741Smckusick } else { 17937741Smckusick vfs_remove(mp); 18037741Smckusick free((caddr_t)mp, M_MOUNT); 18139335Smckusick vput(vp); 18237741Smckusick } 18337741Smckusick RETURN (error); 1846254Sroot } 1856254Sroot 1869167Ssam /* 18737741Smckusick * Unmount system call. 18837741Smckusick * 18937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 19037741Smckusick * not special file (as before). 1919167Ssam */ 19242441Smckusick /* ARGSUSED */ 19342441Smckusick unmount(p, uap, retval) 19442441Smckusick register struct proc *p; 19542441Smckusick register struct args { 19637741Smckusick char *pathp; 19737741Smckusick int flags; 19842441Smckusick } *uap; 19942441Smckusick int *retval; 20042441Smckusick { 20137741Smckusick register struct vnode *vp; 20242441Smckusick register struct nameidata *ndp = &u.u_nd; 20339356Smckusick struct mount *mp; 20437741Smckusick int error; 2056254Sroot 20637741Smckusick /* 20737741Smckusick * Must be super user 20837741Smckusick */ 20942441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 21037741Smckusick RETURN (error); 21137741Smckusick 21237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 21337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 21437741Smckusick ndp->ni_dirp = uap->pathp; 21537741Smckusick if (error = namei(ndp)) 21637741Smckusick RETURN (error); 21737741Smckusick vp = ndp->ni_vp; 21837741Smckusick /* 21937741Smckusick * Must be the root of the filesystem 22037741Smckusick */ 22137741Smckusick if ((vp->v_flag & VROOT) == 0) { 22237741Smckusick vput(vp); 22337741Smckusick RETURN (EINVAL); 22437741Smckusick } 22537741Smckusick mp = vp->v_mount; 22637741Smckusick vput(vp); 22739356Smckusick RETURN (dounmount(mp, uap->flags)); 22839356Smckusick } 22939356Smckusick 23039356Smckusick /* 23139356Smckusick * Do an unmount. 23239356Smckusick */ 23339356Smckusick dounmount(mp, flags) 23439356Smckusick register struct mount *mp; 23539356Smckusick int flags; 23639356Smckusick { 23739356Smckusick struct vnode *coveredvp; 23839356Smckusick int error; 23939356Smckusick 24041400Smckusick coveredvp = mp->mnt_vnodecovered; 24141298Smckusick if (vfs_busy(mp)) 24241298Smckusick return (EBUSY); 24341400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 24437741Smckusick if (error = vfs_lock(mp)) 24539356Smckusick return (error); 24637741Smckusick 24737741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24941676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 25041676Smckusick error = VFS_UNMOUNT(mp, flags); 25141400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 25241298Smckusick vfs_unbusy(mp); 25337741Smckusick if (error) { 25437741Smckusick vfs_unlock(mp); 25537741Smckusick } else { 25637741Smckusick vrele(coveredvp); 25737741Smckusick vfs_remove(mp); 25837741Smckusick free((caddr_t)mp, M_MOUNT); 25937741Smckusick } 26039356Smckusick return (error); 2616254Sroot } 2626254Sroot 2639167Ssam /* 26437741Smckusick * Sync system call. 26537741Smckusick * Sync each mounted filesystem. 2669167Ssam */ 26739491Smckusick /* ARGSUSED */ 26842441Smckusick sync(p, uap, retval) 26942441Smckusick register struct proc *p; 27042441Smckusick struct args *uap; 27142441Smckusick int *retval; 2726254Sroot { 27337741Smckusick register struct mount *mp; 27441298Smckusick struct mount *omp; 27537741Smckusick 27637741Smckusick mp = rootfs; 27737741Smckusick do { 27840343Smckusick /* 27940343Smckusick * The lock check below is to avoid races with mount 28040343Smckusick * and unmount. 28140343Smckusick */ 28241400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28341298Smckusick !vfs_busy(mp)) { 28437741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28541298Smckusick omp = mp; 28641400Smckusick mp = mp->mnt_next; 28741298Smckusick vfs_unbusy(omp); 28841298Smckusick } else 28941400Smckusick mp = mp->mnt_next; 29037741Smckusick } while (mp != rootfs); 29137741Smckusick } 29237741Smckusick 29337741Smckusick /* 29441298Smckusick * operate on filesystem quotas 29541298Smckusick */ 29642441Smckusick /* ARGSUSED */ 29742441Smckusick quotactl(p, uap, retval) 29842441Smckusick register struct proc *p; 29942441Smckusick register struct args { 30041298Smckusick char *path; 30141298Smckusick int cmd; 30241298Smckusick int uid; 30341298Smckusick caddr_t arg; 30442441Smckusick } *uap; 30542441Smckusick int *retval; 30642441Smckusick { 30741298Smckusick register struct mount *mp; 30842441Smckusick register struct nameidata *ndp = &u.u_nd; 30941298Smckusick int error; 31041298Smckusick 31141298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31241298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31341298Smckusick ndp->ni_dirp = uap->path; 31441298Smckusick if (error = namei(ndp)) 31541298Smckusick RETURN (error); 31641298Smckusick mp = ndp->ni_vp->v_mount; 31741298Smckusick vrele(ndp->ni_vp); 31841298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31941298Smckusick } 32041298Smckusick 32141298Smckusick /* 32237741Smckusick * get filesystem statistics 32337741Smckusick */ 32442441Smckusick /* ARGSUSED */ 32542441Smckusick statfs(p, uap, retval) 32642441Smckusick register struct proc *p; 32742441Smckusick register struct args { 32837741Smckusick char *path; 32937741Smckusick struct statfs *buf; 33042441Smckusick } *uap; 33142441Smckusick int *retval; 33242441Smckusick { 33339464Smckusick register struct mount *mp; 33442441Smckusick register struct nameidata *ndp = &u.u_nd; 33540343Smckusick register struct statfs *sp; 33637741Smckusick int error; 33737741Smckusick 33839544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 34037741Smckusick ndp->ni_dirp = uap->path; 34137741Smckusick if (error = namei(ndp)) 34237741Smckusick RETURN (error); 34339544Smckusick mp = ndp->ni_vp->v_mount; 34441400Smckusick sp = &mp->mnt_stat; 34539544Smckusick vrele(ndp->ni_vp); 34640343Smckusick if (error = VFS_STATFS(mp, sp)) 34739544Smckusick RETURN (error); 34841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34940343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35037741Smckusick } 35137741Smckusick 35242441Smckusick /* 35342441Smckusick * get filesystem statistics 35442441Smckusick */ 35542441Smckusick /* ARGSUSED */ 35642441Smckusick fstatfs(p, uap, retval) 35742441Smckusick register struct proc *p; 35842441Smckusick register struct args { 35937741Smckusick int fd; 36037741Smckusick struct statfs *buf; 36142441Smckusick } *uap; 36242441Smckusick int *retval; 36342441Smckusick { 36437741Smckusick struct file *fp; 36539464Smckusick struct mount *mp; 36640343Smckusick register struct statfs *sp; 36737741Smckusick int error; 36837741Smckusick 36942441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 37037741Smckusick RETURN (error); 37139464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37241400Smckusick sp = &mp->mnt_stat; 37340343Smckusick if (error = VFS_STATFS(mp, sp)) 37437741Smckusick RETURN (error); 37541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37640343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37737741Smckusick } 37837741Smckusick 37937741Smckusick /* 38038270Smckusick * get statistics on all filesystems 38138270Smckusick */ 38242441Smckusick getfsstat(p, uap, retval) 38342441Smckusick register struct proc *p; 38442441Smckusick register struct args { 38538270Smckusick struct statfs *buf; 38638270Smckusick long bufsize; 38740343Smckusick int flags; 38842441Smckusick } *uap; 38942441Smckusick int *retval; 39042441Smckusick { 39138270Smckusick register struct mount *mp; 39240343Smckusick register struct statfs *sp; 39339606Smckusick caddr_t sfsp; 39438270Smckusick long count, maxcount, error; 39538270Smckusick 39638270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39739606Smckusick sfsp = (caddr_t)uap->buf; 39838270Smckusick mp = rootfs; 39938270Smckusick count = 0; 40038270Smckusick do { 40141400Smckusick if (sfsp && count < maxcount && 40241400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40341400Smckusick sp = &mp->mnt_stat; 40440343Smckusick /* 40540343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40640343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40740343Smckusick */ 40840343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40940343Smckusick (uap->flags & MNT_WAIT)) && 41040343Smckusick (error = VFS_STATFS(mp, sp))) { 41141400Smckusick mp = mp->mnt_prev; 41239607Smckusick continue; 41339607Smckusick } 41441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41540343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41639606Smckusick RETURN (error); 41740343Smckusick sfsp += sizeof(*sp); 41838270Smckusick } 41939606Smckusick count++; 42041400Smckusick mp = mp->mnt_prev; 42138270Smckusick } while (mp != rootfs); 42238270Smckusick if (sfsp && count > maxcount) 42342441Smckusick *retval = maxcount; 42438270Smckusick else 42542441Smckusick *retval = count; 42638270Smckusick RETURN (0); 42738270Smckusick } 42838270Smckusick 42938270Smckusick /* 43038259Smckusick * Change current working directory to a given file descriptor. 43138259Smckusick */ 43242441Smckusick /* ARGSUSED */ 43342441Smckusick fchdir(p, uap, retval) 43442441Smckusick register struct proc *p; 43542441Smckusick struct args { 43642441Smckusick int fd; 43742441Smckusick } *uap; 43842441Smckusick int *retval; 43938259Smckusick { 44042441Smckusick register struct nameidata *ndp = &u.u_nd; 44138259Smckusick register struct vnode *vp; 44238259Smckusick struct file *fp; 44338259Smckusick int error; 44438259Smckusick 44542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 44638259Smckusick RETURN (error); 44738259Smckusick vp = (struct vnode *)fp->f_data; 44838259Smckusick VOP_LOCK(vp); 44938259Smckusick if (vp->v_type != VDIR) 45038259Smckusick error = ENOTDIR; 45138259Smckusick else 45242441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45338259Smckusick VOP_UNLOCK(vp); 45439860Smckusick if (error) 45539860Smckusick RETURN (error); 45639860Smckusick VREF(vp); 45742441Smckusick vrele(ndp->ni_cdir); 45842441Smckusick ndp->ni_cdir = vp; 45939860Smckusick RETURN (0); 46038259Smckusick } 46138259Smckusick 46238259Smckusick /* 46337741Smckusick * Change current working directory (``.''). 46437741Smckusick */ 46542441Smckusick /* ARGSUSED */ 46642441Smckusick chdir(p, uap, retval) 46742441Smckusick register struct proc *p; 46842441Smckusick struct args { 46942441Smckusick char *fname; 47042441Smckusick } *uap; 47142441Smckusick int *retval; 47237741Smckusick { 47342441Smckusick register struct nameidata *ndp = &u.u_nd; 47437741Smckusick int error; 4756254Sroot 47637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47816694Smckusick ndp->ni_dirp = uap->fname; 47937741Smckusick if (error = chdirec(ndp)) 48037741Smckusick RETURN (error); 48142441Smckusick vrele(ndp->ni_cdir); 48242441Smckusick ndp->ni_cdir = ndp->ni_vp; 48337741Smckusick RETURN (0); 48437741Smckusick } 4856254Sroot 48637741Smckusick /* 48737741Smckusick * Change notion of root (``/'') directory. 48837741Smckusick */ 48942441Smckusick /* ARGSUSED */ 49042441Smckusick chroot(p, uap, retval) 49142441Smckusick register struct proc *p; 49242441Smckusick struct args { 49342441Smckusick char *fname; 49442441Smckusick } *uap; 49542441Smckusick int *retval; 49637741Smckusick { 49742441Smckusick register struct nameidata *ndp = &u.u_nd; 49837741Smckusick int error; 49937741Smckusick 50042441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 50137741Smckusick RETURN (error); 50237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50437741Smckusick ndp->ni_dirp = uap->fname; 50537741Smckusick if (error = chdirec(ndp)) 50637741Smckusick RETURN (error); 50742441Smckusick if (ndp->ni_rdir != NULL) 50842441Smckusick vrele(ndp->ni_rdir); 50942441Smckusick ndp->ni_rdir = ndp->ni_vp; 51037741Smckusick RETURN (0); 5116254Sroot } 5126254Sroot 51337Sbill /* 51437741Smckusick * Common routine for chroot and chdir. 51537741Smckusick */ 51637741Smckusick chdirec(ndp) 51737741Smckusick register struct nameidata *ndp; 51837741Smckusick { 51937741Smckusick struct vnode *vp; 52037741Smckusick int error; 52137741Smckusick 52237741Smckusick if (error = namei(ndp)) 52337741Smckusick return (error); 52437741Smckusick vp = ndp->ni_vp; 52537741Smckusick if (vp->v_type != VDIR) 52637741Smckusick error = ENOTDIR; 52737741Smckusick else 52838399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52937741Smckusick VOP_UNLOCK(vp); 53037741Smckusick if (error) 53137741Smckusick vrele(vp); 53237741Smckusick return (error); 53337741Smckusick } 53437741Smckusick 53537741Smckusick /* 5366254Sroot * Open system call. 53742441Smckusick * Check permissions, allocate an open file structure, 53842441Smckusick * and call the device open routine if any. 5396254Sroot */ 54042441Smckusick open(p, uap, retval) 54142441Smckusick register struct proc *p; 54242441Smckusick register struct args { 5436254Sroot char *fname; 5447701Ssam int mode; 54512756Ssam int crtmode; 54642441Smckusick } *uap; 54742441Smckusick int *retval; 5486254Sroot { 54942441Smckusick struct nameidata *ndp = &u.u_nd; 55042441Smckusick register struct file *fp; 55137741Smckusick int fmode, cmode; 55237741Smckusick struct file *nfp; 55337741Smckusick int indx, error; 55437741Smckusick extern struct fileops vnops; 5556254Sroot 55637741Smckusick if (error = falloc(&nfp, &indx)) 55742441Smckusick RETURN (error); 55837741Smckusick fp = nfp; 55942441Smckusick fmode = uap->mode - FOPEN; 56042441Smckusick cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; 56142441Smckusick ndp->ni_segflg = UIO_USERSPACE; 56242441Smckusick ndp->ni_dirp = uap->fname; 563*43405Smckusick p->p_devtmp = -1; /* XXX check for fdopen */ 56442441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56537741Smckusick crfree(fp->f_cred); 56637741Smckusick fp->f_count--; 567*43405Smckusick if (error == ENODEV && /* XXX from fdopen */ 568*43405Smckusick p->p_devtmp >= 0 && 569*43405Smckusick (error = dupfdopen(indx, p->p_devtmp, fmode)) == 0) { 57042441Smckusick *retval = indx; 57142441Smckusick RETURN (0); 57242441Smckusick } 57340884Smckusick if (error == ERESTART) 57440884Smckusick error = EINTR; 57542441Smckusick u.u_ofile[indx] = NULL; 57642441Smckusick RETURN (error); 57712756Ssam } 57837741Smckusick fp->f_flag = fmode & FMASK; 57937741Smckusick fp->f_type = DTYPE_VNODE; 58037741Smckusick fp->f_ops = &vnops; 58137741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 58242441Smckusick *retval = indx; 58342441Smckusick RETURN (0); 5846254Sroot } 5856254Sroot 58642955Smckusick #ifdef COMPAT_43 5876254Sroot /* 58842441Smckusick * Creat system call. 5896254Sroot */ 59042955Smckusick ocreat(p, uap, retval) 59142441Smckusick struct proc *p; 59242441Smckusick register struct args { 59342441Smckusick char *fname; 59442441Smckusick int fmode; 59542441Smckusick } *uap; 59642441Smckusick int *retval; 5976254Sroot { 59842441Smckusick struct args { 5996254Sroot char *fname; 60042441Smckusick int mode; 60142441Smckusick int crtmode; 60242441Smckusick } openuap; 60342441Smckusick 60442441Smckusick openuap.fname = uap->fname; 60542441Smckusick openuap.crtmode = uap->fmode; 60642441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60742441Smckusick RETURN (open(p, &openuap, retval)); 60842441Smckusick } 60942955Smckusick #endif /* COMPAT_43 */ 61042441Smckusick 61142441Smckusick /* 61242441Smckusick * Mknod system call 61342441Smckusick */ 61442441Smckusick /* ARGSUSED */ 61542441Smckusick mknod(p, uap, retval) 61642441Smckusick register struct proc *p; 61742441Smckusick register struct args { 61842441Smckusick char *fname; 6196254Sroot int fmode; 6206254Sroot int dev; 62142441Smckusick } *uap; 62242441Smckusick int *retval; 62342441Smckusick { 62442441Smckusick register struct nameidata *ndp = &u.u_nd; 62537741Smckusick register struct vnode *vp; 62637741Smckusick struct vattr vattr; 62737741Smckusick int error; 6286254Sroot 62942441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 63037741Smckusick RETURN (error); 63137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 63216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 63316694Smckusick ndp->ni_dirp = uap->fname; 63437741Smckusick if (error = namei(ndp)) 63537741Smckusick RETURN (error); 63637741Smckusick vp = ndp->ni_vp; 63737741Smckusick if (vp != NULL) { 63837741Smckusick error = EEXIST; 63912756Ssam goto out; 6406254Sroot } 64141362Smckusick VATTR_NULL(&vattr); 64240635Smckusick switch (uap->fmode & S_IFMT) { 64312756Ssam 64440635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64537741Smckusick vattr.va_type = VBAD; 64637741Smckusick break; 64740635Smckusick case S_IFCHR: 64837741Smckusick vattr.va_type = VCHR; 64937741Smckusick break; 65040635Smckusick case S_IFBLK: 65137741Smckusick vattr.va_type = VBLK; 65237741Smckusick break; 65337741Smckusick default: 65437741Smckusick error = EINVAL; 65537741Smckusick goto out; 6566254Sroot } 65742441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 65837741Smckusick vattr.va_rdev = uap->dev; 6596254Sroot out: 66042465Smckusick if (!error) { 66142465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 66242465Smckusick } else { 66337741Smckusick VOP_ABORTOP(ndp); 66443344Smckusick if (ndp->ni_dvp == vp) 66543344Smckusick vrele(ndp->ni_dvp); 66643344Smckusick else 66743344Smckusick vput(ndp->ni_dvp); 66842465Smckusick if (vp) 66942465Smckusick vrele(vp); 67042465Smckusick } 67137741Smckusick RETURN (error); 6726254Sroot } 6736254Sroot 6746254Sroot /* 67540285Smckusick * Mkfifo system call 67640285Smckusick */ 67742441Smckusick /* ARGSUSED */ 67842441Smckusick mkfifo(p, uap, retval) 67942441Smckusick register struct proc *p; 68042441Smckusick register struct args { 68140285Smckusick char *fname; 68240285Smckusick int fmode; 68342441Smckusick } *uap; 68442441Smckusick int *retval; 68542441Smckusick { 68642441Smckusick register struct nameidata *ndp = &u.u_nd; 68740285Smckusick struct vattr vattr; 68840285Smckusick int error; 68940285Smckusick 69040285Smckusick #ifndef FIFO 69140285Smckusick RETURN (EOPNOTSUPP); 69240285Smckusick #else 69340285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69440285Smckusick ndp->ni_segflg = UIO_USERSPACE; 69540285Smckusick ndp->ni_dirp = uap->fname; 69640285Smckusick if (error = namei(ndp)) 69740285Smckusick RETURN (error); 69840285Smckusick if (ndp->ni_vp != NULL) { 69940285Smckusick VOP_ABORTOP(ndp); 70043344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 70143344Smckusick vrele(ndp->ni_dvp); 70243344Smckusick else 70343344Smckusick vput(ndp->ni_dvp); 70442465Smckusick vrele(ndp->ni_vp); 70540285Smckusick RETURN (EEXIST); 70640285Smckusick } else { 70741362Smckusick VATTR_NULL(&vattr); 70840285Smckusick vattr.va_type = VFIFO; 70942441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 71040285Smckusick } 71140285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 71240285Smckusick #endif /* FIFO */ 71340285Smckusick } 71440285Smckusick 71540285Smckusick /* 7166254Sroot * link system call 7176254Sroot */ 71842441Smckusick /* ARGSUSED */ 71942441Smckusick link(p, uap, retval) 72042441Smckusick register struct proc *p; 72142441Smckusick register struct args { 7226254Sroot char *target; 7236254Sroot char *linkname; 72442441Smckusick } *uap; 72542441Smckusick int *retval; 72642441Smckusick { 72742441Smckusick register struct nameidata *ndp = &u.u_nd; 72837741Smckusick register struct vnode *vp, *xp; 72937741Smckusick int error; 7306254Sroot 73116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 73216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73316694Smckusick ndp->ni_dirp = uap->target; 73437741Smckusick if (error = namei(ndp)) 73537741Smckusick RETURN (error); 73637741Smckusick vp = ndp->ni_vp; 73737741Smckusick if (vp->v_type == VDIR && 73842441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73937741Smckusick goto out1; 74037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 74116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 74237741Smckusick if (error = namei(ndp)) 74337741Smckusick goto out1; 74437741Smckusick xp = ndp->ni_vp; 7456254Sroot if (xp != NULL) { 74637741Smckusick error = EEXIST; 7476254Sroot goto out; 7486254Sroot } 74937741Smckusick xp = ndp->ni_dvp; 75037741Smckusick if (vp->v_mount != xp->v_mount) 75137741Smckusick error = EXDEV; 7526254Sroot out: 75342465Smckusick if (!error) { 75442465Smckusick error = VOP_LINK(vp, ndp); 75542465Smckusick } else { 75637741Smckusick VOP_ABORTOP(ndp); 75743344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 75843344Smckusick vrele(ndp->ni_dvp); 75943344Smckusick else 76043344Smckusick vput(ndp->ni_dvp); 76142465Smckusick if (ndp->ni_vp) 76242465Smckusick vrele(ndp->ni_vp); 76342465Smckusick } 76437741Smckusick out1: 76537741Smckusick vrele(vp); 76637741Smckusick RETURN (error); 7676254Sroot } 7686254Sroot 7696254Sroot /* 7706254Sroot * symlink -- make a symbolic link 7716254Sroot */ 77242441Smckusick /* ARGSUSED */ 77342441Smckusick symlink(p, uap, retval) 77442441Smckusick register struct proc *p; 77542441Smckusick register struct args { 7766254Sroot char *target; 7776254Sroot char *linkname; 77842441Smckusick } *uap; 77942441Smckusick int *retval; 78042441Smckusick { 78142441Smckusick register struct nameidata *ndp = &u.u_nd; 78237741Smckusick struct vattr vattr; 78337741Smckusick char *target; 78437741Smckusick int error; 7856254Sroot 78616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78716694Smckusick ndp->ni_dirp = uap->linkname; 78837741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78937741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 79042465Smckusick goto out; 79137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 79237741Smckusick if (error = namei(ndp)) 79342465Smckusick goto out; 79442465Smckusick if (ndp->ni_vp) { 79542465Smckusick VOP_ABORTOP(ndp); 79643344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 79743344Smckusick vrele(ndp->ni_dvp); 79843344Smckusick else 79943344Smckusick vput(ndp->ni_dvp); 80042465Smckusick vrele(ndp->ni_vp); 80137741Smckusick error = EEXIST; 80237741Smckusick goto out; 8036254Sroot } 80441362Smckusick VATTR_NULL(&vattr); 80542441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 80642465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 80737741Smckusick out: 80837741Smckusick FREE(target, M_NAMEI); 80937741Smckusick RETURN (error); 8106254Sroot } 8116254Sroot 8126254Sroot /* 8136254Sroot * Unlink system call. 8146254Sroot * Hard to avoid races here, especially 8156254Sroot * in unlinking directories. 8166254Sroot */ 81742441Smckusick /* ARGSUSED */ 81842441Smckusick unlink(p, uap, retval) 81942441Smckusick register struct proc *p; 82042441Smckusick struct args { 82142441Smckusick char *fname; 82242441Smckusick } *uap; 82342441Smckusick int *retval; 8246254Sroot { 82542441Smckusick register struct nameidata *ndp = &u.u_nd; 82637741Smckusick register struct vnode *vp; 82737741Smckusick int error; 8286254Sroot 82937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 83016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83116694Smckusick ndp->ni_dirp = uap->fname; 83237741Smckusick if (error = namei(ndp)) 83337741Smckusick RETURN (error); 83437741Smckusick vp = ndp->ni_vp; 83537741Smckusick if (vp->v_type == VDIR && 83642441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8376254Sroot goto out; 8386254Sroot /* 8396254Sroot * Don't unlink a mounted file. 8406254Sroot */ 84137741Smckusick if (vp->v_flag & VROOT) { 84237741Smckusick error = EBUSY; 8436254Sroot goto out; 8446254Sroot } 84537741Smckusick if (vp->v_flag & VTEXT) 84637741Smckusick xrele(vp); /* try once to free text */ 8476254Sroot out: 84842465Smckusick if (!error) { 84942465Smckusick error = VOP_REMOVE(ndp); 85042465Smckusick } else { 85137741Smckusick VOP_ABORTOP(ndp); 85243344Smckusick if (ndp->ni_dvp == vp) 85343344Smckusick vrele(ndp->ni_dvp); 85443344Smckusick else 85543344Smckusick vput(ndp->ni_dvp); 85642465Smckusick vput(vp); 85742465Smckusick } 85837741Smckusick RETURN (error); 8596254Sroot } 8606254Sroot 8616254Sroot /* 8626254Sroot * Seek system call 8636254Sroot */ 86442441Smckusick lseek(p, uap, retval) 86542441Smckusick register struct proc *p; 86642441Smckusick register struct args { 86737741Smckusick int fdes; 8686254Sroot off_t off; 8696254Sroot int sbase; 87042441Smckusick } *uap; 87142441Smckusick off_t *retval; 87242441Smckusick { 87342441Smckusick struct ucred *cred = u.u_nd.ni_cred; 87442441Smckusick register struct file *fp; 87537741Smckusick struct vattr vattr; 87637741Smckusick int error; 8776254Sroot 87837741Smckusick if ((unsigned)uap->fdes >= NOFILE || 87942441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 88037741Smckusick RETURN (EBADF); 88137741Smckusick if (fp->f_type != DTYPE_VNODE) 88237741Smckusick RETURN (ESPIPE); 88313878Ssam switch (uap->sbase) { 88413878Ssam 88513878Ssam case L_INCR: 88613878Ssam fp->f_offset += uap->off; 88713878Ssam break; 88813878Ssam 88913878Ssam case L_XTND: 89037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 89142441Smckusick &vattr, cred)) 89237741Smckusick RETURN (error); 89337741Smckusick fp->f_offset = uap->off + vattr.va_size; 89413878Ssam break; 89513878Ssam 89613878Ssam case L_SET: 89713878Ssam fp->f_offset = uap->off; 89813878Ssam break; 89913878Ssam 90013878Ssam default: 90137741Smckusick RETURN (EINVAL); 90213878Ssam } 90342441Smckusick *retval = fp->f_offset; 90437741Smckusick RETURN (0); 9056254Sroot } 9066254Sroot 9076254Sroot /* 9086254Sroot * Access system call 9096254Sroot */ 91042441Smckusick /* ARGSUSED */ 91142441Smckusick saccess(p, uap, retval) 91242441Smckusick register struct proc *p; 91342441Smckusick register struct args { 9146254Sroot char *fname; 9156254Sroot int fmode; 91642441Smckusick } *uap; 91742441Smckusick int *retval; 91842441Smckusick { 91942441Smckusick register struct nameidata *ndp = &u.u_nd; 92042441Smckusick register struct ucred *cred = ndp->ni_cred; 92137741Smckusick register struct vnode *vp; 92237741Smckusick int error, mode, svuid, svgid; 9236254Sroot 92442441Smckusick svuid = cred->cr_uid; 92542441Smckusick svgid = cred->cr_groups[0]; 92642441Smckusick cred->cr_uid = p->p_ruid; 92742441Smckusick cred->cr_groups[0] = p->p_rgid; 92837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 93016694Smckusick ndp->ni_dirp = uap->fname; 93137741Smckusick if (error = namei(ndp)) 93237741Smckusick goto out1; 93337741Smckusick vp = ndp->ni_vp; 93437741Smckusick /* 93537741Smckusick * fmode == 0 means only check for exist 93637741Smckusick */ 93737741Smckusick if (uap->fmode) { 93837741Smckusick mode = 0; 93937741Smckusick if (uap->fmode & R_OK) 94037741Smckusick mode |= VREAD; 94137741Smckusick if (uap->fmode & W_OK) 94237741Smckusick mode |= VWRITE; 94337741Smckusick if (uap->fmode & X_OK) 94437741Smckusick mode |= VEXEC; 94539543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 94638399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9476254Sroot } 94837741Smckusick vput(vp); 94937741Smckusick out1: 95042441Smckusick cred->cr_uid = svuid; 95142441Smckusick cred->cr_groups[0] = svgid; 95237741Smckusick RETURN (error); 9536254Sroot } 9546254Sroot 9556254Sroot /* 9566574Smckusic * Stat system call. This version follows links. 95737Sbill */ 95842441Smckusick /* ARGSUSED */ 95942441Smckusick stat(p, uap, retval) 96042441Smckusick register struct proc *p; 96142441Smckusick register struct args { 96242441Smckusick char *fname; 96342441Smckusick struct stat *ub; 96442441Smckusick } *uap; 96542441Smckusick int *retval; 96637Sbill { 96742441Smckusick register struct nameidata *ndp = &u.u_nd; 96842441Smckusick struct stat sb; 96942441Smckusick int error; 97037Sbill 97142441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 97242441Smckusick ndp->ni_segflg = UIO_USERSPACE; 97342441Smckusick ndp->ni_dirp = uap->fname; 97442441Smckusick if (error = namei(ndp)) 97542441Smckusick RETURN (error); 97642441Smckusick error = vn_stat(ndp->ni_vp, &sb); 97742441Smckusick vput(ndp->ni_vp); 97842441Smckusick if (error) 97942441Smckusick RETURN (error); 98042441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 98142441Smckusick RETURN (error); 98237Sbill } 98337Sbill 98437Sbill /* 9856574Smckusic * Lstat system call. This version does not follow links. 9865992Swnj */ 98742441Smckusick /* ARGSUSED */ 98842441Smckusick lstat(p, uap, retval) 98942441Smckusick register struct proc *p; 99042441Smckusick register struct args { 9915992Swnj char *fname; 99212756Ssam struct stat *ub; 99342441Smckusick } *uap; 99442441Smckusick int *retval; 99542441Smckusick { 99642441Smckusick register struct nameidata *ndp = &u.u_nd; 99712756Ssam struct stat sb; 99837741Smckusick int error; 9995992Swnj 100042441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 100116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 100216694Smckusick ndp->ni_dirp = uap->fname; 100337741Smckusick if (error = namei(ndp)) 100437741Smckusick RETURN (error); 100537741Smckusick error = vn_stat(ndp->ni_vp, &sb); 100637741Smckusick vput(ndp->ni_vp); 100737741Smckusick if (error) 100837741Smckusick RETURN (error); 100937741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 101037741Smckusick RETURN (error); 10115992Swnj } 10125992Swnj 10135992Swnj /* 10145992Swnj * Return target name of a symbolic link 101537Sbill */ 101642441Smckusick /* ARGSUSED */ 101742441Smckusick readlink(p, uap, retval) 101842441Smckusick register struct proc *p; 101942441Smckusick register struct args { 10205992Swnj char *name; 10215992Swnj char *buf; 10225992Swnj int count; 102342441Smckusick } *uap; 102442441Smckusick int *retval; 102542441Smckusick { 102642441Smckusick register struct nameidata *ndp = &u.u_nd; 102737741Smckusick register struct vnode *vp; 102837741Smckusick struct iovec aiov; 102937741Smckusick struct uio auio; 103037741Smckusick int error; 10315992Swnj 103237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 103316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103416694Smckusick ndp->ni_dirp = uap->name; 103537741Smckusick if (error = namei(ndp)) 103637741Smckusick RETURN (error); 103737741Smckusick vp = ndp->ni_vp; 103837741Smckusick if (vp->v_type != VLNK) { 103937741Smckusick error = EINVAL; 10405992Swnj goto out; 10415992Swnj } 104237741Smckusick aiov.iov_base = uap->buf; 104337741Smckusick aiov.iov_len = uap->count; 104437741Smckusick auio.uio_iov = &aiov; 104537741Smckusick auio.uio_iovcnt = 1; 104637741Smckusick auio.uio_offset = 0; 104737741Smckusick auio.uio_rw = UIO_READ; 104837741Smckusick auio.uio_segflg = UIO_USERSPACE; 104937741Smckusick auio.uio_resid = uap->count; 105037741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10515992Swnj out: 105237741Smckusick vput(vp); 105342441Smckusick *retval = uap->count - auio.uio_resid; 105437741Smckusick RETURN (error); 10555992Swnj } 10565992Swnj 10579167Ssam /* 105838259Smckusick * Change flags of a file given path name. 105938259Smckusick */ 106042441Smckusick /* ARGSUSED */ 106142441Smckusick chflags(p, uap, retval) 106242441Smckusick register struct proc *p; 106342441Smckusick register struct args { 106438259Smckusick char *fname; 106538259Smckusick int flags; 106642441Smckusick } *uap; 106742441Smckusick int *retval; 106842441Smckusick { 106942441Smckusick register struct nameidata *ndp = &u.u_nd; 107038259Smckusick register struct vnode *vp; 107138259Smckusick struct vattr vattr; 107238259Smckusick int error; 107338259Smckusick 107438259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 107538259Smckusick ndp->ni_segflg = UIO_USERSPACE; 107638259Smckusick ndp->ni_dirp = uap->fname; 107741362Smckusick VATTR_NULL(&vattr); 107838259Smckusick vattr.va_flags = uap->flags; 107938259Smckusick if (error = namei(ndp)) 108038259Smckusick RETURN (error); 108138259Smckusick vp = ndp->ni_vp; 108241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 108338259Smckusick error = EROFS; 108438259Smckusick goto out; 108538259Smckusick } 108638259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108738259Smckusick out: 108838259Smckusick vput(vp); 108938259Smckusick RETURN (error); 109038259Smckusick } 109138259Smckusick 109238259Smckusick /* 109338259Smckusick * Change flags of a file given a file descriptor. 109438259Smckusick */ 109542441Smckusick /* ARGSUSED */ 109642441Smckusick fchflags(p, uap, retval) 109742441Smckusick register struct proc *p; 109842441Smckusick register struct args { 109938259Smckusick int fd; 110038259Smckusick int flags; 110142441Smckusick } *uap; 110242441Smckusick int *retval; 110342441Smckusick { 110438259Smckusick struct vattr vattr; 110538259Smckusick struct vnode *vp; 110638259Smckusick struct file *fp; 110738259Smckusick int error; 110838259Smckusick 110942441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 111038259Smckusick RETURN (error); 111141362Smckusick VATTR_NULL(&vattr); 111238259Smckusick vattr.va_flags = uap->flags; 111338259Smckusick vp = (struct vnode *)fp->f_data; 111438259Smckusick VOP_LOCK(vp); 111541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111638259Smckusick error = EROFS; 111738259Smckusick goto out; 111838259Smckusick } 111938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 112038259Smckusick out: 112138259Smckusick VOP_UNLOCK(vp); 112238259Smckusick RETURN (error); 112338259Smckusick } 112438259Smckusick 112538259Smckusick /* 11269167Ssam * Change mode of a file given path name. 11279167Ssam */ 112842441Smckusick /* ARGSUSED */ 112942441Smckusick chmod(p, uap, retval) 113042441Smckusick register struct proc *p; 113142441Smckusick register struct args { 11326254Sroot char *fname; 11336254Sroot int fmode; 113442441Smckusick } *uap; 113542441Smckusick int *retval; 113642441Smckusick { 113742441Smckusick register struct nameidata *ndp = &u.u_nd; 113837741Smckusick register struct vnode *vp; 113937741Smckusick struct vattr vattr; 114037741Smckusick int error; 11415992Swnj 114237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114437741Smckusick ndp->ni_dirp = uap->fname; 114541362Smckusick VATTR_NULL(&vattr); 114637741Smckusick vattr.va_mode = uap->fmode & 07777; 114737741Smckusick if (error = namei(ndp)) 114837741Smckusick RETURN (error); 114937741Smckusick vp = ndp->ni_vp; 115041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 115137741Smckusick error = EROFS; 115237741Smckusick goto out; 115337741Smckusick } 115437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115537741Smckusick out: 115637741Smckusick vput(vp); 115737741Smckusick RETURN (error); 11587701Ssam } 11597439Sroot 11609167Ssam /* 11619167Ssam * Change mode of a file given a file descriptor. 11629167Ssam */ 116342441Smckusick /* ARGSUSED */ 116442441Smckusick fchmod(p, uap, retval) 116542441Smckusick register struct proc *p; 116642441Smckusick register struct args { 11677701Ssam int fd; 11687701Ssam int fmode; 116942441Smckusick } *uap; 117042441Smckusick int *retval; 117142441Smckusick { 117237741Smckusick struct vattr vattr; 117337741Smckusick struct vnode *vp; 117437741Smckusick struct file *fp; 117537741Smckusick int error; 11767701Ssam 117742441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 117837741Smckusick RETURN (error); 117941362Smckusick VATTR_NULL(&vattr); 118037741Smckusick vattr.va_mode = uap->fmode & 07777; 118137741Smckusick vp = (struct vnode *)fp->f_data; 118237741Smckusick VOP_LOCK(vp); 118341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118437741Smckusick error = EROFS; 118537741Smckusick goto out; 11867439Sroot } 118737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118837741Smckusick out: 118937741Smckusick VOP_UNLOCK(vp); 119037741Smckusick RETURN (error); 11915992Swnj } 11925992Swnj 11939167Ssam /* 11949167Ssam * Set ownership given a path name. 11959167Ssam */ 119642441Smckusick /* ARGSUSED */ 119742441Smckusick chown(p, uap, retval) 119842441Smckusick register struct proc *p; 119942441Smckusick register struct args { 12006254Sroot char *fname; 12016254Sroot int uid; 12026254Sroot int gid; 120342441Smckusick } *uap; 120442441Smckusick int *retval; 120542441Smckusick { 120642441Smckusick register struct nameidata *ndp = &u.u_nd; 120737741Smckusick register struct vnode *vp; 120837741Smckusick struct vattr vattr; 120937741Smckusick int error; 121037Sbill 121137741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 121236614Sbostic ndp->ni_segflg = UIO_USERSPACE; 121336614Sbostic ndp->ni_dirp = uap->fname; 121441362Smckusick VATTR_NULL(&vattr); 121537741Smckusick vattr.va_uid = uap->uid; 121637741Smckusick vattr.va_gid = uap->gid; 121737741Smckusick if (error = namei(ndp)) 121837741Smckusick RETURN (error); 121937741Smckusick vp = ndp->ni_vp; 122041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122137741Smckusick error = EROFS; 122237741Smckusick goto out; 122337741Smckusick } 122437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 122537741Smckusick out: 122637741Smckusick vput(vp); 122737741Smckusick RETURN (error); 12287701Ssam } 12297439Sroot 12309167Ssam /* 12319167Ssam * Set ownership given a file descriptor. 12329167Ssam */ 123342441Smckusick /* ARGSUSED */ 123442441Smckusick fchown(p, uap, retval) 123542441Smckusick register struct proc *p; 123642441Smckusick register struct args { 12377701Ssam int fd; 12387701Ssam int uid; 12397701Ssam int gid; 124042441Smckusick } *uap; 124142441Smckusick int *retval; 124242441Smckusick { 124337741Smckusick struct vattr vattr; 124437741Smckusick struct vnode *vp; 124537741Smckusick struct file *fp; 124637741Smckusick int error; 12477701Ssam 124842441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 124937741Smckusick RETURN (error); 125041362Smckusick VATTR_NULL(&vattr); 125137741Smckusick vattr.va_uid = uap->uid; 125237741Smckusick vattr.va_gid = uap->gid; 125337741Smckusick vp = (struct vnode *)fp->f_data; 125437741Smckusick VOP_LOCK(vp); 125541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125637741Smckusick error = EROFS; 125737741Smckusick goto out; 125837741Smckusick } 125937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 126037741Smckusick out: 126137741Smckusick VOP_UNLOCK(vp); 126237741Smckusick RETURN (error); 12637701Ssam } 12647701Ssam 126542441Smckusick /* 126642441Smckusick * Set the access and modification times of a file. 126742441Smckusick */ 126842441Smckusick /* ARGSUSED */ 126942441Smckusick utimes(p, uap, retval) 127042441Smckusick register struct proc *p; 127142441Smckusick register struct args { 127211811Ssam char *fname; 127311811Ssam struct timeval *tptr; 127442441Smckusick } *uap; 127542441Smckusick int *retval; 127642441Smckusick { 127742441Smckusick register struct nameidata *ndp = &u.u_nd; 127837741Smckusick register struct vnode *vp; 127911811Ssam struct timeval tv[2]; 128037741Smckusick struct vattr vattr; 128137741Smckusick int error; 128211811Ssam 128337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 128437741Smckusick RETURN (error); 128537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 128637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 128737741Smckusick ndp->ni_dirp = uap->fname; 128841362Smckusick VATTR_NULL(&vattr); 128937741Smckusick vattr.va_atime = tv[0]; 129037741Smckusick vattr.va_mtime = tv[1]; 129137741Smckusick if (error = namei(ndp)) 129237741Smckusick RETURN (error); 129337741Smckusick vp = ndp->ni_vp; 129441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129537741Smckusick error = EROFS; 129637741Smckusick goto out; 129721015Smckusick } 129837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129937741Smckusick out: 130037741Smckusick vput(vp); 130137741Smckusick RETURN (error); 130211811Ssam } 130311811Ssam 13049167Ssam /* 13059167Ssam * Truncate a file given its path name. 13069167Ssam */ 130742441Smckusick /* ARGSUSED */ 130842441Smckusick truncate(p, uap, retval) 130942441Smckusick register struct proc *p; 131042441Smckusick register struct args { 13117701Ssam char *fname; 131226473Skarels off_t length; 131342441Smckusick } *uap; 131442441Smckusick int *retval; 131542441Smckusick { 131642441Smckusick register struct nameidata *ndp = &u.u_nd; 131737741Smckusick register struct vnode *vp; 131837741Smckusick struct vattr vattr; 131937741Smckusick int error; 13207701Ssam 132137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 132216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132316694Smckusick ndp->ni_dirp = uap->fname; 132441362Smckusick VATTR_NULL(&vattr); 132537741Smckusick vattr.va_size = uap->length; 132637741Smckusick if (error = namei(ndp)) 132737741Smckusick RETURN (error); 132837741Smckusick vp = ndp->ni_vp; 132937741Smckusick if (vp->v_type == VDIR) { 133037741Smckusick error = EISDIR; 133137741Smckusick goto out; 13327701Ssam } 133338399Smckusick if ((error = vn_writechk(vp)) || 133438399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 133537741Smckusick goto out; 133637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 133737741Smckusick out: 133837741Smckusick vput(vp); 133937741Smckusick RETURN (error); 13407701Ssam } 13417701Ssam 13429167Ssam /* 13439167Ssam * Truncate a file given a file descriptor. 13449167Ssam */ 134542441Smckusick /* ARGSUSED */ 134642441Smckusick ftruncate(p, uap, retval) 134742441Smckusick register struct proc *p; 134842441Smckusick register struct args { 13497701Ssam int fd; 135026473Skarels off_t length; 135142441Smckusick } *uap; 135242441Smckusick int *retval; 135342441Smckusick { 135437741Smckusick struct vattr vattr; 135537741Smckusick struct vnode *vp; 13567701Ssam struct file *fp; 135737741Smckusick int error; 13587701Ssam 135942441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 136037741Smckusick RETURN (error); 136137741Smckusick if ((fp->f_flag & FWRITE) == 0) 136237741Smckusick RETURN (EINVAL); 136341362Smckusick VATTR_NULL(&vattr); 136437741Smckusick vattr.va_size = uap->length; 136537741Smckusick vp = (struct vnode *)fp->f_data; 136637741Smckusick VOP_LOCK(vp); 136737741Smckusick if (vp->v_type == VDIR) { 136837741Smckusick error = EISDIR; 136937741Smckusick goto out; 13707701Ssam } 137138399Smckusick if (error = vn_writechk(vp)) 137237741Smckusick goto out; 137337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 137437741Smckusick out: 137537741Smckusick VOP_UNLOCK(vp); 137637741Smckusick RETURN (error); 13777701Ssam } 13787701Ssam 13799167Ssam /* 13809167Ssam * Synch an open file. 13819167Ssam */ 138242441Smckusick /* ARGSUSED */ 138342441Smckusick fsync(p, uap, retval) 138442441Smckusick register struct proc *p; 138542441Smckusick struct args { 138642441Smckusick int fd; 138742441Smckusick } *uap; 138842441Smckusick int *retval; 13899167Ssam { 139039592Smckusick register struct vnode *vp; 13919167Ssam struct file *fp; 139237741Smckusick int error; 13939167Ssam 139442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 139537741Smckusick RETURN (error); 139639592Smckusick vp = (struct vnode *)fp->f_data; 139739592Smckusick VOP_LOCK(vp); 139839592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139939592Smckusick VOP_UNLOCK(vp); 140037741Smckusick RETURN (error); 14019167Ssam } 14029167Ssam 14039167Ssam /* 14049167Ssam * Rename system call. 14059167Ssam * 14069167Ssam * Source and destination must either both be directories, or both 14079167Ssam * not be directories. If target is a directory, it must be empty. 14089167Ssam */ 140942441Smckusick /* ARGSUSED */ 141042441Smckusick rename(p, uap, retval) 141142441Smckusick register struct proc *p; 141242441Smckusick register struct args { 14137701Ssam char *from; 14147701Ssam char *to; 141542441Smckusick } *uap; 141642441Smckusick int *retval; 141742441Smckusick { 141837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141942441Smckusick register struct nameidata *ndp = &u.u_nd; 142037741Smckusick struct nameidata tond; 142137741Smckusick int error; 14227701Ssam 142337741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 142416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142516694Smckusick ndp->ni_dirp = uap->from; 142637741Smckusick if (error = namei(ndp)) 142737741Smckusick RETURN (error); 142837741Smckusick fvp = ndp->ni_vp; 142938266Smckusick nddup(ndp, &tond); 143037741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 143137741Smckusick tond.ni_segflg = UIO_USERSPACE; 143237741Smckusick tond.ni_dirp = uap->to; 143342465Smckusick if (error = namei(&tond)) { 143442465Smckusick VOP_ABORTOP(ndp); 143542465Smckusick vrele(ndp->ni_dvp); 143642465Smckusick vrele(fvp); 143742465Smckusick goto out1; 143842465Smckusick } 143937741Smckusick tdvp = tond.ni_dvp; 144037741Smckusick tvp = tond.ni_vp; 144137741Smckusick if (tvp != NULL) { 144237741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 144339242Sbostic error = ENOTDIR; 144437741Smckusick goto out; 144537741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 144639242Sbostic error = EISDIR; 144737741Smckusick goto out; 14489167Ssam } 14499167Ssam } 145037741Smckusick if (fvp->v_mount != tdvp->v_mount) { 145137741Smckusick error = EXDEV; 14529167Ssam goto out; 145310051Ssam } 145439286Smckusick if (fvp == tdvp) 145537741Smckusick error = EINVAL; 145639286Smckusick /* 145739286Smckusick * If source is the same as the destination, 145839286Smckusick * then there is nothing to do. 145939286Smckusick */ 146039286Smckusick if (fvp == tvp) 146139286Smckusick error = -1; 146237741Smckusick out: 146342465Smckusick if (!error) { 146442465Smckusick error = VOP_RENAME(ndp, &tond); 146542465Smckusick } else { 146637741Smckusick VOP_ABORTOP(&tond); 146743344Smckusick if (tdvp == tvp) 146843344Smckusick vrele(tdvp); 146943344Smckusick else 147043344Smckusick vput(tdvp); 147142465Smckusick if (tvp) 147242465Smckusick vput(tvp); 147337741Smckusick VOP_ABORTOP(ndp); 147442465Smckusick vrele(ndp->ni_dvp); 147542465Smckusick vrele(fvp); 14769167Ssam } 147737741Smckusick out1: 147838266Smckusick ndrele(&tond); 147939286Smckusick if (error == -1) 148039286Smckusick RETURN (0); 148137741Smckusick RETURN (error); 14827701Ssam } 14837701Ssam 14847535Sroot /* 148512756Ssam * Mkdir system call 148612756Ssam */ 148742441Smckusick /* ARGSUSED */ 148842441Smckusick mkdir(p, uap, retval) 148942441Smckusick register struct proc *p; 149042441Smckusick register struct args { 149112756Ssam char *name; 149212756Ssam int dmode; 149342441Smckusick } *uap; 149442441Smckusick int *retval; 149542441Smckusick { 149642441Smckusick register struct nameidata *ndp = &u.u_nd; 149737741Smckusick register struct vnode *vp; 149837741Smckusick struct vattr vattr; 149937741Smckusick int error; 150012756Ssam 150137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 150216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 150316694Smckusick ndp->ni_dirp = uap->name; 150437741Smckusick if (error = namei(ndp)) 150537741Smckusick RETURN (error); 150637741Smckusick vp = ndp->ni_vp; 150737741Smckusick if (vp != NULL) { 150837741Smckusick VOP_ABORTOP(ndp); 150943344Smckusick if (ndp->ni_dvp == vp) 151043344Smckusick vrele(ndp->ni_dvp); 151143344Smckusick else 151243344Smckusick vput(ndp->ni_dvp); 151342465Smckusick vrele(vp); 151437741Smckusick RETURN (EEXIST); 151512756Ssam } 151641362Smckusick VATTR_NULL(&vattr); 151737741Smckusick vattr.va_type = VDIR; 151842441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 151937741Smckusick error = VOP_MKDIR(ndp, &vattr); 152038145Smckusick if (!error) 152138145Smckusick vput(ndp->ni_vp); 152237741Smckusick RETURN (error); 152312756Ssam } 152412756Ssam 152512756Ssam /* 152612756Ssam * Rmdir system call. 152712756Ssam */ 152842441Smckusick /* ARGSUSED */ 152942441Smckusick rmdir(p, uap, retval) 153042441Smckusick register struct proc *p; 153142441Smckusick struct args { 153242441Smckusick char *name; 153342441Smckusick } *uap; 153442441Smckusick int *retval; 153512756Ssam { 153642441Smckusick register struct nameidata *ndp = &u.u_nd; 153737741Smckusick register struct vnode *vp; 153837741Smckusick int error; 153912756Ssam 154037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 154116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 154216694Smckusick ndp->ni_dirp = uap->name; 154337741Smckusick if (error = namei(ndp)) 154437741Smckusick RETURN (error); 154537741Smckusick vp = ndp->ni_vp; 154637741Smckusick if (vp->v_type != VDIR) { 154737741Smckusick error = ENOTDIR; 154812756Ssam goto out; 154912756Ssam } 155012756Ssam /* 155137741Smckusick * No rmdir "." please. 155212756Ssam */ 155337741Smckusick if (ndp->ni_dvp == vp) { 155437741Smckusick error = EINVAL; 155512756Ssam goto out; 155612756Ssam } 155712756Ssam /* 155837741Smckusick * Don't unlink a mounted file. 155912756Ssam */ 156037741Smckusick if (vp->v_flag & VROOT) 156137741Smckusick error = EBUSY; 156212756Ssam out: 156342465Smckusick if (!error) { 156442465Smckusick error = VOP_RMDIR(ndp); 156542465Smckusick } else { 156637741Smckusick VOP_ABORTOP(ndp); 156743344Smckusick if (ndp->ni_dvp == vp) 156843344Smckusick vrele(ndp->ni_dvp); 156943344Smckusick else 157043344Smckusick vput(ndp->ni_dvp); 157142465Smckusick vput(vp); 157242465Smckusick } 157337741Smckusick RETURN (error); 157412756Ssam } 157512756Ssam 157637741Smckusick /* 157737741Smckusick * Read a block of directory entries in a file system independent format 157837741Smckusick */ 157942441Smckusick getdirentries(p, uap, retval) 158042441Smckusick register struct proc *p; 158142441Smckusick register struct args { 158237741Smckusick int fd; 158337741Smckusick char *buf; 158437741Smckusick unsigned count; 158537741Smckusick long *basep; 158642441Smckusick } *uap; 158742441Smckusick int *retval; 158842441Smckusick { 158939592Smckusick register struct vnode *vp; 159016540Ssam struct file *fp; 159137741Smckusick struct uio auio; 159237741Smckusick struct iovec aiov; 159338129Smckusick off_t off; 159440321Smckusick int error, eofflag; 159512756Ssam 159642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 159737741Smckusick RETURN (error); 159837741Smckusick if ((fp->f_flag & FREAD) == 0) 159937741Smckusick RETURN (EBADF); 160039592Smckusick vp = (struct vnode *)fp->f_data; 160139592Smckusick if (vp->v_type != VDIR) 160239592Smckusick RETURN (EINVAL); 160337741Smckusick aiov.iov_base = uap->buf; 160437741Smckusick aiov.iov_len = uap->count; 160537741Smckusick auio.uio_iov = &aiov; 160637741Smckusick auio.uio_iovcnt = 1; 160737741Smckusick auio.uio_rw = UIO_READ; 160837741Smckusick auio.uio_segflg = UIO_USERSPACE; 160937741Smckusick auio.uio_resid = uap->count; 161039592Smckusick VOP_LOCK(vp); 161139592Smckusick auio.uio_offset = off = fp->f_offset; 161240321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 161339592Smckusick fp->f_offset = auio.uio_offset; 161439592Smckusick VOP_UNLOCK(vp); 161539592Smckusick if (error) 161637741Smckusick RETURN (error); 161739592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 161842441Smckusick *retval = uap->count - auio.uio_resid; 161937741Smckusick RETURN (error); 162012756Ssam } 162112756Ssam 162212756Ssam /* 162312756Ssam * mode mask for creation of files 162412756Ssam */ 162542441Smckusick mode_t 162642441Smckusick umask(p, uap, retval) 162742441Smckusick register struct proc *p; 162842441Smckusick struct args { 162942441Smckusick int mask; 163042441Smckusick } *uap; 163142441Smckusick int *retval; 163212756Ssam { 163312756Ssam 163442441Smckusick *retval = u.u_cmask; 163542441Smckusick u.u_cmask = uap->mask & 07777; 163637741Smckusick RETURN (0); 163712756Ssam } 163837741Smckusick 163939566Smarc /* 164039566Smarc * Void all references to file by ripping underlying filesystem 164139566Smarc * away from vnode. 164239566Smarc */ 164342441Smckusick /* ARGSUSED */ 164442441Smckusick revoke(p, uap, retval) 164542441Smckusick register struct proc *p; 164642441Smckusick register struct args { 164739566Smarc char *fname; 164842441Smckusick } *uap; 164942441Smckusick int *retval; 165042441Smckusick { 165142441Smckusick register struct nameidata *ndp = &u.u_nd; 165239566Smarc register struct vnode *vp; 165339566Smarc struct vattr vattr; 165439566Smarc int error; 165539566Smarc 165639566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 165739566Smarc ndp->ni_segflg = UIO_USERSPACE; 165839566Smarc ndp->ni_dirp = uap->fname; 165939566Smarc if (error = namei(ndp)) 166039566Smarc RETURN (error); 166139566Smarc vp = ndp->ni_vp; 166239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 166339566Smarc error = EINVAL; 166439566Smarc goto out; 166539566Smarc } 166642441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 166739566Smarc goto out; 166842955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 166942441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 167039566Smarc goto out; 167139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 167239632Smckusick vgoneall(vp); 167339566Smarc out: 167439566Smarc vrele(vp); 167539566Smarc RETURN (error); 167639566Smarc } 167739566Smarc 167838408Smckusick getvnode(ofile, fdes, fpp) 167938408Smckusick struct file *ofile[]; 168037741Smckusick struct file **fpp; 168137741Smckusick int fdes; 168237741Smckusick { 168337741Smckusick struct file *fp; 168437741Smckusick 168538408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 168637741Smckusick return (EBADF); 168737741Smckusick if (fp->f_type != DTYPE_VNODE) 168837741Smckusick return (EINVAL); 168937741Smckusick *fpp = fp; 169037741Smckusick return (0); 169137741Smckusick } 1692