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*40110Smckusick * @(#)vfs_syscalls.c 7.37 (Berkeley) 02/16/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "../ufs/inode.h" 2837741Smckusick #include "mount.h" 2917101Sbloom #include "proc.h" 3017101Sbloom #include "uio.h" 3137741Smckusick #include "malloc.h" 3237Sbill 3339797Smckusick #undef RETURN 3439797Smckusick #define RETURN(val) { scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; } 3539797Smckusick 3637741Smckusick /* 3737741Smckusick * Virtual File System System Calls 3837741Smckusick */ 3912756Ssam 409167Ssam /* 4137741Smckusick * mount system call 429167Ssam */ 4338408Smckusick mount(scp) 4438408Smckusick register struct syscontext *scp; 456254Sroot { 4637741Smckusick register struct a { 4737741Smckusick int type; 4837741Smckusick char *dir; 4937741Smckusick int flags; 5037741Smckusick caddr_t data; 5138408Smckusick } *uap = (struct a *)scp->sc_ap; 5238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5339335Smckusick register struct vnode *vp; 5439335Smckusick register struct mount *mp; 5537741Smckusick int error; 566254Sroot 5737741Smckusick /* 5837741Smckusick * Must be super user 5937741Smckusick */ 6038408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 6137741Smckusick RETURN (error); 6237741Smckusick /* 6337741Smckusick * Get vnode to be covered 6437741Smckusick */ 6537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6737741Smckusick ndp->ni_dirp = uap->dir; 6837741Smckusick if (error = namei(ndp)) 6937741Smckusick RETURN (error); 7037741Smckusick vp = ndp->ni_vp; 7139335Smckusick if (uap->flags & M_UPDATE) { 7239335Smckusick if ((vp->v_flag & VROOT) == 0) { 7339335Smckusick vput(vp); 7439335Smckusick RETURN (EINVAL); 7539335Smckusick } 7639335Smckusick mp = vp->v_mount; 7739335Smckusick /* 7839335Smckusick * We allow going from read-only to read-write, 7939335Smckusick * but not from read-write to read-only. 8039335Smckusick */ 8139335Smckusick if ((mp->m_flag & M_RDONLY) == 0 && 8239335Smckusick (uap->flags & M_RDONLY) != 0) { 8339335Smckusick vput(vp); 8439335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8539335Smckusick } 8639335Smckusick mp->m_flag |= M_UPDATE; 8739335Smckusick VOP_UNLOCK(vp); 8839335Smckusick goto update; 8939335Smckusick } 9039665Smckusick vinvalbuf(vp, 1); 9139805Smckusick if (vp->v_usecount != 1) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (EBUSY); 9437741Smckusick } 9537741Smckusick if (vp->v_type != VDIR) { 9637741Smckusick vput(vp); 9737741Smckusick RETURN (ENOTDIR); 9837741Smckusick } 9939741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10037741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10137741Smckusick vput(vp); 10237741Smckusick RETURN (ENODEV); 10337741Smckusick } 10437741Smckusick 10537741Smckusick /* 10639335Smckusick * Allocate and initialize the file system. 10737741Smckusick */ 10837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10937741Smckusick M_MOUNT, M_WAITOK); 11037741Smckusick mp->m_op = vfssw[uap->type]; 11137741Smckusick mp->m_flag = 0; 11237741Smckusick mp->m_exroot = 0; 11339381Smckusick mp->m_mounth = (struct vnode *)0; 11439335Smckusick if (error = vfs_lock(mp)) { 11539335Smckusick free((caddr_t)mp, M_MOUNT); 11639335Smckusick vput(vp); 11739335Smckusick RETURN (error); 11839335Smckusick } 11939335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12039335Smckusick vfs_unlock(mp); 12139335Smckusick free((caddr_t)mp, M_MOUNT); 12239335Smckusick vput(vp); 12339335Smckusick RETURN (EBUSY); 12439335Smckusick } 12539335Smckusick vp->v_mountedhere = mp; 12639335Smckusick mp->m_vnodecovered = vp; 12739335Smckusick update: 12839335Smckusick /* 12939335Smckusick * Set the mount level flags. 13039335Smckusick */ 13139335Smckusick if (uap->flags & M_RDONLY) 13239335Smckusick mp->m_flag |= M_RDONLY; 13339335Smckusick else 13439335Smckusick mp->m_flag &= ~M_RDONLY; 13539335Smckusick if (uap->flags & M_NOSUID) 13639335Smckusick mp->m_flag |= M_NOSUID; 13739335Smckusick else 13839335Smckusick mp->m_flag &= ~M_NOSUID; 13939335Smckusick if (uap->flags & M_NOEXEC) 14039335Smckusick mp->m_flag |= M_NOEXEC; 14139335Smckusick else 14239335Smckusick mp->m_flag &= ~M_NOEXEC; 14339335Smckusick if (uap->flags & M_NODEV) 14439335Smckusick mp->m_flag |= M_NODEV; 14539335Smckusick else 14639335Smckusick mp->m_flag &= ~M_NODEV; 14739335Smckusick if (uap->flags & M_SYNCHRONOUS) 14839335Smckusick mp->m_flag |= M_SYNCHRONOUS; 14939335Smckusick else 15039335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15139335Smckusick /* 15239335Smckusick * Mount the filesystem. 15339335Smckusick */ 15439335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15539335Smckusick if (mp->m_flag & M_UPDATE) { 15639335Smckusick mp->m_flag &= ~M_UPDATE; 15739335Smckusick vrele(vp); 15839335Smckusick RETURN (error); 15939335Smckusick } 160*40110Smckusick /* 161*40110Smckusick * Put the new filesystem on the mount list after root. 162*40110Smckusick */ 163*40110Smckusick mp->m_next = rootfs->m_next; 164*40110Smckusick mp->m_prev = rootfs; 165*40110Smckusick rootfs->m_next = mp; 166*40110Smckusick mp->m_next->m_prev = mp; 16737741Smckusick cache_purge(vp); 16837741Smckusick if (!error) { 16939335Smckusick VOP_UNLOCK(vp); 17037741Smckusick vfs_unlock(mp); 17139044Smckusick error = VFS_START(mp, 0); 17237741Smckusick } else { 17337741Smckusick vfs_remove(mp); 17437741Smckusick free((caddr_t)mp, M_MOUNT); 17539335Smckusick vput(vp); 17637741Smckusick } 17737741Smckusick RETURN (error); 1786254Sroot } 1796254Sroot 1809167Ssam /* 18137741Smckusick * Unmount system call. 18237741Smckusick * 18337741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18437741Smckusick * not special file (as before). 1859167Ssam */ 18638408Smckusick unmount(scp) 18738408Smckusick register struct syscontext *scp; 1886254Sroot { 18937741Smckusick struct a { 19037741Smckusick char *pathp; 19137741Smckusick int flags; 19238408Smckusick } *uap = (struct a *)scp->sc_ap; 19337741Smckusick register struct vnode *vp; 19438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19539356Smckusick struct mount *mp; 19637741Smckusick int error; 1976254Sroot 19837741Smckusick /* 19937741Smckusick * Must be super user 20037741Smckusick */ 20138408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 20237741Smckusick RETURN (error); 20337741Smckusick 20437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20637741Smckusick ndp->ni_dirp = uap->pathp; 20737741Smckusick if (error = namei(ndp)) 20837741Smckusick RETURN (error); 20937741Smckusick vp = ndp->ni_vp; 21037741Smckusick /* 21137741Smckusick * Must be the root of the filesystem 21237741Smckusick */ 21337741Smckusick if ((vp->v_flag & VROOT) == 0) { 21437741Smckusick vput(vp); 21537741Smckusick RETURN (EINVAL); 21637741Smckusick } 21737741Smckusick mp = vp->v_mount; 21837741Smckusick vput(vp); 21939356Smckusick RETURN (dounmount(mp, uap->flags)); 22039356Smckusick } 22139356Smckusick 22239356Smckusick /* 22339356Smckusick * Do an unmount. 22439356Smckusick */ 22539356Smckusick dounmount(mp, flags) 22639356Smckusick register struct mount *mp; 22739356Smckusick int flags; 22839356Smckusick { 22939356Smckusick struct vnode *coveredvp; 23039356Smckusick int error; 23139356Smckusick 23237741Smckusick coveredvp = mp->m_vnodecovered; 23337741Smckusick if (error = vfs_lock(mp)) 23439356Smckusick return (error); 23537741Smckusick 23637741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23737741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23837741Smckusick VFS_SYNC(mp, MNT_WAIT); 23937741Smckusick 24039356Smckusick error = VFS_UNMOUNT(mp, flags); 24137741Smckusick if (error) { 24237741Smckusick vfs_unlock(mp); 24337741Smckusick } else { 24437741Smckusick vrele(coveredvp); 24537741Smckusick vfs_remove(mp); 24637741Smckusick free((caddr_t)mp, M_MOUNT); 24737741Smckusick } 24839356Smckusick return (error); 2496254Sroot } 2506254Sroot 2519167Ssam /* 25237741Smckusick * Sync system call. 25337741Smckusick * Sync each mounted filesystem. 2549167Ssam */ 25539491Smckusick /* ARGSUSED */ 25638408Smckusick sync(scp) 25739491Smckusick struct syscontext *scp; 2586254Sroot { 25937741Smckusick register struct mount *mp; 260*40110Smckusick struct mount *nmp; 26137741Smckusick 26237741Smckusick mp = rootfs; 26337741Smckusick do { 264*40110Smckusick nmp = mp->m_next; 265*40110Smckusick if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0) 26637741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 267*40110Smckusick mp = nmp; 26837741Smckusick } while (mp != rootfs); 26937741Smckusick } 27037741Smckusick 27137741Smckusick /* 27237741Smckusick * get filesystem statistics 27337741Smckusick */ 27438408Smckusick statfs(scp) 27538408Smckusick register struct syscontext *scp; 27637741Smckusick { 2776254Sroot struct a { 27837741Smckusick char *path; 27937741Smckusick struct statfs *buf; 28038408Smckusick } *uap = (struct a *)scp->sc_ap; 28139464Smckusick register struct mount *mp; 28238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 28337741Smckusick struct statfs sb; 28437741Smckusick int error; 28537741Smckusick 28639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 28737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28837741Smckusick ndp->ni_dirp = uap->path; 28937741Smckusick if (error = namei(ndp)) 29037741Smckusick RETURN (error); 29139544Smckusick mp = ndp->ni_vp->v_mount; 29239544Smckusick vrele(ndp->ni_vp); 29339464Smckusick if (error = VFS_STATFS(mp, &sb)) 29439544Smckusick RETURN (error); 29539464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29639464Smckusick sb.f_fsid = mp->m_fsid; 29739544Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 29837741Smckusick } 29937741Smckusick 30038408Smckusick fstatfs(scp) 30138408Smckusick register struct syscontext *scp; 30237741Smckusick { 30337741Smckusick struct a { 30437741Smckusick int fd; 30537741Smckusick struct statfs *buf; 30638408Smckusick } *uap = (struct a *)scp->sc_ap; 30737741Smckusick struct file *fp; 30839464Smckusick struct mount *mp; 30937741Smckusick struct statfs sb; 31037741Smckusick int error; 31137741Smckusick 31238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 31337741Smckusick RETURN (error); 31439464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31539464Smckusick if (error = VFS_STATFS(mp, &sb)) 31637741Smckusick RETURN (error); 31739464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 31839464Smckusick sb.f_fsid = mp->m_fsid; 31937741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 32037741Smckusick } 32137741Smckusick 32237741Smckusick /* 32338270Smckusick * get statistics on all filesystems 32438270Smckusick */ 32538408Smckusick getfsstat(scp) 32638408Smckusick register struct syscontext *scp; 32738270Smckusick { 32838270Smckusick struct a { 32938270Smckusick struct statfs *buf; 33038270Smckusick long bufsize; 33138408Smckusick } *uap = (struct a *)scp->sc_ap; 33238270Smckusick register struct mount *mp; 33339606Smckusick caddr_t sfsp; 33438270Smckusick long count, maxcount, error; 33539606Smckusick struct statfs sb; 33638270Smckusick 33738270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33839606Smckusick sfsp = (caddr_t)uap->buf; 33938270Smckusick mp = rootfs; 34038270Smckusick count = 0; 34138270Smckusick do { 34239606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 34339607Smckusick if (error = VFS_STATFS(mp, &sb)) { 34439607Smckusick mp = mp->m_prev; 34539607Smckusick continue; 34639607Smckusick } 34739606Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 34839606Smckusick sb.f_fsid = mp->m_fsid; 34939606Smckusick if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb))) 35039606Smckusick RETURN (error); 35139606Smckusick sfsp += sizeof(sb); 35238270Smckusick } 35339606Smckusick count++; 35438270Smckusick mp = mp->m_prev; 35538270Smckusick } while (mp != rootfs); 35638270Smckusick if (sfsp && count > maxcount) 35738408Smckusick scp->sc_retval1 = maxcount; 35838270Smckusick else 35938408Smckusick scp->sc_retval1 = count; 36038270Smckusick RETURN (0); 36138270Smckusick } 36238270Smckusick 36338270Smckusick /* 36438259Smckusick * Change current working directory to a given file descriptor. 36538259Smckusick */ 36638408Smckusick fchdir(scp) 36738408Smckusick register struct syscontext *scp; 36838259Smckusick { 36938259Smckusick struct a { 37038259Smckusick int fd; 37138408Smckusick } *uap = (struct a *)scp->sc_ap; 37238259Smckusick register struct vnode *vp; 37338259Smckusick struct file *fp; 37438259Smckusick int error; 37538259Smckusick 37638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 37738259Smckusick RETURN (error); 37838259Smckusick vp = (struct vnode *)fp->f_data; 37938259Smckusick VOP_LOCK(vp); 38038259Smckusick if (vp->v_type != VDIR) 38138259Smckusick error = ENOTDIR; 38238259Smckusick else 38338408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 38438259Smckusick VOP_UNLOCK(vp); 38539860Smckusick if (error) 38639860Smckusick RETURN (error); 38739860Smckusick VREF(vp); 38838408Smckusick vrele(scp->sc_cdir); 38938408Smckusick scp->sc_cdir = vp; 39039860Smckusick RETURN (0); 39138259Smckusick } 39238259Smckusick 39338259Smckusick /* 39437741Smckusick * Change current working directory (``.''). 39537741Smckusick */ 39638408Smckusick chdir(scp) 39738408Smckusick register struct syscontext *scp; 39837741Smckusick { 39937741Smckusick struct a { 4006254Sroot char *fname; 40138408Smckusick } *uap = (struct a *)scp->sc_ap; 40238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 40337741Smckusick int error; 4046254Sroot 40537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 40716694Smckusick ndp->ni_dirp = uap->fname; 40837741Smckusick if (error = chdirec(ndp)) 40937741Smckusick RETURN (error); 41038408Smckusick vrele(scp->sc_cdir); 41138408Smckusick scp->sc_cdir = ndp->ni_vp; 41237741Smckusick RETURN (0); 41337741Smckusick } 4146254Sroot 41537741Smckusick /* 41637741Smckusick * Change notion of root (``/'') directory. 41737741Smckusick */ 41838408Smckusick chroot(scp) 41938408Smckusick register struct syscontext *scp; 42037741Smckusick { 42137741Smckusick struct a { 42237741Smckusick char *fname; 42338408Smckusick } *uap = (struct a *)scp->sc_ap; 42438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 42537741Smckusick int error; 42637741Smckusick 42738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 42837741Smckusick RETURN (error); 42937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 43037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 43137741Smckusick ndp->ni_dirp = uap->fname; 43237741Smckusick if (error = chdirec(ndp)) 43337741Smckusick RETURN (error); 43439515Smckusick if (scp->sc_rdir != NULL) 43539515Smckusick vrele(scp->sc_rdir); 43638408Smckusick scp->sc_rdir = ndp->ni_vp; 43737741Smckusick RETURN (0); 4386254Sroot } 4396254Sroot 44037Sbill /* 44137741Smckusick * Common routine for chroot and chdir. 44237741Smckusick */ 44337741Smckusick chdirec(ndp) 44437741Smckusick register struct nameidata *ndp; 44537741Smckusick { 44637741Smckusick struct vnode *vp; 44737741Smckusick int error; 44837741Smckusick 44937741Smckusick if (error = namei(ndp)) 45037741Smckusick return (error); 45137741Smckusick vp = ndp->ni_vp; 45237741Smckusick if (vp->v_type != VDIR) 45337741Smckusick error = ENOTDIR; 45437741Smckusick else 45538399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45637741Smckusick VOP_UNLOCK(vp); 45737741Smckusick if (error) 45837741Smckusick vrele(vp); 45937741Smckusick return (error); 46037741Smckusick } 46137741Smckusick 46237741Smckusick /* 4636254Sroot * Open system call. 4646254Sroot */ 46538408Smckusick open(scp) 46638408Smckusick register struct syscontext *scp; 4676254Sroot { 46812756Ssam struct a { 4696254Sroot char *fname; 4707701Ssam int mode; 47112756Ssam int crtmode; 47238408Smckusick } *uap = (struct a *) scp->sc_ap; 47338408Smckusick struct nameidata *ndp = &scp->sc_nd; 4746254Sroot 47537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47637741Smckusick ndp->ni_dirp = uap->fname; 47738408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 47838408Smckusick &scp->sc_retval1)); 4796254Sroot } 4806254Sroot 4816254Sroot /* 4826254Sroot * Creat system call. 4836254Sroot */ 48438408Smckusick creat(scp) 48538408Smckusick register struct syscontext *scp; 4866254Sroot { 48712756Ssam struct a { 4886254Sroot char *fname; 4896254Sroot int fmode; 49038408Smckusick } *uap = (struct a *)scp->sc_ap; 49138408Smckusick struct nameidata *ndp = &scp->sc_nd; 4926254Sroot 49337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49437741Smckusick ndp->ni_dirp = uap->fname; 49538408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 49638408Smckusick ndp, &scp->sc_retval1)); 4976254Sroot } 4986254Sroot 4996254Sroot /* 5006254Sroot * Common code for open and creat. 50112756Ssam * Check permissions, allocate an open file structure, 50212756Ssam * and call the device open routine if any. 5036254Sroot */ 50438408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 50538408Smckusick register struct syscontext *scp; 50637741Smckusick int fmode, cmode; 50737741Smckusick struct nameidata *ndp; 50837741Smckusick int *resultfd; 50912756Ssam { 5106254Sroot register struct file *fp; 51137741Smckusick struct file *nfp; 51237741Smckusick int indx, error; 51337741Smckusick extern struct fileops vnops; 5146254Sroot 51537741Smckusick if (error = falloc(&nfp, &indx)) 51637741Smckusick return (error); 51737741Smckusick fp = nfp; 51838408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 51937741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 52037741Smckusick crfree(fp->f_cred); 52137741Smckusick fp->f_count--; 52239499Smckusick if (error == -1) /* XXX from fdopen */ 52339499Smckusick return (0); /* XXX from fdopen */ 52439499Smckusick scp->sc_ofile[indx] = NULL; 52537741Smckusick return (error); 52612756Ssam } 52737741Smckusick fp->f_flag = fmode & FMASK; 52837741Smckusick fp->f_type = DTYPE_VNODE; 52937741Smckusick fp->f_ops = &vnops; 53037741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 53137741Smckusick if (resultfd) 53237741Smckusick *resultfd = indx; 53337741Smckusick return (0); 5346254Sroot } 5356254Sroot 5366254Sroot /* 5376254Sroot * Mknod system call 5386254Sroot */ 53938408Smckusick mknod(scp) 54038408Smckusick register struct syscontext *scp; 5416254Sroot { 5426254Sroot register struct a { 5436254Sroot char *fname; 5446254Sroot int fmode; 5456254Sroot int dev; 54638408Smckusick } *uap = (struct a *)scp->sc_ap; 54738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54837741Smckusick register struct vnode *vp; 54937741Smckusick struct vattr vattr; 55037741Smckusick int error; 5516254Sroot 55238408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 55337741Smckusick RETURN (error); 55437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 55616694Smckusick ndp->ni_dirp = uap->fname; 55737741Smckusick if (error = namei(ndp)) 55837741Smckusick RETURN (error); 55937741Smckusick vp = ndp->ni_vp; 56037741Smckusick if (vp != NULL) { 56137741Smckusick error = EEXIST; 56212756Ssam goto out; 5636254Sroot } 56437741Smckusick vattr_null(&vattr); 56537741Smckusick switch (uap->fmode & IFMT) { 56612756Ssam 56715093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 56837741Smckusick vattr.va_type = VBAD; 56937741Smckusick break; 57012756Ssam case IFCHR: 57137741Smckusick vattr.va_type = VCHR; 57237741Smckusick break; 57312756Ssam case IFBLK: 57437741Smckusick vattr.va_type = VBLK; 57537741Smckusick break; 57637741Smckusick default: 57737741Smckusick error = EINVAL; 57837741Smckusick goto out; 5796254Sroot } 58038408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 58137741Smckusick vattr.va_rdev = uap->dev; 5826254Sroot out: 58337741Smckusick if (error) 58437741Smckusick VOP_ABORTOP(ndp); 58537741Smckusick else 58637741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 58737741Smckusick RETURN (error); 5886254Sroot } 5896254Sroot 5906254Sroot /* 5916254Sroot * link system call 5926254Sroot */ 59338408Smckusick link(scp) 59438408Smckusick register struct syscontext *scp; 5956254Sroot { 5966254Sroot register struct a { 5976254Sroot char *target; 5986254Sroot char *linkname; 59938408Smckusick } *uap = (struct a *)scp->sc_ap; 60038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 60137741Smckusick register struct vnode *vp, *xp; 60237741Smckusick int error; 6036254Sroot 60416694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 60516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 60616694Smckusick ndp->ni_dirp = uap->target; 60737741Smckusick if (error = namei(ndp)) 60837741Smckusick RETURN (error); 60937741Smckusick vp = ndp->ni_vp; 61037741Smckusick if (vp->v_type == VDIR && 61138408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 61237741Smckusick goto out1; 61337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61416694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 61537741Smckusick if (error = namei(ndp)) 61637741Smckusick goto out1; 61737741Smckusick xp = ndp->ni_vp; 6186254Sroot if (xp != NULL) { 61937741Smckusick error = EEXIST; 6206254Sroot goto out; 6216254Sroot } 62237741Smckusick xp = ndp->ni_dvp; 62337741Smckusick if (vp->v_mount != xp->v_mount) 62437741Smckusick error = EXDEV; 6256254Sroot out: 62637741Smckusick if (error) 62737741Smckusick VOP_ABORTOP(ndp); 62837741Smckusick else 62937741Smckusick error = VOP_LINK(vp, ndp); 63037741Smckusick out1: 63137741Smckusick vrele(vp); 63237741Smckusick RETURN (error); 6336254Sroot } 6346254Sroot 6356254Sroot /* 6366254Sroot * symlink -- make a symbolic link 6376254Sroot */ 63838408Smckusick symlink(scp) 63938408Smckusick register struct syscontext *scp; 6406254Sroot { 64137741Smckusick struct a { 6426254Sroot char *target; 6436254Sroot char *linkname; 64438408Smckusick } *uap = (struct a *)scp->sc_ap; 64538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64637741Smckusick register struct vnode *vp; 64737741Smckusick struct vattr vattr; 64837741Smckusick char *target; 64937741Smckusick int error; 6506254Sroot 65116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 65216694Smckusick ndp->ni_dirp = uap->linkname; 65337741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 65437741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 65537741Smckusick goto out1; 65637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65737741Smckusick if (error = namei(ndp)) 65837741Smckusick goto out1; 65937741Smckusick vp = ndp->ni_vp; 66037741Smckusick if (vp) { 66137741Smckusick error = EEXIST; 66237741Smckusick goto out; 6636254Sroot } 66437741Smckusick vp = ndp->ni_dvp; 66537741Smckusick vattr_null(&vattr); 66638408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 66737741Smckusick out: 66837741Smckusick if (error) 66937741Smckusick VOP_ABORTOP(ndp); 67037741Smckusick else 67137741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 67237741Smckusick out1: 67337741Smckusick FREE(target, M_NAMEI); 67437741Smckusick RETURN (error); 6756254Sroot } 6766254Sroot 6776254Sroot /* 6786254Sroot * Unlink system call. 6796254Sroot * Hard to avoid races here, especially 6806254Sroot * in unlinking directories. 6816254Sroot */ 68238408Smckusick unlink(scp) 68338408Smckusick register struct syscontext *scp; 6846254Sroot { 6856254Sroot struct a { 6866254Sroot char *fname; 68738408Smckusick } *uap = (struct a *)scp->sc_ap; 68838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68937741Smckusick register struct vnode *vp; 69037741Smckusick int error; 6916254Sroot 69237741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 69316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69416694Smckusick ndp->ni_dirp = uap->fname; 69537741Smckusick if (error = namei(ndp)) 69637741Smckusick RETURN (error); 69737741Smckusick vp = ndp->ni_vp; 69837741Smckusick if (vp->v_type == VDIR && 69938408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7006254Sroot goto out; 7016254Sroot /* 7026254Sroot * Don't unlink a mounted file. 7036254Sroot */ 70437741Smckusick if (vp->v_flag & VROOT) { 70537741Smckusick error = EBUSY; 7066254Sroot goto out; 7076254Sroot } 70837741Smckusick if (vp->v_flag & VTEXT) 70937741Smckusick xrele(vp); /* try once to free text */ 7106254Sroot out: 71137741Smckusick if (error) 71237741Smckusick VOP_ABORTOP(ndp); 7137142Smckusick else 71437741Smckusick error = VOP_REMOVE(ndp); 71537741Smckusick RETURN (error); 7166254Sroot } 7176254Sroot 7186254Sroot /* 7196254Sroot * Seek system call 7206254Sroot */ 72138408Smckusick lseek(scp) 72238408Smckusick register struct syscontext *scp; 7236254Sroot { 7246254Sroot register struct file *fp; 7256254Sroot register struct a { 72637741Smckusick int fdes; 7276254Sroot off_t off; 7286254Sroot int sbase; 72938408Smckusick } *uap = (struct a *)scp->sc_ap; 73037741Smckusick struct vattr vattr; 73137741Smckusick int error; 7326254Sroot 73337741Smckusick if ((unsigned)uap->fdes >= NOFILE || 73438408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 73537741Smckusick RETURN (EBADF); 73637741Smckusick if (fp->f_type != DTYPE_VNODE) 73737741Smckusick RETURN (ESPIPE); 73813878Ssam switch (uap->sbase) { 73913878Ssam 74013878Ssam case L_INCR: 74113878Ssam fp->f_offset += uap->off; 74213878Ssam break; 74313878Ssam 74413878Ssam case L_XTND: 74537741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 74638408Smckusick &vattr, scp->sc_cred)) 74737741Smckusick RETURN (error); 74837741Smckusick fp->f_offset = uap->off + vattr.va_size; 74913878Ssam break; 75013878Ssam 75113878Ssam case L_SET: 75213878Ssam fp->f_offset = uap->off; 75313878Ssam break; 75413878Ssam 75513878Ssam default: 75637741Smckusick RETURN (EINVAL); 75713878Ssam } 75838408Smckusick scp->sc_offset = fp->f_offset; 75937741Smckusick RETURN (0); 7606254Sroot } 7616254Sroot 7626254Sroot /* 7636254Sroot * Access system call 7646254Sroot */ 76538408Smckusick saccess(scp) 76638408Smckusick register struct syscontext *scp; 7676254Sroot { 7686254Sroot register struct a { 7696254Sroot char *fname; 7706254Sroot int fmode; 77138408Smckusick } *uap = (struct a *)scp->sc_ap; 77238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 77337741Smckusick register struct vnode *vp; 77437741Smckusick int error, mode, svuid, svgid; 7756254Sroot 77638408Smckusick svuid = scp->sc_uid; 77738408Smckusick svgid = scp->sc_gid; 77838408Smckusick scp->sc_uid = scp->sc_ruid; 77938408Smckusick scp->sc_gid = scp->sc_rgid; 78037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 78116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78216694Smckusick ndp->ni_dirp = uap->fname; 78337741Smckusick if (error = namei(ndp)) 78437741Smckusick goto out1; 78537741Smckusick vp = ndp->ni_vp; 78637741Smckusick /* 78737741Smckusick * fmode == 0 means only check for exist 78837741Smckusick */ 78937741Smckusick if (uap->fmode) { 79037741Smckusick mode = 0; 79137741Smckusick if (uap->fmode & R_OK) 79237741Smckusick mode |= VREAD; 79337741Smckusick if (uap->fmode & W_OK) 79437741Smckusick mode |= VWRITE; 79537741Smckusick if (uap->fmode & X_OK) 79637741Smckusick mode |= VEXEC; 79739543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 79838399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7996254Sroot } 80037741Smckusick vput(vp); 80137741Smckusick out1: 80238408Smckusick scp->sc_uid = svuid; 80338408Smckusick scp->sc_gid = svgid; 80437741Smckusick RETURN (error); 8056254Sroot } 8066254Sroot 8076254Sroot /* 8086574Smckusic * Stat system call. This version follows links. 80937Sbill */ 81038408Smckusick stat(scp) 81138408Smckusick struct syscontext *scp; 81237Sbill { 81337Sbill 81438408Smckusick stat1(scp, FOLLOW); 81537Sbill } 81637Sbill 81737Sbill /* 8186574Smckusic * Lstat system call. This version does not follow links. 8195992Swnj */ 82038408Smckusick lstat(scp) 82138408Smckusick struct syscontext *scp; 8225992Swnj { 82312756Ssam 82438408Smckusick stat1(scp, NOFOLLOW); 82512756Ssam } 82612756Ssam 82738408Smckusick stat1(scp, follow) 82838408Smckusick register struct syscontext *scp; 82912756Ssam int follow; 83012756Ssam { 8315992Swnj register struct a { 8325992Swnj char *fname; 83312756Ssam struct stat *ub; 83438408Smckusick } *uap = (struct a *)scp->sc_ap; 83538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 83612756Ssam struct stat sb; 83737741Smckusick int error; 8385992Swnj 83937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 84016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 84116694Smckusick ndp->ni_dirp = uap->fname; 84237741Smckusick if (error = namei(ndp)) 84337741Smckusick RETURN (error); 84437741Smckusick error = vn_stat(ndp->ni_vp, &sb); 84537741Smckusick vput(ndp->ni_vp); 84637741Smckusick if (error) 84737741Smckusick RETURN (error); 84837741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 84937741Smckusick RETURN (error); 8505992Swnj } 8515992Swnj 8525992Swnj /* 8535992Swnj * Return target name of a symbolic link 85437Sbill */ 85538408Smckusick readlink(scp) 85638408Smckusick register struct syscontext *scp; 8575992Swnj { 8585992Swnj register struct a { 8595992Swnj char *name; 8605992Swnj char *buf; 8615992Swnj int count; 86238408Smckusick } *uap = (struct a *)scp->sc_ap; 86338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 86437741Smckusick register struct vnode *vp; 86537741Smckusick struct iovec aiov; 86637741Smckusick struct uio auio; 86737741Smckusick int error; 8685992Swnj 86937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 87016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 87116694Smckusick ndp->ni_dirp = uap->name; 87237741Smckusick if (error = namei(ndp)) 87337741Smckusick RETURN (error); 87437741Smckusick vp = ndp->ni_vp; 87537741Smckusick if (vp->v_type != VLNK) { 87637741Smckusick error = EINVAL; 8775992Swnj goto out; 8785992Swnj } 87937741Smckusick aiov.iov_base = uap->buf; 88037741Smckusick aiov.iov_len = uap->count; 88137741Smckusick auio.uio_iov = &aiov; 88237741Smckusick auio.uio_iovcnt = 1; 88337741Smckusick auio.uio_offset = 0; 88437741Smckusick auio.uio_rw = UIO_READ; 88537741Smckusick auio.uio_segflg = UIO_USERSPACE; 88637741Smckusick auio.uio_resid = uap->count; 88737741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8885992Swnj out: 88937741Smckusick vput(vp); 89038408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 89137741Smckusick RETURN (error); 8925992Swnj } 8935992Swnj 8949167Ssam /* 89538259Smckusick * Change flags of a file given path name. 89638259Smckusick */ 89738408Smckusick chflags(scp) 89838408Smckusick register struct syscontext *scp; 89938259Smckusick { 90038259Smckusick struct a { 90138259Smckusick char *fname; 90238259Smckusick int flags; 90338408Smckusick } *uap = (struct a *)scp->sc_ap; 90438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90538259Smckusick register struct vnode *vp; 90638259Smckusick struct vattr vattr; 90738259Smckusick int error; 90838259Smckusick 90938259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 91038259Smckusick ndp->ni_segflg = UIO_USERSPACE; 91138259Smckusick ndp->ni_dirp = uap->fname; 91238259Smckusick vattr_null(&vattr); 91338259Smckusick vattr.va_flags = uap->flags; 91438259Smckusick if (error = namei(ndp)) 91538259Smckusick RETURN (error); 91638259Smckusick vp = ndp->ni_vp; 91738259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91838259Smckusick error = EROFS; 91938259Smckusick goto out; 92038259Smckusick } 92138259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 92238259Smckusick out: 92338259Smckusick vput(vp); 92438259Smckusick RETURN (error); 92538259Smckusick } 92638259Smckusick 92738259Smckusick /* 92838259Smckusick * Change flags of a file given a file descriptor. 92938259Smckusick */ 93038408Smckusick fchflags(scp) 93138408Smckusick register struct syscontext *scp; 93238259Smckusick { 93338259Smckusick struct a { 93438259Smckusick int fd; 93538259Smckusick int flags; 93638408Smckusick } *uap = (struct a *)scp->sc_ap; 93738259Smckusick struct vattr vattr; 93838259Smckusick struct vnode *vp; 93938259Smckusick struct file *fp; 94038259Smckusick int error; 94138259Smckusick 94238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 94338259Smckusick RETURN (error); 94438259Smckusick vattr_null(&vattr); 94538259Smckusick vattr.va_flags = uap->flags; 94638259Smckusick vp = (struct vnode *)fp->f_data; 94738259Smckusick VOP_LOCK(vp); 94838259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94938259Smckusick error = EROFS; 95038259Smckusick goto out; 95138259Smckusick } 95238259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 95338259Smckusick out: 95438259Smckusick VOP_UNLOCK(vp); 95538259Smckusick RETURN (error); 95638259Smckusick } 95738259Smckusick 95838259Smckusick /* 9599167Ssam * Change mode of a file given path name. 9609167Ssam */ 96138408Smckusick chmod(scp) 96238408Smckusick register struct syscontext *scp; 9635992Swnj { 9647701Ssam struct a { 9656254Sroot char *fname; 9666254Sroot int fmode; 96738408Smckusick } *uap = (struct a *)scp->sc_ap; 96838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 96937741Smckusick register struct vnode *vp; 97037741Smckusick struct vattr vattr; 97137741Smckusick int error; 9725992Swnj 97337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 97437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 97537741Smckusick ndp->ni_dirp = uap->fname; 97637741Smckusick vattr_null(&vattr); 97737741Smckusick vattr.va_mode = uap->fmode & 07777; 97837741Smckusick if (error = namei(ndp)) 97937741Smckusick RETURN (error); 98037741Smckusick vp = ndp->ni_vp; 98137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98237741Smckusick error = EROFS; 98337741Smckusick goto out; 98437741Smckusick } 98537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 98637741Smckusick out: 98737741Smckusick vput(vp); 98837741Smckusick RETURN (error); 9897701Ssam } 9907439Sroot 9919167Ssam /* 9929167Ssam * Change mode of a file given a file descriptor. 9939167Ssam */ 99438408Smckusick fchmod(scp) 99538408Smckusick register struct syscontext *scp; 9967701Ssam { 9977701Ssam struct a { 9987701Ssam int fd; 9997701Ssam int fmode; 100038408Smckusick } *uap = (struct a *)scp->sc_ap; 100137741Smckusick struct vattr vattr; 100237741Smckusick struct vnode *vp; 100337741Smckusick struct file *fp; 100437741Smckusick int error; 10057701Ssam 100638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 100737741Smckusick RETURN (error); 100837741Smckusick vattr_null(&vattr); 100937741Smckusick vattr.va_mode = uap->fmode & 07777; 101037741Smckusick vp = (struct vnode *)fp->f_data; 101137741Smckusick VOP_LOCK(vp); 101237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101337741Smckusick error = EROFS; 101437741Smckusick goto out; 10157439Sroot } 101637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 101737741Smckusick out: 101837741Smckusick VOP_UNLOCK(vp); 101937741Smckusick RETURN (error); 10205992Swnj } 10215992Swnj 10229167Ssam /* 10239167Ssam * Set ownership given a path name. 10249167Ssam */ 102538408Smckusick chown(scp) 102638408Smckusick register struct syscontext *scp; 102737Sbill { 10287701Ssam struct a { 10296254Sroot char *fname; 10306254Sroot int uid; 10316254Sroot int gid; 103238408Smckusick } *uap = (struct a *)scp->sc_ap; 103338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 103437741Smckusick register struct vnode *vp; 103537741Smckusick struct vattr vattr; 103637741Smckusick int error; 103737Sbill 103837741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 103936614Sbostic ndp->ni_segflg = UIO_USERSPACE; 104036614Sbostic ndp->ni_dirp = uap->fname; 104137741Smckusick vattr_null(&vattr); 104237741Smckusick vattr.va_uid = uap->uid; 104337741Smckusick vattr.va_gid = uap->gid; 104437741Smckusick if (error = namei(ndp)) 104537741Smckusick RETURN (error); 104637741Smckusick vp = ndp->ni_vp; 104737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 104837741Smckusick error = EROFS; 104937741Smckusick goto out; 105037741Smckusick } 105137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 105237741Smckusick out: 105337741Smckusick vput(vp); 105437741Smckusick RETURN (error); 10557701Ssam } 10567439Sroot 10579167Ssam /* 10589167Ssam * Set ownership given a file descriptor. 10599167Ssam */ 106038408Smckusick fchown(scp) 106138408Smckusick register struct syscontext *scp; 10627701Ssam { 10637701Ssam struct a { 10647701Ssam int fd; 10657701Ssam int uid; 10667701Ssam int gid; 106738408Smckusick } *uap = (struct a *)scp->sc_ap; 106837741Smckusick struct vattr vattr; 106937741Smckusick struct vnode *vp; 107037741Smckusick struct file *fp; 107137741Smckusick int error; 10727701Ssam 107338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 107437741Smckusick RETURN (error); 107537741Smckusick vattr_null(&vattr); 107637741Smckusick vattr.va_uid = uap->uid; 107737741Smckusick vattr.va_gid = uap->gid; 107837741Smckusick vp = (struct vnode *)fp->f_data; 107937741Smckusick VOP_LOCK(vp); 108037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 108137741Smckusick error = EROFS; 108237741Smckusick goto out; 108337741Smckusick } 108437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108537741Smckusick out: 108637741Smckusick VOP_UNLOCK(vp); 108737741Smckusick RETURN (error); 10887701Ssam } 10897701Ssam 109038408Smckusick utimes(scp) 109138408Smckusick register struct syscontext *scp; 109211811Ssam { 109311811Ssam register struct a { 109411811Ssam char *fname; 109511811Ssam struct timeval *tptr; 109638408Smckusick } *uap = (struct a *)scp->sc_ap; 109738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 109837741Smckusick register struct vnode *vp; 109911811Ssam struct timeval tv[2]; 110037741Smckusick struct vattr vattr; 110137741Smckusick int error; 110211811Ssam 110337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 110437741Smckusick RETURN (error); 110537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 110637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 110737741Smckusick ndp->ni_dirp = uap->fname; 110837741Smckusick vattr_null(&vattr); 110937741Smckusick vattr.va_atime = tv[0]; 111037741Smckusick vattr.va_mtime = tv[1]; 111137741Smckusick if (error = namei(ndp)) 111237741Smckusick RETURN (error); 111337741Smckusick vp = ndp->ni_vp; 111437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 111537741Smckusick error = EROFS; 111637741Smckusick goto out; 111721015Smckusick } 111837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 111937741Smckusick out: 112037741Smckusick vput(vp); 112137741Smckusick RETURN (error); 112211811Ssam } 112311811Ssam 11249167Ssam /* 11259167Ssam * Truncate a file given its path name. 11269167Ssam */ 112738408Smckusick truncate(scp) 112838408Smckusick register struct syscontext *scp; 11297701Ssam { 11307701Ssam struct a { 11317701Ssam char *fname; 113226473Skarels off_t length; 113338408Smckusick } *uap = (struct a *)scp->sc_ap; 113438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 113537741Smckusick register struct vnode *vp; 113637741Smckusick struct vattr vattr; 113737741Smckusick int error; 11387701Ssam 113937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 114116694Smckusick ndp->ni_dirp = uap->fname; 114237741Smckusick vattr_null(&vattr); 114337741Smckusick vattr.va_size = uap->length; 114437741Smckusick if (error = namei(ndp)) 114537741Smckusick RETURN (error); 114637741Smckusick vp = ndp->ni_vp; 114737741Smckusick if (vp->v_type == VDIR) { 114837741Smckusick error = EISDIR; 114937741Smckusick goto out; 11507701Ssam } 115138399Smckusick if ((error = vn_writechk(vp)) || 115238399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 115337741Smckusick goto out; 115437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115537741Smckusick out: 115637741Smckusick vput(vp); 115737741Smckusick RETURN (error); 11587701Ssam } 11597701Ssam 11609167Ssam /* 11619167Ssam * Truncate a file given a file descriptor. 11629167Ssam */ 116338408Smckusick ftruncate(scp) 116438408Smckusick register struct syscontext *scp; 11657701Ssam { 11667701Ssam struct a { 11677701Ssam int fd; 116826473Skarels off_t length; 116938408Smckusick } *uap = (struct a *)scp->sc_ap; 117037741Smckusick struct vattr vattr; 117137741Smckusick struct vnode *vp; 11727701Ssam struct file *fp; 117337741Smckusick int error; 11747701Ssam 117538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 117637741Smckusick RETURN (error); 117737741Smckusick if ((fp->f_flag & FWRITE) == 0) 117837741Smckusick RETURN (EINVAL); 117937741Smckusick vattr_null(&vattr); 118037741Smckusick vattr.va_size = uap->length; 118137741Smckusick vp = (struct vnode *)fp->f_data; 118237741Smckusick VOP_LOCK(vp); 118337741Smckusick if (vp->v_type == VDIR) { 118437741Smckusick error = EISDIR; 118537741Smckusick goto out; 11867701Ssam } 118738399Smckusick if (error = vn_writechk(vp)) 118837741Smckusick goto out; 118937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 119037741Smckusick out: 119137741Smckusick VOP_UNLOCK(vp); 119237741Smckusick RETURN (error); 11937701Ssam } 11947701Ssam 11959167Ssam /* 11969167Ssam * Synch an open file. 11979167Ssam */ 119838408Smckusick fsync(scp) 119938408Smckusick register struct syscontext *scp; 12009167Ssam { 12019167Ssam struct a { 12029167Ssam int fd; 120338408Smckusick } *uap = (struct a *)scp->sc_ap; 120439592Smckusick register struct vnode *vp; 12059167Ssam struct file *fp; 120637741Smckusick int error; 12079167Ssam 120838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 120937741Smckusick RETURN (error); 121039592Smckusick vp = (struct vnode *)fp->f_data; 121139592Smckusick VOP_LOCK(vp); 121239592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 121339592Smckusick VOP_UNLOCK(vp); 121437741Smckusick RETURN (error); 12159167Ssam } 12169167Ssam 12179167Ssam /* 12189167Ssam * Rename system call. 12199167Ssam * 12209167Ssam * Source and destination must either both be directories, or both 12219167Ssam * not be directories. If target is a directory, it must be empty. 12229167Ssam */ 122338408Smckusick rename(scp) 122438408Smckusick register struct syscontext *scp; 12257701Ssam { 12267701Ssam struct a { 12277701Ssam char *from; 12287701Ssam char *to; 122938408Smckusick } *uap = (struct a *)scp->sc_ap; 123037741Smckusick register struct vnode *tvp, *fvp, *tdvp; 123138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 123237741Smckusick struct nameidata tond; 123337741Smckusick int error; 12347701Ssam 123537741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 123616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 123716694Smckusick ndp->ni_dirp = uap->from; 123837741Smckusick if (error = namei(ndp)) 123937741Smckusick RETURN (error); 124037741Smckusick fvp = ndp->ni_vp; 124138266Smckusick nddup(ndp, &tond); 124237741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 124337741Smckusick tond.ni_segflg = UIO_USERSPACE; 124437741Smckusick tond.ni_dirp = uap->to; 124537741Smckusick error = namei(&tond); 124637741Smckusick tdvp = tond.ni_dvp; 124737741Smckusick tvp = tond.ni_vp; 124837741Smckusick if (tvp != NULL) { 124937741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 125039242Sbostic error = ENOTDIR; 125137741Smckusick goto out; 125237741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 125339242Sbostic error = EISDIR; 125437741Smckusick goto out; 12559167Ssam } 12569167Ssam } 125737741Smckusick if (error) { 125837741Smckusick VOP_ABORTOP(ndp); 125937741Smckusick goto out1; 126037741Smckusick } 126137741Smckusick if (fvp->v_mount != tdvp->v_mount) { 126237741Smckusick error = EXDEV; 12639167Ssam goto out; 126410051Ssam } 126539286Smckusick if (fvp == tdvp) 126637741Smckusick error = EINVAL; 126739286Smckusick /* 126839286Smckusick * If source is the same as the destination, 126939286Smckusick * then there is nothing to do. 127039286Smckusick */ 127139286Smckusick if (fvp == tvp) 127239286Smckusick error = -1; 127337741Smckusick out: 127437741Smckusick if (error) { 127537741Smckusick VOP_ABORTOP(&tond); 127637741Smckusick VOP_ABORTOP(ndp); 12779167Ssam } else { 127837741Smckusick error = VOP_RENAME(ndp, &tond); 12799167Ssam } 128037741Smckusick out1: 128138266Smckusick ndrele(&tond); 128239286Smckusick if (error == -1) 128339286Smckusick RETURN (0); 128437741Smckusick RETURN (error); 12857701Ssam } 12867701Ssam 12877535Sroot /* 128812756Ssam * Mkdir system call 128912756Ssam */ 129038408Smckusick mkdir(scp) 129138408Smckusick register struct syscontext *scp; 129212756Ssam { 129312756Ssam struct a { 129412756Ssam char *name; 129512756Ssam int dmode; 129638408Smckusick } *uap = (struct a *)scp->sc_ap; 129738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 129837741Smckusick register struct vnode *vp; 129937741Smckusick struct vattr vattr; 130037741Smckusick int error; 130112756Ssam 130237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 130316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130416694Smckusick ndp->ni_dirp = uap->name; 130537741Smckusick if (error = namei(ndp)) 130637741Smckusick RETURN (error); 130737741Smckusick vp = ndp->ni_vp; 130837741Smckusick if (vp != NULL) { 130937741Smckusick VOP_ABORTOP(ndp); 131037741Smckusick RETURN (EEXIST); 131112756Ssam } 131237741Smckusick vattr_null(&vattr); 131337741Smckusick vattr.va_type = VDIR; 131438408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 131537741Smckusick error = VOP_MKDIR(ndp, &vattr); 131638145Smckusick if (!error) 131738145Smckusick vput(ndp->ni_vp); 131837741Smckusick RETURN (error); 131912756Ssam } 132012756Ssam 132112756Ssam /* 132212756Ssam * Rmdir system call. 132312756Ssam */ 132438408Smckusick rmdir(scp) 132538408Smckusick register struct syscontext *scp; 132612756Ssam { 132712756Ssam struct a { 132812756Ssam char *name; 132938408Smckusick } *uap = (struct a *)scp->sc_ap; 133038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 133137741Smckusick register struct vnode *vp; 133237741Smckusick int error; 133312756Ssam 133437741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 133516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 133616694Smckusick ndp->ni_dirp = uap->name; 133737741Smckusick if (error = namei(ndp)) 133837741Smckusick RETURN (error); 133937741Smckusick vp = ndp->ni_vp; 134037741Smckusick if (vp->v_type != VDIR) { 134137741Smckusick error = ENOTDIR; 134212756Ssam goto out; 134312756Ssam } 134412756Ssam /* 134537741Smckusick * No rmdir "." please. 134612756Ssam */ 134737741Smckusick if (ndp->ni_dvp == vp) { 134837741Smckusick error = EINVAL; 134912756Ssam goto out; 135012756Ssam } 135112756Ssam /* 135237741Smckusick * Don't unlink a mounted file. 135312756Ssam */ 135437741Smckusick if (vp->v_flag & VROOT) 135537741Smckusick error = EBUSY; 135612756Ssam out: 135737741Smckusick if (error) 135837741Smckusick VOP_ABORTOP(ndp); 135937741Smckusick else 136037741Smckusick error = VOP_RMDIR(ndp); 136137741Smckusick RETURN (error); 136212756Ssam } 136312756Ssam 136437741Smckusick /* 136537741Smckusick * Read a block of directory entries in a file system independent format 136637741Smckusick */ 136738408Smckusick getdirentries(scp) 136838408Smckusick register struct syscontext *scp; 136912756Ssam { 137037741Smckusick register struct a { 137137741Smckusick int fd; 137237741Smckusick char *buf; 137337741Smckusick unsigned count; 137437741Smckusick long *basep; 137538408Smckusick } *uap = (struct a *)scp->sc_ap; 137639592Smckusick register struct vnode *vp; 137716540Ssam struct file *fp; 137837741Smckusick struct uio auio; 137937741Smckusick struct iovec aiov; 138038129Smckusick off_t off; 138137741Smckusick int error; 138212756Ssam 138338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 138437741Smckusick RETURN (error); 138537741Smckusick if ((fp->f_flag & FREAD) == 0) 138637741Smckusick RETURN (EBADF); 138739592Smckusick vp = (struct vnode *)fp->f_data; 138839592Smckusick if (vp->v_type != VDIR) 138939592Smckusick RETURN (EINVAL); 139037741Smckusick aiov.iov_base = uap->buf; 139137741Smckusick aiov.iov_len = uap->count; 139237741Smckusick auio.uio_iov = &aiov; 139337741Smckusick auio.uio_iovcnt = 1; 139437741Smckusick auio.uio_rw = UIO_READ; 139537741Smckusick auio.uio_segflg = UIO_USERSPACE; 139637741Smckusick auio.uio_resid = uap->count; 139739592Smckusick VOP_LOCK(vp); 139839592Smckusick auio.uio_offset = off = fp->f_offset; 139939592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 140039592Smckusick fp->f_offset = auio.uio_offset; 140139592Smckusick VOP_UNLOCK(vp); 140239592Smckusick if (error) 140337741Smckusick RETURN (error); 140439592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 140538408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 140637741Smckusick RETURN (error); 140712756Ssam } 140812756Ssam 140912756Ssam /* 141012756Ssam * mode mask for creation of files 141112756Ssam */ 141238408Smckusick umask(scp) 141338408Smckusick register struct syscontext *scp; 141412756Ssam { 141512756Ssam register struct a { 141612756Ssam int mask; 141738408Smckusick } *uap = (struct a *)scp->sc_ap; 141812756Ssam 141938408Smckusick scp->sc_retval1 = scp->sc_cmask; 142038408Smckusick scp->sc_cmask = uap->mask & 07777; 142137741Smckusick RETURN (0); 142212756Ssam } 142337741Smckusick 142439566Smarc /* 142539566Smarc * Void all references to file by ripping underlying filesystem 142639566Smarc * away from vnode. 142739566Smarc */ 142839566Smarc revoke(scp) 142939566Smarc register struct syscontext *scp; 143039566Smarc { 143139566Smarc struct a { 143239566Smarc char *fname; 143339566Smarc } *uap = (struct a *)scp->sc_ap; 143439566Smarc register struct nameidata *ndp = &scp->sc_nd; 143539566Smarc register struct vnode *vp; 143639566Smarc struct vattr vattr; 143739566Smarc int error; 143839566Smarc 143939566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 144039566Smarc ndp->ni_segflg = UIO_USERSPACE; 144139566Smarc ndp->ni_dirp = uap->fname; 144239566Smarc if (error = namei(ndp)) 144339566Smarc RETURN (error); 144439566Smarc vp = ndp->ni_vp; 144539566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 144639566Smarc error = EINVAL; 144739566Smarc goto out; 144839566Smarc } 144939566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 145039566Smarc goto out; 145139566Smarc if (scp->sc_uid != vattr.va_uid || 145239566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 145339566Smarc goto out; 145439805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 145539632Smckusick vgoneall(vp); 145639566Smarc out: 145739566Smarc vrele(vp); 145839566Smarc RETURN (error); 145939566Smarc } 146039566Smarc 146138408Smckusick getvnode(ofile, fdes, fpp) 146238408Smckusick struct file *ofile[]; 146337741Smckusick struct file **fpp; 146437741Smckusick int fdes; 146537741Smckusick { 146637741Smckusick struct file *fp; 146737741Smckusick 146838408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 146937741Smckusick return (EBADF); 147037741Smckusick if (fp->f_type != DTYPE_VNODE) 147137741Smckusick return (EINVAL); 147237741Smckusick *fpp = fp; 147337741Smckusick return (0); 147437741Smckusick } 1475