vfs_syscalls.c revision 1.421 1 /* $NetBSD: vfs_syscalls.c,v 1.421 2011/04/02 04:57:35 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1989, 1993
34 * The Regents of the University of California. All rights reserved.
35 * (c) UNIX System Laboratories, Inc.
36 * All or some portions of this file are derived from material licensed
37 * to the University of California by American Telephone and Telegraph
38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39 * the permission of UNIX System Laboratories, Inc.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95
66 */
67
68 /*
69 * Virtual File System System Calls
70 */
71
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.421 2011/04/02 04:57:35 rmind Exp $");
74
75 #ifdef _KERNEL_OPT
76 #include "opt_fileassoc.h"
77 #include "veriexec.h"
78 #endif
79
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/namei.h>
83 #include <sys/filedesc.h>
84 #include <sys/kernel.h>
85 #include <sys/file.h>
86 #include <sys/stat.h>
87 #include <sys/vnode.h>
88 #include <sys/mount.h>
89 #include <sys/proc.h>
90 #include <sys/uio.h>
91 #include <sys/kmem.h>
92 #include <sys/dirent.h>
93 #include <sys/sysctl.h>
94 #include <sys/syscallargs.h>
95 #include <sys/vfs_syscalls.h>
96 #include <sys/ktrace.h>
97 #ifdef FILEASSOC
98 #include <sys/fileassoc.h>
99 #endif /* FILEASSOC */
100 #include <sys/verified_exec.h>
101 #include <sys/kauth.h>
102 #include <sys/atomic.h>
103 #include <sys/module.h>
104 #include <sys/buf.h>
105
106 #include <miscfs/genfs/genfs.h>
107 #include <miscfs/syncfs/syncfs.h>
108 #include <miscfs/specfs/specdev.h>
109
110 #include <nfs/rpcv2.h>
111 #include <nfs/nfsproto.h>
112 #include <nfs/nfs.h>
113 #include <nfs/nfs_var.h>
114
115 static int change_flags(struct vnode *, u_long, struct lwp *);
116 static int change_mode(struct vnode *, int, struct lwp *l);
117 static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
118
119 /*
120 * This table is used to maintain compatibility with 4.3BSD
121 * and NetBSD 0.9 mount syscalls - and possibly other systems.
122 * Note, the order is important!
123 *
124 * Do not modify this table. It should only contain filesystems
125 * supported by NetBSD 0.9 and 4.3BSD.
126 */
127 const char * const mountcompatnames[] = {
128 NULL, /* 0 = MOUNT_NONE */
129 MOUNT_FFS, /* 1 = MOUNT_UFS */
130 MOUNT_NFS, /* 2 */
131 MOUNT_MFS, /* 3 */
132 MOUNT_MSDOS, /* 4 */
133 MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
134 MOUNT_FDESC, /* 6 */
135 MOUNT_KERNFS, /* 7 */
136 NULL, /* 8 = MOUNT_DEVFS */
137 MOUNT_AFS, /* 9 */
138 };
139
140 const int nmountcompatnames = __arraycount(mountcompatnames);
141
142 static int
143 mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
144 void *data, size_t *data_len)
145 {
146 struct mount *mp;
147 int error = 0, saved_flags;
148
149 mp = vp->v_mount;
150 saved_flags = mp->mnt_flag;
151
152 /* We can operate only on VV_ROOT nodes. */
153 if ((vp->v_vflag & VV_ROOT) == 0) {
154 error = EINVAL;
155 goto out;
156 }
157
158 /*
159 * We only allow the filesystem to be reloaded if it
160 * is currently mounted read-only. Additionally, we
161 * prevent read-write to read-only downgrades.
162 */
163 if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
164 (mp->mnt_flag & MNT_RDONLY) == 0 &&
165 (mp->mnt_iflag & IMNT_CAN_RWTORO) == 0) {
166 error = EOPNOTSUPP; /* Needs translation */
167 goto out;
168 }
169
170 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
171 KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
172 if (error)
173 goto out;
174
175 if (vfs_busy(mp, NULL)) {
176 error = EPERM;
177 goto out;
178 }
179
180 mutex_enter(&mp->mnt_updating);
181
182 mp->mnt_flag &= ~MNT_OP_FLAGS;
183 mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
184
185 /*
186 * Set the mount level flags.
187 */
188 if (flags & MNT_RDONLY)
189 mp->mnt_flag |= MNT_RDONLY;
190 else if (mp->mnt_flag & MNT_RDONLY)
191 mp->mnt_iflag |= IMNT_WANTRDWR;
192 mp->mnt_flag &=
193 ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
194 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
195 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
196 MNT_LOG);
197 mp->mnt_flag |= flags &
198 (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
199 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
200 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
201 MNT_LOG | MNT_IGNORE);
202
203 error = VFS_MOUNT(mp, path, data, data_len);
204
205 if (error && data != NULL) {
206 int error2;
207
208 /*
209 * Update failed; let's try and see if it was an
210 * export request. For compat with 3.0 and earlier.
211 */
212 error2 = vfs_hooks_reexport(mp, path, data);
213
214 /*
215 * Only update error code if the export request was
216 * understood but some problem occurred while
217 * processing it.
218 */
219 if (error2 != EJUSTRETURN)
220 error = error2;
221 }
222
223 if (mp->mnt_iflag & IMNT_WANTRDWR)
224 mp->mnt_flag &= ~MNT_RDONLY;
225 if (error)
226 mp->mnt_flag = saved_flags;
227 mp->mnt_flag &= ~MNT_OP_FLAGS;
228 mp->mnt_iflag &= ~IMNT_WANTRDWR;
229 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
230 if (mp->mnt_syncer == NULL)
231 error = vfs_allocate_syncvnode(mp);
232 } else {
233 if (mp->mnt_syncer != NULL)
234 vfs_deallocate_syncvnode(mp);
235 }
236 mutex_exit(&mp->mnt_updating);
237 vfs_unbusy(mp, false, NULL);
238
239 out:
240 return (error);
241 }
242
243 static int
244 mount_get_vfsops(const char *fstype, struct vfsops **vfsops)
245 {
246 char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)];
247 int error;
248
249 /* Copy file-system type from userspace. */
250 error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
251 if (error) {
252 /*
253 * Historically, filesystem types were identified by numbers.
254 * If we get an integer for the filesystem type instead of a
255 * string, we check to see if it matches one of the historic
256 * filesystem types.
257 */
258 u_long fsindex = (u_long)fstype;
259 if (fsindex >= nmountcompatnames ||
260 mountcompatnames[fsindex] == NULL)
261 return ENODEV;
262 strlcpy(fstypename, mountcompatnames[fsindex],
263 sizeof(fstypename));
264 }
265
266 /* Accept `ufs' as an alias for `ffs', for compatibility. */
267 if (strcmp(fstypename, "ufs") == 0)
268 fstypename[0] = 'f';
269
270 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
271 return 0;
272
273 /* If we can autoload a vfs module, try again */
274 (void)module_autoload(fstypename, MODULE_CLASS_VFS);
275
276 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
277 return 0;
278
279 return ENODEV;
280 }
281
282 static int
283 mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags,
284 void *data, size_t *data_len)
285 {
286 struct mount *mp;
287 int error;
288
289 /* If MNT_GETARGS is specified, it should be the only flag. */
290 if (flags & ~MNT_GETARGS)
291 return EINVAL;
292
293 mp = vp->v_mount;
294
295 /* XXX: probably some notion of "can see" here if we want isolation. */
296 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
297 KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
298 if (error)
299 return error;
300
301 if ((vp->v_vflag & VV_ROOT) == 0)
302 return EINVAL;
303
304 if (vfs_busy(mp, NULL))
305 return EPERM;
306
307 mutex_enter(&mp->mnt_updating);
308 mp->mnt_flag &= ~MNT_OP_FLAGS;
309 mp->mnt_flag |= MNT_GETARGS;
310 error = VFS_MOUNT(mp, path, data, data_len);
311 mp->mnt_flag &= ~MNT_OP_FLAGS;
312 mutex_exit(&mp->mnt_updating);
313
314 vfs_unbusy(mp, false, NULL);
315 return (error);
316 }
317
318 int
319 sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
320 {
321 /* {
322 syscallarg(const char *) type;
323 syscallarg(const char *) path;
324 syscallarg(int) flags;
325 syscallarg(void *) data;
326 syscallarg(size_t) data_len;
327 } */
328
329 return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
330 SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE,
331 SCARG(uap, data_len), retval);
332 }
333
334 int
335 do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type,
336 const char *path, int flags, void *data, enum uio_seg data_seg,
337 size_t data_len, register_t *retval)
338 {
339 struct vnode *vp;
340 void *data_buf = data;
341 bool vfsopsrele = false;
342 int error;
343
344 /* XXX: The calling convention of this routine is totally bizarre */
345 if (vfsops)
346 vfsopsrele = true;
347
348 /*
349 * Get vnode to be covered
350 */
351 error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
352 if (error != 0) {
353 vp = NULL;
354 goto done;
355 }
356
357 if (vfsops == NULL) {
358 if (flags & (MNT_GETARGS | MNT_UPDATE)) {
359 vfsops = vp->v_mount->mnt_op;
360 } else {
361 /* 'type' is userspace */
362 error = mount_get_vfsops(type, &vfsops);
363 if (error != 0)
364 goto done;
365 vfsopsrele = true;
366 }
367 }
368
369 if (data != NULL && data_seg == UIO_USERSPACE) {
370 if (data_len == 0) {
371 /* No length supplied, use default for filesystem */
372 data_len = vfsops->vfs_min_mount_data;
373 if (data_len > VFS_MAX_MOUNT_DATA) {
374 error = EINVAL;
375 goto done;
376 }
377 /*
378 * Hopefully a longer buffer won't make copyin() fail.
379 * For compatibility with 3.0 and earlier.
380 */
381 if (flags & MNT_UPDATE
382 && data_len < sizeof (struct mnt_export_args30))
383 data_len = sizeof (struct mnt_export_args30);
384 }
385 data_buf = kmem_alloc(data_len, KM_SLEEP);
386
387 /* NFS needs the buffer even for mnt_getargs .... */
388 error = copyin(data, data_buf, data_len);
389 if (error != 0)
390 goto done;
391 }
392
393 if (flags & MNT_GETARGS) {
394 if (data_len == 0) {
395 error = EINVAL;
396 goto done;
397 }
398 error = mount_getargs(l, vp, path, flags, data_buf, &data_len);
399 if (error != 0)
400 goto done;
401 if (data_seg == UIO_USERSPACE)
402 error = copyout(data_buf, data, data_len);
403 *retval = data_len;
404 } else if (flags & MNT_UPDATE) {
405 error = mount_update(l, vp, path, flags, data_buf, &data_len);
406 } else {
407 /* Locking is handled internally in mount_domount(). */
408 KASSERT(vfsopsrele == true);
409 error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
410 &data_len);
411 vfsopsrele = false;
412 }
413
414 done:
415 if (vfsopsrele)
416 vfs_delref(vfsops);
417 if (vp != NULL) {
418 vrele(vp);
419 }
420 if (data_buf != data)
421 kmem_free(data_buf, data_len);
422 return (error);
423 }
424
425 /*
426 * Unmount a file system.
427 *
428 * Note: unmount takes a path to the vnode mounted on as argument,
429 * not special file (as before).
430 */
431 /* ARGSUSED */
432 int
433 sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval)
434 {
435 /* {
436 syscallarg(const char *) path;
437 syscallarg(int) flags;
438 } */
439 struct vnode *vp;
440 struct mount *mp;
441 int error;
442 struct pathbuf *pb;
443 struct nameidata nd;
444
445 error = pathbuf_copyin(SCARG(uap, path), &pb);
446 if (error) {
447 return error;
448 }
449
450 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
451 if ((error = namei(&nd)) != 0) {
452 pathbuf_destroy(pb);
453 return error;
454 }
455 vp = nd.ni_vp;
456 pathbuf_destroy(pb);
457
458 mp = vp->v_mount;
459 atomic_inc_uint(&mp->mnt_refcnt);
460 VOP_UNLOCK(vp);
461
462 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
463 KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
464 if (error) {
465 vrele(vp);
466 vfs_destroy(mp);
467 return (error);
468 }
469
470 /*
471 * Don't allow unmounting the root file system.
472 */
473 if (mp->mnt_flag & MNT_ROOTFS) {
474 vrele(vp);
475 vfs_destroy(mp);
476 return (EINVAL);
477 }
478
479 /*
480 * Must be the root of the filesystem
481 */
482 if ((vp->v_vflag & VV_ROOT) == 0) {
483 vrele(vp);
484 vfs_destroy(mp);
485 return (EINVAL);
486 }
487
488 vrele(vp);
489 error = dounmount(mp, SCARG(uap, flags), l);
490 vfs_destroy(mp);
491 return error;
492 }
493
494 /*
495 * Sync each mounted filesystem.
496 */
497 #ifdef DEBUG
498 int syncprt = 0;
499 struct ctldebug debug0 = { "syncprt", &syncprt };
500 #endif
501
502 /* ARGSUSED */
503 int
504 sys_sync(struct lwp *l, const void *v, register_t *retval)
505 {
506 struct mount *mp, *nmp;
507 int asyncflag;
508
509 if (l == NULL)
510 l = &lwp0;
511
512 mutex_enter(&mountlist_lock);
513 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
514 mp = nmp) {
515 if (vfs_busy(mp, &nmp)) {
516 continue;
517 }
518 mutex_enter(&mp->mnt_updating);
519 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
520 asyncflag = mp->mnt_flag & MNT_ASYNC;
521 mp->mnt_flag &= ~MNT_ASYNC;
522 VFS_SYNC(mp, MNT_NOWAIT, l->l_cred);
523 if (asyncflag)
524 mp->mnt_flag |= MNT_ASYNC;
525 }
526 mutex_exit(&mp->mnt_updating);
527 vfs_unbusy(mp, false, &nmp);
528 }
529 mutex_exit(&mountlist_lock);
530 #ifdef DEBUG
531 if (syncprt)
532 vfs_bufstats();
533 #endif /* DEBUG */
534 return (0);
535 }
536
537 /*
538 * Change filesystem quotas.
539 */
540 /* ARGSUSED */
541 int
542 sys___quotactl50(struct lwp *l, const struct sys___quotactl50_args *uap,
543 register_t *retval)
544 {
545 /* {
546 syscallarg(const char *) path;
547 syscallarg(struct plistref *) pref;
548 } */
549 struct mount *mp;
550 int error;
551 struct vnode *vp;
552 prop_dictionary_t dict;
553 struct plistref pref;
554
555 error = namei_simple_user(SCARG(uap, path),
556 NSM_FOLLOW_TRYEMULROOT, &vp);
557 if (error != 0)
558 return (error);
559 mp = vp->v_mount;
560 error = copyin(SCARG(uap, pref), &pref, sizeof(pref));
561 if (error)
562 return error;
563 error = prop_dictionary_copyin(&pref, &dict);
564 if (error)
565 return error;
566 error = VFS_QUOTACTL(mp, dict);
567 vrele(vp);
568 if (!error)
569 error = prop_dictionary_copyout(&pref, dict);
570 if (!error)
571 error = copyout(&pref, SCARG(uap, pref), sizeof(pref));
572 prop_object_release(dict);
573 return (error);
574 }
575
576 int
577 dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
578 int root)
579 {
580 struct cwdinfo *cwdi = l->l_proc->p_cwdi;
581 int error = 0;
582
583 /*
584 * If MNT_NOWAIT or MNT_LAZY is specified, do not
585 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
586 * overrides MNT_NOWAIT.
587 */
588 if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
589 (flags != MNT_WAIT && flags != 0)) {
590 memcpy(sp, &mp->mnt_stat, sizeof(*sp));
591 goto done;
592 }
593
594 /* Get the filesystem stats now */
595 memset(sp, 0, sizeof(*sp));
596 if ((error = VFS_STATVFS(mp, sp)) != 0) {
597 return error;
598 }
599
600 if (cwdi->cwdi_rdir == NULL)
601 (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
602 done:
603 if (cwdi->cwdi_rdir != NULL) {
604 size_t len;
605 char *bp;
606 char c;
607 char *path = PNBUF_GET();
608
609 bp = path + MAXPATHLEN;
610 *--bp = '\0';
611 rw_enter(&cwdi->cwdi_lock, RW_READER);
612 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
613 MAXPATHLEN / 2, 0, l);
614 rw_exit(&cwdi->cwdi_lock);
615 if (error) {
616 PNBUF_PUT(path);
617 return error;
618 }
619 len = strlen(bp);
620 if (len != 1) {
621 /*
622 * for mount points that are below our root, we can see
623 * them, so we fix up the pathname and return them. The
624 * rest we cannot see, so we don't allow viewing the
625 * data.
626 */
627 if (strncmp(bp, sp->f_mntonname, len) == 0 &&
628 ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
629 (void)strlcpy(sp->f_mntonname,
630 c == '\0' ? "/" : &sp->f_mntonname[len],
631 sizeof(sp->f_mntonname));
632 } else {
633 if (root)
634 (void)strlcpy(sp->f_mntonname, "/",
635 sizeof(sp->f_mntonname));
636 else
637 error = EPERM;
638 }
639 }
640 PNBUF_PUT(path);
641 }
642 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
643 return error;
644 }
645
646 /*
647 * Get filesystem statistics by path.
648 */
649 int
650 do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb)
651 {
652 struct mount *mp;
653 int error;
654 struct vnode *vp;
655
656 error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
657 if (error != 0)
658 return error;
659 mp = vp->v_mount;
660 error = dostatvfs(mp, sb, l, flags, 1);
661 vrele(vp);
662 return error;
663 }
664
665 /* ARGSUSED */
666 int
667 sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval)
668 {
669 /* {
670 syscallarg(const char *) path;
671 syscallarg(struct statvfs *) buf;
672 syscallarg(int) flags;
673 } */
674 struct statvfs *sb;
675 int error;
676
677 sb = STATVFSBUF_GET();
678 error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb);
679 if (error == 0)
680 error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
681 STATVFSBUF_PUT(sb);
682 return error;
683 }
684
685 /*
686 * Get filesystem statistics by fd.
687 */
688 int
689 do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb)
690 {
691 file_t *fp;
692 struct mount *mp;
693 int error;
694
695 /* fd_getvnode() will use the descriptor for us */
696 if ((error = fd_getvnode(fd, &fp)) != 0)
697 return (error);
698 mp = ((struct vnode *)fp->f_data)->v_mount;
699 error = dostatvfs(mp, sb, curlwp, flags, 1);
700 fd_putfile(fd);
701 return error;
702 }
703
704 /* ARGSUSED */
705 int
706 sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval)
707 {
708 /* {
709 syscallarg(int) fd;
710 syscallarg(struct statvfs *) buf;
711 syscallarg(int) flags;
712 } */
713 struct statvfs *sb;
714 int error;
715
716 sb = STATVFSBUF_GET();
717 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
718 if (error == 0)
719 error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
720 STATVFSBUF_PUT(sb);
721 return error;
722 }
723
724
725 /*
726 * Get statistics on all filesystems.
727 */
728 int
729 do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags,
730 int (*copyfn)(const void *, void *, size_t), size_t entry_sz,
731 register_t *retval)
732 {
733 int root = 0;
734 struct proc *p = l->l_proc;
735 struct mount *mp, *nmp;
736 struct statvfs *sb;
737 size_t count, maxcount;
738 int error = 0;
739
740 sb = STATVFSBUF_GET();
741 maxcount = bufsize / entry_sz;
742 mutex_enter(&mountlist_lock);
743 count = 0;
744 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
745 mp = nmp) {
746 if (vfs_busy(mp, &nmp)) {
747 continue;
748 }
749 if (sfsp && count < maxcount) {
750 error = dostatvfs(mp, sb, l, flags, 0);
751 if (error) {
752 vfs_unbusy(mp, false, &nmp);
753 error = 0;
754 continue;
755 }
756 error = copyfn(sb, sfsp, entry_sz);
757 if (error) {
758 vfs_unbusy(mp, false, NULL);
759 goto out;
760 }
761 sfsp = (char *)sfsp + entry_sz;
762 root |= strcmp(sb->f_mntonname, "/") == 0;
763 }
764 count++;
765 vfs_unbusy(mp, false, &nmp);
766 }
767 mutex_exit(&mountlist_lock);
768
769 if (root == 0 && p->p_cwdi->cwdi_rdir) {
770 /*
771 * fake a root entry
772 */
773 error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount,
774 sb, l, flags, 1);
775 if (error != 0)
776 goto out;
777 if (sfsp) {
778 error = copyfn(sb, sfsp, entry_sz);
779 if (error != 0)
780 goto out;
781 }
782 count++;
783 }
784 if (sfsp && count > maxcount)
785 *retval = maxcount;
786 else
787 *retval = count;
788 out:
789 STATVFSBUF_PUT(sb);
790 return error;
791 }
792
793 int
794 sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval)
795 {
796 /* {
797 syscallarg(struct statvfs *) buf;
798 syscallarg(size_t) bufsize;
799 syscallarg(int) flags;
800 } */
801
802 return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize),
803 SCARG(uap, flags), copyout, sizeof (struct statvfs), retval);
804 }
805
806 /*
807 * Change current working directory to a given file descriptor.
808 */
809 /* ARGSUSED */
810 int
811 sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval)
812 {
813 /* {
814 syscallarg(int) fd;
815 } */
816 struct proc *p = l->l_proc;
817 struct cwdinfo *cwdi;
818 struct vnode *vp, *tdp;
819 struct mount *mp;
820 file_t *fp;
821 int error, fd;
822
823 /* fd_getvnode() will use the descriptor for us */
824 fd = SCARG(uap, fd);
825 if ((error = fd_getvnode(fd, &fp)) != 0)
826 return (error);
827 vp = fp->f_data;
828
829 vref(vp);
830 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
831 if (vp->v_type != VDIR)
832 error = ENOTDIR;
833 else
834 error = VOP_ACCESS(vp, VEXEC, l->l_cred);
835 if (error) {
836 vput(vp);
837 goto out;
838 }
839 while ((mp = vp->v_mountedhere) != NULL) {
840 error = vfs_busy(mp, NULL);
841 vput(vp);
842 if (error != 0)
843 goto out;
844 error = VFS_ROOT(mp, &tdp);
845 vfs_unbusy(mp, false, NULL);
846 if (error)
847 goto out;
848 vp = tdp;
849 }
850 VOP_UNLOCK(vp);
851
852 /*
853 * Disallow changing to a directory not under the process's
854 * current root directory (if there is one).
855 */
856 cwdi = p->p_cwdi;
857 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
858 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
859 vrele(vp);
860 error = EPERM; /* operation not permitted */
861 } else {
862 vrele(cwdi->cwdi_cdir);
863 cwdi->cwdi_cdir = vp;
864 }
865 rw_exit(&cwdi->cwdi_lock);
866
867 out:
868 fd_putfile(fd);
869 return (error);
870 }
871
872 /*
873 * Change this process's notion of the root directory to a given file
874 * descriptor.
875 */
876 int
877 sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
878 {
879 struct proc *p = l->l_proc;
880 struct vnode *vp;
881 file_t *fp;
882 int error, fd = SCARG(uap, fd);
883
884 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
885 KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
886 return error;
887 /* fd_getvnode() will use the descriptor for us */
888 if ((error = fd_getvnode(fd, &fp)) != 0)
889 return error;
890 vp = fp->f_data;
891 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
892 if (vp->v_type != VDIR)
893 error = ENOTDIR;
894 else
895 error = VOP_ACCESS(vp, VEXEC, l->l_cred);
896 VOP_UNLOCK(vp);
897 if (error)
898 goto out;
899 vref(vp);
900
901 change_root(p->p_cwdi, vp, l);
902
903 out:
904 fd_putfile(fd);
905 return (error);
906 }
907
908 /*
909 * Change current working directory (``.'').
910 */
911 /* ARGSUSED */
912 int
913 sys_chdir(struct lwp *l, const struct sys_chdir_args *uap, register_t *retval)
914 {
915 /* {
916 syscallarg(const char *) path;
917 } */
918 struct proc *p = l->l_proc;
919 struct cwdinfo *cwdi;
920 int error;
921 struct vnode *vp;
922
923 if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
924 &vp, l)) != 0)
925 return (error);
926 cwdi = p->p_cwdi;
927 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
928 vrele(cwdi->cwdi_cdir);
929 cwdi->cwdi_cdir = vp;
930 rw_exit(&cwdi->cwdi_lock);
931 return (0);
932 }
933
934 /*
935 * Change notion of root (``/'') directory.
936 */
937 /* ARGSUSED */
938 int
939 sys_chroot(struct lwp *l, const struct sys_chroot_args *uap, register_t *retval)
940 {
941 /* {
942 syscallarg(const char *) path;
943 } */
944 struct proc *p = l->l_proc;
945 int error;
946 struct vnode *vp;
947
948 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
949 KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
950 return (error);
951 if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
952 &vp, l)) != 0)
953 return (error);
954
955 change_root(p->p_cwdi, vp, l);
956
957 return (0);
958 }
959
960 /*
961 * Common routine for chroot and fchroot.
962 * NB: callers need to properly authorize the change root operation.
963 */
964 void
965 change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l)
966 {
967
968 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
969 if (cwdi->cwdi_rdir != NULL)
970 vrele(cwdi->cwdi_rdir);
971 cwdi->cwdi_rdir = vp;
972
973 /*
974 * Prevent escaping from chroot by putting the root under
975 * the working directory. Silently chdir to / if we aren't
976 * already there.
977 */
978 if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
979 /*
980 * XXX would be more failsafe to change directory to a
981 * deadfs node here instead
982 */
983 vrele(cwdi->cwdi_cdir);
984 vref(vp);
985 cwdi->cwdi_cdir = vp;
986 }
987 rw_exit(&cwdi->cwdi_lock);
988 }
989
990 /*
991 * Common routine for chroot and chdir.
992 * XXX "where" should be enum uio_seg
993 */
994 int
995 chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l)
996 {
997 struct pathbuf *pb;
998 struct nameidata nd;
999 int error;
1000
1001 error = pathbuf_maybe_copyin(path, where, &pb);
1002 if (error) {
1003 return error;
1004 }
1005 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1006 if ((error = namei(&nd)) != 0) {
1007 pathbuf_destroy(pb);
1008 return error;
1009 }
1010 *vpp = nd.ni_vp;
1011 pathbuf_destroy(pb);
1012
1013 if ((*vpp)->v_type != VDIR)
1014 error = ENOTDIR;
1015 else
1016 error = VOP_ACCESS(*vpp, VEXEC, l->l_cred);
1017
1018 if (error)
1019 vput(*vpp);
1020 else
1021 VOP_UNLOCK(*vpp);
1022 return (error);
1023 }
1024
1025 /*
1026 * Check permissions, allocate an open file structure,
1027 * and call the device open routine if any.
1028 */
1029 int
1030 sys_open(struct lwp *l, const struct sys_open_args *uap, register_t *retval)
1031 {
1032 /* {
1033 syscallarg(const char *) path;
1034 syscallarg(int) flags;
1035 syscallarg(int) mode;
1036 } */
1037 struct proc *p = l->l_proc;
1038 struct cwdinfo *cwdi = p->p_cwdi;
1039 file_t *fp;
1040 struct vnode *vp;
1041 int flags, cmode;
1042 int type, indx, error;
1043 struct flock lf;
1044 struct pathbuf *pb;
1045 struct nameidata nd;
1046
1047 flags = FFLAGS(SCARG(uap, flags));
1048 if ((flags & (FREAD | FWRITE)) == 0)
1049 return (EINVAL);
1050
1051 error = pathbuf_copyin(SCARG(uap, path), &pb);
1052 if (error) {
1053 return error;
1054 }
1055
1056 if ((error = fd_allocfile(&fp, &indx)) != 0) {
1057 pathbuf_destroy(pb);
1058 return error;
1059 }
1060 /* We're going to read cwdi->cwdi_cmask unlocked here. */
1061 cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1062 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, pb);
1063 l->l_dupfd = -indx - 1; /* XXX check for fdopen */
1064 if ((error = vn_open(&nd, flags, cmode)) != 0) {
1065 fd_abort(p, fp, indx);
1066 if ((error == EDUPFD || error == EMOVEFD) &&
1067 l->l_dupfd >= 0 && /* XXX from fdopen */
1068 (error =
1069 fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) {
1070 *retval = indx;
1071 pathbuf_destroy(pb);
1072 return (0);
1073 }
1074 if (error == ERESTART)
1075 error = EINTR;
1076 pathbuf_destroy(pb);
1077 return (error);
1078 }
1079
1080 l->l_dupfd = 0;
1081 vp = nd.ni_vp;
1082 pathbuf_destroy(pb);
1083
1084 fp->f_flag = flags & FMASK;
1085 fp->f_type = DTYPE_VNODE;
1086 fp->f_ops = &vnops;
1087 fp->f_data = vp;
1088 if (flags & (O_EXLOCK | O_SHLOCK)) {
1089 lf.l_whence = SEEK_SET;
1090 lf.l_start = 0;
1091 lf.l_len = 0;
1092 if (flags & O_EXLOCK)
1093 lf.l_type = F_WRLCK;
1094 else
1095 lf.l_type = F_RDLCK;
1096 type = F_FLOCK;
1097 if ((flags & FNONBLOCK) == 0)
1098 type |= F_WAIT;
1099 VOP_UNLOCK(vp);
1100 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1101 if (error) {
1102 (void) vn_close(vp, fp->f_flag, fp->f_cred);
1103 fd_abort(p, fp, indx);
1104 return (error);
1105 }
1106 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1107 atomic_or_uint(&fp->f_flag, FHASLOCK);
1108 }
1109 VOP_UNLOCK(vp);
1110 *retval = indx;
1111 fd_affix(p, fp, indx);
1112 return (0);
1113 }
1114
1115 static void
1116 vfs__fhfree(fhandle_t *fhp)
1117 {
1118 size_t fhsize;
1119
1120 if (fhp == NULL) {
1121 return;
1122 }
1123 fhsize = FHANDLE_SIZE(fhp);
1124 kmem_free(fhp, fhsize);
1125 }
1126
1127 /*
1128 * vfs_composefh: compose a filehandle.
1129 */
1130
1131 int
1132 vfs_composefh(struct vnode *vp, fhandle_t *fhp, size_t *fh_size)
1133 {
1134 struct mount *mp;
1135 struct fid *fidp;
1136 int error;
1137 size_t needfhsize;
1138 size_t fidsize;
1139
1140 mp = vp->v_mount;
1141 fidp = NULL;
1142 if (*fh_size < FHANDLE_SIZE_MIN) {
1143 fidsize = 0;
1144 } else {
1145 fidsize = *fh_size - offsetof(fhandle_t, fh_fid);
1146 if (fhp != NULL) {
1147 memset(fhp, 0, *fh_size);
1148 fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1149 fidp = &fhp->fh_fid;
1150 }
1151 }
1152 error = VFS_VPTOFH(vp, fidp, &fidsize);
1153 needfhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1154 if (error == 0 && *fh_size < needfhsize) {
1155 error = E2BIG;
1156 }
1157 *fh_size = needfhsize;
1158 return error;
1159 }
1160
1161 int
1162 vfs_composefh_alloc(struct vnode *vp, fhandle_t **fhpp)
1163 {
1164 struct mount *mp;
1165 fhandle_t *fhp;
1166 size_t fhsize;
1167 size_t fidsize;
1168 int error;
1169
1170 *fhpp = NULL;
1171 mp = vp->v_mount;
1172 fidsize = 0;
1173 error = VFS_VPTOFH(vp, NULL, &fidsize);
1174 KASSERT(error != 0);
1175 if (error != E2BIG) {
1176 goto out;
1177 }
1178 fhsize = FHANDLE_SIZE_FROM_FILEID_SIZE(fidsize);
1179 fhp = kmem_zalloc(fhsize, KM_SLEEP);
1180 if (fhp == NULL) {
1181 error = ENOMEM;
1182 goto out;
1183 }
1184 fhp->fh_fsid = mp->mnt_stat.f_fsidx;
1185 error = VFS_VPTOFH(vp, &fhp->fh_fid, &fidsize);
1186 if (error == 0) {
1187 KASSERT((FHANDLE_SIZE(fhp) == fhsize &&
1188 FHANDLE_FILEID(fhp)->fid_len == fidsize));
1189 *fhpp = fhp;
1190 } else {
1191 kmem_free(fhp, fhsize);
1192 }
1193 out:
1194 return error;
1195 }
1196
1197 void
1198 vfs_composefh_free(fhandle_t *fhp)
1199 {
1200
1201 vfs__fhfree(fhp);
1202 }
1203
1204 /*
1205 * vfs_fhtovp: lookup a vnode by a filehandle.
1206 */
1207
1208 int
1209 vfs_fhtovp(fhandle_t *fhp, struct vnode **vpp)
1210 {
1211 struct mount *mp;
1212 int error;
1213
1214 *vpp = NULL;
1215 mp = vfs_getvfs(FHANDLE_FSID(fhp));
1216 if (mp == NULL) {
1217 error = ESTALE;
1218 goto out;
1219 }
1220 if (mp->mnt_op->vfs_fhtovp == NULL) {
1221 error = EOPNOTSUPP;
1222 goto out;
1223 }
1224 error = VFS_FHTOVP(mp, FHANDLE_FILEID(fhp), vpp);
1225 out:
1226 return error;
1227 }
1228
1229 /*
1230 * vfs_copyinfh_alloc: allocate and copyin a filehandle, given
1231 * the needed size.
1232 */
1233
1234 int
1235 vfs_copyinfh_alloc(const void *ufhp, size_t fhsize, fhandle_t **fhpp)
1236 {
1237 fhandle_t *fhp;
1238 int error;
1239
1240 *fhpp = NULL;
1241 if (fhsize > FHANDLE_SIZE_MAX) {
1242 return EINVAL;
1243 }
1244 if (fhsize < FHANDLE_SIZE_MIN) {
1245 return EINVAL;
1246 }
1247 again:
1248 fhp = kmem_alloc(fhsize, KM_SLEEP);
1249 if (fhp == NULL) {
1250 return ENOMEM;
1251 }
1252 error = copyin(ufhp, fhp, fhsize);
1253 if (error == 0) {
1254 /* XXX this check shouldn't be here */
1255 if (FHANDLE_SIZE(fhp) == fhsize) {
1256 *fhpp = fhp;
1257 return 0;
1258 } else if (fhsize == NFSX_V2FH && FHANDLE_SIZE(fhp) < fhsize) {
1259 /*
1260 * a kludge for nfsv2 padded handles.
1261 */
1262 size_t sz;
1263
1264 sz = FHANDLE_SIZE(fhp);
1265 kmem_free(fhp, fhsize);
1266 fhsize = sz;
1267 goto again;
1268 } else {
1269 /*
1270 * userland told us wrong size.
1271 */
1272 error = EINVAL;
1273 }
1274 }
1275 kmem_free(fhp, fhsize);
1276 return error;
1277 }
1278
1279 void
1280 vfs_copyinfh_free(fhandle_t *fhp)
1281 {
1282
1283 vfs__fhfree(fhp);
1284 }
1285
1286 /*
1287 * Get file handle system call
1288 */
1289 int
1290 sys___getfh30(struct lwp *l, const struct sys___getfh30_args *uap, register_t *retval)
1291 {
1292 /* {
1293 syscallarg(char *) fname;
1294 syscallarg(fhandle_t *) fhp;
1295 syscallarg(size_t *) fh_size;
1296 } */
1297 struct vnode *vp;
1298 fhandle_t *fh;
1299 int error;
1300 struct pathbuf *pb;
1301 struct nameidata nd;
1302 size_t sz;
1303 size_t usz;
1304
1305 /*
1306 * Must be super user
1307 */
1308 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1309 0, NULL, NULL, NULL);
1310 if (error)
1311 return (error);
1312
1313 error = pathbuf_copyin(SCARG(uap, fname), &pb);
1314 if (error) {
1315 return error;
1316 }
1317 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
1318 error = namei(&nd);
1319 if (error) {
1320 pathbuf_destroy(pb);
1321 return error;
1322 }
1323 vp = nd.ni_vp;
1324 pathbuf_destroy(pb);
1325
1326 error = vfs_composefh_alloc(vp, &fh);
1327 vput(vp);
1328 if (error != 0) {
1329 goto out;
1330 }
1331 error = copyin(SCARG(uap, fh_size), &usz, sizeof(size_t));
1332 if (error != 0) {
1333 goto out;
1334 }
1335 sz = FHANDLE_SIZE(fh);
1336 error = copyout(&sz, SCARG(uap, fh_size), sizeof(size_t));
1337 if (error != 0) {
1338 goto out;
1339 }
1340 if (usz >= sz) {
1341 error = copyout(fh, SCARG(uap, fhp), sz);
1342 } else {
1343 error = E2BIG;
1344 }
1345 out:
1346 vfs_composefh_free(fh);
1347 return (error);
1348 }
1349
1350 /*
1351 * Open a file given a file handle.
1352 *
1353 * Check permissions, allocate an open file structure,
1354 * and call the device open routine if any.
1355 */
1356
1357 int
1358 dofhopen(struct lwp *l, const void *ufhp, size_t fhsize, int oflags,
1359 register_t *retval)
1360 {
1361 file_t *fp;
1362 struct vnode *vp = NULL;
1363 kauth_cred_t cred = l->l_cred;
1364 file_t *nfp;
1365 int type, indx, error=0;
1366 struct flock lf;
1367 struct vattr va;
1368 fhandle_t *fh;
1369 int flags;
1370 proc_t *p;
1371
1372 p = curproc;
1373
1374 /*
1375 * Must be super user
1376 */
1377 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1378 0, NULL, NULL, NULL)))
1379 return (error);
1380
1381 flags = FFLAGS(oflags);
1382 if ((flags & (FREAD | FWRITE)) == 0)
1383 return (EINVAL);
1384 if ((flags & O_CREAT))
1385 return (EINVAL);
1386 if ((error = fd_allocfile(&nfp, &indx)) != 0)
1387 return (error);
1388 fp = nfp;
1389 error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1390 if (error != 0) {
1391 goto bad;
1392 }
1393 error = vfs_fhtovp(fh, &vp);
1394 if (error != 0) {
1395 goto bad;
1396 }
1397
1398 /* Now do an effective vn_open */
1399
1400 if (vp->v_type == VSOCK) {
1401 error = EOPNOTSUPP;
1402 goto bad;
1403 }
1404 error = vn_openchk(vp, cred, flags);
1405 if (error != 0)
1406 goto bad;
1407 if (flags & O_TRUNC) {
1408 VOP_UNLOCK(vp); /* XXX */
1409 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1410 vattr_null(&va);
1411 va.va_size = 0;
1412 error = VOP_SETATTR(vp, &va, cred);
1413 if (error)
1414 goto bad;
1415 }
1416 if ((error = VOP_OPEN(vp, flags, cred)) != 0)
1417 goto bad;
1418 if (flags & FWRITE) {
1419 mutex_enter(&vp->v_interlock);
1420 vp->v_writecount++;
1421 mutex_exit(&vp->v_interlock);
1422 }
1423
1424 /* done with modified vn_open, now finish what sys_open does. */
1425
1426 fp->f_flag = flags & FMASK;
1427 fp->f_type = DTYPE_VNODE;
1428 fp->f_ops = &vnops;
1429 fp->f_data = vp;
1430 if (flags & (O_EXLOCK | O_SHLOCK)) {
1431 lf.l_whence = SEEK_SET;
1432 lf.l_start = 0;
1433 lf.l_len = 0;
1434 if (flags & O_EXLOCK)
1435 lf.l_type = F_WRLCK;
1436 else
1437 lf.l_type = F_RDLCK;
1438 type = F_FLOCK;
1439 if ((flags & FNONBLOCK) == 0)
1440 type |= F_WAIT;
1441 VOP_UNLOCK(vp);
1442 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1443 if (error) {
1444 (void) vn_close(vp, fp->f_flag, fp->f_cred);
1445 fd_abort(p, fp, indx);
1446 return (error);
1447 }
1448 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1449 atomic_or_uint(&fp->f_flag, FHASLOCK);
1450 }
1451 VOP_UNLOCK(vp);
1452 *retval = indx;
1453 fd_affix(p, fp, indx);
1454 vfs_copyinfh_free(fh);
1455 return (0);
1456
1457 bad:
1458 fd_abort(p, fp, indx);
1459 if (vp != NULL)
1460 vput(vp);
1461 vfs_copyinfh_free(fh);
1462 return (error);
1463 }
1464
1465 int
1466 sys___fhopen40(struct lwp *l, const struct sys___fhopen40_args *uap, register_t *retval)
1467 {
1468 /* {
1469 syscallarg(const void *) fhp;
1470 syscallarg(size_t) fh_size;
1471 syscallarg(int) flags;
1472 } */
1473
1474 return dofhopen(l, SCARG(uap, fhp), SCARG(uap, fh_size),
1475 SCARG(uap, flags), retval);
1476 }
1477
1478 int
1479 do_fhstat(struct lwp *l, const void *ufhp, size_t fhsize, struct stat *sb)
1480 {
1481 int error;
1482 fhandle_t *fh;
1483 struct vnode *vp;
1484
1485 /*
1486 * Must be super user
1487 */
1488 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1489 0, NULL, NULL, NULL)))
1490 return (error);
1491
1492 error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1493 if (error != 0)
1494 return error;
1495
1496 error = vfs_fhtovp(fh, &vp);
1497 vfs_copyinfh_free(fh);
1498 if (error != 0)
1499 return error;
1500
1501 error = vn_stat(vp, sb);
1502 vput(vp);
1503 return error;
1504 }
1505
1506
1507 /* ARGSUSED */
1508 int
1509 sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval)
1510 {
1511 /* {
1512 syscallarg(const void *) fhp;
1513 syscallarg(size_t) fh_size;
1514 syscallarg(struct stat *) sb;
1515 } */
1516 struct stat sb;
1517 int error;
1518
1519 error = do_fhstat(l, SCARG(uap, fhp), SCARG(uap, fh_size), &sb);
1520 if (error)
1521 return error;
1522 return copyout(&sb, SCARG(uap, sb), sizeof(sb));
1523 }
1524
1525 int
1526 do_fhstatvfs(struct lwp *l, const void *ufhp, size_t fhsize, struct statvfs *sb,
1527 int flags)
1528 {
1529 fhandle_t *fh;
1530 struct mount *mp;
1531 struct vnode *vp;
1532 int error;
1533
1534 /*
1535 * Must be super user
1536 */
1537 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE,
1538 0, NULL, NULL, NULL)))
1539 return error;
1540
1541 error = vfs_copyinfh_alloc(ufhp, fhsize, &fh);
1542 if (error != 0)
1543 return error;
1544
1545 error = vfs_fhtovp(fh, &vp);
1546 vfs_copyinfh_free(fh);
1547 if (error != 0)
1548 return error;
1549
1550 mp = vp->v_mount;
1551 error = dostatvfs(mp, sb, l, flags, 1);
1552 vput(vp);
1553 return error;
1554 }
1555
1556 /* ARGSUSED */
1557 int
1558 sys___fhstatvfs140(struct lwp *l, const struct sys___fhstatvfs140_args *uap, register_t *retval)
1559 {
1560 /* {
1561 syscallarg(const void *) fhp;
1562 syscallarg(size_t) fh_size;
1563 syscallarg(struct statvfs *) buf;
1564 syscallarg(int) flags;
1565 } */
1566 struct statvfs *sb = STATVFSBUF_GET();
1567 int error;
1568
1569 error = do_fhstatvfs(l, SCARG(uap, fhp), SCARG(uap, fh_size), sb,
1570 SCARG(uap, flags));
1571 if (error == 0)
1572 error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1573 STATVFSBUF_PUT(sb);
1574 return error;
1575 }
1576
1577 /*
1578 * Create a special file.
1579 */
1580 /* ARGSUSED */
1581 int
1582 sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap,
1583 register_t *retval)
1584 {
1585 /* {
1586 syscallarg(const char *) path;
1587 syscallarg(mode_t) mode;
1588 syscallarg(dev_t) dev;
1589 } */
1590 return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode),
1591 SCARG(uap, dev), retval, UIO_USERSPACE);
1592 }
1593
1594 int
1595 do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev,
1596 register_t *retval, enum uio_seg seg)
1597 {
1598 struct proc *p = l->l_proc;
1599 struct vnode *vp;
1600 struct vattr vattr;
1601 int error, optype;
1602 struct pathbuf *pb;
1603 struct nameidata nd;
1604 const char *pathstring;
1605
1606 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
1607 0, NULL, NULL, NULL)) != 0)
1608 return (error);
1609
1610 optype = VOP_MKNOD_DESCOFFSET;
1611
1612 error = pathbuf_maybe_copyin(pathname, seg, &pb);
1613 if (error) {
1614 return error;
1615 }
1616 pathstring = pathbuf_stringcopy_get(pb);
1617 if (pathstring == NULL) {
1618 pathbuf_destroy(pb);
1619 return ENOMEM;
1620 }
1621
1622 NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1623 if ((error = namei(&nd)) != 0)
1624 goto out;
1625 vp = nd.ni_vp;
1626
1627 if (vp != NULL)
1628 error = EEXIST;
1629 else {
1630 vattr_null(&vattr);
1631 /* We will read cwdi->cwdi_cmask unlocked. */
1632 vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1633 vattr.va_rdev = dev;
1634
1635 switch (mode & S_IFMT) {
1636 case S_IFMT: /* used by badsect to flag bad sectors */
1637 vattr.va_type = VBAD;
1638 break;
1639 case S_IFCHR:
1640 vattr.va_type = VCHR;
1641 break;
1642 case S_IFBLK:
1643 vattr.va_type = VBLK;
1644 break;
1645 case S_IFWHT:
1646 optype = VOP_WHITEOUT_DESCOFFSET;
1647 break;
1648 case S_IFREG:
1649 #if NVERIEXEC > 0
1650 error = veriexec_openchk(l, nd.ni_vp, pathstring,
1651 O_CREAT);
1652 #endif /* NVERIEXEC > 0 */
1653 vattr.va_type = VREG;
1654 vattr.va_rdev = VNOVAL;
1655 optype = VOP_CREATE_DESCOFFSET;
1656 break;
1657 default:
1658 error = EINVAL;
1659 break;
1660 }
1661 }
1662 if (!error) {
1663 switch (optype) {
1664 case VOP_WHITEOUT_DESCOFFSET:
1665 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1666 if (error)
1667 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1668 vput(nd.ni_dvp);
1669 break;
1670
1671 case VOP_MKNOD_DESCOFFSET:
1672 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1673 &nd.ni_cnd, &vattr);
1674 if (error == 0)
1675 vput(nd.ni_vp);
1676 break;
1677
1678 case VOP_CREATE_DESCOFFSET:
1679 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp,
1680 &nd.ni_cnd, &vattr);
1681 if (error == 0)
1682 vput(nd.ni_vp);
1683 break;
1684 }
1685 } else {
1686 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1687 if (nd.ni_dvp == vp)
1688 vrele(nd.ni_dvp);
1689 else
1690 vput(nd.ni_dvp);
1691 if (vp)
1692 vrele(vp);
1693 }
1694 out:
1695 pathbuf_stringcopy_put(pb, pathstring);
1696 pathbuf_destroy(pb);
1697 return (error);
1698 }
1699
1700 /*
1701 * Create a named pipe.
1702 */
1703 /* ARGSUSED */
1704 int
1705 sys_mkfifo(struct lwp *l, const struct sys_mkfifo_args *uap, register_t *retval)
1706 {
1707 /* {
1708 syscallarg(const char *) path;
1709 syscallarg(int) mode;
1710 } */
1711 struct proc *p = l->l_proc;
1712 struct vattr vattr;
1713 int error;
1714 struct pathbuf *pb;
1715 struct nameidata nd;
1716
1717 error = pathbuf_copyin(SCARG(uap, path), &pb);
1718 if (error) {
1719 return error;
1720 }
1721 NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, pb);
1722 if ((error = namei(&nd)) != 0) {
1723 pathbuf_destroy(pb);
1724 return error;
1725 }
1726 if (nd.ni_vp != NULL) {
1727 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1728 if (nd.ni_dvp == nd.ni_vp)
1729 vrele(nd.ni_dvp);
1730 else
1731 vput(nd.ni_dvp);
1732 vrele(nd.ni_vp);
1733 pathbuf_destroy(pb);
1734 return (EEXIST);
1735 }
1736 vattr_null(&vattr);
1737 vattr.va_type = VFIFO;
1738 /* We will read cwdi->cwdi_cmask unlocked. */
1739 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1740 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1741 if (error == 0)
1742 vput(nd.ni_vp);
1743 pathbuf_destroy(pb);
1744 return (error);
1745 }
1746
1747 /*
1748 * Make a hard file link.
1749 */
1750 /* ARGSUSED */
1751 int
1752 sys_link(struct lwp *l, const struct sys_link_args *uap, register_t *retval)
1753 {
1754 /* {
1755 syscallarg(const char *) path;
1756 syscallarg(const char *) link;
1757 } */
1758 struct vnode *vp;
1759 struct pathbuf *linkpb;
1760 struct nameidata nd;
1761 int error;
1762
1763 error = namei_simple_user(SCARG(uap, path),
1764 NSM_FOLLOW_TRYEMULROOT, &vp);
1765 if (error != 0)
1766 return (error);
1767 error = pathbuf_copyin(SCARG(uap, link), &linkpb);
1768 if (error) {
1769 goto out1;
1770 }
1771 NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1772 if ((error = namei(&nd)) != 0)
1773 goto out2;
1774 if (nd.ni_vp) {
1775 error = EEXIST;
1776 goto abortop;
1777 }
1778 /*
1779 * Prevent cross-mount operation.
1780 */
1781 if (nd.ni_dvp->v_mount != vp->v_mount) {
1782 error = EXDEV;
1783 goto abortop;
1784 }
1785 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1786 out2:
1787 pathbuf_destroy(linkpb);
1788 out1:
1789 vrele(vp);
1790 return (error);
1791 abortop:
1792 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1793 if (nd.ni_dvp == nd.ni_vp)
1794 vrele(nd.ni_dvp);
1795 else
1796 vput(nd.ni_dvp);
1797 if (nd.ni_vp != NULL)
1798 vrele(nd.ni_vp);
1799 goto out2;
1800 }
1801
1802 int
1803 do_sys_symlink(const char *patharg, const char *link, enum uio_seg seg)
1804 {
1805 struct proc *p = curproc;
1806 struct vattr vattr;
1807 char *path;
1808 int error;
1809 struct pathbuf *linkpb;
1810 struct nameidata nd;
1811
1812 path = PNBUF_GET();
1813 if (seg == UIO_USERSPACE) {
1814 if ((error = copyinstr(patharg, path, MAXPATHLEN, NULL)) != 0)
1815 goto out1;
1816 if ((error = pathbuf_copyin(link, &linkpb)) != 0)
1817 goto out1;
1818 } else {
1819 KASSERT(strlen(patharg) < MAXPATHLEN);
1820 strcpy(path, patharg);
1821 linkpb = pathbuf_create(link);
1822 if (linkpb == NULL) {
1823 error = ENOMEM;
1824 goto out1;
1825 }
1826 }
1827 NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, linkpb);
1828 if ((error = namei(&nd)) != 0)
1829 goto out2;
1830 if (nd.ni_vp) {
1831 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1832 if (nd.ni_dvp == nd.ni_vp)
1833 vrele(nd.ni_dvp);
1834 else
1835 vput(nd.ni_dvp);
1836 vrele(nd.ni_vp);
1837 error = EEXIST;
1838 goto out2;
1839 }
1840 vattr_null(&vattr);
1841 vattr.va_type = VLNK;
1842 /* We will read cwdi->cwdi_cmask unlocked. */
1843 vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1844 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1845 if (error == 0)
1846 vput(nd.ni_vp);
1847 out2:
1848 pathbuf_destroy(linkpb);
1849 out1:
1850 PNBUF_PUT(path);
1851 return (error);
1852 }
1853
1854 /*
1855 * Make a symbolic link.
1856 */
1857 /* ARGSUSED */
1858 int
1859 sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)
1860 {
1861 /* {
1862 syscallarg(const char *) path;
1863 syscallarg(const char *) link;
1864 } */
1865
1866 return do_sys_symlink(SCARG(uap, path), SCARG(uap, link),
1867 UIO_USERSPACE);
1868 }
1869
1870 /*
1871 * Delete a whiteout from the filesystem.
1872 */
1873 /* ARGSUSED */
1874 int
1875 sys_undelete(struct lwp *l, const struct sys_undelete_args *uap, register_t *retval)
1876 {
1877 /* {
1878 syscallarg(const char *) path;
1879 } */
1880 int error;
1881 struct pathbuf *pb;
1882 struct nameidata nd;
1883
1884 error = pathbuf_copyin(SCARG(uap, path), &pb);
1885 if (error) {
1886 return error;
1887 }
1888
1889 NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | TRYEMULROOT, pb);
1890 error = namei(&nd);
1891 if (error) {
1892 pathbuf_destroy(pb);
1893 return (error);
1894 }
1895
1896 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1897 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1898 if (nd.ni_dvp == nd.ni_vp)
1899 vrele(nd.ni_dvp);
1900 else
1901 vput(nd.ni_dvp);
1902 if (nd.ni_vp)
1903 vrele(nd.ni_vp);
1904 pathbuf_destroy(pb);
1905 return (EEXIST);
1906 }
1907 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1908 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1909 vput(nd.ni_dvp);
1910 pathbuf_destroy(pb);
1911 return (error);
1912 }
1913
1914 /*
1915 * Delete a name from the filesystem.
1916 */
1917 /* ARGSUSED */
1918 int
1919 sys_unlink(struct lwp *l, const struct sys_unlink_args *uap, register_t *retval)
1920 {
1921 /* {
1922 syscallarg(const char *) path;
1923 } */
1924
1925 return do_sys_unlink(SCARG(uap, path), UIO_USERSPACE);
1926 }
1927
1928 int
1929 do_sys_unlink(const char *arg, enum uio_seg seg)
1930 {
1931 struct vnode *vp;
1932 int error;
1933 struct pathbuf *pb;
1934 struct nameidata nd;
1935 const char *pathstring;
1936
1937 error = pathbuf_maybe_copyin(arg, seg, &pb);
1938 if (error) {
1939 return error;
1940 }
1941 pathstring = pathbuf_stringcopy_get(pb);
1942 if (pathstring == NULL) {
1943 pathbuf_destroy(pb);
1944 return ENOMEM;
1945 }
1946
1947 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, pb);
1948 if ((error = namei(&nd)) != 0)
1949 goto out;
1950 vp = nd.ni_vp;
1951
1952 /*
1953 * The root of a mounted filesystem cannot be deleted.
1954 */
1955 if (vp->v_vflag & VV_ROOT) {
1956 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1957 if (nd.ni_dvp == vp)
1958 vrele(nd.ni_dvp);
1959 else
1960 vput(nd.ni_dvp);
1961 vput(vp);
1962 error = EBUSY;
1963 goto out;
1964 }
1965
1966 #if NVERIEXEC > 0
1967 /* Handle remove requests for veriexec entries. */
1968 if ((error = veriexec_removechk(curlwp, nd.ni_vp, pathstring)) != 0) {
1969 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1970 if (nd.ni_dvp == vp)
1971 vrele(nd.ni_dvp);
1972 else
1973 vput(nd.ni_dvp);
1974 vput(vp);
1975 goto out;
1976 }
1977 #endif /* NVERIEXEC > 0 */
1978
1979 #ifdef FILEASSOC
1980 (void)fileassoc_file_delete(vp);
1981 #endif /* FILEASSOC */
1982 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1983 out:
1984 pathbuf_stringcopy_put(pb, pathstring);
1985 pathbuf_destroy(pb);
1986 return (error);
1987 }
1988
1989 /*
1990 * Reposition read/write file offset.
1991 */
1992 int
1993 sys_lseek(struct lwp *l, const struct sys_lseek_args *uap, register_t *retval)
1994 {
1995 /* {
1996 syscallarg(int) fd;
1997 syscallarg(int) pad;
1998 syscallarg(off_t) offset;
1999 syscallarg(int) whence;
2000 } */
2001 kauth_cred_t cred = l->l_cred;
2002 file_t *fp;
2003 struct vnode *vp;
2004 struct vattr vattr;
2005 off_t newoff;
2006 int error, fd;
2007
2008 fd = SCARG(uap, fd);
2009
2010 if ((fp = fd_getfile(fd)) == NULL)
2011 return (EBADF);
2012
2013 vp = fp->f_data;
2014 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2015 error = ESPIPE;
2016 goto out;
2017 }
2018
2019 switch (SCARG(uap, whence)) {
2020 case SEEK_CUR:
2021 newoff = fp->f_offset + SCARG(uap, offset);
2022 break;
2023 case SEEK_END:
2024 error = VOP_GETATTR(vp, &vattr, cred);
2025 if (error) {
2026 goto out;
2027 }
2028 newoff = SCARG(uap, offset) + vattr.va_size;
2029 break;
2030 case SEEK_SET:
2031 newoff = SCARG(uap, offset);
2032 break;
2033 default:
2034 error = EINVAL;
2035 goto out;
2036 }
2037 if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) == 0) {
2038 *(off_t *)retval = fp->f_offset = newoff;
2039 }
2040 out:
2041 fd_putfile(fd);
2042 return (error);
2043 }
2044
2045 /*
2046 * Positional read system call.
2047 */
2048 int
2049 sys_pread(struct lwp *l, const struct sys_pread_args *uap, register_t *retval)
2050 {
2051 /* {
2052 syscallarg(int) fd;
2053 syscallarg(void *) buf;
2054 syscallarg(size_t) nbyte;
2055 syscallarg(off_t) offset;
2056 } */
2057 file_t *fp;
2058 struct vnode *vp;
2059 off_t offset;
2060 int error, fd = SCARG(uap, fd);
2061
2062 if ((fp = fd_getfile(fd)) == NULL)
2063 return (EBADF);
2064
2065 if ((fp->f_flag & FREAD) == 0) {
2066 fd_putfile(fd);
2067 return (EBADF);
2068 }
2069
2070 vp = fp->f_data;
2071 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2072 error = ESPIPE;
2073 goto out;
2074 }
2075
2076 offset = SCARG(uap, offset);
2077
2078 /*
2079 * XXX This works because no file systems actually
2080 * XXX take any action on the seek operation.
2081 */
2082 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2083 goto out;
2084
2085 /* dofileread() will unuse the descriptor for us */
2086 return (dofileread(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2087 &offset, 0, retval));
2088
2089 out:
2090 fd_putfile(fd);
2091 return (error);
2092 }
2093
2094 /*
2095 * Positional scatter read system call.
2096 */
2097 int
2098 sys_preadv(struct lwp *l, const struct sys_preadv_args *uap, register_t *retval)
2099 {
2100 /* {
2101 syscallarg(int) fd;
2102 syscallarg(const struct iovec *) iovp;
2103 syscallarg(int) iovcnt;
2104 syscallarg(off_t) offset;
2105 } */
2106 off_t offset = SCARG(uap, offset);
2107
2108 return do_filereadv(SCARG(uap, fd), SCARG(uap, iovp),
2109 SCARG(uap, iovcnt), &offset, 0, retval);
2110 }
2111
2112 /*
2113 * Positional write system call.
2114 */
2115 int
2116 sys_pwrite(struct lwp *l, const struct sys_pwrite_args *uap, register_t *retval)
2117 {
2118 /* {
2119 syscallarg(int) fd;
2120 syscallarg(const void *) buf;
2121 syscallarg(size_t) nbyte;
2122 syscallarg(off_t) offset;
2123 } */
2124 file_t *fp;
2125 struct vnode *vp;
2126 off_t offset;
2127 int error, fd = SCARG(uap, fd);
2128
2129 if ((fp = fd_getfile(fd)) == NULL)
2130 return (EBADF);
2131
2132 if ((fp->f_flag & FWRITE) == 0) {
2133 fd_putfile(fd);
2134 return (EBADF);
2135 }
2136
2137 vp = fp->f_data;
2138 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2139 error = ESPIPE;
2140 goto out;
2141 }
2142
2143 offset = SCARG(uap, offset);
2144
2145 /*
2146 * XXX This works because no file systems actually
2147 * XXX take any action on the seek operation.
2148 */
2149 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2150 goto out;
2151
2152 /* dofilewrite() will unuse the descriptor for us */
2153 return (dofilewrite(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2154 &offset, 0, retval));
2155
2156 out:
2157 fd_putfile(fd);
2158 return (error);
2159 }
2160
2161 /*
2162 * Positional gather write system call.
2163 */
2164 int
2165 sys_pwritev(struct lwp *l, const struct sys_pwritev_args *uap, register_t *retval)
2166 {
2167 /* {
2168 syscallarg(int) fd;
2169 syscallarg(const struct iovec *) iovp;
2170 syscallarg(int) iovcnt;
2171 syscallarg(off_t) offset;
2172 } */
2173 off_t offset = SCARG(uap, offset);
2174
2175 return do_filewritev(SCARG(uap, fd), SCARG(uap, iovp),
2176 SCARG(uap, iovcnt), &offset, 0, retval);
2177 }
2178
2179 /*
2180 * Check access permissions.
2181 */
2182 int
2183 sys_access(struct lwp *l, const struct sys_access_args *uap, register_t *retval)
2184 {
2185 /* {
2186 syscallarg(const char *) path;
2187 syscallarg(int) flags;
2188 } */
2189 kauth_cred_t cred;
2190 struct vnode *vp;
2191 int error, flags;
2192 struct pathbuf *pb;
2193 struct nameidata nd;
2194
2195 CTASSERT(F_OK == 0);
2196 if ((SCARG(uap, flags) & ~(R_OK | W_OK | X_OK)) != 0) {
2197 /* nonsense flags */
2198 return EINVAL;
2199 }
2200
2201 error = pathbuf_copyin(SCARG(uap, path), &pb);
2202 if (error) {
2203 return error;
2204 }
2205 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
2206
2207 /* Override default credentials */
2208 cred = kauth_cred_dup(l->l_cred);
2209 kauth_cred_seteuid(cred, kauth_cred_getuid(l->l_cred));
2210 kauth_cred_setegid(cred, kauth_cred_getgid(l->l_cred));
2211 nd.ni_cnd.cn_cred = cred;
2212
2213 if ((error = namei(&nd)) != 0) {
2214 pathbuf_destroy(pb);
2215 goto out;
2216 }
2217 vp = nd.ni_vp;
2218 pathbuf_destroy(pb);
2219
2220 /* Flags == 0 means only check for existence. */
2221 if (SCARG(uap, flags)) {
2222 flags = 0;
2223 if (SCARG(uap, flags) & R_OK)
2224 flags |= VREAD;
2225 if (SCARG(uap, flags) & W_OK)
2226 flags |= VWRITE;
2227 if (SCARG(uap, flags) & X_OK)
2228 flags |= VEXEC;
2229
2230 error = VOP_ACCESS(vp, flags, cred);
2231 if (!error && (flags & VWRITE))
2232 error = vn_writechk(vp);
2233 }
2234 vput(vp);
2235 out:
2236 kauth_cred_free(cred);
2237 return (error);
2238 }
2239
2240 /*
2241 * Common code for all sys_stat functions, including compat versions.
2242 */
2243 int
2244 do_sys_stat(const char *userpath, unsigned int nd_flags, struct stat *sb)
2245 {
2246 int error;
2247 struct pathbuf *pb;
2248 struct nameidata nd;
2249
2250 error = pathbuf_copyin(userpath, &pb);
2251 if (error) {
2252 return error;
2253 }
2254 NDINIT(&nd, LOOKUP, nd_flags | LOCKLEAF | TRYEMULROOT, pb);
2255 error = namei(&nd);
2256 if (error != 0) {
2257 pathbuf_destroy(pb);
2258 return error;
2259 }
2260 error = vn_stat(nd.ni_vp, sb);
2261 vput(nd.ni_vp);
2262 pathbuf_destroy(pb);
2263 return error;
2264 }
2265
2266 /*
2267 * Get file status; this version follows links.
2268 */
2269 /* ARGSUSED */
2270 int
2271 sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval)
2272 {
2273 /* {
2274 syscallarg(const char *) path;
2275 syscallarg(struct stat *) ub;
2276 } */
2277 struct stat sb;
2278 int error;
2279
2280 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb);
2281 if (error)
2282 return error;
2283 return copyout(&sb, SCARG(uap, ub), sizeof(sb));
2284 }
2285
2286 /*
2287 * Get file status; this version does not follow links.
2288 */
2289 /* ARGSUSED */
2290 int
2291 sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval)
2292 {
2293 /* {
2294 syscallarg(const char *) path;
2295 syscallarg(struct stat *) ub;
2296 } */
2297 struct stat sb;
2298 int error;
2299
2300 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb);
2301 if (error)
2302 return error;
2303 return copyout(&sb, SCARG(uap, ub), sizeof(sb));
2304 }
2305
2306 /*
2307 * Get configurable pathname variables.
2308 */
2309 /* ARGSUSED */
2310 int
2311 sys_pathconf(struct lwp *l, const struct sys_pathconf_args *uap, register_t *retval)
2312 {
2313 /* {
2314 syscallarg(const char *) path;
2315 syscallarg(int) name;
2316 } */
2317 int error;
2318 struct pathbuf *pb;
2319 struct nameidata nd;
2320
2321 error = pathbuf_copyin(SCARG(uap, path), &pb);
2322 if (error) {
2323 return error;
2324 }
2325 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb);
2326 if ((error = namei(&nd)) != 0) {
2327 pathbuf_destroy(pb);
2328 return (error);
2329 }
2330 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
2331 vput(nd.ni_vp);
2332 pathbuf_destroy(pb);
2333 return (error);
2334 }
2335
2336 /*
2337 * Return target name of a symbolic link.
2338 */
2339 /* ARGSUSED */
2340 int
2341 sys_readlink(struct lwp *l, const struct sys_readlink_args *uap, register_t *retval)
2342 {
2343 /* {
2344 syscallarg(const char *) path;
2345 syscallarg(char *) buf;
2346 syscallarg(size_t) count;
2347 } */
2348 struct vnode *vp;
2349 struct iovec aiov;
2350 struct uio auio;
2351 int error;
2352 struct pathbuf *pb;
2353 struct nameidata nd;
2354
2355 error = pathbuf_copyin(SCARG(uap, path), &pb);
2356 if (error) {
2357 return error;
2358 }
2359 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | TRYEMULROOT, pb);
2360 if ((error = namei(&nd)) != 0) {
2361 pathbuf_destroy(pb);
2362 return error;
2363 }
2364 vp = nd.ni_vp;
2365 pathbuf_destroy(pb);
2366 if (vp->v_type != VLNK)
2367 error = EINVAL;
2368 else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
2369 (error = VOP_ACCESS(vp, VREAD, l->l_cred)) == 0) {
2370 aiov.iov_base = SCARG(uap, buf);
2371 aiov.iov_len = SCARG(uap, count);
2372 auio.uio_iov = &aiov;
2373 auio.uio_iovcnt = 1;
2374 auio.uio_offset = 0;
2375 auio.uio_rw = UIO_READ;
2376 KASSERT(l == curlwp);
2377 auio.uio_vmspace = l->l_proc->p_vmspace;
2378 auio.uio_resid = SCARG(uap, count);
2379 error = VOP_READLINK(vp, &auio, l->l_cred);
2380 }
2381 vput(vp);
2382 *retval = SCARG(uap, count) - auio.uio_resid;
2383 return (error);
2384 }
2385
2386 /*
2387 * Change flags of a file given a path name.
2388 */
2389 /* ARGSUSED */
2390 int
2391 sys_chflags(struct lwp *l, const struct sys_chflags_args *uap, register_t *retval)
2392 {
2393 /* {
2394 syscallarg(const char *) path;
2395 syscallarg(u_long) flags;
2396 } */
2397 struct vnode *vp;
2398 int error;
2399
2400 error = namei_simple_user(SCARG(uap, path),
2401 NSM_FOLLOW_TRYEMULROOT, &vp);
2402 if (error != 0)
2403 return (error);
2404 error = change_flags(vp, SCARG(uap, flags), l);
2405 vput(vp);
2406 return (error);
2407 }
2408
2409 /*
2410 * Change flags of a file given a file descriptor.
2411 */
2412 /* ARGSUSED */
2413 int
2414 sys_fchflags(struct lwp *l, const struct sys_fchflags_args *uap, register_t *retval)
2415 {
2416 /* {
2417 syscallarg(int) fd;
2418 syscallarg(u_long) flags;
2419 } */
2420 struct vnode *vp;
2421 file_t *fp;
2422 int error;
2423
2424 /* fd_getvnode() will use the descriptor for us */
2425 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2426 return (error);
2427 vp = fp->f_data;
2428 error = change_flags(vp, SCARG(uap, flags), l);
2429 VOP_UNLOCK(vp);
2430 fd_putfile(SCARG(uap, fd));
2431 return (error);
2432 }
2433
2434 /*
2435 * Change flags of a file given a path name; this version does
2436 * not follow links.
2437 */
2438 int
2439 sys_lchflags(struct lwp *l, const struct sys_lchflags_args *uap, register_t *retval)
2440 {
2441 /* {
2442 syscallarg(const char *) path;
2443 syscallarg(u_long) flags;
2444 } */
2445 struct vnode *vp;
2446 int error;
2447
2448 error = namei_simple_user(SCARG(uap, path),
2449 NSM_NOFOLLOW_TRYEMULROOT, &vp);
2450 if (error != 0)
2451 return (error);
2452 error = change_flags(vp, SCARG(uap, flags), l);
2453 vput(vp);
2454 return (error);
2455 }
2456
2457 /*
2458 * Common routine to change flags of a file.
2459 */
2460 int
2461 change_flags(struct vnode *vp, u_long flags, struct lwp *l)
2462 {
2463 struct vattr vattr;
2464 int error;
2465
2466 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2467 /*
2468 * Non-superusers cannot change the flags on devices, even if they
2469 * own them.
2470 */
2471 if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
2472 if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
2473 goto out;
2474 if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
2475 error = EINVAL;
2476 goto out;
2477 }
2478 }
2479 vattr_null(&vattr);
2480 vattr.va_flags = flags;
2481 error = VOP_SETATTR(vp, &vattr, l->l_cred);
2482 out:
2483 return (error);
2484 }
2485
2486 /*
2487 * Change mode of a file given path name; this version follows links.
2488 */
2489 /* ARGSUSED */
2490 int
2491 sys_chmod(struct lwp *l, const struct sys_chmod_args *uap, register_t *retval)
2492 {
2493 /* {
2494 syscallarg(const char *) path;
2495 syscallarg(int) mode;
2496 } */
2497 int error;
2498 struct vnode *vp;
2499
2500 error = namei_simple_user(SCARG(uap, path),
2501 NSM_FOLLOW_TRYEMULROOT, &vp);
2502 if (error != 0)
2503 return (error);
2504
2505 error = change_mode(vp, SCARG(uap, mode), l);
2506
2507 vrele(vp);
2508 return (error);
2509 }
2510
2511 /*
2512 * Change mode of a file given a file descriptor.
2513 */
2514 /* ARGSUSED */
2515 int
2516 sys_fchmod(struct lwp *l, const struct sys_fchmod_args *uap, register_t *retval)
2517 {
2518 /* {
2519 syscallarg(int) fd;
2520 syscallarg(int) mode;
2521 } */
2522 file_t *fp;
2523 int error;
2524
2525 /* fd_getvnode() will use the descriptor for us */
2526 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2527 return (error);
2528 error = change_mode(fp->f_data, SCARG(uap, mode), l);
2529 fd_putfile(SCARG(uap, fd));
2530 return (error);
2531 }
2532
2533 /*
2534 * Change mode of a file given path name; this version does not follow links.
2535 */
2536 /* ARGSUSED */
2537 int
2538 sys_lchmod(struct lwp *l, const struct sys_lchmod_args *uap, register_t *retval)
2539 {
2540 /* {
2541 syscallarg(const char *) path;
2542 syscallarg(int) mode;
2543 } */
2544 int error;
2545 struct vnode *vp;
2546
2547 error = namei_simple_user(SCARG(uap, path),
2548 NSM_NOFOLLOW_TRYEMULROOT, &vp);
2549 if (error != 0)
2550 return (error);
2551
2552 error = change_mode(vp, SCARG(uap, mode), l);
2553
2554 vrele(vp);
2555 return (error);
2556 }
2557
2558 /*
2559 * Common routine to set mode given a vnode.
2560 */
2561 static int
2562 change_mode(struct vnode *vp, int mode, struct lwp *l)
2563 {
2564 struct vattr vattr;
2565 int error;
2566
2567 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2568 vattr_null(&vattr);
2569 vattr.va_mode = mode & ALLPERMS;
2570 error = VOP_SETATTR(vp, &vattr, l->l_cred);
2571 VOP_UNLOCK(vp);
2572 return (error);
2573 }
2574
2575 /*
2576 * Set ownership given a path name; this version follows links.
2577 */
2578 /* ARGSUSED */
2579 int
2580 sys_chown(struct lwp *l, const struct sys_chown_args *uap, register_t *retval)
2581 {
2582 /* {
2583 syscallarg(const char *) path;
2584 syscallarg(uid_t) uid;
2585 syscallarg(gid_t) gid;
2586 } */
2587 int error;
2588 struct vnode *vp;
2589
2590 error = namei_simple_user(SCARG(uap, path),
2591 NSM_FOLLOW_TRYEMULROOT, &vp);
2592 if (error != 0)
2593 return (error);
2594
2595 error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
2596
2597 vrele(vp);
2598 return (error);
2599 }
2600
2601 /*
2602 * Set ownership given a path name; this version follows links.
2603 * Provides POSIX semantics.
2604 */
2605 /* ARGSUSED */
2606 int
2607 sys___posix_chown(struct lwp *l, const struct sys___posix_chown_args *uap, register_t *retval)
2608 {
2609 /* {
2610 syscallarg(const char *) path;
2611 syscallarg(uid_t) uid;
2612 syscallarg(gid_t) gid;
2613 } */
2614 int error;
2615 struct vnode *vp;
2616
2617 error = namei_simple_user(SCARG(uap, path),
2618 NSM_FOLLOW_TRYEMULROOT, &vp);
2619 if (error != 0)
2620 return (error);
2621
2622 error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
2623
2624 vrele(vp);
2625 return (error);
2626 }
2627
2628 /*
2629 * Set ownership given a file descriptor.
2630 */
2631 /* ARGSUSED */
2632 int
2633 sys_fchown(struct lwp *l, const struct sys_fchown_args *uap, register_t *retval)
2634 {
2635 /* {
2636 syscallarg(int) fd;
2637 syscallarg(uid_t) uid;
2638 syscallarg(gid_t) gid;
2639 } */
2640 int error;
2641 file_t *fp;
2642
2643 /* fd_getvnode() will use the descriptor for us */
2644 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2645 return (error);
2646 error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
2647 l, 0);
2648 fd_putfile(SCARG(uap, fd));
2649 return (error);
2650 }
2651
2652 /*
2653 * Set ownership given a file descriptor, providing POSIX/XPG semantics.
2654 */
2655 /* ARGSUSED */
2656 int
2657 sys___posix_fchown(struct lwp *l, const struct sys___posix_fchown_args *uap, register_t *retval)
2658 {
2659 /* {
2660 syscallarg(int) fd;
2661 syscallarg(uid_t) uid;
2662 syscallarg(gid_t) gid;
2663 } */
2664 int error;
2665 file_t *fp;
2666
2667 /* fd_getvnode() will use the descriptor for us */
2668 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2669 return (error);
2670 error = change_owner(fp->f_data, SCARG(uap, uid), SCARG(uap, gid),
2671 l, 1);
2672 fd_putfile(SCARG(uap, fd));
2673 return (error);
2674 }
2675
2676 /*
2677 * Set ownership given a path name; this version does not follow links.
2678 */
2679 /* ARGSUSED */
2680 int
2681 sys_lchown(struct lwp *l, const struct sys_lchown_args *uap, register_t *retval)
2682 {
2683 /* {
2684 syscallarg(const char *) path;
2685 syscallarg(uid_t) uid;
2686 syscallarg(gid_t) gid;
2687 } */
2688 int error;
2689 struct vnode *vp;
2690
2691 error = namei_simple_user(SCARG(uap, path),
2692 NSM_NOFOLLOW_TRYEMULROOT, &vp);
2693 if (error != 0)
2694 return (error);
2695
2696 error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
2697
2698 vrele(vp);
2699 return (error);
2700 }
2701
2702 /*
2703 * Set ownership given a path name; this version does not follow links.
2704 * Provides POSIX/XPG semantics.
2705 */
2706 /* ARGSUSED */
2707 int
2708 sys___posix_lchown(struct lwp *l, const struct sys___posix_lchown_args *uap, register_t *retval)
2709 {
2710 /* {
2711 syscallarg(const char *) path;
2712 syscallarg(uid_t) uid;
2713 syscallarg(gid_t) gid;
2714 } */
2715 int error;
2716 struct vnode *vp;
2717
2718 error = namei_simple_user(SCARG(uap, path),
2719 NSM_NOFOLLOW_TRYEMULROOT, &vp);
2720 if (error != 0)
2721 return (error);
2722
2723 error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
2724
2725 vrele(vp);
2726 return (error);
2727 }
2728
2729 /*
2730 * Common routine to set ownership given a vnode.
2731 */
2732 static int
2733 change_owner(struct vnode *vp, uid_t uid, gid_t gid, struct lwp *l,
2734 int posix_semantics)
2735 {
2736 struct vattr vattr;
2737 mode_t newmode;
2738 int error;
2739
2740 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2741 if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0)
2742 goto out;
2743
2744 #define CHANGED(x) ((int)(x) != -1)
2745 newmode = vattr.va_mode;
2746 if (posix_semantics) {
2747 /*
2748 * POSIX/XPG semantics: if the caller is not the super-user,
2749 * clear set-user-id and set-group-id bits. Both POSIX and
2750 * the XPG consider the behaviour for calls by the super-user
2751 * implementation-defined; we leave the set-user-id and set-
2752 * group-id settings intact in that case.
2753 */
2754 if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
2755 NULL) != 0)
2756 newmode &= ~(S_ISUID | S_ISGID);
2757 } else {
2758 /*
2759 * NetBSD semantics: when changing owner and/or group,
2760 * clear the respective bit(s).
2761 */
2762 if (CHANGED(uid))
2763 newmode &= ~S_ISUID;
2764 if (CHANGED(gid))
2765 newmode &= ~S_ISGID;
2766 }
2767 /* Update va_mode iff altered. */
2768 if (vattr.va_mode == newmode)
2769 newmode = VNOVAL;
2770
2771 vattr_null(&vattr);
2772 vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
2773 vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
2774 vattr.va_mode = newmode;
2775 error = VOP_SETATTR(vp, &vattr, l->l_cred);
2776 #undef CHANGED
2777
2778 out:
2779 VOP_UNLOCK(vp);
2780 return (error);
2781 }
2782
2783 /*
2784 * Set the access and modification times given a path name; this
2785 * version follows links.
2786 */
2787 /* ARGSUSED */
2788 int
2789 sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap,
2790 register_t *retval)
2791 {
2792 /* {
2793 syscallarg(const char *) path;
2794 syscallarg(const struct timeval *) tptr;
2795 } */
2796
2797 return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW,
2798 SCARG(uap, tptr), UIO_USERSPACE);
2799 }
2800
2801 /*
2802 * Set the access and modification times given a file descriptor.
2803 */
2804 /* ARGSUSED */
2805 int
2806 sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap,
2807 register_t *retval)
2808 {
2809 /* {
2810 syscallarg(int) fd;
2811 syscallarg(const struct timeval *) tptr;
2812 } */
2813 int error;
2814 file_t *fp;
2815
2816 /* fd_getvnode() will use the descriptor for us */
2817 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2818 return (error);
2819 error = do_sys_utimes(l, fp->f_data, NULL, 0, SCARG(uap, tptr),
2820 UIO_USERSPACE);
2821 fd_putfile(SCARG(uap, fd));
2822 return (error);
2823 }
2824
2825 /*
2826 * Set the access and modification times given a path name; this
2827 * version does not follow links.
2828 */
2829 int
2830 sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap,
2831 register_t *retval)
2832 {
2833 /* {
2834 syscallarg(const char *) path;
2835 syscallarg(const struct timeval *) tptr;
2836 } */
2837
2838 return do_sys_utimes(l, NULL, SCARG(uap, path), NOFOLLOW,
2839 SCARG(uap, tptr), UIO_USERSPACE);
2840 }
2841
2842 /*
2843 * Common routine to set access and modification times given a vnode.
2844 */
2845 int
2846 do_sys_utimes(struct lwp *l, struct vnode *vp, const char *path, int flag,
2847 const struct timeval *tptr, enum uio_seg seg)
2848 {
2849 struct vattr vattr;
2850 int error, dorele = 0;
2851 namei_simple_flags_t sflags;
2852
2853 bool vanull, setbirthtime;
2854 struct timespec ts[2];
2855
2856 /*
2857 * I have checked all callers and they pass either FOLLOW,
2858 * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW
2859 * is 0. More to the point, they don't pass anything else.
2860 * Let's keep it that way at least until the namei interfaces
2861 * are fully sanitized.
2862 */
2863 KASSERT(flag == NOFOLLOW || flag == FOLLOW);
2864 sflags = (flag == FOLLOW) ?
2865 NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT;
2866
2867 if (tptr == NULL) {
2868 vanull = true;
2869 nanotime(&ts[0]);
2870 ts[1] = ts[0];
2871 } else {
2872 struct timeval tv[2];
2873
2874 vanull = false;
2875 if (seg != UIO_SYSSPACE) {
2876 error = copyin(tptr, tv, sizeof (tv));
2877 if (error != 0)
2878 return error;
2879 tptr = tv;
2880 }
2881 TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]);
2882 TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]);
2883 }
2884
2885 if (vp == NULL) {
2886 /* note: SEG describes TPTR, not PATH; PATH is always user */
2887 error = namei_simple_user(path, sflags, &vp);
2888 if (error != 0)
2889 return error;
2890 dorele = 1;
2891 }
2892
2893 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2894 setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 &&
2895 timespeccmp(&ts[1], &vattr.va_birthtime, <));
2896 vattr_null(&vattr);
2897 vattr.va_atime = ts[0];
2898 vattr.va_mtime = ts[1];
2899 if (setbirthtime)
2900 vattr.va_birthtime = ts[1];
2901 if (vanull)
2902 vattr.va_vaflags |= VA_UTIMES_NULL;
2903 error = VOP_SETATTR(vp, &vattr, l->l_cred);
2904 VOP_UNLOCK(vp);
2905
2906 if (dorele != 0)
2907 vrele(vp);
2908
2909 return error;
2910 }
2911
2912 /*
2913 * Truncate a file given its path name.
2914 */
2915 /* ARGSUSED */
2916 int
2917 sys_truncate(struct lwp *l, const struct sys_truncate_args *uap, register_t *retval)
2918 {
2919 /* {
2920 syscallarg(const char *) path;
2921 syscallarg(int) pad;
2922 syscallarg(off_t) length;
2923 } */
2924 struct vnode *vp;
2925 struct vattr vattr;
2926 int error;
2927
2928 error = namei_simple_user(SCARG(uap, path),
2929 NSM_FOLLOW_TRYEMULROOT, &vp);
2930 if (error != 0)
2931 return (error);
2932 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2933 if (vp->v_type == VDIR)
2934 error = EISDIR;
2935 else if ((error = vn_writechk(vp)) == 0 &&
2936 (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {
2937 vattr_null(&vattr);
2938 vattr.va_size = SCARG(uap, length);
2939 error = VOP_SETATTR(vp, &vattr, l->l_cred);
2940 }
2941 vput(vp);
2942 return (error);
2943 }
2944
2945 /*
2946 * Truncate a file given a file descriptor.
2947 */
2948 /* ARGSUSED */
2949 int
2950 sys_ftruncate(struct lwp *l, const struct sys_ftruncate_args *uap, register_t *retval)
2951 {
2952 /* {
2953 syscallarg(int) fd;
2954 syscallarg(int) pad;
2955 syscallarg(off_t) length;
2956 } */
2957 struct vattr vattr;
2958 struct vnode *vp;
2959 file_t *fp;
2960 int error;
2961
2962 /* fd_getvnode() will use the descriptor for us */
2963 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
2964 return (error);
2965 if ((fp->f_flag & FWRITE) == 0) {
2966 error = EINVAL;
2967 goto out;
2968 }
2969 vp = fp->f_data;
2970 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2971 if (vp->v_type == VDIR)
2972 error = EISDIR;
2973 else if ((error = vn_writechk(vp)) == 0) {
2974 vattr_null(&vattr);
2975 vattr.va_size = SCARG(uap, length);
2976 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
2977 }
2978 VOP_UNLOCK(vp);
2979 out:
2980 fd_putfile(SCARG(uap, fd));
2981 return (error);
2982 }
2983
2984 /*
2985 * Sync an open file.
2986 */
2987 /* ARGSUSED */
2988 int
2989 sys_fsync(struct lwp *l, const struct sys_fsync_args *uap, register_t *retval)
2990 {
2991 /* {
2992 syscallarg(int) fd;
2993 } */
2994 struct vnode *vp;
2995 file_t *fp;
2996 int error;
2997
2998 /* fd_getvnode() will use the descriptor for us */
2999 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
3000 return (error);
3001 vp = fp->f_data;
3002 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3003 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);
3004 VOP_UNLOCK(vp);
3005 fd_putfile(SCARG(uap, fd));
3006 return (error);
3007 }
3008
3009 /*
3010 * Sync a range of file data. API modeled after that found in AIX.
3011 *
3012 * FDATASYNC indicates that we need only save enough metadata to be able
3013 * to re-read the written data. Note we duplicate AIX's requirement that
3014 * the file be open for writing.
3015 */
3016 /* ARGSUSED */
3017 int
3018 sys_fsync_range(struct lwp *l, const struct sys_fsync_range_args *uap, register_t *retval)
3019 {
3020 /* {
3021 syscallarg(int) fd;
3022 syscallarg(int) flags;
3023 syscallarg(off_t) start;
3024 syscallarg(off_t) length;
3025 } */
3026 struct vnode *vp;
3027 file_t *fp;
3028 int flags, nflags;
3029 off_t s, e, len;
3030 int error;
3031
3032 /* fd_getvnode() will use the descriptor for us */
3033 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
3034 return (error);
3035
3036 if ((fp->f_flag & FWRITE) == 0) {
3037 error = EBADF;
3038 goto out;
3039 }
3040
3041 flags = SCARG(uap, flags);
3042 if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
3043 ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
3044 error = EINVAL;
3045 goto out;
3046 }
3047 /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
3048 if (flags & FDATASYNC)
3049 nflags = FSYNC_DATAONLY | FSYNC_WAIT;
3050 else
3051 nflags = FSYNC_WAIT;
3052 if (flags & FDISKSYNC)
3053 nflags |= FSYNC_CACHE;
3054
3055 len = SCARG(uap, length);
3056 /* If length == 0, we do the whole file, and s = l = 0 will do that */
3057 if (len) {
3058 s = SCARG(uap, start);
3059 e = s + len;
3060 if (e < s) {
3061 error = EINVAL;
3062 goto out;
3063 }
3064 } else {
3065 e = 0;
3066 s = 0;
3067 }
3068
3069 vp = fp->f_data;
3070 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3071 error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);
3072 VOP_UNLOCK(vp);
3073 out:
3074 fd_putfile(SCARG(uap, fd));
3075 return (error);
3076 }
3077
3078 /*
3079 * Sync the data of an open file.
3080 */
3081 /* ARGSUSED */
3082 int
3083 sys_fdatasync(struct lwp *l, const struct sys_fdatasync_args *uap, register_t *retval)
3084 {
3085 /* {
3086 syscallarg(int) fd;
3087 } */
3088 struct vnode *vp;
3089 file_t *fp;
3090 int error;
3091
3092 /* fd_getvnode() will use the descriptor for us */
3093 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
3094 return (error);
3095 if ((fp->f_flag & FWRITE) == 0) {
3096 fd_putfile(SCARG(uap, fd));
3097 return (EBADF);
3098 }
3099 vp = fp->f_data;
3100 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3101 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);
3102 VOP_UNLOCK(vp);
3103 fd_putfile(SCARG(uap, fd));
3104 return (error);
3105 }
3106
3107 /*
3108 * Rename files, (standard) BSD semantics frontend.
3109 */
3110 /* ARGSUSED */
3111 int
3112 sys_rename(struct lwp *l, const struct sys_rename_args *uap, register_t *retval)
3113 {
3114 /* {
3115 syscallarg(const char *) from;
3116 syscallarg(const char *) to;
3117 } */
3118
3119 return (do_sys_rename(SCARG(uap, from), SCARG(uap, to), UIO_USERSPACE, 0));
3120 }
3121
3122 /*
3123 * Rename files, POSIX semantics frontend.
3124 */
3125 /* ARGSUSED */
3126 int
3127 sys___posix_rename(struct lwp *l, const struct sys___posix_rename_args *uap, register_t *retval)
3128 {
3129 /* {
3130 syscallarg(const char *) from;
3131 syscallarg(const char *) to;
3132 } */
3133
3134 return (do_sys_rename(SCARG(uap, from), SCARG(uap, to), UIO_USERSPACE, 1));
3135 }
3136
3137 /*
3138 * Rename files. Source and destination must either both be directories,
3139 * or both not be directories. If target is a directory, it must be empty.
3140 * If `from' and `to' refer to the same object, the value of the `retain'
3141 * argument is used to determine whether `from' will be
3142 *
3143 * (retain == 0) deleted unless `from' and `to' refer to the same
3144 * object in the file system's name space (BSD).
3145 * (retain == 1) always retained (POSIX).
3146 */
3147 int
3148 do_sys_rename(const char *from, const char *to, enum uio_seg seg, int retain)
3149 {
3150 struct vnode *tvp, *fvp, *tdvp;
3151 struct pathbuf *frompb, *topb;
3152 struct nameidata fromnd, tond;
3153 struct mount *fs;
3154 struct lwp *l = curlwp;
3155 struct proc *p;
3156 int error;
3157
3158 error = pathbuf_maybe_copyin(from, seg, &frompb);
3159 if (error) {
3160 return error;
3161 }
3162 error = pathbuf_maybe_copyin(to, seg, &topb);
3163 if (error) {
3164 pathbuf_destroy(frompb);
3165 return error;
3166 }
3167
3168 NDINIT(&fromnd, DELETE, LOCKPARENT | TRYEMULROOT | INRENAME,
3169 frompb);
3170 if ((error = namei(&fromnd)) != 0) {
3171 pathbuf_destroy(frompb);
3172 pathbuf_destroy(topb);
3173 return (error);
3174 }
3175 if (fromnd.ni_dvp != fromnd.ni_vp)
3176 VOP_UNLOCK(fromnd.ni_dvp);
3177 fvp = fromnd.ni_vp;
3178
3179 fs = fvp->v_mount;
3180 error = VFS_RENAMELOCK_ENTER(fs);
3181 if (error) {
3182 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3183 vrele(fromnd.ni_dvp);
3184 vrele(fvp);
3185 goto out1;
3186 }
3187
3188 /*
3189 * close, partially, yet another race - ideally we should only
3190 * go as far as getting fromnd.ni_dvp before getting the per-fs
3191 * lock, and then continue to get fromnd.ni_vp, but we can't do
3192 * that with namei as it stands.
3193 *
3194 * This still won't prevent rmdir from nuking fromnd.ni_vp
3195 * under us. The real fix is to get the locks in the right
3196 * order and do the lookups in the right places, but that's a
3197 * major rototill.
3198 *
3199 * Note: this logic (as well as this whole function) is cloned
3200 * in nfs_serv.c. Proceed accordingly.
3201 */
3202 vrele(fvp);
3203 if ((fromnd.ni_cnd.cn_namelen == 1 &&
3204 fromnd.ni_cnd.cn_nameptr[0] == '.') ||
3205 (fromnd.ni_cnd.cn_namelen == 2 &&
3206 fromnd.ni_cnd.cn_nameptr[0] == '.' &&
3207 fromnd.ni_cnd.cn_nameptr[1] == '.')) {
3208 error = EINVAL;
3209 VFS_RENAMELOCK_EXIT(fs);
3210 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3211 vrele(fromnd.ni_dvp);
3212 goto out1;
3213 }
3214 vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
3215 error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd, 0);
3216 if (error) {
3217 VOP_UNLOCK(fromnd.ni_dvp);
3218 VFS_RENAMELOCK_EXIT(fs);
3219 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3220 vrele(fromnd.ni_dvp);
3221 goto out1;
3222 }
3223 VOP_UNLOCK(fromnd.ni_vp);
3224 if (fromnd.ni_dvp != fromnd.ni_vp)
3225 VOP_UNLOCK(fromnd.ni_dvp);
3226 fvp = fromnd.ni_vp;
3227
3228 NDINIT(&tond, RENAME,
3229 LOCKPARENT | LOCKLEAF | NOCACHE | TRYEMULROOT
3230 | INRENAME | (fvp->v_type == VDIR ? CREATEDIR : 0),
3231 topb);
3232 if ((error = namei(&tond)) != 0) {
3233 VFS_RENAMELOCK_EXIT(fs);
3234 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3235 vrele(fromnd.ni_dvp);
3236 vrele(fvp);
3237 goto out1;
3238 }
3239 tdvp = tond.ni_dvp;
3240 tvp = tond.ni_vp;
3241
3242 if (tvp != NULL) {
3243 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3244 error = ENOTDIR;
3245 goto out;
3246 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3247 error = EISDIR;
3248 goto out;
3249 }
3250 }
3251
3252 if (fvp == tdvp)
3253 error = EINVAL;
3254
3255 /*
3256 * Source and destination refer to the same object.
3257 */
3258 if (fvp == tvp) {
3259 if (retain)
3260 error = -1;
3261 else if (fromnd.ni_dvp == tdvp &&
3262 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
3263 !memcmp(fromnd.ni_cnd.cn_nameptr,
3264 tond.ni_cnd.cn_nameptr,
3265 fromnd.ni_cnd.cn_namelen))
3266 error = -1;
3267 }
3268 /*
3269 * Prevent cross-mount operation.
3270 */
3271 if (error == 0) {
3272 if (tond.ni_dvp->v_mount != fromnd.ni_dvp->v_mount) {
3273 error = EXDEV;
3274 }
3275 }
3276 #if NVERIEXEC > 0
3277 if (!error) {
3278 char *f1, *f2;
3279 size_t f1_len;
3280 size_t f2_len;
3281
3282 f1_len = fromnd.ni_cnd.cn_namelen + 1;
3283 f1 = kmem_alloc(f1_len, KM_SLEEP);
3284 strlcpy(f1, fromnd.ni_cnd.cn_nameptr, f1_len);
3285
3286 f2_len = tond.ni_cnd.cn_namelen + 1;
3287 f2 = kmem_alloc(f2_len, KM_SLEEP);
3288 strlcpy(f2, tond.ni_cnd.cn_nameptr, f2_len);
3289
3290 error = veriexec_renamechk(l, fvp, f1, tvp, f2);
3291
3292 kmem_free(f1, f1_len);
3293 kmem_free(f2, f2_len);
3294 }
3295 #endif /* NVERIEXEC > 0 */
3296
3297 out:
3298 p = l->l_proc;
3299 if (!error) {
3300 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3301 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3302 VFS_RENAMELOCK_EXIT(fs);
3303 } else {
3304 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
3305 if (tdvp == tvp)
3306 vrele(tdvp);
3307 else
3308 vput(tdvp);
3309 if (tvp)
3310 vput(tvp);
3311 VFS_RENAMELOCK_EXIT(fs);
3312 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3313 vrele(fromnd.ni_dvp);
3314 vrele(fvp);
3315 }
3316 out1:
3317 pathbuf_destroy(frompb);
3318 pathbuf_destroy(topb);
3319 return (error == -1 ? 0 : error);
3320 }
3321
3322 /*
3323 * Make a directory file.
3324 */
3325 /* ARGSUSED */
3326 int
3327 sys_mkdir(struct lwp *l, const struct sys_mkdir_args *uap, register_t *retval)
3328 {
3329 /* {
3330 syscallarg(const char *) path;
3331 syscallarg(int) mode;
3332 } */
3333
3334 return do_sys_mkdir(SCARG(uap, path), SCARG(uap, mode), UIO_USERSPACE);
3335 }
3336
3337 int
3338 do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg)
3339 {
3340 struct proc *p = curlwp->l_proc;
3341 struct vnode *vp;
3342 struct vattr vattr;
3343 int error;
3344 struct pathbuf *pb;
3345 struct nameidata nd;
3346
3347 /* XXX bollocks, should pass in a pathbuf */
3348 error = pathbuf_maybe_copyin(path, seg, &pb);
3349 if (error) {
3350 return error;
3351 }
3352
3353 NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, pb);
3354 if ((error = namei(&nd)) != 0) {
3355 pathbuf_destroy(pb);
3356 return (error);
3357 }
3358 vp = nd.ni_vp;
3359 if (vp != NULL) {
3360 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3361 if (nd.ni_dvp == vp)
3362 vrele(nd.ni_dvp);
3363 else
3364 vput(nd.ni_dvp);
3365 vrele(vp);
3366 pathbuf_destroy(pb);
3367 return (EEXIST);
3368 }
3369 vattr_null(&vattr);
3370 vattr.va_type = VDIR;
3371 /* We will read cwdi->cwdi_cmask unlocked. */
3372 vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
3373 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3374 if (!error)
3375 vput(nd.ni_vp);
3376 pathbuf_destroy(pb);
3377 return (error);
3378 }
3379
3380 /*
3381 * Remove a directory file.
3382 */
3383 /* ARGSUSED */
3384 int
3385 sys_rmdir(struct lwp *l, const struct sys_rmdir_args *uap, register_t *retval)
3386 {
3387 /* {
3388 syscallarg(const char *) path;
3389 } */
3390 struct vnode *vp;
3391 int error;
3392 struct pathbuf *pb;
3393 struct nameidata nd;
3394
3395 error = pathbuf_copyin(SCARG(uap, path), &pb);
3396 if (error) {
3397 return error;
3398 }
3399 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, pb);
3400 if ((error = namei(&nd)) != 0) {
3401 pathbuf_destroy(pb);
3402 return error;
3403 }
3404 vp = nd.ni_vp;
3405 if (vp->v_type != VDIR) {
3406 error = ENOTDIR;
3407 goto out;
3408 }
3409 /*
3410 * No rmdir "." please.
3411 */
3412 if (nd.ni_dvp == vp) {
3413 error = EINVAL;
3414 goto out;
3415 }
3416 /*
3417 * The root of a mounted filesystem cannot be deleted.
3418 */
3419 if ((vp->v_vflag & VV_ROOT) != 0 || vp->v_mountedhere != NULL) {
3420 error = EBUSY;
3421 goto out;
3422 }
3423 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3424 pathbuf_destroy(pb);
3425 return (error);
3426
3427 out:
3428 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3429 if (nd.ni_dvp == vp)
3430 vrele(nd.ni_dvp);
3431 else
3432 vput(nd.ni_dvp);
3433 vput(vp);
3434 pathbuf_destroy(pb);
3435 return (error);
3436 }
3437
3438 /*
3439 * Read a block of directory entries in a file system independent format.
3440 */
3441 int
3442 sys___getdents30(struct lwp *l, const struct sys___getdents30_args *uap, register_t *retval)
3443 {
3444 /* {
3445 syscallarg(int) fd;
3446 syscallarg(char *) buf;
3447 syscallarg(size_t) count;
3448 } */
3449 file_t *fp;
3450 int error, done;
3451
3452 /* fd_getvnode() will use the descriptor for us */
3453 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
3454 return (error);
3455 if ((fp->f_flag & FREAD) == 0) {
3456 error = EBADF;
3457 goto out;
3458 }
3459 error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
3460 SCARG(uap, count), &done, l, 0, 0);
3461 ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, buf), done, error);
3462 *retval = done;
3463 out:
3464 fd_putfile(SCARG(uap, fd));
3465 return (error);
3466 }
3467
3468 /*
3469 * Set the mode mask for creation of filesystem nodes.
3470 */
3471 int
3472 sys_umask(struct lwp *l, const struct sys_umask_args *uap, register_t *retval)
3473 {
3474 /* {
3475 syscallarg(mode_t) newmask;
3476 } */
3477 struct proc *p = l->l_proc;
3478 struct cwdinfo *cwdi;
3479
3480 /*
3481 * cwdi->cwdi_cmask will be read unlocked elsewhere. What's
3482 * important is that we serialize changes to the mask. The
3483 * rw_exit() will issue a write memory barrier on our behalf,
3484 * and force the changes out to other CPUs (as it must use an
3485 * atomic operation, draining the local CPU's store buffers).
3486 */
3487 cwdi = p->p_cwdi;
3488 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
3489 *retval = cwdi->cwdi_cmask;
3490 cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
3491 rw_exit(&cwdi->cwdi_lock);
3492
3493 return (0);
3494 }
3495
3496 int
3497 dorevoke(struct vnode *vp, kauth_cred_t cred)
3498 {
3499 struct vattr vattr;
3500 int error;
3501
3502 if ((error = VOP_GETATTR(vp, &vattr, cred)) != 0)
3503 return error;
3504 if (kauth_cred_geteuid(cred) == vattr.va_uid ||
3505 (error = kauth_authorize_generic(cred,
3506 KAUTH_GENERIC_ISSUSER, NULL)) == 0)
3507 VOP_REVOKE(vp, REVOKEALL);
3508 return (error);
3509 }
3510
3511 /*
3512 * Void all references to file by ripping underlying filesystem
3513 * away from vnode.
3514 */
3515 /* ARGSUSED */
3516 int
3517 sys_revoke(struct lwp *l, const struct sys_revoke_args *uap, register_t *retval)
3518 {
3519 /* {
3520 syscallarg(const char *) path;
3521 } */
3522 struct vnode *vp;
3523 int error;
3524
3525 error = namei_simple_user(SCARG(uap, path),
3526 NSM_FOLLOW_TRYEMULROOT, &vp);
3527 if (error != 0)
3528 return (error);
3529 error = dorevoke(vp, l->l_cred);
3530 vrele(vp);
3531 return (error);
3532 }
3533