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*40884Smckusick * @(#)vfs_syscalls.c 7.43 (Berkeley) 04/10/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() */ 53040635Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ S_ISVTX)) { 53137741Smckusick crfree(fp->f_cred); 53237741Smckusick fp->f_count--; 533*40884Smckusick if (error == EJUSTRETURN) /* XXX from fdopen */ 534*40884Smckusick return (0); /* XXX from fdopen */ 535*40884Smckusick if (error == ERESTART) 536*40884Smckusick error = EINTR; 53739499Smckusick scp->sc_ofile[indx] = NULL; 53837741Smckusick return (error); 53912756Ssam } 54037741Smckusick fp->f_flag = fmode & FMASK; 54137741Smckusick fp->f_type = DTYPE_VNODE; 54237741Smckusick fp->f_ops = &vnops; 54337741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 54437741Smckusick if (resultfd) 54537741Smckusick *resultfd = indx; 54637741Smckusick return (0); 5476254Sroot } 5486254Sroot 5496254Sroot /* 5506254Sroot * Mknod system call 5516254Sroot */ 55238408Smckusick mknod(scp) 55338408Smckusick register struct syscontext *scp; 5546254Sroot { 5556254Sroot register struct a { 5566254Sroot char *fname; 5576254Sroot int fmode; 5586254Sroot int dev; 55938408Smckusick } *uap = (struct a *)scp->sc_ap; 56038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 56137741Smckusick register struct vnode *vp; 56237741Smckusick struct vattr vattr; 56337741Smckusick int error; 5646254Sroot 56538408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 56637741Smckusick RETURN (error); 56737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 56816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 56916694Smckusick ndp->ni_dirp = uap->fname; 57037741Smckusick if (error = namei(ndp)) 57137741Smckusick RETURN (error); 57237741Smckusick vp = ndp->ni_vp; 57337741Smckusick if (vp != NULL) { 57437741Smckusick error = EEXIST; 57512756Ssam goto out; 5766254Sroot } 57737741Smckusick vattr_null(&vattr); 57840635Smckusick switch (uap->fmode & S_IFMT) { 57912756Ssam 58040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 58137741Smckusick vattr.va_type = VBAD; 58237741Smckusick break; 58340635Smckusick case S_IFCHR: 58437741Smckusick vattr.va_type = VCHR; 58537741Smckusick break; 58640635Smckusick case S_IFBLK: 58737741Smckusick vattr.va_type = VBLK; 58837741Smckusick break; 58937741Smckusick default: 59037741Smckusick error = EINVAL; 59137741Smckusick goto out; 5926254Sroot } 59338408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 59437741Smckusick vattr.va_rdev = uap->dev; 5956254Sroot out: 59637741Smckusick if (error) 59737741Smckusick VOP_ABORTOP(ndp); 59837741Smckusick else 59937741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 60037741Smckusick RETURN (error); 6016254Sroot } 6026254Sroot 6036254Sroot /* 60440285Smckusick * Mkfifo system call 60540285Smckusick */ 60640285Smckusick mkfifo(scp) 60740285Smckusick register struct syscontext *scp; 60840285Smckusick { 60940285Smckusick register struct a { 61040285Smckusick char *fname; 61140285Smckusick int fmode; 61240285Smckusick } *uap = (struct a *)scp->sc_ap; 61340285Smckusick register struct nameidata *ndp = &scp->sc_nd; 61440285Smckusick struct vattr vattr; 61540285Smckusick int error; 61640285Smckusick 61740285Smckusick #ifndef FIFO 61840285Smckusick RETURN (EOPNOTSUPP); 61940285Smckusick #else 62040285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62140285Smckusick ndp->ni_segflg = UIO_USERSPACE; 62240285Smckusick ndp->ni_dirp = uap->fname; 62340285Smckusick if (error = namei(ndp)) 62440285Smckusick RETURN (error); 62540285Smckusick if (ndp->ni_vp != NULL) { 62640285Smckusick VOP_ABORTOP(ndp); 62740285Smckusick RETURN (EEXIST); 62840285Smckusick } else { 62940285Smckusick vattr_null(&vattr); 63040285Smckusick vattr.va_type = VFIFO; 63140285Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 63240285Smckusick } 63340285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 63440285Smckusick #endif /* FIFO */ 63540285Smckusick } 63640285Smckusick 63740285Smckusick /* 6386254Sroot * link system call 6396254Sroot */ 64038408Smckusick link(scp) 64138408Smckusick register struct syscontext *scp; 6426254Sroot { 6436254Sroot register struct a { 6446254Sroot char *target; 6456254Sroot char *linkname; 64638408Smckusick } *uap = (struct a *)scp->sc_ap; 64738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64837741Smckusick register struct vnode *vp, *xp; 64937741Smckusick int error; 6506254Sroot 65116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 65216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 65316694Smckusick ndp->ni_dirp = uap->target; 65437741Smckusick if (error = namei(ndp)) 65537741Smckusick RETURN (error); 65637741Smckusick vp = ndp->ni_vp; 65737741Smckusick if (vp->v_type == VDIR && 65838408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 65937741Smckusick goto out1; 66037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 66116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 66237741Smckusick if (error = namei(ndp)) 66337741Smckusick goto out1; 66437741Smckusick xp = ndp->ni_vp; 6656254Sroot if (xp != NULL) { 66637741Smckusick error = EEXIST; 6676254Sroot goto out; 6686254Sroot } 66937741Smckusick xp = ndp->ni_dvp; 67037741Smckusick if (vp->v_mount != xp->v_mount) 67137741Smckusick error = EXDEV; 6726254Sroot out: 67337741Smckusick if (error) 67437741Smckusick VOP_ABORTOP(ndp); 67537741Smckusick else 67637741Smckusick error = VOP_LINK(vp, ndp); 67737741Smckusick out1: 67837741Smckusick vrele(vp); 67937741Smckusick RETURN (error); 6806254Sroot } 6816254Sroot 6826254Sroot /* 6836254Sroot * symlink -- make a symbolic link 6846254Sroot */ 68538408Smckusick symlink(scp) 68638408Smckusick register struct syscontext *scp; 6876254Sroot { 68837741Smckusick struct a { 6896254Sroot char *target; 6906254Sroot char *linkname; 69138408Smckusick } *uap = (struct a *)scp->sc_ap; 69238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 69337741Smckusick register struct vnode *vp; 69437741Smckusick struct vattr vattr; 69537741Smckusick char *target; 69637741Smckusick int error; 6976254Sroot 69816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69916694Smckusick ndp->ni_dirp = uap->linkname; 70037741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 70137741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 70237741Smckusick goto out1; 70337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 70437741Smckusick if (error = namei(ndp)) 70537741Smckusick goto out1; 70637741Smckusick vp = ndp->ni_vp; 70737741Smckusick if (vp) { 70837741Smckusick error = EEXIST; 70937741Smckusick goto out; 7106254Sroot } 71137741Smckusick vp = ndp->ni_dvp; 71237741Smckusick vattr_null(&vattr); 71338408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 71437741Smckusick out: 71537741Smckusick if (error) 71637741Smckusick VOP_ABORTOP(ndp); 71737741Smckusick else 71837741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 71937741Smckusick out1: 72037741Smckusick FREE(target, M_NAMEI); 72137741Smckusick RETURN (error); 7226254Sroot } 7236254Sroot 7246254Sroot /* 7256254Sroot * Unlink system call. 7266254Sroot * Hard to avoid races here, especially 7276254Sroot * in unlinking directories. 7286254Sroot */ 72938408Smckusick unlink(scp) 73038408Smckusick register struct syscontext *scp; 7316254Sroot { 7326254Sroot struct a { 7336254Sroot char *fname; 73438408Smckusick } *uap = (struct a *)scp->sc_ap; 73538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 73637741Smckusick register struct vnode *vp; 73737741Smckusick int error; 7386254Sroot 73937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 74016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 74116694Smckusick ndp->ni_dirp = uap->fname; 74237741Smckusick if (error = namei(ndp)) 74337741Smckusick RETURN (error); 74437741Smckusick vp = ndp->ni_vp; 74537741Smckusick if (vp->v_type == VDIR && 74638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7476254Sroot goto out; 7486254Sroot /* 7496254Sroot * Don't unlink a mounted file. 7506254Sroot */ 75137741Smckusick if (vp->v_flag & VROOT) { 75237741Smckusick error = EBUSY; 7536254Sroot goto out; 7546254Sroot } 75537741Smckusick if (vp->v_flag & VTEXT) 75637741Smckusick xrele(vp); /* try once to free text */ 7576254Sroot out: 75837741Smckusick if (error) 75937741Smckusick VOP_ABORTOP(ndp); 7607142Smckusick else 76137741Smckusick error = VOP_REMOVE(ndp); 76237741Smckusick RETURN (error); 7636254Sroot } 7646254Sroot 7656254Sroot /* 7666254Sroot * Seek system call 7676254Sroot */ 76838408Smckusick lseek(scp) 76938408Smckusick register struct syscontext *scp; 7706254Sroot { 7716254Sroot register struct file *fp; 7726254Sroot register struct a { 77337741Smckusick int fdes; 7746254Sroot off_t off; 7756254Sroot int sbase; 77638408Smckusick } *uap = (struct a *)scp->sc_ap; 77737741Smckusick struct vattr vattr; 77837741Smckusick int error; 7796254Sroot 78037741Smckusick if ((unsigned)uap->fdes >= NOFILE || 78138408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 78237741Smckusick RETURN (EBADF); 78337741Smckusick if (fp->f_type != DTYPE_VNODE) 78437741Smckusick RETURN (ESPIPE); 78513878Ssam switch (uap->sbase) { 78613878Ssam 78713878Ssam case L_INCR: 78813878Ssam fp->f_offset += uap->off; 78913878Ssam break; 79013878Ssam 79113878Ssam case L_XTND: 79237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 79338408Smckusick &vattr, scp->sc_cred)) 79437741Smckusick RETURN (error); 79537741Smckusick fp->f_offset = uap->off + vattr.va_size; 79613878Ssam break; 79713878Ssam 79813878Ssam case L_SET: 79913878Ssam fp->f_offset = uap->off; 80013878Ssam break; 80113878Ssam 80213878Ssam default: 80337741Smckusick RETURN (EINVAL); 80413878Ssam } 80538408Smckusick scp->sc_offset = fp->f_offset; 80637741Smckusick RETURN (0); 8076254Sroot } 8086254Sroot 8096254Sroot /* 8106254Sroot * Access system call 8116254Sroot */ 81238408Smckusick saccess(scp) 81338408Smckusick register struct syscontext *scp; 8146254Sroot { 8156254Sroot register struct a { 8166254Sroot char *fname; 8176254Sroot int fmode; 81838408Smckusick } *uap = (struct a *)scp->sc_ap; 81938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 82037741Smckusick register struct vnode *vp; 82137741Smckusick int error, mode, svuid, svgid; 8226254Sroot 82338408Smckusick svuid = scp->sc_uid; 82438408Smckusick svgid = scp->sc_gid; 82538408Smckusick scp->sc_uid = scp->sc_ruid; 82638408Smckusick scp->sc_gid = scp->sc_rgid; 82737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 82816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82916694Smckusick ndp->ni_dirp = uap->fname; 83037741Smckusick if (error = namei(ndp)) 83137741Smckusick goto out1; 83237741Smckusick vp = ndp->ni_vp; 83337741Smckusick /* 83437741Smckusick * fmode == 0 means only check for exist 83537741Smckusick */ 83637741Smckusick if (uap->fmode) { 83737741Smckusick mode = 0; 83837741Smckusick if (uap->fmode & R_OK) 83937741Smckusick mode |= VREAD; 84037741Smckusick if (uap->fmode & W_OK) 84137741Smckusick mode |= VWRITE; 84237741Smckusick if (uap->fmode & X_OK) 84337741Smckusick mode |= VEXEC; 84439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 84538399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 8466254Sroot } 84737741Smckusick vput(vp); 84837741Smckusick out1: 84938408Smckusick scp->sc_uid = svuid; 85038408Smckusick scp->sc_gid = svgid; 85137741Smckusick RETURN (error); 8526254Sroot } 8536254Sroot 8546254Sroot /* 8556574Smckusic * Stat system call. This version follows links. 85637Sbill */ 85738408Smckusick stat(scp) 85838408Smckusick struct syscontext *scp; 85937Sbill { 86037Sbill 86138408Smckusick stat1(scp, FOLLOW); 86237Sbill } 86337Sbill 86437Sbill /* 8656574Smckusic * Lstat system call. This version does not follow links. 8665992Swnj */ 86738408Smckusick lstat(scp) 86838408Smckusick struct syscontext *scp; 8695992Swnj { 87012756Ssam 87138408Smckusick stat1(scp, NOFOLLOW); 87212756Ssam } 87312756Ssam 87438408Smckusick stat1(scp, follow) 87538408Smckusick register struct syscontext *scp; 87612756Ssam int follow; 87712756Ssam { 8785992Swnj register struct a { 8795992Swnj char *fname; 88012756Ssam struct stat *ub; 88138408Smckusick } *uap = (struct a *)scp->sc_ap; 88238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 88312756Ssam struct stat sb; 88437741Smckusick int error; 8855992Swnj 88637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 88716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 88816694Smckusick ndp->ni_dirp = uap->fname; 88937741Smckusick if (error = namei(ndp)) 89037741Smckusick RETURN (error); 89137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 89237741Smckusick vput(ndp->ni_vp); 89337741Smckusick if (error) 89437741Smckusick RETURN (error); 89537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 89637741Smckusick RETURN (error); 8975992Swnj } 8985992Swnj 8995992Swnj /* 9005992Swnj * Return target name of a symbolic link 90137Sbill */ 90238408Smckusick readlink(scp) 90338408Smckusick register struct syscontext *scp; 9045992Swnj { 9055992Swnj register struct a { 9065992Swnj char *name; 9075992Swnj char *buf; 9085992Swnj int count; 90938408Smckusick } *uap = (struct a *)scp->sc_ap; 91038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 91137741Smckusick register struct vnode *vp; 91237741Smckusick struct iovec aiov; 91337741Smckusick struct uio auio; 91437741Smckusick int error; 9155992Swnj 91637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 91716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 91816694Smckusick ndp->ni_dirp = uap->name; 91937741Smckusick if (error = namei(ndp)) 92037741Smckusick RETURN (error); 92137741Smckusick vp = ndp->ni_vp; 92237741Smckusick if (vp->v_type != VLNK) { 92337741Smckusick error = EINVAL; 9245992Swnj goto out; 9255992Swnj } 92637741Smckusick aiov.iov_base = uap->buf; 92737741Smckusick aiov.iov_len = uap->count; 92837741Smckusick auio.uio_iov = &aiov; 92937741Smckusick auio.uio_iovcnt = 1; 93037741Smckusick auio.uio_offset = 0; 93137741Smckusick auio.uio_rw = UIO_READ; 93237741Smckusick auio.uio_segflg = UIO_USERSPACE; 93337741Smckusick auio.uio_resid = uap->count; 93437741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 9355992Swnj out: 93637741Smckusick vput(vp); 93738408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 93837741Smckusick RETURN (error); 9395992Swnj } 9405992Swnj 9419167Ssam /* 94238259Smckusick * Change flags of a file given path name. 94338259Smckusick */ 94438408Smckusick chflags(scp) 94538408Smckusick register struct syscontext *scp; 94638259Smckusick { 94738259Smckusick struct a { 94838259Smckusick char *fname; 94938259Smckusick int flags; 95038408Smckusick } *uap = (struct a *)scp->sc_ap; 95138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 95238259Smckusick register struct vnode *vp; 95338259Smckusick struct vattr vattr; 95438259Smckusick int error; 95538259Smckusick 95638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 95838259Smckusick ndp->ni_dirp = uap->fname; 95938259Smckusick vattr_null(&vattr); 96038259Smckusick vattr.va_flags = uap->flags; 96138259Smckusick if (error = namei(ndp)) 96238259Smckusick RETURN (error); 96338259Smckusick vp = ndp->ni_vp; 96438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 96538259Smckusick error = EROFS; 96638259Smckusick goto out; 96738259Smckusick } 96838259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 96938259Smckusick out: 97038259Smckusick vput(vp); 97138259Smckusick RETURN (error); 97238259Smckusick } 97338259Smckusick 97438259Smckusick /* 97538259Smckusick * Change flags of a file given a file descriptor. 97638259Smckusick */ 97738408Smckusick fchflags(scp) 97838408Smckusick register struct syscontext *scp; 97938259Smckusick { 98038259Smckusick struct a { 98138259Smckusick int fd; 98238259Smckusick int flags; 98338408Smckusick } *uap = (struct a *)scp->sc_ap; 98438259Smckusick struct vattr vattr; 98538259Smckusick struct vnode *vp; 98638259Smckusick struct file *fp; 98738259Smckusick int error; 98838259Smckusick 98938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 99038259Smckusick RETURN (error); 99138259Smckusick vattr_null(&vattr); 99238259Smckusick vattr.va_flags = uap->flags; 99338259Smckusick vp = (struct vnode *)fp->f_data; 99438259Smckusick VOP_LOCK(vp); 99538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 99638259Smckusick error = EROFS; 99738259Smckusick goto out; 99838259Smckusick } 99938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 100038259Smckusick out: 100138259Smckusick VOP_UNLOCK(vp); 100238259Smckusick RETURN (error); 100338259Smckusick } 100438259Smckusick 100538259Smckusick /* 10069167Ssam * Change mode of a file given path name. 10079167Ssam */ 100838408Smckusick chmod(scp) 100938408Smckusick register struct syscontext *scp; 10105992Swnj { 10117701Ssam struct a { 10126254Sroot char *fname; 10136254Sroot int fmode; 101438408Smckusick } *uap = (struct a *)scp->sc_ap; 101538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 101637741Smckusick register struct vnode *vp; 101737741Smckusick struct vattr vattr; 101837741Smckusick int error; 10195992Swnj 102037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 102137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 102237741Smckusick ndp->ni_dirp = uap->fname; 102337741Smckusick vattr_null(&vattr); 102437741Smckusick vattr.va_mode = uap->fmode & 07777; 102537741Smckusick if (error = namei(ndp)) 102637741Smckusick RETURN (error); 102737741Smckusick vp = ndp->ni_vp; 102837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 102937741Smckusick error = EROFS; 103037741Smckusick goto out; 103137741Smckusick } 103237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 103337741Smckusick out: 103437741Smckusick vput(vp); 103537741Smckusick RETURN (error); 10367701Ssam } 10377439Sroot 10389167Ssam /* 10399167Ssam * Change mode of a file given a file descriptor. 10409167Ssam */ 104138408Smckusick fchmod(scp) 104238408Smckusick register struct syscontext *scp; 10437701Ssam { 10447701Ssam struct a { 10457701Ssam int fd; 10467701Ssam int fmode; 104738408Smckusick } *uap = (struct a *)scp->sc_ap; 104837741Smckusick struct vattr vattr; 104937741Smckusick struct vnode *vp; 105037741Smckusick struct file *fp; 105137741Smckusick int error; 10527701Ssam 105338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 105437741Smckusick RETURN (error); 105537741Smckusick vattr_null(&vattr); 105637741Smckusick vattr.va_mode = uap->fmode & 07777; 105737741Smckusick vp = (struct vnode *)fp->f_data; 105837741Smckusick VOP_LOCK(vp); 105937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 106037741Smckusick error = EROFS; 106137741Smckusick goto out; 10627439Sroot } 106337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 106437741Smckusick out: 106537741Smckusick VOP_UNLOCK(vp); 106637741Smckusick RETURN (error); 10675992Swnj } 10685992Swnj 10699167Ssam /* 10709167Ssam * Set ownership given a path name. 10719167Ssam */ 107238408Smckusick chown(scp) 107338408Smckusick register struct syscontext *scp; 107437Sbill { 10757701Ssam struct a { 10766254Sroot char *fname; 10776254Sroot int uid; 10786254Sroot int gid; 107938408Smckusick } *uap = (struct a *)scp->sc_ap; 108038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 108137741Smckusick register struct vnode *vp; 108237741Smckusick struct vattr vattr; 108337741Smckusick int error; 108437Sbill 108537741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 108636614Sbostic ndp->ni_segflg = UIO_USERSPACE; 108736614Sbostic ndp->ni_dirp = uap->fname; 108837741Smckusick vattr_null(&vattr); 108937741Smckusick vattr.va_uid = uap->uid; 109037741Smckusick vattr.va_gid = uap->gid; 109137741Smckusick if (error = namei(ndp)) 109237741Smckusick RETURN (error); 109337741Smckusick vp = ndp->ni_vp; 109437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 109537741Smckusick error = EROFS; 109637741Smckusick goto out; 109737741Smckusick } 109837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 109937741Smckusick out: 110037741Smckusick vput(vp); 110137741Smckusick RETURN (error); 11027701Ssam } 11037439Sroot 11049167Ssam /* 11059167Ssam * Set ownership given a file descriptor. 11069167Ssam */ 110738408Smckusick fchown(scp) 110838408Smckusick register struct syscontext *scp; 11097701Ssam { 11107701Ssam struct a { 11117701Ssam int fd; 11127701Ssam int uid; 11137701Ssam int gid; 111438408Smckusick } *uap = (struct a *)scp->sc_ap; 111537741Smckusick struct vattr vattr; 111637741Smckusick struct vnode *vp; 111737741Smckusick struct file *fp; 111837741Smckusick int error; 11197701Ssam 112038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 112137741Smckusick RETURN (error); 112237741Smckusick vattr_null(&vattr); 112337741Smckusick vattr.va_uid = uap->uid; 112437741Smckusick vattr.va_gid = uap->gid; 112537741Smckusick vp = (struct vnode *)fp->f_data; 112637741Smckusick VOP_LOCK(vp); 112737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 112837741Smckusick error = EROFS; 112937741Smckusick goto out; 113037741Smckusick } 113137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 113237741Smckusick out: 113337741Smckusick VOP_UNLOCK(vp); 113437741Smckusick RETURN (error); 11357701Ssam } 11367701Ssam 113738408Smckusick utimes(scp) 113838408Smckusick register struct syscontext *scp; 113911811Ssam { 114011811Ssam register struct a { 114111811Ssam char *fname; 114211811Ssam struct timeval *tptr; 114338408Smckusick } *uap = (struct a *)scp->sc_ap; 114438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 114537741Smckusick register struct vnode *vp; 114611811Ssam struct timeval tv[2]; 114737741Smckusick struct vattr vattr; 114837741Smckusick int error; 114911811Ssam 115037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 115137741Smckusick RETURN (error); 115237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 115337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 115437741Smckusick ndp->ni_dirp = uap->fname; 115537741Smckusick vattr_null(&vattr); 115637741Smckusick vattr.va_atime = tv[0]; 115737741Smckusick vattr.va_mtime = tv[1]; 115837741Smckusick if (error = namei(ndp)) 115937741Smckusick RETURN (error); 116037741Smckusick vp = ndp->ni_vp; 116137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 116237741Smckusick error = EROFS; 116337741Smckusick goto out; 116421015Smckusick } 116537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 116637741Smckusick out: 116737741Smckusick vput(vp); 116837741Smckusick RETURN (error); 116911811Ssam } 117011811Ssam 11719167Ssam /* 11729167Ssam * Truncate a file given its path name. 11739167Ssam */ 117438408Smckusick truncate(scp) 117538408Smckusick register struct syscontext *scp; 11767701Ssam { 11777701Ssam struct a { 11787701Ssam char *fname; 117926473Skarels off_t length; 118038408Smckusick } *uap = (struct a *)scp->sc_ap; 118138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 118237741Smckusick register struct vnode *vp; 118337741Smckusick struct vattr vattr; 118437741Smckusick int error; 11857701Ssam 118637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 118716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 118816694Smckusick ndp->ni_dirp = uap->fname; 118937741Smckusick vattr_null(&vattr); 119037741Smckusick vattr.va_size = uap->length; 119137741Smckusick if (error = namei(ndp)) 119237741Smckusick RETURN (error); 119337741Smckusick vp = ndp->ni_vp; 119437741Smckusick if (vp->v_type == VDIR) { 119537741Smckusick error = EISDIR; 119637741Smckusick goto out; 11977701Ssam } 119838399Smckusick if ((error = vn_writechk(vp)) || 119938399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 120037741Smckusick goto out; 120137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 120237741Smckusick out: 120337741Smckusick vput(vp); 120437741Smckusick RETURN (error); 12057701Ssam } 12067701Ssam 12079167Ssam /* 12089167Ssam * Truncate a file given a file descriptor. 12099167Ssam */ 121038408Smckusick ftruncate(scp) 121138408Smckusick register struct syscontext *scp; 12127701Ssam { 12137701Ssam struct a { 12147701Ssam int fd; 121526473Skarels off_t length; 121638408Smckusick } *uap = (struct a *)scp->sc_ap; 121737741Smckusick struct vattr vattr; 121837741Smckusick struct vnode *vp; 12197701Ssam struct file *fp; 122037741Smckusick int error; 12217701Ssam 122238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 122337741Smckusick RETURN (error); 122437741Smckusick if ((fp->f_flag & FWRITE) == 0) 122537741Smckusick RETURN (EINVAL); 122637741Smckusick vattr_null(&vattr); 122737741Smckusick vattr.va_size = uap->length; 122837741Smckusick vp = (struct vnode *)fp->f_data; 122937741Smckusick VOP_LOCK(vp); 123037741Smckusick if (vp->v_type == VDIR) { 123137741Smckusick error = EISDIR; 123237741Smckusick goto out; 12337701Ssam } 123438399Smckusick if (error = vn_writechk(vp)) 123537741Smckusick goto out; 123637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 123737741Smckusick out: 123837741Smckusick VOP_UNLOCK(vp); 123937741Smckusick RETURN (error); 12407701Ssam } 12417701Ssam 12429167Ssam /* 12439167Ssam * Synch an open file. 12449167Ssam */ 124538408Smckusick fsync(scp) 124638408Smckusick register struct syscontext *scp; 12479167Ssam { 12489167Ssam struct a { 12499167Ssam int fd; 125038408Smckusick } *uap = (struct a *)scp->sc_ap; 125139592Smckusick register struct vnode *vp; 12529167Ssam struct file *fp; 125337741Smckusick int error; 12549167Ssam 125538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 125637741Smckusick RETURN (error); 125739592Smckusick vp = (struct vnode *)fp->f_data; 125839592Smckusick VOP_LOCK(vp); 125939592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 126039592Smckusick VOP_UNLOCK(vp); 126137741Smckusick RETURN (error); 12629167Ssam } 12639167Ssam 12649167Ssam /* 12659167Ssam * Rename system call. 12669167Ssam * 12679167Ssam * Source and destination must either both be directories, or both 12689167Ssam * not be directories. If target is a directory, it must be empty. 12699167Ssam */ 127038408Smckusick rename(scp) 127138408Smckusick register struct syscontext *scp; 12727701Ssam { 12737701Ssam struct a { 12747701Ssam char *from; 12757701Ssam char *to; 127638408Smckusick } *uap = (struct a *)scp->sc_ap; 127737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 127838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 127937741Smckusick struct nameidata tond; 128037741Smckusick int error; 12817701Ssam 128237741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 128316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 128416694Smckusick ndp->ni_dirp = uap->from; 128537741Smckusick if (error = namei(ndp)) 128637741Smckusick RETURN (error); 128737741Smckusick fvp = ndp->ni_vp; 128838266Smckusick nddup(ndp, &tond); 128937741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 129037741Smckusick tond.ni_segflg = UIO_USERSPACE; 129137741Smckusick tond.ni_dirp = uap->to; 129237741Smckusick error = namei(&tond); 129337741Smckusick tdvp = tond.ni_dvp; 129437741Smckusick tvp = tond.ni_vp; 129537741Smckusick if (tvp != NULL) { 129637741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 129739242Sbostic error = ENOTDIR; 129837741Smckusick goto out; 129937741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 130039242Sbostic error = EISDIR; 130137741Smckusick goto out; 13029167Ssam } 13039167Ssam } 130437741Smckusick if (error) { 130537741Smckusick VOP_ABORTOP(ndp); 130637741Smckusick goto out1; 130737741Smckusick } 130837741Smckusick if (fvp->v_mount != tdvp->v_mount) { 130937741Smckusick error = EXDEV; 13109167Ssam goto out; 131110051Ssam } 131239286Smckusick if (fvp == tdvp) 131337741Smckusick error = EINVAL; 131439286Smckusick /* 131539286Smckusick * If source is the same as the destination, 131639286Smckusick * then there is nothing to do. 131739286Smckusick */ 131839286Smckusick if (fvp == tvp) 131939286Smckusick error = -1; 132037741Smckusick out: 132137741Smckusick if (error) { 132237741Smckusick VOP_ABORTOP(&tond); 132337741Smckusick VOP_ABORTOP(ndp); 13249167Ssam } else { 132537741Smckusick error = VOP_RENAME(ndp, &tond); 13269167Ssam } 132737741Smckusick out1: 132838266Smckusick ndrele(&tond); 132939286Smckusick if (error == -1) 133039286Smckusick RETURN (0); 133137741Smckusick RETURN (error); 13327701Ssam } 13337701Ssam 13347535Sroot /* 133512756Ssam * Mkdir system call 133612756Ssam */ 133738408Smckusick mkdir(scp) 133838408Smckusick register struct syscontext *scp; 133912756Ssam { 134012756Ssam struct a { 134112756Ssam char *name; 134212756Ssam int dmode; 134338408Smckusick } *uap = (struct a *)scp->sc_ap; 134438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 134537741Smckusick register struct vnode *vp; 134637741Smckusick struct vattr vattr; 134737741Smckusick int error; 134812756Ssam 134937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 135016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 135116694Smckusick ndp->ni_dirp = uap->name; 135237741Smckusick if (error = namei(ndp)) 135337741Smckusick RETURN (error); 135437741Smckusick vp = ndp->ni_vp; 135537741Smckusick if (vp != NULL) { 135637741Smckusick VOP_ABORTOP(ndp); 135737741Smckusick RETURN (EEXIST); 135812756Ssam } 135937741Smckusick vattr_null(&vattr); 136037741Smckusick vattr.va_type = VDIR; 136138408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 136237741Smckusick error = VOP_MKDIR(ndp, &vattr); 136338145Smckusick if (!error) 136438145Smckusick vput(ndp->ni_vp); 136537741Smckusick RETURN (error); 136612756Ssam } 136712756Ssam 136812756Ssam /* 136912756Ssam * Rmdir system call. 137012756Ssam */ 137138408Smckusick rmdir(scp) 137238408Smckusick register struct syscontext *scp; 137312756Ssam { 137412756Ssam struct a { 137512756Ssam char *name; 137638408Smckusick } *uap = (struct a *)scp->sc_ap; 137738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 137837741Smckusick register struct vnode *vp; 137937741Smckusick int error; 138012756Ssam 138137741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 138216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 138316694Smckusick ndp->ni_dirp = uap->name; 138437741Smckusick if (error = namei(ndp)) 138537741Smckusick RETURN (error); 138637741Smckusick vp = ndp->ni_vp; 138737741Smckusick if (vp->v_type != VDIR) { 138837741Smckusick error = ENOTDIR; 138912756Ssam goto out; 139012756Ssam } 139112756Ssam /* 139237741Smckusick * No rmdir "." please. 139312756Ssam */ 139437741Smckusick if (ndp->ni_dvp == vp) { 139537741Smckusick error = EINVAL; 139612756Ssam goto out; 139712756Ssam } 139812756Ssam /* 139937741Smckusick * Don't unlink a mounted file. 140012756Ssam */ 140137741Smckusick if (vp->v_flag & VROOT) 140237741Smckusick error = EBUSY; 140312756Ssam out: 140437741Smckusick if (error) 140537741Smckusick VOP_ABORTOP(ndp); 140637741Smckusick else 140737741Smckusick error = VOP_RMDIR(ndp); 140837741Smckusick RETURN (error); 140912756Ssam } 141012756Ssam 141137741Smckusick /* 141237741Smckusick * Read a block of directory entries in a file system independent format 141337741Smckusick */ 141438408Smckusick getdirentries(scp) 141538408Smckusick register struct syscontext *scp; 141612756Ssam { 141737741Smckusick register struct a { 141837741Smckusick int fd; 141937741Smckusick char *buf; 142037741Smckusick unsigned count; 142137741Smckusick long *basep; 142238408Smckusick } *uap = (struct a *)scp->sc_ap; 142339592Smckusick register struct vnode *vp; 142416540Ssam struct file *fp; 142537741Smckusick struct uio auio; 142637741Smckusick struct iovec aiov; 142738129Smckusick off_t off; 142840321Smckusick int error, eofflag; 142912756Ssam 143038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 143137741Smckusick RETURN (error); 143237741Smckusick if ((fp->f_flag & FREAD) == 0) 143337741Smckusick RETURN (EBADF); 143439592Smckusick vp = (struct vnode *)fp->f_data; 143539592Smckusick if (vp->v_type != VDIR) 143639592Smckusick RETURN (EINVAL); 143737741Smckusick aiov.iov_base = uap->buf; 143837741Smckusick aiov.iov_len = uap->count; 143937741Smckusick auio.uio_iov = &aiov; 144037741Smckusick auio.uio_iovcnt = 1; 144137741Smckusick auio.uio_rw = UIO_READ; 144237741Smckusick auio.uio_segflg = UIO_USERSPACE; 144337741Smckusick auio.uio_resid = uap->count; 144439592Smckusick VOP_LOCK(vp); 144539592Smckusick auio.uio_offset = off = fp->f_offset; 144640321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 144739592Smckusick fp->f_offset = auio.uio_offset; 144839592Smckusick VOP_UNLOCK(vp); 144939592Smckusick if (error) 145037741Smckusick RETURN (error); 145139592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 145238408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 145337741Smckusick RETURN (error); 145412756Ssam } 145512756Ssam 145612756Ssam /* 145712756Ssam * mode mask for creation of files 145812756Ssam */ 145938408Smckusick umask(scp) 146038408Smckusick register struct syscontext *scp; 146112756Ssam { 146212756Ssam register struct a { 146312756Ssam int mask; 146438408Smckusick } *uap = (struct a *)scp->sc_ap; 146512756Ssam 146638408Smckusick scp->sc_retval1 = scp->sc_cmask; 146738408Smckusick scp->sc_cmask = uap->mask & 07777; 146837741Smckusick RETURN (0); 146912756Ssam } 147037741Smckusick 147139566Smarc /* 147239566Smarc * Void all references to file by ripping underlying filesystem 147339566Smarc * away from vnode. 147439566Smarc */ 147539566Smarc revoke(scp) 147639566Smarc register struct syscontext *scp; 147739566Smarc { 147839566Smarc struct a { 147939566Smarc char *fname; 148039566Smarc } *uap = (struct a *)scp->sc_ap; 148139566Smarc register struct nameidata *ndp = &scp->sc_nd; 148239566Smarc register struct vnode *vp; 148339566Smarc struct vattr vattr; 148439566Smarc int error; 148539566Smarc 148639566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 148739566Smarc ndp->ni_segflg = UIO_USERSPACE; 148839566Smarc ndp->ni_dirp = uap->fname; 148939566Smarc if (error = namei(ndp)) 149039566Smarc RETURN (error); 149139566Smarc vp = ndp->ni_vp; 149239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 149339566Smarc error = EINVAL; 149439566Smarc goto out; 149539566Smarc } 149639566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 149739566Smarc goto out; 149839566Smarc if (scp->sc_uid != vattr.va_uid || 149939566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 150039566Smarc goto out; 150139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 150239632Smckusick vgoneall(vp); 150339566Smarc out: 150439566Smarc vrele(vp); 150539566Smarc RETURN (error); 150639566Smarc } 150739566Smarc 150838408Smckusick getvnode(ofile, fdes, fpp) 150938408Smckusick struct file *ofile[]; 151037741Smckusick struct file **fpp; 151137741Smckusick int fdes; 151237741Smckusick { 151337741Smckusick struct file *fp; 151437741Smckusick 151538408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 151637741Smckusick return (EBADF); 151737741Smckusick if (fp->f_type != DTYPE_VNODE) 151837741Smckusick return (EINVAL); 151937741Smckusick *fpp = fp; 152037741Smckusick return (0); 152137741Smckusick } 1522