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*40111Smckusick * @(#)vfs_syscalls.c 7.38 (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; 55*40111Smckusick int error, flag; 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 } 86*40111Smckusick flag = mp->m_flag; 8739335Smckusick mp->m_flag |= M_UPDATE; 8839335Smckusick VOP_UNLOCK(vp); 8939335Smckusick goto update; 9039335Smckusick } 9139665Smckusick vinvalbuf(vp, 1); 9239805Smckusick if (vp->v_usecount != 1) { 9337741Smckusick vput(vp); 9437741Smckusick RETURN (EBUSY); 9537741Smckusick } 9637741Smckusick if (vp->v_type != VDIR) { 9737741Smckusick vput(vp); 9837741Smckusick RETURN (ENOTDIR); 9937741Smckusick } 10039741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10137741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10237741Smckusick vput(vp); 10337741Smckusick RETURN (ENODEV); 10437741Smckusick } 10537741Smckusick 10637741Smckusick /* 10739335Smckusick * Allocate and initialize the file system. 10837741Smckusick */ 10937741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 11037741Smckusick M_MOUNT, M_WAITOK); 11137741Smckusick mp->m_op = vfssw[uap->type]; 11237741Smckusick mp->m_flag = 0; 11337741Smckusick mp->m_exroot = 0; 11439381Smckusick mp->m_mounth = (struct vnode *)0; 11539335Smckusick if (error = vfs_lock(mp)) { 11639335Smckusick free((caddr_t)mp, M_MOUNT); 11739335Smckusick vput(vp); 11839335Smckusick RETURN (error); 11939335Smckusick } 12039335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12139335Smckusick vfs_unlock(mp); 12239335Smckusick free((caddr_t)mp, M_MOUNT); 12339335Smckusick vput(vp); 12439335Smckusick RETURN (EBUSY); 12539335Smckusick } 12639335Smckusick vp->v_mountedhere = mp; 12739335Smckusick mp->m_vnodecovered = vp; 12839335Smckusick update: 12939335Smckusick /* 13039335Smckusick * Set the mount level flags. 13139335Smckusick */ 13239335Smckusick if (uap->flags & M_RDONLY) 13339335Smckusick mp->m_flag |= M_RDONLY; 13439335Smckusick else 13539335Smckusick mp->m_flag &= ~M_RDONLY; 13639335Smckusick if (uap->flags & M_NOSUID) 13739335Smckusick mp->m_flag |= M_NOSUID; 13839335Smckusick else 13939335Smckusick mp->m_flag &= ~M_NOSUID; 14039335Smckusick if (uap->flags & M_NOEXEC) 14139335Smckusick mp->m_flag |= M_NOEXEC; 14239335Smckusick else 14339335Smckusick mp->m_flag &= ~M_NOEXEC; 14439335Smckusick if (uap->flags & M_NODEV) 14539335Smckusick mp->m_flag |= M_NODEV; 14639335Smckusick else 14739335Smckusick mp->m_flag &= ~M_NODEV; 14839335Smckusick if (uap->flags & M_SYNCHRONOUS) 14939335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15039335Smckusick else 15139335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15239335Smckusick /* 15339335Smckusick * Mount the filesystem. 15439335Smckusick */ 15539335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15639335Smckusick if (mp->m_flag & M_UPDATE) { 15739335Smckusick mp->m_flag &= ~M_UPDATE; 15839335Smckusick vrele(vp); 159*40111Smckusick if (error) 160*40111Smckusick mp->m_flag = flag; 16139335Smckusick RETURN (error); 16239335Smckusick } 16340110Smckusick /* 16440110Smckusick * Put the new filesystem on the mount list after root. 16540110Smckusick */ 16640110Smckusick mp->m_next = rootfs->m_next; 16740110Smckusick mp->m_prev = rootfs; 16840110Smckusick rootfs->m_next = mp; 16940110Smckusick mp->m_next->m_prev = mp; 17037741Smckusick cache_purge(vp); 17137741Smckusick if (!error) { 17239335Smckusick VOP_UNLOCK(vp); 17337741Smckusick vfs_unlock(mp); 17439044Smckusick error = VFS_START(mp, 0); 17537741Smckusick } else { 17637741Smckusick vfs_remove(mp); 17737741Smckusick free((caddr_t)mp, M_MOUNT); 17839335Smckusick vput(vp); 17937741Smckusick } 18037741Smckusick RETURN (error); 1816254Sroot } 1826254Sroot 1839167Ssam /* 18437741Smckusick * Unmount system call. 18537741Smckusick * 18637741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18737741Smckusick * not special file (as before). 1889167Ssam */ 18938408Smckusick unmount(scp) 19038408Smckusick register struct syscontext *scp; 1916254Sroot { 19237741Smckusick struct a { 19337741Smckusick char *pathp; 19437741Smckusick int flags; 19538408Smckusick } *uap = (struct a *)scp->sc_ap; 19637741Smckusick register struct vnode *vp; 19738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19839356Smckusick struct mount *mp; 19937741Smckusick int error; 2006254Sroot 20137741Smckusick /* 20237741Smckusick * Must be super user 20337741Smckusick */ 20438408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 20537741Smckusick RETURN (error); 20637741Smckusick 20737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20937741Smckusick ndp->ni_dirp = uap->pathp; 21037741Smckusick if (error = namei(ndp)) 21137741Smckusick RETURN (error); 21237741Smckusick vp = ndp->ni_vp; 21337741Smckusick /* 21437741Smckusick * Must be the root of the filesystem 21537741Smckusick */ 21637741Smckusick if ((vp->v_flag & VROOT) == 0) { 21737741Smckusick vput(vp); 21837741Smckusick RETURN (EINVAL); 21937741Smckusick } 22037741Smckusick mp = vp->v_mount; 22137741Smckusick vput(vp); 22239356Smckusick RETURN (dounmount(mp, uap->flags)); 22339356Smckusick } 22439356Smckusick 22539356Smckusick /* 22639356Smckusick * Do an unmount. 22739356Smckusick */ 22839356Smckusick dounmount(mp, flags) 22939356Smckusick register struct mount *mp; 23039356Smckusick int flags; 23139356Smckusick { 23239356Smckusick struct vnode *coveredvp; 23339356Smckusick int error; 23439356Smckusick 23537741Smckusick coveredvp = mp->m_vnodecovered; 23637741Smckusick if (error = vfs_lock(mp)) 23739356Smckusick return (error); 23837741Smckusick 23937741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24037741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24137741Smckusick VFS_SYNC(mp, MNT_WAIT); 24237741Smckusick 24339356Smckusick error = VFS_UNMOUNT(mp, flags); 24437741Smckusick if (error) { 24537741Smckusick vfs_unlock(mp); 24637741Smckusick } else { 24737741Smckusick vrele(coveredvp); 24837741Smckusick vfs_remove(mp); 24937741Smckusick free((caddr_t)mp, M_MOUNT); 25037741Smckusick } 25139356Smckusick return (error); 2526254Sroot } 2536254Sroot 2549167Ssam /* 25537741Smckusick * Sync system call. 25637741Smckusick * Sync each mounted filesystem. 2579167Ssam */ 25839491Smckusick /* ARGSUSED */ 25938408Smckusick sync(scp) 26039491Smckusick struct syscontext *scp; 2616254Sroot { 26237741Smckusick register struct mount *mp; 26340110Smckusick struct mount *nmp; 26437741Smckusick 26537741Smckusick mp = rootfs; 26637741Smckusick do { 26740110Smckusick nmp = mp->m_next; 26840110Smckusick if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0) 26937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27040110Smckusick mp = nmp; 27137741Smckusick } while (mp != rootfs); 27237741Smckusick } 27337741Smckusick 27437741Smckusick /* 27537741Smckusick * get filesystem statistics 27637741Smckusick */ 27738408Smckusick statfs(scp) 27838408Smckusick register struct syscontext *scp; 27937741Smckusick { 2806254Sroot struct a { 28137741Smckusick char *path; 28237741Smckusick struct statfs *buf; 28338408Smckusick } *uap = (struct a *)scp->sc_ap; 28439464Smckusick register struct mount *mp; 28538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 28637741Smckusick struct statfs sb; 28737741Smckusick int error; 28837741Smckusick 28939544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 29037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 29137741Smckusick ndp->ni_dirp = uap->path; 29237741Smckusick if (error = namei(ndp)) 29337741Smckusick RETURN (error); 29439544Smckusick mp = ndp->ni_vp->v_mount; 29539544Smckusick vrele(ndp->ni_vp); 29639464Smckusick if (error = VFS_STATFS(mp, &sb)) 29739544Smckusick RETURN (error); 29839464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29939464Smckusick sb.f_fsid = mp->m_fsid; 30039544Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 30137741Smckusick } 30237741Smckusick 30338408Smckusick fstatfs(scp) 30438408Smckusick register struct syscontext *scp; 30537741Smckusick { 30637741Smckusick struct a { 30737741Smckusick int fd; 30837741Smckusick struct statfs *buf; 30938408Smckusick } *uap = (struct a *)scp->sc_ap; 31037741Smckusick struct file *fp; 31139464Smckusick struct mount *mp; 31237741Smckusick struct statfs sb; 31337741Smckusick int error; 31437741Smckusick 31538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 31637741Smckusick RETURN (error); 31739464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31839464Smckusick if (error = VFS_STATFS(mp, &sb)) 31937741Smckusick RETURN (error); 32039464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 32139464Smckusick sb.f_fsid = mp->m_fsid; 32237741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 32337741Smckusick } 32437741Smckusick 32537741Smckusick /* 32638270Smckusick * get statistics on all filesystems 32738270Smckusick */ 32838408Smckusick getfsstat(scp) 32938408Smckusick register struct syscontext *scp; 33038270Smckusick { 33138270Smckusick struct a { 33238270Smckusick struct statfs *buf; 33338270Smckusick long bufsize; 33438408Smckusick } *uap = (struct a *)scp->sc_ap; 33538270Smckusick register struct mount *mp; 33639606Smckusick caddr_t sfsp; 33738270Smckusick long count, maxcount, error; 33839606Smckusick struct statfs sb; 33938270Smckusick 34038270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 34139606Smckusick sfsp = (caddr_t)uap->buf; 34238270Smckusick mp = rootfs; 34338270Smckusick count = 0; 34438270Smckusick do { 34539606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 34639607Smckusick if (error = VFS_STATFS(mp, &sb)) { 34739607Smckusick mp = mp->m_prev; 34839607Smckusick continue; 34939607Smckusick } 35039606Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 35139606Smckusick sb.f_fsid = mp->m_fsid; 35239606Smckusick if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb))) 35339606Smckusick RETURN (error); 35439606Smckusick sfsp += sizeof(sb); 35538270Smckusick } 35639606Smckusick count++; 35738270Smckusick mp = mp->m_prev; 35838270Smckusick } while (mp != rootfs); 35938270Smckusick if (sfsp && count > maxcount) 36038408Smckusick scp->sc_retval1 = maxcount; 36138270Smckusick else 36238408Smckusick scp->sc_retval1 = count; 36338270Smckusick RETURN (0); 36438270Smckusick } 36538270Smckusick 36638270Smckusick /* 36738259Smckusick * Change current working directory to a given file descriptor. 36838259Smckusick */ 36938408Smckusick fchdir(scp) 37038408Smckusick register struct syscontext *scp; 37138259Smckusick { 37238259Smckusick struct a { 37338259Smckusick int fd; 37438408Smckusick } *uap = (struct a *)scp->sc_ap; 37538259Smckusick register struct vnode *vp; 37638259Smckusick struct file *fp; 37738259Smckusick int error; 37838259Smckusick 37938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 38038259Smckusick RETURN (error); 38138259Smckusick vp = (struct vnode *)fp->f_data; 38238259Smckusick VOP_LOCK(vp); 38338259Smckusick if (vp->v_type != VDIR) 38438259Smckusick error = ENOTDIR; 38538259Smckusick else 38638408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 38738259Smckusick VOP_UNLOCK(vp); 38839860Smckusick if (error) 38939860Smckusick RETURN (error); 39039860Smckusick VREF(vp); 39138408Smckusick vrele(scp->sc_cdir); 39238408Smckusick scp->sc_cdir = vp; 39339860Smckusick RETURN (0); 39438259Smckusick } 39538259Smckusick 39638259Smckusick /* 39737741Smckusick * Change current working directory (``.''). 39837741Smckusick */ 39938408Smckusick chdir(scp) 40038408Smckusick register struct syscontext *scp; 40137741Smckusick { 40237741Smckusick struct a { 4036254Sroot char *fname; 40438408Smckusick } *uap = (struct a *)scp->sc_ap; 40538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 40637741Smckusick int error; 4076254Sroot 40837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 41016694Smckusick ndp->ni_dirp = uap->fname; 41137741Smckusick if (error = chdirec(ndp)) 41237741Smckusick RETURN (error); 41338408Smckusick vrele(scp->sc_cdir); 41438408Smckusick scp->sc_cdir = ndp->ni_vp; 41537741Smckusick RETURN (0); 41637741Smckusick } 4176254Sroot 41837741Smckusick /* 41937741Smckusick * Change notion of root (``/'') directory. 42037741Smckusick */ 42138408Smckusick chroot(scp) 42238408Smckusick register struct syscontext *scp; 42337741Smckusick { 42437741Smckusick struct a { 42537741Smckusick char *fname; 42638408Smckusick } *uap = (struct a *)scp->sc_ap; 42738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 42837741Smckusick int error; 42937741Smckusick 43038408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 43137741Smckusick RETURN (error); 43237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 43337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 43437741Smckusick ndp->ni_dirp = uap->fname; 43537741Smckusick if (error = chdirec(ndp)) 43637741Smckusick RETURN (error); 43739515Smckusick if (scp->sc_rdir != NULL) 43839515Smckusick vrele(scp->sc_rdir); 43938408Smckusick scp->sc_rdir = ndp->ni_vp; 44037741Smckusick RETURN (0); 4416254Sroot } 4426254Sroot 44337Sbill /* 44437741Smckusick * Common routine for chroot and chdir. 44537741Smckusick */ 44637741Smckusick chdirec(ndp) 44737741Smckusick register struct nameidata *ndp; 44837741Smckusick { 44937741Smckusick struct vnode *vp; 45037741Smckusick int error; 45137741Smckusick 45237741Smckusick if (error = namei(ndp)) 45337741Smckusick return (error); 45437741Smckusick vp = ndp->ni_vp; 45537741Smckusick if (vp->v_type != VDIR) 45637741Smckusick error = ENOTDIR; 45737741Smckusick else 45838399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45937741Smckusick VOP_UNLOCK(vp); 46037741Smckusick if (error) 46137741Smckusick vrele(vp); 46237741Smckusick return (error); 46337741Smckusick } 46437741Smckusick 46537741Smckusick /* 4666254Sroot * Open system call. 4676254Sroot */ 46838408Smckusick open(scp) 46938408Smckusick register struct syscontext *scp; 4706254Sroot { 47112756Ssam struct a { 4726254Sroot char *fname; 4737701Ssam int mode; 47412756Ssam int crtmode; 47538408Smckusick } *uap = (struct a *) scp->sc_ap; 47638408Smckusick struct nameidata *ndp = &scp->sc_nd; 4776254Sroot 47837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47937741Smckusick ndp->ni_dirp = uap->fname; 48038408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 48138408Smckusick &scp->sc_retval1)); 4826254Sroot } 4836254Sroot 4846254Sroot /* 4856254Sroot * Creat system call. 4866254Sroot */ 48738408Smckusick creat(scp) 48838408Smckusick register struct syscontext *scp; 4896254Sroot { 49012756Ssam struct a { 4916254Sroot char *fname; 4926254Sroot int fmode; 49338408Smckusick } *uap = (struct a *)scp->sc_ap; 49438408Smckusick struct nameidata *ndp = &scp->sc_nd; 4956254Sroot 49637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49737741Smckusick ndp->ni_dirp = uap->fname; 49838408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 49938408Smckusick ndp, &scp->sc_retval1)); 5006254Sroot } 5016254Sroot 5026254Sroot /* 5036254Sroot * Common code for open and creat. 50412756Ssam * Check permissions, allocate an open file structure, 50512756Ssam * and call the device open routine if any. 5066254Sroot */ 50738408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 50838408Smckusick register struct syscontext *scp; 50937741Smckusick int fmode, cmode; 51037741Smckusick struct nameidata *ndp; 51137741Smckusick int *resultfd; 51212756Ssam { 5136254Sroot register struct file *fp; 51437741Smckusick struct file *nfp; 51537741Smckusick int indx, error; 51637741Smckusick extern struct fileops vnops; 5176254Sroot 51837741Smckusick if (error = falloc(&nfp, &indx)) 51937741Smckusick return (error); 52037741Smckusick fp = nfp; 52138408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 52237741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 52337741Smckusick crfree(fp->f_cred); 52437741Smckusick fp->f_count--; 52539499Smckusick if (error == -1) /* XXX from fdopen */ 52639499Smckusick return (0); /* XXX from fdopen */ 52739499Smckusick scp->sc_ofile[indx] = NULL; 52837741Smckusick return (error); 52912756Ssam } 53037741Smckusick fp->f_flag = fmode & FMASK; 53137741Smckusick fp->f_type = DTYPE_VNODE; 53237741Smckusick fp->f_ops = &vnops; 53337741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 53437741Smckusick if (resultfd) 53537741Smckusick *resultfd = indx; 53637741Smckusick return (0); 5376254Sroot } 5386254Sroot 5396254Sroot /* 5406254Sroot * Mknod system call 5416254Sroot */ 54238408Smckusick mknod(scp) 54338408Smckusick register struct syscontext *scp; 5446254Sroot { 5456254Sroot register struct a { 5466254Sroot char *fname; 5476254Sroot int fmode; 5486254Sroot int dev; 54938408Smckusick } *uap = (struct a *)scp->sc_ap; 55038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 55137741Smckusick register struct vnode *vp; 55237741Smckusick struct vattr vattr; 55337741Smckusick int error; 5546254Sroot 55538408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 55637741Smckusick RETURN (error); 55737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 55916694Smckusick ndp->ni_dirp = uap->fname; 56037741Smckusick if (error = namei(ndp)) 56137741Smckusick RETURN (error); 56237741Smckusick vp = ndp->ni_vp; 56337741Smckusick if (vp != NULL) { 56437741Smckusick error = EEXIST; 56512756Ssam goto out; 5666254Sroot } 56737741Smckusick vattr_null(&vattr); 56837741Smckusick switch (uap->fmode & IFMT) { 56912756Ssam 57015093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 57137741Smckusick vattr.va_type = VBAD; 57237741Smckusick break; 57312756Ssam case IFCHR: 57437741Smckusick vattr.va_type = VCHR; 57537741Smckusick break; 57612756Ssam case IFBLK: 57737741Smckusick vattr.va_type = VBLK; 57837741Smckusick break; 57937741Smckusick default: 58037741Smckusick error = EINVAL; 58137741Smckusick goto out; 5826254Sroot } 58338408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 58437741Smckusick vattr.va_rdev = uap->dev; 5856254Sroot out: 58637741Smckusick if (error) 58737741Smckusick VOP_ABORTOP(ndp); 58837741Smckusick else 58937741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 59037741Smckusick RETURN (error); 5916254Sroot } 5926254Sroot 5936254Sroot /* 5946254Sroot * link system call 5956254Sroot */ 59638408Smckusick link(scp) 59738408Smckusick register struct syscontext *scp; 5986254Sroot { 5996254Sroot register struct a { 6006254Sroot char *target; 6016254Sroot char *linkname; 60238408Smckusick } *uap = (struct a *)scp->sc_ap; 60338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 60437741Smckusick register struct vnode *vp, *xp; 60537741Smckusick int error; 6066254Sroot 60716694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 60816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 60916694Smckusick ndp->ni_dirp = uap->target; 61037741Smckusick if (error = namei(ndp)) 61137741Smckusick RETURN (error); 61237741Smckusick vp = ndp->ni_vp; 61337741Smckusick if (vp->v_type == VDIR && 61438408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 61537741Smckusick goto out1; 61637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61716694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 61837741Smckusick if (error = namei(ndp)) 61937741Smckusick goto out1; 62037741Smckusick xp = ndp->ni_vp; 6216254Sroot if (xp != NULL) { 62237741Smckusick error = EEXIST; 6236254Sroot goto out; 6246254Sroot } 62537741Smckusick xp = ndp->ni_dvp; 62637741Smckusick if (vp->v_mount != xp->v_mount) 62737741Smckusick error = EXDEV; 6286254Sroot out: 62937741Smckusick if (error) 63037741Smckusick VOP_ABORTOP(ndp); 63137741Smckusick else 63237741Smckusick error = VOP_LINK(vp, ndp); 63337741Smckusick out1: 63437741Smckusick vrele(vp); 63537741Smckusick RETURN (error); 6366254Sroot } 6376254Sroot 6386254Sroot /* 6396254Sroot * symlink -- make a symbolic link 6406254Sroot */ 64138408Smckusick symlink(scp) 64238408Smckusick register struct syscontext *scp; 6436254Sroot { 64437741Smckusick struct a { 6456254Sroot char *target; 6466254Sroot char *linkname; 64738408Smckusick } *uap = (struct a *)scp->sc_ap; 64838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64937741Smckusick register struct vnode *vp; 65037741Smckusick struct vattr vattr; 65137741Smckusick char *target; 65237741Smckusick int error; 6536254Sroot 65416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 65516694Smckusick ndp->ni_dirp = uap->linkname; 65637741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 65737741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 65837741Smckusick goto out1; 65937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 66037741Smckusick if (error = namei(ndp)) 66137741Smckusick goto out1; 66237741Smckusick vp = ndp->ni_vp; 66337741Smckusick if (vp) { 66437741Smckusick error = EEXIST; 66537741Smckusick goto out; 6666254Sroot } 66737741Smckusick vp = ndp->ni_dvp; 66837741Smckusick vattr_null(&vattr); 66938408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 67037741Smckusick out: 67137741Smckusick if (error) 67237741Smckusick VOP_ABORTOP(ndp); 67337741Smckusick else 67437741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 67537741Smckusick out1: 67637741Smckusick FREE(target, M_NAMEI); 67737741Smckusick RETURN (error); 6786254Sroot } 6796254Sroot 6806254Sroot /* 6816254Sroot * Unlink system call. 6826254Sroot * Hard to avoid races here, especially 6836254Sroot * in unlinking directories. 6846254Sroot */ 68538408Smckusick unlink(scp) 68638408Smckusick register struct syscontext *scp; 6876254Sroot { 6886254Sroot struct a { 6896254Sroot char *fname; 69038408Smckusick } *uap = (struct a *)scp->sc_ap; 69138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 69237741Smckusick register struct vnode *vp; 69337741Smckusick int error; 6946254Sroot 69537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 69616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69716694Smckusick ndp->ni_dirp = uap->fname; 69837741Smckusick if (error = namei(ndp)) 69937741Smckusick RETURN (error); 70037741Smckusick vp = ndp->ni_vp; 70137741Smckusick if (vp->v_type == VDIR && 70238408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7036254Sroot goto out; 7046254Sroot /* 7056254Sroot * Don't unlink a mounted file. 7066254Sroot */ 70737741Smckusick if (vp->v_flag & VROOT) { 70837741Smckusick error = EBUSY; 7096254Sroot goto out; 7106254Sroot } 71137741Smckusick if (vp->v_flag & VTEXT) 71237741Smckusick xrele(vp); /* try once to free text */ 7136254Sroot out: 71437741Smckusick if (error) 71537741Smckusick VOP_ABORTOP(ndp); 7167142Smckusick else 71737741Smckusick error = VOP_REMOVE(ndp); 71837741Smckusick RETURN (error); 7196254Sroot } 7206254Sroot 7216254Sroot /* 7226254Sroot * Seek system call 7236254Sroot */ 72438408Smckusick lseek(scp) 72538408Smckusick register struct syscontext *scp; 7266254Sroot { 7276254Sroot register struct file *fp; 7286254Sroot register struct a { 72937741Smckusick int fdes; 7306254Sroot off_t off; 7316254Sroot int sbase; 73238408Smckusick } *uap = (struct a *)scp->sc_ap; 73337741Smckusick struct vattr vattr; 73437741Smckusick int error; 7356254Sroot 73637741Smckusick if ((unsigned)uap->fdes >= NOFILE || 73738408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 73837741Smckusick RETURN (EBADF); 73937741Smckusick if (fp->f_type != DTYPE_VNODE) 74037741Smckusick RETURN (ESPIPE); 74113878Ssam switch (uap->sbase) { 74213878Ssam 74313878Ssam case L_INCR: 74413878Ssam fp->f_offset += uap->off; 74513878Ssam break; 74613878Ssam 74713878Ssam case L_XTND: 74837741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 74938408Smckusick &vattr, scp->sc_cred)) 75037741Smckusick RETURN (error); 75137741Smckusick fp->f_offset = uap->off + vattr.va_size; 75213878Ssam break; 75313878Ssam 75413878Ssam case L_SET: 75513878Ssam fp->f_offset = uap->off; 75613878Ssam break; 75713878Ssam 75813878Ssam default: 75937741Smckusick RETURN (EINVAL); 76013878Ssam } 76138408Smckusick scp->sc_offset = fp->f_offset; 76237741Smckusick RETURN (0); 7636254Sroot } 7646254Sroot 7656254Sroot /* 7666254Sroot * Access system call 7676254Sroot */ 76838408Smckusick saccess(scp) 76938408Smckusick register struct syscontext *scp; 7706254Sroot { 7716254Sroot register struct a { 7726254Sroot char *fname; 7736254Sroot int fmode; 77438408Smckusick } *uap = (struct a *)scp->sc_ap; 77538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 77637741Smckusick register struct vnode *vp; 77737741Smckusick int error, mode, svuid, svgid; 7786254Sroot 77938408Smckusick svuid = scp->sc_uid; 78038408Smckusick svgid = scp->sc_gid; 78138408Smckusick scp->sc_uid = scp->sc_ruid; 78238408Smckusick scp->sc_gid = scp->sc_rgid; 78337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 78416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78516694Smckusick ndp->ni_dirp = uap->fname; 78637741Smckusick if (error = namei(ndp)) 78737741Smckusick goto out1; 78837741Smckusick vp = ndp->ni_vp; 78937741Smckusick /* 79037741Smckusick * fmode == 0 means only check for exist 79137741Smckusick */ 79237741Smckusick if (uap->fmode) { 79337741Smckusick mode = 0; 79437741Smckusick if (uap->fmode & R_OK) 79537741Smckusick mode |= VREAD; 79637741Smckusick if (uap->fmode & W_OK) 79737741Smckusick mode |= VWRITE; 79837741Smckusick if (uap->fmode & X_OK) 79937741Smckusick mode |= VEXEC; 80039543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 80138399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 8026254Sroot } 80337741Smckusick vput(vp); 80437741Smckusick out1: 80538408Smckusick scp->sc_uid = svuid; 80638408Smckusick scp->sc_gid = svgid; 80737741Smckusick RETURN (error); 8086254Sroot } 8096254Sroot 8106254Sroot /* 8116574Smckusic * Stat system call. This version follows links. 81237Sbill */ 81338408Smckusick stat(scp) 81438408Smckusick struct syscontext *scp; 81537Sbill { 81637Sbill 81738408Smckusick stat1(scp, FOLLOW); 81837Sbill } 81937Sbill 82037Sbill /* 8216574Smckusic * Lstat system call. This version does not follow links. 8225992Swnj */ 82338408Smckusick lstat(scp) 82438408Smckusick struct syscontext *scp; 8255992Swnj { 82612756Ssam 82738408Smckusick stat1(scp, NOFOLLOW); 82812756Ssam } 82912756Ssam 83038408Smckusick stat1(scp, follow) 83138408Smckusick register struct syscontext *scp; 83212756Ssam int follow; 83312756Ssam { 8345992Swnj register struct a { 8355992Swnj char *fname; 83612756Ssam struct stat *ub; 83738408Smckusick } *uap = (struct a *)scp->sc_ap; 83838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 83912756Ssam struct stat sb; 84037741Smckusick int error; 8415992Swnj 84237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 84316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 84416694Smckusick ndp->ni_dirp = uap->fname; 84537741Smckusick if (error = namei(ndp)) 84637741Smckusick RETURN (error); 84737741Smckusick error = vn_stat(ndp->ni_vp, &sb); 84837741Smckusick vput(ndp->ni_vp); 84937741Smckusick if (error) 85037741Smckusick RETURN (error); 85137741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 85237741Smckusick RETURN (error); 8535992Swnj } 8545992Swnj 8555992Swnj /* 8565992Swnj * Return target name of a symbolic link 85737Sbill */ 85838408Smckusick readlink(scp) 85938408Smckusick register struct syscontext *scp; 8605992Swnj { 8615992Swnj register struct a { 8625992Swnj char *name; 8635992Swnj char *buf; 8645992Swnj int count; 86538408Smckusick } *uap = (struct a *)scp->sc_ap; 86638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 86737741Smckusick register struct vnode *vp; 86837741Smckusick struct iovec aiov; 86937741Smckusick struct uio auio; 87037741Smckusick int error; 8715992Swnj 87237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 87316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 87416694Smckusick ndp->ni_dirp = uap->name; 87537741Smckusick if (error = namei(ndp)) 87637741Smckusick RETURN (error); 87737741Smckusick vp = ndp->ni_vp; 87837741Smckusick if (vp->v_type != VLNK) { 87937741Smckusick error = EINVAL; 8805992Swnj goto out; 8815992Swnj } 88237741Smckusick aiov.iov_base = uap->buf; 88337741Smckusick aiov.iov_len = uap->count; 88437741Smckusick auio.uio_iov = &aiov; 88537741Smckusick auio.uio_iovcnt = 1; 88637741Smckusick auio.uio_offset = 0; 88737741Smckusick auio.uio_rw = UIO_READ; 88837741Smckusick auio.uio_segflg = UIO_USERSPACE; 88937741Smckusick auio.uio_resid = uap->count; 89037741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8915992Swnj out: 89237741Smckusick vput(vp); 89338408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 89437741Smckusick RETURN (error); 8955992Swnj } 8965992Swnj 8979167Ssam /* 89838259Smckusick * Change flags of a file given path name. 89938259Smckusick */ 90038408Smckusick chflags(scp) 90138408Smckusick register struct syscontext *scp; 90238259Smckusick { 90338259Smckusick struct a { 90438259Smckusick char *fname; 90538259Smckusick int flags; 90638408Smckusick } *uap = (struct a *)scp->sc_ap; 90738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90838259Smckusick register struct vnode *vp; 90938259Smckusick struct vattr vattr; 91038259Smckusick int error; 91138259Smckusick 91238259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 91338259Smckusick ndp->ni_segflg = UIO_USERSPACE; 91438259Smckusick ndp->ni_dirp = uap->fname; 91538259Smckusick vattr_null(&vattr); 91638259Smckusick vattr.va_flags = uap->flags; 91738259Smckusick if (error = namei(ndp)) 91838259Smckusick RETURN (error); 91938259Smckusick vp = ndp->ni_vp; 92038259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 92138259Smckusick error = EROFS; 92238259Smckusick goto out; 92338259Smckusick } 92438259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 92538259Smckusick out: 92638259Smckusick vput(vp); 92738259Smckusick RETURN (error); 92838259Smckusick } 92938259Smckusick 93038259Smckusick /* 93138259Smckusick * Change flags of a file given a file descriptor. 93238259Smckusick */ 93338408Smckusick fchflags(scp) 93438408Smckusick register struct syscontext *scp; 93538259Smckusick { 93638259Smckusick struct a { 93738259Smckusick int fd; 93838259Smckusick int flags; 93938408Smckusick } *uap = (struct a *)scp->sc_ap; 94038259Smckusick struct vattr vattr; 94138259Smckusick struct vnode *vp; 94238259Smckusick struct file *fp; 94338259Smckusick int error; 94438259Smckusick 94538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 94638259Smckusick RETURN (error); 94738259Smckusick vattr_null(&vattr); 94838259Smckusick vattr.va_flags = uap->flags; 94938259Smckusick vp = (struct vnode *)fp->f_data; 95038259Smckusick VOP_LOCK(vp); 95138259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 95238259Smckusick error = EROFS; 95338259Smckusick goto out; 95438259Smckusick } 95538259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 95638259Smckusick out: 95738259Smckusick VOP_UNLOCK(vp); 95838259Smckusick RETURN (error); 95938259Smckusick } 96038259Smckusick 96138259Smckusick /* 9629167Ssam * Change mode of a file given path name. 9639167Ssam */ 96438408Smckusick chmod(scp) 96538408Smckusick register struct syscontext *scp; 9665992Swnj { 9677701Ssam struct a { 9686254Sroot char *fname; 9696254Sroot int fmode; 97038408Smckusick } *uap = (struct a *)scp->sc_ap; 97138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 97237741Smckusick register struct vnode *vp; 97337741Smckusick struct vattr vattr; 97437741Smckusick int error; 9755992Swnj 97637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 97737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 97837741Smckusick ndp->ni_dirp = uap->fname; 97937741Smckusick vattr_null(&vattr); 98037741Smckusick vattr.va_mode = uap->fmode & 07777; 98137741Smckusick if (error = namei(ndp)) 98237741Smckusick RETURN (error); 98337741Smckusick vp = ndp->ni_vp; 98437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98537741Smckusick error = EROFS; 98637741Smckusick goto out; 98737741Smckusick } 98837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 98937741Smckusick out: 99037741Smckusick vput(vp); 99137741Smckusick RETURN (error); 9927701Ssam } 9937439Sroot 9949167Ssam /* 9959167Ssam * Change mode of a file given a file descriptor. 9969167Ssam */ 99738408Smckusick fchmod(scp) 99838408Smckusick register struct syscontext *scp; 9997701Ssam { 10007701Ssam struct a { 10017701Ssam int fd; 10027701Ssam int fmode; 100338408Smckusick } *uap = (struct a *)scp->sc_ap; 100437741Smckusick struct vattr vattr; 100537741Smckusick struct vnode *vp; 100637741Smckusick struct file *fp; 100737741Smckusick int error; 10087701Ssam 100938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 101037741Smckusick RETURN (error); 101137741Smckusick vattr_null(&vattr); 101237741Smckusick vattr.va_mode = uap->fmode & 07777; 101337741Smckusick vp = (struct vnode *)fp->f_data; 101437741Smckusick VOP_LOCK(vp); 101537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101637741Smckusick error = EROFS; 101737741Smckusick goto out; 10187439Sroot } 101937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 102037741Smckusick out: 102137741Smckusick VOP_UNLOCK(vp); 102237741Smckusick RETURN (error); 10235992Swnj } 10245992Swnj 10259167Ssam /* 10269167Ssam * Set ownership given a path name. 10279167Ssam */ 102838408Smckusick chown(scp) 102938408Smckusick register struct syscontext *scp; 103037Sbill { 10317701Ssam struct a { 10326254Sroot char *fname; 10336254Sroot int uid; 10346254Sroot int gid; 103538408Smckusick } *uap = (struct a *)scp->sc_ap; 103638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 103737741Smckusick register struct vnode *vp; 103837741Smckusick struct vattr vattr; 103937741Smckusick int error; 104037Sbill 104137741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 104236614Sbostic ndp->ni_segflg = UIO_USERSPACE; 104336614Sbostic ndp->ni_dirp = uap->fname; 104437741Smckusick vattr_null(&vattr); 104537741Smckusick vattr.va_uid = uap->uid; 104637741Smckusick vattr.va_gid = uap->gid; 104737741Smckusick if (error = namei(ndp)) 104837741Smckusick RETURN (error); 104937741Smckusick vp = ndp->ni_vp; 105037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 105137741Smckusick error = EROFS; 105237741Smckusick goto out; 105337741Smckusick } 105437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 105537741Smckusick out: 105637741Smckusick vput(vp); 105737741Smckusick RETURN (error); 10587701Ssam } 10597439Sroot 10609167Ssam /* 10619167Ssam * Set ownership given a file descriptor. 10629167Ssam */ 106338408Smckusick fchown(scp) 106438408Smckusick register struct syscontext *scp; 10657701Ssam { 10667701Ssam struct a { 10677701Ssam int fd; 10687701Ssam int uid; 10697701Ssam int gid; 107038408Smckusick } *uap = (struct a *)scp->sc_ap; 107137741Smckusick struct vattr vattr; 107237741Smckusick struct vnode *vp; 107337741Smckusick struct file *fp; 107437741Smckusick int error; 10757701Ssam 107638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 107737741Smckusick RETURN (error); 107837741Smckusick vattr_null(&vattr); 107937741Smckusick vattr.va_uid = uap->uid; 108037741Smckusick vattr.va_gid = uap->gid; 108137741Smckusick vp = (struct vnode *)fp->f_data; 108237741Smckusick VOP_LOCK(vp); 108337741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 108437741Smckusick error = EROFS; 108537741Smckusick goto out; 108637741Smckusick } 108737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108837741Smckusick out: 108937741Smckusick VOP_UNLOCK(vp); 109037741Smckusick RETURN (error); 10917701Ssam } 10927701Ssam 109338408Smckusick utimes(scp) 109438408Smckusick register struct syscontext *scp; 109511811Ssam { 109611811Ssam register struct a { 109711811Ssam char *fname; 109811811Ssam struct timeval *tptr; 109938408Smckusick } *uap = (struct a *)scp->sc_ap; 110038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 110137741Smckusick register struct vnode *vp; 110211811Ssam struct timeval tv[2]; 110337741Smckusick struct vattr vattr; 110437741Smckusick int error; 110511811Ssam 110637741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 110737741Smckusick RETURN (error); 110837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 110937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 111037741Smckusick ndp->ni_dirp = uap->fname; 111137741Smckusick vattr_null(&vattr); 111237741Smckusick vattr.va_atime = tv[0]; 111337741Smckusick vattr.va_mtime = tv[1]; 111437741Smckusick if (error = namei(ndp)) 111537741Smckusick RETURN (error); 111637741Smckusick vp = ndp->ni_vp; 111737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 111837741Smckusick error = EROFS; 111937741Smckusick goto out; 112021015Smckusick } 112137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 112237741Smckusick out: 112337741Smckusick vput(vp); 112437741Smckusick RETURN (error); 112511811Ssam } 112611811Ssam 11279167Ssam /* 11289167Ssam * Truncate a file given its path name. 11299167Ssam */ 113038408Smckusick truncate(scp) 113138408Smckusick register struct syscontext *scp; 11327701Ssam { 11337701Ssam struct a { 11347701Ssam char *fname; 113526473Skarels off_t length; 113638408Smckusick } *uap = (struct a *)scp->sc_ap; 113738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 113837741Smckusick register struct vnode *vp; 113937741Smckusick struct vattr vattr; 114037741Smckusick int error; 11417701Ssam 114237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 114416694Smckusick ndp->ni_dirp = uap->fname; 114537741Smckusick vattr_null(&vattr); 114637741Smckusick vattr.va_size = uap->length; 114737741Smckusick if (error = namei(ndp)) 114837741Smckusick RETURN (error); 114937741Smckusick vp = ndp->ni_vp; 115037741Smckusick if (vp->v_type == VDIR) { 115137741Smckusick error = EISDIR; 115237741Smckusick goto out; 11537701Ssam } 115438399Smckusick if ((error = vn_writechk(vp)) || 115538399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 115637741Smckusick goto out; 115737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115837741Smckusick out: 115937741Smckusick vput(vp); 116037741Smckusick RETURN (error); 11617701Ssam } 11627701Ssam 11639167Ssam /* 11649167Ssam * Truncate a file given a file descriptor. 11659167Ssam */ 116638408Smckusick ftruncate(scp) 116738408Smckusick register struct syscontext *scp; 11687701Ssam { 11697701Ssam struct a { 11707701Ssam int fd; 117126473Skarels off_t length; 117238408Smckusick } *uap = (struct a *)scp->sc_ap; 117337741Smckusick struct vattr vattr; 117437741Smckusick struct vnode *vp; 11757701Ssam struct file *fp; 117637741Smckusick int error; 11777701Ssam 117838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 117937741Smckusick RETURN (error); 118037741Smckusick if ((fp->f_flag & FWRITE) == 0) 118137741Smckusick RETURN (EINVAL); 118237741Smckusick vattr_null(&vattr); 118337741Smckusick vattr.va_size = uap->length; 118437741Smckusick vp = (struct vnode *)fp->f_data; 118537741Smckusick VOP_LOCK(vp); 118637741Smckusick if (vp->v_type == VDIR) { 118737741Smckusick error = EISDIR; 118837741Smckusick goto out; 11897701Ssam } 119038399Smckusick if (error = vn_writechk(vp)) 119137741Smckusick goto out; 119237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 119337741Smckusick out: 119437741Smckusick VOP_UNLOCK(vp); 119537741Smckusick RETURN (error); 11967701Ssam } 11977701Ssam 11989167Ssam /* 11999167Ssam * Synch an open file. 12009167Ssam */ 120138408Smckusick fsync(scp) 120238408Smckusick register struct syscontext *scp; 12039167Ssam { 12049167Ssam struct a { 12059167Ssam int fd; 120638408Smckusick } *uap = (struct a *)scp->sc_ap; 120739592Smckusick register struct vnode *vp; 12089167Ssam struct file *fp; 120937741Smckusick int error; 12109167Ssam 121138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 121237741Smckusick RETURN (error); 121339592Smckusick vp = (struct vnode *)fp->f_data; 121439592Smckusick VOP_LOCK(vp); 121539592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 121639592Smckusick VOP_UNLOCK(vp); 121737741Smckusick RETURN (error); 12189167Ssam } 12199167Ssam 12209167Ssam /* 12219167Ssam * Rename system call. 12229167Ssam * 12239167Ssam * Source and destination must either both be directories, or both 12249167Ssam * not be directories. If target is a directory, it must be empty. 12259167Ssam */ 122638408Smckusick rename(scp) 122738408Smckusick register struct syscontext *scp; 12287701Ssam { 12297701Ssam struct a { 12307701Ssam char *from; 12317701Ssam char *to; 123238408Smckusick } *uap = (struct a *)scp->sc_ap; 123337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 123438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 123537741Smckusick struct nameidata tond; 123637741Smckusick int error; 12377701Ssam 123837741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 123916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 124016694Smckusick ndp->ni_dirp = uap->from; 124137741Smckusick if (error = namei(ndp)) 124237741Smckusick RETURN (error); 124337741Smckusick fvp = ndp->ni_vp; 124438266Smckusick nddup(ndp, &tond); 124537741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 124637741Smckusick tond.ni_segflg = UIO_USERSPACE; 124737741Smckusick tond.ni_dirp = uap->to; 124837741Smckusick error = namei(&tond); 124937741Smckusick tdvp = tond.ni_dvp; 125037741Smckusick tvp = tond.ni_vp; 125137741Smckusick if (tvp != NULL) { 125237741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 125339242Sbostic error = ENOTDIR; 125437741Smckusick goto out; 125537741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 125639242Sbostic error = EISDIR; 125737741Smckusick goto out; 12589167Ssam } 12599167Ssam } 126037741Smckusick if (error) { 126137741Smckusick VOP_ABORTOP(ndp); 126237741Smckusick goto out1; 126337741Smckusick } 126437741Smckusick if (fvp->v_mount != tdvp->v_mount) { 126537741Smckusick error = EXDEV; 12669167Ssam goto out; 126710051Ssam } 126839286Smckusick if (fvp == tdvp) 126937741Smckusick error = EINVAL; 127039286Smckusick /* 127139286Smckusick * If source is the same as the destination, 127239286Smckusick * then there is nothing to do. 127339286Smckusick */ 127439286Smckusick if (fvp == tvp) 127539286Smckusick error = -1; 127637741Smckusick out: 127737741Smckusick if (error) { 127837741Smckusick VOP_ABORTOP(&tond); 127937741Smckusick VOP_ABORTOP(ndp); 12809167Ssam } else { 128137741Smckusick error = VOP_RENAME(ndp, &tond); 12829167Ssam } 128337741Smckusick out1: 128438266Smckusick ndrele(&tond); 128539286Smckusick if (error == -1) 128639286Smckusick RETURN (0); 128737741Smckusick RETURN (error); 12887701Ssam } 12897701Ssam 12907535Sroot /* 129112756Ssam * Mkdir system call 129212756Ssam */ 129338408Smckusick mkdir(scp) 129438408Smckusick register struct syscontext *scp; 129512756Ssam { 129612756Ssam struct a { 129712756Ssam char *name; 129812756Ssam int dmode; 129938408Smckusick } *uap = (struct a *)scp->sc_ap; 130038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 130137741Smckusick register struct vnode *vp; 130237741Smckusick struct vattr vattr; 130337741Smckusick int error; 130412756Ssam 130537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 130616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130716694Smckusick ndp->ni_dirp = uap->name; 130837741Smckusick if (error = namei(ndp)) 130937741Smckusick RETURN (error); 131037741Smckusick vp = ndp->ni_vp; 131137741Smckusick if (vp != NULL) { 131237741Smckusick VOP_ABORTOP(ndp); 131337741Smckusick RETURN (EEXIST); 131412756Ssam } 131537741Smckusick vattr_null(&vattr); 131637741Smckusick vattr.va_type = VDIR; 131738408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 131837741Smckusick error = VOP_MKDIR(ndp, &vattr); 131938145Smckusick if (!error) 132038145Smckusick vput(ndp->ni_vp); 132137741Smckusick RETURN (error); 132212756Ssam } 132312756Ssam 132412756Ssam /* 132512756Ssam * Rmdir system call. 132612756Ssam */ 132738408Smckusick rmdir(scp) 132838408Smckusick register struct syscontext *scp; 132912756Ssam { 133012756Ssam struct a { 133112756Ssam char *name; 133238408Smckusick } *uap = (struct a *)scp->sc_ap; 133338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 133437741Smckusick register struct vnode *vp; 133537741Smckusick int error; 133612756Ssam 133737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 133816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 133916694Smckusick ndp->ni_dirp = uap->name; 134037741Smckusick if (error = namei(ndp)) 134137741Smckusick RETURN (error); 134237741Smckusick vp = ndp->ni_vp; 134337741Smckusick if (vp->v_type != VDIR) { 134437741Smckusick error = ENOTDIR; 134512756Ssam goto out; 134612756Ssam } 134712756Ssam /* 134837741Smckusick * No rmdir "." please. 134912756Ssam */ 135037741Smckusick if (ndp->ni_dvp == vp) { 135137741Smckusick error = EINVAL; 135212756Ssam goto out; 135312756Ssam } 135412756Ssam /* 135537741Smckusick * Don't unlink a mounted file. 135612756Ssam */ 135737741Smckusick if (vp->v_flag & VROOT) 135837741Smckusick error = EBUSY; 135912756Ssam out: 136037741Smckusick if (error) 136137741Smckusick VOP_ABORTOP(ndp); 136237741Smckusick else 136337741Smckusick error = VOP_RMDIR(ndp); 136437741Smckusick RETURN (error); 136512756Ssam } 136612756Ssam 136737741Smckusick /* 136837741Smckusick * Read a block of directory entries in a file system independent format 136937741Smckusick */ 137038408Smckusick getdirentries(scp) 137138408Smckusick register struct syscontext *scp; 137212756Ssam { 137337741Smckusick register struct a { 137437741Smckusick int fd; 137537741Smckusick char *buf; 137637741Smckusick unsigned count; 137737741Smckusick long *basep; 137838408Smckusick } *uap = (struct a *)scp->sc_ap; 137939592Smckusick register struct vnode *vp; 138016540Ssam struct file *fp; 138137741Smckusick struct uio auio; 138237741Smckusick struct iovec aiov; 138338129Smckusick off_t off; 138437741Smckusick int error; 138512756Ssam 138638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 138737741Smckusick RETURN (error); 138837741Smckusick if ((fp->f_flag & FREAD) == 0) 138937741Smckusick RETURN (EBADF); 139039592Smckusick vp = (struct vnode *)fp->f_data; 139139592Smckusick if (vp->v_type != VDIR) 139239592Smckusick RETURN (EINVAL); 139337741Smckusick aiov.iov_base = uap->buf; 139437741Smckusick aiov.iov_len = uap->count; 139537741Smckusick auio.uio_iov = &aiov; 139637741Smckusick auio.uio_iovcnt = 1; 139737741Smckusick auio.uio_rw = UIO_READ; 139837741Smckusick auio.uio_segflg = UIO_USERSPACE; 139937741Smckusick auio.uio_resid = uap->count; 140039592Smckusick VOP_LOCK(vp); 140139592Smckusick auio.uio_offset = off = fp->f_offset; 140239592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 140339592Smckusick fp->f_offset = auio.uio_offset; 140439592Smckusick VOP_UNLOCK(vp); 140539592Smckusick if (error) 140637741Smckusick RETURN (error); 140739592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 140838408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 140937741Smckusick RETURN (error); 141012756Ssam } 141112756Ssam 141212756Ssam /* 141312756Ssam * mode mask for creation of files 141412756Ssam */ 141538408Smckusick umask(scp) 141638408Smckusick register struct syscontext *scp; 141712756Ssam { 141812756Ssam register struct a { 141912756Ssam int mask; 142038408Smckusick } *uap = (struct a *)scp->sc_ap; 142112756Ssam 142238408Smckusick scp->sc_retval1 = scp->sc_cmask; 142338408Smckusick scp->sc_cmask = uap->mask & 07777; 142437741Smckusick RETURN (0); 142512756Ssam } 142637741Smckusick 142739566Smarc /* 142839566Smarc * Void all references to file by ripping underlying filesystem 142939566Smarc * away from vnode. 143039566Smarc */ 143139566Smarc revoke(scp) 143239566Smarc register struct syscontext *scp; 143339566Smarc { 143439566Smarc struct a { 143539566Smarc char *fname; 143639566Smarc } *uap = (struct a *)scp->sc_ap; 143739566Smarc register struct nameidata *ndp = &scp->sc_nd; 143839566Smarc register struct vnode *vp; 143939566Smarc struct vattr vattr; 144039566Smarc int error; 144139566Smarc 144239566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 144339566Smarc ndp->ni_segflg = UIO_USERSPACE; 144439566Smarc ndp->ni_dirp = uap->fname; 144539566Smarc if (error = namei(ndp)) 144639566Smarc RETURN (error); 144739566Smarc vp = ndp->ni_vp; 144839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 144939566Smarc error = EINVAL; 145039566Smarc goto out; 145139566Smarc } 145239566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 145339566Smarc goto out; 145439566Smarc if (scp->sc_uid != vattr.va_uid || 145539566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 145639566Smarc goto out; 145739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 145839632Smckusick vgoneall(vp); 145939566Smarc out: 146039566Smarc vrele(vp); 146139566Smarc RETURN (error); 146239566Smarc } 146339566Smarc 146438408Smckusick getvnode(ofile, fdes, fpp) 146538408Smckusick struct file *ofile[]; 146637741Smckusick struct file **fpp; 146737741Smckusick int fdes; 146837741Smckusick { 146937741Smckusick struct file *fp; 147037741Smckusick 147138408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 147237741Smckusick return (EBADF); 147337741Smckusick if (fp->f_type != DTYPE_VNODE) 147437741Smckusick return (EINVAL); 147537741Smckusick *fpp = fp; 147637741Smckusick return (0); 147737741Smckusick } 1478