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