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