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