xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38399)
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.13 (Berkeley) 07/03/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  * get statistics on all filesystems
228  */
229 getfsstat()
230 {
231 	struct a {
232 		struct statfs *buf;
233 		long bufsize;
234 	} *uap = (struct a *)u.u_ap;
235 	register struct mount *mp;
236 	register struct statfs *sfsp;
237 	long count, maxcount, error;
238 
239 	maxcount = uap->bufsize / sizeof(struct statfs);
240 	sfsp = uap->buf;
241 	mp = rootfs;
242 	count = 0;
243 	do {
244 		count++;
245 		if (sfsp && count <= maxcount) {
246 			if (error = VFS_STATFS(mp, sfsp))
247 				RETURN (error);
248 			sfsp++;
249 		}
250 		mp = mp->m_prev;
251 	} while (mp != rootfs);
252 	if (sfsp && count > maxcount)
253 		u.u_r.r_val1 = maxcount;
254 	else
255 		u.u_r.r_val1 = count;
256 	RETURN (0);
257 }
258 
259 /*
260  * Change current working directory to a given file descriptor.
261  */
262 fchdir()
263 {
264 	struct a {
265 		int	fd;
266 	} *uap = (struct a *)u.u_ap;
267 	register struct vnode *vp;
268 	struct file *fp;
269 	int error;
270 
271 	if (error = getvnode(uap->fd, &fp))
272 		RETURN (error);
273 	vp = (struct vnode *)fp->f_data;
274 	VOP_LOCK(vp);
275 	if (vp->v_type != VDIR)
276 		error = ENOTDIR;
277 	else
278 		error = VOP_ACCESS(vp, VEXEC, u.u_cred);
279 	VOP_UNLOCK(vp);
280 	vrele(u.u_cdir);
281 	u.u_cdir = vp;
282 	RETURN (error);
283 }
284 
285 /*
286  * Change current working directory (``.'').
287  */
288 chdir()
289 {
290 	struct a {
291 		char	*fname;
292 	} *uap = (struct a *)u.u_ap;
293 	register struct nameidata *ndp = &u.u_nd;
294 	int error;
295 
296 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
297 	ndp->ni_segflg = UIO_USERSPACE;
298 	ndp->ni_dirp = uap->fname;
299 	if (error = chdirec(ndp))
300 		RETURN (error);
301 	vrele(u.u_cdir);
302 	u.u_cdir = ndp->ni_vp;
303 	RETURN (0);
304 }
305 
306 /*
307  * Change notion of root (``/'') directory.
308  */
309 chroot()
310 {
311 	struct a {
312 		char	*fname;
313 	} *uap = (struct a *)u.u_ap;
314 	register struct nameidata *ndp = &u.u_nd;
315 	int error;
316 
317 	if (error = suser(u.u_cred, &u.u_acflag))
318 		RETURN (error);
319 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
320 	ndp->ni_segflg = UIO_USERSPACE;
321 	ndp->ni_dirp = uap->fname;
322 	if (error = chdirec(ndp))
323 		RETURN (error);
324 	vrele(u.u_rdir);
325 	u.u_rdir = ndp->ni_vp;
326 	RETURN (0);
327 }
328 
329 /*
330  * Common routine for chroot and chdir.
331  */
332 chdirec(ndp)
333 	register struct nameidata *ndp;
334 {
335 	struct vnode *vp;
336 	int error;
337 
338 	if (error = namei(ndp))
339 		return (error);
340 	vp = ndp->ni_vp;
341 	if (vp->v_type != VDIR)
342 		error = ENOTDIR;
343 	else
344 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
345 	VOP_UNLOCK(vp);
346 	if (error)
347 		vrele(vp);
348 	return (error);
349 }
350 
351 /*
352  * Open system call.
353  */
354 open()
355 {
356 	struct a {
357 		char	*fname;
358 		int	mode;
359 		int	crtmode;
360 	} *uap = (struct a *) u.u_ap;
361 	struct nameidata *ndp = &u.u_nd;
362 
363 	ndp->ni_segflg = UIO_USERSPACE;
364 	ndp->ni_dirp = uap->fname;
365 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
366 		&u.u_r.r_val1));
367 }
368 
369 /*
370  * Creat system call.
371  */
372 creat()
373 {
374 	struct a {
375 		char	*fname;
376 		int	fmode;
377 	} *uap = (struct a *)u.u_ap;
378 	struct nameidata *ndp = &u.u_nd;
379 
380 	ndp->ni_segflg = UIO_USERSPACE;
381 	ndp->ni_dirp = uap->fname;
382 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
383 		&u.u_r.r_val1));
384 }
385 
386 /*
387  * Common code for open and creat.
388  * Check permissions, allocate an open file structure,
389  * and call the device open routine if any.
390  */
391 copen(fmode, cmode, ndp, resultfd)
392 	int fmode, cmode;
393 	struct nameidata *ndp;
394 	int *resultfd;
395 {
396 	register struct file *fp;
397 	struct file *nfp;
398 	int indx, error;
399 	extern struct fileops vnops;
400 
401 	if (error = falloc(&nfp, &indx))
402 		return (error);
403 	fp = nfp;
404 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
405 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
406 		u.u_ofile[indx] = NULL;
407 		crfree(fp->f_cred);
408 		fp->f_count--;
409 		return (error);
410 	}
411 	fp->f_flag = fmode & FMASK;
412 	fp->f_type = DTYPE_VNODE;
413 	fp->f_ops = &vnops;
414 	fp->f_data = (caddr_t)ndp->ni_vp;
415 	if (resultfd)
416 		*resultfd = indx;
417 	return (0);
418 }
419 
420 /*
421  * Mknod system call
422  */
423 mknod()
424 {
425 	register struct a {
426 		char	*fname;
427 		int	fmode;
428 		int	dev;
429 	} *uap = (struct a *)u.u_ap;
430 	register struct nameidata *ndp = &u.u_nd;
431 	register struct vnode *vp;
432 	struct vattr vattr;
433 	int error;
434 
435 	if (error = suser(u.u_cred, &u.u_acflag))
436 		RETURN (error);
437 	ndp->ni_nameiop = CREATE | LOCKPARENT;
438 	ndp->ni_segflg = UIO_USERSPACE;
439 	ndp->ni_dirp = uap->fname;
440 	if (error = namei(ndp))
441 		RETURN (error);
442 	vp = ndp->ni_vp;
443 	if (vp != NULL) {
444 		error = EEXIST;
445 		goto out;
446 	}
447 	vattr_null(&vattr);
448 	switch (uap->fmode & IFMT) {
449 
450 	case IFMT:	/* used by badsect to flag bad sectors */
451 		vattr.va_type = VBAD;
452 		break;
453 	case IFCHR:
454 		vattr.va_type = VCHR;
455 		break;
456 	case IFBLK:
457 		vattr.va_type = VBLK;
458 		break;
459 	default:
460 		error = EINVAL;
461 		goto out;
462 	}
463 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
464 	vattr.va_rdev = uap->dev;
465 out:
466 	if (error)
467 		VOP_ABORTOP(ndp);
468 	else
469 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
470 	RETURN (error);
471 }
472 
473 /*
474  * link system call
475  */
476 link()
477 {
478 	register struct a {
479 		char	*target;
480 		char	*linkname;
481 	} *uap = (struct a *)u.u_ap;
482 	register struct nameidata *ndp = &u.u_nd;
483 	register struct vnode *vp, *xp;
484 	int error;
485 
486 	ndp->ni_nameiop = LOOKUP | FOLLOW;
487 	ndp->ni_segflg = UIO_USERSPACE;
488 	ndp->ni_dirp = uap->target;
489 	if (error = namei(ndp))
490 		RETURN (error);
491 	vp = ndp->ni_vp;
492 	if (vp->v_type == VDIR &&
493 	    (error = suser(u.u_cred, &u.u_acflag)))
494 		goto out1;
495 	ndp->ni_nameiop = CREATE | LOCKPARENT;
496 	ndp->ni_dirp = (caddr_t)uap->linkname;
497 	if (error = namei(ndp))
498 		goto out1;
499 	xp = ndp->ni_vp;
500 	if (xp != NULL) {
501 		error = EEXIST;
502 		goto out;
503 	}
504 	xp = ndp->ni_dvp;
505 	if (vp->v_mount != xp->v_mount)
506 		error = EXDEV;
507 out:
508 	if (error)
509 		VOP_ABORTOP(ndp);
510 	else
511 		error = VOP_LINK(vp, ndp);
512 out1:
513 	vrele(vp);
514 	RETURN (error);
515 }
516 
517 /*
518  * symlink -- make a symbolic link
519  */
520 symlink()
521 {
522 	struct a {
523 		char	*target;
524 		char	*linkname;
525 	} *uap = (struct a *)u.u_ap;
526 	register struct nameidata *ndp = &u.u_nd;
527 	register struct vnode *vp;
528 	struct vattr vattr;
529 	char *target;
530 	int error;
531 
532 	ndp->ni_segflg = UIO_USERSPACE;
533 	ndp->ni_dirp = uap->linkname;
534 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
535 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
536 		goto out1;
537 	ndp->ni_nameiop = CREATE | LOCKPARENT;
538 	if (error = namei(ndp))
539 		goto out1;
540 	vp = ndp->ni_vp;
541 	if (vp) {
542 		error = EEXIST;
543 		goto out;
544 	}
545 	vp = ndp->ni_dvp;
546 	vattr_null(&vattr);
547 	vattr.va_mode = 0777 &~ u.u_cmask;
548 out:
549 	if (error)
550 		VOP_ABORTOP(ndp);
551 	else
552 		error = VOP_SYMLINK(ndp, &vattr, target);
553 out1:
554 	FREE(target, M_NAMEI);
555 	RETURN (error);
556 }
557 
558 /*
559  * Unlink system call.
560  * Hard to avoid races here, especially
561  * in unlinking directories.
562  */
563 unlink()
564 {
565 	struct a {
566 		char	*fname;
567 	} *uap = (struct a *)u.u_ap;
568 	register struct nameidata *ndp = &u.u_nd;
569 	register struct vnode *vp;
570 	int error;
571 
572 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
573 	ndp->ni_segflg = UIO_USERSPACE;
574 	ndp->ni_dirp = uap->fname;
575 	if (error = namei(ndp))
576 		RETURN (error);
577 	vp = ndp->ni_vp;
578 	if (vp->v_type == VDIR &&
579 	    (error = suser(u.u_cred, &u.u_acflag)))
580 		goto out;
581 	/*
582 	 * Don't unlink a mounted file.
583 	 */
584 	if (vp->v_flag & VROOT) {
585 		error = EBUSY;
586 		goto out;
587 	}
588 	if (vp->v_flag & VTEXT)
589 		xrele(vp);	/* try once to free text */
590 out:
591 	if (error)
592 		VOP_ABORTOP(ndp);
593 	else
594 		error = VOP_REMOVE(ndp);
595 	RETURN (error);
596 }
597 
598 /*
599  * Seek system call
600  */
601 lseek()
602 {
603 	register struct file *fp;
604 	register struct a {
605 		int	fdes;
606 		off_t	off;
607 		int	sbase;
608 	} *uap = (struct a *)u.u_ap;
609 	struct vattr vattr;
610 	int error;
611 
612 	if ((unsigned)uap->fdes >= NOFILE ||
613 	    (fp = u.u_ofile[uap->fdes]) == NULL)
614 		RETURN (EBADF);
615 	if (fp->f_type != DTYPE_VNODE)
616 		RETURN (ESPIPE);
617 	switch (uap->sbase) {
618 
619 	case L_INCR:
620 		fp->f_offset += uap->off;
621 		break;
622 
623 	case L_XTND:
624 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
625 		    &vattr, u.u_cred))
626 			RETURN (error);
627 		fp->f_offset = uap->off + vattr.va_size;
628 		break;
629 
630 	case L_SET:
631 		fp->f_offset = uap->off;
632 		break;
633 
634 	default:
635 		RETURN (EINVAL);
636 	}
637 	u.u_r.r_off = fp->f_offset;
638 	RETURN (0);
639 }
640 
641 /*
642  * Access system call
643  */
644 saccess()
645 {
646 	register struct a {
647 		char	*fname;
648 		int	fmode;
649 	} *uap = (struct a *)u.u_ap;
650 	register struct nameidata *ndp = &u.u_nd;
651 	register struct vnode *vp;
652 	int error, mode, svuid, svgid;
653 
654 	svuid = u.u_uid;
655 	svgid = u.u_gid;
656 	u.u_uid = u.u_ruid;
657 	u.u_gid = u.u_rgid;
658 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
659 	ndp->ni_segflg = UIO_USERSPACE;
660 	ndp->ni_dirp = uap->fname;
661 	if (error = namei(ndp))
662 		goto out1;
663 	vp = ndp->ni_vp;
664 	/*
665 	 * fmode == 0 means only check for exist
666 	 */
667 	if (uap->fmode) {
668 		mode = 0;
669 		if (uap->fmode & R_OK)
670 			mode |= VREAD;
671 		if (uap->fmode & W_OK)
672 			mode |= VWRITE;
673 		if (uap->fmode & X_OK)
674 			mode |= VEXEC;
675 		if ((error = vn_writechk(vp)) == 0)
676 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
677 	}
678 	vput(vp);
679 out1:
680 	u.u_uid = svuid;
681 	u.u_gid = svgid;
682 	RETURN (error);
683 }
684 
685 /*
686  * Stat system call.  This version follows links.
687  */
688 stat()
689 {
690 
691 	stat1(FOLLOW);
692 }
693 
694 /*
695  * Lstat system call.  This version does not follow links.
696  */
697 lstat()
698 {
699 
700 	stat1(NOFOLLOW);
701 }
702 
703 stat1(follow)
704 	int follow;
705 {
706 	register struct a {
707 		char	*fname;
708 		struct stat *ub;
709 	} *uap = (struct a *)u.u_ap;
710 	register struct nameidata *ndp = &u.u_nd;
711 	struct stat sb;
712 	int error;
713 
714 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
715 	ndp->ni_segflg = UIO_USERSPACE;
716 	ndp->ni_dirp = uap->fname;
717 	if (error = namei(ndp))
718 		RETURN (error);
719 	error = vn_stat(ndp->ni_vp, &sb);
720 	vput(ndp->ni_vp);
721 	if (error)
722 		RETURN (error);
723 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
724 	RETURN (error);
725 }
726 
727 /*
728  * Return target name of a symbolic link
729  */
730 readlink()
731 {
732 	register struct a {
733 		char	*name;
734 		char	*buf;
735 		int	count;
736 	} *uap = (struct a *)u.u_ap;
737 	register struct nameidata *ndp = &u.u_nd;
738 	register struct vnode *vp;
739 	struct iovec aiov;
740 	struct uio auio;
741 	int error;
742 
743 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
744 	ndp->ni_segflg = UIO_USERSPACE;
745 	ndp->ni_dirp = uap->name;
746 	if (error = namei(ndp))
747 		RETURN (error);
748 	vp = ndp->ni_vp;
749 	if (vp->v_type != VLNK) {
750 		error = EINVAL;
751 		goto out;
752 	}
753 	aiov.iov_base = uap->buf;
754 	aiov.iov_len = uap->count;
755 	auio.uio_iov = &aiov;
756 	auio.uio_iovcnt = 1;
757 	auio.uio_offset = 0;
758 	auio.uio_rw = UIO_READ;
759 	auio.uio_segflg = UIO_USERSPACE;
760 	auio.uio_resid = uap->count;
761 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
762 out:
763 	vput(vp);
764 	u.u_r.r_val1 = uap->count - auio.uio_resid;
765 	RETURN (error);
766 }
767 
768 /*
769  * Change flags of a file given path name.
770  */
771 chflags()
772 {
773 	struct a {
774 		char	*fname;
775 		int	flags;
776 	} *uap = (struct a *)u.u_ap;
777 	register struct nameidata *ndp = &u.u_nd;
778 	register struct vnode *vp;
779 	struct vattr vattr;
780 	int error;
781 
782 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
783 	ndp->ni_segflg = UIO_USERSPACE;
784 	ndp->ni_dirp = uap->fname;
785 	vattr_null(&vattr);
786 	vattr.va_flags = uap->flags;
787 	if (error = namei(ndp))
788 		RETURN (error);
789 	vp = ndp->ni_vp;
790 	if (vp->v_mount->m_flag & M_RDONLY) {
791 		error = EROFS;
792 		goto out;
793 	}
794 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
795 out:
796 	vput(vp);
797 	RETURN (error);
798 }
799 
800 /*
801  * Change flags of a file given a file descriptor.
802  */
803 fchflags()
804 {
805 	struct a {
806 		int	fd;
807 		int	flags;
808 	} *uap = (struct a *)u.u_ap;
809 	struct vattr vattr;
810 	struct vnode *vp;
811 	struct file *fp;
812 	int error;
813 
814 	if (error = getvnode(uap->fd, &fp))
815 		RETURN (error);
816 	vattr_null(&vattr);
817 	vattr.va_flags = uap->flags;
818 	vp = (struct vnode *)fp->f_data;
819 	VOP_LOCK(vp);
820 	if (vp->v_mount->m_flag & M_RDONLY) {
821 		error = EROFS;
822 		goto out;
823 	}
824 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
825 out:
826 	VOP_UNLOCK(vp);
827 	RETURN (error);
828 }
829 
830 /*
831  * Change mode of a file given path name.
832  */
833 chmod()
834 {
835 	struct a {
836 		char	*fname;
837 		int	fmode;
838 	} *uap = (struct a *)u.u_ap;
839 	register struct nameidata *ndp = &u.u_nd;
840 	register struct vnode *vp;
841 	struct vattr vattr;
842 	int error;
843 
844 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
845 	ndp->ni_segflg = UIO_USERSPACE;
846 	ndp->ni_dirp = uap->fname;
847 	vattr_null(&vattr);
848 	vattr.va_mode = uap->fmode & 07777;
849 	if (error = namei(ndp))
850 		RETURN (error);
851 	vp = ndp->ni_vp;
852 	if (vp->v_mount->m_flag & M_RDONLY) {
853 		error = EROFS;
854 		goto out;
855 	}
856 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
857 out:
858 	vput(vp);
859 	RETURN (error);
860 }
861 
862 /*
863  * Change mode of a file given a file descriptor.
864  */
865 fchmod()
866 {
867 	struct a {
868 		int	fd;
869 		int	fmode;
870 	} *uap = (struct a *)u.u_ap;
871 	struct vattr vattr;
872 	struct vnode *vp;
873 	struct file *fp;
874 	int error;
875 
876 	if (error = getvnode(uap->fd, &fp))
877 		RETURN (error);
878 	vattr_null(&vattr);
879 	vattr.va_mode = uap->fmode & 07777;
880 	vp = (struct vnode *)fp->f_data;
881 	VOP_LOCK(vp);
882 	if (vp->v_mount->m_flag & M_RDONLY) {
883 		error = EROFS;
884 		goto out;
885 	}
886 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
887 out:
888 	VOP_UNLOCK(vp);
889 	RETURN (error);
890 }
891 
892 /*
893  * Set ownership given a path name.
894  */
895 chown()
896 {
897 	struct a {
898 		char	*fname;
899 		int	uid;
900 		int	gid;
901 	} *uap = (struct a *)u.u_ap;
902 	register struct nameidata *ndp = &u.u_nd;
903 	register struct vnode *vp;
904 	struct vattr vattr;
905 	int error;
906 
907 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
908 	ndp->ni_segflg = UIO_USERSPACE;
909 	ndp->ni_dirp = uap->fname;
910 	vattr_null(&vattr);
911 	vattr.va_uid = uap->uid;
912 	vattr.va_gid = uap->gid;
913 	if (error = namei(ndp))
914 		RETURN (error);
915 	vp = ndp->ni_vp;
916 	if (vp->v_mount->m_flag & M_RDONLY) {
917 		error = EROFS;
918 		goto out;
919 	}
920 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
921 out:
922 	vput(vp);
923 	RETURN (error);
924 }
925 
926 /*
927  * Set ownership given a file descriptor.
928  */
929 fchown()
930 {
931 	struct a {
932 		int	fd;
933 		int	uid;
934 		int	gid;
935 	} *uap = (struct a *)u.u_ap;
936 	struct vattr vattr;
937 	struct vnode *vp;
938 	struct file *fp;
939 	int error;
940 
941 	if (error = getvnode(uap->fd, &fp))
942 		RETURN (error);
943 	vattr_null(&vattr);
944 	vattr.va_uid = uap->uid;
945 	vattr.va_gid = uap->gid;
946 	vp = (struct vnode *)fp->f_data;
947 	VOP_LOCK(vp);
948 	if (vp->v_mount->m_flag & M_RDONLY) {
949 		error = EROFS;
950 		goto out;
951 	}
952 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
953 out:
954 	VOP_UNLOCK(vp);
955 	RETURN (error);
956 }
957 
958 utimes()
959 {
960 	register struct a {
961 		char	*fname;
962 		struct	timeval *tptr;
963 	} *uap = (struct a *)u.u_ap;
964 	register struct nameidata *ndp = &u.u_nd;
965 	register struct vnode *vp;
966 	struct timeval tv[2];
967 	struct vattr vattr;
968 	int error;
969 
970 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
971 		RETURN (error);
972 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
973 	ndp->ni_segflg = UIO_USERSPACE;
974 	ndp->ni_dirp = uap->fname;
975 	vattr_null(&vattr);
976 	vattr.va_atime = tv[0];
977 	vattr.va_mtime = tv[1];
978 	if (error = namei(ndp))
979 		RETURN (error);
980 	vp = ndp->ni_vp;
981 	if (vp->v_mount->m_flag & M_RDONLY) {
982 		error = EROFS;
983 		goto out;
984 	}
985 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
986 out:
987 	vput(vp);
988 	RETURN (error);
989 }
990 
991 /*
992  * Truncate a file given its path name.
993  */
994 truncate()
995 {
996 	struct a {
997 		char	*fname;
998 		off_t	length;
999 	} *uap = (struct a *)u.u_ap;
1000 	register struct nameidata *ndp = &u.u_nd;
1001 	register struct vnode *vp;
1002 	struct vattr vattr;
1003 	int error;
1004 
1005 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1006 	ndp->ni_segflg = UIO_USERSPACE;
1007 	ndp->ni_dirp = uap->fname;
1008 	vattr_null(&vattr);
1009 	vattr.va_size = uap->length;
1010 	if (error = namei(ndp))
1011 		RETURN (error);
1012 	vp = ndp->ni_vp;
1013 	if (vp->v_type == VDIR) {
1014 		error = EISDIR;
1015 		goto out;
1016 	}
1017 	if ((error = vn_writechk(vp)) ||
1018 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
1019 		goto out;
1020 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1021 out:
1022 	vput(vp);
1023 	RETURN (error);
1024 }
1025 
1026 /*
1027  * Truncate a file given a file descriptor.
1028  */
1029 ftruncate()
1030 {
1031 	struct a {
1032 		int	fd;
1033 		off_t	length;
1034 	} *uap = (struct a *)u.u_ap;
1035 	struct vattr vattr;
1036 	struct vnode *vp;
1037 	struct file *fp;
1038 	int error;
1039 
1040 	if (error = getvnode(uap->fd, &fp))
1041 		RETURN (error);
1042 	if ((fp->f_flag & FWRITE) == 0)
1043 		RETURN (EINVAL);
1044 	vattr_null(&vattr);
1045 	vattr.va_size = uap->length;
1046 	vp = (struct vnode *)fp->f_data;
1047 	VOP_LOCK(vp);
1048 	if (vp->v_type == VDIR) {
1049 		error = EISDIR;
1050 		goto out;
1051 	}
1052 	if (error = vn_writechk(vp))
1053 		goto out;
1054 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1055 out:
1056 	VOP_UNLOCK(vp);
1057 	RETURN (error);
1058 }
1059 
1060 /*
1061  * Synch an open file.
1062  */
1063 fsync()
1064 {
1065 	struct a {
1066 		int	fd;
1067 	} *uap = (struct a *)u.u_ap;
1068 	struct file *fp;
1069 	int error;
1070 
1071 	if (error = getvnode(uap->fd, &fp))
1072 		RETURN (error);
1073 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
1074 	RETURN (error);
1075 }
1076 
1077 /*
1078  * Rename system call.
1079  *
1080  * Source and destination must either both be directories, or both
1081  * not be directories.  If target is a directory, it must be empty.
1082  */
1083 rename()
1084 {
1085 	struct a {
1086 		char	*from;
1087 		char	*to;
1088 	} *uap = (struct a *)u.u_ap;
1089 	register struct vnode *tvp, *fvp, *tdvp;
1090 	register struct nameidata *ndp = &u.u_nd;
1091 	struct nameidata tond;
1092 	int error;
1093 
1094 	ndp->ni_nameiop = DELETE | WANTPARENT;
1095 	ndp->ni_segflg = UIO_USERSPACE;
1096 	ndp->ni_dirp = uap->from;
1097 	if (error = namei(ndp))
1098 		RETURN (error);
1099 	fvp = ndp->ni_vp;
1100 	nddup(ndp, &tond);
1101 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1102 	tond.ni_segflg = UIO_USERSPACE;
1103 	tond.ni_dirp = uap->to;
1104 	error = namei(&tond);
1105 	tdvp = tond.ni_dvp;
1106 	tvp = tond.ni_vp;
1107 	if (tvp != NULL) {
1108 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1109 			error = EISDIR;
1110 			goto out;
1111 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1112 			error = ENOTDIR;
1113 			goto out;
1114 		}
1115 	}
1116 	if (error) {
1117 		VOP_ABORTOP(ndp);
1118 		goto out1;
1119 	}
1120 	if (fvp->v_mount != tdvp->v_mount) {
1121 		error = EXDEV;
1122 		goto out;
1123 	}
1124 	if (fvp == tdvp || fvp == tvp)
1125 		error = EINVAL;
1126 out:
1127 	if (error) {
1128 		VOP_ABORTOP(&tond);
1129 		VOP_ABORTOP(ndp);
1130 	} else {
1131 		error = VOP_RENAME(ndp, &tond);
1132 	}
1133 out1:
1134 	ndrele(&tond);
1135 	RETURN (error);
1136 }
1137 
1138 /*
1139  * Mkdir system call
1140  */
1141 mkdir()
1142 {
1143 	struct a {
1144 		char	*name;
1145 		int	dmode;
1146 	} *uap = (struct a *)u.u_ap;
1147 	register struct nameidata *ndp = &u.u_nd;
1148 	register struct vnode *vp;
1149 	struct vattr vattr;
1150 	int error;
1151 
1152 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1153 	ndp->ni_segflg = UIO_USERSPACE;
1154 	ndp->ni_dirp = uap->name;
1155 	if (error = namei(ndp))
1156 		RETURN (error);
1157 	vp = ndp->ni_vp;
1158 	if (vp != NULL) {
1159 		VOP_ABORTOP(ndp);
1160 		RETURN (EEXIST);
1161 	}
1162 	vattr_null(&vattr);
1163 	vattr.va_type = VDIR;
1164 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
1165 	error = VOP_MKDIR(ndp, &vattr);
1166 	if (!error)
1167 		vput(ndp->ni_vp);
1168 	RETURN (error);
1169 }
1170 
1171 /*
1172  * Rmdir system call.
1173  */
1174 rmdir()
1175 {
1176 	struct a {
1177 		char	*name;
1178 	} *uap = (struct a *)u.u_ap;
1179 	register struct nameidata *ndp = &u.u_nd;
1180 	register struct vnode *vp;
1181 	int error;
1182 
1183 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1184 	ndp->ni_segflg = UIO_USERSPACE;
1185 	ndp->ni_dirp = uap->name;
1186 	if (error = namei(ndp))
1187 		RETURN (error);
1188 	vp = ndp->ni_vp;
1189 	if (vp->v_type != VDIR) {
1190 		error = ENOTDIR;
1191 		goto out;
1192 	}
1193 	/*
1194 	 * No rmdir "." please.
1195 	 */
1196 	if (ndp->ni_dvp == vp) {
1197 		error = EINVAL;
1198 		goto out;
1199 	}
1200 	/*
1201 	 * Don't unlink a mounted file.
1202 	 */
1203 	if (vp->v_flag & VROOT)
1204 		error = EBUSY;
1205 out:
1206 	if (error)
1207 		VOP_ABORTOP(ndp);
1208 	else
1209 		error = VOP_RMDIR(ndp);
1210 	RETURN (error);
1211 }
1212 
1213 /*
1214  * Read a block of directory entries in a file system independent format
1215  */
1216 getdirentries()
1217 {
1218 	register struct a {
1219 		int	fd;
1220 		char	*buf;
1221 		unsigned count;
1222 		long	*basep;
1223 	} *uap = (struct a *)u.u_ap;
1224 	struct file *fp;
1225 	struct uio auio;
1226 	struct iovec aiov;
1227 	off_t off;
1228 	int error;
1229 
1230 	if (error = getvnode(uap->fd, &fp))
1231 		RETURN (error);
1232 	if ((fp->f_flag & FREAD) == 0)
1233 		RETURN (EBADF);
1234 	aiov.iov_base = uap->buf;
1235 	aiov.iov_len = uap->count;
1236 	auio.uio_iov = &aiov;
1237 	auio.uio_iovcnt = 1;
1238 	auio.uio_rw = UIO_READ;
1239 	auio.uio_segflg = UIO_USERSPACE;
1240 	auio.uio_resid = uap->count;
1241 	off = fp->f_offset;
1242 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1243 	    &(fp->f_offset), fp->f_cred))
1244 		RETURN (error);
1245 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
1246 		sizeof(long));
1247 	u.u_r.r_val1 = uap->count - auio.uio_resid;
1248 	RETURN (error);
1249 }
1250 
1251 /*
1252  * mode mask for creation of files
1253  */
1254 umask()
1255 {
1256 	register struct a {
1257 		int	mask;
1258 	} *uap = (struct a *)u.u_ap;
1259 
1260 	u.u_r.r_val1 = u.u_cmask;
1261 	u.u_cmask = uap->mask & 07777;
1262 	RETURN (0);
1263 }
1264 
1265 getvnode(fdes, fpp)
1266 	struct file **fpp;
1267 	int fdes;
1268 {
1269 	struct file *fp;
1270 
1271 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
1272 		return (EBADF);
1273 	if (fp->f_type != DTYPE_VNODE)
1274 		return (EINVAL);
1275 	*fpp = fp;
1276 	return (0);
1277 }
1278