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