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