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