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*39632Smckusick * @(#)vfs_syscalls.c 7.31 (Berkeley) 11/25/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 } 8737741Smckusick if (vp->v_count != 1) { 8837741Smckusick vput(vp); 8937741Smckusick RETURN (EBUSY); 9037741Smckusick } 9137741Smckusick if (vp->v_type != VDIR) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (ENOTDIR); 9437741Smckusick } 9537741Smckusick if (uap->type > MOUNT_MAXTYPE || 9637741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9737741Smckusick vput(vp); 9837741Smckusick RETURN (ENODEV); 9937741Smckusick } 10037741Smckusick 10137741Smckusick /* 10239335Smckusick * Allocate and initialize the file system. 10337741Smckusick */ 10437741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10537741Smckusick M_MOUNT, M_WAITOK); 10637741Smckusick mp->m_op = vfssw[uap->type]; 10737741Smckusick mp->m_flag = 0; 10837741Smckusick mp->m_exroot = 0; 10939381Smckusick mp->m_mounth = (struct vnode *)0; 11039335Smckusick if (error = vfs_lock(mp)) { 11139335Smckusick free((caddr_t)mp, M_MOUNT); 11239335Smckusick vput(vp); 11339335Smckusick RETURN (error); 11439335Smckusick } 11539335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11639335Smckusick vfs_unlock(mp); 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11939335Smckusick RETURN (EBUSY); 12039335Smckusick } 12139335Smckusick /* 12239335Smckusick * Put the new filesystem on the mount list after root. 12339335Smckusick */ 12439335Smckusick mp->m_next = rootfs->m_next; 12539335Smckusick mp->m_prev = rootfs; 12639335Smckusick rootfs->m_next = mp; 12739335Smckusick mp->m_next->m_prev = mp; 12839335Smckusick vp->v_mountedhere = mp; 12939335Smckusick mp->m_vnodecovered = vp; 13039335Smckusick update: 13139335Smckusick /* 13239335Smckusick * Set the mount level flags. 13339335Smckusick */ 13439335Smckusick if (uap->flags & M_RDONLY) 13539335Smckusick mp->m_flag |= M_RDONLY; 13639335Smckusick else 13739335Smckusick mp->m_flag &= ~M_RDONLY; 13839335Smckusick if (uap->flags & M_NOSUID) 13939335Smckusick mp->m_flag |= M_NOSUID; 14039335Smckusick else 14139335Smckusick mp->m_flag &= ~M_NOSUID; 14239335Smckusick if (uap->flags & M_NOEXEC) 14339335Smckusick mp->m_flag |= M_NOEXEC; 14439335Smckusick else 14539335Smckusick mp->m_flag &= ~M_NOEXEC; 14639335Smckusick if (uap->flags & M_NODEV) 14739335Smckusick mp->m_flag |= M_NODEV; 14839335Smckusick else 14939335Smckusick mp->m_flag &= ~M_NODEV; 15039335Smckusick if (uap->flags & M_SYNCHRONOUS) 15139335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15239335Smckusick else 15339335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15439335Smckusick /* 15539335Smckusick * Mount the filesystem. 15639335Smckusick */ 15739335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15839335Smckusick if (mp->m_flag & M_UPDATE) { 15939335Smckusick mp->m_flag &= ~M_UPDATE; 16039335Smckusick vrele(vp); 16139335Smckusick RETURN (error); 16239335Smckusick } 16337741Smckusick cache_purge(vp); 16437741Smckusick if (!error) { 16539335Smckusick VOP_UNLOCK(vp); 16637741Smckusick vfs_unlock(mp); 16739044Smckusick error = VFS_START(mp, 0); 16837741Smckusick } else { 16937741Smckusick vfs_remove(mp); 17037741Smckusick free((caddr_t)mp, M_MOUNT); 17139335Smckusick vput(vp); 17237741Smckusick } 17337741Smckusick RETURN (error); 1746254Sroot } 1756254Sroot 1769167Ssam /* 17737741Smckusick * Unmount system call. 17837741Smckusick * 17937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18037741Smckusick * not special file (as before). 1819167Ssam */ 18238408Smckusick unmount(scp) 18338408Smckusick register struct syscontext *scp; 1846254Sroot { 18537741Smckusick struct a { 18637741Smckusick char *pathp; 18737741Smckusick int flags; 18838408Smckusick } *uap = (struct a *)scp->sc_ap; 18937741Smckusick register struct vnode *vp; 19038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19139356Smckusick struct mount *mp; 19237741Smckusick int error; 1936254Sroot 19437741Smckusick /* 19537741Smckusick * Must be super user 19637741Smckusick */ 19738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 19837741Smckusick RETURN (error); 19937741Smckusick 20037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20237741Smckusick ndp->ni_dirp = uap->pathp; 20337741Smckusick if (error = namei(ndp)) 20437741Smckusick RETURN (error); 20537741Smckusick vp = ndp->ni_vp; 20637741Smckusick /* 20737741Smckusick * Must be the root of the filesystem 20837741Smckusick */ 20937741Smckusick if ((vp->v_flag & VROOT) == 0) { 21037741Smckusick vput(vp); 21137741Smckusick RETURN (EINVAL); 21237741Smckusick } 21337741Smckusick mp = vp->v_mount; 21437741Smckusick vput(vp); 21539356Smckusick RETURN (dounmount(mp, uap->flags)); 21639356Smckusick } 21739356Smckusick 21839356Smckusick /* 21939356Smckusick * Do an unmount. 22039356Smckusick */ 22139356Smckusick dounmount(mp, flags) 22239356Smckusick register struct mount *mp; 22339356Smckusick int flags; 22439356Smckusick { 22539356Smckusick struct vnode *coveredvp; 22639356Smckusick int error; 22739356Smckusick 22837741Smckusick coveredvp = mp->m_vnodecovered; 22937741Smckusick if (error = vfs_lock(mp)) 23039356Smckusick return (error); 23137741Smckusick 23237741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23437741Smckusick VFS_SYNC(mp, MNT_WAIT); 23537741Smckusick 23639356Smckusick error = VFS_UNMOUNT(mp, flags); 23737741Smckusick if (error) { 23837741Smckusick vfs_unlock(mp); 23937741Smckusick } else { 24037741Smckusick vrele(coveredvp); 24137741Smckusick vfs_remove(mp); 24237741Smckusick free((caddr_t)mp, M_MOUNT); 24337741Smckusick } 24439356Smckusick return (error); 2456254Sroot } 2466254Sroot 2479167Ssam /* 24837741Smckusick * Sync system call. 24937741Smckusick * Sync each mounted filesystem. 2509167Ssam */ 25139491Smckusick /* ARGSUSED */ 25238408Smckusick sync(scp) 25339491Smckusick struct syscontext *scp; 2546254Sroot { 25537741Smckusick register struct mount *mp; 25637741Smckusick 25737741Smckusick mp = rootfs; 25837741Smckusick do { 25937741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 26037741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 26137741Smckusick mp = mp->m_next; 26237741Smckusick } while (mp != rootfs); 26337741Smckusick } 26437741Smckusick 26537741Smckusick /* 26637741Smckusick * get filesystem statistics 26737741Smckusick */ 26838408Smckusick statfs(scp) 26938408Smckusick register struct syscontext *scp; 27037741Smckusick { 2716254Sroot struct a { 27237741Smckusick char *path; 27337741Smckusick struct statfs *buf; 27438408Smckusick } *uap = (struct a *)scp->sc_ap; 27539464Smckusick register struct mount *mp; 27638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 27737741Smckusick struct statfs sb; 27837741Smckusick int error; 27937741Smckusick 28039544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 28137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28237741Smckusick ndp->ni_dirp = uap->path; 28337741Smckusick if (error = namei(ndp)) 28437741Smckusick RETURN (error); 28539544Smckusick mp = ndp->ni_vp->v_mount; 28639544Smckusick vrele(ndp->ni_vp); 28739464Smckusick if (error = VFS_STATFS(mp, &sb)) 28839544Smckusick RETURN (error); 28939464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29039464Smckusick sb.f_fsid = mp->m_fsid; 29139544Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 29237741Smckusick } 29337741Smckusick 29438408Smckusick fstatfs(scp) 29538408Smckusick register struct syscontext *scp; 29637741Smckusick { 29737741Smckusick struct a { 29837741Smckusick int fd; 29937741Smckusick struct statfs *buf; 30038408Smckusick } *uap = (struct a *)scp->sc_ap; 30137741Smckusick struct file *fp; 30239464Smckusick struct mount *mp; 30337741Smckusick struct statfs sb; 30437741Smckusick int error; 30537741Smckusick 30638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 30737741Smckusick RETURN (error); 30839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 30939464Smckusick if (error = VFS_STATFS(mp, &sb)) 31037741Smckusick RETURN (error); 31139464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 31239464Smckusick sb.f_fsid = mp->m_fsid; 31337741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 31437741Smckusick } 31537741Smckusick 31637741Smckusick /* 31738270Smckusick * get statistics on all filesystems 31838270Smckusick */ 31938408Smckusick getfsstat(scp) 32038408Smckusick register struct syscontext *scp; 32138270Smckusick { 32238270Smckusick struct a { 32338270Smckusick struct statfs *buf; 32438270Smckusick long bufsize; 32538408Smckusick } *uap = (struct a *)scp->sc_ap; 32638270Smckusick register struct mount *mp; 32739606Smckusick caddr_t sfsp; 32838270Smckusick long count, maxcount, error; 32939606Smckusick struct statfs sb; 33038270Smckusick 33138270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33239606Smckusick sfsp = (caddr_t)uap->buf; 33338270Smckusick mp = rootfs; 33438270Smckusick count = 0; 33538270Smckusick do { 33639606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 33739607Smckusick if (error = VFS_STATFS(mp, &sb)) { 33839607Smckusick mp = mp->m_prev; 33939607Smckusick continue; 34039607Smckusick } 34139606Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 34239606Smckusick sb.f_fsid = mp->m_fsid; 34339606Smckusick if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb))) 34439606Smckusick RETURN (error); 34539606Smckusick sfsp += sizeof(sb); 34638270Smckusick } 34739606Smckusick count++; 34838270Smckusick mp = mp->m_prev; 34938270Smckusick } while (mp != rootfs); 35038270Smckusick if (sfsp && count > maxcount) 35138408Smckusick scp->sc_retval1 = maxcount; 35238270Smckusick else 35338408Smckusick scp->sc_retval1 = count; 35438270Smckusick RETURN (0); 35538270Smckusick } 35638270Smckusick 35738270Smckusick /* 35838259Smckusick * Change current working directory to a given file descriptor. 35938259Smckusick */ 36038408Smckusick fchdir(scp) 36138408Smckusick register struct syscontext *scp; 36238259Smckusick { 36338259Smckusick struct a { 36438259Smckusick int fd; 36538408Smckusick } *uap = (struct a *)scp->sc_ap; 36638259Smckusick register struct vnode *vp; 36738259Smckusick struct file *fp; 36838259Smckusick int error; 36938259Smckusick 37038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 37138259Smckusick RETURN (error); 37238259Smckusick vp = (struct vnode *)fp->f_data; 37338259Smckusick VOP_LOCK(vp); 37438259Smckusick if (vp->v_type != VDIR) 37538259Smckusick error = ENOTDIR; 37638259Smckusick else 37738408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 37838259Smckusick VOP_UNLOCK(vp); 37938408Smckusick vrele(scp->sc_cdir); 38038408Smckusick scp->sc_cdir = vp; 38138259Smckusick RETURN (error); 38238259Smckusick } 38338259Smckusick 38438259Smckusick /* 38537741Smckusick * Change current working directory (``.''). 38637741Smckusick */ 38738408Smckusick chdir(scp) 38838408Smckusick register struct syscontext *scp; 38937741Smckusick { 39037741Smckusick struct a { 3916254Sroot char *fname; 39238408Smckusick } *uap = (struct a *)scp->sc_ap; 39338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 39437741Smckusick int error; 3956254Sroot 39637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 39716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 39816694Smckusick ndp->ni_dirp = uap->fname; 39937741Smckusick if (error = chdirec(ndp)) 40037741Smckusick RETURN (error); 40138408Smckusick vrele(scp->sc_cdir); 40238408Smckusick scp->sc_cdir = ndp->ni_vp; 40337741Smckusick RETURN (0); 40437741Smckusick } 4056254Sroot 40637741Smckusick /* 40737741Smckusick * Change notion of root (``/'') directory. 40837741Smckusick */ 40938408Smckusick chroot(scp) 41038408Smckusick register struct syscontext *scp; 41137741Smckusick { 41237741Smckusick struct a { 41337741Smckusick char *fname; 41438408Smckusick } *uap = (struct a *)scp->sc_ap; 41538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 41637741Smckusick int error; 41737741Smckusick 41838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 41937741Smckusick RETURN (error); 42037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 42137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 42237741Smckusick ndp->ni_dirp = uap->fname; 42337741Smckusick if (error = chdirec(ndp)) 42437741Smckusick RETURN (error); 42539515Smckusick if (scp->sc_rdir != NULL) 42639515Smckusick vrele(scp->sc_rdir); 42738408Smckusick scp->sc_rdir = ndp->ni_vp; 42837741Smckusick RETURN (0); 4296254Sroot } 4306254Sroot 43137Sbill /* 43237741Smckusick * Common routine for chroot and chdir. 43337741Smckusick */ 43437741Smckusick chdirec(ndp) 43537741Smckusick register struct nameidata *ndp; 43637741Smckusick { 43737741Smckusick struct vnode *vp; 43837741Smckusick int error; 43937741Smckusick 44037741Smckusick if (error = namei(ndp)) 44137741Smckusick return (error); 44237741Smckusick vp = ndp->ni_vp; 44337741Smckusick if (vp->v_type != VDIR) 44437741Smckusick error = ENOTDIR; 44537741Smckusick else 44638399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44737741Smckusick VOP_UNLOCK(vp); 44837741Smckusick if (error) 44937741Smckusick vrele(vp); 45037741Smckusick return (error); 45137741Smckusick } 45237741Smckusick 45337741Smckusick /* 4546254Sroot * Open system call. 4556254Sroot */ 45638408Smckusick open(scp) 45738408Smckusick register struct syscontext *scp; 4586254Sroot { 45912756Ssam struct a { 4606254Sroot char *fname; 4617701Ssam int mode; 46212756Ssam int crtmode; 46338408Smckusick } *uap = (struct a *) scp->sc_ap; 46438408Smckusick struct nameidata *ndp = &scp->sc_nd; 4656254Sroot 46637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 46737741Smckusick ndp->ni_dirp = uap->fname; 46838408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 46938408Smckusick &scp->sc_retval1)); 4706254Sroot } 4716254Sroot 4726254Sroot /* 4736254Sroot * Creat system call. 4746254Sroot */ 47538408Smckusick creat(scp) 47638408Smckusick register struct syscontext *scp; 4776254Sroot { 47812756Ssam struct a { 4796254Sroot char *fname; 4806254Sroot int fmode; 48138408Smckusick } *uap = (struct a *)scp->sc_ap; 48238408Smckusick struct nameidata *ndp = &scp->sc_nd; 4836254Sroot 48437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48537741Smckusick ndp->ni_dirp = uap->fname; 48638408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 48738408Smckusick ndp, &scp->sc_retval1)); 4886254Sroot } 4896254Sroot 4906254Sroot /* 4916254Sroot * Common code for open and creat. 49212756Ssam * Check permissions, allocate an open file structure, 49312756Ssam * and call the device open routine if any. 4946254Sroot */ 49538408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 49638408Smckusick register struct syscontext *scp; 49737741Smckusick int fmode, cmode; 49837741Smckusick struct nameidata *ndp; 49937741Smckusick int *resultfd; 50012756Ssam { 5016254Sroot register struct file *fp; 50237741Smckusick struct file *nfp; 50337741Smckusick int indx, error; 50437741Smckusick extern struct fileops vnops; 5056254Sroot 50637741Smckusick if (error = falloc(&nfp, &indx)) 50737741Smckusick return (error); 50837741Smckusick fp = nfp; 50938408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 51037741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 51137741Smckusick crfree(fp->f_cred); 51237741Smckusick fp->f_count--; 51339499Smckusick if (error == -1) /* XXX from fdopen */ 51439499Smckusick return (0); /* XXX from fdopen */ 51539499Smckusick scp->sc_ofile[indx] = NULL; 51637741Smckusick return (error); 51712756Ssam } 51837741Smckusick fp->f_flag = fmode & FMASK; 51937741Smckusick fp->f_type = DTYPE_VNODE; 52037741Smckusick fp->f_ops = &vnops; 52137741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 52237741Smckusick if (resultfd) 52337741Smckusick *resultfd = indx; 52437741Smckusick return (0); 5256254Sroot } 5266254Sroot 5276254Sroot /* 5286254Sroot * Mknod system call 5296254Sroot */ 53038408Smckusick mknod(scp) 53138408Smckusick register struct syscontext *scp; 5326254Sroot { 5336254Sroot register struct a { 5346254Sroot char *fname; 5356254Sroot int fmode; 5366254Sroot int dev; 53738408Smckusick } *uap = (struct a *)scp->sc_ap; 53838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 53937741Smckusick register struct vnode *vp; 54037741Smckusick struct vattr vattr; 54137741Smckusick int error; 5426254Sroot 54338408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 54437741Smckusick RETURN (error); 54537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 54616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 54716694Smckusick ndp->ni_dirp = uap->fname; 54837741Smckusick if (error = namei(ndp)) 54937741Smckusick RETURN (error); 55037741Smckusick vp = ndp->ni_vp; 55137741Smckusick if (vp != NULL) { 55237741Smckusick error = EEXIST; 55312756Ssam goto out; 5546254Sroot } 55537741Smckusick vattr_null(&vattr); 55637741Smckusick switch (uap->fmode & IFMT) { 55712756Ssam 55815093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 55937741Smckusick vattr.va_type = VBAD; 56037741Smckusick break; 56112756Ssam case IFCHR: 56237741Smckusick vattr.va_type = VCHR; 56337741Smckusick break; 56412756Ssam case IFBLK: 56537741Smckusick vattr.va_type = VBLK; 56637741Smckusick break; 56737741Smckusick default: 56837741Smckusick error = EINVAL; 56937741Smckusick goto out; 5706254Sroot } 57138408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 57237741Smckusick vattr.va_rdev = uap->dev; 5736254Sroot out: 57437741Smckusick if (error) 57537741Smckusick VOP_ABORTOP(ndp); 57637741Smckusick else 57737741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 57837741Smckusick RETURN (error); 5796254Sroot } 5806254Sroot 5816254Sroot /* 5826254Sroot * link system call 5836254Sroot */ 58438408Smckusick link(scp) 58538408Smckusick register struct syscontext *scp; 5866254Sroot { 5876254Sroot register struct a { 5886254Sroot char *target; 5896254Sroot char *linkname; 59038408Smckusick } *uap = (struct a *)scp->sc_ap; 59138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59237741Smckusick register struct vnode *vp, *xp; 59337741Smckusick int error; 5946254Sroot 59516694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 59616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59716694Smckusick ndp->ni_dirp = uap->target; 59837741Smckusick if (error = namei(ndp)) 59937741Smckusick RETURN (error); 60037741Smckusick vp = ndp->ni_vp; 60137741Smckusick if (vp->v_type == VDIR && 60238408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 60337741Smckusick goto out1; 60437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60516694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 60637741Smckusick if (error = namei(ndp)) 60737741Smckusick goto out1; 60837741Smckusick xp = ndp->ni_vp; 6096254Sroot if (xp != NULL) { 61037741Smckusick error = EEXIST; 6116254Sroot goto out; 6126254Sroot } 61337741Smckusick xp = ndp->ni_dvp; 61437741Smckusick if (vp->v_mount != xp->v_mount) 61537741Smckusick error = EXDEV; 6166254Sroot out: 61737741Smckusick if (error) 61837741Smckusick VOP_ABORTOP(ndp); 61937741Smckusick else 62037741Smckusick error = VOP_LINK(vp, ndp); 62137741Smckusick out1: 62237741Smckusick vrele(vp); 62337741Smckusick RETURN (error); 6246254Sroot } 6256254Sroot 6266254Sroot /* 6276254Sroot * symlink -- make a symbolic link 6286254Sroot */ 62938408Smckusick symlink(scp) 63038408Smckusick register struct syscontext *scp; 6316254Sroot { 63237741Smckusick struct a { 6336254Sroot char *target; 6346254Sroot char *linkname; 63538408Smckusick } *uap = (struct a *)scp->sc_ap; 63638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 63737741Smckusick register struct vnode *vp; 63837741Smckusick struct vattr vattr; 63937741Smckusick char *target; 64037741Smckusick int error; 6416254Sroot 64216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64316694Smckusick ndp->ni_dirp = uap->linkname; 64437741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 64537741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 64637741Smckusick goto out1; 64737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64837741Smckusick if (error = namei(ndp)) 64937741Smckusick goto out1; 65037741Smckusick vp = ndp->ni_vp; 65137741Smckusick if (vp) { 65237741Smckusick error = EEXIST; 65337741Smckusick goto out; 6546254Sroot } 65537741Smckusick vp = ndp->ni_dvp; 65637741Smckusick vattr_null(&vattr); 65738408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 65837741Smckusick out: 65937741Smckusick if (error) 66037741Smckusick VOP_ABORTOP(ndp); 66137741Smckusick else 66237741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 66337741Smckusick out1: 66437741Smckusick FREE(target, M_NAMEI); 66537741Smckusick RETURN (error); 6666254Sroot } 6676254Sroot 6686254Sroot /* 6696254Sroot * Unlink system call. 6706254Sroot * Hard to avoid races here, especially 6716254Sroot * in unlinking directories. 6726254Sroot */ 67338408Smckusick unlink(scp) 67438408Smckusick register struct syscontext *scp; 6756254Sroot { 6766254Sroot struct a { 6776254Sroot char *fname; 67838408Smckusick } *uap = (struct a *)scp->sc_ap; 67938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68037741Smckusick register struct vnode *vp; 68137741Smckusick int error; 6826254Sroot 68337741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 68416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68516694Smckusick ndp->ni_dirp = uap->fname; 68637741Smckusick if (error = namei(ndp)) 68737741Smckusick RETURN (error); 68837741Smckusick vp = ndp->ni_vp; 68937741Smckusick if (vp->v_type == VDIR && 69038408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6916254Sroot goto out; 6926254Sroot /* 6936254Sroot * Don't unlink a mounted file. 6946254Sroot */ 69537741Smckusick if (vp->v_flag & VROOT) { 69637741Smckusick error = EBUSY; 6976254Sroot goto out; 6986254Sroot } 69937741Smckusick if (vp->v_flag & VTEXT) 70037741Smckusick xrele(vp); /* try once to free text */ 7016254Sroot out: 70237741Smckusick if (error) 70337741Smckusick VOP_ABORTOP(ndp); 7047142Smckusick else 70537741Smckusick error = VOP_REMOVE(ndp); 70637741Smckusick RETURN (error); 7076254Sroot } 7086254Sroot 7096254Sroot /* 7106254Sroot * Seek system call 7116254Sroot */ 71238408Smckusick lseek(scp) 71338408Smckusick register struct syscontext *scp; 7146254Sroot { 7156254Sroot register struct file *fp; 7166254Sroot register struct a { 71737741Smckusick int fdes; 7186254Sroot off_t off; 7196254Sroot int sbase; 72038408Smckusick } *uap = (struct a *)scp->sc_ap; 72137741Smckusick struct vattr vattr; 72237741Smckusick int error; 7236254Sroot 72437741Smckusick if ((unsigned)uap->fdes >= NOFILE || 72538408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 72637741Smckusick RETURN (EBADF); 72737741Smckusick if (fp->f_type != DTYPE_VNODE) 72837741Smckusick RETURN (ESPIPE); 72913878Ssam switch (uap->sbase) { 73013878Ssam 73113878Ssam case L_INCR: 73213878Ssam fp->f_offset += uap->off; 73313878Ssam break; 73413878Ssam 73513878Ssam case L_XTND: 73637741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 73738408Smckusick &vattr, scp->sc_cred)) 73837741Smckusick RETURN (error); 73937741Smckusick fp->f_offset = uap->off + vattr.va_size; 74013878Ssam break; 74113878Ssam 74213878Ssam case L_SET: 74313878Ssam fp->f_offset = uap->off; 74413878Ssam break; 74513878Ssam 74613878Ssam default: 74737741Smckusick RETURN (EINVAL); 74813878Ssam } 74938408Smckusick scp->sc_offset = fp->f_offset; 75037741Smckusick RETURN (0); 7516254Sroot } 7526254Sroot 7536254Sroot /* 7546254Sroot * Access system call 7556254Sroot */ 75638408Smckusick saccess(scp) 75738408Smckusick register struct syscontext *scp; 7586254Sroot { 7596254Sroot register struct a { 7606254Sroot char *fname; 7616254Sroot int fmode; 76238408Smckusick } *uap = (struct a *)scp->sc_ap; 76338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76437741Smckusick register struct vnode *vp; 76537741Smckusick int error, mode, svuid, svgid; 7666254Sroot 76738408Smckusick svuid = scp->sc_uid; 76838408Smckusick svgid = scp->sc_gid; 76938408Smckusick scp->sc_uid = scp->sc_ruid; 77038408Smckusick scp->sc_gid = scp->sc_rgid; 77137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 77216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77316694Smckusick ndp->ni_dirp = uap->fname; 77437741Smckusick if (error = namei(ndp)) 77537741Smckusick goto out1; 77637741Smckusick vp = ndp->ni_vp; 77737741Smckusick /* 77837741Smckusick * fmode == 0 means only check for exist 77937741Smckusick */ 78037741Smckusick if (uap->fmode) { 78137741Smckusick mode = 0; 78237741Smckusick if (uap->fmode & R_OK) 78337741Smckusick mode |= VREAD; 78437741Smckusick if (uap->fmode & W_OK) 78537741Smckusick mode |= VWRITE; 78637741Smckusick if (uap->fmode & X_OK) 78737741Smckusick mode |= VEXEC; 78839543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 78938399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7906254Sroot } 79137741Smckusick vput(vp); 79237741Smckusick out1: 79338408Smckusick scp->sc_uid = svuid; 79438408Smckusick scp->sc_gid = svgid; 79537741Smckusick RETURN (error); 7966254Sroot } 7976254Sroot 7986254Sroot /* 7996574Smckusic * Stat system call. This version follows links. 80037Sbill */ 80138408Smckusick stat(scp) 80238408Smckusick struct syscontext *scp; 80337Sbill { 80437Sbill 80538408Smckusick stat1(scp, FOLLOW); 80637Sbill } 80737Sbill 80837Sbill /* 8096574Smckusic * Lstat system call. This version does not follow links. 8105992Swnj */ 81138408Smckusick lstat(scp) 81238408Smckusick struct syscontext *scp; 8135992Swnj { 81412756Ssam 81538408Smckusick stat1(scp, NOFOLLOW); 81612756Ssam } 81712756Ssam 81838408Smckusick stat1(scp, follow) 81938408Smckusick register struct syscontext *scp; 82012756Ssam int follow; 82112756Ssam { 8225992Swnj register struct a { 8235992Swnj char *fname; 82412756Ssam struct stat *ub; 82538408Smckusick } *uap = (struct a *)scp->sc_ap; 82638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 82712756Ssam struct stat sb; 82837741Smckusick int error; 8295992Swnj 83037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 83116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83216694Smckusick ndp->ni_dirp = uap->fname; 83337741Smckusick if (error = namei(ndp)) 83437741Smckusick RETURN (error); 83537741Smckusick error = vn_stat(ndp->ni_vp, &sb); 83637741Smckusick vput(ndp->ni_vp); 83737741Smckusick if (error) 83837741Smckusick RETURN (error); 83937741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 84037741Smckusick RETURN (error); 8415992Swnj } 8425992Swnj 8435992Swnj /* 8445992Swnj * Return target name of a symbolic link 84537Sbill */ 84638408Smckusick readlink(scp) 84738408Smckusick register struct syscontext *scp; 8485992Swnj { 8495992Swnj register struct a { 8505992Swnj char *name; 8515992Swnj char *buf; 8525992Swnj int count; 85338408Smckusick } *uap = (struct a *)scp->sc_ap; 85438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85537741Smckusick register struct vnode *vp; 85637741Smckusick struct iovec aiov; 85737741Smckusick struct uio auio; 85837741Smckusick int error; 8595992Swnj 86037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 86116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86216694Smckusick ndp->ni_dirp = uap->name; 86337741Smckusick if (error = namei(ndp)) 86437741Smckusick RETURN (error); 86537741Smckusick vp = ndp->ni_vp; 86637741Smckusick if (vp->v_type != VLNK) { 86737741Smckusick error = EINVAL; 8685992Swnj goto out; 8695992Swnj } 87037741Smckusick aiov.iov_base = uap->buf; 87137741Smckusick aiov.iov_len = uap->count; 87237741Smckusick auio.uio_iov = &aiov; 87337741Smckusick auio.uio_iovcnt = 1; 87437741Smckusick auio.uio_offset = 0; 87537741Smckusick auio.uio_rw = UIO_READ; 87637741Smckusick auio.uio_segflg = UIO_USERSPACE; 87737741Smckusick auio.uio_resid = uap->count; 87837741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8795992Swnj out: 88037741Smckusick vput(vp); 88138408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 88237741Smckusick RETURN (error); 8835992Swnj } 8845992Swnj 8859167Ssam /* 88638259Smckusick * Change flags of a file given path name. 88738259Smckusick */ 88838408Smckusick chflags(scp) 88938408Smckusick register struct syscontext *scp; 89038259Smckusick { 89138259Smckusick struct a { 89238259Smckusick char *fname; 89338259Smckusick int flags; 89438408Smckusick } *uap = (struct a *)scp->sc_ap; 89538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 89638259Smckusick register struct vnode *vp; 89738259Smckusick struct vattr vattr; 89838259Smckusick int error; 89938259Smckusick 90038259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 90138259Smckusick ndp->ni_segflg = UIO_USERSPACE; 90238259Smckusick ndp->ni_dirp = uap->fname; 90338259Smckusick vattr_null(&vattr); 90438259Smckusick vattr.va_flags = uap->flags; 90538259Smckusick if (error = namei(ndp)) 90638259Smckusick RETURN (error); 90738259Smckusick vp = ndp->ni_vp; 90838259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 90938259Smckusick error = EROFS; 91038259Smckusick goto out; 91138259Smckusick } 91238259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 91338259Smckusick out: 91438259Smckusick vput(vp); 91538259Smckusick RETURN (error); 91638259Smckusick } 91738259Smckusick 91838259Smckusick /* 91938259Smckusick * Change flags of a file given a file descriptor. 92038259Smckusick */ 92138408Smckusick fchflags(scp) 92238408Smckusick register struct syscontext *scp; 92338259Smckusick { 92438259Smckusick struct a { 92538259Smckusick int fd; 92638259Smckusick int flags; 92738408Smckusick } *uap = (struct a *)scp->sc_ap; 92838259Smckusick struct vattr vattr; 92938259Smckusick struct vnode *vp; 93038259Smckusick struct file *fp; 93138259Smckusick int error; 93238259Smckusick 93338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 93438259Smckusick RETURN (error); 93538259Smckusick vattr_null(&vattr); 93638259Smckusick vattr.va_flags = uap->flags; 93738259Smckusick vp = (struct vnode *)fp->f_data; 93838259Smckusick VOP_LOCK(vp); 93938259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94038259Smckusick error = EROFS; 94138259Smckusick goto out; 94238259Smckusick } 94338259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 94438259Smckusick out: 94538259Smckusick VOP_UNLOCK(vp); 94638259Smckusick RETURN (error); 94738259Smckusick } 94838259Smckusick 94938259Smckusick /* 9509167Ssam * Change mode of a file given path name. 9519167Ssam */ 95238408Smckusick chmod(scp) 95338408Smckusick register struct syscontext *scp; 9545992Swnj { 9557701Ssam struct a { 9566254Sroot char *fname; 9576254Sroot int fmode; 95838408Smckusick } *uap = (struct a *)scp->sc_ap; 95938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 96037741Smckusick register struct vnode *vp; 96137741Smckusick struct vattr vattr; 96237741Smckusick int error; 9635992Swnj 96437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 96537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 96637741Smckusick ndp->ni_dirp = uap->fname; 96737741Smckusick vattr_null(&vattr); 96837741Smckusick vattr.va_mode = uap->fmode & 07777; 96937741Smckusick if (error = namei(ndp)) 97037741Smckusick RETURN (error); 97137741Smckusick vp = ndp->ni_vp; 97237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97337741Smckusick error = EROFS; 97437741Smckusick goto out; 97537741Smckusick } 97637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 97737741Smckusick out: 97837741Smckusick vput(vp); 97937741Smckusick RETURN (error); 9807701Ssam } 9817439Sroot 9829167Ssam /* 9839167Ssam * Change mode of a file given a file descriptor. 9849167Ssam */ 98538408Smckusick fchmod(scp) 98638408Smckusick register struct syscontext *scp; 9877701Ssam { 9887701Ssam struct a { 9897701Ssam int fd; 9907701Ssam int fmode; 99138408Smckusick } *uap = (struct a *)scp->sc_ap; 99237741Smckusick struct vattr vattr; 99337741Smckusick struct vnode *vp; 99437741Smckusick struct file *fp; 99537741Smckusick int error; 9967701Ssam 99738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 99837741Smckusick RETURN (error); 99937741Smckusick vattr_null(&vattr); 100037741Smckusick vattr.va_mode = uap->fmode & 07777; 100137741Smckusick vp = (struct vnode *)fp->f_data; 100237741Smckusick VOP_LOCK(vp); 100337741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 100437741Smckusick error = EROFS; 100537741Smckusick goto out; 10067439Sroot } 100737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 100837741Smckusick out: 100937741Smckusick VOP_UNLOCK(vp); 101037741Smckusick RETURN (error); 10115992Swnj } 10125992Swnj 10139167Ssam /* 10149167Ssam * Set ownership given a path name. 10159167Ssam */ 101638408Smckusick chown(scp) 101738408Smckusick register struct syscontext *scp; 101837Sbill { 10197701Ssam struct a { 10206254Sroot char *fname; 10216254Sroot int uid; 10226254Sroot int gid; 102338408Smckusick } *uap = (struct a *)scp->sc_ap; 102438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 102537741Smckusick register struct vnode *vp; 102637741Smckusick struct vattr vattr; 102737741Smckusick int error; 102837Sbill 102937741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 103036614Sbostic ndp->ni_segflg = UIO_USERSPACE; 103136614Sbostic ndp->ni_dirp = uap->fname; 103237741Smckusick vattr_null(&vattr); 103337741Smckusick vattr.va_uid = uap->uid; 103437741Smckusick vattr.va_gid = uap->gid; 103537741Smckusick if (error = namei(ndp)) 103637741Smckusick RETURN (error); 103737741Smckusick vp = ndp->ni_vp; 103837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 103937741Smckusick error = EROFS; 104037741Smckusick goto out; 104137741Smckusick } 104237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 104337741Smckusick out: 104437741Smckusick vput(vp); 104537741Smckusick RETURN (error); 10467701Ssam } 10477439Sroot 10489167Ssam /* 10499167Ssam * Set ownership given a file descriptor. 10509167Ssam */ 105138408Smckusick fchown(scp) 105238408Smckusick register struct syscontext *scp; 10537701Ssam { 10547701Ssam struct a { 10557701Ssam int fd; 10567701Ssam int uid; 10577701Ssam int gid; 105838408Smckusick } *uap = (struct a *)scp->sc_ap; 105937741Smckusick struct vattr vattr; 106037741Smckusick struct vnode *vp; 106137741Smckusick struct file *fp; 106237741Smckusick int error; 10637701Ssam 106438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 106537741Smckusick RETURN (error); 106637741Smckusick vattr_null(&vattr); 106737741Smckusick vattr.va_uid = uap->uid; 106837741Smckusick vattr.va_gid = uap->gid; 106937741Smckusick vp = (struct vnode *)fp->f_data; 107037741Smckusick VOP_LOCK(vp); 107137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 107237741Smckusick error = EROFS; 107337741Smckusick goto out; 107437741Smckusick } 107537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 107637741Smckusick out: 107737741Smckusick VOP_UNLOCK(vp); 107837741Smckusick RETURN (error); 10797701Ssam } 10807701Ssam 108138408Smckusick utimes(scp) 108238408Smckusick register struct syscontext *scp; 108311811Ssam { 108411811Ssam register struct a { 108511811Ssam char *fname; 108611811Ssam struct timeval *tptr; 108738408Smckusick } *uap = (struct a *)scp->sc_ap; 108838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 108937741Smckusick register struct vnode *vp; 109011811Ssam struct timeval tv[2]; 109137741Smckusick struct vattr vattr; 109237741Smckusick int error; 109311811Ssam 109437741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 109537741Smckusick RETURN (error); 109637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 109737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 109837741Smckusick ndp->ni_dirp = uap->fname; 109937741Smckusick vattr_null(&vattr); 110037741Smckusick vattr.va_atime = tv[0]; 110137741Smckusick vattr.va_mtime = tv[1]; 110237741Smckusick if (error = namei(ndp)) 110337741Smckusick RETURN (error); 110437741Smckusick vp = ndp->ni_vp; 110537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 110637741Smckusick error = EROFS; 110737741Smckusick goto out; 110821015Smckusick } 110937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 111037741Smckusick out: 111137741Smckusick vput(vp); 111237741Smckusick RETURN (error); 111311811Ssam } 111411811Ssam 11159167Ssam /* 11169167Ssam * Truncate a file given its path name. 11179167Ssam */ 111838408Smckusick truncate(scp) 111938408Smckusick register struct syscontext *scp; 11207701Ssam { 11217701Ssam struct a { 11227701Ssam char *fname; 112326473Skarels off_t length; 112438408Smckusick } *uap = (struct a *)scp->sc_ap; 112538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112637741Smckusick register struct vnode *vp; 112737741Smckusick struct vattr vattr; 112837741Smckusick int error; 11297701Ssam 113037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113216694Smckusick ndp->ni_dirp = uap->fname; 113337741Smckusick vattr_null(&vattr); 113437741Smckusick vattr.va_size = uap->length; 113537741Smckusick if (error = namei(ndp)) 113637741Smckusick RETURN (error); 113737741Smckusick vp = ndp->ni_vp; 113837741Smckusick if (vp->v_type == VDIR) { 113937741Smckusick error = EISDIR; 114037741Smckusick goto out; 11417701Ssam } 114238399Smckusick if ((error = vn_writechk(vp)) || 114338399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 114437741Smckusick goto out; 114537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114637741Smckusick out: 114737741Smckusick vput(vp); 114837741Smckusick RETURN (error); 11497701Ssam } 11507701Ssam 11519167Ssam /* 11529167Ssam * Truncate a file given a file descriptor. 11539167Ssam */ 115438408Smckusick ftruncate(scp) 115538408Smckusick register struct syscontext *scp; 11567701Ssam { 11577701Ssam struct a { 11587701Ssam int fd; 115926473Skarels off_t length; 116038408Smckusick } *uap = (struct a *)scp->sc_ap; 116137741Smckusick struct vattr vattr; 116237741Smckusick struct vnode *vp; 11637701Ssam struct file *fp; 116437741Smckusick int error; 11657701Ssam 116638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 116737741Smckusick RETURN (error); 116837741Smckusick if ((fp->f_flag & FWRITE) == 0) 116937741Smckusick RETURN (EINVAL); 117037741Smckusick vattr_null(&vattr); 117137741Smckusick vattr.va_size = uap->length; 117237741Smckusick vp = (struct vnode *)fp->f_data; 117337741Smckusick VOP_LOCK(vp); 117437741Smckusick if (vp->v_type == VDIR) { 117537741Smckusick error = EISDIR; 117637741Smckusick goto out; 11777701Ssam } 117838399Smckusick if (error = vn_writechk(vp)) 117937741Smckusick goto out; 118037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118137741Smckusick out: 118237741Smckusick VOP_UNLOCK(vp); 118337741Smckusick RETURN (error); 11847701Ssam } 11857701Ssam 11869167Ssam /* 11879167Ssam * Synch an open file. 11889167Ssam */ 118938408Smckusick fsync(scp) 119038408Smckusick register struct syscontext *scp; 11919167Ssam { 11929167Ssam struct a { 11939167Ssam int fd; 119438408Smckusick } *uap = (struct a *)scp->sc_ap; 119539592Smckusick register struct vnode *vp; 11969167Ssam struct file *fp; 119737741Smckusick int error; 11989167Ssam 119938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 120037741Smckusick RETURN (error); 120139592Smckusick vp = (struct vnode *)fp->f_data; 120239592Smckusick VOP_LOCK(vp); 120339592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 120439592Smckusick VOP_UNLOCK(vp); 120537741Smckusick RETURN (error); 12069167Ssam } 12079167Ssam 12089167Ssam /* 12099167Ssam * Rename system call. 12109167Ssam * 12119167Ssam * Source and destination must either both be directories, or both 12129167Ssam * not be directories. If target is a directory, it must be empty. 12139167Ssam */ 121438408Smckusick rename(scp) 121538408Smckusick register struct syscontext *scp; 12167701Ssam { 12177701Ssam struct a { 12187701Ssam char *from; 12197701Ssam char *to; 122038408Smckusick } *uap = (struct a *)scp->sc_ap; 122137741Smckusick register struct vnode *tvp, *fvp, *tdvp; 122238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 122337741Smckusick struct nameidata tond; 122437741Smckusick int error; 12257701Ssam 122637741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 122716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122816694Smckusick ndp->ni_dirp = uap->from; 122937741Smckusick if (error = namei(ndp)) 123037741Smckusick RETURN (error); 123137741Smckusick fvp = ndp->ni_vp; 123238266Smckusick nddup(ndp, &tond); 123337741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 123437741Smckusick tond.ni_segflg = UIO_USERSPACE; 123537741Smckusick tond.ni_dirp = uap->to; 123637741Smckusick error = namei(&tond); 123737741Smckusick tdvp = tond.ni_dvp; 123837741Smckusick tvp = tond.ni_vp; 123937741Smckusick if (tvp != NULL) { 124037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 124139242Sbostic error = ENOTDIR; 124237741Smckusick goto out; 124337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 124439242Sbostic error = EISDIR; 124537741Smckusick goto out; 12469167Ssam } 12479167Ssam } 124837741Smckusick if (error) { 124937741Smckusick VOP_ABORTOP(ndp); 125037741Smckusick goto out1; 125137741Smckusick } 125237741Smckusick if (fvp->v_mount != tdvp->v_mount) { 125337741Smckusick error = EXDEV; 12549167Ssam goto out; 125510051Ssam } 125639286Smckusick if (fvp == tdvp) 125737741Smckusick error = EINVAL; 125839286Smckusick /* 125939286Smckusick * If source is the same as the destination, 126039286Smckusick * then there is nothing to do. 126139286Smckusick */ 126239286Smckusick if (fvp == tvp) 126339286Smckusick error = -1; 126437741Smckusick out: 126537741Smckusick if (error) { 126637741Smckusick VOP_ABORTOP(&tond); 126737741Smckusick VOP_ABORTOP(ndp); 12689167Ssam } else { 126937741Smckusick error = VOP_RENAME(ndp, &tond); 12709167Ssam } 127137741Smckusick out1: 127238266Smckusick ndrele(&tond); 127339286Smckusick if (error == -1) 127439286Smckusick RETURN (0); 127537741Smckusick RETURN (error); 12767701Ssam } 12777701Ssam 12787535Sroot /* 127912756Ssam * Mkdir system call 128012756Ssam */ 128138408Smckusick mkdir(scp) 128238408Smckusick register struct syscontext *scp; 128312756Ssam { 128412756Ssam struct a { 128512756Ssam char *name; 128612756Ssam int dmode; 128738408Smckusick } *uap = (struct a *)scp->sc_ap; 128838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 128937741Smckusick register struct vnode *vp; 129037741Smckusick struct vattr vattr; 129137741Smckusick int error; 129212756Ssam 129337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 129416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 129516694Smckusick ndp->ni_dirp = uap->name; 129637741Smckusick if (error = namei(ndp)) 129737741Smckusick RETURN (error); 129837741Smckusick vp = ndp->ni_vp; 129937741Smckusick if (vp != NULL) { 130037741Smckusick VOP_ABORTOP(ndp); 130137741Smckusick RETURN (EEXIST); 130212756Ssam } 130337741Smckusick vattr_null(&vattr); 130437741Smckusick vattr.va_type = VDIR; 130538408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 130637741Smckusick error = VOP_MKDIR(ndp, &vattr); 130738145Smckusick if (!error) 130838145Smckusick vput(ndp->ni_vp); 130937741Smckusick RETURN (error); 131012756Ssam } 131112756Ssam 131212756Ssam /* 131312756Ssam * Rmdir system call. 131412756Ssam */ 131538408Smckusick rmdir(scp) 131638408Smckusick register struct syscontext *scp; 131712756Ssam { 131812756Ssam struct a { 131912756Ssam char *name; 132038408Smckusick } *uap = (struct a *)scp->sc_ap; 132138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 132237741Smckusick register struct vnode *vp; 132337741Smckusick int error; 132412756Ssam 132537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 132616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132716694Smckusick ndp->ni_dirp = uap->name; 132837741Smckusick if (error = namei(ndp)) 132937741Smckusick RETURN (error); 133037741Smckusick vp = ndp->ni_vp; 133137741Smckusick if (vp->v_type != VDIR) { 133237741Smckusick error = ENOTDIR; 133312756Ssam goto out; 133412756Ssam } 133512756Ssam /* 133637741Smckusick * No rmdir "." please. 133712756Ssam */ 133837741Smckusick if (ndp->ni_dvp == vp) { 133937741Smckusick error = EINVAL; 134012756Ssam goto out; 134112756Ssam } 134212756Ssam /* 134337741Smckusick * Don't unlink a mounted file. 134412756Ssam */ 134537741Smckusick if (vp->v_flag & VROOT) 134637741Smckusick error = EBUSY; 134712756Ssam out: 134837741Smckusick if (error) 134937741Smckusick VOP_ABORTOP(ndp); 135037741Smckusick else 135137741Smckusick error = VOP_RMDIR(ndp); 135237741Smckusick RETURN (error); 135312756Ssam } 135412756Ssam 135537741Smckusick /* 135637741Smckusick * Read a block of directory entries in a file system independent format 135737741Smckusick */ 135838408Smckusick getdirentries(scp) 135938408Smckusick register struct syscontext *scp; 136012756Ssam { 136137741Smckusick register struct a { 136237741Smckusick int fd; 136337741Smckusick char *buf; 136437741Smckusick unsigned count; 136537741Smckusick long *basep; 136638408Smckusick } *uap = (struct a *)scp->sc_ap; 136739592Smckusick register struct vnode *vp; 136816540Ssam struct file *fp; 136937741Smckusick struct uio auio; 137037741Smckusick struct iovec aiov; 137138129Smckusick off_t off; 137237741Smckusick int error; 137312756Ssam 137438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 137537741Smckusick RETURN (error); 137637741Smckusick if ((fp->f_flag & FREAD) == 0) 137737741Smckusick RETURN (EBADF); 137839592Smckusick vp = (struct vnode *)fp->f_data; 137939592Smckusick if (vp->v_type != VDIR) 138039592Smckusick RETURN (EINVAL); 138137741Smckusick aiov.iov_base = uap->buf; 138237741Smckusick aiov.iov_len = uap->count; 138337741Smckusick auio.uio_iov = &aiov; 138437741Smckusick auio.uio_iovcnt = 1; 138537741Smckusick auio.uio_rw = UIO_READ; 138637741Smckusick auio.uio_segflg = UIO_USERSPACE; 138737741Smckusick auio.uio_resid = uap->count; 138839592Smckusick VOP_LOCK(vp); 138939592Smckusick auio.uio_offset = off = fp->f_offset; 139039592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 139139592Smckusick fp->f_offset = auio.uio_offset; 139239592Smckusick VOP_UNLOCK(vp); 139339592Smckusick if (error) 139437741Smckusick RETURN (error); 139539592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 139638408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 139737741Smckusick RETURN (error); 139812756Ssam } 139912756Ssam 140012756Ssam /* 140112756Ssam * mode mask for creation of files 140212756Ssam */ 140338408Smckusick umask(scp) 140438408Smckusick register struct syscontext *scp; 140512756Ssam { 140612756Ssam register struct a { 140712756Ssam int mask; 140838408Smckusick } *uap = (struct a *)scp->sc_ap; 140912756Ssam 141038408Smckusick scp->sc_retval1 = scp->sc_cmask; 141138408Smckusick scp->sc_cmask = uap->mask & 07777; 141237741Smckusick RETURN (0); 141312756Ssam } 141437741Smckusick 141539566Smarc /* 141639566Smarc * Void all references to file by ripping underlying filesystem 141739566Smarc * away from vnode. 141839566Smarc */ 141939566Smarc revoke(scp) 142039566Smarc register struct syscontext *scp; 142139566Smarc { 142239566Smarc struct a { 142339566Smarc char *fname; 142439566Smarc } *uap = (struct a *)scp->sc_ap; 142539566Smarc register struct nameidata *ndp = &scp->sc_nd; 142639566Smarc register struct vnode *vp; 142739566Smarc struct vattr vattr; 142839566Smarc int error; 142939566Smarc 143039566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 143139566Smarc ndp->ni_segflg = UIO_USERSPACE; 143239566Smarc ndp->ni_dirp = uap->fname; 143339566Smarc if (error = namei(ndp)) 143439566Smarc RETURN (error); 143539566Smarc vp = ndp->ni_vp; 143639566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 143739566Smarc error = EINVAL; 143839566Smarc goto out; 143939566Smarc } 144039566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 144139566Smarc goto out; 144239566Smarc if (scp->sc_uid != vattr.va_uid || 144339566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 144439566Smarc goto out; 1445*39632Smckusick if (vp->v_count > 1 || (vp->v_flag & VALIASED)) 1446*39632Smckusick vgoneall(vp); 144739566Smarc out: 144839566Smarc vrele(vp); 144939566Smarc RETURN (error); 145039566Smarc } 145139566Smarc 145238408Smckusick getvnode(ofile, fdes, fpp) 145338408Smckusick struct file *ofile[]; 145437741Smckusick struct file **fpp; 145537741Smckusick int fdes; 145637741Smckusick { 145737741Smckusick struct file *fp; 145837741Smckusick 145938408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 146037741Smckusick return (EBADF); 146137741Smckusick if (fp->f_type != DTYPE_VNODE) 146237741Smckusick return (EINVAL); 146337741Smckusick *fpp = fp; 146437741Smckusick return (0); 146537741Smckusick } 1466