vfs_syscalls.c revision 1.203 1 /* $NetBSD: vfs_syscalls.c,v 1.203 2004/02/22 09:56:26 jdolecek 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.203 2004/02/22 09:56:26 jdolecek 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/sysctl.h>
61 #include <sys/sa.h>
62 #include <sys/syscallargs.h>
63 #ifdef KTRACE
64 #include <sys/ktrace.h>
65 #endif
66
67 #include <miscfs/genfs/genfs.h>
68 #include <miscfs/syncfs/syncfs.h>
69
70 #if NFSS > 0
71 #include <dev/fssvar.h>
72 #endif
73
74 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
75
76 static int change_dir __P((struct nameidata *, struct proc *));
77 static int change_flags __P((struct vnode *, u_long, struct proc *));
78 static int change_mode __P((struct vnode *, int, struct proc *p));
79 static int change_owner __P((struct vnode *, uid_t, gid_t, struct proc *,
80 int));
81 static int change_utimes __P((struct vnode *vp, const struct timeval *,
82 struct proc *p));
83 static int rename_files __P((const char *, const char *, struct proc *, int));
84 static int dostatfs __P((struct mount *, struct statfs *, struct proc *, int,
85 int));
86
87 void checkdirs __P((struct vnode *));
88
89 int dovfsusermount = 0;
90
91 /*
92 * Virtual File System System Calls
93 */
94
95 /*
96 * Mount a file system.
97 */
98
99 #if defined(COMPAT_09) || defined(COMPAT_43)
100 /*
101 * This table is used to maintain compatibility with 4.3BSD
102 * and NetBSD 0.9 mount syscalls. Note, the order is important!
103 *
104 * Do not modify this table. It should only contain filesystems
105 * supported by NetBSD 0.9 and 4.3BSD.
106 */
107 const char * const mountcompatnames[] = {
108 NULL, /* 0 = MOUNT_NONE */
109 MOUNT_FFS, /* 1 = MOUNT_UFS */
110 MOUNT_NFS, /* 2 */
111 MOUNT_MFS, /* 3 */
112 MOUNT_MSDOS, /* 4 */
113 MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
114 MOUNT_FDESC, /* 6 */
115 MOUNT_KERNFS, /* 7 */
116 NULL, /* 8 = MOUNT_DEVFS */
117 MOUNT_AFS, /* 9 */
118 };
119 const int nmountcompatnames = sizeof(mountcompatnames) /
120 sizeof(mountcompatnames[0]);
121 #endif /* COMPAT_09 || COMPAT_43 */
122
123 /* ARGSUSED */
124 int
125 sys_mount(l, v, retval)
126 struct lwp *l;
127 void *v;
128 register_t *retval;
129 {
130 struct sys_mount_args /* {
131 syscallarg(const char *) type;
132 syscallarg(const char *) path;
133 syscallarg(int) flags;
134 syscallarg(void *) data;
135 } */ *uap = v;
136 struct proc *p = l->l_proc;
137 struct vnode *vp;
138 struct mount *mp;
139 int error, flag = 0;
140 char fstypename[MFSNAMELEN];
141 struct vattr va;
142 struct nameidata nd;
143 struct vfsops *vfs;
144
145 if (dovfsusermount == 0 && (SCARG(uap, flags) & MNT_GETARGS) == 0 &&
146 (error = suser(p->p_ucred, &p->p_acflag)))
147 return (error);
148 /*
149 * Get vnode to be covered
150 */
151 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
152 SCARG(uap, path), p);
153 if ((error = namei(&nd)) != 0)
154 return (error);
155 vp = nd.ni_vp;
156 /*
157 * A lookup in VFS_MOUNT might result in an attempt to
158 * lock this vnode again, so make the lock recursive.
159 */
160 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_SETRECURSE);
161 if (SCARG(uap, flags) & (MNT_UPDATE | MNT_GETARGS)) {
162 if ((vp->v_flag & VROOT) == 0) {
163 vput(vp);
164 return (EINVAL);
165 }
166 mp = vp->v_mount;
167 flag = mp->mnt_flag;
168 vfs = mp->mnt_op;
169 /*
170 * We only allow the filesystem to be reloaded if it
171 * is currently mounted read-only.
172 */
173 if ((SCARG(uap, flags) & MNT_RELOAD) &&
174 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
175 vput(vp);
176 return (EOPNOTSUPP); /* Needs translation */
177 }
178 /*
179 * In "highly secure" mode, don't let the caller do anything
180 * but downgrade a filesystem from read-write to read-only.
181 * (see also below; MNT_UPDATE or MNT_GETARGS is required.)
182 */
183 if (securelevel >= 2 &&
184 SCARG(uap, flags) != MNT_GETARGS &&
185 SCARG(uap, flags) !=
186 (mp->mnt_flag | MNT_RDONLY |
187 MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) {
188 vput(vp);
189 return (EPERM);
190 }
191 mp->mnt_flag |= SCARG(uap, flags) &
192 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
193 /*
194 * Only root, or the user that did the original mount is
195 * permitted to update it.
196 */
197 if ((mp->mnt_flag & MNT_GETARGS) == 0 &&
198 mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
199 (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
200 vput(vp);
201 return (error);
202 }
203 /*
204 * Do not allow NFS export by non-root users. For non-root
205 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
206 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
207 */
208 if (p->p_ucred->cr_uid != 0) {
209 if (SCARG(uap, flags) & MNT_EXPORTED) {
210 vput(vp);
211 return (EPERM);
212 }
213 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
214 if (flag & MNT_NOEXEC)
215 SCARG(uap, flags) |= MNT_NOEXEC;
216 }
217 if (vfs_busy(mp, LK_NOWAIT, 0)) {
218 vput(vp);
219 return (EPERM);
220 }
221 goto update;
222 } else {
223 if (securelevel >= 2) {
224 vput(vp);
225 return (EPERM);
226 }
227 }
228 /*
229 * If the user is not root, ensure that they own the directory
230 * onto which we are attempting to mount.
231 */
232 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0 ||
233 (va.va_uid != p->p_ucred->cr_uid &&
234 (error = suser(p->p_ucred, &p->p_acflag)) != 0)) {
235 vput(vp);
236 return (error);
237 }
238 /*
239 * Do not allow NFS export by non-root users. For non-root users,
240 * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
241 * mount point is already MNT_NOEXEC.
242 */
243 if (p->p_ucred->cr_uid != 0) {
244 if (SCARG(uap, flags) & MNT_EXPORTED) {
245 vput(vp);
246 return (EPERM);
247 }
248 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
249 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
250 SCARG(uap, flags) |= MNT_NOEXEC;
251 }
252 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
253 vput(vp);
254 return (error);
255 }
256 if (vp->v_type != VDIR) {
257 vput(vp);
258 return (ENOTDIR);
259 }
260 error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
261 if (error) {
262 #if defined(COMPAT_09) || defined(COMPAT_43)
263 /*
264 * Historically filesystem types were identified by number.
265 * If we get an integer for the filesystem type instead of a
266 * string, we check to see if it matches one of the historic
267 * filesystem types.
268 */
269 u_long fsindex = (u_long)SCARG(uap, type);
270 if (fsindex >= nmountcompatnames ||
271 mountcompatnames[fsindex] == NULL) {
272 vput(vp);
273 return (ENODEV);
274 }
275 strncpy(fstypename, mountcompatnames[fsindex], MFSNAMELEN);
276 #else
277 vput(vp);
278 return (error);
279 #endif
280 }
281 #ifdef COMPAT_10
282 /* Accept `ufs' as an alias for `ffs'. */
283 if (!strncmp(fstypename, "ufs", MFSNAMELEN))
284 strncpy(fstypename, "ffs", MFSNAMELEN);
285 #endif
286 if ((vfs = vfs_getopsbyname(fstypename)) == NULL) {
287 vput(vp);
288 return (ENODEV);
289 }
290 if (vp->v_mountedhere != NULL) {
291 vput(vp);
292 return (EBUSY);
293 }
294
295 /*
296 * Allocate and initialize the file system.
297 */
298 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
299 M_MOUNT, M_WAITOK);
300 memset((char *)mp, 0, (u_long)sizeof(struct mount));
301 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
302 (void)vfs_busy(mp, LK_NOWAIT, 0);
303 mp->mnt_op = vfs;
304 vfs->vfs_refcount++;
305 mp->mnt_vnodecovered = vp;
306 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
307 mp->mnt_unmounter = NULL;
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, p);
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_STATFS(mp, &mp->mnt_stat, p);
373 if ((error = VFS_START(mp, 0, p)))
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 LIST_FOREACH(p, &allproc, p_list) {
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), p);
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), p));
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, p)
502 struct mount *mp;
503 int flags;
504 struct proc *p;
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 = p;
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 if (((mp->mnt_flag & MNT_RDONLY) ||
545 #if NFSS > 0
546 (error = fss_umount_hook(mp, (flags & MNT_FORCE))) == 0 ||
547 #endif
548 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
549 (flags & MNT_FORCE))
550 error = VFS_UNMOUNT(mp, flags, p);
551 vn_finished_write(mp, 0);
552 simple_lock(&mountlist_slock);
553 if (error) {
554 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
555 (void) vfs_allocate_syncvnode(mp);
556 mp->mnt_iflag &= ~IMNT_UNMOUNT;
557 mp->mnt_unmounter = NULL;
558 mp->mnt_flag |= async;
559 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
560 &mountlist_slock);
561 if (used_syncer)
562 lockmgr(&syncer_lock, LK_RELEASE, NULL);
563 while (mp->mnt_wcnt > 0) {
564 wakeup(mp);
565 tsleep(&mp->mnt_wcnt, PVFS, "mntwcnt1", 0);
566 }
567 return (error);
568 }
569 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
570 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
571 coveredvp->v_mountedhere = NULL;
572 vrele(coveredvp);
573 }
574 mp->mnt_op->vfs_refcount--;
575 if (LIST_FIRST(&mp->mnt_vnodelist) != NULL)
576 panic("unmount: dangling vnode");
577 mp->mnt_iflag |= IMNT_GONE;
578 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
579 if (used_syncer)
580 lockmgr(&syncer_lock, LK_RELEASE, NULL);
581 while(mp->mnt_wcnt > 0) {
582 wakeup(mp);
583 tsleep(&mp->mnt_wcnt, PVFS, "mntwcnt2", 0);
584 }
585 free(mp, M_MOUNT);
586 return (0);
587 }
588
589 /*
590 * Sync each mounted filesystem.
591 */
592 #ifdef DEBUG
593 int syncprt = 0;
594 struct ctldebug debug0 = { "syncprt", &syncprt };
595 #endif
596
597 /* ARGSUSED */
598 int
599 sys_sync(l, v, retval)
600 struct lwp *l;
601 void *v;
602 register_t *retval;
603 {
604 struct mount *mp, *nmp;
605 int asyncflag;
606 struct proc *p = l == NULL ? &proc0 : l->l_proc;
607
608 simple_lock(&mountlist_slock);
609 for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
610 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
611 nmp = mp->mnt_list.cqe_prev;
612 continue;
613 }
614 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
615 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
616 asyncflag = mp->mnt_flag & MNT_ASYNC;
617 mp->mnt_flag &= ~MNT_ASYNC;
618 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
619 if (asyncflag)
620 mp->mnt_flag |= MNT_ASYNC;
621 vn_finished_write(mp, 0);
622 }
623 simple_lock(&mountlist_slock);
624 nmp = mp->mnt_list.cqe_prev;
625 vfs_unbusy(mp);
626
627 }
628 simple_unlock(&mountlist_slock);
629 #ifdef DEBUG
630 if (syncprt)
631 vfs_bufstats();
632 #endif /* DEBUG */
633 return (0);
634 }
635
636 /*
637 * Change filesystem quotas.
638 */
639 /* ARGSUSED */
640 int
641 sys_quotactl(l, v, retval)
642 struct lwp *l;
643 void *v;
644 register_t *retval;
645 {
646 struct sys_quotactl_args /* {
647 syscallarg(const char *) path;
648 syscallarg(int) cmd;
649 syscallarg(int) uid;
650 syscallarg(caddr_t) arg;
651 } */ *uap = v;
652 struct proc *p = l->l_proc;
653 struct mount *mp;
654 int error;
655 struct nameidata nd;
656
657 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
658 if ((error = namei(&nd)) != 0)
659 return (error);
660 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
661 vrele(nd.ni_vp);
662 if (error)
663 return (error);
664 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
665 SCARG(uap, arg), p);
666 vn_finished_write(mp, 0);
667 return (error);
668 }
669
670 static int
671 dostatfs(struct mount *mp, struct statfs *sp, struct proc *p, int flags,
672 int root)
673 {
674 struct cwdinfo *cwdi = p->p_cwdi;
675 int error = 0;
676
677 /*
678 * If MNT_NOWAIT or MNT_LAZY is specified, do not
679 * refresh the fsstat cache. MNT_WAIT or MNT_LAXY
680 * overrides MNT_NOWAIT.
681 */
682 if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
683 (flags != MNT_WAIT && flags != 0)) {
684 memcpy(sp, &mp->mnt_stat, sizeof(*sp));
685 goto done;
686 }
687
688 if ((error = VFS_STATFS(mp, sp, p)) != 0) {
689 return error;
690 }
691
692 if (cwdi->cwdi_rdir == NULL)
693 (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
694 done:
695 if (cwdi->cwdi_rdir != NULL) {
696 size_t len;
697 char *bp;
698 char *path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
699 if (!path)
700 return ENOMEM;
701
702 bp = path + MAXPATHLEN;
703 *--bp = '\0';
704 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
705 MAXPATHLEN / 2, 0, p);
706 if (error) {
707 free(path, M_TEMP);
708 return error;
709 }
710 len = strlen(bp);
711 /*
712 * for mount points that are below our root, we can see
713 * them, so we fix up the pathname and return them. The
714 * rest we cannot see, so we don't allow viewing the
715 * data.
716 */
717 if (strncmp(bp, sp->f_mntonname, len) == 0) {
718 strlcpy(sp->f_mntonname, &sp->f_mntonname[len],
719 sizeof(sp->f_mntonname));
720 if (sp->f_mntonname[0] == '\0')
721 (void)strlcpy(sp->f_mntonname, "/",
722 sizeof(sp->f_mntonname));
723 } else {
724 if (root)
725 (void)strlcpy(sp->f_mntonname, "/",
726 sizeof(sp->f_mntonname));
727 else
728 error = EPERM;
729 }
730 free(path, M_TEMP);
731 }
732 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
733 sp->f_oflags = sp->f_flags & 0xffff;
734 return error;
735 }
736
737 /*
738 * Get filesystem statistics.
739 */
740 /* ARGSUSED */
741 int
742 sys_statfs(l, v, retval)
743 struct lwp *l;
744 void *v;
745 register_t *retval;
746 {
747 struct sys_statfs_args /* {
748 syscallarg(const char *) path;
749 syscallarg(struct statfs *) buf;
750 } */ *uap = v;
751 struct proc *p = l->l_proc;
752 struct mount *mp;
753 struct statfs sbuf;
754 int error;
755 struct nameidata nd;
756
757 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
758 if ((error = namei(&nd)) != 0)
759 return error;
760 mp = nd.ni_vp->v_mount;
761 vrele(nd.ni_vp);
762 if ((error = dostatfs(mp, &sbuf, p, 0, 1)) != 0)
763 return error;
764 return copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
765 }
766
767 /*
768 * Get filesystem statistics.
769 */
770 /* ARGSUSED */
771 int
772 sys_fstatfs(l, v, retval)
773 struct lwp *l;
774 void *v;
775 register_t *retval;
776 {
777 struct sys_fstatfs_args /* {
778 syscallarg(int) fd;
779 syscallarg(struct statfs *) buf;
780 } */ *uap = v;
781 struct proc *p = l->l_proc;
782 struct file *fp;
783 struct mount *mp;
784 struct statfs sbuf;
785 int error;
786
787 /* getvnode() will use the descriptor for us */
788 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
789 return (error);
790 mp = ((struct vnode *)fp->f_data)->v_mount;
791 if ((error = dostatfs(mp, &sbuf, p, 0, 1)) != 0)
792 goto out;
793 error = copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
794 out:
795 FILE_UNUSE(fp, p);
796 return error;
797 }
798
799
800 /*
801 * Get statistics on all filesystems.
802 */
803 int
804 sys_getfsstat(l, v, retval)
805 struct lwp *l;
806 void *v;
807 register_t *retval;
808 {
809 struct sys_getfsstat_args /* {
810 syscallarg(struct statfs *) buf;
811 syscallarg(long) bufsize;
812 syscallarg(int) flags;
813 } */ *uap = v;
814 int root = 0;
815 struct proc *p = l->l_proc;
816 struct mount *mp, *nmp;
817 struct statfs sbuf;
818 caddr_t sfsp;
819 long count, maxcount, error = 0;
820
821 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
822 sfsp = (caddr_t)SCARG(uap, buf);
823 simple_lock(&mountlist_slock);
824 count = 0;
825 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
826 mp = nmp) {
827 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
828 nmp = CIRCLEQ_NEXT(mp, mnt_list);
829 continue;
830 }
831 if (sfsp && count < maxcount) {
832 error = dostatfs(mp, &sbuf, p, SCARG(uap, flags), 0);
833 if (error) {
834 simple_lock(&mountlist_slock);
835 nmp = CIRCLEQ_NEXT(mp, mnt_list);
836 vfs_unbusy(mp);
837 continue;
838 }
839 error = copyout(&sbuf, sfsp, sizeof(sbuf));
840 if (error) {
841 vfs_unbusy(mp);
842 return (error);
843 }
844 sfsp += sizeof(sbuf);
845 root |= strcmp(sbuf.f_mntonname, "/") == 0;
846 }
847 count++;
848 simple_lock(&mountlist_slock);
849 nmp = CIRCLEQ_NEXT(mp, mnt_list);
850 vfs_unbusy(mp);
851 }
852 simple_unlock(&mountlist_slock);
853 if (root == 0 && p->p_cwdi->cwdi_rdir) {
854 /*
855 * fake a root entry
856 */
857 if ((error = dostatfs(p->p_cwdi->cwdi_rdir->v_mount, &sbuf, p,
858 SCARG(uap, flags), 1)) != 0)
859 return error;
860 if (sfsp)
861 error = copyout(&sbuf, sfsp, sizeof(sbuf));
862 count++;
863 }
864 if (sfsp && count > maxcount)
865 *retval = maxcount;
866 else
867 *retval = count;
868 return error;
869 }
870
871 /*
872 * Change current working directory to a given file descriptor.
873 */
874 /* ARGSUSED */
875 int
876 sys_fchdir(l, v, retval)
877 struct lwp *l;
878 void *v;
879 register_t *retval;
880 {
881 struct sys_fchdir_args /* {
882 syscallarg(int) fd;
883 } */ *uap = v;
884 struct proc *p = l->l_proc;
885 struct filedesc *fdp = p->p_fd;
886 struct cwdinfo *cwdi = p->p_cwdi;
887 struct vnode *vp, *tdp;
888 struct mount *mp;
889 struct file *fp;
890 int error;
891
892 /* getvnode() will use the descriptor for us */
893 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
894 return (error);
895 vp = (struct vnode *)fp->f_data;
896
897 VREF(vp);
898 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
899 if (vp->v_type != VDIR)
900 error = ENOTDIR;
901 else
902 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
903 while (!error && (mp = vp->v_mountedhere) != NULL) {
904 if (vfs_busy(mp, 0, 0))
905 continue;
906 error = VFS_ROOT(mp, &tdp);
907 vfs_unbusy(mp);
908 if (error)
909 break;
910 vput(vp);
911 vp = tdp;
912 }
913 if (error) {
914 vput(vp);
915 goto out;
916 }
917 VOP_UNLOCK(vp, 0);
918
919 /*
920 * Disallow changing to a directory not under the process's
921 * current root directory (if there is one).
922 */
923 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, p)) {
924 vrele(vp);
925 error = EPERM; /* operation not permitted */
926 goto out;
927 }
928
929 vrele(cwdi->cwdi_cdir);
930 cwdi->cwdi_cdir = vp;
931 out:
932 FILE_UNUSE(fp, p);
933 return (error);
934 }
935
936 /*
937 * Change this process's notion of the root directory to a given file descriptor.
938 */
939
940 int
941 sys_fchroot(l, v, retval)
942 struct lwp *l;
943 void *v;
944 register_t *retval;
945 {
946 struct sys_fchroot_args *uap = v;
947 struct proc *p = l->l_proc;
948 struct filedesc *fdp = p->p_fd;
949 struct cwdinfo *cwdi = p->p_cwdi;
950 struct vnode *vp;
951 struct file *fp;
952 int error;
953
954 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
955 return error;
956 /* getvnode() will use the descriptor for us */
957 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
958 return error;
959 vp = (struct vnode *) fp->f_data;
960 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
961 if (vp->v_type != VDIR)
962 error = ENOTDIR;
963 else
964 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
965 VOP_UNLOCK(vp, 0);
966 if (error)
967 goto out;
968 VREF(vp);
969
970 /*
971 * Prevent escaping from chroot by putting the root under
972 * the working directory. Silently chdir to / if we aren't
973 * already there.
974 */
975 if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
976 /*
977 * XXX would be more failsafe to change directory to a
978 * deadfs node here instead
979 */
980 vrele(cwdi->cwdi_cdir);
981 VREF(vp);
982 cwdi->cwdi_cdir = vp;
983 }
984
985 if (cwdi->cwdi_rdir != NULL)
986 vrele(cwdi->cwdi_rdir);
987 cwdi->cwdi_rdir = vp;
988 out:
989 FILE_UNUSE(fp, p);
990 return (error);
991 }
992
993
994
995 /*
996 * Change current working directory (``.'').
997 */
998 /* ARGSUSED */
999 int
1000 sys_chdir(l, v, retval)
1001 struct lwp *l;
1002 void *v;
1003 register_t *retval;
1004 {
1005 struct sys_chdir_args /* {
1006 syscallarg(const char *) path;
1007 } */ *uap = v;
1008 struct proc *p = l->l_proc;
1009 struct cwdinfo *cwdi = p->p_cwdi;
1010 int error;
1011 struct nameidata nd;
1012
1013 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1014 SCARG(uap, path), p);
1015 if ((error = change_dir(&nd, p)) != 0)
1016 return (error);
1017 vrele(cwdi->cwdi_cdir);
1018 cwdi->cwdi_cdir = nd.ni_vp;
1019 return (0);
1020 }
1021
1022 /*
1023 * Change notion of root (``/'') directory.
1024 */
1025 /* ARGSUSED */
1026 int
1027 sys_chroot(l, v, retval)
1028 struct lwp *l;
1029 void *v;
1030 register_t *retval;
1031 {
1032 struct sys_chroot_args /* {
1033 syscallarg(const char *) path;
1034 } */ *uap = v;
1035 struct proc *p = l->l_proc;
1036 struct cwdinfo *cwdi = p->p_cwdi;
1037 struct vnode *vp;
1038 int error;
1039 struct nameidata nd;
1040
1041 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1042 return (error);
1043 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1044 SCARG(uap, path), p);
1045 if ((error = change_dir(&nd, p)) != 0)
1046 return (error);
1047 if (cwdi->cwdi_rdir != NULL)
1048 vrele(cwdi->cwdi_rdir);
1049 vp = nd.ni_vp;
1050 cwdi->cwdi_rdir = vp;
1051
1052 /*
1053 * Prevent escaping from chroot by putting the root under
1054 * the working directory. Silently chdir to / if we aren't
1055 * already there.
1056 */
1057 if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
1058 /*
1059 * XXX would be more failsafe to change directory to a
1060 * deadfs node here instead
1061 */
1062 vrele(cwdi->cwdi_cdir);
1063 VREF(vp);
1064 cwdi->cwdi_cdir = vp;
1065 }
1066
1067 return (0);
1068 }
1069
1070 /*
1071 * Common routine for chroot and chdir.
1072 */
1073 static int
1074 change_dir(ndp, p)
1075 struct nameidata *ndp;
1076 struct proc *p;
1077 {
1078 struct vnode *vp;
1079 int error;
1080
1081 if ((error = namei(ndp)) != 0)
1082 return (error);
1083 vp = ndp->ni_vp;
1084 if (vp->v_type != VDIR)
1085 error = ENOTDIR;
1086 else
1087 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
1088
1089 if (error)
1090 vput(vp);
1091 else
1092 VOP_UNLOCK(vp, 0);
1093 return (error);
1094 }
1095
1096 /*
1097 * Check permissions, allocate an open file structure,
1098 * and call the device open routine if any.
1099 */
1100 int
1101 sys_open(l, v, retval)
1102 struct lwp *l;
1103 void *v;
1104 register_t *retval;
1105 {
1106 struct sys_open_args /* {
1107 syscallarg(const char *) path;
1108 syscallarg(int) flags;
1109 syscallarg(int) mode;
1110 } */ *uap = v;
1111 struct proc *p = l->l_proc;
1112 struct cwdinfo *cwdi = p->p_cwdi;
1113 struct filedesc *fdp = p->p_fd;
1114 struct file *fp;
1115 struct vnode *vp;
1116 int flags, cmode;
1117 int type, indx, error;
1118 struct flock lf;
1119 struct nameidata nd;
1120
1121 flags = FFLAGS(SCARG(uap, flags));
1122 if ((flags & (FREAD | FWRITE)) == 0)
1123 return (EINVAL);
1124 /* falloc() will use the file descriptor for us */
1125 if ((error = falloc(p, &fp, &indx)) != 0)
1126 return (error);
1127 cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
1128 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1129 l->l_dupfd = -indx - 1; /* XXX check for fdopen */
1130 if ((error = vn_open(&nd, flags, cmode)) != 0) {
1131 FILE_UNUSE(fp, p);
1132 fdp->fd_ofiles[indx] = NULL;
1133 ffree(fp);
1134 if ((error == ENODEV || error == ENXIO) &&
1135 l->l_dupfd >= 0 && /* XXX from fdopen */
1136 (error =
1137 dupfdopen(p, indx, l->l_dupfd, flags, error)) == 0) {
1138 *retval = indx;
1139 return (0);
1140 }
1141 if (error == ERESTART)
1142 error = EINTR;
1143 fdremove(fdp, indx);
1144 return (error);
1145 }
1146 l->l_dupfd = 0;
1147 vp = nd.ni_vp;
1148 fp->f_flag = flags & FMASK;
1149 fp->f_type = DTYPE_VNODE;
1150 fp->f_ops = &vnops;
1151 fp->f_data = vp;
1152 if (flags & (O_EXLOCK | O_SHLOCK)) {
1153 lf.l_whence = SEEK_SET;
1154 lf.l_start = 0;
1155 lf.l_len = 0;
1156 if (flags & O_EXLOCK)
1157 lf.l_type = F_WRLCK;
1158 else
1159 lf.l_type = F_RDLCK;
1160 type = F_FLOCK;
1161 if ((flags & FNONBLOCK) == 0)
1162 type |= F_WAIT;
1163 VOP_UNLOCK(vp, 0);
1164 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1165 if (error) {
1166 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
1167 FILE_UNUSE(fp, p);
1168 ffree(fp);
1169 fdremove(fdp, indx);
1170 return (error);
1171 }
1172 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1173 fp->f_flag |= FHASLOCK;
1174 }
1175 VOP_UNLOCK(vp, 0);
1176 *retval = indx;
1177 FILE_SET_MATURE(fp);
1178 FILE_UNUSE(fp, p);
1179 return (0);
1180 }
1181
1182 /*
1183 * Get file handle system call
1184 */
1185 int
1186 sys_getfh(l, v, retval)
1187 struct lwp *l;
1188 void *v;
1189 register_t *retval;
1190 {
1191 struct sys_getfh_args /* {
1192 syscallarg(char *) fname;
1193 syscallarg(fhandle_t *) fhp;
1194 } */ *uap = v;
1195 struct proc *p = l->l_proc;
1196 struct vnode *vp;
1197 fhandle_t fh;
1198 int error;
1199 struct nameidata nd;
1200
1201 /*
1202 * Must be super user
1203 */
1204 error = suser(p->p_ucred, &p->p_acflag);
1205 if (error)
1206 return (error);
1207 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1208 SCARG(uap, fname), p);
1209 error = namei(&nd);
1210 if (error)
1211 return (error);
1212 vp = nd.ni_vp;
1213 memset(&fh, 0, sizeof(fh));
1214 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1215 error = VFS_VPTOFH(vp, &fh.fh_fid);
1216 vput(vp);
1217 if (error)
1218 return (error);
1219 error = copyout(&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh));
1220 return (error);
1221 }
1222
1223 /*
1224 * Open a file given a file handle.
1225 *
1226 * Check permissions, allocate an open file structure,
1227 * and call the device open routine if any.
1228 */
1229 int
1230 sys_fhopen(l, v, retval)
1231 struct lwp *l;
1232 void *v;
1233 register_t *retval;
1234 {
1235 struct sys_fhopen_args /* {
1236 syscallarg(const fhandle_t *) fhp;
1237 syscallarg(int) flags;
1238 } */ *uap = v;
1239 struct proc *p = l->l_proc;
1240 struct filedesc *fdp = p->p_fd;
1241 struct file *fp;
1242 struct vnode *vp = NULL;
1243 struct mount *mp;
1244 struct ucred *cred = p->p_ucred;
1245 int flags;
1246 struct file *nfp;
1247 int type, indx, error=0;
1248 struct flock lf;
1249 struct vattr va;
1250 fhandle_t fh;
1251
1252 /*
1253 * Must be super user
1254 */
1255 if ((error = suser(p->p_ucred, &p->p_acflag)))
1256 return (error);
1257
1258 flags = FFLAGS(SCARG(uap, flags));
1259 if ((flags & (FREAD | FWRITE)) == 0)
1260 return (EINVAL);
1261 if ((flags & O_CREAT))
1262 return (EINVAL);
1263 /* falloc() will use the file descriptor for us */
1264 if ((error = falloc(p, &nfp, &indx)) != 0)
1265 return (error);
1266 fp = nfp;
1267 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1268 goto bad;
1269
1270 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
1271 error = ESTALE;
1272 goto bad;
1273 }
1274
1275 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
1276 vp = NULL; /* most likely unnecessary sanity for bad: */
1277 goto bad;
1278 }
1279
1280 /* Now do an effective vn_open */
1281
1282 if (vp->v_type == VSOCK) {
1283 error = EOPNOTSUPP;
1284 goto bad;
1285 }
1286 if (flags & FREAD) {
1287 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
1288 goto bad;
1289 }
1290 if (flags & (FWRITE | O_TRUNC)) {
1291 if (vp->v_type == VDIR) {
1292 error = EISDIR;
1293 goto bad;
1294 }
1295 if ((error = vn_writechk(vp)) != 0 ||
1296 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
1297 goto bad;
1298 }
1299 if (flags & O_TRUNC) {
1300 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
1301 goto bad;
1302 VOP_UNLOCK(vp, 0); /* XXX */
1303 VOP_LEASE(vp, p, cred, LEASE_WRITE);
1304 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */
1305 VATTR_NULL(&va);
1306 va.va_size = 0;
1307 error = VOP_SETATTR(vp, &va, cred, p);
1308 vn_finished_write(mp, 0);
1309 if (error)
1310 goto bad;
1311 }
1312 if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
1313 goto bad;
1314 if (vp->v_type == VREG &&
1315 uvn_attach(vp, flags & FWRITE ? VM_PROT_WRITE : 0) == NULL) {
1316 error = EIO;
1317 goto bad;
1318 }
1319 if (flags & FWRITE)
1320 vp->v_writecount++;
1321
1322 /* done with modified vn_open, now finish what sys_open does. */
1323
1324 fp->f_flag = flags & FMASK;
1325 fp->f_type = DTYPE_VNODE;
1326 fp->f_ops = &vnops;
1327 fp->f_data = vp;
1328 if (flags & (O_EXLOCK | O_SHLOCK)) {
1329 lf.l_whence = SEEK_SET;
1330 lf.l_start = 0;
1331 lf.l_len = 0;
1332 if (flags & O_EXLOCK)
1333 lf.l_type = F_WRLCK;
1334 else
1335 lf.l_type = F_RDLCK;
1336 type = F_FLOCK;
1337 if ((flags & FNONBLOCK) == 0)
1338 type |= F_WAIT;
1339 VOP_UNLOCK(vp, 0);
1340 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
1341 if (error) {
1342 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
1343 FILE_UNUSE(fp, p);
1344 ffree(fp);
1345 fdremove(fdp, indx);
1346 return (error);
1347 }
1348 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1349 fp->f_flag |= FHASLOCK;
1350 }
1351 VOP_UNLOCK(vp, 0);
1352 *retval = indx;
1353 FILE_SET_MATURE(fp);
1354 FILE_UNUSE(fp, p);
1355 return (0);
1356
1357 bad:
1358 FILE_UNUSE(fp, p);
1359 ffree(fp);
1360 fdremove(fdp, indx);
1361 if (vp != NULL)
1362 vput(vp);
1363 return (error);
1364 }
1365
1366 /* ARGSUSED */
1367 int
1368 sys_fhstat(l, v, retval)
1369 struct lwp *l;
1370 void *v;
1371 register_t *retval;
1372 {
1373 struct sys_fhstat_args /* {
1374 syscallarg(const fhandle_t *) fhp;
1375 syscallarg(struct stat *) sb;
1376 } */ *uap = v;
1377 struct proc *p = l->l_proc;
1378 struct stat sb;
1379 int error;
1380 fhandle_t fh;
1381 struct mount *mp;
1382 struct vnode *vp;
1383
1384 /*
1385 * Must be super user
1386 */
1387 if ((error = suser(p->p_ucred, &p->p_acflag)))
1388 return (error);
1389
1390 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1391 return (error);
1392
1393 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1394 return (ESTALE);
1395 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1396 return (error);
1397 error = vn_stat(vp, &sb, p);
1398 vput(vp);
1399 if (error)
1400 return (error);
1401 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
1402 return (error);
1403 }
1404
1405 /* ARGSUSED */
1406 int
1407 sys_fhstatfs(l, v, retval)
1408 struct lwp *l;
1409 void *v;
1410 register_t *retval;
1411 {
1412 struct sys_fhstatfs_args /*
1413 syscallarg(const fhandle_t *) fhp;
1414 syscallarg(struct statfs *) buf;
1415 } */ *uap = v;
1416 struct proc *p = l->l_proc;
1417 struct statfs sbuf;
1418 fhandle_t fh;
1419 struct mount *mp;
1420 struct vnode *vp;
1421 int error;
1422
1423 /*
1424 * Must be super user
1425 */
1426 if ((error = suser(p->p_ucred, &p->p_acflag)))
1427 return (error);
1428
1429 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1430 return (error);
1431
1432 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1433 return (ESTALE);
1434 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1435 return (error);
1436 mp = vp->v_mount;
1437 vput(vp);
1438 if ((error = VFS_STATFS(mp, &sbuf, p)) != 0)
1439 return (error);
1440 return (copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf)));
1441 }
1442
1443 /*
1444 * Create a special file.
1445 */
1446 /* ARGSUSED */
1447 int
1448 sys_mknod(l, v, retval)
1449 struct lwp *l;
1450 void *v;
1451 register_t *retval;
1452 {
1453 struct sys_mknod_args /* {
1454 syscallarg(const char *) path;
1455 syscallarg(int) mode;
1456 syscallarg(int) dev;
1457 } */ *uap = v;
1458 struct proc *p = l->l_proc;
1459 struct vnode *vp;
1460 struct mount *mp;
1461 struct vattr vattr;
1462 int error;
1463 int whiteout = 0;
1464 struct nameidata nd;
1465
1466 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1467 return (error);
1468 restart:
1469 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1470 if ((error = namei(&nd)) != 0)
1471 return (error);
1472 vp = nd.ni_vp;
1473 if (vp != NULL)
1474 error = EEXIST;
1475 else {
1476 VATTR_NULL(&vattr);
1477 vattr.va_mode =
1478 (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1479 vattr.va_rdev = SCARG(uap, dev);
1480 whiteout = 0;
1481
1482 switch (SCARG(uap, mode) & S_IFMT) {
1483 case S_IFMT: /* used by badsect to flag bad sectors */
1484 vattr.va_type = VBAD;
1485 break;
1486 case S_IFCHR:
1487 vattr.va_type = VCHR;
1488 break;
1489 case S_IFBLK:
1490 vattr.va_type = VBLK;
1491 break;
1492 case S_IFWHT:
1493 whiteout = 1;
1494 break;
1495 default:
1496 error = EINVAL;
1497 break;
1498 }
1499 }
1500 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1501 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1502 if (nd.ni_dvp == vp)
1503 vrele(nd.ni_dvp);
1504 else
1505 vput(nd.ni_dvp);
1506 if (vp)
1507 vrele(vp);
1508 if ((error = vn_start_write(NULL, &mp,
1509 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1510 return (error);
1511 goto restart;
1512 }
1513 if (!error) {
1514 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1515 if (whiteout) {
1516 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1517 if (error)
1518 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1519 vput(nd.ni_dvp);
1520 } else {
1521 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1522 &nd.ni_cnd, &vattr);
1523 if (error == 0)
1524 vput(nd.ni_vp);
1525 }
1526 } else {
1527 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1528 if (nd.ni_dvp == vp)
1529 vrele(nd.ni_dvp);
1530 else
1531 vput(nd.ni_dvp);
1532 if (vp)
1533 vrele(vp);
1534 }
1535 vn_finished_write(mp, 0);
1536 return (error);
1537 }
1538
1539 /*
1540 * Create a named pipe.
1541 */
1542 /* ARGSUSED */
1543 int
1544 sys_mkfifo(l, v, retval)
1545 struct lwp *l;
1546 void *v;
1547 register_t *retval;
1548 {
1549 struct sys_mkfifo_args /* {
1550 syscallarg(const char *) path;
1551 syscallarg(int) mode;
1552 } */ *uap = v;
1553 struct proc *p = l->l_proc;
1554 struct mount *mp;
1555 struct vattr vattr;
1556 int error;
1557 struct nameidata nd;
1558
1559 restart:
1560 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1561 if ((error = namei(&nd)) != 0)
1562 return (error);
1563 if (nd.ni_vp != NULL) {
1564 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1565 if (nd.ni_dvp == nd.ni_vp)
1566 vrele(nd.ni_dvp);
1567 else
1568 vput(nd.ni_dvp);
1569 vrele(nd.ni_vp);
1570 return (EEXIST);
1571 }
1572 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1573 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1574 if (nd.ni_dvp == nd.ni_vp)
1575 vrele(nd.ni_dvp);
1576 else
1577 vput(nd.ni_dvp);
1578 if (nd.ni_vp)
1579 vrele(nd.ni_vp);
1580 if ((error = vn_start_write(NULL, &mp,
1581 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1582 return (error);
1583 goto restart;
1584 }
1585 VATTR_NULL(&vattr);
1586 vattr.va_type = VFIFO;
1587 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
1588 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1589 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1590 if (error == 0)
1591 vput(nd.ni_vp);
1592 vn_finished_write(mp, 0);
1593 return (error);
1594 }
1595
1596 /*
1597 * Make a hard file link.
1598 */
1599 /* ARGSUSED */
1600 int
1601 sys_link(l, v, retval)
1602 struct lwp *l;
1603 void *v;
1604 register_t *retval;
1605 {
1606 struct sys_link_args /* {
1607 syscallarg(const char *) path;
1608 syscallarg(const char *) link;
1609 } */ *uap = v;
1610 struct proc *p = l->l_proc;
1611 struct vnode *vp;
1612 struct mount *mp;
1613 struct nameidata nd;
1614 int error;
1615
1616 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1617 if ((error = namei(&nd)) != 0)
1618 return (error);
1619 vp = nd.ni_vp;
1620 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
1621 vrele(vp);
1622 return (error);
1623 }
1624 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1625 if ((error = namei(&nd)) != 0)
1626 goto out;
1627 if (nd.ni_vp) {
1628 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1629 if (nd.ni_dvp == nd.ni_vp)
1630 vrele(nd.ni_dvp);
1631 else
1632 vput(nd.ni_dvp);
1633 vrele(nd.ni_vp);
1634 error = EEXIST;
1635 goto out;
1636 }
1637 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1638 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1639 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1640 out:
1641 vrele(vp);
1642 vn_finished_write(mp, 0);
1643 return (error);
1644 }
1645
1646 /*
1647 * Make a symbolic link.
1648 */
1649 /* ARGSUSED */
1650 int
1651 sys_symlink(l, v, retval)
1652 struct lwp *l;
1653 void *v;
1654 register_t *retval;
1655 {
1656 struct sys_symlink_args /* {
1657 syscallarg(const char *) path;
1658 syscallarg(const char *) link;
1659 } */ *uap = v;
1660 struct proc *p = l->l_proc;
1661 struct mount *mp;
1662 struct vattr vattr;
1663 char *path;
1664 int error;
1665 struct nameidata nd;
1666
1667 path = PNBUF_GET();
1668 error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
1669 if (error)
1670 goto out;
1671 restart:
1672 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1673 if ((error = namei(&nd)) != 0)
1674 goto out;
1675 if (nd.ni_vp) {
1676 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1677 if (nd.ni_dvp == nd.ni_vp)
1678 vrele(nd.ni_dvp);
1679 else
1680 vput(nd.ni_dvp);
1681 vrele(nd.ni_vp);
1682 error = EEXIST;
1683 goto out;
1684 }
1685 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1686 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1687 if (nd.ni_dvp == nd.ni_vp)
1688 vrele(nd.ni_dvp);
1689 else
1690 vput(nd.ni_dvp);
1691 if ((error = vn_start_write(NULL, &mp,
1692 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1693 return (error);
1694 goto restart;
1695 }
1696 VATTR_NULL(&vattr);
1697 vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
1698 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1699 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1700 if (error == 0)
1701 vput(nd.ni_vp);
1702 vn_finished_write(mp, 0);
1703 out:
1704 PNBUF_PUT(path);
1705 return (error);
1706 }
1707
1708 /*
1709 * Delete a whiteout from the filesystem.
1710 */
1711 /* ARGSUSED */
1712 int
1713 sys_undelete(l, v, retval)
1714 struct lwp *l;
1715 void *v;
1716 register_t *retval;
1717 {
1718 struct sys_undelete_args /* {
1719 syscallarg(const char *) path;
1720 } */ *uap = v;
1721 struct proc *p = l->l_proc;
1722 int error;
1723 struct mount *mp;
1724 struct nameidata nd;
1725
1726 restart:
1727 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1728 SCARG(uap, path), p);
1729 error = namei(&nd);
1730 if (error)
1731 return (error);
1732
1733 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1734 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1735 if (nd.ni_dvp == nd.ni_vp)
1736 vrele(nd.ni_dvp);
1737 else
1738 vput(nd.ni_dvp);
1739 if (nd.ni_vp)
1740 vrele(nd.ni_vp);
1741 return (EEXIST);
1742 }
1743 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1744 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1745 if (nd.ni_dvp == nd.ni_vp)
1746 vrele(nd.ni_dvp);
1747 else
1748 vput(nd.ni_dvp);
1749 if ((error = vn_start_write(NULL, &mp,
1750 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1751 return (error);
1752 goto restart;
1753 }
1754 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1755 if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
1756 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1757 vput(nd.ni_dvp);
1758 vn_finished_write(mp, 0);
1759 return (error);
1760 }
1761
1762 /*
1763 * Delete a name from the filesystem.
1764 */
1765 /* ARGSUSED */
1766 int
1767 sys_unlink(l, v, retval)
1768 struct lwp *l;
1769 void *v;
1770 register_t *retval;
1771 {
1772 struct sys_unlink_args /* {
1773 syscallarg(const char *) path;
1774 } */ *uap = v;
1775 struct proc *p = l->l_proc;
1776 struct mount *mp;
1777 struct vnode *vp;
1778 int error;
1779 struct nameidata nd;
1780
1781 restart:
1782 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1783 SCARG(uap, path), p);
1784 if ((error = namei(&nd)) != 0)
1785 return (error);
1786 vp = nd.ni_vp;
1787
1788 /*
1789 * The root of a mounted filesystem cannot be deleted.
1790 */
1791 if (vp->v_flag & VROOT) {
1792 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1793 if (nd.ni_dvp == vp)
1794 vrele(nd.ni_dvp);
1795 else
1796 vput(nd.ni_dvp);
1797 vput(vp);
1798 error = EBUSY;
1799 goto out;
1800 }
1801 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1802 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1803 if (nd.ni_dvp == vp)
1804 vrele(nd.ni_dvp);
1805 else
1806 vput(nd.ni_dvp);
1807 vput(vp);
1808 if ((error = vn_start_write(NULL, &mp,
1809 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
1810 return (error);
1811 goto restart;
1812 }
1813 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1814 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1815 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1816 vn_finished_write(mp, 0);
1817 out:
1818 return (error);
1819 }
1820
1821 /*
1822 * Reposition read/write file offset.
1823 */
1824 int
1825 sys_lseek(l, v, retval)
1826 struct lwp *l;
1827 void *v;
1828 register_t *retval;
1829 {
1830 struct sys_lseek_args /* {
1831 syscallarg(int) fd;
1832 syscallarg(int) pad;
1833 syscallarg(off_t) offset;
1834 syscallarg(int) whence;
1835 } */ *uap = v;
1836 struct proc *p = l->l_proc;
1837 struct ucred *cred = p->p_ucred;
1838 struct filedesc *fdp = p->p_fd;
1839 struct file *fp;
1840 struct vnode *vp;
1841 struct vattr vattr;
1842 off_t newoff;
1843 int error;
1844
1845 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
1846 return (EBADF);
1847
1848 FILE_USE(fp);
1849
1850 vp = (struct vnode *)fp->f_data;
1851 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1852 error = ESPIPE;
1853 goto out;
1854 }
1855
1856 switch (SCARG(uap, whence)) {
1857 case SEEK_CUR:
1858 newoff = fp->f_offset + SCARG(uap, offset);
1859 break;
1860 case SEEK_END:
1861 error = VOP_GETATTR(vp, &vattr, cred, p);
1862 if (error)
1863 goto out;
1864 newoff = SCARG(uap, offset) + vattr.va_size;
1865 break;
1866 case SEEK_SET:
1867 newoff = SCARG(uap, offset);
1868 break;
1869 default:
1870 error = EINVAL;
1871 goto out;
1872 }
1873 if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
1874 goto out;
1875
1876 *(off_t *)retval = fp->f_offset = newoff;
1877 out:
1878 FILE_UNUSE(fp, p);
1879 return (error);
1880 }
1881
1882 /*
1883 * Positional read system call.
1884 */
1885 int
1886 sys_pread(l, v, retval)
1887 struct lwp *l;
1888 void *v;
1889 register_t *retval;
1890 {
1891 struct sys_pread_args /* {
1892 syscallarg(int) fd;
1893 syscallarg(void *) buf;
1894 syscallarg(size_t) nbyte;
1895 syscallarg(off_t) offset;
1896 } */ *uap = v;
1897 struct proc *p = l->l_proc;
1898 struct filedesc *fdp = p->p_fd;
1899 struct file *fp;
1900 struct vnode *vp;
1901 off_t offset;
1902 int error, fd = SCARG(uap, fd);
1903
1904 if ((fp = fd_getfile(fdp, fd)) == NULL)
1905 return (EBADF);
1906
1907 if ((fp->f_flag & FREAD) == 0) {
1908 simple_unlock(&fp->f_slock);
1909 return (EBADF);
1910 }
1911
1912 FILE_USE(fp);
1913
1914 vp = (struct vnode *)fp->f_data;
1915 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1916 error = ESPIPE;
1917 goto out;
1918 }
1919
1920 offset = SCARG(uap, offset);
1921
1922 /*
1923 * XXX This works because no file systems actually
1924 * XXX take any action on the seek operation.
1925 */
1926 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1927 goto out;
1928
1929 /* dofileread() will unuse the descriptor for us */
1930 return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
1931 &offset, 0, retval));
1932
1933 out:
1934 FILE_UNUSE(fp, p);
1935 return (error);
1936 }
1937
1938 /*
1939 * Positional scatter read system call.
1940 */
1941 int
1942 sys_preadv(l, v, retval)
1943 struct lwp *l;
1944 void *v;
1945 register_t *retval;
1946 {
1947 struct sys_preadv_args /* {
1948 syscallarg(int) fd;
1949 syscallarg(const struct iovec *) iovp;
1950 syscallarg(int) iovcnt;
1951 syscallarg(off_t) offset;
1952 } */ *uap = v;
1953 struct proc *p = l->l_proc;
1954 struct filedesc *fdp = p->p_fd;
1955 struct file *fp;
1956 struct vnode *vp;
1957 off_t offset;
1958 int error, fd = SCARG(uap, fd);
1959
1960 if ((fp = fd_getfile(fdp, fd)) == NULL)
1961 return (EBADF);
1962
1963 if ((fp->f_flag & FREAD) == 0) {
1964 simple_unlock(&fp->f_slock);
1965 return (EBADF);
1966 }
1967
1968 FILE_USE(fp);
1969
1970 vp = (struct vnode *)fp->f_data;
1971 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
1972 error = ESPIPE;
1973 goto out;
1974 }
1975
1976 offset = SCARG(uap, offset);
1977
1978 /*
1979 * XXX This works because no file systems actually
1980 * XXX take any action on the seek operation.
1981 */
1982 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
1983 goto out;
1984
1985 /* dofilereadv() will unuse the descriptor for us */
1986 return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
1987 &offset, 0, retval));
1988
1989 out:
1990 FILE_UNUSE(fp, p);
1991 return (error);
1992 }
1993
1994 /*
1995 * Positional write system call.
1996 */
1997 int
1998 sys_pwrite(l, v, retval)
1999 struct lwp *l;
2000 void *v;
2001 register_t *retval;
2002 {
2003 struct sys_pwrite_args /* {
2004 syscallarg(int) fd;
2005 syscallarg(const void *) buf;
2006 syscallarg(size_t) nbyte;
2007 syscallarg(off_t) offset;
2008 } */ *uap = v;
2009 struct proc *p = l->l_proc;
2010 struct filedesc *fdp = p->p_fd;
2011 struct file *fp;
2012 struct vnode *vp;
2013 off_t offset;
2014 int error, fd = SCARG(uap, fd);
2015
2016 if ((fp = fd_getfile(fdp, fd)) == NULL)
2017 return (EBADF);
2018
2019 if ((fp->f_flag & FWRITE) == 0) {
2020 simple_unlock(&fp->f_slock);
2021 return (EBADF);
2022 }
2023
2024 FILE_USE(fp);
2025
2026 vp = (struct vnode *)fp->f_data;
2027 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2028 error = ESPIPE;
2029 goto out;
2030 }
2031
2032 offset = SCARG(uap, offset);
2033
2034 /*
2035 * XXX This works because no file systems actually
2036 * XXX take any action on the seek operation.
2037 */
2038 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2039 goto out;
2040
2041 /* dofilewrite() will unuse the descriptor for us */
2042 return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2043 &offset, 0, retval));
2044
2045 out:
2046 FILE_UNUSE(fp, p);
2047 return (error);
2048 }
2049
2050 /*
2051 * Positional gather write system call.
2052 */
2053 int
2054 sys_pwritev(l, v, retval)
2055 struct lwp *l;
2056 void *v;
2057 register_t *retval;
2058 {
2059 struct sys_pwritev_args /* {
2060 syscallarg(int) fd;
2061 syscallarg(const struct iovec *) iovp;
2062 syscallarg(int) iovcnt;
2063 syscallarg(off_t) offset;
2064 } */ *uap = v;
2065 struct proc *p = l->l_proc;
2066 struct filedesc *fdp = p->p_fd;
2067 struct file *fp;
2068 struct vnode *vp;
2069 off_t offset;
2070 int error, fd = SCARG(uap, fd);
2071
2072 if ((fp = fd_getfile(fdp, fd)) == NULL)
2073 return (EBADF);
2074
2075 if ((fp->f_flag & FWRITE) == 0) {
2076 simple_unlock(&fp->f_slock);
2077 return (EBADF);
2078 }
2079
2080 FILE_USE(fp);
2081
2082 vp = (struct vnode *)fp->f_data;
2083 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2084 error = ESPIPE;
2085 goto out;
2086 }
2087
2088 offset = SCARG(uap, offset);
2089
2090 /*
2091 * XXX This works because no file systems actually
2092 * XXX take any action on the seek operation.
2093 */
2094 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
2095 goto out;
2096
2097 /* dofilewritev() will unuse the descriptor for us */
2098 return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
2099 &offset, 0, retval));
2100
2101 out:
2102 FILE_UNUSE(fp, p);
2103 return (error);
2104 }
2105
2106 /*
2107 * Check access permissions.
2108 */
2109 int
2110 sys_access(l, v, retval)
2111 struct lwp *l;
2112 void *v;
2113 register_t *retval;
2114 {
2115 struct sys_access_args /* {
2116 syscallarg(const char *) path;
2117 syscallarg(int) flags;
2118 } */ *uap = v;
2119 struct proc *p = l->l_proc;
2120 struct ucred *cred = crget();
2121 struct vnode *vp;
2122 int error, flags;
2123 struct nameidata nd;
2124
2125 (void)memcpy(cred, p->p_ucred, sizeof(*cred));
2126 cred->cr_ref = 1;
2127 cred->cr_uid = p->p_cred->p_ruid;
2128 cred->cr_gid = p->p_cred->p_rgid;
2129 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2130 SCARG(uap, path), p);
2131 /* Override default credentials */
2132 nd.ni_cnd.cn_cred = cred;
2133 if ((error = namei(&nd)) != 0)
2134 goto out;
2135 vp = nd.ni_vp;
2136
2137 /* Flags == 0 means only check for existence. */
2138 if (SCARG(uap, flags)) {
2139 flags = 0;
2140 if (SCARG(uap, flags) & R_OK)
2141 flags |= VREAD;
2142 if (SCARG(uap, flags) & W_OK)
2143 flags |= VWRITE;
2144 if (SCARG(uap, flags) & X_OK)
2145 flags |= VEXEC;
2146
2147 error = VOP_ACCESS(vp, flags, cred, p);
2148 if (!error && (flags & VWRITE))
2149 error = vn_writechk(vp);
2150 }
2151 vput(vp);
2152 out:
2153 crfree(cred);
2154 return (error);
2155 }
2156
2157 /*
2158 * Get file status; this version follows links.
2159 */
2160 /* ARGSUSED */
2161 int
2162 sys___stat13(l, v, retval)
2163 struct lwp *l;
2164 void *v;
2165 register_t *retval;
2166 {
2167 struct sys___stat13_args /* {
2168 syscallarg(const char *) path;
2169 syscallarg(struct stat *) ub;
2170 } */ *uap = v;
2171 struct proc *p = l->l_proc;
2172 struct stat sb;
2173 int error;
2174 struct nameidata nd;
2175
2176 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2177 SCARG(uap, path), p);
2178 if ((error = namei(&nd)) != 0)
2179 return (error);
2180 error = vn_stat(nd.ni_vp, &sb, p);
2181 vput(nd.ni_vp);
2182 if (error)
2183 return (error);
2184 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
2185 return (error);
2186 }
2187
2188 /*
2189 * Get file status; this version does not follow links.
2190 */
2191 /* ARGSUSED */
2192 int
2193 sys___lstat13(l, v, retval)
2194 struct lwp *l;
2195 void *v;
2196 register_t *retval;
2197 {
2198 struct sys___lstat13_args /* {
2199 syscallarg(const char *) path;
2200 syscallarg(struct stat *) ub;
2201 } */ *uap = v;
2202 struct proc *p = l->l_proc;
2203 struct stat sb;
2204 int error;
2205 struct nameidata nd;
2206
2207 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
2208 SCARG(uap, path), p);
2209 if ((error = namei(&nd)) != 0)
2210 return (error);
2211 error = vn_stat(nd.ni_vp, &sb, p);
2212 vput(nd.ni_vp);
2213 if (error)
2214 return (error);
2215 error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
2216 return (error);
2217 }
2218
2219 /*
2220 * Get configurable pathname variables.
2221 */
2222 /* ARGSUSED */
2223 int
2224 sys_pathconf(l, v, retval)
2225 struct lwp *l;
2226 void *v;
2227 register_t *retval;
2228 {
2229 struct sys_pathconf_args /* {
2230 syscallarg(const char *) path;
2231 syscallarg(int) name;
2232 } */ *uap = v;
2233 struct proc *p = l->l_proc;
2234 int error;
2235 struct nameidata nd;
2236
2237 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
2238 SCARG(uap, path), p);
2239 if ((error = namei(&nd)) != 0)
2240 return (error);
2241 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
2242 vput(nd.ni_vp);
2243 return (error);
2244 }
2245
2246 /*
2247 * Return target name of a symbolic link.
2248 */
2249 /* ARGSUSED */
2250 int
2251 sys_readlink(l, v, retval)
2252 struct lwp *l;
2253 void *v;
2254 register_t *retval;
2255 {
2256 struct sys_readlink_args /* {
2257 syscallarg(const char *) path;
2258 syscallarg(char *) buf;
2259 syscallarg(size_t) count;
2260 } */ *uap = v;
2261 struct proc *p = l->l_proc;
2262 struct vnode *vp;
2263 struct iovec aiov;
2264 struct uio auio;
2265 int error;
2266 struct nameidata nd;
2267
2268 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
2269 SCARG(uap, path), p);
2270 if ((error = namei(&nd)) != 0)
2271 return (error);
2272 vp = nd.ni_vp;
2273 if (vp->v_type != VLNK)
2274 error = EINVAL;
2275 else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
2276 (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) == 0) {
2277 aiov.iov_base = SCARG(uap, buf);
2278 aiov.iov_len = SCARG(uap, count);
2279 auio.uio_iov = &aiov;
2280 auio.uio_iovcnt = 1;
2281 auio.uio_offset = 0;
2282 auio.uio_rw = UIO_READ;
2283 auio.uio_segflg = UIO_USERSPACE;
2284 auio.uio_procp = p;
2285 auio.uio_resid = SCARG(uap, count);
2286 error = VOP_READLINK(vp, &auio, p->p_ucred);
2287 }
2288 vput(vp);
2289 *retval = SCARG(uap, count) - auio.uio_resid;
2290 return (error);
2291 }
2292
2293 /*
2294 * Change flags of a file given a path name.
2295 */
2296 /* ARGSUSED */
2297 int
2298 sys_chflags(l, v, retval)
2299 struct lwp *l;
2300 void *v;
2301 register_t *retval;
2302 {
2303 struct sys_chflags_args /* {
2304 syscallarg(const char *) path;
2305 syscallarg(u_long) flags;
2306 } */ *uap = v;
2307 struct proc *p = l->l_proc;
2308 struct vnode *vp;
2309 int error;
2310 struct nameidata nd;
2311
2312 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2313 if ((error = namei(&nd)) != 0)
2314 return (error);
2315 vp = nd.ni_vp;
2316 error = change_flags(vp, SCARG(uap, flags), p);
2317 vput(vp);
2318 return (error);
2319 }
2320
2321 /*
2322 * Change flags of a file given a file descriptor.
2323 */
2324 /* ARGSUSED */
2325 int
2326 sys_fchflags(l, v, retval)
2327 struct lwp *l;
2328 void *v;
2329 register_t *retval;
2330 {
2331 struct sys_fchflags_args /* {
2332 syscallarg(int) fd;
2333 syscallarg(u_long) flags;
2334 } */ *uap = v;
2335 struct proc *p = l->l_proc;
2336 struct vnode *vp;
2337 struct file *fp;
2338 int error;
2339
2340 /* getvnode() will use the descriptor for us */
2341 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2342 return (error);
2343 vp = (struct vnode *)fp->f_data;
2344 error = change_flags(vp, SCARG(uap, flags), p);
2345 VOP_UNLOCK(vp, 0);
2346 FILE_UNUSE(fp, p);
2347 return (error);
2348 }
2349
2350 /*
2351 * Change flags of a file given a path name; this version does
2352 * not follow links.
2353 */
2354 int
2355 sys_lchflags(l, v, retval)
2356 struct lwp *l;
2357 void *v;
2358 register_t *retval;
2359 {
2360 struct sys_lchflags_args /* {
2361 syscallarg(const char *) path;
2362 syscallarg(u_long) flags;
2363 } */ *uap = v;
2364 struct proc *p = l->l_proc;
2365 struct vnode *vp;
2366 int error;
2367 struct nameidata nd;
2368
2369 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2370 if ((error = namei(&nd)) != 0)
2371 return (error);
2372 vp = nd.ni_vp;
2373 error = change_flags(vp, SCARG(uap, flags), p);
2374 vput(vp);
2375 return (error);
2376 }
2377
2378 /*
2379 * Common routine to change flags of a file.
2380 */
2381 int
2382 change_flags(vp, flags, p)
2383 struct vnode *vp;
2384 u_long flags;
2385 struct proc *p;
2386 {
2387 struct mount *mp;
2388 struct vattr vattr;
2389 int error;
2390
2391 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2392 return (error);
2393 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2394 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2395 /*
2396 * Non-superusers cannot change the flags on devices, even if they
2397 * own them.
2398 */
2399 if (suser(p->p_ucred, &p->p_acflag) != 0) {
2400 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2401 goto out;
2402 if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
2403 error = EINVAL;
2404 goto out;
2405 }
2406 }
2407 VATTR_NULL(&vattr);
2408 vattr.va_flags = flags;
2409 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2410 out:
2411 vn_finished_write(mp, 0);
2412 return (error);
2413 }
2414
2415 /*
2416 * Change mode of a file given path name; this version follows links.
2417 */
2418 /* ARGSUSED */
2419 int
2420 sys_chmod(l, v, retval)
2421 struct lwp *l;
2422 void *v;
2423 register_t *retval;
2424 {
2425 struct sys_chmod_args /* {
2426 syscallarg(const char *) path;
2427 syscallarg(int) mode;
2428 } */ *uap = v;
2429 struct proc *p = l->l_proc;
2430 int error;
2431 struct nameidata nd;
2432
2433 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2434 if ((error = namei(&nd)) != 0)
2435 return (error);
2436
2437 error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
2438
2439 vrele(nd.ni_vp);
2440 return (error);
2441 }
2442
2443 /*
2444 * Change mode of a file given a file descriptor.
2445 */
2446 /* ARGSUSED */
2447 int
2448 sys_fchmod(l, v, retval)
2449 struct lwp *l;
2450 void *v;
2451 register_t *retval;
2452 {
2453 struct sys_fchmod_args /* {
2454 syscallarg(int) fd;
2455 syscallarg(int) mode;
2456 } */ *uap = v;
2457 struct proc *p = l->l_proc;
2458 struct file *fp;
2459 int error;
2460
2461 /* getvnode() will use the descriptor for us */
2462 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2463 return (error);
2464
2465 error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), p);
2466 FILE_UNUSE(fp, p);
2467 return (error);
2468 }
2469
2470 /*
2471 * Change mode of a file given path name; this version does not follow links.
2472 */
2473 /* ARGSUSED */
2474 int
2475 sys_lchmod(l, v, retval)
2476 struct lwp *l;
2477 void *v;
2478 register_t *retval;
2479 {
2480 struct sys_lchmod_args /* {
2481 syscallarg(const char *) path;
2482 syscallarg(int) mode;
2483 } */ *uap = v;
2484 struct proc *p = l->l_proc;
2485 int error;
2486 struct nameidata nd;
2487
2488 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2489 if ((error = namei(&nd)) != 0)
2490 return (error);
2491
2492 error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
2493
2494 vrele(nd.ni_vp);
2495 return (error);
2496 }
2497
2498 /*
2499 * Common routine to set mode given a vnode.
2500 */
2501 static int
2502 change_mode(vp, mode, p)
2503 struct vnode *vp;
2504 int mode;
2505 struct proc *p;
2506 {
2507 struct mount *mp;
2508 struct vattr vattr;
2509 int error;
2510
2511 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2512 return (error);
2513 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2514 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2515 VATTR_NULL(&vattr);
2516 vattr.va_mode = mode & ALLPERMS;
2517 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2518 VOP_UNLOCK(vp, 0);
2519 vn_finished_write(mp, 0);
2520 return (error);
2521 }
2522
2523 /*
2524 * Set ownership given a path name; this version follows links.
2525 */
2526 /* ARGSUSED */
2527 int
2528 sys_chown(l, v, retval)
2529 struct lwp *l;
2530 void *v;
2531 register_t *retval;
2532 {
2533 struct sys_chown_args /* {
2534 syscallarg(const char *) path;
2535 syscallarg(uid_t) uid;
2536 syscallarg(gid_t) gid;
2537 } */ *uap = v;
2538 struct proc *p = l->l_proc;
2539 int error;
2540 struct nameidata nd;
2541
2542 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2543 if ((error = namei(&nd)) != 0)
2544 return (error);
2545
2546 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
2547
2548 vrele(nd.ni_vp);
2549 return (error);
2550 }
2551
2552 /*
2553 * Set ownership given a path name; this version follows links.
2554 * Provides POSIX semantics.
2555 */
2556 /* ARGSUSED */
2557 int
2558 sys___posix_chown(l, v, retval)
2559 struct lwp *l;
2560 void *v;
2561 register_t *retval;
2562 {
2563 struct sys_chown_args /* {
2564 syscallarg(const char *) path;
2565 syscallarg(uid_t) uid;
2566 syscallarg(gid_t) gid;
2567 } */ *uap = v;
2568 struct proc *p = l->l_proc;
2569 int error;
2570 struct nameidata nd;
2571
2572 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2573 if ((error = namei(&nd)) != 0)
2574 return (error);
2575
2576 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
2577
2578 vrele(nd.ni_vp);
2579 return (error);
2580 }
2581
2582 /*
2583 * Set ownership given a file descriptor.
2584 */
2585 /* ARGSUSED */
2586 int
2587 sys_fchown(l, v, retval)
2588 struct lwp *l;
2589 void *v;
2590 register_t *retval;
2591 {
2592 struct sys_fchown_args /* {
2593 syscallarg(int) fd;
2594 syscallarg(uid_t) uid;
2595 syscallarg(gid_t) gid;
2596 } */ *uap = v;
2597 struct proc *p = l->l_proc;
2598 int error;
2599 struct file *fp;
2600
2601 /* getvnode() will use the descriptor for us */
2602 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2603 return (error);
2604
2605 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2606 SCARG(uap, gid), p, 0);
2607 FILE_UNUSE(fp, p);
2608 return (error);
2609 }
2610
2611 /*
2612 * Set ownership given a file descriptor, providing POSIX/XPG semantics.
2613 */
2614 /* ARGSUSED */
2615 int
2616 sys___posix_fchown(l, v, retval)
2617 struct lwp *l;
2618 void *v;
2619 register_t *retval;
2620 {
2621 struct sys_fchown_args /* {
2622 syscallarg(int) fd;
2623 syscallarg(uid_t) uid;
2624 syscallarg(gid_t) gid;
2625 } */ *uap = v;
2626 struct proc *p = l->l_proc;
2627 int error;
2628 struct file *fp;
2629
2630 /* getvnode() will use the descriptor for us */
2631 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2632 return (error);
2633
2634 error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
2635 SCARG(uap, gid), p, 1);
2636 FILE_UNUSE(fp, p);
2637 return (error);
2638 }
2639
2640 /*
2641 * Set ownership given a path name; this version does not follow links.
2642 */
2643 /* ARGSUSED */
2644 int
2645 sys_lchown(l, v, retval)
2646 struct lwp *l;
2647 void *v;
2648 register_t *retval;
2649 {
2650 struct sys_lchown_args /* {
2651 syscallarg(const char *) path;
2652 syscallarg(uid_t) uid;
2653 syscallarg(gid_t) gid;
2654 } */ *uap = v;
2655 struct proc *p = l->l_proc;
2656 int error;
2657 struct nameidata nd;
2658
2659 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2660 if ((error = namei(&nd)) != 0)
2661 return (error);
2662
2663 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
2664
2665 vrele(nd.ni_vp);
2666 return (error);
2667 }
2668
2669 /*
2670 * Set ownership given a path name; this version does not follow links.
2671 * Provides POSIX/XPG semantics.
2672 */
2673 /* ARGSUSED */
2674 int
2675 sys___posix_lchown(l, v, retval)
2676 struct lwp *l;
2677 void *v;
2678 register_t *retval;
2679 {
2680 struct sys_lchown_args /* {
2681 syscallarg(const char *) path;
2682 syscallarg(uid_t) uid;
2683 syscallarg(gid_t) gid;
2684 } */ *uap = v;
2685 struct proc *p = l->l_proc;
2686 int error;
2687 struct nameidata nd;
2688
2689 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2690 if ((error = namei(&nd)) != 0)
2691 return (error);
2692
2693 error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
2694
2695 vrele(nd.ni_vp);
2696 return (error);
2697 }
2698
2699 /*
2700 * Common routine to set ownership given a vnode.
2701 */
2702 static int
2703 change_owner(vp, uid, gid, p, posix_semantics)
2704 struct vnode *vp;
2705 uid_t uid;
2706 gid_t gid;
2707 struct proc *p;
2708 int posix_semantics;
2709 {
2710 struct mount *mp;
2711 struct vattr vattr;
2712 mode_t newmode;
2713 int error;
2714
2715 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2716 return (error);
2717 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2718 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2719 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2720 goto out;
2721
2722 #define CHANGED(x) ((int)(x) != -1)
2723 newmode = vattr.va_mode;
2724 if (posix_semantics) {
2725 /*
2726 * POSIX/XPG semantics: if the caller is not the super-user,
2727 * clear set-user-id and set-group-id bits. Both POSIX and
2728 * the XPG consider the behaviour for calls by the super-user
2729 * implementation-defined; we leave the set-user-id and set-
2730 * group-id settings intact in that case.
2731 */
2732 if (suser(p->p_ucred, NULL) != 0)
2733 newmode &= ~(S_ISUID | S_ISGID);
2734 } else {
2735 /*
2736 * NetBSD semantics: when changing owner and/or group,
2737 * clear the respective bit(s).
2738 */
2739 if (CHANGED(uid))
2740 newmode &= ~S_ISUID;
2741 if (CHANGED(gid))
2742 newmode &= ~S_ISGID;
2743 }
2744 /* Update va_mode iff altered. */
2745 if (vattr.va_mode == newmode)
2746 newmode = VNOVAL;
2747
2748 VATTR_NULL(&vattr);
2749 vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
2750 vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
2751 vattr.va_mode = newmode;
2752 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2753 #undef CHANGED
2754
2755 out:
2756 VOP_UNLOCK(vp, 0);
2757 vn_finished_write(mp, 0);
2758 return (error);
2759 }
2760
2761 /*
2762 * Set the access and modification times given a path name; this
2763 * version follows links.
2764 */
2765 /* ARGSUSED */
2766 int
2767 sys_utimes(l, v, retval)
2768 struct lwp *l;
2769 void *v;
2770 register_t *retval;
2771 {
2772 struct sys_utimes_args /* {
2773 syscallarg(const char *) path;
2774 syscallarg(const struct timeval *) tptr;
2775 } */ *uap = v;
2776 struct proc *p = l->l_proc;
2777 int error;
2778 struct nameidata nd;
2779
2780 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2781 if ((error = namei(&nd)) != 0)
2782 return (error);
2783
2784 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
2785
2786 vrele(nd.ni_vp);
2787 return (error);
2788 }
2789
2790 /*
2791 * Set the access and modification times given a file descriptor.
2792 */
2793 /* ARGSUSED */
2794 int
2795 sys_futimes(l, v, retval)
2796 struct lwp *l;
2797 void *v;
2798 register_t *retval;
2799 {
2800 struct sys_futimes_args /* {
2801 syscallarg(int) fd;
2802 syscallarg(const struct timeval *) tptr;
2803 } */ *uap = v;
2804 struct proc *p = l->l_proc;
2805 int error;
2806 struct file *fp;
2807
2808 /* getvnode() will use the descriptor for us */
2809 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2810 return (error);
2811
2812 error = change_utimes((struct vnode *)fp->f_data, SCARG(uap, tptr), p);
2813 FILE_UNUSE(fp, p);
2814 return (error);
2815 }
2816
2817 /*
2818 * Set the access and modification times given a path name; this
2819 * version does not follow links.
2820 */
2821 /* ARGSUSED */
2822 int
2823 sys_lutimes(l, v, retval)
2824 struct lwp *l;
2825 void *v;
2826 register_t *retval;
2827 {
2828 struct sys_lutimes_args /* {
2829 syscallarg(const char *) path;
2830 syscallarg(const struct timeval *) tptr;
2831 } */ *uap = v;
2832 struct proc *p = l->l_proc;
2833 int error;
2834 struct nameidata nd;
2835
2836 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2837 if ((error = namei(&nd)) != 0)
2838 return (error);
2839
2840 error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
2841
2842 vrele(nd.ni_vp);
2843 return (error);
2844 }
2845
2846 /*
2847 * Common routine to set access and modification times given a vnode.
2848 */
2849 static int
2850 change_utimes(vp, tptr, p)
2851 struct vnode *vp;
2852 const struct timeval *tptr;
2853 struct proc *p;
2854 {
2855 struct timeval tv[2];
2856 struct mount *mp;
2857 struct vattr vattr;
2858 int error;
2859
2860 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
2861 return (error);
2862 VATTR_NULL(&vattr);
2863 if (tptr == NULL) {
2864 microtime(&tv[0]);
2865 tv[1] = tv[0];
2866 vattr.va_vaflags |= VA_UTIMES_NULL;
2867 } else {
2868 error = copyin(tptr, tv, sizeof(tv));
2869 if (error)
2870 goto out;
2871 }
2872 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2873 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2874 vattr.va_atime.tv_sec = tv[0].tv_sec;
2875 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
2876 vattr.va_mtime.tv_sec = tv[1].tv_sec;
2877 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
2878 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2879 VOP_UNLOCK(vp, 0);
2880 out:
2881 vn_finished_write(mp, 0);
2882 return (error);
2883 }
2884
2885 /*
2886 * Truncate a file given its path name.
2887 */
2888 /* ARGSUSED */
2889 int
2890 sys_truncate(l, v, retval)
2891 struct lwp *l;
2892 void *v;
2893 register_t *retval;
2894 {
2895 struct sys_truncate_args /* {
2896 syscallarg(const char *) path;
2897 syscallarg(int) pad;
2898 syscallarg(off_t) length;
2899 } */ *uap = v;
2900 struct proc *p = l->l_proc;
2901 struct vnode *vp;
2902 struct mount *mp;
2903 struct vattr vattr;
2904 int error;
2905 struct nameidata nd;
2906
2907 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2908 if ((error = namei(&nd)) != 0)
2909 return (error);
2910 vp = nd.ni_vp;
2911 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
2912 vrele(vp);
2913 return (error);
2914 }
2915 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2916 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2917 if (vp->v_type == VDIR)
2918 error = EISDIR;
2919 else if ((error = vn_writechk(vp)) == 0 &&
2920 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2921 VATTR_NULL(&vattr);
2922 vattr.va_size = SCARG(uap, length);
2923 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2924 }
2925 vput(vp);
2926 vn_finished_write(mp, 0);
2927 return (error);
2928 }
2929
2930 /*
2931 * Truncate a file given a file descriptor.
2932 */
2933 /* ARGSUSED */
2934 int
2935 sys_ftruncate(l, v, retval)
2936 struct lwp *l;
2937 void *v;
2938 register_t *retval;
2939 {
2940 struct sys_ftruncate_args /* {
2941 syscallarg(int) fd;
2942 syscallarg(int) pad;
2943 syscallarg(off_t) length;
2944 } */ *uap = v;
2945 struct proc *p = l->l_proc;
2946 struct mount *mp;
2947 struct vattr vattr;
2948 struct vnode *vp;
2949 struct file *fp;
2950 int error;
2951
2952 /* getvnode() will use the descriptor for us */
2953 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2954 return (error);
2955 if ((fp->f_flag & FWRITE) == 0) {
2956 error = EINVAL;
2957 goto out;
2958 }
2959 vp = (struct vnode *)fp->f_data;
2960 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
2961 FILE_UNUSE(fp, p);
2962 return (error);
2963 }
2964 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2965 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2966 if (vp->v_type == VDIR)
2967 error = EISDIR;
2968 else if ((error = vn_writechk(vp)) == 0) {
2969 VATTR_NULL(&vattr);
2970 vattr.va_size = SCARG(uap, length);
2971 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2972 }
2973 VOP_UNLOCK(vp, 0);
2974 vn_finished_write(mp, 0);
2975 out:
2976 FILE_UNUSE(fp, p);
2977 return (error);
2978 }
2979
2980 /*
2981 * Sync an open file.
2982 */
2983 /* ARGSUSED */
2984 int
2985 sys_fsync(l, v, retval)
2986 struct lwp *l;
2987 void *v;
2988 register_t *retval;
2989 {
2990 struct sys_fsync_args /* {
2991 syscallarg(int) fd;
2992 } */ *uap = v;
2993 struct proc *p = l->l_proc;
2994 struct vnode *vp;
2995 struct mount *mp;
2996 struct file *fp;
2997 int error;
2998
2999 /* getvnode() will use the descriptor for us */
3000 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3001 return (error);
3002 vp = (struct vnode *)fp->f_data;
3003 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
3004 FILE_UNUSE(fp, p);
3005 return (error);
3006 }
3007 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3008 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0, p);
3009 if (error == 0 && bioops.io_fsync != NULL &&
3010 vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
3011 (*bioops.io_fsync)(vp);
3012 VOP_UNLOCK(vp, 0);
3013 vn_finished_write(mp, 0);
3014 FILE_UNUSE(fp, p);
3015 return (error);
3016 }
3017
3018 /*
3019 * Sync a range of file data. API modeled after that found in AIX.
3020 *
3021 * FDATASYNC indicates that we need only save enough metadata to be able
3022 * to re-read the written data. Note we duplicate AIX's requirement that
3023 * the file be open for writing.
3024 */
3025 /* ARGSUSED */
3026 int
3027 sys_fsync_range(l, v, retval)
3028 struct lwp *l;
3029 void *v;
3030 register_t *retval;
3031 {
3032 struct sys_fsync_range_args /* {
3033 syscallarg(int) fd;
3034 syscallarg(int) flags;
3035 syscallarg(off_t) start;
3036 syscallarg(int) length;
3037 } */ *uap = v;
3038 struct proc *p = l->l_proc;
3039 struct vnode *vp;
3040 struct file *fp;
3041 int flags, nflags;
3042 off_t s, e, len;
3043 int error;
3044
3045 /* getvnode() will use the descriptor for us */
3046 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3047 return (error);
3048
3049 if ((fp->f_flag & FWRITE) == 0) {
3050 FILE_UNUSE(fp, p);
3051 return (EBADF);
3052 }
3053
3054 flags = SCARG(uap, flags);
3055 if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
3056 ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
3057 return (EINVAL);
3058 }
3059 /* Now set up the flags for value(s) to pass to VOP_FSYNC() */
3060 if (flags & FDATASYNC)
3061 nflags = FSYNC_DATAONLY | FSYNC_WAIT;
3062 else
3063 nflags = FSYNC_WAIT;
3064
3065 len = SCARG(uap, length);
3066 /* If length == 0, we do the whole file, and s = l = 0 will do that */
3067 if (len) {
3068 s = SCARG(uap, start);
3069 e = s + len;
3070 if (e < s) {
3071 FILE_UNUSE(fp, p);
3072 return (EINVAL);
3073 }
3074 } else {
3075 e = 0;
3076 s = 0;
3077 }
3078
3079 vp = (struct vnode *)fp->f_data;
3080 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3081 error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e, p);
3082
3083 if (error == 0 && bioops.io_fsync != NULL &&
3084 vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
3085 (*bioops.io_fsync)(vp);
3086
3087 VOP_UNLOCK(vp, 0);
3088 FILE_UNUSE(fp, p);
3089 return (error);
3090 }
3091
3092 /*
3093 * Sync the data of an open file.
3094 */
3095 /* ARGSUSED */
3096 int
3097 sys_fdatasync(l, v, retval)
3098 struct lwp *l;
3099 void *v;
3100 register_t *retval;
3101 {
3102 struct sys_fdatasync_args /* {
3103 syscallarg(int) fd;
3104 } */ *uap = v;
3105 struct proc *p = l->l_proc;
3106 struct vnode *vp;
3107 struct file *fp;
3108 int error;
3109
3110 /* getvnode() will use the descriptor for us */
3111 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3112 return (error);
3113 if ((fp->f_flag & FWRITE) == 0) {
3114 FILE_UNUSE(fp, p);
3115 return (EBADF);
3116 }
3117 vp = (struct vnode *)fp->f_data;
3118 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3119 error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0, p);
3120 VOP_UNLOCK(vp, 0);
3121 FILE_UNUSE(fp, p);
3122 return (error);
3123 }
3124
3125 /*
3126 * Rename files, (standard) BSD semantics frontend.
3127 */
3128 /* ARGSUSED */
3129 int
3130 sys_rename(l, v, retval)
3131 struct lwp *l;
3132 void *v;
3133 register_t *retval;
3134 {
3135 struct sys_rename_args /* {
3136 syscallarg(const char *) from;
3137 syscallarg(const char *) to;
3138 } */ *uap = v;
3139 struct proc *p = l->l_proc;
3140
3141 return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 0));
3142 }
3143
3144 /*
3145 * Rename files, POSIX semantics frontend.
3146 */
3147 /* ARGSUSED */
3148 int
3149 sys___posix_rename(l, v, retval)
3150 struct lwp *l;
3151 void *v;
3152 register_t *retval;
3153 {
3154 struct sys___posix_rename_args /* {
3155 syscallarg(const char *) from;
3156 syscallarg(const char *) to;
3157 } */ *uap = v;
3158 struct proc *p = l->l_proc;
3159
3160 return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 1));
3161 }
3162
3163 /*
3164 * Rename files. Source and destination must either both be directories,
3165 * or both not be directories. If target is a directory, it must be empty.
3166 * If `from' and `to' refer to the same object, the value of the `retain'
3167 * argument is used to determine whether `from' will be
3168 *
3169 * (retain == 0) deleted unless `from' and `to' refer to the same
3170 * object in the file system's name space (BSD).
3171 * (retain == 1) always retained (POSIX).
3172 */
3173 static int
3174 rename_files(from, to, p, retain)
3175 const char *from, *to;
3176 struct proc *p;
3177 int retain;
3178 {
3179 struct mount *mp = NULL;
3180 struct vnode *tvp, *fvp, *tdvp;
3181 struct nameidata fromnd, tond;
3182 int error;
3183
3184 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
3185 from, p);
3186 if ((error = namei(&fromnd)) != 0)
3187 return (error);
3188 fvp = fromnd.ni_vp;
3189 error = vn_start_write(fvp, &mp, V_WAIT | V_PCATCH);
3190 if (error != 0) {
3191 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3192 vrele(fromnd.ni_dvp);
3193 vrele(fvp);
3194 if (fromnd.ni_startdir)
3195 vrele(fromnd.ni_startdir);
3196 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
3197 return (error);
3198 }
3199 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
3200 (fvp->v_type == VDIR ? CREATEDIR : 0), UIO_USERSPACE, to, p);
3201 if ((error = namei(&tond)) != 0) {
3202 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3203 vrele(fromnd.ni_dvp);
3204 vrele(fvp);
3205 goto out1;
3206 }
3207 tdvp = tond.ni_dvp;
3208 tvp = tond.ni_vp;
3209
3210 if (tvp != NULL) {
3211 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3212 error = ENOTDIR;
3213 goto out;
3214 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3215 error = EISDIR;
3216 goto out;
3217 }
3218 }
3219
3220 if (fvp == tdvp)
3221 error = EINVAL;
3222
3223 /*
3224 * Source and destination refer to the same object.
3225 */
3226 if (fvp == tvp) {
3227 if (retain)
3228 error = -1;
3229 else if (fromnd.ni_dvp == tdvp &&
3230 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
3231 !memcmp(fromnd.ni_cnd.cn_nameptr,
3232 tond.ni_cnd.cn_nameptr,
3233 fromnd.ni_cnd.cn_namelen))
3234 error = -1;
3235 }
3236
3237 out:
3238 if (!error) {
3239 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
3240 if (fromnd.ni_dvp != tdvp)
3241 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
3242 if (tvp) {
3243 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
3244 }
3245 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3246 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3247 } else {
3248 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
3249 if (tdvp == tvp)
3250 vrele(tdvp);
3251 else
3252 vput(tdvp);
3253 if (tvp)
3254 vput(tvp);
3255 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
3256 vrele(fromnd.ni_dvp);
3257 vrele(fvp);
3258 }
3259 vrele(tond.ni_startdir);
3260 PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
3261 out1:
3262 vn_finished_write(mp, 0);
3263 if (fromnd.ni_startdir)
3264 vrele(fromnd.ni_startdir);
3265 PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
3266 return (error == -1 ? 0 : error);
3267 }
3268
3269 /*
3270 * Make a directory file.
3271 */
3272 /* ARGSUSED */
3273 int
3274 sys_mkdir(l, v, retval)
3275 struct lwp *l;
3276 void *v;
3277 register_t *retval;
3278 {
3279 struct sys_mkdir_args /* {
3280 syscallarg(const char *) path;
3281 syscallarg(int) mode;
3282 } */ *uap = v;
3283 struct proc *p = l->l_proc;
3284 struct mount *mp;
3285 struct vnode *vp;
3286 struct vattr vattr;
3287 int error;
3288 struct nameidata nd;
3289
3290 restart:
3291 NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR, UIO_USERSPACE,
3292 SCARG(uap, path), p);
3293 if ((error = namei(&nd)) != 0)
3294 return (error);
3295 vp = nd.ni_vp;
3296 if (vp != NULL) {
3297 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3298 if (nd.ni_dvp == vp)
3299 vrele(nd.ni_dvp);
3300 else
3301 vput(nd.ni_dvp);
3302 vrele(vp);
3303 return (EEXIST);
3304 }
3305 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3306 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3307 if (nd.ni_dvp == vp)
3308 vrele(nd.ni_dvp);
3309 else
3310 vput(nd.ni_dvp);
3311 if ((error = vn_start_write(NULL, &mp,
3312 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3313 return (error);
3314 goto restart;
3315 }
3316 VATTR_NULL(&vattr);
3317 vattr.va_type = VDIR;
3318 vattr.va_mode =
3319 (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
3320 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
3321 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3322 if (!error)
3323 vput(nd.ni_vp);
3324 vn_finished_write(mp, 0);
3325 return (error);
3326 }
3327
3328 /*
3329 * Remove a directory file.
3330 */
3331 /* ARGSUSED */
3332 int
3333 sys_rmdir(l, v, retval)
3334 struct lwp *l;
3335 void *v;
3336 register_t *retval;
3337 {
3338 struct sys_rmdir_args /* {
3339 syscallarg(const char *) path;
3340 } */ *uap = v;
3341 struct proc *p = l->l_proc;
3342 struct mount *mp;
3343 struct vnode *vp;
3344 int error;
3345 struct nameidata nd;
3346
3347 restart:
3348 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
3349 SCARG(uap, path), p);
3350 if ((error = namei(&nd)) != 0)
3351 return (error);
3352 vp = nd.ni_vp;
3353 if (vp->v_type != VDIR) {
3354 error = ENOTDIR;
3355 goto out;
3356 }
3357 /*
3358 * No rmdir "." please.
3359 */
3360 if (nd.ni_dvp == vp) {
3361 error = EINVAL;
3362 goto out;
3363 }
3364 /*
3365 * The root of a mounted filesystem cannot be deleted.
3366 */
3367 if (vp->v_flag & VROOT) {
3368 error = EBUSY;
3369 goto out;
3370 }
3371 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3372 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3373 if (nd.ni_dvp == vp)
3374 vrele(nd.ni_dvp);
3375 else
3376 vput(nd.ni_dvp);
3377 vput(vp);
3378 if ((error = vn_start_write(NULL, &mp,
3379 V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
3380 return (error);
3381 goto restart;
3382 }
3383 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
3384 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
3385 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3386 vn_finished_write(mp, 0);
3387 return (error);
3388
3389 out:
3390 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
3391 if (nd.ni_dvp == vp)
3392 vrele(nd.ni_dvp);
3393 else
3394 vput(nd.ni_dvp);
3395 vput(vp);
3396 return (error);
3397 }
3398
3399 /*
3400 * Read a block of directory entries in a file system independent format.
3401 */
3402 int
3403 sys_getdents(l, v, retval)
3404 struct lwp *l;
3405 void *v;
3406 register_t *retval;
3407 {
3408 struct sys_getdents_args /* {
3409 syscallarg(int) fd;
3410 syscallarg(char *) buf;
3411 syscallarg(size_t) count;
3412 } */ *uap = v;
3413 struct proc *p = l->l_proc;
3414 struct file *fp;
3415 int error, done;
3416
3417 /* getvnode() will use the descriptor for us */
3418 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
3419 return (error);
3420 if ((fp->f_flag & FREAD) == 0) {
3421 error = EBADF;
3422 goto out;
3423 }
3424 error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
3425 SCARG(uap, count), &done, p, 0, 0);
3426 #ifdef KTRACE
3427 if (!error && KTRPOINT(p, KTR_GENIO)) {
3428 struct iovec iov;
3429 iov.iov_base = SCARG(uap, buf);
3430 iov.iov_len = done;
3431 ktrgenio(p, SCARG(uap, fd), UIO_READ, &iov, done, 0);
3432 }
3433 #endif
3434 *retval = done;
3435 out:
3436 FILE_UNUSE(fp, p);
3437 return (error);
3438 }
3439
3440 /*
3441 * Set the mode mask for creation of filesystem nodes.
3442 */
3443 int
3444 sys_umask(l, v, retval)
3445 struct lwp *l;
3446 void *v;
3447 register_t *retval;
3448 {
3449 struct sys_umask_args /* {
3450 syscallarg(mode_t) newmask;
3451 } */ *uap = v;
3452 struct proc *p = l->l_proc;
3453 struct cwdinfo *cwdi;
3454
3455 cwdi = p->p_cwdi;
3456 *retval = cwdi->cwdi_cmask;
3457 cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
3458 return (0);
3459 }
3460
3461 /*
3462 * Void all references to file by ripping underlying filesystem
3463 * away from vnode.
3464 */
3465 /* ARGSUSED */
3466 int
3467 sys_revoke(l, v, retval)
3468 struct lwp *l;
3469 void *v;
3470 register_t *retval;
3471 {
3472 struct sys_revoke_args /* {
3473 syscallarg(const char *) path;
3474 } */ *uap = v;
3475 struct proc *p = l->l_proc;
3476 struct mount *mp;
3477 struct vnode *vp;
3478 struct vattr vattr;
3479 int error;
3480 struct nameidata nd;
3481
3482 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
3483 if ((error = namei(&nd)) != 0)
3484 return (error);
3485 vp = nd.ni_vp;
3486 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
3487 goto out;
3488 if (p->p_ucred->cr_uid != vattr.va_uid &&
3489 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
3490 goto out;
3491 if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
3492 goto out;
3493 if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER)))
3494 VOP_REVOKE(vp, REVOKEALL);
3495 vn_finished_write(mp, 0);
3496 out:
3497 vrele(vp);
3498 return (error);
3499 }
3500
3501 /*
3502 * Convert a user file descriptor to a kernel file entry.
3503 */
3504 int
3505 getvnode(fdp, fd, fpp)
3506 struct filedesc *fdp;
3507 int fd;
3508 struct file **fpp;
3509 {
3510 struct vnode *vp;
3511 struct file *fp;
3512
3513 if ((fp = fd_getfile(fdp, fd)) == NULL)
3514 return (EBADF);
3515
3516 FILE_USE(fp);
3517
3518 if (fp->f_type != DTYPE_VNODE) {
3519 FILE_UNUSE(fp, NULL);
3520 return (EINVAL);
3521 }
3522
3523 vp = (struct vnode *)fp->f_data;
3524 if (vp->v_type == VBAD) {
3525 FILE_UNUSE(fp, NULL);
3526 return (EBADF);
3527 }
3528
3529 *fpp = fp;
3530 return (0);
3531 }
3532