vfs_syscalls.c revision 1.1.1.4 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.42 (Berkeley) 7/31/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 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
971 if (nd.ni_dvp == nd.ni_vp)
972 vrele(nd.ni_dvp);
973 else
974 vput(nd.ni_dvp);
975 if (nd.ni_vp)
976 vrele(nd.ni_vp);
977 error = EEXIST;
978 } else {
979 VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
980 LEASE_WRITE);
981 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
982 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
983 }
984 }
985 }
986 vrele(vp);
987 return (error);
988 }
989
990 /*
991 * Make a symbolic link.
992 */
993 /* ARGSUSED */
994 int
995 symlink(p, uap, retval)
996 struct proc *p;
997 register struct symlink_args /* {
998 syscallarg(char *) path;
999 syscallarg(char *) link;
1000 } */ *uap;
1001 register_t *retval;
1002 {
1003 struct vattr vattr;
1004 char *path;
1005 int error;
1006 struct nameidata nd;
1007
1008 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1009 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
1010 goto out;
1011 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1012 if (error = namei(&nd))
1013 goto out;
1014 if (nd.ni_vp) {
1015 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1016 if (nd.ni_dvp == nd.ni_vp)
1017 vrele(nd.ni_dvp);
1018 else
1019 vput(nd.ni_dvp);
1020 vrele(nd.ni_vp);
1021 error = EEXIST;
1022 goto out;
1023 }
1024 VATTR_NULL(&vattr);
1025 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1026 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1027 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1028 out:
1029 FREE(path, M_NAMEI);
1030 return (error);
1031 }
1032
1033 /*
1034 * Delete a whiteout from the filesystem.
1035 */
1036 /* ARGSUSED */
1037 int
1038 undelete(p, uap, retval)
1039 struct proc *p;
1040 register struct undelete_args /* {
1041 syscallarg(char *) path;
1042 } */ *uap;
1043 register_t *retval;
1044 {
1045 int error;
1046 struct nameidata nd;
1047
1048 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1049 SCARG(uap, path), p);
1050 error = namei(&nd);
1051 if (error)
1052 return (error);
1053
1054 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1055 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1056 if (nd.ni_dvp == nd.ni_vp)
1057 vrele(nd.ni_dvp);
1058 else
1059 vput(nd.ni_dvp);
1060 if (nd.ni_vp)
1061 vrele(nd.ni_vp);
1062 return (EEXIST);
1063 }
1064
1065 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1066 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1067 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1068 vput(nd.ni_dvp);
1069 return (error);
1070 }
1071
1072 /*
1073 * Delete a name from the filesystem.
1074 */
1075 /* ARGSUSED */
1076 int
1077 unlink(p, uap, retval)
1078 struct proc *p;
1079 struct unlink_args /* {
1080 syscallarg(char *) path;
1081 } */ *uap;
1082 register_t *retval;
1083 {
1084 register struct vnode *vp;
1085 int error;
1086 struct nameidata nd;
1087
1088 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1089 if (error = namei(&nd))
1090 return (error);
1091 vp = nd.ni_vp;
1092 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1093 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1094
1095 if (vp->v_type != VDIR ||
1096 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
1097 /*
1098 * The root of a mounted filesystem cannot be deleted.
1099 */
1100 if (vp->v_flag & VROOT)
1101 error = EBUSY;
1102 else
1103 (void)vnode_pager_uncache(vp);
1104 }
1105
1106 if (!error) {
1107 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1108 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1109 } else {
1110 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1111 if (nd.ni_dvp == vp)
1112 vrele(nd.ni_dvp);
1113 else
1114 vput(nd.ni_dvp);
1115 if (vp != NULLVP)
1116 vput(vp);
1117 }
1118 return (error);
1119 }
1120
1121 /*
1122 * Reposition read/write file offset.
1123 */
1124 int
1125 lseek(p, uap, retval)
1126 struct proc *p;
1127 register struct lseek_args /* {
1128 syscallarg(int) fd;
1129 syscallarg(int) pad;
1130 syscallarg(off_t) offset;
1131 syscallarg(int) whence;
1132 } */ *uap;
1133 register_t *retval;
1134 {
1135 struct ucred *cred = p->p_ucred;
1136 register struct filedesc *fdp = p->p_fd;
1137 register struct file *fp;
1138 struct vattr vattr;
1139 int error;
1140
1141 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1142 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1143 return (EBADF);
1144 if (fp->f_type != DTYPE_VNODE)
1145 return (ESPIPE);
1146 switch (SCARG(uap, whence)) {
1147 case L_INCR:
1148 fp->f_offset += SCARG(uap, offset);
1149 break;
1150 case L_XTND:
1151 if (error =
1152 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
1153 return (error);
1154 fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1155 break;
1156 case L_SET:
1157 fp->f_offset = SCARG(uap, offset);
1158 break;
1159 default:
1160 return (EINVAL);
1161 }
1162 *(off_t *)retval = fp->f_offset;
1163 return (0);
1164 }
1165
1166 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1167 /*
1168 * Reposition read/write file offset.
1169 */
1170 int
1171 compat_43_lseek(p, uap, retval)
1172 struct proc *p;
1173 register struct compat_43_lseek_args /* {
1174 syscallarg(int) fd;
1175 syscallarg(long) offset;
1176 syscallarg(int) whence;
1177 } */ *uap;
1178 register_t *retval;
1179 {
1180 struct lseek_args /* {
1181 syscallarg(int) fd;
1182 syscallarg(int) pad;
1183 syscallarg(off_t) offset;
1184 syscallarg(int) whence;
1185 } */ nuap;
1186 off_t qret;
1187 int error;
1188
1189 SCARG(&nuap, fd) = SCARG(uap, fd);
1190 SCARG(&nuap, offset) = SCARG(uap, offset);
1191 SCARG(&nuap, whence) = SCARG(uap, whence);
1192 error = lseek(p, &nuap, &qret);
1193 *(long *)retval = qret;
1194 return (error);
1195 }
1196 #endif /* COMPAT_43 */
1197
1198 /*
1199 * Check access permissions.
1200 */
1201 int
1202 access(p, uap, retval)
1203 struct proc *p;
1204 register struct access_args /* {
1205 syscallarg(char *) path;
1206 syscallarg(int) flags;
1207 } */ *uap;
1208 register_t *retval;
1209 {
1210 register struct ucred *cred = p->p_ucred;
1211 register struct vnode *vp;
1212 int error, flags, t_gid, t_uid;
1213 struct nameidata nd;
1214
1215 t_uid = cred->cr_uid;
1216 t_gid = cred->cr_groups[0];
1217 cred->cr_uid = p->p_cred->p_ruid;
1218 cred->cr_groups[0] = p->p_cred->p_rgid;
1219 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1220 SCARG(uap, path), p);
1221 if (error = namei(&nd))
1222 goto out1;
1223 vp = nd.ni_vp;
1224
1225 /* Flags == 0 means only check for existence. */
1226 if (SCARG(uap, flags)) {
1227 flags = 0;
1228 if (SCARG(uap, flags) & R_OK)
1229 flags |= VREAD;
1230 if (SCARG(uap, flags) & W_OK)
1231 flags |= VWRITE;
1232 if (SCARG(uap, flags) & X_OK)
1233 flags |= VEXEC;
1234 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1235 error = VOP_ACCESS(vp, flags, cred, p);
1236 }
1237 vput(vp);
1238 out1:
1239 cred->cr_uid = t_uid;
1240 cred->cr_groups[0] = t_gid;
1241 return (error);
1242 }
1243
1244 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1245 /*
1246 * Get file status; this version follows links.
1247 */
1248 /* ARGSUSED */
1249 int
1250 compat_43_stat(p, uap, retval)
1251 struct proc *p;
1252 register struct compat_43_stat_args /* {
1253 syscallarg(char *) path;
1254 syscallarg(struct ostat *) ub;
1255 } */ *uap;
1256 register_t *retval;
1257 {
1258 struct stat sb;
1259 struct ostat osb;
1260 int error;
1261 struct nameidata nd;
1262
1263 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1264 SCARG(uap, path), p);
1265 if (error = namei(&nd))
1266 return (error);
1267 error = vn_stat(nd.ni_vp, &sb, p);
1268 vput(nd.ni_vp);
1269 if (error)
1270 return (error);
1271 cvtstat(&sb, &osb);
1272 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1273 return (error);
1274 }
1275
1276 /*
1277 * Get file status; this version does not follow links.
1278 */
1279 /* ARGSUSED */
1280 int
1281 compat_43_lstat(p, uap, retval)
1282 struct proc *p;
1283 register struct compat_43_lstat_args /* {
1284 syscallarg(char *) path;
1285 syscallarg(struct ostat *) ub;
1286 } */ *uap;
1287 register_t *retval;
1288 {
1289 struct vnode *vp, *dvp;
1290 struct stat sb, sb1;
1291 struct ostat osb;
1292 int error;
1293 struct nameidata nd;
1294
1295 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1296 SCARG(uap, path), p);
1297 if (error = namei(&nd))
1298 return (error);
1299 /*
1300 * For symbolic links, always return the attributes of its
1301 * containing directory, except for mode, size, and links.
1302 */
1303 vp = nd.ni_vp;
1304 dvp = nd.ni_dvp;
1305 if (vp->v_type != VLNK) {
1306 if (dvp == vp)
1307 vrele(dvp);
1308 else
1309 vput(dvp);
1310 error = vn_stat(vp, &sb, p);
1311 vput(vp);
1312 if (error)
1313 return (error);
1314 } else {
1315 error = vn_stat(dvp, &sb, p);
1316 vput(dvp);
1317 if (error) {
1318 vput(vp);
1319 return (error);
1320 }
1321 error = vn_stat(vp, &sb1, p);
1322 vput(vp);
1323 if (error)
1324 return (error);
1325 sb.st_mode &= ~S_IFDIR;
1326 sb.st_mode |= S_IFLNK;
1327 sb.st_nlink = sb1.st_nlink;
1328 sb.st_size = sb1.st_size;
1329 sb.st_blocks = sb1.st_blocks;
1330 }
1331 cvtstat(&sb, &osb);
1332 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1333 return (error);
1334 }
1335
1336 /*
1337 * Convert from an old to a new stat structure.
1338 */
1339 void
1340 cvtstat(st, ost)
1341 struct stat *st;
1342 struct ostat *ost;
1343 {
1344
1345 ost->st_dev = st->st_dev;
1346 ost->st_ino = st->st_ino;
1347 ost->st_mode = st->st_mode;
1348 ost->st_nlink = st->st_nlink;
1349 ost->st_uid = st->st_uid;
1350 ost->st_gid = st->st_gid;
1351 ost->st_rdev = st->st_rdev;
1352 if (st->st_size < (quad_t)1 << 32)
1353 ost->st_size = st->st_size;
1354 else
1355 ost->st_size = -2;
1356 ost->st_atime = st->st_atime;
1357 ost->st_mtime = st->st_mtime;
1358 ost->st_ctime = st->st_ctime;
1359 ost->st_blksize = st->st_blksize;
1360 ost->st_blocks = st->st_blocks;
1361 ost->st_flags = st->st_flags;
1362 ost->st_gen = st->st_gen;
1363 }
1364 #endif /* COMPAT_43 || COMPAT_SUNOS */
1365
1366 /*
1367 * Get file status; this version follows links.
1368 */
1369 /* ARGSUSED */
1370 int
1371 stat(p, uap, retval)
1372 struct proc *p;
1373 register struct stat_args /* {
1374 syscallarg(char *) path;
1375 syscallarg(struct stat *) ub;
1376 } */ *uap;
1377 register_t *retval;
1378 {
1379 struct stat sb;
1380 int error;
1381 struct nameidata nd;
1382
1383 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1384 SCARG(uap, path), p);
1385 if (error = namei(&nd))
1386 return (error);
1387 error = vn_stat(nd.ni_vp, &sb, p);
1388 vput(nd.ni_vp);
1389 if (error)
1390 return (error);
1391 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1392 return (error);
1393 }
1394
1395 /*
1396 * Get file status; this version does not follow links.
1397 */
1398 /* ARGSUSED */
1399 int
1400 lstat(p, uap, retval)
1401 struct proc *p;
1402 register struct lstat_args /* {
1403 syscallarg(char *) path;
1404 syscallarg(struct stat *) ub;
1405 } */ *uap;
1406 register_t *retval;
1407 {
1408 int error;
1409 struct vnode *vp, *dvp;
1410 struct stat sb, sb1;
1411 struct nameidata nd;
1412
1413 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1414 SCARG(uap, path), p);
1415 if (error = namei(&nd))
1416 return (error);
1417 /*
1418 * For symbolic links, always return the attributes of its containing
1419 * directory, except for mode, size, inode number, and links.
1420 */
1421 vp = nd.ni_vp;
1422 dvp = nd.ni_dvp;
1423 if (vp->v_type != VLNK) {
1424 if (dvp == vp)
1425 vrele(dvp);
1426 else
1427 vput(dvp);
1428 error = vn_stat(vp, &sb, p);
1429 vput(vp);
1430 if (error)
1431 return (error);
1432 } else {
1433 error = vn_stat(dvp, &sb, p);
1434 vput(dvp);
1435 if (error) {
1436 vput(vp);
1437 return (error);
1438 }
1439 error = vn_stat(vp, &sb1, p);
1440 vput(vp);
1441 if (error)
1442 return (error);
1443 sb.st_mode &= ~S_IFDIR;
1444 sb.st_mode |= S_IFLNK;
1445 sb.st_nlink = sb1.st_nlink;
1446 sb.st_size = sb1.st_size;
1447 sb.st_blocks = sb1.st_blocks;
1448 sb.st_ino = sb1.st_ino;
1449 }
1450 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1451 return (error);
1452 }
1453
1454 /*
1455 * Get configurable pathname variables.
1456 */
1457 /* ARGSUSED */
1458 int
1459 pathconf(p, uap, retval)
1460 struct proc *p;
1461 register struct pathconf_args /* {
1462 syscallarg(char *) path;
1463 syscallarg(int) name;
1464 } */ *uap;
1465 register_t *retval;
1466 {
1467 int error;
1468 struct nameidata nd;
1469
1470 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1471 SCARG(uap, path), p);
1472 if (error = namei(&nd))
1473 return (error);
1474 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1475 vput(nd.ni_vp);
1476 return (error);
1477 }
1478
1479 /*
1480 * Return target name of a symbolic link.
1481 */
1482 /* ARGSUSED */
1483 int
1484 readlink(p, uap, retval)
1485 struct proc *p;
1486 register struct readlink_args /* {
1487 syscallarg(char *) path;
1488 syscallarg(char *) buf;
1489 syscallarg(int) count;
1490 } */ *uap;
1491 register_t *retval;
1492 {
1493 register struct vnode *vp;
1494 struct iovec aiov;
1495 struct uio auio;
1496 int error;
1497 struct nameidata nd;
1498
1499 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1500 SCARG(uap, path), p);
1501 if (error = namei(&nd))
1502 return (error);
1503 vp = nd.ni_vp;
1504 if (vp->v_type != VLNK)
1505 error = EINVAL;
1506 else {
1507 aiov.iov_base = SCARG(uap, buf);
1508 aiov.iov_len = SCARG(uap, count);
1509 auio.uio_iov = &aiov;
1510 auio.uio_iovcnt = 1;
1511 auio.uio_offset = 0;
1512 auio.uio_rw = UIO_READ;
1513 auio.uio_segflg = UIO_USERSPACE;
1514 auio.uio_procp = p;
1515 auio.uio_resid = SCARG(uap, count);
1516 error = VOP_READLINK(vp, &auio, p->p_ucred);
1517 }
1518 vput(vp);
1519 *retval = SCARG(uap, count) - auio.uio_resid;
1520 return (error);
1521 }
1522
1523 /*
1524 * Change flags of a file given a path name.
1525 */
1526 /* ARGSUSED */
1527 int
1528 chflags(p, uap, retval)
1529 struct proc *p;
1530 register struct chflags_args /* {
1531 syscallarg(char *) path;
1532 syscallarg(int) flags;
1533 } */ *uap;
1534 register_t *retval;
1535 {
1536 register struct vnode *vp;
1537 struct vattr vattr;
1538 int error;
1539 struct nameidata nd;
1540
1541 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1542 if (error = namei(&nd))
1543 return (error);
1544 vp = nd.ni_vp;
1545 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1546 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1547 VATTR_NULL(&vattr);
1548 vattr.va_flags = SCARG(uap, flags);
1549 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1550 vput(vp);
1551 return (error);
1552 }
1553
1554 /*
1555 * Change flags of a file given a file descriptor.
1556 */
1557 /* ARGSUSED */
1558 int
1559 fchflags(p, uap, retval)
1560 struct proc *p;
1561 register struct fchflags_args /* {
1562 syscallarg(int) fd;
1563 syscallarg(int) flags;
1564 } */ *uap;
1565 register_t *retval;
1566 {
1567 struct vattr vattr;
1568 struct vnode *vp;
1569 struct file *fp;
1570 int error;
1571
1572 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1573 return (error);
1574 vp = (struct vnode *)fp->f_data;
1575 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1576 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1577 VATTR_NULL(&vattr);
1578 vattr.va_flags = SCARG(uap, flags);
1579 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1580 VOP_UNLOCK(vp, 0, p);
1581 return (error);
1582 }
1583
1584 /*
1585 * Change mode of a file given path name.
1586 */
1587 /* ARGSUSED */
1588 int
1589 chmod(p, uap, retval)
1590 struct proc *p;
1591 register struct chmod_args /* {
1592 syscallarg(char *) path;
1593 syscallarg(int) mode;
1594 } */ *uap;
1595 register_t *retval;
1596 {
1597 register struct vnode *vp;
1598 struct vattr vattr;
1599 int error;
1600 struct nameidata nd;
1601
1602 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1603 if (error = namei(&nd))
1604 return (error);
1605 vp = nd.ni_vp;
1606 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1607 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1608 VATTR_NULL(&vattr);
1609 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1610 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1611 vput(vp);
1612 return (error);
1613 }
1614
1615 /*
1616 * Change mode of a file given a file descriptor.
1617 */
1618 /* ARGSUSED */
1619 int
1620 fchmod(p, uap, retval)
1621 struct proc *p;
1622 register struct fchmod_args /* {
1623 syscallarg(int) fd;
1624 syscallarg(int) mode;
1625 } */ *uap;
1626 register_t *retval;
1627 {
1628 struct vattr vattr;
1629 struct vnode *vp;
1630 struct file *fp;
1631 int error;
1632
1633 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1634 return (error);
1635 vp = (struct vnode *)fp->f_data;
1636 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1637 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1638 VATTR_NULL(&vattr);
1639 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1640 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1641 VOP_UNLOCK(vp, 0, p);
1642 return (error);
1643 }
1644
1645 /*
1646 * Set ownership given a path name.
1647 */
1648 /* ARGSUSED */
1649 int
1650 chown(p, uap, retval)
1651 struct proc *p;
1652 register struct chown_args /* {
1653 syscallarg(char *) path;
1654 syscallarg(int) uid;
1655 syscallarg(int) gid;
1656 } */ *uap;
1657 register_t *retval;
1658 {
1659 register struct vnode *vp;
1660 struct vattr vattr;
1661 int error;
1662 struct nameidata nd;
1663
1664 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1665 if (error = namei(&nd))
1666 return (error);
1667 vp = nd.ni_vp;
1668 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1669 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1670 VATTR_NULL(&vattr);
1671 vattr.va_uid = SCARG(uap, uid);
1672 vattr.va_gid = SCARG(uap, gid);
1673 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1674 vput(vp);
1675 return (error);
1676 }
1677
1678 /*
1679 * Set ownership given a file descriptor.
1680 */
1681 /* ARGSUSED */
1682 int
1683 fchown(p, uap, retval)
1684 struct proc *p;
1685 register struct fchown_args /* {
1686 syscallarg(int) fd;
1687 syscallarg(int) uid;
1688 syscallarg(int) gid;
1689 } */ *uap;
1690 register_t *retval;
1691 {
1692 struct vattr vattr;
1693 struct vnode *vp;
1694 struct file *fp;
1695 int error;
1696
1697 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1698 return (error);
1699 vp = (struct vnode *)fp->f_data;
1700 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1701 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1702 VATTR_NULL(&vattr);
1703 vattr.va_uid = SCARG(uap, uid);
1704 vattr.va_gid = SCARG(uap, gid);
1705 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1706 VOP_UNLOCK(vp, 0, p);
1707 return (error);
1708 }
1709
1710 /*
1711 * Set the access and modification times of a file.
1712 */
1713 /* ARGSUSED */
1714 int
1715 utimes(p, uap, retval)
1716 struct proc *p;
1717 register struct utimes_args /* {
1718 syscallarg(char *) path;
1719 syscallarg(struct timeval *) tptr;
1720 } */ *uap;
1721 register_t *retval;
1722 {
1723 register struct vnode *vp;
1724 struct timeval tv[2];
1725 struct vattr vattr;
1726 int error;
1727 struct nameidata nd;
1728
1729 VATTR_NULL(&vattr);
1730 if (SCARG(uap, tptr) == NULL) {
1731 microtime(&tv[0]);
1732 tv[1] = tv[0];
1733 vattr.va_vaflags |= VA_UTIMES_NULL;
1734 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1735 sizeof (tv)))
1736 return (error);
1737 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1738 if (error = namei(&nd))
1739 return (error);
1740 vp = nd.ni_vp;
1741 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1742 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1743 vattr.va_atime.ts_sec = tv[0].tv_sec;
1744 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1745 vattr.va_mtime.ts_sec = tv[1].tv_sec;
1746 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
1747 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1748 vput(vp);
1749 return (error);
1750 }
1751
1752 /*
1753 * Truncate a file given its path name.
1754 */
1755 /* ARGSUSED */
1756 int
1757 truncate(p, uap, retval)
1758 struct proc *p;
1759 register struct truncate_args /* {
1760 syscallarg(char *) path;
1761 syscallarg(int) pad;
1762 syscallarg(off_t) length;
1763 } */ *uap;
1764 register_t *retval;
1765 {
1766 register struct vnode *vp;
1767 struct vattr vattr;
1768 int error;
1769 struct nameidata nd;
1770
1771 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1772 if (error = namei(&nd))
1773 return (error);
1774 vp = nd.ni_vp;
1775 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1776 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1777 if (vp->v_type == VDIR)
1778 error = EISDIR;
1779 else if ((error = vn_writechk(vp)) == 0 &&
1780 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1781 VATTR_NULL(&vattr);
1782 vattr.va_size = SCARG(uap, length);
1783 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1784 }
1785 vput(vp);
1786 return (error);
1787 }
1788
1789 /*
1790 * Truncate a file given a file descriptor.
1791 */
1792 /* ARGSUSED */
1793 int
1794 ftruncate(p, uap, retval)
1795 struct proc *p;
1796 register struct ftruncate_args /* {
1797 syscallarg(int) fd;
1798 syscallarg(int) pad;
1799 syscallarg(off_t) length;
1800 } */ *uap;
1801 register_t *retval;
1802 {
1803 struct vattr vattr;
1804 struct vnode *vp;
1805 struct file *fp;
1806 int error;
1807
1808 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1809 return (error);
1810 if ((fp->f_flag & FWRITE) == 0)
1811 return (EINVAL);
1812 vp = (struct vnode *)fp->f_data;
1813 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1814 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1815 if (vp->v_type == VDIR)
1816 error = EISDIR;
1817 else if ((error = vn_writechk(vp)) == 0) {
1818 VATTR_NULL(&vattr);
1819 vattr.va_size = SCARG(uap, length);
1820 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1821 }
1822 VOP_UNLOCK(vp, 0, p);
1823 return (error);
1824 }
1825
1826 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1827 /*
1828 * Truncate a file given its path name.
1829 */
1830 /* ARGSUSED */
1831 int
1832 compat_43_truncate(p, uap, retval)
1833 struct proc *p;
1834 register struct compat_43_truncate_args /* {
1835 syscallarg(char *) path;
1836 syscallarg(long) length;
1837 } */ *uap;
1838 register_t *retval;
1839 {
1840 struct truncate_args /* {
1841 syscallarg(char *) path;
1842 syscallarg(int) pad;
1843 syscallarg(off_t) length;
1844 } */ nuap;
1845
1846 SCARG(&nuap, path) = SCARG(uap, path);
1847 SCARG(&nuap, length) = SCARG(uap, length);
1848 return (truncate(p, &nuap, retval));
1849 }
1850
1851 /*
1852 * Truncate a file given a file descriptor.
1853 */
1854 /* ARGSUSED */
1855 int
1856 compat_43_ftruncate(p, uap, retval)
1857 struct proc *p;
1858 register struct compat_43_ftruncate_args /* {
1859 syscallarg(int) fd;
1860 syscallarg(long) length;
1861 } */ *uap;
1862 register_t *retval;
1863 {
1864 struct ftruncate_args /* {
1865 syscallarg(int) fd;
1866 syscallarg(int) pad;
1867 syscallarg(off_t) length;
1868 } */ nuap;
1869
1870 SCARG(&nuap, fd) = SCARG(uap, fd);
1871 SCARG(&nuap, length) = SCARG(uap, length);
1872 return (ftruncate(p, &nuap, retval));
1873 }
1874 #endif /* COMPAT_43 || COMPAT_SUNOS */
1875
1876 /*
1877 * Sync an open file.
1878 */
1879 /* ARGSUSED */
1880 int
1881 fsync(p, uap, retval)
1882 struct proc *p;
1883 struct fsync_args /* {
1884 syscallarg(int) fd;
1885 } */ *uap;
1886 register_t *retval;
1887 {
1888 register struct vnode *vp;
1889 struct file *fp;
1890 int error;
1891
1892 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1893 return (error);
1894 vp = (struct vnode *)fp->f_data;
1895 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1896 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
1897 VOP_UNLOCK(vp, 0, p);
1898 return (error);
1899 }
1900
1901 /*
1902 * Rename files. Source and destination must either both be directories,
1903 * or both not be directories. If target is a directory, it must be empty.
1904 */
1905 /* ARGSUSED */
1906 int
1907 rename(p, uap, retval)
1908 struct proc *p;
1909 register struct rename_args /* {
1910 syscallarg(char *) from;
1911 syscallarg(char *) to;
1912 } */ *uap;
1913 register_t *retval;
1914 {
1915 register struct vnode *tvp, *fvp, *tdvp;
1916 struct nameidata fromnd, tond;
1917 int error;
1918
1919 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1920 SCARG(uap, from), p);
1921 if (error = namei(&fromnd))
1922 return (error);
1923 fvp = fromnd.ni_vp;
1924 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
1925 UIO_USERSPACE, SCARG(uap, to), p);
1926 if (error = namei(&tond)) {
1927 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1928 vrele(fromnd.ni_dvp);
1929 vrele(fvp);
1930 goto out1;
1931 }
1932 tdvp = tond.ni_dvp;
1933 tvp = tond.ni_vp;
1934 if (tvp != NULL) {
1935 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1936 error = ENOTDIR;
1937 goto out;
1938 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1939 error = EISDIR;
1940 goto out;
1941 }
1942 }
1943 if (fvp == tdvp)
1944 error = EINVAL;
1945 /*
1946 * If source is the same as the destination (that is the
1947 * same inode number with the same name in the same directory),
1948 * then there is nothing to do.
1949 */
1950 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1951 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1952 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1953 fromnd.ni_cnd.cn_namelen))
1954 error = -1;
1955 out:
1956 if (!error) {
1957 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
1958 if (fromnd.ni_dvp != tdvp)
1959 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1960 if (tvp)
1961 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
1962 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1963 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1964 } else {
1965 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1966 if (tdvp == tvp)
1967 vrele(tdvp);
1968 else
1969 vput(tdvp);
1970 if (tvp)
1971 vput(tvp);
1972 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1973 vrele(fromnd.ni_dvp);
1974 vrele(fvp);
1975 }
1976 vrele(tond.ni_startdir);
1977 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1978 out1:
1979 if (fromnd.ni_startdir)
1980 vrele(fromnd.ni_startdir);
1981 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1982 if (error == -1)
1983 return (0);
1984 return (error);
1985 }
1986
1987 /*
1988 * Make a directory file.
1989 */
1990 /* ARGSUSED */
1991 int
1992 mkdir(p, uap, retval)
1993 struct proc *p;
1994 register struct mkdir_args /* {
1995 syscallarg(char *) path;
1996 syscallarg(int) mode;
1997 } */ *uap;
1998 register_t *retval;
1999 {
2000 register struct vnode *vp;
2001 struct vattr vattr;
2002 int error;
2003 struct nameidata nd;
2004
2005 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2006 if (error = namei(&nd))
2007 return (error);
2008 vp = nd.ni_vp;
2009 if (vp != NULL) {
2010 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2011 if (nd.ni_dvp == vp)
2012 vrele(nd.ni_dvp);
2013 else
2014 vput(nd.ni_dvp);
2015 vrele(vp);
2016 return (EEXIST);
2017 }
2018 VATTR_NULL(&vattr);
2019 vattr.va_type = VDIR;
2020 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2021 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2022 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2023 if (!error)
2024 vput(nd.ni_vp);
2025 return (error);
2026 }
2027
2028 /*
2029 * Remove a directory file.
2030 */
2031 /* ARGSUSED */
2032 int
2033 rmdir(p, uap, retval)
2034 struct proc *p;
2035 struct rmdir_args /* {
2036 syscallarg(char *) path;
2037 } */ *uap;
2038 register_t *retval;
2039 {
2040 register struct vnode *vp;
2041 int error;
2042 struct nameidata nd;
2043
2044 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2045 SCARG(uap, path), p);
2046 if (error = namei(&nd))
2047 return (error);
2048 vp = nd.ni_vp;
2049 if (vp->v_type != VDIR) {
2050 error = ENOTDIR;
2051 goto out;
2052 }
2053 /*
2054 * No rmdir "." please.
2055 */
2056 if (nd.ni_dvp == vp) {
2057 error = EINVAL;
2058 goto out;
2059 }
2060 /*
2061 * The root of a mounted filesystem cannot be deleted.
2062 */
2063 if (vp->v_flag & VROOT)
2064 error = EBUSY;
2065 out:
2066 if (!error) {
2067 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2068 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2069 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2070 } else {
2071 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2072 if (nd.ni_dvp == vp)
2073 vrele(nd.ni_dvp);
2074 else
2075 vput(nd.ni_dvp);
2076 vput(vp);
2077 }
2078 return (error);
2079 }
2080
2081 #ifdef COMPAT_43
2082 /*
2083 * Read a block of directory entries in a file system independent format.
2084 */
2085 int
2086 compat_43_getdirentries(p, uap, retval)
2087 struct proc *p;
2088 register struct compat_43_getdirentries_args /* {
2089 syscallarg(int) fd;
2090 syscallarg(char *) buf;
2091 syscallarg(u_int) count;
2092 syscallarg(long *) basep;
2093 } */ *uap;
2094 register_t *retval;
2095 {
2096 register struct vnode *vp;
2097 struct file *fp;
2098 struct uio auio, kuio;
2099 struct iovec aiov, kiov;
2100 struct dirent *dp, *edp;
2101 caddr_t dirbuf;
2102 int error, eofflag, readcnt;
2103 long loff;
2104
2105 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2106 return (error);
2107 if ((fp->f_flag & FREAD) == 0)
2108 return (EBADF);
2109 vp = (struct vnode *)fp->f_data;
2110 unionread:
2111 if (vp->v_type != VDIR)
2112 return (EINVAL);
2113 aiov.iov_base = SCARG(uap, buf);
2114 aiov.iov_len = SCARG(uap, count);
2115 auio.uio_iov = &aiov;
2116 auio.uio_iovcnt = 1;
2117 auio.uio_rw = UIO_READ;
2118 auio.uio_segflg = UIO_USERSPACE;
2119 auio.uio_procp = p;
2120 auio.uio_resid = SCARG(uap, count);
2121 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2122 loff = auio.uio_offset = fp->f_offset;
2123 # if (BYTE_ORDER != LITTLE_ENDIAN)
2124 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2125 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2126 (int *)0, (u_long *)0);
2127 fp->f_offset = auio.uio_offset;
2128 } else
2129 # endif
2130 {
2131 kuio = auio;
2132 kuio.uio_iov = &kiov;
2133 kuio.uio_segflg = UIO_SYSSPACE;
2134 kiov.iov_len = SCARG(uap, count);
2135 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2136 kiov.iov_base = dirbuf;
2137 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2138 (int *)0, (u_long *)0);
2139 fp->f_offset = kuio.uio_offset;
2140 if (error == 0) {
2141 readcnt = SCARG(uap, count) - kuio.uio_resid;
2142 edp = (struct dirent *)&dirbuf[readcnt];
2143 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2144 # if (BYTE_ORDER == LITTLE_ENDIAN)
2145 /*
2146 * The expected low byte of
2147 * dp->d_namlen is our dp->d_type.
2148 * The high MBZ byte of dp->d_namlen
2149 * is our dp->d_namlen.
2150 */
2151 dp->d_type = dp->d_namlen;
2152 dp->d_namlen = 0;
2153 # else
2154 /*
2155 * The dp->d_type is the high byte
2156 * of the expected dp->d_namlen,
2157 * so must be zero'ed.
2158 */
2159 dp->d_type = 0;
2160 # endif
2161 if (dp->d_reclen > 0) {
2162 dp = (struct dirent *)
2163 ((char *)dp + dp->d_reclen);
2164 } else {
2165 error = EIO;
2166 break;
2167 }
2168 }
2169 if (dp >= edp)
2170 error = uiomove(dirbuf, readcnt, &auio);
2171 }
2172 FREE(dirbuf, M_TEMP);
2173 }
2174 VOP_UNLOCK(vp, 0, p);
2175 if (error)
2176 return (error);
2177
2178 #ifdef UNION
2179 {
2180 extern int (**union_vnodeop_p)();
2181 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2182
2183 if ((SCARG(uap, count) == auio.uio_resid) &&
2184 (vp->v_op == union_vnodeop_p)) {
2185 struct vnode *lvp;
2186
2187 lvp = union_dircache(vp, p);
2188 if (lvp != NULLVP) {
2189 struct vattr va;
2190
2191 /*
2192 * If the directory is opaque,
2193 * then don't show lower entries
2194 */
2195 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2196 if (va.va_flags & OPAQUE) {
2197 vput(lvp);
2198 lvp = NULL;
2199 }
2200 }
2201
2202 if (lvp != NULLVP) {
2203 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2204 if (error) {
2205 vput(lvp);
2206 return (error);
2207 }
2208 VOP_UNLOCK(lvp, 0, p);
2209 fp->f_data = (caddr_t) lvp;
2210 fp->f_offset = 0;
2211 error = vn_close(vp, FREAD, fp->f_cred, p);
2212 if (error)
2213 return (error);
2214 vp = lvp;
2215 goto unionread;
2216 }
2217 }
2218 }
2219 #endif /* UNION */
2220
2221 if ((SCARG(uap, count) == auio.uio_resid) &&
2222 (vp->v_flag & VROOT) &&
2223 (vp->v_mount->mnt_flag & MNT_UNION)) {
2224 struct vnode *tvp = vp;
2225 vp = vp->v_mount->mnt_vnodecovered;
2226 VREF(vp);
2227 fp->f_data = (caddr_t) vp;
2228 fp->f_offset = 0;
2229 vrele(tvp);
2230 goto unionread;
2231 }
2232 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2233 sizeof(long));
2234 *retval = SCARG(uap, count) - auio.uio_resid;
2235 return (error);
2236 }
2237 #endif /* COMPAT_43 */
2238
2239 /*
2240 * Read a block of directory entries in a file system independent format.
2241 */
2242 int
2243 getdirentries(p, uap, retval)
2244 struct proc *p;
2245 register struct getdirentries_args /* {
2246 syscallarg(int) fd;
2247 syscallarg(char *) buf;
2248 syscallarg(u_int) count;
2249 syscallarg(long *) basep;
2250 } */ *uap;
2251 register_t *retval;
2252 {
2253 register struct vnode *vp;
2254 struct file *fp;
2255 struct uio auio;
2256 struct iovec aiov;
2257 long loff;
2258 int error, eofflag;
2259
2260 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2261 return (error);
2262 if ((fp->f_flag & FREAD) == 0)
2263 return (EBADF);
2264 vp = (struct vnode *)fp->f_data;
2265 unionread:
2266 if (vp->v_type != VDIR)
2267 return (EINVAL);
2268 aiov.iov_base = SCARG(uap, buf);
2269 aiov.iov_len = SCARG(uap, count);
2270 auio.uio_iov = &aiov;
2271 auio.uio_iovcnt = 1;
2272 auio.uio_rw = UIO_READ;
2273 auio.uio_segflg = UIO_USERSPACE;
2274 auio.uio_procp = p;
2275 auio.uio_resid = SCARG(uap, count);
2276 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2277 loff = auio.uio_offset = fp->f_offset;
2278 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2279 (int *)0, (u_long *)0);
2280 fp->f_offset = auio.uio_offset;
2281 VOP_UNLOCK(vp, 0, p);
2282 if (error)
2283 return (error);
2284
2285 #ifdef UNION
2286 {
2287 extern int (**union_vnodeop_p)();
2288 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2289
2290 if ((SCARG(uap, count) == auio.uio_resid) &&
2291 (vp->v_op == union_vnodeop_p)) {
2292 struct vnode *lvp;
2293
2294 lvp = union_dircache(vp, p);
2295 if (lvp != NULLVP) {
2296 struct vattr va;
2297
2298 /*
2299 * If the directory is opaque,
2300 * then don't show lower entries
2301 */
2302 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2303 if (va.va_flags & OPAQUE) {
2304 vput(lvp);
2305 lvp = NULL;
2306 }
2307 }
2308
2309 if (lvp != NULLVP) {
2310 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2311 if (error) {
2312 vput(lvp);
2313 return (error);
2314 }
2315 VOP_UNLOCK(lvp, 0, p);
2316 fp->f_data = (caddr_t) lvp;
2317 fp->f_offset = 0;
2318 error = vn_close(vp, FREAD, fp->f_cred, p);
2319 if (error)
2320 return (error);
2321 vp = lvp;
2322 goto unionread;
2323 }
2324 }
2325 }
2326 #endif /* UNION */
2327
2328 if ((SCARG(uap, count) == auio.uio_resid) &&
2329 (vp->v_flag & VROOT) &&
2330 (vp->v_mount->mnt_flag & MNT_UNION)) {
2331 struct vnode *tvp = vp;
2332 vp = vp->v_mount->mnt_vnodecovered;
2333 VREF(vp);
2334 fp->f_data = (caddr_t) vp;
2335 fp->f_offset = 0;
2336 vrele(tvp);
2337 goto unionread;
2338 }
2339 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2340 sizeof(long));
2341 *retval = SCARG(uap, count) - auio.uio_resid;
2342 return (error);
2343 }
2344
2345 /*
2346 * Set the mode mask for creation of filesystem nodes.
2347 */
2348 int
2349 umask(p, uap, retval)
2350 struct proc *p;
2351 struct umask_args /* {
2352 syscallarg(int) newmask;
2353 } */ *uap;
2354 register_t *retval;
2355 {
2356 register struct filedesc *fdp;
2357
2358 fdp = p->p_fd;
2359 *retval = fdp->fd_cmask;
2360 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2361 return (0);
2362 }
2363
2364 /*
2365 * Void all references to file by ripping underlying filesystem
2366 * away from vnode.
2367 */
2368 /* ARGSUSED */
2369 int
2370 revoke(p, uap, retval)
2371 struct proc *p;
2372 register struct revoke_args /* {
2373 syscallarg(char *) path;
2374 } */ *uap;
2375 register_t *retval;
2376 {
2377 register struct vnode *vp;
2378 struct vattr vattr;
2379 int error;
2380 struct nameidata nd;
2381
2382 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2383 if (error = namei(&nd))
2384 return (error);
2385 vp = nd.ni_vp;
2386 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2387 goto out;
2388 if (p->p_ucred->cr_uid != vattr.va_uid &&
2389 (error = suser(p->p_ucred, &p->p_acflag)))
2390 goto out;
2391 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2392 VOP_REVOKE(vp, REVOKEALL);
2393 out:
2394 vrele(vp);
2395 return (error);
2396 }
2397
2398 /*
2399 * Convert a user file descriptor to a kernel file entry.
2400 */
2401 int
2402 getvnode(fdp, fd, fpp)
2403 struct filedesc *fdp;
2404 struct file **fpp;
2405 int fd;
2406 {
2407 struct file *fp;
2408
2409 if ((u_int)fd >= fdp->fd_nfiles ||
2410 (fp = fdp->fd_ofiles[fd]) == NULL)
2411 return (EBADF);
2412 if (fp->f_type != DTYPE_VNODE)
2413 return (EINVAL);
2414 *fpp = fp;
2415 return (0);
2416 }
2417