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*40635Smckusick * @(#)vfs_syscalls.c 7.42 (Berkeley) 03/26/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 "mount.h" 2817101Sbloom #include "proc.h" 2917101Sbloom #include "uio.h" 3037741Smckusick #include "malloc.h" 3137Sbill 3239797Smckusick #undef RETURN 3339797Smckusick #define RETURN(val) { scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; } 3439797Smckusick 3537741Smckusick /* 3637741Smckusick * Virtual File System System Calls 3737741Smckusick */ 3812756Ssam 399167Ssam /* 4037741Smckusick * mount system call 419167Ssam */ 4238408Smckusick mount(scp) 4338408Smckusick register struct syscontext *scp; 446254Sroot { 4537741Smckusick register struct a { 4637741Smckusick int type; 4737741Smckusick char *dir; 4837741Smckusick int flags; 4937741Smckusick caddr_t data; 5038408Smckusick } *uap = (struct a *)scp->sc_ap; 5138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5239335Smckusick register struct vnode *vp; 5339335Smckusick register struct mount *mp; 5440111Smckusick int error, flag; 556254Sroot 5637741Smckusick /* 5737741Smckusick * Must be super user 5837741Smckusick */ 5938408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 6037741Smckusick RETURN (error); 6137741Smckusick /* 6237741Smckusick * Get vnode to be covered 6337741Smckusick */ 6437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6637741Smckusick ndp->ni_dirp = uap->dir; 6737741Smckusick if (error = namei(ndp)) 6837741Smckusick RETURN (error); 6937741Smckusick vp = ndp->ni_vp; 7039335Smckusick if (uap->flags & M_UPDATE) { 7139335Smckusick if ((vp->v_flag & VROOT) == 0) { 7239335Smckusick vput(vp); 7339335Smckusick RETURN (EINVAL); 7439335Smckusick } 7539335Smckusick mp = vp->v_mount; 7639335Smckusick /* 7739335Smckusick * We allow going from read-only to read-write, 7839335Smckusick * but not from read-write to read-only. 7939335Smckusick */ 8039335Smckusick if ((mp->m_flag & M_RDONLY) == 0 && 8139335Smckusick (uap->flags & M_RDONLY) != 0) { 8239335Smckusick vput(vp); 8339335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8439335Smckusick } 8540111Smckusick flag = mp->m_flag; 8639335Smckusick mp->m_flag |= M_UPDATE; 8739335Smckusick VOP_UNLOCK(vp); 8839335Smckusick goto update; 8939335Smckusick } 9039665Smckusick vinvalbuf(vp, 1); 9139805Smckusick if (vp->v_usecount != 1) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (EBUSY); 9437741Smckusick } 9537741Smckusick if (vp->v_type != VDIR) { 9637741Smckusick vput(vp); 9737741Smckusick RETURN (ENOTDIR); 9837741Smckusick } 9939741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10037741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10137741Smckusick vput(vp); 10237741Smckusick RETURN (ENODEV); 10337741Smckusick } 10437741Smckusick 10537741Smckusick /* 10639335Smckusick * Allocate and initialize the file system. 10737741Smckusick */ 10837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10937741Smckusick M_MOUNT, M_WAITOK); 11037741Smckusick mp->m_op = vfssw[uap->type]; 11137741Smckusick mp->m_flag = 0; 11237741Smckusick mp->m_exroot = 0; 11339381Smckusick mp->m_mounth = (struct vnode *)0; 11439335Smckusick if (error = vfs_lock(mp)) { 11539335Smckusick free((caddr_t)mp, M_MOUNT); 11639335Smckusick vput(vp); 11739335Smckusick RETURN (error); 11839335Smckusick } 11939335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12039335Smckusick vfs_unlock(mp); 12139335Smckusick free((caddr_t)mp, M_MOUNT); 12239335Smckusick vput(vp); 12339335Smckusick RETURN (EBUSY); 12439335Smckusick } 12539335Smckusick vp->v_mountedhere = mp; 12639335Smckusick mp->m_vnodecovered = vp; 12739335Smckusick update: 12839335Smckusick /* 12939335Smckusick * Set the mount level flags. 13039335Smckusick */ 13139335Smckusick if (uap->flags & M_RDONLY) 13239335Smckusick mp->m_flag |= M_RDONLY; 13339335Smckusick else 13439335Smckusick mp->m_flag &= ~M_RDONLY; 13539335Smckusick if (uap->flags & M_NOSUID) 13639335Smckusick mp->m_flag |= M_NOSUID; 13739335Smckusick else 13839335Smckusick mp->m_flag &= ~M_NOSUID; 13939335Smckusick if (uap->flags & M_NOEXEC) 14039335Smckusick mp->m_flag |= M_NOEXEC; 14139335Smckusick else 14239335Smckusick mp->m_flag &= ~M_NOEXEC; 14339335Smckusick if (uap->flags & M_NODEV) 14439335Smckusick mp->m_flag |= M_NODEV; 14539335Smckusick else 14639335Smckusick mp->m_flag &= ~M_NODEV; 14739335Smckusick if (uap->flags & M_SYNCHRONOUS) 14839335Smckusick mp->m_flag |= M_SYNCHRONOUS; 14939335Smckusick else 15039335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15139335Smckusick /* 15239335Smckusick * Mount the filesystem. 15339335Smckusick */ 15439335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15539335Smckusick if (mp->m_flag & M_UPDATE) { 15639335Smckusick mp->m_flag &= ~M_UPDATE; 15739335Smckusick vrele(vp); 15840111Smckusick if (error) 15940111Smckusick mp->m_flag = flag; 16039335Smckusick RETURN (error); 16139335Smckusick } 16240110Smckusick /* 16340110Smckusick * Put the new filesystem on the mount list after root. 16440110Smckusick */ 16540110Smckusick mp->m_next = rootfs->m_next; 16640110Smckusick mp->m_prev = rootfs; 16740110Smckusick rootfs->m_next = mp; 16840110Smckusick mp->m_next->m_prev = mp; 16937741Smckusick cache_purge(vp); 17037741Smckusick if (!error) { 17139335Smckusick VOP_UNLOCK(vp); 17237741Smckusick vfs_unlock(mp); 17339044Smckusick error = VFS_START(mp, 0); 17437741Smckusick } else { 17537741Smckusick vfs_remove(mp); 17637741Smckusick free((caddr_t)mp, M_MOUNT); 17739335Smckusick vput(vp); 17837741Smckusick } 17937741Smckusick RETURN (error); 1806254Sroot } 1816254Sroot 1829167Ssam /* 18337741Smckusick * Unmount system call. 18437741Smckusick * 18537741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18637741Smckusick * not special file (as before). 1879167Ssam */ 18838408Smckusick unmount(scp) 18938408Smckusick register struct syscontext *scp; 1906254Sroot { 19137741Smckusick struct a { 19237741Smckusick char *pathp; 19337741Smckusick int flags; 19438408Smckusick } *uap = (struct a *)scp->sc_ap; 19537741Smckusick register struct vnode *vp; 19638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19739356Smckusick struct mount *mp; 19837741Smckusick int error; 1996254Sroot 20037741Smckusick /* 20137741Smckusick * Must be super user 20237741Smckusick */ 20338408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 20437741Smckusick RETURN (error); 20537741Smckusick 20637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20837741Smckusick ndp->ni_dirp = uap->pathp; 20937741Smckusick if (error = namei(ndp)) 21037741Smckusick RETURN (error); 21137741Smckusick vp = ndp->ni_vp; 21237741Smckusick /* 21337741Smckusick * Must be the root of the filesystem 21437741Smckusick */ 21537741Smckusick if ((vp->v_flag & VROOT) == 0) { 21637741Smckusick vput(vp); 21737741Smckusick RETURN (EINVAL); 21837741Smckusick } 21937741Smckusick mp = vp->v_mount; 22037741Smckusick vput(vp); 22139356Smckusick RETURN (dounmount(mp, uap->flags)); 22239356Smckusick } 22339356Smckusick 22439356Smckusick /* 22539356Smckusick * Do an unmount. 22639356Smckusick */ 22739356Smckusick dounmount(mp, flags) 22839356Smckusick register struct mount *mp; 22939356Smckusick int flags; 23039356Smckusick { 23139356Smckusick struct vnode *coveredvp; 23239356Smckusick int error; 23339356Smckusick 23437741Smckusick coveredvp = mp->m_vnodecovered; 23537741Smckusick if (error = vfs_lock(mp)) 23639356Smckusick return (error); 23737741Smckusick 23837741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23937741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24037741Smckusick VFS_SYNC(mp, MNT_WAIT); 24137741Smckusick 24239356Smckusick error = VFS_UNMOUNT(mp, flags); 24337741Smckusick if (error) { 24437741Smckusick vfs_unlock(mp); 24537741Smckusick } else { 24637741Smckusick vrele(coveredvp); 24737741Smckusick vfs_remove(mp); 24837741Smckusick free((caddr_t)mp, M_MOUNT); 24937741Smckusick } 25039356Smckusick return (error); 2516254Sroot } 2526254Sroot 2539167Ssam /* 25437741Smckusick * Sync system call. 25537741Smckusick * Sync each mounted filesystem. 2569167Ssam */ 25739491Smckusick /* ARGSUSED */ 25838408Smckusick sync(scp) 25939491Smckusick struct syscontext *scp; 2606254Sroot { 26137741Smckusick register struct mount *mp; 26237741Smckusick 26337741Smckusick mp = rootfs; 26437741Smckusick do { 26540343Smckusick /* 26640343Smckusick * The lock check below is to avoid races with mount 26740343Smckusick * and unmount. 26840343Smckusick */ 26940110Smckusick if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0) 27037741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27140343Smckusick mp = mp->m_next; 27237741Smckusick } while (mp != rootfs); 27337741Smckusick } 27437741Smckusick 27537741Smckusick /* 27637741Smckusick * get filesystem statistics 27737741Smckusick */ 27838408Smckusick statfs(scp) 27938408Smckusick register struct syscontext *scp; 28037741Smckusick { 2816254Sroot struct a { 28237741Smckusick char *path; 28337741Smckusick struct statfs *buf; 28438408Smckusick } *uap = (struct a *)scp->sc_ap; 28539464Smckusick register struct mount *mp; 28638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 28740343Smckusick register struct statfs *sp; 28837741Smckusick int error; 28937741Smckusick 29039544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 29137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 29237741Smckusick ndp->ni_dirp = uap->path; 29337741Smckusick if (error = namei(ndp)) 29437741Smckusick RETURN (error); 29539544Smckusick mp = ndp->ni_vp->v_mount; 29640343Smckusick sp = &mp->m_stat; 29739544Smckusick vrele(ndp->ni_vp); 29840343Smckusick if (error = VFS_STATFS(mp, sp)) 29939544Smckusick RETURN (error); 30040343Smckusick sp->f_flags = mp->m_flag & M_VISFLAGMASK; 30140343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 30237741Smckusick } 30337741Smckusick 30438408Smckusick fstatfs(scp) 30538408Smckusick register struct syscontext *scp; 30637741Smckusick { 30737741Smckusick struct a { 30837741Smckusick int fd; 30937741Smckusick struct statfs *buf; 31038408Smckusick } *uap = (struct a *)scp->sc_ap; 31137741Smckusick struct file *fp; 31239464Smckusick struct mount *mp; 31340343Smckusick register struct statfs *sp; 31437741Smckusick int error; 31537741Smckusick 31638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 31737741Smckusick RETURN (error); 31839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31940343Smckusick sp = &mp->m_stat; 32040343Smckusick if (error = VFS_STATFS(mp, sp)) 32137741Smckusick RETURN (error); 32240343Smckusick sp->f_flags = mp->m_flag & M_VISFLAGMASK; 32340343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 32437741Smckusick } 32537741Smckusick 32637741Smckusick /* 32738270Smckusick * get statistics on all filesystems 32838270Smckusick */ 32938408Smckusick getfsstat(scp) 33038408Smckusick register struct syscontext *scp; 33138270Smckusick { 33238270Smckusick struct a { 33338270Smckusick struct statfs *buf; 33438270Smckusick long bufsize; 33540343Smckusick int flags; 33638408Smckusick } *uap = (struct a *)scp->sc_ap; 33738270Smckusick register struct mount *mp; 33840343Smckusick register struct statfs *sp; 33939606Smckusick caddr_t sfsp; 34038270Smckusick long count, maxcount, error; 34138270Smckusick 34238270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 34339606Smckusick sfsp = (caddr_t)uap->buf; 34438270Smckusick mp = rootfs; 34538270Smckusick count = 0; 34638270Smckusick do { 34739606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 34840343Smckusick sp = &mp->m_stat; 34940343Smckusick /* 35040343Smckusick * If MNT_NOWAIT is specified, do not refresh the 35140343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 35240343Smckusick */ 35340343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 35440343Smckusick (uap->flags & MNT_WAIT)) && 35540343Smckusick (error = VFS_STATFS(mp, sp))) { 35639607Smckusick mp = mp->m_prev; 35739607Smckusick continue; 35839607Smckusick } 35940343Smckusick sp->f_flags = mp->m_flag & M_VISFLAGMASK; 36040343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 36139606Smckusick RETURN (error); 36240343Smckusick sfsp += sizeof(*sp); 36338270Smckusick } 36439606Smckusick count++; 36538270Smckusick mp = mp->m_prev; 36638270Smckusick } while (mp != rootfs); 36738270Smckusick if (sfsp && count > maxcount) 36838408Smckusick scp->sc_retval1 = maxcount; 36938270Smckusick else 37038408Smckusick scp->sc_retval1 = count; 37138270Smckusick RETURN (0); 37238270Smckusick } 37338270Smckusick 37438270Smckusick /* 37538259Smckusick * Change current working directory to a given file descriptor. 37638259Smckusick */ 37738408Smckusick fchdir(scp) 37838408Smckusick register struct syscontext *scp; 37938259Smckusick { 38038259Smckusick struct a { 38138259Smckusick int fd; 38238408Smckusick } *uap = (struct a *)scp->sc_ap; 38338259Smckusick register struct vnode *vp; 38438259Smckusick struct file *fp; 38538259Smckusick int error; 38638259Smckusick 38738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 38838259Smckusick RETURN (error); 38938259Smckusick vp = (struct vnode *)fp->f_data; 39038259Smckusick VOP_LOCK(vp); 39138259Smckusick if (vp->v_type != VDIR) 39238259Smckusick error = ENOTDIR; 39338259Smckusick else 39438408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 39538259Smckusick VOP_UNLOCK(vp); 39639860Smckusick if (error) 39739860Smckusick RETURN (error); 39839860Smckusick VREF(vp); 39938408Smckusick vrele(scp->sc_cdir); 40038408Smckusick scp->sc_cdir = vp; 40139860Smckusick RETURN (0); 40238259Smckusick } 40338259Smckusick 40438259Smckusick /* 40537741Smckusick * Change current working directory (``.''). 40637741Smckusick */ 40738408Smckusick chdir(scp) 40838408Smckusick register struct syscontext *scp; 40937741Smckusick { 41037741Smckusick struct a { 4116254Sroot char *fname; 41238408Smckusick } *uap = (struct a *)scp->sc_ap; 41338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 41437741Smckusick int error; 4156254Sroot 41637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 41716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 41816694Smckusick ndp->ni_dirp = uap->fname; 41937741Smckusick if (error = chdirec(ndp)) 42037741Smckusick RETURN (error); 42138408Smckusick vrele(scp->sc_cdir); 42238408Smckusick scp->sc_cdir = ndp->ni_vp; 42337741Smckusick RETURN (0); 42437741Smckusick } 4256254Sroot 42637741Smckusick /* 42737741Smckusick * Change notion of root (``/'') directory. 42837741Smckusick */ 42938408Smckusick chroot(scp) 43038408Smckusick register struct syscontext *scp; 43137741Smckusick { 43237741Smckusick struct a { 43337741Smckusick char *fname; 43438408Smckusick } *uap = (struct a *)scp->sc_ap; 43538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 43637741Smckusick int error; 43737741Smckusick 43838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 43937741Smckusick RETURN (error); 44037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 44137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 44237741Smckusick ndp->ni_dirp = uap->fname; 44337741Smckusick if (error = chdirec(ndp)) 44437741Smckusick RETURN (error); 44539515Smckusick if (scp->sc_rdir != NULL) 44639515Smckusick vrele(scp->sc_rdir); 44738408Smckusick scp->sc_rdir = ndp->ni_vp; 44837741Smckusick RETURN (0); 4496254Sroot } 4506254Sroot 45137Sbill /* 45237741Smckusick * Common routine for chroot and chdir. 45337741Smckusick */ 45437741Smckusick chdirec(ndp) 45537741Smckusick register struct nameidata *ndp; 45637741Smckusick { 45737741Smckusick struct vnode *vp; 45837741Smckusick int error; 45937741Smckusick 46037741Smckusick if (error = namei(ndp)) 46137741Smckusick return (error); 46237741Smckusick vp = ndp->ni_vp; 46337741Smckusick if (vp->v_type != VDIR) 46437741Smckusick error = ENOTDIR; 46537741Smckusick else 46638399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 46737741Smckusick VOP_UNLOCK(vp); 46837741Smckusick if (error) 46937741Smckusick vrele(vp); 47037741Smckusick return (error); 47137741Smckusick } 47237741Smckusick 47337741Smckusick /* 4746254Sroot * Open system call. 4756254Sroot */ 47638408Smckusick open(scp) 47738408Smckusick register struct syscontext *scp; 4786254Sroot { 47912756Ssam struct a { 4806254Sroot char *fname; 4817701Ssam int mode; 48212756Ssam int crtmode; 48338408Smckusick } *uap = (struct a *) scp->sc_ap; 48438408Smckusick struct nameidata *ndp = &scp->sc_nd; 4856254Sroot 48637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48737741Smckusick ndp->ni_dirp = uap->fname; 48838408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 48938408Smckusick &scp->sc_retval1)); 4906254Sroot } 4916254Sroot 4926254Sroot /* 4936254Sroot * Creat system call. 4946254Sroot */ 49538408Smckusick creat(scp) 49638408Smckusick register struct syscontext *scp; 4976254Sroot { 49812756Ssam struct a { 4996254Sroot char *fname; 5006254Sroot int fmode; 50138408Smckusick } *uap = (struct a *)scp->sc_ap; 50238408Smckusick struct nameidata *ndp = &scp->sc_nd; 5036254Sroot 50437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50537741Smckusick ndp->ni_dirp = uap->fname; 50638408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 50738408Smckusick ndp, &scp->sc_retval1)); 5086254Sroot } 5096254Sroot 5106254Sroot /* 5116254Sroot * Common code for open and creat. 51212756Ssam * Check permissions, allocate an open file structure, 51312756Ssam * and call the device open routine if any. 5146254Sroot */ 51538408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 51638408Smckusick register struct syscontext *scp; 51737741Smckusick int fmode, cmode; 51837741Smckusick struct nameidata *ndp; 51937741Smckusick int *resultfd; 52012756Ssam { 5216254Sroot register struct file *fp; 52237741Smckusick struct file *nfp; 52337741Smckusick int indx, error; 52437741Smckusick extern struct fileops vnops; 5256254Sroot 52637741Smckusick if (error = falloc(&nfp, &indx)) 52737741Smckusick return (error); 52837741Smckusick fp = nfp; 52938408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 530*40635Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ S_ISVTX)) { 53137741Smckusick crfree(fp->f_cred); 53237741Smckusick fp->f_count--; 53339499Smckusick if (error == -1) /* XXX from fdopen */ 53439499Smckusick return (0); /* XXX from fdopen */ 53539499Smckusick scp->sc_ofile[indx] = NULL; 53637741Smckusick return (error); 53712756Ssam } 53837741Smckusick fp->f_flag = fmode & FMASK; 53937741Smckusick fp->f_type = DTYPE_VNODE; 54037741Smckusick fp->f_ops = &vnops; 54137741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 54237741Smckusick if (resultfd) 54337741Smckusick *resultfd = indx; 54437741Smckusick return (0); 5456254Sroot } 5466254Sroot 5476254Sroot /* 5486254Sroot * Mknod system call 5496254Sroot */ 55038408Smckusick mknod(scp) 55138408Smckusick register struct syscontext *scp; 5526254Sroot { 5536254Sroot register struct a { 5546254Sroot char *fname; 5556254Sroot int fmode; 5566254Sroot int dev; 55738408Smckusick } *uap = (struct a *)scp->sc_ap; 55838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 55937741Smckusick register struct vnode *vp; 56037741Smckusick struct vattr vattr; 56137741Smckusick int error; 5626254Sroot 56338408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 56437741Smckusick RETURN (error); 56537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 56616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 56716694Smckusick ndp->ni_dirp = uap->fname; 56837741Smckusick if (error = namei(ndp)) 56937741Smckusick RETURN (error); 57037741Smckusick vp = ndp->ni_vp; 57137741Smckusick if (vp != NULL) { 57237741Smckusick error = EEXIST; 57312756Ssam goto out; 5746254Sroot } 57537741Smckusick vattr_null(&vattr); 576*40635Smckusick switch (uap->fmode & S_IFMT) { 57712756Ssam 578*40635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 57937741Smckusick vattr.va_type = VBAD; 58037741Smckusick break; 581*40635Smckusick case S_IFCHR: 58237741Smckusick vattr.va_type = VCHR; 58337741Smckusick break; 584*40635Smckusick case S_IFBLK: 58537741Smckusick vattr.va_type = VBLK; 58637741Smckusick break; 58737741Smckusick default: 58837741Smckusick error = EINVAL; 58937741Smckusick goto out; 5906254Sroot } 59138408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 59237741Smckusick vattr.va_rdev = uap->dev; 5936254Sroot out: 59437741Smckusick if (error) 59537741Smckusick VOP_ABORTOP(ndp); 59637741Smckusick else 59737741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 59837741Smckusick RETURN (error); 5996254Sroot } 6006254Sroot 6016254Sroot /* 60240285Smckusick * Mkfifo system call 60340285Smckusick */ 60440285Smckusick mkfifo(scp) 60540285Smckusick register struct syscontext *scp; 60640285Smckusick { 60740285Smckusick register struct a { 60840285Smckusick char *fname; 60940285Smckusick int fmode; 61040285Smckusick } *uap = (struct a *)scp->sc_ap; 61140285Smckusick register struct nameidata *ndp = &scp->sc_nd; 61240285Smckusick struct vattr vattr; 61340285Smckusick int error; 61440285Smckusick 61540285Smckusick #ifndef FIFO 61640285Smckusick RETURN (EOPNOTSUPP); 61740285Smckusick #else 61840285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61940285Smckusick ndp->ni_segflg = UIO_USERSPACE; 62040285Smckusick ndp->ni_dirp = uap->fname; 62140285Smckusick if (error = namei(ndp)) 62240285Smckusick RETURN (error); 62340285Smckusick if (ndp->ni_vp != NULL) { 62440285Smckusick VOP_ABORTOP(ndp); 62540285Smckusick RETURN (EEXIST); 62640285Smckusick } else { 62740285Smckusick vattr_null(&vattr); 62840285Smckusick vattr.va_type = VFIFO; 62940285Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 63040285Smckusick } 63140285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 63240285Smckusick #endif /* FIFO */ 63340285Smckusick } 63440285Smckusick 63540285Smckusick /* 6366254Sroot * link system call 6376254Sroot */ 63838408Smckusick link(scp) 63938408Smckusick register struct syscontext *scp; 6406254Sroot { 6416254Sroot register struct a { 6426254Sroot char *target; 6436254Sroot char *linkname; 64438408Smckusick } *uap = (struct a *)scp->sc_ap; 64538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64637741Smckusick register struct vnode *vp, *xp; 64737741Smckusick int error; 6486254Sroot 64916694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 65016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 65116694Smckusick ndp->ni_dirp = uap->target; 65237741Smckusick if (error = namei(ndp)) 65337741Smckusick RETURN (error); 65437741Smckusick vp = ndp->ni_vp; 65537741Smckusick if (vp->v_type == VDIR && 65638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 65737741Smckusick goto out1; 65837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65916694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 66037741Smckusick if (error = namei(ndp)) 66137741Smckusick goto out1; 66237741Smckusick xp = ndp->ni_vp; 6636254Sroot if (xp != NULL) { 66437741Smckusick error = EEXIST; 6656254Sroot goto out; 6666254Sroot } 66737741Smckusick xp = ndp->ni_dvp; 66837741Smckusick if (vp->v_mount != xp->v_mount) 66937741Smckusick error = EXDEV; 6706254Sroot out: 67137741Smckusick if (error) 67237741Smckusick VOP_ABORTOP(ndp); 67337741Smckusick else 67437741Smckusick error = VOP_LINK(vp, ndp); 67537741Smckusick out1: 67637741Smckusick vrele(vp); 67737741Smckusick RETURN (error); 6786254Sroot } 6796254Sroot 6806254Sroot /* 6816254Sroot * symlink -- make a symbolic link 6826254Sroot */ 68338408Smckusick symlink(scp) 68438408Smckusick register struct syscontext *scp; 6856254Sroot { 68637741Smckusick struct a { 6876254Sroot char *target; 6886254Sroot char *linkname; 68938408Smckusick } *uap = (struct a *)scp->sc_ap; 69038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 69137741Smckusick register struct vnode *vp; 69237741Smckusick struct vattr vattr; 69337741Smckusick char *target; 69437741Smckusick int error; 6956254Sroot 69616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69716694Smckusick ndp->ni_dirp = uap->linkname; 69837741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 69937741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 70037741Smckusick goto out1; 70137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 70237741Smckusick if (error = namei(ndp)) 70337741Smckusick goto out1; 70437741Smckusick vp = ndp->ni_vp; 70537741Smckusick if (vp) { 70637741Smckusick error = EEXIST; 70737741Smckusick goto out; 7086254Sroot } 70937741Smckusick vp = ndp->ni_dvp; 71037741Smckusick vattr_null(&vattr); 71138408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 71237741Smckusick out: 71337741Smckusick if (error) 71437741Smckusick VOP_ABORTOP(ndp); 71537741Smckusick else 71637741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 71737741Smckusick out1: 71837741Smckusick FREE(target, M_NAMEI); 71937741Smckusick RETURN (error); 7206254Sroot } 7216254Sroot 7226254Sroot /* 7236254Sroot * Unlink system call. 7246254Sroot * Hard to avoid races here, especially 7256254Sroot * in unlinking directories. 7266254Sroot */ 72738408Smckusick unlink(scp) 72838408Smckusick register struct syscontext *scp; 7296254Sroot { 7306254Sroot struct a { 7316254Sroot char *fname; 73238408Smckusick } *uap = (struct a *)scp->sc_ap; 73338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 73437741Smckusick register struct vnode *vp; 73537741Smckusick int error; 7366254Sroot 73737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 73816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73916694Smckusick ndp->ni_dirp = uap->fname; 74037741Smckusick if (error = namei(ndp)) 74137741Smckusick RETURN (error); 74237741Smckusick vp = ndp->ni_vp; 74337741Smckusick if (vp->v_type == VDIR && 74438408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7456254Sroot goto out; 7466254Sroot /* 7476254Sroot * Don't unlink a mounted file. 7486254Sroot */ 74937741Smckusick if (vp->v_flag & VROOT) { 75037741Smckusick error = EBUSY; 7516254Sroot goto out; 7526254Sroot } 75337741Smckusick if (vp->v_flag & VTEXT) 75437741Smckusick xrele(vp); /* try once to free text */ 7556254Sroot out: 75637741Smckusick if (error) 75737741Smckusick VOP_ABORTOP(ndp); 7587142Smckusick else 75937741Smckusick error = VOP_REMOVE(ndp); 76037741Smckusick RETURN (error); 7616254Sroot } 7626254Sroot 7636254Sroot /* 7646254Sroot * Seek system call 7656254Sroot */ 76638408Smckusick lseek(scp) 76738408Smckusick register struct syscontext *scp; 7686254Sroot { 7696254Sroot register struct file *fp; 7706254Sroot register struct a { 77137741Smckusick int fdes; 7726254Sroot off_t off; 7736254Sroot int sbase; 77438408Smckusick } *uap = (struct a *)scp->sc_ap; 77537741Smckusick struct vattr vattr; 77637741Smckusick int error; 7776254Sroot 77837741Smckusick if ((unsigned)uap->fdes >= NOFILE || 77938408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 78037741Smckusick RETURN (EBADF); 78137741Smckusick if (fp->f_type != DTYPE_VNODE) 78237741Smckusick RETURN (ESPIPE); 78313878Ssam switch (uap->sbase) { 78413878Ssam 78513878Ssam case L_INCR: 78613878Ssam fp->f_offset += uap->off; 78713878Ssam break; 78813878Ssam 78913878Ssam case L_XTND: 79037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 79138408Smckusick &vattr, scp->sc_cred)) 79237741Smckusick RETURN (error); 79337741Smckusick fp->f_offset = uap->off + vattr.va_size; 79413878Ssam break; 79513878Ssam 79613878Ssam case L_SET: 79713878Ssam fp->f_offset = uap->off; 79813878Ssam break; 79913878Ssam 80013878Ssam default: 80137741Smckusick RETURN (EINVAL); 80213878Ssam } 80338408Smckusick scp->sc_offset = fp->f_offset; 80437741Smckusick RETURN (0); 8056254Sroot } 8066254Sroot 8076254Sroot /* 8086254Sroot * Access system call 8096254Sroot */ 81038408Smckusick saccess(scp) 81138408Smckusick register struct syscontext *scp; 8126254Sroot { 8136254Sroot register struct a { 8146254Sroot char *fname; 8156254Sroot int fmode; 81638408Smckusick } *uap = (struct a *)scp->sc_ap; 81738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 81837741Smckusick register struct vnode *vp; 81937741Smckusick int error, mode, svuid, svgid; 8206254Sroot 82138408Smckusick svuid = scp->sc_uid; 82238408Smckusick svgid = scp->sc_gid; 82338408Smckusick scp->sc_uid = scp->sc_ruid; 82438408Smckusick scp->sc_gid = scp->sc_rgid; 82537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 82616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82716694Smckusick ndp->ni_dirp = uap->fname; 82837741Smckusick if (error = namei(ndp)) 82937741Smckusick goto out1; 83037741Smckusick vp = ndp->ni_vp; 83137741Smckusick /* 83237741Smckusick * fmode == 0 means only check for exist 83337741Smckusick */ 83437741Smckusick if (uap->fmode) { 83537741Smckusick mode = 0; 83637741Smckusick if (uap->fmode & R_OK) 83737741Smckusick mode |= VREAD; 83837741Smckusick if (uap->fmode & W_OK) 83937741Smckusick mode |= VWRITE; 84037741Smckusick if (uap->fmode & X_OK) 84137741Smckusick mode |= VEXEC; 84239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 84338399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 8446254Sroot } 84537741Smckusick vput(vp); 84637741Smckusick out1: 84738408Smckusick scp->sc_uid = svuid; 84838408Smckusick scp->sc_gid = svgid; 84937741Smckusick RETURN (error); 8506254Sroot } 8516254Sroot 8526254Sroot /* 8536574Smckusic * Stat system call. This version follows links. 85437Sbill */ 85538408Smckusick stat(scp) 85638408Smckusick struct syscontext *scp; 85737Sbill { 85837Sbill 85938408Smckusick stat1(scp, FOLLOW); 86037Sbill } 86137Sbill 86237Sbill /* 8636574Smckusic * Lstat system call. This version does not follow links. 8645992Swnj */ 86538408Smckusick lstat(scp) 86638408Smckusick struct syscontext *scp; 8675992Swnj { 86812756Ssam 86938408Smckusick stat1(scp, NOFOLLOW); 87012756Ssam } 87112756Ssam 87238408Smckusick stat1(scp, follow) 87338408Smckusick register struct syscontext *scp; 87412756Ssam int follow; 87512756Ssam { 8765992Swnj register struct a { 8775992Swnj char *fname; 87812756Ssam struct stat *ub; 87938408Smckusick } *uap = (struct a *)scp->sc_ap; 88038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 88112756Ssam struct stat sb; 88237741Smckusick int error; 8835992Swnj 88437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 88516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 88616694Smckusick ndp->ni_dirp = uap->fname; 88737741Smckusick if (error = namei(ndp)) 88837741Smckusick RETURN (error); 88937741Smckusick error = vn_stat(ndp->ni_vp, &sb); 89037741Smckusick vput(ndp->ni_vp); 89137741Smckusick if (error) 89237741Smckusick RETURN (error); 89337741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 89437741Smckusick RETURN (error); 8955992Swnj } 8965992Swnj 8975992Swnj /* 8985992Swnj * Return target name of a symbolic link 89937Sbill */ 90038408Smckusick readlink(scp) 90138408Smckusick register struct syscontext *scp; 9025992Swnj { 9035992Swnj register struct a { 9045992Swnj char *name; 9055992Swnj char *buf; 9065992Swnj int count; 90738408Smckusick } *uap = (struct a *)scp->sc_ap; 90838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90937741Smckusick register struct vnode *vp; 91037741Smckusick struct iovec aiov; 91137741Smckusick struct uio auio; 91237741Smckusick int error; 9135992Swnj 91437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 91516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 91616694Smckusick ndp->ni_dirp = uap->name; 91737741Smckusick if (error = namei(ndp)) 91837741Smckusick RETURN (error); 91937741Smckusick vp = ndp->ni_vp; 92037741Smckusick if (vp->v_type != VLNK) { 92137741Smckusick error = EINVAL; 9225992Swnj goto out; 9235992Swnj } 92437741Smckusick aiov.iov_base = uap->buf; 92537741Smckusick aiov.iov_len = uap->count; 92637741Smckusick auio.uio_iov = &aiov; 92737741Smckusick auio.uio_iovcnt = 1; 92837741Smckusick auio.uio_offset = 0; 92937741Smckusick auio.uio_rw = UIO_READ; 93037741Smckusick auio.uio_segflg = UIO_USERSPACE; 93137741Smckusick auio.uio_resid = uap->count; 93237741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 9335992Swnj out: 93437741Smckusick vput(vp); 93538408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 93637741Smckusick RETURN (error); 9375992Swnj } 9385992Swnj 9399167Ssam /* 94038259Smckusick * Change flags of a file given path name. 94138259Smckusick */ 94238408Smckusick chflags(scp) 94338408Smckusick register struct syscontext *scp; 94438259Smckusick { 94538259Smckusick struct a { 94638259Smckusick char *fname; 94738259Smckusick int flags; 94838408Smckusick } *uap = (struct a *)scp->sc_ap; 94938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 95038259Smckusick register struct vnode *vp; 95138259Smckusick struct vattr vattr; 95238259Smckusick int error; 95338259Smckusick 95438259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95538259Smckusick ndp->ni_segflg = UIO_USERSPACE; 95638259Smckusick ndp->ni_dirp = uap->fname; 95738259Smckusick vattr_null(&vattr); 95838259Smckusick vattr.va_flags = uap->flags; 95938259Smckusick if (error = namei(ndp)) 96038259Smckusick RETURN (error); 96138259Smckusick vp = ndp->ni_vp; 96238259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 96338259Smckusick error = EROFS; 96438259Smckusick goto out; 96538259Smckusick } 96638259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 96738259Smckusick out: 96838259Smckusick vput(vp); 96938259Smckusick RETURN (error); 97038259Smckusick } 97138259Smckusick 97238259Smckusick /* 97338259Smckusick * Change flags of a file given a file descriptor. 97438259Smckusick */ 97538408Smckusick fchflags(scp) 97638408Smckusick register struct syscontext *scp; 97738259Smckusick { 97838259Smckusick struct a { 97938259Smckusick int fd; 98038259Smckusick int flags; 98138408Smckusick } *uap = (struct a *)scp->sc_ap; 98238259Smckusick struct vattr vattr; 98338259Smckusick struct vnode *vp; 98438259Smckusick struct file *fp; 98538259Smckusick int error; 98638259Smckusick 98738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 98838259Smckusick RETURN (error); 98938259Smckusick vattr_null(&vattr); 99038259Smckusick vattr.va_flags = uap->flags; 99138259Smckusick vp = (struct vnode *)fp->f_data; 99238259Smckusick VOP_LOCK(vp); 99338259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 99438259Smckusick error = EROFS; 99538259Smckusick goto out; 99638259Smckusick } 99738259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 99838259Smckusick out: 99938259Smckusick VOP_UNLOCK(vp); 100038259Smckusick RETURN (error); 100138259Smckusick } 100238259Smckusick 100338259Smckusick /* 10049167Ssam * Change mode of a file given path name. 10059167Ssam */ 100638408Smckusick chmod(scp) 100738408Smckusick register struct syscontext *scp; 10085992Swnj { 10097701Ssam struct a { 10106254Sroot char *fname; 10116254Sroot int fmode; 101238408Smckusick } *uap = (struct a *)scp->sc_ap; 101338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 101437741Smckusick register struct vnode *vp; 101537741Smckusick struct vattr vattr; 101637741Smckusick int error; 10175992Swnj 101837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 101937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 102037741Smckusick ndp->ni_dirp = uap->fname; 102137741Smckusick vattr_null(&vattr); 102237741Smckusick vattr.va_mode = uap->fmode & 07777; 102337741Smckusick if (error = namei(ndp)) 102437741Smckusick RETURN (error); 102537741Smckusick vp = ndp->ni_vp; 102637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 102737741Smckusick error = EROFS; 102837741Smckusick goto out; 102937741Smckusick } 103037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 103137741Smckusick out: 103237741Smckusick vput(vp); 103337741Smckusick RETURN (error); 10347701Ssam } 10357439Sroot 10369167Ssam /* 10379167Ssam * Change mode of a file given a file descriptor. 10389167Ssam */ 103938408Smckusick fchmod(scp) 104038408Smckusick register struct syscontext *scp; 10417701Ssam { 10427701Ssam struct a { 10437701Ssam int fd; 10447701Ssam int fmode; 104538408Smckusick } *uap = (struct a *)scp->sc_ap; 104637741Smckusick struct vattr vattr; 104737741Smckusick struct vnode *vp; 104837741Smckusick struct file *fp; 104937741Smckusick int error; 10507701Ssam 105138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 105237741Smckusick RETURN (error); 105337741Smckusick vattr_null(&vattr); 105437741Smckusick vattr.va_mode = uap->fmode & 07777; 105537741Smckusick vp = (struct vnode *)fp->f_data; 105637741Smckusick VOP_LOCK(vp); 105737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 105837741Smckusick error = EROFS; 105937741Smckusick goto out; 10607439Sroot } 106137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 106237741Smckusick out: 106337741Smckusick VOP_UNLOCK(vp); 106437741Smckusick RETURN (error); 10655992Swnj } 10665992Swnj 10679167Ssam /* 10689167Ssam * Set ownership given a path name. 10699167Ssam */ 107038408Smckusick chown(scp) 107138408Smckusick register struct syscontext *scp; 107237Sbill { 10737701Ssam struct a { 10746254Sroot char *fname; 10756254Sroot int uid; 10766254Sroot int gid; 107738408Smckusick } *uap = (struct a *)scp->sc_ap; 107838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 107937741Smckusick register struct vnode *vp; 108037741Smckusick struct vattr vattr; 108137741Smckusick int error; 108237Sbill 108337741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 108436614Sbostic ndp->ni_segflg = UIO_USERSPACE; 108536614Sbostic ndp->ni_dirp = uap->fname; 108637741Smckusick vattr_null(&vattr); 108737741Smckusick vattr.va_uid = uap->uid; 108837741Smckusick vattr.va_gid = uap->gid; 108937741Smckusick if (error = namei(ndp)) 109037741Smckusick RETURN (error); 109137741Smckusick vp = ndp->ni_vp; 109237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 109337741Smckusick error = EROFS; 109437741Smckusick goto out; 109537741Smckusick } 109637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 109737741Smckusick out: 109837741Smckusick vput(vp); 109937741Smckusick RETURN (error); 11007701Ssam } 11017439Sroot 11029167Ssam /* 11039167Ssam * Set ownership given a file descriptor. 11049167Ssam */ 110538408Smckusick fchown(scp) 110638408Smckusick register struct syscontext *scp; 11077701Ssam { 11087701Ssam struct a { 11097701Ssam int fd; 11107701Ssam int uid; 11117701Ssam int gid; 111238408Smckusick } *uap = (struct a *)scp->sc_ap; 111337741Smckusick struct vattr vattr; 111437741Smckusick struct vnode *vp; 111537741Smckusick struct file *fp; 111637741Smckusick int error; 11177701Ssam 111838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 111937741Smckusick RETURN (error); 112037741Smckusick vattr_null(&vattr); 112137741Smckusick vattr.va_uid = uap->uid; 112237741Smckusick vattr.va_gid = uap->gid; 112337741Smckusick vp = (struct vnode *)fp->f_data; 112437741Smckusick VOP_LOCK(vp); 112537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 112637741Smckusick error = EROFS; 112737741Smckusick goto out; 112837741Smckusick } 112937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 113037741Smckusick out: 113137741Smckusick VOP_UNLOCK(vp); 113237741Smckusick RETURN (error); 11337701Ssam } 11347701Ssam 113538408Smckusick utimes(scp) 113638408Smckusick register struct syscontext *scp; 113711811Ssam { 113811811Ssam register struct a { 113911811Ssam char *fname; 114011811Ssam struct timeval *tptr; 114138408Smckusick } *uap = (struct a *)scp->sc_ap; 114238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 114337741Smckusick register struct vnode *vp; 114411811Ssam struct timeval tv[2]; 114537741Smckusick struct vattr vattr; 114637741Smckusick int error; 114711811Ssam 114837741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 114937741Smckusick RETURN (error); 115037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 115137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 115237741Smckusick ndp->ni_dirp = uap->fname; 115337741Smckusick vattr_null(&vattr); 115437741Smckusick vattr.va_atime = tv[0]; 115537741Smckusick vattr.va_mtime = tv[1]; 115637741Smckusick if (error = namei(ndp)) 115737741Smckusick RETURN (error); 115837741Smckusick vp = ndp->ni_vp; 115937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 116037741Smckusick error = EROFS; 116137741Smckusick goto out; 116221015Smckusick } 116337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 116437741Smckusick out: 116537741Smckusick vput(vp); 116637741Smckusick RETURN (error); 116711811Ssam } 116811811Ssam 11699167Ssam /* 11709167Ssam * Truncate a file given its path name. 11719167Ssam */ 117238408Smckusick truncate(scp) 117338408Smckusick register struct syscontext *scp; 11747701Ssam { 11757701Ssam struct a { 11767701Ssam char *fname; 117726473Skarels off_t length; 117838408Smckusick } *uap = (struct a *)scp->sc_ap; 117938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 118037741Smckusick register struct vnode *vp; 118137741Smckusick struct vattr vattr; 118237741Smckusick int error; 11837701Ssam 118437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 118516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 118616694Smckusick ndp->ni_dirp = uap->fname; 118737741Smckusick vattr_null(&vattr); 118837741Smckusick vattr.va_size = uap->length; 118937741Smckusick if (error = namei(ndp)) 119037741Smckusick RETURN (error); 119137741Smckusick vp = ndp->ni_vp; 119237741Smckusick if (vp->v_type == VDIR) { 119337741Smckusick error = EISDIR; 119437741Smckusick goto out; 11957701Ssam } 119638399Smckusick if ((error = vn_writechk(vp)) || 119738399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 119837741Smckusick goto out; 119937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 120037741Smckusick out: 120137741Smckusick vput(vp); 120237741Smckusick RETURN (error); 12037701Ssam } 12047701Ssam 12059167Ssam /* 12069167Ssam * Truncate a file given a file descriptor. 12079167Ssam */ 120838408Smckusick ftruncate(scp) 120938408Smckusick register struct syscontext *scp; 12107701Ssam { 12117701Ssam struct a { 12127701Ssam int fd; 121326473Skarels off_t length; 121438408Smckusick } *uap = (struct a *)scp->sc_ap; 121537741Smckusick struct vattr vattr; 121637741Smckusick struct vnode *vp; 12177701Ssam struct file *fp; 121837741Smckusick int error; 12197701Ssam 122038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 122137741Smckusick RETURN (error); 122237741Smckusick if ((fp->f_flag & FWRITE) == 0) 122337741Smckusick RETURN (EINVAL); 122437741Smckusick vattr_null(&vattr); 122537741Smckusick vattr.va_size = uap->length; 122637741Smckusick vp = (struct vnode *)fp->f_data; 122737741Smckusick VOP_LOCK(vp); 122837741Smckusick if (vp->v_type == VDIR) { 122937741Smckusick error = EISDIR; 123037741Smckusick goto out; 12317701Ssam } 123238399Smckusick if (error = vn_writechk(vp)) 123337741Smckusick goto out; 123437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 123537741Smckusick out: 123637741Smckusick VOP_UNLOCK(vp); 123737741Smckusick RETURN (error); 12387701Ssam } 12397701Ssam 12409167Ssam /* 12419167Ssam * Synch an open file. 12429167Ssam */ 124338408Smckusick fsync(scp) 124438408Smckusick register struct syscontext *scp; 12459167Ssam { 12469167Ssam struct a { 12479167Ssam int fd; 124838408Smckusick } *uap = (struct a *)scp->sc_ap; 124939592Smckusick register struct vnode *vp; 12509167Ssam struct file *fp; 125137741Smckusick int error; 12529167Ssam 125338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 125437741Smckusick RETURN (error); 125539592Smckusick vp = (struct vnode *)fp->f_data; 125639592Smckusick VOP_LOCK(vp); 125739592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 125839592Smckusick VOP_UNLOCK(vp); 125937741Smckusick RETURN (error); 12609167Ssam } 12619167Ssam 12629167Ssam /* 12639167Ssam * Rename system call. 12649167Ssam * 12659167Ssam * Source and destination must either both be directories, or both 12669167Ssam * not be directories. If target is a directory, it must be empty. 12679167Ssam */ 126838408Smckusick rename(scp) 126938408Smckusick register struct syscontext *scp; 12707701Ssam { 12717701Ssam struct a { 12727701Ssam char *from; 12737701Ssam char *to; 127438408Smckusick } *uap = (struct a *)scp->sc_ap; 127537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 127638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 127737741Smckusick struct nameidata tond; 127837741Smckusick int error; 12797701Ssam 128037741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 128116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 128216694Smckusick ndp->ni_dirp = uap->from; 128337741Smckusick if (error = namei(ndp)) 128437741Smckusick RETURN (error); 128537741Smckusick fvp = ndp->ni_vp; 128638266Smckusick nddup(ndp, &tond); 128737741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 128837741Smckusick tond.ni_segflg = UIO_USERSPACE; 128937741Smckusick tond.ni_dirp = uap->to; 129037741Smckusick error = namei(&tond); 129137741Smckusick tdvp = tond.ni_dvp; 129237741Smckusick tvp = tond.ni_vp; 129337741Smckusick if (tvp != NULL) { 129437741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 129539242Sbostic error = ENOTDIR; 129637741Smckusick goto out; 129737741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 129839242Sbostic error = EISDIR; 129937741Smckusick goto out; 13009167Ssam } 13019167Ssam } 130237741Smckusick if (error) { 130337741Smckusick VOP_ABORTOP(ndp); 130437741Smckusick goto out1; 130537741Smckusick } 130637741Smckusick if (fvp->v_mount != tdvp->v_mount) { 130737741Smckusick error = EXDEV; 13089167Ssam goto out; 130910051Ssam } 131039286Smckusick if (fvp == tdvp) 131137741Smckusick error = EINVAL; 131239286Smckusick /* 131339286Smckusick * If source is the same as the destination, 131439286Smckusick * then there is nothing to do. 131539286Smckusick */ 131639286Smckusick if (fvp == tvp) 131739286Smckusick error = -1; 131837741Smckusick out: 131937741Smckusick if (error) { 132037741Smckusick VOP_ABORTOP(&tond); 132137741Smckusick VOP_ABORTOP(ndp); 13229167Ssam } else { 132337741Smckusick error = VOP_RENAME(ndp, &tond); 13249167Ssam } 132537741Smckusick out1: 132638266Smckusick ndrele(&tond); 132739286Smckusick if (error == -1) 132839286Smckusick RETURN (0); 132937741Smckusick RETURN (error); 13307701Ssam } 13317701Ssam 13327535Sroot /* 133312756Ssam * Mkdir system call 133412756Ssam */ 133538408Smckusick mkdir(scp) 133638408Smckusick register struct syscontext *scp; 133712756Ssam { 133812756Ssam struct a { 133912756Ssam char *name; 134012756Ssam int dmode; 134138408Smckusick } *uap = (struct a *)scp->sc_ap; 134238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 134337741Smckusick register struct vnode *vp; 134437741Smckusick struct vattr vattr; 134537741Smckusick int error; 134612756Ssam 134737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 134816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 134916694Smckusick ndp->ni_dirp = uap->name; 135037741Smckusick if (error = namei(ndp)) 135137741Smckusick RETURN (error); 135237741Smckusick vp = ndp->ni_vp; 135337741Smckusick if (vp != NULL) { 135437741Smckusick VOP_ABORTOP(ndp); 135537741Smckusick RETURN (EEXIST); 135612756Ssam } 135737741Smckusick vattr_null(&vattr); 135837741Smckusick vattr.va_type = VDIR; 135938408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 136037741Smckusick error = VOP_MKDIR(ndp, &vattr); 136138145Smckusick if (!error) 136238145Smckusick vput(ndp->ni_vp); 136337741Smckusick RETURN (error); 136412756Ssam } 136512756Ssam 136612756Ssam /* 136712756Ssam * Rmdir system call. 136812756Ssam */ 136938408Smckusick rmdir(scp) 137038408Smckusick register struct syscontext *scp; 137112756Ssam { 137212756Ssam struct a { 137312756Ssam char *name; 137438408Smckusick } *uap = (struct a *)scp->sc_ap; 137538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 137637741Smckusick register struct vnode *vp; 137737741Smckusick int error; 137812756Ssam 137937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 138016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 138116694Smckusick ndp->ni_dirp = uap->name; 138237741Smckusick if (error = namei(ndp)) 138337741Smckusick RETURN (error); 138437741Smckusick vp = ndp->ni_vp; 138537741Smckusick if (vp->v_type != VDIR) { 138637741Smckusick error = ENOTDIR; 138712756Ssam goto out; 138812756Ssam } 138912756Ssam /* 139037741Smckusick * No rmdir "." please. 139112756Ssam */ 139237741Smckusick if (ndp->ni_dvp == vp) { 139337741Smckusick error = EINVAL; 139412756Ssam goto out; 139512756Ssam } 139612756Ssam /* 139737741Smckusick * Don't unlink a mounted file. 139812756Ssam */ 139937741Smckusick if (vp->v_flag & VROOT) 140037741Smckusick error = EBUSY; 140112756Ssam out: 140237741Smckusick if (error) 140337741Smckusick VOP_ABORTOP(ndp); 140437741Smckusick else 140537741Smckusick error = VOP_RMDIR(ndp); 140637741Smckusick RETURN (error); 140712756Ssam } 140812756Ssam 140937741Smckusick /* 141037741Smckusick * Read a block of directory entries in a file system independent format 141137741Smckusick */ 141238408Smckusick getdirentries(scp) 141338408Smckusick register struct syscontext *scp; 141412756Ssam { 141537741Smckusick register struct a { 141637741Smckusick int fd; 141737741Smckusick char *buf; 141837741Smckusick unsigned count; 141937741Smckusick long *basep; 142038408Smckusick } *uap = (struct a *)scp->sc_ap; 142139592Smckusick register struct vnode *vp; 142216540Ssam struct file *fp; 142337741Smckusick struct uio auio; 142437741Smckusick struct iovec aiov; 142538129Smckusick off_t off; 142640321Smckusick int error, eofflag; 142712756Ssam 142838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 142937741Smckusick RETURN (error); 143037741Smckusick if ((fp->f_flag & FREAD) == 0) 143137741Smckusick RETURN (EBADF); 143239592Smckusick vp = (struct vnode *)fp->f_data; 143339592Smckusick if (vp->v_type != VDIR) 143439592Smckusick RETURN (EINVAL); 143537741Smckusick aiov.iov_base = uap->buf; 143637741Smckusick aiov.iov_len = uap->count; 143737741Smckusick auio.uio_iov = &aiov; 143837741Smckusick auio.uio_iovcnt = 1; 143937741Smckusick auio.uio_rw = UIO_READ; 144037741Smckusick auio.uio_segflg = UIO_USERSPACE; 144137741Smckusick auio.uio_resid = uap->count; 144239592Smckusick VOP_LOCK(vp); 144339592Smckusick auio.uio_offset = off = fp->f_offset; 144440321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 144539592Smckusick fp->f_offset = auio.uio_offset; 144639592Smckusick VOP_UNLOCK(vp); 144739592Smckusick if (error) 144837741Smckusick RETURN (error); 144939592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 145038408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 145137741Smckusick RETURN (error); 145212756Ssam } 145312756Ssam 145412756Ssam /* 145512756Ssam * mode mask for creation of files 145612756Ssam */ 145738408Smckusick umask(scp) 145838408Smckusick register struct syscontext *scp; 145912756Ssam { 146012756Ssam register struct a { 146112756Ssam int mask; 146238408Smckusick } *uap = (struct a *)scp->sc_ap; 146312756Ssam 146438408Smckusick scp->sc_retval1 = scp->sc_cmask; 146538408Smckusick scp->sc_cmask = uap->mask & 07777; 146637741Smckusick RETURN (0); 146712756Ssam } 146837741Smckusick 146939566Smarc /* 147039566Smarc * Void all references to file by ripping underlying filesystem 147139566Smarc * away from vnode. 147239566Smarc */ 147339566Smarc revoke(scp) 147439566Smarc register struct syscontext *scp; 147539566Smarc { 147639566Smarc struct a { 147739566Smarc char *fname; 147839566Smarc } *uap = (struct a *)scp->sc_ap; 147939566Smarc register struct nameidata *ndp = &scp->sc_nd; 148039566Smarc register struct vnode *vp; 148139566Smarc struct vattr vattr; 148239566Smarc int error; 148339566Smarc 148439566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 148539566Smarc ndp->ni_segflg = UIO_USERSPACE; 148639566Smarc ndp->ni_dirp = uap->fname; 148739566Smarc if (error = namei(ndp)) 148839566Smarc RETURN (error); 148939566Smarc vp = ndp->ni_vp; 149039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 149139566Smarc error = EINVAL; 149239566Smarc goto out; 149339566Smarc } 149439566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 149539566Smarc goto out; 149639566Smarc if (scp->sc_uid != vattr.va_uid || 149739566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 149839566Smarc goto out; 149939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 150039632Smckusick vgoneall(vp); 150139566Smarc out: 150239566Smarc vrele(vp); 150339566Smarc RETURN (error); 150439566Smarc } 150539566Smarc 150638408Smckusick getvnode(ofile, fdes, fpp) 150738408Smckusick struct file *ofile[]; 150837741Smckusick struct file **fpp; 150937741Smckusick int fdes; 151037741Smckusick { 151137741Smckusick struct file *fp; 151237741Smckusick 151338408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 151437741Smckusick return (EBADF); 151537741Smckusick if (fp->f_type != DTYPE_VNODE) 151637741Smckusick return (EINVAL); 151737741Smckusick *fpp = fp; 151837741Smckusick return (0); 151937741Smckusick } 1520