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