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*39356Smckusick * @(#)vfs_syscalls.c 7.19 (Berkeley) 10/20/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; 10939335Smckusick if (error = vfs_lock(mp)) { 11039335Smckusick free((caddr_t)mp, M_MOUNT); 11139335Smckusick vput(vp); 11239335Smckusick RETURN (error); 11339335Smckusick } 11439335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11539335Smckusick vfs_unlock(mp); 11639335Smckusick free((caddr_t)mp, M_MOUNT); 11739335Smckusick vput(vp); 11839335Smckusick RETURN (EBUSY); 11939335Smckusick } 12039335Smckusick /* 12139335Smckusick * Put the new filesystem on the mount list after root. 12239335Smckusick */ 12339335Smckusick mp->m_next = rootfs->m_next; 12439335Smckusick mp->m_prev = rootfs; 12539335Smckusick rootfs->m_next = mp; 12639335Smckusick mp->m_next->m_prev = mp; 12739335Smckusick vp->v_mountedhere = mp; 12839335Smckusick mp->m_vnodecovered = vp; 12939335Smckusick update: 13039335Smckusick /* 13139335Smckusick * Set the mount level flags. 13239335Smckusick */ 13339335Smckusick if (uap->flags & M_RDONLY) 13439335Smckusick mp->m_flag |= M_RDONLY; 13539335Smckusick else 13639335Smckusick mp->m_flag &= ~M_RDONLY; 13739335Smckusick if (uap->flags & M_NOSUID) 13839335Smckusick mp->m_flag |= M_NOSUID; 13939335Smckusick else 14039335Smckusick mp->m_flag &= ~M_NOSUID; 14139335Smckusick if (uap->flags & M_NOEXEC) 14239335Smckusick mp->m_flag |= M_NOEXEC; 14339335Smckusick else 14439335Smckusick mp->m_flag &= ~M_NOEXEC; 14539335Smckusick if (uap->flags & M_NODEV) 14639335Smckusick mp->m_flag |= M_NODEV; 14739335Smckusick else 14839335Smckusick mp->m_flag &= ~M_NODEV; 14939335Smckusick if (uap->flags & M_SYNCHRONOUS) 15039335Smckusick mp->m_flag |= M_SYNCHRONOUS; 15139335Smckusick else 15239335Smckusick mp->m_flag &= ~M_SYNCHRONOUS; 15339335Smckusick /* 15439335Smckusick * Mount the filesystem. 15539335Smckusick */ 15639335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15739335Smckusick if (mp->m_flag & M_UPDATE) { 15839335Smckusick mp->m_flag &= ~M_UPDATE; 15939335Smckusick vrele(vp); 16039335Smckusick RETURN (error); 16139335Smckusick } 16237741Smckusick cache_purge(vp); 16337741Smckusick if (!error) { 16439335Smckusick VOP_UNLOCK(vp); 16537741Smckusick vfs_unlock(mp); 16639044Smckusick error = VFS_START(mp, 0); 16737741Smckusick } else { 16837741Smckusick vfs_remove(mp); 16937741Smckusick free((caddr_t)mp, M_MOUNT); 17039335Smckusick vput(vp); 17137741Smckusick } 17237741Smckusick RETURN (error); 1736254Sroot } 1746254Sroot 1759167Ssam /* 17637741Smckusick * Unmount system call. 17737741Smckusick * 17837741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17937741Smckusick * not special file (as before). 1809167Ssam */ 18138408Smckusick unmount(scp) 18238408Smckusick register struct syscontext *scp; 1836254Sroot { 18437741Smckusick struct a { 18537741Smckusick char *pathp; 18637741Smckusick int flags; 18738408Smckusick } *uap = (struct a *)scp->sc_ap; 18837741Smckusick register struct vnode *vp; 18938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 190*39356Smckusick struct mount *mp; 19137741Smckusick int error; 1926254Sroot 19337741Smckusick /* 19437741Smckusick * Must be super user 19537741Smckusick */ 19638408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 19737741Smckusick RETURN (error); 19837741Smckusick 19937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20137741Smckusick ndp->ni_dirp = uap->pathp; 20237741Smckusick if (error = namei(ndp)) 20337741Smckusick RETURN (error); 20437741Smckusick vp = ndp->ni_vp; 20537741Smckusick /* 20637741Smckusick * Must be the root of the filesystem 20737741Smckusick */ 20837741Smckusick if ((vp->v_flag & VROOT) == 0) { 20937741Smckusick vput(vp); 21037741Smckusick RETURN (EINVAL); 21137741Smckusick } 21237741Smckusick mp = vp->v_mount; 21337741Smckusick vput(vp); 214*39356Smckusick RETURN (dounmount(mp, uap->flags)); 215*39356Smckusick } 216*39356Smckusick 217*39356Smckusick /* 218*39356Smckusick * Do an unmount. 219*39356Smckusick */ 220*39356Smckusick dounmount(mp, flags) 221*39356Smckusick register struct mount *mp; 222*39356Smckusick int flags; 223*39356Smckusick { 224*39356Smckusick struct vnode *coveredvp; 225*39356Smckusick int error; 226*39356Smckusick 22737741Smckusick coveredvp = mp->m_vnodecovered; 22837741Smckusick if (error = vfs_lock(mp)) 229*39356Smckusick return (error); 23037741Smckusick 23137741Smckusick xumount(mp); /* remove unused sticky files from text table */ 23237741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23337741Smckusick VFS_SYNC(mp, MNT_WAIT); 23437741Smckusick 235*39356Smckusick error = VFS_UNMOUNT(mp, flags); 23637741Smckusick if (error) { 23737741Smckusick vfs_unlock(mp); 23837741Smckusick } else { 23937741Smckusick vrele(coveredvp); 24037741Smckusick vfs_remove(mp); 24137741Smckusick free((caddr_t)mp, M_MOUNT); 24237741Smckusick } 243*39356Smckusick return (error); 2446254Sroot } 2456254Sroot 2469167Ssam /* 24737741Smckusick * Sync system call. 24837741Smckusick * Sync each mounted filesystem. 2499167Ssam */ 25038408Smckusick sync(scp) 25138408Smckusick register struct syscontext *scp; 2526254Sroot { 25337741Smckusick register struct mount *mp; 25437741Smckusick 25537741Smckusick mp = rootfs; 25637741Smckusick do { 25737741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 25837741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 25937741Smckusick mp = mp->m_next; 26037741Smckusick } while (mp != rootfs); 26137741Smckusick } 26237741Smckusick 26337741Smckusick /* 26437741Smckusick * get filesystem statistics 26537741Smckusick */ 26638408Smckusick statfs(scp) 26738408Smckusick register struct syscontext *scp; 26837741Smckusick { 2696254Sroot struct a { 27037741Smckusick char *path; 27137741Smckusick struct statfs *buf; 27238408Smckusick } *uap = (struct a *)scp->sc_ap; 27337741Smckusick register struct vnode *vp; 27438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 27537741Smckusick struct statfs sb; 27637741Smckusick int error; 27737741Smckusick 27837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 27937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 28037741Smckusick ndp->ni_dirp = uap->path; 28137741Smckusick if (error = namei(ndp)) 28237741Smckusick RETURN (error); 28337741Smckusick vp = ndp->ni_vp; 28437741Smckusick if (error = VFS_STATFS(vp->v_mount, &sb)) 28537741Smckusick goto out; 28637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 28737741Smckusick out: 28837741Smckusick vput(vp); 28937741Smckusick RETURN (error); 29037741Smckusick } 29137741Smckusick 29238408Smckusick fstatfs(scp) 29338408Smckusick register struct syscontext *scp; 29437741Smckusick { 29537741Smckusick struct a { 29637741Smckusick int fd; 29737741Smckusick struct statfs *buf; 29838408Smckusick } *uap = (struct a *)scp->sc_ap; 29937741Smckusick struct file *fp; 30037741Smckusick struct statfs sb; 30137741Smckusick int error; 30237741Smckusick 30338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 30437741Smckusick RETURN (error); 30537741Smckusick if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 30637741Smckusick RETURN (error); 30737741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 30837741Smckusick } 30937741Smckusick 31037741Smckusick /* 31138270Smckusick * get statistics on all filesystems 31238270Smckusick */ 31338408Smckusick getfsstat(scp) 31438408Smckusick register struct syscontext *scp; 31538270Smckusick { 31638270Smckusick struct a { 31738270Smckusick struct statfs *buf; 31838270Smckusick long bufsize; 31938408Smckusick } *uap = (struct a *)scp->sc_ap; 32038270Smckusick register struct mount *mp; 32138270Smckusick register struct statfs *sfsp; 32238270Smckusick long count, maxcount, error; 32338270Smckusick 32438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 32538270Smckusick sfsp = uap->buf; 32638270Smckusick mp = rootfs; 32738270Smckusick count = 0; 32838270Smckusick do { 32938270Smckusick count++; 33039044Smckusick if (sfsp && count <= maxcount && 33139044Smckusick ((mp->m_flag & M_MLOCK) == 0)) { 33238270Smckusick if (error = VFS_STATFS(mp, sfsp)) 33338270Smckusick RETURN (error); 33438270Smckusick sfsp++; 33538270Smckusick } 33638270Smckusick mp = mp->m_prev; 33738270Smckusick } while (mp != rootfs); 33838270Smckusick if (sfsp && count > maxcount) 33938408Smckusick scp->sc_retval1 = maxcount; 34038270Smckusick else 34138408Smckusick scp->sc_retval1 = count; 34238270Smckusick RETURN (0); 34338270Smckusick } 34438270Smckusick 34538270Smckusick /* 34638259Smckusick * Change current working directory to a given file descriptor. 34738259Smckusick */ 34838408Smckusick fchdir(scp) 34938408Smckusick register struct syscontext *scp; 35038259Smckusick { 35138259Smckusick struct a { 35238259Smckusick int fd; 35338408Smckusick } *uap = (struct a *)scp->sc_ap; 35438259Smckusick register struct vnode *vp; 35538259Smckusick struct file *fp; 35638259Smckusick int error; 35738259Smckusick 35838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 35938259Smckusick RETURN (error); 36038259Smckusick vp = (struct vnode *)fp->f_data; 36138259Smckusick VOP_LOCK(vp); 36238259Smckusick if (vp->v_type != VDIR) 36338259Smckusick error = ENOTDIR; 36438259Smckusick else 36538408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 36638259Smckusick VOP_UNLOCK(vp); 36738408Smckusick vrele(scp->sc_cdir); 36838408Smckusick scp->sc_cdir = vp; 36938259Smckusick RETURN (error); 37038259Smckusick } 37138259Smckusick 37238259Smckusick /* 37337741Smckusick * Change current working directory (``.''). 37437741Smckusick */ 37538408Smckusick chdir(scp) 37638408Smckusick register struct syscontext *scp; 37737741Smckusick { 37837741Smckusick struct a { 3796254Sroot char *fname; 38038408Smckusick } *uap = (struct a *)scp->sc_ap; 38138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 38237741Smckusick int error; 3836254Sroot 38437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 38516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 38616694Smckusick ndp->ni_dirp = uap->fname; 38737741Smckusick if (error = chdirec(ndp)) 38837741Smckusick RETURN (error); 38938408Smckusick vrele(scp->sc_cdir); 39038408Smckusick scp->sc_cdir = ndp->ni_vp; 39137741Smckusick RETURN (0); 39237741Smckusick } 3936254Sroot 39437741Smckusick /* 39537741Smckusick * Change notion of root (``/'') directory. 39637741Smckusick */ 39738408Smckusick chroot(scp) 39838408Smckusick register struct syscontext *scp; 39937741Smckusick { 40037741Smckusick struct a { 40137741Smckusick char *fname; 40238408Smckusick } *uap = (struct a *)scp->sc_ap; 40338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 40437741Smckusick int error; 40537741Smckusick 40638408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 40737741Smckusick RETURN (error); 40837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 41037741Smckusick ndp->ni_dirp = uap->fname; 41137741Smckusick if (error = chdirec(ndp)) 41237741Smckusick RETURN (error); 41338408Smckusick vrele(scp->sc_rdir); 41438408Smckusick scp->sc_rdir = ndp->ni_vp; 41537741Smckusick RETURN (0); 4166254Sroot } 4176254Sroot 41837Sbill /* 41937741Smckusick * Common routine for chroot and chdir. 42037741Smckusick */ 42137741Smckusick chdirec(ndp) 42237741Smckusick register struct nameidata *ndp; 42337741Smckusick { 42437741Smckusick struct vnode *vp; 42537741Smckusick int error; 42637741Smckusick 42737741Smckusick if (error = namei(ndp)) 42837741Smckusick return (error); 42937741Smckusick vp = ndp->ni_vp; 43037741Smckusick if (vp->v_type != VDIR) 43137741Smckusick error = ENOTDIR; 43237741Smckusick else 43338399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 43437741Smckusick VOP_UNLOCK(vp); 43537741Smckusick if (error) 43637741Smckusick vrele(vp); 43737741Smckusick return (error); 43837741Smckusick } 43937741Smckusick 44037741Smckusick /* 4416254Sroot * Open system call. 4426254Sroot */ 44338408Smckusick open(scp) 44438408Smckusick register struct syscontext *scp; 4456254Sroot { 44612756Ssam struct a { 4476254Sroot char *fname; 4487701Ssam int mode; 44912756Ssam int crtmode; 45038408Smckusick } *uap = (struct a *) scp->sc_ap; 45138408Smckusick struct nameidata *ndp = &scp->sc_nd; 4526254Sroot 45337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 45437741Smckusick ndp->ni_dirp = uap->fname; 45538408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 45638408Smckusick &scp->sc_retval1)); 4576254Sroot } 4586254Sroot 4596254Sroot /* 4606254Sroot * Creat system call. 4616254Sroot */ 46238408Smckusick creat(scp) 46338408Smckusick register struct syscontext *scp; 4646254Sroot { 46512756Ssam struct a { 4666254Sroot char *fname; 4676254Sroot int fmode; 46838408Smckusick } *uap = (struct a *)scp->sc_ap; 46938408Smckusick struct nameidata *ndp = &scp->sc_nd; 4706254Sroot 47137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47237741Smckusick ndp->ni_dirp = uap->fname; 47338408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 47438408Smckusick ndp, &scp->sc_retval1)); 4756254Sroot } 4766254Sroot 4776254Sroot /* 4786254Sroot * Common code for open and creat. 47912756Ssam * Check permissions, allocate an open file structure, 48012756Ssam * and call the device open routine if any. 4816254Sroot */ 48238408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 48338408Smckusick register struct syscontext *scp; 48437741Smckusick int fmode, cmode; 48537741Smckusick struct nameidata *ndp; 48637741Smckusick int *resultfd; 48712756Ssam { 4886254Sroot register struct file *fp; 48937741Smckusick struct file *nfp; 49037741Smckusick int indx, error; 49137741Smckusick extern struct fileops vnops; 4926254Sroot 49337741Smckusick if (error = falloc(&nfp, &indx)) 49437741Smckusick return (error); 49537741Smckusick fp = nfp; 49638408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 49737741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 49838408Smckusick scp->sc_ofile[indx] = NULL; 49937741Smckusick crfree(fp->f_cred); 50037741Smckusick fp->f_count--; 50137741Smckusick return (error); 50212756Ssam } 50337741Smckusick fp->f_flag = fmode & FMASK; 50437741Smckusick fp->f_type = DTYPE_VNODE; 50537741Smckusick fp->f_ops = &vnops; 50637741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 50737741Smckusick if (resultfd) 50837741Smckusick *resultfd = indx; 50937741Smckusick return (0); 5106254Sroot } 5116254Sroot 5126254Sroot /* 5136254Sroot * Mknod system call 5146254Sroot */ 51538408Smckusick mknod(scp) 51638408Smckusick register struct syscontext *scp; 5176254Sroot { 5186254Sroot register struct a { 5196254Sroot char *fname; 5206254Sroot int fmode; 5216254Sroot int dev; 52238408Smckusick } *uap = (struct a *)scp->sc_ap; 52338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 52437741Smckusick register struct vnode *vp; 52537741Smckusick struct vattr vattr; 52637741Smckusick int error; 5276254Sroot 52838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 52937741Smckusick RETURN (error); 53037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 53116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 53216694Smckusick ndp->ni_dirp = uap->fname; 53337741Smckusick if (error = namei(ndp)) 53437741Smckusick RETURN (error); 53537741Smckusick vp = ndp->ni_vp; 53637741Smckusick if (vp != NULL) { 53737741Smckusick error = EEXIST; 53812756Ssam goto out; 5396254Sroot } 54037741Smckusick vattr_null(&vattr); 54137741Smckusick switch (uap->fmode & IFMT) { 54212756Ssam 54315093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 54437741Smckusick vattr.va_type = VBAD; 54537741Smckusick break; 54612756Ssam case IFCHR: 54737741Smckusick vattr.va_type = VCHR; 54837741Smckusick break; 54912756Ssam case IFBLK: 55037741Smckusick vattr.va_type = VBLK; 55137741Smckusick break; 55237741Smckusick default: 55337741Smckusick error = EINVAL; 55437741Smckusick goto out; 5556254Sroot } 55638408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 55737741Smckusick vattr.va_rdev = uap->dev; 5586254Sroot out: 55937741Smckusick if (error) 56037741Smckusick VOP_ABORTOP(ndp); 56137741Smckusick else 56237741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 56337741Smckusick RETURN (error); 5646254Sroot } 5656254Sroot 5666254Sroot /* 5676254Sroot * link system call 5686254Sroot */ 56938408Smckusick link(scp) 57038408Smckusick register struct syscontext *scp; 5716254Sroot { 5726254Sroot register struct a { 5736254Sroot char *target; 5746254Sroot char *linkname; 57538408Smckusick } *uap = (struct a *)scp->sc_ap; 57638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 57737741Smckusick register struct vnode *vp, *xp; 57837741Smckusick int error; 5796254Sroot 58016694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 58116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 58216694Smckusick ndp->ni_dirp = uap->target; 58337741Smckusick if (error = namei(ndp)) 58437741Smckusick RETURN (error); 58537741Smckusick vp = ndp->ni_vp; 58637741Smckusick if (vp->v_type == VDIR && 58738408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 58837741Smckusick goto out1; 58937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 59016694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 59137741Smckusick if (error = namei(ndp)) 59237741Smckusick goto out1; 59337741Smckusick xp = ndp->ni_vp; 5946254Sroot if (xp != NULL) { 59537741Smckusick error = EEXIST; 5966254Sroot goto out; 5976254Sroot } 59837741Smckusick xp = ndp->ni_dvp; 59937741Smckusick if (vp->v_mount != xp->v_mount) 60037741Smckusick error = EXDEV; 6016254Sroot out: 60237741Smckusick if (error) 60337741Smckusick VOP_ABORTOP(ndp); 60437741Smckusick else 60537741Smckusick error = VOP_LINK(vp, ndp); 60637741Smckusick out1: 60737741Smckusick vrele(vp); 60837741Smckusick RETURN (error); 6096254Sroot } 6106254Sroot 6116254Sroot /* 6126254Sroot * symlink -- make a symbolic link 6136254Sroot */ 61438408Smckusick symlink(scp) 61538408Smckusick register struct syscontext *scp; 6166254Sroot { 61737741Smckusick struct a { 6186254Sroot char *target; 6196254Sroot char *linkname; 62038408Smckusick } *uap = (struct a *)scp->sc_ap; 62138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 62237741Smckusick register struct vnode *vp; 62337741Smckusick struct vattr vattr; 62437741Smckusick char *target; 62537741Smckusick int error; 6266254Sroot 62716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62816694Smckusick ndp->ni_dirp = uap->linkname; 62937741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 63037741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 63137741Smckusick goto out1; 63237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 63337741Smckusick if (error = namei(ndp)) 63437741Smckusick goto out1; 63537741Smckusick vp = ndp->ni_vp; 63637741Smckusick if (vp) { 63737741Smckusick error = EEXIST; 63837741Smckusick goto out; 6396254Sroot } 64037741Smckusick vp = ndp->ni_dvp; 64137741Smckusick vattr_null(&vattr); 64238408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 64337741Smckusick out: 64437741Smckusick if (error) 64537741Smckusick VOP_ABORTOP(ndp); 64637741Smckusick else 64737741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 64837741Smckusick out1: 64937741Smckusick FREE(target, M_NAMEI); 65037741Smckusick RETURN (error); 6516254Sroot } 6526254Sroot 6536254Sroot /* 6546254Sroot * Unlink system call. 6556254Sroot * Hard to avoid races here, especially 6566254Sroot * in unlinking directories. 6576254Sroot */ 65838408Smckusick unlink(scp) 65938408Smckusick register struct syscontext *scp; 6606254Sroot { 6616254Sroot struct a { 6626254Sroot char *fname; 66338408Smckusick } *uap = (struct a *)scp->sc_ap; 66438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 66537741Smckusick register struct vnode *vp; 66637741Smckusick int error; 6676254Sroot 66837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 66916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 67016694Smckusick ndp->ni_dirp = uap->fname; 67137741Smckusick if (error = namei(ndp)) 67237741Smckusick RETURN (error); 67337741Smckusick vp = ndp->ni_vp; 67437741Smckusick if (vp->v_type == VDIR && 67538408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 6766254Sroot goto out; 6776254Sroot /* 6786254Sroot * Don't unlink a mounted file. 6796254Sroot */ 68037741Smckusick if (vp->v_flag & VROOT) { 68137741Smckusick error = EBUSY; 6826254Sroot goto out; 6836254Sroot } 68437741Smckusick if (vp->v_flag & VTEXT) 68537741Smckusick xrele(vp); /* try once to free text */ 6866254Sroot out: 68737741Smckusick if (error) 68837741Smckusick VOP_ABORTOP(ndp); 6897142Smckusick else 69037741Smckusick error = VOP_REMOVE(ndp); 69137741Smckusick RETURN (error); 6926254Sroot } 6936254Sroot 6946254Sroot /* 6956254Sroot * Seek system call 6966254Sroot */ 69738408Smckusick lseek(scp) 69838408Smckusick register struct syscontext *scp; 6996254Sroot { 7006254Sroot register struct file *fp; 7016254Sroot register struct a { 70237741Smckusick int fdes; 7036254Sroot off_t off; 7046254Sroot int sbase; 70538408Smckusick } *uap = (struct a *)scp->sc_ap; 70637741Smckusick struct vattr vattr; 70737741Smckusick int error; 7086254Sroot 70937741Smckusick if ((unsigned)uap->fdes >= NOFILE || 71038408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 71137741Smckusick RETURN (EBADF); 71237741Smckusick if (fp->f_type != DTYPE_VNODE) 71337741Smckusick RETURN (ESPIPE); 71413878Ssam switch (uap->sbase) { 71513878Ssam 71613878Ssam case L_INCR: 71713878Ssam fp->f_offset += uap->off; 71813878Ssam break; 71913878Ssam 72013878Ssam case L_XTND: 72137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 72238408Smckusick &vattr, scp->sc_cred)) 72337741Smckusick RETURN (error); 72437741Smckusick fp->f_offset = uap->off + vattr.va_size; 72513878Ssam break; 72613878Ssam 72713878Ssam case L_SET: 72813878Ssam fp->f_offset = uap->off; 72913878Ssam break; 73013878Ssam 73113878Ssam default: 73237741Smckusick RETURN (EINVAL); 73313878Ssam } 73438408Smckusick scp->sc_offset = fp->f_offset; 73537741Smckusick RETURN (0); 7366254Sroot } 7376254Sroot 7386254Sroot /* 7396254Sroot * Access system call 7406254Sroot */ 74138408Smckusick saccess(scp) 74238408Smckusick register struct syscontext *scp; 7436254Sroot { 7446254Sroot register struct a { 7456254Sroot char *fname; 7466254Sroot int fmode; 74738408Smckusick } *uap = (struct a *)scp->sc_ap; 74838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 74937741Smckusick register struct vnode *vp; 75037741Smckusick int error, mode, svuid, svgid; 7516254Sroot 75238408Smckusick svuid = scp->sc_uid; 75338408Smckusick svgid = scp->sc_gid; 75438408Smckusick scp->sc_uid = scp->sc_ruid; 75538408Smckusick scp->sc_gid = scp->sc_rgid; 75637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 75716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 75816694Smckusick ndp->ni_dirp = uap->fname; 75937741Smckusick if (error = namei(ndp)) 76037741Smckusick goto out1; 76137741Smckusick vp = ndp->ni_vp; 76237741Smckusick /* 76337741Smckusick * fmode == 0 means only check for exist 76437741Smckusick */ 76537741Smckusick if (uap->fmode) { 76637741Smckusick mode = 0; 76737741Smckusick if (uap->fmode & R_OK) 76837741Smckusick mode |= VREAD; 76937741Smckusick if (uap->fmode & W_OK) 77037741Smckusick mode |= VWRITE; 77137741Smckusick if (uap->fmode & X_OK) 77237741Smckusick mode |= VEXEC; 77338399Smckusick if ((error = vn_writechk(vp)) == 0) 77438399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 7756254Sroot } 77637741Smckusick vput(vp); 77737741Smckusick out1: 77838408Smckusick scp->sc_uid = svuid; 77938408Smckusick scp->sc_gid = svgid; 78037741Smckusick RETURN (error); 7816254Sroot } 7826254Sroot 7836254Sroot /* 7846574Smckusic * Stat system call. This version follows links. 78537Sbill */ 78638408Smckusick stat(scp) 78738408Smckusick struct syscontext *scp; 78837Sbill { 78937Sbill 79038408Smckusick stat1(scp, FOLLOW); 79137Sbill } 79237Sbill 79337Sbill /* 7946574Smckusic * Lstat system call. This version does not follow links. 7955992Swnj */ 79638408Smckusick lstat(scp) 79738408Smckusick struct syscontext *scp; 7985992Swnj { 79912756Ssam 80038408Smckusick stat1(scp, NOFOLLOW); 80112756Ssam } 80212756Ssam 80338408Smckusick stat1(scp, follow) 80438408Smckusick register struct syscontext *scp; 80512756Ssam int follow; 80612756Ssam { 8075992Swnj register struct a { 8085992Swnj char *fname; 80912756Ssam struct stat *ub; 81038408Smckusick } *uap = (struct a *)scp->sc_ap; 81138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 81212756Ssam struct stat sb; 81337741Smckusick int error; 8145992Swnj 81537741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 81616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81716694Smckusick ndp->ni_dirp = uap->fname; 81837741Smckusick if (error = namei(ndp)) 81937741Smckusick RETURN (error); 82037741Smckusick error = vn_stat(ndp->ni_vp, &sb); 82137741Smckusick vput(ndp->ni_vp); 82237741Smckusick if (error) 82337741Smckusick RETURN (error); 82437741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 82537741Smckusick RETURN (error); 8265992Swnj } 8275992Swnj 8285992Swnj /* 8295992Swnj * Return target name of a symbolic link 83037Sbill */ 83138408Smckusick readlink(scp) 83238408Smckusick register struct syscontext *scp; 8335992Swnj { 8345992Swnj register struct a { 8355992Swnj char *name; 8365992Swnj char *buf; 8375992Swnj int count; 83838408Smckusick } *uap = (struct a *)scp->sc_ap; 83938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 84037741Smckusick register struct vnode *vp; 84137741Smckusick struct iovec aiov; 84237741Smckusick struct uio auio; 84337741Smckusick int error; 8445992Swnj 84537741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 84616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 84716694Smckusick ndp->ni_dirp = uap->name; 84837741Smckusick if (error = namei(ndp)) 84937741Smckusick RETURN (error); 85037741Smckusick vp = ndp->ni_vp; 85137741Smckusick if (vp->v_type != VLNK) { 85237741Smckusick error = EINVAL; 8535992Swnj goto out; 8545992Swnj } 85537741Smckusick aiov.iov_base = uap->buf; 85637741Smckusick aiov.iov_len = uap->count; 85737741Smckusick auio.uio_iov = &aiov; 85837741Smckusick auio.uio_iovcnt = 1; 85937741Smckusick auio.uio_offset = 0; 86037741Smckusick auio.uio_rw = UIO_READ; 86137741Smckusick auio.uio_segflg = UIO_USERSPACE; 86237741Smckusick auio.uio_resid = uap->count; 86337741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 8645992Swnj out: 86537741Smckusick vput(vp); 86638408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 86737741Smckusick RETURN (error); 8685992Swnj } 8695992Swnj 8709167Ssam /* 87138259Smckusick * Change flags of a file given path name. 87238259Smckusick */ 87338408Smckusick chflags(scp) 87438408Smckusick register struct syscontext *scp; 87538259Smckusick { 87638259Smckusick struct a { 87738259Smckusick char *fname; 87838259Smckusick int flags; 87938408Smckusick } *uap = (struct a *)scp->sc_ap; 88038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 88138259Smckusick register struct vnode *vp; 88238259Smckusick struct vattr vattr; 88338259Smckusick int error; 88438259Smckusick 88538259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 88638259Smckusick ndp->ni_segflg = UIO_USERSPACE; 88738259Smckusick ndp->ni_dirp = uap->fname; 88838259Smckusick vattr_null(&vattr); 88938259Smckusick vattr.va_flags = uap->flags; 89038259Smckusick if (error = namei(ndp)) 89138259Smckusick RETURN (error); 89238259Smckusick vp = ndp->ni_vp; 89338259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 89438259Smckusick error = EROFS; 89538259Smckusick goto out; 89638259Smckusick } 89738259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 89838259Smckusick out: 89938259Smckusick vput(vp); 90038259Smckusick RETURN (error); 90138259Smckusick } 90238259Smckusick 90338259Smckusick /* 90438259Smckusick * Change flags of a file given a file descriptor. 90538259Smckusick */ 90638408Smckusick fchflags(scp) 90738408Smckusick register struct syscontext *scp; 90838259Smckusick { 90938259Smckusick struct a { 91038259Smckusick int fd; 91138259Smckusick int flags; 91238408Smckusick } *uap = (struct a *)scp->sc_ap; 91338259Smckusick struct vattr vattr; 91438259Smckusick struct vnode *vp; 91538259Smckusick struct file *fp; 91638259Smckusick int error; 91738259Smckusick 91838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 91938259Smckusick RETURN (error); 92038259Smckusick vattr_null(&vattr); 92138259Smckusick vattr.va_flags = uap->flags; 92238259Smckusick vp = (struct vnode *)fp->f_data; 92338259Smckusick VOP_LOCK(vp); 92438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 92538259Smckusick error = EROFS; 92638259Smckusick goto out; 92738259Smckusick } 92838259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 92938259Smckusick out: 93038259Smckusick VOP_UNLOCK(vp); 93138259Smckusick RETURN (error); 93238259Smckusick } 93338259Smckusick 93438259Smckusick /* 9359167Ssam * Change mode of a file given path name. 9369167Ssam */ 93738408Smckusick chmod(scp) 93838408Smckusick register struct syscontext *scp; 9395992Swnj { 9407701Ssam struct a { 9416254Sroot char *fname; 9426254Sroot int fmode; 94338408Smckusick } *uap = (struct a *)scp->sc_ap; 94438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 94537741Smckusick register struct vnode *vp; 94637741Smckusick struct vattr vattr; 94737741Smckusick int error; 9485992Swnj 94937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 95137741Smckusick ndp->ni_dirp = uap->fname; 95237741Smckusick vattr_null(&vattr); 95337741Smckusick vattr.va_mode = uap->fmode & 07777; 95437741Smckusick if (error = namei(ndp)) 95537741Smckusick RETURN (error); 95637741Smckusick vp = ndp->ni_vp; 95737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 95837741Smckusick error = EROFS; 95937741Smckusick goto out; 96037741Smckusick } 96137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 96237741Smckusick out: 96337741Smckusick vput(vp); 96437741Smckusick RETURN (error); 9657701Ssam } 9667439Sroot 9679167Ssam /* 9689167Ssam * Change mode of a file given a file descriptor. 9699167Ssam */ 97038408Smckusick fchmod(scp) 97138408Smckusick register struct syscontext *scp; 9727701Ssam { 9737701Ssam struct a { 9747701Ssam int fd; 9757701Ssam int fmode; 97638408Smckusick } *uap = (struct a *)scp->sc_ap; 97737741Smckusick struct vattr vattr; 97837741Smckusick struct vnode *vp; 97937741Smckusick struct file *fp; 98037741Smckusick int error; 9817701Ssam 98238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 98337741Smckusick RETURN (error); 98437741Smckusick vattr_null(&vattr); 98537741Smckusick vattr.va_mode = uap->fmode & 07777; 98637741Smckusick vp = (struct vnode *)fp->f_data; 98737741Smckusick VOP_LOCK(vp); 98837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98937741Smckusick error = EROFS; 99037741Smckusick goto out; 9917439Sroot } 99237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 99337741Smckusick out: 99437741Smckusick VOP_UNLOCK(vp); 99537741Smckusick RETURN (error); 9965992Swnj } 9975992Swnj 9989167Ssam /* 9999167Ssam * Set ownership given a path name. 10009167Ssam */ 100138408Smckusick chown(scp) 100238408Smckusick register struct syscontext *scp; 100337Sbill { 10047701Ssam struct a { 10056254Sroot char *fname; 10066254Sroot int uid; 10076254Sroot int gid; 100838408Smckusick } *uap = (struct a *)scp->sc_ap; 100938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 101037741Smckusick register struct vnode *vp; 101137741Smckusick struct vattr vattr; 101237741Smckusick int error; 101337Sbill 101437741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 101536614Sbostic ndp->ni_segflg = UIO_USERSPACE; 101636614Sbostic ndp->ni_dirp = uap->fname; 101737741Smckusick vattr_null(&vattr); 101837741Smckusick vattr.va_uid = uap->uid; 101937741Smckusick vattr.va_gid = uap->gid; 102037741Smckusick if (error = namei(ndp)) 102137741Smckusick RETURN (error); 102237741Smckusick vp = ndp->ni_vp; 102337741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 102437741Smckusick error = EROFS; 102537741Smckusick goto out; 102637741Smckusick } 102737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 102837741Smckusick out: 102937741Smckusick vput(vp); 103037741Smckusick RETURN (error); 10317701Ssam } 10327439Sroot 10339167Ssam /* 10349167Ssam * Set ownership given a file descriptor. 10359167Ssam */ 103638408Smckusick fchown(scp) 103738408Smckusick register struct syscontext *scp; 10387701Ssam { 10397701Ssam struct a { 10407701Ssam int fd; 10417701Ssam int uid; 10427701Ssam int gid; 104338408Smckusick } *uap = (struct a *)scp->sc_ap; 104437741Smckusick struct vattr vattr; 104537741Smckusick struct vnode *vp; 104637741Smckusick struct file *fp; 104737741Smckusick int error; 10487701Ssam 104938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 105037741Smckusick RETURN (error); 105137741Smckusick vattr_null(&vattr); 105237741Smckusick vattr.va_uid = uap->uid; 105337741Smckusick vattr.va_gid = uap->gid; 105437741Smckusick vp = (struct vnode *)fp->f_data; 105537741Smckusick VOP_LOCK(vp); 105637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 105737741Smckusick error = EROFS; 105837741Smckusick goto out; 105937741Smckusick } 106037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 106137741Smckusick out: 106237741Smckusick VOP_UNLOCK(vp); 106337741Smckusick RETURN (error); 10647701Ssam } 10657701Ssam 106638408Smckusick utimes(scp) 106738408Smckusick register struct syscontext *scp; 106811811Ssam { 106911811Ssam register struct a { 107011811Ssam char *fname; 107111811Ssam struct timeval *tptr; 107238408Smckusick } *uap = (struct a *)scp->sc_ap; 107338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 107437741Smckusick register struct vnode *vp; 107511811Ssam struct timeval tv[2]; 107637741Smckusick struct vattr vattr; 107737741Smckusick int error; 107811811Ssam 107937741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 108037741Smckusick RETURN (error); 108137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 108237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 108337741Smckusick ndp->ni_dirp = uap->fname; 108437741Smckusick vattr_null(&vattr); 108537741Smckusick vattr.va_atime = tv[0]; 108637741Smckusick vattr.va_mtime = tv[1]; 108737741Smckusick if (error = namei(ndp)) 108837741Smckusick RETURN (error); 108937741Smckusick vp = ndp->ni_vp; 109037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 109137741Smckusick error = EROFS; 109237741Smckusick goto out; 109321015Smckusick } 109437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 109537741Smckusick out: 109637741Smckusick vput(vp); 109737741Smckusick RETURN (error); 109811811Ssam } 109911811Ssam 11009167Ssam /* 11019167Ssam * Truncate a file given its path name. 11029167Ssam */ 110338408Smckusick truncate(scp) 110438408Smckusick register struct syscontext *scp; 11057701Ssam { 11067701Ssam struct a { 11077701Ssam char *fname; 110826473Skarels off_t length; 110938408Smckusick } *uap = (struct a *)scp->sc_ap; 111038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 111137741Smckusick register struct vnode *vp; 111237741Smckusick struct vattr vattr; 111337741Smckusick int error; 11147701Ssam 111537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 111616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 111716694Smckusick ndp->ni_dirp = uap->fname; 111837741Smckusick vattr_null(&vattr); 111937741Smckusick vattr.va_size = uap->length; 112037741Smckusick if (error = namei(ndp)) 112137741Smckusick RETURN (error); 112237741Smckusick vp = ndp->ni_vp; 112337741Smckusick if (vp->v_type == VDIR) { 112437741Smckusick error = EISDIR; 112537741Smckusick goto out; 11267701Ssam } 112738399Smckusick if ((error = vn_writechk(vp)) || 112838399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 112937741Smckusick goto out; 113037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 113137741Smckusick out: 113237741Smckusick vput(vp); 113337741Smckusick RETURN (error); 11347701Ssam } 11357701Ssam 11369167Ssam /* 11379167Ssam * Truncate a file given a file descriptor. 11389167Ssam */ 113938408Smckusick ftruncate(scp) 114038408Smckusick register struct syscontext *scp; 11417701Ssam { 11427701Ssam struct a { 11437701Ssam int fd; 114426473Skarels off_t length; 114538408Smckusick } *uap = (struct a *)scp->sc_ap; 114637741Smckusick struct vattr vattr; 114737741Smckusick struct vnode *vp; 11487701Ssam struct file *fp; 114937741Smckusick int error; 11507701Ssam 115138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 115237741Smckusick RETURN (error); 115337741Smckusick if ((fp->f_flag & FWRITE) == 0) 115437741Smckusick RETURN (EINVAL); 115537741Smckusick vattr_null(&vattr); 115637741Smckusick vattr.va_size = uap->length; 115737741Smckusick vp = (struct vnode *)fp->f_data; 115837741Smckusick VOP_LOCK(vp); 115937741Smckusick if (vp->v_type == VDIR) { 116037741Smckusick error = EISDIR; 116137741Smckusick goto out; 11627701Ssam } 116338399Smckusick if (error = vn_writechk(vp)) 116437741Smckusick goto out; 116537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 116637741Smckusick out: 116737741Smckusick VOP_UNLOCK(vp); 116837741Smckusick RETURN (error); 11697701Ssam } 11707701Ssam 11719167Ssam /* 11729167Ssam * Synch an open file. 11739167Ssam */ 117438408Smckusick fsync(scp) 117538408Smckusick register struct syscontext *scp; 11769167Ssam { 11779167Ssam struct a { 11789167Ssam int fd; 117938408Smckusick } *uap = (struct a *)scp->sc_ap; 11809167Ssam struct file *fp; 118137741Smckusick int error; 11829167Ssam 118338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 118437741Smckusick RETURN (error); 118537741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 118637741Smckusick RETURN (error); 11879167Ssam } 11889167Ssam 11899167Ssam /* 11909167Ssam * Rename system call. 11919167Ssam * 11929167Ssam * Source and destination must either both be directories, or both 11939167Ssam * not be directories. If target is a directory, it must be empty. 11949167Ssam */ 119538408Smckusick rename(scp) 119638408Smckusick register struct syscontext *scp; 11977701Ssam { 11987701Ssam struct a { 11997701Ssam char *from; 12007701Ssam char *to; 120138408Smckusick } *uap = (struct a *)scp->sc_ap; 120237741Smckusick register struct vnode *tvp, *fvp, *tdvp; 120338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 120437741Smckusick struct nameidata tond; 120537741Smckusick int error; 12067701Ssam 120737741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 120816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 120916694Smckusick ndp->ni_dirp = uap->from; 121037741Smckusick if (error = namei(ndp)) 121137741Smckusick RETURN (error); 121237741Smckusick fvp = ndp->ni_vp; 121338266Smckusick nddup(ndp, &tond); 121437741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 121537741Smckusick tond.ni_segflg = UIO_USERSPACE; 121637741Smckusick tond.ni_dirp = uap->to; 121737741Smckusick error = namei(&tond); 121837741Smckusick tdvp = tond.ni_dvp; 121937741Smckusick tvp = tond.ni_vp; 122037741Smckusick if (tvp != NULL) { 122137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 122239242Sbostic error = ENOTDIR; 122337741Smckusick goto out; 122437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 122539242Sbostic error = EISDIR; 122637741Smckusick goto out; 12279167Ssam } 12289167Ssam } 122937741Smckusick if (error) { 123037741Smckusick VOP_ABORTOP(ndp); 123137741Smckusick goto out1; 123237741Smckusick } 123337741Smckusick if (fvp->v_mount != tdvp->v_mount) { 123437741Smckusick error = EXDEV; 12359167Ssam goto out; 123610051Ssam } 123739286Smckusick if (fvp == tdvp) 123837741Smckusick error = EINVAL; 123939286Smckusick /* 124039286Smckusick * If source is the same as the destination, 124139286Smckusick * then there is nothing to do. 124239286Smckusick */ 124339286Smckusick if (fvp == tvp) 124439286Smckusick error = -1; 124537741Smckusick out: 124637741Smckusick if (error) { 124737741Smckusick VOP_ABORTOP(&tond); 124837741Smckusick VOP_ABORTOP(ndp); 12499167Ssam } else { 125037741Smckusick error = VOP_RENAME(ndp, &tond); 12519167Ssam } 125237741Smckusick out1: 125338266Smckusick ndrele(&tond); 125439286Smckusick if (error == -1) 125539286Smckusick RETURN (0); 125637741Smckusick RETURN (error); 12577701Ssam } 12587701Ssam 12597535Sroot /* 126012756Ssam * Mkdir system call 126112756Ssam */ 126238408Smckusick mkdir(scp) 126338408Smckusick register struct syscontext *scp; 126412756Ssam { 126512756Ssam struct a { 126612756Ssam char *name; 126712756Ssam int dmode; 126838408Smckusick } *uap = (struct a *)scp->sc_ap; 126938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 127037741Smckusick register struct vnode *vp; 127137741Smckusick struct vattr vattr; 127237741Smckusick int error; 127312756Ssam 127437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 127516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 127616694Smckusick ndp->ni_dirp = uap->name; 127737741Smckusick if (error = namei(ndp)) 127837741Smckusick RETURN (error); 127937741Smckusick vp = ndp->ni_vp; 128037741Smckusick if (vp != NULL) { 128137741Smckusick VOP_ABORTOP(ndp); 128237741Smckusick RETURN (EEXIST); 128312756Ssam } 128437741Smckusick vattr_null(&vattr); 128537741Smckusick vattr.va_type = VDIR; 128638408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 128737741Smckusick error = VOP_MKDIR(ndp, &vattr); 128838145Smckusick if (!error) 128938145Smckusick vput(ndp->ni_vp); 129037741Smckusick RETURN (error); 129112756Ssam } 129212756Ssam 129312756Ssam /* 129412756Ssam * Rmdir system call. 129512756Ssam */ 129638408Smckusick rmdir(scp) 129738408Smckusick register struct syscontext *scp; 129812756Ssam { 129912756Ssam struct a { 130012756Ssam char *name; 130138408Smckusick } *uap = (struct a *)scp->sc_ap; 130238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 130337741Smckusick register struct vnode *vp; 130437741Smckusick int error; 130512756Ssam 130637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 130716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130816694Smckusick ndp->ni_dirp = uap->name; 130937741Smckusick if (error = namei(ndp)) 131037741Smckusick RETURN (error); 131137741Smckusick vp = ndp->ni_vp; 131237741Smckusick if (vp->v_type != VDIR) { 131337741Smckusick error = ENOTDIR; 131412756Ssam goto out; 131512756Ssam } 131612756Ssam /* 131737741Smckusick * No rmdir "." please. 131812756Ssam */ 131937741Smckusick if (ndp->ni_dvp == vp) { 132037741Smckusick error = EINVAL; 132112756Ssam goto out; 132212756Ssam } 132312756Ssam /* 132437741Smckusick * Don't unlink a mounted file. 132512756Ssam */ 132637741Smckusick if (vp->v_flag & VROOT) 132737741Smckusick error = EBUSY; 132812756Ssam out: 132937741Smckusick if (error) 133037741Smckusick VOP_ABORTOP(ndp); 133137741Smckusick else 133237741Smckusick error = VOP_RMDIR(ndp); 133337741Smckusick RETURN (error); 133412756Ssam } 133512756Ssam 133637741Smckusick /* 133737741Smckusick * Read a block of directory entries in a file system independent format 133837741Smckusick */ 133938408Smckusick getdirentries(scp) 134038408Smckusick register struct syscontext *scp; 134112756Ssam { 134237741Smckusick register struct a { 134337741Smckusick int fd; 134437741Smckusick char *buf; 134537741Smckusick unsigned count; 134637741Smckusick long *basep; 134738408Smckusick } *uap = (struct a *)scp->sc_ap; 134816540Ssam struct file *fp; 134937741Smckusick struct uio auio; 135037741Smckusick struct iovec aiov; 135138129Smckusick off_t off; 135237741Smckusick int error; 135312756Ssam 135438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 135537741Smckusick RETURN (error); 135637741Smckusick if ((fp->f_flag & FREAD) == 0) 135737741Smckusick RETURN (EBADF); 135837741Smckusick aiov.iov_base = uap->buf; 135937741Smckusick aiov.iov_len = uap->count; 136037741Smckusick auio.uio_iov = &aiov; 136137741Smckusick auio.uio_iovcnt = 1; 136237741Smckusick auio.uio_rw = UIO_READ; 136337741Smckusick auio.uio_segflg = UIO_USERSPACE; 136437741Smckusick auio.uio_resid = uap->count; 136538129Smckusick off = fp->f_offset; 136637741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 136737741Smckusick &(fp->f_offset), fp->f_cred)) 136837741Smckusick RETURN (error); 136938129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 137037741Smckusick sizeof(long)); 137138408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 137237741Smckusick RETURN (error); 137312756Ssam } 137412756Ssam 137512756Ssam /* 137612756Ssam * mode mask for creation of files 137712756Ssam */ 137838408Smckusick umask(scp) 137938408Smckusick register struct syscontext *scp; 138012756Ssam { 138112756Ssam register struct a { 138212756Ssam int mask; 138338408Smckusick } *uap = (struct a *)scp->sc_ap; 138412756Ssam 138538408Smckusick scp->sc_retval1 = scp->sc_cmask; 138638408Smckusick scp->sc_cmask = uap->mask & 07777; 138737741Smckusick RETURN (0); 138812756Ssam } 138937741Smckusick 139038408Smckusick getvnode(ofile, fdes, fpp) 139138408Smckusick struct file *ofile[]; 139237741Smckusick struct file **fpp; 139337741Smckusick int fdes; 139437741Smckusick { 139537741Smckusick struct file *fp; 139637741Smckusick 139738408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 139837741Smckusick return (EBADF); 139937741Smckusick if (fp->f_type != DTYPE_VNODE) 140037741Smckusick return (EINVAL); 140137741Smckusick *fpp = fp; 140237741Smckusick return (0); 140337741Smckusick } 1404