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*39044Smckusick * @(#)vfs_syscalls.c 7.15 (Berkeley) 09/05/89 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 2237741Smckusick #include "syscontext.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "../ufs/inode.h" 2837741Smckusick #include "mount.h" 2917101Sbloom #include "proc.h" 3017101Sbloom #include "uio.h" 3137741Smckusick #include "malloc.h" 3237Sbill 3337741Smckusick /* 3437741Smckusick * Virtual File System System Calls 3537741Smckusick */ 3612756Ssam 379167Ssam /* 3837741Smckusick * mount system call 399167Ssam */ 4038408Smckusick mount(scp) 4138408Smckusick register struct syscontext *scp; 426254Sroot { 4337741Smckusick register struct a { 4437741Smckusick int type; 4537741Smckusick char *dir; 4637741Smckusick int flags; 4737741Smckusick caddr_t data; 4838408Smckusick } *uap = (struct a *)scp->sc_ap; 4938408Smckusick register struct nameidata *ndp = &scp->sc_nd; 5037741Smckusick struct vnode *vp; 5137741Smckusick struct mount *mp; 5237741Smckusick int error; 536254Sroot 5437741Smckusick /* 5537741Smckusick * Must be super user 5637741Smckusick */ 5738408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 5837741Smckusick RETURN (error); 5937741Smckusick /* 6037741Smckusick * Get vnode to be covered 6137741Smckusick */ 6237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6437741Smckusick ndp->ni_dirp = uap->dir; 6537741Smckusick if (error = namei(ndp)) 6637741Smckusick RETURN (error); 6737741Smckusick vp = ndp->ni_vp; 6837741Smckusick if (vp->v_count != 1) { 6937741Smckusick vput(vp); 7037741Smckusick RETURN (EBUSY); 7137741Smckusick } 7237741Smckusick if (vp->v_type != VDIR) { 7337741Smckusick vput(vp); 7437741Smckusick RETURN (ENOTDIR); 7537741Smckusick } 7637741Smckusick if (uap->type > MOUNT_MAXTYPE || 7737741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 7837741Smckusick vput(vp); 7937741Smckusick RETURN (ENODEV); 8037741Smckusick } 8137741Smckusick 8237741Smckusick /* 8337741Smckusick * Mount the filesystem. 8437741Smckusick */ 8537741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 8637741Smckusick M_MOUNT, M_WAITOK); 8737741Smckusick mp->m_op = vfssw[uap->type]; 8837741Smckusick mp->m_flag = 0; 8937741Smckusick mp->m_exroot = 0; 9037741Smckusick error = vfs_add(vp, mp, uap->flags); 9137741Smckusick if (!error) 9237741Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 9337741Smckusick cache_purge(vp); 9437741Smckusick VOP_UNLOCK(vp); 9537741Smckusick if (!error) { 9637741Smckusick vfs_unlock(mp); 97*39044Smckusick error = VFS_START(mp, 0); 9837741Smckusick } else { 9937741Smckusick vfs_remove(mp); 10037741Smckusick free((caddr_t)mp, M_MOUNT); 10137741Smckusick vrele(vp); 10237741Smckusick } 10337741Smckusick RETURN (error); 1046254Sroot } 1056254Sroot 1069167Ssam /* 10737741Smckusick * Unmount system call. 10837741Smckusick * 10937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 11037741Smckusick * not special file (as before). 1119167Ssam */ 11238408Smckusick unmount(scp) 11338408Smckusick register struct syscontext *scp; 1146254Sroot { 11537741Smckusick struct a { 11637741Smckusick char *pathp; 11737741Smckusick int flags; 11838408Smckusick } *uap = (struct a *)scp->sc_ap; 11937741Smckusick register struct vnode *vp; 12037741Smckusick register struct mount *mp; 12138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 12237741Smckusick struct vnode *coveredvp; 12337741Smckusick int error; 1246254Sroot 12537741Smckusick /* 12637741Smckusick * Must be super user 12737741Smckusick */ 12838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 12937741Smckusick RETURN (error); 13037741Smckusick 13137741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 13237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 13337741Smckusick ndp->ni_dirp = uap->pathp; 13437741Smckusick if (error = namei(ndp)) 13537741Smckusick RETURN (error); 13637741Smckusick vp = ndp->ni_vp; 13737741Smckusick /* 13837741Smckusick * Must be the root of the filesystem 13937741Smckusick */ 14037741Smckusick if ((vp->v_flag & VROOT) == 0) { 14137741Smckusick vput(vp); 14237741Smckusick RETURN (EINVAL); 14337741Smckusick } 14437741Smckusick mp = vp->v_mount; 14537741Smckusick vput(vp); 14637741Smckusick /* 14737741Smckusick * Do the unmount. 14837741Smckusick */ 14937741Smckusick coveredvp = mp->m_vnodecovered; 15037741Smckusick if (error = vfs_lock(mp)) 15137741Smckusick RETURN (error); 15237741Smckusick 15337741Smckusick xumount(mp); /* remove unused sticky files from text table */ 15437741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 15537741Smckusick VFS_SYNC(mp, MNT_WAIT); 15637741Smckusick 15737741Smckusick error = VFS_UNMOUNT(mp, uap->flags); 15837741Smckusick if (error) { 15937741Smckusick vfs_unlock(mp); 16037741Smckusick } else { 16137741Smckusick vrele(coveredvp); 16237741Smckusick vfs_remove(mp); 16337741Smckusick free((caddr_t)mp, M_MOUNT); 16437741Smckusick } 16537741Smckusick RETURN (error); 1666254Sroot } 1676254Sroot 1689167Ssam /* 16937741Smckusick * Sync system call. 17037741Smckusick * Sync each mounted filesystem. 1719167Ssam */ 17238408Smckusick sync(scp) 17338408Smckusick register struct syscontext *scp; 1746254Sroot { 17537741Smckusick register struct mount *mp; 17637741Smckusick 17737741Smckusick mp = rootfs; 17837741Smckusick do { 17937741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 18037741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 18137741Smckusick mp = mp->m_next; 18237741Smckusick } while (mp != rootfs); 18337741Smckusick } 18437741Smckusick 18537741Smckusick /* 18637741Smckusick * get filesystem statistics 18737741Smckusick */ 18838408Smckusick statfs(scp) 18938408Smckusick register struct syscontext *scp; 19037741Smckusick { 1916254Sroot struct a { 19237741Smckusick char *path; 19337741Smckusick struct statfs *buf; 19438408Smckusick } *uap = (struct a *)scp->sc_ap; 19537741Smckusick register struct vnode *vp; 19638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19737741Smckusick struct statfs sb; 19837741Smckusick int error; 19937741Smckusick 20037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 20137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20237741Smckusick ndp->ni_dirp = uap->path; 20337741Smckusick if (error = namei(ndp)) 20437741Smckusick RETURN (error); 20537741Smckusick vp = ndp->ni_vp; 20637741Smckusick if (error = VFS_STATFS(vp->v_mount, &sb)) 20737741Smckusick goto out; 20837741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 20937741Smckusick out: 21037741Smckusick vput(vp); 21137741Smckusick RETURN (error); 21237741Smckusick } 21337741Smckusick 21438408Smckusick fstatfs(scp) 21538408Smckusick register struct syscontext *scp; 21637741Smckusick { 21737741Smckusick struct a { 21837741Smckusick int fd; 21937741Smckusick struct statfs *buf; 22038408Smckusick } *uap = (struct a *)scp->sc_ap; 22137741Smckusick struct file *fp; 22237741Smckusick struct statfs sb; 22337741Smckusick int error; 22437741Smckusick 22538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 22637741Smckusick RETURN (error); 22737741Smckusick if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 22837741Smckusick RETURN (error); 22937741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 23037741Smckusick } 23137741Smckusick 23237741Smckusick /* 23338270Smckusick * get statistics on all filesystems 23438270Smckusick */ 23538408Smckusick getfsstat(scp) 23638408Smckusick register struct syscontext *scp; 23738270Smckusick { 23838270Smckusick struct a { 23938270Smckusick struct statfs *buf; 24038270Smckusick long bufsize; 24138408Smckusick } *uap = (struct a *)scp->sc_ap; 24238270Smckusick register struct mount *mp; 24338270Smckusick register struct statfs *sfsp; 24438270Smckusick long count, maxcount, error; 24538270Smckusick 24638270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 24738270Smckusick sfsp = uap->buf; 24838270Smckusick mp = rootfs; 24938270Smckusick count = 0; 25038270Smckusick do { 25138270Smckusick count++; 252*39044Smckusick if (sfsp && count <= maxcount && 253*39044Smckusick ((mp->m_flag & M_MLOCK) == 0)) { 25438270Smckusick if (error = VFS_STATFS(mp, sfsp)) 25538270Smckusick RETURN (error); 25638270Smckusick sfsp++; 25738270Smckusick } 25838270Smckusick mp = mp->m_prev; 25938270Smckusick } while (mp != rootfs); 26038270Smckusick if (sfsp && count > maxcount) 26138408Smckusick scp->sc_retval1 = maxcount; 26238270Smckusick else 26338408Smckusick scp->sc_retval1 = count; 26438270Smckusick RETURN (0); 26538270Smckusick } 26638270Smckusick 26738270Smckusick /* 26838259Smckusick * Change current working directory to a given file descriptor. 26938259Smckusick */ 27038408Smckusick fchdir(scp) 27138408Smckusick register struct syscontext *scp; 27238259Smckusick { 27338259Smckusick struct a { 27438259Smckusick int fd; 27538408Smckusick } *uap = (struct a *)scp->sc_ap; 27638259Smckusick register struct vnode *vp; 27738259Smckusick struct file *fp; 27838259Smckusick int error; 27938259Smckusick 28038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 28138259Smckusick RETURN (error); 28238259Smckusick vp = (struct vnode *)fp->f_data; 28338259Smckusick VOP_LOCK(vp); 28438259Smckusick if (vp->v_type != VDIR) 28538259Smckusick error = ENOTDIR; 28638259Smckusick else 28738408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 28838259Smckusick VOP_UNLOCK(vp); 28938408Smckusick vrele(scp->sc_cdir); 29038408Smckusick scp->sc_cdir = vp; 29138259Smckusick RETURN (error); 29238259Smckusick } 29338259Smckusick 29438259Smckusick /* 29537741Smckusick * Change current working directory (``.''). 29637741Smckusick */ 29738408Smckusick chdir(scp) 29838408Smckusick register struct syscontext *scp; 29937741Smckusick { 30037741Smckusick struct a { 3016254Sroot char *fname; 30238408Smckusick } *uap = (struct a *)scp->sc_ap; 30338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 30437741Smckusick int error; 3056254Sroot 30637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 30716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 30816694Smckusick ndp->ni_dirp = uap->fname; 30937741Smckusick if (error = chdirec(ndp)) 31037741Smckusick RETURN (error); 31138408Smckusick vrele(scp->sc_cdir); 31238408Smckusick scp->sc_cdir = ndp->ni_vp; 31337741Smckusick RETURN (0); 31437741Smckusick } 3156254Sroot 31637741Smckusick /* 31737741Smckusick * Change notion of root (``/'') directory. 31837741Smckusick */ 31938408Smckusick chroot(scp) 32038408Smckusick register struct syscontext *scp; 32137741Smckusick { 32237741Smckusick struct a { 32337741Smckusick char *fname; 32438408Smckusick } *uap = (struct a *)scp->sc_ap; 32538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 32637741Smckusick int error; 32737741Smckusick 32838408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 32937741Smckusick RETURN (error); 33037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 33137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33237741Smckusick ndp->ni_dirp = uap->fname; 33337741Smckusick if (error = chdirec(ndp)) 33437741Smckusick RETURN (error); 33538408Smckusick vrele(scp->sc_rdir); 33638408Smckusick scp->sc_rdir = ndp->ni_vp; 33737741Smckusick RETURN (0); 3386254Sroot } 3396254Sroot 34037Sbill /* 34137741Smckusick * Common routine for chroot and chdir. 34237741Smckusick */ 34337741Smckusick chdirec(ndp) 34437741Smckusick register struct nameidata *ndp; 34537741Smckusick { 34637741Smckusick struct vnode *vp; 34737741Smckusick int error; 34837741Smckusick 34937741Smckusick if (error = namei(ndp)) 35037741Smckusick return (error); 35137741Smckusick vp = ndp->ni_vp; 35237741Smckusick if (vp->v_type != VDIR) 35337741Smckusick error = ENOTDIR; 35437741Smckusick else 35538399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 35637741Smckusick VOP_UNLOCK(vp); 35737741Smckusick if (error) 35837741Smckusick vrele(vp); 35937741Smckusick return (error); 36037741Smckusick } 36137741Smckusick 36237741Smckusick /* 3636254Sroot * Open system call. 3646254Sroot */ 36538408Smckusick open(scp) 36638408Smckusick register struct syscontext *scp; 3676254Sroot { 36812756Ssam struct a { 3696254Sroot char *fname; 3707701Ssam int mode; 37112756Ssam int crtmode; 37238408Smckusick } *uap = (struct a *) scp->sc_ap; 37338408Smckusick struct nameidata *ndp = &scp->sc_nd; 3746254Sroot 37537741Smckusick ndp->ni_segflg = UIO_USERSPACE; 37637741Smckusick ndp->ni_dirp = uap->fname; 37738408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 37838408Smckusick &scp->sc_retval1)); 3796254Sroot } 3806254Sroot 3816254Sroot /* 3826254Sroot * Creat system call. 3836254Sroot */ 38438408Smckusick creat(scp) 38538408Smckusick register struct syscontext *scp; 3866254Sroot { 38712756Ssam struct a { 3886254Sroot char *fname; 3896254Sroot int fmode; 39038408Smckusick } *uap = (struct a *)scp->sc_ap; 39138408Smckusick struct nameidata *ndp = &scp->sc_nd; 3926254Sroot 39337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 39437741Smckusick ndp->ni_dirp = uap->fname; 39538408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 39638408Smckusick ndp, &scp->sc_retval1)); 3976254Sroot } 3986254Sroot 3996254Sroot /* 4006254Sroot * Common code for open and creat. 40112756Ssam * Check permissions, allocate an open file structure, 40212756Ssam * and call the device open routine if any. 4036254Sroot */ 40438408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 40538408Smckusick register struct syscontext *scp; 40637741Smckusick int fmode, cmode; 40737741Smckusick struct nameidata *ndp; 40837741Smckusick int *resultfd; 40912756Ssam { 4106254Sroot register struct file *fp; 41137741Smckusick struct file *nfp; 41237741Smckusick int indx, error; 41337741Smckusick extern struct fileops vnops; 4146254Sroot 41537741Smckusick if (error = falloc(&nfp, &indx)) 41637741Smckusick return (error); 41737741Smckusick fp = nfp; 41838408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 41937741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 42038408Smckusick scp->sc_ofile[indx] = NULL; 42137741Smckusick crfree(fp->f_cred); 42237741Smckusick fp->f_count--; 42337741Smckusick return (error); 42412756Ssam } 42537741Smckusick fp->f_flag = fmode & FMASK; 42637741Smckusick fp->f_type = DTYPE_VNODE; 42737741Smckusick fp->f_ops = &vnops; 42837741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 42937741Smckusick if (resultfd) 43037741Smckusick *resultfd = indx; 43137741Smckusick return (0); 4326254Sroot } 4336254Sroot 4346254Sroot /* 4356254Sroot * Mknod system call 4366254Sroot */ 43738408Smckusick mknod(scp) 43838408Smckusick register struct syscontext *scp; 4396254Sroot { 4406254Sroot register struct a { 4416254Sroot char *fname; 4426254Sroot int fmode; 4436254Sroot int dev; 44438408Smckusick } *uap = (struct a *)scp->sc_ap; 44538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 44637741Smckusick register struct vnode *vp; 44737741Smckusick struct vattr vattr; 44837741Smckusick int error; 4496254Sroot 45038408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 45137741Smckusick RETURN (error); 45237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 45316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 45416694Smckusick ndp->ni_dirp = uap->fname; 45537741Smckusick if (error = namei(ndp)) 45637741Smckusick RETURN (error); 45737741Smckusick vp = ndp->ni_vp; 45837741Smckusick if (vp != NULL) { 45937741Smckusick error = EEXIST; 46012756Ssam goto out; 4616254Sroot } 46237741Smckusick vattr_null(&vattr); 46337741Smckusick switch (uap->fmode & IFMT) { 46412756Ssam 46515093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 46637741Smckusick vattr.va_type = VBAD; 46737741Smckusick break; 46812756Ssam case IFCHR: 46937741Smckusick vattr.va_type = VCHR; 47037741Smckusick break; 47112756Ssam case IFBLK: 47237741Smckusick vattr.va_type = VBLK; 47337741Smckusick break; 47437741Smckusick default: 47537741Smckusick error = EINVAL; 47637741Smckusick goto out; 4776254Sroot } 47838408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 47937741Smckusick vattr.va_rdev = uap->dev; 4806254Sroot out: 48137741Smckusick if (error) 48237741Smckusick VOP_ABORTOP(ndp); 48337741Smckusick else 48437741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 48537741Smckusick RETURN (error); 4866254Sroot } 4876254Sroot 4886254Sroot /* 4896254Sroot * link system call 4906254Sroot */ 49138408Smckusick link(scp) 49238408Smckusick register struct syscontext *scp; 4936254Sroot { 4946254Sroot register struct a { 4956254Sroot char *target; 4966254Sroot char *linkname; 49738408Smckusick } *uap = (struct a *)scp->sc_ap; 49838408Smckusick register struct nameidata *ndp = &scp->sc_nd; 49937741Smckusick register struct vnode *vp, *xp; 50037741Smckusick int error; 5016254Sroot 50216694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 50316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 50416694Smckusick ndp->ni_dirp = uap->target; 50537741Smckusick if (error = namei(ndp)) 50637741Smckusick RETURN (error); 50737741Smckusick vp = ndp->ni_vp; 50837741Smckusick if (vp->v_type == VDIR && 50938408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 51037741Smckusick goto out1; 51137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 51216694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 51337741Smckusick if (error = namei(ndp)) 51437741Smckusick goto out1; 51537741Smckusick xp = ndp->ni_vp; 5166254Sroot if (xp != NULL) { 51737741Smckusick error = EEXIST; 5186254Sroot goto out; 5196254Sroot } 52037741Smckusick xp = ndp->ni_dvp; 52137741Smckusick if (vp->v_mount != xp->v_mount) 52237741Smckusick error = EXDEV; 5236254Sroot out: 52437741Smckusick if (error) 52537741Smckusick VOP_ABORTOP(ndp); 52637741Smckusick else 52737741Smckusick error = VOP_LINK(vp, ndp); 52837741Smckusick out1: 52937741Smckusick vrele(vp); 53037741Smckusick RETURN (error); 5316254Sroot } 5326254Sroot 5336254Sroot /* 5346254Sroot * symlink -- make a symbolic link 5356254Sroot */ 53638408Smckusick symlink(scp) 53738408Smckusick register struct syscontext *scp; 5386254Sroot { 53937741Smckusick struct a { 5406254Sroot char *target; 5416254Sroot char *linkname; 54238408Smckusick } *uap = (struct a *)scp->sc_ap; 54338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54437741Smckusick register struct vnode *vp; 54537741Smckusick struct vattr vattr; 54637741Smckusick char *target; 54737741Smckusick int error; 5486254Sroot 54916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 55016694Smckusick ndp->ni_dirp = uap->linkname; 55137741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 55237741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 55337741Smckusick goto out1; 55437741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55537741Smckusick if (error = namei(ndp)) 55637741Smckusick goto out1; 55737741Smckusick vp = ndp->ni_vp; 55837741Smckusick if (vp) { 55937741Smckusick error = EEXIST; 56037741Smckusick goto out; 5616254Sroot } 56237741Smckusick vp = ndp->ni_dvp; 56337741Smckusick vattr_null(&vattr); 56438408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 56537741Smckusick out: 56637741Smckusick if (error) 56737741Smckusick VOP_ABORTOP(ndp); 56837741Smckusick else 56937741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 57037741Smckusick out1: 57137741Smckusick FREE(target, M_NAMEI); 57237741Smckusick RETURN (error); 5736254Sroot } 5746254Sroot 5756254Sroot /* 5766254Sroot * Unlink system call. 5776254Sroot * Hard to avoid races here, especially 5786254Sroot * in unlinking directories. 5796254Sroot */ 58038408Smckusick unlink(scp) 58138408Smckusick register struct syscontext *scp; 5826254Sroot { 5836254Sroot struct a { 5846254Sroot char *fname; 58538408Smckusick } *uap = (struct a *)scp->sc_ap; 58638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 58737741Smckusick register struct vnode *vp; 58837741Smckusick int error; 5896254Sroot 59037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 59116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59216694Smckusick ndp->ni_dirp = uap->fname; 59337741Smckusick if (error = namei(ndp)) 59437741Smckusick RETURN (error); 59537741Smckusick vp = ndp->ni_vp; 59637741Smckusick if (vp->v_type == VDIR && 59738408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 5986254Sroot goto out; 5996254Sroot /* 6006254Sroot * Don't unlink a mounted file. 6016254Sroot */ 60237741Smckusick if (vp->v_flag & VROOT) { 60337741Smckusick error = EBUSY; 6046254Sroot goto out; 6056254Sroot } 60637741Smckusick if (vp->v_flag & VTEXT) 60737741Smckusick xrele(vp); /* try once to free text */ 6086254Sroot out: 60937741Smckusick if (error) 61037741Smckusick VOP_ABORTOP(ndp); 6117142Smckusick else 61237741Smckusick error = VOP_REMOVE(ndp); 61337741Smckusick RETURN (error); 6146254Sroot } 6156254Sroot 6166254Sroot /* 6176254Sroot * Seek system call 6186254Sroot */ 61938408Smckusick lseek(scp) 62038408Smckusick register struct syscontext *scp; 6216254Sroot { 6226254Sroot register struct file *fp; 6236254Sroot register struct a { 62437741Smckusick int fdes; 6256254Sroot off_t off; 6266254Sroot int sbase; 62738408Smckusick } *uap = (struct a *)scp->sc_ap; 62837741Smckusick struct vattr vattr; 62937741Smckusick int error; 6306254Sroot 63137741Smckusick if ((unsigned)uap->fdes >= NOFILE || 63238408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 63337741Smckusick RETURN (EBADF); 63437741Smckusick if (fp->f_type != DTYPE_VNODE) 63537741Smckusick RETURN (ESPIPE); 63613878Ssam switch (uap->sbase) { 63713878Ssam 63813878Ssam case L_INCR: 63913878Ssam fp->f_offset += uap->off; 64013878Ssam break; 64113878Ssam 64213878Ssam case L_XTND: 64337741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 64438408Smckusick &vattr, scp->sc_cred)) 64537741Smckusick RETURN (error); 64637741Smckusick fp->f_offset = uap->off + vattr.va_size; 64713878Ssam break; 64813878Ssam 64913878Ssam case L_SET: 65013878Ssam fp->f_offset = uap->off; 65113878Ssam break; 65213878Ssam 65313878Ssam default: 65437741Smckusick RETURN (EINVAL); 65513878Ssam } 65638408Smckusick scp->sc_offset = fp->f_offset; 65737741Smckusick RETURN (0); 6586254Sroot } 6596254Sroot 6606254Sroot /* 6616254Sroot * Access system call 6626254Sroot */ 66338408Smckusick saccess(scp) 66438408Smckusick register struct syscontext *scp; 6656254Sroot { 6666254Sroot register struct a { 6676254Sroot char *fname; 6686254Sroot int fmode; 66938408Smckusick } *uap = (struct a *)scp->sc_ap; 67038408Smckusick register struct nameidata *ndp = &scp->sc_nd; 67137741Smckusick register struct vnode *vp; 67237741Smckusick int error, mode, svuid, svgid; 6736254Sroot 67438408Smckusick svuid = scp->sc_uid; 67538408Smckusick svgid = scp->sc_gid; 67638408Smckusick scp->sc_uid = scp->sc_ruid; 67738408Smckusick scp->sc_gid = scp->sc_rgid; 67837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 67916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 68016694Smckusick ndp->ni_dirp = uap->fname; 68137741Smckusick if (error = namei(ndp)) 68237741Smckusick goto out1; 68337741Smckusick vp = ndp->ni_vp; 68437741Smckusick /* 68537741Smckusick * fmode == 0 means only check for exist 68637741Smckusick */ 68737741Smckusick if (uap->fmode) { 68837741Smckusick mode = 0; 68937741Smckusick if (uap->fmode & R_OK) 69037741Smckusick mode |= VREAD; 69137741Smckusick if (uap->fmode & W_OK) 69237741Smckusick mode |= VWRITE; 69337741Smckusick if (uap->fmode & X_OK) 69437741Smckusick mode |= VEXEC; 69538399Smckusick if ((error = vn_writechk(vp)) == 0) 69638399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 6976254Sroot } 69837741Smckusick vput(vp); 69937741Smckusick out1: 70038408Smckusick scp->sc_uid = svuid; 70138408Smckusick scp->sc_gid = svgid; 70237741Smckusick RETURN (error); 7036254Sroot } 7046254Sroot 7056254Sroot /* 7066574Smckusic * Stat system call. This version follows links. 70737Sbill */ 70838408Smckusick stat(scp) 70938408Smckusick struct syscontext *scp; 71037Sbill { 71137Sbill 71238408Smckusick stat1(scp, FOLLOW); 71337Sbill } 71437Sbill 71537Sbill /* 7166574Smckusic * Lstat system call. This version does not follow links. 7175992Swnj */ 71838408Smckusick lstat(scp) 71938408Smckusick struct syscontext *scp; 7205992Swnj { 72112756Ssam 72238408Smckusick stat1(scp, NOFOLLOW); 72312756Ssam } 72412756Ssam 72538408Smckusick stat1(scp, follow) 72638408Smckusick register struct syscontext *scp; 72712756Ssam int follow; 72812756Ssam { 7295992Swnj register struct a { 7305992Swnj char *fname; 73112756Ssam struct stat *ub; 73238408Smckusick } *uap = (struct a *)scp->sc_ap; 73338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 73412756Ssam struct stat sb; 73537741Smckusick int error; 7365992Swnj 73737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 73816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73916694Smckusick ndp->ni_dirp = uap->fname; 74037741Smckusick if (error = namei(ndp)) 74137741Smckusick RETURN (error); 74237741Smckusick error = vn_stat(ndp->ni_vp, &sb); 74337741Smckusick vput(ndp->ni_vp); 74437741Smckusick if (error) 74537741Smckusick RETURN (error); 74637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 74737741Smckusick RETURN (error); 7485992Swnj } 7495992Swnj 7505992Swnj /* 7515992Swnj * Return target name of a symbolic link 75237Sbill */ 75338408Smckusick readlink(scp) 75438408Smckusick register struct syscontext *scp; 7555992Swnj { 7565992Swnj register struct a { 7575992Swnj char *name; 7585992Swnj char *buf; 7595992Swnj int count; 76038408Smckusick } *uap = (struct a *)scp->sc_ap; 76138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76237741Smckusick register struct vnode *vp; 76337741Smckusick struct iovec aiov; 76437741Smckusick struct uio auio; 76537741Smckusick int error; 7665992Swnj 76737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 76816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 76916694Smckusick ndp->ni_dirp = uap->name; 77037741Smckusick if (error = namei(ndp)) 77137741Smckusick RETURN (error); 77237741Smckusick vp = ndp->ni_vp; 77337741Smckusick if (vp->v_type != VLNK) { 77437741Smckusick error = EINVAL; 7755992Swnj goto out; 7765992Swnj } 77737741Smckusick aiov.iov_base = uap->buf; 77837741Smckusick aiov.iov_len = uap->count; 77937741Smckusick auio.uio_iov = &aiov; 78037741Smckusick auio.uio_iovcnt = 1; 78137741Smckusick auio.uio_offset = 0; 78237741Smckusick auio.uio_rw = UIO_READ; 78337741Smckusick auio.uio_segflg = UIO_USERSPACE; 78437741Smckusick auio.uio_resid = uap->count; 78537741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 7865992Swnj out: 78737741Smckusick vput(vp); 78838408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 78937741Smckusick RETURN (error); 7905992Swnj } 7915992Swnj 7929167Ssam /* 79338259Smckusick * Change flags of a file given path name. 79438259Smckusick */ 79538408Smckusick chflags(scp) 79638408Smckusick register struct syscontext *scp; 79738259Smckusick { 79838259Smckusick struct a { 79938259Smckusick char *fname; 80038259Smckusick int flags; 80138408Smckusick } *uap = (struct a *)scp->sc_ap; 80238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 80338259Smckusick register struct vnode *vp; 80438259Smckusick struct vattr vattr; 80538259Smckusick int error; 80638259Smckusick 80738259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 80838259Smckusick ndp->ni_segflg = UIO_USERSPACE; 80938259Smckusick ndp->ni_dirp = uap->fname; 81038259Smckusick vattr_null(&vattr); 81138259Smckusick vattr.va_flags = uap->flags; 81238259Smckusick if (error = namei(ndp)) 81338259Smckusick RETURN (error); 81438259Smckusick vp = ndp->ni_vp; 81538259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 81638259Smckusick error = EROFS; 81738259Smckusick goto out; 81838259Smckusick } 81938259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 82038259Smckusick out: 82138259Smckusick vput(vp); 82238259Smckusick RETURN (error); 82338259Smckusick } 82438259Smckusick 82538259Smckusick /* 82638259Smckusick * Change flags of a file given a file descriptor. 82738259Smckusick */ 82838408Smckusick fchflags(scp) 82938408Smckusick register struct syscontext *scp; 83038259Smckusick { 83138259Smckusick struct a { 83238259Smckusick int fd; 83338259Smckusick int flags; 83438408Smckusick } *uap = (struct a *)scp->sc_ap; 83538259Smckusick struct vattr vattr; 83638259Smckusick struct vnode *vp; 83738259Smckusick struct file *fp; 83838259Smckusick int error; 83938259Smckusick 84038408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 84138259Smckusick RETURN (error); 84238259Smckusick vattr_null(&vattr); 84338259Smckusick vattr.va_flags = uap->flags; 84438259Smckusick vp = (struct vnode *)fp->f_data; 84538259Smckusick VOP_LOCK(vp); 84638259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 84738259Smckusick error = EROFS; 84838259Smckusick goto out; 84938259Smckusick } 85038259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 85138259Smckusick out: 85238259Smckusick VOP_UNLOCK(vp); 85338259Smckusick RETURN (error); 85438259Smckusick } 85538259Smckusick 85638259Smckusick /* 8579167Ssam * Change mode of a file given path name. 8589167Ssam */ 85938408Smckusick chmod(scp) 86038408Smckusick register struct syscontext *scp; 8615992Swnj { 8627701Ssam struct a { 8636254Sroot char *fname; 8646254Sroot int fmode; 86538408Smckusick } *uap = (struct a *)scp->sc_ap; 86638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 86737741Smckusick register struct vnode *vp; 86837741Smckusick struct vattr vattr; 86937741Smckusick int error; 8705992Swnj 87137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 87237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 87337741Smckusick ndp->ni_dirp = uap->fname; 87437741Smckusick vattr_null(&vattr); 87537741Smckusick vattr.va_mode = uap->fmode & 07777; 87637741Smckusick if (error = namei(ndp)) 87737741Smckusick RETURN (error); 87837741Smckusick vp = ndp->ni_vp; 87937741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 88037741Smckusick error = EROFS; 88137741Smckusick goto out; 88237741Smckusick } 88337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 88437741Smckusick out: 88537741Smckusick vput(vp); 88637741Smckusick RETURN (error); 8877701Ssam } 8887439Sroot 8899167Ssam /* 8909167Ssam * Change mode of a file given a file descriptor. 8919167Ssam */ 89238408Smckusick fchmod(scp) 89338408Smckusick register struct syscontext *scp; 8947701Ssam { 8957701Ssam struct a { 8967701Ssam int fd; 8977701Ssam int fmode; 89838408Smckusick } *uap = (struct a *)scp->sc_ap; 89937741Smckusick struct vattr vattr; 90037741Smckusick struct vnode *vp; 90137741Smckusick struct file *fp; 90237741Smckusick int error; 9037701Ssam 90438408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 90537741Smckusick RETURN (error); 90637741Smckusick vattr_null(&vattr); 90737741Smckusick vattr.va_mode = uap->fmode & 07777; 90837741Smckusick vp = (struct vnode *)fp->f_data; 90937741Smckusick VOP_LOCK(vp); 91037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 91137741Smckusick error = EROFS; 91237741Smckusick goto out; 9137439Sroot } 91437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 91537741Smckusick out: 91637741Smckusick VOP_UNLOCK(vp); 91737741Smckusick RETURN (error); 9185992Swnj } 9195992Swnj 9209167Ssam /* 9219167Ssam * Set ownership given a path name. 9229167Ssam */ 92338408Smckusick chown(scp) 92438408Smckusick register struct syscontext *scp; 92537Sbill { 9267701Ssam struct a { 9276254Sroot char *fname; 9286254Sroot int uid; 9296254Sroot int gid; 93038408Smckusick } *uap = (struct a *)scp->sc_ap; 93138408Smckusick register struct nameidata *ndp = &scp->sc_nd; 93237741Smckusick register struct vnode *vp; 93337741Smckusick struct vattr vattr; 93437741Smckusick int error; 93537Sbill 93637741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 93736614Sbostic ndp->ni_segflg = UIO_USERSPACE; 93836614Sbostic ndp->ni_dirp = uap->fname; 93937741Smckusick vattr_null(&vattr); 94037741Smckusick vattr.va_uid = uap->uid; 94137741Smckusick vattr.va_gid = uap->gid; 94237741Smckusick if (error = namei(ndp)) 94337741Smckusick RETURN (error); 94437741Smckusick vp = ndp->ni_vp; 94537741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94637741Smckusick error = EROFS; 94737741Smckusick goto out; 94837741Smckusick } 94937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 95037741Smckusick out: 95137741Smckusick vput(vp); 95237741Smckusick RETURN (error); 9537701Ssam } 9547439Sroot 9559167Ssam /* 9569167Ssam * Set ownership given a file descriptor. 9579167Ssam */ 95838408Smckusick fchown(scp) 95938408Smckusick register struct syscontext *scp; 9607701Ssam { 9617701Ssam struct a { 9627701Ssam int fd; 9637701Ssam int uid; 9647701Ssam int gid; 96538408Smckusick } *uap = (struct a *)scp->sc_ap; 96637741Smckusick struct vattr vattr; 96737741Smckusick struct vnode *vp; 96837741Smckusick struct file *fp; 96937741Smckusick int error; 9707701Ssam 97138408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 97237741Smckusick RETURN (error); 97337741Smckusick vattr_null(&vattr); 97437741Smckusick vattr.va_uid = uap->uid; 97537741Smckusick vattr.va_gid = uap->gid; 97637741Smckusick vp = (struct vnode *)fp->f_data; 97737741Smckusick VOP_LOCK(vp); 97837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97937741Smckusick error = EROFS; 98037741Smckusick goto out; 98137741Smckusick } 98237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 98337741Smckusick out: 98437741Smckusick VOP_UNLOCK(vp); 98537741Smckusick RETURN (error); 9867701Ssam } 9877701Ssam 98838408Smckusick utimes(scp) 98938408Smckusick register struct syscontext *scp; 99011811Ssam { 99111811Ssam register struct a { 99211811Ssam char *fname; 99311811Ssam struct timeval *tptr; 99438408Smckusick } *uap = (struct a *)scp->sc_ap; 99538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 99637741Smckusick register struct vnode *vp; 99711811Ssam struct timeval tv[2]; 99837741Smckusick struct vattr vattr; 99937741Smckusick int error; 100011811Ssam 100137741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 100237741Smckusick RETURN (error); 100337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 100437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 100537741Smckusick ndp->ni_dirp = uap->fname; 100637741Smckusick vattr_null(&vattr); 100737741Smckusick vattr.va_atime = tv[0]; 100837741Smckusick vattr.va_mtime = tv[1]; 100937741Smckusick if (error = namei(ndp)) 101037741Smckusick RETURN (error); 101137741Smckusick vp = ndp->ni_vp; 101237741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101337741Smckusick error = EROFS; 101437741Smckusick goto out; 101521015Smckusick } 101637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 101737741Smckusick out: 101837741Smckusick vput(vp); 101937741Smckusick RETURN (error); 102011811Ssam } 102111811Ssam 10229167Ssam /* 10239167Ssam * Truncate a file given its path name. 10249167Ssam */ 102538408Smckusick truncate(scp) 102638408Smckusick register struct syscontext *scp; 10277701Ssam { 10287701Ssam struct a { 10297701Ssam char *fname; 103026473Skarels off_t length; 103138408Smckusick } *uap = (struct a *)scp->sc_ap; 103238408Smckusick register struct nameidata *ndp = &scp->sc_nd; 103337741Smckusick register struct vnode *vp; 103437741Smckusick struct vattr vattr; 103537741Smckusick int error; 10367701Ssam 103737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 103816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103916694Smckusick ndp->ni_dirp = uap->fname; 104037741Smckusick vattr_null(&vattr); 104137741Smckusick vattr.va_size = uap->length; 104237741Smckusick if (error = namei(ndp)) 104337741Smckusick RETURN (error); 104437741Smckusick vp = ndp->ni_vp; 104537741Smckusick if (vp->v_type == VDIR) { 104637741Smckusick error = EISDIR; 104737741Smckusick goto out; 10487701Ssam } 104938399Smckusick if ((error = vn_writechk(vp)) || 105038399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 105137741Smckusick goto out; 105237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 105337741Smckusick out: 105437741Smckusick vput(vp); 105537741Smckusick RETURN (error); 10567701Ssam } 10577701Ssam 10589167Ssam /* 10599167Ssam * Truncate a file given a file descriptor. 10609167Ssam */ 106138408Smckusick ftruncate(scp) 106238408Smckusick register struct syscontext *scp; 10637701Ssam { 10647701Ssam struct a { 10657701Ssam int fd; 106626473Skarels off_t length; 106738408Smckusick } *uap = (struct a *)scp->sc_ap; 106837741Smckusick struct vattr vattr; 106937741Smckusick struct vnode *vp; 10707701Ssam struct file *fp; 107137741Smckusick int error; 10727701Ssam 107338408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 107437741Smckusick RETURN (error); 107537741Smckusick if ((fp->f_flag & FWRITE) == 0) 107637741Smckusick RETURN (EINVAL); 107737741Smckusick vattr_null(&vattr); 107837741Smckusick vattr.va_size = uap->length; 107937741Smckusick vp = (struct vnode *)fp->f_data; 108037741Smckusick VOP_LOCK(vp); 108137741Smckusick if (vp->v_type == VDIR) { 108237741Smckusick error = EISDIR; 108337741Smckusick goto out; 10847701Ssam } 108538399Smckusick if (error = vn_writechk(vp)) 108637741Smckusick goto out; 108737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108837741Smckusick out: 108937741Smckusick VOP_UNLOCK(vp); 109037741Smckusick RETURN (error); 10917701Ssam } 10927701Ssam 10939167Ssam /* 10949167Ssam * Synch an open file. 10959167Ssam */ 109638408Smckusick fsync(scp) 109738408Smckusick register struct syscontext *scp; 10989167Ssam { 10999167Ssam struct a { 11009167Ssam int fd; 110138408Smckusick } *uap = (struct a *)scp->sc_ap; 11029167Ssam struct file *fp; 110337741Smckusick int error; 11049167Ssam 110538408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 110637741Smckusick RETURN (error); 110737741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 110837741Smckusick RETURN (error); 11099167Ssam } 11109167Ssam 11119167Ssam /* 11129167Ssam * Rename system call. 11139167Ssam * 11149167Ssam * Source and destination must either both be directories, or both 11159167Ssam * not be directories. If target is a directory, it must be empty. 11169167Ssam */ 111738408Smckusick rename(scp) 111838408Smckusick register struct syscontext *scp; 11197701Ssam { 11207701Ssam struct a { 11217701Ssam char *from; 11227701Ssam char *to; 112338408Smckusick } *uap = (struct a *)scp->sc_ap; 112437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 112538408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112637741Smckusick struct nameidata tond; 112737741Smckusick int error; 11287701Ssam 112937741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 113016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 113116694Smckusick ndp->ni_dirp = uap->from; 113237741Smckusick if (error = namei(ndp)) 113337741Smckusick RETURN (error); 113437741Smckusick fvp = ndp->ni_vp; 113538266Smckusick nddup(ndp, &tond); 113637741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 113737741Smckusick tond.ni_segflg = UIO_USERSPACE; 113837741Smckusick tond.ni_dirp = uap->to; 113937741Smckusick error = namei(&tond); 114037741Smckusick tdvp = tond.ni_dvp; 114137741Smckusick tvp = tond.ni_vp; 114237741Smckusick if (tvp != NULL) { 114337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 114437741Smckusick error = EISDIR; 114537741Smckusick goto out; 114637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 114737741Smckusick error = ENOTDIR; 114837741Smckusick goto out; 11499167Ssam } 11509167Ssam } 115137741Smckusick if (error) { 115237741Smckusick VOP_ABORTOP(ndp); 115337741Smckusick goto out1; 115437741Smckusick } 115537741Smckusick if (fvp->v_mount != tdvp->v_mount) { 115637741Smckusick error = EXDEV; 11579167Ssam goto out; 115810051Ssam } 115937741Smckusick if (fvp == tdvp || fvp == tvp) 116037741Smckusick error = EINVAL; 116137741Smckusick out: 116237741Smckusick if (error) { 116337741Smckusick VOP_ABORTOP(&tond); 116437741Smckusick VOP_ABORTOP(ndp); 11659167Ssam } else { 116637741Smckusick error = VOP_RENAME(ndp, &tond); 11679167Ssam } 116837741Smckusick out1: 116938266Smckusick ndrele(&tond); 117037741Smckusick RETURN (error); 11717701Ssam } 11727701Ssam 11737535Sroot /* 117412756Ssam * Mkdir system call 117512756Ssam */ 117638408Smckusick mkdir(scp) 117738408Smckusick register struct syscontext *scp; 117812756Ssam { 117912756Ssam struct a { 118012756Ssam char *name; 118112756Ssam int dmode; 118238408Smckusick } *uap = (struct a *)scp->sc_ap; 118338408Smckusick register struct nameidata *ndp = &scp->sc_nd; 118437741Smckusick register struct vnode *vp; 118537741Smckusick struct vattr vattr; 118637741Smckusick int error; 118712756Ssam 118837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 118916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 119016694Smckusick ndp->ni_dirp = uap->name; 119137741Smckusick if (error = namei(ndp)) 119237741Smckusick RETURN (error); 119337741Smckusick vp = ndp->ni_vp; 119437741Smckusick if (vp != NULL) { 119537741Smckusick VOP_ABORTOP(ndp); 119637741Smckusick RETURN (EEXIST); 119712756Ssam } 119837741Smckusick vattr_null(&vattr); 119937741Smckusick vattr.va_type = VDIR; 120038408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 120137741Smckusick error = VOP_MKDIR(ndp, &vattr); 120238145Smckusick if (!error) 120338145Smckusick vput(ndp->ni_vp); 120437741Smckusick RETURN (error); 120512756Ssam } 120612756Ssam 120712756Ssam /* 120812756Ssam * Rmdir system call. 120912756Ssam */ 121038408Smckusick rmdir(scp) 121138408Smckusick register struct syscontext *scp; 121212756Ssam { 121312756Ssam struct a { 121412756Ssam char *name; 121538408Smckusick } *uap = (struct a *)scp->sc_ap; 121638408Smckusick register struct nameidata *ndp = &scp->sc_nd; 121737741Smckusick register struct vnode *vp; 121837741Smckusick int error; 121912756Ssam 122037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 122116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122216694Smckusick ndp->ni_dirp = uap->name; 122337741Smckusick if (error = namei(ndp)) 122437741Smckusick RETURN (error); 122537741Smckusick vp = ndp->ni_vp; 122637741Smckusick if (vp->v_type != VDIR) { 122737741Smckusick error = ENOTDIR; 122812756Ssam goto out; 122912756Ssam } 123012756Ssam /* 123137741Smckusick * No rmdir "." please. 123212756Ssam */ 123337741Smckusick if (ndp->ni_dvp == vp) { 123437741Smckusick error = EINVAL; 123512756Ssam goto out; 123612756Ssam } 123712756Ssam /* 123837741Smckusick * Don't unlink a mounted file. 123912756Ssam */ 124037741Smckusick if (vp->v_flag & VROOT) 124137741Smckusick error = EBUSY; 124212756Ssam out: 124337741Smckusick if (error) 124437741Smckusick VOP_ABORTOP(ndp); 124537741Smckusick else 124637741Smckusick error = VOP_RMDIR(ndp); 124737741Smckusick RETURN (error); 124812756Ssam } 124912756Ssam 125037741Smckusick /* 125137741Smckusick * Read a block of directory entries in a file system independent format 125237741Smckusick */ 125338408Smckusick getdirentries(scp) 125438408Smckusick register struct syscontext *scp; 125512756Ssam { 125637741Smckusick register struct a { 125737741Smckusick int fd; 125837741Smckusick char *buf; 125937741Smckusick unsigned count; 126037741Smckusick long *basep; 126138408Smckusick } *uap = (struct a *)scp->sc_ap; 126216540Ssam struct file *fp; 126337741Smckusick struct uio auio; 126437741Smckusick struct iovec aiov; 126538129Smckusick off_t off; 126637741Smckusick int error; 126712756Ssam 126838408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 126937741Smckusick RETURN (error); 127037741Smckusick if ((fp->f_flag & FREAD) == 0) 127137741Smckusick RETURN (EBADF); 127237741Smckusick aiov.iov_base = uap->buf; 127337741Smckusick aiov.iov_len = uap->count; 127437741Smckusick auio.uio_iov = &aiov; 127537741Smckusick auio.uio_iovcnt = 1; 127637741Smckusick auio.uio_rw = UIO_READ; 127737741Smckusick auio.uio_segflg = UIO_USERSPACE; 127837741Smckusick auio.uio_resid = uap->count; 127938129Smckusick off = fp->f_offset; 128037741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 128137741Smckusick &(fp->f_offset), fp->f_cred)) 128237741Smckusick RETURN (error); 128338129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 128437741Smckusick sizeof(long)); 128538408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 128637741Smckusick RETURN (error); 128712756Ssam } 128812756Ssam 128912756Ssam /* 129012756Ssam * mode mask for creation of files 129112756Ssam */ 129238408Smckusick umask(scp) 129338408Smckusick register struct syscontext *scp; 129412756Ssam { 129512756Ssam register struct a { 129612756Ssam int mask; 129738408Smckusick } *uap = (struct a *)scp->sc_ap; 129812756Ssam 129938408Smckusick scp->sc_retval1 = scp->sc_cmask; 130038408Smckusick scp->sc_cmask = uap->mask & 07777; 130137741Smckusick RETURN (0); 130212756Ssam } 130337741Smckusick 130438408Smckusick getvnode(ofile, fdes, fpp) 130538408Smckusick struct file *ofile[]; 130637741Smckusick struct file **fpp; 130737741Smckusick int fdes; 130837741Smckusick { 130937741Smckusick struct file *fp; 131037741Smckusick 131138408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 131237741Smckusick return (EBADF); 131337741Smckusick if (fp->f_type != DTYPE_VNODE) 131437741Smckusick return (EINVAL); 131537741Smckusick *fpp = fp; 131637741Smckusick return (0); 131737741Smckusick } 1318