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*39544Smckusick * @(#)vfs_syscalls.c 7.26 (Berkeley) 11/19/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 280*39544Smckusick 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); 285*39544Smckusick mp = ndp->ni_vp->v_mount; 286*39544Smckusick vrele(ndp->ni_vp); 28739464Smckusick if (error = VFS_STATFS(mp, &sb)) 288*39544Smckusick RETURN (error); 28939464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29039464Smckusick sb.f_fsid = mp->m_fsid; 291*39544Smckusick 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; 32738270Smckusick register struct statfs *sfsp; 32838270Smckusick long count, maxcount, error; 32938270Smckusick 33038270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33138270Smckusick sfsp = uap->buf; 33238270Smckusick mp = rootfs; 33338270Smckusick count = 0; 33438270Smckusick do { 33538270Smckusick count++; 33639044Smckusick if (sfsp && count <= maxcount && 33739044Smckusick ((mp->m_flag & M_MLOCK) == 0)) { 33838270Smckusick if (error = VFS_STATFS(mp, sfsp)) 33938270Smckusick RETURN (error); 34039464Smckusick sfsp->f_flags = mp->m_flag & M_VISFLAGMASK; 34139464Smckusick sfsp->f_fsid = mp->m_fsid; 34238270Smckusick sfsp++; 34338270Smckusick } 34438270Smckusick mp = mp->m_prev; 34538270Smckusick } while (mp != rootfs); 34638270Smckusick if (sfsp && count > maxcount) 34738408Smckusick scp->sc_retval1 = maxcount; 34838270Smckusick else 34938408Smckusick scp->sc_retval1 = count; 35038270Smckusick RETURN (0); 35138270Smckusick } 35238270Smckusick 35338270Smckusick /* 35438259Smckusick * Change current working directory to a given file descriptor. 35538259Smckusick */ 35638408Smckusick fchdir(scp) 35738408Smckusick register struct syscontext *scp; 35838259Smckusick { 35938259Smckusick struct a { 36038259Smckusick int fd; 36138408Smckusick } *uap = (struct a *)scp->sc_ap; 36238259Smckusick register struct vnode *vp; 36338259Smckusick struct file *fp; 36438259Smckusick int error; 36538259Smckusick 36638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 36738259Smckusick RETURN (error); 36838259Smckusick vp = (struct vnode *)fp->f_data; 36938259Smckusick VOP_LOCK(vp); 37038259Smckusick if (vp->v_type != VDIR) 37138259Smckusick error = ENOTDIR; 37238259Smckusick else 37338408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 37438259Smckusick VOP_UNLOCK(vp); 37538408Smckusick vrele(scp->sc_cdir); 37638408Smckusick scp->sc_cdir = vp; 37738259Smckusick RETURN (error); 37838259Smckusick } 37938259Smckusick 38038259Smckusick /* 38137741Smckusick * Change current working directory (``.''). 38237741Smckusick */ 38338408Smckusick chdir(scp) 38438408Smckusick register struct syscontext *scp; 38537741Smckusick { 38637741Smckusick struct a { 3876254Sroot char *fname; 38838408Smckusick } *uap = (struct a *)scp->sc_ap; 38938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 39037741Smckusick int error; 3916254Sroot 39237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 39316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 39416694Smckusick ndp->ni_dirp = uap->fname; 39537741Smckusick if (error = chdirec(ndp)) 39637741Smckusick RETURN (error); 39738408Smckusick vrele(scp->sc_cdir); 39838408Smckusick scp->sc_cdir = ndp->ni_vp; 39937741Smckusick RETURN (0); 40037741Smckusick } 4016254Sroot 40237741Smckusick /* 40337741Smckusick * Change notion of root (``/'') directory. 40437741Smckusick */ 40538408Smckusick chroot(scp) 40638408Smckusick register struct syscontext *scp; 40737741Smckusick { 40837741Smckusick struct a { 40937741Smckusick char *fname; 41038408Smckusick } *uap = (struct a *)scp->sc_ap; 41138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 41237741Smckusick int error; 41337741Smckusick 41438408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 41537741Smckusick RETURN (error); 41637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 41737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 41837741Smckusick ndp->ni_dirp = uap->fname; 41937741Smckusick if (error = chdirec(ndp)) 42037741Smckusick RETURN (error); 42139515Smckusick if (scp->sc_rdir != NULL) 42239515Smckusick vrele(scp->sc_rdir); 42338408Smckusick scp->sc_rdir = ndp->ni_vp; 42437741Smckusick RETURN (0); 4256254Sroot } 4266254Sroot 42737Sbill /* 42837741Smckusick * Common routine for chroot and chdir. 42937741Smckusick */ 43037741Smckusick chdirec(ndp) 43137741Smckusick register struct nameidata *ndp; 43237741Smckusick { 43337741Smckusick struct vnode *vp; 43437741Smckusick int error; 43537741Smckusick 43637741Smckusick if (error = namei(ndp)) 43737741Smckusick return (error); 43837741Smckusick vp = ndp->ni_vp; 43937741Smckusick if (vp->v_type != VDIR) 44037741Smckusick error = ENOTDIR; 44137741Smckusick else 44238399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44337741Smckusick VOP_UNLOCK(vp); 44437741Smckusick if (error) 44537741Smckusick vrele(vp); 44637741Smckusick return (error); 44737741Smckusick } 44837741Smckusick 44937741Smckusick /* 4506254Sroot * Open system call. 4516254Sroot */ 45238408Smckusick open(scp) 45338408Smckusick register struct syscontext *scp; 4546254Sroot { 45512756Ssam struct a { 4566254Sroot char *fname; 4577701Ssam int mode; 45812756Ssam int crtmode; 45938408Smckusick } *uap = (struct a *) scp->sc_ap; 46038408Smckusick struct nameidata *ndp = &scp->sc_nd; 4616254Sroot 46237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 46337741Smckusick ndp->ni_dirp = uap->fname; 46438408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 46538408Smckusick &scp->sc_retval1)); 4666254Sroot } 4676254Sroot 4686254Sroot /* 4696254Sroot * Creat system call. 4706254Sroot */ 47138408Smckusick creat(scp) 47238408Smckusick register struct syscontext *scp; 4736254Sroot { 47412756Ssam struct a { 4756254Sroot char *fname; 4766254Sroot int fmode; 47738408Smckusick } *uap = (struct a *)scp->sc_ap; 47838408Smckusick struct nameidata *ndp = &scp->sc_nd; 4796254Sroot 48037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48137741Smckusick ndp->ni_dirp = uap->fname; 48238408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 48338408Smckusick ndp, &scp->sc_retval1)); 4846254Sroot } 4856254Sroot 4866254Sroot /* 4876254Sroot * Common code for open and creat. 48812756Ssam * Check permissions, allocate an open file structure, 48912756Ssam * and call the device open routine if any. 4906254Sroot */ 49138408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 49238408Smckusick register struct syscontext *scp; 49337741Smckusick int fmode, cmode; 49437741Smckusick struct nameidata *ndp; 49537741Smckusick int *resultfd; 49612756Ssam { 4976254Sroot register struct file *fp; 49837741Smckusick struct file *nfp; 49937741Smckusick int indx, error; 50037741Smckusick extern struct fileops vnops; 5016254Sroot 50237741Smckusick if (error = falloc(&nfp, &indx)) 50337741Smckusick return (error); 50437741Smckusick fp = nfp; 50538408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 50637741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 50737741Smckusick crfree(fp->f_cred); 50837741Smckusick fp->f_count--; 50939499Smckusick if (error == -1) /* XXX from fdopen */ 51039499Smckusick return (0); /* XXX from fdopen */ 51139499Smckusick scp->sc_ofile[indx] = NULL; 51237741Smckusick return (error); 51312756Ssam } 51437741Smckusick fp->f_flag = fmode & FMASK; 51537741Smckusick fp->f_type = DTYPE_VNODE; 51637741Smckusick fp->f_ops = &vnops; 51737741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 51837741Smckusick if (resultfd) 51937741Smckusick *resultfd = indx; 52037741Smckusick return (0); 5216254Sroot } 5226254Sroot 5236254Sroot /* 5246254Sroot * Mknod system call 5256254Sroot */ 52638408Smckusick mknod(scp) 52738408Smckusick register struct syscontext *scp; 5286254Sroot { 5296254Sroot register struct a { 5306254Sroot char *fname; 5316254Sroot int fmode; 5326254Sroot int dev; 53338408Smckusick } *uap = (struct a *)scp->sc_ap; 53438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 53537741Smckusick register struct vnode *vp; 53637741Smckusick struct vattr vattr; 53737741Smckusick int error; 5386254Sroot 53938408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 54037741Smckusick RETURN (error); 54137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 54216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 54316694Smckusick ndp->ni_dirp = uap->fname; 54437741Smckusick if (error = namei(ndp)) 54537741Smckusick RETURN (error); 54637741Smckusick vp = ndp->ni_vp; 54737741Smckusick if (vp != NULL) { 54837741Smckusick error = EEXIST; 54912756Ssam goto out; 5506254Sroot } 55137741Smckusick vattr_null(&vattr); 55237741Smckusick switch (uap->fmode & IFMT) { 55312756Ssam 55415093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 55537741Smckusick vattr.va_type = VBAD; 55637741Smckusick break; 55712756Ssam case IFCHR: 55837741Smckusick vattr.va_type = VCHR; 55937741Smckusick break; 56012756Ssam case IFBLK: 56137741Smckusick vattr.va_type = VBLK; 56237741Smckusick break; 56337741Smckusick default: 56437741Smckusick error = EINVAL; 56537741Smckusick goto out; 5666254Sroot } 56738408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 56837741Smckusick vattr.va_rdev = uap->dev; 5696254Sroot out: 57037741Smckusick if (error) 57137741Smckusick VOP_ABORTOP(ndp); 57237741Smckusick else 57337741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 57437741Smckusick RETURN (error); 5756254Sroot } 5766254Sroot 5776254Sroot /* 5786254Sroot * link system call 5796254Sroot */ 58038408Smckusick link(scp) 58138408Smckusick register struct syscontext *scp; 5826254Sroot { 5836254Sroot register struct a { 5846254Sroot char *target; 5856254Sroot char *linkname; 58638408Smckusick } *uap = (struct a *)scp->sc_ap; 58738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 58837741Smckusick register struct vnode *vp, *xp; 58937741Smckusick int error; 5906254Sroot 59116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 59216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59316694Smckusick ndp->ni_dirp = uap->target; 59437741Smckusick if (error = namei(ndp)) 59537741Smckusick RETURN (error); 59637741Smckusick vp = ndp->ni_vp; 59737741Smckusick if (vp->v_type == VDIR && 59838408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 59937741Smckusick goto out1; 60037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 60237741Smckusick if (error = namei(ndp)) 60337741Smckusick goto out1; 60437741Smckusick xp = ndp->ni_vp; 6056254Sroot if (xp != NULL) { 60637741Smckusick error = EEXIST; 6076254Sroot goto out; 6086254Sroot } 60937741Smckusick xp = ndp->ni_dvp; 61037741Smckusick if (vp->v_mount != xp->v_mount) 61137741Smckusick error = EXDEV; 6126254Sroot out: 61337741Smckusick if (error) 61437741Smckusick VOP_ABORTOP(ndp); 61537741Smckusick else 61637741Smckusick error = VOP_LINK(vp, ndp); 61737741Smckusick out1: 61837741Smckusick vrele(vp); 61937741Smckusick RETURN (error); 6206254Sroot } 6216254Sroot 6226254Sroot /* 6236254Sroot * symlink -- make a symbolic link 6246254Sroot */ 62538408Smckusick symlink(scp) 62638408Smckusick register struct syscontext *scp; 6276254Sroot { 62837741Smckusick struct a { 6296254Sroot char *target; 6306254Sroot char *linkname; 63138408Smckusick } *uap = (struct a *)scp->sc_ap; 63238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 63337741Smckusick register struct vnode *vp; 63437741Smckusick struct vattr vattr; 63537741Smckusick char *target; 63637741Smckusick int error; 6376254Sroot 63816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 63916694Smckusick ndp->ni_dirp = uap->linkname; 64037741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 64137741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 64237741Smckusick goto out1; 64337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64437741Smckusick if (error = namei(ndp)) 64537741Smckusick goto out1; 64637741Smckusick vp = ndp->ni_vp; 64737741Smckusick if (vp) { 64837741Smckusick error = EEXIST; 64937741Smckusick goto out; 6506254Sroot } 65137741Smckusick vp = ndp->ni_dvp; 65237741Smckusick vattr_null(&vattr); 65338408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 65437741Smckusick out: 65537741Smckusick if (error) 65637741Smckusick VOP_ABORTOP(ndp); 65737741Smckusick else 65837741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 65937741Smckusick out1: 66037741Smckusick FREE(target, M_NAMEI); 66137741Smckusick RETURN (error); 6626254Sroot } 6636254Sroot 6646254Sroot /* 6656254Sroot * Unlink system call. 6666254Sroot * Hard to avoid races here, especially 6676254Sroot * in unlinking directories. 6686254Sroot */ 66938408Smckusick unlink(scp) 67038408Smckusick register struct syscontext *scp; 6716254Sroot { 6726254Sroot struct a { 6736254Sroot char *fname; 67438408Smckusick } *uap = (struct a *)scp->sc_ap; 67538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 67637741Smckusick register struct vnode *vp; 67737741Smckusick int error; 6786254Sroot 67937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 68016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68116694Smckusick ndp->ni_dirp = uap->fname; 68237741Smckusick if (error = namei(ndp)) 68337741Smckusick RETURN (error); 68437741Smckusick vp = ndp->ni_vp; 68537741Smckusick if (vp->v_type == VDIR && 68638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6876254Sroot goto out; 6886254Sroot /* 6896254Sroot * Don't unlink a mounted file. 6906254Sroot */ 69137741Smckusick if (vp->v_flag & VROOT) { 69237741Smckusick error = EBUSY; 6936254Sroot goto out; 6946254Sroot } 69537741Smckusick if (vp->v_flag & VTEXT) 69637741Smckusick xrele(vp); /* try once to free text */ 6976254Sroot out: 69837741Smckusick if (error) 69937741Smckusick VOP_ABORTOP(ndp); 7007142Smckusick else 70137741Smckusick error = VOP_REMOVE(ndp); 70237741Smckusick RETURN (error); 7036254Sroot } 7046254Sroot 7056254Sroot /* 7066254Sroot * Seek system call 7076254Sroot */ 70838408Smckusick lseek(scp) 70938408Smckusick register struct syscontext *scp; 7106254Sroot { 7116254Sroot register struct file *fp; 7126254Sroot register struct a { 71337741Smckusick int fdes; 7146254Sroot off_t off; 7156254Sroot int sbase; 71638408Smckusick } *uap = (struct a *)scp->sc_ap; 71737741Smckusick struct vattr vattr; 71837741Smckusick int error; 7196254Sroot 72037741Smckusick if ((unsigned)uap->fdes >= NOFILE || 72138408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 72237741Smckusick RETURN (EBADF); 72337741Smckusick if (fp->f_type != DTYPE_VNODE) 72437741Smckusick RETURN (ESPIPE); 72513878Ssam switch (uap->sbase) { 72613878Ssam 72713878Ssam case L_INCR: 72813878Ssam fp->f_offset += uap->off; 72913878Ssam break; 73013878Ssam 73113878Ssam case L_XTND: 73237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 73338408Smckusick &vattr, scp->sc_cred)) 73437741Smckusick RETURN (error); 73537741Smckusick fp->f_offset = uap->off + vattr.va_size; 73613878Ssam break; 73713878Ssam 73813878Ssam case L_SET: 73913878Ssam fp->f_offset = uap->off; 74013878Ssam break; 74113878Ssam 74213878Ssam default: 74337741Smckusick RETURN (EINVAL); 74413878Ssam } 74538408Smckusick scp->sc_offset = fp->f_offset; 74637741Smckusick RETURN (0); 7476254Sroot } 7486254Sroot 7496254Sroot /* 7506254Sroot * Access system call 7516254Sroot */ 75238408Smckusick saccess(scp) 75338408Smckusick register struct syscontext *scp; 7546254Sroot { 7556254Sroot register struct a { 7566254Sroot char *fname; 7576254Sroot int fmode; 75838408Smckusick } *uap = (struct a *)scp->sc_ap; 75938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76037741Smckusick register struct vnode *vp; 76137741Smckusick int error, mode, svuid, svgid; 7626254Sroot 76338408Smckusick svuid = scp->sc_uid; 76438408Smckusick svgid = scp->sc_gid; 76538408Smckusick scp->sc_uid = scp->sc_ruid; 76638408Smckusick scp->sc_gid = scp->sc_rgid; 76737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 76816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 76916694Smckusick ndp->ni_dirp = uap->fname; 77037741Smckusick if (error = namei(ndp)) 77137741Smckusick goto out1; 77237741Smckusick vp = ndp->ni_vp; 77337741Smckusick /* 77437741Smckusick * fmode == 0 means only check for exist 77537741Smckusick */ 77637741Smckusick if (uap->fmode) { 77737741Smckusick mode = 0; 77837741Smckusick if (uap->fmode & R_OK) 77937741Smckusick mode |= VREAD; 78037741Smckusick if (uap->fmode & W_OK) 78137741Smckusick mode |= VWRITE; 78237741Smckusick if (uap->fmode & X_OK) 78337741Smckusick mode |= VEXEC; 78439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 78538399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7866254Sroot } 78737741Smckusick vput(vp); 78837741Smckusick out1: 78938408Smckusick scp->sc_uid = svuid; 79038408Smckusick scp->sc_gid = svgid; 79137741Smckusick RETURN (error); 7926254Sroot } 7936254Sroot 7946254Sroot /* 7956574Smckusic * Stat system call. This version follows links. 79637Sbill */ 79738408Smckusick stat(scp) 79838408Smckusick struct syscontext *scp; 79937Sbill { 80037Sbill 80138408Smckusick stat1(scp, FOLLOW); 80237Sbill } 80337Sbill 80437Sbill /* 8056574Smckusic * Lstat system call. This version does not follow links. 8065992Swnj */ 80738408Smckusick lstat(scp) 80838408Smckusick struct syscontext *scp; 8095992Swnj { 81012756Ssam 81138408Smckusick stat1(scp, NOFOLLOW); 81212756Ssam } 81312756Ssam 81438408Smckusick stat1(scp, follow) 81538408Smckusick register struct syscontext *scp; 81612756Ssam int follow; 81712756Ssam { 8185992Swnj register struct a { 8195992Swnj char *fname; 82012756Ssam struct stat *ub; 82138408Smckusick } *uap = (struct a *)scp->sc_ap; 82238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 82312756Ssam struct stat sb; 82437741Smckusick int error; 8255992Swnj 82637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 82716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82816694Smckusick ndp->ni_dirp = uap->fname; 82937741Smckusick if (error = namei(ndp)) 83037741Smckusick RETURN (error); 83137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 83237741Smckusick vput(ndp->ni_vp); 83337741Smckusick if (error) 83437741Smckusick RETURN (error); 83537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 83637741Smckusick RETURN (error); 8375992Swnj } 8385992Swnj 8395992Swnj /* 8405992Swnj * Return target name of a symbolic link 84137Sbill */ 84238408Smckusick readlink(scp) 84338408Smckusick register struct syscontext *scp; 8445992Swnj { 8455992Swnj register struct a { 8465992Swnj char *name; 8475992Swnj char *buf; 8485992Swnj int count; 84938408Smckusick } *uap = (struct a *)scp->sc_ap; 85038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85137741Smckusick register struct vnode *vp; 85237741Smckusick struct iovec aiov; 85337741Smckusick struct uio auio; 85437741Smckusick int error; 8555992Swnj 85637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 85716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 85816694Smckusick ndp->ni_dirp = uap->name; 85937741Smckusick if (error = namei(ndp)) 86037741Smckusick RETURN (error); 86137741Smckusick vp = ndp->ni_vp; 86237741Smckusick if (vp->v_type != VLNK) { 86337741Smckusick error = EINVAL; 8645992Swnj goto out; 8655992Swnj } 86637741Smckusick aiov.iov_base = uap->buf; 86737741Smckusick aiov.iov_len = uap->count; 86837741Smckusick auio.uio_iov = &aiov; 86937741Smckusick auio.uio_iovcnt = 1; 87037741Smckusick auio.uio_offset = 0; 87137741Smckusick auio.uio_rw = UIO_READ; 87237741Smckusick auio.uio_segflg = UIO_USERSPACE; 87337741Smckusick auio.uio_resid = uap->count; 87437741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8755992Swnj out: 87637741Smckusick vput(vp); 87738408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 87837741Smckusick RETURN (error); 8795992Swnj } 8805992Swnj 8819167Ssam /* 88238259Smckusick * Change flags of a file given path name. 88338259Smckusick */ 88438408Smckusick chflags(scp) 88538408Smckusick register struct syscontext *scp; 88638259Smckusick { 88738259Smckusick struct a { 88838259Smckusick char *fname; 88938259Smckusick int flags; 89038408Smckusick } *uap = (struct a *)scp->sc_ap; 89138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 89238259Smckusick register struct vnode *vp; 89338259Smckusick struct vattr vattr; 89438259Smckusick int error; 89538259Smckusick 89638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 89738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 89838259Smckusick ndp->ni_dirp = uap->fname; 89938259Smckusick vattr_null(&vattr); 90038259Smckusick vattr.va_flags = uap->flags; 90138259Smckusick if (error = namei(ndp)) 90238259Smckusick RETURN (error); 90338259Smckusick vp = ndp->ni_vp; 90438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 90538259Smckusick error = EROFS; 90638259Smckusick goto out; 90738259Smckusick } 90838259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 90938259Smckusick out: 91038259Smckusick vput(vp); 91138259Smckusick RETURN (error); 91238259Smckusick } 91338259Smckusick 91438259Smckusick /* 91538259Smckusick * Change flags of a file given a file descriptor. 91638259Smckusick */ 91738408Smckusick fchflags(scp) 91838408Smckusick register struct syscontext *scp; 91938259Smckusick { 92038259Smckusick struct a { 92138259Smckusick int fd; 92238259Smckusick int flags; 92338408Smckusick } *uap = (struct a *)scp->sc_ap; 92438259Smckusick struct vattr vattr; 92538259Smckusick struct vnode *vp; 92638259Smckusick struct file *fp; 92738259Smckusick int error; 92838259Smckusick 92938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 93038259Smckusick RETURN (error); 93138259Smckusick vattr_null(&vattr); 93238259Smckusick vattr.va_flags = uap->flags; 93338259Smckusick vp = (struct vnode *)fp->f_data; 93438259Smckusick VOP_LOCK(vp); 93538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 93638259Smckusick error = EROFS; 93738259Smckusick goto out; 93838259Smckusick } 93938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 94038259Smckusick out: 94138259Smckusick VOP_UNLOCK(vp); 94238259Smckusick RETURN (error); 94338259Smckusick } 94438259Smckusick 94538259Smckusick /* 9469167Ssam * Change mode of a file given path name. 9479167Ssam */ 94838408Smckusick chmod(scp) 94938408Smckusick register struct syscontext *scp; 9505992Swnj { 9517701Ssam struct a { 9526254Sroot char *fname; 9536254Sroot int fmode; 95438408Smckusick } *uap = (struct a *)scp->sc_ap; 95538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 95637741Smckusick register struct vnode *vp; 95737741Smckusick struct vattr vattr; 95837741Smckusick int error; 9595992Swnj 96037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 96137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 96237741Smckusick ndp->ni_dirp = uap->fname; 96337741Smckusick vattr_null(&vattr); 96437741Smckusick vattr.va_mode = uap->fmode & 07777; 96537741Smckusick if (error = namei(ndp)) 96637741Smckusick RETURN (error); 96737741Smckusick vp = ndp->ni_vp; 96837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 96937741Smckusick error = EROFS; 97037741Smckusick goto out; 97137741Smckusick } 97237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 97337741Smckusick out: 97437741Smckusick vput(vp); 97537741Smckusick RETURN (error); 9767701Ssam } 9777439Sroot 9789167Ssam /* 9799167Ssam * Change mode of a file given a file descriptor. 9809167Ssam */ 98138408Smckusick fchmod(scp) 98238408Smckusick register struct syscontext *scp; 9837701Ssam { 9847701Ssam struct a { 9857701Ssam int fd; 9867701Ssam int fmode; 98738408Smckusick } *uap = (struct a *)scp->sc_ap; 98837741Smckusick struct vattr vattr; 98937741Smckusick struct vnode *vp; 99037741Smckusick struct file *fp; 99137741Smckusick int error; 9927701Ssam 99338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 99437741Smckusick RETURN (error); 99537741Smckusick vattr_null(&vattr); 99637741Smckusick vattr.va_mode = uap->fmode & 07777; 99737741Smckusick vp = (struct vnode *)fp->f_data; 99837741Smckusick VOP_LOCK(vp); 99937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 100037741Smckusick error = EROFS; 100137741Smckusick goto out; 10027439Sroot } 100337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 100437741Smckusick out: 100537741Smckusick VOP_UNLOCK(vp); 100637741Smckusick RETURN (error); 10075992Swnj } 10085992Swnj 10099167Ssam /* 10109167Ssam * Set ownership given a path name. 10119167Ssam */ 101238408Smckusick chown(scp) 101338408Smckusick register struct syscontext *scp; 101437Sbill { 10157701Ssam struct a { 10166254Sroot char *fname; 10176254Sroot int uid; 10186254Sroot int gid; 101938408Smckusick } *uap = (struct a *)scp->sc_ap; 102038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 102137741Smckusick register struct vnode *vp; 102237741Smckusick struct vattr vattr; 102337741Smckusick int error; 102437Sbill 102537741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 102636614Sbostic ndp->ni_segflg = UIO_USERSPACE; 102736614Sbostic ndp->ni_dirp = uap->fname; 102837741Smckusick vattr_null(&vattr); 102937741Smckusick vattr.va_uid = uap->uid; 103037741Smckusick vattr.va_gid = uap->gid; 103137741Smckusick if (error = namei(ndp)) 103237741Smckusick RETURN (error); 103337741Smckusick vp = ndp->ni_vp; 103437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 103537741Smckusick error = EROFS; 103637741Smckusick goto out; 103737741Smckusick } 103837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 103937741Smckusick out: 104037741Smckusick vput(vp); 104137741Smckusick RETURN (error); 10427701Ssam } 10437439Sroot 10449167Ssam /* 10459167Ssam * Set ownership given a file descriptor. 10469167Ssam */ 104738408Smckusick fchown(scp) 104838408Smckusick register struct syscontext *scp; 10497701Ssam { 10507701Ssam struct a { 10517701Ssam int fd; 10527701Ssam int uid; 10537701Ssam int gid; 105438408Smckusick } *uap = (struct a *)scp->sc_ap; 105537741Smckusick struct vattr vattr; 105637741Smckusick struct vnode *vp; 105737741Smckusick struct file *fp; 105837741Smckusick int error; 10597701Ssam 106038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 106137741Smckusick RETURN (error); 106237741Smckusick vattr_null(&vattr); 106337741Smckusick vattr.va_uid = uap->uid; 106437741Smckusick vattr.va_gid = uap->gid; 106537741Smckusick vp = (struct vnode *)fp->f_data; 106637741Smckusick VOP_LOCK(vp); 106737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 106837741Smckusick error = EROFS; 106937741Smckusick goto out; 107037741Smckusick } 107137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 107237741Smckusick out: 107337741Smckusick VOP_UNLOCK(vp); 107437741Smckusick RETURN (error); 10757701Ssam } 10767701Ssam 107738408Smckusick utimes(scp) 107838408Smckusick register struct syscontext *scp; 107911811Ssam { 108011811Ssam register struct a { 108111811Ssam char *fname; 108211811Ssam struct timeval *tptr; 108338408Smckusick } *uap = (struct a *)scp->sc_ap; 108438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 108537741Smckusick register struct vnode *vp; 108611811Ssam struct timeval tv[2]; 108737741Smckusick struct vattr vattr; 108837741Smckusick int error; 108911811Ssam 109037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 109137741Smckusick RETURN (error); 109237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 109337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 109437741Smckusick ndp->ni_dirp = uap->fname; 109537741Smckusick vattr_null(&vattr); 109637741Smckusick vattr.va_atime = tv[0]; 109737741Smckusick vattr.va_mtime = tv[1]; 109837741Smckusick if (error = namei(ndp)) 109937741Smckusick RETURN (error); 110037741Smckusick vp = ndp->ni_vp; 110137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 110237741Smckusick error = EROFS; 110337741Smckusick goto out; 110421015Smckusick } 110537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 110637741Smckusick out: 110737741Smckusick vput(vp); 110837741Smckusick RETURN (error); 110911811Ssam } 111011811Ssam 11119167Ssam /* 11129167Ssam * Truncate a file given its path name. 11139167Ssam */ 111438408Smckusick truncate(scp) 111538408Smckusick register struct syscontext *scp; 11167701Ssam { 11177701Ssam struct a { 11187701Ssam char *fname; 111926473Skarels off_t length; 112038408Smckusick } *uap = (struct a *)scp->sc_ap; 112138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112237741Smckusick register struct vnode *vp; 112337741Smckusick struct vattr vattr; 112437741Smckusick int error; 11257701Ssam 112637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 112716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 112816694Smckusick ndp->ni_dirp = uap->fname; 112937741Smckusick vattr_null(&vattr); 113037741Smckusick vattr.va_size = uap->length; 113137741Smckusick if (error = namei(ndp)) 113237741Smckusick RETURN (error); 113337741Smckusick vp = ndp->ni_vp; 113437741Smckusick if (vp->v_type == VDIR) { 113537741Smckusick error = EISDIR; 113637741Smckusick goto out; 11377701Ssam } 113838399Smckusick if ((error = vn_writechk(vp)) || 113938399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 114037741Smckusick goto out; 114137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114237741Smckusick out: 114337741Smckusick vput(vp); 114437741Smckusick RETURN (error); 11457701Ssam } 11467701Ssam 11479167Ssam /* 11489167Ssam * Truncate a file given a file descriptor. 11499167Ssam */ 115038408Smckusick ftruncate(scp) 115138408Smckusick register struct syscontext *scp; 11527701Ssam { 11537701Ssam struct a { 11547701Ssam int fd; 115526473Skarels off_t length; 115638408Smckusick } *uap = (struct a *)scp->sc_ap; 115737741Smckusick struct vattr vattr; 115837741Smckusick struct vnode *vp; 11597701Ssam struct file *fp; 116037741Smckusick int error; 11617701Ssam 116238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 116337741Smckusick RETURN (error); 116437741Smckusick if ((fp->f_flag & FWRITE) == 0) 116537741Smckusick RETURN (EINVAL); 116637741Smckusick vattr_null(&vattr); 116737741Smckusick vattr.va_size = uap->length; 116837741Smckusick vp = (struct vnode *)fp->f_data; 116937741Smckusick VOP_LOCK(vp); 117037741Smckusick if (vp->v_type == VDIR) { 117137741Smckusick error = EISDIR; 117237741Smckusick goto out; 11737701Ssam } 117438399Smckusick if (error = vn_writechk(vp)) 117537741Smckusick goto out; 117637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 117737741Smckusick out: 117837741Smckusick VOP_UNLOCK(vp); 117937741Smckusick RETURN (error); 11807701Ssam } 11817701Ssam 11829167Ssam /* 11839167Ssam * Synch an open file. 11849167Ssam */ 118538408Smckusick fsync(scp) 118638408Smckusick register struct syscontext *scp; 11879167Ssam { 11889167Ssam struct a { 11899167Ssam int fd; 119038408Smckusick } *uap = (struct a *)scp->sc_ap; 11919167Ssam struct file *fp; 119237741Smckusick int error; 11939167Ssam 119438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 119537741Smckusick RETURN (error); 119637741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 119737741Smckusick RETURN (error); 11989167Ssam } 11999167Ssam 12009167Ssam /* 12019167Ssam * Rename system call. 12029167Ssam * 12039167Ssam * Source and destination must either both be directories, or both 12049167Ssam * not be directories. If target is a directory, it must be empty. 12059167Ssam */ 120638408Smckusick rename(scp) 120738408Smckusick register struct syscontext *scp; 12087701Ssam { 12097701Ssam struct a { 12107701Ssam char *from; 12117701Ssam char *to; 121238408Smckusick } *uap = (struct a *)scp->sc_ap; 121337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 121438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 121537741Smckusick struct nameidata tond; 121637741Smckusick int error; 12177701Ssam 121837741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 121916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122016694Smckusick ndp->ni_dirp = uap->from; 122137741Smckusick if (error = namei(ndp)) 122237741Smckusick RETURN (error); 122337741Smckusick fvp = ndp->ni_vp; 122438266Smckusick nddup(ndp, &tond); 122537741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 122637741Smckusick tond.ni_segflg = UIO_USERSPACE; 122737741Smckusick tond.ni_dirp = uap->to; 122837741Smckusick error = namei(&tond); 122937741Smckusick tdvp = tond.ni_dvp; 123037741Smckusick tvp = tond.ni_vp; 123137741Smckusick if (tvp != NULL) { 123237741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 123339242Sbostic error = ENOTDIR; 123437741Smckusick goto out; 123537741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 123639242Sbostic error = EISDIR; 123737741Smckusick goto out; 12389167Ssam } 12399167Ssam } 124037741Smckusick if (error) { 124137741Smckusick VOP_ABORTOP(ndp); 124237741Smckusick goto out1; 124337741Smckusick } 124437741Smckusick if (fvp->v_mount != tdvp->v_mount) { 124537741Smckusick error = EXDEV; 12469167Ssam goto out; 124710051Ssam } 124839286Smckusick if (fvp == tdvp) 124937741Smckusick error = EINVAL; 125039286Smckusick /* 125139286Smckusick * If source is the same as the destination, 125239286Smckusick * then there is nothing to do. 125339286Smckusick */ 125439286Smckusick if (fvp == tvp) 125539286Smckusick error = -1; 125637741Smckusick out: 125737741Smckusick if (error) { 125837741Smckusick VOP_ABORTOP(&tond); 125937741Smckusick VOP_ABORTOP(ndp); 12609167Ssam } else { 126137741Smckusick error = VOP_RENAME(ndp, &tond); 12629167Ssam } 126337741Smckusick out1: 126438266Smckusick ndrele(&tond); 126539286Smckusick if (error == -1) 126639286Smckusick RETURN (0); 126737741Smckusick RETURN (error); 12687701Ssam } 12697701Ssam 12707535Sroot /* 127112756Ssam * Mkdir system call 127212756Ssam */ 127338408Smckusick mkdir(scp) 127438408Smckusick register struct syscontext *scp; 127512756Ssam { 127612756Ssam struct a { 127712756Ssam char *name; 127812756Ssam int dmode; 127938408Smckusick } *uap = (struct a *)scp->sc_ap; 128038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 128137741Smckusick register struct vnode *vp; 128237741Smckusick struct vattr vattr; 128337741Smckusick int error; 128412756Ssam 128537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 128616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 128716694Smckusick ndp->ni_dirp = uap->name; 128837741Smckusick if (error = namei(ndp)) 128937741Smckusick RETURN (error); 129037741Smckusick vp = ndp->ni_vp; 129137741Smckusick if (vp != NULL) { 129237741Smckusick VOP_ABORTOP(ndp); 129337741Smckusick RETURN (EEXIST); 129412756Ssam } 129537741Smckusick vattr_null(&vattr); 129637741Smckusick vattr.va_type = VDIR; 129738408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 129837741Smckusick error = VOP_MKDIR(ndp, &vattr); 129938145Smckusick if (!error) 130038145Smckusick vput(ndp->ni_vp); 130137741Smckusick RETURN (error); 130212756Ssam } 130312756Ssam 130412756Ssam /* 130512756Ssam * Rmdir system call. 130612756Ssam */ 130738408Smckusick rmdir(scp) 130838408Smckusick register struct syscontext *scp; 130912756Ssam { 131012756Ssam struct a { 131112756Ssam char *name; 131238408Smckusick } *uap = (struct a *)scp->sc_ap; 131338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 131437741Smckusick register struct vnode *vp; 131537741Smckusick int error; 131612756Ssam 131737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 131816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 131916694Smckusick ndp->ni_dirp = uap->name; 132037741Smckusick if (error = namei(ndp)) 132137741Smckusick RETURN (error); 132237741Smckusick vp = ndp->ni_vp; 132337741Smckusick if (vp->v_type != VDIR) { 132437741Smckusick error = ENOTDIR; 132512756Ssam goto out; 132612756Ssam } 132712756Ssam /* 132837741Smckusick * No rmdir "." please. 132912756Ssam */ 133037741Smckusick if (ndp->ni_dvp == vp) { 133137741Smckusick error = EINVAL; 133212756Ssam goto out; 133312756Ssam } 133412756Ssam /* 133537741Smckusick * Don't unlink a mounted file. 133612756Ssam */ 133737741Smckusick if (vp->v_flag & VROOT) 133837741Smckusick error = EBUSY; 133912756Ssam out: 134037741Smckusick if (error) 134137741Smckusick VOP_ABORTOP(ndp); 134237741Smckusick else 134337741Smckusick error = VOP_RMDIR(ndp); 134437741Smckusick RETURN (error); 134512756Ssam } 134612756Ssam 134737741Smckusick /* 134837741Smckusick * Read a block of directory entries in a file system independent format 134937741Smckusick */ 135038408Smckusick getdirentries(scp) 135138408Smckusick register struct syscontext *scp; 135212756Ssam { 135337741Smckusick register struct a { 135437741Smckusick int fd; 135537741Smckusick char *buf; 135637741Smckusick unsigned count; 135737741Smckusick long *basep; 135838408Smckusick } *uap = (struct a *)scp->sc_ap; 135916540Ssam struct file *fp; 136037741Smckusick struct uio auio; 136137741Smckusick struct iovec aiov; 136238129Smckusick off_t off; 136337741Smckusick int error; 136412756Ssam 136538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 136637741Smckusick RETURN (error); 136737741Smckusick if ((fp->f_flag & FREAD) == 0) 136837741Smckusick RETURN (EBADF); 136937741Smckusick aiov.iov_base = uap->buf; 137037741Smckusick aiov.iov_len = uap->count; 137137741Smckusick auio.uio_iov = &aiov; 137237741Smckusick auio.uio_iovcnt = 1; 137337741Smckusick auio.uio_rw = UIO_READ; 137437741Smckusick auio.uio_segflg = UIO_USERSPACE; 137537741Smckusick auio.uio_resid = uap->count; 137638129Smckusick off = fp->f_offset; 137737741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 137837741Smckusick &(fp->f_offset), fp->f_cred)) 137937741Smckusick RETURN (error); 138038129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 138137741Smckusick sizeof(long)); 138238408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 138337741Smckusick RETURN (error); 138412756Ssam } 138512756Ssam 138612756Ssam /* 138712756Ssam * mode mask for creation of files 138812756Ssam */ 138938408Smckusick umask(scp) 139038408Smckusick register struct syscontext *scp; 139112756Ssam { 139212756Ssam register struct a { 139312756Ssam int mask; 139438408Smckusick } *uap = (struct a *)scp->sc_ap; 139512756Ssam 139638408Smckusick scp->sc_retval1 = scp->sc_cmask; 139738408Smckusick scp->sc_cmask = uap->mask & 07777; 139837741Smckusick RETURN (0); 139912756Ssam } 140037741Smckusick 140138408Smckusick getvnode(ofile, fdes, fpp) 140238408Smckusick struct file *ofile[]; 140337741Smckusick struct file **fpp; 140437741Smckusick int fdes; 140537741Smckusick { 140637741Smckusick struct file *fp; 140737741Smckusick 140838408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 140937741Smckusick return (EBADF); 141037741Smckusick if (fp->f_type != DTYPE_VNODE) 141137741Smckusick return (EINVAL); 141237741Smckusick *fpp = fp; 141337741Smckusick return (0); 141437741Smckusick } 1415