xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39356)
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.19 (Berkeley) 10/20/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(scp)
41 	register struct syscontext *scp;
42 {
43 	register struct a {
44 		int	type;
45 		char	*dir;
46 		int	flags;
47 		caddr_t	data;
48 	} *uap = (struct a *)scp->sc_ap;
49 	register struct nameidata *ndp = &scp->sc_nd;
50 	register struct vnode *vp;
51 	register struct mount *mp;
52 	int error;
53 
54 	/*
55 	 * Must be super user
56 	 */
57 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
58 		RETURN (error);
59 	/*
60 	 * Get vnode to be covered
61 	 */
62 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
63 	ndp->ni_segflg = UIO_USERSPACE;
64 	ndp->ni_dirp = uap->dir;
65 	if (error = namei(ndp))
66 		RETURN (error);
67 	vp = ndp->ni_vp;
68 	if (uap->flags & M_UPDATE) {
69 		if ((vp->v_flag & VROOT) == 0) {
70 			vput(vp);
71 			RETURN (EINVAL);
72 		}
73 		mp = vp->v_mount;
74 		/*
75 		 * We allow going from read-only to read-write,
76 		 * but not from read-write to read-only.
77 		 */
78 		if ((mp->m_flag & M_RDONLY) == 0 &&
79 		    (uap->flags & M_RDONLY) != 0) {
80 			vput(vp);
81 			RETURN (EOPNOTSUPP);	/* Needs translation */
82 		}
83 		mp->m_flag |= M_UPDATE;
84 		VOP_UNLOCK(vp);
85 		goto update;
86 	}
87 	if (vp->v_count != 1) {
88 		vput(vp);
89 		RETURN (EBUSY);
90 	}
91 	if (vp->v_type != VDIR) {
92 		vput(vp);
93 		RETURN (ENOTDIR);
94 	}
95 	if (uap->type > MOUNT_MAXTYPE ||
96 	    vfssw[uap->type] == (struct vfsops *)0) {
97 		vput(vp);
98 		RETURN (ENODEV);
99 	}
100 
101 	/*
102 	 * Allocate and initialize the file system.
103 	 */
104 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
105 		M_MOUNT, M_WAITOK);
106 	mp->m_op = vfssw[uap->type];
107 	mp->m_flag = 0;
108 	mp->m_exroot = 0;
109 	if (error = vfs_lock(mp)) {
110 		free((caddr_t)mp, M_MOUNT);
111 		vput(vp);
112 		RETURN (error);
113 	}
114 	if (vp->v_mountedhere != (struct mount *)0) {
115 		vfs_unlock(mp);
116 		free((caddr_t)mp, M_MOUNT);
117 		vput(vp);
118 		RETURN (EBUSY);
119 	}
120 	/*
121 	 * Put the new filesystem on the mount list after root.
122 	 */
123 	mp->m_next = rootfs->m_next;
124 	mp->m_prev = rootfs;
125 	rootfs->m_next = mp;
126 	mp->m_next->m_prev = mp;
127 	vp->v_mountedhere = mp;
128 	mp->m_vnodecovered = vp;
129 update:
130 	/*
131 	 * Set the mount level flags.
132 	 */
133 	if (uap->flags & M_RDONLY)
134 		mp->m_flag |= M_RDONLY;
135 	else
136 		mp->m_flag &= ~M_RDONLY;
137 	if (uap->flags & M_NOSUID)
138 		mp->m_flag |= M_NOSUID;
139 	else
140 		mp->m_flag &= ~M_NOSUID;
141 	if (uap->flags & M_NOEXEC)
142 		mp->m_flag |= M_NOEXEC;
143 	else
144 		mp->m_flag &= ~M_NOEXEC;
145 	if (uap->flags & M_NODEV)
146 		mp->m_flag |= M_NODEV;
147 	else
148 		mp->m_flag &= ~M_NODEV;
149 	if (uap->flags & M_SYNCHRONOUS)
150 		mp->m_flag |= M_SYNCHRONOUS;
151 	else
152 		mp->m_flag &= ~M_SYNCHRONOUS;
153 	/*
154 	 * Mount the filesystem.
155 	 */
156 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
157 	if (mp->m_flag & M_UPDATE) {
158 		mp->m_flag &= ~M_UPDATE;
159 		vrele(vp);
160 		RETURN (error);
161 	}
162 	cache_purge(vp);
163 	if (!error) {
164 		VOP_UNLOCK(vp);
165 		vfs_unlock(mp);
166 		error = VFS_START(mp, 0);
167 	} else {
168 		vfs_remove(mp);
169 		free((caddr_t)mp, M_MOUNT);
170 		vput(vp);
171 	}
172 	RETURN (error);
173 }
174 
175 /*
176  * Unmount system call.
177  *
178  * Note: unmount takes a path to the vnode mounted on as argument,
179  * not special file (as before).
180  */
181 unmount(scp)
182 	register struct syscontext *scp;
183 {
184 	struct a {
185 		char	*pathp;
186 		int	flags;
187 	} *uap = (struct a *)scp->sc_ap;
188 	register struct vnode *vp;
189 	register struct nameidata *ndp = &scp->sc_nd;
190 	struct mount *mp;
191 	int error;
192 
193 	/*
194 	 * Must be super user
195 	 */
196 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
197 		RETURN (error);
198 
199 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
200 	ndp->ni_segflg = UIO_USERSPACE;
201 	ndp->ni_dirp = uap->pathp;
202 	if (error = namei(ndp))
203 		RETURN (error);
204 	vp = ndp->ni_vp;
205 	/*
206 	 * Must be the root of the filesystem
207 	 */
208 	if ((vp->v_flag & VROOT) == 0) {
209 		vput(vp);
210 		RETURN (EINVAL);
211 	}
212 	mp = vp->v_mount;
213 	vput(vp);
214 	RETURN (dounmount(mp, uap->flags));
215 }
216 
217 /*
218  * Do an unmount.
219  */
220 dounmount(mp, flags)
221 	register struct mount *mp;
222 	int flags;
223 {
224 	struct vnode *coveredvp;
225 	int error;
226 
227 	coveredvp = mp->m_vnodecovered;
228 	if (error = vfs_lock(mp))
229 		return (error);
230 
231 	xumount(mp);		/* remove unused sticky files from text table */
232 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
233 	VFS_SYNC(mp, MNT_WAIT);
234 
235 	error = VFS_UNMOUNT(mp, flags);
236 	if (error) {
237 		vfs_unlock(mp);
238 	} else {
239 		vrele(coveredvp);
240 		vfs_remove(mp);
241 		free((caddr_t)mp, M_MOUNT);
242 	}
243 	return (error);
244 }
245 
246 /*
247  * Sync system call.
248  * Sync each mounted filesystem.
249  */
250 sync(scp)
251 	register struct syscontext *scp;
252 {
253 	register struct mount *mp;
254 
255 	mp = rootfs;
256 	do {
257 		if ((mp->m_flag & M_RDONLY) == 0)
258 			VFS_SYNC(mp, MNT_NOWAIT);
259 		mp = mp->m_next;
260 	} while (mp != rootfs);
261 }
262 
263 /*
264  * get filesystem statistics
265  */
266 statfs(scp)
267 	register struct syscontext *scp;
268 {
269 	struct a {
270 		char *path;
271 		struct statfs *buf;
272 	} *uap = (struct a *)scp->sc_ap;
273 	register struct vnode *vp;
274 	register struct nameidata *ndp = &scp->sc_nd;
275 	struct statfs sb;
276 	int error;
277 
278 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
279 	ndp->ni_segflg = UIO_USERSPACE;
280 	ndp->ni_dirp = uap->path;
281 	if (error = namei(ndp))
282 		RETURN (error);
283 	vp = ndp->ni_vp;
284 	if (error = VFS_STATFS(vp->v_mount, &sb))
285 		goto out;
286 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
287 out:
288 	vput(vp);
289 	RETURN (error);
290 }
291 
292 fstatfs(scp)
293 	register struct syscontext *scp;
294 {
295 	struct a {
296 		int fd;
297 		struct statfs *buf;
298 	} *uap = (struct a *)scp->sc_ap;
299 	struct file *fp;
300 	struct statfs sb;
301 	int error;
302 
303 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
304 		RETURN (error);
305 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
306 		RETURN (error);
307 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
308 }
309 
310 /*
311  * get statistics on all filesystems
312  */
313 getfsstat(scp)
314 	register struct syscontext *scp;
315 {
316 	struct a {
317 		struct statfs *buf;
318 		long bufsize;
319 	} *uap = (struct a *)scp->sc_ap;
320 	register struct mount *mp;
321 	register struct statfs *sfsp;
322 	long count, maxcount, error;
323 
324 	maxcount = uap->bufsize / sizeof(struct statfs);
325 	sfsp = uap->buf;
326 	mp = rootfs;
327 	count = 0;
328 	do {
329 		count++;
330 		if (sfsp && count <= maxcount &&
331 		    ((mp->m_flag & M_MLOCK) == 0)) {
332 			if (error = VFS_STATFS(mp, sfsp))
333 				RETURN (error);
334 			sfsp++;
335 		}
336 		mp = mp->m_prev;
337 	} while (mp != rootfs);
338 	if (sfsp && count > maxcount)
339 		scp->sc_retval1 = maxcount;
340 	else
341 		scp->sc_retval1 = count;
342 	RETURN (0);
343 }
344 
345 /*
346  * Change current working directory to a given file descriptor.
347  */
348 fchdir(scp)
349 	register struct syscontext *scp;
350 {
351 	struct a {
352 		int	fd;
353 	} *uap = (struct a *)scp->sc_ap;
354 	register struct vnode *vp;
355 	struct file *fp;
356 	int error;
357 
358 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
359 		RETURN (error);
360 	vp = (struct vnode *)fp->f_data;
361 	VOP_LOCK(vp);
362 	if (vp->v_type != VDIR)
363 		error = ENOTDIR;
364 	else
365 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
366 	VOP_UNLOCK(vp);
367 	vrele(scp->sc_cdir);
368 	scp->sc_cdir = vp;
369 	RETURN (error);
370 }
371 
372 /*
373  * Change current working directory (``.'').
374  */
375 chdir(scp)
376 	register struct syscontext *scp;
377 {
378 	struct a {
379 		char	*fname;
380 	} *uap = (struct a *)scp->sc_ap;
381 	register struct nameidata *ndp = &scp->sc_nd;
382 	int error;
383 
384 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
385 	ndp->ni_segflg = UIO_USERSPACE;
386 	ndp->ni_dirp = uap->fname;
387 	if (error = chdirec(ndp))
388 		RETURN (error);
389 	vrele(scp->sc_cdir);
390 	scp->sc_cdir = ndp->ni_vp;
391 	RETURN (0);
392 }
393 
394 /*
395  * Change notion of root (``/'') directory.
396  */
397 chroot(scp)
398 	register struct syscontext *scp;
399 {
400 	struct a {
401 		char	*fname;
402 	} *uap = (struct a *)scp->sc_ap;
403 	register struct nameidata *ndp = &scp->sc_nd;
404 	int error;
405 
406 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
407 		RETURN (error);
408 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
409 	ndp->ni_segflg = UIO_USERSPACE;
410 	ndp->ni_dirp = uap->fname;
411 	if (error = chdirec(ndp))
412 		RETURN (error);
413 	vrele(scp->sc_rdir);
414 	scp->sc_rdir = ndp->ni_vp;
415 	RETURN (0);
416 }
417 
418 /*
419  * Common routine for chroot and chdir.
420  */
421 chdirec(ndp)
422 	register struct nameidata *ndp;
423 {
424 	struct vnode *vp;
425 	int error;
426 
427 	if (error = namei(ndp))
428 		return (error);
429 	vp = ndp->ni_vp;
430 	if (vp->v_type != VDIR)
431 		error = ENOTDIR;
432 	else
433 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
434 	VOP_UNLOCK(vp);
435 	if (error)
436 		vrele(vp);
437 	return (error);
438 }
439 
440 /*
441  * Open system call.
442  */
443 open(scp)
444 	register struct syscontext *scp;
445 {
446 	struct a {
447 		char	*fname;
448 		int	mode;
449 		int	crtmode;
450 	} *uap = (struct a *) scp->sc_ap;
451 	struct nameidata *ndp = &scp->sc_nd;
452 
453 	ndp->ni_segflg = UIO_USERSPACE;
454 	ndp->ni_dirp = uap->fname;
455 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
456 		&scp->sc_retval1));
457 }
458 
459 /*
460  * Creat system call.
461  */
462 creat(scp)
463 	register struct syscontext *scp;
464 {
465 	struct a {
466 		char	*fname;
467 		int	fmode;
468 	} *uap = (struct a *)scp->sc_ap;
469 	struct nameidata *ndp = &scp->sc_nd;
470 
471 	ndp->ni_segflg = UIO_USERSPACE;
472 	ndp->ni_dirp = uap->fname;
473 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
474 		ndp, &scp->sc_retval1));
475 }
476 
477 /*
478  * Common code for open and creat.
479  * Check permissions, allocate an open file structure,
480  * and call the device open routine if any.
481  */
482 copen(scp, fmode, cmode, ndp, resultfd)
483 	register struct syscontext *scp;
484 	int fmode, cmode;
485 	struct nameidata *ndp;
486 	int *resultfd;
487 {
488 	register struct file *fp;
489 	struct file *nfp;
490 	int indx, error;
491 	extern struct fileops vnops;
492 
493 	if (error = falloc(&nfp, &indx))
494 		return (error);
495 	fp = nfp;
496 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
497 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
498 		scp->sc_ofile[indx] = NULL;
499 		crfree(fp->f_cred);
500 		fp->f_count--;
501 		return (error);
502 	}
503 	fp->f_flag = fmode & FMASK;
504 	fp->f_type = DTYPE_VNODE;
505 	fp->f_ops = &vnops;
506 	fp->f_data = (caddr_t)ndp->ni_vp;
507 	if (resultfd)
508 		*resultfd = indx;
509 	return (0);
510 }
511 
512 /*
513  * Mknod system call
514  */
515 mknod(scp)
516 	register struct syscontext *scp;
517 {
518 	register struct a {
519 		char	*fname;
520 		int	fmode;
521 		int	dev;
522 	} *uap = (struct a *)scp->sc_ap;
523 	register struct nameidata *ndp = &scp->sc_nd;
524 	register struct vnode *vp;
525 	struct vattr vattr;
526 	int error;
527 
528 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
529 		RETURN (error);
530 	ndp->ni_nameiop = CREATE | LOCKPARENT;
531 	ndp->ni_segflg = UIO_USERSPACE;
532 	ndp->ni_dirp = uap->fname;
533 	if (error = namei(ndp))
534 		RETURN (error);
535 	vp = ndp->ni_vp;
536 	if (vp != NULL) {
537 		error = EEXIST;
538 		goto out;
539 	}
540 	vattr_null(&vattr);
541 	switch (uap->fmode & IFMT) {
542 
543 	case IFMT:	/* used by badsect to flag bad sectors */
544 		vattr.va_type = VBAD;
545 		break;
546 	case IFCHR:
547 		vattr.va_type = VCHR;
548 		break;
549 	case IFBLK:
550 		vattr.va_type = VBLK;
551 		break;
552 	default:
553 		error = EINVAL;
554 		goto out;
555 	}
556 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
557 	vattr.va_rdev = uap->dev;
558 out:
559 	if (error)
560 		VOP_ABORTOP(ndp);
561 	else
562 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
563 	RETURN (error);
564 }
565 
566 /*
567  * link system call
568  */
569 link(scp)
570 	register struct syscontext *scp;
571 {
572 	register struct a {
573 		char	*target;
574 		char	*linkname;
575 	} *uap = (struct a *)scp->sc_ap;
576 	register struct nameidata *ndp = &scp->sc_nd;
577 	register struct vnode *vp, *xp;
578 	int error;
579 
580 	ndp->ni_nameiop = LOOKUP | FOLLOW;
581 	ndp->ni_segflg = UIO_USERSPACE;
582 	ndp->ni_dirp = uap->target;
583 	if (error = namei(ndp))
584 		RETURN (error);
585 	vp = ndp->ni_vp;
586 	if (vp->v_type == VDIR &&
587 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
588 		goto out1;
589 	ndp->ni_nameiop = CREATE | LOCKPARENT;
590 	ndp->ni_dirp = (caddr_t)uap->linkname;
591 	if (error = namei(ndp))
592 		goto out1;
593 	xp = ndp->ni_vp;
594 	if (xp != NULL) {
595 		error = EEXIST;
596 		goto out;
597 	}
598 	xp = ndp->ni_dvp;
599 	if (vp->v_mount != xp->v_mount)
600 		error = EXDEV;
601 out:
602 	if (error)
603 		VOP_ABORTOP(ndp);
604 	else
605 		error = VOP_LINK(vp, ndp);
606 out1:
607 	vrele(vp);
608 	RETURN (error);
609 }
610 
611 /*
612  * symlink -- make a symbolic link
613  */
614 symlink(scp)
615 	register struct syscontext *scp;
616 {
617 	struct a {
618 		char	*target;
619 		char	*linkname;
620 	} *uap = (struct a *)scp->sc_ap;
621 	register struct nameidata *ndp = &scp->sc_nd;
622 	register struct vnode *vp;
623 	struct vattr vattr;
624 	char *target;
625 	int error;
626 
627 	ndp->ni_segflg = UIO_USERSPACE;
628 	ndp->ni_dirp = uap->linkname;
629 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
630 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
631 		goto out1;
632 	ndp->ni_nameiop = CREATE | LOCKPARENT;
633 	if (error = namei(ndp))
634 		goto out1;
635 	vp = ndp->ni_vp;
636 	if (vp) {
637 		error = EEXIST;
638 		goto out;
639 	}
640 	vp = ndp->ni_dvp;
641 	vattr_null(&vattr);
642 	vattr.va_mode = 0777 &~ scp->sc_cmask;
643 out:
644 	if (error)
645 		VOP_ABORTOP(ndp);
646 	else
647 		error = VOP_SYMLINK(ndp, &vattr, target);
648 out1:
649 	FREE(target, M_NAMEI);
650 	RETURN (error);
651 }
652 
653 /*
654  * Unlink system call.
655  * Hard to avoid races here, especially
656  * in unlinking directories.
657  */
658 unlink(scp)
659 	register struct syscontext *scp;
660 {
661 	struct a {
662 		char	*fname;
663 	} *uap = (struct a *)scp->sc_ap;
664 	register struct nameidata *ndp = &scp->sc_nd;
665 	register struct vnode *vp;
666 	int error;
667 
668 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
669 	ndp->ni_segflg = UIO_USERSPACE;
670 	ndp->ni_dirp = uap->fname;
671 	if (error = namei(ndp))
672 		RETURN (error);
673 	vp = ndp->ni_vp;
674 	if (vp->v_type == VDIR &&
675 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
676 		goto out;
677 	/*
678 	 * Don't unlink a mounted file.
679 	 */
680 	if (vp->v_flag & VROOT) {
681 		error = EBUSY;
682 		goto out;
683 	}
684 	if (vp->v_flag & VTEXT)
685 		xrele(vp);	/* try once to free text */
686 out:
687 	if (error)
688 		VOP_ABORTOP(ndp);
689 	else
690 		error = VOP_REMOVE(ndp);
691 	RETURN (error);
692 }
693 
694 /*
695  * Seek system call
696  */
697 lseek(scp)
698 	register struct syscontext *scp;
699 {
700 	register struct file *fp;
701 	register struct a {
702 		int	fdes;
703 		off_t	off;
704 		int	sbase;
705 	} *uap = (struct a *)scp->sc_ap;
706 	struct vattr vattr;
707 	int error;
708 
709 	if ((unsigned)uap->fdes >= NOFILE ||
710 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
711 		RETURN (EBADF);
712 	if (fp->f_type != DTYPE_VNODE)
713 		RETURN (ESPIPE);
714 	switch (uap->sbase) {
715 
716 	case L_INCR:
717 		fp->f_offset += uap->off;
718 		break;
719 
720 	case L_XTND:
721 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
722 		    &vattr, scp->sc_cred))
723 			RETURN (error);
724 		fp->f_offset = uap->off + vattr.va_size;
725 		break;
726 
727 	case L_SET:
728 		fp->f_offset = uap->off;
729 		break;
730 
731 	default:
732 		RETURN (EINVAL);
733 	}
734 	scp->sc_offset = fp->f_offset;
735 	RETURN (0);
736 }
737 
738 /*
739  * Access system call
740  */
741 saccess(scp)
742 	register struct syscontext *scp;
743 {
744 	register struct a {
745 		char	*fname;
746 		int	fmode;
747 	} *uap = (struct a *)scp->sc_ap;
748 	register struct nameidata *ndp = &scp->sc_nd;
749 	register struct vnode *vp;
750 	int error, mode, svuid, svgid;
751 
752 	svuid = scp->sc_uid;
753 	svgid = scp->sc_gid;
754 	scp->sc_uid = scp->sc_ruid;
755 	scp->sc_gid = scp->sc_rgid;
756 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
757 	ndp->ni_segflg = UIO_USERSPACE;
758 	ndp->ni_dirp = uap->fname;
759 	if (error = namei(ndp))
760 		goto out1;
761 	vp = ndp->ni_vp;
762 	/*
763 	 * fmode == 0 means only check for exist
764 	 */
765 	if (uap->fmode) {
766 		mode = 0;
767 		if (uap->fmode & R_OK)
768 			mode |= VREAD;
769 		if (uap->fmode & W_OK)
770 			mode |= VWRITE;
771 		if (uap->fmode & X_OK)
772 			mode |= VEXEC;
773 		if ((error = vn_writechk(vp)) == 0)
774 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
775 	}
776 	vput(vp);
777 out1:
778 	scp->sc_uid = svuid;
779 	scp->sc_gid = svgid;
780 	RETURN (error);
781 }
782 
783 /*
784  * Stat system call.  This version follows links.
785  */
786 stat(scp)
787 	struct syscontext *scp;
788 {
789 
790 	stat1(scp, FOLLOW);
791 }
792 
793 /*
794  * Lstat system call.  This version does not follow links.
795  */
796 lstat(scp)
797 	struct syscontext *scp;
798 {
799 
800 	stat1(scp, NOFOLLOW);
801 }
802 
803 stat1(scp, follow)
804 	register struct syscontext *scp;
805 	int follow;
806 {
807 	register struct a {
808 		char	*fname;
809 		struct stat *ub;
810 	} *uap = (struct a *)scp->sc_ap;
811 	register struct nameidata *ndp = &scp->sc_nd;
812 	struct stat sb;
813 	int error;
814 
815 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
816 	ndp->ni_segflg = UIO_USERSPACE;
817 	ndp->ni_dirp = uap->fname;
818 	if (error = namei(ndp))
819 		RETURN (error);
820 	error = vn_stat(ndp->ni_vp, &sb);
821 	vput(ndp->ni_vp);
822 	if (error)
823 		RETURN (error);
824 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
825 	RETURN (error);
826 }
827 
828 /*
829  * Return target name of a symbolic link
830  */
831 readlink(scp)
832 	register struct syscontext *scp;
833 {
834 	register struct a {
835 		char	*name;
836 		char	*buf;
837 		int	count;
838 	} *uap = (struct a *)scp->sc_ap;
839 	register struct nameidata *ndp = &scp->sc_nd;
840 	register struct vnode *vp;
841 	struct iovec aiov;
842 	struct uio auio;
843 	int error;
844 
845 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
846 	ndp->ni_segflg = UIO_USERSPACE;
847 	ndp->ni_dirp = uap->name;
848 	if (error = namei(ndp))
849 		RETURN (error);
850 	vp = ndp->ni_vp;
851 	if (vp->v_type != VLNK) {
852 		error = EINVAL;
853 		goto out;
854 	}
855 	aiov.iov_base = uap->buf;
856 	aiov.iov_len = uap->count;
857 	auio.uio_iov = &aiov;
858 	auio.uio_iovcnt = 1;
859 	auio.uio_offset = 0;
860 	auio.uio_rw = UIO_READ;
861 	auio.uio_segflg = UIO_USERSPACE;
862 	auio.uio_resid = uap->count;
863 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
864 out:
865 	vput(vp);
866 	scp->sc_retval1 = uap->count - auio.uio_resid;
867 	RETURN (error);
868 }
869 
870 /*
871  * Change flags of a file given path name.
872  */
873 chflags(scp)
874 	register struct syscontext *scp;
875 {
876 	struct a {
877 		char	*fname;
878 		int	flags;
879 	} *uap = (struct a *)scp->sc_ap;
880 	register struct nameidata *ndp = &scp->sc_nd;
881 	register struct vnode *vp;
882 	struct vattr vattr;
883 	int error;
884 
885 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
886 	ndp->ni_segflg = UIO_USERSPACE;
887 	ndp->ni_dirp = uap->fname;
888 	vattr_null(&vattr);
889 	vattr.va_flags = uap->flags;
890 	if (error = namei(ndp))
891 		RETURN (error);
892 	vp = ndp->ni_vp;
893 	if (vp->v_mount->m_flag & M_RDONLY) {
894 		error = EROFS;
895 		goto out;
896 	}
897 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
898 out:
899 	vput(vp);
900 	RETURN (error);
901 }
902 
903 /*
904  * Change flags of a file given a file descriptor.
905  */
906 fchflags(scp)
907 	register struct syscontext *scp;
908 {
909 	struct a {
910 		int	fd;
911 		int	flags;
912 	} *uap = (struct a *)scp->sc_ap;
913 	struct vattr vattr;
914 	struct vnode *vp;
915 	struct file *fp;
916 	int error;
917 
918 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
919 		RETURN (error);
920 	vattr_null(&vattr);
921 	vattr.va_flags = uap->flags;
922 	vp = (struct vnode *)fp->f_data;
923 	VOP_LOCK(vp);
924 	if (vp->v_mount->m_flag & M_RDONLY) {
925 		error = EROFS;
926 		goto out;
927 	}
928 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
929 out:
930 	VOP_UNLOCK(vp);
931 	RETURN (error);
932 }
933 
934 /*
935  * Change mode of a file given path name.
936  */
937 chmod(scp)
938 	register struct syscontext *scp;
939 {
940 	struct a {
941 		char	*fname;
942 		int	fmode;
943 	} *uap = (struct a *)scp->sc_ap;
944 	register struct nameidata *ndp = &scp->sc_nd;
945 	register struct vnode *vp;
946 	struct vattr vattr;
947 	int error;
948 
949 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
950 	ndp->ni_segflg = UIO_USERSPACE;
951 	ndp->ni_dirp = uap->fname;
952 	vattr_null(&vattr);
953 	vattr.va_mode = uap->fmode & 07777;
954 	if (error = namei(ndp))
955 		RETURN (error);
956 	vp = ndp->ni_vp;
957 	if (vp->v_mount->m_flag & M_RDONLY) {
958 		error = EROFS;
959 		goto out;
960 	}
961 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
962 out:
963 	vput(vp);
964 	RETURN (error);
965 }
966 
967 /*
968  * Change mode of a file given a file descriptor.
969  */
970 fchmod(scp)
971 	register struct syscontext *scp;
972 {
973 	struct a {
974 		int	fd;
975 		int	fmode;
976 	} *uap = (struct a *)scp->sc_ap;
977 	struct vattr vattr;
978 	struct vnode *vp;
979 	struct file *fp;
980 	int error;
981 
982 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
983 		RETURN (error);
984 	vattr_null(&vattr);
985 	vattr.va_mode = uap->fmode & 07777;
986 	vp = (struct vnode *)fp->f_data;
987 	VOP_LOCK(vp);
988 	if (vp->v_mount->m_flag & M_RDONLY) {
989 		error = EROFS;
990 		goto out;
991 	}
992 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
993 out:
994 	VOP_UNLOCK(vp);
995 	RETURN (error);
996 }
997 
998 /*
999  * Set ownership given a path name.
1000  */
1001 chown(scp)
1002 	register struct syscontext *scp;
1003 {
1004 	struct a {
1005 		char	*fname;
1006 		int	uid;
1007 		int	gid;
1008 	} *uap = (struct a *)scp->sc_ap;
1009 	register struct nameidata *ndp = &scp->sc_nd;
1010 	register struct vnode *vp;
1011 	struct vattr vattr;
1012 	int error;
1013 
1014 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
1015 	ndp->ni_segflg = UIO_USERSPACE;
1016 	ndp->ni_dirp = uap->fname;
1017 	vattr_null(&vattr);
1018 	vattr.va_uid = uap->uid;
1019 	vattr.va_gid = uap->gid;
1020 	if (error = namei(ndp))
1021 		RETURN (error);
1022 	vp = ndp->ni_vp;
1023 	if (vp->v_mount->m_flag & M_RDONLY) {
1024 		error = EROFS;
1025 		goto out;
1026 	}
1027 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1028 out:
1029 	vput(vp);
1030 	RETURN (error);
1031 }
1032 
1033 /*
1034  * Set ownership given a file descriptor.
1035  */
1036 fchown(scp)
1037 	register struct syscontext *scp;
1038 {
1039 	struct a {
1040 		int	fd;
1041 		int	uid;
1042 		int	gid;
1043 	} *uap = (struct a *)scp->sc_ap;
1044 	struct vattr vattr;
1045 	struct vnode *vp;
1046 	struct file *fp;
1047 	int error;
1048 
1049 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1050 		RETURN (error);
1051 	vattr_null(&vattr);
1052 	vattr.va_uid = uap->uid;
1053 	vattr.va_gid = uap->gid;
1054 	vp = (struct vnode *)fp->f_data;
1055 	VOP_LOCK(vp);
1056 	if (vp->v_mount->m_flag & M_RDONLY) {
1057 		error = EROFS;
1058 		goto out;
1059 	}
1060 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1061 out:
1062 	VOP_UNLOCK(vp);
1063 	RETURN (error);
1064 }
1065 
1066 utimes(scp)
1067 	register struct syscontext *scp;
1068 {
1069 	register struct a {
1070 		char	*fname;
1071 		struct	timeval *tptr;
1072 	} *uap = (struct a *)scp->sc_ap;
1073 	register struct nameidata *ndp = &scp->sc_nd;
1074 	register struct vnode *vp;
1075 	struct timeval tv[2];
1076 	struct vattr vattr;
1077 	int error;
1078 
1079 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1080 		RETURN (error);
1081 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1082 	ndp->ni_segflg = UIO_USERSPACE;
1083 	ndp->ni_dirp = uap->fname;
1084 	vattr_null(&vattr);
1085 	vattr.va_atime = tv[0];
1086 	vattr.va_mtime = tv[1];
1087 	if (error = namei(ndp))
1088 		RETURN (error);
1089 	vp = ndp->ni_vp;
1090 	if (vp->v_mount->m_flag & M_RDONLY) {
1091 		error = EROFS;
1092 		goto out;
1093 	}
1094 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1095 out:
1096 	vput(vp);
1097 	RETURN (error);
1098 }
1099 
1100 /*
1101  * Truncate a file given its path name.
1102  */
1103 truncate(scp)
1104 	register struct syscontext *scp;
1105 {
1106 	struct a {
1107 		char	*fname;
1108 		off_t	length;
1109 	} *uap = (struct a *)scp->sc_ap;
1110 	register struct nameidata *ndp = &scp->sc_nd;
1111 	register struct vnode *vp;
1112 	struct vattr vattr;
1113 	int error;
1114 
1115 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1116 	ndp->ni_segflg = UIO_USERSPACE;
1117 	ndp->ni_dirp = uap->fname;
1118 	vattr_null(&vattr);
1119 	vattr.va_size = uap->length;
1120 	if (error = namei(ndp))
1121 		RETURN (error);
1122 	vp = ndp->ni_vp;
1123 	if (vp->v_type == VDIR) {
1124 		error = EISDIR;
1125 		goto out;
1126 	}
1127 	if ((error = vn_writechk(vp)) ||
1128 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
1129 		goto out;
1130 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1131 out:
1132 	vput(vp);
1133 	RETURN (error);
1134 }
1135 
1136 /*
1137  * Truncate a file given a file descriptor.
1138  */
1139 ftruncate(scp)
1140 	register struct syscontext *scp;
1141 {
1142 	struct a {
1143 		int	fd;
1144 		off_t	length;
1145 	} *uap = (struct a *)scp->sc_ap;
1146 	struct vattr vattr;
1147 	struct vnode *vp;
1148 	struct file *fp;
1149 	int error;
1150 
1151 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1152 		RETURN (error);
1153 	if ((fp->f_flag & FWRITE) == 0)
1154 		RETURN (EINVAL);
1155 	vattr_null(&vattr);
1156 	vattr.va_size = uap->length;
1157 	vp = (struct vnode *)fp->f_data;
1158 	VOP_LOCK(vp);
1159 	if (vp->v_type == VDIR) {
1160 		error = EISDIR;
1161 		goto out;
1162 	}
1163 	if (error = vn_writechk(vp))
1164 		goto out;
1165 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1166 out:
1167 	VOP_UNLOCK(vp);
1168 	RETURN (error);
1169 }
1170 
1171 /*
1172  * Synch an open file.
1173  */
1174 fsync(scp)
1175 	register struct syscontext *scp;
1176 {
1177 	struct a {
1178 		int	fd;
1179 	} *uap = (struct a *)scp->sc_ap;
1180 	struct file *fp;
1181 	int error;
1182 
1183 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1184 		RETURN (error);
1185 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
1186 	RETURN (error);
1187 }
1188 
1189 /*
1190  * Rename system call.
1191  *
1192  * Source and destination must either both be directories, or both
1193  * not be directories.  If target is a directory, it must be empty.
1194  */
1195 rename(scp)
1196 	register struct syscontext *scp;
1197 {
1198 	struct a {
1199 		char	*from;
1200 		char	*to;
1201 	} *uap = (struct a *)scp->sc_ap;
1202 	register struct vnode *tvp, *fvp, *tdvp;
1203 	register struct nameidata *ndp = &scp->sc_nd;
1204 	struct nameidata tond;
1205 	int error;
1206 
1207 	ndp->ni_nameiop = DELETE | WANTPARENT;
1208 	ndp->ni_segflg = UIO_USERSPACE;
1209 	ndp->ni_dirp = uap->from;
1210 	if (error = namei(ndp))
1211 		RETURN (error);
1212 	fvp = ndp->ni_vp;
1213 	nddup(ndp, &tond);
1214 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1215 	tond.ni_segflg = UIO_USERSPACE;
1216 	tond.ni_dirp = uap->to;
1217 	error = namei(&tond);
1218 	tdvp = tond.ni_dvp;
1219 	tvp = tond.ni_vp;
1220 	if (tvp != NULL) {
1221 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1222 			error = ENOTDIR;
1223 			goto out;
1224 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1225 			error = EISDIR;
1226 			goto out;
1227 		}
1228 	}
1229 	if (error) {
1230 		VOP_ABORTOP(ndp);
1231 		goto out1;
1232 	}
1233 	if (fvp->v_mount != tdvp->v_mount) {
1234 		error = EXDEV;
1235 		goto out;
1236 	}
1237 	if (fvp == tdvp)
1238 		error = EINVAL;
1239 	/*
1240 	 * If source is the same as the destination,
1241 	 * then there is nothing to do.
1242 	 */
1243 	if (fvp == tvp)
1244 		error = -1;
1245 out:
1246 	if (error) {
1247 		VOP_ABORTOP(&tond);
1248 		VOP_ABORTOP(ndp);
1249 	} else {
1250 		error = VOP_RENAME(ndp, &tond);
1251 	}
1252 out1:
1253 	ndrele(&tond);
1254 	if (error == -1)
1255 		RETURN (0);
1256 	RETURN (error);
1257 }
1258 
1259 /*
1260  * Mkdir system call
1261  */
1262 mkdir(scp)
1263 	register struct syscontext *scp;
1264 {
1265 	struct a {
1266 		char	*name;
1267 		int	dmode;
1268 	} *uap = (struct a *)scp->sc_ap;
1269 	register struct nameidata *ndp = &scp->sc_nd;
1270 	register struct vnode *vp;
1271 	struct vattr vattr;
1272 	int error;
1273 
1274 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1275 	ndp->ni_segflg = UIO_USERSPACE;
1276 	ndp->ni_dirp = uap->name;
1277 	if (error = namei(ndp))
1278 		RETURN (error);
1279 	vp = ndp->ni_vp;
1280 	if (vp != NULL) {
1281 		VOP_ABORTOP(ndp);
1282 		RETURN (EEXIST);
1283 	}
1284 	vattr_null(&vattr);
1285 	vattr.va_type = VDIR;
1286 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
1287 	error = VOP_MKDIR(ndp, &vattr);
1288 	if (!error)
1289 		vput(ndp->ni_vp);
1290 	RETURN (error);
1291 }
1292 
1293 /*
1294  * Rmdir system call.
1295  */
1296 rmdir(scp)
1297 	register struct syscontext *scp;
1298 {
1299 	struct a {
1300 		char	*name;
1301 	} *uap = (struct a *)scp->sc_ap;
1302 	register struct nameidata *ndp = &scp->sc_nd;
1303 	register struct vnode *vp;
1304 	int error;
1305 
1306 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1307 	ndp->ni_segflg = UIO_USERSPACE;
1308 	ndp->ni_dirp = uap->name;
1309 	if (error = namei(ndp))
1310 		RETURN (error);
1311 	vp = ndp->ni_vp;
1312 	if (vp->v_type != VDIR) {
1313 		error = ENOTDIR;
1314 		goto out;
1315 	}
1316 	/*
1317 	 * No rmdir "." please.
1318 	 */
1319 	if (ndp->ni_dvp == vp) {
1320 		error = EINVAL;
1321 		goto out;
1322 	}
1323 	/*
1324 	 * Don't unlink a mounted file.
1325 	 */
1326 	if (vp->v_flag & VROOT)
1327 		error = EBUSY;
1328 out:
1329 	if (error)
1330 		VOP_ABORTOP(ndp);
1331 	else
1332 		error = VOP_RMDIR(ndp);
1333 	RETURN (error);
1334 }
1335 
1336 /*
1337  * Read a block of directory entries in a file system independent format
1338  */
1339 getdirentries(scp)
1340 	register struct syscontext *scp;
1341 {
1342 	register struct a {
1343 		int	fd;
1344 		char	*buf;
1345 		unsigned count;
1346 		long	*basep;
1347 	} *uap = (struct a *)scp->sc_ap;
1348 	struct file *fp;
1349 	struct uio auio;
1350 	struct iovec aiov;
1351 	off_t off;
1352 	int error;
1353 
1354 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1355 		RETURN (error);
1356 	if ((fp->f_flag & FREAD) == 0)
1357 		RETURN (EBADF);
1358 	aiov.iov_base = uap->buf;
1359 	aiov.iov_len = uap->count;
1360 	auio.uio_iov = &aiov;
1361 	auio.uio_iovcnt = 1;
1362 	auio.uio_rw = UIO_READ;
1363 	auio.uio_segflg = UIO_USERSPACE;
1364 	auio.uio_resid = uap->count;
1365 	off = fp->f_offset;
1366 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1367 	    &(fp->f_offset), fp->f_cred))
1368 		RETURN (error);
1369 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
1370 		sizeof(long));
1371 	scp->sc_retval1 = uap->count - auio.uio_resid;
1372 	RETURN (error);
1373 }
1374 
1375 /*
1376  * mode mask for creation of files
1377  */
1378 umask(scp)
1379 	register struct syscontext *scp;
1380 {
1381 	register struct a {
1382 		int	mask;
1383 	} *uap = (struct a *)scp->sc_ap;
1384 
1385 	scp->sc_retval1 = scp->sc_cmask;
1386 	scp->sc_cmask = uap->mask & 07777;
1387 	RETURN (0);
1388 }
1389 
1390 getvnode(ofile, fdes, fpp)
1391 	struct file *ofile[];
1392 	struct file **fpp;
1393 	int fdes;
1394 {
1395 	struct file *fp;
1396 
1397 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
1398 		return (EBADF);
1399 	if (fp->f_type != DTYPE_VNODE)
1400 		return (EINVAL);
1401 	*fpp = fp;
1402 	return (0);
1403 }
1404