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