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*39797Smckusick * @(#)vfs_syscalls.c 7.34 (Berkeley) 12/29/89 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "../ufs/inode.h" 2837741Smckusick #include "mount.h" 2917101Sbloom #include "proc.h" 3017101Sbloom #include "uio.h" 3137741Smckusick #include "malloc.h" 3237Sbill 33*39797Smckusick #undef RETURN 34*39797Smckusick #define RETURN(val) { scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; } 35*39797Smckusick 3637741Smckusick /* 3737741Smckusick * Virtual File System System Calls 3837741Smckusick */ 3912756Ssam 409167Ssam /* 4137741Smckusick * mount system call 429167Ssam */ 4338408Smckusick mount(scp) 4438408Smckusick register struct syscontext *scp; 456254Sroot { 4637741Smckusick register struct a { 4737741Smckusick int type; 4837741Smckusick char *dir; 4937741Smckusick int flags; 5037741Smckusick caddr_t data; 5138408Smckusick } *uap = (struct a *)scp->sc_ap; 5238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5339335Smckusick register struct vnode *vp; 5439335Smckusick register struct mount *mp; 5537741Smckusick int error; 566254Sroot 5737741Smckusick /* 5837741Smckusick * Must be super user 5937741Smckusick */ 6038408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 6137741Smckusick RETURN (error); 6237741Smckusick /* 6337741Smckusick * Get vnode to be covered 6437741Smckusick */ 6537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6737741Smckusick ndp->ni_dirp = uap->dir; 6837741Smckusick if (error = namei(ndp)) 6937741Smckusick RETURN (error); 7037741Smckusick vp = ndp->ni_vp; 7139335Smckusick if (uap->flags & M_UPDATE) { 7239335Smckusick if ((vp->v_flag & VROOT) == 0) { 7339335Smckusick vput(vp); 7439335Smckusick RETURN (EINVAL); 7539335Smckusick } 7639335Smckusick mp = vp->v_mount; 7739335Smckusick /* 7839335Smckusick * We allow going from read-only to read-write, 7939335Smckusick * but not from read-write to read-only. 8039335Smckusick */ 8139335Smckusick if ((mp->m_flag & M_RDONLY) == 0 && 8239335Smckusick (uap->flags & M_RDONLY) != 0) { 8339335Smckusick vput(vp); 8439335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8539335Smckusick } 8639335Smckusick mp->m_flag |= M_UPDATE; 8739335Smckusick VOP_UNLOCK(vp); 8839335Smckusick goto update; 8939335Smckusick } 9039665Smckusick vinvalbuf(vp, 1); 9137741Smckusick if (vp->v_count != 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 /* 12639335Smckusick * Put the new filesystem on the mount list after root. 12739335Smckusick */ 12839335Smckusick mp->m_next = rootfs->m_next; 12939335Smckusick mp->m_prev = rootfs; 13039335Smckusick rootfs->m_next = mp; 13139335Smckusick mp->m_next->m_prev = mp; 13239335Smckusick vp->v_mountedhere = mp; 13339335Smckusick mp->m_vnodecovered = vp; 13439335Smckusick update: 13539335Smckusick /* 13639335Smckusick * Set the mount level flags. 13739335Smckusick */ 13839335Smckusick if (uap->flags & M_RDONLY) 13939335Smckusick mp->m_flag |= M_RDONLY; 14039335Smckusick else 14139335Smckusick mp->m_flag &= ~M_RDONLY; 14239335Smckusick if (uap->flags & M_NOSUID) 14339335Smckusick mp->m_flag |= M_NOSUID; 14439335Smckusick else 14539335Smckusick mp->m_flag &= ~M_NOSUID; 14639335Smckusick if (uap->flags & M_NOEXEC) 14739335Smckusick mp->m_flag |= M_NOEXEC; 14839335Smckusick else 14939335Smckusick mp->m_flag &= ~M_NOEXEC; 15039335Smckusick if (uap->flags & M_NODEV) 15139335Smckusick mp->m_flag |= M_NODEV; 15239335Smckusick else 15339335Smckusick mp->m_flag &= ~M_NODEV; 15439335Smckusick if (uap->flags & M_SYNCHRONOUS) 15539335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15639335Smckusick else 15739335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15839335Smckusick /* 15939335Smckusick * Mount the filesystem. 16039335Smckusick */ 16139335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 16239335Smckusick if (mp->m_flag & M_UPDATE) { 16339335Smckusick mp->m_flag &= ~M_UPDATE; 16439335Smckusick vrele(vp); 16539335Smckusick RETURN (error); 16639335Smckusick } 16737741Smckusick cache_purge(vp); 16837741Smckusick if (!error) { 16939335Smckusick VOP_UNLOCK(vp); 17037741Smckusick vfs_unlock(mp); 17139044Smckusick error = VFS_START(mp, 0); 17237741Smckusick } else { 17337741Smckusick vfs_remove(mp); 17437741Smckusick free((caddr_t)mp, M_MOUNT); 17539335Smckusick vput(vp); 17637741Smckusick } 17737741Smckusick RETURN (error); 1786254Sroot } 1796254Sroot 1809167Ssam /* 18137741Smckusick * Unmount system call. 18237741Smckusick * 18337741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18437741Smckusick * not special file (as before). 1859167Ssam */ 18638408Smckusick unmount(scp) 18738408Smckusick register struct syscontext *scp; 1886254Sroot { 18937741Smckusick struct a { 19037741Smckusick char *pathp; 19137741Smckusick int flags; 19238408Smckusick } *uap = (struct a *)scp->sc_ap; 19337741Smckusick register struct vnode *vp; 19438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19539356Smckusick struct mount *mp; 19637741Smckusick int error; 1976254Sroot 19837741Smckusick /* 19937741Smckusick * Must be super user 20037741Smckusick */ 20138408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 20237741Smckusick RETURN (error); 20337741Smckusick 20437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20637741Smckusick ndp->ni_dirp = uap->pathp; 20737741Smckusick if (error = namei(ndp)) 20837741Smckusick RETURN (error); 20937741Smckusick vp = ndp->ni_vp; 21037741Smckusick /* 21137741Smckusick * Must be the root of the filesystem 21237741Smckusick */ 21337741Smckusick if ((vp->v_flag & VROOT) == 0) { 21437741Smckusick vput(vp); 21537741Smckusick RETURN (EINVAL); 21637741Smckusick } 21737741Smckusick mp = vp->v_mount; 21837741Smckusick vput(vp); 21939356Smckusick RETURN (dounmount(mp, uap->flags)); 22039356Smckusick } 22139356Smckusick 22239356Smckusick /* 22339356Smckusick * Do an unmount. 22439356Smckusick */ 22539356Smckusick dounmount(mp, flags) 22639356Smckusick register struct mount *mp; 22739356Smckusick int flags; 22839356Smckusick { 22939356Smckusick struct vnode *coveredvp; 23039356Smckusick int error; 23139356Smckusick 23237741Smckusick coveredvp = mp->m_vnodecovered; 23337741Smckusick if (error = vfs_lock(mp)) 23439356Smckusick return (error); 23537741Smckusick 23637741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23737741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23837741Smckusick VFS_SYNC(mp, MNT_WAIT); 23937741Smckusick 24039356Smckusick error = VFS_UNMOUNT(mp, flags); 24137741Smckusick if (error) { 24237741Smckusick vfs_unlock(mp); 24337741Smckusick } else { 24437741Smckusick vrele(coveredvp); 24537741Smckusick vfs_remove(mp); 24637741Smckusick free((caddr_t)mp, M_MOUNT); 24737741Smckusick } 24839356Smckusick return (error); 2496254Sroot } 2506254Sroot 2519167Ssam /* 25237741Smckusick * Sync system call. 25337741Smckusick * Sync each mounted filesystem. 2549167Ssam */ 25539491Smckusick /* ARGSUSED */ 25638408Smckusick sync(scp) 25739491Smckusick struct syscontext *scp; 2586254Sroot { 25937741Smckusick register struct mount *mp; 26037741Smckusick 26137741Smckusick mp = rootfs; 26237741Smckusick do { 26337741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 26437741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 26537741Smckusick mp = mp->m_next; 26637741Smckusick } while (mp != rootfs); 26737741Smckusick } 26837741Smckusick 26937741Smckusick /* 27037741Smckusick * get filesystem statistics 27137741Smckusick */ 27238408Smckusick statfs(scp) 27338408Smckusick register struct syscontext *scp; 27437741Smckusick { 2756254Sroot struct a { 27637741Smckusick char *path; 27737741Smckusick struct statfs *buf; 27838408Smckusick } *uap = (struct a *)scp->sc_ap; 27939464Smckusick register struct mount *mp; 28038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 28137741Smckusick struct statfs sb; 28237741Smckusick int error; 28337741Smckusick 28439544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 28537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28637741Smckusick ndp->ni_dirp = uap->path; 28737741Smckusick if (error = namei(ndp)) 28837741Smckusick RETURN (error); 28939544Smckusick mp = ndp->ni_vp->v_mount; 29039544Smckusick vrele(ndp->ni_vp); 29139464Smckusick if (error = VFS_STATFS(mp, &sb)) 29239544Smckusick RETURN (error); 29339464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 29439464Smckusick sb.f_fsid = mp->m_fsid; 29539544Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 29637741Smckusick } 29737741Smckusick 29838408Smckusick fstatfs(scp) 29938408Smckusick register struct syscontext *scp; 30037741Smckusick { 30137741Smckusick struct a { 30237741Smckusick int fd; 30337741Smckusick struct statfs *buf; 30438408Smckusick } *uap = (struct a *)scp->sc_ap; 30537741Smckusick struct file *fp; 30639464Smckusick struct mount *mp; 30737741Smckusick struct statfs sb; 30837741Smckusick int error; 30937741Smckusick 31038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 31137741Smckusick RETURN (error); 31239464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 31339464Smckusick if (error = VFS_STATFS(mp, &sb)) 31437741Smckusick RETURN (error); 31539464Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 31639464Smckusick sb.f_fsid = mp->m_fsid; 31737741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 31837741Smckusick } 31937741Smckusick 32037741Smckusick /* 32138270Smckusick * get statistics on all filesystems 32238270Smckusick */ 32338408Smckusick getfsstat(scp) 32438408Smckusick register struct syscontext *scp; 32538270Smckusick { 32638270Smckusick struct a { 32738270Smckusick struct statfs *buf; 32838270Smckusick long bufsize; 32938408Smckusick } *uap = (struct a *)scp->sc_ap; 33038270Smckusick register struct mount *mp; 33139606Smckusick caddr_t sfsp; 33238270Smckusick long count, maxcount, error; 33339606Smckusick struct statfs sb; 33438270Smckusick 33538270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 33639606Smckusick sfsp = (caddr_t)uap->buf; 33738270Smckusick mp = rootfs; 33838270Smckusick count = 0; 33938270Smckusick do { 34039606Smckusick if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) { 34139607Smckusick if (error = VFS_STATFS(mp, &sb)) { 34239607Smckusick mp = mp->m_prev; 34339607Smckusick continue; 34439607Smckusick } 34539606Smckusick sb.f_flags = mp->m_flag & M_VISFLAGMASK; 34639606Smckusick sb.f_fsid = mp->m_fsid; 34739606Smckusick if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb))) 34839606Smckusick RETURN (error); 34939606Smckusick sfsp += sizeof(sb); 35038270Smckusick } 35139606Smckusick count++; 35238270Smckusick mp = mp->m_prev; 35338270Smckusick } while (mp != rootfs); 35438270Smckusick if (sfsp && count > maxcount) 35538408Smckusick scp->sc_retval1 = maxcount; 35638270Smckusick else 35738408Smckusick scp->sc_retval1 = count; 35838270Smckusick RETURN (0); 35938270Smckusick } 36038270Smckusick 36138270Smckusick /* 36238259Smckusick * Change current working directory to a given file descriptor. 36338259Smckusick */ 36438408Smckusick fchdir(scp) 36538408Smckusick register struct syscontext *scp; 36638259Smckusick { 36738259Smckusick struct a { 36838259Smckusick int fd; 36938408Smckusick } *uap = (struct a *)scp->sc_ap; 37038259Smckusick register struct vnode *vp; 37138259Smckusick struct file *fp; 37238259Smckusick int error; 37338259Smckusick 37438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 37538259Smckusick RETURN (error); 37638259Smckusick vp = (struct vnode *)fp->f_data; 37738259Smckusick VOP_LOCK(vp); 37838259Smckusick if (vp->v_type != VDIR) 37938259Smckusick error = ENOTDIR; 38038259Smckusick else 38138408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 38238259Smckusick VOP_UNLOCK(vp); 38338408Smckusick vrele(scp->sc_cdir); 38438408Smckusick scp->sc_cdir = vp; 38538259Smckusick RETURN (error); 38638259Smckusick } 38738259Smckusick 38838259Smckusick /* 38937741Smckusick * Change current working directory (``.''). 39037741Smckusick */ 39138408Smckusick chdir(scp) 39238408Smckusick register struct syscontext *scp; 39337741Smckusick { 39437741Smckusick struct a { 3956254Sroot char *fname; 39638408Smckusick } *uap = (struct a *)scp->sc_ap; 39738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 39837741Smckusick int error; 3996254Sroot 40037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 40216694Smckusick ndp->ni_dirp = uap->fname; 40337741Smckusick if (error = chdirec(ndp)) 40437741Smckusick RETURN (error); 40538408Smckusick vrele(scp->sc_cdir); 40638408Smckusick scp->sc_cdir = ndp->ni_vp; 40737741Smckusick RETURN (0); 40837741Smckusick } 4096254Sroot 41037741Smckusick /* 41137741Smckusick * Change notion of root (``/'') directory. 41237741Smckusick */ 41338408Smckusick chroot(scp) 41438408Smckusick register struct syscontext *scp; 41537741Smckusick { 41637741Smckusick struct a { 41737741Smckusick char *fname; 41838408Smckusick } *uap = (struct a *)scp->sc_ap; 41938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 42037741Smckusick int error; 42137741Smckusick 42238408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 42337741Smckusick RETURN (error); 42437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 42537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 42637741Smckusick ndp->ni_dirp = uap->fname; 42737741Smckusick if (error = chdirec(ndp)) 42837741Smckusick RETURN (error); 42939515Smckusick if (scp->sc_rdir != NULL) 43039515Smckusick vrele(scp->sc_rdir); 43138408Smckusick scp->sc_rdir = ndp->ni_vp; 43237741Smckusick RETURN (0); 4336254Sroot } 4346254Sroot 43537Sbill /* 43637741Smckusick * Common routine for chroot and chdir. 43737741Smckusick */ 43837741Smckusick chdirec(ndp) 43937741Smckusick register struct nameidata *ndp; 44037741Smckusick { 44137741Smckusick struct vnode *vp; 44237741Smckusick int error; 44337741Smckusick 44437741Smckusick if (error = namei(ndp)) 44537741Smckusick return (error); 44637741Smckusick vp = ndp->ni_vp; 44737741Smckusick if (vp->v_type != VDIR) 44837741Smckusick error = ENOTDIR; 44937741Smckusick else 45038399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45137741Smckusick VOP_UNLOCK(vp); 45237741Smckusick if (error) 45337741Smckusick vrele(vp); 45437741Smckusick return (error); 45537741Smckusick } 45637741Smckusick 45737741Smckusick /* 4586254Sroot * Open system call. 4596254Sroot */ 46038408Smckusick open(scp) 46138408Smckusick register struct syscontext *scp; 4626254Sroot { 46312756Ssam struct a { 4646254Sroot char *fname; 4657701Ssam int mode; 46612756Ssam int crtmode; 46738408Smckusick } *uap = (struct a *) scp->sc_ap; 46838408Smckusick struct nameidata *ndp = &scp->sc_nd; 4696254Sroot 47037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47137741Smckusick ndp->ni_dirp = uap->fname; 47238408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 47338408Smckusick &scp->sc_retval1)); 4746254Sroot } 4756254Sroot 4766254Sroot /* 4776254Sroot * Creat system call. 4786254Sroot */ 47938408Smckusick creat(scp) 48038408Smckusick register struct syscontext *scp; 4816254Sroot { 48212756Ssam struct a { 4836254Sroot char *fname; 4846254Sroot int fmode; 48538408Smckusick } *uap = (struct a *)scp->sc_ap; 48638408Smckusick struct nameidata *ndp = &scp->sc_nd; 4876254Sroot 48837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 48937741Smckusick ndp->ni_dirp = uap->fname; 49038408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 49138408Smckusick ndp, &scp->sc_retval1)); 4926254Sroot } 4936254Sroot 4946254Sroot /* 4956254Sroot * Common code for open and creat. 49612756Ssam * Check permissions, allocate an open file structure, 49712756Ssam * and call the device open routine if any. 4986254Sroot */ 49938408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 50038408Smckusick register struct syscontext *scp; 50137741Smckusick int fmode, cmode; 50237741Smckusick struct nameidata *ndp; 50337741Smckusick int *resultfd; 50412756Ssam { 5056254Sroot register struct file *fp; 50637741Smckusick struct file *nfp; 50737741Smckusick int indx, error; 50837741Smckusick extern struct fileops vnops; 5096254Sroot 51037741Smckusick if (error = falloc(&nfp, &indx)) 51137741Smckusick return (error); 51237741Smckusick fp = nfp; 51338408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 51437741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 51537741Smckusick crfree(fp->f_cred); 51637741Smckusick fp->f_count--; 51739499Smckusick if (error == -1) /* XXX from fdopen */ 51839499Smckusick return (0); /* XXX from fdopen */ 51939499Smckusick scp->sc_ofile[indx] = NULL; 52037741Smckusick return (error); 52112756Ssam } 52237741Smckusick fp->f_flag = fmode & FMASK; 52337741Smckusick fp->f_type = DTYPE_VNODE; 52437741Smckusick fp->f_ops = &vnops; 52537741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 52637741Smckusick if (resultfd) 52737741Smckusick *resultfd = indx; 52837741Smckusick return (0); 5296254Sroot } 5306254Sroot 5316254Sroot /* 5326254Sroot * Mknod system call 5336254Sroot */ 53438408Smckusick mknod(scp) 53538408Smckusick register struct syscontext *scp; 5366254Sroot { 5376254Sroot register struct a { 5386254Sroot char *fname; 5396254Sroot int fmode; 5406254Sroot int dev; 54138408Smckusick } *uap = (struct a *)scp->sc_ap; 54238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54337741Smckusick register struct vnode *vp; 54437741Smckusick struct vattr vattr; 54537741Smckusick int error; 5466254Sroot 54738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 54837741Smckusick RETURN (error); 54937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 55116694Smckusick ndp->ni_dirp = uap->fname; 55237741Smckusick if (error = namei(ndp)) 55337741Smckusick RETURN (error); 55437741Smckusick vp = ndp->ni_vp; 55537741Smckusick if (vp != NULL) { 55637741Smckusick error = EEXIST; 55712756Ssam goto out; 5586254Sroot } 55937741Smckusick vattr_null(&vattr); 56037741Smckusick switch (uap->fmode & IFMT) { 56112756Ssam 56215093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 56337741Smckusick vattr.va_type = VBAD; 56437741Smckusick break; 56512756Ssam case IFCHR: 56637741Smckusick vattr.va_type = VCHR; 56737741Smckusick break; 56812756Ssam case IFBLK: 56937741Smckusick vattr.va_type = VBLK; 57037741Smckusick break; 57137741Smckusick default: 57237741Smckusick error = EINVAL; 57337741Smckusick goto out; 5746254Sroot } 57538408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 57637741Smckusick vattr.va_rdev = uap->dev; 5776254Sroot out: 57837741Smckusick if (error) 57937741Smckusick VOP_ABORTOP(ndp); 58037741Smckusick else 58137741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 58237741Smckusick RETURN (error); 5836254Sroot } 5846254Sroot 5856254Sroot /* 5866254Sroot * link system call 5876254Sroot */ 58838408Smckusick link(scp) 58938408Smckusick register struct syscontext *scp; 5906254Sroot { 5916254Sroot register struct a { 5926254Sroot char *target; 5936254Sroot char *linkname; 59438408Smckusick } *uap = (struct a *)scp->sc_ap; 59538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59637741Smckusick register struct vnode *vp, *xp; 59737741Smckusick int error; 5986254Sroot 59916694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 60016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 60116694Smckusick ndp->ni_dirp = uap->target; 60237741Smckusick if (error = namei(ndp)) 60337741Smckusick RETURN (error); 60437741Smckusick vp = ndp->ni_vp; 60537741Smckusick if (vp->v_type == VDIR && 60638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 60737741Smckusick goto out1; 60837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60916694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 61037741Smckusick if (error = namei(ndp)) 61137741Smckusick goto out1; 61237741Smckusick xp = ndp->ni_vp; 6136254Sroot if (xp != NULL) { 61437741Smckusick error = EEXIST; 6156254Sroot goto out; 6166254Sroot } 61737741Smckusick xp = ndp->ni_dvp; 61837741Smckusick if (vp->v_mount != xp->v_mount) 61937741Smckusick error = EXDEV; 6206254Sroot out: 62137741Smckusick if (error) 62237741Smckusick VOP_ABORTOP(ndp); 62337741Smckusick else 62437741Smckusick error = VOP_LINK(vp, ndp); 62537741Smckusick out1: 62637741Smckusick vrele(vp); 62737741Smckusick RETURN (error); 6286254Sroot } 6296254Sroot 6306254Sroot /* 6316254Sroot * symlink -- make a symbolic link 6326254Sroot */ 63338408Smckusick symlink(scp) 63438408Smckusick register struct syscontext *scp; 6356254Sroot { 63637741Smckusick struct a { 6376254Sroot char *target; 6386254Sroot char *linkname; 63938408Smckusick } *uap = (struct a *)scp->sc_ap; 64038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64137741Smckusick register struct vnode *vp; 64237741Smckusick struct vattr vattr; 64337741Smckusick char *target; 64437741Smckusick int error; 6456254Sroot 64616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64716694Smckusick ndp->ni_dirp = uap->linkname; 64837741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 64937741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 65037741Smckusick goto out1; 65137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65237741Smckusick if (error = namei(ndp)) 65337741Smckusick goto out1; 65437741Smckusick vp = ndp->ni_vp; 65537741Smckusick if (vp) { 65637741Smckusick error = EEXIST; 65737741Smckusick goto out; 6586254Sroot } 65937741Smckusick vp = ndp->ni_dvp; 66037741Smckusick vattr_null(&vattr); 66138408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 66237741Smckusick out: 66337741Smckusick if (error) 66437741Smckusick VOP_ABORTOP(ndp); 66537741Smckusick else 66637741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 66737741Smckusick out1: 66837741Smckusick FREE(target, M_NAMEI); 66937741Smckusick RETURN (error); 6706254Sroot } 6716254Sroot 6726254Sroot /* 6736254Sroot * Unlink system call. 6746254Sroot * Hard to avoid races here, especially 6756254Sroot * in unlinking directories. 6766254Sroot */ 67738408Smckusick unlink(scp) 67838408Smckusick register struct syscontext *scp; 6796254Sroot { 6806254Sroot struct a { 6816254Sroot char *fname; 68238408Smckusick } *uap = (struct a *)scp->sc_ap; 68338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68437741Smckusick register struct vnode *vp; 68537741Smckusick int error; 6866254Sroot 68737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 68816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68916694Smckusick ndp->ni_dirp = uap->fname; 69037741Smckusick if (error = namei(ndp)) 69137741Smckusick RETURN (error); 69237741Smckusick vp = ndp->ni_vp; 69337741Smckusick if (vp->v_type == VDIR && 69438408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6956254Sroot goto out; 6966254Sroot /* 6976254Sroot * Don't unlink a mounted file. 6986254Sroot */ 69937741Smckusick if (vp->v_flag & VROOT) { 70037741Smckusick error = EBUSY; 7016254Sroot goto out; 7026254Sroot } 70337741Smckusick if (vp->v_flag & VTEXT) 70437741Smckusick xrele(vp); /* try once to free text */ 7056254Sroot out: 70637741Smckusick if (error) 70737741Smckusick VOP_ABORTOP(ndp); 7087142Smckusick else 70937741Smckusick error = VOP_REMOVE(ndp); 71037741Smckusick RETURN (error); 7116254Sroot } 7126254Sroot 7136254Sroot /* 7146254Sroot * Seek system call 7156254Sroot */ 71638408Smckusick lseek(scp) 71738408Smckusick register struct syscontext *scp; 7186254Sroot { 7196254Sroot register struct file *fp; 7206254Sroot register struct a { 72137741Smckusick int fdes; 7226254Sroot off_t off; 7236254Sroot int sbase; 72438408Smckusick } *uap = (struct a *)scp->sc_ap; 72537741Smckusick struct vattr vattr; 72637741Smckusick int error; 7276254Sroot 72837741Smckusick if ((unsigned)uap->fdes >= NOFILE || 72938408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 73037741Smckusick RETURN (EBADF); 73137741Smckusick if (fp->f_type != DTYPE_VNODE) 73237741Smckusick RETURN (ESPIPE); 73313878Ssam switch (uap->sbase) { 73413878Ssam 73513878Ssam case L_INCR: 73613878Ssam fp->f_offset += uap->off; 73713878Ssam break; 73813878Ssam 73913878Ssam case L_XTND: 74037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 74138408Smckusick &vattr, scp->sc_cred)) 74237741Smckusick RETURN (error); 74337741Smckusick fp->f_offset = uap->off + vattr.va_size; 74413878Ssam break; 74513878Ssam 74613878Ssam case L_SET: 74713878Ssam fp->f_offset = uap->off; 74813878Ssam break; 74913878Ssam 75013878Ssam default: 75137741Smckusick RETURN (EINVAL); 75213878Ssam } 75338408Smckusick scp->sc_offset = fp->f_offset; 75437741Smckusick RETURN (0); 7556254Sroot } 7566254Sroot 7576254Sroot /* 7586254Sroot * Access system call 7596254Sroot */ 76038408Smckusick saccess(scp) 76138408Smckusick register struct syscontext *scp; 7626254Sroot { 7636254Sroot register struct a { 7646254Sroot char *fname; 7656254Sroot int fmode; 76638408Smckusick } *uap = (struct a *)scp->sc_ap; 76738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76837741Smckusick register struct vnode *vp; 76937741Smckusick int error, mode, svuid, svgid; 7706254Sroot 77138408Smckusick svuid = scp->sc_uid; 77238408Smckusick svgid = scp->sc_gid; 77338408Smckusick scp->sc_uid = scp->sc_ruid; 77438408Smckusick scp->sc_gid = scp->sc_rgid; 77537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 77616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77716694Smckusick ndp->ni_dirp = uap->fname; 77837741Smckusick if (error = namei(ndp)) 77937741Smckusick goto out1; 78037741Smckusick vp = ndp->ni_vp; 78137741Smckusick /* 78237741Smckusick * fmode == 0 means only check for exist 78337741Smckusick */ 78437741Smckusick if (uap->fmode) { 78537741Smckusick mode = 0; 78637741Smckusick if (uap->fmode & R_OK) 78737741Smckusick mode |= VREAD; 78837741Smckusick if (uap->fmode & W_OK) 78937741Smckusick mode |= VWRITE; 79037741Smckusick if (uap->fmode & X_OK) 79137741Smckusick mode |= VEXEC; 79239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 79338399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7946254Sroot } 79537741Smckusick vput(vp); 79637741Smckusick out1: 79738408Smckusick scp->sc_uid = svuid; 79838408Smckusick scp->sc_gid = svgid; 79937741Smckusick RETURN (error); 8006254Sroot } 8016254Sroot 8026254Sroot /* 8036574Smckusic * Stat system call. This version follows links. 80437Sbill */ 80538408Smckusick stat(scp) 80638408Smckusick struct syscontext *scp; 80737Sbill { 80837Sbill 80938408Smckusick stat1(scp, FOLLOW); 81037Sbill } 81137Sbill 81237Sbill /* 8136574Smckusic * Lstat system call. This version does not follow links. 8145992Swnj */ 81538408Smckusick lstat(scp) 81638408Smckusick struct syscontext *scp; 8175992Swnj { 81812756Ssam 81938408Smckusick stat1(scp, NOFOLLOW); 82012756Ssam } 82112756Ssam 82238408Smckusick stat1(scp, follow) 82338408Smckusick register struct syscontext *scp; 82412756Ssam int follow; 82512756Ssam { 8265992Swnj register struct a { 8275992Swnj char *fname; 82812756Ssam struct stat *ub; 82938408Smckusick } *uap = (struct a *)scp->sc_ap; 83038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 83112756Ssam struct stat sb; 83237741Smckusick int error; 8335992Swnj 83437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 83516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83616694Smckusick ndp->ni_dirp = uap->fname; 83737741Smckusick if (error = namei(ndp)) 83837741Smckusick RETURN (error); 83937741Smckusick error = vn_stat(ndp->ni_vp, &sb); 84037741Smckusick vput(ndp->ni_vp); 84137741Smckusick if (error) 84237741Smckusick RETURN (error); 84337741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 84437741Smckusick RETURN (error); 8455992Swnj } 8465992Swnj 8475992Swnj /* 8485992Swnj * Return target name of a symbolic link 84937Sbill */ 85038408Smckusick readlink(scp) 85138408Smckusick register struct syscontext *scp; 8525992Swnj { 8535992Swnj register struct a { 8545992Swnj char *name; 8555992Swnj char *buf; 8565992Swnj int count; 85738408Smckusick } *uap = (struct a *)scp->sc_ap; 85838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85937741Smckusick register struct vnode *vp; 86037741Smckusick struct iovec aiov; 86137741Smckusick struct uio auio; 86237741Smckusick int error; 8635992Swnj 86437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 86516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86616694Smckusick ndp->ni_dirp = uap->name; 86737741Smckusick if (error = namei(ndp)) 86837741Smckusick RETURN (error); 86937741Smckusick vp = ndp->ni_vp; 87037741Smckusick if (vp->v_type != VLNK) { 87137741Smckusick error = EINVAL; 8725992Swnj goto out; 8735992Swnj } 87437741Smckusick aiov.iov_base = uap->buf; 87537741Smckusick aiov.iov_len = uap->count; 87637741Smckusick auio.uio_iov = &aiov; 87737741Smckusick auio.uio_iovcnt = 1; 87837741Smckusick auio.uio_offset = 0; 87937741Smckusick auio.uio_rw = UIO_READ; 88037741Smckusick auio.uio_segflg = UIO_USERSPACE; 88137741Smckusick auio.uio_resid = uap->count; 88237741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8835992Swnj out: 88437741Smckusick vput(vp); 88538408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 88637741Smckusick RETURN (error); 8875992Swnj } 8885992Swnj 8899167Ssam /* 89038259Smckusick * Change flags of a file given path name. 89138259Smckusick */ 89238408Smckusick chflags(scp) 89338408Smckusick register struct syscontext *scp; 89438259Smckusick { 89538259Smckusick struct a { 89638259Smckusick char *fname; 89738259Smckusick int flags; 89838408Smckusick } *uap = (struct a *)scp->sc_ap; 89938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90038259Smckusick register struct vnode *vp; 90138259Smckusick struct vattr vattr; 90238259Smckusick int error; 90338259Smckusick 90438259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 90538259Smckusick ndp->ni_segflg = UIO_USERSPACE; 90638259Smckusick ndp->ni_dirp = uap->fname; 90738259Smckusick vattr_null(&vattr); 90838259Smckusick vattr.va_flags = uap->flags; 90938259Smckusick if (error = namei(ndp)) 91038259Smckusick RETURN (error); 91138259Smckusick vp = ndp->ni_vp; 91238259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91338259Smckusick error = EROFS; 91438259Smckusick goto out; 91538259Smckusick } 91638259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 91738259Smckusick out: 91838259Smckusick vput(vp); 91938259Smckusick RETURN (error); 92038259Smckusick } 92138259Smckusick 92238259Smckusick /* 92338259Smckusick * Change flags of a file given a file descriptor. 92438259Smckusick */ 92538408Smckusick fchflags(scp) 92638408Smckusick register struct syscontext *scp; 92738259Smckusick { 92838259Smckusick struct a { 92938259Smckusick int fd; 93038259Smckusick int flags; 93138408Smckusick } *uap = (struct a *)scp->sc_ap; 93238259Smckusick struct vattr vattr; 93338259Smckusick struct vnode *vp; 93438259Smckusick struct file *fp; 93538259Smckusick int error; 93638259Smckusick 93738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 93838259Smckusick RETURN (error); 93938259Smckusick vattr_null(&vattr); 94038259Smckusick vattr.va_flags = uap->flags; 94138259Smckusick vp = (struct vnode *)fp->f_data; 94238259Smckusick VOP_LOCK(vp); 94338259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94438259Smckusick error = EROFS; 94538259Smckusick goto out; 94638259Smckusick } 94738259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 94838259Smckusick out: 94938259Smckusick VOP_UNLOCK(vp); 95038259Smckusick RETURN (error); 95138259Smckusick } 95238259Smckusick 95338259Smckusick /* 9549167Ssam * Change mode of a file given path name. 9559167Ssam */ 95638408Smckusick chmod(scp) 95738408Smckusick register struct syscontext *scp; 9585992Swnj { 9597701Ssam struct a { 9606254Sroot char *fname; 9616254Sroot int fmode; 96238408Smckusick } *uap = (struct a *)scp->sc_ap; 96338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 96437741Smckusick register struct vnode *vp; 96537741Smckusick struct vattr vattr; 96637741Smckusick int error; 9675992Swnj 96837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 96937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 97037741Smckusick ndp->ni_dirp = uap->fname; 97137741Smckusick vattr_null(&vattr); 97237741Smckusick vattr.va_mode = uap->fmode & 07777; 97337741Smckusick if (error = namei(ndp)) 97437741Smckusick RETURN (error); 97537741Smckusick vp = ndp->ni_vp; 97637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97737741Smckusick error = EROFS; 97837741Smckusick goto out; 97937741Smckusick } 98037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 98137741Smckusick out: 98237741Smckusick vput(vp); 98337741Smckusick RETURN (error); 9847701Ssam } 9857439Sroot 9869167Ssam /* 9879167Ssam * Change mode of a file given a file descriptor. 9889167Ssam */ 98938408Smckusick fchmod(scp) 99038408Smckusick register struct syscontext *scp; 9917701Ssam { 9927701Ssam struct a { 9937701Ssam int fd; 9947701Ssam int fmode; 99538408Smckusick } *uap = (struct a *)scp->sc_ap; 99637741Smckusick struct vattr vattr; 99737741Smckusick struct vnode *vp; 99837741Smckusick struct file *fp; 99937741Smckusick int error; 10007701Ssam 100138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 100237741Smckusick RETURN (error); 100337741Smckusick vattr_null(&vattr); 100437741Smckusick vattr.va_mode = uap->fmode & 07777; 100537741Smckusick vp = (struct vnode *)fp->f_data; 100637741Smckusick VOP_LOCK(vp); 100737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 100837741Smckusick error = EROFS; 100937741Smckusick goto out; 10107439Sroot } 101137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 101237741Smckusick out: 101337741Smckusick VOP_UNLOCK(vp); 101437741Smckusick RETURN (error); 10155992Swnj } 10165992Swnj 10179167Ssam /* 10189167Ssam * Set ownership given a path name. 10199167Ssam */ 102038408Smckusick chown(scp) 102138408Smckusick register struct syscontext *scp; 102237Sbill { 10237701Ssam struct a { 10246254Sroot char *fname; 10256254Sroot int uid; 10266254Sroot int gid; 102738408Smckusick } *uap = (struct a *)scp->sc_ap; 102838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 102937741Smckusick register struct vnode *vp; 103037741Smckusick struct vattr vattr; 103137741Smckusick int error; 103237Sbill 103337741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 103436614Sbostic ndp->ni_segflg = UIO_USERSPACE; 103536614Sbostic ndp->ni_dirp = uap->fname; 103637741Smckusick vattr_null(&vattr); 103737741Smckusick vattr.va_uid = uap->uid; 103837741Smckusick vattr.va_gid = uap->gid; 103937741Smckusick if (error = namei(ndp)) 104037741Smckusick RETURN (error); 104137741Smckusick vp = ndp->ni_vp; 104237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 104337741Smckusick error = EROFS; 104437741Smckusick goto out; 104537741Smckusick } 104637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 104737741Smckusick out: 104837741Smckusick vput(vp); 104937741Smckusick RETURN (error); 10507701Ssam } 10517439Sroot 10529167Ssam /* 10539167Ssam * Set ownership given a file descriptor. 10549167Ssam */ 105538408Smckusick fchown(scp) 105638408Smckusick register struct syscontext *scp; 10577701Ssam { 10587701Ssam struct a { 10597701Ssam int fd; 10607701Ssam int uid; 10617701Ssam int gid; 106238408Smckusick } *uap = (struct a *)scp->sc_ap; 106337741Smckusick struct vattr vattr; 106437741Smckusick struct vnode *vp; 106537741Smckusick struct file *fp; 106637741Smckusick int error; 10677701Ssam 106838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 106937741Smckusick RETURN (error); 107037741Smckusick vattr_null(&vattr); 107137741Smckusick vattr.va_uid = uap->uid; 107237741Smckusick vattr.va_gid = uap->gid; 107337741Smckusick vp = (struct vnode *)fp->f_data; 107437741Smckusick VOP_LOCK(vp); 107537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 107637741Smckusick error = EROFS; 107737741Smckusick goto out; 107837741Smckusick } 107937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108037741Smckusick out: 108137741Smckusick VOP_UNLOCK(vp); 108237741Smckusick RETURN (error); 10837701Ssam } 10847701Ssam 108538408Smckusick utimes(scp) 108638408Smckusick register struct syscontext *scp; 108711811Ssam { 108811811Ssam register struct a { 108911811Ssam char *fname; 109011811Ssam struct timeval *tptr; 109138408Smckusick } *uap = (struct a *)scp->sc_ap; 109238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 109337741Smckusick register struct vnode *vp; 109411811Ssam struct timeval tv[2]; 109537741Smckusick struct vattr vattr; 109637741Smckusick int error; 109711811Ssam 109837741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 109937741Smckusick RETURN (error); 110037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 110137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 110237741Smckusick ndp->ni_dirp = uap->fname; 110337741Smckusick vattr_null(&vattr); 110437741Smckusick vattr.va_atime = tv[0]; 110537741Smckusick vattr.va_mtime = tv[1]; 110637741Smckusick if (error = namei(ndp)) 110737741Smckusick RETURN (error); 110837741Smckusick vp = ndp->ni_vp; 110937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 111037741Smckusick error = EROFS; 111137741Smckusick goto out; 111221015Smckusick } 111337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 111437741Smckusick out: 111537741Smckusick vput(vp); 111637741Smckusick RETURN (error); 111711811Ssam } 111811811Ssam 11199167Ssam /* 11209167Ssam * Truncate a file given its path name. 11219167Ssam */ 112238408Smckusick truncate(scp) 112338408Smckusick register struct syscontext *scp; 11247701Ssam { 11257701Ssam struct a { 11267701Ssam char *fname; 112726473Skarels off_t length; 112838408Smckusick } *uap = (struct a *)scp->sc_ap; 112938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 113037741Smckusick register struct vnode *vp; 113137741Smckusick struct vattr vattr; 113237741Smckusick int error; 11337701Ssam 113437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113616694Smckusick ndp->ni_dirp = uap->fname; 113737741Smckusick vattr_null(&vattr); 113837741Smckusick vattr.va_size = uap->length; 113937741Smckusick if (error = namei(ndp)) 114037741Smckusick RETURN (error); 114137741Smckusick vp = ndp->ni_vp; 114237741Smckusick if (vp->v_type == VDIR) { 114337741Smckusick error = EISDIR; 114437741Smckusick goto out; 11457701Ssam } 114638399Smckusick if ((error = vn_writechk(vp)) || 114738399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 114837741Smckusick goto out; 114937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115037741Smckusick out: 115137741Smckusick vput(vp); 115237741Smckusick RETURN (error); 11537701Ssam } 11547701Ssam 11559167Ssam /* 11569167Ssam * Truncate a file given a file descriptor. 11579167Ssam */ 115838408Smckusick ftruncate(scp) 115938408Smckusick register struct syscontext *scp; 11607701Ssam { 11617701Ssam struct a { 11627701Ssam int fd; 116326473Skarels off_t length; 116438408Smckusick } *uap = (struct a *)scp->sc_ap; 116537741Smckusick struct vattr vattr; 116637741Smckusick struct vnode *vp; 11677701Ssam struct file *fp; 116837741Smckusick int error; 11697701Ssam 117038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 117137741Smckusick RETURN (error); 117237741Smckusick if ((fp->f_flag & FWRITE) == 0) 117337741Smckusick RETURN (EINVAL); 117437741Smckusick vattr_null(&vattr); 117537741Smckusick vattr.va_size = uap->length; 117637741Smckusick vp = (struct vnode *)fp->f_data; 117737741Smckusick VOP_LOCK(vp); 117837741Smckusick if (vp->v_type == VDIR) { 117937741Smckusick error = EISDIR; 118037741Smckusick goto out; 11817701Ssam } 118238399Smckusick if (error = vn_writechk(vp)) 118337741Smckusick goto out; 118437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118537741Smckusick out: 118637741Smckusick VOP_UNLOCK(vp); 118737741Smckusick RETURN (error); 11887701Ssam } 11897701Ssam 11909167Ssam /* 11919167Ssam * Synch an open file. 11929167Ssam */ 119338408Smckusick fsync(scp) 119438408Smckusick register struct syscontext *scp; 11959167Ssam { 11969167Ssam struct a { 11979167Ssam int fd; 119838408Smckusick } *uap = (struct a *)scp->sc_ap; 119939592Smckusick register struct vnode *vp; 12009167Ssam struct file *fp; 120137741Smckusick int error; 12029167Ssam 120338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 120437741Smckusick RETURN (error); 120539592Smckusick vp = (struct vnode *)fp->f_data; 120639592Smckusick VOP_LOCK(vp); 120739592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 120839592Smckusick VOP_UNLOCK(vp); 120937741Smckusick RETURN (error); 12109167Ssam } 12119167Ssam 12129167Ssam /* 12139167Ssam * Rename system call. 12149167Ssam * 12159167Ssam * Source and destination must either both be directories, or both 12169167Ssam * not be directories. If target is a directory, it must be empty. 12179167Ssam */ 121838408Smckusick rename(scp) 121938408Smckusick register struct syscontext *scp; 12207701Ssam { 12217701Ssam struct a { 12227701Ssam char *from; 12237701Ssam char *to; 122438408Smckusick } *uap = (struct a *)scp->sc_ap; 122537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 122638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 122737741Smckusick struct nameidata tond; 122837741Smckusick int error; 12297701Ssam 123037741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 123116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 123216694Smckusick ndp->ni_dirp = uap->from; 123337741Smckusick if (error = namei(ndp)) 123437741Smckusick RETURN (error); 123537741Smckusick fvp = ndp->ni_vp; 123638266Smckusick nddup(ndp, &tond); 123737741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 123837741Smckusick tond.ni_segflg = UIO_USERSPACE; 123937741Smckusick tond.ni_dirp = uap->to; 124037741Smckusick error = namei(&tond); 124137741Smckusick tdvp = tond.ni_dvp; 124237741Smckusick tvp = tond.ni_vp; 124337741Smckusick if (tvp != NULL) { 124437741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 124539242Sbostic error = ENOTDIR; 124637741Smckusick goto out; 124737741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 124839242Sbostic error = EISDIR; 124937741Smckusick goto out; 12509167Ssam } 12519167Ssam } 125237741Smckusick if (error) { 125337741Smckusick VOP_ABORTOP(ndp); 125437741Smckusick goto out1; 125537741Smckusick } 125637741Smckusick if (fvp->v_mount != tdvp->v_mount) { 125737741Smckusick error = EXDEV; 12589167Ssam goto out; 125910051Ssam } 126039286Smckusick if (fvp == tdvp) 126137741Smckusick error = EINVAL; 126239286Smckusick /* 126339286Smckusick * If source is the same as the destination, 126439286Smckusick * then there is nothing to do. 126539286Smckusick */ 126639286Smckusick if (fvp == tvp) 126739286Smckusick error = -1; 126837741Smckusick out: 126937741Smckusick if (error) { 127037741Smckusick VOP_ABORTOP(&tond); 127137741Smckusick VOP_ABORTOP(ndp); 12729167Ssam } else { 127337741Smckusick error = VOP_RENAME(ndp, &tond); 12749167Ssam } 127537741Smckusick out1: 127638266Smckusick ndrele(&tond); 127739286Smckusick if (error == -1) 127839286Smckusick RETURN (0); 127937741Smckusick RETURN (error); 12807701Ssam } 12817701Ssam 12827535Sroot /* 128312756Ssam * Mkdir system call 128412756Ssam */ 128538408Smckusick mkdir(scp) 128638408Smckusick register struct syscontext *scp; 128712756Ssam { 128812756Ssam struct a { 128912756Ssam char *name; 129012756Ssam int dmode; 129138408Smckusick } *uap = (struct a *)scp->sc_ap; 129238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 129337741Smckusick register struct vnode *vp; 129437741Smckusick struct vattr vattr; 129537741Smckusick int error; 129612756Ssam 129737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 129816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 129916694Smckusick ndp->ni_dirp = uap->name; 130037741Smckusick if (error = namei(ndp)) 130137741Smckusick RETURN (error); 130237741Smckusick vp = ndp->ni_vp; 130337741Smckusick if (vp != NULL) { 130437741Smckusick VOP_ABORTOP(ndp); 130537741Smckusick RETURN (EEXIST); 130612756Ssam } 130737741Smckusick vattr_null(&vattr); 130837741Smckusick vattr.va_type = VDIR; 130938408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 131037741Smckusick error = VOP_MKDIR(ndp, &vattr); 131138145Smckusick if (!error) 131238145Smckusick vput(ndp->ni_vp); 131337741Smckusick RETURN (error); 131412756Ssam } 131512756Ssam 131612756Ssam /* 131712756Ssam * Rmdir system call. 131812756Ssam */ 131938408Smckusick rmdir(scp) 132038408Smckusick register struct syscontext *scp; 132112756Ssam { 132212756Ssam struct a { 132312756Ssam char *name; 132438408Smckusick } *uap = (struct a *)scp->sc_ap; 132538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 132637741Smckusick register struct vnode *vp; 132737741Smckusick int error; 132812756Ssam 132937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 133016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 133116694Smckusick ndp->ni_dirp = uap->name; 133237741Smckusick if (error = namei(ndp)) 133337741Smckusick RETURN (error); 133437741Smckusick vp = ndp->ni_vp; 133537741Smckusick if (vp->v_type != VDIR) { 133637741Smckusick error = ENOTDIR; 133712756Ssam goto out; 133812756Ssam } 133912756Ssam /* 134037741Smckusick * No rmdir "." please. 134112756Ssam */ 134237741Smckusick if (ndp->ni_dvp == vp) { 134337741Smckusick error = EINVAL; 134412756Ssam goto out; 134512756Ssam } 134612756Ssam /* 134737741Smckusick * Don't unlink a mounted file. 134812756Ssam */ 134937741Smckusick if (vp->v_flag & VROOT) 135037741Smckusick error = EBUSY; 135112756Ssam out: 135237741Smckusick if (error) 135337741Smckusick VOP_ABORTOP(ndp); 135437741Smckusick else 135537741Smckusick error = VOP_RMDIR(ndp); 135637741Smckusick RETURN (error); 135712756Ssam } 135812756Ssam 135937741Smckusick /* 136037741Smckusick * Read a block of directory entries in a file system independent format 136137741Smckusick */ 136238408Smckusick getdirentries(scp) 136338408Smckusick register struct syscontext *scp; 136412756Ssam { 136537741Smckusick register struct a { 136637741Smckusick int fd; 136737741Smckusick char *buf; 136837741Smckusick unsigned count; 136937741Smckusick long *basep; 137038408Smckusick } *uap = (struct a *)scp->sc_ap; 137139592Smckusick register struct vnode *vp; 137216540Ssam struct file *fp; 137337741Smckusick struct uio auio; 137437741Smckusick struct iovec aiov; 137538129Smckusick off_t off; 137637741Smckusick int error; 137712756Ssam 137838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 137937741Smckusick RETURN (error); 138037741Smckusick if ((fp->f_flag & FREAD) == 0) 138137741Smckusick RETURN (EBADF); 138239592Smckusick vp = (struct vnode *)fp->f_data; 138339592Smckusick if (vp->v_type != VDIR) 138439592Smckusick RETURN (EINVAL); 138537741Smckusick aiov.iov_base = uap->buf; 138637741Smckusick aiov.iov_len = uap->count; 138737741Smckusick auio.uio_iov = &aiov; 138837741Smckusick auio.uio_iovcnt = 1; 138937741Smckusick auio.uio_rw = UIO_READ; 139037741Smckusick auio.uio_segflg = UIO_USERSPACE; 139137741Smckusick auio.uio_resid = uap->count; 139239592Smckusick VOP_LOCK(vp); 139339592Smckusick auio.uio_offset = off = fp->f_offset; 139439592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 139539592Smckusick fp->f_offset = auio.uio_offset; 139639592Smckusick VOP_UNLOCK(vp); 139739592Smckusick if (error) 139837741Smckusick RETURN (error); 139939592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 140038408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 140137741Smckusick RETURN (error); 140212756Ssam } 140312756Ssam 140412756Ssam /* 140512756Ssam * mode mask for creation of files 140612756Ssam */ 140738408Smckusick umask(scp) 140838408Smckusick register struct syscontext *scp; 140912756Ssam { 141012756Ssam register struct a { 141112756Ssam int mask; 141238408Smckusick } *uap = (struct a *)scp->sc_ap; 141312756Ssam 141438408Smckusick scp->sc_retval1 = scp->sc_cmask; 141538408Smckusick scp->sc_cmask = uap->mask & 07777; 141637741Smckusick RETURN (0); 141712756Ssam } 141837741Smckusick 141939566Smarc /* 142039566Smarc * Void all references to file by ripping underlying filesystem 142139566Smarc * away from vnode. 142239566Smarc */ 142339566Smarc revoke(scp) 142439566Smarc register struct syscontext *scp; 142539566Smarc { 142639566Smarc struct a { 142739566Smarc char *fname; 142839566Smarc } *uap = (struct a *)scp->sc_ap; 142939566Smarc register struct nameidata *ndp = &scp->sc_nd; 143039566Smarc register struct vnode *vp; 143139566Smarc struct vattr vattr; 143239566Smarc int error; 143339566Smarc 143439566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 143539566Smarc ndp->ni_segflg = UIO_USERSPACE; 143639566Smarc ndp->ni_dirp = uap->fname; 143739566Smarc if (error = namei(ndp)) 143839566Smarc RETURN (error); 143939566Smarc vp = ndp->ni_vp; 144039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 144139566Smarc error = EINVAL; 144239566Smarc goto out; 144339566Smarc } 144439566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 144539566Smarc goto out; 144639566Smarc if (scp->sc_uid != vattr.va_uid || 144739566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 144839566Smarc goto out; 144939632Smckusick if (vp->v_count > 1 || (vp->v_flag & VALIASED)) 145039632Smckusick vgoneall(vp); 145139566Smarc out: 145239566Smarc vrele(vp); 145339566Smarc RETURN (error); 145439566Smarc } 145539566Smarc 145638408Smckusick getvnode(ofile, fdes, fpp) 145738408Smckusick struct file *ofile[]; 145837741Smckusick struct file **fpp; 145937741Smckusick int fdes; 146037741Smckusick { 146137741Smckusick struct file *fp; 146237741Smckusick 146338408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 146437741Smckusick return (EBADF); 146537741Smckusick if (fp->f_type != DTYPE_VNODE) 146637741Smckusick return (EINVAL); 146737741Smckusick *fpp = fp; 146837741Smckusick return (0); 146937741Smckusick } 1470