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*39860Smckusick * @(#)vfs_syscalls.c 7.36 (Berkeley) 01/03/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "../ufs/inode.h" 2837741Smckusick #include "mount.h" 2917101Sbloom #include "proc.h" 3017101Sbloom #include "uio.h" 3137741Smckusick #include "malloc.h" 3237Sbill 3339797Smckusick #undef RETURN 3439797Smckusick #define RETURN(val) { scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; } 3539797Smckusick 3637741Smckusick /* 3737741Smckusick * Virtual File System System Calls 3837741Smckusick */ 3912756Ssam 409167Ssam /* 4137741Smckusick * mount system call 429167Ssam */ 4338408Smckusick mount(scp) 4438408Smckusick register struct syscontext *scp; 456254Sroot { 4637741Smckusick register struct a { 4737741Smckusick int type; 4837741Smckusick char *dir; 4937741Smckusick int flags; 5037741Smckusick caddr_t data; 5138408Smckusick } *uap = (struct a *)scp->sc_ap; 5238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5339335Smckusick register struct vnode *vp; 5439335Smckusick register struct mount *mp; 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); 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 /* 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); 383*39860Smckusick if (error) 384*39860Smckusick RETURN (error); 385*39860Smckusick VREF(vp); 38638408Smckusick vrele(scp->sc_cdir); 38738408Smckusick scp->sc_cdir = vp; 388*39860Smckusick RETURN (0); 38938259Smckusick } 39038259Smckusick 39138259Smckusick /* 39237741Smckusick * Change current working directory (``.''). 39337741Smckusick */ 39438408Smckusick chdir(scp) 39538408Smckusick register struct syscontext *scp; 39637741Smckusick { 39737741Smckusick struct a { 3986254Sroot char *fname; 39938408Smckusick } *uap = (struct a *)scp->sc_ap; 40038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 40137741Smckusick int error; 4026254Sroot 40337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 40516694Smckusick ndp->ni_dirp = uap->fname; 40637741Smckusick if (error = chdirec(ndp)) 40737741Smckusick RETURN (error); 40838408Smckusick vrele(scp->sc_cdir); 40938408Smckusick scp->sc_cdir = ndp->ni_vp; 41037741Smckusick RETURN (0); 41137741Smckusick } 4126254Sroot 41337741Smckusick /* 41437741Smckusick * Change notion of root (``/'') directory. 41537741Smckusick */ 41638408Smckusick chroot(scp) 41738408Smckusick register struct syscontext *scp; 41837741Smckusick { 41937741Smckusick struct a { 42037741Smckusick char *fname; 42138408Smckusick } *uap = (struct a *)scp->sc_ap; 42238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 42337741Smckusick int error; 42437741Smckusick 42538408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 42637741Smckusick RETURN (error); 42737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 42837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 42937741Smckusick ndp->ni_dirp = uap->fname; 43037741Smckusick if (error = chdirec(ndp)) 43137741Smckusick RETURN (error); 43239515Smckusick if (scp->sc_rdir != NULL) 43339515Smckusick vrele(scp->sc_rdir); 43438408Smckusick scp->sc_rdir = ndp->ni_vp; 43537741Smckusick RETURN (0); 4366254Sroot } 4376254Sroot 43837Sbill /* 43937741Smckusick * Common routine for chroot and chdir. 44037741Smckusick */ 44137741Smckusick chdirec(ndp) 44237741Smckusick register struct nameidata *ndp; 44337741Smckusick { 44437741Smckusick struct vnode *vp; 44537741Smckusick int error; 44637741Smckusick 44737741Smckusick if (error = namei(ndp)) 44837741Smckusick return (error); 44937741Smckusick vp = ndp->ni_vp; 45037741Smckusick if (vp->v_type != VDIR) 45137741Smckusick error = ENOTDIR; 45237741Smckusick else 45338399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45437741Smckusick VOP_UNLOCK(vp); 45537741Smckusick if (error) 45637741Smckusick vrele(vp); 45737741Smckusick return (error); 45837741Smckusick } 45937741Smckusick 46037741Smckusick /* 4616254Sroot * Open system call. 4626254Sroot */ 46338408Smckusick open(scp) 46438408Smckusick register struct syscontext *scp; 4656254Sroot { 46612756Ssam struct a { 4676254Sroot char *fname; 4687701Ssam int mode; 46912756Ssam int crtmode; 47038408Smckusick } *uap = (struct a *) scp->sc_ap; 47138408Smckusick struct nameidata *ndp = &scp->sc_nd; 4726254Sroot 47337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47437741Smckusick ndp->ni_dirp = uap->fname; 47538408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 47638408Smckusick &scp->sc_retval1)); 4776254Sroot } 4786254Sroot 4796254Sroot /* 4806254Sroot * Creat system call. 4816254Sroot */ 48238408Smckusick creat(scp) 48338408Smckusick register struct syscontext *scp; 4846254Sroot { 48512756Ssam struct a { 4866254Sroot char *fname; 4876254Sroot int fmode; 48838408Smckusick } *uap = (struct a *)scp->sc_ap; 48938408Smckusick struct nameidata *ndp = &scp->sc_nd; 4906254Sroot 49137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49237741Smckusick ndp->ni_dirp = uap->fname; 49338408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 49438408Smckusick ndp, &scp->sc_retval1)); 4956254Sroot } 4966254Sroot 4976254Sroot /* 4986254Sroot * Common code for open and creat. 49912756Ssam * Check permissions, allocate an open file structure, 50012756Ssam * and call the device open routine if any. 5016254Sroot */ 50238408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 50338408Smckusick register struct syscontext *scp; 50437741Smckusick int fmode, cmode; 50537741Smckusick struct nameidata *ndp; 50637741Smckusick int *resultfd; 50712756Ssam { 5086254Sroot register struct file *fp; 50937741Smckusick struct file *nfp; 51037741Smckusick int indx, error; 51137741Smckusick extern struct fileops vnops; 5126254Sroot 51337741Smckusick if (error = falloc(&nfp, &indx)) 51437741Smckusick return (error); 51537741Smckusick fp = nfp; 51638408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 51737741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 51837741Smckusick crfree(fp->f_cred); 51937741Smckusick fp->f_count--; 52039499Smckusick if (error == -1) /* XXX from fdopen */ 52139499Smckusick return (0); /* XXX from fdopen */ 52239499Smckusick scp->sc_ofile[indx] = NULL; 52337741Smckusick return (error); 52412756Ssam } 52537741Smckusick fp->f_flag = fmode & FMASK; 52637741Smckusick fp->f_type = DTYPE_VNODE; 52737741Smckusick fp->f_ops = &vnops; 52837741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 52937741Smckusick if (resultfd) 53037741Smckusick *resultfd = indx; 53137741Smckusick return (0); 5326254Sroot } 5336254Sroot 5346254Sroot /* 5356254Sroot * Mknod system call 5366254Sroot */ 53738408Smckusick mknod(scp) 53838408Smckusick register struct syscontext *scp; 5396254Sroot { 5406254Sroot register struct a { 5416254Sroot char *fname; 5426254Sroot int fmode; 5436254Sroot int dev; 54438408Smckusick } *uap = (struct a *)scp->sc_ap; 54538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54637741Smckusick register struct vnode *vp; 54737741Smckusick struct vattr vattr; 54837741Smckusick int error; 5496254Sroot 55038408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 55137741Smckusick RETURN (error); 55237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 55416694Smckusick ndp->ni_dirp = uap->fname; 55537741Smckusick if (error = namei(ndp)) 55637741Smckusick RETURN (error); 55737741Smckusick vp = ndp->ni_vp; 55837741Smckusick if (vp != NULL) { 55937741Smckusick error = EEXIST; 56012756Ssam goto out; 5616254Sroot } 56237741Smckusick vattr_null(&vattr); 56337741Smckusick switch (uap->fmode & IFMT) { 56412756Ssam 56515093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 56637741Smckusick vattr.va_type = VBAD; 56737741Smckusick break; 56812756Ssam case IFCHR: 56937741Smckusick vattr.va_type = VCHR; 57037741Smckusick break; 57112756Ssam case IFBLK: 57237741Smckusick vattr.va_type = VBLK; 57337741Smckusick break; 57437741Smckusick default: 57537741Smckusick error = EINVAL; 57637741Smckusick goto out; 5776254Sroot } 57838408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 57937741Smckusick vattr.va_rdev = uap->dev; 5806254Sroot out: 58137741Smckusick if (error) 58237741Smckusick VOP_ABORTOP(ndp); 58337741Smckusick else 58437741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 58537741Smckusick RETURN (error); 5866254Sroot } 5876254Sroot 5886254Sroot /* 5896254Sroot * link system call 5906254Sroot */ 59138408Smckusick link(scp) 59238408Smckusick register struct syscontext *scp; 5936254Sroot { 5946254Sroot register struct a { 5956254Sroot char *target; 5966254Sroot char *linkname; 59738408Smckusick } *uap = (struct a *)scp->sc_ap; 59838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59937741Smckusick register struct vnode *vp, *xp; 60037741Smckusick int error; 6016254Sroot 60216694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 60316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 60416694Smckusick ndp->ni_dirp = uap->target; 60537741Smckusick if (error = namei(ndp)) 60637741Smckusick RETURN (error); 60737741Smckusick vp = ndp->ni_vp; 60837741Smckusick if (vp->v_type == VDIR && 60938408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 61037741Smckusick goto out1; 61137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61216694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 61337741Smckusick if (error = namei(ndp)) 61437741Smckusick goto out1; 61537741Smckusick xp = ndp->ni_vp; 6166254Sroot if (xp != NULL) { 61737741Smckusick error = EEXIST; 6186254Sroot goto out; 6196254Sroot } 62037741Smckusick xp = ndp->ni_dvp; 62137741Smckusick if (vp->v_mount != xp->v_mount) 62237741Smckusick error = EXDEV; 6236254Sroot out: 62437741Smckusick if (error) 62537741Smckusick VOP_ABORTOP(ndp); 62637741Smckusick else 62737741Smckusick error = VOP_LINK(vp, ndp); 62837741Smckusick out1: 62937741Smckusick vrele(vp); 63037741Smckusick RETURN (error); 6316254Sroot } 6326254Sroot 6336254Sroot /* 6346254Sroot * symlink -- make a symbolic link 6356254Sroot */ 63638408Smckusick symlink(scp) 63738408Smckusick register struct syscontext *scp; 6386254Sroot { 63937741Smckusick struct a { 6406254Sroot char *target; 6416254Sroot char *linkname; 64238408Smckusick } *uap = (struct a *)scp->sc_ap; 64338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 64437741Smckusick register struct vnode *vp; 64537741Smckusick struct vattr vattr; 64637741Smckusick char *target; 64737741Smckusick int error; 6486254Sroot 64916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 65016694Smckusick ndp->ni_dirp = uap->linkname; 65137741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 65237741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 65337741Smckusick goto out1; 65437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65537741Smckusick if (error = namei(ndp)) 65637741Smckusick goto out1; 65737741Smckusick vp = ndp->ni_vp; 65837741Smckusick if (vp) { 65937741Smckusick error = EEXIST; 66037741Smckusick goto out; 6616254Sroot } 66237741Smckusick vp = ndp->ni_dvp; 66337741Smckusick vattr_null(&vattr); 66438408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 66537741Smckusick out: 66637741Smckusick if (error) 66737741Smckusick VOP_ABORTOP(ndp); 66837741Smckusick else 66937741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 67037741Smckusick out1: 67137741Smckusick FREE(target, M_NAMEI); 67237741Smckusick RETURN (error); 6736254Sroot } 6746254Sroot 6756254Sroot /* 6766254Sroot * Unlink system call. 6776254Sroot * Hard to avoid races here, especially 6786254Sroot * in unlinking directories. 6796254Sroot */ 68038408Smckusick unlink(scp) 68138408Smckusick register struct syscontext *scp; 6826254Sroot { 6836254Sroot struct a { 6846254Sroot char *fname; 68538408Smckusick } *uap = (struct a *)scp->sc_ap; 68638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68737741Smckusick register struct vnode *vp; 68837741Smckusick int error; 6896254Sroot 69037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 69116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69216694Smckusick ndp->ni_dirp = uap->fname; 69337741Smckusick if (error = namei(ndp)) 69437741Smckusick RETURN (error); 69537741Smckusick vp = ndp->ni_vp; 69637741Smckusick if (vp->v_type == VDIR && 69738408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6986254Sroot goto out; 6996254Sroot /* 7006254Sroot * Don't unlink a mounted file. 7016254Sroot */ 70237741Smckusick if (vp->v_flag & VROOT) { 70337741Smckusick error = EBUSY; 7046254Sroot goto out; 7056254Sroot } 70637741Smckusick if (vp->v_flag & VTEXT) 70737741Smckusick xrele(vp); /* try once to free text */ 7086254Sroot out: 70937741Smckusick if (error) 71037741Smckusick VOP_ABORTOP(ndp); 7117142Smckusick else 71237741Smckusick error = VOP_REMOVE(ndp); 71337741Smckusick RETURN (error); 7146254Sroot } 7156254Sroot 7166254Sroot /* 7176254Sroot * Seek system call 7186254Sroot */ 71938408Smckusick lseek(scp) 72038408Smckusick register struct syscontext *scp; 7216254Sroot { 7226254Sroot register struct file *fp; 7236254Sroot register struct a { 72437741Smckusick int fdes; 7256254Sroot off_t off; 7266254Sroot int sbase; 72738408Smckusick } *uap = (struct a *)scp->sc_ap; 72837741Smckusick struct vattr vattr; 72937741Smckusick int error; 7306254Sroot 73137741Smckusick if ((unsigned)uap->fdes >= NOFILE || 73238408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 73337741Smckusick RETURN (EBADF); 73437741Smckusick if (fp->f_type != DTYPE_VNODE) 73537741Smckusick RETURN (ESPIPE); 73613878Ssam switch (uap->sbase) { 73713878Ssam 73813878Ssam case L_INCR: 73913878Ssam fp->f_offset += uap->off; 74013878Ssam break; 74113878Ssam 74213878Ssam case L_XTND: 74337741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 74438408Smckusick &vattr, scp->sc_cred)) 74537741Smckusick RETURN (error); 74637741Smckusick fp->f_offset = uap->off + vattr.va_size; 74713878Ssam break; 74813878Ssam 74913878Ssam case L_SET: 75013878Ssam fp->f_offset = uap->off; 75113878Ssam break; 75213878Ssam 75313878Ssam default: 75437741Smckusick RETURN (EINVAL); 75513878Ssam } 75638408Smckusick scp->sc_offset = fp->f_offset; 75737741Smckusick RETURN (0); 7586254Sroot } 7596254Sroot 7606254Sroot /* 7616254Sroot * Access system call 7626254Sroot */ 76338408Smckusick saccess(scp) 76438408Smckusick register struct syscontext *scp; 7656254Sroot { 7666254Sroot register struct a { 7676254Sroot char *fname; 7686254Sroot int fmode; 76938408Smckusick } *uap = (struct a *)scp->sc_ap; 77038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 77137741Smckusick register struct vnode *vp; 77237741Smckusick int error, mode, svuid, svgid; 7736254Sroot 77438408Smckusick svuid = scp->sc_uid; 77538408Smckusick svgid = scp->sc_gid; 77638408Smckusick scp->sc_uid = scp->sc_ruid; 77738408Smckusick scp->sc_gid = scp->sc_rgid; 77837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 77916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78016694Smckusick ndp->ni_dirp = uap->fname; 78137741Smckusick if (error = namei(ndp)) 78237741Smckusick goto out1; 78337741Smckusick vp = ndp->ni_vp; 78437741Smckusick /* 78537741Smckusick * fmode == 0 means only check for exist 78637741Smckusick */ 78737741Smckusick if (uap->fmode) { 78837741Smckusick mode = 0; 78937741Smckusick if (uap->fmode & R_OK) 79037741Smckusick mode |= VREAD; 79137741Smckusick if (uap->fmode & W_OK) 79237741Smckusick mode |= VWRITE; 79337741Smckusick if (uap->fmode & X_OK) 79437741Smckusick mode |= VEXEC; 79539543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 79638399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7976254Sroot } 79837741Smckusick vput(vp); 79937741Smckusick out1: 80038408Smckusick scp->sc_uid = svuid; 80138408Smckusick scp->sc_gid = svgid; 80237741Smckusick RETURN (error); 8036254Sroot } 8046254Sroot 8056254Sroot /* 8066574Smckusic * Stat system call. This version follows links. 80737Sbill */ 80838408Smckusick stat(scp) 80938408Smckusick struct syscontext *scp; 81037Sbill { 81137Sbill 81238408Smckusick stat1(scp, FOLLOW); 81337Sbill } 81437Sbill 81537Sbill /* 8166574Smckusic * Lstat system call. This version does not follow links. 8175992Swnj */ 81838408Smckusick lstat(scp) 81938408Smckusick struct syscontext *scp; 8205992Swnj { 82112756Ssam 82238408Smckusick stat1(scp, NOFOLLOW); 82312756Ssam } 82412756Ssam 82538408Smckusick stat1(scp, follow) 82638408Smckusick register struct syscontext *scp; 82712756Ssam int follow; 82812756Ssam { 8295992Swnj register struct a { 8305992Swnj char *fname; 83112756Ssam struct stat *ub; 83238408Smckusick } *uap = (struct a *)scp->sc_ap; 83338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 83412756Ssam struct stat sb; 83537741Smckusick int error; 8365992Swnj 83737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 83816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83916694Smckusick ndp->ni_dirp = uap->fname; 84037741Smckusick if (error = namei(ndp)) 84137741Smckusick RETURN (error); 84237741Smckusick error = vn_stat(ndp->ni_vp, &sb); 84337741Smckusick vput(ndp->ni_vp); 84437741Smckusick if (error) 84537741Smckusick RETURN (error); 84637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 84737741Smckusick RETURN (error); 8485992Swnj } 8495992Swnj 8505992Swnj /* 8515992Swnj * Return target name of a symbolic link 85237Sbill */ 85338408Smckusick readlink(scp) 85438408Smckusick register struct syscontext *scp; 8555992Swnj { 8565992Swnj register struct a { 8575992Swnj char *name; 8585992Swnj char *buf; 8595992Swnj int count; 86038408Smckusick } *uap = (struct a *)scp->sc_ap; 86138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 86237741Smckusick register struct vnode *vp; 86337741Smckusick struct iovec aiov; 86437741Smckusick struct uio auio; 86537741Smckusick int error; 8665992Swnj 86737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 86816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86916694Smckusick ndp->ni_dirp = uap->name; 87037741Smckusick if (error = namei(ndp)) 87137741Smckusick RETURN (error); 87237741Smckusick vp = ndp->ni_vp; 87337741Smckusick if (vp->v_type != VLNK) { 87437741Smckusick error = EINVAL; 8755992Swnj goto out; 8765992Swnj } 87737741Smckusick aiov.iov_base = uap->buf; 87837741Smckusick aiov.iov_len = uap->count; 87937741Smckusick auio.uio_iov = &aiov; 88037741Smckusick auio.uio_iovcnt = 1; 88137741Smckusick auio.uio_offset = 0; 88237741Smckusick auio.uio_rw = UIO_READ; 88337741Smckusick auio.uio_segflg = UIO_USERSPACE; 88437741Smckusick auio.uio_resid = uap->count; 88537741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8865992Swnj out: 88737741Smckusick vput(vp); 88838408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 88937741Smckusick RETURN (error); 8905992Swnj } 8915992Swnj 8929167Ssam /* 89338259Smckusick * Change flags of a file given path name. 89438259Smckusick */ 89538408Smckusick chflags(scp) 89638408Smckusick register struct syscontext *scp; 89738259Smckusick { 89838259Smckusick struct a { 89938259Smckusick char *fname; 90038259Smckusick int flags; 90138408Smckusick } *uap = (struct a *)scp->sc_ap; 90238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 90338259Smckusick register struct vnode *vp; 90438259Smckusick struct vattr vattr; 90538259Smckusick int error; 90638259Smckusick 90738259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 90838259Smckusick ndp->ni_segflg = UIO_USERSPACE; 90938259Smckusick ndp->ni_dirp = uap->fname; 91038259Smckusick vattr_null(&vattr); 91138259Smckusick vattr.va_flags = uap->flags; 91238259Smckusick if (error = namei(ndp)) 91338259Smckusick RETURN (error); 91438259Smckusick vp = ndp->ni_vp; 91538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91638259Smckusick error = EROFS; 91738259Smckusick goto out; 91838259Smckusick } 91938259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 92038259Smckusick out: 92138259Smckusick vput(vp); 92238259Smckusick RETURN (error); 92338259Smckusick } 92438259Smckusick 92538259Smckusick /* 92638259Smckusick * Change flags of a file given a file descriptor. 92738259Smckusick */ 92838408Smckusick fchflags(scp) 92938408Smckusick register struct syscontext *scp; 93038259Smckusick { 93138259Smckusick struct a { 93238259Smckusick int fd; 93338259Smckusick int flags; 93438408Smckusick } *uap = (struct a *)scp->sc_ap; 93538259Smckusick struct vattr vattr; 93638259Smckusick struct vnode *vp; 93738259Smckusick struct file *fp; 93838259Smckusick int error; 93938259Smckusick 94038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 94138259Smckusick RETURN (error); 94238259Smckusick vattr_null(&vattr); 94338259Smckusick vattr.va_flags = uap->flags; 94438259Smckusick vp = (struct vnode *)fp->f_data; 94538259Smckusick VOP_LOCK(vp); 94638259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94738259Smckusick error = EROFS; 94838259Smckusick goto out; 94938259Smckusick } 95038259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 95138259Smckusick out: 95238259Smckusick VOP_UNLOCK(vp); 95338259Smckusick RETURN (error); 95438259Smckusick } 95538259Smckusick 95638259Smckusick /* 9579167Ssam * Change mode of a file given path name. 9589167Ssam */ 95938408Smckusick chmod(scp) 96038408Smckusick register struct syscontext *scp; 9615992Swnj { 9627701Ssam struct a { 9636254Sroot char *fname; 9646254Sroot int fmode; 96538408Smckusick } *uap = (struct a *)scp->sc_ap; 96638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 96737741Smckusick register struct vnode *vp; 96837741Smckusick struct vattr vattr; 96937741Smckusick int error; 9705992Swnj 97137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 97237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 97337741Smckusick ndp->ni_dirp = uap->fname; 97437741Smckusick vattr_null(&vattr); 97537741Smckusick vattr.va_mode = uap->fmode & 07777; 97637741Smckusick if (error = namei(ndp)) 97737741Smckusick RETURN (error); 97837741Smckusick vp = ndp->ni_vp; 97937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98037741Smckusick error = EROFS; 98137741Smckusick goto out; 98237741Smckusick } 98337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 98437741Smckusick out: 98537741Smckusick vput(vp); 98637741Smckusick RETURN (error); 9877701Ssam } 9887439Sroot 9899167Ssam /* 9909167Ssam * Change mode of a file given a file descriptor. 9919167Ssam */ 99238408Smckusick fchmod(scp) 99338408Smckusick register struct syscontext *scp; 9947701Ssam { 9957701Ssam struct a { 9967701Ssam int fd; 9977701Ssam int fmode; 99838408Smckusick } *uap = (struct a *)scp->sc_ap; 99937741Smckusick struct vattr vattr; 100037741Smckusick struct vnode *vp; 100137741Smckusick struct file *fp; 100237741Smckusick int error; 10037701Ssam 100438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 100537741Smckusick RETURN (error); 100637741Smckusick vattr_null(&vattr); 100737741Smckusick vattr.va_mode = uap->fmode & 07777; 100837741Smckusick vp = (struct vnode *)fp->f_data; 100937741Smckusick VOP_LOCK(vp); 101037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101137741Smckusick error = EROFS; 101237741Smckusick goto out; 10137439Sroot } 101437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 101537741Smckusick out: 101637741Smckusick VOP_UNLOCK(vp); 101737741Smckusick RETURN (error); 10185992Swnj } 10195992Swnj 10209167Ssam /* 10219167Ssam * Set ownership given a path name. 10229167Ssam */ 102338408Smckusick chown(scp) 102438408Smckusick register struct syscontext *scp; 102537Sbill { 10267701Ssam struct a { 10276254Sroot char *fname; 10286254Sroot int uid; 10296254Sroot int gid; 103038408Smckusick } *uap = (struct a *)scp->sc_ap; 103138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 103237741Smckusick register struct vnode *vp; 103337741Smckusick struct vattr vattr; 103437741Smckusick int error; 103537Sbill 103637741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 103736614Sbostic ndp->ni_segflg = UIO_USERSPACE; 103836614Sbostic ndp->ni_dirp = uap->fname; 103937741Smckusick vattr_null(&vattr); 104037741Smckusick vattr.va_uid = uap->uid; 104137741Smckusick vattr.va_gid = uap->gid; 104237741Smckusick if (error = namei(ndp)) 104337741Smckusick RETURN (error); 104437741Smckusick vp = ndp->ni_vp; 104537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 104637741Smckusick error = EROFS; 104737741Smckusick goto out; 104837741Smckusick } 104937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 105037741Smckusick out: 105137741Smckusick vput(vp); 105237741Smckusick RETURN (error); 10537701Ssam } 10547439Sroot 10559167Ssam /* 10569167Ssam * Set ownership given a file descriptor. 10579167Ssam */ 105838408Smckusick fchown(scp) 105938408Smckusick register struct syscontext *scp; 10607701Ssam { 10617701Ssam struct a { 10627701Ssam int fd; 10637701Ssam int uid; 10647701Ssam int gid; 106538408Smckusick } *uap = (struct a *)scp->sc_ap; 106637741Smckusick struct vattr vattr; 106737741Smckusick struct vnode *vp; 106837741Smckusick struct file *fp; 106937741Smckusick int error; 10707701Ssam 107138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 107237741Smckusick RETURN (error); 107337741Smckusick vattr_null(&vattr); 107437741Smckusick vattr.va_uid = uap->uid; 107537741Smckusick vattr.va_gid = uap->gid; 107637741Smckusick vp = (struct vnode *)fp->f_data; 107737741Smckusick VOP_LOCK(vp); 107837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 107937741Smckusick error = EROFS; 108037741Smckusick goto out; 108137741Smckusick } 108237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108337741Smckusick out: 108437741Smckusick VOP_UNLOCK(vp); 108537741Smckusick RETURN (error); 10867701Ssam } 10877701Ssam 108838408Smckusick utimes(scp) 108938408Smckusick register struct syscontext *scp; 109011811Ssam { 109111811Ssam register struct a { 109211811Ssam char *fname; 109311811Ssam struct timeval *tptr; 109438408Smckusick } *uap = (struct a *)scp->sc_ap; 109538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 109637741Smckusick register struct vnode *vp; 109711811Ssam struct timeval tv[2]; 109837741Smckusick struct vattr vattr; 109937741Smckusick int error; 110011811Ssam 110137741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 110237741Smckusick RETURN (error); 110337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 110437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 110537741Smckusick ndp->ni_dirp = uap->fname; 110637741Smckusick vattr_null(&vattr); 110737741Smckusick vattr.va_atime = tv[0]; 110837741Smckusick vattr.va_mtime = tv[1]; 110937741Smckusick if (error = namei(ndp)) 111037741Smckusick RETURN (error); 111137741Smckusick vp = ndp->ni_vp; 111237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 111337741Smckusick error = EROFS; 111437741Smckusick goto out; 111521015Smckusick } 111637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 111737741Smckusick out: 111837741Smckusick vput(vp); 111937741Smckusick RETURN (error); 112011811Ssam } 112111811Ssam 11229167Ssam /* 11239167Ssam * Truncate a file given its path name. 11249167Ssam */ 112538408Smckusick truncate(scp) 112638408Smckusick register struct syscontext *scp; 11277701Ssam { 11287701Ssam struct a { 11297701Ssam char *fname; 113026473Skarels off_t length; 113138408Smckusick } *uap = (struct a *)scp->sc_ap; 113238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 113337741Smckusick register struct vnode *vp; 113437741Smckusick struct vattr vattr; 113537741Smckusick int error; 11367701Ssam 113737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113916694Smckusick ndp->ni_dirp = uap->fname; 114037741Smckusick vattr_null(&vattr); 114137741Smckusick vattr.va_size = uap->length; 114237741Smckusick if (error = namei(ndp)) 114337741Smckusick RETURN (error); 114437741Smckusick vp = ndp->ni_vp; 114537741Smckusick if (vp->v_type == VDIR) { 114637741Smckusick error = EISDIR; 114737741Smckusick goto out; 11487701Ssam } 114938399Smckusick if ((error = vn_writechk(vp)) || 115038399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 115137741Smckusick goto out; 115237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115337741Smckusick out: 115437741Smckusick vput(vp); 115537741Smckusick RETURN (error); 11567701Ssam } 11577701Ssam 11589167Ssam /* 11599167Ssam * Truncate a file given a file descriptor. 11609167Ssam */ 116138408Smckusick ftruncate(scp) 116238408Smckusick register struct syscontext *scp; 11637701Ssam { 11647701Ssam struct a { 11657701Ssam int fd; 116626473Skarels off_t length; 116738408Smckusick } *uap = (struct a *)scp->sc_ap; 116837741Smckusick struct vattr vattr; 116937741Smckusick struct vnode *vp; 11707701Ssam struct file *fp; 117137741Smckusick int error; 11727701Ssam 117338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 117437741Smckusick RETURN (error); 117537741Smckusick if ((fp->f_flag & FWRITE) == 0) 117637741Smckusick RETURN (EINVAL); 117737741Smckusick vattr_null(&vattr); 117837741Smckusick vattr.va_size = uap->length; 117937741Smckusick vp = (struct vnode *)fp->f_data; 118037741Smckusick VOP_LOCK(vp); 118137741Smckusick if (vp->v_type == VDIR) { 118237741Smckusick error = EISDIR; 118337741Smckusick goto out; 11847701Ssam } 118538399Smckusick if (error = vn_writechk(vp)) 118637741Smckusick goto out; 118737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118837741Smckusick out: 118937741Smckusick VOP_UNLOCK(vp); 119037741Smckusick RETURN (error); 11917701Ssam } 11927701Ssam 11939167Ssam /* 11949167Ssam * Synch an open file. 11959167Ssam */ 119638408Smckusick fsync(scp) 119738408Smckusick register struct syscontext *scp; 11989167Ssam { 11999167Ssam struct a { 12009167Ssam int fd; 120138408Smckusick } *uap = (struct a *)scp->sc_ap; 120239592Smckusick register struct vnode *vp; 12039167Ssam struct file *fp; 120437741Smckusick int error; 12059167Ssam 120638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 120737741Smckusick RETURN (error); 120839592Smckusick vp = (struct vnode *)fp->f_data; 120939592Smckusick VOP_LOCK(vp); 121039592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 121139592Smckusick VOP_UNLOCK(vp); 121237741Smckusick RETURN (error); 12139167Ssam } 12149167Ssam 12159167Ssam /* 12169167Ssam * Rename system call. 12179167Ssam * 12189167Ssam * Source and destination must either both be directories, or both 12199167Ssam * not be directories. If target is a directory, it must be empty. 12209167Ssam */ 122138408Smckusick rename(scp) 122238408Smckusick register struct syscontext *scp; 12237701Ssam { 12247701Ssam struct a { 12257701Ssam char *from; 12267701Ssam char *to; 122738408Smckusick } *uap = (struct a *)scp->sc_ap; 122837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 122938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 123037741Smckusick struct nameidata tond; 123137741Smckusick int error; 12327701Ssam 123337741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 123416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 123516694Smckusick ndp->ni_dirp = uap->from; 123637741Smckusick if (error = namei(ndp)) 123737741Smckusick RETURN (error); 123837741Smckusick fvp = ndp->ni_vp; 123938266Smckusick nddup(ndp, &tond); 124037741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 124137741Smckusick tond.ni_segflg = UIO_USERSPACE; 124237741Smckusick tond.ni_dirp = uap->to; 124337741Smckusick error = namei(&tond); 124437741Smckusick tdvp = tond.ni_dvp; 124537741Smckusick tvp = tond.ni_vp; 124637741Smckusick if (tvp != NULL) { 124737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 124839242Sbostic error = ENOTDIR; 124937741Smckusick goto out; 125037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 125139242Sbostic error = EISDIR; 125237741Smckusick goto out; 12539167Ssam } 12549167Ssam } 125537741Smckusick if (error) { 125637741Smckusick VOP_ABORTOP(ndp); 125737741Smckusick goto out1; 125837741Smckusick } 125937741Smckusick if (fvp->v_mount != tdvp->v_mount) { 126037741Smckusick error = EXDEV; 12619167Ssam goto out; 126210051Ssam } 126339286Smckusick if (fvp == tdvp) 126437741Smckusick error = EINVAL; 126539286Smckusick /* 126639286Smckusick * If source is the same as the destination, 126739286Smckusick * then there is nothing to do. 126839286Smckusick */ 126939286Smckusick if (fvp == tvp) 127039286Smckusick error = -1; 127137741Smckusick out: 127237741Smckusick if (error) { 127337741Smckusick VOP_ABORTOP(&tond); 127437741Smckusick VOP_ABORTOP(ndp); 12759167Ssam } else { 127637741Smckusick error = VOP_RENAME(ndp, &tond); 12779167Ssam } 127837741Smckusick out1: 127938266Smckusick ndrele(&tond); 128039286Smckusick if (error == -1) 128139286Smckusick RETURN (0); 128237741Smckusick RETURN (error); 12837701Ssam } 12847701Ssam 12857535Sroot /* 128612756Ssam * Mkdir system call 128712756Ssam */ 128838408Smckusick mkdir(scp) 128938408Smckusick register struct syscontext *scp; 129012756Ssam { 129112756Ssam struct a { 129212756Ssam char *name; 129312756Ssam int dmode; 129438408Smckusick } *uap = (struct a *)scp->sc_ap; 129538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 129637741Smckusick register struct vnode *vp; 129737741Smckusick struct vattr vattr; 129837741Smckusick int error; 129912756Ssam 130037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 130116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130216694Smckusick ndp->ni_dirp = uap->name; 130337741Smckusick if (error = namei(ndp)) 130437741Smckusick RETURN (error); 130537741Smckusick vp = ndp->ni_vp; 130637741Smckusick if (vp != NULL) { 130737741Smckusick VOP_ABORTOP(ndp); 130837741Smckusick RETURN (EEXIST); 130912756Ssam } 131037741Smckusick vattr_null(&vattr); 131137741Smckusick vattr.va_type = VDIR; 131238408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 131337741Smckusick error = VOP_MKDIR(ndp, &vattr); 131438145Smckusick if (!error) 131538145Smckusick vput(ndp->ni_vp); 131637741Smckusick RETURN (error); 131712756Ssam } 131812756Ssam 131912756Ssam /* 132012756Ssam * Rmdir system call. 132112756Ssam */ 132238408Smckusick rmdir(scp) 132338408Smckusick register struct syscontext *scp; 132412756Ssam { 132512756Ssam struct a { 132612756Ssam char *name; 132738408Smckusick } *uap = (struct a *)scp->sc_ap; 132838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 132937741Smckusick register struct vnode *vp; 133037741Smckusick int error; 133112756Ssam 133237741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 133316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 133416694Smckusick ndp->ni_dirp = uap->name; 133537741Smckusick if (error = namei(ndp)) 133637741Smckusick RETURN (error); 133737741Smckusick vp = ndp->ni_vp; 133837741Smckusick if (vp->v_type != VDIR) { 133937741Smckusick error = ENOTDIR; 134012756Ssam goto out; 134112756Ssam } 134212756Ssam /* 134337741Smckusick * No rmdir "." please. 134412756Ssam */ 134537741Smckusick if (ndp->ni_dvp == vp) { 134637741Smckusick error = EINVAL; 134712756Ssam goto out; 134812756Ssam } 134912756Ssam /* 135037741Smckusick * Don't unlink a mounted file. 135112756Ssam */ 135237741Smckusick if (vp->v_flag & VROOT) 135337741Smckusick error = EBUSY; 135412756Ssam out: 135537741Smckusick if (error) 135637741Smckusick VOP_ABORTOP(ndp); 135737741Smckusick else 135837741Smckusick error = VOP_RMDIR(ndp); 135937741Smckusick RETURN (error); 136012756Ssam } 136112756Ssam 136237741Smckusick /* 136337741Smckusick * Read a block of directory entries in a file system independent format 136437741Smckusick */ 136538408Smckusick getdirentries(scp) 136638408Smckusick register struct syscontext *scp; 136712756Ssam { 136837741Smckusick register struct a { 136937741Smckusick int fd; 137037741Smckusick char *buf; 137137741Smckusick unsigned count; 137237741Smckusick long *basep; 137338408Smckusick } *uap = (struct a *)scp->sc_ap; 137439592Smckusick register struct vnode *vp; 137516540Ssam struct file *fp; 137637741Smckusick struct uio auio; 137737741Smckusick struct iovec aiov; 137838129Smckusick off_t off; 137937741Smckusick int error; 138012756Ssam 138138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 138237741Smckusick RETURN (error); 138337741Smckusick if ((fp->f_flag & FREAD) == 0) 138437741Smckusick RETURN (EBADF); 138539592Smckusick vp = (struct vnode *)fp->f_data; 138639592Smckusick if (vp->v_type != VDIR) 138739592Smckusick RETURN (EINVAL); 138837741Smckusick aiov.iov_base = uap->buf; 138937741Smckusick aiov.iov_len = uap->count; 139037741Smckusick auio.uio_iov = &aiov; 139137741Smckusick auio.uio_iovcnt = 1; 139237741Smckusick auio.uio_rw = UIO_READ; 139337741Smckusick auio.uio_segflg = UIO_USERSPACE; 139437741Smckusick auio.uio_resid = uap->count; 139539592Smckusick VOP_LOCK(vp); 139639592Smckusick auio.uio_offset = off = fp->f_offset; 139739592Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 139839592Smckusick fp->f_offset = auio.uio_offset; 139939592Smckusick VOP_UNLOCK(vp); 140039592Smckusick if (error) 140137741Smckusick RETURN (error); 140239592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 140338408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 140437741Smckusick RETURN (error); 140512756Ssam } 140612756Ssam 140712756Ssam /* 140812756Ssam * mode mask for creation of files 140912756Ssam */ 141038408Smckusick umask(scp) 141138408Smckusick register struct syscontext *scp; 141212756Ssam { 141312756Ssam register struct a { 141412756Ssam int mask; 141538408Smckusick } *uap = (struct a *)scp->sc_ap; 141612756Ssam 141738408Smckusick scp->sc_retval1 = scp->sc_cmask; 141838408Smckusick scp->sc_cmask = uap->mask & 07777; 141937741Smckusick RETURN (0); 142012756Ssam } 142137741Smckusick 142239566Smarc /* 142339566Smarc * Void all references to file by ripping underlying filesystem 142439566Smarc * away from vnode. 142539566Smarc */ 142639566Smarc revoke(scp) 142739566Smarc register struct syscontext *scp; 142839566Smarc { 142939566Smarc struct a { 143039566Smarc char *fname; 143139566Smarc } *uap = (struct a *)scp->sc_ap; 143239566Smarc register struct nameidata *ndp = &scp->sc_nd; 143339566Smarc register struct vnode *vp; 143439566Smarc struct vattr vattr; 143539566Smarc int error; 143639566Smarc 143739566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 143839566Smarc ndp->ni_segflg = UIO_USERSPACE; 143939566Smarc ndp->ni_dirp = uap->fname; 144039566Smarc if (error = namei(ndp)) 144139566Smarc RETURN (error); 144239566Smarc vp = ndp->ni_vp; 144339566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 144439566Smarc error = EINVAL; 144539566Smarc goto out; 144639566Smarc } 144739566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 144839566Smarc goto out; 144939566Smarc if (scp->sc_uid != vattr.va_uid || 145039566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 145139566Smarc goto out; 145239805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 145339632Smckusick vgoneall(vp); 145439566Smarc out: 145539566Smarc vrele(vp); 145639566Smarc RETURN (error); 145739566Smarc } 145839566Smarc 145938408Smckusick getvnode(ofile, fdes, fpp) 146038408Smckusick struct file *ofile[]; 146137741Smckusick struct file **fpp; 146237741Smckusick int fdes; 146337741Smckusick { 146437741Smckusick struct file *fp; 146537741Smckusick 146638408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 146737741Smckusick return (EBADF); 146837741Smckusick if (fp->f_type != DTYPE_VNODE) 146937741Smckusick return (EINVAL); 147037741Smckusick *fpp = fp; 147137741Smckusick return (0); 147237741Smckusick } 1473