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*38399Smckusick * @(#)vfs_syscalls.c 7.13 (Berkeley) 07/03/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 */ 4037741Smckusick mount() 416254Sroot { 4237741Smckusick register struct a { 4337741Smckusick int type; 4437741Smckusick char *dir; 4537741Smckusick int flags; 4637741Smckusick caddr_t data; 4737741Smckusick } *uap = (struct a *)u.u_ap; 4837741Smckusick register struct nameidata *ndp = &u.u_nd; 4937741Smckusick struct vnode *vp; 5037741Smckusick struct mount *mp; 5137741Smckusick int error; 526254Sroot 5337741Smckusick /* 5437741Smckusick * Must be super user 5537741Smckusick */ 5637741Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 5737741Smckusick RETURN (error); 5837741Smckusick /* 5937741Smckusick * Get vnode to be covered 6037741Smckusick */ 6137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6337741Smckusick ndp->ni_dirp = uap->dir; 6437741Smckusick if (error = namei(ndp)) 6537741Smckusick RETURN (error); 6637741Smckusick vp = ndp->ni_vp; 6737741Smckusick if (vp->v_count != 1) { 6837741Smckusick vput(vp); 6937741Smckusick RETURN (EBUSY); 7037741Smckusick } 7137741Smckusick if (vp->v_type != VDIR) { 7237741Smckusick vput(vp); 7337741Smckusick RETURN (ENOTDIR); 7437741Smckusick } 7537741Smckusick if (uap->type > MOUNT_MAXTYPE || 7637741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 7737741Smckusick vput(vp); 7837741Smckusick RETURN (ENODEV); 7937741Smckusick } 8037741Smckusick 8137741Smckusick /* 8237741Smckusick * Mount the filesystem. 8337741Smckusick */ 8437741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 8537741Smckusick M_MOUNT, M_WAITOK); 8637741Smckusick mp->m_op = vfssw[uap->type]; 8737741Smckusick mp->m_flag = 0; 8837741Smckusick mp->m_exroot = 0; 8937741Smckusick error = vfs_add(vp, mp, uap->flags); 9037741Smckusick if (!error) 9137741Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 9237741Smckusick cache_purge(vp); 9337741Smckusick VOP_UNLOCK(vp); 9437741Smckusick if (!error) { 9537741Smckusick vfs_unlock(mp); 9637741Smckusick } else { 9737741Smckusick vfs_remove(mp); 9837741Smckusick free((caddr_t)mp, M_MOUNT); 9937741Smckusick vrele(vp); 10037741Smckusick } 10137741Smckusick RETURN (error); 1026254Sroot } 1036254Sroot 1049167Ssam /* 10537741Smckusick * Unmount system call. 10637741Smckusick * 10737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 10837741Smckusick * not special file (as before). 1099167Ssam */ 11037741Smckusick unmount() 1116254Sroot { 11237741Smckusick struct a { 11337741Smckusick char *pathp; 11437741Smckusick int flags; 11537741Smckusick } *uap = (struct a *)u.u_ap; 11637741Smckusick register struct vnode *vp; 11737741Smckusick register struct mount *mp; 11837741Smckusick register struct nameidata *ndp = &u.u_nd; 11937741Smckusick struct vnode *coveredvp; 12037741Smckusick int error; 1216254Sroot 12237741Smckusick /* 12337741Smckusick * Must be super user 12437741Smckusick */ 12537741Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 12637741Smckusick RETURN (error); 12737741Smckusick 12837741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 12937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 13037741Smckusick ndp->ni_dirp = uap->pathp; 13137741Smckusick if (error = namei(ndp)) 13237741Smckusick RETURN (error); 13337741Smckusick vp = ndp->ni_vp; 13437741Smckusick /* 13537741Smckusick * Must be the root of the filesystem 13637741Smckusick */ 13737741Smckusick if ((vp->v_flag & VROOT) == 0) { 13837741Smckusick vput(vp); 13937741Smckusick RETURN (EINVAL); 14037741Smckusick } 14137741Smckusick mp = vp->v_mount; 14237741Smckusick vput(vp); 14337741Smckusick /* 14437741Smckusick * Do the unmount. 14537741Smckusick */ 14637741Smckusick coveredvp = mp->m_vnodecovered; 14737741Smckusick if (error = vfs_lock(mp)) 14837741Smckusick RETURN (error); 14937741Smckusick 15037741Smckusick xumount(mp); /* remove unused sticky files from text table */ 15137741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 15237741Smckusick VFS_SYNC(mp, MNT_WAIT); 15337741Smckusick 15437741Smckusick error = VFS_UNMOUNT(mp, uap->flags); 15537741Smckusick if (error) { 15637741Smckusick vfs_unlock(mp); 15737741Smckusick } else { 15837741Smckusick vrele(coveredvp); 15937741Smckusick vfs_remove(mp); 16037741Smckusick free((caddr_t)mp, M_MOUNT); 16137741Smckusick } 16237741Smckusick RETURN (error); 1636254Sroot } 1646254Sroot 1659167Ssam /* 16637741Smckusick * Sync system call. 16737741Smckusick * Sync each mounted filesystem. 1689167Ssam */ 16937741Smckusick sync() 1706254Sroot { 17137741Smckusick register struct mount *mp; 17237741Smckusick 17337741Smckusick mp = rootfs; 17437741Smckusick do { 17537741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 17637741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 17737741Smckusick mp = mp->m_next; 17837741Smckusick } while (mp != rootfs); 17937741Smckusick } 18037741Smckusick 18137741Smckusick /* 18237741Smckusick * get filesystem statistics 18337741Smckusick */ 18437741Smckusick statfs() 18537741Smckusick { 1866254Sroot struct a { 18737741Smckusick char *path; 18837741Smckusick struct statfs *buf; 18937741Smckusick } *uap = (struct a *)u.u_ap; 19037741Smckusick register struct vnode *vp; 19137741Smckusick register struct nameidata *ndp = &u.u_nd; 19237741Smckusick struct statfs sb; 19337741Smckusick int error; 19437741Smckusick 19537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 19637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 19737741Smckusick ndp->ni_dirp = uap->path; 19837741Smckusick if (error = namei(ndp)) 19937741Smckusick RETURN (error); 20037741Smckusick vp = ndp->ni_vp; 20137741Smckusick if (error = VFS_STATFS(vp->v_mount, &sb)) 20237741Smckusick goto out; 20337741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 20437741Smckusick out: 20537741Smckusick vput(vp); 20637741Smckusick RETURN (error); 20737741Smckusick } 20837741Smckusick 20937741Smckusick fstatfs() 21037741Smckusick { 21137741Smckusick struct a { 21237741Smckusick int fd; 21337741Smckusick struct statfs *buf; 21437741Smckusick } *uap = (struct a *)u.u_ap; 21537741Smckusick struct file *fp; 21637741Smckusick struct statfs sb; 21737741Smckusick int error; 21837741Smckusick 21937741Smckusick if (error = getvnode(uap->fd, &fp)) 22037741Smckusick RETURN (error); 22137741Smckusick if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 22237741Smckusick RETURN (error); 22337741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 22437741Smckusick } 22537741Smckusick 22637741Smckusick /* 22738270Smckusick * get statistics on all filesystems 22838270Smckusick */ 22938270Smckusick getfsstat() 23038270Smckusick { 23138270Smckusick struct a { 23238270Smckusick struct statfs *buf; 23338270Smckusick long bufsize; 23438270Smckusick } *uap = (struct a *)u.u_ap; 23538270Smckusick register struct mount *mp; 23638270Smckusick register struct statfs *sfsp; 23738270Smckusick long count, maxcount, error; 23838270Smckusick 23938270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 24038270Smckusick sfsp = uap->buf; 24138270Smckusick mp = rootfs; 24238270Smckusick count = 0; 24338270Smckusick do { 24438270Smckusick count++; 24538270Smckusick if (sfsp && count <= maxcount) { 24638270Smckusick if (error = VFS_STATFS(mp, sfsp)) 24738270Smckusick RETURN (error); 24838270Smckusick sfsp++; 24938270Smckusick } 25038270Smckusick mp = mp->m_prev; 25138270Smckusick } while (mp != rootfs); 25238270Smckusick if (sfsp && count > maxcount) 25338270Smckusick u.u_r.r_val1 = maxcount; 25438270Smckusick else 25538270Smckusick u.u_r.r_val1 = count; 25638270Smckusick RETURN (0); 25738270Smckusick } 25838270Smckusick 25938270Smckusick /* 26038259Smckusick * Change current working directory to a given file descriptor. 26138259Smckusick */ 26238259Smckusick fchdir() 26338259Smckusick { 26438259Smckusick struct a { 26538259Smckusick int fd; 26638259Smckusick } *uap = (struct a *)u.u_ap; 26738259Smckusick register struct vnode *vp; 26838259Smckusick struct file *fp; 26938259Smckusick int error; 27038259Smckusick 27138259Smckusick if (error = getvnode(uap->fd, &fp)) 27238259Smckusick RETURN (error); 27338259Smckusick vp = (struct vnode *)fp->f_data; 27438259Smckusick VOP_LOCK(vp); 27538259Smckusick if (vp->v_type != VDIR) 27638259Smckusick error = ENOTDIR; 27738259Smckusick else 278*38399Smckusick error = VOP_ACCESS(vp, VEXEC, u.u_cred); 27938259Smckusick VOP_UNLOCK(vp); 28038259Smckusick vrele(u.u_cdir); 28138259Smckusick u.u_cdir = vp; 28238259Smckusick RETURN (error); 28338259Smckusick } 28438259Smckusick 28538259Smckusick /* 28637741Smckusick * Change current working directory (``.''). 28737741Smckusick */ 28837741Smckusick chdir() 28937741Smckusick { 29037741Smckusick struct a { 2916254Sroot char *fname; 29216694Smckusick } *uap = (struct a *)u.u_ap; 29316694Smckusick register struct nameidata *ndp = &u.u_nd; 29437741Smckusick int error; 2956254Sroot 29637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 29716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 29816694Smckusick ndp->ni_dirp = uap->fname; 29937741Smckusick if (error = chdirec(ndp)) 30037741Smckusick RETURN (error); 30137741Smckusick vrele(u.u_cdir); 30237741Smckusick u.u_cdir = ndp->ni_vp; 30337741Smckusick RETURN (0); 30437741Smckusick } 3056254Sroot 30637741Smckusick /* 30737741Smckusick * Change notion of root (``/'') directory. 30837741Smckusick */ 30937741Smckusick chroot() 31037741Smckusick { 31137741Smckusick struct a { 31237741Smckusick char *fname; 31337741Smckusick } *uap = (struct a *)u.u_ap; 31437741Smckusick register struct nameidata *ndp = &u.u_nd; 31537741Smckusick int error; 31637741Smckusick 31737741Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 31837741Smckusick RETURN (error); 31937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 32037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 32137741Smckusick ndp->ni_dirp = uap->fname; 32237741Smckusick if (error = chdirec(ndp)) 32337741Smckusick RETURN (error); 32437741Smckusick vrele(u.u_rdir); 32537741Smckusick u.u_rdir = ndp->ni_vp; 32637741Smckusick RETURN (0); 3276254Sroot } 3286254Sroot 32937Sbill /* 33037741Smckusick * Common routine for chroot and chdir. 33137741Smckusick */ 33237741Smckusick chdirec(ndp) 33337741Smckusick register struct nameidata *ndp; 33437741Smckusick { 33537741Smckusick struct vnode *vp; 33637741Smckusick int error; 33737741Smckusick 33837741Smckusick if (error = namei(ndp)) 33937741Smckusick return (error); 34037741Smckusick vp = ndp->ni_vp; 34137741Smckusick if (vp->v_type != VDIR) 34237741Smckusick error = ENOTDIR; 34337741Smckusick else 344*38399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 34537741Smckusick VOP_UNLOCK(vp); 34637741Smckusick if (error) 34737741Smckusick vrele(vp); 34837741Smckusick return (error); 34937741Smckusick } 35037741Smckusick 35137741Smckusick /* 3526254Sroot * Open system call. 3536254Sroot */ 3546254Sroot open() 3556254Sroot { 35612756Ssam struct a { 3576254Sroot char *fname; 3587701Ssam int mode; 35912756Ssam int crtmode; 36012756Ssam } *uap = (struct a *) u.u_ap; 36137741Smckusick struct nameidata *ndp = &u.u_nd; 3626254Sroot 36337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 36437741Smckusick ndp->ni_dirp = uap->fname; 36537741Smckusick RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp, 36637741Smckusick &u.u_r.r_val1)); 3676254Sroot } 3686254Sroot 3696254Sroot /* 3706254Sroot * Creat system call. 3716254Sroot */ 37212756Ssam creat() 3736254Sroot { 37412756Ssam struct a { 3756254Sroot char *fname; 3766254Sroot int fmode; 37712756Ssam } *uap = (struct a *)u.u_ap; 37837741Smckusick struct nameidata *ndp = &u.u_nd; 3796254Sroot 38037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 38137741Smckusick ndp->ni_dirp = uap->fname; 38237741Smckusick RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp, 38337741Smckusick &u.u_r.r_val1)); 3846254Sroot } 3856254Sroot 3866254Sroot /* 3876254Sroot * Common code for open and creat. 38812756Ssam * Check permissions, allocate an open file structure, 38912756Ssam * and call the device open routine if any. 3906254Sroot */ 39137741Smckusick copen(fmode, cmode, ndp, resultfd) 39237741Smckusick int fmode, cmode; 39337741Smckusick struct nameidata *ndp; 39437741Smckusick int *resultfd; 39512756Ssam { 3966254Sroot register struct file *fp; 39737741Smckusick struct file *nfp; 39837741Smckusick int indx, error; 39937741Smckusick extern struct fileops vnops; 4006254Sroot 40137741Smckusick if (error = falloc(&nfp, &indx)) 40237741Smckusick return (error); 40337741Smckusick fp = nfp; 40437741Smckusick u.u_r.r_val1 = indx; /* XXX for fdopen() */ 40537741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 40624543Smckusick u.u_ofile[indx] = NULL; 40737741Smckusick crfree(fp->f_cred); 40837741Smckusick fp->f_count--; 40937741Smckusick return (error); 41012756Ssam } 41137741Smckusick fp->f_flag = fmode & FMASK; 41237741Smckusick fp->f_type = DTYPE_VNODE; 41337741Smckusick fp->f_ops = &vnops; 41437741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 41537741Smckusick if (resultfd) 41637741Smckusick *resultfd = indx; 41737741Smckusick return (0); 4186254Sroot } 4196254Sroot 4206254Sroot /* 4216254Sroot * Mknod system call 4226254Sroot */ 4236254Sroot mknod() 4246254Sroot { 4256254Sroot register struct a { 4266254Sroot char *fname; 4276254Sroot int fmode; 4286254Sroot int dev; 42916694Smckusick } *uap = (struct a *)u.u_ap; 43016694Smckusick register struct nameidata *ndp = &u.u_nd; 43137741Smckusick register struct vnode *vp; 43237741Smckusick struct vattr vattr; 43337741Smckusick int error; 4346254Sroot 43537741Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 43637741Smckusick RETURN (error); 43737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 43816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 43916694Smckusick ndp->ni_dirp = uap->fname; 44037741Smckusick if (error = namei(ndp)) 44137741Smckusick RETURN (error); 44237741Smckusick vp = ndp->ni_vp; 44337741Smckusick if (vp != NULL) { 44437741Smckusick error = EEXIST; 44512756Ssam goto out; 4466254Sroot } 44737741Smckusick vattr_null(&vattr); 44837741Smckusick switch (uap->fmode & IFMT) { 44912756Ssam 45015093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 45137741Smckusick vattr.va_type = VBAD; 45237741Smckusick break; 45312756Ssam case IFCHR: 45437741Smckusick vattr.va_type = VCHR; 45537741Smckusick break; 45612756Ssam case IFBLK: 45737741Smckusick vattr.va_type = VBLK; 45837741Smckusick break; 45937741Smckusick default: 46037741Smckusick error = EINVAL; 46137741Smckusick goto out; 4626254Sroot } 46337741Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 46437741Smckusick vattr.va_rdev = uap->dev; 4656254Sroot out: 46637741Smckusick if (error) 46737741Smckusick VOP_ABORTOP(ndp); 46837741Smckusick else 46937741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 47037741Smckusick RETURN (error); 4716254Sroot } 4726254Sroot 4736254Sroot /* 4746254Sroot * link system call 4756254Sroot */ 4766254Sroot link() 4776254Sroot { 4786254Sroot register struct a { 4796254Sroot char *target; 4806254Sroot char *linkname; 48116694Smckusick } *uap = (struct a *)u.u_ap; 48216694Smckusick register struct nameidata *ndp = &u.u_nd; 48337741Smckusick register struct vnode *vp, *xp; 48437741Smckusick int error; 4856254Sroot 48616694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 48716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48816694Smckusick ndp->ni_dirp = uap->target; 48937741Smckusick if (error = namei(ndp)) 49037741Smckusick RETURN (error); 49137741Smckusick vp = ndp->ni_vp; 49237741Smckusick if (vp->v_type == VDIR && 49337741Smckusick (error = suser(u.u_cred, &u.u_acflag))) 49437741Smckusick goto out1; 49537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 49616694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 49737741Smckusick if (error = namei(ndp)) 49837741Smckusick goto out1; 49937741Smckusick xp = ndp->ni_vp; 5006254Sroot if (xp != NULL) { 50137741Smckusick error = EEXIST; 5026254Sroot goto out; 5036254Sroot } 50437741Smckusick xp = ndp->ni_dvp; 50537741Smckusick if (vp->v_mount != xp->v_mount) 50637741Smckusick error = EXDEV; 5076254Sroot out: 50837741Smckusick if (error) 50937741Smckusick VOP_ABORTOP(ndp); 51037741Smckusick else 51137741Smckusick error = VOP_LINK(vp, ndp); 51237741Smckusick out1: 51337741Smckusick vrele(vp); 51437741Smckusick RETURN (error); 5156254Sroot } 5166254Sroot 5176254Sroot /* 5186254Sroot * symlink -- make a symbolic link 5196254Sroot */ 5206254Sroot symlink() 5216254Sroot { 52237741Smckusick struct a { 5236254Sroot char *target; 5246254Sroot char *linkname; 52516694Smckusick } *uap = (struct a *)u.u_ap; 52616694Smckusick register struct nameidata *ndp = &u.u_nd; 52737741Smckusick register struct vnode *vp; 52837741Smckusick struct vattr vattr; 52937741Smckusick char *target; 53037741Smckusick int error; 5316254Sroot 53216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 53316694Smckusick ndp->ni_dirp = uap->linkname; 53437741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 53537741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 53637741Smckusick goto out1; 53737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 53837741Smckusick if (error = namei(ndp)) 53937741Smckusick goto out1; 54037741Smckusick vp = ndp->ni_vp; 54137741Smckusick if (vp) { 54237741Smckusick error = EEXIST; 54337741Smckusick goto out; 5446254Sroot } 54537741Smckusick vp = ndp->ni_dvp; 54637741Smckusick vattr_null(&vattr); 54737741Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 54837741Smckusick out: 54937741Smckusick if (error) 55037741Smckusick VOP_ABORTOP(ndp); 55137741Smckusick else 55237741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 55337741Smckusick out1: 55437741Smckusick FREE(target, M_NAMEI); 55537741Smckusick RETURN (error); 5566254Sroot } 5576254Sroot 5586254Sroot /* 5596254Sroot * Unlink system call. 5606254Sroot * Hard to avoid races here, especially 5616254Sroot * in unlinking directories. 5626254Sroot */ 5636254Sroot unlink() 5646254Sroot { 5656254Sroot struct a { 5666254Sroot char *fname; 56716694Smckusick } *uap = (struct a *)u.u_ap; 56816694Smckusick register struct nameidata *ndp = &u.u_nd; 56937741Smckusick register struct vnode *vp; 57037741Smckusick int error; 5716254Sroot 57237741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 57316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 57416694Smckusick ndp->ni_dirp = uap->fname; 57537741Smckusick if (error = namei(ndp)) 57637741Smckusick RETURN (error); 57737741Smckusick vp = ndp->ni_vp; 57837741Smckusick if (vp->v_type == VDIR && 57937741Smckusick (error = suser(u.u_cred, &u.u_acflag))) 5806254Sroot goto out; 5816254Sroot /* 5826254Sroot * Don't unlink a mounted file. 5836254Sroot */ 58437741Smckusick if (vp->v_flag & VROOT) { 58537741Smckusick error = EBUSY; 5866254Sroot goto out; 5876254Sroot } 58837741Smckusick if (vp->v_flag & VTEXT) 58937741Smckusick xrele(vp); /* try once to free text */ 5906254Sroot out: 59137741Smckusick if (error) 59237741Smckusick VOP_ABORTOP(ndp); 5937142Smckusick else 59437741Smckusick error = VOP_REMOVE(ndp); 59537741Smckusick RETURN (error); 5966254Sroot } 5976254Sroot 5986254Sroot /* 5996254Sroot * Seek system call 6006254Sroot */ 6018040Sroot lseek() 6026254Sroot { 6036254Sroot register struct file *fp; 6046254Sroot register struct a { 60537741Smckusick int fdes; 6066254Sroot off_t off; 6076254Sroot int sbase; 60816694Smckusick } *uap = (struct a *)u.u_ap; 60937741Smckusick struct vattr vattr; 61037741Smckusick int error; 6116254Sroot 61237741Smckusick if ((unsigned)uap->fdes >= NOFILE || 61337741Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 61437741Smckusick RETURN (EBADF); 61537741Smckusick if (fp->f_type != DTYPE_VNODE) 61637741Smckusick RETURN (ESPIPE); 61713878Ssam switch (uap->sbase) { 61813878Ssam 61913878Ssam case L_INCR: 62013878Ssam fp->f_offset += uap->off; 62113878Ssam break; 62213878Ssam 62313878Ssam case L_XTND: 62437741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 62537741Smckusick &vattr, u.u_cred)) 62637741Smckusick RETURN (error); 62737741Smckusick fp->f_offset = uap->off + vattr.va_size; 62813878Ssam break; 62913878Ssam 63013878Ssam case L_SET: 63113878Ssam fp->f_offset = uap->off; 63213878Ssam break; 63313878Ssam 63413878Ssam default: 63537741Smckusick RETURN (EINVAL); 63613878Ssam } 63713878Ssam u.u_r.r_off = fp->f_offset; 63837741Smckusick RETURN (0); 6396254Sroot } 6406254Sroot 6416254Sroot /* 6426254Sroot * Access system call 6436254Sroot */ 6446254Sroot saccess() 6456254Sroot { 6466254Sroot register struct a { 6476254Sroot char *fname; 6486254Sroot int fmode; 64916694Smckusick } *uap = (struct a *)u.u_ap; 65016694Smckusick register struct nameidata *ndp = &u.u_nd; 65137741Smckusick register struct vnode *vp; 65237741Smckusick int error, mode, svuid, svgid; 6536254Sroot 6546254Sroot svuid = u.u_uid; 6556254Sroot svgid = u.u_gid; 6566254Sroot u.u_uid = u.u_ruid; 6576254Sroot u.u_gid = u.u_rgid; 65837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 65916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 66016694Smckusick ndp->ni_dirp = uap->fname; 66137741Smckusick if (error = namei(ndp)) 66237741Smckusick goto out1; 66337741Smckusick vp = ndp->ni_vp; 66437741Smckusick /* 66537741Smckusick * fmode == 0 means only check for exist 66637741Smckusick */ 66737741Smckusick if (uap->fmode) { 66837741Smckusick mode = 0; 66937741Smckusick if (uap->fmode & R_OK) 67037741Smckusick mode |= VREAD; 67137741Smckusick if (uap->fmode & W_OK) 67237741Smckusick mode |= VWRITE; 67337741Smckusick if (uap->fmode & X_OK) 67437741Smckusick mode |= VEXEC; 675*38399Smckusick if ((error = vn_writechk(vp)) == 0) 676*38399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 6776254Sroot } 67837741Smckusick vput(vp); 67937741Smckusick out1: 6806254Sroot u.u_uid = svuid; 6816254Sroot u.u_gid = svgid; 68237741Smckusick RETURN (error); 6836254Sroot } 6846254Sroot 6856254Sroot /* 6866574Smckusic * Stat system call. This version follows links. 68737Sbill */ 68837Sbill stat() 68937Sbill { 69037Sbill 69116694Smckusick stat1(FOLLOW); 69237Sbill } 69337Sbill 69437Sbill /* 6956574Smckusic * Lstat system call. This version does not follow links. 6965992Swnj */ 6975992Swnj lstat() 6985992Swnj { 69912756Ssam 70016694Smckusick stat1(NOFOLLOW); 70112756Ssam } 70212756Ssam 70312756Ssam stat1(follow) 70412756Ssam int follow; 70512756Ssam { 7065992Swnj register struct a { 7075992Swnj char *fname; 70812756Ssam struct stat *ub; 70916694Smckusick } *uap = (struct a *)u.u_ap; 71037741Smckusick register struct nameidata *ndp = &u.u_nd; 71112756Ssam struct stat sb; 71237741Smckusick int error; 7135992Swnj 71437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 71516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 71616694Smckusick ndp->ni_dirp = uap->fname; 71737741Smckusick if (error = namei(ndp)) 71837741Smckusick RETURN (error); 71937741Smckusick error = vn_stat(ndp->ni_vp, &sb); 72037741Smckusick vput(ndp->ni_vp); 72137741Smckusick if (error) 72237741Smckusick RETURN (error); 72337741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 72437741Smckusick RETURN (error); 7255992Swnj } 7265992Swnj 7275992Swnj /* 7285992Swnj * Return target name of a symbolic link 72937Sbill */ 7305992Swnj readlink() 7315992Swnj { 7325992Swnj register struct a { 7335992Swnj char *name; 7345992Swnj char *buf; 7355992Swnj int count; 7367826Sroot } *uap = (struct a *)u.u_ap; 73716694Smckusick register struct nameidata *ndp = &u.u_nd; 73837741Smckusick register struct vnode *vp; 73937741Smckusick struct iovec aiov; 74037741Smckusick struct uio auio; 74137741Smckusick int error; 7425992Swnj 74337741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 74416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 74516694Smckusick ndp->ni_dirp = uap->name; 74637741Smckusick if (error = namei(ndp)) 74737741Smckusick RETURN (error); 74837741Smckusick vp = ndp->ni_vp; 74937741Smckusick if (vp->v_type != VLNK) { 75037741Smckusick error = EINVAL; 7515992Swnj goto out; 7525992Swnj } 75337741Smckusick aiov.iov_base = uap->buf; 75437741Smckusick aiov.iov_len = uap->count; 75537741Smckusick auio.uio_iov = &aiov; 75637741Smckusick auio.uio_iovcnt = 1; 75737741Smckusick auio.uio_offset = 0; 75837741Smckusick auio.uio_rw = UIO_READ; 75937741Smckusick auio.uio_segflg = UIO_USERSPACE; 76037741Smckusick auio.uio_resid = uap->count; 76137741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 7625992Swnj out: 76337741Smckusick vput(vp); 76437741Smckusick u.u_r.r_val1 = uap->count - auio.uio_resid; 76537741Smckusick RETURN (error); 7665992Swnj } 7675992Swnj 7689167Ssam /* 76938259Smckusick * Change flags of a file given path name. 77038259Smckusick */ 77138259Smckusick chflags() 77238259Smckusick { 77338259Smckusick struct a { 77438259Smckusick char *fname; 77538259Smckusick int flags; 77638259Smckusick } *uap = (struct a *)u.u_ap; 77738259Smckusick register struct nameidata *ndp = &u.u_nd; 77838259Smckusick register struct vnode *vp; 77938259Smckusick struct vattr vattr; 78038259Smckusick int error; 78138259Smckusick 78238259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 78338259Smckusick ndp->ni_segflg = UIO_USERSPACE; 78438259Smckusick ndp->ni_dirp = uap->fname; 78538259Smckusick vattr_null(&vattr); 78638259Smckusick vattr.va_flags = uap->flags; 78738259Smckusick if (error = namei(ndp)) 78838259Smckusick RETURN (error); 78938259Smckusick vp = ndp->ni_vp; 79038259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 79138259Smckusick error = EROFS; 79238259Smckusick goto out; 79338259Smckusick } 79438259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 79538259Smckusick out: 79638259Smckusick vput(vp); 79738259Smckusick RETURN (error); 79838259Smckusick } 79938259Smckusick 80038259Smckusick /* 80138259Smckusick * Change flags of a file given a file descriptor. 80238259Smckusick */ 80338259Smckusick fchflags() 80438259Smckusick { 80538259Smckusick struct a { 80638259Smckusick int fd; 80738259Smckusick int flags; 80838259Smckusick } *uap = (struct a *)u.u_ap; 80938259Smckusick struct vattr vattr; 81038259Smckusick struct vnode *vp; 81138259Smckusick struct file *fp; 81238259Smckusick int error; 81338259Smckusick 81438259Smckusick if (error = getvnode(uap->fd, &fp)) 81538259Smckusick RETURN (error); 81638259Smckusick vattr_null(&vattr); 81738259Smckusick vattr.va_flags = uap->flags; 81838259Smckusick vp = (struct vnode *)fp->f_data; 81938259Smckusick VOP_LOCK(vp); 82038259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 82138259Smckusick error = EROFS; 82238259Smckusick goto out; 82338259Smckusick } 82438259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 82538259Smckusick out: 82638259Smckusick VOP_UNLOCK(vp); 82738259Smckusick RETURN (error); 82838259Smckusick } 82938259Smckusick 83038259Smckusick /* 8319167Ssam * Change mode of a file given path name. 8329167Ssam */ 8336254Sroot chmod() 8345992Swnj { 8357701Ssam struct a { 8366254Sroot char *fname; 8376254Sroot int fmode; 83816694Smckusick } *uap = (struct a *)u.u_ap; 83937741Smckusick register struct nameidata *ndp = &u.u_nd; 84037741Smckusick register struct vnode *vp; 84137741Smckusick struct vattr vattr; 84237741Smckusick int error; 8435992Swnj 84437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 84537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 84637741Smckusick ndp->ni_dirp = uap->fname; 84737741Smckusick vattr_null(&vattr); 84837741Smckusick vattr.va_mode = uap->fmode & 07777; 84937741Smckusick if (error = namei(ndp)) 85037741Smckusick RETURN (error); 85137741Smckusick vp = ndp->ni_vp; 85237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 85337741Smckusick error = EROFS; 85437741Smckusick goto out; 85537741Smckusick } 85637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 85737741Smckusick out: 85837741Smckusick vput(vp); 85937741Smckusick RETURN (error); 8607701Ssam } 8617439Sroot 8629167Ssam /* 8639167Ssam * Change mode of a file given a file descriptor. 8649167Ssam */ 8657701Ssam fchmod() 8667701Ssam { 8677701Ssam struct a { 8687701Ssam int fd; 8697701Ssam int fmode; 87016694Smckusick } *uap = (struct a *)u.u_ap; 87137741Smckusick struct vattr vattr; 87237741Smckusick struct vnode *vp; 87337741Smckusick struct file *fp; 87437741Smckusick int error; 8757701Ssam 87637741Smckusick if (error = getvnode(uap->fd, &fp)) 87737741Smckusick RETURN (error); 87837741Smckusick vattr_null(&vattr); 87937741Smckusick vattr.va_mode = uap->fmode & 07777; 88037741Smckusick vp = (struct vnode *)fp->f_data; 88137741Smckusick VOP_LOCK(vp); 88237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 88337741Smckusick error = EROFS; 88437741Smckusick goto out; 8857439Sroot } 88637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 88737741Smckusick out: 88837741Smckusick VOP_UNLOCK(vp); 88937741Smckusick RETURN (error); 8905992Swnj } 8915992Swnj 8929167Ssam /* 8939167Ssam * Set ownership given a path name. 8949167Ssam */ 8956254Sroot chown() 89637Sbill { 8977701Ssam struct a { 8986254Sroot char *fname; 8996254Sroot int uid; 9006254Sroot int gid; 90116694Smckusick } *uap = (struct a *)u.u_ap; 90236614Sbostic register struct nameidata *ndp = &u.u_nd; 90337741Smckusick register struct vnode *vp; 90437741Smckusick struct vattr vattr; 90537741Smckusick int error; 90637Sbill 90737741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 90836614Sbostic ndp->ni_segflg = UIO_USERSPACE; 90936614Sbostic ndp->ni_dirp = uap->fname; 91037741Smckusick vattr_null(&vattr); 91137741Smckusick vattr.va_uid = uap->uid; 91237741Smckusick vattr.va_gid = uap->gid; 91337741Smckusick if (error = namei(ndp)) 91437741Smckusick RETURN (error); 91537741Smckusick vp = ndp->ni_vp; 91637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91737741Smckusick error = EROFS; 91837741Smckusick goto out; 91937741Smckusick } 92037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 92137741Smckusick out: 92237741Smckusick vput(vp); 92337741Smckusick RETURN (error); 9247701Ssam } 9257439Sroot 9269167Ssam /* 9279167Ssam * Set ownership given a file descriptor. 9289167Ssam */ 9297701Ssam fchown() 9307701Ssam { 9317701Ssam struct a { 9327701Ssam int fd; 9337701Ssam int uid; 9347701Ssam int gid; 93516694Smckusick } *uap = (struct a *)u.u_ap; 93637741Smckusick struct vattr vattr; 93737741Smckusick struct vnode *vp; 93837741Smckusick struct file *fp; 93937741Smckusick int error; 9407701Ssam 94137741Smckusick if (error = getvnode(uap->fd, &fp)) 94237741Smckusick RETURN (error); 94337741Smckusick vattr_null(&vattr); 94437741Smckusick vattr.va_uid = uap->uid; 94537741Smckusick vattr.va_gid = uap->gid; 94637741Smckusick vp = (struct vnode *)fp->f_data; 94737741Smckusick VOP_LOCK(vp); 94837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94937741Smckusick error = EROFS; 95037741Smckusick goto out; 95137741Smckusick } 95237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 95337741Smckusick out: 95437741Smckusick VOP_UNLOCK(vp); 95537741Smckusick RETURN (error); 9567701Ssam } 9577701Ssam 95811811Ssam utimes() 95911811Ssam { 96011811Ssam register struct a { 96111811Ssam char *fname; 96211811Ssam struct timeval *tptr; 96311811Ssam } *uap = (struct a *)u.u_ap; 96437741Smckusick register struct nameidata *ndp = &u.u_nd; 96537741Smckusick register struct vnode *vp; 96611811Ssam struct timeval tv[2]; 96737741Smckusick struct vattr vattr; 96837741Smckusick int error; 96911811Ssam 97037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 97137741Smckusick RETURN (error); 97237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 97337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 97437741Smckusick ndp->ni_dirp = uap->fname; 97537741Smckusick vattr_null(&vattr); 97637741Smckusick vattr.va_atime = tv[0]; 97737741Smckusick vattr.va_mtime = tv[1]; 97837741Smckusick if (error = namei(ndp)) 97937741Smckusick RETURN (error); 98037741Smckusick vp = ndp->ni_vp; 98137741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 98237741Smckusick error = EROFS; 98337741Smckusick goto out; 98421015Smckusick } 98537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 98637741Smckusick out: 98737741Smckusick vput(vp); 98837741Smckusick RETURN (error); 98911811Ssam } 99011811Ssam 9919167Ssam /* 9929167Ssam * Truncate a file given its path name. 9939167Ssam */ 9947701Ssam truncate() 9957701Ssam { 9967701Ssam struct a { 9977701Ssam char *fname; 99826473Skarels off_t length; 9997826Sroot } *uap = (struct a *)u.u_ap; 100016694Smckusick register struct nameidata *ndp = &u.u_nd; 100137741Smckusick register struct vnode *vp; 100237741Smckusick struct vattr vattr; 100337741Smckusick int error; 10047701Ssam 100537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 100616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 100716694Smckusick ndp->ni_dirp = uap->fname; 100837741Smckusick vattr_null(&vattr); 100937741Smckusick vattr.va_size = uap->length; 101037741Smckusick if (error = namei(ndp)) 101137741Smckusick RETURN (error); 101237741Smckusick vp = ndp->ni_vp; 101337741Smckusick if (vp->v_type == VDIR) { 101437741Smckusick error = EISDIR; 101537741Smckusick goto out; 10167701Ssam } 1017*38399Smckusick if ((error = vn_writechk(vp)) || 1018*38399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 101937741Smckusick goto out; 102037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 102137741Smckusick out: 102237741Smckusick vput(vp); 102337741Smckusick RETURN (error); 10247701Ssam } 10257701Ssam 10269167Ssam /* 10279167Ssam * Truncate a file given a file descriptor. 10289167Ssam */ 10297701Ssam ftruncate() 10307701Ssam { 10317701Ssam struct a { 10327701Ssam int fd; 103326473Skarels off_t length; 10347826Sroot } *uap = (struct a *)u.u_ap; 103537741Smckusick struct vattr vattr; 103637741Smckusick struct vnode *vp; 10377701Ssam struct file *fp; 103837741Smckusick int error; 10397701Ssam 104037741Smckusick if (error = getvnode(uap->fd, &fp)) 104137741Smckusick RETURN (error); 104237741Smckusick if ((fp->f_flag & FWRITE) == 0) 104337741Smckusick RETURN (EINVAL); 104437741Smckusick vattr_null(&vattr); 104537741Smckusick vattr.va_size = uap->length; 104637741Smckusick vp = (struct vnode *)fp->f_data; 104737741Smckusick VOP_LOCK(vp); 104837741Smckusick if (vp->v_type == VDIR) { 104937741Smckusick error = EISDIR; 105037741Smckusick goto out; 10517701Ssam } 1052*38399Smckusick if (error = vn_writechk(vp)) 105337741Smckusick goto out; 105437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 105537741Smckusick out: 105637741Smckusick VOP_UNLOCK(vp); 105737741Smckusick RETURN (error); 10587701Ssam } 10597701Ssam 10609167Ssam /* 10619167Ssam * Synch an open file. 10629167Ssam */ 10639167Ssam fsync() 10649167Ssam { 10659167Ssam struct a { 10669167Ssam int fd; 10679167Ssam } *uap = (struct a *)u.u_ap; 10689167Ssam struct file *fp; 106937741Smckusick int error; 10709167Ssam 107137741Smckusick if (error = getvnode(uap->fd, &fp)) 107237741Smckusick RETURN (error); 107337741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 107437741Smckusick RETURN (error); 10759167Ssam } 10769167Ssam 10779167Ssam /* 10789167Ssam * Rename system call. 10799167Ssam * 10809167Ssam * Source and destination must either both be directories, or both 10819167Ssam * not be directories. If target is a directory, it must be empty. 10829167Ssam */ 10837701Ssam rename() 10847701Ssam { 10857701Ssam struct a { 10867701Ssam char *from; 10877701Ssam char *to; 108816694Smckusick } *uap = (struct a *)u.u_ap; 108937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 109016694Smckusick register struct nameidata *ndp = &u.u_nd; 109137741Smckusick struct nameidata tond; 109237741Smckusick int error; 10937701Ssam 109437741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 109516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 109616694Smckusick ndp->ni_dirp = uap->from; 109737741Smckusick if (error = namei(ndp)) 109837741Smckusick RETURN (error); 109937741Smckusick fvp = ndp->ni_vp; 110038266Smckusick nddup(ndp, &tond); 110137741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 110237741Smckusick tond.ni_segflg = UIO_USERSPACE; 110337741Smckusick tond.ni_dirp = uap->to; 110437741Smckusick error = namei(&tond); 110537741Smckusick tdvp = tond.ni_dvp; 110637741Smckusick tvp = tond.ni_vp; 110737741Smckusick if (tvp != NULL) { 110837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 110937741Smckusick error = EISDIR; 111037741Smckusick goto out; 111137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 111237741Smckusick error = ENOTDIR; 111337741Smckusick goto out; 11149167Ssam } 11159167Ssam } 111637741Smckusick if (error) { 111737741Smckusick VOP_ABORTOP(ndp); 111837741Smckusick goto out1; 111937741Smckusick } 112037741Smckusick if (fvp->v_mount != tdvp->v_mount) { 112137741Smckusick error = EXDEV; 11229167Ssam goto out; 112310051Ssam } 112437741Smckusick if (fvp == tdvp || fvp == tvp) 112537741Smckusick error = EINVAL; 112637741Smckusick out: 112737741Smckusick if (error) { 112837741Smckusick VOP_ABORTOP(&tond); 112937741Smckusick VOP_ABORTOP(ndp); 11309167Ssam } else { 113137741Smckusick error = VOP_RENAME(ndp, &tond); 11329167Ssam } 113337741Smckusick out1: 113438266Smckusick ndrele(&tond); 113537741Smckusick RETURN (error); 11367701Ssam } 11377701Ssam 11387535Sroot /* 113912756Ssam * Mkdir system call 114012756Ssam */ 114112756Ssam mkdir() 114212756Ssam { 114312756Ssam struct a { 114412756Ssam char *name; 114512756Ssam int dmode; 114616694Smckusick } *uap = (struct a *)u.u_ap; 114716694Smckusick register struct nameidata *ndp = &u.u_nd; 114837741Smckusick register struct vnode *vp; 114937741Smckusick struct vattr vattr; 115037741Smckusick int error; 115112756Ssam 115237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 115316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 115416694Smckusick ndp->ni_dirp = uap->name; 115537741Smckusick if (error = namei(ndp)) 115637741Smckusick RETURN (error); 115737741Smckusick vp = ndp->ni_vp; 115837741Smckusick if (vp != NULL) { 115937741Smckusick VOP_ABORTOP(ndp); 116037741Smckusick RETURN (EEXIST); 116112756Ssam } 116237741Smckusick vattr_null(&vattr); 116337741Smckusick vattr.va_type = VDIR; 116437741Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 116537741Smckusick error = VOP_MKDIR(ndp, &vattr); 116638145Smckusick if (!error) 116738145Smckusick vput(ndp->ni_vp); 116837741Smckusick RETURN (error); 116912756Ssam } 117012756Ssam 117112756Ssam /* 117212756Ssam * Rmdir system call. 117312756Ssam */ 117412756Ssam rmdir() 117512756Ssam { 117612756Ssam struct a { 117712756Ssam char *name; 117816694Smckusick } *uap = (struct a *)u.u_ap; 117916694Smckusick register struct nameidata *ndp = &u.u_nd; 118037741Smckusick register struct vnode *vp; 118137741Smckusick int error; 118212756Ssam 118337741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 118416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 118516694Smckusick ndp->ni_dirp = uap->name; 118637741Smckusick if (error = namei(ndp)) 118737741Smckusick RETURN (error); 118837741Smckusick vp = ndp->ni_vp; 118937741Smckusick if (vp->v_type != VDIR) { 119037741Smckusick error = ENOTDIR; 119112756Ssam goto out; 119212756Ssam } 119312756Ssam /* 119437741Smckusick * No rmdir "." please. 119512756Ssam */ 119637741Smckusick if (ndp->ni_dvp == vp) { 119737741Smckusick error = EINVAL; 119812756Ssam goto out; 119912756Ssam } 120012756Ssam /* 120137741Smckusick * Don't unlink a mounted file. 120212756Ssam */ 120337741Smckusick if (vp->v_flag & VROOT) 120437741Smckusick error = EBUSY; 120512756Ssam out: 120637741Smckusick if (error) 120737741Smckusick VOP_ABORTOP(ndp); 120837741Smckusick else 120937741Smckusick error = VOP_RMDIR(ndp); 121037741Smckusick RETURN (error); 121112756Ssam } 121212756Ssam 121337741Smckusick /* 121437741Smckusick * Read a block of directory entries in a file system independent format 121537741Smckusick */ 121637741Smckusick getdirentries() 121712756Ssam { 121837741Smckusick register struct a { 121937741Smckusick int fd; 122037741Smckusick char *buf; 122137741Smckusick unsigned count; 122237741Smckusick long *basep; 122337741Smckusick } *uap = (struct a *)u.u_ap; 122416540Ssam struct file *fp; 122537741Smckusick struct uio auio; 122637741Smckusick struct iovec aiov; 122738129Smckusick off_t off; 122837741Smckusick int error; 122912756Ssam 123037741Smckusick if (error = getvnode(uap->fd, &fp)) 123137741Smckusick RETURN (error); 123237741Smckusick if ((fp->f_flag & FREAD) == 0) 123337741Smckusick RETURN (EBADF); 123437741Smckusick aiov.iov_base = uap->buf; 123537741Smckusick aiov.iov_len = uap->count; 123637741Smckusick auio.uio_iov = &aiov; 123737741Smckusick auio.uio_iovcnt = 1; 123837741Smckusick auio.uio_rw = UIO_READ; 123937741Smckusick auio.uio_segflg = UIO_USERSPACE; 124037741Smckusick auio.uio_resid = uap->count; 124138129Smckusick off = fp->f_offset; 124237741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 124337741Smckusick &(fp->f_offset), fp->f_cred)) 124437741Smckusick RETURN (error); 124538129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 124637741Smckusick sizeof(long)); 124737741Smckusick u.u_r.r_val1 = uap->count - auio.uio_resid; 124837741Smckusick RETURN (error); 124912756Ssam } 125012756Ssam 125112756Ssam /* 125212756Ssam * mode mask for creation of files 125312756Ssam */ 125412756Ssam umask() 125512756Ssam { 125612756Ssam register struct a { 125712756Ssam int mask; 125816694Smckusick } *uap = (struct a *)u.u_ap; 125912756Ssam 126012756Ssam u.u_r.r_val1 = u.u_cmask; 126112756Ssam u.u_cmask = uap->mask & 07777; 126237741Smckusick RETURN (0); 126312756Ssam } 126437741Smckusick 126537741Smckusick getvnode(fdes, fpp) 126637741Smckusick struct file **fpp; 126737741Smckusick int fdes; 126837741Smckusick { 126937741Smckusick struct file *fp; 127037741Smckusick 127137741Smckusick if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) 127237741Smckusick return (EBADF); 127337741Smckusick if (fp->f_type != DTYPE_VNODE) 127437741Smckusick return (EINVAL); 127537741Smckusick *fpp = fp; 127637741Smckusick return (0); 127737741Smckusick } 1278