xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38270)
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.12 (Berkeley) 06/08/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 = vn_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 = vn_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 		error = vn_access(vp, mode, u.u_cred);
676 	}
677 	vput(vp);
678 out1:
679 	u.u_uid = svuid;
680 	u.u_gid = svgid;
681 	RETURN (error);
682 }
683 
684 /*
685  * Stat system call.  This version follows links.
686  */
687 stat()
688 {
689 
690 	stat1(FOLLOW);
691 }
692 
693 /*
694  * Lstat system call.  This version does not follow links.
695  */
696 lstat()
697 {
698 
699 	stat1(NOFOLLOW);
700 }
701 
702 stat1(follow)
703 	int follow;
704 {
705 	register struct a {
706 		char	*fname;
707 		struct stat *ub;
708 	} *uap = (struct a *)u.u_ap;
709 	register struct nameidata *ndp = &u.u_nd;
710 	struct stat sb;
711 	int error;
712 
713 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
714 	ndp->ni_segflg = UIO_USERSPACE;
715 	ndp->ni_dirp = uap->fname;
716 	if (error = namei(ndp))
717 		RETURN (error);
718 	error = vn_stat(ndp->ni_vp, &sb);
719 	vput(ndp->ni_vp);
720 	if (error)
721 		RETURN (error);
722 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
723 	RETURN (error);
724 }
725 
726 /*
727  * Return target name of a symbolic link
728  */
729 readlink()
730 {
731 	register struct a {
732 		char	*name;
733 		char	*buf;
734 		int	count;
735 	} *uap = (struct a *)u.u_ap;
736 	register struct nameidata *ndp = &u.u_nd;
737 	register struct vnode *vp;
738 	struct iovec aiov;
739 	struct uio auio;
740 	int error;
741 
742 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
743 	ndp->ni_segflg = UIO_USERSPACE;
744 	ndp->ni_dirp = uap->name;
745 	if (error = namei(ndp))
746 		RETURN (error);
747 	vp = ndp->ni_vp;
748 	if (vp->v_type != VLNK) {
749 		error = EINVAL;
750 		goto out;
751 	}
752 	aiov.iov_base = uap->buf;
753 	aiov.iov_len = uap->count;
754 	auio.uio_iov = &aiov;
755 	auio.uio_iovcnt = 1;
756 	auio.uio_offset = 0;
757 	auio.uio_rw = UIO_READ;
758 	auio.uio_segflg = UIO_USERSPACE;
759 	auio.uio_resid = uap->count;
760 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
761 out:
762 	vput(vp);
763 	u.u_r.r_val1 = uap->count - auio.uio_resid;
764 	RETURN (error);
765 }
766 
767 /*
768  * Change flags of a file given path name.
769  */
770 chflags()
771 {
772 	struct a {
773 		char	*fname;
774 		int	flags;
775 	} *uap = (struct a *)u.u_ap;
776 	register struct nameidata *ndp = &u.u_nd;
777 	register struct vnode *vp;
778 	struct vattr vattr;
779 	int error;
780 
781 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
782 	ndp->ni_segflg = UIO_USERSPACE;
783 	ndp->ni_dirp = uap->fname;
784 	vattr_null(&vattr);
785 	vattr.va_flags = uap->flags;
786 	if (error = namei(ndp))
787 		RETURN (error);
788 	vp = ndp->ni_vp;
789 	if (vp->v_mount->m_flag & M_RDONLY) {
790 		error = EROFS;
791 		goto out;
792 	}
793 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
794 out:
795 	vput(vp);
796 	RETURN (error);
797 }
798 
799 /*
800  * Change flags of a file given a file descriptor.
801  */
802 fchflags()
803 {
804 	struct a {
805 		int	fd;
806 		int	flags;
807 	} *uap = (struct a *)u.u_ap;
808 	struct vattr vattr;
809 	struct vnode *vp;
810 	struct file *fp;
811 	int error;
812 
813 	if (error = getvnode(uap->fd, &fp))
814 		RETURN (error);
815 	vattr_null(&vattr);
816 	vattr.va_flags = uap->flags;
817 	vp = (struct vnode *)fp->f_data;
818 	VOP_LOCK(vp);
819 	if (vp->v_mount->m_flag & M_RDONLY) {
820 		error = EROFS;
821 		goto out;
822 	}
823 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
824 out:
825 	VOP_UNLOCK(vp);
826 	RETURN (error);
827 }
828 
829 /*
830  * Change mode of a file given path name.
831  */
832 chmod()
833 {
834 	struct a {
835 		char	*fname;
836 		int	fmode;
837 	} *uap = (struct a *)u.u_ap;
838 	register struct nameidata *ndp = &u.u_nd;
839 	register struct vnode *vp;
840 	struct vattr vattr;
841 	int error;
842 
843 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
844 	ndp->ni_segflg = UIO_USERSPACE;
845 	ndp->ni_dirp = uap->fname;
846 	vattr_null(&vattr);
847 	vattr.va_mode = uap->fmode & 07777;
848 	if (error = namei(ndp))
849 		RETURN (error);
850 	vp = ndp->ni_vp;
851 	if (vp->v_mount->m_flag & M_RDONLY) {
852 		error = EROFS;
853 		goto out;
854 	}
855 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
856 out:
857 	vput(vp);
858 	RETURN (error);
859 }
860 
861 /*
862  * Change mode of a file given a file descriptor.
863  */
864 fchmod()
865 {
866 	struct a {
867 		int	fd;
868 		int	fmode;
869 	} *uap = (struct a *)u.u_ap;
870 	struct vattr vattr;
871 	struct vnode *vp;
872 	struct file *fp;
873 	int error;
874 
875 	if (error = getvnode(uap->fd, &fp))
876 		RETURN (error);
877 	vattr_null(&vattr);
878 	vattr.va_mode = uap->fmode & 07777;
879 	vp = (struct vnode *)fp->f_data;
880 	VOP_LOCK(vp);
881 	if (vp->v_mount->m_flag & M_RDONLY) {
882 		error = EROFS;
883 		goto out;
884 	}
885 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
886 out:
887 	VOP_UNLOCK(vp);
888 	RETURN (error);
889 }
890 
891 /*
892  * Set ownership given a path name.
893  */
894 chown()
895 {
896 	struct a {
897 		char	*fname;
898 		int	uid;
899 		int	gid;
900 	} *uap = (struct a *)u.u_ap;
901 	register struct nameidata *ndp = &u.u_nd;
902 	register struct vnode *vp;
903 	struct vattr vattr;
904 	int error;
905 
906 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
907 	ndp->ni_segflg = UIO_USERSPACE;
908 	ndp->ni_dirp = uap->fname;
909 	vattr_null(&vattr);
910 	vattr.va_uid = uap->uid;
911 	vattr.va_gid = uap->gid;
912 	if (error = namei(ndp))
913 		RETURN (error);
914 	vp = ndp->ni_vp;
915 	if (vp->v_mount->m_flag & M_RDONLY) {
916 		error = EROFS;
917 		goto out;
918 	}
919 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
920 out:
921 	vput(vp);
922 	RETURN (error);
923 }
924 
925 /*
926  * Set ownership given a file descriptor.
927  */
928 fchown()
929 {
930 	struct a {
931 		int	fd;
932 		int	uid;
933 		int	gid;
934 	} *uap = (struct a *)u.u_ap;
935 	struct vattr vattr;
936 	struct vnode *vp;
937 	struct file *fp;
938 	int error;
939 
940 	if (error = getvnode(uap->fd, &fp))
941 		RETURN (error);
942 	vattr_null(&vattr);
943 	vattr.va_uid = uap->uid;
944 	vattr.va_gid = uap->gid;
945 	vp = (struct vnode *)fp->f_data;
946 	VOP_LOCK(vp);
947 	if (vp->v_mount->m_flag & M_RDONLY) {
948 		error = EROFS;
949 		goto out;
950 	}
951 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
952 out:
953 	VOP_UNLOCK(vp);
954 	RETURN (error);
955 }
956 
957 utimes()
958 {
959 	register struct a {
960 		char	*fname;
961 		struct	timeval *tptr;
962 	} *uap = (struct a *)u.u_ap;
963 	register struct nameidata *ndp = &u.u_nd;
964 	register struct vnode *vp;
965 	struct timeval tv[2];
966 	struct vattr vattr;
967 	int error;
968 
969 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
970 		RETURN (error);
971 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
972 	ndp->ni_segflg = UIO_USERSPACE;
973 	ndp->ni_dirp = uap->fname;
974 	vattr_null(&vattr);
975 	vattr.va_atime = tv[0];
976 	vattr.va_mtime = tv[1];
977 	if (error = namei(ndp))
978 		RETURN (error);
979 	vp = ndp->ni_vp;
980 	if (vp->v_mount->m_flag & M_RDONLY) {
981 		error = EROFS;
982 		goto out;
983 	}
984 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
985 out:
986 	vput(vp);
987 	RETURN (error);
988 }
989 
990 /*
991  * Truncate a file given its path name.
992  */
993 truncate()
994 {
995 	struct a {
996 		char	*fname;
997 		off_t	length;
998 	} *uap = (struct a *)u.u_ap;
999 	register struct nameidata *ndp = &u.u_nd;
1000 	register struct vnode *vp;
1001 	struct vattr vattr;
1002 	int error;
1003 
1004 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1005 	ndp->ni_segflg = UIO_USERSPACE;
1006 	ndp->ni_dirp = uap->fname;
1007 	vattr_null(&vattr);
1008 	vattr.va_size = uap->length;
1009 	if (error = namei(ndp))
1010 		RETURN (error);
1011 	vp = ndp->ni_vp;
1012 	if (vp->v_type == VDIR) {
1013 		error = EISDIR;
1014 		goto out;
1015 	}
1016 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
1017 		goto out;
1018 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1019 out:
1020 	vput(vp);
1021 	RETURN (error);
1022 }
1023 
1024 /*
1025  * Truncate a file given a file descriptor.
1026  */
1027 ftruncate()
1028 {
1029 	struct a {
1030 		int	fd;
1031 		off_t	length;
1032 	} *uap = (struct a *)u.u_ap;
1033 	struct vattr vattr;
1034 	struct vnode *vp;
1035 	struct file *fp;
1036 	int error;
1037 
1038 	if (error = getvnode(uap->fd, &fp))
1039 		RETURN (error);
1040 	if ((fp->f_flag & FWRITE) == 0)
1041 		RETURN (EINVAL);
1042 	vattr_null(&vattr);
1043 	vattr.va_size = uap->length;
1044 	vp = (struct vnode *)fp->f_data;
1045 	VOP_LOCK(vp);
1046 	if (vp->v_type == VDIR) {
1047 		error = EISDIR;
1048 		goto out;
1049 	}
1050 	if (error = vn_access(vp, VWRITE, fp->f_cred))
1051 		goto out;
1052 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1053 out:
1054 	VOP_UNLOCK(vp);
1055 	RETURN (error);
1056 }
1057 
1058 /*
1059  * Synch an open file.
1060  */
1061 fsync()
1062 {
1063 	struct a {
1064 		int	fd;
1065 	} *uap = (struct a *)u.u_ap;
1066 	struct file *fp;
1067 	int error;
1068 
1069 	if (error = getvnode(uap->fd, &fp))
1070 		RETURN (error);
1071 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
1072 	RETURN (error);
1073 }
1074 
1075 /*
1076  * Rename system call.
1077  *
1078  * Source and destination must either both be directories, or both
1079  * not be directories.  If target is a directory, it must be empty.
1080  */
1081 rename()
1082 {
1083 	struct a {
1084 		char	*from;
1085 		char	*to;
1086 	} *uap = (struct a *)u.u_ap;
1087 	register struct vnode *tvp, *fvp, *tdvp;
1088 	register struct nameidata *ndp = &u.u_nd;
1089 	struct nameidata tond;
1090 	int error;
1091 
1092 	ndp->ni_nameiop = DELETE | WANTPARENT;
1093 	ndp->ni_segflg = UIO_USERSPACE;
1094 	ndp->ni_dirp = uap->from;
1095 	if (error = namei(ndp))
1096 		RETURN (error);
1097 	fvp = ndp->ni_vp;
1098 	nddup(ndp, &tond);
1099 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1100 	tond.ni_segflg = UIO_USERSPACE;
1101 	tond.ni_dirp = uap->to;
1102 	error = namei(&tond);
1103 	tdvp = tond.ni_dvp;
1104 	tvp = tond.ni_vp;
1105 	if (tvp != NULL) {
1106 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1107 			error = EISDIR;
1108 			goto out;
1109 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1110 			error = ENOTDIR;
1111 			goto out;
1112 		}
1113 	}
1114 	if (error) {
1115 		VOP_ABORTOP(ndp);
1116 		goto out1;
1117 	}
1118 	if (fvp->v_mount != tdvp->v_mount) {
1119 		error = EXDEV;
1120 		goto out;
1121 	}
1122 	if (fvp == tdvp || fvp == tvp)
1123 		error = EINVAL;
1124 out:
1125 	if (error) {
1126 		VOP_ABORTOP(&tond);
1127 		VOP_ABORTOP(ndp);
1128 	} else {
1129 		error = VOP_RENAME(ndp, &tond);
1130 	}
1131 out1:
1132 	ndrele(&tond);
1133 	RETURN (error);
1134 }
1135 
1136 /*
1137  * Mkdir system call
1138  */
1139 mkdir()
1140 {
1141 	struct a {
1142 		char	*name;
1143 		int	dmode;
1144 	} *uap = (struct a *)u.u_ap;
1145 	register struct nameidata *ndp = &u.u_nd;
1146 	register struct vnode *vp;
1147 	struct vattr vattr;
1148 	int error;
1149 
1150 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1151 	ndp->ni_segflg = UIO_USERSPACE;
1152 	ndp->ni_dirp = uap->name;
1153 	if (error = namei(ndp))
1154 		RETURN (error);
1155 	vp = ndp->ni_vp;
1156 	if (vp != NULL) {
1157 		VOP_ABORTOP(ndp);
1158 		RETURN (EEXIST);
1159 	}
1160 	vattr_null(&vattr);
1161 	vattr.va_type = VDIR;
1162 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
1163 	error = VOP_MKDIR(ndp, &vattr);
1164 	if (!error)
1165 		vput(ndp->ni_vp);
1166 	RETURN (error);
1167 }
1168 
1169 /*
1170  * Rmdir system call.
1171  */
1172 rmdir()
1173 {
1174 	struct a {
1175 		char	*name;
1176 	} *uap = (struct a *)u.u_ap;
1177 	register struct nameidata *ndp = &u.u_nd;
1178 	register struct vnode *vp;
1179 	int error;
1180 
1181 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1182 	ndp->ni_segflg = UIO_USERSPACE;
1183 	ndp->ni_dirp = uap->name;
1184 	if (error = namei(ndp))
1185 		RETURN (error);
1186 	vp = ndp->ni_vp;
1187 	if (vp->v_type != VDIR) {
1188 		error = ENOTDIR;
1189 		goto out;
1190 	}
1191 	/*
1192 	 * No rmdir "." please.
1193 	 */
1194 	if (ndp->ni_dvp == vp) {
1195 		error = EINVAL;
1196 		goto out;
1197 	}
1198 	/*
1199 	 * Don't unlink a mounted file.
1200 	 */
1201 	if (vp->v_flag & VROOT)
1202 		error = EBUSY;
1203 out:
1204 	if (error)
1205 		VOP_ABORTOP(ndp);
1206 	else
1207 		error = VOP_RMDIR(ndp);
1208 	RETURN (error);
1209 }
1210 
1211 /*
1212  * Read a block of directory entries in a file system independent format
1213  */
1214 getdirentries()
1215 {
1216 	register struct a {
1217 		int	fd;
1218 		char	*buf;
1219 		unsigned count;
1220 		long	*basep;
1221 	} *uap = (struct a *)u.u_ap;
1222 	struct file *fp;
1223 	struct uio auio;
1224 	struct iovec aiov;
1225 	off_t off;
1226 	int error;
1227 
1228 	if (error = getvnode(uap->fd, &fp))
1229 		RETURN (error);
1230 	if ((fp->f_flag & FREAD) == 0)
1231 		RETURN (EBADF);
1232 	aiov.iov_base = uap->buf;
1233 	aiov.iov_len = uap->count;
1234 	auio.uio_iov = &aiov;
1235 	auio.uio_iovcnt = 1;
1236 	auio.uio_rw = UIO_READ;
1237 	auio.uio_segflg = UIO_USERSPACE;
1238 	auio.uio_resid = uap->count;
1239 	off = fp->f_offset;
1240 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1241 	    &(fp->f_offset), fp->f_cred))
1242 		RETURN (error);
1243 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
1244 		sizeof(long));
1245 	u.u_r.r_val1 = uap->count - auio.uio_resid;
1246 	RETURN (error);
1247 }
1248 
1249 /*
1250  * mode mask for creation of files
1251  */
1252 umask()
1253 {
1254 	register struct a {
1255 		int	mask;
1256 	} *uap = (struct a *)u.u_ap;
1257 
1258 	u.u_r.r_val1 = u.u_cmask;
1259 	u.u_cmask = uap->mask & 07777;
1260 	RETURN (0);
1261 }
1262 
1263 getvnode(fdes, fpp)
1264 	struct file **fpp;
1265 	int fdes;
1266 {
1267 	struct file *fp;
1268 
1269 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
1270 		return (EBADF);
1271 	if (fp->f_type != DTYPE_VNODE)
1272 		return (EINVAL);
1273 	*fpp = fp;
1274 	return (0);
1275 }
1276