xref: /original-bsd/sys/kern/vfs_syscalls.c (revision a76afa45)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)vfs_syscalls.c	7.7 (Berkeley) 05/09/89
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "syscontext.h"
23 #include "kernel.h"
24 #include "file.h"
25 #include "stat.h"
26 #include "vnode.h"
27 #include "../ufs/inode.h"
28 #include "mount.h"
29 #include "proc.h"
30 #include "uio.h"
31 #include "malloc.h"
32 
33 /*
34  * Virtual File System System Calls
35  */
36 
37 /*
38  * mount system call
39  */
40 mount()
41 {
42 	register struct a {
43 		int	type;
44 		char	*dir;
45 		int	flags;
46 		caddr_t	data;
47 	} *uap = (struct a *)u.u_ap;
48 	register struct nameidata *ndp = &u.u_nd;
49 	struct vnode *vp;
50 	struct mount *mp;
51 	int error;
52 
53 	/*
54 	 * Must be super user
55 	 */
56 	if (error = suser(u.u_cred, &u.u_acflag))
57 		RETURN (error);
58 	/*
59 	 * Get vnode to be covered
60 	 */
61 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
62 	ndp->ni_segflg = UIO_USERSPACE;
63 	ndp->ni_dirp = uap->dir;
64 	if (error = namei(ndp))
65 		RETURN (error);
66 	vp = ndp->ni_vp;
67 	if (vp->v_count != 1) {
68 		vput(vp);
69 		RETURN (EBUSY);
70 	}
71 	if (vp->v_type != VDIR) {
72 		vput(vp);
73 		RETURN (ENOTDIR);
74 	}
75 	if (uap->type > MOUNT_MAXTYPE ||
76 	    vfssw[uap->type] == (struct vfsops *)0) {
77 		vput(vp);
78 		RETURN (ENODEV);
79 	}
80 
81 	/*
82 	 * Mount the filesystem.
83 	 */
84 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
85 		M_MOUNT, M_WAITOK);
86 	mp->m_op = vfssw[uap->type];
87 	mp->m_flag = 0;
88 	mp->m_exroot = 0;
89 	error = vfs_add(vp, mp, uap->flags);
90 	if (!error)
91 		error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
92 	cache_purge(vp);
93 	VOP_UNLOCK(vp);
94 	if (!error) {
95 		vfs_unlock(mp);
96 	} else {
97 		vfs_remove(mp);
98 		free((caddr_t)mp, M_MOUNT);
99 		vrele(vp);
100 	}
101 	RETURN (error);
102 }
103 
104 /*
105  * Unmount system call.
106  *
107  * Note: unmount takes a path to the vnode mounted on as argument,
108  * not special file (as before).
109  */
110 unmount()
111 {
112 	struct a {
113 		char	*pathp;
114 		int	flags;
115 	} *uap = (struct a *)u.u_ap;
116 	register struct vnode *vp;
117 	register struct mount *mp;
118 	register struct nameidata *ndp = &u.u_nd;
119 	struct vnode *coveredvp;
120 	int error;
121 
122 	/*
123 	 * Must be super user
124 	 */
125 	if (error = suser(u.u_cred, &u.u_acflag))
126 		RETURN (error);
127 
128 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
129 	ndp->ni_segflg = UIO_USERSPACE;
130 	ndp->ni_dirp = uap->pathp;
131 	if (error = namei(ndp))
132 		RETURN (error);
133 	vp = ndp->ni_vp;
134 	/*
135 	 * Must be the root of the filesystem
136 	 */
137 	if ((vp->v_flag & VROOT) == 0) {
138 		vput(vp);
139 		RETURN (EINVAL);
140 	}
141 	mp = vp->v_mount;
142 	vput(vp);
143 	/*
144 	 * Do the unmount.
145 	 */
146 	coveredvp = mp->m_vnodecovered;
147 	if (error = vfs_lock(mp))
148 		RETURN (error);
149 
150 	xumount(mp);		/* remove unused sticky files from text table */
151 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
152 	VFS_SYNC(mp, MNT_WAIT);
153 
154 	error = VFS_UNMOUNT(mp, uap->flags);
155 	if (error) {
156 		vfs_unlock(mp);
157 	} else {
158 		vrele(coveredvp);
159 		vfs_remove(mp);
160 		free((caddr_t)mp, M_MOUNT);
161 	}
162 	RETURN (error);
163 }
164 
165 /*
166  * Sync system call.
167  * Sync each mounted filesystem.
168  */
169 sync()
170 {
171 	register struct mount *mp;
172 
173 	mp = rootfs;
174 	do {
175 		if ((mp->m_flag & M_RDONLY) == 0)
176 			VFS_SYNC(mp, MNT_NOWAIT);
177 		mp = mp->m_next;
178 	} while (mp != rootfs);
179 }
180 
181 /*
182  * get filesystem statistics
183  */
184 statfs()
185 {
186 	struct a {
187 		char *path;
188 		struct statfs *buf;
189 	} *uap = (struct a *)u.u_ap;
190 	register struct vnode *vp;
191 	register struct nameidata *ndp = &u.u_nd;
192 	struct statfs sb;
193 	int error;
194 
195 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
196 	ndp->ni_segflg = UIO_USERSPACE;
197 	ndp->ni_dirp = uap->path;
198 	if (error = namei(ndp))
199 		RETURN (error);
200 	vp = ndp->ni_vp;
201 	if (error = VFS_STATFS(vp->v_mount, &sb))
202 		goto out;
203 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
204 out:
205 	vput(vp);
206 	RETURN (error);
207 }
208 
209 fstatfs()
210 {
211 	struct a {
212 		int fd;
213 		struct statfs *buf;
214 	} *uap = (struct a *)u.u_ap;
215 	struct file *fp;
216 	struct statfs sb;
217 	int error;
218 
219 	if (error = getvnode(uap->fd, &fp))
220 		RETURN (error);
221 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
222 		RETURN (error);
223 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
224 }
225 
226 /*
227  * Change current working directory (``.'').
228  */
229 chdir()
230 {
231 	struct a {
232 		char	*fname;
233 	} *uap = (struct a *)u.u_ap;
234 	register struct nameidata *ndp = &u.u_nd;
235 	int error;
236 
237 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
238 	ndp->ni_segflg = UIO_USERSPACE;
239 	ndp->ni_dirp = uap->fname;
240 	if (error = chdirec(ndp))
241 		RETURN (error);
242 	vrele(u.u_cdir);
243 	u.u_cdir = ndp->ni_vp;
244 	RETURN (0);
245 }
246 
247 /*
248  * Change notion of root (``/'') directory.
249  */
250 chroot()
251 {
252 	struct a {
253 		char	*fname;
254 	} *uap = (struct a *)u.u_ap;
255 	register struct nameidata *ndp = &u.u_nd;
256 	int error;
257 
258 	if (error = suser(u.u_cred, &u.u_acflag))
259 		RETURN (error);
260 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
261 	ndp->ni_segflg = UIO_USERSPACE;
262 	ndp->ni_dirp = uap->fname;
263 	if (error = chdirec(ndp))
264 		RETURN (error);
265 	vrele(u.u_rdir);
266 	u.u_rdir = ndp->ni_vp;
267 	RETURN (0);
268 }
269 
270 /*
271  * Common routine for chroot and chdir.
272  */
273 chdirec(ndp)
274 	register struct nameidata *ndp;
275 {
276 	struct vnode *vp;
277 	int error;
278 
279 	if (error = namei(ndp))
280 		return (error);
281 	vp = ndp->ni_vp;
282 	if (vp->v_type != VDIR)
283 		error = ENOTDIR;
284 	else
285 		error = vn_access(vp, VEXEC, ndp->ni_cred);
286 	VOP_UNLOCK(vp);
287 	if (error)
288 		vrele(vp);
289 	return (error);
290 }
291 
292 /*
293  * Open system call.
294  */
295 open()
296 {
297 	struct a {
298 		char	*fname;
299 		int	mode;
300 		int	crtmode;
301 	} *uap = (struct a *) u.u_ap;
302 	struct nameidata *ndp = &u.u_nd;
303 
304 	ndp->ni_segflg = UIO_USERSPACE;
305 	ndp->ni_dirp = uap->fname;
306 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
307 		&u.u_r.r_val1));
308 }
309 
310 /*
311  * Creat system call.
312  */
313 creat()
314 {
315 	struct a {
316 		char	*fname;
317 		int	fmode;
318 	} *uap = (struct a *)u.u_ap;
319 	struct nameidata *ndp = &u.u_nd;
320 
321 	ndp->ni_segflg = UIO_USERSPACE;
322 	ndp->ni_dirp = uap->fname;
323 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
324 		&u.u_r.r_val1));
325 }
326 
327 /*
328  * Common code for open and creat.
329  * Check permissions, allocate an open file structure,
330  * and call the device open routine if any.
331  */
332 copen(fmode, cmode, ndp, resultfd)
333 	int fmode, cmode;
334 	struct nameidata *ndp;
335 	int *resultfd;
336 {
337 	register struct file *fp;
338 	struct file *nfp;
339 	int indx, error;
340 	extern struct fileops vnops;
341 
342 	if (error = falloc(&nfp, &indx))
343 		return (error);
344 	fp = nfp;
345 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
346 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
347 		u.u_ofile[indx] = NULL;
348 		crfree(fp->f_cred);
349 		fp->f_count--;
350 		return (error);
351 	}
352 	fp->f_flag = fmode & FMASK;
353 	fp->f_type = DTYPE_VNODE;
354 	fp->f_ops = &vnops;
355 	fp->f_data = (caddr_t)ndp->ni_vp;
356 	if (resultfd)
357 		*resultfd = indx;
358 	return (0);
359 }
360 
361 /*
362  * Mknod system call
363  */
364 mknod()
365 {
366 	register struct a {
367 		char	*fname;
368 		int	fmode;
369 		int	dev;
370 	} *uap = (struct a *)u.u_ap;
371 	register struct nameidata *ndp = &u.u_nd;
372 	register struct vnode *vp;
373 	struct vattr vattr;
374 	int error;
375 
376 	if (error = suser(u.u_cred, &u.u_acflag))
377 		RETURN (error);
378 	ndp->ni_nameiop = CREATE | LOCKPARENT;
379 	ndp->ni_segflg = UIO_USERSPACE;
380 	ndp->ni_dirp = uap->fname;
381 	if (error = namei(ndp))
382 		RETURN (error);
383 	vp = ndp->ni_vp;
384 	if (vp != NULL) {
385 		error = EEXIST;
386 		goto out;
387 	}
388 	vattr_null(&vattr);
389 	switch (uap->fmode & IFMT) {
390 
391 	case IFMT:	/* used by badsect to flag bad sectors */
392 		vattr.va_type = VBAD;
393 		break;
394 	case IFCHR:
395 		vattr.va_type = VCHR;
396 		break;
397 	case IFBLK:
398 		vattr.va_type = VBLK;
399 		break;
400 	default:
401 		error = EINVAL;
402 		goto out;
403 	}
404 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
405 	vattr.va_rdev = uap->dev;
406 out:
407 	if (error)
408 		VOP_ABORTOP(ndp);
409 	else
410 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
411 	RETURN (error);
412 }
413 
414 /*
415  * link system call
416  */
417 link()
418 {
419 	register struct a {
420 		char	*target;
421 		char	*linkname;
422 	} *uap = (struct a *)u.u_ap;
423 	register struct nameidata *ndp = &u.u_nd;
424 	register struct vnode *vp, *xp;
425 	int error;
426 
427 	ndp->ni_nameiop = LOOKUP | FOLLOW;
428 	ndp->ni_segflg = UIO_USERSPACE;
429 	ndp->ni_dirp = uap->target;
430 	if (error = namei(ndp))
431 		RETURN (error);
432 	vp = ndp->ni_vp;
433 	if (vp->v_type == VDIR &&
434 	    (error = suser(u.u_cred, &u.u_acflag)))
435 		goto out1;
436 	ndp->ni_nameiop = CREATE | LOCKPARENT;
437 	ndp->ni_dirp = (caddr_t)uap->linkname;
438 	if (error = namei(ndp))
439 		goto out1;
440 	xp = ndp->ni_vp;
441 	if (xp != NULL) {
442 		error = EEXIST;
443 		goto out;
444 	}
445 	xp = ndp->ni_dvp;
446 	if (vp->v_mount != xp->v_mount)
447 		error = EXDEV;
448 out:
449 	if (error)
450 		VOP_ABORTOP(ndp);
451 	else
452 		error = VOP_LINK(vp, ndp);
453 out1:
454 	vrele(vp);
455 	RETURN (error);
456 }
457 
458 /*
459  * symlink -- make a symbolic link
460  */
461 symlink()
462 {
463 	struct a {
464 		char	*target;
465 		char	*linkname;
466 	} *uap = (struct a *)u.u_ap;
467 	register struct nameidata *ndp = &u.u_nd;
468 	register struct vnode *vp;
469 	struct vattr vattr;
470 	char *target;
471 	int error;
472 
473 	ndp->ni_segflg = UIO_USERSPACE;
474 	ndp->ni_dirp = uap->linkname;
475 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
476 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
477 		goto out1;
478 	ndp->ni_nameiop = CREATE | LOCKPARENT;
479 	if (error = namei(ndp))
480 		goto out1;
481 	vp = ndp->ni_vp;
482 	if (vp) {
483 		error = EEXIST;
484 		goto out;
485 	}
486 	vp = ndp->ni_dvp;
487 	vattr_null(&vattr);
488 	vattr.va_mode = 0777 &~ u.u_cmask;
489 out:
490 	if (error)
491 		VOP_ABORTOP(ndp);
492 	else
493 		error = VOP_SYMLINK(ndp, &vattr, target);
494 out1:
495 	FREE(target, M_NAMEI);
496 	RETURN (error);
497 }
498 
499 /*
500  * Unlink system call.
501  * Hard to avoid races here, especially
502  * in unlinking directories.
503  */
504 unlink()
505 {
506 	struct a {
507 		char	*fname;
508 	} *uap = (struct a *)u.u_ap;
509 	register struct nameidata *ndp = &u.u_nd;
510 	register struct vnode *vp;
511 	int error;
512 
513 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
514 	ndp->ni_segflg = UIO_USERSPACE;
515 	ndp->ni_dirp = uap->fname;
516 	if (error = namei(ndp))
517 		RETURN (error);
518 	vp = ndp->ni_vp;
519 	if (vp->v_type == VDIR &&
520 	    (error = suser(u.u_cred, &u.u_acflag)))
521 		goto out;
522 	/*
523 	 * Don't unlink a mounted file.
524 	 */
525 	if (vp->v_flag & VROOT) {
526 		error = EBUSY;
527 		goto out;
528 	}
529 	if (vp->v_flag & VTEXT)
530 		xrele(vp);	/* try once to free text */
531 out:
532 	if (error)
533 		VOP_ABORTOP(ndp);
534 	else
535 		error = VOP_REMOVE(ndp);
536 	RETURN (error);
537 }
538 
539 /*
540  * Seek system call
541  */
542 lseek()
543 {
544 	register struct file *fp;
545 	register struct a {
546 		int	fdes;
547 		off_t	off;
548 		int	sbase;
549 	} *uap = (struct a *)u.u_ap;
550 	struct vattr vattr;
551 	int error;
552 
553 	if ((unsigned)uap->fdes >= NOFILE ||
554 	    (fp = u.u_ofile[uap->fdes]) == NULL)
555 		RETURN (EBADF);
556 	if (fp->f_type != DTYPE_VNODE)
557 		RETURN (ESPIPE);
558 	switch (uap->sbase) {
559 
560 	case L_INCR:
561 		fp->f_offset += uap->off;
562 		break;
563 
564 	case L_XTND:
565 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
566 		    &vattr, u.u_cred))
567 			RETURN (error);
568 		fp->f_offset = uap->off + vattr.va_size;
569 		break;
570 
571 	case L_SET:
572 		fp->f_offset = uap->off;
573 		break;
574 
575 	default:
576 		RETURN (EINVAL);
577 	}
578 	u.u_r.r_off = fp->f_offset;
579 	RETURN (0);
580 }
581 
582 /*
583  * Access system call
584  */
585 saccess()
586 {
587 	register struct a {
588 		char	*fname;
589 		int	fmode;
590 	} *uap = (struct a *)u.u_ap;
591 	register struct nameidata *ndp = &u.u_nd;
592 	register struct vnode *vp;
593 	int error, mode, svuid, svgid;
594 
595 	svuid = u.u_uid;
596 	svgid = u.u_gid;
597 	u.u_uid = u.u_ruid;
598 	u.u_gid = u.u_rgid;
599 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
600 	ndp->ni_segflg = UIO_USERSPACE;
601 	ndp->ni_dirp = uap->fname;
602 	if (error = namei(ndp))
603 		goto out1;
604 	vp = ndp->ni_vp;
605 	/*
606 	 * fmode == 0 means only check for exist
607 	 */
608 	if (uap->fmode) {
609 		mode = 0;
610 		if (uap->fmode & R_OK)
611 			mode |= VREAD;
612 		if (uap->fmode & W_OK)
613 			mode |= VWRITE;
614 		if (uap->fmode & X_OK)
615 			mode |= VEXEC;
616 		error = vn_access(vp, mode, u.u_cred);
617 	}
618 	vput(vp);
619 out1:
620 	u.u_uid = svuid;
621 	u.u_gid = svgid;
622 	RETURN (error);
623 }
624 
625 /*
626  * Stat system call.  This version follows links.
627  */
628 stat()
629 {
630 
631 	stat1(FOLLOW);
632 }
633 
634 /*
635  * Lstat system call.  This version does not follow links.
636  */
637 lstat()
638 {
639 
640 	stat1(NOFOLLOW);
641 }
642 
643 stat1(follow)
644 	int follow;
645 {
646 	register struct a {
647 		char	*fname;
648 		struct stat *ub;
649 	} *uap = (struct a *)u.u_ap;
650 	register struct nameidata *ndp = &u.u_nd;
651 	struct stat sb;
652 	int error;
653 
654 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
655 	ndp->ni_segflg = UIO_USERSPACE;
656 	ndp->ni_dirp = uap->fname;
657 	if (error = namei(ndp))
658 		RETURN (error);
659 	error = vn_stat(ndp->ni_vp, &sb);
660 	vput(ndp->ni_vp);
661 	if (error)
662 		RETURN (error);
663 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
664 	RETURN (error);
665 }
666 
667 /*
668  * Return target name of a symbolic link
669  */
670 readlink()
671 {
672 	register struct a {
673 		char	*name;
674 		char	*buf;
675 		int	count;
676 	} *uap = (struct a *)u.u_ap;
677 	register struct nameidata *ndp = &u.u_nd;
678 	register struct vnode *vp;
679 	struct iovec aiov;
680 	struct uio auio;
681 	int error;
682 
683 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
684 	ndp->ni_segflg = UIO_USERSPACE;
685 	ndp->ni_dirp = uap->name;
686 	if (error = namei(ndp))
687 		RETURN (error);
688 	vp = ndp->ni_vp;
689 	if (vp->v_type != VLNK) {
690 		error = EINVAL;
691 		goto out;
692 	}
693 	aiov.iov_base = uap->buf;
694 	aiov.iov_len = uap->count;
695 	auio.uio_iov = &aiov;
696 	auio.uio_iovcnt = 1;
697 	auio.uio_offset = 0;
698 	auio.uio_rw = UIO_READ;
699 	auio.uio_segflg = UIO_USERSPACE;
700 	auio.uio_resid = uap->count;
701 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
702 out:
703 	vput(vp);
704 	u.u_r.r_val1 = uap->count - auio.uio_resid;
705 	RETURN (error);
706 }
707 
708 /*
709  * Change mode of a file given path name.
710  */
711 chmod()
712 {
713 	struct a {
714 		char	*fname;
715 		int	fmode;
716 	} *uap = (struct a *)u.u_ap;
717 	register struct nameidata *ndp = &u.u_nd;
718 	register struct vnode *vp;
719 	struct vattr vattr;
720 	int error;
721 
722 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
723 	ndp->ni_segflg = UIO_USERSPACE;
724 	ndp->ni_dirp = uap->fname;
725 	vattr_null(&vattr);
726 	vattr.va_mode = uap->fmode & 07777;
727 	if (error = namei(ndp))
728 		RETURN (error);
729 	vp = ndp->ni_vp;
730 	if (vp->v_mount->m_flag & M_RDONLY) {
731 		error = EROFS;
732 		goto out;
733 	}
734 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
735 out:
736 	vput(vp);
737 	RETURN (error);
738 }
739 
740 /*
741  * Change mode of a file given a file descriptor.
742  */
743 fchmod()
744 {
745 	struct a {
746 		int	fd;
747 		int	fmode;
748 	} *uap = (struct a *)u.u_ap;
749 	struct vattr vattr;
750 	struct vnode *vp;
751 	struct file *fp;
752 	int error;
753 
754 	if (error = getvnode(uap->fd, &fp))
755 		RETURN (error);
756 	vattr_null(&vattr);
757 	vattr.va_mode = uap->fmode & 07777;
758 	vp = (struct vnode *)fp->f_data;
759 	VOP_LOCK(vp);
760 	if (vp->v_mount->m_flag & M_RDONLY) {
761 		error = EROFS;
762 		goto out;
763 	}
764 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
765 out:
766 	VOP_UNLOCK(vp);
767 	RETURN (error);
768 }
769 
770 /*
771  * Set ownership given a path name.
772  */
773 chown()
774 {
775 	struct a {
776 		char	*fname;
777 		int	uid;
778 		int	gid;
779 	} *uap = (struct a *)u.u_ap;
780 	register struct nameidata *ndp = &u.u_nd;
781 	register struct vnode *vp;
782 	struct vattr vattr;
783 	int error;
784 
785 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
786 	ndp->ni_segflg = UIO_USERSPACE;
787 	ndp->ni_dirp = uap->fname;
788 	vattr_null(&vattr);
789 	vattr.va_uid = uap->uid;
790 	vattr.va_gid = uap->gid;
791 	if (error = namei(ndp))
792 		RETURN (error);
793 	vp = ndp->ni_vp;
794 	if (vp->v_mount->m_flag & M_RDONLY) {
795 		error = EROFS;
796 		goto out;
797 	}
798 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
799 out:
800 	vput(vp);
801 	RETURN (error);
802 }
803 
804 /*
805  * Set ownership given a file descriptor.
806  */
807 fchown()
808 {
809 	struct a {
810 		int	fd;
811 		int	uid;
812 		int	gid;
813 	} *uap = (struct a *)u.u_ap;
814 	struct vattr vattr;
815 	struct vnode *vp;
816 	struct file *fp;
817 	int error;
818 
819 	if (error = getvnode(uap->fd, &fp))
820 		RETURN (error);
821 	vattr_null(&vattr);
822 	vattr.va_uid = uap->uid;
823 	vattr.va_gid = uap->gid;
824 	vp = (struct vnode *)fp->f_data;
825 	VOP_LOCK(vp);
826 	if (vp->v_mount->m_flag & M_RDONLY) {
827 		error = EROFS;
828 		goto out;
829 	}
830 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
831 out:
832 	VOP_UNLOCK(vp);
833 	RETURN (error);
834 }
835 
836 utimes()
837 {
838 	register struct a {
839 		char	*fname;
840 		struct	timeval *tptr;
841 	} *uap = (struct a *)u.u_ap;
842 	register struct nameidata *ndp = &u.u_nd;
843 	register struct vnode *vp;
844 	struct timeval tv[2];
845 	struct vattr vattr;
846 	int error;
847 
848 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
849 		RETURN (error);
850 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
851 	ndp->ni_segflg = UIO_USERSPACE;
852 	ndp->ni_dirp = uap->fname;
853 	vattr_null(&vattr);
854 	vattr.va_atime = tv[0];
855 	vattr.va_mtime = tv[1];
856 	if (error = namei(ndp))
857 		RETURN (error);
858 	vp = ndp->ni_vp;
859 	if (vp->v_mount->m_flag & M_RDONLY) {
860 		error = EROFS;
861 		goto out;
862 	}
863 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
864 out:
865 	vput(vp);
866 	RETURN (error);
867 }
868 
869 /*
870  * Truncate a file given its path name.
871  */
872 truncate()
873 {
874 	struct a {
875 		char	*fname;
876 		off_t	length;
877 	} *uap = (struct a *)u.u_ap;
878 	register struct nameidata *ndp = &u.u_nd;
879 	register struct vnode *vp;
880 	struct vattr vattr;
881 	int error;
882 
883 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
884 	ndp->ni_segflg = UIO_USERSPACE;
885 	ndp->ni_dirp = uap->fname;
886 	vattr_null(&vattr);
887 	vattr.va_size = uap->length;
888 	if (error = namei(ndp))
889 		RETURN (error);
890 	vp = ndp->ni_vp;
891 	if (vp->v_type == VDIR) {
892 		error = EISDIR;
893 		goto out;
894 	}
895 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
896 		goto out;
897 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
898 out:
899 	vput(vp);
900 	RETURN (error);
901 }
902 
903 /*
904  * Truncate a file given a file descriptor.
905  */
906 ftruncate()
907 {
908 	struct a {
909 		int	fd;
910 		off_t	length;
911 	} *uap = (struct a *)u.u_ap;
912 	struct vattr vattr;
913 	struct vnode *vp;
914 	struct file *fp;
915 	int error;
916 
917 	if (error = getvnode(uap->fd, &fp))
918 		RETURN (error);
919 	if ((fp->f_flag & FWRITE) == 0)
920 		RETURN (EINVAL);
921 	vattr_null(&vattr);
922 	vattr.va_size = uap->length;
923 	vp = (struct vnode *)fp->f_data;
924 	VOP_LOCK(vp);
925 	if (vp->v_type == VDIR) {
926 		error = EISDIR;
927 		goto out;
928 	}
929 	if (error = vn_access(vp, VWRITE, fp->f_cred))
930 		goto out;
931 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
932 out:
933 	VOP_UNLOCK(vp);
934 	RETURN (error);
935 }
936 
937 /*
938  * Synch an open file.
939  */
940 fsync()
941 {
942 	struct a {
943 		int	fd;
944 	} *uap = (struct a *)u.u_ap;
945 	struct file *fp;
946 	int error;
947 
948 	if (error = getvnode(uap->fd, &fp))
949 		RETURN (error);
950 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
951 	RETURN (error);
952 }
953 
954 /*
955  * Rename system call.
956  *
957  * Source and destination must either both be directories, or both
958  * not be directories.  If target is a directory, it must be empty.
959  */
960 rename()
961 {
962 	struct a {
963 		char	*from;
964 		char	*to;
965 	} *uap = (struct a *)u.u_ap;
966 	register struct vnode *tvp, *fvp, *tdvp;
967 	register struct nameidata *ndp = &u.u_nd;
968 	struct nameidata tond;
969 	int error;
970 
971 	ndp->ni_nameiop = DELETE | WANTPARENT;
972 	ndp->ni_segflg = UIO_USERSPACE;
973 	ndp->ni_dirp = uap->from;
974 	if (error = namei(ndp))
975 		RETURN (error);
976 	fvp = ndp->ni_vp;
977 	bzero((caddr_t)&tond, sizeof(tond));
978 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
979 	tond.ni_segflg = UIO_USERSPACE;
980 	tond.ni_dirp = uap->to;
981 	tond.ni_cdir = ndp->ni_cdir;
982 	tond.ni_cdir->v_count++;
983 	tond.ni_rdir = ndp->ni_rdir;
984 	if (tond.ni_rdir)
985 		tond.ni_rdir->v_count++;
986 	tond.ni_cred = ndp->ni_cred;
987 	crhold(tond.ni_cred);
988 	error = namei(&tond);
989 	tdvp = tond.ni_dvp;
990 	tvp = tond.ni_vp;
991 	if (tvp != NULL) {
992 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
993 			error = EISDIR;
994 			goto out;
995 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
996 			error = ENOTDIR;
997 			goto out;
998 		}
999 	}
1000 	if (error) {
1001 		VOP_ABORTOP(ndp);
1002 		goto out1;
1003 	}
1004 	if (fvp->v_mount != tdvp->v_mount) {
1005 		error = EXDEV;
1006 		goto out;
1007 	}
1008 	if (fvp == tdvp || fvp == tvp)
1009 		error = EINVAL;
1010 out:
1011 	if (error) {
1012 		VOP_ABORTOP(&tond);
1013 		VOP_ABORTOP(ndp);
1014 	} else {
1015 		error = VOP_RENAME(ndp, &tond);
1016 	}
1017 out1:
1018 	vrele(tond.ni_cdir);
1019 	if (tond.ni_rdir)
1020 		vrele(tond.ni_rdir);
1021 	crfree(tond.ni_cred);
1022 	RETURN (error);
1023 }
1024 
1025 /*
1026  * Mkdir system call
1027  */
1028 mkdir()
1029 {
1030 	struct a {
1031 		char	*name;
1032 		int	dmode;
1033 	} *uap = (struct a *)u.u_ap;
1034 	register struct nameidata *ndp = &u.u_nd;
1035 	register struct vnode *vp;
1036 	struct vattr vattr;
1037 	int error;
1038 
1039 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1040 	ndp->ni_segflg = UIO_USERSPACE;
1041 	ndp->ni_dirp = uap->name;
1042 	if (error = namei(ndp))
1043 		RETURN (error);
1044 	vp = ndp->ni_vp;
1045 	if (vp != NULL) {
1046 		VOP_ABORTOP(ndp);
1047 		RETURN (EEXIST);
1048 	}
1049 	vattr_null(&vattr);
1050 	vattr.va_type = VDIR;
1051 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
1052 	error = VOP_MKDIR(ndp, &vattr);
1053 	RETURN (error);
1054 }
1055 
1056 /*
1057  * Rmdir system call.
1058  */
1059 rmdir()
1060 {
1061 	struct a {
1062 		char	*name;
1063 	} *uap = (struct a *)u.u_ap;
1064 	register struct nameidata *ndp = &u.u_nd;
1065 	register struct vnode *vp;
1066 	int error;
1067 
1068 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1069 	ndp->ni_segflg = UIO_USERSPACE;
1070 	ndp->ni_dirp = uap->name;
1071 	if (error = namei(ndp))
1072 		RETURN (error);
1073 	vp = ndp->ni_vp;
1074 	if (vp->v_type != VDIR) {
1075 		error = ENOTDIR;
1076 		goto out;
1077 	}
1078 	/*
1079 	 * No rmdir "." please.
1080 	 */
1081 	if (ndp->ni_dvp == vp) {
1082 		error = EINVAL;
1083 		goto out;
1084 	}
1085 	/*
1086 	 * Don't unlink a mounted file.
1087 	 */
1088 	if (vp->v_flag & VROOT)
1089 		error = EBUSY;
1090 out:
1091 	if (error)
1092 		VOP_ABORTOP(ndp);
1093 	else
1094 		error = VOP_RMDIR(ndp);
1095 	RETURN (error);
1096 }
1097 
1098 /*
1099  * Read a block of directory entries in a file system independent format
1100  */
1101 getdirentries()
1102 {
1103 	register struct a {
1104 		int	fd;
1105 		char	*buf;
1106 		unsigned count;
1107 		long	*basep;
1108 	} *uap = (struct a *)u.u_ap;
1109 	struct file *fp;
1110 	struct uio auio;
1111 	struct iovec aiov;
1112 	int error;
1113 
1114 	if (error = getvnode(uap->fd, &fp))
1115 		RETURN (error);
1116 	if ((fp->f_flag & FREAD) == 0)
1117 		RETURN (EBADF);
1118 	aiov.iov_base = uap->buf;
1119 	aiov.iov_len = uap->count;
1120 	auio.uio_iov = &aiov;
1121 	auio.uio_iovcnt = 1;
1122 	auio.uio_rw = UIO_READ;
1123 	auio.uio_segflg = UIO_USERSPACE;
1124 	auio.uio_resid = uap->count;
1125 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1126 	    &(fp->f_offset), fp->f_cred))
1127 		RETURN (error);
1128 	error = copyout((caddr_t)&fp->f_offset, (caddr_t)uap->basep,
1129 		sizeof(long));
1130 	u.u_r.r_val1 = uap->count - auio.uio_resid;
1131 	RETURN (error);
1132 }
1133 
1134 /*
1135  * mode mask for creation of files
1136  */
1137 umask()
1138 {
1139 	register struct a {
1140 		int	mask;
1141 	} *uap = (struct a *)u.u_ap;
1142 
1143 	u.u_r.r_val1 = u.u_cmask;
1144 	u.u_cmask = uap->mask & 07777;
1145 	RETURN (0);
1146 }
1147 
1148 getvnode(fdes, fpp)
1149 	struct file **fpp;
1150 	int fdes;
1151 {
1152 	struct file *fp;
1153 
1154 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
1155 		return (EBADF);
1156 	if (fp->f_type != DTYPE_VNODE)
1157 		return (EINVAL);
1158 	*fpp = fp;
1159 	return (0);
1160 }
1161