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