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