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*42955Smckusick * @(#)vfs_syscalls.c 7.50 (Berkeley) 06/06/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "mount.h" 2817101Sbloom #include "proc.h" 2917101Sbloom #include "uio.h" 3037741Smckusick #include "malloc.h" 3137Sbill 3239797Smckusick #undef RETURN 3342441Smckusick #define RETURN(val) { u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); } 3439797Smckusick 3537741Smckusick /* 3637741Smckusick * Virtual File System System Calls 3737741Smckusick */ 3812756Ssam 399167Ssam /* 4037741Smckusick * mount system call 419167Ssam */ 4242441Smckusick /* ARGSUSED */ 4342441Smckusick mount(p, uap, retval) 4442441Smckusick register struct proc *p; 4542441Smckusick register struct args { 4637741Smckusick int type; 4737741Smckusick char *dir; 4837741Smckusick int flags; 4937741Smckusick caddr_t data; 5042441Smckusick } *uap; 5142441Smckusick int *retval; 5242441Smckusick { 5342441Smckusick register struct nameidata *ndp = &u.u_nd; 5439335Smckusick register struct vnode *vp; 5539335Smckusick register struct mount *mp; 5640111Smckusick int error, flag; 576254Sroot 5837741Smckusick /* 5937741Smckusick * Must be super user 6037741Smckusick */ 6142441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 6237741Smckusick RETURN (error); 6337741Smckusick /* 6437741Smckusick * Get vnode to be covered 6537741Smckusick */ 6637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6837741Smckusick ndp->ni_dirp = uap->dir; 6937741Smckusick if (error = namei(ndp)) 7037741Smckusick RETURN (error); 7137741Smckusick vp = ndp->ni_vp; 7241400Smckusick if (uap->flags & MNT_UPDATE) { 7339335Smckusick if ((vp->v_flag & VROOT) == 0) { 7439335Smckusick vput(vp); 7539335Smckusick RETURN (EINVAL); 7639335Smckusick } 7739335Smckusick mp = vp->v_mount; 7839335Smckusick /* 7939335Smckusick * We allow going from read-only to read-write, 8039335Smckusick * but not from read-write to read-only. 8139335Smckusick */ 8241400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 8341400Smckusick (uap->flags & MNT_RDONLY) != 0) { 8439335Smckusick vput(vp); 8539335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8639335Smckusick } 8741400Smckusick flag = mp->mnt_flag; 8841400Smckusick mp->mnt_flag |= MNT_UPDATE; 8939335Smckusick VOP_UNLOCK(vp); 9039335Smckusick goto update; 9139335Smckusick } 9239665Smckusick vinvalbuf(vp, 1); 9339805Smckusick if (vp->v_usecount != 1) { 9437741Smckusick vput(vp); 9537741Smckusick RETURN (EBUSY); 9637741Smckusick } 9737741Smckusick if (vp->v_type != VDIR) { 9837741Smckusick vput(vp); 9937741Smckusick RETURN (ENOTDIR); 10037741Smckusick } 10139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10337741Smckusick vput(vp); 10437741Smckusick RETURN (ENODEV); 10537741Smckusick } 10637741Smckusick 10737741Smckusick /* 10839335Smckusick * Allocate and initialize the file system. 10937741Smckusick */ 11037741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 11137741Smckusick M_MOUNT, M_WAITOK); 11241400Smckusick mp->mnt_op = vfssw[uap->type]; 11341400Smckusick mp->mnt_flag = 0; 11441400Smckusick mp->mnt_exroot = 0; 11541400Smckusick mp->mnt_mounth = NULLVP; 11639335Smckusick if (error = vfs_lock(mp)) { 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11939335Smckusick RETURN (error); 12039335Smckusick } 12139335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12239335Smckusick vfs_unlock(mp); 12339335Smckusick free((caddr_t)mp, M_MOUNT); 12439335Smckusick vput(vp); 12539335Smckusick RETURN (EBUSY); 12639335Smckusick } 12739335Smckusick vp->v_mountedhere = mp; 12841400Smckusick mp->mnt_vnodecovered = vp; 12939335Smckusick update: 13039335Smckusick /* 13139335Smckusick * Set the mount level flags. 13239335Smckusick */ 13341400Smckusick if (uap->flags & MNT_RDONLY) 13441400Smckusick mp->mnt_flag |= MNT_RDONLY; 13539335Smckusick else 13641400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13741400Smckusick if (uap->flags & MNT_NOSUID) 13841400Smckusick mp->mnt_flag |= MNT_NOSUID; 13939335Smckusick else 14041400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 14141400Smckusick if (uap->flags & MNT_NOEXEC) 14241400Smckusick mp->mnt_flag |= MNT_NOEXEC; 14339335Smckusick else 14441400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 14541400Smckusick if (uap->flags & MNT_NODEV) 14641400Smckusick mp->mnt_flag |= MNT_NODEV; 14739335Smckusick else 14841400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14941400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 15041400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 15139335Smckusick else 15241400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 15339335Smckusick /* 15439335Smckusick * Mount the filesystem. 15539335Smckusick */ 15639335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15741400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15841400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15939335Smckusick vrele(vp); 16040111Smckusick if (error) 16141400Smckusick mp->mnt_flag = flag; 16239335Smckusick RETURN (error); 16339335Smckusick } 16440110Smckusick /* 16540110Smckusick * Put the new filesystem on the mount list after root. 16640110Smckusick */ 16741400Smckusick mp->mnt_next = rootfs->mnt_next; 16841400Smckusick mp->mnt_prev = rootfs; 16941400Smckusick rootfs->mnt_next = mp; 17041400Smckusick mp->mnt_next->mnt_prev = mp; 17137741Smckusick cache_purge(vp); 17237741Smckusick if (!error) { 17339335Smckusick VOP_UNLOCK(vp); 17437741Smckusick vfs_unlock(mp); 17539044Smckusick error = VFS_START(mp, 0); 17637741Smckusick } else { 17737741Smckusick vfs_remove(mp); 17837741Smckusick free((caddr_t)mp, M_MOUNT); 17939335Smckusick vput(vp); 18037741Smckusick } 18137741Smckusick RETURN (error); 1826254Sroot } 1836254Sroot 1849167Ssam /* 18537741Smckusick * Unmount system call. 18637741Smckusick * 18737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18837741Smckusick * not special file (as before). 1899167Ssam */ 19042441Smckusick /* ARGSUSED */ 19142441Smckusick unmount(p, uap, retval) 19242441Smckusick register struct proc *p; 19342441Smckusick register struct args { 19437741Smckusick char *pathp; 19537741Smckusick int flags; 19642441Smckusick } *uap; 19742441Smckusick int *retval; 19842441Smckusick { 19937741Smckusick register struct vnode *vp; 20042441Smckusick register struct nameidata *ndp = &u.u_nd; 20139356Smckusick struct mount *mp; 20237741Smckusick int error; 2036254Sroot 20437741Smckusick /* 20537741Smckusick * Must be super user 20637741Smckusick */ 20742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 20837741Smckusick RETURN (error); 20937741Smckusick 21037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 21137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 21237741Smckusick ndp->ni_dirp = uap->pathp; 21337741Smckusick if (error = namei(ndp)) 21437741Smckusick RETURN (error); 21537741Smckusick vp = ndp->ni_vp; 21637741Smckusick /* 21737741Smckusick * Must be the root of the filesystem 21837741Smckusick */ 21937741Smckusick if ((vp->v_flag & VROOT) == 0) { 22037741Smckusick vput(vp); 22137741Smckusick RETURN (EINVAL); 22237741Smckusick } 22337741Smckusick mp = vp->v_mount; 22437741Smckusick vput(vp); 22539356Smckusick RETURN (dounmount(mp, uap->flags)); 22639356Smckusick } 22739356Smckusick 22839356Smckusick /* 22939356Smckusick * Do an unmount. 23039356Smckusick */ 23139356Smckusick dounmount(mp, flags) 23239356Smckusick register struct mount *mp; 23339356Smckusick int flags; 23439356Smckusick { 23539356Smckusick struct vnode *coveredvp; 23639356Smckusick int error; 23739356Smckusick 23841400Smckusick coveredvp = mp->mnt_vnodecovered; 23941298Smckusick if (vfs_busy(mp)) 24041298Smckusick return (EBUSY); 24141400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 24237741Smckusick if (error = vfs_lock(mp)) 24339356Smckusick return (error); 24437741Smckusick 24537741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24637741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24741676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24841676Smckusick error = VFS_UNMOUNT(mp, flags); 24941400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 25041298Smckusick vfs_unbusy(mp); 25137741Smckusick if (error) { 25237741Smckusick vfs_unlock(mp); 25337741Smckusick } else { 25437741Smckusick vrele(coveredvp); 25537741Smckusick vfs_remove(mp); 25637741Smckusick free((caddr_t)mp, M_MOUNT); 25737741Smckusick } 25839356Smckusick return (error); 2596254Sroot } 2606254Sroot 2619167Ssam /* 26237741Smckusick * Sync system call. 26337741Smckusick * Sync each mounted filesystem. 2649167Ssam */ 26539491Smckusick /* ARGSUSED */ 26642441Smckusick sync(p, uap, retval) 26742441Smckusick register struct proc *p; 26842441Smckusick struct args *uap; 26942441Smckusick int *retval; 2706254Sroot { 27137741Smckusick register struct mount *mp; 27241298Smckusick struct mount *omp; 27337741Smckusick 27437741Smckusick mp = rootfs; 27537741Smckusick do { 27640343Smckusick /* 27740343Smckusick * The lock check below is to avoid races with mount 27840343Smckusick * and unmount. 27940343Smckusick */ 28041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28141298Smckusick !vfs_busy(mp)) { 28237741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28341298Smckusick omp = mp; 28441400Smckusick mp = mp->mnt_next; 28541298Smckusick vfs_unbusy(omp); 28641298Smckusick } else 28741400Smckusick mp = mp->mnt_next; 28837741Smckusick } while (mp != rootfs); 28937741Smckusick } 29037741Smckusick 29137741Smckusick /* 29241298Smckusick * operate on filesystem quotas 29341298Smckusick */ 29442441Smckusick /* ARGSUSED */ 29542441Smckusick quotactl(p, uap, retval) 29642441Smckusick register struct proc *p; 29742441Smckusick register struct args { 29841298Smckusick char *path; 29941298Smckusick int cmd; 30041298Smckusick int uid; 30141298Smckusick caddr_t arg; 30242441Smckusick } *uap; 30342441Smckusick int *retval; 30442441Smckusick { 30541298Smckusick register struct mount *mp; 30642441Smckusick register struct nameidata *ndp = &u.u_nd; 30741298Smckusick int error; 30841298Smckusick 30941298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31041298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31141298Smckusick ndp->ni_dirp = uap->path; 31241298Smckusick if (error = namei(ndp)) 31341298Smckusick RETURN (error); 31441298Smckusick mp = ndp->ni_vp->v_mount; 31541298Smckusick vrele(ndp->ni_vp); 31641298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31741298Smckusick } 31841298Smckusick 31941298Smckusick /* 32037741Smckusick * get filesystem statistics 32137741Smckusick */ 32242441Smckusick /* ARGSUSED */ 32342441Smckusick statfs(p, uap, retval) 32442441Smckusick register struct proc *p; 32542441Smckusick register struct args { 32637741Smckusick char *path; 32737741Smckusick struct statfs *buf; 32842441Smckusick } *uap; 32942441Smckusick int *retval; 33042441Smckusick { 33139464Smckusick register struct mount *mp; 33242441Smckusick register struct nameidata *ndp = &u.u_nd; 33340343Smckusick register struct statfs *sp; 33437741Smckusick int error; 33537741Smckusick 33639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33837741Smckusick ndp->ni_dirp = uap->path; 33937741Smckusick if (error = namei(ndp)) 34037741Smckusick RETURN (error); 34139544Smckusick mp = ndp->ni_vp->v_mount; 34241400Smckusick sp = &mp->mnt_stat; 34339544Smckusick vrele(ndp->ni_vp); 34440343Smckusick if (error = VFS_STATFS(mp, sp)) 34539544Smckusick RETURN (error); 34641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34740343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34837741Smckusick } 34937741Smckusick 35042441Smckusick /* 35142441Smckusick * get filesystem statistics 35242441Smckusick */ 35342441Smckusick /* ARGSUSED */ 35442441Smckusick fstatfs(p, uap, retval) 35542441Smckusick register struct proc *p; 35642441Smckusick register struct args { 35737741Smckusick int fd; 35837741Smckusick struct statfs *buf; 35942441Smckusick } *uap; 36042441Smckusick int *retval; 36142441Smckusick { 36237741Smckusick struct file *fp; 36339464Smckusick struct mount *mp; 36440343Smckusick register struct statfs *sp; 36537741Smckusick int error; 36637741Smckusick 36742441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 36837741Smckusick RETURN (error); 36939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37041400Smckusick sp = &mp->mnt_stat; 37140343Smckusick if (error = VFS_STATFS(mp, sp)) 37237741Smckusick RETURN (error); 37341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37440343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37537741Smckusick } 37637741Smckusick 37737741Smckusick /* 37838270Smckusick * get statistics on all filesystems 37938270Smckusick */ 38042441Smckusick getfsstat(p, uap, retval) 38142441Smckusick register struct proc *p; 38242441Smckusick register struct args { 38338270Smckusick struct statfs *buf; 38438270Smckusick long bufsize; 38540343Smckusick int flags; 38642441Smckusick } *uap; 38742441Smckusick int *retval; 38842441Smckusick { 38938270Smckusick register struct mount *mp; 39040343Smckusick register struct statfs *sp; 39139606Smckusick caddr_t sfsp; 39238270Smckusick long count, maxcount, error; 39338270Smckusick 39438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39539606Smckusick sfsp = (caddr_t)uap->buf; 39638270Smckusick mp = rootfs; 39738270Smckusick count = 0; 39838270Smckusick do { 39941400Smckusick if (sfsp && count < maxcount && 40041400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40141400Smckusick sp = &mp->mnt_stat; 40240343Smckusick /* 40340343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40440343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40540343Smckusick */ 40640343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40740343Smckusick (uap->flags & MNT_WAIT)) && 40840343Smckusick (error = VFS_STATFS(mp, sp))) { 40941400Smckusick mp = mp->mnt_prev; 41039607Smckusick continue; 41139607Smckusick } 41241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41439606Smckusick RETURN (error); 41540343Smckusick sfsp += sizeof(*sp); 41638270Smckusick } 41739606Smckusick count++; 41841400Smckusick mp = mp->mnt_prev; 41938270Smckusick } while (mp != rootfs); 42038270Smckusick if (sfsp && count > maxcount) 42142441Smckusick *retval = maxcount; 42238270Smckusick else 42342441Smckusick *retval = count; 42438270Smckusick RETURN (0); 42538270Smckusick } 42638270Smckusick 42738270Smckusick /* 42838259Smckusick * Change current working directory to a given file descriptor. 42938259Smckusick */ 43042441Smckusick /* ARGSUSED */ 43142441Smckusick fchdir(p, uap, retval) 43242441Smckusick register struct proc *p; 43342441Smckusick struct args { 43442441Smckusick int fd; 43542441Smckusick } *uap; 43642441Smckusick int *retval; 43738259Smckusick { 43842441Smckusick register struct nameidata *ndp = &u.u_nd; 43938259Smckusick register struct vnode *vp; 44038259Smckusick struct file *fp; 44138259Smckusick int error; 44238259Smckusick 44342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 44438259Smckusick RETURN (error); 44538259Smckusick vp = (struct vnode *)fp->f_data; 44638259Smckusick VOP_LOCK(vp); 44738259Smckusick if (vp->v_type != VDIR) 44838259Smckusick error = ENOTDIR; 44938259Smckusick else 45042441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45138259Smckusick VOP_UNLOCK(vp); 45239860Smckusick if (error) 45339860Smckusick RETURN (error); 45439860Smckusick VREF(vp); 45542441Smckusick vrele(ndp->ni_cdir); 45642441Smckusick ndp->ni_cdir = vp; 45739860Smckusick RETURN (0); 45838259Smckusick } 45938259Smckusick 46038259Smckusick /* 46137741Smckusick * Change current working directory (``.''). 46237741Smckusick */ 46342441Smckusick /* ARGSUSED */ 46442441Smckusick chdir(p, uap, retval) 46542441Smckusick register struct proc *p; 46642441Smckusick struct args { 46742441Smckusick char *fname; 46842441Smckusick } *uap; 46942441Smckusick int *retval; 47037741Smckusick { 47142441Smckusick register struct nameidata *ndp = &u.u_nd; 47237741Smckusick int error; 4736254Sroot 47437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47616694Smckusick ndp->ni_dirp = uap->fname; 47737741Smckusick if (error = chdirec(ndp)) 47837741Smckusick RETURN (error); 47942441Smckusick vrele(ndp->ni_cdir); 48042441Smckusick ndp->ni_cdir = ndp->ni_vp; 48137741Smckusick RETURN (0); 48237741Smckusick } 4836254Sroot 48437741Smckusick /* 48537741Smckusick * Change notion of root (``/'') directory. 48637741Smckusick */ 48742441Smckusick /* ARGSUSED */ 48842441Smckusick chroot(p, uap, retval) 48942441Smckusick register struct proc *p; 49042441Smckusick struct args { 49142441Smckusick char *fname; 49242441Smckusick } *uap; 49342441Smckusick int *retval; 49437741Smckusick { 49542441Smckusick register struct nameidata *ndp = &u.u_nd; 49637741Smckusick int error; 49737741Smckusick 49842441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 49937741Smckusick RETURN (error); 50037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50237741Smckusick ndp->ni_dirp = uap->fname; 50337741Smckusick if (error = chdirec(ndp)) 50437741Smckusick RETURN (error); 50542441Smckusick if (ndp->ni_rdir != NULL) 50642441Smckusick vrele(ndp->ni_rdir); 50742441Smckusick ndp->ni_rdir = ndp->ni_vp; 50837741Smckusick RETURN (0); 5096254Sroot } 5106254Sroot 51137Sbill /* 51237741Smckusick * Common routine for chroot and chdir. 51337741Smckusick */ 51437741Smckusick chdirec(ndp) 51537741Smckusick register struct nameidata *ndp; 51637741Smckusick { 51737741Smckusick struct vnode *vp; 51837741Smckusick int error; 51937741Smckusick 52037741Smckusick if (error = namei(ndp)) 52137741Smckusick return (error); 52237741Smckusick vp = ndp->ni_vp; 52337741Smckusick if (vp->v_type != VDIR) 52437741Smckusick error = ENOTDIR; 52537741Smckusick else 52638399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52737741Smckusick VOP_UNLOCK(vp); 52837741Smckusick if (error) 52937741Smckusick vrele(vp); 53037741Smckusick return (error); 53137741Smckusick } 53237741Smckusick 53337741Smckusick /* 5346254Sroot * Open system call. 53542441Smckusick * Check permissions, allocate an open file structure, 53642441Smckusick * and call the device open routine if any. 5376254Sroot */ 53842441Smckusick open(p, uap, retval) 53942441Smckusick register struct proc *p; 54042441Smckusick register struct args { 5416254Sroot char *fname; 5427701Ssam int mode; 54312756Ssam int crtmode; 54442441Smckusick } *uap; 54542441Smckusick int *retval; 5466254Sroot { 54742441Smckusick struct nameidata *ndp = &u.u_nd; 54842441Smckusick register struct file *fp; 54937741Smckusick int fmode, cmode; 55037741Smckusick struct file *nfp; 55137741Smckusick int indx, error; 55237741Smckusick extern struct fileops vnops; 5536254Sroot 55437741Smckusick if (error = falloc(&nfp, &indx)) 55542441Smckusick RETURN (error); 55637741Smckusick fp = nfp; 55742441Smckusick fmode = uap->mode - FOPEN; 55842441Smckusick cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; 55942441Smckusick ndp->ni_segflg = UIO_USERSPACE; 56042441Smckusick ndp->ni_dirp = uap->fname; 56142441Smckusick u.u_r.u_rv.R_val1 = indx; /* XXX for fdopen() */ 56242441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56337741Smckusick crfree(fp->f_cred); 56437741Smckusick fp->f_count--; 56542441Smckusick if (error == EJUSTRETURN) { /* XXX from fdopen */ 56642441Smckusick *retval = indx; 56742441Smckusick RETURN (0); 56842441Smckusick } 56940884Smckusick if (error == ERESTART) 57040884Smckusick error = EINTR; 57142441Smckusick u.u_ofile[indx] = NULL; 57242441Smckusick RETURN (error); 57312756Ssam } 57437741Smckusick fp->f_flag = fmode & FMASK; 57537741Smckusick fp->f_type = DTYPE_VNODE; 57637741Smckusick fp->f_ops = &vnops; 57737741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 57842441Smckusick *retval = indx; 57942441Smckusick RETURN (0); 5806254Sroot } 5816254Sroot 582*42955Smckusick #ifdef COMPAT_43 5836254Sroot /* 58442441Smckusick * Creat system call. 5856254Sroot */ 586*42955Smckusick ocreat(p, uap, retval) 58742441Smckusick struct proc *p; 58842441Smckusick register struct args { 58942441Smckusick char *fname; 59042441Smckusick int fmode; 59142441Smckusick } *uap; 59242441Smckusick int *retval; 5936254Sroot { 59442441Smckusick struct args { 5956254Sroot char *fname; 59642441Smckusick int mode; 59742441Smckusick int crtmode; 59842441Smckusick } openuap; 59942441Smckusick 60042441Smckusick openuap.fname = uap->fname; 60142441Smckusick openuap.crtmode = uap->fmode; 60242441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60342441Smckusick RETURN (open(p, &openuap, retval)); 60442441Smckusick } 605*42955Smckusick #endif /* COMPAT_43 */ 60642441Smckusick 60742441Smckusick /* 60842441Smckusick * Mknod system call 60942441Smckusick */ 61042441Smckusick /* ARGSUSED */ 61142441Smckusick mknod(p, uap, retval) 61242441Smckusick register struct proc *p; 61342441Smckusick register struct args { 61442441Smckusick char *fname; 6156254Sroot int fmode; 6166254Sroot int dev; 61742441Smckusick } *uap; 61842441Smckusick int *retval; 61942441Smckusick { 62042441Smckusick register struct nameidata *ndp = &u.u_nd; 62137741Smckusick register struct vnode *vp; 62237741Smckusick struct vattr vattr; 62337741Smckusick int error; 6246254Sroot 62542441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62637741Smckusick RETURN (error); 62737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62916694Smckusick ndp->ni_dirp = uap->fname; 63037741Smckusick if (error = namei(ndp)) 63137741Smckusick RETURN (error); 63237741Smckusick vp = ndp->ni_vp; 63337741Smckusick if (vp != NULL) { 63437741Smckusick error = EEXIST; 63512756Ssam goto out; 6366254Sroot } 63741362Smckusick VATTR_NULL(&vattr); 63840635Smckusick switch (uap->fmode & S_IFMT) { 63912756Ssam 64040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64137741Smckusick vattr.va_type = VBAD; 64237741Smckusick break; 64340635Smckusick case S_IFCHR: 64437741Smckusick vattr.va_type = VCHR; 64537741Smckusick break; 64640635Smckusick case S_IFBLK: 64737741Smckusick vattr.va_type = VBLK; 64837741Smckusick break; 64937741Smckusick default: 65037741Smckusick error = EINVAL; 65137741Smckusick goto out; 6526254Sroot } 65342441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 65437741Smckusick vattr.va_rdev = uap->dev; 6556254Sroot out: 65642465Smckusick if (!error) { 65742465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 65842465Smckusick } else { 65937741Smckusick VOP_ABORTOP(ndp); 66042465Smckusick vput(ndp->ni_dvp); 66142465Smckusick if (vp) 66242465Smckusick vrele(vp); 66342465Smckusick } 66437741Smckusick RETURN (error); 6656254Sroot } 6666254Sroot 6676254Sroot /* 66840285Smckusick * Mkfifo system call 66940285Smckusick */ 67042441Smckusick /* ARGSUSED */ 67142441Smckusick mkfifo(p, uap, retval) 67242441Smckusick register struct proc *p; 67342441Smckusick register struct args { 67440285Smckusick char *fname; 67540285Smckusick int fmode; 67642441Smckusick } *uap; 67742441Smckusick int *retval; 67842441Smckusick { 67942441Smckusick register struct nameidata *ndp = &u.u_nd; 68040285Smckusick struct vattr vattr; 68140285Smckusick int error; 68240285Smckusick 68340285Smckusick #ifndef FIFO 68440285Smckusick RETURN (EOPNOTSUPP); 68540285Smckusick #else 68640285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 68740285Smckusick ndp->ni_segflg = UIO_USERSPACE; 68840285Smckusick ndp->ni_dirp = uap->fname; 68940285Smckusick if (error = namei(ndp)) 69040285Smckusick RETURN (error); 69140285Smckusick if (ndp->ni_vp != NULL) { 69240285Smckusick VOP_ABORTOP(ndp); 69342465Smckusick vput(ndp->ni_dvp); 69442465Smckusick vrele(ndp->ni_vp); 69540285Smckusick RETURN (EEXIST); 69640285Smckusick } else { 69741362Smckusick VATTR_NULL(&vattr); 69840285Smckusick vattr.va_type = VFIFO; 69942441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 70040285Smckusick } 70140285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 70240285Smckusick #endif /* FIFO */ 70340285Smckusick } 70440285Smckusick 70540285Smckusick /* 7066254Sroot * link system call 7076254Sroot */ 70842441Smckusick /* ARGSUSED */ 70942441Smckusick link(p, uap, retval) 71042441Smckusick register struct proc *p; 71142441Smckusick register struct args { 7126254Sroot char *target; 7136254Sroot char *linkname; 71442441Smckusick } *uap; 71542441Smckusick int *retval; 71642441Smckusick { 71742441Smckusick register struct nameidata *ndp = &u.u_nd; 71837741Smckusick register struct vnode *vp, *xp; 71937741Smckusick int error; 7206254Sroot 72116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72316694Smckusick ndp->ni_dirp = uap->target; 72437741Smckusick if (error = namei(ndp)) 72537741Smckusick RETURN (error); 72637741Smckusick vp = ndp->ni_vp; 72737741Smckusick if (vp->v_type == VDIR && 72842441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 72937741Smckusick goto out1; 73037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 73237741Smckusick if (error = namei(ndp)) 73337741Smckusick goto out1; 73437741Smckusick xp = ndp->ni_vp; 7356254Sroot if (xp != NULL) { 73637741Smckusick error = EEXIST; 7376254Sroot goto out; 7386254Sroot } 73937741Smckusick xp = ndp->ni_dvp; 74037741Smckusick if (vp->v_mount != xp->v_mount) 74137741Smckusick error = EXDEV; 7426254Sroot out: 74342465Smckusick if (!error) { 74442465Smckusick error = VOP_LINK(vp, ndp); 74542465Smckusick } else { 74637741Smckusick VOP_ABORTOP(ndp); 74742465Smckusick vput(ndp->ni_dvp); 74842465Smckusick if (ndp->ni_vp) 74942465Smckusick vrele(ndp->ni_vp); 75042465Smckusick } 75137741Smckusick out1: 75237741Smckusick vrele(vp); 75337741Smckusick RETURN (error); 7546254Sroot } 7556254Sroot 7566254Sroot /* 7576254Sroot * symlink -- make a symbolic link 7586254Sroot */ 75942441Smckusick /* ARGSUSED */ 76042441Smckusick symlink(p, uap, retval) 76142441Smckusick register struct proc *p; 76242441Smckusick register struct args { 7636254Sroot char *target; 7646254Sroot char *linkname; 76542441Smckusick } *uap; 76642441Smckusick int *retval; 76742441Smckusick { 76842441Smckusick register struct nameidata *ndp = &u.u_nd; 76937741Smckusick struct vattr vattr; 77037741Smckusick char *target; 77137741Smckusick int error; 7726254Sroot 77316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77416694Smckusick ndp->ni_dirp = uap->linkname; 77537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 77637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 77742465Smckusick goto out; 77837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 77937741Smckusick if (error = namei(ndp)) 78042465Smckusick goto out; 78142465Smckusick if (ndp->ni_vp) { 78242465Smckusick VOP_ABORTOP(ndp); 78342465Smckusick vput(ndp->ni_dvp); 78442465Smckusick vrele(ndp->ni_vp); 78537741Smckusick error = EEXIST; 78637741Smckusick goto out; 7876254Sroot } 78841362Smckusick VATTR_NULL(&vattr); 78942441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 79042465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 79137741Smckusick out: 79237741Smckusick FREE(target, M_NAMEI); 79337741Smckusick RETURN (error); 7946254Sroot } 7956254Sroot 7966254Sroot /* 7976254Sroot * Unlink system call. 7986254Sroot * Hard to avoid races here, especially 7996254Sroot * in unlinking directories. 8006254Sroot */ 80142441Smckusick /* ARGSUSED */ 80242441Smckusick unlink(p, uap, retval) 80342441Smckusick register struct proc *p; 80442441Smckusick struct args { 80542441Smckusick char *fname; 80642441Smckusick } *uap; 80742441Smckusick int *retval; 8086254Sroot { 80942441Smckusick register struct nameidata *ndp = &u.u_nd; 81037741Smckusick register struct vnode *vp; 81137741Smckusick int error; 8126254Sroot 81337741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 81416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81516694Smckusick ndp->ni_dirp = uap->fname; 81637741Smckusick if (error = namei(ndp)) 81737741Smckusick RETURN (error); 81837741Smckusick vp = ndp->ni_vp; 81937741Smckusick if (vp->v_type == VDIR && 82042441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8216254Sroot goto out; 8226254Sroot /* 8236254Sroot * Don't unlink a mounted file. 8246254Sroot */ 82537741Smckusick if (vp->v_flag & VROOT) { 82637741Smckusick error = EBUSY; 8276254Sroot goto out; 8286254Sroot } 82937741Smckusick if (vp->v_flag & VTEXT) 83037741Smckusick xrele(vp); /* try once to free text */ 8316254Sroot out: 83242465Smckusick if (!error) { 83342465Smckusick error = VOP_REMOVE(ndp); 83442465Smckusick } else { 83537741Smckusick VOP_ABORTOP(ndp); 83642465Smckusick vput(ndp->ni_dvp); 83742465Smckusick vput(vp); 83842465Smckusick } 83937741Smckusick RETURN (error); 8406254Sroot } 8416254Sroot 8426254Sroot /* 8436254Sroot * Seek system call 8446254Sroot */ 84542441Smckusick lseek(p, uap, retval) 84642441Smckusick register struct proc *p; 84742441Smckusick register struct args { 84837741Smckusick int fdes; 8496254Sroot off_t off; 8506254Sroot int sbase; 85142441Smckusick } *uap; 85242441Smckusick off_t *retval; 85342441Smckusick { 85442441Smckusick struct ucred *cred = u.u_nd.ni_cred; 85542441Smckusick register struct file *fp; 85637741Smckusick struct vattr vattr; 85737741Smckusick int error; 8586254Sroot 85937741Smckusick if ((unsigned)uap->fdes >= NOFILE || 86042441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 86137741Smckusick RETURN (EBADF); 86237741Smckusick if (fp->f_type != DTYPE_VNODE) 86337741Smckusick RETURN (ESPIPE); 86413878Ssam switch (uap->sbase) { 86513878Ssam 86613878Ssam case L_INCR: 86713878Ssam fp->f_offset += uap->off; 86813878Ssam break; 86913878Ssam 87013878Ssam case L_XTND: 87137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 87242441Smckusick &vattr, cred)) 87337741Smckusick RETURN (error); 87437741Smckusick fp->f_offset = uap->off + vattr.va_size; 87513878Ssam break; 87613878Ssam 87713878Ssam case L_SET: 87813878Ssam fp->f_offset = uap->off; 87913878Ssam break; 88013878Ssam 88113878Ssam default: 88237741Smckusick RETURN (EINVAL); 88313878Ssam } 88442441Smckusick *retval = fp->f_offset; 88537741Smckusick RETURN (0); 8866254Sroot } 8876254Sroot 8886254Sroot /* 8896254Sroot * Access system call 8906254Sroot */ 89142441Smckusick /* ARGSUSED */ 89242441Smckusick saccess(p, uap, retval) 89342441Smckusick register struct proc *p; 89442441Smckusick register struct args { 8956254Sroot char *fname; 8966254Sroot int fmode; 89742441Smckusick } *uap; 89842441Smckusick int *retval; 89942441Smckusick { 90042441Smckusick register struct nameidata *ndp = &u.u_nd; 90142441Smckusick register struct ucred *cred = ndp->ni_cred; 90237741Smckusick register struct vnode *vp; 90337741Smckusick int error, mode, svuid, svgid; 9046254Sroot 90542441Smckusick svuid = cred->cr_uid; 90642441Smckusick svgid = cred->cr_groups[0]; 90742441Smckusick cred->cr_uid = p->p_ruid; 90842441Smckusick cred->cr_groups[0] = p->p_rgid; 90937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 91016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 91116694Smckusick ndp->ni_dirp = uap->fname; 91237741Smckusick if (error = namei(ndp)) 91337741Smckusick goto out1; 91437741Smckusick vp = ndp->ni_vp; 91537741Smckusick /* 91637741Smckusick * fmode == 0 means only check for exist 91737741Smckusick */ 91837741Smckusick if (uap->fmode) { 91937741Smckusick mode = 0; 92037741Smckusick if (uap->fmode & R_OK) 92137741Smckusick mode |= VREAD; 92237741Smckusick if (uap->fmode & W_OK) 92337741Smckusick mode |= VWRITE; 92437741Smckusick if (uap->fmode & X_OK) 92537741Smckusick mode |= VEXEC; 92639543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 92738399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9286254Sroot } 92937741Smckusick vput(vp); 93037741Smckusick out1: 93142441Smckusick cred->cr_uid = svuid; 93242441Smckusick cred->cr_groups[0] = svgid; 93337741Smckusick RETURN (error); 9346254Sroot } 9356254Sroot 9366254Sroot /* 9376574Smckusic * Stat system call. This version follows links. 93837Sbill */ 93942441Smckusick /* ARGSUSED */ 94042441Smckusick stat(p, uap, retval) 94142441Smckusick register struct proc *p; 94242441Smckusick register struct args { 94342441Smckusick char *fname; 94442441Smckusick struct stat *ub; 94542441Smckusick } *uap; 94642441Smckusick int *retval; 94737Sbill { 94842441Smckusick register struct nameidata *ndp = &u.u_nd; 94942441Smckusick struct stat sb; 95042441Smckusick int error; 95137Sbill 95242441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 95342441Smckusick ndp->ni_segflg = UIO_USERSPACE; 95442441Smckusick ndp->ni_dirp = uap->fname; 95542441Smckusick if (error = namei(ndp)) 95642441Smckusick RETURN (error); 95742441Smckusick error = vn_stat(ndp->ni_vp, &sb); 95842441Smckusick vput(ndp->ni_vp); 95942441Smckusick if (error) 96042441Smckusick RETURN (error); 96142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 96242441Smckusick RETURN (error); 96337Sbill } 96437Sbill 96537Sbill /* 9666574Smckusic * Lstat system call. This version does not follow links. 9675992Swnj */ 96842441Smckusick /* ARGSUSED */ 96942441Smckusick lstat(p, uap, retval) 97042441Smckusick register struct proc *p; 97142441Smckusick register struct args { 9725992Swnj char *fname; 97312756Ssam struct stat *ub; 97442441Smckusick } *uap; 97542441Smckusick int *retval; 97642441Smckusick { 97742441Smckusick register struct nameidata *ndp = &u.u_nd; 97812756Ssam struct stat sb; 97937741Smckusick int error; 9805992Swnj 98142441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 98216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 98316694Smckusick ndp->ni_dirp = uap->fname; 98437741Smckusick if (error = namei(ndp)) 98537741Smckusick RETURN (error); 98637741Smckusick error = vn_stat(ndp->ni_vp, &sb); 98737741Smckusick vput(ndp->ni_vp); 98837741Smckusick if (error) 98937741Smckusick RETURN (error); 99037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 99137741Smckusick RETURN (error); 9925992Swnj } 9935992Swnj 9945992Swnj /* 9955992Swnj * Return target name of a symbolic link 99637Sbill */ 99742441Smckusick /* ARGSUSED */ 99842441Smckusick readlink(p, uap, retval) 99942441Smckusick register struct proc *p; 100042441Smckusick register struct args { 10015992Swnj char *name; 10025992Swnj char *buf; 10035992Swnj int count; 100442441Smckusick } *uap; 100542441Smckusick int *retval; 100642441Smckusick { 100742441Smckusick register struct nameidata *ndp = &u.u_nd; 100837741Smckusick register struct vnode *vp; 100937741Smckusick struct iovec aiov; 101037741Smckusick struct uio auio; 101137741Smckusick int error; 10125992Swnj 101337741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 101416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 101516694Smckusick ndp->ni_dirp = uap->name; 101637741Smckusick if (error = namei(ndp)) 101737741Smckusick RETURN (error); 101837741Smckusick vp = ndp->ni_vp; 101937741Smckusick if (vp->v_type != VLNK) { 102037741Smckusick error = EINVAL; 10215992Swnj goto out; 10225992Swnj } 102337741Smckusick aiov.iov_base = uap->buf; 102437741Smckusick aiov.iov_len = uap->count; 102537741Smckusick auio.uio_iov = &aiov; 102637741Smckusick auio.uio_iovcnt = 1; 102737741Smckusick auio.uio_offset = 0; 102837741Smckusick auio.uio_rw = UIO_READ; 102937741Smckusick auio.uio_segflg = UIO_USERSPACE; 103037741Smckusick auio.uio_resid = uap->count; 103137741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10325992Swnj out: 103337741Smckusick vput(vp); 103442441Smckusick *retval = uap->count - auio.uio_resid; 103537741Smckusick RETURN (error); 10365992Swnj } 10375992Swnj 10389167Ssam /* 103938259Smckusick * Change flags of a file given path name. 104038259Smckusick */ 104142441Smckusick /* ARGSUSED */ 104242441Smckusick chflags(p, uap, retval) 104342441Smckusick register struct proc *p; 104442441Smckusick register struct args { 104538259Smckusick char *fname; 104638259Smckusick int flags; 104742441Smckusick } *uap; 104842441Smckusick int *retval; 104942441Smckusick { 105042441Smckusick register struct nameidata *ndp = &u.u_nd; 105138259Smckusick register struct vnode *vp; 105238259Smckusick struct vattr vattr; 105338259Smckusick int error; 105438259Smckusick 105538259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 105638259Smckusick ndp->ni_segflg = UIO_USERSPACE; 105738259Smckusick ndp->ni_dirp = uap->fname; 105841362Smckusick VATTR_NULL(&vattr); 105938259Smckusick vattr.va_flags = uap->flags; 106038259Smckusick if (error = namei(ndp)) 106138259Smckusick RETURN (error); 106238259Smckusick vp = ndp->ni_vp; 106341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 106438259Smckusick error = EROFS; 106538259Smckusick goto out; 106638259Smckusick } 106738259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 106838259Smckusick out: 106938259Smckusick vput(vp); 107038259Smckusick RETURN (error); 107138259Smckusick } 107238259Smckusick 107338259Smckusick /* 107438259Smckusick * Change flags of a file given a file descriptor. 107538259Smckusick */ 107642441Smckusick /* ARGSUSED */ 107742441Smckusick fchflags(p, uap, retval) 107842441Smckusick register struct proc *p; 107942441Smckusick register struct args { 108038259Smckusick int fd; 108138259Smckusick int flags; 108242441Smckusick } *uap; 108342441Smckusick int *retval; 108442441Smckusick { 108538259Smckusick struct vattr vattr; 108638259Smckusick struct vnode *vp; 108738259Smckusick struct file *fp; 108838259Smckusick int error; 108938259Smckusick 109042441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 109138259Smckusick RETURN (error); 109241362Smckusick VATTR_NULL(&vattr); 109338259Smckusick vattr.va_flags = uap->flags; 109438259Smckusick vp = (struct vnode *)fp->f_data; 109538259Smckusick VOP_LOCK(vp); 109641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 109738259Smckusick error = EROFS; 109838259Smckusick goto out; 109938259Smckusick } 110038259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 110138259Smckusick out: 110238259Smckusick VOP_UNLOCK(vp); 110338259Smckusick RETURN (error); 110438259Smckusick } 110538259Smckusick 110638259Smckusick /* 11079167Ssam * Change mode of a file given path name. 11089167Ssam */ 110942441Smckusick /* ARGSUSED */ 111042441Smckusick chmod(p, uap, retval) 111142441Smckusick register struct proc *p; 111242441Smckusick register struct args { 11136254Sroot char *fname; 11146254Sroot int fmode; 111542441Smckusick } *uap; 111642441Smckusick int *retval; 111742441Smckusick { 111842441Smckusick register struct nameidata *ndp = &u.u_nd; 111937741Smckusick register struct vnode *vp; 112037741Smckusick struct vattr vattr; 112137741Smckusick int error; 11225992Swnj 112337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 112437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 112537741Smckusick ndp->ni_dirp = uap->fname; 112641362Smckusick VATTR_NULL(&vattr); 112737741Smckusick vattr.va_mode = uap->fmode & 07777; 112837741Smckusick if (error = namei(ndp)) 112937741Smckusick RETURN (error); 113037741Smckusick vp = ndp->ni_vp; 113141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 113237741Smckusick error = EROFS; 113337741Smckusick goto out; 113437741Smckusick } 113537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 113637741Smckusick out: 113737741Smckusick vput(vp); 113837741Smckusick RETURN (error); 11397701Ssam } 11407439Sroot 11419167Ssam /* 11429167Ssam * Change mode of a file given a file descriptor. 11439167Ssam */ 114442441Smckusick /* ARGSUSED */ 114542441Smckusick fchmod(p, uap, retval) 114642441Smckusick register struct proc *p; 114742441Smckusick register struct args { 11487701Ssam int fd; 11497701Ssam int fmode; 115042441Smckusick } *uap; 115142441Smckusick int *retval; 115242441Smckusick { 115337741Smckusick struct vattr vattr; 115437741Smckusick struct vnode *vp; 115537741Smckusick struct file *fp; 115637741Smckusick int error; 11577701Ssam 115842441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 115937741Smckusick RETURN (error); 116041362Smckusick VATTR_NULL(&vattr); 116137741Smckusick vattr.va_mode = uap->fmode & 07777; 116237741Smckusick vp = (struct vnode *)fp->f_data; 116337741Smckusick VOP_LOCK(vp); 116441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 116537741Smckusick error = EROFS; 116637741Smckusick goto out; 11677439Sroot } 116837741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 116937741Smckusick out: 117037741Smckusick VOP_UNLOCK(vp); 117137741Smckusick RETURN (error); 11725992Swnj } 11735992Swnj 11749167Ssam /* 11759167Ssam * Set ownership given a path name. 11769167Ssam */ 117742441Smckusick /* ARGSUSED */ 117842441Smckusick chown(p, uap, retval) 117942441Smckusick register struct proc *p; 118042441Smckusick register struct args { 11816254Sroot char *fname; 11826254Sroot int uid; 11836254Sroot int gid; 118442441Smckusick } *uap; 118542441Smckusick int *retval; 118642441Smckusick { 118742441Smckusick register struct nameidata *ndp = &u.u_nd; 118837741Smckusick register struct vnode *vp; 118937741Smckusick struct vattr vattr; 119037741Smckusick int error; 119137Sbill 119237741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 119336614Sbostic ndp->ni_segflg = UIO_USERSPACE; 119436614Sbostic ndp->ni_dirp = uap->fname; 119541362Smckusick VATTR_NULL(&vattr); 119637741Smckusick vattr.va_uid = uap->uid; 119737741Smckusick vattr.va_gid = uap->gid; 119837741Smckusick if (error = namei(ndp)) 119937741Smckusick RETURN (error); 120037741Smckusick vp = ndp->ni_vp; 120141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 120237741Smckusick error = EROFS; 120337741Smckusick goto out; 120437741Smckusick } 120537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 120637741Smckusick out: 120737741Smckusick vput(vp); 120837741Smckusick RETURN (error); 12097701Ssam } 12107439Sroot 12119167Ssam /* 12129167Ssam * Set ownership given a file descriptor. 12139167Ssam */ 121442441Smckusick /* ARGSUSED */ 121542441Smckusick fchown(p, uap, retval) 121642441Smckusick register struct proc *p; 121742441Smckusick register struct args { 12187701Ssam int fd; 12197701Ssam int uid; 12207701Ssam int gid; 122142441Smckusick } *uap; 122242441Smckusick int *retval; 122342441Smckusick { 122437741Smckusick struct vattr vattr; 122537741Smckusick struct vnode *vp; 122637741Smckusick struct file *fp; 122737741Smckusick int error; 12287701Ssam 122942441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 123037741Smckusick RETURN (error); 123141362Smckusick VATTR_NULL(&vattr); 123237741Smckusick vattr.va_uid = uap->uid; 123337741Smckusick vattr.va_gid = uap->gid; 123437741Smckusick vp = (struct vnode *)fp->f_data; 123537741Smckusick VOP_LOCK(vp); 123641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 123737741Smckusick error = EROFS; 123837741Smckusick goto out; 123937741Smckusick } 124037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 124137741Smckusick out: 124237741Smckusick VOP_UNLOCK(vp); 124337741Smckusick RETURN (error); 12447701Ssam } 12457701Ssam 124642441Smckusick /* 124742441Smckusick * Set the access and modification times of a file. 124842441Smckusick */ 124942441Smckusick /* ARGSUSED */ 125042441Smckusick utimes(p, uap, retval) 125142441Smckusick register struct proc *p; 125242441Smckusick register struct args { 125311811Ssam char *fname; 125411811Ssam struct timeval *tptr; 125542441Smckusick } *uap; 125642441Smckusick int *retval; 125742441Smckusick { 125842441Smckusick register struct nameidata *ndp = &u.u_nd; 125937741Smckusick register struct vnode *vp; 126011811Ssam struct timeval tv[2]; 126137741Smckusick struct vattr vattr; 126237741Smckusick int error; 126311811Ssam 126437741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 126537741Smckusick RETURN (error); 126637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 126737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 126837741Smckusick ndp->ni_dirp = uap->fname; 126941362Smckusick VATTR_NULL(&vattr); 127037741Smckusick vattr.va_atime = tv[0]; 127137741Smckusick vattr.va_mtime = tv[1]; 127237741Smckusick if (error = namei(ndp)) 127337741Smckusick RETURN (error); 127437741Smckusick vp = ndp->ni_vp; 127541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 127637741Smckusick error = EROFS; 127737741Smckusick goto out; 127821015Smckusick } 127937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 128037741Smckusick out: 128137741Smckusick vput(vp); 128237741Smckusick RETURN (error); 128311811Ssam } 128411811Ssam 12859167Ssam /* 12869167Ssam * Truncate a file given its path name. 12879167Ssam */ 128842441Smckusick /* ARGSUSED */ 128942441Smckusick truncate(p, uap, retval) 129042441Smckusick register struct proc *p; 129142441Smckusick register struct args { 12927701Ssam char *fname; 129326473Skarels off_t length; 129442441Smckusick } *uap; 129542441Smckusick int *retval; 129642441Smckusick { 129742441Smckusick register struct nameidata *ndp = &u.u_nd; 129837741Smckusick register struct vnode *vp; 129937741Smckusick struct vattr vattr; 130037741Smckusick int error; 13017701Ssam 130237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 130316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130416694Smckusick ndp->ni_dirp = uap->fname; 130541362Smckusick VATTR_NULL(&vattr); 130637741Smckusick vattr.va_size = uap->length; 130737741Smckusick if (error = namei(ndp)) 130837741Smckusick RETURN (error); 130937741Smckusick vp = ndp->ni_vp; 131037741Smckusick if (vp->v_type == VDIR) { 131137741Smckusick error = EISDIR; 131237741Smckusick goto out; 13137701Ssam } 131438399Smckusick if ((error = vn_writechk(vp)) || 131538399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 131637741Smckusick goto out; 131737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 131837741Smckusick out: 131937741Smckusick vput(vp); 132037741Smckusick RETURN (error); 13217701Ssam } 13227701Ssam 13239167Ssam /* 13249167Ssam * Truncate a file given a file descriptor. 13259167Ssam */ 132642441Smckusick /* ARGSUSED */ 132742441Smckusick ftruncate(p, uap, retval) 132842441Smckusick register struct proc *p; 132942441Smckusick register struct args { 13307701Ssam int fd; 133126473Skarels off_t length; 133242441Smckusick } *uap; 133342441Smckusick int *retval; 133442441Smckusick { 133537741Smckusick struct vattr vattr; 133637741Smckusick struct vnode *vp; 13377701Ssam struct file *fp; 133837741Smckusick int error; 13397701Ssam 134042441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 134137741Smckusick RETURN (error); 134237741Smckusick if ((fp->f_flag & FWRITE) == 0) 134337741Smckusick RETURN (EINVAL); 134441362Smckusick VATTR_NULL(&vattr); 134537741Smckusick vattr.va_size = uap->length; 134637741Smckusick vp = (struct vnode *)fp->f_data; 134737741Smckusick VOP_LOCK(vp); 134837741Smckusick if (vp->v_type == VDIR) { 134937741Smckusick error = EISDIR; 135037741Smckusick goto out; 13517701Ssam } 135238399Smckusick if (error = vn_writechk(vp)) 135337741Smckusick goto out; 135437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 135537741Smckusick out: 135637741Smckusick VOP_UNLOCK(vp); 135737741Smckusick RETURN (error); 13587701Ssam } 13597701Ssam 13609167Ssam /* 13619167Ssam * Synch an open file. 13629167Ssam */ 136342441Smckusick /* ARGSUSED */ 136442441Smckusick fsync(p, uap, retval) 136542441Smckusick register struct proc *p; 136642441Smckusick struct args { 136742441Smckusick int fd; 136842441Smckusick } *uap; 136942441Smckusick int *retval; 13709167Ssam { 137139592Smckusick register struct vnode *vp; 13729167Ssam struct file *fp; 137337741Smckusick int error; 13749167Ssam 137542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 137637741Smckusick RETURN (error); 137739592Smckusick vp = (struct vnode *)fp->f_data; 137839592Smckusick VOP_LOCK(vp); 137939592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 138039592Smckusick VOP_UNLOCK(vp); 138137741Smckusick RETURN (error); 13829167Ssam } 13839167Ssam 13849167Ssam /* 13859167Ssam * Rename system call. 13869167Ssam * 13879167Ssam * Source and destination must either both be directories, or both 13889167Ssam * not be directories. If target is a directory, it must be empty. 13899167Ssam */ 139042441Smckusick /* ARGSUSED */ 139142441Smckusick rename(p, uap, retval) 139242441Smckusick register struct proc *p; 139342441Smckusick register struct args { 13947701Ssam char *from; 13957701Ssam char *to; 139642441Smckusick } *uap; 139742441Smckusick int *retval; 139842441Smckusick { 139937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 140042441Smckusick register struct nameidata *ndp = &u.u_nd; 140137741Smckusick struct nameidata tond; 140237741Smckusick int error; 14037701Ssam 140437741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 140516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 140616694Smckusick ndp->ni_dirp = uap->from; 140737741Smckusick if (error = namei(ndp)) 140837741Smckusick RETURN (error); 140937741Smckusick fvp = ndp->ni_vp; 141038266Smckusick nddup(ndp, &tond); 141137741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 141237741Smckusick tond.ni_segflg = UIO_USERSPACE; 141337741Smckusick tond.ni_dirp = uap->to; 141442465Smckusick if (error = namei(&tond)) { 141542465Smckusick VOP_ABORTOP(ndp); 141642465Smckusick vrele(ndp->ni_dvp); 141742465Smckusick vrele(fvp); 141842465Smckusick goto out1; 141942465Smckusick } 142037741Smckusick tdvp = tond.ni_dvp; 142137741Smckusick tvp = tond.ni_vp; 142237741Smckusick if (tvp != NULL) { 142337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 142439242Sbostic error = ENOTDIR; 142537741Smckusick goto out; 142637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 142739242Sbostic error = EISDIR; 142837741Smckusick goto out; 14299167Ssam } 14309167Ssam } 143137741Smckusick if (fvp->v_mount != tdvp->v_mount) { 143237741Smckusick error = EXDEV; 14339167Ssam goto out; 143410051Ssam } 143539286Smckusick if (fvp == tdvp) 143637741Smckusick error = EINVAL; 143739286Smckusick /* 143839286Smckusick * If source is the same as the destination, 143939286Smckusick * then there is nothing to do. 144039286Smckusick */ 144139286Smckusick if (fvp == tvp) 144239286Smckusick error = -1; 144337741Smckusick out: 144442465Smckusick if (!error) { 144542465Smckusick error = VOP_RENAME(ndp, &tond); 144642465Smckusick } else { 144737741Smckusick VOP_ABORTOP(&tond); 144842465Smckusick vput(tdvp); 144942465Smckusick if (tvp) 145042465Smckusick vput(tvp); 145137741Smckusick VOP_ABORTOP(ndp); 145242465Smckusick vrele(ndp->ni_dvp); 145342465Smckusick vrele(fvp); 14549167Ssam } 145537741Smckusick out1: 145638266Smckusick ndrele(&tond); 145739286Smckusick if (error == -1) 145839286Smckusick RETURN (0); 145937741Smckusick RETURN (error); 14607701Ssam } 14617701Ssam 14627535Sroot /* 146312756Ssam * Mkdir system call 146412756Ssam */ 146542441Smckusick /* ARGSUSED */ 146642441Smckusick mkdir(p, uap, retval) 146742441Smckusick register struct proc *p; 146842441Smckusick register struct args { 146912756Ssam char *name; 147012756Ssam int dmode; 147142441Smckusick } *uap; 147242441Smckusick int *retval; 147342441Smckusick { 147442441Smckusick register struct nameidata *ndp = &u.u_nd; 147537741Smckusick register struct vnode *vp; 147637741Smckusick struct vattr vattr; 147737741Smckusick int error; 147812756Ssam 147937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 148016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 148116694Smckusick ndp->ni_dirp = uap->name; 148237741Smckusick if (error = namei(ndp)) 148337741Smckusick RETURN (error); 148437741Smckusick vp = ndp->ni_vp; 148537741Smckusick if (vp != NULL) { 148637741Smckusick VOP_ABORTOP(ndp); 148742465Smckusick vput(ndp->ni_dvp); 148842465Smckusick vrele(vp); 148937741Smckusick RETURN (EEXIST); 149012756Ssam } 149141362Smckusick VATTR_NULL(&vattr); 149237741Smckusick vattr.va_type = VDIR; 149342441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 149437741Smckusick error = VOP_MKDIR(ndp, &vattr); 149538145Smckusick if (!error) 149638145Smckusick vput(ndp->ni_vp); 149737741Smckusick RETURN (error); 149812756Ssam } 149912756Ssam 150012756Ssam /* 150112756Ssam * Rmdir system call. 150212756Ssam */ 150342441Smckusick /* ARGSUSED */ 150442441Smckusick rmdir(p, uap, retval) 150542441Smckusick register struct proc *p; 150642441Smckusick struct args { 150742441Smckusick char *name; 150842441Smckusick } *uap; 150942441Smckusick int *retval; 151012756Ssam { 151142441Smckusick register struct nameidata *ndp = &u.u_nd; 151237741Smckusick register struct vnode *vp; 151337741Smckusick int error; 151412756Ssam 151537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 151616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 151716694Smckusick ndp->ni_dirp = uap->name; 151837741Smckusick if (error = namei(ndp)) 151937741Smckusick RETURN (error); 152037741Smckusick vp = ndp->ni_vp; 152137741Smckusick if (vp->v_type != VDIR) { 152237741Smckusick error = ENOTDIR; 152312756Ssam goto out; 152412756Ssam } 152512756Ssam /* 152637741Smckusick * No rmdir "." please. 152712756Ssam */ 152837741Smckusick if (ndp->ni_dvp == vp) { 152937741Smckusick error = EINVAL; 153012756Ssam goto out; 153112756Ssam } 153212756Ssam /* 153337741Smckusick * Don't unlink a mounted file. 153412756Ssam */ 153537741Smckusick if (vp->v_flag & VROOT) 153637741Smckusick error = EBUSY; 153712756Ssam out: 153842465Smckusick if (!error) { 153942465Smckusick error = VOP_RMDIR(ndp); 154042465Smckusick } else { 154137741Smckusick VOP_ABORTOP(ndp); 154242465Smckusick vput(ndp->ni_dvp); 154342465Smckusick vput(vp); 154442465Smckusick } 154537741Smckusick RETURN (error); 154612756Ssam } 154712756Ssam 154837741Smckusick /* 154937741Smckusick * Read a block of directory entries in a file system independent format 155037741Smckusick */ 155142441Smckusick getdirentries(p, uap, retval) 155242441Smckusick register struct proc *p; 155342441Smckusick register struct args { 155437741Smckusick int fd; 155537741Smckusick char *buf; 155637741Smckusick unsigned count; 155737741Smckusick long *basep; 155842441Smckusick } *uap; 155942441Smckusick int *retval; 156042441Smckusick { 156139592Smckusick register struct vnode *vp; 156216540Ssam struct file *fp; 156337741Smckusick struct uio auio; 156437741Smckusick struct iovec aiov; 156538129Smckusick off_t off; 156640321Smckusick int error, eofflag; 156712756Ssam 156842441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 156937741Smckusick RETURN (error); 157037741Smckusick if ((fp->f_flag & FREAD) == 0) 157137741Smckusick RETURN (EBADF); 157239592Smckusick vp = (struct vnode *)fp->f_data; 157339592Smckusick if (vp->v_type != VDIR) 157439592Smckusick RETURN (EINVAL); 157537741Smckusick aiov.iov_base = uap->buf; 157637741Smckusick aiov.iov_len = uap->count; 157737741Smckusick auio.uio_iov = &aiov; 157837741Smckusick auio.uio_iovcnt = 1; 157937741Smckusick auio.uio_rw = UIO_READ; 158037741Smckusick auio.uio_segflg = UIO_USERSPACE; 158137741Smckusick auio.uio_resid = uap->count; 158239592Smckusick VOP_LOCK(vp); 158339592Smckusick auio.uio_offset = off = fp->f_offset; 158440321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 158539592Smckusick fp->f_offset = auio.uio_offset; 158639592Smckusick VOP_UNLOCK(vp); 158739592Smckusick if (error) 158837741Smckusick RETURN (error); 158939592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 159042441Smckusick *retval = uap->count - auio.uio_resid; 159137741Smckusick RETURN (error); 159212756Ssam } 159312756Ssam 159412756Ssam /* 159512756Ssam * mode mask for creation of files 159612756Ssam */ 159742441Smckusick mode_t 159842441Smckusick umask(p, uap, retval) 159942441Smckusick register struct proc *p; 160042441Smckusick struct args { 160142441Smckusick int mask; 160242441Smckusick } *uap; 160342441Smckusick int *retval; 160412756Ssam { 160512756Ssam 160642441Smckusick *retval = u.u_cmask; 160742441Smckusick u.u_cmask = uap->mask & 07777; 160837741Smckusick RETURN (0); 160912756Ssam } 161037741Smckusick 161139566Smarc /* 161239566Smarc * Void all references to file by ripping underlying filesystem 161339566Smarc * away from vnode. 161439566Smarc */ 161542441Smckusick /* ARGSUSED */ 161642441Smckusick revoke(p, uap, retval) 161742441Smckusick register struct proc *p; 161842441Smckusick register struct args { 161939566Smarc char *fname; 162041676Smckusick int flags; 162142441Smckusick } *uap; 162242441Smckusick int *retval; 162342441Smckusick { 162442441Smckusick register struct nameidata *ndp = &u.u_nd; 162539566Smarc register struct vnode *vp; 162639566Smarc struct vattr vattr; 162739566Smarc int error; 162839566Smarc 162939566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 163039566Smarc ndp->ni_segflg = UIO_USERSPACE; 163139566Smarc ndp->ni_dirp = uap->fname; 163239566Smarc if (error = namei(ndp)) 163339566Smarc RETURN (error); 163439566Smarc vp = ndp->ni_vp; 163539566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 163639566Smarc error = EINVAL; 163739566Smarc goto out; 163839566Smarc } 163942441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 164039566Smarc goto out; 1641*42955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 164242441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 164339566Smarc goto out; 164439805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 164539632Smckusick vgoneall(vp); 164639566Smarc out: 164739566Smarc vrele(vp); 164839566Smarc RETURN (error); 164939566Smarc } 165039566Smarc 165138408Smckusick getvnode(ofile, fdes, fpp) 165238408Smckusick struct file *ofile[]; 165337741Smckusick struct file **fpp; 165437741Smckusick int fdes; 165537741Smckusick { 165637741Smckusick struct file *fp; 165737741Smckusick 165838408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 165937741Smckusick return (EBADF); 166037741Smckusick if (fp->f_type != DTYPE_VNODE) 166137741Smckusick return (EINVAL); 166237741Smckusick *fpp = fp; 166337741Smckusick return (0); 166437741Smckusick } 1665