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*39381Smckusick * @(#)vfs_syscalls.c 7.20 (Berkeley) 10/24/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 3337741Smckusick /* 3437741Smckusick * Virtual File System System Calls 3537741Smckusick */ 3612756Ssam 379167Ssam /* 3837741Smckusick * mount system call 399167Ssam */ 4038408Smckusick mount(scp) 4138408Smckusick register struct syscontext *scp; 426254Sroot { 4337741Smckusick register struct a { 4437741Smckusick int type; 4537741Smckusick char *dir; 4637741Smckusick int flags; 4737741Smckusick caddr_t data; 4838408Smckusick } *uap = (struct a *)scp->sc_ap; 4938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5039335Smckusick register struct vnode *vp; 5139335Smckusick register struct mount *mp; 5237741Smckusick int error; 536254Sroot 5437741Smckusick /* 5537741Smckusick * Must be super user 5637741Smckusick */ 5738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 5837741Smckusick RETURN (error); 5937741Smckusick /* 6037741Smckusick * Get vnode to be covered 6137741Smckusick */ 6237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6437741Smckusick ndp->ni_dirp = uap->dir; 6537741Smckusick if (error = namei(ndp)) 6637741Smckusick RETURN (error); 6737741Smckusick vp = ndp->ni_vp; 6839335Smckusick if (uap->flags & M_UPDATE) { 6939335Smckusick if ((vp->v_flag & VROOT) == 0) { 7039335Smckusick vput(vp); 7139335Smckusick RETURN (EINVAL); 7239335Smckusick } 7339335Smckusick mp = vp->v_mount; 7439335Smckusick /* 7539335Smckusick * We allow going from read-only to read-write, 7639335Smckusick * but not from read-write to read-only. 7739335Smckusick */ 7839335Smckusick if ((mp->m_flag & M_RDONLY) == 0 && 7939335Smckusick (uap->flags & M_RDONLY) != 0) { 8039335Smckusick vput(vp); 8139335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8239335Smckusick } 8339335Smckusick mp->m_flag |= M_UPDATE; 8439335Smckusick VOP_UNLOCK(vp); 8539335Smckusick goto update; 8639335Smckusick } 8737741Smckusick if (vp->v_count != 1) { 8837741Smckusick vput(vp); 8937741Smckusick RETURN (EBUSY); 9037741Smckusick } 9137741Smckusick if (vp->v_type != VDIR) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (ENOTDIR); 9437741Smckusick } 9537741Smckusick if (uap->type > MOUNT_MAXTYPE || 9637741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9737741Smckusick vput(vp); 9837741Smckusick RETURN (ENODEV); 9937741Smckusick } 10037741Smckusick 10137741Smckusick /* 10239335Smckusick * Allocate and initialize the file system. 10337741Smckusick */ 10437741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10537741Smckusick M_MOUNT, M_WAITOK); 10637741Smckusick mp->m_op = vfssw[uap->type]; 10737741Smckusick mp->m_flag = 0; 10837741Smckusick mp->m_exroot = 0; 109*39381Smckusick mp->m_mounth = (struct vnode *)0; 11039335Smckusick if (error = vfs_lock(mp)) { 11139335Smckusick free((caddr_t)mp, M_MOUNT); 11239335Smckusick vput(vp); 11339335Smckusick RETURN (error); 11439335Smckusick } 11539335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11639335Smckusick vfs_unlock(mp); 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11939335Smckusick RETURN (EBUSY); 12039335Smckusick } 12139335Smckusick /* 12239335Smckusick * Put the new filesystem on the mount list after root. 12339335Smckusick */ 12439335Smckusick mp->m_next = rootfs->m_next; 12539335Smckusick mp->m_prev = rootfs; 12639335Smckusick rootfs->m_next = mp; 12739335Smckusick mp->m_next->m_prev = mp; 12839335Smckusick vp->v_mountedhere = mp; 12939335Smckusick mp->m_vnodecovered = vp; 13039335Smckusick update: 13139335Smckusick /* 13239335Smckusick * Set the mount level flags. 13339335Smckusick */ 13439335Smckusick if (uap->flags & M_RDONLY) 13539335Smckusick mp->m_flag |= M_RDONLY; 13639335Smckusick else 13739335Smckusick mp->m_flag &= ~M_RDONLY; 13839335Smckusick if (uap->flags & M_NOSUID) 13939335Smckusick mp->m_flag |= M_NOSUID; 14039335Smckusick else 14139335Smckusick mp->m_flag &= ~M_NOSUID; 14239335Smckusick if (uap->flags & M_NOEXEC) 14339335Smckusick mp->m_flag |= M_NOEXEC; 14439335Smckusick else 14539335Smckusick mp->m_flag &= ~M_NOEXEC; 14639335Smckusick if (uap->flags & M_NODEV) 14739335Smckusick mp->m_flag |= M_NODEV; 14839335Smckusick else 14939335Smckusick mp->m_flag &= ~M_NODEV; 15039335Smckusick if (uap->flags & M_SYNCHRONOUS) 15139335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15239335Smckusick else 15339335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15439335Smckusick /* 15539335Smckusick * Mount the filesystem. 15639335Smckusick */ 15739335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15839335Smckusick if (mp->m_flag & M_UPDATE) { 15939335Smckusick mp->m_flag &= ~M_UPDATE; 16039335Smckusick vrele(vp); 16139335Smckusick RETURN (error); 16239335Smckusick } 16337741Smckusick cache_purge(vp); 16437741Smckusick if (!error) { 16539335Smckusick VOP_UNLOCK(vp); 16637741Smckusick vfs_unlock(mp); 16739044Smckusick error = VFS_START(mp, 0); 16837741Smckusick } else { 16937741Smckusick vfs_remove(mp); 17037741Smckusick free((caddr_t)mp, M_MOUNT); 17139335Smckusick vput(vp); 17237741Smckusick } 17337741Smckusick RETURN (error); 1746254Sroot } 1756254Sroot 1769167Ssam /* 17737741Smckusick * Unmount system call. 17837741Smckusick * 17937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18037741Smckusick * not special file (as before). 1819167Ssam */ 18238408Smckusick unmount(scp) 18338408Smckusick register struct syscontext *scp; 1846254Sroot { 18537741Smckusick struct a { 18637741Smckusick char *pathp; 18737741Smckusick int flags; 18838408Smckusick } *uap = (struct a *)scp->sc_ap; 18937741Smckusick register struct vnode *vp; 19038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19139356Smckusick struct mount *mp; 19237741Smckusick int error; 1936254Sroot 19437741Smckusick /* 19537741Smckusick * Must be super user 19637741Smckusick */ 19738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 19837741Smckusick RETURN (error); 19937741Smckusick 20037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20237741Smckusick ndp->ni_dirp = uap->pathp; 20337741Smckusick if (error = namei(ndp)) 20437741Smckusick RETURN (error); 20537741Smckusick vp = ndp->ni_vp; 20637741Smckusick /* 20737741Smckusick * Must be the root of the filesystem 20837741Smckusick */ 20937741Smckusick if ((vp->v_flag & VROOT) == 0) { 21037741Smckusick vput(vp); 21137741Smckusick RETURN (EINVAL); 21237741Smckusick } 21337741Smckusick mp = vp->v_mount; 21437741Smckusick vput(vp); 21539356Smckusick RETURN (dounmount(mp, uap->flags)); 21639356Smckusick } 21739356Smckusick 21839356Smckusick /* 21939356Smckusick * Do an unmount. 22039356Smckusick */ 22139356Smckusick dounmount(mp, flags) 22239356Smckusick register struct mount *mp; 22339356Smckusick int flags; 22439356Smckusick { 22539356Smckusick struct vnode *coveredvp; 22639356Smckusick int error; 22739356Smckusick 22837741Smckusick coveredvp = mp->m_vnodecovered; 22937741Smckusick if (error = vfs_lock(mp)) 23039356Smckusick return (error); 23137741Smckusick 23237741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23437741Smckusick VFS_SYNC(mp, MNT_WAIT); 23537741Smckusick 23639356Smckusick error = VFS_UNMOUNT(mp, flags); 23737741Smckusick if (error) { 23837741Smckusick vfs_unlock(mp); 23937741Smckusick } else { 24037741Smckusick vrele(coveredvp); 24137741Smckusick vfs_remove(mp); 24237741Smckusick free((caddr_t)mp, M_MOUNT); 24337741Smckusick } 24439356Smckusick return (error); 2456254Sroot } 2466254Sroot 2479167Ssam /* 24837741Smckusick * Sync system call. 24937741Smckusick * Sync each mounted filesystem. 2509167Ssam */ 25138408Smckusick sync(scp) 25238408Smckusick register struct syscontext *scp; 2536254Sroot { 25437741Smckusick register struct mount *mp; 25537741Smckusick 25637741Smckusick mp = rootfs; 25737741Smckusick do { 25837741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 25937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 26037741Smckusick mp = mp->m_next; 26137741Smckusick } while (mp != rootfs); 26237741Smckusick } 26337741Smckusick 26437741Smckusick /* 26537741Smckusick * get filesystem statistics 26637741Smckusick */ 26738408Smckusick statfs(scp) 26838408Smckusick register struct syscontext *scp; 26937741Smckusick { 2706254Sroot struct a { 27137741Smckusick char *path; 27237741Smckusick struct statfs *buf; 27338408Smckusick } *uap = (struct a *)scp->sc_ap; 27437741Smckusick register struct vnode *vp; 27538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 27637741Smckusick struct statfs sb; 27737741Smckusick int error; 27837741Smckusick 27937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 28037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28137741Smckusick ndp->ni_dirp = uap->path; 28237741Smckusick if (error = namei(ndp)) 28337741Smckusick RETURN (error); 28437741Smckusick vp = ndp->ni_vp; 28537741Smckusick if (error = VFS_STATFS(vp->v_mount, &sb)) 28637741Smckusick goto out; 28737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 28837741Smckusick out: 28937741Smckusick vput(vp); 29037741Smckusick RETURN (error); 29137741Smckusick } 29237741Smckusick 29338408Smckusick fstatfs(scp) 29438408Smckusick register struct syscontext *scp; 29537741Smckusick { 29637741Smckusick struct a { 29737741Smckusick int fd; 29837741Smckusick struct statfs *buf; 29938408Smckusick } *uap = (struct a *)scp->sc_ap; 30037741Smckusick struct file *fp; 30137741Smckusick struct statfs sb; 30237741Smckusick int error; 30337741Smckusick 30438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 30537741Smckusick RETURN (error); 30637741Smckusick if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 30737741Smckusick RETURN (error); 30837741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 30937741Smckusick } 31037741Smckusick 31137741Smckusick /* 31238270Smckusick * get statistics on all filesystems 31338270Smckusick */ 31438408Smckusick getfsstat(scp) 31538408Smckusick register struct syscontext *scp; 31638270Smckusick { 31738270Smckusick struct a { 31838270Smckusick struct statfs *buf; 31938270Smckusick long bufsize; 32038408Smckusick } *uap = (struct a *)scp->sc_ap; 32138270Smckusick register struct mount *mp; 32238270Smckusick register struct statfs *sfsp; 32338270Smckusick long count, maxcount, error; 32438270Smckusick 32538270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 32638270Smckusick sfsp = uap->buf; 32738270Smckusick mp = rootfs; 32838270Smckusick count = 0; 32938270Smckusick do { 33038270Smckusick count++; 33139044Smckusick if (sfsp && count <= maxcount && 33239044Smckusick ((mp->m_flag & M_MLOCK) == 0)) { 33338270Smckusick if (error = VFS_STATFS(mp, sfsp)) 33438270Smckusick RETURN (error); 33538270Smckusick sfsp++; 33638270Smckusick } 33738270Smckusick mp = mp->m_prev; 33838270Smckusick } while (mp != rootfs); 33938270Smckusick if (sfsp && count > maxcount) 34038408Smckusick scp->sc_retval1 = maxcount; 34138270Smckusick else 34238408Smckusick scp->sc_retval1 = count; 34338270Smckusick RETURN (0); 34438270Smckusick } 34538270Smckusick 34638270Smckusick /* 34738259Smckusick * Change current working directory to a given file descriptor. 34838259Smckusick */ 34938408Smckusick fchdir(scp) 35038408Smckusick register struct syscontext *scp; 35138259Smckusick { 35238259Smckusick struct a { 35338259Smckusick int fd; 35438408Smckusick } *uap = (struct a *)scp->sc_ap; 35538259Smckusick register struct vnode *vp; 35638259Smckusick struct file *fp; 35738259Smckusick int error; 35838259Smckusick 35938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 36038259Smckusick RETURN (error); 36138259Smckusick vp = (struct vnode *)fp->f_data; 36238259Smckusick VOP_LOCK(vp); 36338259Smckusick if (vp->v_type != VDIR) 36438259Smckusick error = ENOTDIR; 36538259Smckusick else 36638408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 36738259Smckusick VOP_UNLOCK(vp); 36838408Smckusick vrele(scp->sc_cdir); 36938408Smckusick scp->sc_cdir = vp; 37038259Smckusick RETURN (error); 37138259Smckusick } 37238259Smckusick 37338259Smckusick /* 37437741Smckusick * Change current working directory (``.''). 37537741Smckusick */ 37638408Smckusick chdir(scp) 37738408Smckusick register struct syscontext *scp; 37837741Smckusick { 37937741Smckusick struct a { 3806254Sroot char *fname; 38138408Smckusick } *uap = (struct a *)scp->sc_ap; 38238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 38337741Smckusick int error; 3846254Sroot 38537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 38616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 38716694Smckusick ndp->ni_dirp = uap->fname; 38837741Smckusick if (error = chdirec(ndp)) 38937741Smckusick RETURN (error); 39038408Smckusick vrele(scp->sc_cdir); 39138408Smckusick scp->sc_cdir = ndp->ni_vp; 39237741Smckusick RETURN (0); 39337741Smckusick } 3946254Sroot 39537741Smckusick /* 39637741Smckusick * Change notion of root (``/'') directory. 39737741Smckusick */ 39838408Smckusick chroot(scp) 39938408Smckusick register struct syscontext *scp; 40037741Smckusick { 40137741Smckusick struct a { 40237741Smckusick char *fname; 40338408Smckusick } *uap = (struct a *)scp->sc_ap; 40438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 40537741Smckusick int error; 40637741Smckusick 40738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 40837741Smckusick RETURN (error); 40937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 41037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 41137741Smckusick ndp->ni_dirp = uap->fname; 41237741Smckusick if (error = chdirec(ndp)) 41337741Smckusick RETURN (error); 41438408Smckusick vrele(scp->sc_rdir); 41538408Smckusick scp->sc_rdir = ndp->ni_vp; 41637741Smckusick RETURN (0); 4176254Sroot } 4186254Sroot 41937Sbill /* 42037741Smckusick * Common routine for chroot and chdir. 42137741Smckusick */ 42237741Smckusick chdirec(ndp) 42337741Smckusick register struct nameidata *ndp; 42437741Smckusick { 42537741Smckusick struct vnode *vp; 42637741Smckusick int error; 42737741Smckusick 42837741Smckusick if (error = namei(ndp)) 42937741Smckusick return (error); 43037741Smckusick vp = ndp->ni_vp; 43137741Smckusick if (vp->v_type != VDIR) 43237741Smckusick error = ENOTDIR; 43337741Smckusick else 43438399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 43537741Smckusick VOP_UNLOCK(vp); 43637741Smckusick if (error) 43737741Smckusick vrele(vp); 43837741Smckusick return (error); 43937741Smckusick } 44037741Smckusick 44137741Smckusick /* 4426254Sroot * Open system call. 4436254Sroot */ 44438408Smckusick open(scp) 44538408Smckusick register struct syscontext *scp; 4466254Sroot { 44712756Ssam struct a { 4486254Sroot char *fname; 4497701Ssam int mode; 45012756Ssam int crtmode; 45138408Smckusick } *uap = (struct a *) scp->sc_ap; 45238408Smckusick struct nameidata *ndp = &scp->sc_nd; 4536254Sroot 45437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 45537741Smckusick ndp->ni_dirp = uap->fname; 45638408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 45738408Smckusick &scp->sc_retval1)); 4586254Sroot } 4596254Sroot 4606254Sroot /* 4616254Sroot * Creat system call. 4626254Sroot */ 46338408Smckusick creat(scp) 46438408Smckusick register struct syscontext *scp; 4656254Sroot { 46612756Ssam struct a { 4676254Sroot char *fname; 4686254Sroot int fmode; 46938408Smckusick } *uap = (struct a *)scp->sc_ap; 47038408Smckusick struct nameidata *ndp = &scp->sc_nd; 4716254Sroot 47237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47337741Smckusick ndp->ni_dirp = uap->fname; 47438408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 47538408Smckusick ndp, &scp->sc_retval1)); 4766254Sroot } 4776254Sroot 4786254Sroot /* 4796254Sroot * Common code for open and creat. 48012756Ssam * Check permissions, allocate an open file structure, 48112756Ssam * and call the device open routine if any. 4826254Sroot */ 48338408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 48438408Smckusick register struct syscontext *scp; 48537741Smckusick int fmode, cmode; 48637741Smckusick struct nameidata *ndp; 48737741Smckusick int *resultfd; 48812756Ssam { 4896254Sroot register struct file *fp; 49037741Smckusick struct file *nfp; 49137741Smckusick int indx, error; 49237741Smckusick extern struct fileops vnops; 4936254Sroot 49437741Smckusick if (error = falloc(&nfp, &indx)) 49537741Smckusick return (error); 49637741Smckusick fp = nfp; 49738408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 49837741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 49938408Smckusick scp->sc_ofile[indx] = NULL; 50037741Smckusick crfree(fp->f_cred); 50137741Smckusick fp->f_count--; 50237741Smckusick return (error); 50312756Ssam } 50437741Smckusick fp->f_flag = fmode & FMASK; 50537741Smckusick fp->f_type = DTYPE_VNODE; 50637741Smckusick fp->f_ops = &vnops; 50737741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 50837741Smckusick if (resultfd) 50937741Smckusick *resultfd = indx; 51037741Smckusick return (0); 5116254Sroot } 5126254Sroot 5136254Sroot /* 5146254Sroot * Mknod system call 5156254Sroot */ 51638408Smckusick mknod(scp) 51738408Smckusick register struct syscontext *scp; 5186254Sroot { 5196254Sroot register struct a { 5206254Sroot char *fname; 5216254Sroot int fmode; 5226254Sroot int dev; 52338408Smckusick } *uap = (struct a *)scp->sc_ap; 52438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 52537741Smckusick register struct vnode *vp; 52637741Smckusick struct vattr vattr; 52737741Smckusick int error; 5286254Sroot 52938408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 53037741Smckusick RETURN (error); 53137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 53216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 53316694Smckusick ndp->ni_dirp = uap->fname; 53437741Smckusick if (error = namei(ndp)) 53537741Smckusick RETURN (error); 53637741Smckusick vp = ndp->ni_vp; 53737741Smckusick if (vp != NULL) { 53837741Smckusick error = EEXIST; 53912756Ssam goto out; 5406254Sroot } 54137741Smckusick vattr_null(&vattr); 54237741Smckusick switch (uap->fmode & IFMT) { 54312756Ssam 54415093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 54537741Smckusick vattr.va_type = VBAD; 54637741Smckusick break; 54712756Ssam case IFCHR: 54837741Smckusick vattr.va_type = VCHR; 54937741Smckusick break; 55012756Ssam case IFBLK: 55137741Smckusick vattr.va_type = VBLK; 55237741Smckusick break; 55337741Smckusick default: 55437741Smckusick error = EINVAL; 55537741Smckusick goto out; 5566254Sroot } 55738408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 55837741Smckusick vattr.va_rdev = uap->dev; 5596254Sroot out: 56037741Smckusick if (error) 56137741Smckusick VOP_ABORTOP(ndp); 56237741Smckusick else 56337741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 56437741Smckusick RETURN (error); 5656254Sroot } 5666254Sroot 5676254Sroot /* 5686254Sroot * link system call 5696254Sroot */ 57038408Smckusick link(scp) 57138408Smckusick register struct syscontext *scp; 5726254Sroot { 5736254Sroot register struct a { 5746254Sroot char *target; 5756254Sroot char *linkname; 57638408Smckusick } *uap = (struct a *)scp->sc_ap; 57738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 57837741Smckusick register struct vnode *vp, *xp; 57937741Smckusick int error; 5806254Sroot 58116694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 58216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 58316694Smckusick ndp->ni_dirp = uap->target; 58437741Smckusick if (error = namei(ndp)) 58537741Smckusick RETURN (error); 58637741Smckusick vp = ndp->ni_vp; 58737741Smckusick if (vp->v_type == VDIR && 58838408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 58937741Smckusick goto out1; 59037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 59116694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 59237741Smckusick if (error = namei(ndp)) 59337741Smckusick goto out1; 59437741Smckusick xp = ndp->ni_vp; 5956254Sroot if (xp != NULL) { 59637741Smckusick error = EEXIST; 5976254Sroot goto out; 5986254Sroot } 59937741Smckusick xp = ndp->ni_dvp; 60037741Smckusick if (vp->v_mount != xp->v_mount) 60137741Smckusick error = EXDEV; 6026254Sroot out: 60337741Smckusick if (error) 60437741Smckusick VOP_ABORTOP(ndp); 60537741Smckusick else 60637741Smckusick error = VOP_LINK(vp, ndp); 60737741Smckusick out1: 60837741Smckusick vrele(vp); 60937741Smckusick RETURN (error); 6106254Sroot } 6116254Sroot 6126254Sroot /* 6136254Sroot * symlink -- make a symbolic link 6146254Sroot */ 61538408Smckusick symlink(scp) 61638408Smckusick register struct syscontext *scp; 6176254Sroot { 61837741Smckusick struct a { 6196254Sroot char *target; 6206254Sroot char *linkname; 62138408Smckusick } *uap = (struct a *)scp->sc_ap; 62238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 62337741Smckusick register struct vnode *vp; 62437741Smckusick struct vattr vattr; 62537741Smckusick char *target; 62637741Smckusick int error; 6276254Sroot 62816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62916694Smckusick ndp->ni_dirp = uap->linkname; 63037741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 63137741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 63237741Smckusick goto out1; 63337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 63437741Smckusick if (error = namei(ndp)) 63537741Smckusick goto out1; 63637741Smckusick vp = ndp->ni_vp; 63737741Smckusick if (vp) { 63837741Smckusick error = EEXIST; 63937741Smckusick goto out; 6406254Sroot } 64137741Smckusick vp = ndp->ni_dvp; 64237741Smckusick vattr_null(&vattr); 64338408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 64437741Smckusick out: 64537741Smckusick if (error) 64637741Smckusick VOP_ABORTOP(ndp); 64737741Smckusick else 64837741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 64937741Smckusick out1: 65037741Smckusick FREE(target, M_NAMEI); 65137741Smckusick RETURN (error); 6526254Sroot } 6536254Sroot 6546254Sroot /* 6556254Sroot * Unlink system call. 6566254Sroot * Hard to avoid races here, especially 6576254Sroot * in unlinking directories. 6586254Sroot */ 65938408Smckusick unlink(scp) 66038408Smckusick register struct syscontext *scp; 6616254Sroot { 6626254Sroot struct a { 6636254Sroot char *fname; 66438408Smckusick } *uap = (struct a *)scp->sc_ap; 66538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 66637741Smckusick register struct vnode *vp; 66737741Smckusick int error; 6686254Sroot 66937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 67016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 67116694Smckusick ndp->ni_dirp = uap->fname; 67237741Smckusick if (error = namei(ndp)) 67337741Smckusick RETURN (error); 67437741Smckusick vp = ndp->ni_vp; 67537741Smckusick if (vp->v_type == VDIR && 67638408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6776254Sroot goto out; 6786254Sroot /* 6796254Sroot * Don't unlink a mounted file. 6806254Sroot */ 68137741Smckusick if (vp->v_flag & VROOT) { 68237741Smckusick error = EBUSY; 6836254Sroot goto out; 6846254Sroot } 68537741Smckusick if (vp->v_flag & VTEXT) 68637741Smckusick xrele(vp); /* try once to free text */ 6876254Sroot out: 68837741Smckusick if (error) 68937741Smckusick VOP_ABORTOP(ndp); 6907142Smckusick else 69137741Smckusick error = VOP_REMOVE(ndp); 69237741Smckusick RETURN (error); 6936254Sroot } 6946254Sroot 6956254Sroot /* 6966254Sroot * Seek system call 6976254Sroot */ 69838408Smckusick lseek(scp) 69938408Smckusick register struct syscontext *scp; 7006254Sroot { 7016254Sroot register struct file *fp; 7026254Sroot register struct a { 70337741Smckusick int fdes; 7046254Sroot off_t off; 7056254Sroot int sbase; 70638408Smckusick } *uap = (struct a *)scp->sc_ap; 70737741Smckusick struct vattr vattr; 70837741Smckusick int error; 7096254Sroot 71037741Smckusick if ((unsigned)uap->fdes >= NOFILE || 71138408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 71237741Smckusick RETURN (EBADF); 71337741Smckusick if (fp->f_type != DTYPE_VNODE) 71437741Smckusick RETURN (ESPIPE); 71513878Ssam switch (uap->sbase) { 71613878Ssam 71713878Ssam case L_INCR: 71813878Ssam fp->f_offset += uap->off; 71913878Ssam break; 72013878Ssam 72113878Ssam case L_XTND: 72237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 72338408Smckusick &vattr, scp->sc_cred)) 72437741Smckusick RETURN (error); 72537741Smckusick fp->f_offset = uap->off + vattr.va_size; 72613878Ssam break; 72713878Ssam 72813878Ssam case L_SET: 72913878Ssam fp->f_offset = uap->off; 73013878Ssam break; 73113878Ssam 73213878Ssam default: 73337741Smckusick RETURN (EINVAL); 73413878Ssam } 73538408Smckusick scp->sc_offset = fp->f_offset; 73637741Smckusick RETURN (0); 7376254Sroot } 7386254Sroot 7396254Sroot /* 7406254Sroot * Access system call 7416254Sroot */ 74238408Smckusick saccess(scp) 74338408Smckusick register struct syscontext *scp; 7446254Sroot { 7456254Sroot register struct a { 7466254Sroot char *fname; 7476254Sroot int fmode; 74838408Smckusick } *uap = (struct a *)scp->sc_ap; 74938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 75037741Smckusick register struct vnode *vp; 75137741Smckusick int error, mode, svuid, svgid; 7526254Sroot 75338408Smckusick svuid = scp->sc_uid; 75438408Smckusick svgid = scp->sc_gid; 75538408Smckusick scp->sc_uid = scp->sc_ruid; 75638408Smckusick scp->sc_gid = scp->sc_rgid; 75737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 75816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 75916694Smckusick ndp->ni_dirp = uap->fname; 76037741Smckusick if (error = namei(ndp)) 76137741Smckusick goto out1; 76237741Smckusick vp = ndp->ni_vp; 76337741Smckusick /* 76437741Smckusick * fmode == 0 means only check for exist 76537741Smckusick */ 76637741Smckusick if (uap->fmode) { 76737741Smckusick mode = 0; 76837741Smckusick if (uap->fmode & R_OK) 76937741Smckusick mode |= VREAD; 77037741Smckusick if (uap->fmode & W_OK) 77137741Smckusick mode |= VWRITE; 77237741Smckusick if (uap->fmode & X_OK) 77337741Smckusick mode |= VEXEC; 77438399Smckusick if ((error = vn_writechk(vp)) == 0) 77538399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7766254Sroot } 77737741Smckusick vput(vp); 77837741Smckusick out1: 77938408Smckusick scp->sc_uid = svuid; 78038408Smckusick scp->sc_gid = svgid; 78137741Smckusick RETURN (error); 7826254Sroot } 7836254Sroot 7846254Sroot /* 7856574Smckusic * Stat system call. This version follows links. 78637Sbill */ 78738408Smckusick stat(scp) 78838408Smckusick struct syscontext *scp; 78937Sbill { 79037Sbill 79138408Smckusick stat1(scp, FOLLOW); 79237Sbill } 79337Sbill 79437Sbill /* 7956574Smckusic * Lstat system call. This version does not follow links. 7965992Swnj */ 79738408Smckusick lstat(scp) 79838408Smckusick struct syscontext *scp; 7995992Swnj { 80012756Ssam 80138408Smckusick stat1(scp, NOFOLLOW); 80212756Ssam } 80312756Ssam 80438408Smckusick stat1(scp, follow) 80538408Smckusick register struct syscontext *scp; 80612756Ssam int follow; 80712756Ssam { 8085992Swnj register struct a { 8095992Swnj char *fname; 81012756Ssam struct stat *ub; 81138408Smckusick } *uap = (struct a *)scp->sc_ap; 81238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 81312756Ssam struct stat sb; 81437741Smckusick int error; 8155992Swnj 81637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 81716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81816694Smckusick ndp->ni_dirp = uap->fname; 81937741Smckusick if (error = namei(ndp)) 82037741Smckusick RETURN (error); 82137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 82237741Smckusick vput(ndp->ni_vp); 82337741Smckusick if (error) 82437741Smckusick RETURN (error); 82537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 82637741Smckusick RETURN (error); 8275992Swnj } 8285992Swnj 8295992Swnj /* 8305992Swnj * Return target name of a symbolic link 83137Sbill */ 83238408Smckusick readlink(scp) 83338408Smckusick register struct syscontext *scp; 8345992Swnj { 8355992Swnj register struct a { 8365992Swnj char *name; 8375992Swnj char *buf; 8385992Swnj int count; 83938408Smckusick } *uap = (struct a *)scp->sc_ap; 84038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 84137741Smckusick register struct vnode *vp; 84237741Smckusick struct iovec aiov; 84337741Smckusick struct uio auio; 84437741Smckusick int error; 8455992Swnj 84637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 84716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 84816694Smckusick ndp->ni_dirp = uap->name; 84937741Smckusick if (error = namei(ndp)) 85037741Smckusick RETURN (error); 85137741Smckusick vp = ndp->ni_vp; 85237741Smckusick if (vp->v_type != VLNK) { 85337741Smckusick error = EINVAL; 8545992Swnj goto out; 8555992Swnj } 85637741Smckusick aiov.iov_base = uap->buf; 85737741Smckusick aiov.iov_len = uap->count; 85837741Smckusick auio.uio_iov = &aiov; 85937741Smckusick auio.uio_iovcnt = 1; 86037741Smckusick auio.uio_offset = 0; 86137741Smckusick auio.uio_rw = UIO_READ; 86237741Smckusick auio.uio_segflg = UIO_USERSPACE; 86337741Smckusick auio.uio_resid = uap->count; 86437741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8655992Swnj out: 86637741Smckusick vput(vp); 86738408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 86837741Smckusick RETURN (error); 8695992Swnj } 8705992Swnj 8719167Ssam /* 87238259Smckusick * Change flags of a file given path name. 87338259Smckusick */ 87438408Smckusick chflags(scp) 87538408Smckusick register struct syscontext *scp; 87638259Smckusick { 87738259Smckusick struct a { 87838259Smckusick char *fname; 87938259Smckusick int flags; 88038408Smckusick } *uap = (struct a *)scp->sc_ap; 88138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 88238259Smckusick register struct vnode *vp; 88338259Smckusick struct vattr vattr; 88438259Smckusick int error; 88538259Smckusick 88638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 88738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 88838259Smckusick ndp->ni_dirp = uap->fname; 88938259Smckusick vattr_null(&vattr); 89038259Smckusick vattr.va_flags = uap->flags; 89138259Smckusick if (error = namei(ndp)) 89238259Smckusick RETURN (error); 89338259Smckusick vp = ndp->ni_vp; 89438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 89538259Smckusick error = EROFS; 89638259Smckusick goto out; 89738259Smckusick } 89838259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 89938259Smckusick out: 90038259Smckusick vput(vp); 90138259Smckusick RETURN (error); 90238259Smckusick } 90338259Smckusick 90438259Smckusick /* 90538259Smckusick * Change flags of a file given a file descriptor. 90638259Smckusick */ 90738408Smckusick fchflags(scp) 90838408Smckusick register struct syscontext *scp; 90938259Smckusick { 91038259Smckusick struct a { 91138259Smckusick int fd; 91238259Smckusick int flags; 91338408Smckusick } *uap = (struct a *)scp->sc_ap; 91438259Smckusick struct vattr vattr; 91538259Smckusick struct vnode *vp; 91638259Smckusick struct file *fp; 91738259Smckusick int error; 91838259Smckusick 91938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 92038259Smckusick RETURN (error); 92138259Smckusick vattr_null(&vattr); 92238259Smckusick vattr.va_flags = uap->flags; 92338259Smckusick vp = (struct vnode *)fp->f_data; 92438259Smckusick VOP_LOCK(vp); 92538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 92638259Smckusick error = EROFS; 92738259Smckusick goto out; 92838259Smckusick } 92938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 93038259Smckusick out: 93138259Smckusick VOP_UNLOCK(vp); 93238259Smckusick RETURN (error); 93338259Smckusick } 93438259Smckusick 93538259Smckusick /* 9369167Ssam * Change mode of a file given path name. 9379167Ssam */ 93838408Smckusick chmod(scp) 93938408Smckusick register struct syscontext *scp; 9405992Swnj { 9417701Ssam struct a { 9426254Sroot char *fname; 9436254Sroot int fmode; 94438408Smckusick } *uap = (struct a *)scp->sc_ap; 94538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 94637741Smckusick register struct vnode *vp; 94737741Smckusick struct vattr vattr; 94837741Smckusick int error; 9495992Swnj 95037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 95237741Smckusick ndp->ni_dirp = uap->fname; 95337741Smckusick vattr_null(&vattr); 95437741Smckusick vattr.va_mode = uap->fmode & 07777; 95537741Smckusick if (error = namei(ndp)) 95637741Smckusick RETURN (error); 95737741Smckusick vp = ndp->ni_vp; 95837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 95937741Smckusick error = EROFS; 96037741Smckusick goto out; 96137741Smckusick } 96237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 96337741Smckusick out: 96437741Smckusick vput(vp); 96537741Smckusick RETURN (error); 9667701Ssam } 9677439Sroot 9689167Ssam /* 9699167Ssam * Change mode of a file given a file descriptor. 9709167Ssam */ 97138408Smckusick fchmod(scp) 97238408Smckusick register struct syscontext *scp; 9737701Ssam { 9747701Ssam struct a { 9757701Ssam int fd; 9767701Ssam int fmode; 97738408Smckusick } *uap = (struct a *)scp->sc_ap; 97837741Smckusick struct vattr vattr; 97937741Smckusick struct vnode *vp; 98037741Smckusick struct file *fp; 98137741Smckusick int error; 9827701Ssam 98338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 98437741Smckusick RETURN (error); 98537741Smckusick vattr_null(&vattr); 98637741Smckusick vattr.va_mode = uap->fmode & 07777; 98737741Smckusick vp = (struct vnode *)fp->f_data; 98837741Smckusick VOP_LOCK(vp); 98937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 99037741Smckusick error = EROFS; 99137741Smckusick goto out; 9927439Sroot } 99337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 99437741Smckusick out: 99537741Smckusick VOP_UNLOCK(vp); 99637741Smckusick RETURN (error); 9975992Swnj } 9985992Swnj 9999167Ssam /* 10009167Ssam * Set ownership given a path name. 10019167Ssam */ 100238408Smckusick chown(scp) 100338408Smckusick register struct syscontext *scp; 100437Sbill { 10057701Ssam struct a { 10066254Sroot char *fname; 10076254Sroot int uid; 10086254Sroot int gid; 100938408Smckusick } *uap = (struct a *)scp->sc_ap; 101038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 101137741Smckusick register struct vnode *vp; 101237741Smckusick struct vattr vattr; 101337741Smckusick int error; 101437Sbill 101537741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 101636614Sbostic ndp->ni_segflg = UIO_USERSPACE; 101736614Sbostic ndp->ni_dirp = uap->fname; 101837741Smckusick vattr_null(&vattr); 101937741Smckusick vattr.va_uid = uap->uid; 102037741Smckusick vattr.va_gid = uap->gid; 102137741Smckusick if (error = namei(ndp)) 102237741Smckusick RETURN (error); 102337741Smckusick vp = ndp->ni_vp; 102437741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 102537741Smckusick error = EROFS; 102637741Smckusick goto out; 102737741Smckusick } 102837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 102937741Smckusick out: 103037741Smckusick vput(vp); 103137741Smckusick RETURN (error); 10327701Ssam } 10337439Sroot 10349167Ssam /* 10359167Ssam * Set ownership given a file descriptor. 10369167Ssam */ 103738408Smckusick fchown(scp) 103838408Smckusick register struct syscontext *scp; 10397701Ssam { 10407701Ssam struct a { 10417701Ssam int fd; 10427701Ssam int uid; 10437701Ssam int gid; 104438408Smckusick } *uap = (struct a *)scp->sc_ap; 104537741Smckusick struct vattr vattr; 104637741Smckusick struct vnode *vp; 104737741Smckusick struct file *fp; 104837741Smckusick int error; 10497701Ssam 105038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 105137741Smckusick RETURN (error); 105237741Smckusick vattr_null(&vattr); 105337741Smckusick vattr.va_uid = uap->uid; 105437741Smckusick vattr.va_gid = uap->gid; 105537741Smckusick vp = (struct vnode *)fp->f_data; 105637741Smckusick VOP_LOCK(vp); 105737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 105837741Smckusick error = EROFS; 105937741Smckusick goto out; 106037741Smckusick } 106137741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 106237741Smckusick out: 106337741Smckusick VOP_UNLOCK(vp); 106437741Smckusick RETURN (error); 10657701Ssam } 10667701Ssam 106738408Smckusick utimes(scp) 106838408Smckusick register struct syscontext *scp; 106911811Ssam { 107011811Ssam register struct a { 107111811Ssam char *fname; 107211811Ssam struct timeval *tptr; 107338408Smckusick } *uap = (struct a *)scp->sc_ap; 107438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 107537741Smckusick register struct vnode *vp; 107611811Ssam struct timeval tv[2]; 107737741Smckusick struct vattr vattr; 107837741Smckusick int error; 107911811Ssam 108037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 108137741Smckusick RETURN (error); 108237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 108337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 108437741Smckusick ndp->ni_dirp = uap->fname; 108537741Smckusick vattr_null(&vattr); 108637741Smckusick vattr.va_atime = tv[0]; 108737741Smckusick vattr.va_mtime = tv[1]; 108837741Smckusick if (error = namei(ndp)) 108937741Smckusick RETURN (error); 109037741Smckusick vp = ndp->ni_vp; 109137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 109237741Smckusick error = EROFS; 109337741Smckusick goto out; 109421015Smckusick } 109537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 109637741Smckusick out: 109737741Smckusick vput(vp); 109837741Smckusick RETURN (error); 109911811Ssam } 110011811Ssam 11019167Ssam /* 11029167Ssam * Truncate a file given its path name. 11039167Ssam */ 110438408Smckusick truncate(scp) 110538408Smckusick register struct syscontext *scp; 11067701Ssam { 11077701Ssam struct a { 11087701Ssam char *fname; 110926473Skarels off_t length; 111038408Smckusick } *uap = (struct a *)scp->sc_ap; 111138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 111237741Smckusick register struct vnode *vp; 111337741Smckusick struct vattr vattr; 111437741Smckusick int error; 11157701Ssam 111637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 111716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 111816694Smckusick ndp->ni_dirp = uap->fname; 111937741Smckusick vattr_null(&vattr); 112037741Smckusick vattr.va_size = uap->length; 112137741Smckusick if (error = namei(ndp)) 112237741Smckusick RETURN (error); 112337741Smckusick vp = ndp->ni_vp; 112437741Smckusick if (vp->v_type == VDIR) { 112537741Smckusick error = EISDIR; 112637741Smckusick goto out; 11277701Ssam } 112838399Smckusick if ((error = vn_writechk(vp)) || 112938399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 113037741Smckusick goto out; 113137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 113237741Smckusick out: 113337741Smckusick vput(vp); 113437741Smckusick RETURN (error); 11357701Ssam } 11367701Ssam 11379167Ssam /* 11389167Ssam * Truncate a file given a file descriptor. 11399167Ssam */ 114038408Smckusick ftruncate(scp) 114138408Smckusick register struct syscontext *scp; 11427701Ssam { 11437701Ssam struct a { 11447701Ssam int fd; 114526473Skarels off_t length; 114638408Smckusick } *uap = (struct a *)scp->sc_ap; 114737741Smckusick struct vattr vattr; 114837741Smckusick struct vnode *vp; 11497701Ssam struct file *fp; 115037741Smckusick int error; 11517701Ssam 115238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 115337741Smckusick RETURN (error); 115437741Smckusick if ((fp->f_flag & FWRITE) == 0) 115537741Smckusick RETURN (EINVAL); 115637741Smckusick vattr_null(&vattr); 115737741Smckusick vattr.va_size = uap->length; 115837741Smckusick vp = (struct vnode *)fp->f_data; 115937741Smckusick VOP_LOCK(vp); 116037741Smckusick if (vp->v_type == VDIR) { 116137741Smckusick error = EISDIR; 116237741Smckusick goto out; 11637701Ssam } 116438399Smckusick if (error = vn_writechk(vp)) 116537741Smckusick goto out; 116637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 116737741Smckusick out: 116837741Smckusick VOP_UNLOCK(vp); 116937741Smckusick RETURN (error); 11707701Ssam } 11717701Ssam 11729167Ssam /* 11739167Ssam * Synch an open file. 11749167Ssam */ 117538408Smckusick fsync(scp) 117638408Smckusick register struct syscontext *scp; 11779167Ssam { 11789167Ssam struct a { 11799167Ssam int fd; 118038408Smckusick } *uap = (struct a *)scp->sc_ap; 11819167Ssam struct file *fp; 118237741Smckusick int error; 11839167Ssam 118438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 118537741Smckusick RETURN (error); 118637741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 118737741Smckusick RETURN (error); 11889167Ssam } 11899167Ssam 11909167Ssam /* 11919167Ssam * Rename system call. 11929167Ssam * 11939167Ssam * Source and destination must either both be directories, or both 11949167Ssam * not be directories. If target is a directory, it must be empty. 11959167Ssam */ 119638408Smckusick rename(scp) 119738408Smckusick register struct syscontext *scp; 11987701Ssam { 11997701Ssam struct a { 12007701Ssam char *from; 12017701Ssam char *to; 120238408Smckusick } *uap = (struct a *)scp->sc_ap; 120337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 120438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 120537741Smckusick struct nameidata tond; 120637741Smckusick int error; 12077701Ssam 120837741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 120916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 121016694Smckusick ndp->ni_dirp = uap->from; 121137741Smckusick if (error = namei(ndp)) 121237741Smckusick RETURN (error); 121337741Smckusick fvp = ndp->ni_vp; 121438266Smckusick nddup(ndp, &tond); 121537741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 121637741Smckusick tond.ni_segflg = UIO_USERSPACE; 121737741Smckusick tond.ni_dirp = uap->to; 121837741Smckusick error = namei(&tond); 121937741Smckusick tdvp = tond.ni_dvp; 122037741Smckusick tvp = tond.ni_vp; 122137741Smckusick if (tvp != NULL) { 122237741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 122339242Sbostic error = ENOTDIR; 122437741Smckusick goto out; 122537741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 122639242Sbostic error = EISDIR; 122737741Smckusick goto out; 12289167Ssam } 12299167Ssam } 123037741Smckusick if (error) { 123137741Smckusick VOP_ABORTOP(ndp); 123237741Smckusick goto out1; 123337741Smckusick } 123437741Smckusick if (fvp->v_mount != tdvp->v_mount) { 123537741Smckusick error = EXDEV; 12369167Ssam goto out; 123710051Ssam } 123839286Smckusick if (fvp == tdvp) 123937741Smckusick error = EINVAL; 124039286Smckusick /* 124139286Smckusick * If source is the same as the destination, 124239286Smckusick * then there is nothing to do. 124339286Smckusick */ 124439286Smckusick if (fvp == tvp) 124539286Smckusick error = -1; 124637741Smckusick out: 124737741Smckusick if (error) { 124837741Smckusick VOP_ABORTOP(&tond); 124937741Smckusick VOP_ABORTOP(ndp); 12509167Ssam } else { 125137741Smckusick error = VOP_RENAME(ndp, &tond); 12529167Ssam } 125337741Smckusick out1: 125438266Smckusick ndrele(&tond); 125539286Smckusick if (error == -1) 125639286Smckusick RETURN (0); 125737741Smckusick RETURN (error); 12587701Ssam } 12597701Ssam 12607535Sroot /* 126112756Ssam * Mkdir system call 126212756Ssam */ 126338408Smckusick mkdir(scp) 126438408Smckusick register struct syscontext *scp; 126512756Ssam { 126612756Ssam struct a { 126712756Ssam char *name; 126812756Ssam int dmode; 126938408Smckusick } *uap = (struct a *)scp->sc_ap; 127038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 127137741Smckusick register struct vnode *vp; 127237741Smckusick struct vattr vattr; 127337741Smckusick int error; 127412756Ssam 127537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 127616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 127716694Smckusick ndp->ni_dirp = uap->name; 127837741Smckusick if (error = namei(ndp)) 127937741Smckusick RETURN (error); 128037741Smckusick vp = ndp->ni_vp; 128137741Smckusick if (vp != NULL) { 128237741Smckusick VOP_ABORTOP(ndp); 128337741Smckusick RETURN (EEXIST); 128412756Ssam } 128537741Smckusick vattr_null(&vattr); 128637741Smckusick vattr.va_type = VDIR; 128738408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 128837741Smckusick error = VOP_MKDIR(ndp, &vattr); 128938145Smckusick if (!error) 129038145Smckusick vput(ndp->ni_vp); 129137741Smckusick RETURN (error); 129212756Ssam } 129312756Ssam 129412756Ssam /* 129512756Ssam * Rmdir system call. 129612756Ssam */ 129738408Smckusick rmdir(scp) 129838408Smckusick register struct syscontext *scp; 129912756Ssam { 130012756Ssam struct a { 130112756Ssam char *name; 130238408Smckusick } *uap = (struct a *)scp->sc_ap; 130338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 130437741Smckusick register struct vnode *vp; 130537741Smckusick int error; 130612756Ssam 130737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 130816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130916694Smckusick ndp->ni_dirp = uap->name; 131037741Smckusick if (error = namei(ndp)) 131137741Smckusick RETURN (error); 131237741Smckusick vp = ndp->ni_vp; 131337741Smckusick if (vp->v_type != VDIR) { 131437741Smckusick error = ENOTDIR; 131512756Ssam goto out; 131612756Ssam } 131712756Ssam /* 131837741Smckusick * No rmdir "." please. 131912756Ssam */ 132037741Smckusick if (ndp->ni_dvp == vp) { 132137741Smckusick error = EINVAL; 132212756Ssam goto out; 132312756Ssam } 132412756Ssam /* 132537741Smckusick * Don't unlink a mounted file. 132612756Ssam */ 132737741Smckusick if (vp->v_flag & VROOT) 132837741Smckusick error = EBUSY; 132912756Ssam out: 133037741Smckusick if (error) 133137741Smckusick VOP_ABORTOP(ndp); 133237741Smckusick else 133337741Smckusick error = VOP_RMDIR(ndp); 133437741Smckusick RETURN (error); 133512756Ssam } 133612756Ssam 133737741Smckusick /* 133837741Smckusick * Read a block of directory entries in a file system independent format 133937741Smckusick */ 134038408Smckusick getdirentries(scp) 134138408Smckusick register struct syscontext *scp; 134212756Ssam { 134337741Smckusick register struct a { 134437741Smckusick int fd; 134537741Smckusick char *buf; 134637741Smckusick unsigned count; 134737741Smckusick long *basep; 134838408Smckusick } *uap = (struct a *)scp->sc_ap; 134916540Ssam struct file *fp; 135037741Smckusick struct uio auio; 135137741Smckusick struct iovec aiov; 135238129Smckusick off_t off; 135337741Smckusick int error; 135412756Ssam 135538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 135637741Smckusick RETURN (error); 135737741Smckusick if ((fp->f_flag & FREAD) == 0) 135837741Smckusick RETURN (EBADF); 135937741Smckusick aiov.iov_base = uap->buf; 136037741Smckusick aiov.iov_len = uap->count; 136137741Smckusick auio.uio_iov = &aiov; 136237741Smckusick auio.uio_iovcnt = 1; 136337741Smckusick auio.uio_rw = UIO_READ; 136437741Smckusick auio.uio_segflg = UIO_USERSPACE; 136537741Smckusick auio.uio_resid = uap->count; 136638129Smckusick off = fp->f_offset; 136737741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 136837741Smckusick &(fp->f_offset), fp->f_cred)) 136937741Smckusick RETURN (error); 137038129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 137137741Smckusick sizeof(long)); 137238408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 137337741Smckusick RETURN (error); 137412756Ssam } 137512756Ssam 137612756Ssam /* 137712756Ssam * mode mask for creation of files 137812756Ssam */ 137938408Smckusick umask(scp) 138038408Smckusick register struct syscontext *scp; 138112756Ssam { 138212756Ssam register struct a { 138312756Ssam int mask; 138438408Smckusick } *uap = (struct a *)scp->sc_ap; 138512756Ssam 138638408Smckusick scp->sc_retval1 = scp->sc_cmask; 138738408Smckusick scp->sc_cmask = uap->mask & 07777; 138837741Smckusick RETURN (0); 138912756Ssam } 139037741Smckusick 139138408Smckusick getvnode(ofile, fdes, fpp) 139238408Smckusick struct file *ofile[]; 139337741Smckusick struct file **fpp; 139437741Smckusick int fdes; 139537741Smckusick { 139637741Smckusick struct file *fp; 139737741Smckusick 139838408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 139937741Smckusick return (EBADF); 140037741Smckusick if (fp->f_type != DTYPE_VNODE) 140137741Smckusick return (EINVAL); 140237741Smckusick *fpp = fp; 140337741Smckusick return (0); 140437741Smckusick } 1405