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*38408Smckusick * @(#)vfs_syscalls.c 7.14 (Berkeley) 07/04/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 */ 40*38408Smckusick mount(scp) 41*38408Smckusick register struct syscontext *scp; 426254Sroot { 4337741Smckusick register struct a { 4437741Smckusick int type; 4537741Smckusick char *dir; 4637741Smckusick int flags; 4737741Smckusick caddr_t data; 48*38408Smckusick } *uap = (struct a *)scp->sc_ap; 49*38408Smckusick 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 */ 57*38408Smckusick 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); 9737741Smckusick } else { 9837741Smckusick vfs_remove(mp); 9937741Smckusick free((caddr_t)mp, M_MOUNT); 10037741Smckusick vrele(vp); 10137741Smckusick } 10237741Smckusick RETURN (error); 1036254Sroot } 1046254Sroot 1059167Ssam /* 10637741Smckusick * Unmount system call. 10737741Smckusick * 10837741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 10937741Smckusick * not special file (as before). 1109167Ssam */ 111*38408Smckusick unmount(scp) 112*38408Smckusick register struct syscontext *scp; 1136254Sroot { 11437741Smckusick struct a { 11537741Smckusick char *pathp; 11637741Smckusick int flags; 117*38408Smckusick } *uap = (struct a *)scp->sc_ap; 11837741Smckusick register struct vnode *vp; 11937741Smckusick register struct mount *mp; 120*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 12137741Smckusick struct vnode *coveredvp; 12237741Smckusick int error; 1236254Sroot 12437741Smckusick /* 12537741Smckusick * Must be super user 12637741Smckusick */ 127*38408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 12837741Smckusick RETURN (error); 12937741Smckusick 13037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 13137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 13237741Smckusick ndp->ni_dirp = uap->pathp; 13337741Smckusick if (error = namei(ndp)) 13437741Smckusick RETURN (error); 13537741Smckusick vp = ndp->ni_vp; 13637741Smckusick /* 13737741Smckusick * Must be the root of the filesystem 13837741Smckusick */ 13937741Smckusick if ((vp->v_flag & VROOT) == 0) { 14037741Smckusick vput(vp); 14137741Smckusick RETURN (EINVAL); 14237741Smckusick } 14337741Smckusick mp = vp->v_mount; 14437741Smckusick vput(vp); 14537741Smckusick /* 14637741Smckusick * Do the unmount. 14737741Smckusick */ 14837741Smckusick coveredvp = mp->m_vnodecovered; 14937741Smckusick if (error = vfs_lock(mp)) 15037741Smckusick RETURN (error); 15137741Smckusick 15237741Smckusick xumount(mp); /* remove unused sticky files from text table */ 15337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 15437741Smckusick VFS_SYNC(mp, MNT_WAIT); 15537741Smckusick 15637741Smckusick error = VFS_UNMOUNT(mp, uap->flags); 15737741Smckusick if (error) { 15837741Smckusick vfs_unlock(mp); 15937741Smckusick } else { 16037741Smckusick vrele(coveredvp); 16137741Smckusick vfs_remove(mp); 16237741Smckusick free((caddr_t)mp, M_MOUNT); 16337741Smckusick } 16437741Smckusick RETURN (error); 1656254Sroot } 1666254Sroot 1679167Ssam /* 16837741Smckusick * Sync system call. 16937741Smckusick * Sync each mounted filesystem. 1709167Ssam */ 171*38408Smckusick sync(scp) 172*38408Smckusick register struct syscontext *scp; 1736254Sroot { 17437741Smckusick register struct mount *mp; 17537741Smckusick 17637741Smckusick mp = rootfs; 17737741Smckusick do { 17837741Smckusick if ((mp->m_flag & M_RDONLY) == 0) 17937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 18037741Smckusick mp = mp->m_next; 18137741Smckusick } while (mp != rootfs); 18237741Smckusick } 18337741Smckusick 18437741Smckusick /* 18537741Smckusick * get filesystem statistics 18637741Smckusick */ 187*38408Smckusick statfs(scp) 188*38408Smckusick register struct syscontext *scp; 18937741Smckusick { 1906254Sroot struct a { 19137741Smckusick char *path; 19237741Smckusick struct statfs *buf; 193*38408Smckusick } *uap = (struct a *)scp->sc_ap; 19437741Smckusick register struct vnode *vp; 195*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 19637741Smckusick struct statfs sb; 19737741Smckusick int error; 19837741Smckusick 19937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 20037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20137741Smckusick ndp->ni_dirp = uap->path; 20237741Smckusick if (error = namei(ndp)) 20337741Smckusick RETURN (error); 20437741Smckusick vp = ndp->ni_vp; 20537741Smckusick if (error = VFS_STATFS(vp->v_mount, &sb)) 20637741Smckusick goto out; 20737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 20837741Smckusick out: 20937741Smckusick vput(vp); 21037741Smckusick RETURN (error); 21137741Smckusick } 21237741Smckusick 213*38408Smckusick fstatfs(scp) 214*38408Smckusick register struct syscontext *scp; 21537741Smckusick { 21637741Smckusick struct a { 21737741Smckusick int fd; 21837741Smckusick struct statfs *buf; 219*38408Smckusick } *uap = (struct a *)scp->sc_ap; 22037741Smckusick struct file *fp; 22137741Smckusick struct statfs sb; 22237741Smckusick int error; 22337741Smckusick 224*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 22537741Smckusick RETURN (error); 22637741Smckusick if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 22737741Smckusick RETURN (error); 22837741Smckusick RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 22937741Smckusick } 23037741Smckusick 23137741Smckusick /* 23238270Smckusick * get statistics on all filesystems 23338270Smckusick */ 234*38408Smckusick getfsstat(scp) 235*38408Smckusick register struct syscontext *scp; 23638270Smckusick { 23738270Smckusick struct a { 23838270Smckusick struct statfs *buf; 23938270Smckusick long bufsize; 240*38408Smckusick } *uap = (struct a *)scp->sc_ap; 24138270Smckusick register struct mount *mp; 24238270Smckusick register struct statfs *sfsp; 24338270Smckusick long count, maxcount, error; 24438270Smckusick 24538270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 24638270Smckusick sfsp = uap->buf; 24738270Smckusick mp = rootfs; 24838270Smckusick count = 0; 24938270Smckusick do { 25038270Smckusick count++; 25138270Smckusick if (sfsp && count <= maxcount) { 25238270Smckusick if (error = VFS_STATFS(mp, sfsp)) 25338270Smckusick RETURN (error); 25438270Smckusick sfsp++; 25538270Smckusick } 25638270Smckusick mp = mp->m_prev; 25738270Smckusick } while (mp != rootfs); 25838270Smckusick if (sfsp && count > maxcount) 259*38408Smckusick scp->sc_retval1 = maxcount; 26038270Smckusick else 261*38408Smckusick scp->sc_retval1 = count; 26238270Smckusick RETURN (0); 26338270Smckusick } 26438270Smckusick 26538270Smckusick /* 26638259Smckusick * Change current working directory to a given file descriptor. 26738259Smckusick */ 268*38408Smckusick fchdir(scp) 269*38408Smckusick register struct syscontext *scp; 27038259Smckusick { 27138259Smckusick struct a { 27238259Smckusick int fd; 273*38408Smckusick } *uap = (struct a *)scp->sc_ap; 27438259Smckusick register struct vnode *vp; 27538259Smckusick struct file *fp; 27638259Smckusick int error; 27738259Smckusick 278*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 27938259Smckusick RETURN (error); 28038259Smckusick vp = (struct vnode *)fp->f_data; 28138259Smckusick VOP_LOCK(vp); 28238259Smckusick if (vp->v_type != VDIR) 28338259Smckusick error = ENOTDIR; 28438259Smckusick else 285*38408Smckusick error = VOP_ACCESS(vp, VEXEC, scp->sc_cred); 28638259Smckusick VOP_UNLOCK(vp); 287*38408Smckusick vrele(scp->sc_cdir); 288*38408Smckusick scp->sc_cdir = vp; 28938259Smckusick RETURN (error); 29038259Smckusick } 29138259Smckusick 29238259Smckusick /* 29337741Smckusick * Change current working directory (``.''). 29437741Smckusick */ 295*38408Smckusick chdir(scp) 296*38408Smckusick register struct syscontext *scp; 29737741Smckusick { 29837741Smckusick struct a { 2996254Sroot char *fname; 300*38408Smckusick } *uap = (struct a *)scp->sc_ap; 301*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 30237741Smckusick int error; 3036254Sroot 30437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 30516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 30616694Smckusick ndp->ni_dirp = uap->fname; 30737741Smckusick if (error = chdirec(ndp)) 30837741Smckusick RETURN (error); 309*38408Smckusick vrele(scp->sc_cdir); 310*38408Smckusick scp->sc_cdir = ndp->ni_vp; 31137741Smckusick RETURN (0); 31237741Smckusick } 3136254Sroot 31437741Smckusick /* 31537741Smckusick * Change notion of root (``/'') directory. 31637741Smckusick */ 317*38408Smckusick chroot(scp) 318*38408Smckusick register struct syscontext *scp; 31937741Smckusick { 32037741Smckusick struct a { 32137741Smckusick char *fname; 322*38408Smckusick } *uap = (struct a *)scp->sc_ap; 323*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 32437741Smckusick int error; 32537741Smckusick 326*38408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 32737741Smckusick RETURN (error); 32837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 32937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33037741Smckusick ndp->ni_dirp = uap->fname; 33137741Smckusick if (error = chdirec(ndp)) 33237741Smckusick RETURN (error); 333*38408Smckusick vrele(scp->sc_rdir); 334*38408Smckusick scp->sc_rdir = ndp->ni_vp; 33537741Smckusick RETURN (0); 3366254Sroot } 3376254Sroot 33837Sbill /* 33937741Smckusick * Common routine for chroot and chdir. 34037741Smckusick */ 34137741Smckusick chdirec(ndp) 34237741Smckusick register struct nameidata *ndp; 34337741Smckusick { 34437741Smckusick struct vnode *vp; 34537741Smckusick int error; 34637741Smckusick 34737741Smckusick if (error = namei(ndp)) 34837741Smckusick return (error); 34937741Smckusick vp = ndp->ni_vp; 35037741Smckusick if (vp->v_type != VDIR) 35137741Smckusick error = ENOTDIR; 35237741Smckusick else 35338399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 35437741Smckusick VOP_UNLOCK(vp); 35537741Smckusick if (error) 35637741Smckusick vrele(vp); 35737741Smckusick return (error); 35837741Smckusick } 35937741Smckusick 36037741Smckusick /* 3616254Sroot * Open system call. 3626254Sroot */ 363*38408Smckusick open(scp) 364*38408Smckusick register struct syscontext *scp; 3656254Sroot { 36612756Ssam struct a { 3676254Sroot char *fname; 3687701Ssam int mode; 36912756Ssam int crtmode; 370*38408Smckusick } *uap = (struct a *) scp->sc_ap; 371*38408Smckusick struct nameidata *ndp = &scp->sc_nd; 3726254Sroot 37337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 37437741Smckusick ndp->ni_dirp = uap->fname; 375*38408Smckusick RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp, 376*38408Smckusick &scp->sc_retval1)); 3776254Sroot } 3786254Sroot 3796254Sroot /* 3806254Sroot * Creat system call. 3816254Sroot */ 382*38408Smckusick creat(scp) 383*38408Smckusick register struct syscontext *scp; 3846254Sroot { 38512756Ssam struct a { 3866254Sroot char *fname; 3876254Sroot int fmode; 388*38408Smckusick } *uap = (struct a *)scp->sc_ap; 389*38408Smckusick struct nameidata *ndp = &scp->sc_nd; 3906254Sroot 39137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 39237741Smckusick ndp->ni_dirp = uap->fname; 393*38408Smckusick RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask, 394*38408Smckusick ndp, &scp->sc_retval1)); 3956254Sroot } 3966254Sroot 3976254Sroot /* 3986254Sroot * Common code for open and creat. 39912756Ssam * Check permissions, allocate an open file structure, 40012756Ssam * and call the device open routine if any. 4016254Sroot */ 402*38408Smckusick copen(scp, fmode, cmode, ndp, resultfd) 403*38408Smckusick register struct syscontext *scp; 40437741Smckusick int fmode, cmode; 40537741Smckusick struct nameidata *ndp; 40637741Smckusick int *resultfd; 40712756Ssam { 4086254Sroot register struct file *fp; 40937741Smckusick struct file *nfp; 41037741Smckusick int indx, error; 41137741Smckusick extern struct fileops vnops; 4126254Sroot 41337741Smckusick if (error = falloc(&nfp, &indx)) 41437741Smckusick return (error); 41537741Smckusick fp = nfp; 416*38408Smckusick scp->sc_retval1 = indx; /* XXX for fdopen() */ 41737741Smckusick if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 418*38408Smckusick scp->sc_ofile[indx] = NULL; 41937741Smckusick crfree(fp->f_cred); 42037741Smckusick fp->f_count--; 42137741Smckusick return (error); 42212756Ssam } 42337741Smckusick fp->f_flag = fmode & FMASK; 42437741Smckusick fp->f_type = DTYPE_VNODE; 42537741Smckusick fp->f_ops = &vnops; 42637741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 42737741Smckusick if (resultfd) 42837741Smckusick *resultfd = indx; 42937741Smckusick return (0); 4306254Sroot } 4316254Sroot 4326254Sroot /* 4336254Sroot * Mknod system call 4346254Sroot */ 435*38408Smckusick mknod(scp) 436*38408Smckusick register struct syscontext *scp; 4376254Sroot { 4386254Sroot register struct a { 4396254Sroot char *fname; 4406254Sroot int fmode; 4416254Sroot int dev; 442*38408Smckusick } *uap = (struct a *)scp->sc_ap; 443*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 44437741Smckusick register struct vnode *vp; 44537741Smckusick struct vattr vattr; 44637741Smckusick int error; 4476254Sroot 448*38408Smckusick if (error = suser(scp->sc_cred, &scp->sc_acflag)) 44937741Smckusick RETURN (error); 45037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 45116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 45216694Smckusick ndp->ni_dirp = uap->fname; 45337741Smckusick if (error = namei(ndp)) 45437741Smckusick RETURN (error); 45537741Smckusick vp = ndp->ni_vp; 45637741Smckusick if (vp != NULL) { 45737741Smckusick error = EEXIST; 45812756Ssam goto out; 4596254Sroot } 46037741Smckusick vattr_null(&vattr); 46137741Smckusick switch (uap->fmode & IFMT) { 46212756Ssam 46315093Smckusick case IFMT: /* used by badsect to flag bad sectors */ 46437741Smckusick vattr.va_type = VBAD; 46537741Smckusick break; 46612756Ssam case IFCHR: 46737741Smckusick vattr.va_type = VCHR; 46837741Smckusick break; 46912756Ssam case IFBLK: 47037741Smckusick vattr.va_type = VBLK; 47137741Smckusick break; 47237741Smckusick default: 47337741Smckusick error = EINVAL; 47437741Smckusick goto out; 4756254Sroot } 476*38408Smckusick vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask; 47737741Smckusick vattr.va_rdev = uap->dev; 4786254Sroot out: 47937741Smckusick if (error) 48037741Smckusick VOP_ABORTOP(ndp); 48137741Smckusick else 48237741Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 48337741Smckusick RETURN (error); 4846254Sroot } 4856254Sroot 4866254Sroot /* 4876254Sroot * link system call 4886254Sroot */ 489*38408Smckusick link(scp) 490*38408Smckusick register struct syscontext *scp; 4916254Sroot { 4926254Sroot register struct a { 4936254Sroot char *target; 4946254Sroot char *linkname; 495*38408Smckusick } *uap = (struct a *)scp->sc_ap; 496*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 49737741Smckusick register struct vnode *vp, *xp; 49837741Smckusick int error; 4996254Sroot 50016694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 50116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 50216694Smckusick ndp->ni_dirp = uap->target; 50337741Smckusick if (error = namei(ndp)) 50437741Smckusick RETURN (error); 50537741Smckusick vp = ndp->ni_vp; 50637741Smckusick if (vp->v_type == VDIR && 507*38408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 50837741Smckusick goto out1; 50937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 51016694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 51137741Smckusick if (error = namei(ndp)) 51237741Smckusick goto out1; 51337741Smckusick xp = ndp->ni_vp; 5146254Sroot if (xp != NULL) { 51537741Smckusick error = EEXIST; 5166254Sroot goto out; 5176254Sroot } 51837741Smckusick xp = ndp->ni_dvp; 51937741Smckusick if (vp->v_mount != xp->v_mount) 52037741Smckusick error = EXDEV; 5216254Sroot out: 52237741Smckusick if (error) 52337741Smckusick VOP_ABORTOP(ndp); 52437741Smckusick else 52537741Smckusick error = VOP_LINK(vp, ndp); 52637741Smckusick out1: 52737741Smckusick vrele(vp); 52837741Smckusick RETURN (error); 5296254Sroot } 5306254Sroot 5316254Sroot /* 5326254Sroot * symlink -- make a symbolic link 5336254Sroot */ 534*38408Smckusick symlink(scp) 535*38408Smckusick register struct syscontext *scp; 5366254Sroot { 53737741Smckusick struct a { 5386254Sroot char *target; 5396254Sroot char *linkname; 540*38408Smckusick } *uap = (struct a *)scp->sc_ap; 541*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 54237741Smckusick register struct vnode *vp; 54337741Smckusick struct vattr vattr; 54437741Smckusick char *target; 54537741Smckusick int error; 5466254Sroot 54716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 54816694Smckusick ndp->ni_dirp = uap->linkname; 54937741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 55037741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 55137741Smckusick goto out1; 55237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 55337741Smckusick if (error = namei(ndp)) 55437741Smckusick goto out1; 55537741Smckusick vp = ndp->ni_vp; 55637741Smckusick if (vp) { 55737741Smckusick error = EEXIST; 55837741Smckusick goto out; 5596254Sroot } 56037741Smckusick vp = ndp->ni_dvp; 56137741Smckusick vattr_null(&vattr); 562*38408Smckusick vattr.va_mode = 0777 &~ scp->sc_cmask; 56337741Smckusick out: 56437741Smckusick if (error) 56537741Smckusick VOP_ABORTOP(ndp); 56637741Smckusick else 56737741Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 56837741Smckusick out1: 56937741Smckusick FREE(target, M_NAMEI); 57037741Smckusick RETURN (error); 5716254Sroot } 5726254Sroot 5736254Sroot /* 5746254Sroot * Unlink system call. 5756254Sroot * Hard to avoid races here, especially 5766254Sroot * in unlinking directories. 5776254Sroot */ 578*38408Smckusick unlink(scp) 579*38408Smckusick register struct syscontext *scp; 5806254Sroot { 5816254Sroot struct a { 5826254Sroot char *fname; 583*38408Smckusick } *uap = (struct a *)scp->sc_ap; 584*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 58537741Smckusick register struct vnode *vp; 58637741Smckusick int error; 5876254Sroot 58837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 58916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 59016694Smckusick ndp->ni_dirp = uap->fname; 59137741Smckusick if (error = namei(ndp)) 59237741Smckusick RETURN (error); 59337741Smckusick vp = ndp->ni_vp; 59437741Smckusick if (vp->v_type == VDIR && 595*38408Smckusick (error = suser(scp->sc_cred, &scp->sc_acflag))) 5966254Sroot goto out; 5976254Sroot /* 5986254Sroot * Don't unlink a mounted file. 5996254Sroot */ 60037741Smckusick if (vp->v_flag & VROOT) { 60137741Smckusick error = EBUSY; 6026254Sroot goto out; 6036254Sroot } 60437741Smckusick if (vp->v_flag & VTEXT) 60537741Smckusick xrele(vp); /* try once to free text */ 6066254Sroot out: 60737741Smckusick if (error) 60837741Smckusick VOP_ABORTOP(ndp); 6097142Smckusick else 61037741Smckusick error = VOP_REMOVE(ndp); 61137741Smckusick RETURN (error); 6126254Sroot } 6136254Sroot 6146254Sroot /* 6156254Sroot * Seek system call 6166254Sroot */ 617*38408Smckusick lseek(scp) 618*38408Smckusick register struct syscontext *scp; 6196254Sroot { 6206254Sroot register struct file *fp; 6216254Sroot register struct a { 62237741Smckusick int fdes; 6236254Sroot off_t off; 6246254Sroot int sbase; 625*38408Smckusick } *uap = (struct a *)scp->sc_ap; 62637741Smckusick struct vattr vattr; 62737741Smckusick int error; 6286254Sroot 62937741Smckusick if ((unsigned)uap->fdes >= NOFILE || 630*38408Smckusick (fp = scp->sc_ofile[uap->fdes]) == NULL) 63137741Smckusick RETURN (EBADF); 63237741Smckusick if (fp->f_type != DTYPE_VNODE) 63337741Smckusick RETURN (ESPIPE); 63413878Ssam switch (uap->sbase) { 63513878Ssam 63613878Ssam case L_INCR: 63713878Ssam fp->f_offset += uap->off; 63813878Ssam break; 63913878Ssam 64013878Ssam case L_XTND: 64137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 642*38408Smckusick &vattr, scp->sc_cred)) 64337741Smckusick RETURN (error); 64437741Smckusick fp->f_offset = uap->off + vattr.va_size; 64513878Ssam break; 64613878Ssam 64713878Ssam case L_SET: 64813878Ssam fp->f_offset = uap->off; 64913878Ssam break; 65013878Ssam 65113878Ssam default: 65237741Smckusick RETURN (EINVAL); 65313878Ssam } 654*38408Smckusick scp->sc_offset = fp->f_offset; 65537741Smckusick RETURN (0); 6566254Sroot } 6576254Sroot 6586254Sroot /* 6596254Sroot * Access system call 6606254Sroot */ 661*38408Smckusick saccess(scp) 662*38408Smckusick register struct syscontext *scp; 6636254Sroot { 6646254Sroot register struct a { 6656254Sroot char *fname; 6666254Sroot int fmode; 667*38408Smckusick } *uap = (struct a *)scp->sc_ap; 668*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 66937741Smckusick register struct vnode *vp; 67037741Smckusick int error, mode, svuid, svgid; 6716254Sroot 672*38408Smckusick svuid = scp->sc_uid; 673*38408Smckusick svgid = scp->sc_gid; 674*38408Smckusick scp->sc_uid = scp->sc_ruid; 675*38408Smckusick scp->sc_gid = scp->sc_rgid; 67637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 67716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 67816694Smckusick ndp->ni_dirp = uap->fname; 67937741Smckusick if (error = namei(ndp)) 68037741Smckusick goto out1; 68137741Smckusick vp = ndp->ni_vp; 68237741Smckusick /* 68337741Smckusick * fmode == 0 means only check for exist 68437741Smckusick */ 68537741Smckusick if (uap->fmode) { 68637741Smckusick mode = 0; 68737741Smckusick if (uap->fmode & R_OK) 68837741Smckusick mode |= VREAD; 68937741Smckusick if (uap->fmode & W_OK) 69037741Smckusick mode |= VWRITE; 69137741Smckusick if (uap->fmode & X_OK) 69237741Smckusick mode |= VEXEC; 69338399Smckusick if ((error = vn_writechk(vp)) == 0) 69438399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 6956254Sroot } 69637741Smckusick vput(vp); 69737741Smckusick out1: 698*38408Smckusick scp->sc_uid = svuid; 699*38408Smckusick scp->sc_gid = svgid; 70037741Smckusick RETURN (error); 7016254Sroot } 7026254Sroot 7036254Sroot /* 7046574Smckusic * Stat system call. This version follows links. 70537Sbill */ 706*38408Smckusick stat(scp) 707*38408Smckusick struct syscontext *scp; 70837Sbill { 70937Sbill 710*38408Smckusick stat1(scp, FOLLOW); 71137Sbill } 71237Sbill 71337Sbill /* 7146574Smckusic * Lstat system call. This version does not follow links. 7155992Swnj */ 716*38408Smckusick lstat(scp) 717*38408Smckusick struct syscontext *scp; 7185992Swnj { 71912756Ssam 720*38408Smckusick stat1(scp, NOFOLLOW); 72112756Ssam } 72212756Ssam 723*38408Smckusick stat1(scp, follow) 724*38408Smckusick register struct syscontext *scp; 72512756Ssam int follow; 72612756Ssam { 7275992Swnj register struct a { 7285992Swnj char *fname; 72912756Ssam struct stat *ub; 730*38408Smckusick } *uap = (struct a *)scp->sc_ap; 731*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 73212756Ssam struct stat sb; 73337741Smckusick int error; 7345992Swnj 73537741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 73616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73716694Smckusick ndp->ni_dirp = uap->fname; 73837741Smckusick if (error = namei(ndp)) 73937741Smckusick RETURN (error); 74037741Smckusick error = vn_stat(ndp->ni_vp, &sb); 74137741Smckusick vput(ndp->ni_vp); 74237741Smckusick if (error) 74337741Smckusick RETURN (error); 74437741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 74537741Smckusick RETURN (error); 7465992Swnj } 7475992Swnj 7485992Swnj /* 7495992Swnj * Return target name of a symbolic link 75037Sbill */ 751*38408Smckusick readlink(scp) 752*38408Smckusick register struct syscontext *scp; 7535992Swnj { 7545992Swnj register struct a { 7555992Swnj char *name; 7565992Swnj char *buf; 7575992Swnj int count; 758*38408Smckusick } *uap = (struct a *)scp->sc_ap; 759*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 76037741Smckusick register struct vnode *vp; 76137741Smckusick struct iovec aiov; 76237741Smckusick struct uio auio; 76337741Smckusick int error; 7645992Swnj 76537741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 76616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 76716694Smckusick ndp->ni_dirp = uap->name; 76837741Smckusick if (error = namei(ndp)) 76937741Smckusick RETURN (error); 77037741Smckusick vp = ndp->ni_vp; 77137741Smckusick if (vp->v_type != VLNK) { 77237741Smckusick error = EINVAL; 7735992Swnj goto out; 7745992Swnj } 77537741Smckusick aiov.iov_base = uap->buf; 77637741Smckusick aiov.iov_len = uap->count; 77737741Smckusick auio.uio_iov = &aiov; 77837741Smckusick auio.uio_iovcnt = 1; 77937741Smckusick auio.uio_offset = 0; 78037741Smckusick auio.uio_rw = UIO_READ; 78137741Smckusick auio.uio_segflg = UIO_USERSPACE; 78237741Smckusick auio.uio_resid = uap->count; 78337741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 7845992Swnj out: 78537741Smckusick vput(vp); 786*38408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 78737741Smckusick RETURN (error); 7885992Swnj } 7895992Swnj 7909167Ssam /* 79138259Smckusick * Change flags of a file given path name. 79238259Smckusick */ 793*38408Smckusick chflags(scp) 794*38408Smckusick register struct syscontext *scp; 79538259Smckusick { 79638259Smckusick struct a { 79738259Smckusick char *fname; 79838259Smckusick int flags; 799*38408Smckusick } *uap = (struct a *)scp->sc_ap; 800*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 80138259Smckusick register struct vnode *vp; 80238259Smckusick struct vattr vattr; 80338259Smckusick int error; 80438259Smckusick 80538259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 80638259Smckusick ndp->ni_segflg = UIO_USERSPACE; 80738259Smckusick ndp->ni_dirp = uap->fname; 80838259Smckusick vattr_null(&vattr); 80938259Smckusick vattr.va_flags = uap->flags; 81038259Smckusick if (error = namei(ndp)) 81138259Smckusick RETURN (error); 81238259Smckusick vp = ndp->ni_vp; 81338259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 81438259Smckusick error = EROFS; 81538259Smckusick goto out; 81638259Smckusick } 81738259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 81838259Smckusick out: 81938259Smckusick vput(vp); 82038259Smckusick RETURN (error); 82138259Smckusick } 82238259Smckusick 82338259Smckusick /* 82438259Smckusick * Change flags of a file given a file descriptor. 82538259Smckusick */ 826*38408Smckusick fchflags(scp) 827*38408Smckusick register struct syscontext *scp; 82838259Smckusick { 82938259Smckusick struct a { 83038259Smckusick int fd; 83138259Smckusick int flags; 832*38408Smckusick } *uap = (struct a *)scp->sc_ap; 83338259Smckusick struct vattr vattr; 83438259Smckusick struct vnode *vp; 83538259Smckusick struct file *fp; 83638259Smckusick int error; 83738259Smckusick 838*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 83938259Smckusick RETURN (error); 84038259Smckusick vattr_null(&vattr); 84138259Smckusick vattr.va_flags = uap->flags; 84238259Smckusick vp = (struct vnode *)fp->f_data; 84338259Smckusick VOP_LOCK(vp); 84438259Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 84538259Smckusick error = EROFS; 84638259Smckusick goto out; 84738259Smckusick } 84838259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 84938259Smckusick out: 85038259Smckusick VOP_UNLOCK(vp); 85138259Smckusick RETURN (error); 85238259Smckusick } 85338259Smckusick 85438259Smckusick /* 8559167Ssam * Change mode of a file given path name. 8569167Ssam */ 857*38408Smckusick chmod(scp) 858*38408Smckusick register struct syscontext *scp; 8595992Swnj { 8607701Ssam struct a { 8616254Sroot char *fname; 8626254Sroot int fmode; 863*38408Smckusick } *uap = (struct a *)scp->sc_ap; 864*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 86537741Smckusick register struct vnode *vp; 86637741Smckusick struct vattr vattr; 86737741Smckusick int error; 8685992Swnj 86937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 87037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 87137741Smckusick ndp->ni_dirp = uap->fname; 87237741Smckusick vattr_null(&vattr); 87337741Smckusick vattr.va_mode = uap->fmode & 07777; 87437741Smckusick if (error = namei(ndp)) 87537741Smckusick RETURN (error); 87637741Smckusick vp = ndp->ni_vp; 87737741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 87837741Smckusick error = EROFS; 87937741Smckusick goto out; 88037741Smckusick } 88137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 88237741Smckusick out: 88337741Smckusick vput(vp); 88437741Smckusick RETURN (error); 8857701Ssam } 8867439Sroot 8879167Ssam /* 8889167Ssam * Change mode of a file given a file descriptor. 8899167Ssam */ 890*38408Smckusick fchmod(scp) 891*38408Smckusick register struct syscontext *scp; 8927701Ssam { 8937701Ssam struct a { 8947701Ssam int fd; 8957701Ssam int fmode; 896*38408Smckusick } *uap = (struct a *)scp->sc_ap; 89737741Smckusick struct vattr vattr; 89837741Smckusick struct vnode *vp; 89937741Smckusick struct file *fp; 90037741Smckusick int error; 9017701Ssam 902*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 90337741Smckusick RETURN (error); 90437741Smckusick vattr_null(&vattr); 90537741Smckusick vattr.va_mode = uap->fmode & 07777; 90637741Smckusick vp = (struct vnode *)fp->f_data; 90737741Smckusick VOP_LOCK(vp); 90837741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 90937741Smckusick error = EROFS; 91037741Smckusick goto out; 9117439Sroot } 91237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 91337741Smckusick out: 91437741Smckusick VOP_UNLOCK(vp); 91537741Smckusick RETURN (error); 9165992Swnj } 9175992Swnj 9189167Ssam /* 9199167Ssam * Set ownership given a path name. 9209167Ssam */ 921*38408Smckusick chown(scp) 922*38408Smckusick register struct syscontext *scp; 92337Sbill { 9247701Ssam struct a { 9256254Sroot char *fname; 9266254Sroot int uid; 9276254Sroot int gid; 928*38408Smckusick } *uap = (struct a *)scp->sc_ap; 929*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 93037741Smckusick register struct vnode *vp; 93137741Smckusick struct vattr vattr; 93237741Smckusick int error; 93337Sbill 93437741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 93536614Sbostic ndp->ni_segflg = UIO_USERSPACE; 93636614Sbostic ndp->ni_dirp = uap->fname; 93737741Smckusick vattr_null(&vattr); 93837741Smckusick vattr.va_uid = uap->uid; 93937741Smckusick vattr.va_gid = uap->gid; 94037741Smckusick if (error = namei(ndp)) 94137741Smckusick RETURN (error); 94237741Smckusick vp = ndp->ni_vp; 94337741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 94437741Smckusick error = EROFS; 94537741Smckusick goto out; 94637741Smckusick } 94737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 94837741Smckusick out: 94937741Smckusick vput(vp); 95037741Smckusick RETURN (error); 9517701Ssam } 9527439Sroot 9539167Ssam /* 9549167Ssam * Set ownership given a file descriptor. 9559167Ssam */ 956*38408Smckusick fchown(scp) 957*38408Smckusick register struct syscontext *scp; 9587701Ssam { 9597701Ssam struct a { 9607701Ssam int fd; 9617701Ssam int uid; 9627701Ssam int gid; 963*38408Smckusick } *uap = (struct a *)scp->sc_ap; 96437741Smckusick struct vattr vattr; 96537741Smckusick struct vnode *vp; 96637741Smckusick struct file *fp; 96737741Smckusick int error; 9687701Ssam 969*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 97037741Smckusick RETURN (error); 97137741Smckusick vattr_null(&vattr); 97237741Smckusick vattr.va_uid = uap->uid; 97337741Smckusick vattr.va_gid = uap->gid; 97437741Smckusick vp = (struct vnode *)fp->f_data; 97537741Smckusick VOP_LOCK(vp); 97637741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 97737741Smckusick error = EROFS; 97837741Smckusick goto out; 97937741Smckusick } 98037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 98137741Smckusick out: 98237741Smckusick VOP_UNLOCK(vp); 98337741Smckusick RETURN (error); 9847701Ssam } 9857701Ssam 986*38408Smckusick utimes(scp) 987*38408Smckusick register struct syscontext *scp; 98811811Ssam { 98911811Ssam register struct a { 99011811Ssam char *fname; 99111811Ssam struct timeval *tptr; 992*38408Smckusick } *uap = (struct a *)scp->sc_ap; 993*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 99437741Smckusick register struct vnode *vp; 99511811Ssam struct timeval tv[2]; 99637741Smckusick struct vattr vattr; 99737741Smckusick int error; 99811811Ssam 99937741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 100037741Smckusick RETURN (error); 100137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 100237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 100337741Smckusick ndp->ni_dirp = uap->fname; 100437741Smckusick vattr_null(&vattr); 100537741Smckusick vattr.va_atime = tv[0]; 100637741Smckusick vattr.va_mtime = tv[1]; 100737741Smckusick if (error = namei(ndp)) 100837741Smckusick RETURN (error); 100937741Smckusick vp = ndp->ni_vp; 101037741Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 101137741Smckusick error = EROFS; 101237741Smckusick goto out; 101321015Smckusick } 101437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 101537741Smckusick out: 101637741Smckusick vput(vp); 101737741Smckusick RETURN (error); 101811811Ssam } 101911811Ssam 10209167Ssam /* 10219167Ssam * Truncate a file given its path name. 10229167Ssam */ 1023*38408Smckusick truncate(scp) 1024*38408Smckusick register struct syscontext *scp; 10257701Ssam { 10267701Ssam struct a { 10277701Ssam char *fname; 102826473Skarels off_t length; 1029*38408Smckusick } *uap = (struct a *)scp->sc_ap; 1030*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 103137741Smckusick register struct vnode *vp; 103237741Smckusick struct vattr vattr; 103337741Smckusick int error; 10347701Ssam 103537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 103616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103716694Smckusick ndp->ni_dirp = uap->fname; 103837741Smckusick vattr_null(&vattr); 103937741Smckusick vattr.va_size = uap->length; 104037741Smckusick if (error = namei(ndp)) 104137741Smckusick RETURN (error); 104237741Smckusick vp = ndp->ni_vp; 104337741Smckusick if (vp->v_type == VDIR) { 104437741Smckusick error = EISDIR; 104537741Smckusick goto out; 10467701Ssam } 104738399Smckusick if ((error = vn_writechk(vp)) || 104838399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 104937741Smckusick goto out; 105037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 105137741Smckusick out: 105237741Smckusick vput(vp); 105337741Smckusick RETURN (error); 10547701Ssam } 10557701Ssam 10569167Ssam /* 10579167Ssam * Truncate a file given a file descriptor. 10589167Ssam */ 1059*38408Smckusick ftruncate(scp) 1060*38408Smckusick register struct syscontext *scp; 10617701Ssam { 10627701Ssam struct a { 10637701Ssam int fd; 106426473Skarels off_t length; 1065*38408Smckusick } *uap = (struct a *)scp->sc_ap; 106637741Smckusick struct vattr vattr; 106737741Smckusick struct vnode *vp; 10687701Ssam struct file *fp; 106937741Smckusick int error; 10707701Ssam 1071*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 107237741Smckusick RETURN (error); 107337741Smckusick if ((fp->f_flag & FWRITE) == 0) 107437741Smckusick RETURN (EINVAL); 107537741Smckusick vattr_null(&vattr); 107637741Smckusick vattr.va_size = uap->length; 107737741Smckusick vp = (struct vnode *)fp->f_data; 107837741Smckusick VOP_LOCK(vp); 107937741Smckusick if (vp->v_type == VDIR) { 108037741Smckusick error = EISDIR; 108137741Smckusick goto out; 10827701Ssam } 108338399Smckusick if (error = vn_writechk(vp)) 108437741Smckusick goto out; 108537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 108637741Smckusick out: 108737741Smckusick VOP_UNLOCK(vp); 108837741Smckusick RETURN (error); 10897701Ssam } 10907701Ssam 10919167Ssam /* 10929167Ssam * Synch an open file. 10939167Ssam */ 1094*38408Smckusick fsync(scp) 1095*38408Smckusick register struct syscontext *scp; 10969167Ssam { 10979167Ssam struct a { 10989167Ssam int fd; 1099*38408Smckusick } *uap = (struct a *)scp->sc_ap; 11009167Ssam struct file *fp; 110137741Smckusick int error; 11029167Ssam 1103*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 110437741Smckusick RETURN (error); 110537741Smckusick error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 110637741Smckusick RETURN (error); 11079167Ssam } 11089167Ssam 11099167Ssam /* 11109167Ssam * Rename system call. 11119167Ssam * 11129167Ssam * Source and destination must either both be directories, or both 11139167Ssam * not be directories. If target is a directory, it must be empty. 11149167Ssam */ 1115*38408Smckusick rename(scp) 1116*38408Smckusick register struct syscontext *scp; 11177701Ssam { 11187701Ssam struct a { 11197701Ssam char *from; 11207701Ssam char *to; 1121*38408Smckusick } *uap = (struct a *)scp->sc_ap; 112237741Smckusick register struct vnode *tvp, *fvp, *tdvp; 1123*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 112437741Smckusick struct nameidata tond; 112537741Smckusick int error; 11267701Ssam 112737741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 112816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 112916694Smckusick ndp->ni_dirp = uap->from; 113037741Smckusick if (error = namei(ndp)) 113137741Smckusick RETURN (error); 113237741Smckusick fvp = ndp->ni_vp; 113338266Smckusick nddup(ndp, &tond); 113437741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 113537741Smckusick tond.ni_segflg = UIO_USERSPACE; 113637741Smckusick tond.ni_dirp = uap->to; 113737741Smckusick error = namei(&tond); 113837741Smckusick tdvp = tond.ni_dvp; 113937741Smckusick tvp = tond.ni_vp; 114037741Smckusick if (tvp != NULL) { 114137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 114237741Smckusick error = EISDIR; 114337741Smckusick goto out; 114437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 114537741Smckusick error = ENOTDIR; 114637741Smckusick goto out; 11479167Ssam } 11489167Ssam } 114937741Smckusick if (error) { 115037741Smckusick VOP_ABORTOP(ndp); 115137741Smckusick goto out1; 115237741Smckusick } 115337741Smckusick if (fvp->v_mount != tdvp->v_mount) { 115437741Smckusick error = EXDEV; 11559167Ssam goto out; 115610051Ssam } 115737741Smckusick if (fvp == tdvp || fvp == tvp) 115837741Smckusick error = EINVAL; 115937741Smckusick out: 116037741Smckusick if (error) { 116137741Smckusick VOP_ABORTOP(&tond); 116237741Smckusick VOP_ABORTOP(ndp); 11639167Ssam } else { 116437741Smckusick error = VOP_RENAME(ndp, &tond); 11659167Ssam } 116637741Smckusick out1: 116738266Smckusick ndrele(&tond); 116837741Smckusick RETURN (error); 11697701Ssam } 11707701Ssam 11717535Sroot /* 117212756Ssam * Mkdir system call 117312756Ssam */ 1174*38408Smckusick mkdir(scp) 1175*38408Smckusick register struct syscontext *scp; 117612756Ssam { 117712756Ssam struct a { 117812756Ssam char *name; 117912756Ssam int dmode; 1180*38408Smckusick } *uap = (struct a *)scp->sc_ap; 1181*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 118237741Smckusick register struct vnode *vp; 118337741Smckusick struct vattr vattr; 118437741Smckusick int error; 118512756Ssam 118637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 118716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 118816694Smckusick ndp->ni_dirp = uap->name; 118937741Smckusick if (error = namei(ndp)) 119037741Smckusick RETURN (error); 119137741Smckusick vp = ndp->ni_vp; 119237741Smckusick if (vp != NULL) { 119337741Smckusick VOP_ABORTOP(ndp); 119437741Smckusick RETURN (EEXIST); 119512756Ssam } 119637741Smckusick vattr_null(&vattr); 119737741Smckusick vattr.va_type = VDIR; 1198*38408Smckusick vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask; 119937741Smckusick error = VOP_MKDIR(ndp, &vattr); 120038145Smckusick if (!error) 120138145Smckusick vput(ndp->ni_vp); 120237741Smckusick RETURN (error); 120312756Ssam } 120412756Ssam 120512756Ssam /* 120612756Ssam * Rmdir system call. 120712756Ssam */ 1208*38408Smckusick rmdir(scp) 1209*38408Smckusick register struct syscontext *scp; 121012756Ssam { 121112756Ssam struct a { 121212756Ssam char *name; 1213*38408Smckusick } *uap = (struct a *)scp->sc_ap; 1214*38408Smckusick register struct nameidata *ndp = &scp->sc_nd; 121537741Smckusick register struct vnode *vp; 121637741Smckusick int error; 121712756Ssam 121837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 121916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 122016694Smckusick ndp->ni_dirp = uap->name; 122137741Smckusick if (error = namei(ndp)) 122237741Smckusick RETURN (error); 122337741Smckusick vp = ndp->ni_vp; 122437741Smckusick if (vp->v_type != VDIR) { 122537741Smckusick error = ENOTDIR; 122612756Ssam goto out; 122712756Ssam } 122812756Ssam /* 122937741Smckusick * No rmdir "." please. 123012756Ssam */ 123137741Smckusick if (ndp->ni_dvp == vp) { 123237741Smckusick error = EINVAL; 123312756Ssam goto out; 123412756Ssam } 123512756Ssam /* 123637741Smckusick * Don't unlink a mounted file. 123712756Ssam */ 123837741Smckusick if (vp->v_flag & VROOT) 123937741Smckusick error = EBUSY; 124012756Ssam out: 124137741Smckusick if (error) 124237741Smckusick VOP_ABORTOP(ndp); 124337741Smckusick else 124437741Smckusick error = VOP_RMDIR(ndp); 124537741Smckusick RETURN (error); 124612756Ssam } 124712756Ssam 124837741Smckusick /* 124937741Smckusick * Read a block of directory entries in a file system independent format 125037741Smckusick */ 1251*38408Smckusick getdirentries(scp) 1252*38408Smckusick register struct syscontext *scp; 125312756Ssam { 125437741Smckusick register struct a { 125537741Smckusick int fd; 125637741Smckusick char *buf; 125737741Smckusick unsigned count; 125837741Smckusick long *basep; 1259*38408Smckusick } *uap = (struct a *)scp->sc_ap; 126016540Ssam struct file *fp; 126137741Smckusick struct uio auio; 126237741Smckusick struct iovec aiov; 126338129Smckusick off_t off; 126437741Smckusick int error; 126512756Ssam 1266*38408Smckusick if (error = getvnode(scp->sc_ofile, uap->fd, &fp)) 126737741Smckusick RETURN (error); 126837741Smckusick if ((fp->f_flag & FREAD) == 0) 126937741Smckusick RETURN (EBADF); 127037741Smckusick aiov.iov_base = uap->buf; 127137741Smckusick aiov.iov_len = uap->count; 127237741Smckusick auio.uio_iov = &aiov; 127337741Smckusick auio.uio_iovcnt = 1; 127437741Smckusick auio.uio_rw = UIO_READ; 127537741Smckusick auio.uio_segflg = UIO_USERSPACE; 127637741Smckusick auio.uio_resid = uap->count; 127738129Smckusick off = fp->f_offset; 127837741Smckusick if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 127937741Smckusick &(fp->f_offset), fp->f_cred)) 128037741Smckusick RETURN (error); 128138129Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, 128237741Smckusick sizeof(long)); 1283*38408Smckusick scp->sc_retval1 = uap->count - auio.uio_resid; 128437741Smckusick RETURN (error); 128512756Ssam } 128612756Ssam 128712756Ssam /* 128812756Ssam * mode mask for creation of files 128912756Ssam */ 1290*38408Smckusick umask(scp) 1291*38408Smckusick register struct syscontext *scp; 129212756Ssam { 129312756Ssam register struct a { 129412756Ssam int mask; 1295*38408Smckusick } *uap = (struct a *)scp->sc_ap; 129612756Ssam 1297*38408Smckusick scp->sc_retval1 = scp->sc_cmask; 1298*38408Smckusick scp->sc_cmask = uap->mask & 07777; 129937741Smckusick RETURN (0); 130012756Ssam } 130137741Smckusick 1302*38408Smckusick getvnode(ofile, fdes, fpp) 1303*38408Smckusick struct file *ofile[]; 130437741Smckusick struct file **fpp; 130537741Smckusick int fdes; 130637741Smckusick { 130737741Smckusick struct file *fp; 130837741Smckusick 1309*38408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 131037741Smckusick return (EBADF); 131137741Smckusick if (fp->f_type != DTYPE_VNODE) 131237741Smckusick return (EINVAL); 131337741Smckusick *fpp = fp; 131437741Smckusick return (0); 131537741Smckusick } 1316