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*40321Smckusick * @(#)vfs_syscalls.c 7.40 (Berkeley) 03/06/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; 5540111Smckusick 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 } 8640111Smckusick 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); 15940111Smckusick if (error) 16040111Smckusick 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 /* 59440285Smckusick * Mkfifo system call 59540285Smckusick */ 59640285Smckusick mkfifo(scp) 59740285Smckusick register struct syscontext *scp; 59840285Smckusick { 59940285Smckusick register struct a { 60040285Smckusick char *fname; 60140285Smckusick int fmode; 60240285Smckusick } *uap = (struct a *)scp->sc_ap; 60340285Smckusick register struct nameidata *ndp = &scp->sc_nd; 60440285Smckusick struct vattr vattr; 60540285Smckusick int error; 60640285Smckusick 60740285Smckusick #ifndef FIFO 60840285Smckusick RETURN (EOPNOTSUPP); 60940285Smckusick #else 61040285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61140285Smckusick ndp->ni_segflg = UIO_USERSPACE; 61240285Smckusick ndp->ni_dirp = uap->fname; 61340285Smckusick if (error = namei(ndp)) 61440285Smckusick RETURN (error); 61540285Smckusick if (ndp->ni_vp != NULL) { 61640285Smckusick VOP_ABORTOP(ndp); 61740285Smckusick RETURN (EEXIST); 61840285Smckusick } else { 61940285Smckusick vattr_null(&vattr); 62040285Smckusick vattr.va_type = VFIFO; 62140285Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 62240285Smckusick } 62340285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 62440285Smckusick #endif /* FIFO */ 62540285Smckusick } 62640285Smckusick 62740285Smckusick /* 6286254Sroot * link system call 6296254Sroot */ 63038408Smckusick link(scp) 63138408Smckusick register struct syscontext *scp; 6326254Sroot { 6336254Sroot register struct a { 6346254Sroot char *target; 6356254Sroot char *linkname; 63638408Smckusick } *uap = (struct a *)scp->sc_ap; 63738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 63837741Smckusick register struct vnode *vp, *xp; 63937741Smckusick int error; 6406254Sroot 64116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 64216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64316694Smckusick ndp->ni_dirp = uap->target; 64437741Smckusick if (error = namei(ndp)) 64537741Smckusick RETURN (error); 64637741Smckusick vp = ndp->ni_vp; 64737741Smckusick if (vp->v_type == VDIR && 64838408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 64937741Smckusick goto out1; 65037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 65237741Smckusick if (error = namei(ndp)) 65337741Smckusick goto out1; 65437741Smckusick xp = ndp->ni_vp; 6556254Sroot if (xp != NULL) { 65637741Smckusick error = EEXIST; 6576254Sroot goto out; 6586254Sroot } 65937741Smckusick xp = ndp->ni_dvp; 66037741Smckusick if (vp->v_mount != xp->v_mount) 66137741Smckusick error = EXDEV; 6626254Sroot out: 66337741Smckusick if (error) 66437741Smckusick VOP_ABORTOP(ndp); 66537741Smckusick else 66637741Smckusick error = VOP_LINK(vp, ndp); 66737741Smckusick out1: 66837741Smckusick vrele(vp); 66937741Smckusick RETURN (error); 6706254Sroot } 6716254Sroot 6726254Sroot /* 6736254Sroot * symlink -- make a symbolic link 6746254Sroot */ 67538408Smckusick symlink(scp) 67638408Smckusick register struct syscontext *scp; 6776254Sroot { 67837741Smckusick struct a { 6796254Sroot char *target; 6806254Sroot char *linkname; 68138408Smckusick } *uap = (struct a *)scp->sc_ap; 68238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68337741Smckusick register struct vnode *vp; 68437741Smckusick struct vattr vattr; 68537741Smckusick char *target; 68637741Smckusick int error; 6876254Sroot 68816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68916694Smckusick ndp->ni_dirp = uap->linkname; 69037741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 69137741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 69237741Smckusick goto out1; 69337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69437741Smckusick if (error = namei(ndp)) 69537741Smckusick goto out1; 69637741Smckusick vp = ndp->ni_vp; 69737741Smckusick if (vp) { 69837741Smckusick error = EEXIST; 69937741Smckusick goto out; 7006254Sroot } 70137741Smckusick vp = ndp->ni_dvp; 70237741Smckusick vattr_null(&vattr); 70338408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 70437741Smckusick out: 70537741Smckusick if (error) 70637741Smckusick VOP_ABORTOP(ndp); 70737741Smckusick else 70837741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 70937741Smckusick out1: 71037741Smckusick FREE(target, M_NAMEI); 71137741Smckusick RETURN (error); 7126254Sroot } 7136254Sroot 7146254Sroot /* 7156254Sroot * Unlink system call. 7166254Sroot * Hard to avoid races here, especially 7176254Sroot * in unlinking directories. 7186254Sroot */ 71938408Smckusick unlink(scp) 72038408Smckusick register struct syscontext *scp; 7216254Sroot { 7226254Sroot struct a { 7236254Sroot char *fname; 72438408Smckusick } *uap = (struct a *)scp->sc_ap; 72538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 72637741Smckusick register struct vnode *vp; 72737741Smckusick int error; 7286254Sroot 72937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 73016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73116694Smckusick ndp->ni_dirp = uap->fname; 73237741Smckusick if (error = namei(ndp)) 73337741Smckusick RETURN (error); 73437741Smckusick vp = ndp->ni_vp; 73537741Smckusick if (vp->v_type == VDIR && 73638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7376254Sroot goto out; 7386254Sroot /* 7396254Sroot * Don't unlink a mounted file. 7406254Sroot */ 74137741Smckusick if (vp->v_flag & VROOT) { 74237741Smckusick error = EBUSY; 7436254Sroot goto out; 7446254Sroot } 74537741Smckusick if (vp->v_flag & VTEXT) 74637741Smckusick xrele(vp); /* try once to free text */ 7476254Sroot out: 74837741Smckusick if (error) 74937741Smckusick VOP_ABORTOP(ndp); 7507142Smckusick else 75137741Smckusick error = VOP_REMOVE(ndp); 75237741Smckusick RETURN (error); 7536254Sroot } 7546254Sroot 7556254Sroot /* 7566254Sroot * Seek system call 7576254Sroot */ 75838408Smckusick lseek(scp) 75938408Smckusick register struct syscontext *scp; 7606254Sroot { 7616254Sroot register struct file *fp; 7626254Sroot register struct a { 76337741Smckusick int fdes; 7646254Sroot off_t off; 7656254Sroot int sbase; 76638408Smckusick } *uap = (struct a *)scp->sc_ap; 76737741Smckusick struct vattr vattr; 76837741Smckusick int error; 7696254Sroot 77037741Smckusick if ((unsigned)uap->fdes >= NOFILE || 77138408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 77237741Smckusick RETURN (EBADF); 77337741Smckusick if (fp->f_type != DTYPE_VNODE) 77437741Smckusick RETURN (ESPIPE); 77513878Ssam switch (uap->sbase) { 77613878Ssam 77713878Ssam case L_INCR: 77813878Ssam fp->f_offset += uap->off; 77913878Ssam break; 78013878Ssam 78113878Ssam case L_XTND: 78237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 78338408Smckusick &vattr, scp->sc_cred)) 78437741Smckusick RETURN (error); 78537741Smckusick fp->f_offset = uap->off + vattr.va_size; 78613878Ssam break; 78713878Ssam 78813878Ssam case L_SET: 78913878Ssam fp->f_offset = uap->off; 79013878Ssam break; 79113878Ssam 79213878Ssam default: 79337741Smckusick RETURN (EINVAL); 79413878Ssam } 79538408Smckusick scp->sc_offset = fp->f_offset; 79637741Smckusick RETURN (0); 7976254Sroot } 7986254Sroot 7996254Sroot /* 8006254Sroot * Access system call 8016254Sroot */ 80238408Smckusick saccess(scp) 80338408Smckusick register struct syscontext *scp; 8046254Sroot { 8056254Sroot register struct a { 8066254Sroot char *fname; 8076254Sroot int fmode; 80838408Smckusick } *uap = (struct a *)scp->sc_ap; 80938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 81037741Smckusick register struct vnode *vp; 81137741Smckusick int error, mode, svuid, svgid; 8126254Sroot 81338408Smckusick svuid = scp->sc_uid; 81438408Smckusick svgid = scp->sc_gid; 81538408Smckusick scp->sc_uid = scp->sc_ruid; 81638408Smckusick scp->sc_gid = scp->sc_rgid; 81737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 81816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81916694Smckusick ndp->ni_dirp = uap->fname; 82037741Smckusick if (error = namei(ndp)) 82137741Smckusick goto out1; 82237741Smckusick vp = ndp->ni_vp; 82337741Smckusick /* 82437741Smckusick * fmode == 0 means only check for exist 82537741Smckusick */ 82637741Smckusick if (uap->fmode) { 82737741Smckusick mode = 0; 82837741Smckusick if (uap->fmode & R_OK) 82937741Smckusick mode |= VREAD; 83037741Smckusick if (uap->fmode & W_OK) 83137741Smckusick mode |= VWRITE; 83237741Smckusick if (uap->fmode & X_OK) 83337741Smckusick mode |= VEXEC; 83439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 83538399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 8366254Sroot } 83737741Smckusick vput(vp); 83837741Smckusick out1: 83938408Smckusick scp->sc_uid = svuid; 84038408Smckusick scp->sc_gid = svgid; 84137741Smckusick RETURN (error); 8426254Sroot } 8436254Sroot 8446254Sroot /* 8456574Smckusic * Stat system call. This version follows links. 84637Sbill */ 84738408Smckusick stat(scp) 84838408Smckusick struct syscontext *scp; 84937Sbill { 85037Sbill 85138408Smckusick stat1(scp, FOLLOW); 85237Sbill } 85337Sbill 85437Sbill /* 8556574Smckusic * Lstat system call. This version does not follow links. 8565992Swnj */ 85738408Smckusick lstat(scp) 85838408Smckusick struct syscontext *scp; 8595992Swnj { 86012756Ssam 86138408Smckusick stat1(scp, NOFOLLOW); 86212756Ssam } 86312756Ssam 86438408Smckusick stat1(scp, follow) 86538408Smckusick register struct syscontext *scp; 86612756Ssam int follow; 86712756Ssam { 8685992Swnj register struct a { 8695992Swnj char *fname; 87012756Ssam struct stat *ub; 87138408Smckusick } *uap = (struct a *)scp->sc_ap; 87238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 87312756Ssam struct stat sb; 87437741Smckusick int error; 8755992Swnj 87637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 87716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 87816694Smckusick ndp->ni_dirp = uap->fname; 87937741Smckusick if (error = namei(ndp)) 88037741Smckusick RETURN (error); 88137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 88237741Smckusick vput(ndp->ni_vp); 88337741Smckusick if (error) 88437741Smckusick RETURN (error); 88537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 88637741Smckusick RETURN (error); 8875992Swnj } 8885992Swnj 8895992Swnj /* 8905992Swnj * Return target name of a symbolic link 89137Sbill */ 89238408Smckusick readlink(scp) 89338408Smckusick register struct syscontext *scp; 8945992Swnj { 8955992Swnj register struct a { 8965992Swnj char *name; 8975992Swnj char *buf; 8985992Swnj int count; 89938408Smckusick } *uap = (struct a *)scp->sc_ap; 90038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90137741Smckusick register struct vnode *vp; 90237741Smckusick struct iovec aiov; 90337741Smckusick struct uio auio; 90437741Smckusick int error; 9055992Swnj 90637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 90716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 90816694Smckusick ndp->ni_dirp = uap->name; 90937741Smckusick if (error = namei(ndp)) 91037741Smckusick RETURN (error); 91137741Smckusick vp = ndp->ni_vp; 91237741Smckusick if (vp->v_type != VLNK) { 91337741Smckusick error = EINVAL; 9145992Swnj goto out; 9155992Swnj } 91637741Smckusick aiov.iov_base = uap->buf; 91737741Smckusick aiov.iov_len = uap->count; 91837741Smckusick auio.uio_iov = &aiov; 91937741Smckusick auio.uio_iovcnt = 1; 92037741Smckusick auio.uio_offset = 0; 92137741Smckusick auio.uio_rw = UIO_READ; 92237741Smckusick auio.uio_segflg = UIO_USERSPACE; 92337741Smckusick auio.uio_resid = uap->count; 92437741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 9255992Swnj out: 92637741Smckusick vput(vp); 92738408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 92837741Smckusick RETURN (error); 9295992Swnj } 9305992Swnj 9319167Ssam /* 93238259Smckusick * Change flags of a file given path name. 93338259Smckusick */ 93438408Smckusick chflags(scp) 93538408Smckusick register struct syscontext *scp; 93638259Smckusick { 93738259Smckusick struct a { 93838259Smckusick char *fname; 93938259Smckusick int flags; 94038408Smckusick } *uap = (struct a *)scp->sc_ap; 94138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 94238259Smckusick register struct vnode *vp; 94338259Smckusick struct vattr vattr; 94438259Smckusick int error; 94538259Smckusick 94638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 94738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 94838259Smckusick ndp->ni_dirp = uap->fname; 94938259Smckusick vattr_null(&vattr); 95038259Smckusick vattr.va_flags = uap->flags; 95138259Smckusick if (error = namei(ndp)) 95238259Smckusick RETURN (error); 95338259Smckusick vp = ndp->ni_vp; 95438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 95538259Smckusick error = EROFS; 95638259Smckusick goto out; 95738259Smckusick } 95838259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 95938259Smckusick out: 96038259Smckusick vput(vp); 96138259Smckusick RETURN (error); 96238259Smckusick } 96338259Smckusick 96438259Smckusick /* 96538259Smckusick * Change flags of a file given a file descriptor. 96638259Smckusick */ 96738408Smckusick fchflags(scp) 96838408Smckusick register struct syscontext *scp; 96938259Smckusick { 97038259Smckusick struct a { 97138259Smckusick int fd; 97238259Smckusick int flags; 97338408Smckusick } *uap = (struct a *)scp->sc_ap; 97438259Smckusick struct vattr vattr; 97538259Smckusick struct vnode *vp; 97638259Smckusick struct file *fp; 97738259Smckusick int error; 97838259Smckusick 97938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 98038259Smckusick RETURN (error); 98138259Smckusick vattr_null(&vattr); 98238259Smckusick vattr.va_flags = uap->flags; 98338259Smckusick vp = (struct vnode *)fp->f_data; 98438259Smckusick VOP_LOCK(vp); 98538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98638259Smckusick error = EROFS; 98738259Smckusick goto out; 98838259Smckusick } 98938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 99038259Smckusick out: 99138259Smckusick VOP_UNLOCK(vp); 99238259Smckusick RETURN (error); 99338259Smckusick } 99438259Smckusick 99538259Smckusick /* 9969167Ssam * Change mode of a file given path name. 9979167Ssam */ 99838408Smckusick chmod(scp) 99938408Smckusick register struct syscontext *scp; 10005992Swnj { 10017701Ssam struct a { 10026254Sroot char *fname; 10036254Sroot int fmode; 100438408Smckusick } *uap = (struct a *)scp->sc_ap; 100538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 100637741Smckusick register struct vnode *vp; 100737741Smckusick struct vattr vattr; 100837741Smckusick int error; 10095992Swnj 101037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 101137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 101237741Smckusick ndp->ni_dirp = uap->fname; 101337741Smckusick vattr_null(&vattr); 101437741Smckusick vattr.va_mode = uap->fmode & 07777; 101537741Smckusick if (error = namei(ndp)) 101637741Smckusick RETURN (error); 101737741Smckusick vp = ndp->ni_vp; 101837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101937741Smckusick error = EROFS; 102037741Smckusick goto out; 102137741Smckusick } 102237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 102337741Smckusick out: 102437741Smckusick vput(vp); 102537741Smckusick RETURN (error); 10267701Ssam } 10277439Sroot 10289167Ssam /* 10299167Ssam * Change mode of a file given a file descriptor. 10309167Ssam */ 103138408Smckusick fchmod(scp) 103238408Smckusick register struct syscontext *scp; 10337701Ssam { 10347701Ssam struct a { 10357701Ssam int fd; 10367701Ssam int fmode; 103738408Smckusick } *uap = (struct a *)scp->sc_ap; 103837741Smckusick struct vattr vattr; 103937741Smckusick struct vnode *vp; 104037741Smckusick struct file *fp; 104137741Smckusick int error; 10427701Ssam 104338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 104437741Smckusick RETURN (error); 104537741Smckusick vattr_null(&vattr); 104637741Smckusick vattr.va_mode = uap->fmode & 07777; 104737741Smckusick vp = (struct vnode *)fp->f_data; 104837741Smckusick VOP_LOCK(vp); 104937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 105037741Smckusick error = EROFS; 105137741Smckusick goto out; 10527439Sroot } 105337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 105437741Smckusick out: 105537741Smckusick VOP_UNLOCK(vp); 105637741Smckusick RETURN (error); 10575992Swnj } 10585992Swnj 10599167Ssam /* 10609167Ssam * Set ownership given a path name. 10619167Ssam */ 106238408Smckusick chown(scp) 106338408Smckusick register struct syscontext *scp; 106437Sbill { 10657701Ssam struct a { 10666254Sroot char *fname; 10676254Sroot int uid; 10686254Sroot int gid; 106938408Smckusick } *uap = (struct a *)scp->sc_ap; 107038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 107137741Smckusick register struct vnode *vp; 107237741Smckusick struct vattr vattr; 107337741Smckusick int error; 107437Sbill 107537741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 107636614Sbostic ndp->ni_segflg = UIO_USERSPACE; 107736614Sbostic ndp->ni_dirp = uap->fname; 107837741Smckusick vattr_null(&vattr); 107937741Smckusick vattr.va_uid = uap->uid; 108037741Smckusick vattr.va_gid = uap->gid; 108137741Smckusick if (error = namei(ndp)) 108237741Smckusick RETURN (error); 108337741Smckusick vp = ndp->ni_vp; 108437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 108537741Smckusick error = EROFS; 108637741Smckusick goto out; 108737741Smckusick } 108837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108937741Smckusick out: 109037741Smckusick vput(vp); 109137741Smckusick RETURN (error); 10927701Ssam } 10937439Sroot 10949167Ssam /* 10959167Ssam * Set ownership given a file descriptor. 10969167Ssam */ 109738408Smckusick fchown(scp) 109838408Smckusick register struct syscontext *scp; 10997701Ssam { 11007701Ssam struct a { 11017701Ssam int fd; 11027701Ssam int uid; 11037701Ssam int gid; 110438408Smckusick } *uap = (struct a *)scp->sc_ap; 110537741Smckusick struct vattr vattr; 110637741Smckusick struct vnode *vp; 110737741Smckusick struct file *fp; 110837741Smckusick int error; 11097701Ssam 111038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 111137741Smckusick RETURN (error); 111237741Smckusick vattr_null(&vattr); 111337741Smckusick vattr.va_uid = uap->uid; 111437741Smckusick vattr.va_gid = uap->gid; 111537741Smckusick vp = (struct vnode *)fp->f_data; 111637741Smckusick VOP_LOCK(vp); 111737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 111837741Smckusick error = EROFS; 111937741Smckusick goto out; 112037741Smckusick } 112137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 112237741Smckusick out: 112337741Smckusick VOP_UNLOCK(vp); 112437741Smckusick RETURN (error); 11257701Ssam } 11267701Ssam 112738408Smckusick utimes(scp) 112838408Smckusick register struct syscontext *scp; 112911811Ssam { 113011811Ssam register struct a { 113111811Ssam char *fname; 113211811Ssam struct timeval *tptr; 113338408Smckusick } *uap = (struct a *)scp->sc_ap; 113438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 113537741Smckusick register struct vnode *vp; 113611811Ssam struct timeval tv[2]; 113737741Smckusick struct vattr vattr; 113837741Smckusick int error; 113911811Ssam 114037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 114137741Smckusick RETURN (error); 114237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114437741Smckusick ndp->ni_dirp = uap->fname; 114537741Smckusick vattr_null(&vattr); 114637741Smckusick vattr.va_atime = tv[0]; 114737741Smckusick vattr.va_mtime = tv[1]; 114837741Smckusick if (error = namei(ndp)) 114937741Smckusick RETURN (error); 115037741Smckusick vp = ndp->ni_vp; 115137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 115237741Smckusick error = EROFS; 115337741Smckusick goto out; 115421015Smckusick } 115537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115637741Smckusick out: 115737741Smckusick vput(vp); 115837741Smckusick RETURN (error); 115911811Ssam } 116011811Ssam 11619167Ssam /* 11629167Ssam * Truncate a file given its path name. 11639167Ssam */ 116438408Smckusick truncate(scp) 116538408Smckusick register struct syscontext *scp; 11667701Ssam { 11677701Ssam struct a { 11687701Ssam char *fname; 116926473Skarels off_t length; 117038408Smckusick } *uap = (struct a *)scp->sc_ap; 117138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 117237741Smckusick register struct vnode *vp; 117337741Smckusick struct vattr vattr; 117437741Smckusick int error; 11757701Ssam 117637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 117716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 117816694Smckusick ndp->ni_dirp = uap->fname; 117937741Smckusick vattr_null(&vattr); 118037741Smckusick vattr.va_size = uap->length; 118137741Smckusick if (error = namei(ndp)) 118237741Smckusick RETURN (error); 118337741Smckusick vp = ndp->ni_vp; 118437741Smckusick if (vp->v_type == VDIR) { 118537741Smckusick error = EISDIR; 118637741Smckusick goto out; 11877701Ssam } 118838399Smckusick if ((error = vn_writechk(vp)) || 118938399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 119037741Smckusick goto out; 119137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 119237741Smckusick out: 119337741Smckusick vput(vp); 119437741Smckusick RETURN (error); 11957701Ssam } 11967701Ssam 11979167Ssam /* 11989167Ssam * Truncate a file given a file descriptor. 11999167Ssam */ 120038408Smckusick ftruncate(scp) 120138408Smckusick register struct syscontext *scp; 12027701Ssam { 12037701Ssam struct a { 12047701Ssam int fd; 120526473Skarels off_t length; 120638408Smckusick } *uap = (struct a *)scp->sc_ap; 120737741Smckusick struct vattr vattr; 120837741Smckusick struct vnode *vp; 12097701Ssam struct file *fp; 121037741Smckusick int error; 12117701Ssam 121238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 121337741Smckusick RETURN (error); 121437741Smckusick if ((fp->f_flag & FWRITE) == 0) 121537741Smckusick RETURN (EINVAL); 121637741Smckusick vattr_null(&vattr); 121737741Smckusick vattr.va_size = uap->length; 121837741Smckusick vp = (struct vnode *)fp->f_data; 121937741Smckusick VOP_LOCK(vp); 122037741Smckusick if (vp->v_type == VDIR) { 122137741Smckusick error = EISDIR; 122237741Smckusick goto out; 12237701Ssam } 122438399Smckusick if (error = vn_writechk(vp)) 122537741Smckusick goto out; 122637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 122737741Smckusick out: 122837741Smckusick VOP_UNLOCK(vp); 122937741Smckusick RETURN (error); 12307701Ssam } 12317701Ssam 12329167Ssam /* 12339167Ssam * Synch an open file. 12349167Ssam */ 123538408Smckusick fsync(scp) 123638408Smckusick register struct syscontext *scp; 12379167Ssam { 12389167Ssam struct a { 12399167Ssam int fd; 124038408Smckusick } *uap = (struct a *)scp->sc_ap; 124139592Smckusick register struct vnode *vp; 12429167Ssam struct file *fp; 124337741Smckusick int error; 12449167Ssam 124538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 124637741Smckusick RETURN (error); 124739592Smckusick vp = (struct vnode *)fp->f_data; 124839592Smckusick VOP_LOCK(vp); 124939592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 125039592Smckusick VOP_UNLOCK(vp); 125137741Smckusick RETURN (error); 12529167Ssam } 12539167Ssam 12549167Ssam /* 12559167Ssam * Rename system call. 12569167Ssam * 12579167Ssam * Source and destination must either both be directories, or both 12589167Ssam * not be directories. If target is a directory, it must be empty. 12599167Ssam */ 126038408Smckusick rename(scp) 126138408Smckusick register struct syscontext *scp; 12627701Ssam { 12637701Ssam struct a { 12647701Ssam char *from; 12657701Ssam char *to; 126638408Smckusick } *uap = (struct a *)scp->sc_ap; 126737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 126838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 126937741Smckusick struct nameidata tond; 127037741Smckusick int error; 12717701Ssam 127237741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 127316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 127416694Smckusick ndp->ni_dirp = uap->from; 127537741Smckusick if (error = namei(ndp)) 127637741Smckusick RETURN (error); 127737741Smckusick fvp = ndp->ni_vp; 127838266Smckusick nddup(ndp, &tond); 127937741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 128037741Smckusick tond.ni_segflg = UIO_USERSPACE; 128137741Smckusick tond.ni_dirp = uap->to; 128237741Smckusick error = namei(&tond); 128337741Smckusick tdvp = tond.ni_dvp; 128437741Smckusick tvp = tond.ni_vp; 128537741Smckusick if (tvp != NULL) { 128637741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 128739242Sbostic error = ENOTDIR; 128837741Smckusick goto out; 128937741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 129039242Sbostic error = EISDIR; 129137741Smckusick goto out; 12929167Ssam } 12939167Ssam } 129437741Smckusick if (error) { 129537741Smckusick VOP_ABORTOP(ndp); 129637741Smckusick goto out1; 129737741Smckusick } 129837741Smckusick if (fvp->v_mount != tdvp->v_mount) { 129937741Smckusick error = EXDEV; 13009167Ssam goto out; 130110051Ssam } 130239286Smckusick if (fvp == tdvp) 130337741Smckusick error = EINVAL; 130439286Smckusick /* 130539286Smckusick * If source is the same as the destination, 130639286Smckusick * then there is nothing to do. 130739286Smckusick */ 130839286Smckusick if (fvp == tvp) 130939286Smckusick error = -1; 131037741Smckusick out: 131137741Smckusick if (error) { 131237741Smckusick VOP_ABORTOP(&tond); 131337741Smckusick VOP_ABORTOP(ndp); 13149167Ssam } else { 131537741Smckusick error = VOP_RENAME(ndp, &tond); 13169167Ssam } 131737741Smckusick out1: 131838266Smckusick ndrele(&tond); 131939286Smckusick if (error == -1) 132039286Smckusick RETURN (0); 132137741Smckusick RETURN (error); 13227701Ssam } 13237701Ssam 13247535Sroot /* 132512756Ssam * Mkdir system call 132612756Ssam */ 132738408Smckusick mkdir(scp) 132838408Smckusick register struct syscontext *scp; 132912756Ssam { 133012756Ssam struct a { 133112756Ssam char *name; 133212756Ssam int dmode; 133338408Smckusick } *uap = (struct a *)scp->sc_ap; 133438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 133537741Smckusick register struct vnode *vp; 133637741Smckusick struct vattr vattr; 133737741Smckusick int error; 133812756Ssam 133937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 134016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 134116694Smckusick ndp->ni_dirp = uap->name; 134237741Smckusick if (error = namei(ndp)) 134337741Smckusick RETURN (error); 134437741Smckusick vp = ndp->ni_vp; 134537741Smckusick if (vp != NULL) { 134637741Smckusick VOP_ABORTOP(ndp); 134737741Smckusick RETURN (EEXIST); 134812756Ssam } 134937741Smckusick vattr_null(&vattr); 135037741Smckusick vattr.va_type = VDIR; 135138408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 135237741Smckusick error = VOP_MKDIR(ndp, &vattr); 135338145Smckusick if (!error) 135438145Smckusick vput(ndp->ni_vp); 135537741Smckusick RETURN (error); 135612756Ssam } 135712756Ssam 135812756Ssam /* 135912756Ssam * Rmdir system call. 136012756Ssam */ 136138408Smckusick rmdir(scp) 136238408Smckusick register struct syscontext *scp; 136312756Ssam { 136412756Ssam struct a { 136512756Ssam char *name; 136638408Smckusick } *uap = (struct a *)scp->sc_ap; 136738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 136837741Smckusick register struct vnode *vp; 136937741Smckusick int error; 137012756Ssam 137137741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 137216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 137316694Smckusick ndp->ni_dirp = uap->name; 137437741Smckusick if (error = namei(ndp)) 137537741Smckusick RETURN (error); 137637741Smckusick vp = ndp->ni_vp; 137737741Smckusick if (vp->v_type != VDIR) { 137837741Smckusick error = ENOTDIR; 137912756Ssam goto out; 138012756Ssam } 138112756Ssam /* 138237741Smckusick * No rmdir "." please. 138312756Ssam */ 138437741Smckusick if (ndp->ni_dvp == vp) { 138537741Smckusick error = EINVAL; 138612756Ssam goto out; 138712756Ssam } 138812756Ssam /* 138937741Smckusick * Don't unlink a mounted file. 139012756Ssam */ 139137741Smckusick if (vp->v_flag & VROOT) 139237741Smckusick error = EBUSY; 139312756Ssam out: 139437741Smckusick if (error) 139537741Smckusick VOP_ABORTOP(ndp); 139637741Smckusick else 139737741Smckusick error = VOP_RMDIR(ndp); 139837741Smckusick RETURN (error); 139912756Ssam } 140012756Ssam 140137741Smckusick /* 140237741Smckusick * Read a block of directory entries in a file system independent format 140337741Smckusick */ 140438408Smckusick getdirentries(scp) 140538408Smckusick register struct syscontext *scp; 140612756Ssam { 140737741Smckusick register struct a { 140837741Smckusick int fd; 140937741Smckusick char *buf; 141037741Smckusick unsigned count; 141137741Smckusick long *basep; 141238408Smckusick } *uap = (struct a *)scp->sc_ap; 141339592Smckusick register struct vnode *vp; 141416540Ssam struct file *fp; 141537741Smckusick struct uio auio; 141637741Smckusick struct iovec aiov; 141738129Smckusick off_t off; 1418*40321Smckusick int error, eofflag; 141912756Ssam 142038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 142137741Smckusick RETURN (error); 142237741Smckusick if ((fp->f_flag & FREAD) == 0) 142337741Smckusick RETURN (EBADF); 142439592Smckusick vp = (struct vnode *)fp->f_data; 142539592Smckusick if (vp->v_type != VDIR) 142639592Smckusick RETURN (EINVAL); 142737741Smckusick aiov.iov_base = uap->buf; 142837741Smckusick aiov.iov_len = uap->count; 142937741Smckusick auio.uio_iov = &aiov; 143037741Smckusick auio.uio_iovcnt = 1; 143137741Smckusick auio.uio_rw = UIO_READ; 143237741Smckusick auio.uio_segflg = UIO_USERSPACE; 143337741Smckusick auio.uio_resid = uap->count; 143439592Smckusick VOP_LOCK(vp); 143539592Smckusick auio.uio_offset = off = fp->f_offset; 1436*40321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 143739592Smckusick fp->f_offset = auio.uio_offset; 143839592Smckusick VOP_UNLOCK(vp); 143939592Smckusick if (error) 144037741Smckusick RETURN (error); 144139592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 144238408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 144337741Smckusick RETURN (error); 144412756Ssam } 144512756Ssam 144612756Ssam /* 144712756Ssam * mode mask for creation of files 144812756Ssam */ 144938408Smckusick umask(scp) 145038408Smckusick register struct syscontext *scp; 145112756Ssam { 145212756Ssam register struct a { 145312756Ssam int mask; 145438408Smckusick } *uap = (struct a *)scp->sc_ap; 145512756Ssam 145638408Smckusick scp->sc_retval1 = scp->sc_cmask; 145738408Smckusick scp->sc_cmask = uap->mask & 07777; 145837741Smckusick RETURN (0); 145912756Ssam } 146037741Smckusick 146139566Smarc /* 146239566Smarc * Void all references to file by ripping underlying filesystem 146339566Smarc * away from vnode. 146439566Smarc */ 146539566Smarc revoke(scp) 146639566Smarc register struct syscontext *scp; 146739566Smarc { 146839566Smarc struct a { 146939566Smarc char *fname; 147039566Smarc } *uap = (struct a *)scp->sc_ap; 147139566Smarc register struct nameidata *ndp = &scp->sc_nd; 147239566Smarc register struct vnode *vp; 147339566Smarc struct vattr vattr; 147439566Smarc int error; 147539566Smarc 147639566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 147739566Smarc ndp->ni_segflg = UIO_USERSPACE; 147839566Smarc ndp->ni_dirp = uap->fname; 147939566Smarc if (error = namei(ndp)) 148039566Smarc RETURN (error); 148139566Smarc vp = ndp->ni_vp; 148239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 148339566Smarc error = EINVAL; 148439566Smarc goto out; 148539566Smarc } 148639566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 148739566Smarc goto out; 148839566Smarc if (scp->sc_uid != vattr.va_uid || 148939566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 149039566Smarc goto out; 149139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 149239632Smckusick vgoneall(vp); 149339566Smarc out: 149439566Smarc vrele(vp); 149539566Smarc RETURN (error); 149639566Smarc } 149739566Smarc 149838408Smckusick getvnode(ofile, fdes, fpp) 149938408Smckusick struct file *ofile[]; 150037741Smckusick struct file **fpp; 150137741Smckusick int fdes; 150237741Smckusick { 150337741Smckusick struct file *fp; 150437741Smckusick 150538408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 150637741Smckusick return (EBADF); 150737741Smckusick if (fp->f_type != DTYPE_VNODE) 150837741Smckusick return (EINVAL); 150937741Smckusick *fpp = fp; 151037741Smckusick return (0); 151137741Smckusick } 1512