PageRenderTime 10ms CodeModel.GetById 8ms app.highlight 163ms RepoModel.GetById 1ms app.codeStats 1ms

/netbsd/src/sys/kern/vfs_syscalls.c

https://bitbucket.org/mischief/oskit
C | 2114 lines | 1609 code | 115 blank | 390 comment | 363 complexity | 2e4908f50cc0f97808dd585eea860811 MD5 | raw file
   1/*	$NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $	*/
   2
   3/*
   4 * Copyright (c) 1989, 1993
   5 *	The Regents of the University of California.  All rights reserved.
   6 * (c) UNIX System Laboratories, Inc.
   7 * All or some portions of this file are derived from material licensed
   8 * to the University of California by American Telephone and Telegraph
   9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  10 * the permission of UNIX System Laboratories, Inc.
  11 *
  12 * Redistribution and use in source and binary forms, with or without
  13 * modification, are permitted provided that the following conditions
  14 * are met:
  15 * 1. Redistributions of source code must retain the above copyright
  16 *    notice, this list of conditions and the following disclaimer.
  17 * 2. Redistributions in binary form must reproduce the above copyright
  18 *    notice, this list of conditions and the following disclaimer in the
  19 *    documentation and/or other materials provided with the distribution.
  20 * 3. All advertising materials mentioning features or use of this software
  21 *    must display the following acknowledgement:
  22 *	This product includes software developed by the University of
  23 *	California, Berkeley and its contributors.
  24 * 4. Neither the name of the University nor the names of its contributors
  25 *    may be used to endorse or promote products derived from this software
  26 *    without specific prior written permission.
  27 *
  28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38 * SUCH DAMAGE.
  39 *
  40 *	@(#)vfs_syscalls.c	8.28 (Berkeley) 12/10/94
  41 */
  42
  43#include <sys/param.h>
  44#include <sys/systm.h>
  45#include <sys/namei.h>
  46#include <sys/filedesc.h>
  47#include <sys/kernel.h>
  48#include <sys/file.h>
  49#include <sys/stat.h>
  50#include <sys/vnode.h>
  51#include <sys/mount.h>
  52#include <sys/proc.h>
  53#include <sys/uio.h>
  54#include <sys/malloc.h>
  55#include <sys/dirent.h>
  56
  57#include <sys/syscallargs.h>
  58
  59#include <vm/vm.h>
  60#include <sys/sysctl.h>
  61
  62static int change_dir __P((struct nameidata *, struct proc *));
  63
  64void checkdirs __P((struct vnode *));
  65int dounmount __P((struct mount *, int, struct proc *));
  66
  67/*
  68 * Virtual File System System Calls
  69 */
  70
  71/*
  72 * Mount a file system.
  73 */
  74/* ARGSUSED */
  75int
  76sys_mount(p, v, retval)
  77	struct proc *p;
  78	void *v;
  79	register_t *retval;
  80{
  81	register struct sys_mount_args /* {
  82		syscallarg(char *) type;
  83		syscallarg(char *) path;
  84		syscallarg(int) flags;
  85		syscallarg(caddr_t) data;
  86	} */ *uap = v;
  87	register struct vnode *vp;
  88	register struct mount *mp;
  89	int error, flag = 0;
  90	u_long fsindex = 0;
  91	char fstypename[MFSNAMELEN];
  92	struct vattr va;
  93	struct nameidata nd;
  94
  95	/*
  96	 * Get vnode to be covered
  97	 */
  98	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
  99	    SCARG(uap, path), p);
 100	if ((error = namei(&nd)) != 0)
 101		return (error);
 102	vp = nd.ni_vp;
 103	if (SCARG(uap, flags) & MNT_UPDATE) {
 104		if ((vp->v_flag & VROOT) == 0) {
 105			vput(vp);
 106			return (EINVAL);
 107		}
 108		mp = vp->v_mount;
 109		flag = mp->mnt_flag;
 110		/*
 111		 * We only allow the filesystem to be reloaded if it
 112		 * is currently mounted read-only.
 113		 */
 114		if ((SCARG(uap, flags) & MNT_RELOAD) &&
 115		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
 116			vput(vp);
 117			return (EOPNOTSUPP);	/* Needs translation */
 118		}
 119		mp->mnt_flag |=
 120		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
 121		/*
 122		 * Only root, or the user that did the original mount is
 123		 * permitted to update it.
 124		 */
 125		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
 126		    (error = suser(p->p_ucred, &p->p_acflag))) {
 127			vput(vp);
 128			return (error);
 129		}
 130		/*
 131		 * Do not allow NFS export by non-root users. Silently
 132		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
 133		 */
 134		if (p->p_ucred->cr_uid != 0) {
 135			if (SCARG(uap, flags) & MNT_EXPORTED) {
 136				vput(vp);
 137				return (EPERM);
 138			}
 139			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
 140		}
 141		VOP_UNLOCK(vp);
 142		goto update;
 143	}
 144	/*
 145	 * If the user is not root, ensure that they own the directory
 146	 * onto which we are attempting to mount.
 147	 */
 148	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
 149	    (va.va_uid != p->p_ucred->cr_uid &&
 150	     (error = suser(p->p_ucred, &p->p_acflag)))) {
 151		vput(vp);
 152		return (error);
 153	}
 154	/*
 155	 * Do not allow NFS export by non-root users. Silently
 156	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
 157	 */
 158	if (p->p_ucred->cr_uid != 0) {
 159		if (SCARG(uap, flags) & MNT_EXPORTED) {
 160			vput(vp);
 161			return (EPERM);
 162		}
 163		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
 164	}
 165	if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
 166		return (error);
 167	if (vp->v_type != VDIR) {
 168		vput(vp);
 169		return (ENOTDIR);
 170	}
 171	error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
 172	if (error) {
 173#if defined(COMPAT_09) || defined(COMPAT_43)
 174		/*
 175		 * Historically filesystem types were identified by number.
 176		 * If we get an integer for the filesystem type instead of a
 177		 * string, we check to see if it matches one of the historic
 178		 * filesystem types.
 179		 */     
 180		fsindex = (u_long)SCARG(uap, type);
 181		if (fsindex >= nvfssw || vfssw[fsindex] == NULL) {
 182			vput(vp);
 183			return (ENODEV);
 184		}
 185		strncpy(fstypename, vfssw[fsindex]->vfs_name, MFSNAMELEN);
 186#else
 187		vput(vp);
 188		return (error);
 189#endif
 190	}
 191#ifdef	COMPAT_10
 192	/* Accept `ufs' as an alias for `ffs'. */
 193	if (!strncmp(fstypename, "ufs", MFSNAMELEN))
 194		strncpy(fstypename, "ffs", MFSNAMELEN);
 195#endif
 196	for (fsindex = 0; fsindex < nvfssw; fsindex++)
 197		if (vfssw[fsindex] != NULL &&
 198		    !strncmp(vfssw[fsindex]->vfs_name, fstypename, MFSNAMELEN))
 199			break;
 200	if (fsindex >= nvfssw) {
 201		vput(vp);
 202		return (ENODEV);
 203	}
 204	if (vp->v_mountedhere != NULL) {
 205		vput(vp);
 206		return (EBUSY);
 207	}
 208
 209	/*
 210	 * Allocate and initialize the file system.
 211	 */
 212	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
 213		M_MOUNT, M_WAITOK);
 214	bzero((char *)mp, (u_long)sizeof(struct mount));
 215	mp->mnt_op = vfssw[fsindex];
 216	if ((error = vfs_lock(mp)) != 0) {
 217		free((caddr_t)mp, M_MOUNT);
 218		vput(vp);
 219		return (error);
 220	}
 221	/* Do this early in case we block later. */
 222	vfssw[fsindex]->vfs_refcount++;
 223	vp->v_mountedhere = mp;
 224	mp->mnt_vnodecovered = vp;
 225	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
 226update:
 227	/*
 228	 * Set the mount level flags.
 229	 */
 230	if (SCARG(uap, flags) & MNT_RDONLY)
 231		mp->mnt_flag |= MNT_RDONLY;
 232	else if (mp->mnt_flag & MNT_RDONLY)
 233		mp->mnt_flag |= MNT_WANTRDWR;
 234	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
 235	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
 236	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
 237	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
 238	/*
 239	 * Mount the filesystem.
 240	 */
 241	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
 242	if (mp->mnt_flag & MNT_UPDATE) {
 243		vrele(vp);
 244		if (mp->mnt_flag & MNT_WANTRDWR)
 245			mp->mnt_flag &= ~MNT_RDONLY;
 246		mp->mnt_flag &=~
 247		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
 248		if (error)
 249			mp->mnt_flag = flag;
 250		return (error);
 251	}
 252	/*
 253	 * Put the new filesystem on the mount list after root.
 254	 */
 255	cache_purge(vp);
 256	if (!error) {
 257		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
 258		checkdirs(vp);
 259		VOP_UNLOCK(vp);
 260		vfs_unlock(mp);
 261		(void) VFS_STATFS(mp, &mp->mnt_stat, p);
 262		error = VFS_START(mp, 0, p);
 263	} else {
 264		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
 265		vfssw[fsindex]->vfs_refcount--;
 266		vfs_unlock(mp);
 267		free((caddr_t)mp, M_MOUNT);
 268		vput(vp);
 269	}
 270	return (error);
 271}
 272
 273/*
 274 * Scan all active processes to see if any of them have a current
 275 * or root directory onto which the new filesystem has just been
 276 * mounted. If so, replace them with the new mount point.
 277 */
 278void
 279checkdirs(olddp)
 280	struct vnode *olddp;
 281{
 282	struct filedesc *fdp;
 283	struct vnode *newdp;
 284	struct proc *p;
 285
 286	if (olddp->v_usecount == 1)
 287		return;
 288	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
 289		panic("mount: lost mount");
 290	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
 291		fdp = p->p_fd;
 292		if (fdp->fd_cdir == olddp) {
 293			vrele(fdp->fd_cdir);
 294			VREF(newdp);
 295			fdp->fd_cdir = newdp;
 296		}
 297		if (fdp->fd_rdir == olddp) {
 298			vrele(fdp->fd_rdir);
 299			VREF(newdp);
 300			fdp->fd_rdir = newdp;
 301		}
 302	}
 303	if (rootvnode == olddp) {
 304		vrele(rootvnode);
 305		VREF(newdp);
 306		rootvnode = newdp;
 307	}
 308	vput(newdp);
 309}
 310
 311/*
 312 * Unmount a file system.
 313 *
 314 * Note: unmount takes a path to the vnode mounted on as argument,
 315 * not special file (as before).
 316 */
 317/* ARGSUSED */
 318int
 319sys_unmount(p, v, retval)
 320	struct proc *p;
 321	void *v;
 322	register_t *retval;
 323{
 324	register struct sys_unmount_args /* {
 325		syscallarg(char *) path;
 326		syscallarg(int) flags;
 327	} */ *uap = v;
 328	register struct vnode *vp;
 329	struct mount *mp;
 330	int error;
 331	struct nameidata nd;
 332
 333	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
 334	    SCARG(uap, path), p);
 335	if ((error = namei(&nd)) != 0)
 336		return (error);
 337	vp = nd.ni_vp;
 338	mp = vp->v_mount;
 339
 340	/*
 341	 * Only root, or the user that did the original mount is
 342	 * permitted to unmount this filesystem.
 343	 */
 344	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
 345	    (error = suser(p->p_ucred, &p->p_acflag))) {
 346		vput(vp);
 347		return (error);
 348	}
 349
 350	/*
 351	 * Don't allow unmounting the root file system.
 352	 */
 353	if (mp->mnt_flag & MNT_ROOTFS) {
 354		vput(vp);
 355		return (EINVAL);
 356	}
 357
 358	/*
 359	 * Must be the root of the filesystem
 360	 */
 361	if ((vp->v_flag & VROOT) == 0) {
 362		vput(vp);
 363		return (EINVAL);
 364	}
 365	vput(vp);
 366	return (dounmount(mp, SCARG(uap, flags), p));
 367}
 368
 369/*
 370 * Do the actual file system unmount.
 371 */
 372int
 373dounmount(mp, flags, p)
 374	register struct mount *mp;
 375	int flags;
 376	struct proc *p;
 377{
 378	struct vnode *coveredvp;
 379	int error;
 380
 381	coveredvp = mp->mnt_vnodecovered;
 382	if (vfs_busy(mp))
 383		return (EBUSY);
 384	mp->mnt_flag |= MNT_UNMOUNT;
 385	if ((error = vfs_lock(mp)) != 0)
 386		return (error);
 387
 388	mp->mnt_flag &=~ MNT_ASYNC;
 389	vnode_pager_umount(mp);	/* release cached vnodes */
 390	cache_purgevfs(mp);	/* remove cache entries for this file sys */
 391	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
 392	    (flags & MNT_FORCE))
 393		error = VFS_UNMOUNT(mp, flags, p);
 394	mp->mnt_flag &= ~MNT_UNMOUNT;
 395	vfs_unbusy(mp);
 396	if (error) {
 397		vfs_unlock(mp);
 398	} else {
 399		CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
 400		if (coveredvp != NULLVP) {
 401			vrele(coveredvp);
 402			coveredvp->v_mountedhere = (struct mount *)0;
 403		}
 404		mp->mnt_op->vfs_refcount--;
 405		vfs_unlock(mp);
 406		if (mp->mnt_vnodelist.lh_first != NULL)
 407			panic("unmount: dangling vnode");
 408		free((caddr_t)mp, M_MOUNT);
 409	}
 410	return (error);
 411}
 412
 413/*
 414 * Sync each mounted filesystem.
 415 */
 416#ifdef DEBUG
 417int syncprt = 0;
 418struct ctldebug debug0 = { "syncprt", &syncprt };
 419#endif
 420
 421/* ARGSUSED */
 422int
 423sys_sync(p, v, retval)
 424	struct proc *p;
 425	void *v;
 426	register_t *retval;
 427{
 428	register struct mount *mp, *nmp;
 429	int asyncflag;
 430
 431	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
 432		/*
 433		 * Get the next pointer in case we hang on vfs_busy
 434		 * while we are being unmounted.
 435		 */
 436		nmp = mp->mnt_list.cqe_next;
 437		/*
 438		 * The lock check below is to avoid races with mount
 439		 * and unmount.
 440		 */
 441		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
 442		    !vfs_busy(mp)) {
 443			asyncflag = mp->mnt_flag & MNT_ASYNC;
 444			mp->mnt_flag &= ~MNT_ASYNC;
 445			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
 446			if (asyncflag)
 447				mp->mnt_flag |= MNT_ASYNC;
 448			/*
 449			 * Get the next pointer again, as the next filesystem
 450			 * might have been unmounted while we were sync'ing.
 451			 */
 452			nmp = mp->mnt_list.cqe_next;
 453			vfs_unbusy(mp);
 454		}
 455	}
 456#ifdef DEBUG
 457	if (syncprt)
 458		vfs_bufstats();
 459#endif /* DEBUG */
 460	return (0);
 461}
 462
 463/*
 464 * Change filesystem quotas.
 465 */
 466/* ARGSUSED */
 467int
 468sys_quotactl(p, v, retval)
 469	struct proc *p;
 470	void *v;
 471	register_t *retval;
 472{
 473	register struct sys_quotactl_args /* {
 474		syscallarg(char *) path;
 475		syscallarg(int) cmd;
 476		syscallarg(int) uid;
 477		syscallarg(caddr_t) arg;
 478	} */ *uap = v;
 479	register struct mount *mp;
 480	int error;
 481	struct nameidata nd;
 482
 483	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
 484	if ((error = namei(&nd)) != 0)
 485		return (error);
 486	mp = nd.ni_vp->v_mount;
 487	vrele(nd.ni_vp);
 488	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
 489	    SCARG(uap, arg), p));
 490}
 491
 492/*
 493 * Get filesystem statistics.
 494 */
 495/* ARGSUSED */
 496int
 497sys_statfs(p, v, retval)
 498	struct proc *p;
 499	void *v;
 500	register_t *retval;
 501{
 502	register struct sys_statfs_args /* {
 503		syscallarg(char *) path;
 504		syscallarg(struct statfs *) buf;
 505	} */ *uap = v;
 506	register struct mount *mp;
 507	register struct statfs *sp;
 508	int error;
 509	struct nameidata nd;
 510
 511	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
 512	if ((error = namei(&nd)) != 0)
 513		return (error);
 514	mp = nd.ni_vp->v_mount;
 515	sp = &mp->mnt_stat;
 516	vrele(nd.ni_vp);
 517	if ((error = VFS_STATFS(mp, sp, p)) != 0)
 518		return (error);
 519	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
 520	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
 521}
 522
 523/*
 524 * Get filesystem statistics.
 525 */
 526/* ARGSUSED */
 527int
 528sys_fstatfs(p, v, retval)
 529	struct proc *p;
 530	void *v;
 531	register_t *retval;
 532{
 533	register struct sys_fstatfs_args /* {
 534		syscallarg(int) fd;
 535		syscallarg(struct statfs *) buf;
 536	} */ *uap = v;
 537	struct file *fp;
 538	struct mount *mp;
 539	register struct statfs *sp;
 540	int error;
 541
 542	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
 543		return (error);
 544	mp = ((struct vnode *)fp->f_data)->v_mount;
 545	sp = &mp->mnt_stat;
 546	if ((error = VFS_STATFS(mp, sp, p)) != 0)
 547		return (error);
 548	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
 549	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
 550}
 551
 552/*
 553 * Get statistics on all filesystems.
 554 */
 555int
 556sys_getfsstat(p, v, retval)
 557	struct proc *p;
 558	void *v;
 559	register_t *retval;
 560{
 561	register struct sys_getfsstat_args /* {
 562		syscallarg(struct statfs *) buf;
 563		syscallarg(long) bufsize;
 564		syscallarg(int) flags;
 565	} */ *uap = v;
 566	register struct mount *mp, *nmp;
 567	register struct statfs *sp;
 568	caddr_t sfsp;
 569	long count, maxcount, error;
 570
 571	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
 572	sfsp = (caddr_t)SCARG(uap, buf);
 573	for (count = 0,
 574	     mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
 575		nmp = mp->mnt_list.cqe_next;
 576		if (sfsp && count < maxcount &&
 577		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
 578			sp = &mp->mnt_stat;
 579			/*
 580			 * If MNT_NOWAIT is specified, do not refresh the
 581			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
 582			 */
 583			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
 584			    (SCARG(uap, flags) & MNT_WAIT)) &&
 585			    (error = VFS_STATFS(mp, sp, p)))
 586				continue;
 587			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
 588			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
 589			if (error)
 590				return (error);
 591			sfsp += sizeof(*sp);
 592		}
 593		count++;
 594	}
 595	if (sfsp && count > maxcount)
 596		*retval = maxcount;
 597	else
 598		*retval = count;
 599	return (0);
 600}
 601
 602/*
 603 * Change current working directory to a given file descriptor.
 604 */
 605/* ARGSUSED */
 606int
 607sys_fchdir(p, v, retval)
 608	struct proc *p;
 609	void *v;
 610	register_t *retval;
 611{
 612	struct sys_fchdir_args /* {
 613		syscallarg(int) fd;
 614	} */ *uap = v;
 615	register struct filedesc *fdp = p->p_fd;
 616	struct vnode *vp, *tdp;
 617	struct mount *mp;
 618	struct file *fp;
 619	int error;
 620
 621	if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
 622		return (error);
 623	vp = (struct vnode *)fp->f_data;
 624	VREF(vp);
 625	VOP_LOCK(vp);
 626	if (vp->v_type != VDIR)
 627		error = ENOTDIR;
 628	else
 629		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
 630	while (!error && (mp = vp->v_mountedhere) != NULL) {
 631		if (mp->mnt_flag & MNT_MLOCK) {
 632			mp->mnt_flag |= MNT_MWAIT;
 633			sleep((caddr_t)mp, PVFS);
 634			continue;
 635		}
 636		if ((error = VFS_ROOT(mp, &tdp)) != 0)
 637			break;
 638		vput(vp);
 639		vp = tdp;
 640	}
 641	VOP_UNLOCK(vp);
 642	if (error) {
 643		vrele(vp);
 644		return (error);
 645	}
 646	vrele(fdp->fd_cdir);
 647	fdp->fd_cdir = vp;
 648	return (0);
 649}
 650
 651/*
 652 * Change current working directory (``.'').
 653 */
 654/* ARGSUSED */
 655int
 656sys_chdir(p, v, retval)
 657	struct proc *p;
 658	void *v;
 659	register_t *retval;
 660{
 661	struct sys_chdir_args /* {
 662		syscallarg(char *) path;
 663	} */ *uap = v;
 664	register struct filedesc *fdp = p->p_fd;
 665	int error;
 666	struct nameidata nd;
 667
 668	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
 669	    SCARG(uap, path), p);
 670	if ((error = change_dir(&nd, p)) != 0)
 671		return (error);
 672	vrele(fdp->fd_cdir);
 673	fdp->fd_cdir = nd.ni_vp;
 674	return (0);
 675}
 676
 677/*
 678 * Change notion of root (``/'') directory.
 679 */
 680/* ARGSUSED */
 681int
 682sys_chroot(p, v, retval)
 683	struct proc *p;
 684	void *v;
 685	register_t *retval;
 686{
 687	struct sys_chroot_args /* {
 688		syscallarg(char *) path;
 689	} */ *uap = v;
 690	register struct filedesc *fdp = p->p_fd;
 691	int error;
 692	struct nameidata nd;
 693
 694	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
 695		return (error);
 696	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
 697	    SCARG(uap, path), p);
 698	if ((error = change_dir(&nd, p)) != 0)
 699		return (error);
 700	if (fdp->fd_rdir != NULL)
 701		vrele(fdp->fd_rdir);
 702	fdp->fd_rdir = nd.ni_vp;
 703	return (0);
 704}
 705
 706/*
 707 * Common routine for chroot and chdir.
 708 */
 709static int
 710change_dir(ndp, p)
 711	register struct nameidata *ndp;
 712	struct proc *p;
 713{
 714	struct vnode *vp;
 715	int error;
 716
 717	if ((error = namei(ndp)) != 0)
 718		return (error);
 719	vp = ndp->ni_vp;
 720	if (vp->v_type != VDIR)
 721		error = ENOTDIR;
 722	else
 723		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
 724	VOP_UNLOCK(vp);
 725	if (error)
 726		vrele(vp);
 727	return (error);
 728}
 729
 730/*
 731 * Check permissions, allocate an open file structure,
 732 * and call the device open routine if any.
 733 */
 734int
 735sys_open(p, v, retval)
 736	struct proc *p;
 737	void *v;
 738	register_t *retval;
 739{
 740	register struct sys_open_args /* {
 741		syscallarg(char *) path;
 742		syscallarg(int) flags;
 743		syscallarg(int) mode;
 744	} */ *uap = v;
 745	register struct filedesc *fdp = p->p_fd;
 746	register struct file *fp;
 747	register struct vnode *vp;
 748	int flags, cmode;
 749	struct file *nfp;
 750	int type, indx, error;
 751	struct flock lf;
 752	struct nameidata nd;
 753	extern struct fileops vnops;
 754
 755	if ((error = falloc(p, &nfp, &indx)) != 0)
 756		return (error);
 757	fp = nfp;
 758	flags = FFLAGS(SCARG(uap, flags));
 759	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
 760	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
 761	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
 762	if ((error = vn_open(&nd, flags, cmode)) != 0) {
 763		ffree(fp);
 764		if ((error == ENODEV || error == ENXIO) &&
 765		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
 766		    (error =
 767			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
 768			*retval = indx;
 769			return (0);
 770		}
 771		if (error == ERESTART)
 772			error = EINTR;
 773		fdp->fd_ofiles[indx] = NULL;
 774		return (error);
 775	}
 776	p->p_dupfd = 0;
 777	vp = nd.ni_vp;
 778	fp->f_flag = flags & FMASK;
 779	fp->f_type = DTYPE_VNODE;
 780	fp->f_ops = &vnops;
 781	fp->f_data = (caddr_t)vp;
 782	if (flags & (O_EXLOCK | O_SHLOCK)) {
 783		lf.l_whence = SEEK_SET;
 784		lf.l_start = 0;
 785		lf.l_len = 0;
 786		if (flags & O_EXLOCK)
 787			lf.l_type = F_WRLCK;
 788		else
 789			lf.l_type = F_RDLCK;
 790		type = F_FLOCK;
 791		if ((flags & FNONBLOCK) == 0)
 792			type |= F_WAIT;
 793		VOP_UNLOCK(vp);
 794		error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
 795		if (error) {
 796			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
 797			ffree(fp);
 798			fdp->fd_ofiles[indx] = NULL;
 799			return (error);
 800		}
 801		VOP_LOCK(vp);
 802		fp->f_flag |= FHASLOCK;
 803	}
 804	VOP_UNLOCK(vp);
 805	*retval = indx;
 806	return (0);
 807}
 808
 809/*
 810 * Create a special file.
 811 */
 812/* ARGSUSED */
 813int
 814sys_mknod(p, v, retval)
 815	struct proc *p;
 816	void *v;
 817	register_t *retval;
 818{
 819	register struct sys_mknod_args /* {
 820		syscallarg(char *) path;
 821		syscallarg(int) mode;
 822		syscallarg(int) dev;
 823	} */ *uap = v;
 824	register struct vnode *vp;
 825	struct vattr vattr;
 826	int error;
 827	int whiteout = 0;
 828	struct nameidata nd;
 829
 830	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
 831		return (error);
 832	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
 833	if ((error = namei(&nd)) != 0)
 834		return (error);
 835	vp = nd.ni_vp;
 836	if (vp != NULL)
 837		error = EEXIST;
 838	else {
 839		VATTR_NULL(&vattr);
 840		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
 841		vattr.va_rdev = SCARG(uap, dev);
 842		whiteout = 0;
 843
 844		switch (SCARG(uap, mode) & S_IFMT) {
 845		case S_IFMT:	/* used by badsect to flag bad sectors */
 846			vattr.va_type = VBAD;
 847			break;
 848		case S_IFCHR:
 849			vattr.va_type = VCHR;
 850			break;
 851		case S_IFBLK:
 852			vattr.va_type = VBLK;
 853			break;
 854		case S_IFWHT:
 855			whiteout = 1;
 856			break;
 857		default:
 858			error = EINVAL;
 859			break;
 860		}
 861	}
 862	if (!error) {
 863		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
 864		if (whiteout) {
 865			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
 866			if (error)
 867				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
 868			vput(nd.ni_dvp);
 869		} else {
 870			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
 871						&nd.ni_cnd, &vattr);
 872		}
 873	} else {
 874		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
 875		if (nd.ni_dvp == vp)
 876			vrele(nd.ni_dvp);
 877		else
 878			vput(nd.ni_dvp);
 879		if (vp)
 880			vrele(vp);
 881	}
 882	return (error);
 883}
 884
 885/*
 886 * Create a named pipe.
 887 */
 888/* ARGSUSED */
 889int
 890sys_mkfifo(p, v, retval)
 891	struct proc *p;
 892	void *v;
 893	register_t *retval;
 894{
 895#ifndef FIFO
 896	return (EOPNOTSUPP);
 897#else
 898	register struct sys_mkfifo_args /* {
 899		syscallarg(char *) path;
 900		syscallarg(int) mode;
 901	} */ *uap = v;
 902	struct vattr vattr;
 903	int error;
 904	struct nameidata nd;
 905
 906	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
 907	if ((error = namei(&nd)) != 0)
 908		return (error);
 909	if (nd.ni_vp != NULL) {
 910		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
 911		if (nd.ni_dvp == nd.ni_vp)
 912			vrele(nd.ni_dvp);
 913		else
 914			vput(nd.ni_dvp);
 915		vrele(nd.ni_vp);
 916		return (EEXIST);
 917	}
 918	VATTR_NULL(&vattr);
 919	vattr.va_type = VFIFO;
 920	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
 921	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
 922	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
 923#endif /* FIFO */
 924}
 925
 926/*
 927 * Make a hard file link.
 928 */
 929/* ARGSUSED */
 930int
 931sys_link(p, v, retval)
 932	struct proc *p;
 933	void *v;
 934	register_t *retval;
 935{
 936	register struct sys_link_args /* {
 937		syscallarg(char *) path;
 938		syscallarg(char *) link;
 939	} */ *uap = v;
 940	register struct vnode *vp;
 941	struct nameidata nd;
 942	int error;
 943
 944	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
 945	if ((error = namei(&nd)) != 0)
 946		return (error);
 947	vp = nd.ni_vp;
 948	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
 949	if ((error = namei(&nd)) != 0)
 950		goto out;
 951	if (nd.ni_vp) {
 952		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
 953		if (nd.ni_dvp == nd.ni_vp)
 954			vrele(nd.ni_dvp);
 955		else
 956			vput(nd.ni_dvp);
 957		vrele(nd.ni_vp);
 958		error = EEXIST;
 959		goto out;
 960	}
 961	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
 962	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
 963	error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
 964out:
 965	vrele(vp);
 966	return (error);
 967}
 968
 969/*
 970 * Make a symbolic link.
 971 */
 972/* ARGSUSED */
 973int
 974sys_symlink(p, v, retval)
 975	struct proc *p;
 976	void *v;
 977	register_t *retval;
 978{
 979	register struct sys_symlink_args /* {
 980		syscallarg(char *) path;
 981		syscallarg(char *) link;
 982	} */ *uap = v;
 983	struct vattr vattr;
 984	char *path;
 985	int error;
 986	struct nameidata nd;
 987
 988	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
 989	error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
 990	if (error)
 991		goto out;
 992	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
 993	if ((error = namei(&nd)) != 0)
 994		goto out;
 995	if (nd.ni_vp) {
 996		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
 997		if (nd.ni_dvp == nd.ni_vp)
 998			vrele(nd.ni_dvp);
 999		else
1000			vput(nd.ni_dvp);
1001		vrele(nd.ni_vp);
1002		error = EEXIST;
1003		goto out;
1004	}
1005	VATTR_NULL(&vattr);
1006	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1007	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1008	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1009out:
1010	FREE(path, M_NAMEI);
1011	return (error);
1012}
1013
1014/*
1015 * Delete a whiteout from the filesystem.
1016 */
1017/* ARGSUSED */
1018int
1019sys_undelete(p, v, retval)
1020	struct proc *p;
1021	void *v;
1022	register_t *retval;
1023{
1024	register struct sys_undelete_args /* {
1025		syscallarg(char *) path;
1026	} */ *uap = v;
1027	int error;
1028	struct nameidata nd;
1029
1030	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1031	    SCARG(uap, path), p);
1032	error = namei(&nd);
1033	if (error)
1034		return (error);
1035
1036	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1037		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1038		if (nd.ni_dvp == nd.ni_vp)
1039			vrele(nd.ni_dvp);
1040		else
1041			vput(nd.ni_dvp);
1042		if (nd.ni_vp)
1043			vrele(nd.ni_vp);
1044		return (EEXIST);
1045	}
1046
1047	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1048	if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1049		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1050	vput(nd.ni_dvp);
1051	return (error);
1052}
1053
1054/*
1055 * Delete a name from the filesystem.
1056 */
1057/* ARGSUSED */
1058int
1059sys_unlink(p, v, retval)
1060	struct proc *p;
1061	void *v;
1062	register_t *retval;
1063{
1064	struct sys_unlink_args /* {
1065		syscallarg(char *) path;
1066	} */ *uap = v;
1067	register struct vnode *vp;
1068	int error;
1069	struct nameidata nd;
1070
1071	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1072	    SCARG(uap, path), p);
1073	if ((error = namei(&nd)) != 0)
1074		return (error);
1075	vp = nd.ni_vp;
1076
1077	/*
1078	 * The root of a mounted filesystem cannot be deleted.
1079	 */
1080	if (vp->v_flag & VROOT) {
1081		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1082		if (nd.ni_dvp == vp)
1083			vrele(nd.ni_dvp);
1084		else
1085			vput(nd.ni_dvp);
1086		vput(vp);
1087		error = EBUSY;
1088		goto out;
1089	}
1090
1091	(void)vnode_pager_uncache(vp);
1092
1093	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1094	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1095	error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1096out:
1097	return (error);
1098}
1099
1100/*
1101 * Reposition read/write file offset.
1102 */
1103int
1104sys_lseek(p, v, retval)
1105	struct proc *p;
1106	void *v;
1107	register_t *retval;
1108{
1109	register struct sys_lseek_args /* {
1110		syscallarg(int) fd;
1111		syscallarg(int) pad;
1112		syscallarg(off_t) offset;
1113		syscallarg(int) whence;
1114	} */ *uap = v;
1115	struct ucred *cred = p->p_ucred;
1116	register struct filedesc *fdp = p->p_fd;
1117	register struct file *fp;
1118	struct vattr vattr;
1119	int error;
1120
1121	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1122	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1123		return (EBADF);
1124	if (fp->f_type != DTYPE_VNODE)
1125		return (ESPIPE);
1126	switch (SCARG(uap, whence)) {
1127	case L_INCR:
1128		fp->f_offset += SCARG(uap, offset);
1129		break;
1130	case L_XTND:
1131		error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr,
1132				    cred, p);
1133		if (error)
1134			return (error);
1135		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1136		break;
1137	case L_SET:
1138		fp->f_offset = SCARG(uap, offset);
1139		break;
1140	default:
1141		return (EINVAL);
1142	}
1143	*(off_t *)retval = fp->f_offset;
1144	return (0);
1145}
1146
1147/*
1148 * Check access permissions.
1149 */
1150int
1151sys_access(p, v, retval)
1152	struct proc *p;
1153	void *v;
1154	register_t *retval;
1155{
1156	register struct sys_access_args /* {
1157		syscallarg(char *) path;
1158		syscallarg(int) flags;
1159	} */ *uap = v;
1160	register struct ucred *cred = p->p_ucred;
1161	register struct vnode *vp;
1162	int error, flags, t_gid, t_uid;
1163	struct nameidata nd;
1164
1165	t_uid = cred->cr_uid;
1166	t_gid = cred->cr_gid;
1167	cred->cr_uid = p->p_cred->p_ruid;
1168	cred->cr_gid = p->p_cred->p_rgid;
1169	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1170	    SCARG(uap, path), p);
1171	if ((error = namei(&nd)) != 0)
1172		goto out1;
1173	vp = nd.ni_vp;
1174
1175	/* Flags == 0 means only check for existence. */
1176	if (SCARG(uap, flags)) {
1177		flags = 0;
1178		if (SCARG(uap, flags) & R_OK)
1179			flags |= VREAD;
1180		if (SCARG(uap, flags) & W_OK)
1181			flags |= VWRITE;
1182		if (SCARG(uap, flags) & X_OK)
1183			flags |= VEXEC;
1184		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1185			error = VOP_ACCESS(vp, flags, cred, p);
1186	}
1187	vput(vp);
1188out1:
1189	cred->cr_uid = t_uid;
1190	cred->cr_gid = t_gid;
1191	return (error);
1192}
1193
1194/*
1195 * Get file status; this version follows links.
1196 */
1197/* ARGSUSED */
1198int
1199sys_stat(p, v, retval)
1200	struct proc *p;
1201	void *v;
1202	register_t *retval;
1203{
1204	register struct sys_stat_args /* {
1205		syscallarg(char *) path;
1206		syscallarg(struct stat *) ub;
1207	} */ *uap = v;
1208	struct stat sb;
1209	int error;
1210	struct nameidata nd;
1211
1212	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1213	    SCARG(uap, path), p);
1214	if ((error = namei(&nd)) != 0)
1215		return (error);
1216	error = vn_stat(nd.ni_vp, &sb, p);
1217	vput(nd.ni_vp);
1218	if (error)
1219		return (error);
1220	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1221	return (error);
1222}
1223
1224/*
1225 * Get file status; this version does not follow links.
1226 */
1227/* ARGSUSED */
1228int
1229sys_lstat(p, v, retval)
1230	struct proc *p;
1231	void *v;
1232	register_t *retval;
1233{
1234	register struct sys_lstat_args /* {
1235		syscallarg(char *) path;
1236		syscallarg(struct stat *) ub;
1237	} */ *uap = v;
1238	struct stat sb;
1239	int error;
1240	struct nameidata nd;
1241
1242	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1243	    SCARG(uap, path), p);
1244	if ((error = namei(&nd)) != 0)
1245		return (error);
1246	error = vn_stat(nd.ni_vp, &sb, p);
1247	vput(nd.ni_vp);
1248	if (error)
1249		return (error);
1250	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1251	return (error);
1252}
1253
1254/*
1255 * Get configurable pathname variables.
1256 */
1257/* ARGSUSED */
1258int
1259sys_pathconf(p, v, retval)
1260	struct proc *p;
1261	void *v;
1262	register_t *retval;
1263{
1264	register struct sys_pathconf_args /* {
1265		syscallarg(char *) path;
1266		syscallarg(int) name;
1267	} */ *uap = v;
1268	int error;
1269	struct nameidata nd;
1270
1271	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1272	    SCARG(uap, path), p);
1273	if ((error = namei(&nd)) != 0)
1274		return (error);
1275	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1276	vput(nd.ni_vp);
1277	return (error);
1278}
1279
1280/*
1281 * Return target name of a symbolic link.
1282 */
1283/* ARGSUSED */
1284int
1285sys_readlink(p, v, retval)
1286	struct proc *p;
1287	void *v;
1288	register_t *retval;
1289{
1290	register struct sys_readlink_args /* {
1291		syscallarg(char *) path;
1292		syscallarg(char *) buf;
1293		syscallarg(int) count;
1294	} */ *uap = v;
1295	register struct vnode *vp;
1296	struct iovec aiov;
1297	struct uio auio;
1298	int error;
1299	struct nameidata nd;
1300
1301	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1302	    SCARG(uap, path), p);
1303	if ((error = namei(&nd)) != 0)
1304		return (error);
1305	vp = nd.ni_vp;
1306	if (vp->v_type != VLNK)
1307		error = EINVAL;
1308	else {
1309		aiov.iov_base = SCARG(uap, buf);
1310		aiov.iov_len = SCARG(uap, count);
1311		auio.uio_iov = &aiov;
1312		auio.uio_iovcnt = 1;
1313		auio.uio_offset = 0;
1314		auio.uio_rw = UIO_READ;
1315		auio.uio_segflg = UIO_USERSPACE;
1316		auio.uio_procp = p;
1317		auio.uio_resid = SCARG(uap, count);
1318		error = VOP_READLINK(vp, &auio, p->p_ucred);
1319	}
1320	vput(vp);
1321	*retval = SCARG(uap, count) - auio.uio_resid;
1322	return (error);
1323}
1324
1325/*
1326 * Change flags of a file given a path name.
1327 */
1328/* ARGSUSED */
1329int
1330sys_chflags(p, v, retval)
1331	struct proc *p;
1332	void *v;
1333	register_t *retval;
1334{
1335	register struct sys_chflags_args /* {
1336		syscallarg(char *) path;
1337		syscallarg(int) flags;
1338	} */ *uap = v;
1339	register struct vnode *vp;
1340	struct vattr vattr;
1341	int error;
1342	struct nameidata nd;
1343
1344	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1345	if ((error = namei(&nd)) != 0)
1346		return (error);
1347	vp = nd.ni_vp;
1348	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1349	VOP_LOCK(vp);
1350	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1351		error = EROFS;
1352	else {
1353		VATTR_NULL(&vattr);
1354		vattr.va_flags = SCARG(uap, flags);
1355		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1356	}
1357	vput(vp);
1358	return (error);
1359}
1360
1361/*
1362 * Change flags of a file given a file descriptor.
1363 */
1364/* ARGSUSED */
1365int
1366sys_fchflags(p, v, retval)
1367	struct proc *p;
1368	void *v;
1369	register_t *retval;
1370{
1371	register struct sys_fchflags_args /* {
1372		syscallarg(int) fd;
1373		syscallarg(int) flags;
1374	} */ *uap = v;
1375	struct vattr vattr;
1376	struct vnode *vp;
1377	struct file *fp;
1378	int error;
1379
1380	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1381		return (error);
1382	vp = (struct vnode *)fp->f_data;
1383	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1384	VOP_LOCK(vp);
1385	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1386		error = EROFS;
1387	else {
1388		VATTR_NULL(&vattr);
1389		vattr.va_flags = SCARG(uap, flags);
1390		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1391	}
1392	VOP_UNLOCK(vp);
1393	return (error);
1394}
1395
1396/*
1397 * Change mode of a file given path name.
1398 */
1399/* ARGSUSED */
1400int
1401sys_chmod(p, v, retval)
1402	struct proc *p;
1403	void *v;
1404	register_t *retval;
1405{
1406	register struct sys_chmod_args /* {
1407		syscallarg(char *) path;
1408		syscallarg(int) mode;
1409	} */ *uap = v;
1410	register struct vnode *vp;
1411	struct vattr vattr;
1412	int error;
1413	struct nameidata nd;
1414
1415	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1416	if ((error = namei(&nd)) != 0)
1417		return (error);
1418	vp = nd.ni_vp;
1419	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1420	VOP_LOCK(vp);
1421	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1422		error = EROFS;
1423	else {
1424		VATTR_NULL(&vattr);
1425		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1426		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1427	}
1428	vput(vp);
1429	return (error);
1430}
1431
1432/*
1433 * Change mode of a file given a file descriptor.
1434 */
1435/* ARGSUSED */
1436int
1437sys_fchmod(p, v, retval)
1438	struct proc *p;
1439	void *v;
1440	register_t *retval;
1441{
1442	register struct sys_fchmod_args /* {
1443		syscallarg(int) fd;
1444		syscallarg(int) mode;
1445	} */ *uap = v;
1446	struct vattr vattr;
1447	struct vnode *vp;
1448	struct file *fp;
1449	int error;
1450
1451	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1452		return (error);
1453	vp = (struct vnode *)fp->f_data;
1454	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1455	VOP_LOCK(vp);
1456	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1457		error = EROFS;
1458	else {
1459		VATTR_NULL(&vattr);
1460		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1461		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1462	}
1463	VOP_UNLOCK(vp);
1464	return (error);
1465}
1466
1467/*
1468 * Set ownership given a path name.
1469 */
1470/* ARGSUSED */
1471int
1472sys_chown(p, v, retval)
1473	struct proc *p;
1474	void *v;
1475	register_t *retval;
1476{
1477	register struct sys_chown_args /* {
1478		syscallarg(char *) path;
1479		syscallarg(int) uid;
1480		syscallarg(int) gid;
1481	} */ *uap = v;
1482	register struct vnode *vp;
1483	struct vattr vattr;
1484	int error;
1485	struct nameidata nd;
1486
1487	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1488	if ((error = namei(&nd)) != 0)
1489		return (error);
1490	vp = nd.ni_vp;
1491	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1492	VOP_LOCK(vp);
1493	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1494		error = EROFS;
1495	else {
1496		VATTR_NULL(&vattr);
1497		vattr.va_uid = SCARG(uap, uid);
1498		vattr.va_gid = SCARG(uap, gid);
1499		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1500	}
1501	vput(vp);
1502	return (error);
1503}
1504
1505/*
1506 * Set ownership given a file descriptor.
1507 */
1508/* ARGSUSED */
1509int
1510sys_fchown(p, v, retval)
1511	struct proc *p;
1512	void *v;
1513	register_t *retval;
1514{
1515	register struct sys_fchown_args /* {
1516		syscallarg(int) fd;
1517		syscallarg(int) uid;
1518		syscallarg(int) gid;
1519	} */ *uap = v;
1520	register struct vnode *vp;
1521	struct vattr vattr;
1522	int error;
1523	struct file *fp;
1524
1525	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1526		return (error);
1527	vp = (struct vnode *)fp->f_data;
1528	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1529	VOP_LOCK(vp);
1530	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1531		error = EROFS;
1532	else {
1533		VATTR_NULL(&vattr);
1534		vattr.va_uid = SCARG(uap, uid);
1535		vattr.va_gid = SCARG(uap, gid);
1536		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1537	}
1538	VOP_UNLOCK(vp);
1539	return (error);
1540}
1541
1542/*
1543 * Set the access and modification times given a path name.
1544 */
1545/* ARGSUSED */
1546int
1547sys_utimes(p, v, retval)
1548	struct proc *p;
1549	void *v;
1550	register_t *retval;
1551{
1552	register struct sys_utimes_args /* {
1553		syscallarg(char *) path;
1554		syscallarg(struct timeval *) tptr;
1555	} */ *uap = v;
1556	register struct vnode *vp;
1557	struct timeval tv[2];
1558	struct vattr vattr;
1559	int error;
1560	struct nameidata nd;
1561
1562	VATTR_NULL(&vattr);
1563	if (SCARG(uap, tptr) == NULL) {
1564		microtime(&tv[0]);
1565		tv[1] = tv[0];
1566		vattr.va_vaflags |= VA_UTIMES_NULL;
1567	} else {
1568		error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1569			       sizeof (tv));
1570		if (error)
1571			return (error);
1572	}
1573	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1574	if ((error = namei(&nd)) != 0)
1575		return (error);
1576	vp = nd.ni_vp;
1577	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1578	VOP_LOCK(vp);
1579	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1580		error = EROFS;
1581	else {
1582		vattr.va_atime.tv_sec = tv[0].tv_sec;
1583		vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1584		vattr.va_mtime.tv_sec = tv[1].tv_sec;
1585		vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1586		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1587	}
1588	vput(vp);
1589	return (error);
1590}
1591
1592/*
1593 * Set the access and modification times given a file descriptor.
1594 */
1595/* ARGSUSED */
1596int
1597sys_futimes(p, v, retval)
1598	struct proc *p;
1599	void *v;
1600	register_t *retval;
1601{
1602	register struct sys_futimes_args /* {
1603		syscallarg(int) fd;
1604		syscallarg(struct timeval *) tptr;
1605	} */ *uap = v;
1606	register struct vnode *vp;
1607	struct timeval tv[2];
1608	struct vattr vattr;
1609	int error;
1610	struct file *fp;
1611
1612	VATTR_NULL(&vattr);
1613	if (SCARG(uap, tptr) == NULL) {
1614		microtime(&tv[0]);
1615		tv[1] = tv[0];
1616		vattr.va_vaflags |= VA_UTIMES_NULL;
1617	} else {
1618		error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1619			       sizeof (tv));
1620		if (error)
1621			return (error);
1622	}
1623	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1624		return (error);
1625	vp = (struct vnode *)fp->f_data;
1626	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1627	VOP_LOCK(vp);
1628	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1629		error = EROFS;
1630	else {
1631		vattr.va_atime.tv_sec = tv[0].tv_sec;
1632		vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1633		vattr.va_mtime.tv_sec = tv[1].tv_sec;
1634		vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1635		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1636	}
1637	VOP_UNLOCK(vp);
1638	return (error);
1639}
1640
1641/*
1642 * Truncate a file given its path name.
1643 */
1644/* ARGSUSED */
1645int
1646sys_truncate(p, v, retval)
1647	struct proc *p;
1648	void *v;
1649	register_t *retval;
1650{
1651	register struct sys_truncate_args /* {
1652		syscallarg(char *) path;
1653		syscallarg(int) pad;
1654		syscallarg(off_t) length;
1655	} */ *uap = v;
1656	register struct vnode *vp;
1657	struct vattr vattr;
1658	int error;
1659	struct nameidata nd;
1660
1661	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1662	if ((error = namei(&nd)) != 0)
1663		return (error);
1664	vp = nd.ni_vp;
1665	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1666	VOP_LOCK(vp);
1667	if (vp->v_type == VDIR)
1668		error = EISDIR;
1669	else if ((error = vn_writechk(vp)) == 0 &&
1670	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1671		VATTR_NULL(&vattr);
1672		vattr.va_size = SCARG(uap, length);
1673		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1674	}
1675	vput(vp);
1676	return (error);
1677}
1678
1679/*
1680 * Truncate a file given a file descriptor.
1681 */
1682/* ARGSUSED */
1683int
1684sys_ftruncate(p, v, retval)
1685	struct proc *p;
1686	void *v;
1687	register_t *retval;
1688{
1689	register struct sys_ftruncate_args /* {
1690		syscallarg(int) fd;
1691		syscallarg(int) pad;
1692		syscallarg(off_t) length;
1693	} */ *uap = v;
1694	struct vattr vattr;
1695	struct vnode *vp;
1696	struct file *fp;
1697	int error;
1698
1699	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1700		return (error);
1701	if ((fp->f_flag & FWRITE) == 0)
1702		return (EINVAL);
1703	vp = (struct vnode *)fp->f_data;
1704	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1705	VOP_LOCK(vp);
1706	if (vp->v_type == VDIR)
1707		error = EISDIR;
1708	else if ((error = vn_writechk(vp)) == 0) {
1709		VATTR_NULL(&vattr);
1710		vattr.va_size = SCARG(uap, length);
1711		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1712	}
1713	VOP_UNLOCK(vp);
1714	return (error);
1715}
1716
1717/*
1718 * Sync an open file.
1719 */
1720/* ARGSUSED */
1721int
1722sys_fsync(p, v, retval)
1723	struct proc *p;
1724	void *v;
1725	register_t *retval;
1726{
1727	struct sys_fsync_args /* {
1728		syscallarg(int) fd;
1729	} */ *uap = v;
1730	register struct vnode *vp;
1731	struct file *fp;
1732	int error;
1733
1734	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1735		return (error);
1736	vp = (struct vnode *)fp->f_data;
1737	VOP_LOCK(vp);
1738	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
1739	VOP_UNLOCK(vp);
1740	return (error);
1741}
1742
1743/*
1744 * Rename files.  Source and destination must either both be directories,
1745 * or both not be directories.  If target is a directory, it must be empty.
1746 */
1747/* ARGSUSED */
1748int
1749sys_rename(p, v, retval)
1750	struct proc *p;
1751	void *v;
1752	register_t *retval;
1753{
1754	register struct sys_rename_args /* {
1755		syscallarg(char *) from;
1756		syscallarg(char *) to;
1757	} */ *uap = v;
1758	register struct vnode *tvp, *fvp, *tdvp;
1759	struct nameidata fromnd, tond;
1760	int error;
1761
1762	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1763	    SCARG(uap, from), p);
1764	if ((error = namei(&fromnd)) != 0)
1765		return (error);
1766	fvp = fromnd.ni_vp;
1767	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
1768	    UIO_USERSPACE, SCARG(uap, to), p);
1769	if ((error = namei(&tond)) != 0) {
1770		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1771		vrele(fromnd.ni_dvp);
1772		vrele(fvp);
1773		goto out1;
1774	}
1775	tdvp = tond.ni_dvp;
1776	tvp = tond.ni_vp;
1777	if (tvp != NULL) {
1778		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1779			error = ENOTDIR;
1780			goto out;
1781		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1782			error = EISDIR;
1783			goto out;
1784		}
1785	}
1786	if (fvp == tdvp)
1787		error = EINVAL;
1788	/*
1789	 * If source is the same as the destination (that is the
1790	 * same inode number with the same name in the same directory),
1791	 * then there is nothing to do.
1792	 */
1793	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1794	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1795	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1796	      fromnd.ni_cnd.cn_namelen))
1797		error = -1;
1798out:
1799	if (!error) {
1800		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
1801		if (fromnd.ni_dvp != tdvp)
1802			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1803		if (tvp)
1804			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
1805		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1806				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1807	} else {
1808		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1809		if (tdvp == tvp)
1810			vrele(tdvp);
1811		else
1812			vput(tdvp);
1813		if (tvp)
1814			vput(tvp);
1815		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1816		vrele(fromnd.ni_dvp);
1817		vrele(fvp);
1818	}
1819	vrele(tond.ni_startdir);
1820	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1821out1:
1822	if (fromnd.ni_startdir)
1823		vrele(fromnd.ni_startdir);
1824	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1825	if (error == -1)
1826		return (0);
1827	return (error);
1828}
1829
1830/*
1831 * Make a directory file.
1832 */
1833/* ARGSUSED */
1834int
1835sys_mkdir(p, v, retval)
1836	struct proc *p;
1837	void *v;
1838	register_t *retval;
1839{
1840	register struct sys_mkdir_args /* {
1841		syscallarg(char *) path;
1842		syscallarg(int) mode;
1843	} */ *uap = v;
1844	register struct vnode *vp;
1845	struct vattr vattr;
1846	int error;
1847	struct nameidata nd;
1848
1849	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1850	if ((error = namei(&nd)) != 0)
1851		return (error);
1852	vp = nd.ni_vp;
1853	if (vp != NULL) {
1854		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1855		if (nd.ni_dvp == vp)
1856			vrele(nd.ni_dvp);
1857		else
1858			vput(nd.ni_dvp);
1859		vrele(vp);
1860		return (EEXIST);
1861	}
1862	VATTR_NULL(&vattr);
1863	vattr.va_type = VDIR;
1864	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
1865	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1866	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1867	if (!error)
1868		vput(nd.ni_vp);
1869	return (error);
1870}
1871
1872/*
1873 * Remove a directory file.
1874 */
1875/* ARGSUSED */
1876int
1877sys_rmdir(p, v, retval)
1878	struct proc *p;
1879	void *v;
1880	register_t *retval;
1881{
1882	struct sys_rmdir_args /* {
1883		syscallarg(char *) path;
1884	} */ *uap = v;
1885	register struct vnode *vp;
1886	int error;
1887	struct nameidata nd;
1888
1889	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1890	    SCARG(uap, path), p);
1891	if ((error = namei(&nd)) != 0)
1892		return (error);
1893	vp = nd.ni_vp;
1894	if (vp->v_type != VDIR) {
1895		error = ENOTDIR;
1896		goto out;
1897	}
1898	/*
1899	 * No rmdir "." please.
1900	 */
1901	if (nd.ni_dvp == vp) {
1902		error = EINVAL;
1903		goto out;
1904	}
1905	/*
1906	 * The root of a mounted filesystem cannot be deleted.
1907	 */
1908	if (vp->v_flag & VROOT)
1909		error = EBUSY;
1910out:
1911	if (!error) {
1912		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1913		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1914		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1915	} else {
1916		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1917		if (nd.ni_dvp == vp)
1918			vrele(nd.ni_dvp);
1919		else
1920			vput(nd.ni_dvp);
1921		vput(vp);
1922	}
1923	return (error);
1924}
1925
1926/*
1927 * Read a block of directory entries in a file system independent format.
1928 */
1929int
1930sys_getdirentries(p, v, retval)
1931	struct proc *p;
1932	void *v;
1933	register_t *retval;
1934{
1935	register struct sys_getdirentries_args /* {
1936		syscallarg(int) fd;
1937		syscallarg(char *) buf;
1938		syscallarg(u_int) count;
1939		syscallarg(long *) basep;
1940	} */ *uap = v;
1941	register struct vnode *vp;
1942	struct file *fp;
1943	struct uio auio;
1944	struct iovec aiov;
1945	long loff;
1946	int error, eofflag;
1947
1948	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1949		return (error);
1950	if ((fp->f_flag & FREAD) == 0)
1951		return (EBADF);
1952	vp = (struct vnode *)fp->f_data;
1953unionread:
1954	if (vp->v_type != VDIR)
1955		return (EINVAL);
1956	aiov.iov_base = SCARG(uap, buf);
1957	aiov.iov_len = SCARG(uap, count);
1958	auio.uio_iov = &aiov;
1959	auio.uio_iovcnt = 1;
1960	auio.uio_rw = UIO_READ;
1961	auio.uio_segflg = UIO_USERSPACE;
1962	auio.uio_procp = p;
1963	auio.uio_resid = SCARG(uap, count);
1964	VOP_LOCK(vp);
1965	loff = auio.uio_offset = fp->f_offset;
1966	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
1967	fp->f_offset = auio.uio_offset;
1968	VOP_UNLOCK(vp);
1969	if (error)
1970		return (error);
1971
1972#ifdef UNION
1973{
1974	extern int (**union_vnodeop_p) __P((void *));
1975	extern struct vnode *union_dircache __P((struct vnode *));
1976
1977	if ((SCARG(uap, count) == auio.uio_resid) &&
1978	    (vp->v_op == union_vnodeop_p)) {
1979		struct vnode *lvp;
1980
1981		lvp = union_dircache(vp);
1982		if (lvp != NULLVP) {
1983			struct vattr va;
1984
1985			/*
1986			 * If the directory is opaque,
1987			 * then don't show lower entries
1988			 */
1989			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
1990			if (va.va_flags & OPAQUE) {
1991				vput(lvp);
1992				lvp = NULL;
1993			}
1994		}
1995		
1996		if (lvp != NULLVP) {
1997			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
1998			VOP_UNLOCK(lvp);
1999
2000			if (error) {
2001				vrele(lvp);
2002				return (error);
2003			}
2004			fp->f_data = (caddr_t) lvp;
2005			fp->f_offset = 0;
2006			error = vn_close(vp, FREAD, fp->f_cred, p);
2007			if (error)
2008				return (error);
2009			vp = lvp;
2010			goto unionread;
2011		}
2012	}
2013}
2014#endif /* UNION */
2015
2016	if ((SCARG(uap, count) == auio.uio_resid) &&
2017	    (vp->v_flag & VROOT) &&
2018	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2019		struct vnode *tvp = vp;
2020		vp = vp->v_mount->mnt_vnodecovered;
2021		VREF(vp);
2022		fp->f_data = (caddr_t) vp;
2023		fp->f_offset = 0;
2024		vrele(tvp);
2025		goto unionread;
2026	}
2027	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2028	    sizeof(long));
2029	*retval = SCARG(uap, count) - auio.uio_resid;
2030	return (error);
2031}
2032
2033/*
2034 * Set the mode mask for creation of filesystem nodes.
2035 */
2036int
2037sys_umask(p, v, retval)
2038	struct proc *p;
2039	void *v;
2040	register_t *retval;
2041{
2042	struct sys_umask_args /* {
2043		syscallarg(int) newmask;
2044	} */ *uap = v;
2045	register struct filedesc *fdp;
2046
2047	fdp = p->p_fd;
2048	*retval = fdp->fd_cmask;
2049	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2050	return (0);
2051}
2052
2053/*
2054 * Void all references to file by ripping underlying filesystem
2055 * away from vnode.
2056 */
2057/* ARGSUSED */
2058int
2059sys_revoke(p, v, retval)
2060	struct proc *p;
2061	void *v;
2062	register_t *retval;
2063{
2064	register struct sys_revoke_args /* {
2065		syscallarg(char *) path;
2066	} */ *uap = v;
2067	register struct vnode *vp;
2068	struct vattr vattr;
2069	int error;
2070	struct nameidata nd;
2071
2072	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2073	if ((error = namei(&nd)) != 0)
2074		return (error);
2075	vp = nd.ni_vp;
2076	if (vp->v_type != VCHR && vp->v_type != VBLK) {
2077		error = EINVAL;
2078		goto out;
2079	}
2080	if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2081		goto out;
2082	if (p->p_ucred->cr_uid != vattr.va_uid &&
2083	    (error = suser(p->p_ucred, &p->p_acflag)))
2084		goto out;
2085	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2086		vgoneall(vp);
2087out:
2088	vrele(vp);
2089	return (error);
2090}
2091
2092/*
2093 * Convert a user file descriptor to a kernel file entry.
2094 */
2095int
2096getvnode(fdp, fd, fpp)
2097	struct filedesc *fdp;
2098	int fd;
2099	struct file **fpp;
2100{
2101	struct vnode *vp;
2102	struct file *fp;
2103
2104	if ((u_int)fd >= fdp->fd_nfiles ||
2105	    (fp = fdp->fd_ofiles[fd]) == NULL)
2106		return (EBADF);
2107	if (fp->f_type != DTYPE_VNODE)
2108		return (EINVAL);
2109	vp = (struct vnode *)fp->f_data;
2110	if (vp->v_type == VBAD)
2111		return (EBADF);
2112	*fpp = fp;
2113	return (0);
2114}