1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * %sccs.include.redist.c%
11 *
12 * @(#)vfs_syscalls.c 8.41 (Berkeley) 06/15/95
13 */
14
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/namei.h>
18 #include <sys/filedesc.h>
19 #include <sys/kernel.h>
20 #include <sys/file.h>
21 #include <sys/stat.h>
22 #include <sys/vnode.h>
23 #include <sys/mount.h>
24 #include <sys/proc.h>
25 #include <sys/uio.h>
26 #include <sys/malloc.h>
27 #include <sys/dirent.h>
28
29 #include <sys/syscallargs.h>
30
31 #include <vm/vm.h>
32 #include <sys/sysctl.h>
33
34 static int change_dir __P((struct nameidata *ndp, struct proc *p));
35 static void checkdirs __P((struct vnode *olddp));
36
37 /*
38 * Virtual File System System Calls
39 */
40
41 /*
42 * Mount a file system.
43 */
44 /* ARGSUSED */
45 int
mount(p,uap,retval)46 mount(p, uap, retval)
47 struct proc *p;
48 register struct mount_args /* {
49 syscallarg(char *) type;
50 syscallarg(char *) path;
51 syscallarg(int) flags;
52 syscallarg(caddr_t) data;
53 } */ *uap;
54 register_t *retval;
55 {
56 struct vnode *vp;
57 struct mount *mp;
58 struct vfsconf *vfsp;
59 int error, flag;
60 struct vattr va;
61 u_long fstypenum;
62 struct nameidata nd;
63 char fstypename[MFSNAMELEN];
64
65 /*
66 * Get vnode to be covered
67 */
68 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
69 SCARG(uap, path), p);
70 if (error = namei(&nd))
71 return (error);
72 vp = nd.ni_vp;
73 if (SCARG(uap, flags) & MNT_UPDATE) {
74 if ((vp->v_flag & VROOT) == 0) {
75 vput(vp);
76 return (EINVAL);
77 }
78 mp = vp->v_mount;
79 flag = mp->mnt_flag;
80 /*
81 * We only allow the filesystem to be reloaded if it
82 * is currently mounted read-only.
83 */
84 if ((SCARG(uap, flags) & MNT_RELOAD) &&
85 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
86 vput(vp);
87 return (EOPNOTSUPP); /* Needs translation */
88 }
89 mp->mnt_flag |=
90 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
91 /*
92 * Only root, or the user that did the original mount is
93 * permitted to update it.
94 */
95 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
96 (error = suser(p->p_ucred, &p->p_acflag))) {
97 vput(vp);
98 return (error);
99 }
100 /*
101 * Do not allow NFS export by non-root users. Silently
102 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
103 */
104 if (p->p_ucred->cr_uid != 0) {
105 if (SCARG(uap, flags) & MNT_EXPORTED) {
106 vput(vp);
107 return (EPERM);
108 }
109 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
110 }
111 if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
112 vput(vp);
113 return (EBUSY);
114 }
115 VOP_UNLOCK(vp, 0, p);
116 goto update;
117 }
118 /*
119 * If the user is not root, ensure that they own the directory
120 * onto which we are attempting to mount.
121 */
122 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
123 (va.va_uid != p->p_ucred->cr_uid &&
124 (error = suser(p->p_ucred, &p->p_acflag)))) {
125 vput(vp);
126 return (error);
127 }
128 /*
129 * Do not allow NFS export by non-root users. Silently
130 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
131 */
132 if (p->p_ucred->cr_uid != 0) {
133 if (SCARG(uap, flags) & MNT_EXPORTED) {
134 vput(vp);
135 return (EPERM);
136 }
137 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
138 }
139 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
140 return (error);
141 if (vp->v_type != VDIR) {
142 vput(vp);
143 return (ENOTDIR);
144 }
145 #ifdef COMPAT_43
146 /*
147 * Historically filesystem types were identified by number. If we
148 * get an integer for the filesystem type instead of a string, we
149 * check to see if it matches one of the historic filesystem types.
150 */
151 fstypenum = (u_long)SCARG(uap, type);
152 if (fstypenum < maxvfsconf) {
153 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
154 if (vfsp->vfc_typenum == fstypenum)
155 break;
156 if (vfsp == NULL) {
157 vput(vp);
158 return (ENODEV);
159 }
160 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
161 } else
162 #endif /* COMPAT_43 */
163 if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
164 vput(vp);
165 return (error);
166 }
167 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
168 if (!strcmp(vfsp->vfc_name, fstypename))
169 break;
170 if (vfsp == NULL) {
171 vput(vp);
172 return (ENODEV);
173 }
174 if (vp->v_mountedhere != NULL) {
175 vput(vp);
176 return (EBUSY);
177 }
178
179 /*
180 * Allocate and initialize the filesystem.
181 */
182 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
183 M_MOUNT, M_WAITOK);
184 bzero((char *)mp, (u_long)sizeof(struct mount));
185 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
186 (void)vfs_busy(mp, LK_NOWAIT, 0, p);
187 mp->mnt_op = vfsp->vfc_vfsops;
188 mp->mnt_vfc = vfsp;
189 vfsp->vfc_refcount++;
190 mp->mnt_stat.f_type = vfsp->vfc_typenum;
191 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
192 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
193 vp->v_mountedhere = mp;
194 mp->mnt_vnodecovered = vp;
195 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
196 update:
197 /*
198 * Set the mount level flags.
199 */
200 if (SCARG(uap, flags) & MNT_RDONLY)
201 mp->mnt_flag |= MNT_RDONLY;
202 else if (mp->mnt_flag & MNT_RDONLY)
203 mp->mnt_flag |= MNT_WANTRDWR;
204 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
205 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
206 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
207 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
208 /*
209 * Mount the filesystem.
210 */
211 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
212 if (mp->mnt_flag & MNT_UPDATE) {
213 vrele(vp);
214 if (mp->mnt_flag & MNT_WANTRDWR)
215 mp->mnt_flag &= ~MNT_RDONLY;
216 mp->mnt_flag &=~
217 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
218 if (error)
219 mp->mnt_flag = flag;
220 vfs_unbusy(mp, p);
221 return (error);
222 }
223 /*
224 * Put the new filesystem on the mount list after root.
225 */
226 cache_purge(vp);
227 if (!error) {
228 simple_lock(&mountlist_slock);
229 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
230 simple_unlock(&mountlist_slock);
231 checkdirs(vp);
232 VOP_UNLOCK(vp, 0, p);
233 vfs_unbusy(mp, p);
234 if (error = VFS_START(mp, 0, p))
235 vrele(vp);
236 } else {
237 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
238 mp->mnt_vfc->vfc_refcount--;
239 vfs_unbusy(mp, p);
240 free((caddr_t)mp, M_MOUNT);
241 vput(vp);
242 }
243 return (error);
244 }
245
246 /*
247 * Scan all active processes to see if any of them have a current
248 * or root directory onto which the new filesystem has just been
249 * mounted. If so, replace them with the new mount point.
250 */
251 static void
checkdirs(olddp)252 checkdirs(olddp)
253 struct vnode *olddp;
254 {
255 struct filedesc *fdp;
256 struct vnode *newdp;
257 struct proc *p;
258
259 if (olddp->v_usecount == 1)
260 return;
261 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
262 panic("mount: lost mount");
263 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
264 fdp = p->p_fd;
265 if (fdp->fd_cdir == olddp) {
266 vrele(fdp->fd_cdir);
267 VREF(newdp);
268 fdp->fd_cdir = newdp;
269 }
270 if (fdp->fd_rdir == olddp) {
271 vrele(fdp->fd_rdir);
272 VREF(newdp);
273 fdp->fd_rdir = newdp;
274 }
275 }
276 if (rootvnode == olddp) {
277 vrele(rootvnode);
278 VREF(newdp);
279 rootvnode = newdp;
280 }
281 vput(newdp);
282 }
283
284 /*
285 * Unmount a file system.
286 *
287 * Note: unmount takes a path to the vnode mounted on as argument,
288 * not special file (as before).
289 */
290 /* ARGSUSED */
291 int
unmount(p,uap,retval)292 unmount(p, uap, retval)
293 struct proc *p;
294 register struct unmount_args /* {
295 syscallarg(char *) path;
296 syscallarg(int) flags;
297 } */ *uap;
298 register_t *retval;
299 {
300 register struct vnode *vp;
301 struct mount *mp;
302 int error;
303 struct nameidata nd;
304
305 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
306 SCARG(uap, path), p);
307 if (error = namei(&nd))
308 return (error);
309 vp = nd.ni_vp;
310 mp = vp->v_mount;
311
312 /*
313 * Only root, or the user that did the original mount is
314 * permitted to unmount this filesystem.
315 */
316 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
317 (error = suser(p->p_ucred, &p->p_acflag))) {
318 vput(vp);
319 return (error);
320 }
321
322 /*
323 * Don't allow unmounting the root file system.
324 */
325 if (mp->mnt_flag & MNT_ROOTFS) {
326 vput(vp);
327 return (EINVAL);
328 }
329
330 /*
331 * Must be the root of the filesystem
332 */
333 if ((vp->v_flag & VROOT) == 0) {
334 vput(vp);
335 return (EINVAL);
336 }
337 vput(vp);
338 return (dounmount(mp, SCARG(uap, flags), p));
339 }
340
341 /*
342 * Do the actual file system unmount.
343 */
344 int
dounmount(mp,flags,p)345 dounmount(mp, flags, p)
346 register struct mount *mp;
347 int flags;
348 struct proc *p;
349 {
350 struct vnode *coveredvp;
351 int error;
352
353 simple_lock(&mountlist_slock);
354 mp->mnt_flag |= MNT_UNMOUNT;
355 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
356 mp->mnt_flag &=~ MNT_ASYNC;
357 vnode_pager_umount(mp); /* release cached vnodes */
358 cache_purgevfs(mp); /* remove cache entries for this file sys */
359 if (((mp->mnt_flag & MNT_RDONLY) ||
360 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
361 (flags & MNT_FORCE))
362 error = VFS_UNMOUNT(mp, flags, p);
363 simple_lock(&mountlist_slock);
364 if (error) {
365 mp->mnt_flag &= ~MNT_UNMOUNT;
366 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
367 &mountlist_slock, p);
368 return (error);
369 }
370 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
371 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
372 coveredvp->v_mountedhere = (struct mount *)0;
373 vrele(coveredvp);
374 }
375 mp->mnt_vfc->vfc_refcount--;
376 if (mp->mnt_vnodelist.lh_first != NULL)
377 panic("unmount: dangling vnode");
378 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
379 if (mp->mnt_flag & MNT_MWAIT)
380 wakeup((caddr_t)mp);
381 free((caddr_t)mp, M_MOUNT);
382 return (0);
383 }
384
385 /*
386 * Sync each mounted filesystem.
387 */
388 #ifdef DEBUG
389 int syncprt = 0;
390 struct ctldebug debug0 = { "syncprt", &syncprt };
391 #endif
392
393 /* ARGSUSED */
394 int
sync(p,uap,retval)395 sync(p, uap, retval)
396 struct proc *p;
397 void *uap;
398 register_t *retval;
399 {
400 register struct mount *mp, *nmp;
401 int asyncflag;
402
403 simple_lock(&mountlist_slock);
404 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
405 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
406 nmp = mp->mnt_list.cqe_next;
407 continue;
408 }
409 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
410 asyncflag = mp->mnt_flag & MNT_ASYNC;
411 mp->mnt_flag &= ~MNT_ASYNC;
412 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
413 if (asyncflag)
414 mp->mnt_flag |= MNT_ASYNC;
415 }
416 simple_lock(&mountlist_slock);
417 nmp = mp->mnt_list.cqe_next;
418 vfs_unbusy(mp, p);
419 }
420 simple_unlock(&mountlist_slock);
421 #ifdef DIAGNOSTIC
422 if (syncprt)
423 vfs_bufstats();
424 #endif /* DIAGNOSTIC */
425 return (0);
426 }
427
428 /*
429 * Change filesystem quotas.
430 */
431 /* ARGSUSED */
432 int
quotactl(p,uap,retval)433 quotactl(p, uap, retval)
434 struct proc *p;
435 register struct quotactl_args /* {
436 syscallarg(char *) path;
437 syscallarg(int) cmd;
438 syscallarg(int) uid;
439 syscallarg(caddr_t) arg;
440 } */ *uap;
441 register_t *retval;
442 {
443 register struct mount *mp;
444 int error;
445 struct nameidata nd;
446
447 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
448 if (error = namei(&nd))
449 return (error);
450 mp = nd.ni_vp->v_mount;
451 vrele(nd.ni_vp);
452 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
453 SCARG(uap, arg), p));
454 }
455
456 /*
457 * Get filesystem statistics.
458 */
459 /* ARGSUSED */
460 int
statfs(p,uap,retval)461 statfs(p, uap, retval)
462 struct proc *p;
463 register struct statfs_args /* {
464 syscallarg(char *) path;
465 syscallarg(struct statfs *) buf;
466 } */ *uap;
467 register_t *retval;
468 {
469 register struct mount *mp;
470 register struct statfs *sp;
471 int error;
472 struct nameidata nd;
473
474 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
475 if (error = namei(&nd))
476 return (error);
477 mp = nd.ni_vp->v_mount;
478 sp = &mp->mnt_stat;
479 vrele(nd.ni_vp);
480 if (error = VFS_STATFS(mp, sp, p))
481 return (error);
482 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
483 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
484 }
485
486 /*
487 * Get filesystem statistics.
488 */
489 /* ARGSUSED */
490 int
fstatfs(p,uap,retval)491 fstatfs(p, uap, retval)
492 struct proc *p;
493 register struct fstatfs_args /* {
494 syscallarg(int) fd;
495 syscallarg(struct statfs *) buf;
496 } */ *uap;
497 register_t *retval;
498 {
499 struct file *fp;
500 struct mount *mp;
501 register struct statfs *sp;
502 int error;
503
504 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
505 return (error);
506 mp = ((struct vnode *)fp->f_data)->v_mount;
507 sp = &mp->mnt_stat;
508 if (error = VFS_STATFS(mp, sp, p))
509 return (error);
510 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
511 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
512 }
513
514 /*
515 * Get statistics on all filesystems.
516 */
517 int
getfsstat(p,uap,retval)518 getfsstat(p, uap, retval)
519 struct proc *p;
520 register struct getfsstat_args /* {
521 syscallarg(struct statfs *) buf;
522 syscallarg(long) bufsize;
523 syscallarg(int) flags;
524 } */ *uap;
525 register_t *retval;
526 {
527 register struct mount *mp, *nmp;
528 register struct statfs *sp;
529 caddr_t sfsp;
530 long count, maxcount, error;
531
532 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
533 sfsp = (caddr_t)SCARG(uap, buf);
534 count = 0;
535 simple_lock(&mountlist_slock);
536 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
537 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
538 nmp = mp->mnt_list.cqe_next;
539 continue;
540 }
541 if (sfsp && count < maxcount) {
542 sp = &mp->mnt_stat;
543 /*
544 * If MNT_NOWAIT is specified, do not refresh the
545 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
546 */
547 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
548 (SCARG(uap, flags) & MNT_WAIT)) &&
549 (error = VFS_STATFS(mp, sp, p))) {
550 simple_lock(&mountlist_slock);
551 nmp = mp->mnt_list.cqe_next;
552 vfs_unbusy(mp, p);
553 continue;
554 }
555 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
556 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
557 return (error);
558 sfsp += sizeof(*sp);
559 }
560 count++;
561 simple_lock(&mountlist_slock);
562 nmp = mp->mnt_list.cqe_next;
563 vfs_unbusy(mp, p);
564 }
565 simple_unlock(&mountlist_slock);
566 if (sfsp && count > maxcount)
567 *retval = maxcount;
568 else
569 *retval = count;
570 return (0);
571 }
572
573 /*
574 * Change current working directory to a given file descriptor.
575 */
576 /* ARGSUSED */
577 int
fchdir(p,uap,retval)578 fchdir(p, uap, retval)
579 struct proc *p;
580 struct fchdir_args /* {
581 syscallarg(int) fd;
582 } */ *uap;
583 register_t *retval;
584 {
585 register struct filedesc *fdp = p->p_fd;
586 struct vnode *vp, *tdp;
587 struct mount *mp;
588 struct file *fp;
589 int error;
590
591 if (error = getvnode(fdp, SCARG(uap, fd), &fp))
592 return (error);
593 vp = (struct vnode *)fp->f_data;
594 VREF(vp);
595 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
596 if (vp->v_type != VDIR)
597 error = ENOTDIR;
598 else
599 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
600 while (!error && (mp = vp->v_mountedhere) != NULL) {
601 if (vfs_busy(mp, 0, 0, p))
602 continue;
603 error = VFS_ROOT(mp, &tdp);
604 vfs_unbusy(mp, p);
605 if (error)
606 break;
607 vput(vp);
608 vp = tdp;
609 }
610 if (error) {
611 vput(vp);
612 return (error);
613 }
614 VOP_UNLOCK(vp, 0, p);
615 vrele(fdp->fd_cdir);
616 fdp->fd_cdir = vp;
617 return (0);
618 }
619
620 /*
621 * Change current working directory (``.'').
622 */
623 /* ARGSUSED */
624 int
chdir(p,uap,retval)625 chdir(p, uap, retval)
626 struct proc *p;
627 struct chdir_args /* {
628 syscallarg(char *) path;
629 } */ *uap;
630 register_t *retval;
631 {
632 register struct filedesc *fdp = p->p_fd;
633 int error;
634 struct nameidata nd;
635
636 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
637 SCARG(uap, path), p);
638 if (error = change_dir(&nd, p))
639 return (error);
640 vrele(fdp->fd_cdir);
641 fdp->fd_cdir = nd.ni_vp;
642 return (0);
643 }
644
645 /*
646 * Change notion of root (``/'') directory.
647 */
648 /* ARGSUSED */
649 int
chroot(p,uap,retval)650 chroot(p, uap, retval)
651 struct proc *p;
652 struct chroot_args /* {
653 syscallarg(char *) path;
654 } */ *uap;
655 register_t *retval;
656 {
657 register struct filedesc *fdp = p->p_fd;
658 int error;
659 struct nameidata nd;
660
661 if (error = suser(p->p_ucred, &p->p_acflag))
662 return (error);
663 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
664 SCARG(uap, path), p);
665 if (error = change_dir(&nd, p))
666 return (error);
667 if (fdp->fd_rdir != NULL)
668 vrele(fdp->fd_rdir);
669 fdp->fd_rdir = nd.ni_vp;
670 return (0);
671 }
672
673 /*
674 * Common routine for chroot and chdir.
675 */
676 static int
change_dir(ndp,p)677 change_dir(ndp, p)
678 register struct nameidata *ndp;
679 struct proc *p;
680 {
681 struct vnode *vp;
682 int error;
683
684 if (error = namei(ndp))
685 return (error);
686 vp = ndp->ni_vp;
687 if (vp->v_type != VDIR)
688 error = ENOTDIR;
689 else
690 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
691 if (error)
692 vput(vp);
693 else
694 VOP_UNLOCK(vp, 0, p);
695 return (error);
696 }
697
698 /*
699 * Check permissions, allocate an open file structure,
700 * and call the device open routine if any.
701 */
702 int
open(p,uap,retval)703 open(p, uap, retval)
704 struct proc *p;
705 register struct open_args /* {
706 syscallarg(char *) path;
707 syscallarg(int) flags;
708 syscallarg(int) mode;
709 } */ *uap;
710 register_t *retval;
711 {
712 register struct filedesc *fdp = p->p_fd;
713 register struct file *fp;
714 register struct vnode *vp;
715 int flags, cmode;
716 struct file *nfp;
717 int type, indx, error;
718 struct flock lf;
719 struct nameidata nd;
720 extern struct fileops vnops;
721
722 if (error = falloc(p, &nfp, &indx))
723 return (error);
724 fp = nfp;
725 flags = FFLAGS(SCARG(uap, flags));
726 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
727 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
728 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
729 if (error = vn_open(&nd, flags, cmode)) {
730 ffree(fp);
731 if ((error == ENODEV || error == ENXIO) &&
732 p->p_dupfd >= 0 && /* XXX from fdopen */
733 (error =
734 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
735 *retval = indx;
736 return (0);
737 }
738 if (error == ERESTART)
739 error = EINTR;
740 fdp->fd_ofiles[indx] = NULL;
741 return (error);
742 }
743 p->p_dupfd = 0;
744 vp = nd.ni_vp;
745 fp->f_flag = flags & FMASK;
746 fp->f_type = DTYPE_VNODE;
747 fp->f_ops = &vnops;
748 fp->f_data = (caddr_t)vp;
749 if (flags & (O_EXLOCK | O_SHLOCK)) {
750 lf.l_whence = SEEK_SET;
751 lf.l_start = 0;
752 lf.l_len = 0;
753 if (flags & O_EXLOCK)
754 lf.l_type = F_WRLCK;
755 else
756 lf.l_type = F_RDLCK;
757 type = F_FLOCK;
758 if ((flags & FNONBLOCK) == 0)
759 type |= F_WAIT;
760 VOP_UNLOCK(vp, 0, p);
761 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
762 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
763 ffree(fp);
764 fdp->fd_ofiles[indx] = NULL;
765 return (error);
766 }
767 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
768 fp->f_flag |= FHASLOCK;
769 }
770 VOP_UNLOCK(vp, 0, p);
771 *retval = indx;
772 return (0);
773 }
774
775 #ifdef COMPAT_43
776 /*
777 * Create a file.
778 */
779 int
compat_43_creat(p,uap,retval)780 compat_43_creat(p, uap, retval)
781 struct proc *p;
782 register struct compat_43_creat_args /* {
783 syscallarg(char *) path;
784 syscallarg(int) mode;
785 } */ *uap;
786 register_t *retval;
787 {
788 struct open_args /* {
789 syscallarg(char *) path;
790 syscallarg(int) flags;
791 syscallarg(int) mode;
792 } */ nuap;
793
794 SCARG(&nuap, path) = SCARG(uap, path);
795 SCARG(&nuap, mode) = SCARG(uap, mode);
796 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
797 return (open(p, &nuap, retval));
798 }
799 #endif /* COMPAT_43 */
800
801 /*
802 * Create a special file.
803 */
804 /* ARGSUSED */
805 int
mknod(p,uap,retval)806 mknod(p, uap, retval)
807 struct proc *p;
808 register struct mknod_args /* {
809 syscallarg(char *) path;
810 syscallarg(int) mode;
811 syscallarg(int) dev;
812 } */ *uap;
813 register_t *retval;
814 {
815 register struct vnode *vp;
816 struct vattr vattr;
817 int error;
818 int whiteout;
819 struct nameidata nd;
820
821 if (error = suser(p->p_ucred, &p->p_acflag))
822 return (error);
823 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
824 if (error = namei(&nd))
825 return (error);
826 vp = nd.ni_vp;
827 if (vp != NULL)
828 error = EEXIST;
829 else {
830 VATTR_NULL(&vattr);
831 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
832 vattr.va_rdev = SCARG(uap, dev);
833 whiteout = 0;
834
835 switch (SCARG(uap, mode) & S_IFMT) {
836 case S_IFMT: /* used by badsect to flag bad sectors */
837 vattr.va_type = VBAD;
838 break;
839 case S_IFCHR:
840 vattr.va_type = VCHR;
841 break;
842 case S_IFBLK:
843 vattr.va_type = VBLK;
844 break;
845 case S_IFWHT:
846 whiteout = 1;
847 break;
848 default:
849 error = EINVAL;
850 break;
851 }
852 }
853 if (!error) {
854 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
855 if (whiteout) {
856 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
857 if (error)
858 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
859 vput(nd.ni_dvp);
860 } else {
861 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
862 &nd.ni_cnd, &vattr);
863 }
864 } else {
865 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
866 if (nd.ni_dvp == vp)
867 vrele(nd.ni_dvp);
868 else
869 vput(nd.ni_dvp);
870 if (vp)
871 vrele(vp);
872 }
873 return (error);
874 }
875
876 /*
877 * Create a named pipe.
878 */
879 /* ARGSUSED */
880 int
mkfifo(p,uap,retval)881 mkfifo(p, uap, retval)
882 struct proc *p;
883 register struct mkfifo_args /* {
884 syscallarg(char *) path;
885 syscallarg(int) mode;
886 } */ *uap;
887 register_t *retval;
888 {
889 struct vattr vattr;
890 int error;
891 struct nameidata nd;
892
893 #ifndef FIFO
894 return (EOPNOTSUPP);
895 #else
896 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
897 if (error = namei(&nd))
898 return (error);
899 if (nd.ni_vp != NULL) {
900 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
901 if (nd.ni_dvp == nd.ni_vp)
902 vrele(nd.ni_dvp);
903 else
904 vput(nd.ni_dvp);
905 vrele(nd.ni_vp);
906 return (EEXIST);
907 }
908 VATTR_NULL(&vattr);
909 vattr.va_type = VFIFO;
910 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
911 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
912 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
913 #endif /* FIFO */
914 }
915
916 /*
917 * Make a hard file link.
918 */
919 /* ARGSUSED */
920 int
link(p,uap,retval)921 link(p, uap, retval)
922 struct proc *p;
923 register struct link_args /* {
924 syscallarg(char *) path;
925 syscallarg(char *) link;
926 } */ *uap;
927 register_t *retval;
928 {
929 register struct vnode *vp;
930 struct nameidata nd;
931 int error;
932
933 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
934 if (error = namei(&nd))
935 return (error);
936 vp = nd.ni_vp;
937 if (vp->v_type != VDIR ||
938 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
939 nd.ni_cnd.cn_nameiop = CREATE;
940 nd.ni_cnd.cn_flags = LOCKPARENT;
941 nd.ni_dirp = SCARG(uap, link);
942 if ((error = namei(&nd)) == 0) {
943 if (nd.ni_vp != NULL)
944 error = EEXIST;
945 if (!error) {
946 VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
947 LEASE_WRITE);
948 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
949 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
950 } else {
951 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
952 if (nd.ni_dvp == nd.ni_vp)
953 vrele(nd.ni_dvp);
954 else
955 vput(nd.ni_dvp);
956 if (nd.ni_vp)
957 vrele(nd.ni_vp);
958 }
959 }
960 }
961 vrele(vp);
962 return (error);
963 }
964
965 /*
966 * Make a symbolic link.
967 */
968 /* ARGSUSED */
969 int
symlink(p,uap,retval)970 symlink(p, uap, retval)
971 struct proc *p;
972 register struct symlink_args /* {
973 syscallarg(char *) path;
974 syscallarg(char *) link;
975 } */ *uap;
976 register_t *retval;
977 {
978 struct vattr vattr;
979 char *path;
980 int error;
981 struct nameidata nd;
982
983 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
984 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
985 goto out;
986 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
987 if (error = namei(&nd))
988 goto out;
989 if (nd.ni_vp) {
990 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
991 if (nd.ni_dvp == nd.ni_vp)
992 vrele(nd.ni_dvp);
993 else
994 vput(nd.ni_dvp);
995 vrele(nd.ni_vp);
996 error = EEXIST;
997 goto out;
998 }
999 VATTR_NULL(&vattr);
1000 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1001 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1002 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1003 out:
1004 FREE(path, M_NAMEI);
1005 return (error);
1006 }
1007
1008 /*
1009 * Delete a whiteout from the filesystem.
1010 */
1011 /* ARGSUSED */
1012 int
undelete(p,uap,retval)1013 undelete(p, uap, retval)
1014 struct proc *p;
1015 register struct undelete_args /* {
1016 syscallarg(char *) path;
1017 } */ *uap;
1018 register_t *retval;
1019 {
1020 int error;
1021 struct nameidata nd;
1022
1023 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1024 SCARG(uap, path), p);
1025 error = namei(&nd);
1026 if (error)
1027 return (error);
1028
1029 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1030 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1031 if (nd.ni_dvp == nd.ni_vp)
1032 vrele(nd.ni_dvp);
1033 else
1034 vput(nd.ni_dvp);
1035 if (nd.ni_vp)
1036 vrele(nd.ni_vp);
1037 return (EEXIST);
1038 }
1039
1040 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1041 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1042 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1043 vput(nd.ni_dvp);
1044 return (error);
1045 }
1046
1047 /*
1048 * Delete a name from the filesystem.
1049 */
1050 /* ARGSUSED */
1051 int
unlink(p,uap,retval)1052 unlink(p, uap, retval)
1053 struct proc *p;
1054 struct unlink_args /* {
1055 syscallarg(char *) path;
1056 } */ *uap;
1057 register_t *retval;
1058 {
1059 register struct vnode *vp;
1060 int error;
1061 struct nameidata nd;
1062
1063 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1064 if (error = namei(&nd))
1065 return (error);
1066 vp = nd.ni_vp;
1067 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1068 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1069
1070 if (vp->v_type != VDIR ||
1071 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
1072 /*
1073 * The root of a mounted filesystem cannot be deleted.
1074 */
1075 if (vp->v_flag & VROOT)
1076 error = EBUSY;
1077 else
1078 (void)vnode_pager_uncache(vp);
1079 }
1080
1081 if (!error) {
1082 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1083 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1084 } else {
1085 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1086 if (nd.ni_dvp == vp)
1087 vrele(nd.ni_dvp);
1088 else
1089 vput(nd.ni_dvp);
1090 if (vp != NULLVP)
1091 vput(vp);
1092 }
1093 return (error);
1094 }
1095
1096 /*
1097 * Reposition read/write file offset.
1098 */
1099 int
lseek(p,uap,retval)1100 lseek(p, uap, retval)
1101 struct proc *p;
1102 register struct lseek_args /* {
1103 syscallarg(int) fd;
1104 syscallarg(int) pad;
1105 syscallarg(off_t) offset;
1106 syscallarg(int) whence;
1107 } */ *uap;
1108 register_t *retval;
1109 {
1110 struct ucred *cred = p->p_ucred;
1111 register struct filedesc *fdp = p->p_fd;
1112 register struct file *fp;
1113 struct vattr vattr;
1114 int error;
1115
1116 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1117 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1118 return (EBADF);
1119 if (fp->f_type != DTYPE_VNODE)
1120 return (ESPIPE);
1121 switch (SCARG(uap, whence)) {
1122 case L_INCR:
1123 fp->f_offset += SCARG(uap, offset);
1124 break;
1125 case L_XTND:
1126 if (error =
1127 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
1128 return (error);
1129 fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1130 break;
1131 case L_SET:
1132 fp->f_offset = SCARG(uap, offset);
1133 break;
1134 default:
1135 return (EINVAL);
1136 }
1137 *(off_t *)retval = fp->f_offset;
1138 return (0);
1139 }
1140
1141 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1142 /*
1143 * Reposition read/write file offset.
1144 */
1145 int
compat_43_lseek(p,uap,retval)1146 compat_43_lseek(p, uap, retval)
1147 struct proc *p;
1148 register struct compat_43_lseek_args /* {
1149 syscallarg(int) fd;
1150 syscallarg(long) offset;
1151 syscallarg(int) whence;
1152 } */ *uap;
1153 register_t *retval;
1154 {
1155 struct lseek_args /* {
1156 syscallarg(int) fd;
1157 syscallarg(int) pad;
1158 syscallarg(off_t) offset;
1159 syscallarg(int) whence;
1160 } */ nuap;
1161 off_t qret;
1162 int error;
1163
1164 SCARG(&nuap, fd) = SCARG(uap, fd);
1165 SCARG(&nuap, offset) = SCARG(uap, offset);
1166 SCARG(&nuap, whence) = SCARG(uap, whence);
1167 error = lseek(p, &nuap, &qret);
1168 *(long *)retval = qret;
1169 return (error);
1170 }
1171 #endif /* COMPAT_43 */
1172
1173 /*
1174 * Check access permissions.
1175 */
1176 int
access(p,uap,retval)1177 access(p, uap, retval)
1178 struct proc *p;
1179 register struct access_args /* {
1180 syscallarg(char *) path;
1181 syscallarg(int) flags;
1182 } */ *uap;
1183 register_t *retval;
1184 {
1185 register struct ucred *cred = p->p_ucred;
1186 register struct vnode *vp;
1187 int error, flags, t_gid, t_uid;
1188 struct nameidata nd;
1189
1190 t_uid = cred->cr_uid;
1191 t_gid = cred->cr_groups[0];
1192 cred->cr_uid = p->p_cred->p_ruid;
1193 cred->cr_groups[0] = p->p_cred->p_rgid;
1194 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1195 SCARG(uap, path), p);
1196 if (error = namei(&nd))
1197 goto out1;
1198 vp = nd.ni_vp;
1199
1200 /* Flags == 0 means only check for existence. */
1201 if (SCARG(uap, flags)) {
1202 flags = 0;
1203 if (SCARG(uap, flags) & R_OK)
1204 flags |= VREAD;
1205 if (SCARG(uap, flags) & W_OK)
1206 flags |= VWRITE;
1207 if (SCARG(uap, flags) & X_OK)
1208 flags |= VEXEC;
1209 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1210 error = VOP_ACCESS(vp, flags, cred, p);
1211 }
1212 vput(vp);
1213 out1:
1214 cred->cr_uid = t_uid;
1215 cred->cr_groups[0] = t_gid;
1216 return (error);
1217 }
1218
1219 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1220 /*
1221 * Get file status; this version follows links.
1222 */
1223 /* ARGSUSED */
1224 int
compat_43_stat(p,uap,retval)1225 compat_43_stat(p, uap, retval)
1226 struct proc *p;
1227 register struct compat_43_stat_args /* {
1228 syscallarg(char *) path;
1229 syscallarg(struct ostat *) ub;
1230 } */ *uap;
1231 register_t *retval;
1232 {
1233 struct stat sb;
1234 struct ostat osb;
1235 int error;
1236 struct nameidata nd;
1237
1238 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1239 SCARG(uap, path), p);
1240 if (error = namei(&nd))
1241 return (error);
1242 error = vn_stat(nd.ni_vp, &sb, p);
1243 vput(nd.ni_vp);
1244 if (error)
1245 return (error);
1246 cvtstat(&sb, &osb);
1247 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1248 return (error);
1249 }
1250
1251 /*
1252 * Get file status; this version does not follow links.
1253 */
1254 /* ARGSUSED */
1255 int
compat_43_lstat(p,uap,retval)1256 compat_43_lstat(p, uap, retval)
1257 struct proc *p;
1258 register struct compat_43_lstat_args /* {
1259 syscallarg(char *) path;
1260 syscallarg(struct ostat *) ub;
1261 } */ *uap;
1262 register_t *retval;
1263 {
1264 struct vnode *vp, *dvp;
1265 struct stat sb, sb1;
1266 struct ostat osb;
1267 int error;
1268 struct nameidata nd;
1269
1270 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1271 SCARG(uap, path), p);
1272 if (error = namei(&nd))
1273 return (error);
1274 /*
1275 * For symbolic links, always return the attributes of its
1276 * containing directory, except for mode, size, and links.
1277 */
1278 vp = nd.ni_vp;
1279 dvp = nd.ni_dvp;
1280 if (vp->v_type != VLNK) {
1281 if (dvp == vp)
1282 vrele(dvp);
1283 else
1284 vput(dvp);
1285 error = vn_stat(vp, &sb, p);
1286 vput(vp);
1287 if (error)
1288 return (error);
1289 } else {
1290 error = vn_stat(dvp, &sb, p);
1291 vput(dvp);
1292 if (error) {
1293 vput(vp);
1294 return (error);
1295 }
1296 error = vn_stat(vp, &sb1, p);
1297 vput(vp);
1298 if (error)
1299 return (error);
1300 sb.st_mode &= ~S_IFDIR;
1301 sb.st_mode |= S_IFLNK;
1302 sb.st_nlink = sb1.st_nlink;
1303 sb.st_size = sb1.st_size;
1304 sb.st_blocks = sb1.st_blocks;
1305 }
1306 cvtstat(&sb, &osb);
1307 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1308 return (error);
1309 }
1310
1311 /*
1312 * Convert from an old to a new stat structure.
1313 */
1314 void
cvtstat(st,ost)1315 cvtstat(st, ost)
1316 struct stat *st;
1317 struct ostat *ost;
1318 {
1319
1320 ost->st_dev = st->st_dev;
1321 ost->st_ino = st->st_ino;
1322 ost->st_mode = st->st_mode;
1323 ost->st_nlink = st->st_nlink;
1324 ost->st_uid = st->st_uid;
1325 ost->st_gid = st->st_gid;
1326 ost->st_rdev = st->st_rdev;
1327 if (st->st_size < (quad_t)1 << 32)
1328 ost->st_size = st->st_size;
1329 else
1330 ost->st_size = -2;
1331 ost->st_atime = st->st_atime;
1332 ost->st_mtime = st->st_mtime;
1333 ost->st_ctime = st->st_ctime;
1334 ost->st_blksize = st->st_blksize;
1335 ost->st_blocks = st->st_blocks;
1336 ost->st_flags = st->st_flags;
1337 ost->st_gen = st->st_gen;
1338 }
1339 #endif /* COMPAT_43 || COMPAT_SUNOS */
1340
1341 /*
1342 * Get file status; this version follows links.
1343 */
1344 /* ARGSUSED */
1345 int
stat(p,uap,retval)1346 stat(p, uap, retval)
1347 struct proc *p;
1348 register struct stat_args /* {
1349 syscallarg(char *) path;
1350 syscallarg(struct stat *) ub;
1351 } */ *uap;
1352 register_t *retval;
1353 {
1354 struct stat sb;
1355 int error;
1356 struct nameidata nd;
1357
1358 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1359 SCARG(uap, path), p);
1360 if (error = namei(&nd))
1361 return (error);
1362 error = vn_stat(nd.ni_vp, &sb, p);
1363 vput(nd.ni_vp);
1364 if (error)
1365 return (error);
1366 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1367 return (error);
1368 }
1369
1370 /*
1371 * Get file status; this version does not follow links.
1372 */
1373 /* ARGSUSED */
1374 int
lstat(p,uap,retval)1375 lstat(p, uap, retval)
1376 struct proc *p;
1377 register struct lstat_args /* {
1378 syscallarg(char *) path;
1379 syscallarg(struct stat *) ub;
1380 } */ *uap;
1381 register_t *retval;
1382 {
1383 int error;
1384 struct vnode *vp, *dvp;
1385 struct stat sb, sb1;
1386 struct nameidata nd;
1387
1388 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1389 SCARG(uap, path), p);
1390 if (error = namei(&nd))
1391 return (error);
1392 /*
1393 * For symbolic links, always return the attributes of its containing
1394 * directory, except for mode, size, inode number, and links.
1395 */
1396 vp = nd.ni_vp;
1397 dvp = nd.ni_dvp;
1398 if (vp->v_type != VLNK) {
1399 if (dvp == vp)
1400 vrele(dvp);
1401 else
1402 vput(dvp);
1403 error = vn_stat(vp, &sb, p);
1404 vput(vp);
1405 if (error)
1406 return (error);
1407 } else {
1408 error = vn_stat(dvp, &sb, p);
1409 vput(dvp);
1410 if (error) {
1411 vput(vp);
1412 return (error);
1413 }
1414 error = vn_stat(vp, &sb1, p);
1415 vput(vp);
1416 if (error)
1417 return (error);
1418 sb.st_mode &= ~S_IFDIR;
1419 sb.st_mode |= S_IFLNK;
1420 sb.st_nlink = sb1.st_nlink;
1421 sb.st_size = sb1.st_size;
1422 sb.st_blocks = sb1.st_blocks;
1423 sb.st_ino = sb1.st_ino;
1424 }
1425 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1426 return (error);
1427 }
1428
1429 /*
1430 * Get configurable pathname variables.
1431 */
1432 /* ARGSUSED */
1433 int
pathconf(p,uap,retval)1434 pathconf(p, uap, retval)
1435 struct proc *p;
1436 register struct pathconf_args /* {
1437 syscallarg(char *) path;
1438 syscallarg(int) name;
1439 } */ *uap;
1440 register_t *retval;
1441 {
1442 int error;
1443 struct nameidata nd;
1444
1445 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1446 SCARG(uap, path), p);
1447 if (error = namei(&nd))
1448 return (error);
1449 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1450 vput(nd.ni_vp);
1451 return (error);
1452 }
1453
1454 /*
1455 * Return target name of a symbolic link.
1456 */
1457 /* ARGSUSED */
1458 int
readlink(p,uap,retval)1459 readlink(p, uap, retval)
1460 struct proc *p;
1461 register struct readlink_args /* {
1462 syscallarg(char *) path;
1463 syscallarg(char *) buf;
1464 syscallarg(int) count;
1465 } */ *uap;
1466 register_t *retval;
1467 {
1468 register struct vnode *vp;
1469 struct iovec aiov;
1470 struct uio auio;
1471 int error;
1472 struct nameidata nd;
1473
1474 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1475 SCARG(uap, path), p);
1476 if (error = namei(&nd))
1477 return (error);
1478 vp = nd.ni_vp;
1479 if (vp->v_type != VLNK)
1480 error = EINVAL;
1481 else {
1482 aiov.iov_base = SCARG(uap, buf);
1483 aiov.iov_len = SCARG(uap, count);
1484 auio.uio_iov = &aiov;
1485 auio.uio_iovcnt = 1;
1486 auio.uio_offset = 0;
1487 auio.uio_rw = UIO_READ;
1488 auio.uio_segflg = UIO_USERSPACE;
1489 auio.uio_procp = p;
1490 auio.uio_resid = SCARG(uap, count);
1491 error = VOP_READLINK(vp, &auio, p->p_ucred);
1492 }
1493 vput(vp);
1494 *retval = SCARG(uap, count) - auio.uio_resid;
1495 return (error);
1496 }
1497
1498 /*
1499 * Change flags of a file given a path name.
1500 */
1501 /* ARGSUSED */
1502 int
chflags(p,uap,retval)1503 chflags(p, uap, retval)
1504 struct proc *p;
1505 register struct chflags_args /* {
1506 syscallarg(char *) path;
1507 syscallarg(int) flags;
1508 } */ *uap;
1509 register_t *retval;
1510 {
1511 register struct vnode *vp;
1512 struct vattr vattr;
1513 int error;
1514 struct nameidata nd;
1515
1516 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1517 if (error = namei(&nd))
1518 return (error);
1519 vp = nd.ni_vp;
1520 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1521 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1522 VATTR_NULL(&vattr);
1523 vattr.va_flags = SCARG(uap, flags);
1524 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1525 vput(vp);
1526 return (error);
1527 }
1528
1529 /*
1530 * Change flags of a file given a file descriptor.
1531 */
1532 /* ARGSUSED */
1533 int
fchflags(p,uap,retval)1534 fchflags(p, uap, retval)
1535 struct proc *p;
1536 register struct fchflags_args /* {
1537 syscallarg(int) fd;
1538 syscallarg(int) flags;
1539 } */ *uap;
1540 register_t *retval;
1541 {
1542 struct vattr vattr;
1543 struct vnode *vp;
1544 struct file *fp;
1545 int error;
1546
1547 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1548 return (error);
1549 vp = (struct vnode *)fp->f_data;
1550 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1551 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1552 VATTR_NULL(&vattr);
1553 vattr.va_flags = SCARG(uap, flags);
1554 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1555 VOP_UNLOCK(vp, 0, p);
1556 return (error);
1557 }
1558
1559 /*
1560 * Change mode of a file given path name.
1561 */
1562 /* ARGSUSED */
1563 int
chmod(p,uap,retval)1564 chmod(p, uap, retval)
1565 struct proc *p;
1566 register struct chmod_args /* {
1567 syscallarg(char *) path;
1568 syscallarg(int) mode;
1569 } */ *uap;
1570 register_t *retval;
1571 {
1572 register struct vnode *vp;
1573 struct vattr vattr;
1574 int error;
1575 struct nameidata nd;
1576
1577 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1578 if (error = namei(&nd))
1579 return (error);
1580 vp = nd.ni_vp;
1581 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1582 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1583 VATTR_NULL(&vattr);
1584 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1585 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1586 vput(vp);
1587 return (error);
1588 }
1589
1590 /*
1591 * Change mode of a file given a file descriptor.
1592 */
1593 /* ARGSUSED */
1594 int
fchmod(p,uap,retval)1595 fchmod(p, uap, retval)
1596 struct proc *p;
1597 register struct fchmod_args /* {
1598 syscallarg(int) fd;
1599 syscallarg(int) mode;
1600 } */ *uap;
1601 register_t *retval;
1602 {
1603 struct vattr vattr;
1604 struct vnode *vp;
1605 struct file *fp;
1606 int error;
1607
1608 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1609 return (error);
1610 vp = (struct vnode *)fp->f_data;
1611 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1612 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1613 VATTR_NULL(&vattr);
1614 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1615 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1616 VOP_UNLOCK(vp, 0, p);
1617 return (error);
1618 }
1619
1620 /*
1621 * Set ownership given a path name.
1622 */
1623 /* ARGSUSED */
1624 int
chown(p,uap,retval)1625 chown(p, uap, retval)
1626 struct proc *p;
1627 register struct chown_args /* {
1628 syscallarg(char *) path;
1629 syscallarg(int) uid;
1630 syscallarg(int) gid;
1631 } */ *uap;
1632 register_t *retval;
1633 {
1634 register struct vnode *vp;
1635 struct vattr vattr;
1636 int error;
1637 struct nameidata nd;
1638
1639 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1640 if (error = namei(&nd))
1641 return (error);
1642 vp = nd.ni_vp;
1643 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1644 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1645 VATTR_NULL(&vattr);
1646 vattr.va_uid = SCARG(uap, uid);
1647 vattr.va_gid = SCARG(uap, gid);
1648 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1649 vput(vp);
1650 return (error);
1651 }
1652
1653 /*
1654 * Set ownership given a file descriptor.
1655 */
1656 /* ARGSUSED */
1657 int
fchown(p,uap,retval)1658 fchown(p, uap, retval)
1659 struct proc *p;
1660 register struct fchown_args /* {
1661 syscallarg(int) fd;
1662 syscallarg(int) uid;
1663 syscallarg(int) gid;
1664 } */ *uap;
1665 register_t *retval;
1666 {
1667 struct vattr vattr;
1668 struct vnode *vp;
1669 struct file *fp;
1670 int error;
1671
1672 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1673 return (error);
1674 vp = (struct vnode *)fp->f_data;
1675 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1676 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1677 VATTR_NULL(&vattr);
1678 vattr.va_uid = SCARG(uap, uid);
1679 vattr.va_gid = SCARG(uap, gid);
1680 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1681 VOP_UNLOCK(vp, 0, p);
1682 return (error);
1683 }
1684
1685 /*
1686 * Set the access and modification times of a file.
1687 */
1688 /* ARGSUSED */
1689 int
utimes(p,uap,retval)1690 utimes(p, uap, retval)
1691 struct proc *p;
1692 register struct utimes_args /* {
1693 syscallarg(char *) path;
1694 syscallarg(struct timeval *) tptr;
1695 } */ *uap;
1696 register_t *retval;
1697 {
1698 register struct vnode *vp;
1699 struct timeval tv[2];
1700 struct vattr vattr;
1701 int error;
1702 struct nameidata nd;
1703
1704 VATTR_NULL(&vattr);
1705 if (SCARG(uap, tptr) == NULL) {
1706 microtime(&tv[0]);
1707 tv[1] = tv[0];
1708 vattr.va_vaflags |= VA_UTIMES_NULL;
1709 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1710 sizeof (tv)))
1711 return (error);
1712 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1713 if (error = namei(&nd))
1714 return (error);
1715 vp = nd.ni_vp;
1716 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1717 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1718 vattr.va_atime.ts_sec = tv[0].tv_sec;
1719 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1720 vattr.va_mtime.ts_sec = tv[1].tv_sec;
1721 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
1722 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1723 vput(vp);
1724 return (error);
1725 }
1726
1727 /*
1728 * Truncate a file given its path name.
1729 */
1730 /* ARGSUSED */
1731 int
truncate(p,uap,retval)1732 truncate(p, uap, retval)
1733 struct proc *p;
1734 register struct truncate_args /* {
1735 syscallarg(char *) path;
1736 syscallarg(int) pad;
1737 syscallarg(off_t) length;
1738 } */ *uap;
1739 register_t *retval;
1740 {
1741 register struct vnode *vp;
1742 struct vattr vattr;
1743 int error;
1744 struct nameidata nd;
1745
1746 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1747 if (error = namei(&nd))
1748 return (error);
1749 vp = nd.ni_vp;
1750 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1751 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1752 if (vp->v_type == VDIR)
1753 error = EISDIR;
1754 else if ((error = vn_writechk(vp)) == 0 &&
1755 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1756 VATTR_NULL(&vattr);
1757 vattr.va_size = SCARG(uap, length);
1758 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1759 }
1760 vput(vp);
1761 return (error);
1762 }
1763
1764 /*
1765 * Truncate a file given a file descriptor.
1766 */
1767 /* ARGSUSED */
1768 int
ftruncate(p,uap,retval)1769 ftruncate(p, uap, retval)
1770 struct proc *p;
1771 register struct ftruncate_args /* {
1772 syscallarg(int) fd;
1773 syscallarg(int) pad;
1774 syscallarg(off_t) length;
1775 } */ *uap;
1776 register_t *retval;
1777 {
1778 struct vattr vattr;
1779 struct vnode *vp;
1780 struct file *fp;
1781 int error;
1782
1783 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1784 return (error);
1785 if ((fp->f_flag & FWRITE) == 0)
1786 return (EINVAL);
1787 vp = (struct vnode *)fp->f_data;
1788 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1789 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1790 if (vp->v_type == VDIR)
1791 error = EISDIR;
1792 else if ((error = vn_writechk(vp)) == 0) {
1793 VATTR_NULL(&vattr);
1794 vattr.va_size = SCARG(uap, length);
1795 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1796 }
1797 VOP_UNLOCK(vp, 0, p);
1798 return (error);
1799 }
1800
1801 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1802 /*
1803 * Truncate a file given its path name.
1804 */
1805 /* ARGSUSED */
1806 int
compat_43_truncate(p,uap,retval)1807 compat_43_truncate(p, uap, retval)
1808 struct proc *p;
1809 register struct compat_43_truncate_args /* {
1810 syscallarg(char *) path;
1811 syscallarg(long) length;
1812 } */ *uap;
1813 register_t *retval;
1814 {
1815 struct truncate_args /* {
1816 syscallarg(char *) path;
1817 syscallarg(int) pad;
1818 syscallarg(off_t) length;
1819 } */ nuap;
1820
1821 SCARG(&nuap, path) = SCARG(uap, path);
1822 SCARG(&nuap, length) = SCARG(uap, length);
1823 return (truncate(p, &nuap, retval));
1824 }
1825
1826 /*
1827 * Truncate a file given a file descriptor.
1828 */
1829 /* ARGSUSED */
1830 int
compat_43_ftruncate(p,uap,retval)1831 compat_43_ftruncate(p, uap, retval)
1832 struct proc *p;
1833 register struct compat_43_ftruncate_args /* {
1834 syscallarg(int) fd;
1835 syscallarg(long) length;
1836 } */ *uap;
1837 register_t *retval;
1838 {
1839 struct ftruncate_args /* {
1840 syscallarg(int) fd;
1841 syscallarg(int) pad;
1842 syscallarg(off_t) length;
1843 } */ nuap;
1844
1845 SCARG(&nuap, fd) = SCARG(uap, fd);
1846 SCARG(&nuap, length) = SCARG(uap, length);
1847 return (ftruncate(p, &nuap, retval));
1848 }
1849 #endif /* COMPAT_43 || COMPAT_SUNOS */
1850
1851 /*
1852 * Sync an open file.
1853 */
1854 /* ARGSUSED */
1855 int
fsync(p,uap,retval)1856 fsync(p, uap, retval)
1857 struct proc *p;
1858 struct fsync_args /* {
1859 syscallarg(int) fd;
1860 } */ *uap;
1861 register_t *retval;
1862 {
1863 register struct vnode *vp;
1864 struct file *fp;
1865 int error;
1866
1867 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1868 return (error);
1869 vp = (struct vnode *)fp->f_data;
1870 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1871 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
1872 VOP_UNLOCK(vp, 0, p);
1873 return (error);
1874 }
1875
1876 /*
1877 * Rename files. Source and destination must either both be directories,
1878 * or both not be directories. If target is a directory, it must be empty.
1879 */
1880 /* ARGSUSED */
1881 int
rename(p,uap,retval)1882 rename(p, uap, retval)
1883 struct proc *p;
1884 register struct rename_args /* {
1885 syscallarg(char *) from;
1886 syscallarg(char *) to;
1887 } */ *uap;
1888 register_t *retval;
1889 {
1890 register struct vnode *tvp, *fvp, *tdvp;
1891 struct nameidata fromnd, tond;
1892 int error;
1893
1894 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1895 SCARG(uap, from), p);
1896 if (error = namei(&fromnd))
1897 return (error);
1898 fvp = fromnd.ni_vp;
1899 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
1900 UIO_USERSPACE, SCARG(uap, to), p);
1901 if (error = namei(&tond)) {
1902 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1903 vrele(fromnd.ni_dvp);
1904 vrele(fvp);
1905 goto out1;
1906 }
1907 tdvp = tond.ni_dvp;
1908 tvp = tond.ni_vp;
1909 if (tvp != NULL) {
1910 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1911 error = ENOTDIR;
1912 goto out;
1913 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1914 error = EISDIR;
1915 goto out;
1916 }
1917 }
1918 if (fvp == tdvp)
1919 error = EINVAL;
1920 /*
1921 * If source is the same as the destination (that is the
1922 * same inode number with the same name in the same directory),
1923 * then there is nothing to do.
1924 */
1925 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1926 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1927 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1928 fromnd.ni_cnd.cn_namelen))
1929 error = -1;
1930 out:
1931 if (!error) {
1932 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
1933 if (fromnd.ni_dvp != tdvp)
1934 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1935 if (tvp)
1936 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
1937 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1938 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1939 } else {
1940 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1941 if (tdvp == tvp)
1942 vrele(tdvp);
1943 else
1944 vput(tdvp);
1945 if (tvp)
1946 vput(tvp);
1947 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1948 vrele(fromnd.ni_dvp);
1949 vrele(fvp);
1950 }
1951 vrele(tond.ni_startdir);
1952 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1953 out1:
1954 if (fromnd.ni_startdir)
1955 vrele(fromnd.ni_startdir);
1956 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1957 if (error == -1)
1958 return (0);
1959 return (error);
1960 }
1961
1962 /*
1963 * Make a directory file.
1964 */
1965 /* ARGSUSED */
1966 int
mkdir(p,uap,retval)1967 mkdir(p, uap, retval)
1968 struct proc *p;
1969 register struct mkdir_args /* {
1970 syscallarg(char *) path;
1971 syscallarg(int) mode;
1972 } */ *uap;
1973 register_t *retval;
1974 {
1975 register struct vnode *vp;
1976 struct vattr vattr;
1977 int error;
1978 struct nameidata nd;
1979
1980 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1981 if (error = namei(&nd))
1982 return (error);
1983 vp = nd.ni_vp;
1984 if (vp != NULL) {
1985 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1986 if (nd.ni_dvp == vp)
1987 vrele(nd.ni_dvp);
1988 else
1989 vput(nd.ni_dvp);
1990 vrele(vp);
1991 return (EEXIST);
1992 }
1993 VATTR_NULL(&vattr);
1994 vattr.va_type = VDIR;
1995 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
1996 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1997 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1998 if (!error)
1999 vput(nd.ni_vp);
2000 return (error);
2001 }
2002
2003 /*
2004 * Remove a directory file.
2005 */
2006 /* ARGSUSED */
2007 int
rmdir(p,uap,retval)2008 rmdir(p, uap, retval)
2009 struct proc *p;
2010 struct rmdir_args /* {
2011 syscallarg(char *) path;
2012 } */ *uap;
2013 register_t *retval;
2014 {
2015 register struct vnode *vp;
2016 int error;
2017 struct nameidata nd;
2018
2019 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2020 SCARG(uap, path), p);
2021 if (error = namei(&nd))
2022 return (error);
2023 vp = nd.ni_vp;
2024 if (vp->v_type != VDIR) {
2025 error = ENOTDIR;
2026 goto out;
2027 }
2028 /*
2029 * No rmdir "." please.
2030 */
2031 if (nd.ni_dvp == vp) {
2032 error = EINVAL;
2033 goto out;
2034 }
2035 /*
2036 * The root of a mounted filesystem cannot be deleted.
2037 */
2038 if (vp->v_flag & VROOT)
2039 error = EBUSY;
2040 out:
2041 if (!error) {
2042 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2043 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2044 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2045 } else {
2046 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2047 if (nd.ni_dvp == vp)
2048 vrele(nd.ni_dvp);
2049 else
2050 vput(nd.ni_dvp);
2051 vput(vp);
2052 }
2053 return (error);
2054 }
2055
2056 #ifdef COMPAT_43
2057 /*
2058 * Read a block of directory entries in a file system independent format.
2059 */
2060 int
compat_43_getdirentries(p,uap,retval)2061 compat_43_getdirentries(p, uap, retval)
2062 struct proc *p;
2063 register struct compat_43_getdirentries_args /* {
2064 syscallarg(int) fd;
2065 syscallarg(char *) buf;
2066 syscallarg(u_int) count;
2067 syscallarg(long *) basep;
2068 } */ *uap;
2069 register_t *retval;
2070 {
2071 register struct vnode *vp;
2072 struct file *fp;
2073 struct uio auio, kuio;
2074 struct iovec aiov, kiov;
2075 struct dirent *dp, *edp;
2076 caddr_t dirbuf;
2077 int error, eofflag, readcnt;
2078 long loff;
2079
2080 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2081 return (error);
2082 if ((fp->f_flag & FREAD) == 0)
2083 return (EBADF);
2084 vp = (struct vnode *)fp->f_data;
2085 unionread:
2086 if (vp->v_type != VDIR)
2087 return (EINVAL);
2088 aiov.iov_base = SCARG(uap, buf);
2089 aiov.iov_len = SCARG(uap, count);
2090 auio.uio_iov = &aiov;
2091 auio.uio_iovcnt = 1;
2092 auio.uio_rw = UIO_READ;
2093 auio.uio_segflg = UIO_USERSPACE;
2094 auio.uio_procp = p;
2095 auio.uio_resid = SCARG(uap, count);
2096 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2097 loff = auio.uio_offset = fp->f_offset;
2098 # if (BYTE_ORDER != LITTLE_ENDIAN)
2099 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2100 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2101 (int *)0, (u_long *)0);
2102 fp->f_offset = auio.uio_offset;
2103 } else
2104 # endif
2105 {
2106 kuio = auio;
2107 kuio.uio_iov = &kiov;
2108 kuio.uio_segflg = UIO_SYSSPACE;
2109 kiov.iov_len = SCARG(uap, count);
2110 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2111 kiov.iov_base = dirbuf;
2112 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2113 (int *)0, (u_long *)0);
2114 fp->f_offset = kuio.uio_offset;
2115 if (error == 0) {
2116 readcnt = SCARG(uap, count) - kuio.uio_resid;
2117 edp = (struct dirent *)&dirbuf[readcnt];
2118 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2119 # if (BYTE_ORDER == LITTLE_ENDIAN)
2120 /*
2121 * The expected low byte of
2122 * dp->d_namlen is our dp->d_type.
2123 * The high MBZ byte of dp->d_namlen
2124 * is our dp->d_namlen.
2125 */
2126 dp->d_type = dp->d_namlen;
2127 dp->d_namlen = 0;
2128 # else
2129 /*
2130 * The dp->d_type is the high byte
2131 * of the expected dp->d_namlen,
2132 * so must be zero'ed.
2133 */
2134 dp->d_type = 0;
2135 # endif
2136 if (dp->d_reclen > 0) {
2137 dp = (struct dirent *)
2138 ((char *)dp + dp->d_reclen);
2139 } else {
2140 error = EIO;
2141 break;
2142 }
2143 }
2144 if (dp >= edp)
2145 error = uiomove(dirbuf, readcnt, &auio);
2146 }
2147 FREE(dirbuf, M_TEMP);
2148 }
2149 VOP_UNLOCK(vp, 0, p);
2150 if (error)
2151 return (error);
2152
2153 #ifdef UNION
2154 {
2155 extern int (**union_vnodeop_p)();
2156 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2157
2158 if ((SCARG(uap, count) == auio.uio_resid) &&
2159 (vp->v_op == union_vnodeop_p)) {
2160 struct vnode *lvp;
2161
2162 lvp = union_dircache(vp, p);
2163 if (lvp != NULLVP) {
2164 struct vattr va;
2165
2166 /*
2167 * If the directory is opaque,
2168 * then don't show lower entries
2169 */
2170 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2171 if (va.va_flags & OPAQUE) {
2172 vput(lvp);
2173 lvp = NULL;
2174 }
2175 }
2176
2177 if (lvp != NULLVP) {
2178 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2179 if (error) {
2180 vput(lvp);
2181 return (error);
2182 }
2183 VOP_UNLOCK(lvp, 0, p);
2184 fp->f_data = (caddr_t) lvp;
2185 fp->f_offset = 0;
2186 error = vn_close(vp, FREAD, fp->f_cred, p);
2187 if (error)
2188 return (error);
2189 vp = lvp;
2190 goto unionread;
2191 }
2192 }
2193 }
2194 #endif /* UNION */
2195
2196 if ((SCARG(uap, count) == auio.uio_resid) &&
2197 (vp->v_flag & VROOT) &&
2198 (vp->v_mount->mnt_flag & MNT_UNION)) {
2199 struct vnode *tvp = vp;
2200 vp = vp->v_mount->mnt_vnodecovered;
2201 VREF(vp);
2202 fp->f_data = (caddr_t) vp;
2203 fp->f_offset = 0;
2204 vrele(tvp);
2205 goto unionread;
2206 }
2207 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2208 sizeof(long));
2209 *retval = SCARG(uap, count) - auio.uio_resid;
2210 return (error);
2211 }
2212 #endif /* COMPAT_43 */
2213
2214 /*
2215 * Read a block of directory entries in a file system independent format.
2216 */
2217 int
getdirentries(p,uap,retval)2218 getdirentries(p, uap, retval)
2219 struct proc *p;
2220 register struct getdirentries_args /* {
2221 syscallarg(int) fd;
2222 syscallarg(char *) buf;
2223 syscallarg(u_int) count;
2224 syscallarg(long *) basep;
2225 } */ *uap;
2226 register_t *retval;
2227 {
2228 register struct vnode *vp;
2229 struct file *fp;
2230 struct uio auio;
2231 struct iovec aiov;
2232 long loff;
2233 int error, eofflag;
2234
2235 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2236 return (error);
2237 if ((fp->f_flag & FREAD) == 0)
2238 return (EBADF);
2239 vp = (struct vnode *)fp->f_data;
2240 unionread:
2241 if (vp->v_type != VDIR)
2242 return (EINVAL);
2243 aiov.iov_base = SCARG(uap, buf);
2244 aiov.iov_len = SCARG(uap, count);
2245 auio.uio_iov = &aiov;
2246 auio.uio_iovcnt = 1;
2247 auio.uio_rw = UIO_READ;
2248 auio.uio_segflg = UIO_USERSPACE;
2249 auio.uio_procp = p;
2250 auio.uio_resid = SCARG(uap, count);
2251 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2252 loff = auio.uio_offset = fp->f_offset;
2253 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2254 (int *)0, (u_long *)0);
2255 fp->f_offset = auio.uio_offset;
2256 VOP_UNLOCK(vp, 0, p);
2257 if (error)
2258 return (error);
2259
2260 #ifdef UNION
2261 {
2262 extern int (**union_vnodeop_p)();
2263 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2264
2265 if ((SCARG(uap, count) == auio.uio_resid) &&
2266 (vp->v_op == union_vnodeop_p)) {
2267 struct vnode *lvp;
2268
2269 lvp = union_dircache(vp, p);
2270 if (lvp != NULLVP) {
2271 struct vattr va;
2272
2273 /*
2274 * If the directory is opaque,
2275 * then don't show lower entries
2276 */
2277 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2278 if (va.va_flags & OPAQUE) {
2279 vput(lvp);
2280 lvp = NULL;
2281 }
2282 }
2283
2284 if (lvp != NULLVP) {
2285 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2286 if (error) {
2287 vput(lvp);
2288 return (error);
2289 }
2290 VOP_UNLOCK(lvp, 0, p);
2291 fp->f_data = (caddr_t) lvp;
2292 fp->f_offset = 0;
2293 error = vn_close(vp, FREAD, fp->f_cred, p);
2294 if (error)
2295 return (error);
2296 vp = lvp;
2297 goto unionread;
2298 }
2299 }
2300 }
2301 #endif /* UNION */
2302
2303 if ((SCARG(uap, count) == auio.uio_resid) &&
2304 (vp->v_flag & VROOT) &&
2305 (vp->v_mount->mnt_flag & MNT_UNION)) {
2306 struct vnode *tvp = vp;
2307 vp = vp->v_mount->mnt_vnodecovered;
2308 VREF(vp);
2309 fp->f_data = (caddr_t) vp;
2310 fp->f_offset = 0;
2311 vrele(tvp);
2312 goto unionread;
2313 }
2314 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2315 sizeof(long));
2316 *retval = SCARG(uap, count) - auio.uio_resid;
2317 return (error);
2318 }
2319
2320 /*
2321 * Set the mode mask for creation of filesystem nodes.
2322 */
2323 int
umask(p,uap,retval)2324 umask(p, uap, retval)
2325 struct proc *p;
2326 struct umask_args /* {
2327 syscallarg(int) newmask;
2328 } */ *uap;
2329 register_t *retval;
2330 {
2331 register struct filedesc *fdp;
2332
2333 fdp = p->p_fd;
2334 *retval = fdp->fd_cmask;
2335 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2336 return (0);
2337 }
2338
2339 /*
2340 * Void all references to file by ripping underlying filesystem
2341 * away from vnode.
2342 */
2343 /* ARGSUSED */
2344 int
revoke(p,uap,retval)2345 revoke(p, uap, retval)
2346 struct proc *p;
2347 register struct revoke_args /* {
2348 syscallarg(char *) path;
2349 } */ *uap;
2350 register_t *retval;
2351 {
2352 register struct vnode *vp;
2353 struct vattr vattr;
2354 int error;
2355 struct nameidata nd;
2356
2357 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2358 if (error = namei(&nd))
2359 return (error);
2360 vp = nd.ni_vp;
2361 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2362 goto out;
2363 if (p->p_ucred->cr_uid != vattr.va_uid &&
2364 (error = suser(p->p_ucred, &p->p_acflag)))
2365 goto out;
2366 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2367 VOP_REVOKE(vp, REVOKEALL);
2368 out:
2369 vrele(vp);
2370 return (error);
2371 }
2372
2373 /*
2374 * Convert a user file descriptor to a kernel file entry.
2375 */
2376 int
getvnode(fdp,fd,fpp)2377 getvnode(fdp, fd, fpp)
2378 struct filedesc *fdp;
2379 struct file **fpp;
2380 int fd;
2381 {
2382 struct file *fp;
2383
2384 if ((u_int)fd >= fdp->fd_nfiles ||
2385 (fp = fdp->fd_ofiles[fd]) == NULL)
2386 return (EBADF);
2387 if (fp->f_type != DTYPE_VNODE)
2388 return (EINVAL);
2389 *fpp = fp;
2390 return (0);
2391 }
2392