xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39499)
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.23 (Berkeley) 11/09/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 		crfree(fp->f_cred);
511 		fp->f_count--;
512 		if (error == -1)	/* XXX from fdopen */
513 			return (0);	/* XXX from fdopen */
514 		scp->sc_ofile[indx] = NULL;
515 		return (error);
516 	}
517 	fp->f_flag = fmode & FMASK;
518 	fp->f_type = DTYPE_VNODE;
519 	fp->f_ops = &vnops;
520 	fp->f_data = (caddr_t)ndp->ni_vp;
521 	if (resultfd)
522 		*resultfd = indx;
523 	return (0);
524 }
525 
526 /*
527  * Mknod system call
528  */
529 mknod(scp)
530 	register struct syscontext *scp;
531 {
532 	register struct a {
533 		char	*fname;
534 		int	fmode;
535 		int	dev;
536 	} *uap = (struct a *)scp->sc_ap;
537 	register struct nameidata *ndp = &scp->sc_nd;
538 	register struct vnode *vp;
539 	struct vattr vattr;
540 	int error;
541 
542 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
543 		RETURN (error);
544 	ndp->ni_nameiop = CREATE | LOCKPARENT;
545 	ndp->ni_segflg = UIO_USERSPACE;
546 	ndp->ni_dirp = uap->fname;
547 	if (error = namei(ndp))
548 		RETURN (error);
549 	vp = ndp->ni_vp;
550 	if (vp != NULL) {
551 		error = EEXIST;
552 		goto out;
553 	}
554 	vattr_null(&vattr);
555 	switch (uap->fmode & IFMT) {
556 
557 	case IFMT:	/* used by badsect to flag bad sectors */
558 		vattr.va_type = VBAD;
559 		break;
560 	case IFCHR:
561 		vattr.va_type = VCHR;
562 		break;
563 	case IFBLK:
564 		vattr.va_type = VBLK;
565 		break;
566 	default:
567 		error = EINVAL;
568 		goto out;
569 	}
570 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
571 	vattr.va_rdev = uap->dev;
572 out:
573 	if (error)
574 		VOP_ABORTOP(ndp);
575 	else
576 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
577 	RETURN (error);
578 }
579 
580 /*
581  * link system call
582  */
583 link(scp)
584 	register struct syscontext *scp;
585 {
586 	register struct a {
587 		char	*target;
588 		char	*linkname;
589 	} *uap = (struct a *)scp->sc_ap;
590 	register struct nameidata *ndp = &scp->sc_nd;
591 	register struct vnode *vp, *xp;
592 	int error;
593 
594 	ndp->ni_nameiop = LOOKUP | FOLLOW;
595 	ndp->ni_segflg = UIO_USERSPACE;
596 	ndp->ni_dirp = uap->target;
597 	if (error = namei(ndp))
598 		RETURN (error);
599 	vp = ndp->ni_vp;
600 	if (vp->v_type == VDIR &&
601 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
602 		goto out1;
603 	ndp->ni_nameiop = CREATE | LOCKPARENT;
604 	ndp->ni_dirp = (caddr_t)uap->linkname;
605 	if (error = namei(ndp))
606 		goto out1;
607 	xp = ndp->ni_vp;
608 	if (xp != NULL) {
609 		error = EEXIST;
610 		goto out;
611 	}
612 	xp = ndp->ni_dvp;
613 	if (vp->v_mount != xp->v_mount)
614 		error = EXDEV;
615 out:
616 	if (error)
617 		VOP_ABORTOP(ndp);
618 	else
619 		error = VOP_LINK(vp, ndp);
620 out1:
621 	vrele(vp);
622 	RETURN (error);
623 }
624 
625 /*
626  * symlink -- make a symbolic link
627  */
628 symlink(scp)
629 	register struct syscontext *scp;
630 {
631 	struct a {
632 		char	*target;
633 		char	*linkname;
634 	} *uap = (struct a *)scp->sc_ap;
635 	register struct nameidata *ndp = &scp->sc_nd;
636 	register struct vnode *vp;
637 	struct vattr vattr;
638 	char *target;
639 	int error;
640 
641 	ndp->ni_segflg = UIO_USERSPACE;
642 	ndp->ni_dirp = uap->linkname;
643 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
644 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
645 		goto out1;
646 	ndp->ni_nameiop = CREATE | LOCKPARENT;
647 	if (error = namei(ndp))
648 		goto out1;
649 	vp = ndp->ni_vp;
650 	if (vp) {
651 		error = EEXIST;
652 		goto out;
653 	}
654 	vp = ndp->ni_dvp;
655 	vattr_null(&vattr);
656 	vattr.va_mode = 0777 &~ scp->sc_cmask;
657 out:
658 	if (error)
659 		VOP_ABORTOP(ndp);
660 	else
661 		error = VOP_SYMLINK(ndp, &vattr, target);
662 out1:
663 	FREE(target, M_NAMEI);
664 	RETURN (error);
665 }
666 
667 /*
668  * Unlink system call.
669  * Hard to avoid races here, especially
670  * in unlinking directories.
671  */
672 unlink(scp)
673 	register struct syscontext *scp;
674 {
675 	struct a {
676 		char	*fname;
677 	} *uap = (struct a *)scp->sc_ap;
678 	register struct nameidata *ndp = &scp->sc_nd;
679 	register struct vnode *vp;
680 	int error;
681 
682 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
683 	ndp->ni_segflg = UIO_USERSPACE;
684 	ndp->ni_dirp = uap->fname;
685 	if (error = namei(ndp))
686 		RETURN (error);
687 	vp = ndp->ni_vp;
688 	if (vp->v_type == VDIR &&
689 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
690 		goto out;
691 	/*
692 	 * Don't unlink a mounted file.
693 	 */
694 	if (vp->v_flag & VROOT) {
695 		error = EBUSY;
696 		goto out;
697 	}
698 	if (vp->v_flag & VTEXT)
699 		xrele(vp);	/* try once to free text */
700 out:
701 	if (error)
702 		VOP_ABORTOP(ndp);
703 	else
704 		error = VOP_REMOVE(ndp);
705 	RETURN (error);
706 }
707 
708 /*
709  * Seek system call
710  */
711 lseek(scp)
712 	register struct syscontext *scp;
713 {
714 	register struct file *fp;
715 	register struct a {
716 		int	fdes;
717 		off_t	off;
718 		int	sbase;
719 	} *uap = (struct a *)scp->sc_ap;
720 	struct vattr vattr;
721 	int error;
722 
723 	if ((unsigned)uap->fdes >= NOFILE ||
724 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
725 		RETURN (EBADF);
726 	if (fp->f_type != DTYPE_VNODE)
727 		RETURN (ESPIPE);
728 	switch (uap->sbase) {
729 
730 	case L_INCR:
731 		fp->f_offset += uap->off;
732 		break;
733 
734 	case L_XTND:
735 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
736 		    &vattr, scp->sc_cred))
737 			RETURN (error);
738 		fp->f_offset = uap->off + vattr.va_size;
739 		break;
740 
741 	case L_SET:
742 		fp->f_offset = uap->off;
743 		break;
744 
745 	default:
746 		RETURN (EINVAL);
747 	}
748 	scp->sc_offset = fp->f_offset;
749 	RETURN (0);
750 }
751 
752 /*
753  * Access system call
754  */
755 saccess(scp)
756 	register struct syscontext *scp;
757 {
758 	register struct a {
759 		char	*fname;
760 		int	fmode;
761 	} *uap = (struct a *)scp->sc_ap;
762 	register struct nameidata *ndp = &scp->sc_nd;
763 	register struct vnode *vp;
764 	int error, mode, svuid, svgid;
765 
766 	svuid = scp->sc_uid;
767 	svgid = scp->sc_gid;
768 	scp->sc_uid = scp->sc_ruid;
769 	scp->sc_gid = scp->sc_rgid;
770 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
771 	ndp->ni_segflg = UIO_USERSPACE;
772 	ndp->ni_dirp = uap->fname;
773 	if (error = namei(ndp))
774 		goto out1;
775 	vp = ndp->ni_vp;
776 	/*
777 	 * fmode == 0 means only check for exist
778 	 */
779 	if (uap->fmode) {
780 		mode = 0;
781 		if (uap->fmode & R_OK)
782 			mode |= VREAD;
783 		if (uap->fmode & W_OK)
784 			mode |= VWRITE;
785 		if (uap->fmode & X_OK)
786 			mode |= VEXEC;
787 		if ((error = vn_writechk(vp)) == 0)
788 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
789 	}
790 	vput(vp);
791 out1:
792 	scp->sc_uid = svuid;
793 	scp->sc_gid = svgid;
794 	RETURN (error);
795 }
796 
797 /*
798  * Stat system call.  This version follows links.
799  */
800 stat(scp)
801 	struct syscontext *scp;
802 {
803 
804 	stat1(scp, FOLLOW);
805 }
806 
807 /*
808  * Lstat system call.  This version does not follow links.
809  */
810 lstat(scp)
811 	struct syscontext *scp;
812 {
813 
814 	stat1(scp, NOFOLLOW);
815 }
816 
817 stat1(scp, follow)
818 	register struct syscontext *scp;
819 	int follow;
820 {
821 	register struct a {
822 		char	*fname;
823 		struct stat *ub;
824 	} *uap = (struct a *)scp->sc_ap;
825 	register struct nameidata *ndp = &scp->sc_nd;
826 	struct stat sb;
827 	int error;
828 
829 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
830 	ndp->ni_segflg = UIO_USERSPACE;
831 	ndp->ni_dirp = uap->fname;
832 	if (error = namei(ndp))
833 		RETURN (error);
834 	error = vn_stat(ndp->ni_vp, &sb);
835 	vput(ndp->ni_vp);
836 	if (error)
837 		RETURN (error);
838 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
839 	RETURN (error);
840 }
841 
842 /*
843  * Return target name of a symbolic link
844  */
845 readlink(scp)
846 	register struct syscontext *scp;
847 {
848 	register struct a {
849 		char	*name;
850 		char	*buf;
851 		int	count;
852 	} *uap = (struct a *)scp->sc_ap;
853 	register struct nameidata *ndp = &scp->sc_nd;
854 	register struct vnode *vp;
855 	struct iovec aiov;
856 	struct uio auio;
857 	int error;
858 
859 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
860 	ndp->ni_segflg = UIO_USERSPACE;
861 	ndp->ni_dirp = uap->name;
862 	if (error = namei(ndp))
863 		RETURN (error);
864 	vp = ndp->ni_vp;
865 	if (vp->v_type != VLNK) {
866 		error = EINVAL;
867 		goto out;
868 	}
869 	aiov.iov_base = uap->buf;
870 	aiov.iov_len = uap->count;
871 	auio.uio_iov = &aiov;
872 	auio.uio_iovcnt = 1;
873 	auio.uio_offset = 0;
874 	auio.uio_rw = UIO_READ;
875 	auio.uio_segflg = UIO_USERSPACE;
876 	auio.uio_resid = uap->count;
877 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
878 out:
879 	vput(vp);
880 	scp->sc_retval1 = uap->count - auio.uio_resid;
881 	RETURN (error);
882 }
883 
884 /*
885  * Change flags of a file given path name.
886  */
887 chflags(scp)
888 	register struct syscontext *scp;
889 {
890 	struct a {
891 		char	*fname;
892 		int	flags;
893 	} *uap = (struct a *)scp->sc_ap;
894 	register struct nameidata *ndp = &scp->sc_nd;
895 	register struct vnode *vp;
896 	struct vattr vattr;
897 	int error;
898 
899 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
900 	ndp->ni_segflg = UIO_USERSPACE;
901 	ndp->ni_dirp = uap->fname;
902 	vattr_null(&vattr);
903 	vattr.va_flags = uap->flags;
904 	if (error = namei(ndp))
905 		RETURN (error);
906 	vp = ndp->ni_vp;
907 	if (vp->v_mount->m_flag & M_RDONLY) {
908 		error = EROFS;
909 		goto out;
910 	}
911 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
912 out:
913 	vput(vp);
914 	RETURN (error);
915 }
916 
917 /*
918  * Change flags of a file given a file descriptor.
919  */
920 fchflags(scp)
921 	register struct syscontext *scp;
922 {
923 	struct a {
924 		int	fd;
925 		int	flags;
926 	} *uap = (struct a *)scp->sc_ap;
927 	struct vattr vattr;
928 	struct vnode *vp;
929 	struct file *fp;
930 	int error;
931 
932 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
933 		RETURN (error);
934 	vattr_null(&vattr);
935 	vattr.va_flags = uap->flags;
936 	vp = (struct vnode *)fp->f_data;
937 	VOP_LOCK(vp);
938 	if (vp->v_mount->m_flag & M_RDONLY) {
939 		error = EROFS;
940 		goto out;
941 	}
942 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
943 out:
944 	VOP_UNLOCK(vp);
945 	RETURN (error);
946 }
947 
948 /*
949  * Change mode of a file given path name.
950  */
951 chmod(scp)
952 	register struct syscontext *scp;
953 {
954 	struct a {
955 		char	*fname;
956 		int	fmode;
957 	} *uap = (struct a *)scp->sc_ap;
958 	register struct nameidata *ndp = &scp->sc_nd;
959 	register struct vnode *vp;
960 	struct vattr vattr;
961 	int error;
962 
963 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
964 	ndp->ni_segflg = UIO_USERSPACE;
965 	ndp->ni_dirp = uap->fname;
966 	vattr_null(&vattr);
967 	vattr.va_mode = uap->fmode & 07777;
968 	if (error = namei(ndp))
969 		RETURN (error);
970 	vp = ndp->ni_vp;
971 	if (vp->v_mount->m_flag & M_RDONLY) {
972 		error = EROFS;
973 		goto out;
974 	}
975 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
976 out:
977 	vput(vp);
978 	RETURN (error);
979 }
980 
981 /*
982  * Change mode of a file given a file descriptor.
983  */
984 fchmod(scp)
985 	register struct syscontext *scp;
986 {
987 	struct a {
988 		int	fd;
989 		int	fmode;
990 	} *uap = (struct a *)scp->sc_ap;
991 	struct vattr vattr;
992 	struct vnode *vp;
993 	struct file *fp;
994 	int error;
995 
996 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
997 		RETURN (error);
998 	vattr_null(&vattr);
999 	vattr.va_mode = uap->fmode & 07777;
1000 	vp = (struct vnode *)fp->f_data;
1001 	VOP_LOCK(vp);
1002 	if (vp->v_mount->m_flag & M_RDONLY) {
1003 		error = EROFS;
1004 		goto out;
1005 	}
1006 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1007 out:
1008 	VOP_UNLOCK(vp);
1009 	RETURN (error);
1010 }
1011 
1012 /*
1013  * Set ownership given a path name.
1014  */
1015 chown(scp)
1016 	register struct syscontext *scp;
1017 {
1018 	struct a {
1019 		char	*fname;
1020 		int	uid;
1021 		int	gid;
1022 	} *uap = (struct a *)scp->sc_ap;
1023 	register struct nameidata *ndp = &scp->sc_nd;
1024 	register struct vnode *vp;
1025 	struct vattr vattr;
1026 	int error;
1027 
1028 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
1029 	ndp->ni_segflg = UIO_USERSPACE;
1030 	ndp->ni_dirp = uap->fname;
1031 	vattr_null(&vattr);
1032 	vattr.va_uid = uap->uid;
1033 	vattr.va_gid = uap->gid;
1034 	if (error = namei(ndp))
1035 		RETURN (error);
1036 	vp = ndp->ni_vp;
1037 	if (vp->v_mount->m_flag & M_RDONLY) {
1038 		error = EROFS;
1039 		goto out;
1040 	}
1041 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1042 out:
1043 	vput(vp);
1044 	RETURN (error);
1045 }
1046 
1047 /*
1048  * Set ownership given a file descriptor.
1049  */
1050 fchown(scp)
1051 	register struct syscontext *scp;
1052 {
1053 	struct a {
1054 		int	fd;
1055 		int	uid;
1056 		int	gid;
1057 	} *uap = (struct a *)scp->sc_ap;
1058 	struct vattr vattr;
1059 	struct vnode *vp;
1060 	struct file *fp;
1061 	int error;
1062 
1063 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1064 		RETURN (error);
1065 	vattr_null(&vattr);
1066 	vattr.va_uid = uap->uid;
1067 	vattr.va_gid = uap->gid;
1068 	vp = (struct vnode *)fp->f_data;
1069 	VOP_LOCK(vp);
1070 	if (vp->v_mount->m_flag & M_RDONLY) {
1071 		error = EROFS;
1072 		goto out;
1073 	}
1074 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1075 out:
1076 	VOP_UNLOCK(vp);
1077 	RETURN (error);
1078 }
1079 
1080 utimes(scp)
1081 	register struct syscontext *scp;
1082 {
1083 	register struct a {
1084 		char	*fname;
1085 		struct	timeval *tptr;
1086 	} *uap = (struct a *)scp->sc_ap;
1087 	register struct nameidata *ndp = &scp->sc_nd;
1088 	register struct vnode *vp;
1089 	struct timeval tv[2];
1090 	struct vattr vattr;
1091 	int error;
1092 
1093 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1094 		RETURN (error);
1095 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1096 	ndp->ni_segflg = UIO_USERSPACE;
1097 	ndp->ni_dirp = uap->fname;
1098 	vattr_null(&vattr);
1099 	vattr.va_atime = tv[0];
1100 	vattr.va_mtime = tv[1];
1101 	if (error = namei(ndp))
1102 		RETURN (error);
1103 	vp = ndp->ni_vp;
1104 	if (vp->v_mount->m_flag & M_RDONLY) {
1105 		error = EROFS;
1106 		goto out;
1107 	}
1108 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1109 out:
1110 	vput(vp);
1111 	RETURN (error);
1112 }
1113 
1114 /*
1115  * Truncate a file given its path name.
1116  */
1117 truncate(scp)
1118 	register struct syscontext *scp;
1119 {
1120 	struct a {
1121 		char	*fname;
1122 		off_t	length;
1123 	} *uap = (struct a *)scp->sc_ap;
1124 	register struct nameidata *ndp = &scp->sc_nd;
1125 	register struct vnode *vp;
1126 	struct vattr vattr;
1127 	int error;
1128 
1129 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1130 	ndp->ni_segflg = UIO_USERSPACE;
1131 	ndp->ni_dirp = uap->fname;
1132 	vattr_null(&vattr);
1133 	vattr.va_size = uap->length;
1134 	if (error = namei(ndp))
1135 		RETURN (error);
1136 	vp = ndp->ni_vp;
1137 	if (vp->v_type == VDIR) {
1138 		error = EISDIR;
1139 		goto out;
1140 	}
1141 	if ((error = vn_writechk(vp)) ||
1142 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
1143 		goto out;
1144 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1145 out:
1146 	vput(vp);
1147 	RETURN (error);
1148 }
1149 
1150 /*
1151  * Truncate a file given a file descriptor.
1152  */
1153 ftruncate(scp)
1154 	register struct syscontext *scp;
1155 {
1156 	struct a {
1157 		int	fd;
1158 		off_t	length;
1159 	} *uap = (struct a *)scp->sc_ap;
1160 	struct vattr vattr;
1161 	struct vnode *vp;
1162 	struct file *fp;
1163 	int error;
1164 
1165 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1166 		RETURN (error);
1167 	if ((fp->f_flag & FWRITE) == 0)
1168 		RETURN (EINVAL);
1169 	vattr_null(&vattr);
1170 	vattr.va_size = uap->length;
1171 	vp = (struct vnode *)fp->f_data;
1172 	VOP_LOCK(vp);
1173 	if (vp->v_type == VDIR) {
1174 		error = EISDIR;
1175 		goto out;
1176 	}
1177 	if (error = vn_writechk(vp))
1178 		goto out;
1179 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1180 out:
1181 	VOP_UNLOCK(vp);
1182 	RETURN (error);
1183 }
1184 
1185 /*
1186  * Synch an open file.
1187  */
1188 fsync(scp)
1189 	register struct syscontext *scp;
1190 {
1191 	struct a {
1192 		int	fd;
1193 	} *uap = (struct a *)scp->sc_ap;
1194 	struct file *fp;
1195 	int error;
1196 
1197 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1198 		RETURN (error);
1199 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
1200 	RETURN (error);
1201 }
1202 
1203 /*
1204  * Rename system call.
1205  *
1206  * Source and destination must either both be directories, or both
1207  * not be directories.  If target is a directory, it must be empty.
1208  */
1209 rename(scp)
1210 	register struct syscontext *scp;
1211 {
1212 	struct a {
1213 		char	*from;
1214 		char	*to;
1215 	} *uap = (struct a *)scp->sc_ap;
1216 	register struct vnode *tvp, *fvp, *tdvp;
1217 	register struct nameidata *ndp = &scp->sc_nd;
1218 	struct nameidata tond;
1219 	int error;
1220 
1221 	ndp->ni_nameiop = DELETE | WANTPARENT;
1222 	ndp->ni_segflg = UIO_USERSPACE;
1223 	ndp->ni_dirp = uap->from;
1224 	if (error = namei(ndp))
1225 		RETURN (error);
1226 	fvp = ndp->ni_vp;
1227 	nddup(ndp, &tond);
1228 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1229 	tond.ni_segflg = UIO_USERSPACE;
1230 	tond.ni_dirp = uap->to;
1231 	error = namei(&tond);
1232 	tdvp = tond.ni_dvp;
1233 	tvp = tond.ni_vp;
1234 	if (tvp != NULL) {
1235 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1236 			error = ENOTDIR;
1237 			goto out;
1238 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1239 			error = EISDIR;
1240 			goto out;
1241 		}
1242 	}
1243 	if (error) {
1244 		VOP_ABORTOP(ndp);
1245 		goto out1;
1246 	}
1247 	if (fvp->v_mount != tdvp->v_mount) {
1248 		error = EXDEV;
1249 		goto out;
1250 	}
1251 	if (fvp == tdvp)
1252 		error = EINVAL;
1253 	/*
1254 	 * If source is the same as the destination,
1255 	 * then there is nothing to do.
1256 	 */
1257 	if (fvp == tvp)
1258 		error = -1;
1259 out:
1260 	if (error) {
1261 		VOP_ABORTOP(&tond);
1262 		VOP_ABORTOP(ndp);
1263 	} else {
1264 		error = VOP_RENAME(ndp, &tond);
1265 	}
1266 out1:
1267 	ndrele(&tond);
1268 	if (error == -1)
1269 		RETURN (0);
1270 	RETURN (error);
1271 }
1272 
1273 /*
1274  * Mkdir system call
1275  */
1276 mkdir(scp)
1277 	register struct syscontext *scp;
1278 {
1279 	struct a {
1280 		char	*name;
1281 		int	dmode;
1282 	} *uap = (struct a *)scp->sc_ap;
1283 	register struct nameidata *ndp = &scp->sc_nd;
1284 	register struct vnode *vp;
1285 	struct vattr vattr;
1286 	int error;
1287 
1288 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1289 	ndp->ni_segflg = UIO_USERSPACE;
1290 	ndp->ni_dirp = uap->name;
1291 	if (error = namei(ndp))
1292 		RETURN (error);
1293 	vp = ndp->ni_vp;
1294 	if (vp != NULL) {
1295 		VOP_ABORTOP(ndp);
1296 		RETURN (EEXIST);
1297 	}
1298 	vattr_null(&vattr);
1299 	vattr.va_type = VDIR;
1300 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
1301 	error = VOP_MKDIR(ndp, &vattr);
1302 	if (!error)
1303 		vput(ndp->ni_vp);
1304 	RETURN (error);
1305 }
1306 
1307 /*
1308  * Rmdir system call.
1309  */
1310 rmdir(scp)
1311 	register struct syscontext *scp;
1312 {
1313 	struct a {
1314 		char	*name;
1315 	} *uap = (struct a *)scp->sc_ap;
1316 	register struct nameidata *ndp = &scp->sc_nd;
1317 	register struct vnode *vp;
1318 	int error;
1319 
1320 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1321 	ndp->ni_segflg = UIO_USERSPACE;
1322 	ndp->ni_dirp = uap->name;
1323 	if (error = namei(ndp))
1324 		RETURN (error);
1325 	vp = ndp->ni_vp;
1326 	if (vp->v_type != VDIR) {
1327 		error = ENOTDIR;
1328 		goto out;
1329 	}
1330 	/*
1331 	 * No rmdir "." please.
1332 	 */
1333 	if (ndp->ni_dvp == vp) {
1334 		error = EINVAL;
1335 		goto out;
1336 	}
1337 	/*
1338 	 * Don't unlink a mounted file.
1339 	 */
1340 	if (vp->v_flag & VROOT)
1341 		error = EBUSY;
1342 out:
1343 	if (error)
1344 		VOP_ABORTOP(ndp);
1345 	else
1346 		error = VOP_RMDIR(ndp);
1347 	RETURN (error);
1348 }
1349 
1350 /*
1351  * Read a block of directory entries in a file system independent format
1352  */
1353 getdirentries(scp)
1354 	register struct syscontext *scp;
1355 {
1356 	register struct a {
1357 		int	fd;
1358 		char	*buf;
1359 		unsigned count;
1360 		long	*basep;
1361 	} *uap = (struct a *)scp->sc_ap;
1362 	struct file *fp;
1363 	struct uio auio;
1364 	struct iovec aiov;
1365 	off_t off;
1366 	int error;
1367 
1368 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1369 		RETURN (error);
1370 	if ((fp->f_flag & FREAD) == 0)
1371 		RETURN (EBADF);
1372 	aiov.iov_base = uap->buf;
1373 	aiov.iov_len = uap->count;
1374 	auio.uio_iov = &aiov;
1375 	auio.uio_iovcnt = 1;
1376 	auio.uio_rw = UIO_READ;
1377 	auio.uio_segflg = UIO_USERSPACE;
1378 	auio.uio_resid = uap->count;
1379 	off = fp->f_offset;
1380 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1381 	    &(fp->f_offset), fp->f_cred))
1382 		RETURN (error);
1383 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
1384 		sizeof(long));
1385 	scp->sc_retval1 = uap->count - auio.uio_resid;
1386 	RETURN (error);
1387 }
1388 
1389 /*
1390  * mode mask for creation of files
1391  */
1392 umask(scp)
1393 	register struct syscontext *scp;
1394 {
1395 	register struct a {
1396 		int	mask;
1397 	} *uap = (struct a *)scp->sc_ap;
1398 
1399 	scp->sc_retval1 = scp->sc_cmask;
1400 	scp->sc_cmask = uap->mask & 07777;
1401 	RETURN (0);
1402 }
1403 
1404 getvnode(ofile, fdes, fpp)
1405 	struct file *ofile[];
1406 	struct file **fpp;
1407 	int fdes;
1408 {
1409 	struct file *fp;
1410 
1411 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
1412 		return (EBADF);
1413 	if (fp->f_type != DTYPE_VNODE)
1414 		return (EINVAL);
1415 	*fpp = fp;
1416 	return (0);
1417 }
1418