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*39665Smckusick * @(#)vfs_syscalls.c 7.32 (Berkeley) 11/30/89 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 "../ufs/inode.h" 2837741Smckusick #include "mount.h" 2917101Sbloom #include "proc.h" 3017101Sbloom #include "uio.h" 3137741Smckusick #include "malloc.h" 3237Sbill 3337741Smckusick /* 3437741Smckusick * Virtual File System System Calls 3537741Smckusick */ 3612756Ssam 379167Ssam /* 3837741Smckusick * mount system call 399167Ssam */ 4038408Smckusick mount(scp) 4138408Smckusick register struct syscontext *scp; 426254Sroot { 4337741Smckusick register struct a { 4437741Smckusick int type; 4537741Smckusick char *dir; 4637741Smckusick int flags; 4737741Smckusick caddr_t data; 4838408Smckusick } *uap = (struct a *)scp->sc_ap; 4938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5039335Smckusick register struct vnode *vp; 5139335Smckusick register struct mount *mp; 5237741Smckusick int error; 536254Sroot 5437741Smckusick /* 5537741Smckusick * Must be super user 5637741Smckusick */ 5738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 5837741Smckusick RETURN (error); 5937741Smckusick /* 6037741Smckusick * Get vnode to be covered 6137741Smckusick */ 6237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6437741Smckusick ndp->ni_dirp = uap->dir; 6537741Smckusick if (error = namei(ndp)) 6637741Smckusick RETURN (error); 6737741Smckusick vp = ndp->ni_vp; 6839335Smckusick if (uap->flags & M_UPDATE) { 6939335Smckusick if ((vp->v_flag & VROOT) == 0) { 7039335Smckusick vput(vp); 7139335Smckusick RETURN (EINVAL); 7239335Smckusick } 7339335Smckusick mp = vp->v_mount; 7439335Smckusick /* 7539335Smckusick * We allow going from read-only to read-write, 7639335Smckusick * but not from read-write to read-only. 7739335Smckusick */ 7839335Smckusick if ((mp->m_flag & M_RDONLY) == 0 && 7939335Smckusick (uap->flags & M_RDONLY) != 0) { 8039335Smckusick vput(vp); 8139335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8239335Smckusick } 8339335Smckusick mp->m_flag |= M_UPDATE; 8439335Smckusick VOP_UNLOCK(vp); 8539335Smckusick goto update; 8639335Smckusick } 87*39665Smckusick vinvalbuf(vp, 1); 8837741Smckusick if (vp->v_count != 1) { 8937741Smckusick vput(vp); 9037741Smckusick RETURN (EBUSY); 9137741Smckusick } 9237741Smckusick if (vp->v_type != VDIR) { 9337741Smckusick vput(vp); 9437741Smckusick RETURN (ENOTDIR); 9537741Smckusick } 9637741Smckusick if (uap->type > MOUNT_MAXTYPE || 9737741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9837741Smckusick vput(vp); 9937741Smckusick RETURN (ENODEV); 10037741Smckusick } 10137741Smckusick 10237741Smckusick /* 10339335Smckusick * Allocate and initialize the file system. 10437741Smckusick */ 10537741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10637741Smckusick M_MOUNT, M_WAITOK); 10737741Smckusick mp->m_op = vfssw[uap->type]; 10837741Smckusick mp->m_flag = 0; 10937741Smckusick mp->m_exroot = 0; 11039381Smckusick mp->m_mounth = (struct vnode *)0; 11139335Smckusick if (error = vfs_lock(mp)) { 11239335Smckusick free((caddr_t)mp, M_MOUNT); 11339335Smckusick vput(vp); 11439335Smckusick RETURN (error); 11539335Smckusick } 11639335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11739335Smckusick vfs_unlock(mp); 11839335Smckusick free((caddr_t)mp, M_MOUNT); 11939335Smckusick vput(vp); 12039335Smckusick RETURN (EBUSY); 12139335Smckusick } 12239335Smckusick /* 12339335Smckusick * Put the new filesystem on the mount list after root. 12439335Smckusick */ 12539335Smckusick mp->m_next = rootfs->m_next; 12639335Smckusick mp->m_prev = rootfs; 12739335Smckusick rootfs->m_next = mp; 12839335Smckusick mp->m_next->m_prev = mp; 12939335Smckusick vp->v_mountedhere = mp; 13039335Smckusick mp->m_vnodecovered = vp; 13139335Smckusick update: 13239335Smckusick /* 13339335Smckusick * Set the mount level flags. 13439335Smckusick */ 13539335Smckusick if (uap->flags & M_RDONLY) 13639335Smckusick mp->m_flag |= M_RDONLY; 13739335Smckusick else 13839335Smckusick mp->m_flag &= ~M_RDONLY; 13939335Smckusick if (uap->flags & M_NOSUID) 14039335Smckusick mp->m_flag |= M_NOSUID; 14139335Smckusick else 14239335Smckusick mp->m_flag &= ~M_NOSUID; 14339335Smckusick if (uap->flags & M_NOEXEC) 14439335Smckusick mp->m_flag |= M_NOEXEC; 14539335Smckusick else 14639335Smckusick mp->m_flag &= ~M_NOEXEC; 14739335Smckusick if (uap->flags & M_NODEV) 14839335Smckusick mp->m_flag |= M_NODEV; 14939335Smckusick else 15039335Smckusick mp->m_flag &= ~M_NODEV; 15139335Smckusick if (uap->flags & M_SYNCHRONOUS) 15239335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15339335Smckusick else 15439335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15539335Smckusick /* 15639335Smckusick * Mount the filesystem. 15739335Smckusick */ 15839335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15939335Smckusick if (mp->m_flag & M_UPDATE) { 16039335Smckusick mp->m_flag &= ~M_UPDATE; 16139335Smckusick vrele(vp); 16239335Smckusick RETURN (error); 16339335Smckusick } 16437741Smckusick cache_purge(vp); 16537741Smckusick if (!error) { 16639335Smckusick VOP_UNLOCK(vp); 16737741Smckusick vfs_unlock(mp); 16839044Smckusick error = VFS_START(mp, 0); 16937741Smckusick } else { 17037741Smckusick vfs_remove(mp); 17137741Smckusick free((caddr_t)mp, M_MOUNT); 17239335Smckusick vput(vp); 17337741Smckusick } 17437741Smckusick RETURN (error); 1756254Sroot } 1766254Sroot 1779167Ssam /* 17837741Smckusick * Unmount system call. 17937741Smckusick * 18037741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18137741Smckusick * not special file (as before). 1829167Ssam */ 18338408Smckusick unmount(scp) 18438408Smckusick register struct syscontext *scp; 1856254Sroot { 18637741Smckusick struct a { 18737741Smckusick char *pathp; 18837741Smckusick int flags; 18938408Smckusick } *uap = (struct a *)scp->sc_ap; 19037741Smckusick register struct vnode *vp; 19138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19239356Smckusick struct mount *mp; 19337741Smckusick int error; 1946254Sroot 19537741Smckusick /* 19637741Smckusick * Must be super user 19737741Smckusick */ 19838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 19937741Smckusick RETURN (error); 20037741Smckusick 20137741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20337741Smckusick ndp->ni_dirp = uap->pathp; 20437741Smckusick if (error = namei(ndp)) 20537741Smckusick RETURN (error); 20637741Smckusick vp = ndp->ni_vp; 20737741Smckusick /* 20837741Smckusick * Must be the root of the filesystem 20937741Smckusick */ 21037741Smckusick if ((vp->v_flag & VROOT) == 0) { 21137741Smckusick vput(vp); 21237741Smckusick RETURN (EINVAL); 21337741Smckusick } 21437741Smckusick mp = vp->v_mount; 21537741Smckusick vput(vp); 21639356Smckusick RETURN (dounmount(mp, uap->flags)); 21739356Smckusick } 21839356Smckusick 21939356Smckusick /* 22039356Smckusick * Do an unmount. 22139356Smckusick */ 22239356Smckusick dounmount(mp, flags) 22339356Smckusick register struct mount *mp; 22439356Smckusick int flags; 22539356Smckusick { 22639356Smckusick struct vnode *coveredvp; 22739356Smckusick int error; 22839356Smckusick 22937741Smckusick coveredvp = mp->m_vnodecovered; 23037741Smckusick if (error = vfs_lock(mp)) 23139356Smckusick return (error); 23237741Smckusick 23337741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23437741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23537741Smckusick VFS_SYNC(mp, MNT_WAIT); 23637741Smckusick 23739356Smckusick error = VFS_UNMOUNT(mp, flags); 23837741Smckusick if (error) { 23937741Smckusick vfs_unlock(mp); 24037741Smckusick } else { 24137741Smckusick vrele(coveredvp); 24237741Smckusick vfs_remove(mp); 24337741Smckusick free((caddr_t)mp, M_MOUNT); 24437741Smckusick } 24539356Smckusick return (error); 2466254Sroot } 2476254Sroot 2489167Ssam /* 24937741Smckusick * Sync system call. 25037741Smckusick * Sync each mounted filesystem. 2519167Ssam */ 25239491Smckusick /* ARGSUSED */ 25338408Smckusick sync(scp) 25439491Smckusick struct syscontext *scp; 2556254Sroot { 25637741Smckusick register struct mount *mp; 25737741Smckusick 25837741Smckusick mp = rootfs; 25937741Smckusick do { 26037741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 26137741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 26237741Smckusick mp = mp->m_next; 26337741Smckusick } while (mp != rootfs); 26437741Smckusick } 26537741Smckusick 26637741Smckusick /* 26737741Smckusick * get filesystem statistics 26837741Smckusick */ 26938408Smckusick statfs(scp) 27038408Smckusick register struct syscontext *scp; 27137741Smckusick { 2726254Sroot struct a { 27337741Smckusick char *path; 27437741Smckusick struct statfs *buf; 27538408Smckusick } *uap = (struct a *)scp->sc_ap; 27639464Smckusick register struct mount *mp; 27738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 27837741Smckusick struct statfs sb; 27937741Smckusick int error; 28037741Smckusick 28139544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 28237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28337741Smckusick ndp->ni_dirp = uap->path; 28437741Smckusick if (error = namei(ndp)) 28537741Smckusick RETURN (error); 28639544Smckusick mp = ndp->ni_vp->v_mount; 28739544Smckusick vrele(ndp->ni_vp); 28839464Smckusick if (error = VFS_STATFS(mp, &sb)) 28939544Smckusick RETURN (error); 29039464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29139464Smckusick sb.f_fsid = mp->m_fsid; 29239544Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 29337741Smckusick } 29437741Smckusick 29538408Smckusick fstatfs(scp) 29638408Smckusick register struct syscontext *scp; 29737741Smckusick { 29837741Smckusick struct a { 29937741Smckusick int fd; 30037741Smckusick struct statfs *buf; 30138408Smckusick } *uap = (struct a *)scp->sc_ap; 30237741Smckusick struct file *fp; 30339464Smckusick struct mount *mp; 30437741Smckusick struct statfs sb; 30537741Smckusick int error; 30637741Smckusick 30738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 30837741Smckusick RETURN (error); 30939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31039464Smckusick if (error = VFS_STATFS(mp, &sb)) 31137741Smckusick RETURN (error); 31239464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 31339464Smckusick sb.f_fsid = mp->m_fsid; 31437741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 31537741Smckusick } 31637741Smckusick 31737741Smckusick /* 31838270Smckusick * get statistics on all filesystems 31938270Smckusick */ 32038408Smckusick getfsstat(scp) 32138408Smckusick register struct syscontext *scp; 32238270Smckusick { 32338270Smckusick struct a { 32438270Smckusick struct statfs *buf; 32538270Smckusick long bufsize; 32638408Smckusick } *uap = (struct a *)scp->sc_ap; 32738270Smckusick register struct mount *mp; 32839606Smckusick caddr_t sfsp; 32938270Smckusick long count, maxcount, error; 33039606Smckusick struct statfs sb; 33138270Smckusick 33238270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33339606Smckusick sfsp = (caddr_t)uap->buf; 33438270Smckusick mp = rootfs; 33538270Smckusick count = 0; 33638270Smckusick do { 33739606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 33839607Smckusick if (error = VFS_STATFS(mp, &sb)) { 33939607Smckusick mp = mp->m_prev; 34039607Smckusick continue; 34139607Smckusick } 34239606Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 34339606Smckusick sb.f_fsid = mp->m_fsid; 34439606Smckusick if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb))) 34539606Smckusick RETURN (error); 34639606Smckusick sfsp += sizeof(sb); 34738270Smckusick } 34839606Smckusick count++; 34938270Smckusick mp = mp->m_prev; 35038270Smckusick } while (mp != rootfs); 35138270Smckusick if (sfsp && count > maxcount) 35238408Smckusick scp->sc_retval1 = maxcount; 35338270Smckusick else 35438408Smckusick scp->sc_retval1 = count; 35538270Smckusick RETURN (0); 35638270Smckusick } 35738270Smckusick 35838270Smckusick /* 35938259Smckusick * Change current working directory to a given file descriptor. 36038259Smckusick */ 36138408Smckusick fchdir(scp) 36238408Smckusick register struct syscontext *scp; 36338259Smckusick { 36438259Smckusick struct a { 36538259Smckusick int fd; 36638408Smckusick } *uap = (struct a *)scp->sc_ap; 36738259Smckusick register struct vnode *vp; 36838259Smckusick struct file *fp; 36938259Smckusick int error; 37038259Smckusick 37138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 37238259Smckusick RETURN (error); 37338259Smckusick vp = (struct vnode *)fp->f_data; 37438259Smckusick VOP_LOCK(vp); 37538259Smckusick if (vp->v_type != VDIR) 37638259Smckusick error = ENOTDIR; 37738259Smckusick else 37838408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 37938259Smckusick VOP_UNLOCK(vp); 38038408Smckusick vrele(scp->sc_cdir); 38138408Smckusick scp->sc_cdir = vp; 38238259Smckusick RETURN (error); 38338259Smckusick } 38438259Smckusick 38538259Smckusick /* 38637741Smckusick * Change current working directory (``.''). 38737741Smckusick */ 38838408Smckusick chdir(scp) 38938408Smckusick register struct syscontext *scp; 39037741Smckusick { 39137741Smckusick struct a { 3926254Sroot char *fname; 39338408Smckusick } *uap = (struct a *)scp->sc_ap; 39438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 39537741Smckusick int error; 3966254Sroot 39737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 39816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 39916694Smckusick ndp->ni_dirp = uap->fname; 40037741Smckusick if (error = chdirec(ndp)) 40137741Smckusick RETURN (error); 40238408Smckusick vrele(scp->sc_cdir); 40338408Smckusick scp->sc_cdir = ndp->ni_vp; 40437741Smckusick RETURN (0); 40537741Smckusick } 4066254Sroot 40737741Smckusick /* 40837741Smckusick * Change notion of root (``/'') directory. 40937741Smckusick */ 41038408Smckusick chroot(scp) 41138408Smckusick register struct syscontext *scp; 41237741Smckusick { 41337741Smckusick struct a { 41437741Smckusick char *fname; 41538408Smckusick } *uap = (struct a *)scp->sc_ap; 41638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 41737741Smckusick int error; 41837741Smckusick 41938408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 42037741Smckusick RETURN (error); 42137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 42237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 42337741Smckusick ndp->ni_dirp = uap->fname; 42437741Smckusick if (error = chdirec(ndp)) 42537741Smckusick RETURN (error); 42639515Smckusick if (scp->sc_rdir != NULL) 42739515Smckusick vrele(scp->sc_rdir); 42838408Smckusick scp->sc_rdir = ndp->ni_vp; 42937741Smckusick RETURN (0); 4306254Sroot } 4316254Sroot 43237Sbill /* 43337741Smckusick * Common routine for chroot and chdir. 43437741Smckusick */ 43537741Smckusick chdirec(ndp) 43637741Smckusick register struct nameidata *ndp; 43737741Smckusick { 43837741Smckusick struct vnode *vp; 43937741Smckusick int error; 44037741Smckusick 44137741Smckusick if (error = namei(ndp)) 44237741Smckusick return (error); 44337741Smckusick vp = ndp->ni_vp; 44437741Smckusick if (vp->v_type != VDIR) 44537741Smckusick error = ENOTDIR; 44637741Smckusick else 44738399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44837741Smckusick VOP_UNLOCK(vp); 44937741Smckusick if (error) 45037741Smckusick vrele(vp); 45137741Smckusick return (error); 45237741Smckusick } 45337741Smckusick 45437741Smckusick /* 4556254Sroot * Open system call. 4566254Sroot */ 45738408Smckusick open(scp) 45838408Smckusick register struct syscontext *scp; 4596254Sroot { 46012756Ssam struct a { 4616254Sroot char *fname; 4627701Ssam int mode; 46312756Ssam int crtmode; 46438408Smckusick } *uap = (struct a *) scp->sc_ap; 46538408Smckusick struct nameidata *ndp = &scp->sc_nd; 4666254Sroot 46737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 46837741Smckusick ndp->ni_dirp = uap->fname; 46938408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 47038408Smckusick &scp->sc_retval1)); 4716254Sroot } 4726254Sroot 4736254Sroot /* 4746254Sroot * Creat system call. 4756254Sroot */ 47638408Smckusick creat(scp) 47738408Smckusick register struct syscontext *scp; 4786254Sroot { 47912756Ssam struct a { 4806254Sroot char *fname; 4816254Sroot int fmode; 48238408Smckusick } *uap = (struct a *)scp->sc_ap; 48338408Smckusick struct nameidata *ndp = &scp->sc_nd; 4846254Sroot 48537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48637741Smckusick ndp->ni_dirp = uap->fname; 48738408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 48838408Smckusick ndp, &scp->sc_retval1)); 4896254Sroot } 4906254Sroot 4916254Sroot /* 4926254Sroot * Common code for open and creat. 49312756Ssam * Check permissions, allocate an open file structure, 49412756Ssam * and call the device open routine if any. 4956254Sroot */ 49638408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 49738408Smckusick register struct syscontext *scp; 49837741Smckusick int fmode, cmode; 49937741Smckusick struct nameidata *ndp; 50037741Smckusick int *resultfd; 50112756Ssam { 5026254Sroot register struct file *fp; 50337741Smckusick struct file *nfp; 50437741Smckusick int indx, error; 50537741Smckusick extern struct fileops vnops; 5066254Sroot 50737741Smckusick if (error = falloc(&nfp, &indx)) 50837741Smckusick return (error); 50937741Smckusick fp = nfp; 51038408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 51137741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 51237741Smckusick crfree(fp->f_cred); 51337741Smckusick fp->f_count--; 51439499Smckusick if (error == -1) /* XXX from fdopen */ 51539499Smckusick return (0); /* XXX from fdopen */ 51639499Smckusick scp->sc_ofile[indx] = NULL; 51737741Smckusick return (error); 51812756Ssam } 51937741Smckusick fp->f_flag = fmode & FMASK; 52037741Smckusick fp->f_type = DTYPE_VNODE; 52137741Smckusick fp->f_ops = &vnops; 52237741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 52337741Smckusick if (resultfd) 52437741Smckusick *resultfd = indx; 52537741Smckusick return (0); 5266254Sroot } 5276254Sroot 5286254Sroot /* 5296254Sroot * Mknod system call 5306254Sroot */ 53138408Smckusick mknod(scp) 53238408Smckusick register struct syscontext *scp; 5336254Sroot { 5346254Sroot register struct a { 5356254Sroot char *fname; 5366254Sroot int fmode; 5376254Sroot int dev; 53838408Smckusick } *uap = (struct a *)scp->sc_ap; 53938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54037741Smckusick register struct vnode *vp; 54137741Smckusick struct vattr vattr; 54237741Smckusick int error; 5436254Sroot 54438408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 54537741Smckusick RETURN (error); 54637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 54716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 54816694Smckusick ndp->ni_dirp = uap->fname; 54937741Smckusick if (error = namei(ndp)) 55037741Smckusick RETURN (error); 55137741Smckusick vp = ndp->ni_vp; 55237741Smckusick if (vp != NULL) { 55337741Smckusick error = EEXIST; 55412756Ssam goto out; 5556254Sroot } 55637741Smckusick vattr_null(&vattr); 55737741Smckusick switch (uap->fmode & IFMT) { 55812756Ssam 55915093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 56037741Smckusick vattr.va_type = VBAD; 56137741Smckusick break; 56212756Ssam case IFCHR: 56337741Smckusick vattr.va_type = VCHR; 56437741Smckusick break; 56512756Ssam case IFBLK: 56637741Smckusick vattr.va_type = VBLK; 56737741Smckusick break; 56837741Smckusick default: 56937741Smckusick error = EINVAL; 57037741Smckusick goto out; 5716254Sroot } 57238408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 57337741Smckusick vattr.va_rdev = uap->dev; 5746254Sroot out: 57537741Smckusick if (error) 57637741Smckusick VOP_ABORTOP(ndp); 57737741Smckusick else 57837741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 57937741Smckusick RETURN (error); 5806254Sroot } 5816254Sroot 5826254Sroot /* 5836254Sroot * link system call 5846254Sroot */ 58538408Smckusick link(scp) 58638408Smckusick register struct syscontext *scp; 5876254Sroot { 5886254Sroot register struct a { 5896254Sroot char *target; 5906254Sroot char *linkname; 59138408Smckusick } *uap = (struct a *)scp->sc_ap; 59238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59337741Smckusick register struct vnode *vp, *xp; 59437741Smckusick int error; 5956254Sroot 59616694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 59716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59816694Smckusick ndp->ni_dirp = uap->target; 59937741Smckusick if (error = namei(ndp)) 60037741Smckusick RETURN (error); 60137741Smckusick vp = ndp->ni_vp; 60237741Smckusick if (vp->v_type == VDIR && 60338408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 60437741Smckusick goto out1; 60537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60616694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 60737741Smckusick if (error = namei(ndp)) 60837741Smckusick goto out1; 60937741Smckusick xp = ndp->ni_vp; 6106254Sroot if (xp != NULL) { 61137741Smckusick error = EEXIST; 6126254Sroot goto out; 6136254Sroot } 61437741Smckusick xp = ndp->ni_dvp; 61537741Smckusick if (vp->v_mount != xp->v_mount) 61637741Smckusick error = EXDEV; 6176254Sroot out: 61837741Smckusick if (error) 61937741Smckusick VOP_ABORTOP(ndp); 62037741Smckusick else 62137741Smckusick error = VOP_LINK(vp, ndp); 62237741Smckusick out1: 62337741Smckusick vrele(vp); 62437741Smckusick RETURN (error); 6256254Sroot } 6266254Sroot 6276254Sroot /* 6286254Sroot * symlink -- make a symbolic link 6296254Sroot */ 63038408Smckusick symlink(scp) 63138408Smckusick register struct syscontext *scp; 6326254Sroot { 63337741Smckusick struct a { 6346254Sroot char *target; 6356254Sroot char *linkname; 63638408Smckusick } *uap = (struct a *)scp->sc_ap; 63738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 63837741Smckusick register struct vnode *vp; 63937741Smckusick struct vattr vattr; 64037741Smckusick char *target; 64137741Smckusick int error; 6426254Sroot 64316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64416694Smckusick ndp->ni_dirp = uap->linkname; 64537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 64637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 64737741Smckusick goto out1; 64837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64937741Smckusick if (error = namei(ndp)) 65037741Smckusick goto out1; 65137741Smckusick vp = ndp->ni_vp; 65237741Smckusick if (vp) { 65337741Smckusick error = EEXIST; 65437741Smckusick goto out; 6556254Sroot } 65637741Smckusick vp = ndp->ni_dvp; 65737741Smckusick vattr_null(&vattr); 65838408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 65937741Smckusick out: 66037741Smckusick if (error) 66137741Smckusick VOP_ABORTOP(ndp); 66237741Smckusick else 66337741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 66437741Smckusick out1: 66537741Smckusick FREE(target, M_NAMEI); 66637741Smckusick RETURN (error); 6676254Sroot } 6686254Sroot 6696254Sroot /* 6706254Sroot * Unlink system call. 6716254Sroot * Hard to avoid races here, especially 6726254Sroot * in unlinking directories. 6736254Sroot */ 67438408Smckusick unlink(scp) 67538408Smckusick register struct syscontext *scp; 6766254Sroot { 6776254Sroot struct a { 6786254Sroot char *fname; 67938408Smckusick } *uap = (struct a *)scp->sc_ap; 68038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68137741Smckusick register struct vnode *vp; 68237741Smckusick int error; 6836254Sroot 68437741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 68516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68616694Smckusick ndp->ni_dirp = uap->fname; 68737741Smckusick if (error = namei(ndp)) 68837741Smckusick RETURN (error); 68937741Smckusick vp = ndp->ni_vp; 69037741Smckusick if (vp->v_type == VDIR && 69138408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6926254Sroot goto out; 6936254Sroot /* 6946254Sroot * Don't unlink a mounted file. 6956254Sroot */ 69637741Smckusick if (vp->v_flag & VROOT) { 69737741Smckusick error = EBUSY; 6986254Sroot goto out; 6996254Sroot } 70037741Smckusick if (vp->v_flag & VTEXT) 70137741Smckusick xrele(vp); /* try once to free text */ 7026254Sroot out: 70337741Smckusick if (error) 70437741Smckusick VOP_ABORTOP(ndp); 7057142Smckusick else 70637741Smckusick error = VOP_REMOVE(ndp); 70737741Smckusick RETURN (error); 7086254Sroot } 7096254Sroot 7106254Sroot /* 7116254Sroot * Seek system call 7126254Sroot */ 71338408Smckusick lseek(scp) 71438408Smckusick register struct syscontext *scp; 7156254Sroot { 7166254Sroot register struct file *fp; 7176254Sroot register struct a { 71837741Smckusick int fdes; 7196254Sroot off_t off; 7206254Sroot int sbase; 72138408Smckusick } *uap = (struct a *)scp->sc_ap; 72237741Smckusick struct vattr vattr; 72337741Smckusick int error; 7246254Sroot 72537741Smckusick if ((unsigned)uap->fdes >= NOFILE || 72638408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 72737741Smckusick RETURN (EBADF); 72837741Smckusick if (fp->f_type != DTYPE_VNODE) 72937741Smckusick RETURN (ESPIPE); 73013878Ssam switch (uap->sbase) { 73113878Ssam 73213878Ssam case L_INCR: 73313878Ssam fp->f_offset += uap->off; 73413878Ssam break; 73513878Ssam 73613878Ssam case L_XTND: 73737741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 73838408Smckusick &vattr, scp->sc_cred)) 73937741Smckusick RETURN (error); 74037741Smckusick fp->f_offset = uap->off + vattr.va_size; 74113878Ssam break; 74213878Ssam 74313878Ssam case L_SET: 74413878Ssam fp->f_offset = uap->off; 74513878Ssam break; 74613878Ssam 74713878Ssam default: 74837741Smckusick RETURN (EINVAL); 74913878Ssam } 75038408Smckusick scp->sc_offset = fp->f_offset; 75137741Smckusick RETURN (0); 7526254Sroot } 7536254Sroot 7546254Sroot /* 7556254Sroot * Access system call 7566254Sroot */ 75738408Smckusick saccess(scp) 75838408Smckusick register struct syscontext *scp; 7596254Sroot { 7606254Sroot register struct a { 7616254Sroot char *fname; 7626254Sroot int fmode; 76338408Smckusick } *uap = (struct a *)scp->sc_ap; 76438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76537741Smckusick register struct vnode *vp; 76637741Smckusick int error, mode, svuid, svgid; 7676254Sroot 76838408Smckusick svuid = scp->sc_uid; 76938408Smckusick svgid = scp->sc_gid; 77038408Smckusick scp->sc_uid = scp->sc_ruid; 77138408Smckusick scp->sc_gid = scp->sc_rgid; 77237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 77316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77416694Smckusick ndp->ni_dirp = uap->fname; 77537741Smckusick if (error = namei(ndp)) 77637741Smckusick goto out1; 77737741Smckusick vp = ndp->ni_vp; 77837741Smckusick /* 77937741Smckusick * fmode == 0 means only check for exist 78037741Smckusick */ 78137741Smckusick if (uap->fmode) { 78237741Smckusick mode = 0; 78337741Smckusick if (uap->fmode & R_OK) 78437741Smckusick mode |= VREAD; 78537741Smckusick if (uap->fmode & W_OK) 78637741Smckusick mode |= VWRITE; 78737741Smckusick if (uap->fmode & X_OK) 78837741Smckusick mode |= VEXEC; 78939543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 79038399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7916254Sroot } 79237741Smckusick vput(vp); 79337741Smckusick out1: 79438408Smckusick scp->sc_uid = svuid; 79538408Smckusick scp->sc_gid = svgid; 79637741Smckusick RETURN (error); 7976254Sroot } 7986254Sroot 7996254Sroot /* 8006574Smckusic * Stat system call. This version follows links. 80137Sbill */ 80238408Smckusick stat(scp) 80338408Smckusick struct syscontext *scp; 80437Sbill { 80537Sbill 80638408Smckusick stat1(scp, FOLLOW); 80737Sbill } 80837Sbill 80937Sbill /* 8106574Smckusic * Lstat system call. This version does not follow links. 8115992Swnj */ 81238408Smckusick lstat(scp) 81338408Smckusick struct syscontext *scp; 8145992Swnj { 81512756Ssam 81638408Smckusick stat1(scp, NOFOLLOW); 81712756Ssam } 81812756Ssam 81938408Smckusick stat1(scp, follow) 82038408Smckusick register struct syscontext *scp; 82112756Ssam int follow; 82212756Ssam { 8235992Swnj register struct a { 8245992Swnj char *fname; 82512756Ssam struct stat *ub; 82638408Smckusick } *uap = (struct a *)scp->sc_ap; 82738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 82812756Ssam struct stat sb; 82937741Smckusick int error; 8305992Swnj 83137741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 83216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83316694Smckusick ndp->ni_dirp = uap->fname; 83437741Smckusick if (error = namei(ndp)) 83537741Smckusick RETURN (error); 83637741Smckusick error = vn_stat(ndp->ni_vp, &sb); 83737741Smckusick vput(ndp->ni_vp); 83837741Smckusick if (error) 83937741Smckusick RETURN (error); 84037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 84137741Smckusick RETURN (error); 8425992Swnj } 8435992Swnj 8445992Swnj /* 8455992Swnj * Return target name of a symbolic link 84637Sbill */ 84738408Smckusick readlink(scp) 84838408Smckusick register struct syscontext *scp; 8495992Swnj { 8505992Swnj register struct a { 8515992Swnj char *name; 8525992Swnj char *buf; 8535992Swnj int count; 85438408Smckusick } *uap = (struct a *)scp->sc_ap; 85538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85637741Smckusick register struct vnode *vp; 85737741Smckusick struct iovec aiov; 85837741Smckusick struct uio auio; 85937741Smckusick int error; 8605992Swnj 86137741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 86216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86316694Smckusick ndp->ni_dirp = uap->name; 86437741Smckusick if (error = namei(ndp)) 86537741Smckusick RETURN (error); 86637741Smckusick vp = ndp->ni_vp; 86737741Smckusick if (vp->v_type != VLNK) { 86837741Smckusick error = EINVAL; 8695992Swnj goto out; 8705992Swnj } 87137741Smckusick aiov.iov_base = uap->buf; 87237741Smckusick aiov.iov_len = uap->count; 87337741Smckusick auio.uio_iov = &aiov; 87437741Smckusick auio.uio_iovcnt = 1; 87537741Smckusick auio.uio_offset = 0; 87637741Smckusick auio.uio_rw = UIO_READ; 87737741Smckusick auio.uio_segflg = UIO_USERSPACE; 87837741Smckusick auio.uio_resid = uap->count; 87937741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8805992Swnj out: 88137741Smckusick vput(vp); 88238408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 88337741Smckusick RETURN (error); 8845992Swnj } 8855992Swnj 8869167Ssam /* 88738259Smckusick * Change flags of a file given path name. 88838259Smckusick */ 88938408Smckusick chflags(scp) 89038408Smckusick register struct syscontext *scp; 89138259Smckusick { 89238259Smckusick struct a { 89338259Smckusick char *fname; 89438259Smckusick int flags; 89538408Smckusick } *uap = (struct a *)scp->sc_ap; 89638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 89738259Smckusick register struct vnode *vp; 89838259Smckusick struct vattr vattr; 89938259Smckusick int error; 90038259Smckusick 90138259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 90238259Smckusick ndp->ni_segflg = UIO_USERSPACE; 90338259Smckusick ndp->ni_dirp = uap->fname; 90438259Smckusick vattr_null(&vattr); 90538259Smckusick vattr.va_flags = uap->flags; 90638259Smckusick if (error = namei(ndp)) 90738259Smckusick RETURN (error); 90838259Smckusick vp = ndp->ni_vp; 90938259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91038259Smckusick error = EROFS; 91138259Smckusick goto out; 91238259Smckusick } 91338259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 91438259Smckusick out: 91538259Smckusick vput(vp); 91638259Smckusick RETURN (error); 91738259Smckusick } 91838259Smckusick 91938259Smckusick /* 92038259Smckusick * Change flags of a file given a file descriptor. 92138259Smckusick */ 92238408Smckusick fchflags(scp) 92338408Smckusick register struct syscontext *scp; 92438259Smckusick { 92538259Smckusick struct a { 92638259Smckusick int fd; 92738259Smckusick int flags; 92838408Smckusick } *uap = (struct a *)scp->sc_ap; 92938259Smckusick struct vattr vattr; 93038259Smckusick struct vnode *vp; 93138259Smckusick struct file *fp; 93238259Smckusick int error; 93338259Smckusick 93438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 93538259Smckusick RETURN (error); 93638259Smckusick vattr_null(&vattr); 93738259Smckusick vattr.va_flags = uap->flags; 93838259Smckusick vp = (struct vnode *)fp->f_data; 93938259Smckusick VOP_LOCK(vp); 94038259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94138259Smckusick error = EROFS; 94238259Smckusick goto out; 94338259Smckusick } 94438259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 94538259Smckusick out: 94638259Smckusick VOP_UNLOCK(vp); 94738259Smckusick RETURN (error); 94838259Smckusick } 94938259Smckusick 95038259Smckusick /* 9519167Ssam * Change mode of a file given path name. 9529167Ssam */ 95338408Smckusick chmod(scp) 95438408Smckusick register struct syscontext *scp; 9555992Swnj { 9567701Ssam struct a { 9576254Sroot char *fname; 9586254Sroot int fmode; 95938408Smckusick } *uap = (struct a *)scp->sc_ap; 96038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 96137741Smckusick register struct vnode *vp; 96237741Smckusick struct vattr vattr; 96337741Smckusick int error; 9645992Swnj 96537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 96637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 96737741Smckusick ndp->ni_dirp = uap->fname; 96837741Smckusick vattr_null(&vattr); 96937741Smckusick vattr.va_mode = uap->fmode & 07777; 97037741Smckusick if (error = namei(ndp)) 97137741Smckusick RETURN (error); 97237741Smckusick vp = ndp->ni_vp; 97337741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97437741Smckusick error = EROFS; 97537741Smckusick goto out; 97637741Smckusick } 97737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 97837741Smckusick out: 97937741Smckusick vput(vp); 98037741Smckusick RETURN (error); 9817701Ssam } 9827439Sroot 9839167Ssam /* 9849167Ssam * Change mode of a file given a file descriptor. 9859167Ssam */ 98638408Smckusick fchmod(scp) 98738408Smckusick register struct syscontext *scp; 9887701Ssam { 9897701Ssam struct a { 9907701Ssam int fd; 9917701Ssam int fmode; 99238408Smckusick } *uap = (struct a *)scp->sc_ap; 99337741Smckusick struct vattr vattr; 99437741Smckusick struct vnode *vp; 99537741Smckusick struct file *fp; 99637741Smckusick int error; 9977701Ssam 99838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 99937741Smckusick RETURN (error); 100037741Smckusick vattr_null(&vattr); 100137741Smckusick vattr.va_mode = uap->fmode & 07777; 100237741Smckusick vp = (struct vnode *)fp->f_data; 100337741Smckusick VOP_LOCK(vp); 100437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 100537741Smckusick error = EROFS; 100637741Smckusick goto out; 10077439Sroot } 100837741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 100937741Smckusick out: 101037741Smckusick VOP_UNLOCK(vp); 101137741Smckusick RETURN (error); 10125992Swnj } 10135992Swnj 10149167Ssam /* 10159167Ssam * Set ownership given a path name. 10169167Ssam */ 101738408Smckusick chown(scp) 101838408Smckusick register struct syscontext *scp; 101937Sbill { 10207701Ssam struct a { 10216254Sroot char *fname; 10226254Sroot int uid; 10236254Sroot int gid; 102438408Smckusick } *uap = (struct a *)scp->sc_ap; 102538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 102637741Smckusick register struct vnode *vp; 102737741Smckusick struct vattr vattr; 102837741Smckusick int error; 102937Sbill 103037741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 103136614Sbostic ndp->ni_segflg = UIO_USERSPACE; 103236614Sbostic ndp->ni_dirp = uap->fname; 103337741Smckusick vattr_null(&vattr); 103437741Smckusick vattr.va_uid = uap->uid; 103537741Smckusick vattr.va_gid = uap->gid; 103637741Smckusick if (error = namei(ndp)) 103737741Smckusick RETURN (error); 103837741Smckusick vp = ndp->ni_vp; 103937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 104037741Smckusick error = EROFS; 104137741Smckusick goto out; 104237741Smckusick } 104337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 104437741Smckusick out: 104537741Smckusick vput(vp); 104637741Smckusick RETURN (error); 10477701Ssam } 10487439Sroot 10499167Ssam /* 10509167Ssam * Set ownership given a file descriptor. 10519167Ssam */ 105238408Smckusick fchown(scp) 105338408Smckusick register struct syscontext *scp; 10547701Ssam { 10557701Ssam struct a { 10567701Ssam int fd; 10577701Ssam int uid; 10587701Ssam int gid; 105938408Smckusick } *uap = (struct a *)scp->sc_ap; 106037741Smckusick struct vattr vattr; 106137741Smckusick struct vnode *vp; 106237741Smckusick struct file *fp; 106337741Smckusick int error; 10647701Ssam 106538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 106637741Smckusick RETURN (error); 106737741Smckusick vattr_null(&vattr); 106837741Smckusick vattr.va_uid = uap->uid; 106937741Smckusick vattr.va_gid = uap->gid; 107037741Smckusick vp = (struct vnode *)fp->f_data; 107137741Smckusick VOP_LOCK(vp); 107237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 107337741Smckusick error = EROFS; 107437741Smckusick goto out; 107537741Smckusick } 107637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 107737741Smckusick out: 107837741Smckusick VOP_UNLOCK(vp); 107937741Smckusick RETURN (error); 10807701Ssam } 10817701Ssam 108238408Smckusick utimes(scp) 108338408Smckusick register struct syscontext *scp; 108411811Ssam { 108511811Ssam register struct a { 108611811Ssam char *fname; 108711811Ssam struct timeval *tptr; 108838408Smckusick } *uap = (struct a *)scp->sc_ap; 108938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 109037741Smckusick register struct vnode *vp; 109111811Ssam struct timeval tv[2]; 109237741Smckusick struct vattr vattr; 109337741Smckusick int error; 109411811Ssam 109537741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 109637741Smckusick RETURN (error); 109737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 109837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 109937741Smckusick ndp->ni_dirp = uap->fname; 110037741Smckusick vattr_null(&vattr); 110137741Smckusick vattr.va_atime = tv[0]; 110237741Smckusick vattr.va_mtime = tv[1]; 110337741Smckusick if (error = namei(ndp)) 110437741Smckusick RETURN (error); 110537741Smckusick vp = ndp->ni_vp; 110637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 110737741Smckusick error = EROFS; 110837741Smckusick goto out; 110921015Smckusick } 111037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 111137741Smckusick out: 111237741Smckusick vput(vp); 111337741Smckusick RETURN (error); 111411811Ssam } 111511811Ssam 11169167Ssam /* 11179167Ssam * Truncate a file given its path name. 11189167Ssam */ 111938408Smckusick truncate(scp) 112038408Smckusick register struct syscontext *scp; 11217701Ssam { 11227701Ssam struct a { 11237701Ssam char *fname; 112426473Skarels off_t length; 112538408Smckusick } *uap = (struct a *)scp->sc_ap; 112638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112737741Smckusick register struct vnode *vp; 112837741Smckusick struct vattr vattr; 112937741Smckusick int error; 11307701Ssam 113137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113316694Smckusick ndp->ni_dirp = uap->fname; 113437741Smckusick vattr_null(&vattr); 113537741Smckusick vattr.va_size = uap->length; 113637741Smckusick if (error = namei(ndp)) 113737741Smckusick RETURN (error); 113837741Smckusick vp = ndp->ni_vp; 113937741Smckusick if (vp->v_type == VDIR) { 114037741Smckusick error = EISDIR; 114137741Smckusick goto out; 11427701Ssam } 114338399Smckusick if ((error = vn_writechk(vp)) || 114438399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 114537741Smckusick goto out; 114637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114737741Smckusick out: 114837741Smckusick vput(vp); 114937741Smckusick RETURN (error); 11507701Ssam } 11517701Ssam 11529167Ssam /* 11539167Ssam * Truncate a file given a file descriptor. 11549167Ssam */ 115538408Smckusick ftruncate(scp) 115638408Smckusick register struct syscontext *scp; 11577701Ssam { 11587701Ssam struct a { 11597701Ssam int fd; 116026473Skarels off_t length; 116138408Smckusick } *uap = (struct a *)scp->sc_ap; 116237741Smckusick struct vattr vattr; 116337741Smckusick struct vnode *vp; 11647701Ssam struct file *fp; 116537741Smckusick int error; 11667701Ssam 116738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 116837741Smckusick RETURN (error); 116937741Smckusick if ((fp->f_flag & FWRITE) == 0) 117037741Smckusick RETURN (EINVAL); 117137741Smckusick vattr_null(&vattr); 117237741Smckusick vattr.va_size = uap->length; 117337741Smckusick vp = (struct vnode *)fp->f_data; 117437741Smckusick VOP_LOCK(vp); 117537741Smckusick if (vp->v_type == VDIR) { 117637741Smckusick error = EISDIR; 117737741Smckusick goto out; 11787701Ssam } 117938399Smckusick if (error = vn_writechk(vp)) 118037741Smckusick goto out; 118137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118237741Smckusick out: 118337741Smckusick VOP_UNLOCK(vp); 118437741Smckusick RETURN (error); 11857701Ssam } 11867701Ssam 11879167Ssam /* 11889167Ssam * Synch an open file. 11899167Ssam */ 119038408Smckusick fsync(scp) 119138408Smckusick register struct syscontext *scp; 11929167Ssam { 11939167Ssam struct a { 11949167Ssam int fd; 119538408Smckusick } *uap = (struct a *)scp->sc_ap; 119639592Smckusick register struct vnode *vp; 11979167Ssam struct file *fp; 119837741Smckusick int error; 11999167Ssam 120038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 120137741Smckusick RETURN (error); 120239592Smckusick vp = (struct vnode *)fp->f_data; 120339592Smckusick VOP_LOCK(vp); 120439592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 120539592Smckusick VOP_UNLOCK(vp); 120637741Smckusick RETURN (error); 12079167Ssam } 12089167Ssam 12099167Ssam /* 12109167Ssam * Rename system call. 12119167Ssam * 12129167Ssam * Source and destination must either both be directories, or both 12139167Ssam * not be directories. If target is a directory, it must be empty. 12149167Ssam */ 121538408Smckusick rename(scp) 121638408Smckusick register struct syscontext *scp; 12177701Ssam { 12187701Ssam struct a { 12197701Ssam char *from; 12207701Ssam char *to; 122138408Smckusick } *uap = (struct a *)scp->sc_ap; 122237741Smckusick register struct vnode *tvp, *fvp, *tdvp; 122338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 122437741Smckusick struct nameidata tond; 122537741Smckusick int error; 12267701Ssam 122737741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 122816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122916694Smckusick ndp->ni_dirp = uap->from; 123037741Smckusick if (error = namei(ndp)) 123137741Smckusick RETURN (error); 123237741Smckusick fvp = ndp->ni_vp; 123338266Smckusick nddup(ndp, &tond); 123437741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 123537741Smckusick tond.ni_segflg = UIO_USERSPACE; 123637741Smckusick tond.ni_dirp = uap->to; 123737741Smckusick error = namei(&tond); 123837741Smckusick tdvp = tond.ni_dvp; 123937741Smckusick tvp = tond.ni_vp; 124037741Smckusick if (tvp != NULL) { 124137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 124239242Sbostic error = ENOTDIR; 124337741Smckusick goto out; 124437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 124539242Sbostic error = EISDIR; 124637741Smckusick goto out; 12479167Ssam } 12489167Ssam } 124937741Smckusick if (error) { 125037741Smckusick VOP_ABORTOP(ndp); 125137741Smckusick goto out1; 125237741Smckusick } 125337741Smckusick if (fvp->v_mount != tdvp->v_mount) { 125437741Smckusick error = EXDEV; 12559167Ssam goto out; 125610051Ssam } 125739286Smckusick if (fvp == tdvp) 125837741Smckusick error = EINVAL; 125939286Smckusick /* 126039286Smckusick * If source is the same as the destination, 126139286Smckusick * then there is nothing to do. 126239286Smckusick */ 126339286Smckusick if (fvp == tvp) 126439286Smckusick error = -1; 126537741Smckusick out: 126637741Smckusick if (error) { 126737741Smckusick VOP_ABORTOP(&tond); 126837741Smckusick VOP_ABORTOP(ndp); 12699167Ssam } else { 127037741Smckusick error = VOP_RENAME(ndp, &tond); 12719167Ssam } 127237741Smckusick out1: 127338266Smckusick ndrele(&tond); 127439286Smckusick if (error == -1) 127539286Smckusick RETURN (0); 127637741Smckusick RETURN (error); 12777701Ssam } 12787701Ssam 12797535Sroot /* 128012756Ssam * Mkdir system call 128112756Ssam */ 128238408Smckusick mkdir(scp) 128338408Smckusick register struct syscontext *scp; 128412756Ssam { 128512756Ssam struct a { 128612756Ssam char *name; 128712756Ssam int dmode; 128838408Smckusick } *uap = (struct a *)scp->sc_ap; 128938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 129037741Smckusick register struct vnode *vp; 129137741Smckusick struct vattr vattr; 129237741Smckusick int error; 129312756Ssam 129437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 129516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 129616694Smckusick ndp->ni_dirp = uap->name; 129737741Smckusick if (error = namei(ndp)) 129837741Smckusick RETURN (error); 129937741Smckusick vp = ndp->ni_vp; 130037741Smckusick if (vp != NULL) { 130137741Smckusick VOP_ABORTOP(ndp); 130237741Smckusick RETURN (EEXIST); 130312756Ssam } 130437741Smckusick vattr_null(&vattr); 130537741Smckusick vattr.va_type = VDIR; 130638408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 130737741Smckusick error = VOP_MKDIR(ndp, &vattr); 130838145Smckusick if (!error) 130938145Smckusick vput(ndp->ni_vp); 131037741Smckusick RETURN (error); 131112756Ssam } 131212756Ssam 131312756Ssam /* 131412756Ssam * Rmdir system call. 131512756Ssam */ 131638408Smckusick rmdir(scp) 131738408Smckusick register struct syscontext *scp; 131812756Ssam { 131912756Ssam struct a { 132012756Ssam char *name; 132138408Smckusick } *uap = (struct a *)scp->sc_ap; 132238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 132337741Smckusick register struct vnode *vp; 132437741Smckusick int error; 132512756Ssam 132637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 132716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132816694Smckusick ndp->ni_dirp = uap->name; 132937741Smckusick if (error = namei(ndp)) 133037741Smckusick RETURN (error); 133137741Smckusick vp = ndp->ni_vp; 133237741Smckusick if (vp->v_type != VDIR) { 133337741Smckusick error = ENOTDIR; 133412756Ssam goto out; 133512756Ssam } 133612756Ssam /* 133737741Smckusick * No rmdir "." please. 133812756Ssam */ 133937741Smckusick if (ndp->ni_dvp == vp) { 134037741Smckusick error = EINVAL; 134112756Ssam goto out; 134212756Ssam } 134312756Ssam /* 134437741Smckusick * Don't unlink a mounted file. 134512756Ssam */ 134637741Smckusick if (vp->v_flag & VROOT) 134737741Smckusick error = EBUSY; 134812756Ssam out: 134937741Smckusick if (error) 135037741Smckusick VOP_ABORTOP(ndp); 135137741Smckusick else 135237741Smckusick error = VOP_RMDIR(ndp); 135337741Smckusick RETURN (error); 135412756Ssam } 135512756Ssam 135637741Smckusick /* 135737741Smckusick * Read a block of directory entries in a file system independent format 135837741Smckusick */ 135938408Smckusick getdirentries(scp) 136038408Smckusick register struct syscontext *scp; 136112756Ssam { 136237741Smckusick register struct a { 136337741Smckusick int fd; 136437741Smckusick char *buf; 136537741Smckusick unsigned count; 136637741Smckusick long *basep; 136738408Smckusick } *uap = (struct a *)scp->sc_ap; 136839592Smckusick register struct vnode *vp; 136916540Ssam struct file *fp; 137037741Smckusick struct uio auio; 137137741Smckusick struct iovec aiov; 137238129Smckusick off_t off; 137337741Smckusick int error; 137412756Ssam 137538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 137637741Smckusick RETURN (error); 137737741Smckusick if ((fp->f_flag & FREAD) == 0) 137837741Smckusick RETURN (EBADF); 137939592Smckusick vp = (struct vnode *)fp->f_data; 138039592Smckusick if (vp->v_type != VDIR) 138139592Smckusick RETURN (EINVAL); 138237741Smckusick aiov.iov_base = uap->buf; 138337741Smckusick aiov.iov_len = uap->count; 138437741Smckusick auio.uio_iov = &aiov; 138537741Smckusick auio.uio_iovcnt = 1; 138637741Smckusick auio.uio_rw = UIO_READ; 138737741Smckusick auio.uio_segflg = UIO_USERSPACE; 138837741Smckusick auio.uio_resid = uap->count; 138939592Smckusick VOP_LOCK(vp); 139039592Smckusick auio.uio_offset = off = fp->f_offset; 139139592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 139239592Smckusick fp->f_offset = auio.uio_offset; 139339592Smckusick VOP_UNLOCK(vp); 139439592Smckusick if (error) 139537741Smckusick RETURN (error); 139639592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 139738408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 139837741Smckusick RETURN (error); 139912756Ssam } 140012756Ssam 140112756Ssam /* 140212756Ssam * mode mask for creation of files 140312756Ssam */ 140438408Smckusick umask(scp) 140538408Smckusick register struct syscontext *scp; 140612756Ssam { 140712756Ssam register struct a { 140812756Ssam int mask; 140938408Smckusick } *uap = (struct a *)scp->sc_ap; 141012756Ssam 141138408Smckusick scp->sc_retval1 = scp->sc_cmask; 141238408Smckusick scp->sc_cmask = uap->mask & 07777; 141337741Smckusick RETURN (0); 141412756Ssam } 141537741Smckusick 141639566Smarc /* 141739566Smarc * Void all references to file by ripping underlying filesystem 141839566Smarc * away from vnode. 141939566Smarc */ 142039566Smarc revoke(scp) 142139566Smarc register struct syscontext *scp; 142239566Smarc { 142339566Smarc struct a { 142439566Smarc char *fname; 142539566Smarc } *uap = (struct a *)scp->sc_ap; 142639566Smarc register struct nameidata *ndp = &scp->sc_nd; 142739566Smarc register struct vnode *vp; 142839566Smarc struct vattr vattr; 142939566Smarc int error; 143039566Smarc 143139566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 143239566Smarc ndp->ni_segflg = UIO_USERSPACE; 143339566Smarc ndp->ni_dirp = uap->fname; 143439566Smarc if (error = namei(ndp)) 143539566Smarc RETURN (error); 143639566Smarc vp = ndp->ni_vp; 143739566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 143839566Smarc error = EINVAL; 143939566Smarc goto out; 144039566Smarc } 144139566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 144239566Smarc goto out; 144339566Smarc if (scp->sc_uid != vattr.va_uid || 144439566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 144539566Smarc goto out; 144639632Smckusick if (vp->v_count > 1 || (vp->v_flag & VALIASED)) 144739632Smckusick vgoneall(vp); 144839566Smarc out: 144939566Smarc vrele(vp); 145039566Smarc RETURN (error); 145139566Smarc } 145239566Smarc 145338408Smckusick getvnode(ofile, fdes, fpp) 145438408Smckusick struct file *ofile[]; 145537741Smckusick struct file **fpp; 145637741Smckusick int fdes; 145737741Smckusick { 145837741Smckusick struct file *fp; 145937741Smckusick 146038408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 146137741Smckusick return (EBADF); 146237741Smckusick if (fp->f_type != DTYPE_VNODE) 146337741Smckusick return (EINVAL); 146437741Smckusick *fpp = fp; 146537741Smckusick return (0); 146637741Smckusick } 1467