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*39499Smckusick * @(#)vfs_syscalls.c 7.23 (Berkeley) 11/09/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; 27537741Smckusick register struct vnode *vp; 27639464Smckusick register struct mount *mp; 27738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 27837741Smckusick struct statfs sb; 27937741Smckusick int error; 28037741Smckusick 28137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 28237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28337741Smckusick ndp->ni_dirp = uap->path; 28437741Smckusick if (error = namei(ndp)) 28537741Smckusick RETURN (error); 28637741Smckusick vp = ndp->ni_vp; 28739464Smckusick mp = vp->v_mount; 28839464Smckusick if (error = VFS_STATFS(mp, &sb)) 28937741Smckusick goto out; 29039464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29139464Smckusick sb.f_fsid = mp->m_fsid; 29237741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 29337741Smckusick out: 29437741Smckusick vput(vp); 29537741Smckusick RETURN (error); 29637741Smckusick } 29737741Smckusick 29838408Smckusick fstatfs(scp) 29938408Smckusick register struct syscontext *scp; 30037741Smckusick { 30137741Smckusick struct a { 30237741Smckusick int fd; 30337741Smckusick struct statfs *buf; 30438408Smckusick } *uap = (struct a *)scp->sc_ap; 30537741Smckusick struct file *fp; 30639464Smckusick struct mount *mp; 30737741Smckusick struct statfs sb; 30837741Smckusick int error; 30937741Smckusick 31038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 31137741Smckusick RETURN (error); 31239464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31339464Smckusick if (error = VFS_STATFS(mp, &sb)) 31437741Smckusick RETURN (error); 31539464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 31639464Smckusick sb.f_fsid = mp->m_fsid; 31737741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 31837741Smckusick } 31937741Smckusick 32037741Smckusick /* 32138270Smckusick * get statistics on all filesystems 32238270Smckusick */ 32338408Smckusick getfsstat(scp) 32438408Smckusick register struct syscontext *scp; 32538270Smckusick { 32638270Smckusick struct a { 32738270Smckusick struct statfs *buf; 32838270Smckusick long bufsize; 32938408Smckusick } *uap = (struct a *)scp->sc_ap; 33038270Smckusick register struct mount *mp; 33138270Smckusick register struct statfs *sfsp; 33238270Smckusick long count, maxcount, error; 33338270Smckusick 33438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33538270Smckusick sfsp = uap->buf; 33638270Smckusick mp = rootfs; 33738270Smckusick count = 0; 33838270Smckusick do { 33938270Smckusick count++; 34039044Smckusick if (sfsp && count <= maxcount && 34139044Smckusick ((mp->m_flag & M_MLOCK) == 0)) { 34238270Smckusick if (error = VFS_STATFS(mp, sfsp)) 34338270Smckusick RETURN (error); 34439464Smckusick sfsp->f_flags = mp->m_flag & M_VISFLAGMASK; 34539464Smckusick sfsp->f_fsid = mp->m_fsid; 34638270Smckusick sfsp++; 34738270Smckusick } 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); 42538408Smckusick vrele(scp->sc_rdir); 42638408Smckusick scp->sc_rdir = ndp->ni_vp; 42737741Smckusick RETURN (0); 4286254Sroot } 4296254Sroot 43037Sbill /* 43137741Smckusick * Common routine for chroot and chdir. 43237741Smckusick */ 43337741Smckusick chdirec(ndp) 43437741Smckusick register struct nameidata *ndp; 43537741Smckusick { 43637741Smckusick struct vnode *vp; 43737741Smckusick int error; 43837741Smckusick 43937741Smckusick if (error = namei(ndp)) 44037741Smckusick return (error); 44137741Smckusick vp = ndp->ni_vp; 44237741Smckusick if (vp->v_type != VDIR) 44337741Smckusick error = ENOTDIR; 44437741Smckusick else 44538399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44637741Smckusick VOP_UNLOCK(vp); 44737741Smckusick if (error) 44837741Smckusick vrele(vp); 44937741Smckusick return (error); 45037741Smckusick } 45137741Smckusick 45237741Smckusick /* 4536254Sroot * Open system call. 4546254Sroot */ 45538408Smckusick open(scp) 45638408Smckusick register struct syscontext *scp; 4576254Sroot { 45812756Ssam struct a { 4596254Sroot char *fname; 4607701Ssam int mode; 46112756Ssam int crtmode; 46238408Smckusick } *uap = (struct a *) scp->sc_ap; 46338408Smckusick struct nameidata *ndp = &scp->sc_nd; 4646254Sroot 46537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 46637741Smckusick ndp->ni_dirp = uap->fname; 46738408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 46838408Smckusick &scp->sc_retval1)); 4696254Sroot } 4706254Sroot 4716254Sroot /* 4726254Sroot * Creat system call. 4736254Sroot */ 47438408Smckusick creat(scp) 47538408Smckusick register struct syscontext *scp; 4766254Sroot { 47712756Ssam struct a { 4786254Sroot char *fname; 4796254Sroot int fmode; 48038408Smckusick } *uap = (struct a *)scp->sc_ap; 48138408Smckusick struct nameidata *ndp = &scp->sc_nd; 4826254Sroot 48337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48437741Smckusick ndp->ni_dirp = uap->fname; 48538408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 48638408Smckusick ndp, &scp->sc_retval1)); 4876254Sroot } 4886254Sroot 4896254Sroot /* 4906254Sroot * Common code for open and creat. 49112756Ssam * Check permissions, allocate an open file structure, 49212756Ssam * and call the device open routine if any. 4936254Sroot */ 49438408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 49538408Smckusick register struct syscontext *scp; 49637741Smckusick int fmode, cmode; 49737741Smckusick struct nameidata *ndp; 49837741Smckusick int *resultfd; 49912756Ssam { 5006254Sroot register struct file *fp; 50137741Smckusick struct file *nfp; 50237741Smckusick int indx, error; 50337741Smckusick extern struct fileops vnops; 5046254Sroot 50537741Smckusick if (error = falloc(&nfp, &indx)) 50637741Smckusick return (error); 50737741Smckusick fp = nfp; 50838408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 50937741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 51037741Smckusick crfree(fp->f_cred); 51137741Smckusick fp->f_count--; 512*39499Smckusick if (error == -1) /* XXX from fdopen */ 513*39499Smckusick return (0); /* XXX from fdopen */ 514*39499Smckusick scp->sc_ofile[indx] = NULL; 51537741Smckusick return (error); 51612756Ssam } 51737741Smckusick fp->f_flag = fmode & FMASK; 51837741Smckusick fp->f_type = DTYPE_VNODE; 51937741Smckusick fp->f_ops = &vnops; 52037741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 52137741Smckusick if (resultfd) 52237741Smckusick *resultfd = indx; 52337741Smckusick return (0); 5246254Sroot } 5256254Sroot 5266254Sroot /* 5276254Sroot * Mknod system call 5286254Sroot */ 52938408Smckusick mknod(scp) 53038408Smckusick register struct syscontext *scp; 5316254Sroot { 5326254Sroot register struct a { 5336254Sroot char *fname; 5346254Sroot int fmode; 5356254Sroot int dev; 53638408Smckusick } *uap = (struct a *)scp->sc_ap; 53738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 53837741Smckusick register struct vnode *vp; 53937741Smckusick struct vattr vattr; 54037741Smckusick int error; 5416254Sroot 54238408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 54337741Smckusick RETURN (error); 54437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 54516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 54616694Smckusick ndp->ni_dirp = uap->fname; 54737741Smckusick if (error = namei(ndp)) 54837741Smckusick RETURN (error); 54937741Smckusick vp = ndp->ni_vp; 55037741Smckusick if (vp != NULL) { 55137741Smckusick error = EEXIST; 55212756Ssam goto out; 5536254Sroot } 55437741Smckusick vattr_null(&vattr); 55537741Smckusick switch (uap->fmode & IFMT) { 55612756Ssam 55715093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 55837741Smckusick vattr.va_type = VBAD; 55937741Smckusick break; 56012756Ssam case IFCHR: 56137741Smckusick vattr.va_type = VCHR; 56237741Smckusick break; 56312756Ssam case IFBLK: 56437741Smckusick vattr.va_type = VBLK; 56537741Smckusick break; 56637741Smckusick default: 56737741Smckusick error = EINVAL; 56837741Smckusick goto out; 5696254Sroot } 57038408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 57137741Smckusick vattr.va_rdev = uap->dev; 5726254Sroot out: 57337741Smckusick if (error) 57437741Smckusick VOP_ABORTOP(ndp); 57537741Smckusick else 57637741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 57737741Smckusick RETURN (error); 5786254Sroot } 5796254Sroot 5806254Sroot /* 5816254Sroot * link system call 5826254Sroot */ 58338408Smckusick link(scp) 58438408Smckusick register struct syscontext *scp; 5856254Sroot { 5866254Sroot register struct a { 5876254Sroot char *target; 5886254Sroot char *linkname; 58938408Smckusick } *uap = (struct a *)scp->sc_ap; 59038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59137741Smckusick register struct vnode *vp, *xp; 59237741Smckusick int error; 5936254Sroot 59416694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 59516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59616694Smckusick ndp->ni_dirp = uap->target; 59737741Smckusick if (error = namei(ndp)) 59837741Smckusick RETURN (error); 59937741Smckusick vp = ndp->ni_vp; 60037741Smckusick if (vp->v_type == VDIR && 60138408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 60237741Smckusick goto out1; 60337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60416694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 60537741Smckusick if (error = namei(ndp)) 60637741Smckusick goto out1; 60737741Smckusick xp = ndp->ni_vp; 6086254Sroot if (xp != NULL) { 60937741Smckusick error = EEXIST; 6106254Sroot goto out; 6116254Sroot } 61237741Smckusick xp = ndp->ni_dvp; 61337741Smckusick if (vp->v_mount != xp->v_mount) 61437741Smckusick error = EXDEV; 6156254Sroot out: 61637741Smckusick if (error) 61737741Smckusick VOP_ABORTOP(ndp); 61837741Smckusick else 61937741Smckusick error = VOP_LINK(vp, ndp); 62037741Smckusick out1: 62137741Smckusick vrele(vp); 62237741Smckusick RETURN (error); 6236254Sroot } 6246254Sroot 6256254Sroot /* 6266254Sroot * symlink -- make a symbolic link 6276254Sroot */ 62838408Smckusick symlink(scp) 62938408Smckusick register struct syscontext *scp; 6306254Sroot { 63137741Smckusick struct a { 6326254Sroot char *target; 6336254Sroot char *linkname; 63438408Smckusick } *uap = (struct a *)scp->sc_ap; 63538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 63637741Smckusick register struct vnode *vp; 63737741Smckusick struct vattr vattr; 63837741Smckusick char *target; 63937741Smckusick int error; 6406254Sroot 64116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64216694Smckusick ndp->ni_dirp = uap->linkname; 64337741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 64437741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 64537741Smckusick goto out1; 64637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64737741Smckusick if (error = namei(ndp)) 64837741Smckusick goto out1; 64937741Smckusick vp = ndp->ni_vp; 65037741Smckusick if (vp) { 65137741Smckusick error = EEXIST; 65237741Smckusick goto out; 6536254Sroot } 65437741Smckusick vp = ndp->ni_dvp; 65537741Smckusick vattr_null(&vattr); 65638408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 65737741Smckusick out: 65837741Smckusick if (error) 65937741Smckusick VOP_ABORTOP(ndp); 66037741Smckusick else 66137741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 66237741Smckusick out1: 66337741Smckusick FREE(target, M_NAMEI); 66437741Smckusick RETURN (error); 6656254Sroot } 6666254Sroot 6676254Sroot /* 6686254Sroot * Unlink system call. 6696254Sroot * Hard to avoid races here, especially 6706254Sroot * in unlinking directories. 6716254Sroot */ 67238408Smckusick unlink(scp) 67338408Smckusick register struct syscontext *scp; 6746254Sroot { 6756254Sroot struct a { 6766254Sroot char *fname; 67738408Smckusick } *uap = (struct a *)scp->sc_ap; 67838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 67937741Smckusick register struct vnode *vp; 68037741Smckusick int error; 6816254Sroot 68237741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 68316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68416694Smckusick ndp->ni_dirp = uap->fname; 68537741Smckusick if (error = namei(ndp)) 68637741Smckusick RETURN (error); 68737741Smckusick vp = ndp->ni_vp; 68837741Smckusick if (vp->v_type == VDIR && 68938408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6906254Sroot goto out; 6916254Sroot /* 6926254Sroot * Don't unlink a mounted file. 6936254Sroot */ 69437741Smckusick if (vp->v_flag & VROOT) { 69537741Smckusick error = EBUSY; 6966254Sroot goto out; 6976254Sroot } 69837741Smckusick if (vp->v_flag & VTEXT) 69937741Smckusick xrele(vp); /* try once to free text */ 7006254Sroot out: 70137741Smckusick if (error) 70237741Smckusick VOP_ABORTOP(ndp); 7037142Smckusick else 70437741Smckusick error = VOP_REMOVE(ndp); 70537741Smckusick RETURN (error); 7066254Sroot } 7076254Sroot 7086254Sroot /* 7096254Sroot * Seek system call 7106254Sroot */ 71138408Smckusick lseek(scp) 71238408Smckusick register struct syscontext *scp; 7136254Sroot { 7146254Sroot register struct file *fp; 7156254Sroot register struct a { 71637741Smckusick int fdes; 7176254Sroot off_t off; 7186254Sroot int sbase; 71938408Smckusick } *uap = (struct a *)scp->sc_ap; 72037741Smckusick struct vattr vattr; 72137741Smckusick int error; 7226254Sroot 72337741Smckusick if ((unsigned)uap->fdes >= NOFILE || 72438408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 72537741Smckusick RETURN (EBADF); 72637741Smckusick if (fp->f_type != DTYPE_VNODE) 72737741Smckusick RETURN (ESPIPE); 72813878Ssam switch (uap->sbase) { 72913878Ssam 73013878Ssam case L_INCR: 73113878Ssam fp->f_offset += uap->off; 73213878Ssam break; 73313878Ssam 73413878Ssam case L_XTND: 73537741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 73638408Smckusick &vattr, scp->sc_cred)) 73737741Smckusick RETURN (error); 73837741Smckusick fp->f_offset = uap->off + vattr.va_size; 73913878Ssam break; 74013878Ssam 74113878Ssam case L_SET: 74213878Ssam fp->f_offset = uap->off; 74313878Ssam break; 74413878Ssam 74513878Ssam default: 74637741Smckusick RETURN (EINVAL); 74713878Ssam } 74838408Smckusick scp->sc_offset = fp->f_offset; 74937741Smckusick RETURN (0); 7506254Sroot } 7516254Sroot 7526254Sroot /* 7536254Sroot * Access system call 7546254Sroot */ 75538408Smckusick saccess(scp) 75638408Smckusick register struct syscontext *scp; 7576254Sroot { 7586254Sroot register struct a { 7596254Sroot char *fname; 7606254Sroot int fmode; 76138408Smckusick } *uap = (struct a *)scp->sc_ap; 76238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76337741Smckusick register struct vnode *vp; 76437741Smckusick int error, mode, svuid, svgid; 7656254Sroot 76638408Smckusick svuid = scp->sc_uid; 76738408Smckusick svgid = scp->sc_gid; 76838408Smckusick scp->sc_uid = scp->sc_ruid; 76938408Smckusick scp->sc_gid = scp->sc_rgid; 77037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 77116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77216694Smckusick ndp->ni_dirp = uap->fname; 77337741Smckusick if (error = namei(ndp)) 77437741Smckusick goto out1; 77537741Smckusick vp = ndp->ni_vp; 77637741Smckusick /* 77737741Smckusick * fmode == 0 means only check for exist 77837741Smckusick */ 77937741Smckusick if (uap->fmode) { 78037741Smckusick mode = 0; 78137741Smckusick if (uap->fmode & R_OK) 78237741Smckusick mode |= VREAD; 78337741Smckusick if (uap->fmode & W_OK) 78437741Smckusick mode |= VWRITE; 78537741Smckusick if (uap->fmode & X_OK) 78637741Smckusick mode |= VEXEC; 78738399Smckusick if ((error = vn_writechk(vp)) == 0) 78838399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7896254Sroot } 79037741Smckusick vput(vp); 79137741Smckusick out1: 79238408Smckusick scp->sc_uid = svuid; 79338408Smckusick scp->sc_gid = svgid; 79437741Smckusick RETURN (error); 7956254Sroot } 7966254Sroot 7976254Sroot /* 7986574Smckusic * Stat system call. This version follows links. 79937Sbill */ 80038408Smckusick stat(scp) 80138408Smckusick struct syscontext *scp; 80237Sbill { 80337Sbill 80438408Smckusick stat1(scp, FOLLOW); 80537Sbill } 80637Sbill 80737Sbill /* 8086574Smckusic * Lstat system call. This version does not follow links. 8095992Swnj */ 81038408Smckusick lstat(scp) 81138408Smckusick struct syscontext *scp; 8125992Swnj { 81312756Ssam 81438408Smckusick stat1(scp, NOFOLLOW); 81512756Ssam } 81612756Ssam 81738408Smckusick stat1(scp, follow) 81838408Smckusick register struct syscontext *scp; 81912756Ssam int follow; 82012756Ssam { 8215992Swnj register struct a { 8225992Swnj char *fname; 82312756Ssam struct stat *ub; 82438408Smckusick } *uap = (struct a *)scp->sc_ap; 82538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 82612756Ssam struct stat sb; 82737741Smckusick int error; 8285992Swnj 82937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 83016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83116694Smckusick ndp->ni_dirp = uap->fname; 83237741Smckusick if (error = namei(ndp)) 83337741Smckusick RETURN (error); 83437741Smckusick error = vn_stat(ndp->ni_vp, &sb); 83537741Smckusick vput(ndp->ni_vp); 83637741Smckusick if (error) 83737741Smckusick RETURN (error); 83837741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 83937741Smckusick RETURN (error); 8405992Swnj } 8415992Swnj 8425992Swnj /* 8435992Swnj * Return target name of a symbolic link 84437Sbill */ 84538408Smckusick readlink(scp) 84638408Smckusick register struct syscontext *scp; 8475992Swnj { 8485992Swnj register struct a { 8495992Swnj char *name; 8505992Swnj char *buf; 8515992Swnj int count; 85238408Smckusick } *uap = (struct a *)scp->sc_ap; 85338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85437741Smckusick register struct vnode *vp; 85537741Smckusick struct iovec aiov; 85637741Smckusick struct uio auio; 85737741Smckusick int error; 8585992Swnj 85937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 86016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86116694Smckusick ndp->ni_dirp = uap->name; 86237741Smckusick if (error = namei(ndp)) 86337741Smckusick RETURN (error); 86437741Smckusick vp = ndp->ni_vp; 86537741Smckusick if (vp->v_type != VLNK) { 86637741Smckusick error = EINVAL; 8675992Swnj goto out; 8685992Swnj } 86937741Smckusick aiov.iov_base = uap->buf; 87037741Smckusick aiov.iov_len = uap->count; 87137741Smckusick auio.uio_iov = &aiov; 87237741Smckusick auio.uio_iovcnt = 1; 87337741Smckusick auio.uio_offset = 0; 87437741Smckusick auio.uio_rw = UIO_READ; 87537741Smckusick auio.uio_segflg = UIO_USERSPACE; 87637741Smckusick auio.uio_resid = uap->count; 87737741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8785992Swnj out: 87937741Smckusick vput(vp); 88038408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 88137741Smckusick RETURN (error); 8825992Swnj } 8835992Swnj 8849167Ssam /* 88538259Smckusick * Change flags of a file given path name. 88638259Smckusick */ 88738408Smckusick chflags(scp) 88838408Smckusick register struct syscontext *scp; 88938259Smckusick { 89038259Smckusick struct a { 89138259Smckusick char *fname; 89238259Smckusick int flags; 89338408Smckusick } *uap = (struct a *)scp->sc_ap; 89438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 89538259Smckusick register struct vnode *vp; 89638259Smckusick struct vattr vattr; 89738259Smckusick int error; 89838259Smckusick 89938259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 90038259Smckusick ndp->ni_segflg = UIO_USERSPACE; 90138259Smckusick ndp->ni_dirp = uap->fname; 90238259Smckusick vattr_null(&vattr); 90338259Smckusick vattr.va_flags = uap->flags; 90438259Smckusick if (error = namei(ndp)) 90538259Smckusick RETURN (error); 90638259Smckusick vp = ndp->ni_vp; 90738259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 90838259Smckusick error = EROFS; 90938259Smckusick goto out; 91038259Smckusick } 91138259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 91238259Smckusick out: 91338259Smckusick vput(vp); 91438259Smckusick RETURN (error); 91538259Smckusick } 91638259Smckusick 91738259Smckusick /* 91838259Smckusick * Change flags of a file given a file descriptor. 91938259Smckusick */ 92038408Smckusick fchflags(scp) 92138408Smckusick register struct syscontext *scp; 92238259Smckusick { 92338259Smckusick struct a { 92438259Smckusick int fd; 92538259Smckusick int flags; 92638408Smckusick } *uap = (struct a *)scp->sc_ap; 92738259Smckusick struct vattr vattr; 92838259Smckusick struct vnode *vp; 92938259Smckusick struct file *fp; 93038259Smckusick int error; 93138259Smckusick 93238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 93338259Smckusick RETURN (error); 93438259Smckusick vattr_null(&vattr); 93538259Smckusick vattr.va_flags = uap->flags; 93638259Smckusick vp = (struct vnode *)fp->f_data; 93738259Smckusick VOP_LOCK(vp); 93838259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 93938259Smckusick error = EROFS; 94038259Smckusick goto out; 94138259Smckusick } 94238259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 94338259Smckusick out: 94438259Smckusick VOP_UNLOCK(vp); 94538259Smckusick RETURN (error); 94638259Smckusick } 94738259Smckusick 94838259Smckusick /* 9499167Ssam * Change mode of a file given path name. 9509167Ssam */ 95138408Smckusick chmod(scp) 95238408Smckusick register struct syscontext *scp; 9535992Swnj { 9547701Ssam struct a { 9556254Sroot char *fname; 9566254Sroot int fmode; 95738408Smckusick } *uap = (struct a *)scp->sc_ap; 95838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 95937741Smckusick register struct vnode *vp; 96037741Smckusick struct vattr vattr; 96137741Smckusick int error; 9625992Swnj 96337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 96437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 96537741Smckusick ndp->ni_dirp = uap->fname; 96637741Smckusick vattr_null(&vattr); 96737741Smckusick vattr.va_mode = uap->fmode & 07777; 96837741Smckusick if (error = namei(ndp)) 96937741Smckusick RETURN (error); 97037741Smckusick vp = ndp->ni_vp; 97137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97237741Smckusick error = EROFS; 97337741Smckusick goto out; 97437741Smckusick } 97537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 97637741Smckusick out: 97737741Smckusick vput(vp); 97837741Smckusick RETURN (error); 9797701Ssam } 9807439Sroot 9819167Ssam /* 9829167Ssam * Change mode of a file given a file descriptor. 9839167Ssam */ 98438408Smckusick fchmod(scp) 98538408Smckusick register struct syscontext *scp; 9867701Ssam { 9877701Ssam struct a { 9887701Ssam int fd; 9897701Ssam int fmode; 99038408Smckusick } *uap = (struct a *)scp->sc_ap; 99137741Smckusick struct vattr vattr; 99237741Smckusick struct vnode *vp; 99337741Smckusick struct file *fp; 99437741Smckusick int error; 9957701Ssam 99638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 99737741Smckusick RETURN (error); 99837741Smckusick vattr_null(&vattr); 99937741Smckusick vattr.va_mode = uap->fmode & 07777; 100037741Smckusick vp = (struct vnode *)fp->f_data; 100137741Smckusick VOP_LOCK(vp); 100237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 100337741Smckusick error = EROFS; 100437741Smckusick goto out; 10057439Sroot } 100637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 100737741Smckusick out: 100837741Smckusick VOP_UNLOCK(vp); 100937741Smckusick RETURN (error); 10105992Swnj } 10115992Swnj 10129167Ssam /* 10139167Ssam * Set ownership given a path name. 10149167Ssam */ 101538408Smckusick chown(scp) 101638408Smckusick register struct syscontext *scp; 101737Sbill { 10187701Ssam struct a { 10196254Sroot char *fname; 10206254Sroot int uid; 10216254Sroot int gid; 102238408Smckusick } *uap = (struct a *)scp->sc_ap; 102338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 102437741Smckusick register struct vnode *vp; 102537741Smckusick struct vattr vattr; 102637741Smckusick int error; 102737Sbill 102837741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 102936614Sbostic ndp->ni_segflg = UIO_USERSPACE; 103036614Sbostic ndp->ni_dirp = uap->fname; 103137741Smckusick vattr_null(&vattr); 103237741Smckusick vattr.va_uid = uap->uid; 103337741Smckusick vattr.va_gid = uap->gid; 103437741Smckusick if (error = namei(ndp)) 103537741Smckusick RETURN (error); 103637741Smckusick vp = ndp->ni_vp; 103737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 103837741Smckusick error = EROFS; 103937741Smckusick goto out; 104037741Smckusick } 104137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 104237741Smckusick out: 104337741Smckusick vput(vp); 104437741Smckusick RETURN (error); 10457701Ssam } 10467439Sroot 10479167Ssam /* 10489167Ssam * Set ownership given a file descriptor. 10499167Ssam */ 105038408Smckusick fchown(scp) 105138408Smckusick register struct syscontext *scp; 10527701Ssam { 10537701Ssam struct a { 10547701Ssam int fd; 10557701Ssam int uid; 10567701Ssam int gid; 105738408Smckusick } *uap = (struct a *)scp->sc_ap; 105837741Smckusick struct vattr vattr; 105937741Smckusick struct vnode *vp; 106037741Smckusick struct file *fp; 106137741Smckusick int error; 10627701Ssam 106338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 106437741Smckusick RETURN (error); 106537741Smckusick vattr_null(&vattr); 106637741Smckusick vattr.va_uid = uap->uid; 106737741Smckusick vattr.va_gid = uap->gid; 106837741Smckusick vp = (struct vnode *)fp->f_data; 106937741Smckusick VOP_LOCK(vp); 107037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 107137741Smckusick error = EROFS; 107237741Smckusick goto out; 107337741Smckusick } 107437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 107537741Smckusick out: 107637741Smckusick VOP_UNLOCK(vp); 107737741Smckusick RETURN (error); 10787701Ssam } 10797701Ssam 108038408Smckusick utimes(scp) 108138408Smckusick register struct syscontext *scp; 108211811Ssam { 108311811Ssam register struct a { 108411811Ssam char *fname; 108511811Ssam struct timeval *tptr; 108638408Smckusick } *uap = (struct a *)scp->sc_ap; 108738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 108837741Smckusick register struct vnode *vp; 108911811Ssam struct timeval tv[2]; 109037741Smckusick struct vattr vattr; 109137741Smckusick int error; 109211811Ssam 109337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 109437741Smckusick RETURN (error); 109537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 109637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 109737741Smckusick ndp->ni_dirp = uap->fname; 109837741Smckusick vattr_null(&vattr); 109937741Smckusick vattr.va_atime = tv[0]; 110037741Smckusick vattr.va_mtime = tv[1]; 110137741Smckusick if (error = namei(ndp)) 110237741Smckusick RETURN (error); 110337741Smckusick vp = ndp->ni_vp; 110437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 110537741Smckusick error = EROFS; 110637741Smckusick goto out; 110721015Smckusick } 110837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 110937741Smckusick out: 111037741Smckusick vput(vp); 111137741Smckusick RETURN (error); 111211811Ssam } 111311811Ssam 11149167Ssam /* 11159167Ssam * Truncate a file given its path name. 11169167Ssam */ 111738408Smckusick truncate(scp) 111838408Smckusick register struct syscontext *scp; 11197701Ssam { 11207701Ssam struct a { 11217701Ssam char *fname; 112226473Skarels off_t length; 112338408Smckusick } *uap = (struct a *)scp->sc_ap; 112438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112537741Smckusick register struct vnode *vp; 112637741Smckusick struct vattr vattr; 112737741Smckusick int error; 11287701Ssam 112937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113116694Smckusick ndp->ni_dirp = uap->fname; 113237741Smckusick vattr_null(&vattr); 113337741Smckusick vattr.va_size = uap->length; 113437741Smckusick if (error = namei(ndp)) 113537741Smckusick RETURN (error); 113637741Smckusick vp = ndp->ni_vp; 113737741Smckusick if (vp->v_type == VDIR) { 113837741Smckusick error = EISDIR; 113937741Smckusick goto out; 11407701Ssam } 114138399Smckusick if ((error = vn_writechk(vp)) || 114238399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 114337741Smckusick goto out; 114437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114537741Smckusick out: 114637741Smckusick vput(vp); 114737741Smckusick RETURN (error); 11487701Ssam } 11497701Ssam 11509167Ssam /* 11519167Ssam * Truncate a file given a file descriptor. 11529167Ssam */ 115338408Smckusick ftruncate(scp) 115438408Smckusick register struct syscontext *scp; 11557701Ssam { 11567701Ssam struct a { 11577701Ssam int fd; 115826473Skarels off_t length; 115938408Smckusick } *uap = (struct a *)scp->sc_ap; 116037741Smckusick struct vattr vattr; 116137741Smckusick struct vnode *vp; 11627701Ssam struct file *fp; 116337741Smckusick int error; 11647701Ssam 116538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 116637741Smckusick RETURN (error); 116737741Smckusick if ((fp->f_flag & FWRITE) == 0) 116837741Smckusick RETURN (EINVAL); 116937741Smckusick vattr_null(&vattr); 117037741Smckusick vattr.va_size = uap->length; 117137741Smckusick vp = (struct vnode *)fp->f_data; 117237741Smckusick VOP_LOCK(vp); 117337741Smckusick if (vp->v_type == VDIR) { 117437741Smckusick error = EISDIR; 117537741Smckusick goto out; 11767701Ssam } 117738399Smckusick if (error = vn_writechk(vp)) 117837741Smckusick goto out; 117937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118037741Smckusick out: 118137741Smckusick VOP_UNLOCK(vp); 118237741Smckusick RETURN (error); 11837701Ssam } 11847701Ssam 11859167Ssam /* 11869167Ssam * Synch an open file. 11879167Ssam */ 118838408Smckusick fsync(scp) 118938408Smckusick register struct syscontext *scp; 11909167Ssam { 11919167Ssam struct a { 11929167Ssam int fd; 119338408Smckusick } *uap = (struct a *)scp->sc_ap; 11949167Ssam struct file *fp; 119537741Smckusick int error; 11969167Ssam 119738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 119837741Smckusick RETURN (error); 119937741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 120037741Smckusick RETURN (error); 12019167Ssam } 12029167Ssam 12039167Ssam /* 12049167Ssam * Rename system call. 12059167Ssam * 12069167Ssam * Source and destination must either both be directories, or both 12079167Ssam * not be directories. If target is a directory, it must be empty. 12089167Ssam */ 120938408Smckusick rename(scp) 121038408Smckusick register struct syscontext *scp; 12117701Ssam { 12127701Ssam struct a { 12137701Ssam char *from; 12147701Ssam char *to; 121538408Smckusick } *uap = (struct a *)scp->sc_ap; 121637741Smckusick register struct vnode *tvp, *fvp, *tdvp; 121738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 121837741Smckusick struct nameidata tond; 121937741Smckusick int error; 12207701Ssam 122137741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 122216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122316694Smckusick ndp->ni_dirp = uap->from; 122437741Smckusick if (error = namei(ndp)) 122537741Smckusick RETURN (error); 122637741Smckusick fvp = ndp->ni_vp; 122738266Smckusick nddup(ndp, &tond); 122837741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 122937741Smckusick tond.ni_segflg = UIO_USERSPACE; 123037741Smckusick tond.ni_dirp = uap->to; 123137741Smckusick error = namei(&tond); 123237741Smckusick tdvp = tond.ni_dvp; 123337741Smckusick tvp = tond.ni_vp; 123437741Smckusick if (tvp != NULL) { 123537741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 123639242Sbostic error = ENOTDIR; 123737741Smckusick goto out; 123837741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 123939242Sbostic error = EISDIR; 124037741Smckusick goto out; 12419167Ssam } 12429167Ssam } 124337741Smckusick if (error) { 124437741Smckusick VOP_ABORTOP(ndp); 124537741Smckusick goto out1; 124637741Smckusick } 124737741Smckusick if (fvp->v_mount != tdvp->v_mount) { 124837741Smckusick error = EXDEV; 12499167Ssam goto out; 125010051Ssam } 125139286Smckusick if (fvp == tdvp) 125237741Smckusick error = EINVAL; 125339286Smckusick /* 125439286Smckusick * If source is the same as the destination, 125539286Smckusick * then there is nothing to do. 125639286Smckusick */ 125739286Smckusick if (fvp == tvp) 125839286Smckusick error = -1; 125937741Smckusick out: 126037741Smckusick if (error) { 126137741Smckusick VOP_ABORTOP(&tond); 126237741Smckusick VOP_ABORTOP(ndp); 12639167Ssam } else { 126437741Smckusick error = VOP_RENAME(ndp, &tond); 12659167Ssam } 126637741Smckusick out1: 126738266Smckusick ndrele(&tond); 126839286Smckusick if (error == -1) 126939286Smckusick RETURN (0); 127037741Smckusick RETURN (error); 12717701Ssam } 12727701Ssam 12737535Sroot /* 127412756Ssam * Mkdir system call 127512756Ssam */ 127638408Smckusick mkdir(scp) 127738408Smckusick register struct syscontext *scp; 127812756Ssam { 127912756Ssam struct a { 128012756Ssam char *name; 128112756Ssam int dmode; 128238408Smckusick } *uap = (struct a *)scp->sc_ap; 128338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 128437741Smckusick register struct vnode *vp; 128537741Smckusick struct vattr vattr; 128637741Smckusick int error; 128712756Ssam 128837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 128916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 129016694Smckusick ndp->ni_dirp = uap->name; 129137741Smckusick if (error = namei(ndp)) 129237741Smckusick RETURN (error); 129337741Smckusick vp = ndp->ni_vp; 129437741Smckusick if (vp != NULL) { 129537741Smckusick VOP_ABORTOP(ndp); 129637741Smckusick RETURN (EEXIST); 129712756Ssam } 129837741Smckusick vattr_null(&vattr); 129937741Smckusick vattr.va_type = VDIR; 130038408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 130137741Smckusick error = VOP_MKDIR(ndp, &vattr); 130238145Smckusick if (!error) 130338145Smckusick vput(ndp->ni_vp); 130437741Smckusick RETURN (error); 130512756Ssam } 130612756Ssam 130712756Ssam /* 130812756Ssam * Rmdir system call. 130912756Ssam */ 131038408Smckusick rmdir(scp) 131138408Smckusick register struct syscontext *scp; 131212756Ssam { 131312756Ssam struct a { 131412756Ssam char *name; 131538408Smckusick } *uap = (struct a *)scp->sc_ap; 131638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 131737741Smckusick register struct vnode *vp; 131837741Smckusick int error; 131912756Ssam 132037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 132116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132216694Smckusick ndp->ni_dirp = uap->name; 132337741Smckusick if (error = namei(ndp)) 132437741Smckusick RETURN (error); 132537741Smckusick vp = ndp->ni_vp; 132637741Smckusick if (vp->v_type != VDIR) { 132737741Smckusick error = ENOTDIR; 132812756Ssam goto out; 132912756Ssam } 133012756Ssam /* 133137741Smckusick * No rmdir "." please. 133212756Ssam */ 133337741Smckusick if (ndp->ni_dvp == vp) { 133437741Smckusick error = EINVAL; 133512756Ssam goto out; 133612756Ssam } 133712756Ssam /* 133837741Smckusick * Don't unlink a mounted file. 133912756Ssam */ 134037741Smckusick if (vp->v_flag & VROOT) 134137741Smckusick error = EBUSY; 134212756Ssam out: 134337741Smckusick if (error) 134437741Smckusick VOP_ABORTOP(ndp); 134537741Smckusick else 134637741Smckusick error = VOP_RMDIR(ndp); 134737741Smckusick RETURN (error); 134812756Ssam } 134912756Ssam 135037741Smckusick /* 135137741Smckusick * Read a block of directory entries in a file system independent format 135237741Smckusick */ 135338408Smckusick getdirentries(scp) 135438408Smckusick register struct syscontext *scp; 135512756Ssam { 135637741Smckusick register struct a { 135737741Smckusick int fd; 135837741Smckusick char *buf; 135937741Smckusick unsigned count; 136037741Smckusick long *basep; 136138408Smckusick } *uap = (struct a *)scp->sc_ap; 136216540Ssam struct file *fp; 136337741Smckusick struct uio auio; 136437741Smckusick struct iovec aiov; 136538129Smckusick off_t off; 136637741Smckusick int error; 136712756Ssam 136838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 136937741Smckusick RETURN (error); 137037741Smckusick if ((fp->f_flag & FREAD) == 0) 137137741Smckusick RETURN (EBADF); 137237741Smckusick aiov.iov_base = uap->buf; 137337741Smckusick aiov.iov_len = uap->count; 137437741Smckusick auio.uio_iov = &aiov; 137537741Smckusick auio.uio_iovcnt = 1; 137637741Smckusick auio.uio_rw = UIO_READ; 137737741Smckusick auio.uio_segflg = UIO_USERSPACE; 137837741Smckusick auio.uio_resid = uap->count; 137938129Smckusick off = fp->f_offset; 138037741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 138137741Smckusick &(fp->f_offset), fp->f_cred)) 138237741Smckusick RETURN (error); 138338129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 138437741Smckusick sizeof(long)); 138538408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 138637741Smckusick RETURN (error); 138712756Ssam } 138812756Ssam 138912756Ssam /* 139012756Ssam * mode mask for creation of files 139112756Ssam */ 139238408Smckusick umask(scp) 139338408Smckusick register struct syscontext *scp; 139412756Ssam { 139512756Ssam register struct a { 139612756Ssam int mask; 139738408Smckusick } *uap = (struct a *)scp->sc_ap; 139812756Ssam 139938408Smckusick scp->sc_retval1 = scp->sc_cmask; 140038408Smckusick scp->sc_cmask = uap->mask & 07777; 140137741Smckusick RETURN (0); 140212756Ssam } 140337741Smckusick 140438408Smckusick getvnode(ofile, fdes, fpp) 140538408Smckusick struct file *ofile[]; 140637741Smckusick struct file **fpp; 140737741Smckusick int fdes; 140837741Smckusick { 140937741Smckusick struct file *fp; 141037741Smckusick 141138408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 141237741Smckusick return (EBADF); 141337741Smckusick if (fp->f_type != DTYPE_VNODE) 141437741Smckusick return (EINVAL); 141537741Smckusick *fpp = fp; 141637741Smckusick return (0); 141737741Smckusick } 1418