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