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*41676Smckusick * @(#)vfs_syscalls.c 7.47 (Berkeley) 05/11/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "mount.h" 2817101Sbloom #include "proc.h" 2917101Sbloom #include "uio.h" 3037741Smckusick #include "malloc.h" 3137Sbill 3239797Smckusick #undef RETURN 3339797Smckusick #define RETURN(val) { scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; } 3439797Smckusick 3537741Smckusick /* 3637741Smckusick * Virtual File System System Calls 3737741Smckusick */ 3812756Ssam 399167Ssam /* 4037741Smckusick * mount system call 419167Ssam */ 4238408Smckusick mount(scp) 4338408Smckusick register struct syscontext *scp; 446254Sroot { 4537741Smckusick register struct a { 4637741Smckusick int type; 4737741Smckusick char *dir; 4837741Smckusick int flags; 4937741Smckusick caddr_t data; 5038408Smckusick } *uap = (struct a *)scp->sc_ap; 5138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5239335Smckusick register struct vnode *vp; 5339335Smckusick register struct mount *mp; 5440111Smckusick int error, flag; 556254Sroot 5637741Smckusick /* 5737741Smckusick * Must be super user 5837741Smckusick */ 5938408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 6037741Smckusick RETURN (error); 6137741Smckusick /* 6237741Smckusick * Get vnode to be covered 6337741Smckusick */ 6437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6637741Smckusick ndp->ni_dirp = uap->dir; 6737741Smckusick if (error = namei(ndp)) 6837741Smckusick RETURN (error); 6937741Smckusick vp = ndp->ni_vp; 7041400Smckusick if (uap->flags & MNT_UPDATE) { 7139335Smckusick if ((vp->v_flag & VROOT) == 0) { 7239335Smckusick vput(vp); 7339335Smckusick RETURN (EINVAL); 7439335Smckusick } 7539335Smckusick mp = vp->v_mount; 7639335Smckusick /* 7739335Smckusick * We allow going from read-only to read-write, 7839335Smckusick * but not from read-write to read-only. 7939335Smckusick */ 8041400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 8141400Smckusick (uap->flags & MNT_RDONLY) != 0) { 8239335Smckusick vput(vp); 8339335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8439335Smckusick } 8541400Smckusick flag = mp->mnt_flag; 8641400Smckusick mp->mnt_flag |= MNT_UPDATE; 8739335Smckusick VOP_UNLOCK(vp); 8839335Smckusick goto update; 8939335Smckusick } 9039665Smckusick vinvalbuf(vp, 1); 9139805Smckusick if (vp->v_usecount != 1) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (EBUSY); 9437741Smckusick } 9537741Smckusick if (vp->v_type != VDIR) { 9637741Smckusick vput(vp); 9737741Smckusick RETURN (ENOTDIR); 9837741Smckusick } 9939741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10037741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10137741Smckusick vput(vp); 10237741Smckusick RETURN (ENODEV); 10337741Smckusick } 10437741Smckusick 10537741Smckusick /* 10639335Smckusick * Allocate and initialize the file system. 10737741Smckusick */ 10837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10937741Smckusick M_MOUNT, M_WAITOK); 11041400Smckusick mp->mnt_op = vfssw[uap->type]; 11141400Smckusick mp->mnt_flag = 0; 11241400Smckusick mp->mnt_exroot = 0; 11341400Smckusick mp->mnt_mounth = NULLVP; 11439335Smckusick if (error = vfs_lock(mp)) { 11539335Smckusick free((caddr_t)mp, M_MOUNT); 11639335Smckusick vput(vp); 11739335Smckusick RETURN (error); 11839335Smckusick } 11939335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12039335Smckusick vfs_unlock(mp); 12139335Smckusick free((caddr_t)mp, M_MOUNT); 12239335Smckusick vput(vp); 12339335Smckusick RETURN (EBUSY); 12439335Smckusick } 12539335Smckusick vp->v_mountedhere = mp; 12641400Smckusick mp->mnt_vnodecovered = vp; 12739335Smckusick update: 12839335Smckusick /* 12939335Smckusick * Set the mount level flags. 13039335Smckusick */ 13141400Smckusick if (uap->flags & MNT_RDONLY) 13241400Smckusick mp->mnt_flag |= MNT_RDONLY; 13339335Smckusick else 13441400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13541400Smckusick if (uap->flags & MNT_NOSUID) 13641400Smckusick mp->mnt_flag |= MNT_NOSUID; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 13941400Smckusick if (uap->flags & MNT_NOEXEC) 14041400Smckusick mp->mnt_flag |= MNT_NOEXEC; 14139335Smckusick else 14241400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 14341400Smckusick if (uap->flags & MNT_NODEV) 14441400Smckusick mp->mnt_flag |= MNT_NODEV; 14539335Smckusick else 14641400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14741400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 14841400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 14939335Smckusick else 15041400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 15139335Smckusick /* 15239335Smckusick * Mount the filesystem. 15339335Smckusick */ 15439335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15541400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15641400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15739335Smckusick vrele(vp); 15840111Smckusick if (error) 15941400Smckusick mp->mnt_flag = flag; 16039335Smckusick RETURN (error); 16139335Smckusick } 16240110Smckusick /* 16340110Smckusick * Put the new filesystem on the mount list after root. 16440110Smckusick */ 16541400Smckusick mp->mnt_next = rootfs->mnt_next; 16641400Smckusick mp->mnt_prev = rootfs; 16741400Smckusick rootfs->mnt_next = mp; 16841400Smckusick mp->mnt_next->mnt_prev = mp; 16937741Smckusick cache_purge(vp); 17037741Smckusick if (!error) { 17139335Smckusick VOP_UNLOCK(vp); 17237741Smckusick vfs_unlock(mp); 17339044Smckusick error = VFS_START(mp, 0); 17437741Smckusick } else { 17537741Smckusick vfs_remove(mp); 17637741Smckusick free((caddr_t)mp, M_MOUNT); 17739335Smckusick vput(vp); 17837741Smckusick } 17937741Smckusick RETURN (error); 1806254Sroot } 1816254Sroot 1829167Ssam /* 18337741Smckusick * Unmount system call. 18437741Smckusick * 18537741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18637741Smckusick * not special file (as before). 1879167Ssam */ 18838408Smckusick unmount(scp) 18938408Smckusick register struct syscontext *scp; 1906254Sroot { 19137741Smckusick struct a { 19237741Smckusick char *pathp; 19337741Smckusick int flags; 19438408Smckusick } *uap = (struct a *)scp->sc_ap; 19537741Smckusick register struct vnode *vp; 19638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19739356Smckusick struct mount *mp; 19837741Smckusick int error; 1996254Sroot 20037741Smckusick /* 20137741Smckusick * Must be super user 20237741Smckusick */ 20338408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 20437741Smckusick RETURN (error); 20537741Smckusick 20637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20837741Smckusick ndp->ni_dirp = uap->pathp; 20937741Smckusick if (error = namei(ndp)) 21037741Smckusick RETURN (error); 21137741Smckusick vp = ndp->ni_vp; 21237741Smckusick /* 21337741Smckusick * Must be the root of the filesystem 21437741Smckusick */ 21537741Smckusick if ((vp->v_flag & VROOT) == 0) { 21637741Smckusick vput(vp); 21737741Smckusick RETURN (EINVAL); 21837741Smckusick } 21937741Smckusick mp = vp->v_mount; 22037741Smckusick vput(vp); 22139356Smckusick RETURN (dounmount(mp, uap->flags)); 22239356Smckusick } 22339356Smckusick 22439356Smckusick /* 22539356Smckusick * Do an unmount. 22639356Smckusick */ 22739356Smckusick dounmount(mp, flags) 22839356Smckusick register struct mount *mp; 22939356Smckusick int flags; 23039356Smckusick { 23139356Smckusick struct vnode *coveredvp; 23239356Smckusick int error; 23339356Smckusick 23441400Smckusick coveredvp = mp->mnt_vnodecovered; 23541298Smckusick if (vfs_busy(mp)) 23641298Smckusick return (EBUSY); 23741400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23837741Smckusick if (error = vfs_lock(mp)) 23939356Smckusick return (error); 24037741Smckusick 24137741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24237741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 243*41676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 244*41676Smckusick error = VFS_UNMOUNT(mp, flags); 24541400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24641298Smckusick vfs_unbusy(mp); 24737741Smckusick if (error) { 24837741Smckusick vfs_unlock(mp); 24937741Smckusick } else { 25037741Smckusick vrele(coveredvp); 25137741Smckusick vfs_remove(mp); 25237741Smckusick free((caddr_t)mp, M_MOUNT); 25337741Smckusick } 25439356Smckusick return (error); 2556254Sroot } 2566254Sroot 2579167Ssam /* 25837741Smckusick * Sync system call. 25937741Smckusick * Sync each mounted filesystem. 2609167Ssam */ 26139491Smckusick /* ARGSUSED */ 26238408Smckusick sync(scp) 26339491Smckusick struct syscontext *scp; 2646254Sroot { 26537741Smckusick register struct mount *mp; 26641298Smckusick struct mount *omp; 26737741Smckusick 26837741Smckusick mp = rootfs; 26937741Smckusick do { 27040343Smckusick /* 27140343Smckusick * The lock check below is to avoid races with mount 27240343Smckusick * and unmount. 27340343Smckusick */ 27441400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27541298Smckusick !vfs_busy(mp)) { 27637741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27741298Smckusick omp = mp; 27841400Smckusick mp = mp->mnt_next; 27941298Smckusick vfs_unbusy(omp); 28041298Smckusick } else 28141400Smckusick mp = mp->mnt_next; 28237741Smckusick } while (mp != rootfs); 28337741Smckusick } 28437741Smckusick 28537741Smckusick /* 28641298Smckusick * operate on filesystem quotas 28741298Smckusick */ 28841298Smckusick quotactl(scp) 28941298Smckusick register struct syscontext *scp; 29041298Smckusick { 29141298Smckusick struct a { 29241298Smckusick char *path; 29341298Smckusick int cmd; 29441298Smckusick int uid; 29541298Smckusick caddr_t arg; 29641298Smckusick } *uap = (struct a *)scp->sc_ap; 29741298Smckusick register struct mount *mp; 29841298Smckusick register struct nameidata *ndp = &scp->sc_nd; 29941298Smckusick int error; 30041298Smckusick 30141298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 30241298Smckusick ndp->ni_segflg = UIO_USERSPACE; 30341298Smckusick ndp->ni_dirp = uap->path; 30441298Smckusick if (error = namei(ndp)) 30541298Smckusick RETURN (error); 30641298Smckusick mp = ndp->ni_vp->v_mount; 30741298Smckusick vrele(ndp->ni_vp); 30841298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 30941298Smckusick } 31041298Smckusick 31141298Smckusick /* 31237741Smckusick * get filesystem statistics 31337741Smckusick */ 31438408Smckusick statfs(scp) 31538408Smckusick register struct syscontext *scp; 31637741Smckusick { 3176254Sroot struct a { 31837741Smckusick char *path; 31937741Smckusick struct statfs *buf; 32038408Smckusick } *uap = (struct a *)scp->sc_ap; 32139464Smckusick register struct mount *mp; 32238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 32340343Smckusick register struct statfs *sp; 32437741Smckusick int error; 32537741Smckusick 32639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 32737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 32837741Smckusick ndp->ni_dirp = uap->path; 32937741Smckusick if (error = namei(ndp)) 33037741Smckusick RETURN (error); 33139544Smckusick mp = ndp->ni_vp->v_mount; 33241400Smckusick sp = &mp->mnt_stat; 33339544Smckusick vrele(ndp->ni_vp); 33440343Smckusick if (error = VFS_STATFS(mp, sp)) 33539544Smckusick RETURN (error); 33641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33740343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33837741Smckusick } 33937741Smckusick 34038408Smckusick fstatfs(scp) 34138408Smckusick register struct syscontext *scp; 34237741Smckusick { 34337741Smckusick struct a { 34437741Smckusick int fd; 34537741Smckusick struct statfs *buf; 34638408Smckusick } *uap = (struct a *)scp->sc_ap; 34737741Smckusick struct file *fp; 34839464Smckusick struct mount *mp; 34940343Smckusick register struct statfs *sp; 35037741Smckusick int error; 35137741Smckusick 35238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 35337741Smckusick RETURN (error); 35439464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35541400Smckusick sp = &mp->mnt_stat; 35640343Smckusick if (error = VFS_STATFS(mp, sp)) 35737741Smckusick RETURN (error); 35841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 35940343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36037741Smckusick } 36137741Smckusick 36237741Smckusick /* 36338270Smckusick * get statistics on all filesystems 36438270Smckusick */ 36538408Smckusick getfsstat(scp) 36638408Smckusick register struct syscontext *scp; 36738270Smckusick { 36838270Smckusick struct a { 36938270Smckusick struct statfs *buf; 37038270Smckusick long bufsize; 37140343Smckusick int flags; 37238408Smckusick } *uap = (struct a *)scp->sc_ap; 37338270Smckusick register struct mount *mp; 37440343Smckusick register struct statfs *sp; 37539606Smckusick caddr_t sfsp; 37638270Smckusick long count, maxcount, error; 37738270Smckusick 37838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 37939606Smckusick sfsp = (caddr_t)uap->buf; 38038270Smckusick mp = rootfs; 38138270Smckusick count = 0; 38238270Smckusick do { 38341400Smckusick if (sfsp && count < maxcount && 38441400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 38541400Smckusick sp = &mp->mnt_stat; 38640343Smckusick /* 38740343Smckusick * If MNT_NOWAIT is specified, do not refresh the 38840343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 38940343Smckusick */ 39040343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39140343Smckusick (uap->flags & MNT_WAIT)) && 39240343Smckusick (error = VFS_STATFS(mp, sp))) { 39341400Smckusick mp = mp->mnt_prev; 39439607Smckusick continue; 39539607Smckusick } 39641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 39740343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 39839606Smckusick RETURN (error); 39940343Smckusick sfsp += sizeof(*sp); 40038270Smckusick } 40139606Smckusick count++; 40241400Smckusick mp = mp->mnt_prev; 40338270Smckusick } while (mp != rootfs); 40438270Smckusick if (sfsp && count > maxcount) 40538408Smckusick scp->sc_retval1 = maxcount; 40638270Smckusick else 40738408Smckusick scp->sc_retval1 = count; 40838270Smckusick RETURN (0); 40938270Smckusick } 41038270Smckusick 41138270Smckusick /* 41238259Smckusick * Change current working directory to a given file descriptor. 41338259Smckusick */ 41438408Smckusick fchdir(scp) 41538408Smckusick register struct syscontext *scp; 41638259Smckusick { 41738259Smckusick struct a { 41838259Smckusick int fd; 41938408Smckusick } *uap = (struct a *)scp->sc_ap; 42038259Smckusick register struct vnode *vp; 42138259Smckusick struct file *fp; 42238259Smckusick int error; 42338259Smckusick 42438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 42538259Smckusick RETURN (error); 42638259Smckusick vp = (struct vnode *)fp->f_data; 42738259Smckusick VOP_LOCK(vp); 42838259Smckusick if (vp->v_type != VDIR) 42938259Smckusick error = ENOTDIR; 43038259Smckusick else 43138408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 43238259Smckusick VOP_UNLOCK(vp); 43339860Smckusick if (error) 43439860Smckusick RETURN (error); 43539860Smckusick VREF(vp); 43638408Smckusick vrele(scp->sc_cdir); 43738408Smckusick scp->sc_cdir = vp; 43839860Smckusick RETURN (0); 43938259Smckusick } 44038259Smckusick 44138259Smckusick /* 44237741Smckusick * Change current working directory (``.''). 44337741Smckusick */ 44438408Smckusick chdir(scp) 44538408Smckusick register struct syscontext *scp; 44637741Smckusick { 44737741Smckusick struct a { 4486254Sroot char *fname; 44938408Smckusick } *uap = (struct a *)scp->sc_ap; 45038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 45137741Smckusick int error; 4526254Sroot 45337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 45416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 45516694Smckusick ndp->ni_dirp = uap->fname; 45637741Smckusick if (error = chdirec(ndp)) 45737741Smckusick RETURN (error); 45838408Smckusick vrele(scp->sc_cdir); 45938408Smckusick scp->sc_cdir = ndp->ni_vp; 46037741Smckusick RETURN (0); 46137741Smckusick } 4626254Sroot 46337741Smckusick /* 46437741Smckusick * Change notion of root (``/'') directory. 46537741Smckusick */ 46638408Smckusick chroot(scp) 46738408Smckusick register struct syscontext *scp; 46837741Smckusick { 46937741Smckusick struct a { 47037741Smckusick char *fname; 47138408Smckusick } *uap = (struct a *)scp->sc_ap; 47238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 47337741Smckusick int error; 47437741Smckusick 47538408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 47637741Smckusick RETURN (error); 47737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 47937741Smckusick ndp->ni_dirp = uap->fname; 48037741Smckusick if (error = chdirec(ndp)) 48137741Smckusick RETURN (error); 48239515Smckusick if (scp->sc_rdir != NULL) 48339515Smckusick vrele(scp->sc_rdir); 48438408Smckusick scp->sc_rdir = ndp->ni_vp; 48537741Smckusick RETURN (0); 4866254Sroot } 4876254Sroot 48837Sbill /* 48937741Smckusick * Common routine for chroot and chdir. 49037741Smckusick */ 49137741Smckusick chdirec(ndp) 49237741Smckusick register struct nameidata *ndp; 49337741Smckusick { 49437741Smckusick struct vnode *vp; 49537741Smckusick int error; 49637741Smckusick 49737741Smckusick if (error = namei(ndp)) 49837741Smckusick return (error); 49937741Smckusick vp = ndp->ni_vp; 50037741Smckusick if (vp->v_type != VDIR) 50137741Smckusick error = ENOTDIR; 50237741Smckusick else 50338399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 50437741Smckusick VOP_UNLOCK(vp); 50537741Smckusick if (error) 50637741Smckusick vrele(vp); 50737741Smckusick return (error); 50837741Smckusick } 50937741Smckusick 51037741Smckusick /* 5116254Sroot * Open system call. 5126254Sroot */ 51338408Smckusick open(scp) 51438408Smckusick register struct syscontext *scp; 5156254Sroot { 51612756Ssam struct a { 5176254Sroot char *fname; 5187701Ssam int mode; 51912756Ssam int crtmode; 52038408Smckusick } *uap = (struct a *) scp->sc_ap; 52138408Smckusick struct nameidata *ndp = &scp->sc_nd; 5226254Sroot 52337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 52437741Smckusick ndp->ni_dirp = uap->fname; 52538408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 52638408Smckusick &scp->sc_retval1)); 5276254Sroot } 5286254Sroot 5296254Sroot /* 5306254Sroot * Creat system call. 5316254Sroot */ 53238408Smckusick creat(scp) 53338408Smckusick register struct syscontext *scp; 5346254Sroot { 53512756Ssam struct a { 5366254Sroot char *fname; 5376254Sroot int fmode; 53838408Smckusick } *uap = (struct a *)scp->sc_ap; 53938408Smckusick struct nameidata *ndp = &scp->sc_nd; 5406254Sroot 54137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 54237741Smckusick ndp->ni_dirp = uap->fname; 54338408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 54438408Smckusick ndp, &scp->sc_retval1)); 5456254Sroot } 5466254Sroot 5476254Sroot /* 5486254Sroot * Common code for open and creat. 54912756Ssam * Check permissions, allocate an open file structure, 55012756Ssam * and call the device open routine if any. 5516254Sroot */ 55238408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 55338408Smckusick register struct syscontext *scp; 55437741Smckusick int fmode, cmode; 55537741Smckusick struct nameidata *ndp; 55637741Smckusick int *resultfd; 55712756Ssam { 5586254Sroot register struct file *fp; 55937741Smckusick struct file *nfp; 56037741Smckusick int indx, error; 56137741Smckusick extern struct fileops vnops; 5626254Sroot 56337741Smckusick if (error = falloc(&nfp, &indx)) 56437741Smckusick return (error); 56537741Smckusick fp = nfp; 56638408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 56740635Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ S_ISVTX)) { 56837741Smckusick crfree(fp->f_cred); 56937741Smckusick fp->f_count--; 57040884Smckusick if (error == EJUSTRETURN) /* XXX from fdopen */ 57140884Smckusick return (0); /* XXX from fdopen */ 57240884Smckusick if (error == ERESTART) 57340884Smckusick error = EINTR; 57439499Smckusick scp->sc_ofile[indx] = NULL; 57537741Smckusick return (error); 57612756Ssam } 57737741Smckusick fp->f_flag = fmode & FMASK; 57837741Smckusick fp->f_type = DTYPE_VNODE; 57937741Smckusick fp->f_ops = &vnops; 58037741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 58137741Smckusick if (resultfd) 58237741Smckusick *resultfd = indx; 58337741Smckusick return (0); 5846254Sroot } 5856254Sroot 5866254Sroot /* 5876254Sroot * Mknod system call 5886254Sroot */ 58938408Smckusick mknod(scp) 59038408Smckusick register struct syscontext *scp; 5916254Sroot { 5926254Sroot register struct a { 5936254Sroot char *fname; 5946254Sroot int fmode; 5956254Sroot int dev; 59638408Smckusick } *uap = (struct a *)scp->sc_ap; 59738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 59837741Smckusick register struct vnode *vp; 59937741Smckusick struct vattr vattr; 60037741Smckusick int error; 6016254Sroot 60238408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 60337741Smckusick RETURN (error); 60437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 60516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 60616694Smckusick ndp->ni_dirp = uap->fname; 60737741Smckusick if (error = namei(ndp)) 60837741Smckusick RETURN (error); 60937741Smckusick vp = ndp->ni_vp; 61037741Smckusick if (vp != NULL) { 61137741Smckusick error = EEXIST; 61212756Ssam goto out; 6136254Sroot } 61441362Smckusick VATTR_NULL(&vattr); 61540635Smckusick switch (uap->fmode & S_IFMT) { 61612756Ssam 61740635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 61837741Smckusick vattr.va_type = VBAD; 61937741Smckusick break; 62040635Smckusick case S_IFCHR: 62137741Smckusick vattr.va_type = VCHR; 62237741Smckusick break; 62340635Smckusick case S_IFBLK: 62437741Smckusick vattr.va_type = VBLK; 62537741Smckusick break; 62637741Smckusick default: 62737741Smckusick error = EINVAL; 62837741Smckusick goto out; 6296254Sroot } 63038408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 63137741Smckusick vattr.va_rdev = uap->dev; 6326254Sroot out: 63337741Smckusick if (error) 63437741Smckusick VOP_ABORTOP(ndp); 63537741Smckusick else 63637741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 63737741Smckusick RETURN (error); 6386254Sroot } 6396254Sroot 6406254Sroot /* 64140285Smckusick * Mkfifo system call 64240285Smckusick */ 64340285Smckusick mkfifo(scp) 64440285Smckusick register struct syscontext *scp; 64540285Smckusick { 64640285Smckusick register struct a { 64740285Smckusick char *fname; 64840285Smckusick int fmode; 64940285Smckusick } *uap = (struct a *)scp->sc_ap; 65040285Smckusick register struct nameidata *ndp = &scp->sc_nd; 65140285Smckusick struct vattr vattr; 65240285Smckusick int error; 65340285Smckusick 65440285Smckusick #ifndef FIFO 65540285Smckusick RETURN (EOPNOTSUPP); 65640285Smckusick #else 65740285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 65840285Smckusick ndp->ni_segflg = UIO_USERSPACE; 65940285Smckusick ndp->ni_dirp = uap->fname; 66040285Smckusick if (error = namei(ndp)) 66140285Smckusick RETURN (error); 66240285Smckusick if (ndp->ni_vp != NULL) { 66340285Smckusick VOP_ABORTOP(ndp); 66440285Smckusick RETURN (EEXIST); 66540285Smckusick } else { 66641362Smckusick VATTR_NULL(&vattr); 66740285Smckusick vattr.va_type = VFIFO; 66840285Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 66940285Smckusick } 67040285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 67140285Smckusick #endif /* FIFO */ 67240285Smckusick } 67340285Smckusick 67440285Smckusick /* 6756254Sroot * link system call 6766254Sroot */ 67738408Smckusick link(scp) 67838408Smckusick register struct syscontext *scp; 6796254Sroot { 6806254Sroot register struct a { 6816254Sroot char *target; 6826254Sroot char *linkname; 68338408Smckusick } *uap = (struct a *)scp->sc_ap; 68438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 68537741Smckusick register struct vnode *vp, *xp; 68637741Smckusick int error; 6876254Sroot 68816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 68916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 69016694Smckusick ndp->ni_dirp = uap->target; 69137741Smckusick if (error = namei(ndp)) 69237741Smckusick RETURN (error); 69337741Smckusick vp = ndp->ni_vp; 69437741Smckusick if (vp->v_type == VDIR && 69538408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 69637741Smckusick goto out1; 69737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69816694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 69937741Smckusick if (error = namei(ndp)) 70037741Smckusick goto out1; 70137741Smckusick xp = ndp->ni_vp; 7026254Sroot if (xp != NULL) { 70337741Smckusick error = EEXIST; 7046254Sroot goto out; 7056254Sroot } 70637741Smckusick xp = ndp->ni_dvp; 70737741Smckusick if (vp->v_mount != xp->v_mount) 70837741Smckusick error = EXDEV; 7096254Sroot out: 71037741Smckusick if (error) 71137741Smckusick VOP_ABORTOP(ndp); 71237741Smckusick else 71337741Smckusick error = VOP_LINK(vp, ndp); 71437741Smckusick out1: 71537741Smckusick vrele(vp); 71637741Smckusick RETURN (error); 7176254Sroot } 7186254Sroot 7196254Sroot /* 7206254Sroot * symlink -- make a symbolic link 7216254Sroot */ 72238408Smckusick symlink(scp) 72338408Smckusick register struct syscontext *scp; 7246254Sroot { 72537741Smckusick struct a { 7266254Sroot char *target; 7276254Sroot char *linkname; 72838408Smckusick } *uap = (struct a *)scp->sc_ap; 72938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 73037741Smckusick register struct vnode *vp; 73137741Smckusick struct vattr vattr; 73237741Smckusick char *target; 73337741Smckusick int error; 7346254Sroot 73516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73616694Smckusick ndp->ni_dirp = uap->linkname; 73737741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 73837741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 73937741Smckusick goto out1; 74037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 74137741Smckusick if (error = namei(ndp)) 74237741Smckusick goto out1; 74337741Smckusick vp = ndp->ni_vp; 74437741Smckusick if (vp) { 74537741Smckusick error = EEXIST; 74637741Smckusick goto out; 7476254Sroot } 74837741Smckusick vp = ndp->ni_dvp; 74941362Smckusick VATTR_NULL(&vattr); 75038408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 75137741Smckusick out: 75237741Smckusick if (error) 75337741Smckusick VOP_ABORTOP(ndp); 75437741Smckusick else 75537741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 75637741Smckusick out1: 75737741Smckusick FREE(target, M_NAMEI); 75837741Smckusick RETURN (error); 7596254Sroot } 7606254Sroot 7616254Sroot /* 7626254Sroot * Unlink system call. 7636254Sroot * Hard to avoid races here, especially 7646254Sroot * in unlinking directories. 7656254Sroot */ 76638408Smckusick unlink(scp) 76738408Smckusick register struct syscontext *scp; 7686254Sroot { 7696254Sroot struct a { 7706254Sroot char *fname; 77138408Smckusick } *uap = (struct a *)scp->sc_ap; 77238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 77337741Smckusick register struct vnode *vp; 77437741Smckusick int error; 7756254Sroot 77637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 77716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77816694Smckusick ndp->ni_dirp = uap->fname; 77937741Smckusick if (error = namei(ndp)) 78037741Smckusick RETURN (error); 78137741Smckusick vp = ndp->ni_vp; 78237741Smckusick if (vp->v_type == VDIR && 78338408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 7846254Sroot goto out; 7856254Sroot /* 7866254Sroot * Don't unlink a mounted file. 7876254Sroot */ 78837741Smckusick if (vp->v_flag & VROOT) { 78937741Smckusick error = EBUSY; 7906254Sroot goto out; 7916254Sroot } 79237741Smckusick if (vp->v_flag & VTEXT) 79337741Smckusick xrele(vp); /* try once to free text */ 7946254Sroot out: 79537741Smckusick if (error) 79637741Smckusick VOP_ABORTOP(ndp); 7977142Smckusick else 79837741Smckusick error = VOP_REMOVE(ndp); 79937741Smckusick RETURN (error); 8006254Sroot } 8016254Sroot 8026254Sroot /* 8036254Sroot * Seek system call 8046254Sroot */ 80538408Smckusick lseek(scp) 80638408Smckusick register struct syscontext *scp; 8076254Sroot { 8086254Sroot register struct file *fp; 8096254Sroot register struct a { 81037741Smckusick int fdes; 8116254Sroot off_t off; 8126254Sroot int sbase; 81338408Smckusick } *uap = (struct a *)scp->sc_ap; 81437741Smckusick struct vattr vattr; 81537741Smckusick int error; 8166254Sroot 81737741Smckusick if ((unsigned)uap->fdes >= NOFILE || 81838408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 81937741Smckusick RETURN (EBADF); 82037741Smckusick if (fp->f_type != DTYPE_VNODE) 82137741Smckusick RETURN (ESPIPE); 82213878Ssam switch (uap->sbase) { 82313878Ssam 82413878Ssam case L_INCR: 82513878Ssam fp->f_offset += uap->off; 82613878Ssam break; 82713878Ssam 82813878Ssam case L_XTND: 82937741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 83038408Smckusick &vattr, scp->sc_cred)) 83137741Smckusick RETURN (error); 83237741Smckusick fp->f_offset = uap->off + vattr.va_size; 83313878Ssam break; 83413878Ssam 83513878Ssam case L_SET: 83613878Ssam fp->f_offset = uap->off; 83713878Ssam break; 83813878Ssam 83913878Ssam default: 84037741Smckusick RETURN (EINVAL); 84113878Ssam } 84238408Smckusick scp->sc_offset = fp->f_offset; 84337741Smckusick RETURN (0); 8446254Sroot } 8456254Sroot 8466254Sroot /* 8476254Sroot * Access system call 8486254Sroot */ 84938408Smckusick saccess(scp) 85038408Smckusick register struct syscontext *scp; 8516254Sroot { 8526254Sroot register struct a { 8536254Sroot char *fname; 8546254Sroot int fmode; 85538408Smckusick } *uap = (struct a *)scp->sc_ap; 85638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 85737741Smckusick register struct vnode *vp; 85837741Smckusick int error, mode, svuid, svgid; 8596254Sroot 86038408Smckusick svuid = scp->sc_uid; 86138408Smckusick svgid = scp->sc_gid; 86238408Smckusick scp->sc_uid = scp->sc_ruid; 86338408Smckusick scp->sc_gid = scp->sc_rgid; 86437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 86516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 86616694Smckusick ndp->ni_dirp = uap->fname; 86737741Smckusick if (error = namei(ndp)) 86837741Smckusick goto out1; 86937741Smckusick vp = ndp->ni_vp; 87037741Smckusick /* 87137741Smckusick * fmode == 0 means only check for exist 87237741Smckusick */ 87337741Smckusick if (uap->fmode) { 87437741Smckusick mode = 0; 87537741Smckusick if (uap->fmode & R_OK) 87637741Smckusick mode |= VREAD; 87737741Smckusick if (uap->fmode & W_OK) 87837741Smckusick mode |= VWRITE; 87937741Smckusick if (uap->fmode & X_OK) 88037741Smckusick mode |= VEXEC; 88139543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 88238399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 8836254Sroot } 88437741Smckusick vput(vp); 88537741Smckusick out1: 88638408Smckusick scp->sc_uid = svuid; 88738408Smckusick scp->sc_gid = svgid; 88837741Smckusick RETURN (error); 8896254Sroot } 8906254Sroot 8916254Sroot /* 8926574Smckusic * Stat system call. This version follows links. 89337Sbill */ 89438408Smckusick stat(scp) 89538408Smckusick struct syscontext *scp; 89637Sbill { 89737Sbill 89838408Smckusick stat1(scp, FOLLOW); 89937Sbill } 90037Sbill 90137Sbill /* 9026574Smckusic * Lstat system call. This version does not follow links. 9035992Swnj */ 90438408Smckusick lstat(scp) 90538408Smckusick struct syscontext *scp; 9065992Swnj { 90712756Ssam 90838408Smckusick stat1(scp, NOFOLLOW); 90912756Ssam } 91012756Ssam 91138408Smckusick stat1(scp, follow) 91238408Smckusick register struct syscontext *scp; 91312756Ssam int follow; 91412756Ssam { 9155992Swnj register struct a { 9165992Swnj char *fname; 91712756Ssam struct stat *ub; 91838408Smckusick } *uap = (struct a *)scp->sc_ap; 91938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 92012756Ssam struct stat sb; 92137741Smckusick int error; 9225992Swnj 92337741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 92416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 92516694Smckusick ndp->ni_dirp = uap->fname; 92637741Smckusick if (error = namei(ndp)) 92737741Smckusick RETURN (error); 92837741Smckusick error = vn_stat(ndp->ni_vp, &sb); 92937741Smckusick vput(ndp->ni_vp); 93037741Smckusick if (error) 93137741Smckusick RETURN (error); 93237741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 93337741Smckusick RETURN (error); 9345992Swnj } 9355992Swnj 9365992Swnj /* 9375992Swnj * Return target name of a symbolic link 93837Sbill */ 93938408Smckusick readlink(scp) 94038408Smckusick register struct syscontext *scp; 9415992Swnj { 9425992Swnj register struct a { 9435992Swnj char *name; 9445992Swnj char *buf; 9455992Swnj int count; 94638408Smckusick } *uap = (struct a *)scp->sc_ap; 94738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 94837741Smckusick register struct vnode *vp; 94937741Smckusick struct iovec aiov; 95037741Smckusick struct uio auio; 95137741Smckusick int error; 9525992Swnj 95337741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 95416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 95516694Smckusick ndp->ni_dirp = uap->name; 95637741Smckusick if (error = namei(ndp)) 95737741Smckusick RETURN (error); 95837741Smckusick vp = ndp->ni_vp; 95937741Smckusick if (vp->v_type != VLNK) { 96037741Smckusick error = EINVAL; 9615992Swnj goto out; 9625992Swnj } 96337741Smckusick aiov.iov_base = uap->buf; 96437741Smckusick aiov.iov_len = uap->count; 96537741Smckusick auio.uio_iov = &aiov; 96637741Smckusick auio.uio_iovcnt = 1; 96737741Smckusick auio.uio_offset = 0; 96837741Smckusick auio.uio_rw = UIO_READ; 96937741Smckusick auio.uio_segflg = UIO_USERSPACE; 97037741Smckusick auio.uio_resid = uap->count; 97137741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 9725992Swnj out: 97337741Smckusick vput(vp); 97438408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 97537741Smckusick RETURN (error); 9765992Swnj } 9775992Swnj 9789167Ssam /* 97938259Smckusick * Change flags of a file given path name. 98038259Smckusick */ 98138408Smckusick chflags(scp) 98238408Smckusick register struct syscontext *scp; 98338259Smckusick { 98438259Smckusick struct a { 98538259Smckusick char *fname; 98638259Smckusick int flags; 98738408Smckusick } *uap = (struct a *)scp->sc_ap; 98838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 98938259Smckusick register struct vnode *vp; 99038259Smckusick struct vattr vattr; 99138259Smckusick int error; 99238259Smckusick 99338259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 99438259Smckusick ndp->ni_segflg = UIO_USERSPACE; 99538259Smckusick ndp->ni_dirp = uap->fname; 99641362Smckusick VATTR_NULL(&vattr); 99738259Smckusick vattr.va_flags = uap->flags; 99838259Smckusick if (error = namei(ndp)) 99938259Smckusick RETURN (error); 100038259Smckusick vp = ndp->ni_vp; 100141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 100238259Smckusick error = EROFS; 100338259Smckusick goto out; 100438259Smckusick } 100538259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 100638259Smckusick out: 100738259Smckusick vput(vp); 100838259Smckusick RETURN (error); 100938259Smckusick } 101038259Smckusick 101138259Smckusick /* 101238259Smckusick * Change flags of a file given a file descriptor. 101338259Smckusick */ 101438408Smckusick fchflags(scp) 101538408Smckusick register struct syscontext *scp; 101638259Smckusick { 101738259Smckusick struct a { 101838259Smckusick int fd; 101938259Smckusick int flags; 102038408Smckusick } *uap = (struct a *)scp->sc_ap; 102138259Smckusick struct vattr vattr; 102238259Smckusick struct vnode *vp; 102338259Smckusick struct file *fp; 102438259Smckusick int error; 102538259Smckusick 102638408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 102738259Smckusick RETURN (error); 102841362Smckusick VATTR_NULL(&vattr); 102938259Smckusick vattr.va_flags = uap->flags; 103038259Smckusick vp = (struct vnode *)fp->f_data; 103138259Smckusick VOP_LOCK(vp); 103241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 103338259Smckusick error = EROFS; 103438259Smckusick goto out; 103538259Smckusick } 103638259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 103738259Smckusick out: 103838259Smckusick VOP_UNLOCK(vp); 103938259Smckusick RETURN (error); 104038259Smckusick } 104138259Smckusick 104238259Smckusick /* 10439167Ssam * Change mode of a file given path name. 10449167Ssam */ 104538408Smckusick chmod(scp) 104638408Smckusick register struct syscontext *scp; 10475992Swnj { 10487701Ssam struct a { 10496254Sroot char *fname; 10506254Sroot int fmode; 105138408Smckusick } *uap = (struct a *)scp->sc_ap; 105238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 105337741Smckusick register struct vnode *vp; 105437741Smckusick struct vattr vattr; 105537741Smckusick int error; 10565992Swnj 105737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 105837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 105937741Smckusick ndp->ni_dirp = uap->fname; 106041362Smckusick VATTR_NULL(&vattr); 106137741Smckusick vattr.va_mode = uap->fmode & 07777; 106237741Smckusick if (error = namei(ndp)) 106337741Smckusick RETURN (error); 106437741Smckusick vp = ndp->ni_vp; 106541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 106637741Smckusick error = EROFS; 106737741Smckusick goto out; 106837741Smckusick } 106937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 107037741Smckusick out: 107137741Smckusick vput(vp); 107237741Smckusick RETURN (error); 10737701Ssam } 10747439Sroot 10759167Ssam /* 10769167Ssam * Change mode of a file given a file descriptor. 10779167Ssam */ 107838408Smckusick fchmod(scp) 107938408Smckusick register struct syscontext *scp; 10807701Ssam { 10817701Ssam struct a { 10827701Ssam int fd; 10837701Ssam int fmode; 108438408Smckusick } *uap = (struct a *)scp->sc_ap; 108537741Smckusick struct vattr vattr; 108637741Smckusick struct vnode *vp; 108737741Smckusick struct file *fp; 108837741Smckusick int error; 10897701Ssam 109038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 109137741Smckusick RETURN (error); 109241362Smckusick VATTR_NULL(&vattr); 109337741Smckusick vattr.va_mode = uap->fmode & 07777; 109437741Smckusick vp = (struct vnode *)fp->f_data; 109537741Smckusick VOP_LOCK(vp); 109641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 109737741Smckusick error = EROFS; 109837741Smckusick goto out; 10997439Sroot } 110037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 110137741Smckusick out: 110237741Smckusick VOP_UNLOCK(vp); 110337741Smckusick RETURN (error); 11045992Swnj } 11055992Swnj 11069167Ssam /* 11079167Ssam * Set ownership given a path name. 11089167Ssam */ 110938408Smckusick chown(scp) 111038408Smckusick register struct syscontext *scp; 111137Sbill { 11127701Ssam struct a { 11136254Sroot char *fname; 11146254Sroot int uid; 11156254Sroot int gid; 111638408Smckusick } *uap = (struct a *)scp->sc_ap; 111738408Smckusick register struct nameidata *ndp = &scp->sc_nd; 111837741Smckusick register struct vnode *vp; 111937741Smckusick struct vattr vattr; 112037741Smckusick int error; 112137Sbill 112237741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 112336614Sbostic ndp->ni_segflg = UIO_USERSPACE; 112436614Sbostic ndp->ni_dirp = uap->fname; 112541362Smckusick VATTR_NULL(&vattr); 112637741Smckusick vattr.va_uid = uap->uid; 112737741Smckusick vattr.va_gid = uap->gid; 112837741Smckusick if (error = namei(ndp)) 112937741Smckusick RETURN (error); 113037741Smckusick vp = ndp->ni_vp; 113141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 113237741Smckusick error = EROFS; 113337741Smckusick goto out; 113437741Smckusick } 113537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 113637741Smckusick out: 113737741Smckusick vput(vp); 113837741Smckusick RETURN (error); 11397701Ssam } 11407439Sroot 11419167Ssam /* 11429167Ssam * Set ownership given a file descriptor. 11439167Ssam */ 114438408Smckusick fchown(scp) 114538408Smckusick register struct syscontext *scp; 11467701Ssam { 11477701Ssam struct a { 11487701Ssam int fd; 11497701Ssam int uid; 11507701Ssam int gid; 115138408Smckusick } *uap = (struct a *)scp->sc_ap; 115237741Smckusick struct vattr vattr; 115337741Smckusick struct vnode *vp; 115437741Smckusick struct file *fp; 115537741Smckusick int error; 11567701Ssam 115738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 115837741Smckusick RETURN (error); 115941362Smckusick VATTR_NULL(&vattr); 116037741Smckusick vattr.va_uid = uap->uid; 116137741Smckusick vattr.va_gid = uap->gid; 116237741Smckusick vp = (struct vnode *)fp->f_data; 116337741Smckusick VOP_LOCK(vp); 116441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 116537741Smckusick error = EROFS; 116637741Smckusick goto out; 116737741Smckusick } 116837741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 116937741Smckusick out: 117037741Smckusick VOP_UNLOCK(vp); 117137741Smckusick RETURN (error); 11727701Ssam } 11737701Ssam 117438408Smckusick utimes(scp) 117538408Smckusick register struct syscontext *scp; 117611811Ssam { 117711811Ssam register struct a { 117811811Ssam char *fname; 117911811Ssam struct timeval *tptr; 118038408Smckusick } *uap = (struct a *)scp->sc_ap; 118138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 118237741Smckusick register struct vnode *vp; 118311811Ssam struct timeval tv[2]; 118437741Smckusick struct vattr vattr; 118537741Smckusick int error; 118611811Ssam 118737741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 118837741Smckusick RETURN (error); 118937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 119037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 119137741Smckusick ndp->ni_dirp = uap->fname; 119241362Smckusick VATTR_NULL(&vattr); 119337741Smckusick vattr.va_atime = tv[0]; 119437741Smckusick vattr.va_mtime = tv[1]; 119537741Smckusick if (error = namei(ndp)) 119637741Smckusick RETURN (error); 119737741Smckusick vp = ndp->ni_vp; 119841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 119937741Smckusick error = EROFS; 120037741Smckusick goto out; 120121015Smckusick } 120237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 120337741Smckusick out: 120437741Smckusick vput(vp); 120537741Smckusick RETURN (error); 120611811Ssam } 120711811Ssam 12089167Ssam /* 12099167Ssam * Truncate a file given its path name. 12109167Ssam */ 121138408Smckusick truncate(scp) 121238408Smckusick register struct syscontext *scp; 12137701Ssam { 12147701Ssam struct a { 12157701Ssam char *fname; 121626473Skarels off_t length; 121738408Smckusick } *uap = (struct a *)scp->sc_ap; 121838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 121937741Smckusick register struct vnode *vp; 122037741Smckusick struct vattr vattr; 122137741Smckusick int error; 12227701Ssam 122337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 122416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122516694Smckusick ndp->ni_dirp = uap->fname; 122641362Smckusick VATTR_NULL(&vattr); 122737741Smckusick vattr.va_size = uap->length; 122837741Smckusick if (error = namei(ndp)) 122937741Smckusick RETURN (error); 123037741Smckusick vp = ndp->ni_vp; 123137741Smckusick if (vp->v_type == VDIR) { 123237741Smckusick error = EISDIR; 123337741Smckusick goto out; 12347701Ssam } 123538399Smckusick if ((error = vn_writechk(vp)) || 123638399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 123737741Smckusick goto out; 123837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 123937741Smckusick out: 124037741Smckusick vput(vp); 124137741Smckusick RETURN (error); 12427701Ssam } 12437701Ssam 12449167Ssam /* 12459167Ssam * Truncate a file given a file descriptor. 12469167Ssam */ 124738408Smckusick ftruncate(scp) 124838408Smckusick register struct syscontext *scp; 12497701Ssam { 12507701Ssam struct a { 12517701Ssam int fd; 125226473Skarels off_t length; 125338408Smckusick } *uap = (struct a *)scp->sc_ap; 125437741Smckusick struct vattr vattr; 125537741Smckusick struct vnode *vp; 12567701Ssam struct file *fp; 125737741Smckusick int error; 12587701Ssam 125938408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 126037741Smckusick RETURN (error); 126137741Smckusick if ((fp->f_flag & FWRITE) == 0) 126237741Smckusick RETURN (EINVAL); 126341362Smckusick VATTR_NULL(&vattr); 126437741Smckusick vattr.va_size = uap->length; 126537741Smckusick vp = (struct vnode *)fp->f_data; 126637741Smckusick VOP_LOCK(vp); 126737741Smckusick if (vp->v_type == VDIR) { 126837741Smckusick error = EISDIR; 126937741Smckusick goto out; 12707701Ssam } 127138399Smckusick if (error = vn_writechk(vp)) 127237741Smckusick goto out; 127337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 127437741Smckusick out: 127537741Smckusick VOP_UNLOCK(vp); 127637741Smckusick RETURN (error); 12777701Ssam } 12787701Ssam 12799167Ssam /* 12809167Ssam * Synch an open file. 12819167Ssam */ 128238408Smckusick fsync(scp) 128338408Smckusick register struct syscontext *scp; 12849167Ssam { 12859167Ssam struct a { 12869167Ssam int fd; 128738408Smckusick } *uap = (struct a *)scp->sc_ap; 128839592Smckusick register struct vnode *vp; 12899167Ssam struct file *fp; 129037741Smckusick int error; 12919167Ssam 129238408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 129337741Smckusick RETURN (error); 129439592Smckusick vp = (struct vnode *)fp->f_data; 129539592Smckusick VOP_LOCK(vp); 129639592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 129739592Smckusick VOP_UNLOCK(vp); 129837741Smckusick RETURN (error); 12999167Ssam } 13009167Ssam 13019167Ssam /* 13029167Ssam * Rename system call. 13039167Ssam * 13049167Ssam * Source and destination must either both be directories, or both 13059167Ssam * not be directories. If target is a directory, it must be empty. 13069167Ssam */ 130738408Smckusick rename(scp) 130838408Smckusick register struct syscontext *scp; 13097701Ssam { 13107701Ssam struct a { 13117701Ssam char *from; 13127701Ssam char *to; 131338408Smckusick } *uap = (struct a *)scp->sc_ap; 131437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 131538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 131637741Smckusick struct nameidata tond; 131737741Smckusick int error; 13187701Ssam 131937741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 132016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132116694Smckusick ndp->ni_dirp = uap->from; 132237741Smckusick if (error = namei(ndp)) 132337741Smckusick RETURN (error); 132437741Smckusick fvp = ndp->ni_vp; 132538266Smckusick nddup(ndp, &tond); 132637741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 132737741Smckusick tond.ni_segflg = UIO_USERSPACE; 132837741Smckusick tond.ni_dirp = uap->to; 132937741Smckusick error = namei(&tond); 133037741Smckusick tdvp = tond.ni_dvp; 133137741Smckusick tvp = tond.ni_vp; 133237741Smckusick if (tvp != NULL) { 133337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 133439242Sbostic error = ENOTDIR; 133537741Smckusick goto out; 133637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 133739242Sbostic error = EISDIR; 133837741Smckusick goto out; 13399167Ssam } 13409167Ssam } 134137741Smckusick if (error) { 134237741Smckusick VOP_ABORTOP(ndp); 134337741Smckusick goto out1; 134437741Smckusick } 134537741Smckusick if (fvp->v_mount != tdvp->v_mount) { 134637741Smckusick error = EXDEV; 13479167Ssam goto out; 134810051Ssam } 134939286Smckusick if (fvp == tdvp) 135037741Smckusick error = EINVAL; 135139286Smckusick /* 135239286Smckusick * If source is the same as the destination, 135339286Smckusick * then there is nothing to do. 135439286Smckusick */ 135539286Smckusick if (fvp == tvp) 135639286Smckusick error = -1; 135737741Smckusick out: 135837741Smckusick if (error) { 135937741Smckusick VOP_ABORTOP(&tond); 136037741Smckusick VOP_ABORTOP(ndp); 13619167Ssam } else { 136237741Smckusick error = VOP_RENAME(ndp, &tond); 13639167Ssam } 136437741Smckusick out1: 136538266Smckusick ndrele(&tond); 136639286Smckusick if (error == -1) 136739286Smckusick RETURN (0); 136837741Smckusick RETURN (error); 13697701Ssam } 13707701Ssam 13717535Sroot /* 137212756Ssam * Mkdir system call 137312756Ssam */ 137438408Smckusick mkdir(scp) 137538408Smckusick register struct syscontext *scp; 137612756Ssam { 137712756Ssam struct a { 137812756Ssam char *name; 137912756Ssam int dmode; 138038408Smckusick } *uap = (struct a *)scp->sc_ap; 138138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 138237741Smckusick register struct vnode *vp; 138337741Smckusick struct vattr vattr; 138437741Smckusick int error; 138512756Ssam 138637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 138716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 138816694Smckusick ndp->ni_dirp = uap->name; 138937741Smckusick if (error = namei(ndp)) 139037741Smckusick RETURN (error); 139137741Smckusick vp = ndp->ni_vp; 139237741Smckusick if (vp != NULL) { 139337741Smckusick VOP_ABORTOP(ndp); 139437741Smckusick RETURN (EEXIST); 139512756Ssam } 139641362Smckusick VATTR_NULL(&vattr); 139737741Smckusick vattr.va_type = VDIR; 139838408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 139937741Smckusick error = VOP_MKDIR(ndp, &vattr); 140038145Smckusick if (!error) 140138145Smckusick vput(ndp->ni_vp); 140237741Smckusick RETURN (error); 140312756Ssam } 140412756Ssam 140512756Ssam /* 140612756Ssam * Rmdir system call. 140712756Ssam */ 140838408Smckusick rmdir(scp) 140938408Smckusick register struct syscontext *scp; 141012756Ssam { 141112756Ssam struct a { 141212756Ssam char *name; 141338408Smckusick } *uap = (struct a *)scp->sc_ap; 141438408Smckusick register struct nameidata *ndp = &scp->sc_nd; 141537741Smckusick register struct vnode *vp; 141637741Smckusick int error; 141712756Ssam 141837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 141916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142016694Smckusick ndp->ni_dirp = uap->name; 142137741Smckusick if (error = namei(ndp)) 142237741Smckusick RETURN (error); 142337741Smckusick vp = ndp->ni_vp; 142437741Smckusick if (vp->v_type != VDIR) { 142537741Smckusick error = ENOTDIR; 142612756Ssam goto out; 142712756Ssam } 142812756Ssam /* 142937741Smckusick * No rmdir "." please. 143012756Ssam */ 143137741Smckusick if (ndp->ni_dvp == vp) { 143237741Smckusick error = EINVAL; 143312756Ssam goto out; 143412756Ssam } 143512756Ssam /* 143637741Smckusick * Don't unlink a mounted file. 143712756Ssam */ 143837741Smckusick if (vp->v_flag & VROOT) 143937741Smckusick error = EBUSY; 144012756Ssam out: 144137741Smckusick if (error) 144237741Smckusick VOP_ABORTOP(ndp); 144337741Smckusick else 144437741Smckusick error = VOP_RMDIR(ndp); 144537741Smckusick RETURN (error); 144612756Ssam } 144712756Ssam 144837741Smckusick /* 144937741Smckusick * Read a block of directory entries in a file system independent format 145037741Smckusick */ 145138408Smckusick getdirentries(scp) 145238408Smckusick register struct syscontext *scp; 145312756Ssam { 145437741Smckusick register struct a { 145537741Smckusick int fd; 145637741Smckusick char *buf; 145737741Smckusick unsigned count; 145837741Smckusick long *basep; 145938408Smckusick } *uap = (struct a *)scp->sc_ap; 146039592Smckusick register struct vnode *vp; 146116540Ssam struct file *fp; 146237741Smckusick struct uio auio; 146337741Smckusick struct iovec aiov; 146438129Smckusick off_t off; 146540321Smckusick int error, eofflag; 146612756Ssam 146738408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 146837741Smckusick RETURN (error); 146937741Smckusick if ((fp->f_flag & FREAD) == 0) 147037741Smckusick RETURN (EBADF); 147139592Smckusick vp = (struct vnode *)fp->f_data; 147239592Smckusick if (vp->v_type != VDIR) 147339592Smckusick RETURN (EINVAL); 147437741Smckusick aiov.iov_base = uap->buf; 147537741Smckusick aiov.iov_len = uap->count; 147637741Smckusick auio.uio_iov = &aiov; 147737741Smckusick auio.uio_iovcnt = 1; 147837741Smckusick auio.uio_rw = UIO_READ; 147937741Smckusick auio.uio_segflg = UIO_USERSPACE; 148037741Smckusick auio.uio_resid = uap->count; 148139592Smckusick VOP_LOCK(vp); 148239592Smckusick auio.uio_offset = off = fp->f_offset; 148340321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 148439592Smckusick fp->f_offset = auio.uio_offset; 148539592Smckusick VOP_UNLOCK(vp); 148639592Smckusick if (error) 148737741Smckusick RETURN (error); 148839592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 148938408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 149037741Smckusick RETURN (error); 149112756Ssam } 149212756Ssam 149312756Ssam /* 149412756Ssam * mode mask for creation of files 149512756Ssam */ 149638408Smckusick umask(scp) 149738408Smckusick register struct syscontext *scp; 149812756Ssam { 149912756Ssam register struct a { 150012756Ssam int mask; 150138408Smckusick } *uap = (struct a *)scp->sc_ap; 150212756Ssam 150338408Smckusick scp->sc_retval1 = scp->sc_cmask; 150438408Smckusick scp->sc_cmask = uap->mask & 07777; 150537741Smckusick RETURN (0); 150612756Ssam } 150737741Smckusick 150839566Smarc /* 150939566Smarc * Void all references to file by ripping underlying filesystem 151039566Smarc * away from vnode. 151139566Smarc */ 151239566Smarc revoke(scp) 151339566Smarc register struct syscontext *scp; 151439566Smarc { 151539566Smarc struct a { 151639566Smarc char *fname; 1517*41676Smckusick int flags; 151839566Smarc } *uap = (struct a *)scp->sc_ap; 151939566Smarc register struct nameidata *ndp = &scp->sc_nd; 152039566Smarc register struct vnode *vp; 152139566Smarc struct vattr vattr; 152239566Smarc int error; 152339566Smarc 152439566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 152539566Smarc ndp->ni_segflg = UIO_USERSPACE; 152639566Smarc ndp->ni_dirp = uap->fname; 152739566Smarc if (error = namei(ndp)) 152839566Smarc RETURN (error); 152939566Smarc vp = ndp->ni_vp; 153039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 153139566Smarc error = EINVAL; 153239566Smarc goto out; 153339566Smarc } 153439566Smarc if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred)) 153539566Smarc goto out; 153639566Smarc if (scp->sc_uid != vattr.va_uid || 153739566Smarc (error = suser(scp->sc_cred, &scp->sc_acflag))) 153839566Smarc goto out; 153939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 154039632Smckusick vgoneall(vp); 154139566Smarc out: 154239566Smarc vrele(vp); 154339566Smarc RETURN (error); 154439566Smarc } 154539566Smarc 154638408Smckusick getvnode(ofile, fdes, fpp) 154738408Smckusick struct file *ofile[]; 154837741Smckusick struct file **fpp; 154937741Smckusick int fdes; 155037741Smckusick { 155137741Smckusick struct file *fp; 155237741Smckusick 155338408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 155437741Smckusick return (EBADF); 155537741Smckusick if (fp->f_type != DTYPE_VNODE) 155637741Smckusick return (EINVAL); 155737741Smckusick *fpp = fp; 155837741Smckusick return (0); 155937741Smckusick } 1560