xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 37741)
123405Smckusick /*
2*37741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
3*37741Smckusick  * All rights reserved.
423405Smckusick  *
5*37741Smckusick  * Redistribution and use in source and binary forms are permitted
6*37741Smckusick  * provided that the above copyright notice and this paragraph are
7*37741Smckusick  * duplicated in all such forms and that any documentation,
8*37741Smckusick  * advertising materials, and other materials related to such
9*37741Smckusick  * distribution and use acknowledge that the software was developed
10*37741Smckusick  * by the University of California, Berkeley.  The name of the
11*37741Smckusick  * University may not be used to endorse or promote products derived
12*37741Smckusick  * from this software without specific prior written permission.
13*37741Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37741Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37741Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37741Smckusick  *
17*37741Smckusick  *	@(#)vfs_syscalls.c	7.7 (Berkeley) 05/09/89
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
22*37741Smckusick #include "syscontext.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
26*37741Smckusick #include "vnode.h"
27*37741Smckusick #include "../ufs/inode.h"
28*37741Smckusick #include "mount.h"
2917101Sbloom #include "proc.h"
3017101Sbloom #include "uio.h"
31*37741Smckusick #include "malloc.h"
3237Sbill 
33*37741Smckusick /*
34*37741Smckusick  * Virtual File System System Calls
35*37741Smckusick  */
3612756Ssam 
379167Ssam /*
38*37741Smckusick  * mount system call
399167Ssam  */
40*37741Smckusick mount()
416254Sroot {
42*37741Smckusick 	register struct a {
43*37741Smckusick 		int	type;
44*37741Smckusick 		char	*dir;
45*37741Smckusick 		int	flags;
46*37741Smckusick 		caddr_t	data;
47*37741Smckusick 	} *uap = (struct a *)u.u_ap;
48*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
49*37741Smckusick 	struct vnode *vp;
50*37741Smckusick 	struct mount *mp;
51*37741Smckusick 	int error;
526254Sroot 
53*37741Smckusick 	/*
54*37741Smckusick 	 * Must be super user
55*37741Smckusick 	 */
56*37741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
57*37741Smckusick 		RETURN (error);
58*37741Smckusick 	/*
59*37741Smckusick 	 * Get vnode to be covered
60*37741Smckusick 	 */
61*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
62*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
63*37741Smckusick 	ndp->ni_dirp = uap->dir;
64*37741Smckusick 	if (error = namei(ndp))
65*37741Smckusick 		RETURN (error);
66*37741Smckusick 	vp = ndp->ni_vp;
67*37741Smckusick 	if (vp->v_count != 1) {
68*37741Smckusick 		vput(vp);
69*37741Smckusick 		RETURN (EBUSY);
70*37741Smckusick 	}
71*37741Smckusick 	if (vp->v_type != VDIR) {
72*37741Smckusick 		vput(vp);
73*37741Smckusick 		RETURN (ENOTDIR);
74*37741Smckusick 	}
75*37741Smckusick 	if (uap->type > MOUNT_MAXTYPE ||
76*37741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
77*37741Smckusick 		vput(vp);
78*37741Smckusick 		RETURN (ENODEV);
79*37741Smckusick 	}
80*37741Smckusick 
81*37741Smckusick 	/*
82*37741Smckusick 	 * Mount the filesystem.
83*37741Smckusick 	 */
84*37741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
85*37741Smckusick 		M_MOUNT, M_WAITOK);
86*37741Smckusick 	mp->m_op = vfssw[uap->type];
87*37741Smckusick 	mp->m_flag = 0;
88*37741Smckusick 	mp->m_exroot = 0;
89*37741Smckusick 	error = vfs_add(vp, mp, uap->flags);
90*37741Smckusick 	if (!error)
91*37741Smckusick 		error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
92*37741Smckusick 	cache_purge(vp);
93*37741Smckusick 	VOP_UNLOCK(vp);
94*37741Smckusick 	if (!error) {
95*37741Smckusick 		vfs_unlock(mp);
96*37741Smckusick 	} else {
97*37741Smckusick 		vfs_remove(mp);
98*37741Smckusick 		free((caddr_t)mp, M_MOUNT);
99*37741Smckusick 		vrele(vp);
100*37741Smckusick 	}
101*37741Smckusick 	RETURN (error);
1026254Sroot }
1036254Sroot 
1049167Ssam /*
105*37741Smckusick  * Unmount system call.
106*37741Smckusick  *
107*37741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
108*37741Smckusick  * not special file (as before).
1099167Ssam  */
110*37741Smckusick unmount()
1116254Sroot {
112*37741Smckusick 	struct a {
113*37741Smckusick 		char	*pathp;
114*37741Smckusick 		int	flags;
115*37741Smckusick 	} *uap = (struct a *)u.u_ap;
116*37741Smckusick 	register struct vnode *vp;
117*37741Smckusick 	register struct mount *mp;
118*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
119*37741Smckusick 	struct vnode *coveredvp;
120*37741Smckusick 	int error;
1216254Sroot 
122*37741Smckusick 	/*
123*37741Smckusick 	 * Must be super user
124*37741Smckusick 	 */
125*37741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
126*37741Smckusick 		RETURN (error);
127*37741Smckusick 
128*37741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
129*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130*37741Smckusick 	ndp->ni_dirp = uap->pathp;
131*37741Smckusick 	if (error = namei(ndp))
132*37741Smckusick 		RETURN (error);
133*37741Smckusick 	vp = ndp->ni_vp;
134*37741Smckusick 	/*
135*37741Smckusick 	 * Must be the root of the filesystem
136*37741Smckusick 	 */
137*37741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
138*37741Smckusick 		vput(vp);
139*37741Smckusick 		RETURN (EINVAL);
140*37741Smckusick 	}
141*37741Smckusick 	mp = vp->v_mount;
142*37741Smckusick 	vput(vp);
143*37741Smckusick 	/*
144*37741Smckusick 	 * Do the unmount.
145*37741Smckusick 	 */
146*37741Smckusick 	coveredvp = mp->m_vnodecovered;
147*37741Smckusick 	if (error = vfs_lock(mp))
148*37741Smckusick 		RETURN (error);
149*37741Smckusick 
150*37741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
151*37741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
152*37741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
153*37741Smckusick 
154*37741Smckusick 	error = VFS_UNMOUNT(mp, uap->flags);
155*37741Smckusick 	if (error) {
156*37741Smckusick 		vfs_unlock(mp);
157*37741Smckusick 	} else {
158*37741Smckusick 		vrele(coveredvp);
159*37741Smckusick 		vfs_remove(mp);
160*37741Smckusick 		free((caddr_t)mp, M_MOUNT);
161*37741Smckusick 	}
162*37741Smckusick 	RETURN (error);
1636254Sroot }
1646254Sroot 
1659167Ssam /*
166*37741Smckusick  * Sync system call.
167*37741Smckusick  * Sync each mounted filesystem.
1689167Ssam  */
169*37741Smckusick sync()
1706254Sroot {
171*37741Smckusick 	register struct mount *mp;
172*37741Smckusick 
173*37741Smckusick 	mp = rootfs;
174*37741Smckusick 	do {
175*37741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
176*37741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
177*37741Smckusick 		mp = mp->m_next;
178*37741Smckusick 	} while (mp != rootfs);
179*37741Smckusick }
180*37741Smckusick 
181*37741Smckusick /*
182*37741Smckusick  * get filesystem statistics
183*37741Smckusick  */
184*37741Smckusick statfs()
185*37741Smckusick {
1866254Sroot 	struct a {
187*37741Smckusick 		char *path;
188*37741Smckusick 		struct statfs *buf;
189*37741Smckusick 	} *uap = (struct a *)u.u_ap;
190*37741Smckusick 	register struct vnode *vp;
191*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
192*37741Smckusick 	struct statfs sb;
193*37741Smckusick 	int error;
194*37741Smckusick 
195*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
196*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
197*37741Smckusick 	ndp->ni_dirp = uap->path;
198*37741Smckusick 	if (error = namei(ndp))
199*37741Smckusick 		RETURN (error);
200*37741Smckusick 	vp = ndp->ni_vp;
201*37741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
202*37741Smckusick 		goto out;
203*37741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
204*37741Smckusick out:
205*37741Smckusick 	vput(vp);
206*37741Smckusick 	RETURN (error);
207*37741Smckusick }
208*37741Smckusick 
209*37741Smckusick fstatfs()
210*37741Smckusick {
211*37741Smckusick 	struct a {
212*37741Smckusick 		int fd;
213*37741Smckusick 		struct statfs *buf;
214*37741Smckusick 	} *uap = (struct a *)u.u_ap;
215*37741Smckusick 	struct file *fp;
216*37741Smckusick 	struct statfs sb;
217*37741Smckusick 	int error;
218*37741Smckusick 
219*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
220*37741Smckusick 		RETURN (error);
221*37741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
222*37741Smckusick 		RETURN (error);
223*37741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
224*37741Smckusick }
225*37741Smckusick 
226*37741Smckusick /*
227*37741Smckusick  * Change current working directory (``.'').
228*37741Smckusick  */
229*37741Smckusick chdir()
230*37741Smckusick {
231*37741Smckusick 	struct a {
2326254Sroot 		char	*fname;
23316694Smckusick 	} *uap = (struct a *)u.u_ap;
23416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
235*37741Smckusick 	int error;
2366254Sroot 
237*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
23816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
23916694Smckusick 	ndp->ni_dirp = uap->fname;
240*37741Smckusick 	if (error = chdirec(ndp))
241*37741Smckusick 		RETURN (error);
242*37741Smckusick 	vrele(u.u_cdir);
243*37741Smckusick 	u.u_cdir = ndp->ni_vp;
244*37741Smckusick 	RETURN (0);
245*37741Smckusick }
2466254Sroot 
247*37741Smckusick /*
248*37741Smckusick  * Change notion of root (``/'') directory.
249*37741Smckusick  */
250*37741Smckusick chroot()
251*37741Smckusick {
252*37741Smckusick 	struct a {
253*37741Smckusick 		char	*fname;
254*37741Smckusick 	} *uap = (struct a *)u.u_ap;
255*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
256*37741Smckusick 	int error;
257*37741Smckusick 
258*37741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
259*37741Smckusick 		RETURN (error);
260*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
261*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
262*37741Smckusick 	ndp->ni_dirp = uap->fname;
263*37741Smckusick 	if (error = chdirec(ndp))
264*37741Smckusick 		RETURN (error);
265*37741Smckusick 	vrele(u.u_rdir);
266*37741Smckusick 	u.u_rdir = ndp->ni_vp;
267*37741Smckusick 	RETURN (0);
2686254Sroot }
2696254Sroot 
27037Sbill /*
271*37741Smckusick  * Common routine for chroot and chdir.
272*37741Smckusick  */
273*37741Smckusick chdirec(ndp)
274*37741Smckusick 	register struct nameidata *ndp;
275*37741Smckusick {
276*37741Smckusick 	struct vnode *vp;
277*37741Smckusick 	int error;
278*37741Smckusick 
279*37741Smckusick 	if (error = namei(ndp))
280*37741Smckusick 		return (error);
281*37741Smckusick 	vp = ndp->ni_vp;
282*37741Smckusick 	if (vp->v_type != VDIR)
283*37741Smckusick 		error = ENOTDIR;
284*37741Smckusick 	else
285*37741Smckusick 		error = vn_access(vp, VEXEC, ndp->ni_cred);
286*37741Smckusick 	VOP_UNLOCK(vp);
287*37741Smckusick 	if (error)
288*37741Smckusick 		vrele(vp);
289*37741Smckusick 	return (error);
290*37741Smckusick }
291*37741Smckusick 
292*37741Smckusick /*
2936254Sroot  * Open system call.
2946254Sroot  */
2956254Sroot open()
2966254Sroot {
29712756Ssam 	struct a {
2986254Sroot 		char	*fname;
2997701Ssam 		int	mode;
30012756Ssam 		int	crtmode;
30112756Ssam 	} *uap = (struct a *) u.u_ap;
302*37741Smckusick 	struct nameidata *ndp = &u.u_nd;
3036254Sroot 
304*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
305*37741Smckusick 	ndp->ni_dirp = uap->fname;
306*37741Smckusick 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
307*37741Smckusick 		&u.u_r.r_val1));
3086254Sroot }
3096254Sroot 
3106254Sroot /*
3116254Sroot  * Creat system call.
3126254Sroot  */
31312756Ssam creat()
3146254Sroot {
31512756Ssam 	struct a {
3166254Sroot 		char	*fname;
3176254Sroot 		int	fmode;
31812756Ssam 	} *uap = (struct a *)u.u_ap;
319*37741Smckusick 	struct nameidata *ndp = &u.u_nd;
3206254Sroot 
321*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
322*37741Smckusick 	ndp->ni_dirp = uap->fname;
323*37741Smckusick 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
324*37741Smckusick 		&u.u_r.r_val1));
3256254Sroot }
3266254Sroot 
3276254Sroot /*
3286254Sroot  * Common code for open and creat.
32912756Ssam  * Check permissions, allocate an open file structure,
33012756Ssam  * and call the device open routine if any.
3316254Sroot  */
332*37741Smckusick copen(fmode, cmode, ndp, resultfd)
333*37741Smckusick 	int fmode, cmode;
334*37741Smckusick 	struct nameidata *ndp;
335*37741Smckusick 	int *resultfd;
33612756Ssam {
3376254Sroot 	register struct file *fp;
338*37741Smckusick 	struct file *nfp;
339*37741Smckusick 	int indx, error;
340*37741Smckusick 	extern struct fileops vnops;
3416254Sroot 
342*37741Smckusick 	if (error = falloc(&nfp, &indx))
343*37741Smckusick 		return (error);
344*37741Smckusick 	fp = nfp;
345*37741Smckusick 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
346*37741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
34724543Smckusick 		u.u_ofile[indx] = NULL;
348*37741Smckusick 		crfree(fp->f_cred);
349*37741Smckusick 		fp->f_count--;
350*37741Smckusick 		return (error);
35112756Ssam 	}
352*37741Smckusick 	fp->f_flag = fmode & FMASK;
353*37741Smckusick 	fp->f_type = DTYPE_VNODE;
354*37741Smckusick 	fp->f_ops = &vnops;
355*37741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
356*37741Smckusick 	if (resultfd)
357*37741Smckusick 		*resultfd = indx;
358*37741Smckusick 	return (0);
3596254Sroot }
3606254Sroot 
3616254Sroot /*
3626254Sroot  * Mknod system call
3636254Sroot  */
3646254Sroot mknod()
3656254Sroot {
3666254Sroot 	register struct a {
3676254Sroot 		char	*fname;
3686254Sroot 		int	fmode;
3696254Sroot 		int	dev;
37016694Smckusick 	} *uap = (struct a *)u.u_ap;
37116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
372*37741Smckusick 	register struct vnode *vp;
373*37741Smckusick 	struct vattr vattr;
374*37741Smckusick 	int error;
3756254Sroot 
376*37741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
377*37741Smckusick 		RETURN (error);
378*37741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
37916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
38016694Smckusick 	ndp->ni_dirp = uap->fname;
381*37741Smckusick 	if (error = namei(ndp))
382*37741Smckusick 		RETURN (error);
383*37741Smckusick 	vp = ndp->ni_vp;
384*37741Smckusick 	if (vp != NULL) {
385*37741Smckusick 		error = EEXIST;
38612756Ssam 		goto out;
3876254Sroot 	}
388*37741Smckusick 	vattr_null(&vattr);
389*37741Smckusick 	switch (uap->fmode & IFMT) {
39012756Ssam 
39115093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
392*37741Smckusick 		vattr.va_type = VBAD;
393*37741Smckusick 		break;
39412756Ssam 	case IFCHR:
395*37741Smckusick 		vattr.va_type = VCHR;
396*37741Smckusick 		break;
39712756Ssam 	case IFBLK:
398*37741Smckusick 		vattr.va_type = VBLK;
399*37741Smckusick 		break;
400*37741Smckusick 	default:
401*37741Smckusick 		error = EINVAL;
402*37741Smckusick 		goto out;
4036254Sroot 	}
404*37741Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
405*37741Smckusick 	vattr.va_rdev = uap->dev;
4066254Sroot out:
407*37741Smckusick 	if (error)
408*37741Smckusick 		VOP_ABORTOP(ndp);
409*37741Smckusick 	else
410*37741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
411*37741Smckusick 	RETURN (error);
4126254Sroot }
4136254Sroot 
4146254Sroot /*
4156254Sroot  * link system call
4166254Sroot  */
4176254Sroot link()
4186254Sroot {
4196254Sroot 	register struct a {
4206254Sroot 		char	*target;
4216254Sroot 		char	*linkname;
42216694Smckusick 	} *uap = (struct a *)u.u_ap;
42316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
424*37741Smckusick 	register struct vnode *vp, *xp;
425*37741Smckusick 	int error;
4266254Sroot 
42716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
42816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
42916694Smckusick 	ndp->ni_dirp = uap->target;
430*37741Smckusick 	if (error = namei(ndp))
431*37741Smckusick 		RETURN (error);
432*37741Smckusick 	vp = ndp->ni_vp;
433*37741Smckusick 	if (vp->v_type == VDIR &&
434*37741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
435*37741Smckusick 		goto out1;
436*37741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
43716694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
438*37741Smckusick 	if (error = namei(ndp))
439*37741Smckusick 		goto out1;
440*37741Smckusick 	xp = ndp->ni_vp;
4416254Sroot 	if (xp != NULL) {
442*37741Smckusick 		error = EEXIST;
4436254Sroot 		goto out;
4446254Sroot 	}
445*37741Smckusick 	xp = ndp->ni_dvp;
446*37741Smckusick 	if (vp->v_mount != xp->v_mount)
447*37741Smckusick 		error = EXDEV;
4486254Sroot out:
449*37741Smckusick 	if (error)
450*37741Smckusick 		VOP_ABORTOP(ndp);
451*37741Smckusick 	else
452*37741Smckusick 		error = VOP_LINK(vp, ndp);
453*37741Smckusick out1:
454*37741Smckusick 	vrele(vp);
455*37741Smckusick 	RETURN (error);
4566254Sroot }
4576254Sroot 
4586254Sroot /*
4596254Sroot  * symlink -- make a symbolic link
4606254Sroot  */
4616254Sroot symlink()
4626254Sroot {
463*37741Smckusick 	struct a {
4646254Sroot 		char	*target;
4656254Sroot 		char	*linkname;
46616694Smckusick 	} *uap = (struct a *)u.u_ap;
46716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
468*37741Smckusick 	register struct vnode *vp;
469*37741Smckusick 	struct vattr vattr;
470*37741Smckusick 	char *target;
471*37741Smckusick 	int error;
4726254Sroot 
47316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47416694Smckusick 	ndp->ni_dirp = uap->linkname;
475*37741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
476*37741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
477*37741Smckusick 		goto out1;
478*37741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
479*37741Smckusick 	if (error = namei(ndp))
480*37741Smckusick 		goto out1;
481*37741Smckusick 	vp = ndp->ni_vp;
482*37741Smckusick 	if (vp) {
483*37741Smckusick 		error = EEXIST;
484*37741Smckusick 		goto out;
4856254Sroot 	}
486*37741Smckusick 	vp = ndp->ni_dvp;
487*37741Smckusick 	vattr_null(&vattr);
488*37741Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
489*37741Smckusick out:
490*37741Smckusick 	if (error)
491*37741Smckusick 		VOP_ABORTOP(ndp);
492*37741Smckusick 	else
493*37741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
494*37741Smckusick out1:
495*37741Smckusick 	FREE(target, M_NAMEI);
496*37741Smckusick 	RETURN (error);
4976254Sroot }
4986254Sroot 
4996254Sroot /*
5006254Sroot  * Unlink system call.
5016254Sroot  * Hard to avoid races here, especially
5026254Sroot  * in unlinking directories.
5036254Sroot  */
5046254Sroot unlink()
5056254Sroot {
5066254Sroot 	struct a {
5076254Sroot 		char	*fname;
50816694Smckusick 	} *uap = (struct a *)u.u_ap;
50916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
510*37741Smckusick 	register struct vnode *vp;
511*37741Smckusick 	int error;
5126254Sroot 
513*37741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
51416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51516694Smckusick 	ndp->ni_dirp = uap->fname;
516*37741Smckusick 	if (error = namei(ndp))
517*37741Smckusick 		RETURN (error);
518*37741Smckusick 	vp = ndp->ni_vp;
519*37741Smckusick 	if (vp->v_type == VDIR &&
520*37741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
5216254Sroot 		goto out;
5226254Sroot 	/*
5236254Sroot 	 * Don't unlink a mounted file.
5246254Sroot 	 */
525*37741Smckusick 	if (vp->v_flag & VROOT) {
526*37741Smckusick 		error = EBUSY;
5276254Sroot 		goto out;
5286254Sroot 	}
529*37741Smckusick 	if (vp->v_flag & VTEXT)
530*37741Smckusick 		xrele(vp);	/* try once to free text */
5316254Sroot out:
532*37741Smckusick 	if (error)
533*37741Smckusick 		VOP_ABORTOP(ndp);
5347142Smckusick 	else
535*37741Smckusick 		error = VOP_REMOVE(ndp);
536*37741Smckusick 	RETURN (error);
5376254Sroot }
5386254Sroot 
5396254Sroot /*
5406254Sroot  * Seek system call
5416254Sroot  */
5428040Sroot lseek()
5436254Sroot {
5446254Sroot 	register struct file *fp;
5456254Sroot 	register struct a {
546*37741Smckusick 		int	fdes;
5476254Sroot 		off_t	off;
5486254Sroot 		int	sbase;
54916694Smckusick 	} *uap = (struct a *)u.u_ap;
550*37741Smckusick 	struct vattr vattr;
551*37741Smckusick 	int error;
5526254Sroot 
553*37741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
554*37741Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
555*37741Smckusick 		RETURN (EBADF);
556*37741Smckusick 	if (fp->f_type != DTYPE_VNODE)
557*37741Smckusick 		RETURN (ESPIPE);
55813878Ssam 	switch (uap->sbase) {
55913878Ssam 
56013878Ssam 	case L_INCR:
56113878Ssam 		fp->f_offset += uap->off;
56213878Ssam 		break;
56313878Ssam 
56413878Ssam 	case L_XTND:
565*37741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
566*37741Smckusick 		    &vattr, u.u_cred))
567*37741Smckusick 			RETURN (error);
568*37741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
56913878Ssam 		break;
57013878Ssam 
57113878Ssam 	case L_SET:
57213878Ssam 		fp->f_offset = uap->off;
57313878Ssam 		break;
57413878Ssam 
57513878Ssam 	default:
576*37741Smckusick 		RETURN (EINVAL);
57713878Ssam 	}
57813878Ssam 	u.u_r.r_off = fp->f_offset;
579*37741Smckusick 	RETURN (0);
5806254Sroot }
5816254Sroot 
5826254Sroot /*
5836254Sroot  * Access system call
5846254Sroot  */
5856254Sroot saccess()
5866254Sroot {
5876254Sroot 	register struct a {
5886254Sroot 		char	*fname;
5896254Sroot 		int	fmode;
59016694Smckusick 	} *uap = (struct a *)u.u_ap;
59116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
592*37741Smckusick 	register struct vnode *vp;
593*37741Smckusick 	int error, mode, svuid, svgid;
5946254Sroot 
5956254Sroot 	svuid = u.u_uid;
5966254Sroot 	svgid = u.u_gid;
5976254Sroot 	u.u_uid = u.u_ruid;
5986254Sroot 	u.u_gid = u.u_rgid;
599*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
60016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
60116694Smckusick 	ndp->ni_dirp = uap->fname;
602*37741Smckusick 	if (error = namei(ndp))
603*37741Smckusick 		goto out1;
604*37741Smckusick 	vp = ndp->ni_vp;
605*37741Smckusick 	/*
606*37741Smckusick 	 * fmode == 0 means only check for exist
607*37741Smckusick 	 */
608*37741Smckusick 	if (uap->fmode) {
609*37741Smckusick 		mode = 0;
610*37741Smckusick 		if (uap->fmode & R_OK)
611*37741Smckusick 			mode |= VREAD;
612*37741Smckusick 		if (uap->fmode & W_OK)
613*37741Smckusick 			mode |= VWRITE;
614*37741Smckusick 		if (uap->fmode & X_OK)
615*37741Smckusick 			mode |= VEXEC;
616*37741Smckusick 		error = vn_access(vp, mode, u.u_cred);
6176254Sroot 	}
618*37741Smckusick 	vput(vp);
619*37741Smckusick out1:
6206254Sroot 	u.u_uid = svuid;
6216254Sroot 	u.u_gid = svgid;
622*37741Smckusick 	RETURN (error);
6236254Sroot }
6246254Sroot 
6256254Sroot /*
6266574Smckusic  * Stat system call.  This version follows links.
62737Sbill  */
62837Sbill stat()
62937Sbill {
63037Sbill 
63116694Smckusick 	stat1(FOLLOW);
63237Sbill }
63337Sbill 
63437Sbill /*
6356574Smckusic  * Lstat system call.  This version does not follow links.
6365992Swnj  */
6375992Swnj lstat()
6385992Swnj {
63912756Ssam 
64016694Smckusick 	stat1(NOFOLLOW);
64112756Ssam }
64212756Ssam 
64312756Ssam stat1(follow)
64412756Ssam 	int follow;
64512756Ssam {
6465992Swnj 	register struct a {
6475992Swnj 		char	*fname;
64812756Ssam 		struct stat *ub;
64916694Smckusick 	} *uap = (struct a *)u.u_ap;
650*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
65112756Ssam 	struct stat sb;
652*37741Smckusick 	int error;
6535992Swnj 
654*37741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
65516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
65616694Smckusick 	ndp->ni_dirp = uap->fname;
657*37741Smckusick 	if (error = namei(ndp))
658*37741Smckusick 		RETURN (error);
659*37741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
660*37741Smckusick 	vput(ndp->ni_vp);
661*37741Smckusick 	if (error)
662*37741Smckusick 		RETURN (error);
663*37741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
664*37741Smckusick 	RETURN (error);
6655992Swnj }
6665992Swnj 
6675992Swnj /*
6685992Swnj  * Return target name of a symbolic link
66937Sbill  */
6705992Swnj readlink()
6715992Swnj {
6725992Swnj 	register struct a {
6735992Swnj 		char	*name;
6745992Swnj 		char	*buf;
6755992Swnj 		int	count;
6767826Sroot 	} *uap = (struct a *)u.u_ap;
67716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
678*37741Smckusick 	register struct vnode *vp;
679*37741Smckusick 	struct iovec aiov;
680*37741Smckusick 	struct uio auio;
681*37741Smckusick 	int error;
6825992Swnj 
683*37741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
68416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68516694Smckusick 	ndp->ni_dirp = uap->name;
686*37741Smckusick 	if (error = namei(ndp))
687*37741Smckusick 		RETURN (error);
688*37741Smckusick 	vp = ndp->ni_vp;
689*37741Smckusick 	if (vp->v_type != VLNK) {
690*37741Smckusick 		error = EINVAL;
6915992Swnj 		goto out;
6925992Swnj 	}
693*37741Smckusick 	aiov.iov_base = uap->buf;
694*37741Smckusick 	aiov.iov_len = uap->count;
695*37741Smckusick 	auio.uio_iov = &aiov;
696*37741Smckusick 	auio.uio_iovcnt = 1;
697*37741Smckusick 	auio.uio_offset = 0;
698*37741Smckusick 	auio.uio_rw = UIO_READ;
699*37741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
700*37741Smckusick 	auio.uio_resid = uap->count;
701*37741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7025992Swnj out:
703*37741Smckusick 	vput(vp);
704*37741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
705*37741Smckusick 	RETURN (error);
7065992Swnj }
7075992Swnj 
7089167Ssam /*
7099167Ssam  * Change mode of a file given path name.
7109167Ssam  */
7116254Sroot chmod()
7125992Swnj {
7137701Ssam 	struct a {
7146254Sroot 		char	*fname;
7156254Sroot 		int	fmode;
71616694Smckusick 	} *uap = (struct a *)u.u_ap;
717*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
718*37741Smckusick 	register struct vnode *vp;
719*37741Smckusick 	struct vattr vattr;
720*37741Smckusick 	int error;
7215992Swnj 
722*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
723*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
724*37741Smckusick 	ndp->ni_dirp = uap->fname;
725*37741Smckusick 	vattr_null(&vattr);
726*37741Smckusick 	vattr.va_mode = uap->fmode & 07777;
727*37741Smckusick 	if (error = namei(ndp))
728*37741Smckusick 		RETURN (error);
729*37741Smckusick 	vp = ndp->ni_vp;
730*37741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
731*37741Smckusick 		error = EROFS;
732*37741Smckusick 		goto out;
733*37741Smckusick 	}
734*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
735*37741Smckusick out:
736*37741Smckusick 	vput(vp);
737*37741Smckusick 	RETURN (error);
7387701Ssam }
7397439Sroot 
7409167Ssam /*
7419167Ssam  * Change mode of a file given a file descriptor.
7429167Ssam  */
7437701Ssam fchmod()
7447701Ssam {
7457701Ssam 	struct a {
7467701Ssam 		int	fd;
7477701Ssam 		int	fmode;
74816694Smckusick 	} *uap = (struct a *)u.u_ap;
749*37741Smckusick 	struct vattr vattr;
750*37741Smckusick 	struct vnode *vp;
751*37741Smckusick 	struct file *fp;
752*37741Smckusick 	int error;
7537701Ssam 
754*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
755*37741Smckusick 		RETURN (error);
756*37741Smckusick 	vattr_null(&vattr);
757*37741Smckusick 	vattr.va_mode = uap->fmode & 07777;
758*37741Smckusick 	vp = (struct vnode *)fp->f_data;
759*37741Smckusick 	VOP_LOCK(vp);
760*37741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
761*37741Smckusick 		error = EROFS;
762*37741Smckusick 		goto out;
7637439Sroot 	}
764*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
765*37741Smckusick out:
766*37741Smckusick 	VOP_UNLOCK(vp);
767*37741Smckusick 	RETURN (error);
7685992Swnj }
7695992Swnj 
7709167Ssam /*
7719167Ssam  * Set ownership given a path name.
7729167Ssam  */
7736254Sroot chown()
77437Sbill {
7757701Ssam 	struct a {
7766254Sroot 		char	*fname;
7776254Sroot 		int	uid;
7786254Sroot 		int	gid;
77916694Smckusick 	} *uap = (struct a *)u.u_ap;
78036614Sbostic 	register struct nameidata *ndp = &u.u_nd;
781*37741Smckusick 	register struct vnode *vp;
782*37741Smckusick 	struct vattr vattr;
783*37741Smckusick 	int error;
78437Sbill 
785*37741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
78636614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
78736614Sbostic 	ndp->ni_dirp = uap->fname;
788*37741Smckusick 	vattr_null(&vattr);
789*37741Smckusick 	vattr.va_uid = uap->uid;
790*37741Smckusick 	vattr.va_gid = uap->gid;
791*37741Smckusick 	if (error = namei(ndp))
792*37741Smckusick 		RETURN (error);
793*37741Smckusick 	vp = ndp->ni_vp;
794*37741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
795*37741Smckusick 		error = EROFS;
796*37741Smckusick 		goto out;
797*37741Smckusick 	}
798*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
799*37741Smckusick out:
800*37741Smckusick 	vput(vp);
801*37741Smckusick 	RETURN (error);
8027701Ssam }
8037439Sroot 
8049167Ssam /*
8059167Ssam  * Set ownership given a file descriptor.
8069167Ssam  */
8077701Ssam fchown()
8087701Ssam {
8097701Ssam 	struct a {
8107701Ssam 		int	fd;
8117701Ssam 		int	uid;
8127701Ssam 		int	gid;
81316694Smckusick 	} *uap = (struct a *)u.u_ap;
814*37741Smckusick 	struct vattr vattr;
815*37741Smckusick 	struct vnode *vp;
816*37741Smckusick 	struct file *fp;
817*37741Smckusick 	int error;
8187701Ssam 
819*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
820*37741Smckusick 		RETURN (error);
821*37741Smckusick 	vattr_null(&vattr);
822*37741Smckusick 	vattr.va_uid = uap->uid;
823*37741Smckusick 	vattr.va_gid = uap->gid;
824*37741Smckusick 	vp = (struct vnode *)fp->f_data;
825*37741Smckusick 	VOP_LOCK(vp);
826*37741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
827*37741Smckusick 		error = EROFS;
828*37741Smckusick 		goto out;
829*37741Smckusick 	}
830*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
831*37741Smckusick out:
832*37741Smckusick 	VOP_UNLOCK(vp);
833*37741Smckusick 	RETURN (error);
8347701Ssam }
8357701Ssam 
83611811Ssam utimes()
83711811Ssam {
83811811Ssam 	register struct a {
83911811Ssam 		char	*fname;
84011811Ssam 		struct	timeval *tptr;
84111811Ssam 	} *uap = (struct a *)u.u_ap;
842*37741Smckusick 	register struct nameidata *ndp = &u.u_nd;
843*37741Smckusick 	register struct vnode *vp;
84411811Ssam 	struct timeval tv[2];
845*37741Smckusick 	struct vattr vattr;
846*37741Smckusick 	int error;
84711811Ssam 
848*37741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
849*37741Smckusick 		RETURN (error);
850*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
851*37741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
852*37741Smckusick 	ndp->ni_dirp = uap->fname;
853*37741Smckusick 	vattr_null(&vattr);
854*37741Smckusick 	vattr.va_atime = tv[0];
855*37741Smckusick 	vattr.va_mtime = tv[1];
856*37741Smckusick 	if (error = namei(ndp))
857*37741Smckusick 		RETURN (error);
858*37741Smckusick 	vp = ndp->ni_vp;
859*37741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
860*37741Smckusick 		error = EROFS;
861*37741Smckusick 		goto out;
86221015Smckusick 	}
863*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
864*37741Smckusick out:
865*37741Smckusick 	vput(vp);
866*37741Smckusick 	RETURN (error);
86711811Ssam }
86811811Ssam 
8699167Ssam /*
8709167Ssam  * Truncate a file given its path name.
8719167Ssam  */
8727701Ssam truncate()
8737701Ssam {
8747701Ssam 	struct a {
8757701Ssam 		char	*fname;
87626473Skarels 		off_t	length;
8777826Sroot 	} *uap = (struct a *)u.u_ap;
87816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
879*37741Smckusick 	register struct vnode *vp;
880*37741Smckusick 	struct vattr vattr;
881*37741Smckusick 	int error;
8827701Ssam 
883*37741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
88416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88516694Smckusick 	ndp->ni_dirp = uap->fname;
886*37741Smckusick 	vattr_null(&vattr);
887*37741Smckusick 	vattr.va_size = uap->length;
888*37741Smckusick 	if (error = namei(ndp))
889*37741Smckusick 		RETURN (error);
890*37741Smckusick 	vp = ndp->ni_vp;
891*37741Smckusick 	if (vp->v_type == VDIR) {
892*37741Smckusick 		error = EISDIR;
893*37741Smckusick 		goto out;
8947701Ssam 	}
895*37741Smckusick 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
896*37741Smckusick 		goto out;
897*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
898*37741Smckusick out:
899*37741Smckusick 	vput(vp);
900*37741Smckusick 	RETURN (error);
9017701Ssam }
9027701Ssam 
9039167Ssam /*
9049167Ssam  * Truncate a file given a file descriptor.
9059167Ssam  */
9067701Ssam ftruncate()
9077701Ssam {
9087701Ssam 	struct a {
9097701Ssam 		int	fd;
91026473Skarels 		off_t	length;
9117826Sroot 	} *uap = (struct a *)u.u_ap;
912*37741Smckusick 	struct vattr vattr;
913*37741Smckusick 	struct vnode *vp;
9147701Ssam 	struct file *fp;
915*37741Smckusick 	int error;
9167701Ssam 
917*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
918*37741Smckusick 		RETURN (error);
919*37741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
920*37741Smckusick 		RETURN (EINVAL);
921*37741Smckusick 	vattr_null(&vattr);
922*37741Smckusick 	vattr.va_size = uap->length;
923*37741Smckusick 	vp = (struct vnode *)fp->f_data;
924*37741Smckusick 	VOP_LOCK(vp);
925*37741Smckusick 	if (vp->v_type == VDIR) {
926*37741Smckusick 		error = EISDIR;
927*37741Smckusick 		goto out;
9287701Ssam 	}
929*37741Smckusick 	if (error = vn_access(vp, VWRITE, fp->f_cred))
930*37741Smckusick 		goto out;
931*37741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
932*37741Smckusick out:
933*37741Smckusick 	VOP_UNLOCK(vp);
934*37741Smckusick 	RETURN (error);
9357701Ssam }
9367701Ssam 
9379167Ssam /*
9389167Ssam  * Synch an open file.
9399167Ssam  */
9409167Ssam fsync()
9419167Ssam {
9429167Ssam 	struct a {
9439167Ssam 		int	fd;
9449167Ssam 	} *uap = (struct a *)u.u_ap;
9459167Ssam 	struct file *fp;
946*37741Smckusick 	int error;
9479167Ssam 
948*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
949*37741Smckusick 		RETURN (error);
950*37741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
951*37741Smckusick 	RETURN (error);
9529167Ssam }
9539167Ssam 
9549167Ssam /*
9559167Ssam  * Rename system call.
9569167Ssam  *
9579167Ssam  * Source and destination must either both be directories, or both
9589167Ssam  * not be directories.  If target is a directory, it must be empty.
9599167Ssam  */
9607701Ssam rename()
9617701Ssam {
9627701Ssam 	struct a {
9637701Ssam 		char	*from;
9647701Ssam 		char	*to;
96516694Smckusick 	} *uap = (struct a *)u.u_ap;
966*37741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
96716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
968*37741Smckusick 	struct nameidata tond;
969*37741Smckusick 	int error;
9707701Ssam 
971*37741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
97216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97316694Smckusick 	ndp->ni_dirp = uap->from;
974*37741Smckusick 	if (error = namei(ndp))
975*37741Smckusick 		RETURN (error);
976*37741Smckusick 	fvp = ndp->ni_vp;
977*37741Smckusick 	bzero((caddr_t)&tond, sizeof(tond));
978*37741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
979*37741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
980*37741Smckusick 	tond.ni_dirp = uap->to;
981*37741Smckusick 	tond.ni_cdir = ndp->ni_cdir;
982*37741Smckusick 	tond.ni_cdir->v_count++;
983*37741Smckusick 	tond.ni_rdir = ndp->ni_rdir;
984*37741Smckusick 	if (tond.ni_rdir)
985*37741Smckusick 		tond.ni_rdir->v_count++;
986*37741Smckusick 	tond.ni_cred = ndp->ni_cred;
987*37741Smckusick 	crhold(tond.ni_cred);
988*37741Smckusick 	error = namei(&tond);
989*37741Smckusick 	tdvp = tond.ni_dvp;
990*37741Smckusick 	tvp = tond.ni_vp;
991*37741Smckusick 	if (tvp != NULL) {
992*37741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
993*37741Smckusick 			error = EISDIR;
994*37741Smckusick 			goto out;
995*37741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
996*37741Smckusick 			error = ENOTDIR;
997*37741Smckusick 			goto out;
9989167Ssam 		}
9999167Ssam 	}
1000*37741Smckusick 	if (error) {
1001*37741Smckusick 		VOP_ABORTOP(ndp);
1002*37741Smckusick 		goto out1;
1003*37741Smckusick 	}
1004*37741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
1005*37741Smckusick 		error = EXDEV;
10069167Ssam 		goto out;
100710051Ssam 	}
1008*37741Smckusick 	if (fvp == tdvp || fvp == tvp)
1009*37741Smckusick 		error = EINVAL;
1010*37741Smckusick out:
1011*37741Smckusick 	if (error) {
1012*37741Smckusick 		VOP_ABORTOP(&tond);
1013*37741Smckusick 		VOP_ABORTOP(ndp);
10149167Ssam 	} else {
1015*37741Smckusick 		error = VOP_RENAME(ndp, &tond);
10169167Ssam 	}
1017*37741Smckusick out1:
1018*37741Smckusick 	vrele(tond.ni_cdir);
1019*37741Smckusick 	if (tond.ni_rdir)
1020*37741Smckusick 		vrele(tond.ni_rdir);
1021*37741Smckusick 	crfree(tond.ni_cred);
1022*37741Smckusick 	RETURN (error);
10237701Ssam }
10247701Ssam 
10257535Sroot /*
102612756Ssam  * Mkdir system call
102712756Ssam  */
102812756Ssam mkdir()
102912756Ssam {
103012756Ssam 	struct a {
103112756Ssam 		char	*name;
103212756Ssam 		int	dmode;
103316694Smckusick 	} *uap = (struct a *)u.u_ap;
103416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
1035*37741Smckusick 	register struct vnode *vp;
1036*37741Smckusick 	struct vattr vattr;
1037*37741Smckusick 	int error;
103812756Ssam 
1039*37741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
104016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
104116694Smckusick 	ndp->ni_dirp = uap->name;
1042*37741Smckusick 	if (error = namei(ndp))
1043*37741Smckusick 		RETURN (error);
1044*37741Smckusick 	vp = ndp->ni_vp;
1045*37741Smckusick 	if (vp != NULL) {
1046*37741Smckusick 		VOP_ABORTOP(ndp);
1047*37741Smckusick 		RETURN (EEXIST);
104812756Ssam 	}
1049*37741Smckusick 	vattr_null(&vattr);
1050*37741Smckusick 	vattr.va_type = VDIR;
1051*37741Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
1052*37741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
1053*37741Smckusick 	RETURN (error);
105412756Ssam }
105512756Ssam 
105612756Ssam /*
105712756Ssam  * Rmdir system call.
105812756Ssam  */
105912756Ssam rmdir()
106012756Ssam {
106112756Ssam 	struct a {
106212756Ssam 		char	*name;
106316694Smckusick 	} *uap = (struct a *)u.u_ap;
106416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
1065*37741Smckusick 	register struct vnode *vp;
1066*37741Smckusick 	int error;
106712756Ssam 
1068*37741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
106916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107016694Smckusick 	ndp->ni_dirp = uap->name;
1071*37741Smckusick 	if (error = namei(ndp))
1072*37741Smckusick 		RETURN (error);
1073*37741Smckusick 	vp = ndp->ni_vp;
1074*37741Smckusick 	if (vp->v_type != VDIR) {
1075*37741Smckusick 		error = ENOTDIR;
107612756Ssam 		goto out;
107712756Ssam 	}
107812756Ssam 	/*
1079*37741Smckusick 	 * No rmdir "." please.
108012756Ssam 	 */
1081*37741Smckusick 	if (ndp->ni_dvp == vp) {
1082*37741Smckusick 		error = EINVAL;
108312756Ssam 		goto out;
108412756Ssam 	}
108512756Ssam 	/*
1086*37741Smckusick 	 * Don't unlink a mounted file.
108712756Ssam 	 */
1088*37741Smckusick 	if (vp->v_flag & VROOT)
1089*37741Smckusick 		error = EBUSY;
109012756Ssam out:
1091*37741Smckusick 	if (error)
1092*37741Smckusick 		VOP_ABORTOP(ndp);
1093*37741Smckusick 	else
1094*37741Smckusick 		error = VOP_RMDIR(ndp);
1095*37741Smckusick 	RETURN (error);
109612756Ssam }
109712756Ssam 
1098*37741Smckusick /*
1099*37741Smckusick  * Read a block of directory entries in a file system independent format
1100*37741Smckusick  */
1101*37741Smckusick getdirentries()
110212756Ssam {
1103*37741Smckusick 	register struct a {
1104*37741Smckusick 		int	fd;
1105*37741Smckusick 		char	*buf;
1106*37741Smckusick 		unsigned count;
1107*37741Smckusick 		long	*basep;
1108*37741Smckusick 	} *uap = (struct a *)u.u_ap;
110916540Ssam 	struct file *fp;
1110*37741Smckusick 	struct uio auio;
1111*37741Smckusick 	struct iovec aiov;
1112*37741Smckusick 	int error;
111312756Ssam 
1114*37741Smckusick 	if (error = getvnode(uap->fd, &fp))
1115*37741Smckusick 		RETURN (error);
1116*37741Smckusick 	if ((fp->f_flag & FREAD) == 0)
1117*37741Smckusick 		RETURN (EBADF);
1118*37741Smckusick 	aiov.iov_base = uap->buf;
1119*37741Smckusick 	aiov.iov_len = uap->count;
1120*37741Smckusick 	auio.uio_iov = &aiov;
1121*37741Smckusick 	auio.uio_iovcnt = 1;
1122*37741Smckusick 	auio.uio_rw = UIO_READ;
1123*37741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
1124*37741Smckusick 	auio.uio_resid = uap->count;
1125*37741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1126*37741Smckusick 	    &(fp->f_offset), fp->f_cred))
1127*37741Smckusick 		RETURN (error);
1128*37741Smckusick 	error = copyout((caddr_t)&fp->f_offset, (caddr_t)uap->basep,
1129*37741Smckusick 		sizeof(long));
1130*37741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
1131*37741Smckusick 	RETURN (error);
113212756Ssam }
113312756Ssam 
113412756Ssam /*
113512756Ssam  * mode mask for creation of files
113612756Ssam  */
113712756Ssam umask()
113812756Ssam {
113912756Ssam 	register struct a {
114012756Ssam 		int	mask;
114116694Smckusick 	} *uap = (struct a *)u.u_ap;
114212756Ssam 
114312756Ssam 	u.u_r.r_val1 = u.u_cmask;
114412756Ssam 	u.u_cmask = uap->mask & 07777;
1145*37741Smckusick 	RETURN (0);
114612756Ssam }
1147*37741Smckusick 
1148*37741Smckusick getvnode(fdes, fpp)
1149*37741Smckusick 	struct file **fpp;
1150*37741Smckusick 	int fdes;
1151*37741Smckusick {
1152*37741Smckusick 	struct file *fp;
1153*37741Smckusick 
1154*37741Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
1155*37741Smckusick 		return (EBADF);
1156*37741Smckusick 	if (fp->f_type != DTYPE_VNODE)
1157*37741Smckusick 		return (EINVAL);
1158*37741Smckusick 	*fpp = fp;
1159*37741Smckusick 	return (0);
1160*37741Smckusick }
1161