vfs_syscalls.c revision 1.190.2.8 1 /* $NetBSD: vfs_syscalls.c,v 1.190.2.8 2005/01/17 19:32:26 skrll 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. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.190.2.8 2005/01/17 19:32:26 skrll Exp $");
41
42 #include "opt_compat_netbsd.h"
43 #include "opt_compat_43.h"
44 #include "opt_ktrace.h"
45 #include "fss.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/namei.h>
50 #include <sys/filedesc.h>
51 #include <sys/kernel.h>
52 #include <sys/file.h>
53 #include <sys/stat.h>
54 #include <sys/vnode.h>
55 #include <sys/mount.h>
56 #include <sys/proc.h>
57 #include <sys/uio.h>
58 #include <sys/malloc.h>
59 #include <sys/dirent.h>
60 #include <sys/extattr.h>
61 #include <sys/sysctl.h>
62 #include <sys/sa.h>
63 #include <sys/syscallargs.h>
64 #ifdef KTRACE
65 #include <sys/ktrace.h>
66 #endif
67
68 #include <miscfs/genfs/genfs.h>
69 #include <miscfs/syncfs/syncfs.h>
70
71 #if NFSS > 0
72 #include <dev/fssvar.h>
73 #endif
74
75 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
76
77 static int change_dir(struct nameidata *, struct lwp *);
78 static int change_flags(struct vnode *, u_long, struct lwp *);
79 static int change_mode(struct vnode *, int, struct lwp *l);
80 static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
81 static int change_utimes(struct vnode *vp, const struct timeval *,
82 struct lwp *l);
83 static int rename_files(const char *, const char *, struct lwp *, int);
84
85 void checkdirs(struct vnode *);
86
87 int dovfsusermount = 0;
88
89 /*
90 * Virtual File System System Calls
91 */
92
93 /*
94 * Mount a file system.
95 */
96
97 #if defined(COMPAT_09) || defined(COMPAT_43)
98 /*
99 * This table is used to maintain compatibility with 4.3BSD
100 * and NetBSD 0.9 mount syscalls. Note, the order is important!
101 *
102 * Do not modify this table. It should only contain filesystems
103 * supported by NetBSD 0.9 and 4.3BSD.
104 */
105 const char * const mountcompatnames[] = {
106 NULL, /* 0 = MOUNT_NONE */
107 MOUNT_FFS, /* 1 = MOUNT_UFS */
108 MOUNT_NFS, /* 2 */
109 MOUNT_MFS, /* 3 */
110 MOUNT_MSDOS, /* 4 */
111 MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
112 MOUNT_FDESC, /* 6 */
113 MOUNT_KERNFS, /* 7 */
114 NULL, /* 8 = MOUNT_DEVFS */
115 MOUNT_AFS, /* 9 */
116 };
117 const int nmountcompatnames = sizeof(mountcompatnames) /
118 sizeof(mountcompatnames[0]);
119 #endif /* COMPAT_09 || COMPAT_43 */
120
121 /* ARGSUSED */
122 int
123 sys_mount(l, v, retval)
124 struct lwp *l;
125 void *v;
126 register_t *retval;
127 {
128 struct sys_mount_args /* {
129 syscallarg(const char *) type;
130 syscallarg(const char *) path;
131 syscallarg(int) flags;
132 syscallarg(void *) data;
133 } */ *uap = v;
134 struct proc *p = l->l_proc;
135 struct vnode *vp;
136 struct mount *mp;
137 int error, flag = 0;
138 char fstypename[MFSNAMELEN];
139 struct vattr va;
140 struct nameidata nd;
141 struct vfsops *vfs;
142
143 if (dovfsusermount == 0 && (SCARG(uap, flags) & MNT_GETARGS) == 0 &&
144 (error = suser(p->p_ucred, &p->p_acflag)))
145 return (error);
146 /*
147 * Get vnode to be covered
148 */
149 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
150 SCARG(uap, path), l);
151 if ((error = namei(&nd)) != 0)
152 return (error);
153 vp = nd.ni_vp;
154 /*
155 * A lookup in VFS_MOUNT might result in an attempt to
156 * lock this vnode again, so make the lock recursive.
157 */
158 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_SETRECURSE);
159 if (SCARG(uap, flags) & (MNT_UPDATE | MNT_GETARGS)) {
160 if ((vp->v_flag & VROOT) == 0) {
161 vput(vp);
162 return (EINVAL);
163 }
164 mp = vp->v_mount;
165 flag = mp->mnt_flag;
166 vfs = mp->mnt_op;
167 /*
168 * We only allow the filesystem to be reloaded if it
169 * is currently mounted read-only.
170 */
171 if ((SCARG(uap, flags) & MNT_RELOAD) &&
172 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
173 vput(vp);
174 return (EOPNOTSUPP); /* Needs translation */
175 }
176 /*
177 * In "highly secure" mode, don't let the caller do anything
178 * but downgrade a filesystem from read-write to read-only.
179 * (see also below; MNT_UPDATE or MNT_GETARGS is required.)
180 */
181 if (securelevel >= 2 &&
182 SCARG(uap, flags) != MNT_GETARGS &&
183 SCARG(uap, flags) !=
184 (mp->mnt_flag | MNT_RDONLY |
185 MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) {
186 vput(vp);
187 return (EPERM);
188 }
189 mp->mnt_flag |= SCARG(uap, flags) &
190 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
191 /*
192 * Only root, or the user that did the original mount is
193 * permitted to update it.
194 */
195 if ((mp->mnt_flag & MNT_GETARGS) == 0 &&
196 mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
197 (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
198 vput(vp);
199 return (error);
200 }
201 /*
202 * Do not allow NFS export by non-root users. For non-root
203 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
204 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
205 */
206 if (p->p_ucred->cr_uid != 0) {
207 if (SCARG(uap, flags) & MNT_EXPORTED) {
208 vput(vp);
209 return (EPERM);
210 }
211 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
212 if (flag & MNT_NOEXEC)
213 SCARG(uap, flags) |= MNT_NOEXEC;
214 }
215 if (vfs_busy(mp, LK_NOWAIT, 0)) {
216 vput(vp);
217 return (EPERM);
218 }
219 goto update;
220 } else {
221 if (securelevel >= 2) {
222 vput(vp);
223 return (EPERM);
224 }
225 }
226 /*
227 * If the user is not root, ensure that they own the directory
228 * onto which we are attempting to mount.
229 */
230 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, l)) != 0 ||
231 (va.va_uid != p->p_ucred->cr_uid &&
232 (error = suser(p->p_ucred, &p->p_acflag)) != 0)) {
233 vput(vp);
234 return (error);
235 }
236 /*
237 * Do not allow NFS export by non-root users. For non-root users,
238 * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
239 * mount point is already MNT_NOEXEC.
240 */
241 if (p->p_ucred->cr_uid != 0) {
242 if (SCARG(uap, flags) & MNT_EXPORTED) {
243 vput(vp);
244 return (EPERM);
245 }
246 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
247 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
248 SCARG(uap, flags) |= MNT_NOEXEC;
249 }
250 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, l, 0, 0)) != 0) {
251 vput(vp);
252 return (error);
253 }
254 if (vp->v_type != VDIR) {
255 vput(vp);
256 return (ENOTDIR);
257 }
258 error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
259 if (error) {
260 #if defined(COMPAT_09) || defined(COMPAT_43)
261 /*
262 * Historically filesystem types were identified by number.
263 * If we get an integer for the filesystem type instead of a
264 * string, we check to see if it matches one of the historic
265 * filesystem types.
266 */
267 u_long fsindex = (u_long)SCARG(uap, type);
268 if (fsindex >= nmountcompatnames ||
269 mountcompatnames[fsindex] == NULL) {
270 vput(vp);
271 return (ENODEV);
272 }
273 strncpy(fstypename, mountcompatnames[fsindex], MFSNAMELEN);
274 #else
275 vput(vp);
276 return (error);
277 #endif
278 }
279 #ifdef COMPAT_10
280 /* Accept `ufs' as an alias for `ffs'. */
281 if (!strncmp(fstypename, "ufs", MFSNAMELEN))
282 strncpy(fstypename, "ffs", MFSNAMELEN);
283 #endif
284 if ((vfs = vfs_getopsbyname(fstypename)) == NULL) {
285 vput(vp);
286 return (ENODEV);
287 }
288 if (vp->v_mountedhere != NULL) {
289 vput(vp);
290 return (EBUSY);
291 }
292
293 /*
294 * Allocate and initialize the file system.
295 */
296 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
297 M_MOUNT, M_WAITOK);
298 memset((char *)mp, 0, (u_long)sizeof(struct mount));
299 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
300 simple_lock_init(&mp->mnt_slock);
301 (void)vfs_busy(mp, LK_NOWAIT, 0);
302 mp->mnt_op = vfs;
303 vfs->vfs_refcount++;
304 mp->mnt_vnodecovered = vp;
305 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
306 mp->mnt_unmounter = NULL;
307 mp->mnt_leaf = mp;
308
309 /*
310 * The underlying file system may refuse the mount for
311 * various reasons. Allow the user to force it to happen.
312 */
313 mp->mnt_flag |= SCARG(uap, flags) & MNT_FORCE;
314 update:
315 /*
316 * Set the mount level flags.
317 */
318 if (SCARG(uap, flags) & MNT_RDONLY)
319 mp->mnt_flag |= MNT_RDONLY;
320 else if (mp->mnt_flag & MNT_RDONLY)
321 mp->mnt_iflag |= IMNT_WANTRDWR;
322 mp->mnt_flag &=
323 ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
324 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
325 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP);
326 mp->mnt_flag |= SCARG(uap, flags) &
327 (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
328 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
329 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
330 MNT_IGNORE);
331 /*
332 * Mount the filesystem.
333 */
334 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, l);
335 if (mp->mnt_flag & (MNT_UPDATE | MNT_GETARGS)) {
336 if (mp->mnt_iflag & IMNT_WANTRDWR)
337 mp->mnt_flag &= ~MNT_RDONLY;
338 if (error || (mp->mnt_flag & MNT_GETARGS))
339 mp->mnt_flag = flag;
340 mp->mnt_flag &=~
341 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
342 mp->mnt_iflag &=~ IMNT_WANTRDWR;
343 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
344 if (mp->mnt_syncer == NULL)
345 error = vfs_allocate_syncvnode(mp);
346 } else {
347 if (mp->mnt_syncer != NULL)
348 vfs_deallocate_syncvnode(mp);
349 }
350 vfs_unbusy(mp);
351 VOP_UNLOCK(vp, 0);
352 vrele(vp);
353 return (error);
354 }
355 /*
356 * Put the new filesystem on the mount list after root.
357 */
358 cache_purge(vp);
359 if (!error) {
360 mp->mnt_flag &=~
361 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
362 mp->mnt_iflag &=~ IMNT_WANTRDWR;
363 vp->v_mountedhere = mp;
364 simple_lock(&mountlist_slock);
365 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
366 simple_unlock(&mountlist_slock);
367 checkdirs(vp);
368 VOP_UNLOCK(vp, 0);
369 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
370 error = vfs_allocate_syncvnode(mp);
371 vfs_unbusy(mp);
372 (void) VFS_STATVFS(mp, &mp->mnt_stat, l);
373 if ((error = VFS_START(mp, 0, l)))
374 vrele(vp);
375 } else {
376 vp->v_mountedhere = (struct mount *)0;
377 vfs->vfs_refcount--;
378 vfs_unbusy(mp);
379 free(mp, M_MOUNT);
380 vput(vp);
381 }
382 return (error);
383 }
384
385 /*
386 * Scan all active processes to see if any of them have a current
387 * or root directory onto which the new filesystem has just been
388 * mounted. If so, replace them with the new mount point.
389 */
390 void
391 checkdirs(olddp)
392 struct vnode *olddp;
393 {
394 struct cwdinfo *cwdi;
395 struct vnode *newdp;
396 struct proc *p;
397
398 if (olddp->v_usecount == 1)
399 return;
400 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
401 panic("mount: lost mount");
402 proclist_lock_read();
403 PROCLIST_FOREACH(p, &allproc) {
404 cwdi = p->p_cwdi;
405 if (cwdi->cwdi_cdir == olddp) {
406 vrele(cwdi->cwdi_cdir);
407 VREF(newdp);
408 cwdi->cwdi_cdir = newdp;
409 }
410 if (cwdi->cwdi_rdir == olddp) {
411 vrele(cwdi->cwdi_rdir);
412 VREF(newdp);
413 cwdi->cwdi_rdir = newdp;
414 }
415 }
416 proclist_unlock_read();
417 if (rootvnode == olddp) {
418 vrele(rootvnode);
419 VREF(newdp);
420 rootvnode = newdp;
421 }
422 vput(newdp);
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(l, v, retval)
434 struct lwp *l;
435 void *v;
436 register_t *retval;
437 {
438 struct sys_unmount_args /* {
439 syscallarg(const char *) path;
440 syscallarg(int) flags;
441 } */ *uap = v;
442 struct proc *p = l->l_proc;
443 struct vnode *vp;
444 struct mount *mp;
445 int error;
446 struct nameidata nd;
447
448 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
449 SCARG(uap, path), l);
450 if ((error = namei(&nd)) != 0)
451 return (error);
452 vp = nd.ni_vp;
453 mp = vp->v_mount;
454
455 /*
456 * Only root, or the user that did the original mount is
457 * permitted to unmount this filesystem.
458 */
459 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
460 (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
461 vput(vp);
462 return (error);
463 }
464
465 /*
466 * Don't allow unmounting the root file system.
467 */
468 if (mp->mnt_flag & MNT_ROOTFS) {
469 vput(vp);
470 return (EINVAL);
471 }
472
473 /*
474 * Must be the root of the filesystem
475 */
476 if ((vp->v_flag & VROOT) == 0) {
477 vput(vp);
478 return (EINVAL);
479 }
480 vput(vp);
481
482 /*
483 * XXX Freeze syncer. Must do this before locking the
484 * mount point. See dounmount() for details.
485 */
486 lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
487
488 if (vfs_busy(mp, 0, 0)) {
489 lockmgr(&syncer_lock, LK_RELEASE, NULL);
490 return (EBUSY);
491 }
492
493 return (dounmount(mp, SCARG(uap, flags), l));
494 }
495
496 /*
497 * Do the actual file system unmount. File system is assumed to have been
498 * marked busy by the caller.
499 */
500 int
501 dounmount(mp, flags, l)
502 struct mount *mp;
503 int flags;
504 struct lwp *l;
505 {
506 struct vnode *coveredvp;
507 int error;
508 int async;
509 int used_syncer;
510
511 simple_lock(&mountlist_slock);
512 vfs_unbusy(mp);
513 used_syncer = (mp->mnt_syncer != NULL);
514
515 /*
516 * XXX Syncer must be frozen when we get here. This should really
517 * be done on a per-mountpoint basis, but especially the softdep
518 * code possibly called from the syncer doens't exactly work on a
519 * per-mountpoint basis, so the softdep code would become a maze
520 * of vfs_busy() calls.
521 *
522 * The caller of dounmount() must acquire syncer_lock because
523 * the syncer itself acquires locks in syncer_lock -> vfs_busy
524 * order, and we must preserve that order to avoid deadlock.
525 *
526 * So, if the file system did not use the syncer, now is
527 * the time to release the syncer_lock.
528 */
529 if (used_syncer == 0)
530 lockmgr(&syncer_lock, LK_RELEASE, NULL);
531
532 mp->mnt_iflag |= IMNT_UNMOUNT;
533 mp->mnt_unmounter = l;
534 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock);
535 vn_start_write(NULL, &mp, V_WAIT);
536
537 if (mp->mnt_flag & MNT_EXPUBLIC)
538 vfs_setpublicfs(NULL, NULL, NULL);
539 async = mp->mnt_flag & MNT_ASYNC;
540 mp->mnt_flag &= ~MNT_ASYNC;
541 cache_purgevfs(mp); /* remove cache entries for this file sys */
542 if (mp->mnt_syncer != NULL)
543 vfs_deallocate_syncvnode(mp);
544 error = 0;
545 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
546 #if NFSS > 0
547 error = fss_umount_hook(mp, (flags & MNT_FORCE));
548 #endif
549 if (error == 0)
550 error = VFS_SYNC(mp, MNT_WAIT, l->l_proc->p_ucred, l);
551 }
552 if (error == 0 || (flags & MNT_FORCE))
553 error = VFS_UNMOUNT(mp, flags, l);
554 vn_finished_write(mp, 0);
555 simple_lock(&mountlist_slock);
556 if (error) {
557 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
558 (void) vfs_allocate_syncvnode(mp);
559 mp->mnt_iflag &= ~IMNT_UNMOUNT;
560 mp->mnt_unmounter = NULL;
561 mp->mnt_flag |= async;
562 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
563 &mountlist_slock);
564 if (used_syncer)
565 lockmgr(&syncer_lock, LK_RELEASE, NULL);
566 simple_lock(&mp->mnt_slock);
567 while (mp->mnt_wcnt > 0) {
568 wakeup(mp);
569 ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt1",
570 0, &mp->mnt_slock);
571 }
572 simple_unlock(&mp->mnt_slock);
573 return (error);
574 }
575 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
576 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
577 coveredvp->v_mountedhere = NULL;
578 vrele(coveredvp);
579 }
580 mp->mnt_op->vfs_refcount--;
581 if (LIST_FIRST(&mp->mnt_vnodelist) != NULL)
582 panic("unmount: dangling vnode");
583 mp->mnt_iflag |= IMNT_GONE;
584 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
585 if (used_syncer)
586 lockmgr(&syncer_lock, LK_RELEASE, NULL);
587 simple_lock(&mp->mnt_slock);
588 while (mp->mnt_wcnt > 0) {
589 wakeup(mp);
590 ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt2", 0, &mp->mnt_slock);
591 }
592 simple_unlock(&mp->mnt_slock);
593 free(mp, M_MOUNT);
594 return (0);
595 }
596
597 /*
598 * Sync each mounted filesystem.
599 */
600 #ifdef DEBUG
601 int syncprt = 0;
602 struct ctldebug debug0 = { "syncprt", &syncprt };
603 #endif
604
605 /* ARGSUSED */
606 int
607 sys_sync(l, v, retval)
608 struct lwp *l;
609 void *v;
610 register_t *retval;
611 {
612 struct mount *mp, *nmp;
613 int asyncflag;
614 struct proc *p = l == NULL ? &proc0 : l->l_proc;
615
616 simple_lock(&mountlist_slock);
617 for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
618 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
619 nmp = mp->mnt_list.cqe_prev;
620 continue;
621 }
622 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
623 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
624 asyncflag = mp->mnt_flag & MNT_ASYNC;
625 mp->mnt_flag &= ~MNT_ASYNC;
626 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, l);
627 if (asyncflag)
628 mp->mnt_flag |= MNT_ASYNC;
629 vn_finished_write(mp, 0);
630 }
631 simple_lock(&mountlist_slock);
632 nmp = mp->mnt_list.cqe_prev;
633 vfs_unbusy(mp);
634
635 }
636 simple_unlock(&mountlist_slock);
637 #ifdef DEBUG
638 if (syncprt)
639 vfs_bufstats();
640 #endif /* DEBUG */
641 return (0);
642 }
643
644 /*
645 * Change filesystem quotas.
646 */
647 /* ARGSUSED */
648 int
649 sys_quotactl(l, v, retval)
650 struct lwp *l;
651 void *v;
652 register_t *retval;
653 {
654 struct sys_quotactl_args /* {
655 syscallarg(const char *) path;
656 syscallarg(int) cmd;
657 syscallarg(int) uid;
658 syscallarg(caddr_t) arg;
659 } */ *uap = v;
660 struct mount *mp;
661 int error;
662 struct nameidata nd;
663
664 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
665 if ((error = namei(&nd)) != 0)
666 return (error);
667 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
668 vrele(nd.ni_vp);
669 if (error)
670 return (error);
671 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
672 SCARG(uap, arg), l);
673 vn_finished_write(mp, 0);
674 return (error);
675 }
676
677 int
678 dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
679 int root)
680 {
681 struct cwdinfo *cwdi = l->l_proc->p_cwdi;
682 int error = 0;
683
684 /*
685 * If MNT_NOWAIT or MNT_LAZY is specified, do not
686 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
687 * overrides MNT_NOWAIT.
688 */
689 if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
690 (flags != MNT_WAIT && flags != 0)) {
691 memcpy(sp, &mp->mnt_stat, sizeof(*sp));
692 goto done;
693 }
694
695 /* Get the filesystem stats now */
696 memset(sp, 0, sizeof(*sp));
697 if ((error = VFS_STATVFS(mp, sp, l)) != 0) {
698 return error;
699 }
700
701 if (cwdi->cwdi_rdir == NULL)
702 (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
703 done:
704 if (cwdi->cwdi_rdir != NULL) {
705 size_t len;
706 char *bp;
707 char *path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
708 if (!path)
709 return ENOMEM;
710
711 bp = path + MAXPATHLEN;
712 *--bp = '\0';
713 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
714 MAXPATHLEN / 2, 0, l);
715 if (error) {
716 free(path, M_TEMP);
717 return error;
718 }
719 len = strlen(bp);
720 /*
721 * for mount points that are below our root, we can see
722 * them, so we fix up the pathname and return them. The
723 * rest we cannot see, so we don't allow viewing the
724 * data.
725 */
726 if (strncmp(bp, sp->f_mntonname, len) == 0) {
727 strlcpy(sp->f_mntonname, &sp->f_mntonname[len],
728 sizeof(sp->f_mntonname));
729 if (sp->f_mntonname[0] == '\0')
730 (void)strlcpy(sp->f_mntonname, "/",
731 sizeof(sp->f_mntonname));
732 } else {
733 if (root)
734 (void)strlcpy(sp->f_mntonname, "/",
735 sizeof(sp->f_mntonname));
736 else
737 error = EPERM;
738 }
739 free(path, M_TEMP);
740 }
741 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
742 return error;
743 }
744
745 /*
746 * Get filesystem statistics.
747 */
748 /* ARGSUSED */
749 int
750 sys_statvfs1(l, v, retval)
751 struct lwp *l;
752 void *v;
753 register_t *retval;
754 {
755 struct sys_statvfs1_args /* {
756 syscallarg(const char *) path;
757 syscallarg(struct statvfs *) buf;
758 syscallarg(int) flags;
759 } */ *uap = v;
760 struct mount *mp;
761 struct statvfs sbuf;
762 int error;
763 struct nameidata nd;
764
765 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
766 if ((error = namei(&nd)) != 0)
767 return error;
768 mp = nd.ni_vp->v_mount;
769 vrele(nd.ni_vp);
770 if ((error = dostatvfs(mp, &sbuf, l, SCARG(uap, flags), 1)) != 0)
771 return error;
772 return copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
773 }
774
775 /*
776 * Get filesystem statistics.
777 */
778 /* ARGSUSED */
779 int
780 sys_fstatvfs1(l, v, retval)
781 struct lwp *l;
782 void *v;
783 register_t *retval;
784 {
785 struct sys_fstatvfs1_args /* {
786 syscallarg(int) fd;
787 syscallarg(struct statvfs *) buf;
788 syscallarg(int) flags;
789 } */ *uap = v;
790 struct proc *p = l->l_proc;
791 struct file *fp;
792 struct mount *mp;
793 struct statvfs sbuf;
794 int error;
795
796 /* getvnode() will use the descriptor for us */
797 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
798 return (error);
799 mp = ((struct vnode *)fp->f_data)->v_mount;
800 if ((error = dostatvfs(mp, &sbuf, l, SCARG(uap, flags), 1)) != 0)
801 goto out;
802 error = copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
803 out:
804 FILE_UNUSE(fp, l);
805 return error;
806 }
807
808
809 /*
810 * Get statistics on all filesystems.
811 */
812 int
813 sys_getvfsstat(l, v, retval)
814 struct lwp *l;
815 void *v;
816 register_t *retval;
817 {
818 struct sys_getvfsstat_args /* {
819 syscallarg(struct statvfs *) buf;
820 syscallarg(size_t) bufsize;
821 syscallarg(int) flags;
822 } */ *uap = v;
823 int root = 0;
824 struct proc *p = l->l_proc;
825 struct mount *mp, *nmp;
826 struct statvfs sbuf;
827 struct statvfs *sfsp;
828 size_t count, maxcount;
829 int error = 0;
830
831 maxcount = SCARG(uap, bufsize) / sizeof(struct statvfs);
832 sfsp = SCARG(uap, buf);
833 simple_lock(&mountlist_slock);
834 count = 0;
835 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
836 mp = nmp) {
837 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
838 nmp = CIRCLEQ_NEXT(mp, mnt_list);
839 continue;
840 }
841 if (sfsp && count < maxcount) {
842 error = dostatvfs(mp, &sbuf, l, SCARG(uap, flags), 0);
843 if (error) {
844 simple_lock(&mountlist_slock);
845 nmp = CIRCLEQ_NEXT(mp, mnt_list);
846 vfs_unbusy(mp);
847 continue;
848 }
849 error = copyout(&sbuf, sfsp, sizeof(*sfsp));
850 if (error) {
851 vfs_unbusy(mp);
852 return (error);
853 }
854 sfsp++;
855 root |= strcmp(sbuf.f_mntonname, "/") == 0;
856 }
857 count++;
858 simple_lock(&mountlist_slock);
859 nmp = CIRCLEQ_NEXT(mp, mnt_list);
860 vfs_unbusy(mp);
861 }
862 simple_unlock(&mountlist_slock);
863 if (root == 0 && p->p_cwdi->cwdi_rdir) {
864 /*
865 * fake a root entry
866 */
867 if ((error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, &sbuf, l,
868 SCARG(uap, flags), 1)) != 0)
869 return error;
870 if (sfsp)
871 error = copyout(&sbuf, sfsp, sizeof(*sfsp));
872 count++;
873 }
874 if (sfsp && count > maxcount)
875 *retval = maxcount;
876 else
877 *retval = count;
878 return error;
879 }
880
881 /*
882 * Change current working directory to a given file descriptor.
883 */
884 /* ARGSUSED */
885 int
886 sys_fchdir(l, v, retval)
887 struct lwp *l;
888 void *v;
889 register_t *retval;
890 {
891 struct sys_fchdir_args /* {
892 syscallarg(int) fd;
893 } */ *uap = v;
894 struct proc *p = l->l_proc;
895 struct filedesc *fdp = p->p_fd;
896 struct cwdinfo *cwdi = p->p_cwdi;
897 struct vnode *vp, *tdp;
898 struct mount *mp;
899 struct file *fp;
900 int error;
901
902 /* getvnode() will use the descriptor for us */
903 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
904 return (error);
905 vp = (struct vnode *)fp->f_data;
906
907 VREF(vp);
908 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
909 if (vp->v_type != VDIR)
910 error = ENOTDIR;
911 else
912 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, l);
913 while (!error && (mp = vp->v_mountedhere) != NULL) {
914 if (vfs_busy(mp, 0, 0))
915 continue;
916 error = VFS_ROOT(mp, &tdp);
917 vfs_unbusy(mp);
918 if (error)
919 break;
920 vput(vp);
921 vp = tdp;
922 }
923 if (error) {
924 vput(vp);
925 goto out;
926 }
927 VOP_UNLOCK(vp, 0);
928
929 /*
930 * Disallow changing to a directory not under the process's
931 * current root directory (if there is one).
932 */
933 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
934 vrele(vp);
935 error = EPERM; /* operation not permitted */
936 goto out;
937 }
938
939 vrele(cwdi->cwdi_cdir);
940 cwdi->cwdi_cdir = vp;
941 out:
942 FILE_UNUSE(fp, l);
943 return (error);
944 }
945
946 /*
947 * Change this process's notion of the root directory to a given file descriptor.
948 */
949
950 int
951 sys_fchroot(l, v, retval)
952 struct lwp *l;
953 void *v;
954 register_t *retval;
955 {
956 struct sys_fchroot_args *uap = v;
957 struct proc *p = l->l_proc;
958 struct filedesc *fdp = p->p_fd;
959 struct cwdinfo *cwdi = p->p_cwdi;
960 struct vnode *vp;
961 struct file *fp;
962 int error;
963
964 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
965 return error;
966 /* getvnode() will use the descriptor for us */
967 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
968 return error;
969 vp = (struct vnode *) fp->f_data;
970 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
971 if (vp->v_type != VDIR)
972 error = ENOTDIR;
973 else
974 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, l);
975 VOP_UNLOCK(vp, 0);
976 if (error)
977 goto out;
978 VREF(vp);
979
980 /*
981 * Prevent escaping from chroot by putting the root under
982 * the working directory. Silently chdir to / if we aren't
983 * already there.
984 */
985 if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
986 /*
987 * XXX would be more failsafe to change directory to a
988 * deadfs node here instead
989 */
990 vrele(cwdi->cwdi_cdir);
991 VREF(vp);
992 cwdi->cwdi_cdir = vp;
993 }
994
995 if (cwdi->cwdi_rdir != NULL)
996 vrele(cwdi->cwdi_rdir);
997 cwdi->cwdi_rdir = vp;
998 out:
999 FILE_UNUSE(fp, l);
1000 return (error);
1001 }
1002
1003
1004
1005 /*
1006 * Change current working directory (``.'').
1007 */
1008 /* ARGSUSED */
1009 int
1010 sys_chdir(l, v, retval)
1011 struct lwp *l;
1012 void *v;
1013 register_t *retval;
1014 {
1015 struct sys_chdir_args /* {
1016 syscallarg(const char *) path;
1017 } */ *uap = v;
1018 struct proc *p = l->l_proc;
1019 struct cwdinfo *cwdi = p->p_cwdi;
1020 int error;
1021 struct nameidata nd;
1022
1023 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1024 SCARG(uap, path), l);
1025 if ((error = change_dir(&nd, l)) != 0)
1026 return (error);
1027 vrele(cwdi->cwdi_cdir);
1028 cwdi->cwdi_cdir = nd.ni_vp;
1029 return (0);
1030 }
1031
1032 /*
1033 * Change notion of root (``/'') directory.
1034 */
1035 /* ARGSUSED */
1036 int
1037 sys_chroot(l, v, retval)
1038 struct lwp *l;
1039 void *v;
1040 register_t *retval;
1041 {
1042 struct sys_chroot_args /* {
1043 syscallarg(const char *) path;
1044 } */ *uap = v;
1045 struct proc *p = l->l_proc;
1046 struct cwdinfo *cwdi = p->p_cwdi;
1047 struct vnode *vp;
1048 int error;
1049 struct nameidata nd;
1050
1051 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1052 return (error);
1053 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1054 SCARG(uap, path), l);
1055 if ((error = change_dir(&nd, l)) != 0)
1056 return (error);
1057 if (cwdi->cwdi_rdir != NULL)
1058 vrele(cwdi->cwdi_rdir);
1059 vp = nd.ni_vp;
1060 cwdi->cwdi_rdir = vp;
1061
1062 /*
1063 * Prevent escaping from chroot by putting the root under
1064 * the working directory. Silently chdir to / if we aren't
1065 * already there.
1066 */
1067 if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {
1068 /*
1069 * XXX would be more failsafe to change directory to a
1070 * deadfs node here instead
1071 */
1072 vrele(cwdi->cwdi_cdir);
1073 VREF(vp);
1074 cwdi->cwdi_cdir = vp;
1075 }
1076
1077 return (0);
1078 }
1079
1080 /*
1081 * Common routine for chroot and chdir.
1082 */
1083 static int
1084 change_dir(ndp, l)
1085 struct nameidata *ndp;
1086 struct lwp *l;
1087 {
1088 struct vnode *vp;
1089 int error;
1090
1091 if ((error = namei(ndp)) != 0)
1092 return (error);
1093 vp = ndp->ni_vp;
1094 if (vp->v_type != VDIR)
1095 error = ENOTDIR;
1096 else
1097 error = VOP_ACCESS(vp, VEXEC, l->l_proc->p_ucred, l);
1098
1099 if (error)
1100 vput(vp);
1101 else
1102 VOP_UNLOCK(vp, 0);
1103 return (error);
1104 }
1105
1106 /*
1107 * Check permissions, allocate an open file structure,
1108 * and call the device open routine if any.
1109 */
1110 int
1111 sys_open(l, v, retval)
1112 struct lwp *l;
1113 void *v;
1114 register_t *retval;
1115 {
1116 struct sys_open_args /* {
1117 syscallarg(const char *) path;
1118 syscallarg(int) flags;
1119 syscallarg(int) mode;
1120 } */ *uap = v;
1121 struct proc *p = l->l_proc;
1122 struct cwdinfo *cwdi = p->p_cwdi;
1123 struct filedesc *fdp = p->p_fd;
1124 struct file *fp;
1125 struct vnode *vp;
1126 int flags, cmode;
1127 int type, indx, error;
1128 struct flock lf;
1129 struct nameidata nd;
1130
1131 flags = FFLAGS(SCARG(uap, flags));
1132 if ((flags & (FREAD | FWRITE)) == 0)
1133 return (EINVAL);
1134 /* falloc() will use the file descriptor for us */
1135 if ((error = falloc(p, &fp, &indx)) != 0)
1136 return (error);
1137 cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1138 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1139 l->l_dupfd = -indx - 1; /* XXX check for fdopen */
1140 if ((error = vn_open(&nd, flags, cmode)) != 0) {
1141 FILE_UNUSE(fp, l);
1142 fdp->fd_ofiles[indx] = NULL;
1143 ffree(fp);
1144 if ((error == EDUPFD || error == EMOVEFD) &&
1145 l->l_dupfd >= 0 && /* XXX from fdopen */
1146 (error =
1147 dupfdopen(l, indx, l->l_dupfd, flags, error)) == 0) {
1148 *retval = indx;
1149 return (0);
1150 }
1151 if (error == ERESTART)
1152 error = EINTR;
1153 fdremove(fdp, indx);
1154 return (error);
1155 }
1156 l->l_dupfd = 0;
1157 vp = nd.ni_vp;
1158 fp->f_flag = flags & FMASK;
1159 fp->f_type = DTYPE_VNODE;
1160 fp->f_ops = &vnops;
1161 fp->f_data = vp;
1162 if (flags & (O_EXLOCK | O_SHLOCK)) {
1163 lf.l_whence = SEEK_SET;
1164 lf.l_start = 0;
1165 lf.l_len = 0;
1166 if (flags & O_EXLOCK)
1167 lf.l_type = F_WRLCK;
1168 else
1169 lf.l_type = F_RDLCK;
1170 type = F_FLOCK;
1171 if ((flags & FNONBLOCK) == 0)
1172 type |= F_WAIT;
1173 VOP_UNLOCK(vp, 0);
1174 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1175 if (error) {
1176 (void) vn_close(vp, fp->f_flag, fp->f_cred, l);
1177 FILE_UNUSE(fp, l);
1178 ffree(fp);
1179 fdremove(fdp, indx);
1180 return (error);
1181 }
1182 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1183 fp->f_flag |= FHASLOCK;
1184 }
1185 VOP_UNLOCK(vp, 0);
1186 *retval = indx;
1187 FILE_SET_MATURE(fp);
1188 FILE_UNUSE(fp, l);
1189 return (0);
1190 }
1191
1192 /*
1193 * Get file handle system call
1194 */
1195 int
1196 sys_getfh(l, v, retval)
1197 struct lwp *l;
1198 void *v;
1199 register_t *retval;
1200 {
1201 struct sys_getfh_args /* {
1202 syscallarg(char *) fname;
1203 syscallarg(fhandle_t *) fhp;
1204 } */ *uap = v;
1205 struct proc *p = l->l_proc;
1206 struct vnode *vp;
1207 fhandle_t fh;
1208 int error;
1209 struct nameidata nd;
1210
1211 /*
1212 * Must be super user
1213 */
1214 error = suser(p->p_ucred, &p->p_acflag);
1215 if (error)
1216 return (error);
1217 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1218 SCARG(uap, fname), l);
1219 error = namei(&nd);
1220 if (error)
1221 return (error);
1222 vp = nd.ni_vp;
1223 memset(&fh, 0, sizeof(fh));
1224 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
1225 error = VFS_VPTOFH(vp, &fh.fh_fid);
1226 vput(vp);
1227 if (error)
1228 return (error);
1229 error = copyout(&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh));
1230 return (error);
1231 }
1232
1233 /*
1234 * Open a file given a file handle.
1235 *
1236 * Check permissions, allocate an open file structure,
1237 * and call the device open routine if any.
1238 */
1239 int
1240 sys_fhopen(l, v, retval)
1241 struct lwp *l;
1242 void *v;
1243 register_t *retval;
1244 {
1245 struct sys_fhopen_args /* {
1246 syscallarg(const fhandle_t *) fhp;
1247 syscallarg(int) flags;
1248 } */ *uap = v;
1249 struct proc *p = l->l_proc;
1250 struct filedesc *fdp = p->p_fd;
1251 struct file *fp;
1252 struct vnode *vp = NULL;
1253 struct mount *mp;
1254 struct ucred *cred = p->p_ucred;
1255 int flags;
1256 struct file *nfp;
1257 int type, indx, error=0;
1258 struct flock lf;
1259 struct vattr va;
1260 fhandle_t fh;
1261
1262 /*
1263 * Must be super user
1264 */
1265 if ((error = suser(p->p_ucred, &p->p_acflag)))
1266 return (error);
1267
1268 flags = FFLAGS(SCARG(uap, flags));
1269 if ((flags & (FREAD | FWRITE)) == 0)
1270 return (EINVAL);
1271 if ((flags & O_CREAT))
1272 return (EINVAL);
1273 /* falloc() will use the file descriptor for us */
1274 if ((error = falloc(p, &nfp, &indx)) != 0)
1275 return (error);
1276 fp = nfp;
1277 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1278 goto bad;
1279
1280 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
1281 error = ESTALE;
1282 goto bad;
1283 }
1284
1285 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
1286 vp = NULL; /* most likely unnecessary sanity for bad: */
1287 goto bad;
1288 }
1289
1290 /* Now do an effective vn_open */
1291
1292 if (vp->v_type == VSOCK) {
1293 error = EOPNOTSUPP;
1294 goto bad;
1295 }
1296 if (flags & FREAD) {
1297 if ((error = VOP_ACCESS(vp, VREAD, cred, l)) != 0)
1298 goto bad;
1299 }
1300 if (flags & (FWRITE | O_TRUNC)) {
1301 if (vp->v_type == VDIR) {
1302 error = EISDIR;
1303 goto bad;
1304 }
1305 if ((error = vn_writechk(vp)) != 0 ||
1306 (error = VOP_ACCESS(vp, VWRITE, cred, l)) != 0)
1307 goto bad;
1308 }
1309 if (flags & O_TRUNC) {
1310 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
1311 goto bad;
1312 VOP_UNLOCK(vp, 0); /* XXX */
1313 VOP_LEASE(vp, l, cred, LEASE_WRITE);
1314 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1315 VATTR_NULL(&va);
1316 va.va_size = 0;
1317 error = VOP_SETATTR(vp, &va, cred, l);
1318 vn_finished_write(mp, 0);
1319 if (error)
1320 goto bad;
1321 }
1322 if ((error = VOP_OPEN(vp, flags, cred, l)) != 0)
1323 goto bad;
1324 if (vp->v_type == VREG &&
1325 uvn_attach(vp, flags & FWRITE ? VM_PROT_WRITE : 0) == NULL) {
1326 error = EIO;
1327 goto bad;
1328 }
1329 if (flags & FWRITE)
1330 vp->v_writecount++;
1331
1332 /* done with modified vn_open, now finish what sys_open does. */
1333
1334 fp->f_flag = flags & FMASK;
1335 fp->f_type = DTYPE_VNODE;
1336 fp->f_ops = &vnops;
1337 fp->f_data = vp;
1338 if (flags & (O_EXLOCK | O_SHLOCK)) {
1339 lf.l_whence = SEEK_SET;
1340 lf.l_start = 0;
1341 lf.l_len = 0;
1342 if (flags & O_EXLOCK)
1343 lf.l_type = F_WRLCK;
1344 else
1345 lf.l_type = F_RDLCK;
1346 type = F_FLOCK;
1347 if ((flags & FNONBLOCK) == 0)
1348 type |= F_WAIT;
1349 VOP_UNLOCK(vp, 0);
1350 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1351 if (error) {
1352 (void) vn_close(vp, fp->f_flag, fp->f_cred, l);
1353 FILE_UNUSE(fp, l);
1354 ffree(fp);
1355 fdremove(fdp, indx);
1356 return (error);
1357 }
1358 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1359 fp->f_flag |= FHASLOCK;
1360 }
1361 VOP_UNLOCK(vp, 0);
1362 *retval = indx;
1363 FILE_SET_MATURE(fp);
1364 FILE_UNUSE(fp, l);
1365 return (0);
1366
1367 bad:
1368 FILE_UNUSE(fp, l);
1369 ffree(fp);
1370 fdremove(fdp, indx);
1371 if (vp != NULL)
1372 vput(vp);
1373 return (error);
1374 }
1375
1376 /* ARGSUSED */
1377 int
1378 sys_fhstat(l, v, retval)
1379 struct lwp *l;
1380 void *v;
1381 register_t *retval;
1382 {
1383 struct sys_fhstat_args /* {
1384 syscallarg(const fhandle_t *) fhp;
1385 syscallarg(struct stat *) sb;
1386 } */ *uap = v;
1387 struct proc *p = l->l_proc;
1388 struct stat sb;
1389 int error;
1390 fhandle_t fh;
1391 struct mount *mp;
1392 struct vnode *vp;
1393
1394 /*
1395 * Must be super user
1396 */
1397 if ((error = suser(p->p_ucred, &p->p_acflag)))
1398 return (error);
1399
1400 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1401 return (error);
1402
1403 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1404 return (ESTALE);
1405 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1406 return (error);
1407 error = vn_stat(vp, &sb, l);
1408 vput(vp);
1409 if (error)
1410 return (error);
1411 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
1412 return (error);
1413 }
1414
1415 /* ARGSUSED */
1416 int
1417 sys_fhstatvfs1(l, v, retval)
1418 struct lwp *l;
1419 void *v;
1420 register_t *retval;
1421 {
1422 struct sys_fhstatvfs1_args /*
1423 syscallarg(const fhandle_t *) fhp;
1424 syscallarg(struct statvfs *) buf;
1425 syscallarg(int) flags;
1426 } */ *uap = v;
1427 struct proc *p = l->l_proc;
1428 struct statvfs sbuf;
1429 fhandle_t fh;
1430 struct mount *mp;
1431 struct vnode *vp;
1432 int error;
1433
1434 /*
1435 * Must be super user
1436 */
1437 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1438 return error;
1439
1440 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1441 return error;
1442
1443 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1444 return ESTALE;
1445 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1446 return error;
1447
1448 mp = vp->v_mount;
1449 if ((error = dostatvfs(mp, &sbuf, l, SCARG(uap, flags), 1)) != 0) {
1450 vput(vp);
1451 return error;
1452 }
1453 vput(vp);
1454 return copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
1455 }
1456
1457 /*
1458 * Create a special file.
1459 */
1460 /* ARGSUSED */
1461 int
1462 sys_mknod(l, v, retval)
1463 struct lwp *l;
1464 void *v;
1465 register_t *retval;
1466 {
1467 struct sys_mknod_args /* {
1468 syscallarg(const char *) path;
1469 syscallarg(int) mode;
1470 syscallarg(int) dev;
1471 } */ *uap = v;
1472 struct proc *p = l->l_proc;
1473 struct vnode *vp;
1474 struct mount *mp;
1475 struct vattr vattr;
1476 int error;
1477 int whiteout = 0;
1478 struct nameidata nd;
1479
1480 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1481 return (error);
1482 restart:
1483 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), l);
1484 if ((error = namei(&nd)) != 0)
1485 return (error);
1486 vp = nd.ni_vp;
1487 if (vp != NULL)
1488 error = EEXIST;
1489 else {
1490 VATTR_NULL(&vattr);
1491 vattr.va_mode =
1492 (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1493 vattr.va_rdev = SCARG(uap, dev);
1494 whiteout = 0;
1495
1496 switch (SCARG(uap, mode) & S_IFMT) {
1497 case S_IFMT: /* used by badsect to flag bad sectors */
1498 vattr.va_type = VBAD;
1499 break;
1500 case S_IFCHR:
1501 vattr.va_type = VCHR;
1502 break;
1503 case S_IFBLK:
1504 vattr.va_type = VBLK;
1505 break;
1506 case S_IFWHT:
1507 whiteout = 1;
1508 break;
1509 default:
1510 error = EINVAL;
1511 break;
1512 }
1513 }
1514 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1515 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1516 if (nd.ni_dvp == vp)
1517 vrele(nd.ni_dvp);
1518 else
1519 vput(nd.ni_dvp);
1520 if (vp)
1521 vrele(vp);
1522 if ((error = vn_start_write(NULL, &mp,
1523 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1524 return (error);
1525 goto restart;
1526 }
1527 if (!error) {
1528 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1529 if (whiteout) {
1530 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1531 if (error)
1532 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1533 vput(nd.ni_dvp);
1534 } else {
1535 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1536 &nd.ni_cnd, &vattr);
1537 if (error == 0)
1538 vput(nd.ni_vp);
1539 }
1540 } else {
1541 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1542 if (nd.ni_dvp == vp)
1543 vrele(nd.ni_dvp);
1544 else
1545 vput(nd.ni_dvp);
1546 if (vp)
1547 vrele(vp);
1548 }
1549 vn_finished_write(mp, 0);
1550 return (error);
1551 }
1552
1553 /*
1554 * Create a named pipe.
1555 */
1556 /* ARGSUSED */
1557 int
1558 sys_mkfifo(l, v, retval)
1559 struct lwp *l;
1560 void *v;
1561 register_t *retval;
1562 {
1563 struct sys_mkfifo_args /* {
1564 syscallarg(const char *) path;
1565 syscallarg(int) mode;
1566 } */ *uap = v;
1567 struct proc *p = l->l_proc;
1568 struct mount *mp;
1569 struct vattr vattr;
1570 int error;
1571 struct nameidata nd;
1572
1573 restart:
1574 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), l);
1575 if ((error = namei(&nd)) != 0)
1576 return (error);
1577 if (nd.ni_vp != NULL) {
1578 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1579 if (nd.ni_dvp == nd.ni_vp)
1580 vrele(nd.ni_dvp);
1581 else
1582 vput(nd.ni_dvp);
1583 vrele(nd.ni_vp);
1584 return (EEXIST);
1585 }
1586 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1587 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1588 if (nd.ni_dvp == nd.ni_vp)
1589 vrele(nd.ni_dvp);
1590 else
1591 vput(nd.ni_dvp);
1592 if (nd.ni_vp)
1593 vrele(nd.ni_vp);
1594 if ((error = vn_start_write(NULL, &mp,
1595 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1596 return (error);
1597 goto restart;
1598 }
1599 VATTR_NULL(&vattr);
1600 vattr.va_type = VFIFO;
1601 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1602 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1603 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1604 if (error == 0)
1605 vput(nd.ni_vp);
1606 vn_finished_write(mp, 0);
1607 return (error);
1608 }
1609
1610 /*
1611 * Make a hard file link.
1612 */
1613 /* ARGSUSED */
1614 int
1615 sys_link(l, v, retval)
1616 struct lwp *l;
1617 void *v;
1618 register_t *retval;
1619 {
1620 struct sys_link_args /* {
1621 syscallarg(const char *) path;
1622 syscallarg(const char *) link;
1623 } */ *uap = v;
1624 struct proc *p = l->l_proc;
1625 struct vnode *vp;
1626 struct mount *mp;
1627 struct nameidata nd;
1628 int error;
1629
1630 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1631 if ((error = namei(&nd)) != 0)
1632 return (error);
1633 vp = nd.ni_vp;
1634 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
1635 vrele(vp);
1636 return (error);
1637 }
1638 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), l);
1639 if ((error = namei(&nd)) != 0)
1640 goto out;
1641 if (nd.ni_vp) {
1642 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1643 if (nd.ni_dvp == nd.ni_vp)
1644 vrele(nd.ni_dvp);
1645 else
1646 vput(nd.ni_dvp);
1647 vrele(nd.ni_vp);
1648 error = EEXIST;
1649 goto out;
1650 }
1651 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1652 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
1653 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1654 out:
1655 vrele(vp);
1656 vn_finished_write(mp, 0);
1657 return (error);
1658 }
1659
1660 /*
1661 * Make a symbolic link.
1662 */
1663 /* ARGSUSED */
1664 int
1665 sys_symlink(l, v, retval)
1666 struct lwp *l;
1667 void *v;
1668 register_t *retval;
1669 {
1670 struct sys_symlink_args /* {
1671 syscallarg(const char *) path;
1672 syscallarg(const char *) link;
1673 } */ *uap = v;
1674 struct proc *p = l->l_proc;
1675 struct mount *mp;
1676 struct vattr vattr;
1677 char *path;
1678 int error;
1679 struct nameidata nd;
1680
1681 path = PNBUF_GET();
1682 error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
1683 if (error)
1684 goto out;
1685 restart:
1686 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), l);
1687 if ((error = namei(&nd)) != 0)
1688 goto out;
1689 if (nd.ni_vp) {
1690 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1691 if (nd.ni_dvp == nd.ni_vp)
1692 vrele(nd.ni_dvp);
1693 else
1694 vput(nd.ni_dvp);
1695 vrele(nd.ni_vp);
1696 error = EEXIST;
1697 goto out;
1698 }
1699 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1700 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1701 if (nd.ni_dvp == nd.ni_vp)
1702 vrele(nd.ni_dvp);
1703 else
1704 vput(nd.ni_dvp);
1705 if ((error = vn_start_write(NULL, &mp,
1706 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1707 return (error);
1708 goto restart;
1709 }
1710 VATTR_NULL(&vattr);
1711 vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1712 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1713 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1714 if (error == 0)
1715 vput(nd.ni_vp);
1716 vn_finished_write(mp, 0);
1717 out:
1718 PNBUF_PUT(path);
1719 return (error);
1720 }
1721
1722 /*
1723 * Delete a whiteout from the filesystem.
1724 */
1725 /* ARGSUSED */
1726 int
1727 sys_undelete(l, v, retval)
1728 struct lwp *l;
1729 void *v;
1730 register_t *retval;
1731 {
1732 struct sys_undelete_args /* {
1733 syscallarg(const char *) path;
1734 } */ *uap = v;
1735 struct proc *p = l->l_proc;
1736 int error;
1737 struct mount *mp;
1738 struct nameidata nd;
1739
1740 restart:
1741 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1742 SCARG(uap, path), l);
1743 error = namei(&nd);
1744 if (error)
1745 return (error);
1746
1747 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1748 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1749 if (nd.ni_dvp == nd.ni_vp)
1750 vrele(nd.ni_dvp);
1751 else
1752 vput(nd.ni_dvp);
1753 if (nd.ni_vp)
1754 vrele(nd.ni_vp);
1755 return (EEXIST);
1756 }
1757 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1758 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1759 if (nd.ni_dvp == nd.ni_vp)
1760 vrele(nd.ni_dvp);
1761 else
1762 vput(nd.ni_dvp);
1763 if ((error = vn_start_write(NULL, &mp,
1764 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1765 return (error);
1766 goto restart;
1767 }
1768 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1769 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1770 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1771 vput(nd.ni_dvp);
1772 vn_finished_write(mp, 0);
1773 return (error);
1774 }
1775
1776 /*
1777 * Delete a name from the filesystem.
1778 */
1779 /* ARGSUSED */
1780 int
1781 sys_unlink(l, v, retval)
1782 struct lwp *l;
1783 void *v;
1784 register_t *retval;
1785 {
1786 struct sys_unlink_args /* {
1787 syscallarg(const char *) path;
1788 } */ *uap = v;
1789 struct proc *p = l->l_proc;
1790 struct mount *mp;
1791 struct vnode *vp;
1792 int error;
1793 struct nameidata nd;
1794
1795 restart:
1796 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1797 SCARG(uap, path), l);
1798 if ((error = namei(&nd)) != 0)
1799 return (error);
1800 vp = nd.ni_vp;
1801
1802 /*
1803 * The root of a mounted filesystem cannot be deleted.
1804 */
1805 if (vp->v_flag & VROOT) {
1806 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1807 if (nd.ni_dvp == vp)
1808 vrele(nd.ni_dvp);
1809 else
1810 vput(nd.ni_dvp);
1811 vput(vp);
1812 error = EBUSY;
1813 goto out;
1814 }
1815 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1816 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1817 if (nd.ni_dvp == vp)
1818 vrele(nd.ni_dvp);
1819 else
1820 vput(nd.ni_dvp);
1821 vput(vp);
1822 if ((error = vn_start_write(NULL, &mp,
1823 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1824 return (error);
1825 goto restart;
1826 }
1827 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
1828 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
1829 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1830 vn_finished_write(mp, 0);
1831 out:
1832 return (error);
1833 }
1834
1835 /*
1836 * Reposition read/write file offset.
1837 */
1838 int
1839 sys_lseek(l, v, retval)
1840 struct lwp *l;
1841 void *v;
1842 register_t *retval;
1843 {
1844 struct sys_lseek_args /* {
1845 syscallarg(int) fd;
1846 syscallarg(int) pad;
1847 syscallarg(off_t) offset;
1848 syscallarg(int) whence;
1849 } */ *uap = v;
1850 struct proc *p = l->l_proc;
1851 struct ucred *cred = p->p_ucred;
1852 struct filedesc *fdp = p->p_fd;
1853 struct file *fp;
1854 struct vnode *vp;
1855 struct vattr vattr;
1856 off_t newoff;
1857 int error;
1858
1859 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
1860 return (EBADF);
1861
1862 FILE_USE(fp);
1863
1864 vp = (struct vnode *)fp->f_data;
1865 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1866 error = ESPIPE;
1867 goto out;
1868 }
1869
1870 switch (SCARG(uap, whence)) {
1871 case SEEK_CUR:
1872 newoff = fp->f_offset + SCARG(uap, offset);
1873 break;
1874 case SEEK_END:
1875 error = VOP_GETATTR(vp, &vattr, cred, l);
1876 if (error)
1877 goto out;
1878 newoff = SCARG(uap, offset) + vattr.va_size;
1879 break;
1880 case SEEK_SET:
1881 newoff = SCARG(uap, offset);
1882 break;
1883 default:
1884 error = EINVAL;
1885 goto out;
1886 }
1887 if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
1888 goto out;
1889
1890 *(off_t *)retval = fp->f_offset = newoff;
1891 out:
1892 FILE_UNUSE(fp, l);
1893 return (error);
1894 }
1895
1896 /*
1897 * Positional read system call.
1898 */
1899 int
1900 sys_pread(l, v, retval)
1901 struct lwp *l;
1902 void *v;
1903 register_t *retval;
1904 {
1905 struct sys_pread_args /* {
1906 syscallarg(int) fd;
1907 syscallarg(void *) buf;
1908 syscallarg(size_t) nbyte;
1909 syscallarg(off_t) offset;
1910 } */ *uap = v;
1911 struct proc *p = l->l_proc;
1912 struct filedesc *fdp = p->p_fd;
1913 struct file *fp;
1914 struct vnode *vp;
1915 off_t offset;
1916 int error, fd = SCARG(uap, fd);
1917
1918 if ((fp = fd_getfile(fdp, fd)) == NULL)
1919 return (EBADF);
1920
1921 if ((fp->f_flag & FREAD) == 0) {
1922 simple_unlock(&fp->f_slock);
1923 return (EBADF);
1924 }
1925
1926 FILE_USE(fp);
1927
1928 vp = (struct vnode *)fp->f_data;
1929 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1930 error = ESPIPE;
1931 goto out;
1932 }
1933
1934 offset = SCARG(uap, offset);
1935
1936 /*
1937 * XXX This works because no file systems actually
1938 * XXX take any action on the seek operation.
1939 */
1940 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1941 goto out;
1942
1943 /* dofileread() will unuse the descriptor for us */
1944 return (dofileread(l, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1945 &offset, 0, retval));
1946
1947 out:
1948 FILE_UNUSE(fp, l);
1949 return (error);
1950 }
1951
1952 /*
1953 * Positional scatter read system call.
1954 */
1955 int
1956 sys_preadv(l, v, retval)
1957 struct lwp *l;
1958 void *v;
1959 register_t *retval;
1960 {
1961 struct sys_preadv_args /* {
1962 syscallarg(int) fd;
1963 syscallarg(const struct iovec *) iovp;
1964 syscallarg(int) iovcnt;
1965 syscallarg(off_t) offset;
1966 } */ *uap = v;
1967 struct proc *p = l->l_proc;
1968 struct filedesc *fdp = p->p_fd;
1969 struct file *fp;
1970 struct vnode *vp;
1971 off_t offset;
1972 int error, fd = SCARG(uap, fd);
1973
1974 if ((fp = fd_getfile(fdp, fd)) == NULL)
1975 return (EBADF);
1976
1977 if ((fp->f_flag & FREAD) == 0) {
1978 simple_unlock(&fp->f_slock);
1979 return (EBADF);
1980 }
1981
1982 FILE_USE(fp);
1983
1984 vp = (struct vnode *)fp->f_data;
1985 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1986 error = ESPIPE;
1987 goto out;
1988 }
1989
1990 offset = SCARG(uap, offset);
1991
1992 /*
1993 * XXX This works because no file systems actually
1994 * XXX take any action on the seek operation.
1995 */
1996 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1997 goto out;
1998
1999 /* dofilereadv() will unuse the descriptor for us */
2000 return (dofilereadv(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
2001 &offset, 0, retval));
2002
2003 out:
2004 FILE_UNUSE(fp, l);
2005 return (error);
2006 }
2007
2008 /*
2009 * Positional write system call.
2010 */
2011 int
2012 sys_pwrite(l, v, retval)
2013 struct lwp *l;
2014 void *v;
2015 register_t *retval;
2016 {
2017 struct sys_pwrite_args /* {
2018 syscallarg(int) fd;
2019 syscallarg(const void *) buf;
2020 syscallarg(size_t) nbyte;
2021 syscallarg(off_t) offset;
2022 } */ *uap = v;
2023 struct proc *p = l->l_proc;
2024 struct filedesc *fdp = p->p_fd;
2025 struct file *fp;
2026 struct vnode *vp;
2027 off_t offset;
2028 int error, fd = SCARG(uap, fd);
2029
2030 if ((fp = fd_getfile(fdp, fd)) == NULL)
2031 return (EBADF);
2032
2033 if ((fp->f_flag & FWRITE) == 0) {
2034 simple_unlock(&fp->f_slock);
2035 return (EBADF);
2036 }
2037
2038 FILE_USE(fp);
2039
2040 vp = (struct vnode *)fp->f_data;
2041 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2042 error = ESPIPE;
2043 goto out;
2044 }
2045
2046 offset = SCARG(uap, offset);
2047
2048 /*
2049 * XXX This works because no file systems actually
2050 * XXX take any action on the seek operation.
2051 */
2052 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2053 goto out;
2054
2055 /* dofilewrite() will unuse the descriptor for us */
2056 return (dofilewrite(l, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2057 &offset, 0, retval));
2058
2059 out:
2060 FILE_UNUSE(fp, l);
2061 return (error);
2062 }
2063
2064 /*
2065 * Positional gather write system call.
2066 */
2067 int
2068 sys_pwritev(l, v, retval)
2069 struct lwp *l;
2070 void *v;
2071 register_t *retval;
2072 {
2073 struct sys_pwritev_args /* {
2074 syscallarg(int) fd;
2075 syscallarg(const struct iovec *) iovp;
2076 syscallarg(int) iovcnt;
2077 syscallarg(off_t) offset;
2078 } */ *uap = v;
2079 struct proc *p = l->l_proc;
2080 struct filedesc *fdp = p->p_fd;
2081 struct file *fp;
2082 struct vnode *vp;
2083 off_t offset;
2084 int error, fd = SCARG(uap, fd);
2085
2086 if ((fp = fd_getfile(fdp, fd)) == NULL)
2087 return (EBADF);
2088
2089 if ((fp->f_flag & FWRITE) == 0) {
2090 simple_unlock(&fp->f_slock);
2091 return (EBADF);
2092 }
2093
2094 FILE_USE(fp);
2095
2096 vp = (struct vnode *)fp->f_data;
2097 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2098 error = ESPIPE;
2099 goto out;
2100 }
2101
2102 offset = SCARG(uap, offset);
2103
2104 /*
2105 * XXX This works because no file systems actually
2106 * XXX take any action on the seek operation.
2107 */
2108 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2109 goto out;
2110
2111 /* dofilewritev() will unuse the descriptor for us */
2112 return (dofilewritev(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
2113 &offset, 0, retval));
2114
2115 out:
2116 FILE_UNUSE(fp, l);
2117 return (error);
2118 }
2119
2120 /*
2121 * Check access permissions.
2122 */
2123 int
2124 sys_access(l, v, retval)
2125 struct lwp *l;
2126 void *v;
2127 register_t *retval;
2128 {
2129 struct sys_access_args /* {
2130 syscallarg(const char *) path;
2131 syscallarg(int) flags;
2132 } */ *uap = v;
2133 struct proc *p = l->l_proc;
2134 struct ucred *cred;
2135 struct vnode *vp;
2136 int error, flags;
2137 struct nameidata nd;
2138
2139 cred = crdup(p->p_ucred);
2140 cred->cr_uid = p->p_cred->p_ruid;
2141 cred->cr_gid = p->p_cred->p_rgid;
2142 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2143 SCARG(uap, path), l);
2144 /* Override default credentials */
2145 nd.ni_cnd.cn_cred = cred;
2146 if ((error = namei(&nd)) != 0)
2147 goto out;
2148 vp = nd.ni_vp;
2149
2150 /* Flags == 0 means only check for existence. */
2151 if (SCARG(uap, flags)) {
2152 flags = 0;
2153 if (SCARG(uap, flags) & R_OK)
2154 flags |= VREAD;
2155 if (SCARG(uap, flags) & W_OK)
2156 flags |= VWRITE;
2157 if (SCARG(uap, flags) & X_OK)
2158 flags |= VEXEC;
2159
2160 error = VOP_ACCESS(vp, flags, cred, l);
2161 if (!error && (flags & VWRITE))
2162 error = vn_writechk(vp);
2163 }
2164 vput(vp);
2165 out:
2166 crfree(cred);
2167 return (error);
2168 }
2169
2170 /*
2171 * Get file status; this version follows links.
2172 */
2173 /* ARGSUSED */
2174 int
2175 sys___stat13(l, v, retval)
2176 struct lwp *l;
2177 void *v;
2178 register_t *retval;
2179 {
2180 struct sys___stat13_args /* {
2181 syscallarg(const char *) path;
2182 syscallarg(struct stat *) ub;
2183 } */ *uap = v;
2184 struct stat sb;
2185 int error;
2186 struct nameidata nd;
2187
2188 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2189 SCARG(uap, path), l);
2190 if ((error = namei(&nd)) != 0)
2191 return (error);
2192 error = vn_stat(nd.ni_vp, &sb, l);
2193 vput(nd.ni_vp);
2194 if (error)
2195 return (error);
2196 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
2197 return (error);
2198 }
2199
2200 /*
2201 * Get file status; this version does not follow links.
2202 */
2203 /* ARGSUSED */
2204 int
2205 sys___lstat13(l, v, retval)
2206 struct lwp *l;
2207 void *v;
2208 register_t *retval;
2209 {
2210 struct sys___lstat13_args /* {
2211 syscallarg(const char *) path;
2212 syscallarg(struct stat *) ub;
2213 } */ *uap = v;
2214 struct stat sb;
2215 int error;
2216 struct nameidata nd;
2217
2218 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
2219 SCARG(uap, path), l);
2220 if ((error = namei(&nd)) != 0)
2221 return (error);
2222 error = vn_stat(nd.ni_vp, &sb, l);
2223 vput(nd.ni_vp);
2224 if (error)
2225 return (error);
2226 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
2227 return (error);
2228 }
2229
2230 /*
2231 * Get configurable pathname variables.
2232 */
2233 /* ARGSUSED */
2234 int
2235 sys_pathconf(l, v, retval)
2236 struct lwp *l;
2237 void *v;
2238 register_t *retval;
2239 {
2240 struct sys_pathconf_args /* {
2241 syscallarg(const char *) path;
2242 syscallarg(int) name;
2243 } */ *uap = v;
2244 int error;
2245 struct nameidata nd;
2246
2247 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2248 SCARG(uap, path), l);
2249 if ((error = namei(&nd)) != 0)
2250 return (error);
2251 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
2252 vput(nd.ni_vp);
2253 return (error);
2254 }
2255
2256 /*
2257 * Return target name of a symbolic link.
2258 */
2259 /* ARGSUSED */
2260 int
2261 sys_readlink(l, v, retval)
2262 struct lwp *l;
2263 void *v;
2264 register_t *retval;
2265 {
2266 struct sys_readlink_args /* {
2267 syscallarg(const char *) path;
2268 syscallarg(char *) buf;
2269 syscallarg(size_t) count;
2270 } */ *uap = v;
2271 struct proc *p = l->l_proc;
2272 struct vnode *vp;
2273 struct iovec aiov;
2274 struct uio auio;
2275 int error;
2276 struct nameidata nd;
2277
2278 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
2279 SCARG(uap, path), l);
2280 if ((error = namei(&nd)) != 0)
2281 return (error);
2282 vp = nd.ni_vp;
2283 if (vp->v_type != VLNK)
2284 error = EINVAL;
2285 else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
2286 (error = VOP_ACCESS(vp, VREAD, p->p_ucred, l)) == 0) {
2287 aiov.iov_base = SCARG(uap, buf);
2288 aiov.iov_len = SCARG(uap, count);
2289 auio.uio_iov = &aiov;
2290 auio.uio_iovcnt = 1;
2291 auio.uio_offset = 0;
2292 auio.uio_rw = UIO_READ;
2293 auio.uio_segflg = UIO_USERSPACE;
2294 auio.uio_lwp = l;
2295 auio.uio_resid = SCARG(uap, count);
2296 error = VOP_READLINK(vp, &auio, p->p_ucred);
2297 }
2298 vput(vp);
2299 *retval = SCARG(uap, count) - auio.uio_resid;
2300 return (error);
2301 }
2302
2303 /*
2304 * Change flags of a file given a path name.
2305 */
2306 /* ARGSUSED */
2307 int
2308 sys_chflags(l, v, retval)
2309 struct lwp *l;
2310 void *v;
2311 register_t *retval;
2312 {
2313 struct sys_chflags_args /* {
2314 syscallarg(const char *) path;
2315 syscallarg(u_long) flags;
2316 } */ *uap = v;
2317 struct vnode *vp;
2318 int error;
2319 struct nameidata nd;
2320
2321 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2322 if ((error = namei(&nd)) != 0)
2323 return (error);
2324 vp = nd.ni_vp;
2325 error = change_flags(vp, SCARG(uap, flags), l);
2326 vput(vp);
2327 return (error);
2328 }
2329
2330 /*
2331 * Change flags of a file given a file descriptor.
2332 */
2333 /* ARGSUSED */
2334 int
2335 sys_fchflags(l, v, retval)
2336 struct lwp *l;
2337 void *v;
2338 register_t *retval;
2339 {
2340 struct sys_fchflags_args /* {
2341 syscallarg(int) fd;
2342 syscallarg(u_long) flags;
2343 } */ *uap = v;
2344 struct proc *p = l->l_proc;
2345 struct vnode *vp;
2346 struct file *fp;
2347 int error;
2348
2349 /* getvnode() will use the descriptor for us */
2350 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2351 return (error);
2352 vp = (struct vnode *)fp->f_data;
2353 error = change_flags(vp, SCARG(uap, flags), l);
2354 VOP_UNLOCK(vp, 0);
2355 FILE_UNUSE(fp, l);
2356 return (error);
2357 }
2358
2359 /*
2360 * Change flags of a file given a path name; this version does
2361 * not follow links.
2362 */
2363 int
2364 sys_lchflags(l, v, retval)
2365 struct lwp *l;
2366 void *v;
2367 register_t *retval;
2368 {
2369 struct sys_lchflags_args /* {
2370 syscallarg(const char *) path;
2371 syscallarg(u_long) flags;
2372 } */ *uap = v;
2373 struct vnode *vp;
2374 int error;
2375 struct nameidata nd;
2376
2377 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2378 if ((error = namei(&nd)) != 0)
2379 return (error);
2380 vp = nd.ni_vp;
2381 error = change_flags(vp, SCARG(uap, flags), l);
2382 vput(vp);
2383 return (error);
2384 }
2385
2386 /*
2387 * Common routine to change flags of a file.
2388 */
2389 int
2390 change_flags(vp, flags, l)
2391 struct vnode *vp;
2392 u_long flags;
2393 struct lwp *l;
2394 {
2395 struct proc *p = l->l_proc;
2396 struct mount *mp;
2397 struct vattr vattr;
2398 int error;
2399
2400 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2401 return (error);
2402 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2403 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2404 /*
2405 * Non-superusers cannot change the flags on devices, even if they
2406 * own them.
2407 */
2408 if (suser(p->p_ucred, &p->p_acflag) != 0) {
2409 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, l)) != 0)
2410 goto out;
2411 if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
2412 error = EINVAL;
2413 goto out;
2414 }
2415 }
2416 VATTR_NULL(&vattr);
2417 vattr.va_flags = flags;
2418 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l);
2419 out:
2420 vn_finished_write(mp, 0);
2421 return (error);
2422 }
2423
2424 /*
2425 * Change mode of a file given path name; this version follows links.
2426 */
2427 /* ARGSUSED */
2428 int
2429 sys_chmod(l, v, retval)
2430 struct lwp *l;
2431 void *v;
2432 register_t *retval;
2433 {
2434 struct sys_chmod_args /* {
2435 syscallarg(const char *) path;
2436 syscallarg(int) mode;
2437 } */ *uap = v;
2438 int error;
2439 struct nameidata nd;
2440
2441 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2442 if ((error = namei(&nd)) != 0)
2443 return (error);
2444
2445 error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
2446
2447 vrele(nd.ni_vp);
2448 return (error);
2449 }
2450
2451 /*
2452 * Change mode of a file given a file descriptor.
2453 */
2454 /* ARGSUSED */
2455 int
2456 sys_fchmod(l, v, retval)
2457 struct lwp *l;
2458 void *v;
2459 register_t *retval;
2460 {
2461 struct sys_fchmod_args /* {
2462 syscallarg(int) fd;
2463 syscallarg(int) mode;
2464 } */ *uap = v;
2465 struct proc *p = l->l_proc;
2466 struct file *fp;
2467 int error;
2468
2469 /* getvnode() will use the descriptor for us */
2470 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2471 return (error);
2472
2473 error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), l);
2474 FILE_UNUSE(fp, l);
2475 return (error);
2476 }
2477
2478 /*
2479 * Change mode of a file given path name; this version does not follow links.
2480 */
2481 /* ARGSUSED */
2482 int
2483 sys_lchmod(l, v, retval)
2484 struct lwp *l;
2485 void *v;
2486 register_t *retval;
2487 {
2488 struct sys_lchmod_args /* {
2489 syscallarg(const char *) path;
2490 syscallarg(int) mode;
2491 } */ *uap = v;
2492 int error;
2493 struct nameidata nd;
2494
2495 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2496 if ((error = namei(&nd)) != 0)
2497 return (error);
2498
2499 error = change_mode(nd.ni_vp, SCARG(uap, mode), l);
2500
2501 vrele(nd.ni_vp);
2502 return (error);
2503 }
2504
2505 /*
2506 * Common routine to set mode given a vnode.
2507 */
2508 static int
2509 change_mode(vp, mode, l)
2510 struct vnode *vp;
2511 int mode;
2512 struct lwp *l;
2513 {
2514 struct proc *p = l->l_proc;
2515 struct mount *mp;
2516 struct vattr vattr;
2517 int error;
2518
2519 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2520 return (error);
2521 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2522 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2523 VATTR_NULL(&vattr);
2524 vattr.va_mode = mode & ALLPERMS;
2525 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l);
2526 VOP_UNLOCK(vp, 0);
2527 vn_finished_write(mp, 0);
2528 return (error);
2529 }
2530
2531 /*
2532 * Set ownership given a path name; this version follows links.
2533 */
2534 /* ARGSUSED */
2535 int
2536 sys_chown(l, v, retval)
2537 struct lwp *l;
2538 void *v;
2539 register_t *retval;
2540 {
2541 struct sys_chown_args /* {
2542 syscallarg(const char *) path;
2543 syscallarg(uid_t) uid;
2544 syscallarg(gid_t) gid;
2545 } */ *uap = v;
2546 int error;
2547 struct nameidata nd;
2548
2549 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2550 if ((error = namei(&nd)) != 0)
2551 return (error);
2552
2553 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
2554
2555 vrele(nd.ni_vp);
2556 return (error);
2557 }
2558
2559 /*
2560 * Set ownership given a path name; this version follows links.
2561 * Provides POSIX semantics.
2562 */
2563 /* ARGSUSED */
2564 int
2565 sys___posix_chown(l, v, retval)
2566 struct lwp *l;
2567 void *v;
2568 register_t *retval;
2569 {
2570 struct sys_chown_args /* {
2571 syscallarg(const char *) path;
2572 syscallarg(uid_t) uid;
2573 syscallarg(gid_t) gid;
2574 } */ *uap = v;
2575 int error;
2576 struct nameidata nd;
2577
2578 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2579 if ((error = namei(&nd)) != 0)
2580 return (error);
2581
2582 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
2583
2584 vrele(nd.ni_vp);
2585 return (error);
2586 }
2587
2588 /*
2589 * Set ownership given a file descriptor.
2590 */
2591 /* ARGSUSED */
2592 int
2593 sys_fchown(l, v, retval)
2594 struct lwp *l;
2595 void *v;
2596 register_t *retval;
2597 {
2598 struct sys_fchown_args /* {
2599 syscallarg(int) fd;
2600 syscallarg(uid_t) uid;
2601 syscallarg(gid_t) gid;
2602 } */ *uap = v;
2603 struct proc *p = l->l_proc;
2604 int error;
2605 struct file *fp;
2606
2607 /* getvnode() will use the descriptor for us */
2608 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2609 return (error);
2610
2611 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2612 SCARG(uap, gid), l, 0);
2613 FILE_UNUSE(fp, l);
2614 return (error);
2615 }
2616
2617 /*
2618 * Set ownership given a file descriptor, providing POSIX/XPG semantics.
2619 */
2620 /* ARGSUSED */
2621 int
2622 sys___posix_fchown(l, v, retval)
2623 struct lwp *l;
2624 void *v;
2625 register_t *retval;
2626 {
2627 struct sys_fchown_args /* {
2628 syscallarg(int) fd;
2629 syscallarg(uid_t) uid;
2630 syscallarg(gid_t) gid;
2631 } */ *uap = v;
2632 struct proc *p = l->l_proc;
2633 int error;
2634 struct file *fp;
2635
2636 /* getvnode() will use the descriptor for us */
2637 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2638 return (error);
2639
2640 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2641 SCARG(uap, gid), l, 1);
2642 FILE_UNUSE(fp, l);
2643 return (error);
2644 }
2645
2646 /*
2647 * Set ownership given a path name; this version does not follow links.
2648 */
2649 /* ARGSUSED */
2650 int
2651 sys_lchown(l, v, retval)
2652 struct lwp *l;
2653 void *v;
2654 register_t *retval;
2655 {
2656 struct sys_lchown_args /* {
2657 syscallarg(const char *) path;
2658 syscallarg(uid_t) uid;
2659 syscallarg(gid_t) gid;
2660 } */ *uap = v;
2661 int error;
2662 struct nameidata nd;
2663
2664 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2665 if ((error = namei(&nd)) != 0)
2666 return (error);
2667
2668 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
2669
2670 vrele(nd.ni_vp);
2671 return (error);
2672 }
2673
2674 /*
2675 * Set ownership given a path name; this version does not follow links.
2676 * Provides POSIX/XPG semantics.
2677 */
2678 /* ARGSUSED */
2679 int
2680 sys___posix_lchown(l, v, retval)
2681 struct lwp *l;
2682 void *v;
2683 register_t *retval;
2684 {
2685 struct sys_lchown_args /* {
2686 syscallarg(const char *) path;
2687 syscallarg(uid_t) uid;
2688 syscallarg(gid_t) gid;
2689 } */ *uap = v;
2690 int error;
2691 struct nameidata nd;
2692
2693 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2694 if ((error = namei(&nd)) != 0)
2695 return (error);
2696
2697 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
2698
2699 vrele(nd.ni_vp);
2700 return (error);
2701 }
2702
2703 /*
2704 * Common routine to set ownership given a vnode.
2705 */
2706 static int
2707 change_owner(vp, uid, gid, l, posix_semantics)
2708 struct vnode *vp;
2709 uid_t uid;
2710 gid_t gid;
2711 struct lwp *l;
2712 int posix_semantics;
2713 {
2714 struct proc *p = l->l_proc;
2715 struct mount *mp;
2716 struct vattr vattr;
2717 mode_t newmode;
2718 int error;
2719
2720 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2721 return (error);
2722 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2723 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2724 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, l)) != 0)
2725 goto out;
2726
2727 #define CHANGED(x) ((int)(x) != -1)
2728 newmode = vattr.va_mode;
2729 if (posix_semantics) {
2730 /*
2731 * POSIX/XPG semantics: if the caller is not the super-user,
2732 * clear set-user-id and set-group-id bits. Both POSIX and
2733 * the XPG consider the behaviour for calls by the super-user
2734 * implementation-defined; we leave the set-user-id and set-
2735 * group-id settings intact in that case.
2736 */
2737 if (suser(p->p_ucred, NULL) != 0)
2738 newmode &= ~(S_ISUID | S_ISGID);
2739 } else {
2740 /*
2741 * NetBSD semantics: when changing owner and/or group,
2742 * clear the respective bit(s).
2743 */
2744 if (CHANGED(uid))
2745 newmode &= ~S_ISUID;
2746 if (CHANGED(gid))
2747 newmode &= ~S_ISGID;
2748 }
2749 /* Update va_mode iff altered. */
2750 if (vattr.va_mode == newmode)
2751 newmode = VNOVAL;
2752
2753 VATTR_NULL(&vattr);
2754 vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
2755 vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
2756 vattr.va_mode = newmode;
2757 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l);
2758 #undef CHANGED
2759
2760 out:
2761 VOP_UNLOCK(vp, 0);
2762 vn_finished_write(mp, 0);
2763 return (error);
2764 }
2765
2766 /*
2767 * Set the access and modification times given a path name; this
2768 * version follows links.
2769 */
2770 /* ARGSUSED */
2771 int
2772 sys_utimes(l, v, retval)
2773 struct lwp *l;
2774 void *v;
2775 register_t *retval;
2776 {
2777 struct sys_utimes_args /* {
2778 syscallarg(const char *) path;
2779 syscallarg(const struct timeval *) tptr;
2780 } */ *uap = v;
2781 int error;
2782 struct nameidata nd;
2783
2784 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2785 if ((error = namei(&nd)) != 0)
2786 return (error);
2787
2788 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), l);
2789
2790 vrele(nd.ni_vp);
2791 return (error);
2792 }
2793
2794 /*
2795 * Set the access and modification times given a file descriptor.
2796 */
2797 /* ARGSUSED */
2798 int
2799 sys_futimes(l, v, retval)
2800 struct lwp *l;
2801 void *v;
2802 register_t *retval;
2803 {
2804 struct sys_futimes_args /* {
2805 syscallarg(int) fd;
2806 syscallarg(const struct timeval *) tptr;
2807 } */ *uap = v;
2808 struct proc *p = l->l_proc;
2809 int error;
2810 struct file *fp;
2811
2812 /* getvnode() will use the descriptor for us */
2813 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2814 return (error);
2815
2816 error = change_utimes((struct vnode *)fp->f_data, SCARG(uap, tptr), l);
2817 FILE_UNUSE(fp, l);
2818 return (error);
2819 }
2820
2821 /*
2822 * Set the access and modification times given a path name; this
2823 * version does not follow links.
2824 */
2825 /* ARGSUSED */
2826 int
2827 sys_lutimes(l, v, retval)
2828 struct lwp *l;
2829 void *v;
2830 register_t *retval;
2831 {
2832 struct sys_lutimes_args /* {
2833 syscallarg(const char *) path;
2834 syscallarg(const struct timeval *) tptr;
2835 } */ *uap = v;
2836 int error;
2837 struct nameidata nd;
2838
2839 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2840 if ((error = namei(&nd)) != 0)
2841 return (error);
2842
2843 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), l);
2844
2845 vrele(nd.ni_vp);
2846 return (error);
2847 }
2848
2849 /*
2850 * Common routine to set access and modification times given a vnode.
2851 */
2852 static int
2853 change_utimes(vp, tptr, l)
2854 struct vnode *vp;
2855 const struct timeval *tptr;
2856 struct lwp *l;
2857 {
2858 struct proc *p = l->l_proc;
2859 struct timeval tv[2];
2860 struct mount *mp;
2861 struct vattr vattr;
2862 int error;
2863
2864 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2865 return (error);
2866 VATTR_NULL(&vattr);
2867 if (tptr == NULL) {
2868 microtime(&tv[0]);
2869 tv[1] = tv[0];
2870 vattr.va_vaflags |= VA_UTIMES_NULL;
2871 } else {
2872 error = copyin(tptr, tv, sizeof(tv));
2873 if (error)
2874 goto out;
2875 }
2876 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2877 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2878 vattr.va_atime.tv_sec = tv[0].tv_sec;
2879 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
2880 vattr.va_mtime.tv_sec = tv[1].tv_sec;
2881 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
2882 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l);
2883 VOP_UNLOCK(vp, 0);
2884 out:
2885 vn_finished_write(mp, 0);
2886 return (error);
2887 }
2888
2889 /*
2890 * Truncate a file given its path name.
2891 */
2892 /* ARGSUSED */
2893 int
2894 sys_truncate(l, v, retval)
2895 struct lwp *l;
2896 void *v;
2897 register_t *retval;
2898 {
2899 struct sys_truncate_args /* {
2900 syscallarg(const char *) path;
2901 syscallarg(int) pad;
2902 syscallarg(off_t) length;
2903 } */ *uap = v;
2904 struct proc *p = l->l_proc;
2905 struct vnode *vp;
2906 struct mount *mp;
2907 struct vattr vattr;
2908 int error;
2909 struct nameidata nd;
2910
2911 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
2912 if ((error = namei(&nd)) != 0)
2913 return (error);
2914 vp = nd.ni_vp;
2915 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
2916 vrele(vp);
2917 return (error);
2918 }
2919 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2920 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2921 if (vp->v_type == VDIR)
2922 error = EISDIR;
2923 else if ((error = vn_writechk(vp)) == 0 &&
2924 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, l)) == 0) {
2925 VATTR_NULL(&vattr);
2926 vattr.va_size = SCARG(uap, length);
2927 error = VOP_SETATTR(vp, &vattr, p->p_ucred, l);
2928 }
2929 vput(vp);
2930 vn_finished_write(mp, 0);
2931 return (error);
2932 }
2933
2934 /*
2935 * Truncate a file given a file descriptor.
2936 */
2937 /* ARGSUSED */
2938 int
2939 sys_ftruncate(l, v, retval)
2940 struct lwp *l;
2941 void *v;
2942 register_t *retval;
2943 {
2944 struct sys_ftruncate_args /* {
2945 syscallarg(int) fd;
2946 syscallarg(int) pad;
2947 syscallarg(off_t) length;
2948 } */ *uap = v;
2949 struct proc *p = l->l_proc;
2950 struct mount *mp;
2951 struct vattr vattr;
2952 struct vnode *vp;
2953 struct file *fp;
2954 int error;
2955
2956 /* getvnode() will use the descriptor for us */
2957 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2958 return (error);
2959 if ((fp->f_flag & FWRITE) == 0) {
2960 error = EINVAL;
2961 goto out;
2962 }
2963 vp = (struct vnode *)fp->f_data;
2964 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
2965 FILE_UNUSE(fp, l);
2966 return (error);
2967 }
2968 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
2969 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2970 if (vp->v_type == VDIR)
2971 error = EISDIR;
2972 else if ((error = vn_writechk(vp)) == 0) {
2973 VATTR_NULL(&vattr);
2974 vattr.va_size = SCARG(uap, length);
2975 error = VOP_SETATTR(vp, &vattr, fp->f_cred, l);
2976 }
2977 VOP_UNLOCK(vp, 0);
2978 vn_finished_write(mp, 0);
2979 out:
2980 FILE_UNUSE(fp, l);
2981 return (error);
2982 }
2983
2984 /*
2985 * Sync an open file.
2986 */
2987 /* ARGSUSED */
2988 int
2989 sys_fsync(l, v, retval)
2990 struct lwp *l;
2991 void *v;
2992 register_t *retval;
2993 {
2994 struct sys_fsync_args /* {
2995 syscallarg(int) fd;
2996 } */ *uap = v;
2997 struct proc *p = l->l_proc;
2998 struct vnode *vp;
2999 struct mount *mp;
3000 struct file *fp;
3001 int error;
3002
3003 /* getvnode() will use the descriptor for us */
3004 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3005 return (error);
3006 vp = (struct vnode *)fp->f_data;
3007 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
3008 FILE_UNUSE(fp, l);
3009 return (error);
3010 }
3011 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3012 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0, l);
3013 if (error == 0 && bioops.io_fsync != NULL &&
3014 vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
3015 (*bioops.io_fsync)(vp);
3016 VOP_UNLOCK(vp, 0);
3017 vn_finished_write(mp, 0);
3018 FILE_UNUSE(fp, l);
3019 return (error);
3020 }
3021
3022 /*
3023 * Sync a range of file data. API modeled after that found in AIX.
3024 *
3025 * FDATASYNC indicates that we need only save enough metadata to be able
3026 * to re-read the written data. Note we duplicate AIX's requirement that
3027 * the file be open for writing.
3028 */
3029 /* ARGSUSED */
3030 int
3031 sys_fsync_range(l, v, retval)
3032 struct lwp *l;
3033 void *v;
3034 register_t *retval;
3035 {
3036 struct sys_fsync_range_args /* {
3037 syscallarg(int) fd;
3038 syscallarg(int) flags;
3039 syscallarg(off_t) start;
3040 syscallarg(int) length;
3041 } */ *uap = v;
3042 struct proc *p = l->l_proc;
3043 struct vnode *vp;
3044 struct file *fp;
3045 int flags, nflags;
3046 off_t s, e, len;
3047 int error;
3048
3049 /* getvnode() will use the descriptor for us */
3050 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3051 return (error);
3052
3053 if ((fp->f_flag & FWRITE) == 0) {
3054 FILE_UNUSE(fp, l);
3055 return (EBADF);
3056 }
3057
3058 flags = SCARG(uap, flags);
3059 if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
3060 ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
3061 return (EINVAL);
3062 }
3063 /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
3064 if (flags & FDATASYNC)
3065 nflags = FSYNC_DATAONLY | FSYNC_WAIT;
3066 else
3067 nflags = FSYNC_WAIT;
3068
3069 len = SCARG(uap, length);
3070 /* If length == 0, we do the whole file, and s = l = 0 will do that */
3071 if (len) {
3072 s = SCARG(uap, start);
3073 e = s + len;
3074 if (e < s) {
3075 FILE_UNUSE(fp, l);
3076 return (EINVAL);
3077 }
3078 } else {
3079 e = 0;
3080 s = 0;
3081 }
3082
3083 vp = (struct vnode *)fp->f_data;
3084 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3085 error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e, l);
3086
3087 if (error == 0 && bioops.io_fsync != NULL &&
3088 vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
3089 (*bioops.io_fsync)(vp);
3090
3091 VOP_UNLOCK(vp, 0);
3092 FILE_UNUSE(fp, l);
3093 return (error);
3094 }
3095
3096 /*
3097 * Sync the data of an open file.
3098 */
3099 /* ARGSUSED */
3100 int
3101 sys_fdatasync(l, v, retval)
3102 struct lwp *l;
3103 void *v;
3104 register_t *retval;
3105 {
3106 struct sys_fdatasync_args /* {
3107 syscallarg(int) fd;
3108 } */ *uap = v;
3109 struct proc *p = l->l_proc;
3110 struct vnode *vp;
3111 struct file *fp;
3112 int error;
3113
3114 /* getvnode() will use the descriptor for us */
3115 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3116 return (error);
3117 if ((fp->f_flag & FWRITE) == 0) {
3118 FILE_UNUSE(fp, l);
3119 return (EBADF);
3120 }
3121 vp = (struct vnode *)fp->f_data;
3122 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3123 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0, l);
3124 VOP_UNLOCK(vp, 0);
3125 FILE_UNUSE(fp, l);
3126 return (error);
3127 }
3128
3129 /*
3130 * Rename files, (standard) BSD semantics frontend.
3131 */
3132 /* ARGSUSED */
3133 int
3134 sys_rename(l, v, retval)
3135 struct lwp *l;
3136 void *v;
3137 register_t *retval;
3138 {
3139 struct sys_rename_args /* {
3140 syscallarg(const char *) from;
3141 syscallarg(const char *) to;
3142 } */ *uap = v;
3143
3144 return (rename_files(SCARG(uap, from), SCARG(uap, to), l, 0));
3145 }
3146
3147 /*
3148 * Rename files, POSIX semantics frontend.
3149 */
3150 /* ARGSUSED */
3151 int
3152 sys___posix_rename(l, v, retval)
3153 struct lwp *l;
3154 void *v;
3155 register_t *retval;
3156 {
3157 struct sys___posix_rename_args /* {
3158 syscallarg(const char *) from;
3159 syscallarg(const char *) to;
3160 } */ *uap = v;
3161
3162 return (rename_files(SCARG(uap, from), SCARG(uap, to), l, 1));
3163 }
3164
3165 /*
3166 * Rename files. Source and destination must either both be directories,
3167 * or both not be directories. If target is a directory, it must be empty.
3168 * If `from' and `to' refer to the same object, the value of the `retain'
3169 * argument is used to determine whether `from' will be
3170 *
3171 * (retain == 0) deleted unless `from' and `to' refer to the same
3172 * object in the file system's name space (BSD).
3173 * (retain == 1) always retained (POSIX).
3174 */
3175 static int
3176 rename_files(from, to, l, retain)
3177 const char *from, *to;
3178 struct lwp *l;
3179 int retain;
3180 {
3181 struct mount *mp = NULL;
3182 struct vnode *tvp, *fvp, *tdvp;
3183 struct nameidata fromnd, tond;
3184 struct proc *p;
3185 int error;
3186
3187 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
3188 from, l);
3189 if ((error = namei(&fromnd)) != 0)
3190 return (error);
3191 fvp = fromnd.ni_vp;
3192 error = vn_start_write(fvp, &mp, V_WAIT | V_PCATCH);
3193 if (error != 0) {
3194 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3195 vrele(fromnd.ni_dvp);
3196 vrele(fvp);
3197 if (fromnd.ni_startdir)
3198 vrele(fromnd.ni_startdir);
3199 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
3200 return (error);
3201 }
3202 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
3203 (fvp->v_type == VDIR ? CREATEDIR : 0), UIO_USERSPACE, to, l);
3204 if ((error = namei(&tond)) != 0) {
3205 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3206 vrele(fromnd.ni_dvp);
3207 vrele(fvp);
3208 goto out1;
3209 }
3210 tdvp = tond.ni_dvp;
3211 tvp = tond.ni_vp;
3212
3213 if (tvp != NULL) {
3214 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3215 error = ENOTDIR;
3216 goto out;
3217 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3218 error = EISDIR;
3219 goto out;
3220 }
3221 }
3222
3223 if (fvp == tdvp)
3224 error = EINVAL;
3225
3226 /*
3227 * Source and destination refer to the same object.
3228 */
3229 if (fvp == tvp) {
3230 if (retain)
3231 error = -1;
3232 else if (fromnd.ni_dvp == tdvp &&
3233 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
3234 !memcmp(fromnd.ni_cnd.cn_nameptr,
3235 tond.ni_cnd.cn_nameptr,
3236 fromnd.ni_cnd.cn_namelen))
3237 error = -1;
3238 }
3239
3240 out:
3241 p = l->l_proc;
3242 if (!error) {
3243 VOP_LEASE(tdvp, l, p->p_ucred, LEASE_WRITE);
3244 if (fromnd.ni_dvp != tdvp)
3245 VOP_LEASE(fromnd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
3246 if (tvp) {
3247 VOP_LEASE(tvp, l, p->p_ucred, LEASE_WRITE);
3248 }
3249 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3250 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3251 } else {
3252 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
3253 if (tdvp == tvp)
3254 vrele(tdvp);
3255 else
3256 vput(tdvp);
3257 if (tvp)
3258 vput(tvp);
3259 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3260 vrele(fromnd.ni_dvp);
3261 vrele(fvp);
3262 }
3263 vrele(tond.ni_startdir);
3264 PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
3265 out1:
3266 vn_finished_write(mp, 0);
3267 if (fromnd.ni_startdir)
3268 vrele(fromnd.ni_startdir);
3269 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
3270 return (error == -1 ? 0 : error);
3271 }
3272
3273 /*
3274 * Make a directory file.
3275 */
3276 /* ARGSUSED */
3277 int
3278 sys_mkdir(l, v, retval)
3279 struct lwp *l;
3280 void *v;
3281 register_t *retval;
3282 {
3283 struct sys_mkdir_args /* {
3284 syscallarg(const char *) path;
3285 syscallarg(int) mode;
3286 } */ *uap = v;
3287 struct proc *p = l->l_proc;
3288 struct mount *mp;
3289 struct vnode *vp;
3290 struct vattr vattr;
3291 int error;
3292 struct nameidata nd;
3293
3294 restart:
3295 NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR, UIO_USERSPACE,
3296 SCARG(uap, path), l);
3297 if ((error = namei(&nd)) != 0)
3298 return (error);
3299 vp = nd.ni_vp;
3300 if (vp != NULL) {
3301 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3302 if (nd.ni_dvp == vp)
3303 vrele(nd.ni_dvp);
3304 else
3305 vput(nd.ni_dvp);
3306 vrele(vp);
3307 return (EEXIST);
3308 }
3309 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3310 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3311 if (nd.ni_dvp == vp)
3312 vrele(nd.ni_dvp);
3313 else
3314 vput(nd.ni_dvp);
3315 if ((error = vn_start_write(NULL, &mp,
3316 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3317 return (error);
3318 goto restart;
3319 }
3320 VATTR_NULL(&vattr);
3321 vattr.va_type = VDIR;
3322 vattr.va_mode =
3323 (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
3324 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
3325 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3326 if (!error)
3327 vput(nd.ni_vp);
3328 vn_finished_write(mp, 0);
3329 return (error);
3330 }
3331
3332 /*
3333 * Remove a directory file.
3334 */
3335 /* ARGSUSED */
3336 int
3337 sys_rmdir(l, v, retval)
3338 struct lwp *l;
3339 void *v;
3340 register_t *retval;
3341 {
3342 struct sys_rmdir_args /* {
3343 syscallarg(const char *) path;
3344 } */ *uap = v;
3345 struct proc *p = l->l_proc;
3346 struct mount *mp;
3347 struct vnode *vp;
3348 int error;
3349 struct nameidata nd;
3350
3351 restart:
3352 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
3353 SCARG(uap, path), l);
3354 if ((error = namei(&nd)) != 0)
3355 return (error);
3356 vp = nd.ni_vp;
3357 if (vp->v_type != VDIR) {
3358 error = ENOTDIR;
3359 goto out;
3360 }
3361 /*
3362 * No rmdir "." please.
3363 */
3364 if (nd.ni_dvp == vp) {
3365 error = EINVAL;
3366 goto out;
3367 }
3368 /*
3369 * The root of a mounted filesystem cannot be deleted.
3370 */
3371 if (vp->v_flag & VROOT) {
3372 error = EBUSY;
3373 goto out;
3374 }
3375 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3376 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3377 if (nd.ni_dvp == vp)
3378 vrele(nd.ni_dvp);
3379 else
3380 vput(nd.ni_dvp);
3381 vput(vp);
3382 if ((error = vn_start_write(NULL, &mp,
3383 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3384 return (error);
3385 goto restart;
3386 }
3387 VOP_LEASE(nd.ni_dvp, l, p->p_ucred, LEASE_WRITE);
3388 VOP_LEASE(vp, l, p->p_ucred, LEASE_WRITE);
3389 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3390 vn_finished_write(mp, 0);
3391 return (error);
3392
3393 out:
3394 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3395 if (nd.ni_dvp == vp)
3396 vrele(nd.ni_dvp);
3397 else
3398 vput(nd.ni_dvp);
3399 vput(vp);
3400 return (error);
3401 }
3402
3403 /*
3404 * Read a block of directory entries in a file system independent format.
3405 */
3406 int
3407 sys_getdents(l, v, retval)
3408 struct lwp *l;
3409 void *v;
3410 register_t *retval;
3411 {
3412 struct sys_getdents_args /* {
3413 syscallarg(int) fd;
3414 syscallarg(char *) buf;
3415 syscallarg(size_t) count;
3416 } */ *uap = v;
3417 struct proc *p = l->l_proc;
3418 struct file *fp;
3419 int error, done;
3420
3421 /* getvnode() will use the descriptor for us */
3422 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3423 return (error);
3424 if ((fp->f_flag & FREAD) == 0) {
3425 error = EBADF;
3426 goto out;
3427 }
3428 error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
3429 SCARG(uap, count), &done, l, 0, 0);
3430 #ifdef KTRACE
3431 if (!error && KTRPOINT(p, KTR_GENIO)) {
3432 struct iovec iov;
3433 iov.iov_base = SCARG(uap, buf);
3434 iov.iov_len = done;
3435 ktrgenio(l, SCARG(uap, fd), UIO_READ, &iov, done, 0);
3436 }
3437 #endif
3438 *retval = done;
3439 out:
3440 FILE_UNUSE(fp, l);
3441 return (error);
3442 }
3443
3444 /*
3445 * Set the mode mask for creation of filesystem nodes.
3446 */
3447 int
3448 sys_umask(l, v, retval)
3449 struct lwp *l;
3450 void *v;
3451 register_t *retval;
3452 {
3453 struct sys_umask_args /* {
3454 syscallarg(mode_t) newmask;
3455 } */ *uap = v;
3456 struct proc *p = l->l_proc;
3457 struct cwdinfo *cwdi;
3458
3459 cwdi = p->p_cwdi;
3460 *retval = cwdi->cwdi_cmask;
3461 cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
3462 return (0);
3463 }
3464
3465 /*
3466 * Void all references to file by ripping underlying filesystem
3467 * away from vnode.
3468 */
3469 /* ARGSUSED */
3470 int
3471 sys_revoke(l, v, retval)
3472 struct lwp *l;
3473 void *v;
3474 register_t *retval;
3475 {
3476 struct sys_revoke_args /* {
3477 syscallarg(const char *) path;
3478 } */ *uap = v;
3479 struct proc *p = l->l_proc;
3480 struct mount *mp;
3481 struct vnode *vp;
3482 struct vattr vattr;
3483 int error;
3484 struct nameidata nd;
3485
3486 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3487 if ((error = namei(&nd)) != 0)
3488 return (error);
3489 vp = nd.ni_vp;
3490 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, l)) != 0)
3491 goto out;
3492 if (p->p_ucred->cr_uid != vattr.va_uid &&
3493 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
3494 goto out;
3495 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
3496 goto out;
3497 if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER)))
3498 VOP_REVOKE(vp, REVOKEALL);
3499 vn_finished_write(mp, 0);
3500 out:
3501 vrele(vp);
3502 return (error);
3503 }
3504
3505 /*
3506 * Convert a user file descriptor to a kernel file entry.
3507 */
3508 int
3509 getvnode(fdp, fd, fpp)
3510 struct filedesc *fdp;
3511 int fd;
3512 struct file **fpp;
3513 {
3514 struct vnode *vp;
3515 struct file *fp;
3516
3517 if ((fp = fd_getfile(fdp, fd)) == NULL)
3518 return (EBADF);
3519
3520 FILE_USE(fp);
3521
3522 if (fp->f_type != DTYPE_VNODE) {
3523 FILE_UNUSE(fp, NULL);
3524 return (EINVAL);
3525 }
3526
3527 vp = (struct vnode *)fp->f_data;
3528 if (vp->v_type == VBAD) {
3529 FILE_UNUSE(fp, NULL);
3530 return (EBADF);
3531 }
3532
3533 *fpp = fp;
3534 return (0);
3535 }
3536
3537 /*
3538 * Push extended attribute configuration information into the VFS.
3539 *
3540 * NOTE: Not all file systems that support extended attributes will
3541 * require the use of this system call.
3542 */
3543 int
3544 sys_extattrctl(struct lwp *l, void *v, register_t *retval)
3545 {
3546 struct sys_extattrctl_args /* {
3547 syscallarg(const char *) path;
3548 syscallarg(int) cmd;
3549 syscallarg(const char *) filename;
3550 syscallarg(int) attrnamespace;
3551 syscallarg(const char *) attrname;
3552 } */ *uap = v;
3553 struct vnode *vp;
3554 struct nameidata nd;
3555 struct mount *mp;
3556 char attrname[EXTATTR_MAXNAMELEN];
3557 int error;
3558
3559 if (SCARG(uap, attrname) != NULL) {
3560 error = copyinstr(SCARG(uap, attrname), attrname,
3561 sizeof(attrname), NULL);
3562 if (error)
3563 return (error);
3564 }
3565
3566 vp = NULL;
3567 if (SCARG(uap, filename) != NULL) {
3568 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3569 SCARG(uap, filename), l);
3570 error = namei(&nd);
3571 if (error)
3572 return (error);
3573 vp = nd.ni_vp;
3574 }
3575
3576 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3577 error = namei(&nd);
3578 if (error) {
3579 if (vp != NULL)
3580 vput(vp);
3581 return (error);
3582 }
3583
3584 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
3585 if (error) {
3586 if (vp != NULL)
3587 vput(vp);
3588 return (error);
3589 }
3590
3591 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), vp,
3592 SCARG(uap, attrnamespace),
3593 SCARG(uap, attrname) != NULL ? attrname : NULL, l);
3594
3595 vn_finished_write(mp, 0);
3596
3597 if (vp != NULL)
3598 vrele(vp);
3599
3600 return (error);
3601 }
3602
3603 /*
3604 * Set a named extended attribute on a file or directory.
3605 */
3606 static int
3607 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3608 const void *data, size_t nbytes, struct lwp *l, register_t *retval)
3609 {
3610 struct mount *mp;
3611 struct uio auio;
3612 struct iovec aiov;
3613 ssize_t cnt;
3614 int error;
3615
3616 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
3617 if (error)
3618 return (error);
3619 VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_WRITE);
3620 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3621
3622 aiov.iov_base = (caddr_t) data; /* XXX kills const */
3623 aiov.iov_len = nbytes;
3624 auio.uio_iov = &aiov;
3625 auio.uio_iovcnt = 1;
3626 auio.uio_offset = 0;
3627 if (nbytes > INT_MAX) {
3628 error = EINVAL;
3629 goto done;
3630 }
3631 auio.uio_resid = nbytes;
3632 auio.uio_rw = UIO_WRITE;
3633 auio.uio_segflg = UIO_USERSPACE;
3634 auio.uio_lwp = l;
3635 cnt = nbytes;
3636
3637 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3638 l->l_proc->p_ucred, l);
3639 cnt -= auio.uio_resid;
3640 retval[0] = cnt;
3641
3642 done:
3643 VOP_UNLOCK(vp, 0);
3644 vn_finished_write(mp, 0);
3645 return (error);
3646 }
3647
3648 int
3649 sys_extattr_set_fd(struct lwp *l, void *v, register_t *retval)
3650 {
3651 struct sys_extattr_set_fd_args /* {
3652 syscallarg(int) fd;
3653 syscallarg(int) attrnamespace;
3654 syscallarg(const char *) attrname;
3655 syscallarg(const void *) data;
3656 syscallarg(size_t) nbytes;
3657 } */ *uap = v;
3658 struct file *fp;
3659 struct vnode *vp;
3660 char attrname[EXTATTR_MAXNAMELEN];
3661 int error;
3662
3663 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3664 NULL);
3665 if (error)
3666 return (error);
3667
3668 error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
3669 if (error)
3670 return (error);
3671 vp = (struct vnode *) fp->f_data;
3672
3673 error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
3674 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3675
3676 FILE_UNUSE(fp, l);
3677 return (error);
3678 }
3679
3680 int
3681 sys_extattr_set_file(struct lwp *l, void *v, register_t *retval)
3682 {
3683 struct sys_extattr_set_file_args /* {
3684 syscallarg(const char *) path;
3685 syscallarg(int) attrnamespace;
3686 syscallarg(const char *) attrname;
3687 syscallarg(const void *) data;
3688 syscallarg(size_t) nbytes;
3689 } */ *uap = v;
3690 struct nameidata nd;
3691 char attrname[EXTATTR_MAXNAMELEN];
3692 int error;
3693
3694 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3695 NULL);
3696 if (error)
3697 return (error);
3698
3699 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3700 error = namei(&nd);
3701 if (error)
3702 return (error);
3703
3704 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3705 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3706
3707 vrele(nd.ni_vp);
3708 return (error);
3709 }
3710
3711 int
3712 sys_extattr_set_link(struct lwp *l, void *v, register_t *retval)
3713 {
3714 struct sys_extattr_set_link_args /* {
3715 syscallarg(const char *) path;
3716 syscallarg(int) attrnamespace;
3717 syscallarg(const char *) attrname;
3718 syscallarg(const void *) data;
3719 syscallarg(size_t) nbytes;
3720 } */ *uap = v;
3721 struct nameidata nd;
3722 char attrname[EXTATTR_MAXNAMELEN];
3723 int error;
3724
3725 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3726 NULL);
3727 if (error)
3728 return (error);
3729
3730 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3731 error = namei(&nd);
3732 if (error)
3733 return (error);
3734
3735 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3736 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3737
3738 vrele(nd.ni_vp);
3739 return (error);
3740 }
3741
3742 /*
3743 * Get a named extended attribute on a file or directory.
3744 */
3745 static int
3746 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3747 void *data, size_t nbytes, struct lwp *l, register_t *retval)
3748 {
3749 struct uio auio, *auiop;
3750 struct iovec aiov;
3751 ssize_t cnt;
3752 size_t size, *sizep;
3753 int error;
3754
3755 VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_READ);
3756 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3757
3758 /*
3759 * Slightly unusual semantics: if the user provides a NULL data
3760 * pointer, they don't want to receive the data, just the maximum
3761 * read length.
3762 */
3763 auiop = NULL;
3764 sizep = NULL;
3765 cnt = 0;
3766 if (data != NULL) {
3767 aiov.iov_base = data;
3768 aiov.iov_len = nbytes;
3769 auio.uio_iov = &aiov;
3770 auio.uio_offset = 0;
3771 if (nbytes > INT_MAX) {
3772 error = EINVAL;
3773 goto done;
3774 }
3775 auio.uio_resid = nbytes;
3776 auio.uio_rw = UIO_READ;
3777 auio.uio_segflg = UIO_USERSPACE;
3778 auio.uio_lwp = l;
3779 auiop = &auio;
3780 cnt = nbytes;
3781 } else
3782 sizep = &size;
3783
3784 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
3785 l->l_proc->p_ucred, l);
3786
3787 if (auiop != NULL) {
3788 cnt -= auio.uio_resid;
3789 retval[0] = cnt;
3790 } else
3791 retval[0] = size;
3792
3793 done:
3794 VOP_UNLOCK(vp, 0);
3795 return (error);
3796 }
3797
3798 int
3799 sys_extattr_get_fd(struct lwp *l, void *v, register_t *retval)
3800 {
3801 struct sys_extattr_get_fd_args /* {
3802 syscallarg(int) fd;
3803 syscallarg(int) attrnamespace;
3804 syscallarg(const char *) attrname;
3805 syscallarg(void *) data;
3806 syscallarg(size_t) nbytes;
3807 } */ *uap = v;
3808 struct file *fp;
3809 struct vnode *vp;
3810 char attrname[EXTATTR_MAXNAMELEN];
3811 int error;
3812
3813 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3814 NULL);
3815 if (error)
3816 return (error);
3817
3818 error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
3819 if (error)
3820 return (error);
3821 vp = (struct vnode *) fp->f_data;
3822
3823 error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
3824 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3825
3826 FILE_UNUSE(fp, l);
3827 return (error);
3828 }
3829
3830 int
3831 sys_extattr_get_file(struct lwp *l, void *v, register_t *retval)
3832 {
3833 struct sys_extattr_get_file_args /* {
3834 syscallarg(const char *) path;
3835 syscallarg(int) attrnamespace;
3836 syscallarg(const char *) attrname;
3837 syscallarg(void *) data;
3838 syscallarg(size_t) nbytes;
3839 } */ *uap = v;
3840 struct nameidata nd;
3841 char attrname[EXTATTR_MAXNAMELEN];
3842 int error;
3843
3844 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3845 NULL);
3846 if (error)
3847 return (error);
3848
3849 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3850 error = namei(&nd);
3851 if (error)
3852 return (error);
3853
3854 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3855 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3856
3857 vrele(nd.ni_vp);
3858 return (error);
3859 }
3860
3861 int
3862 sys_extattr_get_link(struct lwp *l, void *v, register_t *retval)
3863 {
3864 struct sys_extattr_get_link_args /* {
3865 syscallarg(const char *) path;
3866 syscallarg(int) attrnamespace;
3867 syscallarg(const char *) attrname;
3868 syscallarg(void *) data;
3869 syscallarg(size_t) nbytes;
3870 } */ *uap = v;
3871 struct nameidata nd;
3872 char attrname[EXTATTR_MAXNAMELEN];
3873 int error;
3874
3875 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3876 NULL);
3877 if (error)
3878 return (error);
3879
3880 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3881 error = namei(&nd);
3882 if (error)
3883 return (error);
3884
3885 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3886 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
3887
3888 vrele(nd.ni_vp);
3889 return (error);
3890 }
3891
3892 /*
3893 * Delete a named extended attribute on a file or directory.
3894 */
3895 static int
3896 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3897 struct lwp *l)
3898 {
3899 struct mount *mp;
3900 int error;
3901
3902 error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
3903 if (error)
3904 return (error);
3905 VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_WRITE);
3906 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3907
3908 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname,
3909 l->l_proc->p_ucred, l);
3910 if (error == EOPNOTSUPP)
3911 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
3912 l->l_proc->p_ucred, l);
3913
3914 VOP_UNLOCK(vp, 0);
3915 vn_finished_write(mp, 0);
3916 return (error);
3917 }
3918
3919 int
3920 sys_extattr_delete_fd(struct lwp *l, void *v, register_t *retval)
3921 {
3922 struct sys_extattr_delete_fd_args /* {
3923 syscallarg(int) fd;
3924 syscallarg(int) attrnamespace;
3925 syscallarg(const char *) attrname;
3926 } */ *uap = v;
3927 struct file *fp;
3928 struct vnode *vp;
3929 char attrname[EXTATTR_MAXNAMELEN];
3930 int error;
3931
3932 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3933 NULL);
3934 if (error)
3935 return (error);
3936
3937 error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
3938 if (error)
3939 return (error);
3940 vp = (struct vnode *) fp->f_data;
3941
3942 error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
3943
3944 FILE_UNUSE(fp, l);
3945 return (error);
3946 }
3947
3948 int
3949 sys_extattr_delete_file(struct lwp *l, void *v, register_t *retval)
3950 {
3951 struct sys_extattr_delete_file_args /* {
3952 syscallarg(const char *) path;
3953 syscallarg(int) attrnamespace;
3954 syscallarg(const char *) attrname;
3955 } */ *uap = v;
3956 struct nameidata nd;
3957 char attrname[EXTATTR_MAXNAMELEN];
3958 int error;
3959
3960 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3961 NULL);
3962 if (error)
3963 return (error);
3964
3965 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3966 error = namei(&nd);
3967 if (error)
3968 return (error);
3969
3970 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3971 l);
3972
3973 vrele(nd.ni_vp);
3974 return (error);
3975 }
3976
3977 int
3978 sys_extattr_delete_link(struct lwp *l, void *v, register_t *retval)
3979 {
3980 struct sys_extattr_delete_link_args /* {
3981 syscallarg(const char *) path;
3982 syscallarg(int) attrnamespace;
3983 syscallarg(const char *) attrname;
3984 } */ *uap = v;
3985 struct nameidata nd;
3986 char attrname[EXTATTR_MAXNAMELEN];
3987 int error;
3988
3989 error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
3990 NULL);
3991 if (error)
3992 return (error);
3993
3994 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
3995 error = namei(&nd);
3996 if (error)
3997 return (error);
3998
3999 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
4000 l);
4001
4002 vrele(nd.ni_vp);
4003 return (error);
4004 }
4005
4006 /*
4007 * Retrieve a list of extended attributes on a file or directory.
4008 */
4009 static int
4010 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
4011 struct lwp *l, register_t *retval)
4012 {
4013 struct uio auio, *auiop;
4014 size_t size, *sizep;
4015 struct iovec aiov;
4016 ssize_t cnt;
4017 int error;
4018
4019 VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_READ);
4020 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
4021
4022 auiop = NULL;
4023 sizep = NULL;
4024 cnt = 0;
4025 if (data != NULL) {
4026 aiov.iov_base = data;
4027 aiov.iov_len = nbytes;
4028 auio.uio_iov = &aiov;
4029 auio.uio_offset = 0;
4030 if (nbytes > INT_MAX) {
4031 error = EINVAL;
4032 goto done;
4033 }
4034 auio.uio_resid = nbytes;
4035 auio.uio_rw = UIO_READ;
4036 auio.uio_segflg = UIO_USERSPACE;
4037 auio.uio_lwp = l;
4038 auiop = &auio;
4039 cnt = nbytes;
4040 } else
4041 sizep = &size;
4042
4043 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
4044 l->l_proc->p_ucred, l);
4045
4046 if (auiop != NULL) {
4047 cnt -= auio.uio_resid;
4048 retval[0] = cnt;
4049 } else
4050 retval[0] = size;
4051
4052 done:
4053 VOP_UNLOCK(vp, 0);
4054 return (error);
4055 }
4056
4057 int
4058 sys_extattr_list_fd(struct lwp *l, void *v, register_t *retval)
4059 {
4060 struct sys_extattr_list_fd_args /* {
4061 syscallarg(int) fd;
4062 syscallarg(int) attrnamespace;
4063 syscallarg(void *) data;
4064 syscallarg(size_t) nbytes;
4065 } */ *uap = v;
4066 struct file *fp;
4067 struct vnode *vp;
4068 int error;
4069
4070 error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
4071 if (error)
4072 return (error);
4073 vp = (struct vnode *) fp->f_data;
4074
4075 error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
4076 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
4077
4078 FILE_UNUSE(fp, l);
4079 return (error);
4080 }
4081
4082 int
4083 sys_extattr_list_file(struct lwp *l, void *v, register_t *retval)
4084 {
4085 struct sys_extattr_list_file_args /* {
4086 syscallarg(const char *) path;
4087 syscallarg(int) attrnamespace;
4088 syscallarg(void *) data;
4089 syscallarg(size_t) nbytes;
4090 } */ *uap = v;
4091 struct nameidata nd;
4092 int error;
4093
4094 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
4095 error = namei(&nd);
4096 if (error)
4097 return (error);
4098
4099 error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
4100 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
4101
4102 vrele(nd.ni_vp);
4103 return (error);
4104 }
4105
4106 int
4107 sys_extattr_list_link(struct lwp *l, void *v, register_t *retval)
4108 {
4109 struct sys_extattr_list_link_args /* {
4110 syscallarg(const char *) path;
4111 syscallarg(int) attrnamespace;
4112 syscallarg(void *) data;
4113 syscallarg(size_t) nbytes;
4114 } */ *uap = v;
4115 struct nameidata nd;
4116 int error;
4117
4118 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
4119 error = namei(&nd);
4120 if (error)
4121 return (error);
4122
4123 error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
4124 SCARG(uap, data), SCARG(uap, nbytes), l, retval);
4125
4126 vrele(nd.ni_vp);
4127 return (error);
4128 }
4129