xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 68663)
123405Smckusick /*
263428Sbostic  * Copyright (c) 1989, 1993
363428Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923405Smckusick  *
1044459Sbostic  * %sccs.include.redist.c%
1137741Smckusick  *
12*68663Smckusick  *	@(#)vfs_syscalls.c	8.33 (Berkeley) 03/30/95
1323405Smckusick  */
1437Sbill 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/namei.h>
1856517Sbostic #include <sys/filedesc.h>
1956517Sbostic #include <sys/kernel.h>
2056517Sbostic #include <sys/file.h>
2156517Sbostic #include <sys/stat.h>
2256517Sbostic #include <sys/vnode.h>
2356517Sbostic #include <sys/mount.h>
2456517Sbostic #include <sys/proc.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/malloc.h>
2756517Sbostic #include <sys/dirent.h>
2856517Sbostic 
2968318Scgd #include <sys/syscallargs.h>
3068318Scgd 
3153468Smckusick #include <vm/vm.h>
3259875Smckusick #include <sys/sysctl.h>
3337Sbill 
3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
3568318Scgd static void checkdirs __P((struct vnode *olddp));
3664410Sbostic 
3737741Smckusick /*
3837741Smckusick  * Virtual File System System Calls
3937741Smckusick  */
4012756Ssam 
419167Ssam /*
4264410Sbostic  * Mount a file system.
439167Ssam  */
4442441Smckusick /* ARGSUSED */
4568318Scgd int
4642441Smckusick mount(p, uap, retval)
4745914Smckusick 	struct proc *p;
4868318Scgd 	register struct mount_args /* {
49*68663Smckusick 		syscallarg(char *) type;
5068318Scgd 		syscallarg(char *) path;
5168318Scgd 		syscallarg(int) flags;
5268318Scgd 		syscallarg(caddr_t) data;
5368318Scgd 	} */ *uap;
5468318Scgd 	register_t *retval;
5542441Smckusick {
56*68663Smckusick 	struct vnode *vp;
57*68663Smckusick 	struct mount *mp;
58*68663Smckusick 	struct vfsconf *vfsp;
5940111Smckusick 	int error, flag;
6067532Smckusick 	struct vattr va;
61*68663Smckusick 	u_long fstypenum;
6247540Skarels 	struct nameidata nd;
63*68663Smckusick 	char fstypename[MFSNAMELEN];
646254Sroot 
6537741Smckusick 	/*
6637741Smckusick 	 * Get vnode to be covered
6737741Smckusick 	 */
6868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
6968318Scgd 	    SCARG(uap, path), p);
7052322Smckusick 	if (error = namei(&nd))
7147540Skarels 		return (error);
7252322Smckusick 	vp = nd.ni_vp;
7368318Scgd 	if (SCARG(uap, flags) & MNT_UPDATE) {
7439335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7539335Smckusick 			vput(vp);
7647540Skarels 			return (EINVAL);
7739335Smckusick 		}
7839335Smckusick 		mp = vp->v_mount;
7957047Smckusick 		flag = mp->mnt_flag;
8039335Smckusick 		/*
8157047Smckusick 		 * We only allow the filesystem to be reloaded if it
8257047Smckusick 		 * is currently mounted read-only.
8339335Smckusick 		 */
8468318Scgd 		if ((SCARG(uap, flags) & MNT_RELOAD) &&
8557047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
8639335Smckusick 			vput(vp);
8747540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8839335Smckusick 		}
8957047Smckusick 		mp->mnt_flag |=
9068318Scgd 		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
9167532Smckusick 		/*
9267532Smckusick 		 * Only root, or the user that did the original mount is
9367532Smckusick 		 * permitted to update it.
9467532Smckusick 		 */
9567532Smckusick 		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
9667532Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag))) {
9767532Smckusick 			vput(vp);
9867532Smckusick 			return (error);
9967532Smckusick 		}
10067532Smckusick 		/*
10167532Smckusick 		 * Do not allow NFS export by non-root users. Silently
10267532Smckusick 		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
10367532Smckusick 		 */
10467532Smckusick 		if (p->p_ucred->cr_uid != 0) {
10568318Scgd 			if (SCARG(uap, flags) & MNT_EXPORTED) {
10667532Smckusick 				vput(vp);
10767532Smckusick 				return (EPERM);
10867532Smckusick 			}
10968318Scgd 			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
11067532Smckusick 		}
11139335Smckusick 		VOP_UNLOCK(vp);
11239335Smckusick 		goto update;
11339335Smckusick 	}
11467532Smckusick 	/*
11567532Smckusick 	 * If the user is not root, ensure that they own the directory
11667532Smckusick 	 * onto which we are attempting to mount.
11767532Smckusick 	 */
11867532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
11967532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
12067532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
12167532Smckusick 		vput(vp);
12267532Smckusick 		return (error);
12367532Smckusick 	}
12467532Smckusick 	/*
12567532Smckusick 	 * Do not allow NFS export by non-root users. Silently
12667532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
12767532Smckusick 	 */
12867532Smckusick 	if (p->p_ucred->cr_uid != 0) {
12968318Scgd 		if (SCARG(uap, flags) & MNT_EXPORTED) {
13067532Smckusick 			vput(vp);
13167532Smckusick 			return (EPERM);
13267532Smckusick 		}
13368318Scgd 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
13467532Smckusick 	}
13557793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
13654441Smckusick 		return (error);
13737741Smckusick 	if (vp->v_type != VDIR) {
13837741Smckusick 		vput(vp);
13947540Skarels 		return (ENOTDIR);
14037741Smckusick 	}
141*68663Smckusick #ifdef COMPAT_43
142*68663Smckusick 	/*
143*68663Smckusick 	 * Historically filesystem types were identified by number. If we
144*68663Smckusick 	 * get an integer for the filesystem type instead of a string, we
145*68663Smckusick 	 * check to see if it matches one of the historic filesystem types.
146*68663Smckusick 	 */
147*68663Smckusick 	fstypenum = (u_long)SCARG(uap, type);
148*68663Smckusick 	if (fstypenum < maxvfsconf) {
149*68663Smckusick 		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
150*68663Smckusick 			if (vfsp->vfc_typenum == fstypenum)
151*68663Smckusick 				break;
152*68663Smckusick 		if (vfsp == NULL) {
153*68663Smckusick 			vput(vp);
154*68663Smckusick 			return (ENODEV);
155*68663Smckusick 		}
156*68663Smckusick 		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
157*68663Smckusick 	} else
158*68663Smckusick #endif /* COMPAT_43 */
159*68663Smckusick 	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
16037741Smckusick 		vput(vp);
161*68663Smckusick 		return (error);
162*68663Smckusick 	}
163*68663Smckusick 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
164*68663Smckusick 		if (!strcmp(vfsp->vfc_name, fstypename))
165*68663Smckusick 			break;
166*68663Smckusick 	if (vfsp == NULL) {
167*68663Smckusick 		vput(vp);
16847540Skarels 		return (ENODEV);
16937741Smckusick 	}
17067969Spendry 	if (vp->v_mountedhere != NULL) {
17167961Smckusick 		vput(vp);
17267961Smckusick 		return (EBUSY);
17367961Smckusick 	}
17437741Smckusick 
17537741Smckusick 	/*
176*68663Smckusick 	 * Allocate and initialize the filesystem.
17737741Smckusick 	 */
17837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
17937741Smckusick 		M_MOUNT, M_WAITOK);
18054172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
181*68663Smckusick 	mp->mnt_op = vfsp->vfc_vfsops;
18239335Smckusick 	if (error = vfs_lock(mp)) {
18339335Smckusick 		free((caddr_t)mp, M_MOUNT);
18439335Smckusick 		vput(vp);
18547540Skarels 		return (error);
18639335Smckusick 	}
187*68663Smckusick 	mp->mnt_vfc = vfsp;
188*68663Smckusick 	vfsp->vfc_refcount++;
189*68663Smckusick 	mp->mnt_stat.f_type = vfsp->vfc_typenum;
190*68663Smckusick 	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
191*68663Smckusick 	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
19239335Smckusick 	vp->v_mountedhere = mp;
19341400Smckusick 	mp->mnt_vnodecovered = vp;
19467532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
19539335Smckusick update:
19639335Smckusick 	/*
19739335Smckusick 	 * Set the mount level flags.
19839335Smckusick 	 */
19968318Scgd 	if (SCARG(uap, flags) & MNT_RDONLY)
20041400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
20157047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
20257047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
20365613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
20465613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20568318Scgd 	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
20668318Scgd 	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20739335Smckusick 	/*
20839335Smckusick 	 * Mount the filesystem.
20939335Smckusick 	 */
21068318Scgd 	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
21141400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
21239335Smckusick 		vrele(vp);
21357047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
21457047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
21557047Smckusick 		mp->mnt_flag &=~
21657047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
21740111Smckusick 		if (error)
21841400Smckusick 			mp->mnt_flag = flag;
21947540Skarels 		return (error);
22039335Smckusick 	}
22140110Smckusick 	/*
22240110Smckusick 	 * Put the new filesystem on the mount list after root.
22340110Smckusick 	 */
22437741Smckusick 	cache_purge(vp);
22537741Smckusick 	if (!error) {
22665259Smckusick 		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
22767974Smckusick 		checkdirs(vp);
22839335Smckusick 		VOP_UNLOCK(vp);
22937741Smckusick 		vfs_unlock(mp);
23048026Smckusick 		error = VFS_START(mp, 0, p);
23137741Smckusick 	} else {
23265259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
233*68663Smckusick 		mp->mnt_vfc->vfc_refcount--;
23465259Smckusick 		vfs_unlock(mp);
23537741Smckusick 		free((caddr_t)mp, M_MOUNT);
23639335Smckusick 		vput(vp);
23737741Smckusick 	}
23847540Skarels 	return (error);
2396254Sroot }
2406254Sroot 
2419167Ssam /*
24267974Smckusick  * Scan all active processes to see if any of them have a current
24367974Smckusick  * or root directory onto which the new filesystem has just been
24467974Smckusick  * mounted. If so, replace them with the new mount point.
24567974Smckusick  */
24668318Scgd static void
24767974Smckusick checkdirs(olddp)
24867974Smckusick 	struct vnode *olddp;
24967974Smckusick {
25067974Smckusick 	struct filedesc *fdp;
25167974Smckusick 	struct vnode *newdp;
25267974Smckusick 	struct proc *p;
25367974Smckusick 
25467974Smckusick 	if (olddp->v_usecount == 1)
25567974Smckusick 		return;
25667974Smckusick 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
25767974Smckusick 		panic("mount: lost mount");
25867974Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
25967974Smckusick 		fdp = p->p_fd;
26067974Smckusick 		if (fdp->fd_cdir == olddp) {
26167974Smckusick 			vrele(fdp->fd_cdir);
26267974Smckusick 			VREF(newdp);
26367974Smckusick 			fdp->fd_cdir = newdp;
26467974Smckusick 		}
26567974Smckusick 		if (fdp->fd_rdir == olddp) {
26667974Smckusick 			vrele(fdp->fd_rdir);
26767974Smckusick 			VREF(newdp);
26867974Smckusick 			fdp->fd_rdir = newdp;
26967974Smckusick 		}
27067974Smckusick 	}
27167974Smckusick 	if (rootvnode == olddp) {
27267974Smckusick 		vrele(rootvnode);
27367974Smckusick 		VREF(newdp);
27467974Smckusick 		rootvnode = newdp;
27567974Smckusick 	}
27667974Smckusick 	vput(newdp);
27767974Smckusick }
27867974Smckusick 
27967974Smckusick /*
28064410Sbostic  * Unmount a file system.
28137741Smckusick  *
28237741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
28337741Smckusick  * not special file (as before).
2849167Ssam  */
28542441Smckusick /* ARGSUSED */
28668318Scgd int
28742441Smckusick unmount(p, uap, retval)
28845914Smckusick 	struct proc *p;
28968318Scgd 	register struct unmount_args /* {
29068318Scgd 		syscallarg(char *) path;
29168318Scgd 		syscallarg(int) flags;
29268318Scgd 	} */ *uap;
29368318Scgd 	register_t *retval;
29442441Smckusick {
29537741Smckusick 	register struct vnode *vp;
29639356Smckusick 	struct mount *mp;
29737741Smckusick 	int error;
29847540Skarels 	struct nameidata nd;
2996254Sroot 
30068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
30168318Scgd 	    SCARG(uap, path), p);
30252322Smckusick 	if (error = namei(&nd))
30347540Skarels 		return (error);
30452322Smckusick 	vp = nd.ni_vp;
30567532Smckusick 	mp = vp->v_mount;
30666172Spendry 
30737741Smckusick 	/*
30867532Smckusick 	 * Only root, or the user that did the original mount is
30967532Smckusick 	 * permitted to unmount this filesystem.
31066172Spendry 	 */
31167532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
31266172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
31366172Spendry 		vput(vp);
31466172Spendry 		return (error);
31566172Spendry 	}
31666172Spendry 
31766172Spendry 	/*
31837741Smckusick 	 * Must be the root of the filesystem
31937741Smckusick 	 */
32037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
32137741Smckusick 		vput(vp);
32247540Skarels 		return (EINVAL);
32337741Smckusick 	}
32437741Smckusick 	vput(vp);
32568318Scgd 	return (dounmount(mp, SCARG(uap, flags), p));
32639356Smckusick }
32739356Smckusick 
32839356Smckusick /*
32964410Sbostic  * Do the actual file system unmount.
33039356Smckusick  */
33168318Scgd int
33248026Smckusick dounmount(mp, flags, p)
33339356Smckusick 	register struct mount *mp;
33439356Smckusick 	int flags;
33548026Smckusick 	struct proc *p;
33639356Smckusick {
33739356Smckusick 	struct vnode *coveredvp;
33839356Smckusick 	int error;
33939356Smckusick 
34041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
34141298Smckusick 	if (vfs_busy(mp))
34241298Smckusick 		return (EBUSY);
34341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
34437741Smckusick 	if (error = vfs_lock(mp))
34539356Smckusick 		return (error);
34637741Smckusick 
34765859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
34845738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
34937741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
35054441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
35154441Smckusick 	    (flags & MNT_FORCE))
35248026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
35341400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
35441298Smckusick 	vfs_unbusy(mp);
35537741Smckusick 	if (error) {
35637741Smckusick 		vfs_unlock(mp);
35737741Smckusick 	} else {
35837741Smckusick 		vrele(coveredvp);
35965259Smckusick 		TAILQ_REMOVE(&mountlist, mp, mnt_list);
36065259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
361*68663Smckusick 		mp->mnt_vfc->vfc_refcount--;
36265259Smckusick 		vfs_unlock(mp);
36365259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
36452287Smckusick 			panic("unmount: dangling vnode");
36537741Smckusick 		free((caddr_t)mp, M_MOUNT);
36637741Smckusick 	}
36739356Smckusick 	return (error);
3686254Sroot }
3696254Sroot 
3709167Ssam /*
37137741Smckusick  * Sync each mounted filesystem.
3729167Ssam  */
37367403Smckusick #ifdef DEBUG
37456352Smckusick int syncprt = 0;
37559875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
37656352Smckusick #endif
37756352Smckusick 
37839491Smckusick /* ARGSUSED */
37968318Scgd int
38042441Smckusick sync(p, uap, retval)
38145914Smckusick 	struct proc *p;
38268318Scgd 	void *uap;
38368318Scgd 	register_t *retval;
3846254Sroot {
38565259Smckusick 	register struct mount *mp, *nmp;
38665859Smckusick 	int asyncflag;
38737741Smckusick 
38865259Smckusick 	for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
38967678Smckusick 		/*
39067678Smckusick 		 * Get the next pointer in case we hang on vfs_busy
39167678Smckusick 		 * while we are being unmounted.
39267678Smckusick 		 */
39365259Smckusick 		nmp = mp->mnt_list.tqe_next;
39440343Smckusick 		/*
39540343Smckusick 		 * The lock check below is to avoid races with mount
39640343Smckusick 		 * and unmount.
39740343Smckusick 		 */
39841400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
39941298Smckusick 		    !vfs_busy(mp)) {
40065859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
40165859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
40254441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
40365859Smckusick 			if (asyncflag)
40465859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
40567678Smckusick 			/*
40667678Smckusick 			 * Get the next pointer again, as the next filesystem
40767678Smckusick 			 * might have been unmounted while we were sync'ing.
40867678Smckusick 			 */
40967678Smckusick 			nmp = mp->mnt_list.tqe_next;
41065259Smckusick 			vfs_unbusy(mp);
41165259Smckusick 		}
41265259Smckusick 	}
41356352Smckusick #ifdef DIAGNOSTIC
41456352Smckusick 	if (syncprt)
41556352Smckusick 		vfs_bufstats();
41656352Smckusick #endif /* DIAGNOSTIC */
41747688Skarels 	return (0);
41837741Smckusick }
41937741Smckusick 
42037741Smckusick /*
42164410Sbostic  * Change filesystem quotas.
42241298Smckusick  */
42342441Smckusick /* ARGSUSED */
42468318Scgd int
42542441Smckusick quotactl(p, uap, retval)
42645914Smckusick 	struct proc *p;
42768318Scgd 	register struct quotactl_args /* {
42868318Scgd 		syscallarg(char *) path;
42968318Scgd 		syscallarg(int) cmd;
43068318Scgd 		syscallarg(int) uid;
43168318Scgd 		syscallarg(caddr_t) arg;
43268318Scgd 	} */ *uap;
43368318Scgd 	register_t *retval;
43442441Smckusick {
43541298Smckusick 	register struct mount *mp;
43641298Smckusick 	int error;
43747540Skarels 	struct nameidata nd;
43841298Smckusick 
43968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
44052322Smckusick 	if (error = namei(&nd))
44147540Skarels 		return (error);
44252322Smckusick 	mp = nd.ni_vp->v_mount;
44352322Smckusick 	vrele(nd.ni_vp);
44468318Scgd 	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
44568318Scgd 	    SCARG(uap, arg), p));
44641298Smckusick }
44741298Smckusick 
44841298Smckusick /*
44949365Smckusick  * Get filesystem statistics.
45037741Smckusick  */
45142441Smckusick /* ARGSUSED */
45268318Scgd int
45342441Smckusick statfs(p, uap, retval)
45445914Smckusick 	struct proc *p;
45568318Scgd 	register struct statfs_args /* {
45668318Scgd 		syscallarg(char *) path;
45768318Scgd 		syscallarg(struct statfs *) buf;
45868318Scgd 	} */ *uap;
45968318Scgd 	register_t *retval;
46042441Smckusick {
46139464Smckusick 	register struct mount *mp;
46240343Smckusick 	register struct statfs *sp;
46337741Smckusick 	int error;
46447540Skarels 	struct nameidata nd;
46537741Smckusick 
46668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
46752322Smckusick 	if (error = namei(&nd))
46847540Skarels 		return (error);
46952322Smckusick 	mp = nd.ni_vp->v_mount;
47041400Smckusick 	sp = &mp->mnt_stat;
47152322Smckusick 	vrele(nd.ni_vp);
47248026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
47347540Skarels 		return (error);
47441400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
47568318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
47637741Smckusick }
47737741Smckusick 
47842441Smckusick /*
47949365Smckusick  * Get filesystem statistics.
48042441Smckusick  */
48142441Smckusick /* ARGSUSED */
48268318Scgd int
48342441Smckusick fstatfs(p, uap, retval)
48445914Smckusick 	struct proc *p;
48568318Scgd 	register struct fstatfs_args /* {
48668318Scgd 		syscallarg(int) fd;
48768318Scgd 		syscallarg(struct statfs *) buf;
48868318Scgd 	} */ *uap;
48968318Scgd 	register_t *retval;
49042441Smckusick {
49137741Smckusick 	struct file *fp;
49239464Smckusick 	struct mount *mp;
49340343Smckusick 	register struct statfs *sp;
49437741Smckusick 	int error;
49537741Smckusick 
49668318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
49747540Skarels 		return (error);
49839464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
49941400Smckusick 	sp = &mp->mnt_stat;
50048026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
50147540Skarels 		return (error);
50241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
50368318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
50437741Smckusick }
50537741Smckusick 
50637741Smckusick /*
50749365Smckusick  * Get statistics on all filesystems.
50838270Smckusick  */
50968318Scgd int
51042441Smckusick getfsstat(p, uap, retval)
51145914Smckusick 	struct proc *p;
51268318Scgd 	register struct getfsstat_args /* {
51368318Scgd 		syscallarg(struct statfs *) buf;
51468318Scgd 		syscallarg(long) bufsize;
51568318Scgd 		syscallarg(int) flags;
51668318Scgd 	} */ *uap;
51768318Scgd 	register_t *retval;
51842441Smckusick {
51965259Smckusick 	register struct mount *mp, *nmp;
52040343Smckusick 	register struct statfs *sp;
52139606Smckusick 	caddr_t sfsp;
52238270Smckusick 	long count, maxcount, error;
52338270Smckusick 
52468318Scgd 	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
52568318Scgd 	sfsp = (caddr_t)SCARG(uap, buf);
52665259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
52765259Smckusick 		nmp = mp->mnt_list.tqe_next;
52841400Smckusick 		if (sfsp && count < maxcount &&
52941400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
53041400Smckusick 			sp = &mp->mnt_stat;
53140343Smckusick 			/*
53240343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
53340343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
53440343Smckusick 			 */
53568318Scgd 			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
53668318Scgd 			    (SCARG(uap, flags) & MNT_WAIT)) &&
53765259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
53839607Smckusick 				continue;
53941400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
54040343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
54147540Skarels 				return (error);
54240343Smckusick 			sfsp += sizeof(*sp);
54338270Smckusick 		}
54439606Smckusick 		count++;
54565259Smckusick 	}
54638270Smckusick 	if (sfsp && count > maxcount)
54742441Smckusick 		*retval = maxcount;
54838270Smckusick 	else
54942441Smckusick 		*retval = count;
55047540Skarels 	return (0);
55138270Smckusick }
55238270Smckusick 
55338270Smckusick /*
55438259Smckusick  * Change current working directory to a given file descriptor.
55538259Smckusick  */
55642441Smckusick /* ARGSUSED */
55768318Scgd int
55842441Smckusick fchdir(p, uap, retval)
55945914Smckusick 	struct proc *p;
56068318Scgd 	struct fchdir_args /* {
56168318Scgd 		syscallarg(int) fd;
56268318Scgd 	} */ *uap;
56368318Scgd 	register_t *retval;
56438259Smckusick {
56545914Smckusick 	register struct filedesc *fdp = p->p_fd;
56667974Smckusick 	struct vnode *vp, *tdp;
56767974Smckusick 	struct mount *mp;
56838259Smckusick 	struct file *fp;
56938259Smckusick 	int error;
57038259Smckusick 
57168318Scgd 	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
57247540Skarels 		return (error);
57338259Smckusick 	vp = (struct vnode *)fp->f_data;
57467974Smckusick 	VREF(vp);
57538259Smckusick 	VOP_LOCK(vp);
57638259Smckusick 	if (vp->v_type != VDIR)
57738259Smckusick 		error = ENOTDIR;
57838259Smckusick 	else
57948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
58067974Smckusick 	while (!error && (mp = vp->v_mountedhere) != NULL) {
58167974Smckusick 		if (mp->mnt_flag & MNT_MLOCK) {
58267974Smckusick 			mp->mnt_flag |= MNT_MWAIT;
58367974Smckusick 			sleep((caddr_t)mp, PVFS);
58467974Smckusick 			continue;
58567974Smckusick 		}
58667974Smckusick 		if (error = VFS_ROOT(mp, &tdp))
58767974Smckusick 			break;
58867974Smckusick 		vput(vp);
58967974Smckusick 		vp = tdp;
59067974Smckusick 	}
59138259Smckusick 	VOP_UNLOCK(vp);
59267974Smckusick 	if (error) {
59367974Smckusick 		vrele(vp);
59447540Skarels 		return (error);
59567974Smckusick 	}
59645914Smckusick 	vrele(fdp->fd_cdir);
59745914Smckusick 	fdp->fd_cdir = vp;
59847540Skarels 	return (0);
59938259Smckusick }
60038259Smckusick 
60138259Smckusick /*
60237741Smckusick  * Change current working directory (``.'').
60337741Smckusick  */
60442441Smckusick /* ARGSUSED */
60568318Scgd int
60642441Smckusick chdir(p, uap, retval)
60745914Smckusick 	struct proc *p;
60868318Scgd 	struct chdir_args /* {
60968318Scgd 		syscallarg(char *) path;
61068318Scgd 	} */ *uap;
61168318Scgd 	register_t *retval;
61237741Smckusick {
61345914Smckusick 	register struct filedesc *fdp = p->p_fd;
61437741Smckusick 	int error;
61547540Skarels 	struct nameidata nd;
6166254Sroot 
61768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
61868318Scgd 	    SCARG(uap, path), p);
61964410Sbostic 	if (error = change_dir(&nd, p))
62047540Skarels 		return (error);
62145914Smckusick 	vrele(fdp->fd_cdir);
62252322Smckusick 	fdp->fd_cdir = nd.ni_vp;
62347540Skarels 	return (0);
62437741Smckusick }
6256254Sroot 
62637741Smckusick /*
62737741Smckusick  * Change notion of root (``/'') directory.
62837741Smckusick  */
62942441Smckusick /* ARGSUSED */
63068318Scgd int
63142441Smckusick chroot(p, uap, retval)
63245914Smckusick 	struct proc *p;
63368318Scgd 	struct chroot_args /* {
63468318Scgd 		syscallarg(char *) path;
63568318Scgd 	} */ *uap;
63668318Scgd 	register_t *retval;
63737741Smckusick {
63845914Smckusick 	register struct filedesc *fdp = p->p_fd;
63937741Smckusick 	int error;
64047540Skarels 	struct nameidata nd;
64137741Smckusick 
64247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64347540Skarels 		return (error);
64468318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
64568318Scgd 	    SCARG(uap, path), p);
64664410Sbostic 	if (error = change_dir(&nd, p))
64747540Skarels 		return (error);
64845914Smckusick 	if (fdp->fd_rdir != NULL)
64945914Smckusick 		vrele(fdp->fd_rdir);
65052322Smckusick 	fdp->fd_rdir = nd.ni_vp;
65147540Skarels 	return (0);
6526254Sroot }
6536254Sroot 
65437Sbill /*
65537741Smckusick  * Common routine for chroot and chdir.
65637741Smckusick  */
65764410Sbostic static int
65864410Sbostic change_dir(ndp, p)
65952322Smckusick 	register struct nameidata *ndp;
66047540Skarels 	struct proc *p;
66137741Smckusick {
66237741Smckusick 	struct vnode *vp;
66337741Smckusick 	int error;
66437741Smckusick 
66552322Smckusick 	if (error = namei(ndp))
66637741Smckusick 		return (error);
66737741Smckusick 	vp = ndp->ni_vp;
66837741Smckusick 	if (vp->v_type != VDIR)
66937741Smckusick 		error = ENOTDIR;
67037741Smckusick 	else
67148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
67237741Smckusick 	VOP_UNLOCK(vp);
67337741Smckusick 	if (error)
67437741Smckusick 		vrele(vp);
67537741Smckusick 	return (error);
67637741Smckusick }
67737741Smckusick 
67837741Smckusick /*
67942441Smckusick  * Check permissions, allocate an open file structure,
68042441Smckusick  * and call the device open routine if any.
6816254Sroot  */
68268318Scgd int
68342441Smckusick open(p, uap, retval)
68445914Smckusick 	struct proc *p;
68568318Scgd 	register struct open_args /* {
68668318Scgd 		syscallarg(char *) path;
68768318Scgd 		syscallarg(int) flags;
68868318Scgd 		syscallarg(int) mode;
68968318Scgd 	} */ *uap;
69068318Scgd 	register_t *retval;
6916254Sroot {
69245914Smckusick 	register struct filedesc *fdp = p->p_fd;
69342441Smckusick 	register struct file *fp;
69450111Smckusick 	register struct vnode *vp;
69564410Sbostic 	int flags, cmode;
69637741Smckusick 	struct file *nfp;
69749945Smckusick 	int type, indx, error;
69849945Smckusick 	struct flock lf;
69947540Skarels 	struct nameidata nd;
70037741Smckusick 	extern struct fileops vnops;
7016254Sroot 
70245914Smckusick 	if (error = falloc(p, &nfp, &indx))
70347540Skarels 		return (error);
70437741Smckusick 	fp = nfp;
70568318Scgd 	flags = FFLAGS(SCARG(uap, flags));
70668318Scgd 	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
70768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
70845202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
70964410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
71049980Smckusick 		ffree(fp);
71154723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
71268318Scgd 		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
71364410Sbostic 		    (error =
71468318Scgd 			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
71542441Smckusick 			*retval = indx;
71647540Skarels 			return (0);
71742441Smckusick 		}
71840884Smckusick 		if (error == ERESTART)
71940884Smckusick 			error = EINTR;
72047688Skarels 		fdp->fd_ofiles[indx] = NULL;
72147540Skarels 		return (error);
72212756Ssam 	}
72353828Spendry 	p->p_dupfd = 0;
72452322Smckusick 	vp = nd.ni_vp;
72564410Sbostic 	fp->f_flag = flags & FMASK;
72654348Smckusick 	fp->f_type = DTYPE_VNODE;
72754348Smckusick 	fp->f_ops = &vnops;
72854348Smckusick 	fp->f_data = (caddr_t)vp;
72964410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
73049945Smckusick 		lf.l_whence = SEEK_SET;
73149945Smckusick 		lf.l_start = 0;
73249945Smckusick 		lf.l_len = 0;
73364410Sbostic 		if (flags & O_EXLOCK)
73449945Smckusick 			lf.l_type = F_WRLCK;
73549945Smckusick 		else
73649945Smckusick 			lf.l_type = F_RDLCK;
73749945Smckusick 		type = F_FLOCK;
73864410Sbostic 		if ((flags & FNONBLOCK) == 0)
73949945Smckusick 			type |= F_WAIT;
74065757Smckusick 		VOP_UNLOCK(vp);
74150111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
74250111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
74349980Smckusick 			ffree(fp);
74449945Smckusick 			fdp->fd_ofiles[indx] = NULL;
74549945Smckusick 			return (error);
74649945Smckusick 		}
74765757Smckusick 		VOP_LOCK(vp);
74849949Smckusick 		fp->f_flag |= FHASLOCK;
74949945Smckusick 	}
75050111Smckusick 	VOP_UNLOCK(vp);
75142441Smckusick 	*retval = indx;
75247540Skarels 	return (0);
7536254Sroot }
7546254Sroot 
75542955Smckusick #ifdef COMPAT_43
7566254Sroot /*
75764410Sbostic  * Create a file.
7586254Sroot  */
75968318Scgd int
76068318Scgd compat_43_creat(p, uap, retval)
76142441Smckusick 	struct proc *p;
76268318Scgd 	register struct compat_43_creat_args /* {
76368318Scgd 		syscallarg(char *) path;
76468318Scgd 		syscallarg(int) mode;
76568318Scgd 	} */ *uap;
76668318Scgd 	register_t *retval;
7676254Sroot {
76868318Scgd 	struct open_args /* {
76968318Scgd 		syscallarg(char *) path;
77068318Scgd 		syscallarg(int) flags;
77168318Scgd 		syscallarg(int) mode;
77268318Scgd 	} */ nuap;
77342441Smckusick 
77468318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
77568318Scgd 	SCARG(&nuap, mode) = SCARG(uap, mode);
77668318Scgd 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
77768318Scgd 	return (open(p, &nuap, retval));
77842441Smckusick }
77942955Smckusick #endif /* COMPAT_43 */
78042441Smckusick 
78142441Smckusick /*
78264410Sbostic  * Create a special file.
78342441Smckusick  */
78442441Smckusick /* ARGSUSED */
78568318Scgd int
78642441Smckusick mknod(p, uap, retval)
78745914Smckusick 	struct proc *p;
78868318Scgd 	register struct mknod_args /* {
78968318Scgd 		syscallarg(char *) path;
79068318Scgd 		syscallarg(int) mode;
79168318Scgd 		syscallarg(int) dev;
79268318Scgd 	} */ *uap;
79368318Scgd 	register_t *retval;
79442441Smckusick {
79537741Smckusick 	register struct vnode *vp;
79637741Smckusick 	struct vattr vattr;
79737741Smckusick 	int error;
79867575Spendry 	int whiteout;
79947540Skarels 	struct nameidata nd;
8006254Sroot 
80147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
80247540Skarels 		return (error);
80368318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
80452322Smckusick 	if (error = namei(&nd))
80547540Skarels 		return (error);
80652322Smckusick 	vp = nd.ni_vp;
80764585Sbostic 	if (vp != NULL)
80837741Smckusick 		error = EEXIST;
80964585Sbostic 	else {
81064585Sbostic 		VATTR_NULL(&vattr);
81168318Scgd 		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
81268318Scgd 		vattr.va_rdev = SCARG(uap, dev);
81367575Spendry 		whiteout = 0;
81464585Sbostic 
81568318Scgd 		switch (SCARG(uap, mode) & S_IFMT) {
81664585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
81764585Sbostic 			vattr.va_type = VBAD;
81864585Sbostic 			break;
81964585Sbostic 		case S_IFCHR:
82064585Sbostic 			vattr.va_type = VCHR;
82164585Sbostic 			break;
82264585Sbostic 		case S_IFBLK:
82364585Sbostic 			vattr.va_type = VBLK;
82464585Sbostic 			break;
82567575Spendry 		case S_IFWHT:
82667575Spendry 			whiteout = 1;
82767575Spendry 			break;
82864585Sbostic 		default:
82964585Sbostic 			error = EINVAL;
83064585Sbostic 			break;
83164585Sbostic 		}
8326254Sroot 	}
83367747Spendry 	if (!error) {
83467654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
83567747Spendry 		if (whiteout) {
83667747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
83767747Spendry 			if (error)
83867747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
83967747Spendry 			vput(nd.ni_dvp);
84067747Spendry 		} else {
84167747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
84267747Spendry 						&nd.ni_cnd, &vattr);
84367747Spendry 		}
84442465Smckusick 	} else {
84552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
84652322Smckusick 		if (nd.ni_dvp == vp)
84752322Smckusick 			vrele(nd.ni_dvp);
84843344Smckusick 		else
84952322Smckusick 			vput(nd.ni_dvp);
85042465Smckusick 		if (vp)
85142465Smckusick 			vrele(vp);
85242465Smckusick 	}
85347540Skarels 	return (error);
8546254Sroot }
8556254Sroot 
8566254Sroot /*
85768318Scgd  * Create a named pipe.
85840285Smckusick  */
85942441Smckusick /* ARGSUSED */
86068318Scgd int
86142441Smckusick mkfifo(p, uap, retval)
86245914Smckusick 	struct proc *p;
86368318Scgd 	register struct mkfifo_args /* {
86468318Scgd 		syscallarg(char *) path;
86568318Scgd 		syscallarg(int) mode;
86668318Scgd 	} */ *uap;
86768318Scgd 	register_t *retval;
86842441Smckusick {
86940285Smckusick 	struct vattr vattr;
87040285Smckusick 	int error;
87147540Skarels 	struct nameidata nd;
87240285Smckusick 
87340285Smckusick #ifndef FIFO
87447540Skarels 	return (EOPNOTSUPP);
87540285Smckusick #else
87668318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
87752322Smckusick 	if (error = namei(&nd))
87847540Skarels 		return (error);
87952322Smckusick 	if (nd.ni_vp != NULL) {
88052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
88152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
88252322Smckusick 			vrele(nd.ni_dvp);
88343344Smckusick 		else
88452322Smckusick 			vput(nd.ni_dvp);
88552322Smckusick 		vrele(nd.ni_vp);
88647540Skarels 		return (EEXIST);
88740285Smckusick 	}
88845785Sbostic 	VATTR_NULL(&vattr);
88945785Sbostic 	vattr.va_type = VFIFO;
89068318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
89167654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
89252322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
89340285Smckusick #endif /* FIFO */
89440285Smckusick }
89540285Smckusick 
89640285Smckusick /*
89764410Sbostic  * Make a hard file link.
8986254Sroot  */
89942441Smckusick /* ARGSUSED */
90068318Scgd int
90142441Smckusick link(p, uap, retval)
90245914Smckusick 	struct proc *p;
90368318Scgd 	register struct link_args /* {
90468318Scgd 		syscallarg(char *) path;
90568318Scgd 		syscallarg(char *) link;
90668318Scgd 	} */ *uap;
90768318Scgd 	register_t *retval;
90842441Smckusick {
90964410Sbostic 	register struct vnode *vp;
91064410Sbostic 	struct nameidata nd;
91137741Smckusick 	int error;
9126254Sroot 
91368318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
91452322Smckusick 	if (error = namei(&nd))
91547540Skarels 		return (error);
91652322Smckusick 	vp = nd.ni_vp;
91764585Sbostic 	if (vp->v_type != VDIR ||
91864585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
91964585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
92064585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
92168318Scgd 		nd.ni_dirp = SCARG(uap, link);
92264585Sbostic 		if ((error = namei(&nd)) == 0) {
92364585Sbostic 			if (nd.ni_vp != NULL)
92464585Sbostic 				error = EEXIST;
92564585Sbostic 			if (!error) {
92667654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
92767654Smckusick 				    LEASE_WRITE);
92867654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
92968538Smckusick 				error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
93064585Sbostic 			} else {
93164585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
93264585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
93364585Sbostic 					vrele(nd.ni_dvp);
93464585Sbostic 				else
93564585Sbostic 					vput(nd.ni_dvp);
93664585Sbostic 				if (nd.ni_vp)
93764585Sbostic 					vrele(nd.ni_vp);
93864585Sbostic 			}
93964585Sbostic 		}
94042465Smckusick 	}
94164585Sbostic 	vrele(vp);
94247540Skarels 	return (error);
9436254Sroot }
9446254Sroot 
9456254Sroot /*
94649365Smckusick  * Make a symbolic link.
9476254Sroot  */
94842441Smckusick /* ARGSUSED */
94968318Scgd int
95042441Smckusick symlink(p, uap, retval)
95145914Smckusick 	struct proc *p;
95268318Scgd 	register struct symlink_args /* {
95368318Scgd 		syscallarg(char *) path;
95468318Scgd 		syscallarg(char *) link;
95568318Scgd 	} */ *uap;
95668318Scgd 	register_t *retval;
95742441Smckusick {
95837741Smckusick 	struct vattr vattr;
95964410Sbostic 	char *path;
96037741Smckusick 	int error;
96147540Skarels 	struct nameidata nd;
9626254Sroot 
96364410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
96468318Scgd 	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
96542465Smckusick 		goto out;
96668318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
96752322Smckusick 	if (error = namei(&nd))
96842465Smckusick 		goto out;
96952322Smckusick 	if (nd.ni_vp) {
97052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
97152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
97252322Smckusick 			vrele(nd.ni_dvp);
97343344Smckusick 		else
97452322Smckusick 			vput(nd.ni_dvp);
97552322Smckusick 		vrele(nd.ni_vp);
97637741Smckusick 		error = EEXIST;
97737741Smckusick 		goto out;
9786254Sroot 	}
97941362Smckusick 	VATTR_NULL(&vattr);
98064410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
98167654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
98264410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
98337741Smckusick out:
98464410Sbostic 	FREE(path, M_NAMEI);
98547540Skarels 	return (error);
9866254Sroot }
9876254Sroot 
9886254Sroot /*
98967518Spendry  * Delete a whiteout from the filesystem.
99067518Spendry  */
99167518Spendry /* ARGSUSED */
99268318Scgd int
99367845Smckusick undelete(p, uap, retval)
99467518Spendry 	struct proc *p;
99568318Scgd 	register struct undelete_args /* {
99668318Scgd 		syscallarg(char *) path;
99768318Scgd 	} */ *uap;
99868318Scgd 	register_t *retval;
99967518Spendry {
100067518Spendry 	int error;
100167518Spendry 	struct nameidata nd;
100267518Spendry 
100368318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
100468318Scgd 	    SCARG(uap, path), p);
100567575Spendry 	error = namei(&nd);
100667575Spendry 	if (error)
100767518Spendry 		return (error);
100867575Spendry 
100967575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
101067518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
101167518Spendry 		if (nd.ni_dvp == nd.ni_vp)
101267518Spendry 			vrele(nd.ni_dvp);
101367518Spendry 		else
101467518Spendry 			vput(nd.ni_dvp);
101567518Spendry 		if (nd.ni_vp)
101667518Spendry 			vrele(nd.ni_vp);
101767518Spendry 		return (EEXIST);
101867518Spendry 	}
101967575Spendry 
102067654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
102167747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
102267575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
102367518Spendry 	vput(nd.ni_dvp);
102467518Spendry 	return (error);
102567518Spendry }
102667518Spendry 
102767518Spendry /*
102849365Smckusick  * Delete a name from the filesystem.
10296254Sroot  */
103042441Smckusick /* ARGSUSED */
103168318Scgd int
103242441Smckusick unlink(p, uap, retval)
103345914Smckusick 	struct proc *p;
103468318Scgd 	struct unlink_args /* {
103568318Scgd 		syscallarg(char *) path;
103668318Scgd 	} */ *uap;
103768318Scgd 	register_t *retval;
10386254Sroot {
103937741Smckusick 	register struct vnode *vp;
104037741Smckusick 	int error;
104147540Skarels 	struct nameidata nd;
10426254Sroot 
104368318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
104452322Smckusick 	if (error = namei(&nd))
104547540Skarels 		return (error);
104652322Smckusick 	vp = nd.ni_vp;
104767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
104859382Smckusick 	VOP_LOCK(vp);
104964410Sbostic 
105064585Sbostic 	if (vp->v_type != VDIR ||
105164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
105264585Sbostic 		/*
105364585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
105464585Sbostic 		 */
105564585Sbostic 		if (vp->v_flag & VROOT)
105664585Sbostic 			error = EBUSY;
105764585Sbostic 		else
105864585Sbostic 			(void)vnode_pager_uncache(vp);
105964585Sbostic 	}
106064585Sbostic 
106164585Sbostic 	if (!error) {
106267654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
106352322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
106442465Smckusick 	} else {
106552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
106652322Smckusick 		if (nd.ni_dvp == vp)
106752322Smckusick 			vrele(nd.ni_dvp);
106843344Smckusick 		else
106952322Smckusick 			vput(nd.ni_dvp);
107067575Spendry 		if (vp != NULLVP)
107167575Spendry 			vput(vp);
107242465Smckusick 	}
107347540Skarels 	return (error);
10746254Sroot }
10756254Sroot 
107664410Sbostic /*
107764410Sbostic  * Reposition read/write file offset.
107864410Sbostic  */
107968318Scgd int
108060414Smckusick lseek(p, uap, retval)
108153468Smckusick 	struct proc *p;
108268318Scgd 	register struct lseek_args /* {
108368318Scgd 		syscallarg(int) fd;
108468318Scgd 		syscallarg(int) pad;
108568318Scgd 		syscallarg(off_t) offset;
108668318Scgd 		syscallarg(int) whence;
108768318Scgd 	} */ *uap;
108868318Scgd 	register_t *retval;
108942441Smckusick {
109047540Skarels 	struct ucred *cred = p->p_ucred;
109145914Smckusick 	register struct filedesc *fdp = p->p_fd;
109242441Smckusick 	register struct file *fp;
109337741Smckusick 	struct vattr vattr;
109437741Smckusick 	int error;
10956254Sroot 
109668318Scgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
109768318Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
109847540Skarels 		return (EBADF);
109937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
110047540Skarels 		return (ESPIPE);
110168318Scgd 	switch (SCARG(uap, whence)) {
110213878Ssam 	case L_INCR:
110368318Scgd 		fp->f_offset += SCARG(uap, offset);
110413878Ssam 		break;
110513878Ssam 	case L_XTND:
110664410Sbostic 		if (error =
110764410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
110847540Skarels 			return (error);
110968318Scgd 		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
111013878Ssam 		break;
111113878Ssam 	case L_SET:
111268318Scgd 		fp->f_offset = SCARG(uap, offset);
111313878Ssam 		break;
111413878Ssam 	default:
111547540Skarels 		return (EINVAL);
111613878Ssam 	}
111754916Storek 	*(off_t *)retval = fp->f_offset;
111847540Skarels 	return (0);
11196254Sroot }
11206254Sroot 
112160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11226254Sroot /*
112364410Sbostic  * Reposition read/write file offset.
112460036Smckusick  */
112568318Scgd int
112668318Scgd compat_43_lseek(p, uap, retval)
112760036Smckusick 	struct proc *p;
112868318Scgd 	register struct compat_43_lseek_args /* {
112968318Scgd 		syscallarg(int) fd;
113068318Scgd 		syscallarg(long) offset;
113168318Scgd 		syscallarg(int) whence;
113268318Scgd 	} */ *uap;
113368318Scgd 	register_t *retval;
113460036Smckusick {
113568318Scgd 	struct lseek_args /* {
113668318Scgd 		syscallarg(int) fd;
113768318Scgd 		syscallarg(int) pad;
113868318Scgd 		syscallarg(off_t) offset;
113968318Scgd 		syscallarg(int) whence;
114068318Scgd 	} */ nuap;
114160036Smckusick 	off_t qret;
114260036Smckusick 	int error;
114360036Smckusick 
114468318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
114568318Scgd 	SCARG(&nuap, offset) = SCARG(uap, offset);
114668318Scgd 	SCARG(&nuap, whence) = SCARG(uap, whence);
114760428Smckusick 	error = lseek(p, &nuap, &qret);
114860036Smckusick 	*(long *)retval = qret;
114960036Smckusick 	return (error);
115060036Smckusick }
115160414Smckusick #endif /* COMPAT_43 */
115260036Smckusick 
115360036Smckusick /*
115449365Smckusick  * Check access permissions.
11556254Sroot  */
115668318Scgd int
115763427Sbostic access(p, uap, retval)
115845914Smckusick 	struct proc *p;
115968318Scgd 	register struct access_args /* {
116068318Scgd 		syscallarg(char *) path;
116168318Scgd 		syscallarg(int) flags;
116268318Scgd 	} */ *uap;
116368318Scgd 	register_t *retval;
116442441Smckusick {
116547540Skarels 	register struct ucred *cred = p->p_ucred;
116637741Smckusick 	register struct vnode *vp;
116764585Sbostic 	int error, flags, t_gid, t_uid;
116847540Skarels 	struct nameidata nd;
11696254Sroot 
117064585Sbostic 	t_uid = cred->cr_uid;
117164585Sbostic 	t_gid = cred->cr_groups[0];
117247540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
117347540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
117468318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
117568318Scgd 	    SCARG(uap, path), p);
117652322Smckusick 	if (error = namei(&nd))
117737741Smckusick 		goto out1;
117852322Smckusick 	vp = nd.ni_vp;
117964410Sbostic 
118064410Sbostic 	/* Flags == 0 means only check for existence. */
118168318Scgd 	if (SCARG(uap, flags)) {
118264410Sbostic 		flags = 0;
118368318Scgd 		if (SCARG(uap, flags) & R_OK)
118464410Sbostic 			flags |= VREAD;
118568318Scgd 		if (SCARG(uap, flags) & W_OK)
118664410Sbostic 			flags |= VWRITE;
118768318Scgd 		if (SCARG(uap, flags) & X_OK)
118864410Sbostic 			flags |= VEXEC;
118964410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
119064410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
11916254Sroot 	}
119237741Smckusick 	vput(vp);
119337741Smckusick out1:
119464585Sbostic 	cred->cr_uid = t_uid;
119564585Sbostic 	cred->cr_groups[0] = t_gid;
119647540Skarels 	return (error);
11976254Sroot }
11986254Sroot 
119954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
12006254Sroot /*
120164410Sbostic  * Get file status; this version follows links.
120237Sbill  */
120342441Smckusick /* ARGSUSED */
120468318Scgd int
120568318Scgd compat_43_stat(p, uap, retval)
120645914Smckusick 	struct proc *p;
120768318Scgd 	register struct compat_43_stat_args /* {
120868318Scgd 		syscallarg(char *) path;
120968318Scgd 		syscallarg(struct ostat *) ub;
121068318Scgd 	} */ *uap;
121168318Scgd 	register_t *retval;
121253468Smckusick {
121353468Smckusick 	struct stat sb;
121453468Smckusick 	struct ostat osb;
121553468Smckusick 	int error;
121653468Smckusick 	struct nameidata nd;
121753468Smckusick 
121868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
121968318Scgd 	    SCARG(uap, path), p);
122053468Smckusick 	if (error = namei(&nd))
122153468Smckusick 		return (error);
122253468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
122353468Smckusick 	vput(nd.ni_vp);
122453468Smckusick 	if (error)
122553468Smckusick 		return (error);
122653468Smckusick 	cvtstat(&sb, &osb);
122768318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
122853468Smckusick 	return (error);
122953468Smckusick }
123053468Smckusick 
123153468Smckusick /*
123264410Sbostic  * Get file status; this version does not follow links.
123353468Smckusick  */
123453468Smckusick /* ARGSUSED */
123568318Scgd int
123668318Scgd compat_43_lstat(p, uap, retval)
123753468Smckusick 	struct proc *p;
123868318Scgd 	register struct compat_43_lstat_args /* {
123968318Scgd 		syscallarg(char *) path;
124068318Scgd 		syscallarg(struct ostat *) ub;
124168318Scgd 	} */ *uap;
124268318Scgd 	register_t *retval;
124353468Smckusick {
124467748Smckusick 	struct vnode *vp, *dvp;
124567748Smckusick 	struct stat sb, sb1;
124653468Smckusick 	struct ostat osb;
124753468Smckusick 	int error;
124853468Smckusick 	struct nameidata nd;
124953468Smckusick 
125067748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
125168318Scgd 	    SCARG(uap, path), p);
125253468Smckusick 	if (error = namei(&nd))
125353468Smckusick 		return (error);
125467748Smckusick 	/*
125567748Smckusick 	 * For symbolic links, always return the attributes of its
125667748Smckusick 	 * containing directory, except for mode, size, and links.
125767748Smckusick 	 */
125867748Smckusick 	vp = nd.ni_vp;
125967748Smckusick 	dvp = nd.ni_dvp;
126067748Smckusick 	if (vp->v_type != VLNK) {
126167748Smckusick 		if (dvp == vp)
126267748Smckusick 			vrele(dvp);
126367748Smckusick 		else
126467748Smckusick 			vput(dvp);
126567748Smckusick 		error = vn_stat(vp, &sb, p);
126667748Smckusick 		vput(vp);
126767748Smckusick 		if (error)
126867748Smckusick 			return (error);
126967748Smckusick 	} else {
127067748Smckusick 		error = vn_stat(dvp, &sb, p);
127167748Smckusick 		vput(dvp);
127267748Smckusick 		if (error) {
127367748Smckusick 			vput(vp);
127467748Smckusick 			return (error);
127567748Smckusick 		}
127667748Smckusick 		error = vn_stat(vp, &sb1, p);
127767748Smckusick 		vput(vp);
127867748Smckusick 		if (error)
127967748Smckusick 			return (error);
128067748Smckusick 		sb.st_mode &= ~S_IFDIR;
128167748Smckusick 		sb.st_mode |= S_IFLNK;
128267748Smckusick 		sb.st_nlink = sb1.st_nlink;
128367748Smckusick 		sb.st_size = sb1.st_size;
128467748Smckusick 		sb.st_blocks = sb1.st_blocks;
128567748Smckusick 	}
128653468Smckusick 	cvtstat(&sb, &osb);
128768318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
128853468Smckusick 	return (error);
128953468Smckusick }
129053468Smckusick 
129153468Smckusick /*
129264410Sbostic  * Convert from an old to a new stat structure.
129353468Smckusick  */
129468318Scgd void
129553468Smckusick cvtstat(st, ost)
129653468Smckusick 	struct stat *st;
129753468Smckusick 	struct ostat *ost;
129853468Smckusick {
129953468Smckusick 
130053468Smckusick 	ost->st_dev = st->st_dev;
130153468Smckusick 	ost->st_ino = st->st_ino;
130253468Smckusick 	ost->st_mode = st->st_mode;
130353468Smckusick 	ost->st_nlink = st->st_nlink;
130453468Smckusick 	ost->st_uid = st->st_uid;
130553468Smckusick 	ost->st_gid = st->st_gid;
130653468Smckusick 	ost->st_rdev = st->st_rdev;
130753468Smckusick 	if (st->st_size < (quad_t)1 << 32)
130853468Smckusick 		ost->st_size = st->st_size;
130953468Smckusick 	else
131053468Smckusick 		ost->st_size = -2;
131153468Smckusick 	ost->st_atime = st->st_atime;
131253468Smckusick 	ost->st_mtime = st->st_mtime;
131353468Smckusick 	ost->st_ctime = st->st_ctime;
131453468Smckusick 	ost->st_blksize = st->st_blksize;
131553468Smckusick 	ost->st_blocks = st->st_blocks;
131653468Smckusick 	ost->st_flags = st->st_flags;
131753468Smckusick 	ost->st_gen = st->st_gen;
131853468Smckusick }
131954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
132053468Smckusick 
132153468Smckusick /*
132264410Sbostic  * Get file status; this version follows links.
132353468Smckusick  */
132453468Smckusick /* ARGSUSED */
132568318Scgd int
132653759Smckusick stat(p, uap, retval)
132753468Smckusick 	struct proc *p;
132868318Scgd 	register struct stat_args /* {
132968318Scgd 		syscallarg(char *) path;
133068318Scgd 		syscallarg(struct stat *) ub;
133168318Scgd 	} */ *uap;
133268318Scgd 	register_t *retval;
133337Sbill {
133442441Smckusick 	struct stat sb;
133542441Smckusick 	int error;
133647540Skarels 	struct nameidata nd;
133737Sbill 
133868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
133968318Scgd 	    SCARG(uap, path), p);
134052322Smckusick 	if (error = namei(&nd))
134147540Skarels 		return (error);
134252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
134352322Smckusick 	vput(nd.ni_vp);
134442441Smckusick 	if (error)
134547540Skarels 		return (error);
134668318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
134747540Skarels 	return (error);
134837Sbill }
134937Sbill 
135037Sbill /*
135164410Sbostic  * Get file status; this version does not follow links.
13525992Swnj  */
135342441Smckusick /* ARGSUSED */
135468318Scgd int
135553759Smckusick lstat(p, uap, retval)
135645914Smckusick 	struct proc *p;
135768318Scgd 	register struct lstat_args /* {
135868318Scgd 		syscallarg(char *) path;
135968318Scgd 		syscallarg(struct stat *) ub;
136068318Scgd 	} */ *uap;
136168318Scgd 	register_t *retval;
136242441Smckusick {
136337741Smckusick 	int error;
136459373Smckusick 	struct vnode *vp, *dvp;
136559373Smckusick 	struct stat sb, sb1;
136647540Skarels 	struct nameidata nd;
13675992Swnj 
136859373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
136968318Scgd 	    SCARG(uap, path), p);
137052322Smckusick 	if (error = namei(&nd))
137147540Skarels 		return (error);
137259373Smckusick 	/*
137368579Smckusick 	 * For symbolic links, always return the attributes of its containing
137468579Smckusick 	 * directory, except for mode, size, inode number, and links.
137559373Smckusick 	 */
137659373Smckusick 	vp = nd.ni_vp;
137759373Smckusick 	dvp = nd.ni_dvp;
137859373Smckusick 	if (vp->v_type != VLNK) {
137959373Smckusick 		if (dvp == vp)
138059373Smckusick 			vrele(dvp);
138159373Smckusick 		else
138259373Smckusick 			vput(dvp);
138359373Smckusick 		error = vn_stat(vp, &sb, p);
138459373Smckusick 		vput(vp);
138559373Smckusick 		if (error)
138659373Smckusick 			return (error);
138759373Smckusick 	} else {
138859373Smckusick 		error = vn_stat(dvp, &sb, p);
138959373Smckusick 		vput(dvp);
139059373Smckusick 		if (error) {
139159373Smckusick 			vput(vp);
139259373Smckusick 			return (error);
139359373Smckusick 		}
139459373Smckusick 		error = vn_stat(vp, &sb1, p);
139559373Smckusick 		vput(vp);
139659373Smckusick 		if (error)
139759373Smckusick 			return (error);
139859373Smckusick 		sb.st_mode &= ~S_IFDIR;
139959373Smckusick 		sb.st_mode |= S_IFLNK;
140059373Smckusick 		sb.st_nlink = sb1.st_nlink;
140159373Smckusick 		sb.st_size = sb1.st_size;
140259373Smckusick 		sb.st_blocks = sb1.st_blocks;
140368579Smckusick 		sb.st_ino = sb1.st_ino;
140459373Smckusick 	}
140568318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
140647540Skarels 	return (error);
14075992Swnj }
14085992Swnj 
14095992Swnj /*
141064410Sbostic  * Get configurable pathname variables.
141160414Smckusick  */
141260414Smckusick /* ARGSUSED */
141368318Scgd int
141460414Smckusick pathconf(p, uap, retval)
141560414Smckusick 	struct proc *p;
141668318Scgd 	register struct pathconf_args /* {
141768318Scgd 		syscallarg(char *) path;
141868318Scgd 		syscallarg(int) name;
141968318Scgd 	} */ *uap;
142068318Scgd 	register_t *retval;
142160414Smckusick {
142260414Smckusick 	int error;
142360414Smckusick 	struct nameidata nd;
142460414Smckusick 
142568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
142668318Scgd 	    SCARG(uap, path), p);
142760414Smckusick 	if (error = namei(&nd))
142860414Smckusick 		return (error);
142968318Scgd 	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
143060414Smckusick 	vput(nd.ni_vp);
143160414Smckusick 	return (error);
143260414Smckusick }
143360414Smckusick 
143460414Smckusick /*
143549365Smckusick  * Return target name of a symbolic link.
143637Sbill  */
143742441Smckusick /* ARGSUSED */
143868318Scgd int
143942441Smckusick readlink(p, uap, retval)
144045914Smckusick 	struct proc *p;
144168318Scgd 	register struct readlink_args /* {
144268318Scgd 		syscallarg(char *) path;
144368318Scgd 		syscallarg(char *) buf;
144468318Scgd 		syscallarg(int) count;
144568318Scgd 	} */ *uap;
144668318Scgd 	register_t *retval;
144742441Smckusick {
144837741Smckusick 	register struct vnode *vp;
144937741Smckusick 	struct iovec aiov;
145037741Smckusick 	struct uio auio;
145137741Smckusick 	int error;
145247540Skarels 	struct nameidata nd;
14535992Swnj 
145468318Scgd 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
145568318Scgd 	    SCARG(uap, path), p);
145652322Smckusick 	if (error = namei(&nd))
145747540Skarels 		return (error);
145852322Smckusick 	vp = nd.ni_vp;
145964410Sbostic 	if (vp->v_type != VLNK)
146037741Smckusick 		error = EINVAL;
146164410Sbostic 	else {
146268318Scgd 		aiov.iov_base = SCARG(uap, buf);
146368318Scgd 		aiov.iov_len = SCARG(uap, count);
146464410Sbostic 		auio.uio_iov = &aiov;
146564410Sbostic 		auio.uio_iovcnt = 1;
146664410Sbostic 		auio.uio_offset = 0;
146764410Sbostic 		auio.uio_rw = UIO_READ;
146864410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
146964410Sbostic 		auio.uio_procp = p;
147068318Scgd 		auio.uio_resid = SCARG(uap, count);
147164410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
14725992Swnj 	}
147337741Smckusick 	vput(vp);
147468318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
147547540Skarels 	return (error);
14765992Swnj }
14775992Swnj 
14789167Ssam /*
147964410Sbostic  * Change flags of a file given a path name.
148038259Smckusick  */
148142441Smckusick /* ARGSUSED */
148268318Scgd int
148342441Smckusick chflags(p, uap, retval)
148445914Smckusick 	struct proc *p;
148568318Scgd 	register struct chflags_args /* {
148668318Scgd 		syscallarg(char *) path;
148768318Scgd 		syscallarg(int) flags;
148868318Scgd 	} */ *uap;
148968318Scgd 	register_t *retval;
149042441Smckusick {
149138259Smckusick 	register struct vnode *vp;
149238259Smckusick 	struct vattr vattr;
149338259Smckusick 	int error;
149447540Skarels 	struct nameidata nd;
149538259Smckusick 
149668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
149752322Smckusick 	if (error = namei(&nd))
149847540Skarels 		return (error);
149952322Smckusick 	vp = nd.ni_vp;
150067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
150159382Smckusick 	VOP_LOCK(vp);
150264410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
150338259Smckusick 		error = EROFS;
150464410Sbostic 	else {
150564410Sbostic 		VATTR_NULL(&vattr);
150668318Scgd 		vattr.va_flags = SCARG(uap, flags);
150764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
150838259Smckusick 	}
150938259Smckusick 	vput(vp);
151047540Skarels 	return (error);
151138259Smckusick }
151238259Smckusick 
151338259Smckusick /*
151438259Smckusick  * Change flags of a file given a file descriptor.
151538259Smckusick  */
151642441Smckusick /* ARGSUSED */
151768318Scgd int
151842441Smckusick fchflags(p, uap, retval)
151945914Smckusick 	struct proc *p;
152068318Scgd 	register struct fchflags_args /* {
152168318Scgd 		syscallarg(int) fd;
152268318Scgd 		syscallarg(int) flags;
152368318Scgd 	} */ *uap;
152468318Scgd 	register_t *retval;
152542441Smckusick {
152638259Smckusick 	struct vattr vattr;
152738259Smckusick 	struct vnode *vp;
152838259Smckusick 	struct file *fp;
152938259Smckusick 	int error;
153038259Smckusick 
153168318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
153247540Skarels 		return (error);
153338259Smckusick 	vp = (struct vnode *)fp->f_data;
153467654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
153538259Smckusick 	VOP_LOCK(vp);
153664410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
153738259Smckusick 		error = EROFS;
153864410Sbostic 	else {
153964410Sbostic 		VATTR_NULL(&vattr);
154068318Scgd 		vattr.va_flags = SCARG(uap, flags);
154164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
154238259Smckusick 	}
154338259Smckusick 	VOP_UNLOCK(vp);
154447540Skarels 	return (error);
154538259Smckusick }
154638259Smckusick 
154738259Smckusick /*
15489167Ssam  * Change mode of a file given path name.
15499167Ssam  */
155042441Smckusick /* ARGSUSED */
155168318Scgd int
155242441Smckusick chmod(p, uap, retval)
155345914Smckusick 	struct proc *p;
155468318Scgd 	register struct chmod_args /* {
155568318Scgd 		syscallarg(char *) path;
155668318Scgd 		syscallarg(int) mode;
155768318Scgd 	} */ *uap;
155868318Scgd 	register_t *retval;
155942441Smckusick {
156037741Smckusick 	register struct vnode *vp;
156137741Smckusick 	struct vattr vattr;
156237741Smckusick 	int error;
156347540Skarels 	struct nameidata nd;
15645992Swnj 
156568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
156652322Smckusick 	if (error = namei(&nd))
156747540Skarels 		return (error);
156852322Smckusick 	vp = nd.ni_vp;
156967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
157059382Smckusick 	VOP_LOCK(vp);
157164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
157237741Smckusick 		error = EROFS;
157364410Sbostic 	else {
157464410Sbostic 		VATTR_NULL(&vattr);
157568318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
157664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
157737741Smckusick 	}
157837741Smckusick 	vput(vp);
157947540Skarels 	return (error);
15807701Ssam }
15817439Sroot 
15829167Ssam /*
15839167Ssam  * Change mode of a file given a file descriptor.
15849167Ssam  */
158542441Smckusick /* ARGSUSED */
158668318Scgd int
158742441Smckusick fchmod(p, uap, retval)
158845914Smckusick 	struct proc *p;
158968318Scgd 	register struct fchmod_args /* {
159068318Scgd 		syscallarg(int) fd;
159168318Scgd 		syscallarg(int) mode;
159268318Scgd 	} */ *uap;
159368318Scgd 	register_t *retval;
159442441Smckusick {
159537741Smckusick 	struct vattr vattr;
159637741Smckusick 	struct vnode *vp;
159737741Smckusick 	struct file *fp;
159837741Smckusick 	int error;
15997701Ssam 
160068318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
160147540Skarels 		return (error);
160237741Smckusick 	vp = (struct vnode *)fp->f_data;
160367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
160437741Smckusick 	VOP_LOCK(vp);
160564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
160637741Smckusick 		error = EROFS;
160764410Sbostic 	else {
160864410Sbostic 		VATTR_NULL(&vattr);
160968318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
161064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16117439Sroot 	}
161237741Smckusick 	VOP_UNLOCK(vp);
161347540Skarels 	return (error);
16145992Swnj }
16155992Swnj 
16169167Ssam /*
16179167Ssam  * Set ownership given a path name.
16189167Ssam  */
161942441Smckusick /* ARGSUSED */
162068318Scgd int
162142441Smckusick chown(p, uap, retval)
162245914Smckusick 	struct proc *p;
162368318Scgd 	register struct chown_args /* {
162468318Scgd 		syscallarg(char *) path;
162568318Scgd 		syscallarg(int) uid;
162668318Scgd 		syscallarg(int) gid;
162768318Scgd 	} */ *uap;
162868318Scgd 	register_t *retval;
162942441Smckusick {
163037741Smckusick 	register struct vnode *vp;
163137741Smckusick 	struct vattr vattr;
163237741Smckusick 	int error;
163347540Skarels 	struct nameidata nd;
163437Sbill 
163568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
163652322Smckusick 	if (error = namei(&nd))
163747540Skarels 		return (error);
163852322Smckusick 	vp = nd.ni_vp;
163967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
164059382Smckusick 	VOP_LOCK(vp);
164164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
164237741Smckusick 		error = EROFS;
164364410Sbostic 	else {
164464410Sbostic 		VATTR_NULL(&vattr);
164568318Scgd 		vattr.va_uid = SCARG(uap, uid);
164668318Scgd 		vattr.va_gid = SCARG(uap, gid);
164764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
164837741Smckusick 	}
164937741Smckusick 	vput(vp);
165047540Skarels 	return (error);
16517701Ssam }
16527439Sroot 
16539167Ssam /*
16549167Ssam  * Set ownership given a file descriptor.
16559167Ssam  */
165642441Smckusick /* ARGSUSED */
165768318Scgd int
165842441Smckusick fchown(p, uap, retval)
165945914Smckusick 	struct proc *p;
166068318Scgd 	register struct fchown_args /* {
166168318Scgd 		syscallarg(int) fd;
166268318Scgd 		syscallarg(int) uid;
166368318Scgd 		syscallarg(int) gid;
166468318Scgd 	} */ *uap;
166568318Scgd 	register_t *retval;
166642441Smckusick {
166737741Smckusick 	struct vattr vattr;
166837741Smckusick 	struct vnode *vp;
166937741Smckusick 	struct file *fp;
167037741Smckusick 	int error;
16717701Ssam 
167268318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
167347540Skarels 		return (error);
167437741Smckusick 	vp = (struct vnode *)fp->f_data;
167567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
167637741Smckusick 	VOP_LOCK(vp);
167764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
167837741Smckusick 		error = EROFS;
167964410Sbostic 	else {
168064410Sbostic 		VATTR_NULL(&vattr);
168168318Scgd 		vattr.va_uid = SCARG(uap, uid);
168268318Scgd 		vattr.va_gid = SCARG(uap, gid);
168364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
168437741Smckusick 	}
168537741Smckusick 	VOP_UNLOCK(vp);
168647540Skarels 	return (error);
16877701Ssam }
16887701Ssam 
168942441Smckusick /*
169042441Smckusick  * Set the access and modification times of a file.
169142441Smckusick  */
169242441Smckusick /* ARGSUSED */
169368318Scgd int
169442441Smckusick utimes(p, uap, retval)
169545914Smckusick 	struct proc *p;
169668318Scgd 	register struct utimes_args /* {
169768318Scgd 		syscallarg(char *) path;
169868318Scgd 		syscallarg(struct timeval *) tptr;
169968318Scgd 	} */ *uap;
170068318Scgd 	register_t *retval;
170142441Smckusick {
170237741Smckusick 	register struct vnode *vp;
170311811Ssam 	struct timeval tv[2];
170437741Smckusick 	struct vattr vattr;
170558840Storek 	int error;
170647540Skarels 	struct nameidata nd;
170711811Ssam 
170858505Sbostic 	VATTR_NULL(&vattr);
170968318Scgd 	if (SCARG(uap, tptr) == NULL) {
171058505Sbostic 		microtime(&tv[0]);
171158505Sbostic 		tv[1] = tv[0];
171258548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
171368318Scgd 	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
171468318Scgd 	    sizeof (tv)))
171558505Sbostic   		return (error);
171668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
171752322Smckusick 	if (error = namei(&nd))
171847540Skarels 		return (error);
171952322Smckusick 	vp = nd.ni_vp;
172067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
172159382Smckusick 	VOP_LOCK(vp);
172264410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
172337741Smckusick 		error = EROFS;
172464410Sbostic 	else {
172564410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
172664410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
172764410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
172864410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
172964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
173021015Smckusick 	}
173137741Smckusick 	vput(vp);
173247540Skarels 	return (error);
173311811Ssam }
173411811Ssam 
173564410Sbostic /*
173664410Sbostic  * Truncate a file given its path name.
173764410Sbostic  */
173853468Smckusick /* ARGSUSED */
173968318Scgd int
174060414Smckusick truncate(p, uap, retval)
174153468Smckusick 	struct proc *p;
174268318Scgd 	register struct truncate_args /* {
174368318Scgd 		syscallarg(char *) path;
174468318Scgd 		syscallarg(int) pad;
174568318Scgd 		syscallarg(off_t) length;
174668318Scgd 	} */ *uap;
174768318Scgd 	register_t *retval;
174853468Smckusick {
174937741Smckusick 	register struct vnode *vp;
175037741Smckusick 	struct vattr vattr;
175137741Smckusick 	int error;
175247540Skarels 	struct nameidata nd;
17537701Ssam 
175468318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
175552322Smckusick 	if (error = namei(&nd))
175647540Skarels 		return (error);
175752322Smckusick 	vp = nd.ni_vp;
175867654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
175959382Smckusick 	VOP_LOCK(vp);
176064410Sbostic 	if (vp->v_type == VDIR)
176137741Smckusick 		error = EISDIR;
176264410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
176364410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
176464410Sbostic 		VATTR_NULL(&vattr);
176568318Scgd 		vattr.va_size = SCARG(uap, length);
176664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17677701Ssam 	}
176837741Smckusick 	vput(vp);
176947540Skarels 	return (error);
17707701Ssam }
17717701Ssam 
177264410Sbostic /*
177364410Sbostic  * Truncate a file given a file descriptor.
177464410Sbostic  */
177542441Smckusick /* ARGSUSED */
177668318Scgd int
177760414Smckusick ftruncate(p, uap, retval)
177845914Smckusick 	struct proc *p;
177968318Scgd 	register struct ftruncate_args /* {
178068318Scgd 		syscallarg(int) fd;
178168318Scgd 		syscallarg(int) pad;
178268318Scgd 		syscallarg(off_t) length;
178368318Scgd 	} */ *uap;
178468318Scgd 	register_t *retval;
178542441Smckusick {
178637741Smckusick 	struct vattr vattr;
178737741Smckusick 	struct vnode *vp;
17887701Ssam 	struct file *fp;
178937741Smckusick 	int error;
17907701Ssam 
179168318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
179247540Skarels 		return (error);
179337741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
179447540Skarels 		return (EINVAL);
179537741Smckusick 	vp = (struct vnode *)fp->f_data;
179667654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
179737741Smckusick 	VOP_LOCK(vp);
179864410Sbostic 	if (vp->v_type == VDIR)
179937741Smckusick 		error = EISDIR;
180064410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
180164410Sbostic 		VATTR_NULL(&vattr);
180268318Scgd 		vattr.va_size = SCARG(uap, length);
180364410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
18047701Ssam 	}
180537741Smckusick 	VOP_UNLOCK(vp);
180647540Skarels 	return (error);
18077701Ssam }
18087701Ssam 
180954863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18109167Ssam /*
181154863Storek  * Truncate a file given its path name.
181254863Storek  */
181354863Storek /* ARGSUSED */
181468318Scgd int
181568318Scgd compat_43_truncate(p, uap, retval)
181654863Storek 	struct proc *p;
181768318Scgd 	register struct compat_43_truncate_args /* {
181868318Scgd 		syscallarg(char *) path;
181968318Scgd 		syscallarg(long) length;
182068318Scgd 	} */ *uap;
182168318Scgd 	register_t *retval;
182254863Storek {
182368318Scgd 	struct truncate_args /* {
182468318Scgd 		syscallarg(char *) path;
182568318Scgd 		syscallarg(int) pad;
182668318Scgd 		syscallarg(off_t) length;
182768318Scgd 	} */ nuap;
182854863Storek 
182968318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
183068318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
183160428Smckusick 	return (truncate(p, &nuap, retval));
183254863Storek }
183354863Storek 
183454863Storek /*
183554863Storek  * Truncate a file given a file descriptor.
183654863Storek  */
183754863Storek /* ARGSUSED */
183868318Scgd int
183968318Scgd compat_43_ftruncate(p, uap, retval)
184054863Storek 	struct proc *p;
184168318Scgd 	register struct compat_43_ftruncate_args /* {
184268318Scgd 		syscallarg(int) fd;
184368318Scgd 		syscallarg(long) length;
184468318Scgd 	} */ *uap;
184568318Scgd 	register_t *retval;
184654863Storek {
184768318Scgd 	struct ftruncate_args /* {
184868318Scgd 		syscallarg(int) fd;
184968318Scgd 		syscallarg(int) pad;
185068318Scgd 		syscallarg(off_t) length;
185168318Scgd 	} */ nuap;
185254863Storek 
185368318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
185468318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
185560428Smckusick 	return (ftruncate(p, &nuap, retval));
185654863Storek }
185754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
185854863Storek 
185954863Storek /*
186064410Sbostic  * Sync an open file.
18619167Ssam  */
186242441Smckusick /* ARGSUSED */
186368318Scgd int
186442441Smckusick fsync(p, uap, retval)
186545914Smckusick 	struct proc *p;
186668318Scgd 	struct fsync_args /* {
186768318Scgd 		syscallarg(int) fd;
186868318Scgd 	} */ *uap;
186968318Scgd 	register_t *retval;
18709167Ssam {
187139592Smckusick 	register struct vnode *vp;
18729167Ssam 	struct file *fp;
187337741Smckusick 	int error;
18749167Ssam 
187568318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
187647540Skarels 		return (error);
187739592Smckusick 	vp = (struct vnode *)fp->f_data;
187839592Smckusick 	VOP_LOCK(vp);
187954441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
188039592Smckusick 	VOP_UNLOCK(vp);
188147540Skarels 	return (error);
18829167Ssam }
18839167Ssam 
18849167Ssam /*
188564410Sbostic  * Rename files.  Source and destination must either both be directories,
188664410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
18879167Ssam  */
188842441Smckusick /* ARGSUSED */
188968318Scgd int
189042441Smckusick rename(p, uap, retval)
189145914Smckusick 	struct proc *p;
189268318Scgd 	register struct rename_args /* {
189368318Scgd 		syscallarg(char *) from;
189468318Scgd 		syscallarg(char *) to;
189568318Scgd 	} */ *uap;
189668318Scgd 	register_t *retval;
189742441Smckusick {
189837741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
189949735Smckusick 	struct nameidata fromnd, tond;
190037741Smckusick 	int error;
19017701Ssam 
190252322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
190368318Scgd 	    SCARG(uap, from), p);
190452322Smckusick 	if (error = namei(&fromnd))
190547540Skarels 		return (error);
190649735Smckusick 	fvp = fromnd.ni_vp;
190752322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
190868318Scgd 	    UIO_USERSPACE, SCARG(uap, to), p);
190952322Smckusick 	if (error = namei(&tond)) {
191052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
191149735Smckusick 		vrele(fromnd.ni_dvp);
191242465Smckusick 		vrele(fvp);
191342465Smckusick 		goto out1;
191442465Smckusick 	}
191537741Smckusick 	tdvp = tond.ni_dvp;
191637741Smckusick 	tvp = tond.ni_vp;
191737741Smckusick 	if (tvp != NULL) {
191837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
191939242Sbostic 			error = ENOTDIR;
192037741Smckusick 			goto out;
192137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
192239242Sbostic 			error = EISDIR;
192337741Smckusick 			goto out;
19249167Ssam 		}
19259167Ssam 	}
192639286Smckusick 	if (fvp == tdvp)
192737741Smckusick 		error = EINVAL;
192839286Smckusick 	/*
192949735Smckusick 	 * If source is the same as the destination (that is the
193049735Smckusick 	 * same inode number with the same name in the same directory),
193139286Smckusick 	 * then there is nothing to do.
193239286Smckusick 	 */
193349735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
193452322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
193552322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
193652322Smckusick 	      fromnd.ni_cnd.cn_namelen))
193739286Smckusick 		error = -1;
193837741Smckusick out:
193942465Smckusick 	if (!error) {
194067654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
194152192Smckusick 		if (fromnd.ni_dvp != tdvp)
194267654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
194352192Smckusick 		if (tvp)
194467654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
194552230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
194652230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
194742465Smckusick 	} else {
194852230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
194943344Smckusick 		if (tdvp == tvp)
195043344Smckusick 			vrele(tdvp);
195143344Smckusick 		else
195243344Smckusick 			vput(tdvp);
195342465Smckusick 		if (tvp)
195442465Smckusick 			vput(tvp);
195552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
195649735Smckusick 		vrele(fromnd.ni_dvp);
195742465Smckusick 		vrele(fvp);
19589167Ssam 	}
195949735Smckusick 	vrele(tond.ni_startdir);
196052322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
196137741Smckusick out1:
196266801Smckusick 	if (fromnd.ni_startdir)
196366801Smckusick 		vrele(fromnd.ni_startdir);
196452322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
196539286Smckusick 	if (error == -1)
196647540Skarels 		return (0);
196747540Skarels 	return (error);
19687701Ssam }
19697701Ssam 
19707535Sroot /*
197164410Sbostic  * Make a directory file.
197212756Ssam  */
197342441Smckusick /* ARGSUSED */
197468318Scgd int
197542441Smckusick mkdir(p, uap, retval)
197645914Smckusick 	struct proc *p;
197768318Scgd 	register struct mkdir_args /* {
197868318Scgd 		syscallarg(char *) path;
197968318Scgd 		syscallarg(int) mode;
198068318Scgd 	} */ *uap;
198168318Scgd 	register_t *retval;
198242441Smckusick {
198337741Smckusick 	register struct vnode *vp;
198437741Smckusick 	struct vattr vattr;
198537741Smckusick 	int error;
198647540Skarels 	struct nameidata nd;
198712756Ssam 
198868318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
198952322Smckusick 	if (error = namei(&nd))
199047540Skarels 		return (error);
199152322Smckusick 	vp = nd.ni_vp;
199237741Smckusick 	if (vp != NULL) {
199352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
199452322Smckusick 		if (nd.ni_dvp == vp)
199552322Smckusick 			vrele(nd.ni_dvp);
199643344Smckusick 		else
199752322Smckusick 			vput(nd.ni_dvp);
199842465Smckusick 		vrele(vp);
199947540Skarels 		return (EEXIST);
200012756Ssam 	}
200141362Smckusick 	VATTR_NULL(&vattr);
200237741Smckusick 	vattr.va_type = VDIR;
200368318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
200467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
200552322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
200638145Smckusick 	if (!error)
200752322Smckusick 		vput(nd.ni_vp);
200847540Skarels 	return (error);
200912756Ssam }
201012756Ssam 
201112756Ssam /*
201264410Sbostic  * Remove a directory file.
201312756Ssam  */
201442441Smckusick /* ARGSUSED */
201568318Scgd int
201642441Smckusick rmdir(p, uap, retval)
201745914Smckusick 	struct proc *p;
201868318Scgd 	struct rmdir_args /* {
201968318Scgd 		syscallarg(char *) path;
202068318Scgd 	} */ *uap;
202168318Scgd 	register_t *retval;
202212756Ssam {
202337741Smckusick 	register struct vnode *vp;
202437741Smckusick 	int error;
202547540Skarels 	struct nameidata nd;
202612756Ssam 
202768318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
202868318Scgd 	    SCARG(uap, path), p);
202952322Smckusick 	if (error = namei(&nd))
203047540Skarels 		return (error);
203152322Smckusick 	vp = nd.ni_vp;
203237741Smckusick 	if (vp->v_type != VDIR) {
203337741Smckusick 		error = ENOTDIR;
203412756Ssam 		goto out;
203512756Ssam 	}
203612756Ssam 	/*
203737741Smckusick 	 * No rmdir "." please.
203812756Ssam 	 */
203952322Smckusick 	if (nd.ni_dvp == vp) {
204037741Smckusick 		error = EINVAL;
204112756Ssam 		goto out;
204212756Ssam 	}
204312756Ssam 	/*
204449365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
204512756Ssam 	 */
204637741Smckusick 	if (vp->v_flag & VROOT)
204737741Smckusick 		error = EBUSY;
204812756Ssam out:
204942465Smckusick 	if (!error) {
205067654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
205167654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
205252322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
205342465Smckusick 	} else {
205452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
205552322Smckusick 		if (nd.ni_dvp == vp)
205652322Smckusick 			vrele(nd.ni_dvp);
205743344Smckusick 		else
205852322Smckusick 			vput(nd.ni_dvp);
205942465Smckusick 		vput(vp);
206042465Smckusick 	}
206147540Skarels 	return (error);
206212756Ssam }
206312756Ssam 
206454620Smckusick #ifdef COMPAT_43
206537741Smckusick /*
206649365Smckusick  * Read a block of directory entries in a file system independent format.
206737741Smckusick  */
206868318Scgd int
206968318Scgd compat_43_getdirentries(p, uap, retval)
207054620Smckusick 	struct proc *p;
207168318Scgd 	register struct compat_43_getdirentries_args /* {
207268318Scgd 		syscallarg(int) fd;
207368318Scgd 		syscallarg(char *) buf;
207468318Scgd 		syscallarg(u_int) count;
207568318Scgd 		syscallarg(long *) basep;
207668318Scgd 	} */ *uap;
207768318Scgd 	register_t *retval;
207854620Smckusick {
207954620Smckusick 	register struct vnode *vp;
208054620Smckusick 	struct file *fp;
208154620Smckusick 	struct uio auio, kuio;
208254620Smckusick 	struct iovec aiov, kiov;
208354620Smckusick 	struct dirent *dp, *edp;
208454620Smckusick 	caddr_t dirbuf;
208567362Smckusick 	int error, eofflag, readcnt;
208654969Smckusick 	long loff;
208754620Smckusick 
208868318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
208954620Smckusick 		return (error);
209054620Smckusick 	if ((fp->f_flag & FREAD) == 0)
209154620Smckusick 		return (EBADF);
209254620Smckusick 	vp = (struct vnode *)fp->f_data;
209367362Smckusick unionread:
209454620Smckusick 	if (vp->v_type != VDIR)
209554620Smckusick 		return (EINVAL);
209668318Scgd 	aiov.iov_base = SCARG(uap, buf);
209768318Scgd 	aiov.iov_len = SCARG(uap, count);
209854620Smckusick 	auio.uio_iov = &aiov;
209954620Smckusick 	auio.uio_iovcnt = 1;
210054620Smckusick 	auio.uio_rw = UIO_READ;
210154620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
210254620Smckusick 	auio.uio_procp = p;
210368318Scgd 	auio.uio_resid = SCARG(uap, count);
210454620Smckusick 	VOP_LOCK(vp);
210554969Smckusick 	loff = auio.uio_offset = fp->f_offset;
210654620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
210756339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
210867362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2109*68663Smckusick 			    (int *)0, (u_long *)0);
211056339Smckusick 			fp->f_offset = auio.uio_offset;
211156339Smckusick 		} else
211254620Smckusick #	endif
211354620Smckusick 	{
211454620Smckusick 		kuio = auio;
211554620Smckusick 		kuio.uio_iov = &kiov;
211654620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
211768318Scgd 		kiov.iov_len = SCARG(uap, count);
211868318Scgd 		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
211954620Smckusick 		kiov.iov_base = dirbuf;
212067362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2121*68663Smckusick 			    (int *)0, (u_long *)0);
212256339Smckusick 		fp->f_offset = kuio.uio_offset;
212354620Smckusick 		if (error == 0) {
212468318Scgd 			readcnt = SCARG(uap, count) - kuio.uio_resid;
212554620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
212654620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
212754620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
212854969Smckusick 					/*
212955009Smckusick 					 * The expected low byte of
213055009Smckusick 					 * dp->d_namlen is our dp->d_type.
213155009Smckusick 					 * The high MBZ byte of dp->d_namlen
213255009Smckusick 					 * is our dp->d_namlen.
213354969Smckusick 					 */
213455009Smckusick 					dp->d_type = dp->d_namlen;
213555009Smckusick 					dp->d_namlen = 0;
213655009Smckusick #				else
213755009Smckusick 					/*
213855009Smckusick 					 * The dp->d_type is the high byte
213955009Smckusick 					 * of the expected dp->d_namlen,
214055009Smckusick 					 * so must be zero'ed.
214155009Smckusick 					 */
214255009Smckusick 					dp->d_type = 0;
214354620Smckusick #				endif
214454620Smckusick 				if (dp->d_reclen > 0) {
214554620Smckusick 					dp = (struct dirent *)
214654620Smckusick 					    ((char *)dp + dp->d_reclen);
214754620Smckusick 				} else {
214854620Smckusick 					error = EIO;
214954620Smckusick 					break;
215054620Smckusick 				}
215154620Smckusick 			}
215254620Smckusick 			if (dp >= edp)
215354620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
215454620Smckusick 		}
215554620Smckusick 		FREE(dirbuf, M_TEMP);
215654620Smckusick 	}
215754620Smckusick 	VOP_UNLOCK(vp);
215854620Smckusick 	if (error)
215954620Smckusick 		return (error);
216067362Smckusick 
216167362Smckusick #ifdef UNION
216267362Smckusick {
216367362Smckusick 	extern int (**union_vnodeop_p)();
216468079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
216567362Smckusick 
216668318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
216767362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
216867362Smckusick 		struct vnode *lvp;
216967362Smckusick 
217068079Spendry 		lvp = union_dircache(vp);
217167362Smckusick 		if (lvp != NULLVP) {
217267575Spendry 			struct vattr va;
217367575Spendry 
217467575Spendry 			/*
217567575Spendry 			 * If the directory is opaque,
217667575Spendry 			 * then don't show lower entries
217767575Spendry 			 */
217867575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
217967575Spendry 			if (va.va_flags & OPAQUE) {
218068079Spendry 				vput(lvp);
218167575Spendry 				lvp = NULL;
218267575Spendry 			}
218367575Spendry 		}
218467575Spendry 
218567575Spendry 		if (lvp != NULLVP) {
218667362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
218767362Smckusick 			VOP_UNLOCK(lvp);
218867362Smckusick 
218967362Smckusick 			if (error) {
219067362Smckusick 				vrele(lvp);
219167362Smckusick 				return (error);
219267362Smckusick 			}
219367362Smckusick 			fp->f_data = (caddr_t) lvp;
219467362Smckusick 			fp->f_offset = 0;
219567362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
219667362Smckusick 			if (error)
219767362Smckusick 				return (error);
219867362Smckusick 			vp = lvp;
219967362Smckusick 			goto unionread;
220067362Smckusick 		}
220167362Smckusick 	}
220267362Smckusick }
220367362Smckusick #endif /* UNION */
220467362Smckusick 
220568318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
220667362Smckusick 	    (vp->v_flag & VROOT) &&
220767362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
220867362Smckusick 		struct vnode *tvp = vp;
220967362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
221067362Smckusick 		VREF(vp);
221167362Smckusick 		fp->f_data = (caddr_t) vp;
221267362Smckusick 		fp->f_offset = 0;
221367362Smckusick 		vrele(tvp);
221467362Smckusick 		goto unionread;
221567362Smckusick 	}
221668318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
221768318Scgd 	    sizeof(long));
221868318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
221954620Smckusick 	return (error);
222054620Smckusick }
222167362Smckusick #endif /* COMPAT_43 */
222254620Smckusick 
222354620Smckusick /*
222454620Smckusick  * Read a block of directory entries in a file system independent format.
222554620Smckusick  */
222668318Scgd int
222742441Smckusick getdirentries(p, uap, retval)
222845914Smckusick 	struct proc *p;
222968318Scgd 	register struct getdirentries_args /* {
223068318Scgd 		syscallarg(int) fd;
223168318Scgd 		syscallarg(char *) buf;
223268318Scgd 		syscallarg(u_int) count;
223368318Scgd 		syscallarg(long *) basep;
223468318Scgd 	} */ *uap;
223568318Scgd 	register_t *retval;
223642441Smckusick {
223739592Smckusick 	register struct vnode *vp;
223816540Ssam 	struct file *fp;
223937741Smckusick 	struct uio auio;
224037741Smckusick 	struct iovec aiov;
224154969Smckusick 	long loff;
224267362Smckusick 	int error, eofflag;
224312756Ssam 
224468318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
224547540Skarels 		return (error);
224637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
224747540Skarels 		return (EBADF);
224839592Smckusick 	vp = (struct vnode *)fp->f_data;
224955451Spendry unionread:
225039592Smckusick 	if (vp->v_type != VDIR)
225147540Skarels 		return (EINVAL);
225268318Scgd 	aiov.iov_base = SCARG(uap, buf);
225368318Scgd 	aiov.iov_len = SCARG(uap, count);
225437741Smckusick 	auio.uio_iov = &aiov;
225537741Smckusick 	auio.uio_iovcnt = 1;
225637741Smckusick 	auio.uio_rw = UIO_READ;
225737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
225848026Smckusick 	auio.uio_procp = p;
225968318Scgd 	auio.uio_resid = SCARG(uap, count);
226039592Smckusick 	VOP_LOCK(vp);
226154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
2262*68663Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2263*68663Smckusick 			    (int *)0, (u_long *)0);
226439592Smckusick 	fp->f_offset = auio.uio_offset;
226539592Smckusick 	VOP_UNLOCK(vp);
226639592Smckusick 	if (error)
226747540Skarels 		return (error);
226866095Spendry 
226966095Spendry #ifdef UNION
227066095Spendry {
227166095Spendry 	extern int (**union_vnodeop_p)();
227268079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
227366095Spendry 
227468318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
227566095Spendry 	    (vp->v_op == union_vnodeop_p)) {
227667122Spendry 		struct vnode *lvp;
227766095Spendry 
227868079Spendry 		lvp = union_dircache(vp);
227967122Spendry 		if (lvp != NULLVP) {
228067575Spendry 			struct vattr va;
228167575Spendry 
228267575Spendry 			/*
228367575Spendry 			 * If the directory is opaque,
228467575Spendry 			 * then don't show lower entries
228567575Spendry 			 */
228667575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
228767575Spendry 			if (va.va_flags & OPAQUE) {
228868079Spendry 				vput(lvp);
228967575Spendry 				lvp = NULL;
229067575Spendry 			}
229167575Spendry 		}
229267575Spendry 
229367575Spendry 		if (lvp != NULLVP) {
229467362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
229567122Spendry 			VOP_UNLOCK(lvp);
229666095Spendry 
229766095Spendry 			if (error) {
229867122Spendry 				vrele(lvp);
229966095Spendry 				return (error);
230066095Spendry 			}
230167122Spendry 			fp->f_data = (caddr_t) lvp;
230266095Spendry 			fp->f_offset = 0;
230367122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
230466095Spendry 			if (error)
230566095Spendry 				return (error);
230667122Spendry 			vp = lvp;
230766095Spendry 			goto unionread;
230866095Spendry 		}
230966095Spendry 	}
231066095Spendry }
231168318Scgd #endif /* UNION */
231266095Spendry 
231368318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
231455451Spendry 	    (vp->v_flag & VROOT) &&
231555451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
231655451Spendry 		struct vnode *tvp = vp;
231755451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
231855451Spendry 		VREF(vp);
231955451Spendry 		fp->f_data = (caddr_t) vp;
232055451Spendry 		fp->f_offset = 0;
232155451Spendry 		vrele(tvp);
232255451Spendry 		goto unionread;
232355451Spendry 	}
232468318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
232568318Scgd 	    sizeof(long));
232668318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
232747540Skarels 	return (error);
232812756Ssam }
232912756Ssam 
233012756Ssam /*
233149365Smckusick  * Set the mode mask for creation of filesystem nodes.
233212756Ssam  */
233368318Scgd int
233442441Smckusick umask(p, uap, retval)
233545914Smckusick 	struct proc *p;
233668318Scgd 	struct umask_args /* {
233768318Scgd 		syscallarg(int) newmask;
233868318Scgd 	} */ *uap;
233968318Scgd 	register_t *retval;
234012756Ssam {
234164410Sbostic 	register struct filedesc *fdp;
234212756Ssam 
234364410Sbostic 	fdp = p->p_fd;
234445914Smckusick 	*retval = fdp->fd_cmask;
234568318Scgd 	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
234647540Skarels 	return (0);
234712756Ssam }
234837741Smckusick 
234939566Smarc /*
235039566Smarc  * Void all references to file by ripping underlying filesystem
235139566Smarc  * away from vnode.
235239566Smarc  */
235342441Smckusick /* ARGSUSED */
235468318Scgd int
235542441Smckusick revoke(p, uap, retval)
235645914Smckusick 	struct proc *p;
235768318Scgd 	register struct revoke_args /* {
235868318Scgd 		syscallarg(char *) path;
235968318Scgd 	} */ *uap;
236068318Scgd 	register_t *retval;
236142441Smckusick {
236239566Smarc 	register struct vnode *vp;
236339566Smarc 	struct vattr vattr;
236439566Smarc 	int error;
236547540Skarels 	struct nameidata nd;
236639566Smarc 
236768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
236852322Smckusick 	if (error = namei(&nd))
236947540Skarels 		return (error);
237052322Smckusick 	vp = nd.ni_vp;
237148026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
237239566Smarc 		goto out;
237347540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
237447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
237539566Smarc 		goto out;
237639805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
237768423Smckusick 		VOP_REVOKE(vp, REVOKEALL);
237839566Smarc out:
237939566Smarc 	vrele(vp);
238047540Skarels 	return (error);
238139566Smarc }
238239566Smarc 
238349365Smckusick /*
238449365Smckusick  * Convert a user file descriptor to a kernel file entry.
238549365Smckusick  */
238668318Scgd int
238764410Sbostic getvnode(fdp, fd, fpp)
238845914Smckusick 	struct filedesc *fdp;
238937741Smckusick 	struct file **fpp;
239064410Sbostic 	int fd;
239137741Smckusick {
239237741Smckusick 	struct file *fp;
239337741Smckusick 
239464410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
239564410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
239637741Smckusick 		return (EBADF);
239737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
239837741Smckusick 		return (EINVAL);
239937741Smckusick 	*fpp = fp;
240037741Smckusick 	return (0);
240137741Smckusick }
2402