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