vfs_syscalls.c revision 1.142 1 /* $NetBSD: vfs_syscalls.c,v 1.142 1999/07/04 16:20:13 sommerfeld 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.42 (Berkeley) 7/31/95
41 */
42
43 #include "opt_compat_netbsd.h"
44 #include "opt_compat_43.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/namei.h>
49 #include <sys/filedesc.h>
50 #include <sys/kernel.h>
51 #include <sys/file.h>
52 #include <sys/stat.h>
53 #include <sys/vnode.h>
54 #include <sys/mount.h>
55 #include <sys/proc.h>
56 #include <sys/uio.h>
57 #include <sys/malloc.h>
58 #include <sys/dirent.h>
59
60 #include <sys/syscallargs.h>
61
62 #include <vm/vm.h>
63 #include <sys/sysctl.h>
64
65 #include <uvm/uvm_extern.h>
66
67 static int change_dir __P((struct nameidata *, struct proc *));
68 static int change_mode __P((struct vnode *, int, struct proc *p));
69 static int change_owner __P((struct vnode *, uid_t, gid_t, struct proc *,
70 int));
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 /*
87 * This table is used to maintain compatibility with 4.3BSD
88 * and NetBSD 0.9 mount syscalls. Note, the order is important!
89 *
90 * Also note that not all of these had actual numbers in 4.3BSD
91 * or NetBSD 0.9!
92 */
93 const char *mountcompatnames[] = {
94 NULL, /* 0 = MOUNT_NONE */
95 MOUNT_FFS, /* 1 */
96 MOUNT_NFS, /* 2 */
97 MOUNT_MFS, /* 3 */
98 MOUNT_MSDOS, /* 4 */
99 MOUNT_LFS, /* 5 */
100 NULL, /* 6 = MOUNT_LOFS */
101 MOUNT_FDESC, /* 7 */
102 MOUNT_PORTAL, /* 8 */
103 MOUNT_NULL, /* 9 */
104 MOUNT_UMAP, /* 10 */
105 MOUNT_KERNFS, /* 11 */
106 MOUNT_PROCFS, /* 12 */
107 MOUNT_AFS, /* 13 */
108 MOUNT_CD9660, /* 14 = MOUNT_ISOFS */
109 MOUNT_UNION, /* 15 */
110 MOUNT_ADOSFS, /* 16 */
111 MOUNT_EXT2FS, /* 17 */
112 MOUNT_CODA, /* 18 */
113 MOUNT_FILECORE, /* 19 */
114 MOUNT_NTFS, /* 20 */
115 };
116 const int nmountcompatnames = sizeof(mountcompatnames) /
117 sizeof(mountcompatnames[0]);
118
119 /* ARGSUSED */
120 int
121 sys_mount(p, v, retval)
122 struct proc *p;
123 void *v;
124 register_t *retval;
125 {
126 register struct sys_mount_args /* {
127 syscallarg(const char *) type;
128 syscallarg(const char *) path;
129 syscallarg(int) flags;
130 syscallarg(void *) data;
131 } */ *uap = v;
132 struct vnode *vp;
133 struct mount *mp;
134 int error, flag = 0;
135 char fstypename[MFSNAMELEN];
136 struct vattr va;
137 struct nameidata nd;
138 struct vfsops *vfs;
139
140 /*
141 * Get vnode to be covered
142 */
143 NDINIT(&nd, LOOKUP, FOLLOW , UIO_USERSPACE,
144 SCARG(uap, path), p);
145 if ((error = namei(&nd)) != 0)
146 return (error);
147 vp = nd.ni_vp;
148 /*
149 * A lookup in VFS_MOUNT might result in an attempt to
150 * lock this vnode again, so make the lock resursive.
151 */
152 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_SETRECURSE);
153 if (SCARG(uap, flags) & MNT_UPDATE) {
154 if ((vp->v_flag & VROOT) == 0) {
155 vput(vp);
156 return (EINVAL);
157 }
158 mp = vp->v_mount;
159 flag = mp->mnt_flag;
160 vfs = mp->mnt_op;
161 /*
162 * We only allow the filesystem to be reloaded if it
163 * is currently mounted read-only.
164 */
165 if ((SCARG(uap, flags) & MNT_RELOAD) &&
166 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
167 vput(vp);
168 return (EOPNOTSUPP); /* Needs translation */
169 }
170 /*
171 * In "highly secure" mode, don't let the caller do anything
172 * but downgrade a filesystem from read-write to read-only.
173 * (see also below; MNT_UPDATE is required.)
174 */
175 if (securelevel >= 2 &&
176 (SCARG(uap, flags) !=
177 (mp->mnt_flag | MNT_RDONLY |
178 MNT_RELOAD | MNT_FORCE | MNT_UPDATE))) {
179 vput(vp);
180 return (EPERM);
181 }
182 mp->mnt_flag |=
183 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
184 /*
185 * Only root, or the user that did the original mount is
186 * permitted to update it.
187 */
188 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
189 (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
190 vput(vp);
191 return (error);
192 }
193 /*
194 * Do not allow NFS export by non-root users. For non-root
195 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
196 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
197 */
198 if (p->p_ucred->cr_uid != 0) {
199 if (SCARG(uap, flags) & MNT_EXPORTED) {
200 vput(vp);
201 return (EPERM);
202 }
203 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
204 if (flag & MNT_NOEXEC)
205 SCARG(uap, flags) |= MNT_NOEXEC;
206 }
207 if (vfs_busy(mp, LK_NOWAIT, 0)) {
208 vput(vp);
209 return (EPERM);
210 }
211 VOP_UNLOCK(vp, 0);
212 goto update;
213 } else {
214 if (securelevel >= 2)
215 return (EPERM);
216 }
217 /*
218 * If the user is not root, ensure that they own the directory
219 * onto which we are attempting to mount.
220 */
221 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0 ||
222 (va.va_uid != p->p_ucred->cr_uid &&
223 (error = suser(p->p_ucred, &p->p_acflag)) != 0)) {
224 vput(vp);
225 return (error);
226 }
227 /*
228 * Do not allow NFS export by non-root users. For non-root users,
229 * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
230 * mount point is already MNT_NOEXEC.
231 */
232 if (p->p_ucred->cr_uid != 0) {
233 if (SCARG(uap, flags) & MNT_EXPORTED) {
234 vput(vp);
235 return (EPERM);
236 }
237 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
238 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
239 SCARG(uap, flags) |= MNT_NOEXEC;
240 }
241 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
242 return (error);
243 if (vp->v_type != VDIR) {
244 vput(vp);
245 return (ENOTDIR);
246 }
247 error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
248 if (error) {
249 #if defined(COMPAT_09) || defined(COMPAT_43)
250 /*
251 * Historically filesystem types were identified by number.
252 * If we get an integer for the filesystem type instead of a
253 * string, we check to see if it matches one of the historic
254 * filesystem types.
255 */
256 u_long fsindex = (u_long)SCARG(uap, type);
257 if (fsindex >= nmountcompatnames ||
258 mountcompatnames[fsindex] == NULL) {
259 vput(vp);
260 return (ENODEV);
261 }
262 strncpy(fstypename, mountcompatnames[fsindex], MFSNAMELEN);
263 #else
264 vput(vp);
265 return (error);
266 #endif
267 }
268 #ifdef COMPAT_10
269 /* Accept `ufs' as an alias for `ffs'. */
270 if (!strncmp(fstypename, "ufs", MFSNAMELEN))
271 strncpy(fstypename, "ffs", MFSNAMELEN);
272 #endif
273 if ((vfs = vfs_getopsbyname(fstypename)) == NULL) {
274 vput(vp);
275 return (ENODEV);
276 }
277 if (vp->v_mountedhere != NULL) {
278 vput(vp);
279 return (EBUSY);
280 }
281
282 /*
283 * Allocate and initialize the file system.
284 */
285 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
286 M_MOUNT, M_WAITOK);
287 memset((char *)mp, 0, (u_long)sizeof(struct mount));
288 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
289 (void)vfs_busy(mp, LK_NOWAIT, 0);
290 mp->mnt_op = vfs;
291 vfs->vfs_refcount++;
292 mp->mnt_vnodecovered = vp;
293 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
294 update:
295 /*
296 * Set the mount level flags.
297 */
298 if (SCARG(uap, flags) & MNT_RDONLY)
299 mp->mnt_flag |= MNT_RDONLY;
300 else if (mp->mnt_flag & MNT_RDONLY)
301 mp->mnt_flag |= MNT_WANTRDWR;
302 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
303 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
304 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM);
305 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
306 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |
307 MNT_NOCOREDUMP | MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM);
308 /*
309 * Mount the filesystem.
310 */
311 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
312 if (mp->mnt_flag & MNT_UPDATE) {
313 vrele(vp);
314 if (mp->mnt_flag & MNT_WANTRDWR)
315 mp->mnt_flag &= ~MNT_RDONLY;
316 mp->mnt_flag &=~
317 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
318 if (error)
319 mp->mnt_flag = flag;
320 vfs_unbusy(mp);
321 return (error);
322 }
323 /*
324 * Put the new filesystem on the mount list after root.
325 */
326 cache_purge(vp);
327 if (!error) {
328 vp->v_mountedhere = mp;
329 simple_lock(&mountlist_slock);
330 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
331 simple_unlock(&mountlist_slock);
332 checkdirs(vp);
333 VOP_UNLOCK(vp, 0);
334 vfs_unbusy(mp);
335 (void) VFS_STATFS(mp, &mp->mnt_stat, p);
336 if ((error = VFS_START(mp, 0, p)))
337 vrele(vp);
338 } else {
339 vp->v_mountedhere = (struct mount *)0;
340 vfs->vfs_refcount--;
341 vfs_unbusy(mp);
342 free((caddr_t)mp, M_MOUNT);
343 vput(vp);
344 }
345 return (error);
346 }
347
348 /*
349 * Scan all active processes to see if any of them have a current
350 * or root directory onto which the new filesystem has just been
351 * mounted. If so, replace them with the new mount point.
352 */
353 void
354 checkdirs(olddp)
355 struct vnode *olddp;
356 {
357 struct cwdinfo *cwdi;
358 struct vnode *newdp;
359 struct proc *p;
360
361 if (olddp->v_usecount == 1)
362 return;
363 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
364 panic("mount: lost mount");
365 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
366 cwdi = p->p_cwdi;
367 if (cwdi->cwdi_cdir == olddp) {
368 vrele(cwdi->cwdi_cdir);
369 VREF(newdp);
370 cwdi->cwdi_cdir = newdp;
371 }
372 if (cwdi->cwdi_rdir == olddp) {
373 vrele(cwdi->cwdi_rdir);
374 VREF(newdp);
375 cwdi->cwdi_rdir = newdp;
376 }
377 }
378 if (rootvnode == olddp) {
379 vrele(rootvnode);
380 VREF(newdp);
381 rootvnode = newdp;
382 }
383 vput(newdp);
384 }
385
386 /*
387 * Unmount a file system.
388 *
389 * Note: unmount takes a path to the vnode mounted on as argument,
390 * not special file (as before).
391 */
392 /* ARGSUSED */
393 int
394 sys_unmount(p, v, retval)
395 struct proc *p;
396 void *v;
397 register_t *retval;
398 {
399 register struct sys_unmount_args /* {
400 syscallarg(const char *) path;
401 syscallarg(int) flags;
402 } */ *uap = v;
403 register struct vnode *vp;
404 struct mount *mp;
405 int error;
406 struct nameidata nd;
407
408 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
409 SCARG(uap, path), p);
410 if ((error = namei(&nd)) != 0)
411 return (error);
412 vp = nd.ni_vp;
413 mp = vp->v_mount;
414
415 /*
416 * Only root, or the user that did the original mount is
417 * permitted to unmount this filesystem.
418 */
419 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
420 (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
421 vput(vp);
422 return (error);
423 }
424
425 /*
426 * Don't allow unmounting the root file system.
427 */
428 if (mp->mnt_flag & MNT_ROOTFS) {
429 vput(vp);
430 return (EINVAL);
431 }
432
433 /*
434 * Must be the root of the filesystem
435 */
436 if ((vp->v_flag & VROOT) == 0) {
437 vput(vp);
438 return (EINVAL);
439 }
440 vput(vp);
441
442 if (vfs_busy(mp, 0, 0))
443 return (EBUSY);
444
445 return (dounmount(mp, SCARG(uap, flags), p));
446 }
447
448 /*
449 * Do the actual file system unmount. File system is assumed to have been
450 * marked busy by the caller.
451 */
452 int
453 dounmount(mp, flags, p)
454 register struct mount *mp;
455 int flags;
456 struct proc *p;
457 {
458 struct vnode *coveredvp;
459 int error;
460 int async;
461
462 simple_lock(&mountlist_slock);
463 mp->mnt_flag |= MNT_UNMOUNT;
464 vfs_unbusy(mp);
465 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock);
466 if (mp->mnt_flag & MNT_EXPUBLIC)
467 vfs_setpublicfs(NULL, NULL, NULL);
468 async = mp->mnt_flag & MNT_ASYNC;
469 mp->mnt_flag &=~ MNT_ASYNC;
470 cache_purgevfs(mp); /* remove cache entries for this file sys */
471 if (((mp->mnt_flag & MNT_RDONLY) ||
472 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
473 (flags & MNT_FORCE))
474 error = VFS_UNMOUNT(mp, flags, p);
475 simple_lock(&mountlist_slock);
476 if (error) {
477 mp->mnt_flag &= ~MNT_UNMOUNT;
478 mp->mnt_flag |= async;
479 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
480 &mountlist_slock);
481 while(mp->mnt_wcnt > 0) {
482 wakeup((caddr_t)mp);
483 sleep(&mp->mnt_wcnt, PVFS);
484 }
485 return (error);
486 }
487 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
488 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
489 coveredvp->v_mountedhere = NULL;
490 vrele(coveredvp);
491 }
492 mp->mnt_op->vfs_refcount--;
493 if (mp->mnt_vnodelist.lh_first != NULL)
494 panic("unmount: dangling vnode");
495 mp->mnt_flag |= MNT_GONE;
496 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
497 while(mp->mnt_wcnt > 0) {
498 wakeup((caddr_t)mp);
499 sleep(&mp->mnt_wcnt, PVFS);
500 }
501 free((caddr_t)mp, M_MOUNT);
502 return (0);
503 }
504
505 /*
506 * Sync each mounted filesystem.
507 */
508 #ifdef DEBUG
509 int syncprt = 0;
510 struct ctldebug debug0 = { "syncprt", &syncprt };
511 #endif
512
513 /* ARGSUSED */
514 int
515 sys_sync(p, v, retval)
516 struct proc *p;
517 void *v;
518 register_t *retval;
519 {
520 register struct mount *mp, *nmp;
521 int asyncflag;
522
523 simple_lock(&mountlist_slock);
524 for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
525 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
526 nmp = mp->mnt_list.cqe_prev;
527 continue;
528 }
529 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
530 asyncflag = mp->mnt_flag & MNT_ASYNC;
531 mp->mnt_flag &= ~MNT_ASYNC;
532 uvm_vnp_sync(mp);
533 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
534 if (asyncflag)
535 mp->mnt_flag |= MNT_ASYNC;
536 }
537 simple_lock(&mountlist_slock);
538 nmp = mp->mnt_list.cqe_prev;
539 vfs_unbusy(mp);
540
541 }
542 simple_unlock(&mountlist_slock);
543 #ifdef DEBUG
544 if (syncprt)
545 vfs_bufstats();
546 #endif /* DEBUG */
547 return (0);
548 }
549
550 /*
551 * Change filesystem quotas.
552 */
553 /* ARGSUSED */
554 int
555 sys_quotactl(p, v, retval)
556 struct proc *p;
557 void *v;
558 register_t *retval;
559 {
560 register struct sys_quotactl_args /* {
561 syscallarg(const char *) path;
562 syscallarg(int) cmd;
563 syscallarg(int) uid;
564 syscallarg(caddr_t) arg;
565 } */ *uap = v;
566 register struct mount *mp;
567 int error;
568 struct nameidata nd;
569
570 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
571 if ((error = namei(&nd)) != 0)
572 return (error);
573 mp = nd.ni_vp->v_mount;
574 vrele(nd.ni_vp);
575 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
576 SCARG(uap, arg), p));
577 }
578
579 /*
580 * Get filesystem statistics.
581 */
582 /* ARGSUSED */
583 int
584 sys_statfs(p, v, retval)
585 struct proc *p;
586 void *v;
587 register_t *retval;
588 {
589 register struct sys_statfs_args /* {
590 syscallarg(const char *) path;
591 syscallarg(struct statfs *) buf;
592 } */ *uap = v;
593 register struct mount *mp;
594 register struct statfs *sp;
595 int error;
596 struct nameidata nd;
597
598 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
599 if ((error = namei(&nd)) != 0)
600 return (error);
601 mp = nd.ni_vp->v_mount;
602 sp = &mp->mnt_stat;
603 vrele(nd.ni_vp);
604 if ((error = VFS_STATFS(mp, sp, p)) != 0)
605 return (error);
606 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
607 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
608 }
609
610 /*
611 * Get filesystem statistics.
612 */
613 /* ARGSUSED */
614 int
615 sys_fstatfs(p, v, retval)
616 struct proc *p;
617 void *v;
618 register_t *retval;
619 {
620 register struct sys_fstatfs_args /* {
621 syscallarg(int) fd;
622 syscallarg(struct statfs *) buf;
623 } */ *uap = v;
624 struct file *fp;
625 struct mount *mp;
626 register struct statfs *sp;
627 int error;
628
629 /* getvnode() will use the descriptor for us */
630 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
631 return (error);
632 mp = ((struct vnode *)fp->f_data)->v_mount;
633 sp = &mp->mnt_stat;
634 if ((error = VFS_STATFS(mp, sp, p)) != 0)
635 goto out;
636 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
637 error = copyout(sp, SCARG(uap, buf), sizeof(*sp));
638 out:
639 FILE_UNUSE(fp, p);
640 return (error);
641 }
642
643 /*
644 * Get statistics on all filesystems.
645 */
646 int
647 sys_getfsstat(p, v, retval)
648 struct proc *p;
649 void *v;
650 register_t *retval;
651 {
652 register struct sys_getfsstat_args /* {
653 syscallarg(struct statfs *) buf;
654 syscallarg(long) bufsize;
655 syscallarg(int) flags;
656 } */ *uap = v;
657 register struct mount *mp, *nmp;
658 register struct statfs *sp;
659 caddr_t sfsp;
660 long count, maxcount, error;
661
662 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
663 sfsp = (caddr_t)SCARG(uap, buf);
664 simple_lock(&mountlist_slock);
665 count = 0;
666 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
667 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
668 nmp = mp->mnt_list.cqe_next;
669 continue;
670 }
671 if (sfsp && count < maxcount) {
672 sp = &mp->mnt_stat;
673 /*
674 * If MNT_NOWAIT is specified, do not refresh the
675 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
676 */
677 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
678 (SCARG(uap, flags) & MNT_WAIT)) &&
679 (error = VFS_STATFS(mp, sp, p)) != 0) {
680 simple_lock(&mountlist_slock);
681 nmp = mp->mnt_list.cqe_next;
682 vfs_unbusy(mp);
683 continue;
684 }
685 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
686 error = copyout(sp, sfsp, sizeof(*sp));
687 if (error) {
688 vfs_unbusy(mp);
689 return (error);
690 }
691 sfsp += sizeof(*sp);
692 }
693 count++;
694 simple_lock(&mountlist_slock);
695 nmp = mp->mnt_list.cqe_next;
696 vfs_unbusy(mp);
697 }
698 simple_unlock(&mountlist_slock);
699 if (sfsp && count > maxcount)
700 *retval = maxcount;
701 else
702 *retval = count;
703 return (0);
704 }
705
706 /*
707 * Change current working directory to a given file descriptor.
708 */
709 /* ARGSUSED */
710 int
711 sys_fchdir(p, v, retval)
712 struct proc *p;
713 void *v;
714 register_t *retval;
715 {
716 struct sys_fchdir_args /* {
717 syscallarg(int) fd;
718 } */ *uap = v;
719 struct filedesc *fdp = p->p_fd;
720 struct cwdinfo *cwdi = p->p_cwdi;
721 struct vnode *vp, *tdp;
722 struct mount *mp;
723 struct file *fp;
724 int error;
725
726 /* getvnode() will use the descriptor for us */
727 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
728 return (error);
729 vp = (struct vnode *)fp->f_data;
730
731 VREF(vp);
732 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
733 if (vp->v_type != VDIR)
734 error = ENOTDIR;
735 else
736 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
737 while (!error && (mp = vp->v_mountedhere) != NULL) {
738 if (vfs_busy(mp, 0, 0))
739 continue;
740 error = VFS_ROOT(mp, &tdp);
741 vfs_unbusy(mp);
742 if (error)
743 break;
744 vput(vp);
745 vp = tdp;
746 }
747 if (error) {
748 vput(vp);
749 goto out;
750 }
751 VOP_UNLOCK(vp, 0);
752
753 /*
754 * Disallow changing to a directory not under the process's
755 * current root directory (if there is one).
756 */
757 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, p)) {
758 vrele(vp);
759 error = EPERM; /* operation not permitted */
760 goto out;
761 }
762
763 vrele(cwdi->cwdi_cdir);
764 cwdi->cwdi_cdir = vp;
765 out:
766 FILE_UNUSE(fp, p);
767 return (error);
768 }
769
770 /*
771 * Change this process's notion of the root directory to a given file descriptor.
772 */
773
774 int
775 sys_fchroot(p, v, retval)
776 struct proc *p;
777 void *v;
778 register_t *retval;
779 {
780 struct sys_fchroot_args *uap = v;
781 struct filedesc *fdp = p->p_fd;
782 struct cwdinfo *cwdi = p->p_cwdi;
783 struct vnode *vp;
784 struct file *fp;
785 int error;
786
787 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
788 return error;
789 /* getvnode() will use the descriptor for us */
790 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
791 return error;
792 vp = (struct vnode *) fp->f_data;
793 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
794 if (vp->v_type != VDIR)
795 error = ENOTDIR;
796 else
797 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
798 VOP_UNLOCK(vp, 0);
799 if (error)
800 goto out;
801 VREF(vp);
802
803 /*
804 * Prevent escaping from chroot by putting the root under
805 * the working directory. Silently chdir to / if we aren't
806 * already there.
807 */
808 if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
809 /*
810 * XXX would be more failsafe to change directory to a
811 * deadfs node here instead
812 */
813 vrele(cwdi->cwdi_cdir);
814 VREF(vp);
815 cwdi->cwdi_cdir = vp;
816 }
817
818 if (cwdi->cwdi_rdir != NULL)
819 vrele(cwdi->cwdi_rdir);
820 cwdi->cwdi_rdir = vp;
821 out:
822 FILE_UNUSE(fp, p);
823 return (error);
824 }
825
826
827
828 /*
829 * Change current working directory (``.'').
830 */
831 /* ARGSUSED */
832 int
833 sys_chdir(p, v, retval)
834 struct proc *p;
835 void *v;
836 register_t *retval;
837 {
838 struct sys_chdir_args /* {
839 syscallarg(const char *) path;
840 } */ *uap = v;
841 struct cwdinfo *cwdi = p->p_cwdi;
842 int error;
843 struct nameidata nd;
844
845 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
846 SCARG(uap, path), p);
847 if ((error = change_dir(&nd, p)) != 0)
848 return (error);
849 vrele(cwdi->cwdi_cdir);
850 cwdi->cwdi_cdir = nd.ni_vp;
851 return (0);
852 }
853
854 /*
855 * Change notion of root (``/'') directory.
856 */
857 /* ARGSUSED */
858 int
859 sys_chroot(p, v, retval)
860 struct proc *p;
861 void *v;
862 register_t *retval;
863 {
864 struct sys_chroot_args /* {
865 syscallarg(const char *) path;
866 } */ *uap = v;
867 struct cwdinfo *cwdi = p->p_cwdi;
868 struct vnode *vp;
869 int error;
870 struct nameidata nd;
871
872 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
873 return (error);
874 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
875 SCARG(uap, path), p);
876 if ((error = change_dir(&nd, p)) != 0)
877 return (error);
878 if (cwdi->cwdi_rdir != NULL)
879 vrele(cwdi->cwdi_rdir);
880 vp = nd.ni_vp;
881 cwdi->cwdi_rdir = vp;
882
883 /*
884 * Prevent escaping from chroot by putting the root under
885 * the working directory. Silently chdir to / if we aren't
886 * already there.
887 */
888 if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
889 /*
890 * XXX would be more failsafe to change directory to a
891 * deadfs node here instead
892 */
893 vrele(cwdi->cwdi_cdir);
894 VREF(vp);
895 cwdi->cwdi_cdir = vp;
896 }
897
898 return (0);
899 }
900
901 /*
902 * Common routine for chroot and chdir.
903 */
904 static int
905 change_dir(ndp, p)
906 register struct nameidata *ndp;
907 struct proc *p;
908 {
909 struct vnode *vp;
910 int error;
911
912 if ((error = namei(ndp)) != 0)
913 return (error);
914 vp = ndp->ni_vp;
915 if (vp->v_type != VDIR)
916 error = ENOTDIR;
917 else
918 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
919
920 if (error)
921 vput(vp);
922 else
923 VOP_UNLOCK(vp, 0);
924 return (error);
925 }
926
927 /*
928 * Check permissions, allocate an open file structure,
929 * and call the device open routine if any.
930 */
931 int
932 sys_open(p, v, retval)
933 struct proc *p;
934 void *v;
935 register_t *retval;
936 {
937 register struct sys_open_args /* {
938 syscallarg(const char *) path;
939 syscallarg(int) flags;
940 syscallarg(int) mode;
941 } */ *uap = v;
942 struct cwdinfo *cwdi = p->p_cwdi;
943 struct filedesc *fdp = p->p_fd;
944 struct file *fp;
945 struct vnode *vp;
946 int flags, cmode;
947 int type, indx, error;
948 struct flock lf;
949 struct nameidata nd;
950 extern struct fileops vnops;
951
952 flags = FFLAGS(SCARG(uap, flags));
953 if ((flags & (FREAD | FWRITE)) == 0)
954 return (EINVAL);
955 /* falloc() will use the file descriptor for us */
956 if ((error = falloc(p, &fp, &indx)) != 0)
957 return (error);
958 cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
959 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
960 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
961 if ((error = vn_open(&nd, flags, cmode)) != 0) {
962 FILE_UNUSE(fp, p);
963 ffree(fp);
964 if ((error == ENODEV || error == ENXIO) &&
965 p->p_dupfd >= 0 && /* XXX from fdopen */
966 (error =
967 dupfdopen(p, indx, p->p_dupfd, flags, error)) == 0) {
968 *retval = indx;
969 return (0);
970 }
971 if (error == ERESTART)
972 error = EINTR;
973 fdp->fd_ofiles[indx] = NULL;
974 return (error);
975 }
976 p->p_dupfd = 0;
977 vp = nd.ni_vp;
978 fp->f_flag = flags & FMASK;
979 fp->f_type = DTYPE_VNODE;
980 fp->f_ops = &vnops;
981 fp->f_data = (caddr_t)vp;
982 if (flags & (O_EXLOCK | O_SHLOCK)) {
983 lf.l_whence = SEEK_SET;
984 lf.l_start = 0;
985 lf.l_len = 0;
986 if (flags & O_EXLOCK)
987 lf.l_type = F_WRLCK;
988 else
989 lf.l_type = F_RDLCK;
990 type = F_FLOCK;
991 if ((flags & FNONBLOCK) == 0)
992 type |= F_WAIT;
993 VOP_UNLOCK(vp, 0);
994 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
995 if (error) {
996 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
997 FILE_UNUSE(fp, p);
998 ffree(fp);
999 fdp->fd_ofiles[indx] = NULL;
1000 return (error);
1001 }
1002 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1003 fp->f_flag |= FHASLOCK;
1004 }
1005 VOP_UNLOCK(vp, 0);
1006 *retval = indx;
1007 FILE_UNUSE(fp, p);
1008 return (0);
1009 }
1010
1011 /*
1012 * Get file handle system call
1013 */
1014 int
1015 sys_getfh(p, v, retval)
1016 struct proc *p;
1017 register void *v;
1018 register_t *retval;
1019 {
1020 register struct sys_getfh_args /* {
1021 syscallarg(char *) fname;
1022 syscallarg(fhandle_t *) fhp;
1023 } */ *uap = v;
1024 register struct vnode *vp;
1025 fhandle_t fh;
1026 int error;
1027 struct nameidata nd;
1028
1029 /*
1030 * Must be super user
1031 */
1032 error = suser(p->p_ucred, &p->p_acflag);
1033 if (error)
1034 return (error);
1035 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1036 SCARG(uap, fname), p);
1037 error = namei(&nd);
1038 if (error)
1039 return (error);
1040 vp = nd.ni_vp;
1041 memset((caddr_t)&fh, 0, sizeof(fh));
1042 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1043 error = VFS_VPTOFH(vp, &fh.fh_fid);
1044 vput(vp);
1045 if (error)
1046 return (error);
1047 error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh));
1048 return (error);
1049 }
1050
1051 /*
1052 * Open a file given a file handle.
1053 *
1054 * Check permissions, allocate an open file structure,
1055 * and call the device open routine if any.
1056 */
1057 int
1058 sys_fhopen(p, v, retval)
1059 struct proc *p;
1060 void *v;
1061 register_t *retval;
1062 {
1063 register struct sys_fhopen_args /* {
1064 syscallarg(const fhandle_t *) fhp;
1065 syscallarg(int) flags;
1066 } */ *uap = v;
1067 struct filedesc *fdp = p->p_fd;
1068 struct file *fp;
1069 struct vnode *vp = NULL;
1070 struct mount *mp;
1071 struct ucred *cred = p->p_ucred;
1072 int flags;
1073 struct file *nfp;
1074 int type, indx, error=0;
1075 struct flock lf;
1076 struct vattr va;
1077 fhandle_t fh;
1078 extern struct fileops vnops;
1079
1080 /*
1081 * Must be super user
1082 */
1083 if ((error = suser(p->p_ucred, &p->p_acflag)))
1084 return (error);
1085
1086 flags = FFLAGS(SCARG(uap, flags));
1087 if ((flags & (FREAD | FWRITE)) == 0)
1088 return (EINVAL);
1089 if ((flags & O_CREAT))
1090 return (EINVAL);
1091 /* falloc() will use the file descriptor for us */
1092 if ((error = falloc(p, &nfp, &indx)) != 0)
1093 return (error);
1094 fp = nfp;
1095 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1096 goto bad;
1097
1098 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
1099 error = ESTALE;
1100 goto bad;
1101 }
1102
1103 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
1104 vp = NULL; /* most likely unnecessary sanity for bad: */
1105 goto bad;
1106 }
1107
1108 /* Now do an effective vn_open */
1109
1110 if (vp->v_type == VSOCK) {
1111 error = EOPNOTSUPP;
1112 goto bad;
1113 }
1114 if (flags & FREAD) {
1115 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
1116 goto bad;
1117 }
1118 if (flags & (FWRITE | O_TRUNC)) {
1119 if (vp->v_type == VDIR) {
1120 error = EISDIR;
1121 goto bad;
1122 }
1123 if ((error = vn_writechk(vp)) != 0 ||
1124 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
1125 goto bad;
1126 }
1127 if (flags & O_TRUNC) {
1128 VOP_UNLOCK(vp, 0); /* XXX */
1129 VOP_LEASE(vp, p, cred, LEASE_WRITE);
1130 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1131 VATTR_NULL(&va);
1132 va.va_size = 0;
1133 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
1134 goto bad;
1135 }
1136 if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
1137 goto bad;
1138 if (flags & FWRITE)
1139 vp->v_writecount++;
1140
1141 /* done with modified vn_open, now finish what sys_open does. */
1142
1143 fp->f_flag = flags & FMASK;
1144 fp->f_type = DTYPE_VNODE;
1145 fp->f_ops = &vnops;
1146 fp->f_data = (caddr_t)vp;
1147 if (flags & (O_EXLOCK | O_SHLOCK)) {
1148 lf.l_whence = SEEK_SET;
1149 lf.l_start = 0;
1150 lf.l_len = 0;
1151 if (flags & O_EXLOCK)
1152 lf.l_type = F_WRLCK;
1153 else
1154 lf.l_type = F_RDLCK;
1155 type = F_FLOCK;
1156 if ((flags & FNONBLOCK) == 0)
1157 type |= F_WAIT;
1158 VOP_UNLOCK(vp, 0);
1159 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
1160 if (error) {
1161 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
1162 FILE_UNUSE(fp, p);
1163 ffree(fp);
1164 fdp->fd_ofiles[indx] = NULL;
1165 return (error);
1166 }
1167 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1168 fp->f_flag |= FHASLOCK;
1169 }
1170 VOP_UNLOCK(vp, 0);
1171 *retval = indx;
1172 FILE_UNUSE(fp, p);
1173 return (0);
1174
1175 bad:
1176 FILE_UNUSE(fp, p);
1177 ffree(fp);
1178 fdp->fd_ofiles[indx] = NULL;
1179 if (vp != NULL)
1180 vput(vp);
1181 return (error);
1182 }
1183
1184 /* ARGSUSED */
1185 int
1186 sys_fhstat(p, v, retval)
1187 struct proc *p;
1188 void *v;
1189 register_t *retval;
1190 {
1191 register struct sys_fhstat_args /* {
1192 syscallarg(const fhandle_t *) fhp;
1193 syscallarg(struct stat *) sb;
1194 } */ *uap = v;
1195 struct stat sb;
1196 int error;
1197 fhandle_t fh;
1198 struct mount *mp;
1199 struct vnode *vp;
1200
1201 /*
1202 * Must be super user
1203 */
1204 if ((error = suser(p->p_ucred, &p->p_acflag)))
1205 return (error);
1206
1207 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1208 return (error);
1209
1210 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1211 return (ESTALE);
1212 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1213 return (error);
1214 error = vn_stat(vp, &sb, p);
1215 vput(vp);
1216 if (error)
1217 return (error);
1218 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
1219 return (error);
1220 }
1221
1222 /* ARGSUSED */
1223 int
1224 sys_fhstatfs(p, v, retval)
1225 struct proc *p;
1226 void *v;
1227 register_t *retval;
1228 {
1229 register struct sys_fhstatfs_args /*
1230 syscallarg(const fhandle_t *) fhp;
1231 syscallarg(struct statfs *) buf;
1232 } */ *uap = v;
1233 struct statfs sp;
1234 fhandle_t fh;
1235 struct mount *mp;
1236 struct vnode *vp;
1237 int error;
1238
1239 /*
1240 * Must be super user
1241 */
1242 if ((error = suser(p->p_ucred, &p->p_acflag)))
1243 return (error);
1244
1245 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1246 return (error);
1247
1248 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1249 return (ESTALE);
1250 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1251 return (error);
1252 mp = vp->v_mount;
1253 vput(vp);
1254 if ((error = VFS_STATFS(mp, &sp, p)) != 0)
1255 return (error);
1256 sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
1257 return (copyout(&sp, SCARG(uap, buf), sizeof(sp)));
1258 }
1259
1260 /*
1261 * Create a special file.
1262 */
1263 /* ARGSUSED */
1264 int
1265 sys_mknod(p, v, retval)
1266 struct proc *p;
1267 void *v;
1268 register_t *retval;
1269 {
1270 register struct sys_mknod_args /* {
1271 syscallarg(const char *) path;
1272 syscallarg(int) mode;
1273 syscallarg(int) dev;
1274 } */ *uap = v;
1275 register struct vnode *vp;
1276 struct vattr vattr;
1277 int error;
1278 int whiteout = 0;
1279 struct nameidata nd;
1280
1281 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1282 return (error);
1283 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1284 if ((error = namei(&nd)) != 0)
1285 return (error);
1286 vp = nd.ni_vp;
1287 if (vp != NULL)
1288 error = EEXIST;
1289 else {
1290 VATTR_NULL(&vattr);
1291 vattr.va_mode =
1292 (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1293 vattr.va_rdev = SCARG(uap, dev);
1294 whiteout = 0;
1295
1296 switch (SCARG(uap, mode) & S_IFMT) {
1297 case S_IFMT: /* used by badsect to flag bad sectors */
1298 vattr.va_type = VBAD;
1299 break;
1300 case S_IFCHR:
1301 vattr.va_type = VCHR;
1302 break;
1303 case S_IFBLK:
1304 vattr.va_type = VBLK;
1305 break;
1306 case S_IFWHT:
1307 whiteout = 1;
1308 break;
1309 default:
1310 error = EINVAL;
1311 break;
1312 }
1313 }
1314 if (!error) {
1315 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1316 if (whiteout) {
1317 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1318 if (error)
1319 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1320 vput(nd.ni_dvp);
1321 } else {
1322 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1323 &nd.ni_cnd, &vattr);
1324 }
1325 } else {
1326 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1327 if (nd.ni_dvp == vp)
1328 vrele(nd.ni_dvp);
1329 else
1330 vput(nd.ni_dvp);
1331 if (vp)
1332 vrele(vp);
1333 }
1334 return (error);
1335 }
1336
1337 /*
1338 * Create a named pipe.
1339 */
1340 /* ARGSUSED */
1341 int
1342 sys_mkfifo(p, v, retval)
1343 struct proc *p;
1344 void *v;
1345 register_t *retval;
1346 {
1347 register struct sys_mkfifo_args /* {
1348 syscallarg(const char *) path;
1349 syscallarg(int) mode;
1350 } */ *uap = v;
1351 struct vattr vattr;
1352 int error;
1353 struct nameidata nd;
1354
1355 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1356 if ((error = namei(&nd)) != 0)
1357 return (error);
1358 if (nd.ni_vp != NULL) {
1359 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1360 if (nd.ni_dvp == nd.ni_vp)
1361 vrele(nd.ni_dvp);
1362 else
1363 vput(nd.ni_dvp);
1364 vrele(nd.ni_vp);
1365 return (EEXIST);
1366 }
1367 VATTR_NULL(&vattr);
1368 vattr.va_type = VFIFO;
1369 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1370 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1371 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1372 }
1373
1374 /*
1375 * Make a hard file link.
1376 */
1377 /* ARGSUSED */
1378 int
1379 sys_link(p, v, retval)
1380 struct proc *p;
1381 void *v;
1382 register_t *retval;
1383 {
1384 register struct sys_link_args /* {
1385 syscallarg(const char *) path;
1386 syscallarg(const char *) link;
1387 } */ *uap = v;
1388 register struct vnode *vp;
1389 struct nameidata nd;
1390 int error;
1391
1392 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1393 if ((error = namei(&nd)) != 0)
1394 return (error);
1395 vp = nd.ni_vp;
1396 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1397 if ((error = namei(&nd)) != 0)
1398 goto out;
1399 if (nd.ni_vp) {
1400 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1401 if (nd.ni_dvp == nd.ni_vp)
1402 vrele(nd.ni_dvp);
1403 else
1404 vput(nd.ni_dvp);
1405 vrele(nd.ni_vp);
1406 error = EEXIST;
1407 goto out;
1408 }
1409 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1410 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1411 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1412 out:
1413 vrele(vp);
1414 return (error);
1415 }
1416
1417 /*
1418 * Make a symbolic link.
1419 */
1420 /* ARGSUSED */
1421 int
1422 sys_symlink(p, v, retval)
1423 struct proc *p;
1424 void *v;
1425 register_t *retval;
1426 {
1427 register struct sys_symlink_args /* {
1428 syscallarg(const char *) path;
1429 syscallarg(const char *) link;
1430 } */ *uap = v;
1431 struct vattr vattr;
1432 char *path;
1433 int error;
1434 struct nameidata nd;
1435
1436 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1437 error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
1438 if (error)
1439 goto out;
1440 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1441 if ((error = namei(&nd)) != 0)
1442 goto out;
1443 if (nd.ni_vp) {
1444 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1445 if (nd.ni_dvp == nd.ni_vp)
1446 vrele(nd.ni_dvp);
1447 else
1448 vput(nd.ni_dvp);
1449 vrele(nd.ni_vp);
1450 error = EEXIST;
1451 goto out;
1452 }
1453 VATTR_NULL(&vattr);
1454 vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1455 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1456 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1457 out:
1458 FREE(path, M_NAMEI);
1459 return (error);
1460 }
1461
1462 /*
1463 * Delete a whiteout from the filesystem.
1464 */
1465 /* ARGSUSED */
1466 int
1467 sys_undelete(p, v, retval)
1468 struct proc *p;
1469 void *v;
1470 register_t *retval;
1471 {
1472 register struct sys_undelete_args /* {
1473 syscallarg(const char *) path;
1474 } */ *uap = v;
1475 int error;
1476 struct nameidata nd;
1477
1478 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1479 SCARG(uap, path), p);
1480 error = namei(&nd);
1481 if (error)
1482 return (error);
1483
1484 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1485 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1486 if (nd.ni_dvp == nd.ni_vp)
1487 vrele(nd.ni_dvp);
1488 else
1489 vput(nd.ni_dvp);
1490 if (nd.ni_vp)
1491 vrele(nd.ni_vp);
1492 return (EEXIST);
1493 }
1494
1495 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1496 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1497 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1498 vput(nd.ni_dvp);
1499 return (error);
1500 }
1501
1502 /*
1503 * Delete a name from the filesystem.
1504 */
1505 /* ARGSUSED */
1506 int
1507 sys_unlink(p, v, retval)
1508 struct proc *p;
1509 void *v;
1510 register_t *retval;
1511 {
1512 struct sys_unlink_args /* {
1513 syscallarg(const char *) path;
1514 } */ *uap = v;
1515 register struct vnode *vp;
1516 int error;
1517 struct nameidata nd;
1518
1519 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1520 SCARG(uap, path), p);
1521 if ((error = namei(&nd)) != 0)
1522 return (error);
1523 vp = nd.ni_vp;
1524
1525 /*
1526 * The root of a mounted filesystem cannot be deleted.
1527 */
1528 if (vp->v_flag & VROOT) {
1529 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1530 if (nd.ni_dvp == vp)
1531 vrele(nd.ni_dvp);
1532 else
1533 vput(nd.ni_dvp);
1534 vput(vp);
1535 error = EBUSY;
1536 goto out;
1537 }
1538
1539 (void)uvm_vnp_uncache(vp);
1540
1541 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1542 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1543 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1544 out:
1545 return (error);
1546 }
1547
1548 /*
1549 * Reposition read/write file offset.
1550 */
1551 int
1552 sys_lseek(p, v, retval)
1553 struct proc *p;
1554 void *v;
1555 register_t *retval;
1556 {
1557 register struct sys_lseek_args /* {
1558 syscallarg(int) fd;
1559 syscallarg(int) pad;
1560 syscallarg(off_t) offset;
1561 syscallarg(int) whence;
1562 } */ *uap = v;
1563 struct ucred *cred = p->p_ucred;
1564 register struct filedesc *fdp = p->p_fd;
1565 register struct file *fp;
1566 struct vnode *vp;
1567 struct vattr vattr;
1568 register off_t newoff;
1569 int error;
1570
1571 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1572 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
1573 (fp->f_iflags & FIF_WANTCLOSE) != 0)
1574 return (EBADF);
1575
1576 FILE_USE(fp);
1577
1578 vp = (struct vnode *)fp->f_data;
1579 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1580 error = ESPIPE;
1581 goto out;
1582 }
1583
1584 switch (SCARG(uap, whence)) {
1585 case SEEK_CUR:
1586 newoff = fp->f_offset + SCARG(uap, offset);
1587 break;
1588 case SEEK_END:
1589 error = VOP_GETATTR(vp, &vattr, cred, p);
1590 if (error)
1591 goto out;
1592 newoff = SCARG(uap, offset) + vattr.va_size;
1593 break;
1594 case SEEK_SET:
1595 newoff = SCARG(uap, offset);
1596 break;
1597 default:
1598 error = EINVAL;
1599 goto out;
1600 }
1601 if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
1602 goto out;
1603
1604 *(off_t *)retval = fp->f_offset = newoff;
1605 out:
1606 FILE_UNUSE(fp, p);
1607 return (error);
1608 }
1609
1610 /*
1611 * Positional read system call.
1612 */
1613 int
1614 sys_pread(p, v, retval)
1615 struct proc *p;
1616 void *v;
1617 register_t *retval;
1618 {
1619 struct sys_pread_args /* {
1620 syscallarg(int) fd;
1621 syscallarg(void *) buf;
1622 syscallarg(size_t) nbyte;
1623 syscallarg(off_t) offset;
1624 } */ *uap = v;
1625 struct filedesc *fdp = p->p_fd;
1626 struct file *fp;
1627 struct vnode *vp;
1628 off_t offset;
1629 int error, fd = SCARG(uap, fd);
1630
1631 if ((u_int)fd >= fdp->fd_nfiles ||
1632 (fp = fdp->fd_ofiles[fd]) == NULL ||
1633 (fp->f_iflags & FIF_WANTCLOSE) != 0 ||
1634 (fp->f_flag & FREAD) == 0)
1635 return (EBADF);
1636
1637 FILE_USE(fp);
1638
1639 vp = (struct vnode *)fp->f_data;
1640 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1641 error = ESPIPE;
1642 goto out;
1643 }
1644
1645 offset = SCARG(uap, offset);
1646
1647 /*
1648 * XXX This works because no file systems actually
1649 * XXX take any action on the seek operation.
1650 */
1651 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1652 goto out;
1653
1654 /* dofileread() will unuse the descriptor for us */
1655 return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1656 &offset, 0, retval));
1657
1658 out:
1659 FILE_UNUSE(fp, p);
1660 return (error);
1661 }
1662
1663 /*
1664 * Positional scatter read system call.
1665 */
1666 int
1667 sys_preadv(p, v, retval)
1668 struct proc *p;
1669 void *v;
1670 register_t *retval;
1671 {
1672 struct sys_preadv_args /* {
1673 syscallarg(int) fd;
1674 syscallarg(const struct iovec *) iovp;
1675 syscallarg(int) iovcnt;
1676 syscallarg(off_t) offset;
1677 } */ *uap = v;
1678 struct filedesc *fdp = p->p_fd;
1679 struct file *fp;
1680 struct vnode *vp;
1681 off_t offset;
1682 int error, fd = SCARG(uap, fd);
1683
1684 if ((u_int)fd >= fdp->fd_nfiles ||
1685 (fp = fdp->fd_ofiles[fd]) == NULL ||
1686 (fp->f_iflags & FIF_WANTCLOSE) != 0 ||
1687 (fp->f_flag & FREAD) == 0)
1688 return (EBADF);
1689
1690 FILE_USE(fp);
1691
1692 vp = (struct vnode *)fp->f_data;
1693 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1694 error = ESPIPE;
1695 goto out;
1696 }
1697
1698 offset = SCARG(uap, offset);
1699
1700 /*
1701 * XXX This works because no file systems actually
1702 * XXX take any action on the seek operation.
1703 */
1704 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1705 goto out;
1706
1707 /* dofilereadv() will unuse the descriptor for us */
1708 return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
1709 &offset, 0, retval));
1710
1711 out:
1712 FILE_UNUSE(fp, p);
1713 return (error);
1714 }
1715
1716 /*
1717 * Positional write system call.
1718 */
1719 int
1720 sys_pwrite(p, v, retval)
1721 struct proc *p;
1722 void *v;
1723 register_t *retval;
1724 {
1725 struct sys_pwrite_args /* {
1726 syscallarg(int) fd;
1727 syscallarg(const void *) buf;
1728 syscallarg(size_t) nbyte;
1729 syscallarg(off_t) offset;
1730 } */ *uap = v;
1731 struct filedesc *fdp = p->p_fd;
1732 struct file *fp;
1733 struct vnode *vp;
1734 off_t offset;
1735 int error, fd = SCARG(uap, fd);
1736
1737 if ((u_int)fd >= fdp->fd_nfiles ||
1738 (fp = fdp->fd_ofiles[fd]) == NULL ||
1739 (fp->f_iflags & FIF_WANTCLOSE) != 0 ||
1740 (fp->f_flag & FWRITE) == 0)
1741 return (EBADF);
1742
1743 FILE_USE(fp);
1744
1745 vp = (struct vnode *)fp->f_data;
1746 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1747 error = ESPIPE;
1748 goto out;
1749 }
1750
1751 offset = SCARG(uap, offset);
1752
1753 /*
1754 * XXX This works because no file systems actually
1755 * XXX take any action on the seek operation.
1756 */
1757 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1758 goto out;
1759
1760 /* dofilewrite() will unuse the descriptor for us */
1761 return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1762 &offset, 0, retval));
1763
1764 out:
1765 FILE_UNUSE(fp, p);
1766 return (error);
1767 }
1768
1769 /*
1770 * Positional gather write system call.
1771 */
1772 int
1773 sys_pwritev(p, v, retval)
1774 struct proc *p;
1775 void *v;
1776 register_t *retval;
1777 {
1778 struct sys_pwritev_args /* {
1779 syscallarg(int) fd;
1780 syscallarg(const struct iovec *) iovp;
1781 syscallarg(int) iovcnt;
1782 syscallarg(off_t) offset;
1783 } */ *uap = v;
1784 struct filedesc *fdp = p->p_fd;
1785 struct file *fp;
1786 struct vnode *vp;
1787 off_t offset;
1788 int error, fd = SCARG(uap, fd);
1789
1790 if ((u_int)fd >= fdp->fd_nfiles ||
1791 (fp = fdp->fd_ofiles[fd]) == NULL ||
1792 (fp->f_iflags & FIF_WANTCLOSE) != 0 ||
1793 (fp->f_flag & FWRITE) == 0)
1794 return (EBADF);
1795
1796 FILE_USE(fp);
1797
1798 vp = (struct vnode *)fp->f_data;
1799 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1800 error = ESPIPE;
1801 goto out;
1802 }
1803
1804 offset = SCARG(uap, offset);
1805
1806 /*
1807 * XXX This works because no file systems actually
1808 * XXX take any action on the seek operation.
1809 */
1810 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1811 goto out;
1812
1813 /* dofilewritev() will unuse the descriptor for us */
1814 return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
1815 &offset, 0, retval));
1816
1817 out:
1818 FILE_UNUSE(fp, p);
1819 return (error);
1820 }
1821
1822 /*
1823 * Check access permissions.
1824 */
1825 int
1826 sys_access(p, v, retval)
1827 struct proc *p;
1828 void *v;
1829 register_t *retval;
1830 {
1831 register struct sys_access_args /* {
1832 syscallarg(const char *) path;
1833 syscallarg(int) flags;
1834 } */ *uap = v;
1835 register struct ucred *cred = p->p_ucred;
1836 register struct vnode *vp;
1837 int error, flags, t_gid, t_uid;
1838 struct nameidata nd;
1839
1840 t_uid = cred->cr_uid;
1841 t_gid = cred->cr_gid;
1842 cred->cr_uid = p->p_cred->p_ruid;
1843 cred->cr_gid = p->p_cred->p_rgid;
1844 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1845 SCARG(uap, path), p);
1846 if ((error = namei(&nd)) != 0)
1847 goto out1;
1848 vp = nd.ni_vp;
1849
1850 /* Flags == 0 means only check for existence. */
1851 if (SCARG(uap, flags)) {
1852 flags = 0;
1853 if (SCARG(uap, flags) & R_OK)
1854 flags |= VREAD;
1855 if (SCARG(uap, flags) & W_OK)
1856 flags |= VWRITE;
1857 if (SCARG(uap, flags) & X_OK)
1858 flags |= VEXEC;
1859
1860 error = VOP_ACCESS(vp, flags, cred, p);
1861 if (!error && (flags & VWRITE))
1862 error = vn_writechk(vp);
1863 }
1864 vput(vp);
1865 out1:
1866 cred->cr_uid = t_uid;
1867 cred->cr_gid = t_gid;
1868 return (error);
1869 }
1870
1871 /*
1872 * Get file status; this version follows links.
1873 */
1874 /* ARGSUSED */
1875 int
1876 sys___stat13(p, v, retval)
1877 struct proc *p;
1878 void *v;
1879 register_t *retval;
1880 {
1881 register struct sys___stat13_args /* {
1882 syscallarg(const char *) path;
1883 syscallarg(struct stat *) ub;
1884 } */ *uap = v;
1885 struct stat sb;
1886 int error;
1887 struct nameidata nd;
1888
1889 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1890 SCARG(uap, path), p);
1891 if ((error = namei(&nd)) != 0)
1892 return (error);
1893 error = vn_stat(nd.ni_vp, &sb, p);
1894 vput(nd.ni_vp);
1895 if (error)
1896 return (error);
1897 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1898 return (error);
1899 }
1900
1901 /*
1902 * Get file status; this version does not follow links.
1903 */
1904 /* ARGSUSED */
1905 int
1906 sys___lstat13(p, v, retval)
1907 struct proc *p;
1908 void *v;
1909 register_t *retval;
1910 {
1911 register struct sys___lstat13_args /* {
1912 syscallarg(const char *) path;
1913 syscallarg(struct stat *) ub;
1914 } */ *uap = v;
1915 struct stat sb;
1916 int error;
1917 struct nameidata nd;
1918
1919 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1920 SCARG(uap, path), p);
1921 if ((error = namei(&nd)) != 0)
1922 return (error);
1923 error = vn_stat(nd.ni_vp, &sb, p);
1924 vput(nd.ni_vp);
1925 if (error)
1926 return (error);
1927 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1928 return (error);
1929 }
1930
1931 /*
1932 * Get configurable pathname variables.
1933 */
1934 /* ARGSUSED */
1935 int
1936 sys_pathconf(p, v, retval)
1937 struct proc *p;
1938 void *v;
1939 register_t *retval;
1940 {
1941 register struct sys_pathconf_args /* {
1942 syscallarg(const char *) path;
1943 syscallarg(int) name;
1944 } */ *uap = v;
1945 int error;
1946 struct nameidata nd;
1947
1948 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1949 SCARG(uap, path), p);
1950 if ((error = namei(&nd)) != 0)
1951 return (error);
1952 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1953 vput(nd.ni_vp);
1954 return (error);
1955 }
1956
1957 /*
1958 * Return target name of a symbolic link.
1959 */
1960 /* ARGSUSED */
1961 int
1962 sys_readlink(p, v, retval)
1963 struct proc *p;
1964 void *v;
1965 register_t *retval;
1966 {
1967 register struct sys_readlink_args /* {
1968 syscallarg(const char *) path;
1969 syscallarg(char *) buf;
1970 syscallarg(size_t) count;
1971 } */ *uap = v;
1972 register struct vnode *vp;
1973 struct iovec aiov;
1974 struct uio auio;
1975 int error;
1976 struct nameidata nd;
1977
1978 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1979 SCARG(uap, path), p);
1980 if ((error = namei(&nd)) != 0)
1981 return (error);
1982 vp = nd.ni_vp;
1983 if (vp->v_type != VLNK)
1984 error = EINVAL;
1985 else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
1986 (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) == 0) {
1987 aiov.iov_base = SCARG(uap, buf);
1988 aiov.iov_len = SCARG(uap, count);
1989 auio.uio_iov = &aiov;
1990 auio.uio_iovcnt = 1;
1991 auio.uio_offset = 0;
1992 auio.uio_rw = UIO_READ;
1993 auio.uio_segflg = UIO_USERSPACE;
1994 auio.uio_procp = p;
1995 auio.uio_resid = SCARG(uap, count);
1996 error = VOP_READLINK(vp, &auio, p->p_ucred);
1997 }
1998 vput(vp);
1999 *retval = SCARG(uap, count) - auio.uio_resid;
2000 return (error);
2001 }
2002
2003 /*
2004 * Change flags of a file given a path name.
2005 */
2006 /* ARGSUSED */
2007 int
2008 sys_chflags(p, v, retval)
2009 struct proc *p;
2010 void *v;
2011 register_t *retval;
2012 {
2013 register struct sys_chflags_args /* {
2014 syscallarg(const char *) path;
2015 syscallarg(u_long) flags;
2016 } */ *uap = v;
2017 register struct vnode *vp;
2018 struct vattr vattr;
2019 int error;
2020 struct nameidata nd;
2021
2022 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2023 if ((error = namei(&nd)) != 0)
2024 return (error);
2025 vp = nd.ni_vp;
2026 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2027 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2028 VATTR_NULL(&vattr);
2029 vattr.va_flags = SCARG(uap, flags);
2030 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2031 vput(vp);
2032 return (error);
2033 }
2034
2035 /*
2036 * Change flags of a file given a file descriptor.
2037 */
2038 /* ARGSUSED */
2039 int
2040 sys_fchflags(p, v, retval)
2041 struct proc *p;
2042 void *v;
2043 register_t *retval;
2044 {
2045 register struct sys_fchflags_args /* {
2046 syscallarg(int) fd;
2047 syscallarg(u_long) flags;
2048 } */ *uap = v;
2049 struct vattr vattr;
2050 struct vnode *vp;
2051 struct file *fp;
2052 int error;
2053
2054 /* getvnode() will use the descriptor for us */
2055 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2056 return (error);
2057 vp = (struct vnode *)fp->f_data;
2058 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2059 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2060 VATTR_NULL(&vattr);
2061 vattr.va_flags = SCARG(uap, flags);
2062 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2063 VOP_UNLOCK(vp, 0);
2064 FILE_UNUSE(fp, p);
2065 return (error);
2066 }
2067
2068 /*
2069 * Change mode of a file given path name; this version follows links.
2070 */
2071 /* ARGSUSED */
2072 int
2073 sys_chmod(p, v, retval)
2074 struct proc *p;
2075 void *v;
2076 register_t *retval;
2077 {
2078 register struct sys_chmod_args /* {
2079 syscallarg(const char *) path;
2080 syscallarg(int) mode;
2081 } */ *uap = v;
2082 int error;
2083 struct nameidata nd;
2084
2085 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2086 if ((error = namei(&nd)) != 0)
2087 return (error);
2088
2089 error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
2090
2091 vrele(nd.ni_vp);
2092 return (error);
2093 }
2094
2095 /*
2096 * Change mode of a file given a file descriptor.
2097 */
2098 /* ARGSUSED */
2099 int
2100 sys_fchmod(p, v, retval)
2101 struct proc *p;
2102 void *v;
2103 register_t *retval;
2104 {
2105 register struct sys_fchmod_args /* {
2106 syscallarg(int) fd;
2107 syscallarg(int) mode;
2108 } */ *uap = v;
2109 struct file *fp;
2110 int error;
2111
2112 /* getvnode() will use the descriptor for us */
2113 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2114 return (error);
2115
2116 error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), p);
2117 FILE_UNUSE(fp, p);
2118 return (error);
2119 }
2120
2121 /*
2122 * Change mode of a file given path name; this version does not follow links.
2123 */
2124 /* ARGSUSED */
2125 int
2126 sys_lchmod(p, v, retval)
2127 struct proc *p;
2128 void *v;
2129 register_t *retval;
2130 {
2131 register struct sys_lchmod_args /* {
2132 syscallarg(const char *) path;
2133 syscallarg(int) mode;
2134 } */ *uap = v;
2135 int error;
2136 struct nameidata nd;
2137
2138 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2139 if ((error = namei(&nd)) != 0)
2140 return (error);
2141
2142 error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
2143
2144 vrele(nd.ni_vp);
2145 return (error);
2146 }
2147
2148 /*
2149 * Common routine to set mode given a vnode.
2150 */
2151 static int
2152 change_mode(vp, mode, p)
2153 struct vnode *vp;
2154 int mode;
2155 struct proc *p;
2156 {
2157 struct vattr vattr;
2158 int error;
2159
2160 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2161 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2162 VATTR_NULL(&vattr);
2163 vattr.va_mode = mode & ALLPERMS;
2164 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2165 VOP_UNLOCK(vp, 0);
2166 return (error);
2167 }
2168
2169 /*
2170 * Set ownership given a path name; this version follows links.
2171 */
2172 /* ARGSUSED */
2173 int
2174 sys_chown(p, v, retval)
2175 struct proc *p;
2176 void *v;
2177 register_t *retval;
2178 {
2179 register struct sys_chown_args /* {
2180 syscallarg(const char *) path;
2181 syscallarg(uid_t) uid;
2182 syscallarg(gid_t) gid;
2183 } */ *uap = v;
2184 int error;
2185 struct nameidata nd;
2186
2187 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2188 if ((error = namei(&nd)) != 0)
2189 return (error);
2190
2191 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
2192
2193 vrele(nd.ni_vp);
2194 return (error);
2195 }
2196
2197 /*
2198 * Set ownership given a path name; this version follows links.
2199 * Provides POSIX semantics.
2200 */
2201 /* ARGSUSED */
2202 int
2203 sys___posix_chown(p, v, retval)
2204 struct proc *p;
2205 void *v;
2206 register_t *retval;
2207 {
2208 register struct sys_chown_args /* {
2209 syscallarg(const char *) path;
2210 syscallarg(uid_t) uid;
2211 syscallarg(gid_t) gid;
2212 } */ *uap = v;
2213 int error;
2214 struct nameidata nd;
2215
2216 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2217 if ((error = namei(&nd)) != 0)
2218 return (error);
2219
2220 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
2221
2222 vrele(nd.ni_vp);
2223 return (error);
2224 }
2225
2226 /*
2227 * Set ownership given a file descriptor.
2228 */
2229 /* ARGSUSED */
2230 int
2231 sys_fchown(p, v, retval)
2232 struct proc *p;
2233 void *v;
2234 register_t *retval;
2235 {
2236 register struct sys_fchown_args /* {
2237 syscallarg(int) fd;
2238 syscallarg(uid_t) uid;
2239 syscallarg(gid_t) gid;
2240 } */ *uap = v;
2241 int error;
2242 struct file *fp;
2243
2244 /* getvnode() will use the descriptor for us */
2245 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2246 return (error);
2247
2248 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2249 SCARG(uap, gid), p, 0);
2250 FILE_UNUSE(fp, p);
2251 return (error);
2252 }
2253
2254 /*
2255 * Set ownership given a file descriptor, providing POSIX/XPG semantics.
2256 */
2257 /* ARGSUSED */
2258 int
2259 sys___posix_fchown(p, v, retval)
2260 struct proc *p;
2261 void *v;
2262 register_t *retval;
2263 {
2264 register struct sys_fchown_args /* {
2265 syscallarg(int) fd;
2266 syscallarg(uid_t) uid;
2267 syscallarg(gid_t) gid;
2268 } */ *uap = v;
2269 int error;
2270 struct file *fp;
2271
2272 /* getvnode() will use the descriptor for us */
2273 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2274 return (error);
2275
2276 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2277 SCARG(uap, gid), p, 1);
2278 FILE_UNUSE(fp, p);
2279 return (error);
2280 }
2281
2282 /*
2283 * Set ownership given a path name; this version does not follow links.
2284 */
2285 /* ARGSUSED */
2286 int
2287 sys_lchown(p, v, retval)
2288 struct proc *p;
2289 void *v;
2290 register_t *retval;
2291 {
2292 register struct sys_lchown_args /* {
2293 syscallarg(const char *) path;
2294 syscallarg(uid_t) uid;
2295 syscallarg(gid_t) gid;
2296 } */ *uap = v;
2297 int error;
2298 struct nameidata nd;
2299
2300 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2301 if ((error = namei(&nd)) != 0)
2302 return (error);
2303
2304 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
2305
2306 vrele(nd.ni_vp);
2307 return (error);
2308 }
2309
2310 /*
2311 * Set ownership given a path name; this version does not follow links.
2312 * Provides POSIX/XPG semantics.
2313 */
2314 /* ARGSUSED */
2315 int
2316 sys___posix_lchown(p, v, retval)
2317 struct proc *p;
2318 void *v;
2319 register_t *retval;
2320 {
2321 register struct sys_lchown_args /* {
2322 syscallarg(const char *) path;
2323 syscallarg(uid_t) uid;
2324 syscallarg(gid_t) gid;
2325 } */ *uap = v;
2326 int error;
2327 struct nameidata nd;
2328
2329 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2330 if ((error = namei(&nd)) != 0)
2331 return (error);
2332
2333 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
2334
2335 vrele(nd.ni_vp);
2336 return (error);
2337 }
2338
2339 /*
2340 * Common routine to set ownership given a vnode.
2341 */
2342 static int
2343 change_owner(vp, uid, gid, p, posix_semantics)
2344 register struct vnode *vp;
2345 uid_t uid;
2346 gid_t gid;
2347 struct proc *p;
2348 int posix_semantics;
2349 {
2350 struct vattr vattr;
2351 mode_t newmode;
2352 int error;
2353
2354 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2355 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2356 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2357 goto out;
2358
2359 #define CHANGED(x) ((x) != -1)
2360 newmode = vattr.va_mode;
2361 if (posix_semantics) {
2362 /*
2363 * POSIX/XPG semantics: if the caller is not the super-user,
2364 * clear set-user-id and set-group-id bits. Both POSIX and
2365 * the XPG consider the behaviour for calls by the super-user
2366 * implementation-defined; we leave the set-user-id and set-
2367 * group-id settings intact in that case.
2368 */
2369 if (suser(p->p_ucred, NULL) != 0)
2370 newmode &= ~(S_ISUID | S_ISGID);
2371 } else {
2372 /*
2373 * NetBSD semantics: when changing owner and/or group,
2374 * clear the respective bit(s).
2375 */
2376 if (CHANGED(uid))
2377 newmode &= ~S_ISUID;
2378 if (CHANGED(gid))
2379 newmode &= ~S_ISGID;
2380 }
2381 /* Update va_mode iff altered. */
2382 if (vattr.va_mode == newmode)
2383 newmode = VNOVAL;
2384
2385 VATTR_NULL(&vattr);
2386 vattr.va_uid = CHANGED(uid) ? uid : VNOVAL;
2387 vattr.va_gid = CHANGED(gid) ? gid : VNOVAL;
2388 vattr.va_mode = newmode;
2389 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2390 #undef CHANGED
2391
2392 out:
2393 VOP_UNLOCK(vp, 0);
2394 return (error);
2395 }
2396
2397 /*
2398 * Set the access and modification times given a path name; this
2399 * version follows links.
2400 */
2401 /* ARGSUSED */
2402 int
2403 sys_utimes(p, v, retval)
2404 struct proc *p;
2405 void *v;
2406 register_t *retval;
2407 {
2408 register struct sys_utimes_args /* {
2409 syscallarg(const char *) path;
2410 syscallarg(const struct timeval *) tptr;
2411 } */ *uap = v;
2412 int error;
2413 struct nameidata nd;
2414
2415 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2416 if ((error = namei(&nd)) != 0)
2417 return (error);
2418
2419 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
2420
2421 vrele(nd.ni_vp);
2422 return (error);
2423 }
2424
2425 /*
2426 * Set the access and modification times given a file descriptor.
2427 */
2428 /* ARGSUSED */
2429 int
2430 sys_futimes(p, v, retval)
2431 struct proc *p;
2432 void *v;
2433 register_t *retval;
2434 {
2435 register struct sys_futimes_args /* {
2436 syscallarg(int) fd;
2437 syscallarg(const struct timeval *) tptr;
2438 } */ *uap = v;
2439 int error;
2440 struct file *fp;
2441
2442 /* getvnode() will use the descriptor for us */
2443 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2444 return (error);
2445
2446 error = change_utimes((struct vnode *)fp->f_data, SCARG(uap, tptr), p);
2447 FILE_UNUSE(fp, p);
2448 return (error);
2449 }
2450
2451 /*
2452 * Set the access and modification times given a path name; this
2453 * version does not follow links.
2454 */
2455 /* ARGSUSED */
2456 int
2457 sys_lutimes(p, v, retval)
2458 struct proc *p;
2459 void *v;
2460 register_t *retval;
2461 {
2462 register struct sys_lutimes_args /* {
2463 syscallarg(const char *) path;
2464 syscallarg(const struct timeval *) tptr;
2465 } */ *uap = v;
2466 int error;
2467 struct nameidata nd;
2468
2469 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2470 if ((error = namei(&nd)) != 0)
2471 return (error);
2472
2473 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
2474
2475 vrele(nd.ni_vp);
2476 return (error);
2477 }
2478
2479 /*
2480 * Common routine to set access and modification times given a vnode.
2481 */
2482 static int
2483 change_utimes(vp, tptr, p)
2484 struct vnode *vp;
2485 const struct timeval *tptr;
2486 struct proc *p;
2487 {
2488 struct timeval tv[2];
2489 struct vattr vattr;
2490 int error;
2491
2492 VATTR_NULL(&vattr);
2493 if (tptr == NULL) {
2494 microtime(&tv[0]);
2495 tv[1] = tv[0];
2496 vattr.va_vaflags |= VA_UTIMES_NULL;
2497 } else {
2498 error = copyin(tptr, tv, sizeof(tv));
2499 if (error)
2500 return (error);
2501 }
2502 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2503 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2504 vattr.va_atime.tv_sec = tv[0].tv_sec;
2505 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
2506 vattr.va_mtime.tv_sec = tv[1].tv_sec;
2507 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
2508 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2509 VOP_UNLOCK(vp, 0);
2510 return (error);
2511 }
2512
2513 /*
2514 * Truncate a file given its path name.
2515 */
2516 /* ARGSUSED */
2517 int
2518 sys_truncate(p, v, retval)
2519 struct proc *p;
2520 void *v;
2521 register_t *retval;
2522 {
2523 register struct sys_truncate_args /* {
2524 syscallarg(const char *) path;
2525 syscallarg(int) pad;
2526 syscallarg(off_t) length;
2527 } */ *uap = v;
2528 register struct vnode *vp;
2529 struct vattr vattr;
2530 int error;
2531 struct nameidata nd;
2532
2533 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2534 if ((error = namei(&nd)) != 0)
2535 return (error);
2536 vp = nd.ni_vp;
2537 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2538 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2539 if (vp->v_type == VDIR)
2540 error = EISDIR;
2541 else if ((error = vn_writechk(vp)) == 0 &&
2542 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2543 VATTR_NULL(&vattr);
2544 vattr.va_size = SCARG(uap, length);
2545 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2546 }
2547 vput(vp);
2548 return (error);
2549 }
2550
2551 /*
2552 * Truncate a file given a file descriptor.
2553 */
2554 /* ARGSUSED */
2555 int
2556 sys_ftruncate(p, v, retval)
2557 struct proc *p;
2558 void *v;
2559 register_t *retval;
2560 {
2561 register struct sys_ftruncate_args /* {
2562 syscallarg(int) fd;
2563 syscallarg(int) pad;
2564 syscallarg(off_t) length;
2565 } */ *uap = v;
2566 struct vattr vattr;
2567 struct vnode *vp;
2568 struct file *fp;
2569 int error;
2570
2571 /* getvnode() will use the descriptor for us */
2572 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2573 return (error);
2574 if ((fp->f_flag & FWRITE) == 0) {
2575 error = EINVAL;
2576 goto out;
2577 }
2578 vp = (struct vnode *)fp->f_data;
2579 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2580 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2581 if (vp->v_type == VDIR)
2582 error = EISDIR;
2583 else if ((error = vn_writechk(vp)) == 0) {
2584 VATTR_NULL(&vattr);
2585 vattr.va_size = SCARG(uap, length);
2586 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2587 }
2588 VOP_UNLOCK(vp, 0);
2589 out:
2590 FILE_UNUSE(fp, p);
2591 return (error);
2592 }
2593
2594 /*
2595 * Sync an open file.
2596 */
2597 /* ARGSUSED */
2598 int
2599 sys_fsync(p, v, retval)
2600 struct proc *p;
2601 void *v;
2602 register_t *retval;
2603 {
2604 struct sys_fsync_args /* {
2605 syscallarg(int) fd;
2606 } */ *uap = v;
2607 register struct vnode *vp;
2608 struct file *fp;
2609 int error;
2610
2611 /* getvnode() will use the descriptor for us */
2612 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2613 return (error);
2614 vp = (struct vnode *)fp->f_data;
2615 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2616 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, p);
2617 VOP_UNLOCK(vp, 0);
2618 FILE_UNUSE(fp, p);
2619 return (error);
2620 }
2621
2622 /*
2623 * Sync the data of an open file.
2624 */
2625 /* ARGSUSED */
2626 int
2627 sys_fdatasync(p, v, retval)
2628 struct proc *p;
2629 void *v;
2630 register_t *retval;
2631 {
2632 struct sys_fdatasync_args /* {
2633 syscallarg(int) fd;
2634 } */ *uap = v;
2635 struct vnode *vp;
2636 struct file *fp;
2637 int error;
2638
2639 /* getvnode() will use the descriptor for us */
2640 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2641 return (error);
2642 vp = (struct vnode *)fp->f_data;
2643 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2644 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, p);
2645 VOP_UNLOCK(vp, 0);
2646 FILE_UNUSE(fp, p);
2647 return (error);
2648 }
2649
2650 /*
2651 * Rename files, (standard) BSD semantics frontend.
2652 */
2653 /* ARGSUSED */
2654 int
2655 sys_rename(p, v, retval)
2656 struct proc *p;
2657 void *v;
2658 register_t *retval;
2659 {
2660 register struct sys_rename_args /* {
2661 syscallarg(const char *) from;
2662 syscallarg(const char *) to;
2663 } */ *uap = v;
2664
2665 return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 0));
2666 }
2667
2668 /*
2669 * Rename files, POSIX semantics frontend.
2670 */
2671 /* ARGSUSED */
2672 int
2673 sys___posix_rename(p, v, retval)
2674 struct proc *p;
2675 void *v;
2676 register_t *retval;
2677 {
2678 register struct sys___posix_rename_args /* {
2679 syscallarg(const char *) from;
2680 syscallarg(const char *) to;
2681 } */ *uap = v;
2682
2683 return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 1));
2684 }
2685
2686 /*
2687 * Rename files. Source and destination must either both be directories,
2688 * or both not be directories. If target is a directory, it must be empty.
2689 * If `from' and `to' refer to the same object, the value of the `retain'
2690 * argument is used to determine whether `from' will be
2691 *
2692 * (retain == 0) deleted unless `from' and `to' refer to the same
2693 * object in the file system's name space (BSD).
2694 * (retain == 1) always retained (POSIX).
2695 */
2696 static int
2697 rename_files(from, to, p, retain)
2698 const char *from, *to;
2699 struct proc *p;
2700 int retain;
2701 {
2702 register struct vnode *tvp, *fvp, *tdvp;
2703 struct nameidata fromnd, tond;
2704 int error;
2705
2706 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2707 from, p);
2708 if ((error = namei(&fromnd)) != 0)
2709 return (error);
2710 fvp = fromnd.ni_vp;
2711 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2712 UIO_USERSPACE, to, p);
2713 if ((error = namei(&tond)) != 0) {
2714 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2715 vrele(fromnd.ni_dvp);
2716 vrele(fvp);
2717 goto out1;
2718 }
2719 tdvp = tond.ni_dvp;
2720 tvp = tond.ni_vp;
2721
2722 if (tvp != NULL) {
2723 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2724 error = ENOTDIR;
2725 goto out;
2726 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2727 error = EISDIR;
2728 goto out;
2729 }
2730 }
2731
2732 if (fvp == tdvp)
2733 error = EINVAL;
2734
2735 /*
2736 * Source and destination refer to the same object.
2737 */
2738 if (fvp == tvp) {
2739 if (retain)
2740 error = -1;
2741 else if (fromnd.ni_dvp == tdvp &&
2742 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2743 !memcmp(fromnd.ni_cnd.cn_nameptr,
2744 tond.ni_cnd.cn_nameptr,
2745 fromnd.ni_cnd.cn_namelen))
2746 error = -1;
2747 }
2748
2749 out:
2750 if (!error) {
2751 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2752 if (fromnd.ni_dvp != tdvp)
2753 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2754 if (tvp) {
2755 (void)uvm_vnp_uncache(tvp);
2756 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2757 }
2758 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2759 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2760 } else {
2761 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2762 if (tdvp == tvp)
2763 vrele(tdvp);
2764 else
2765 vput(tdvp);
2766 if (tvp)
2767 vput(tvp);
2768 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2769 vrele(fromnd.ni_dvp);
2770 vrele(fvp);
2771 }
2772 vrele(tond.ni_startdir);
2773 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
2774 out1:
2775 if (fromnd.ni_startdir)
2776 vrele(fromnd.ni_startdir);
2777 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
2778 return (error == -1 ? 0 : error);
2779 }
2780
2781 /*
2782 * Make a directory file.
2783 */
2784 /* ARGSUSED */
2785 int
2786 sys_mkdir(p, v, retval)
2787 struct proc *p;
2788 void *v;
2789 register_t *retval;
2790 {
2791 register struct sys_mkdir_args /* {
2792 syscallarg(const char *) path;
2793 syscallarg(int) mode;
2794 } */ *uap = v;
2795 register struct vnode *vp;
2796 struct vattr vattr;
2797 int error;
2798 struct nameidata nd;
2799
2800 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2801 if ((error = namei(&nd)) != 0)
2802 return (error);
2803 vp = nd.ni_vp;
2804 if (vp != NULL) {
2805 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2806 if (nd.ni_dvp == vp)
2807 vrele(nd.ni_dvp);
2808 else
2809 vput(nd.ni_dvp);
2810 vrele(vp);
2811 return (EEXIST);
2812 }
2813 VATTR_NULL(&vattr);
2814 vattr.va_type = VDIR;
2815 vattr.va_mode =
2816 (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
2817 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2818 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2819 if (!error)
2820 vput(nd.ni_vp);
2821 return (error);
2822 }
2823
2824 /*
2825 * Remove a directory file.
2826 */
2827 /* ARGSUSED */
2828 int
2829 sys_rmdir(p, v, retval)
2830 struct proc *p;
2831 void *v;
2832 register_t *retval;
2833 {
2834 struct sys_rmdir_args /* {
2835 syscallarg(const char *) path;
2836 } */ *uap = v;
2837 register struct vnode *vp;
2838 int error;
2839 struct nameidata nd;
2840
2841 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2842 SCARG(uap, path), p);
2843 if ((error = namei(&nd)) != 0)
2844 return (error);
2845 vp = nd.ni_vp;
2846 if (vp->v_type != VDIR) {
2847 error = ENOTDIR;
2848 goto out;
2849 }
2850 /*
2851 * No rmdir "." please.
2852 */
2853 if (nd.ni_dvp == vp) {
2854 error = EINVAL;
2855 goto out;
2856 }
2857 /*
2858 * The root of a mounted filesystem cannot be deleted.
2859 */
2860 if (vp->v_flag & VROOT)
2861 error = EBUSY;
2862 out:
2863 if (!error) {
2864 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2865 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2866 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2867 } else {
2868 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2869 if (nd.ni_dvp == vp)
2870 vrele(nd.ni_dvp);
2871 else
2872 vput(nd.ni_dvp);
2873 vput(vp);
2874 }
2875 return (error);
2876 }
2877
2878 /*
2879 * Read a block of directory entries in a file system independent format.
2880 */
2881 int
2882 sys_getdents(p, v, retval)
2883 struct proc *p;
2884 void *v;
2885 register_t *retval;
2886 {
2887 register struct sys_getdents_args /* {
2888 syscallarg(int) fd;
2889 syscallarg(char *) buf;
2890 syscallarg(size_t) count;
2891 } */ *uap = v;
2892 struct file *fp;
2893 int error, done;
2894
2895 /* getvnode() will use the descriptor for us */
2896 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2897 return (error);
2898 if ((fp->f_flag & FREAD) == 0) {
2899 error = EBADF;
2900 goto out;
2901 }
2902 error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
2903 SCARG(uap, count), &done, p, 0, 0);
2904 *retval = done;
2905 out:
2906 FILE_UNUSE(fp, p);
2907 return (error);
2908 }
2909
2910 /*
2911 * Set the mode mask for creation of filesystem nodes.
2912 */
2913 int
2914 sys_umask(p, v, retval)
2915 struct proc *p;
2916 void *v;
2917 register_t *retval;
2918 {
2919 struct sys_umask_args /* {
2920 syscallarg(mode_t) newmask;
2921 } */ *uap = v;
2922 struct cwdinfo *cwdi;
2923
2924 cwdi = p->p_cwdi;
2925 *retval = cwdi->cwdi_cmask;
2926 cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
2927 return (0);
2928 }
2929
2930 /*
2931 * Void all references to file by ripping underlying filesystem
2932 * away from vnode.
2933 */
2934 /* ARGSUSED */
2935 int
2936 sys_revoke(p, v, retval)
2937 struct proc *p;
2938 void *v;
2939 register_t *retval;
2940 {
2941 register struct sys_revoke_args /* {
2942 syscallarg(const char *) path;
2943 } */ *uap = v;
2944 register struct vnode *vp;
2945 struct vattr vattr;
2946 int error;
2947 struct nameidata nd;
2948
2949 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2950 if ((error = namei(&nd)) != 0)
2951 return (error);
2952 vp = nd.ni_vp;
2953 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2954 goto out;
2955 if (p->p_ucred->cr_uid != vattr.va_uid &&
2956 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
2957 goto out;
2958 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2959 VOP_REVOKE(vp, REVOKEALL);
2960 out:
2961 vrele(vp);
2962 return (error);
2963 }
2964
2965 /*
2966 * Convert a user file descriptor to a kernel file entry.
2967 */
2968 int
2969 getvnode(fdp, fd, fpp)
2970 struct filedesc *fdp;
2971 int fd;
2972 struct file **fpp;
2973 {
2974 struct vnode *vp;
2975 struct file *fp;
2976
2977 if ((u_int)fd >= fdp->fd_nfiles ||
2978 (fp = fdp->fd_ofiles[fd]) == NULL ||
2979 (fp->f_iflags & FIF_WANTCLOSE) != 0)
2980 return (EBADF);
2981
2982 FILE_USE(fp);
2983
2984 if (fp->f_type != DTYPE_VNODE) {
2985 FILE_UNUSE(fp, NULL);
2986 return (EINVAL);
2987 }
2988
2989 vp = (struct vnode *)fp->f_data;
2990 if (vp->v_type == VBAD) {
2991 FILE_UNUSE(fp, NULL);
2992 return (EBADF);
2993 }
2994
2995 *fpp = fp;
2996 return (0);
2997 }
2998