oops, forgot one. Remove another curproc/cred dependancy
[dragonfly.git] / sys / kern / vfs_syscalls.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94
39 * $FreeBSD: src/sys/kern/vfs_syscalls.c,v 1.151.2.18 2003/04/04 20:35:58 tegge Exp $
0cfcada1 40 * $DragonFly: src/sys/kern/vfs_syscalls.c,v 1.7 2003/06/27 01:53:25 dillon Exp $
984263bc
MD
41 */
42
43/* For 4.3 integer FS ID compatibility */
44#include "opt_compat.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/buf.h>
49#include <sys/sysent.h>
50#include <sys/malloc.h>
51#include <sys/mount.h>
52#include <sys/sysproto.h>
984263bc
MD
53#include <sys/filedesc.h>
54#include <sys/kernel.h>
55#include <sys/fcntl.h>
56#include <sys/file.h>
57#include <sys/linker.h>
58#include <sys/stat.h>
59#include <sys/unistd.h>
60#include <sys/vnode.h>
61#include <sys/proc.h>
dadab5e9 62#include <sys/namei.h>
984263bc
MD
63#include <sys/dirent.h>
64#include <sys/extattr.h>
65
66#include <machine/limits.h>
67#include <miscfs/union/union.h>
68#include <sys/sysctl.h>
69#include <vm/vm.h>
70#include <vm/vm_object.h>
71#include <vm/vm_zone.h>
72#include <vm/vm_page.h>
73
dadab5e9
MD
74#include <sys/file2.h>
75
76static int change_dir __P((struct nameidata *ndp, struct thread *td));
984263bc
MD
77static void checkdirs __P((struct vnode *olddp));
78static int chroot_refuse_vdir_fds __P((struct filedesc *fdp));
79static int getutimes __P((const struct timeval *, struct timespec *));
41c20dac
MD
80static int setfown __P((struct vnode *, uid_t, gid_t));
81static int setfmode __P((struct vnode *, int));
82static int setfflags __P((struct vnode *, int));
83static int setutimes __P((struct vnode *, const struct timespec *, int));
984263bc
MD
84static int usermount = 0; /* if 1, non-root can mount fs. */
85
dadab5e9 86int (*union_dircheckp) __P((struct thread *, struct vnode **, struct file *));
984263bc
MD
87
88SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
89
90/*
91 * Virtual File System System Calls
92 */
93
94/*
95 * Mount a file system.
96 */
97#ifndef _SYS_SYSPROTO_H_
98struct mount_args {
99 char *type;
100 char *path;
101 int flags;
102 caddr_t data;
103};
104#endif
41c20dac
MD
105/*
106 * mount_args(char *type, char *path, int flags, caddr_t data)
107 */
984263bc
MD
108/* ARGSUSED */
109int
41c20dac 110mount(struct mount_args *uap)
984263bc 111{
dadab5e9
MD
112 struct thread *td = curthread;
113 struct proc *p = td->td_proc;
984263bc
MD
114 struct vnode *vp;
115 struct mount *mp;
116 struct vfsconf *vfsp;
117 int error, flag = 0, flag2 = 0;
118 struct vattr va;
119#ifdef COMPAT_43
120 u_long fstypenum;
121#endif
122 struct nameidata nd;
123 char fstypename[MFSNAMELEN];
124
dadab5e9 125 if (usermount == 0 && (error = suser(td)))
984263bc
MD
126 return (error);
127 /*
128 * Do not allow NFS export by non-root users.
129 */
130 if (SCARG(uap, flags) & MNT_EXPORTED) {
dadab5e9 131 error = suser(td);
984263bc
MD
132 if (error)
133 return (error);
134 }
135 /*
136 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
137 */
dadab5e9 138 if (suser(td))
984263bc
MD
139 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
140 /*
141 * Get vnode to be covered
142 */
143 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9 144 SCARG(uap, path), td);
984263bc
MD
145 if ((error = namei(&nd)) != 0)
146 return (error);
147 NDFREE(&nd, NDF_ONLY_PNBUF);
148 vp = nd.ni_vp;
149 if (SCARG(uap, flags) & MNT_UPDATE) {
150 if ((vp->v_flag & VROOT) == 0) {
151 vput(vp);
152 return (EINVAL);
153 }
154 mp = vp->v_mount;
155 flag = mp->mnt_flag;
156 flag2 = mp->mnt_kern_flag;
157 /*
158 * We only allow the filesystem to be reloaded if it
159 * is currently mounted read-only.
160 */
161 if ((SCARG(uap, flags) & MNT_RELOAD) &&
162 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
163 vput(vp);
164 return (EOPNOTSUPP); /* Needs translation */
165 }
166 /*
167 * Only root, or the user that did the original mount is
168 * permitted to update it.
169 */
170 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
dadab5e9 171 (error = suser(td))) {
984263bc
MD
172 vput(vp);
173 return (error);
174 }
dadab5e9 175 if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
984263bc
MD
176 vput(vp);
177 return (EBUSY);
178 }
179 simple_lock(&vp->v_interlock);
180 if ((vp->v_flag & VMOUNT) != 0 ||
181 vp->v_mountedhere != NULL) {
182 simple_unlock(&vp->v_interlock);
dadab5e9 183 vfs_unbusy(mp, td);
984263bc
MD
184 vput(vp);
185 return (EBUSY);
186 }
187 vp->v_flag |= VMOUNT;
188 simple_unlock(&vp->v_interlock);
189 mp->mnt_flag |=
190 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
dadab5e9 191 VOP_UNLOCK(vp, 0, td);
984263bc
MD
192 goto update;
193 }
194 /*
195 * If the user is not root, ensure that they own the directory
196 * onto which we are attempting to mount.
197 */
3b568787 198 if ((error = VOP_GETATTR(vp, &va, td)) ||
984263bc 199 (va.va_uid != p->p_ucred->cr_uid &&
dadab5e9 200 (error = suser(td)))) {
984263bc
MD
201 vput(vp);
202 return (error);
203 }
3b568787 204 if ((error = vinvalbuf(vp, V_SAVE, td, 0, 0)) != 0) {
984263bc
MD
205 vput(vp);
206 return (error);
207 }
208 if (vp->v_type != VDIR) {
209 vput(vp);
210 return (ENOTDIR);
211 }
212#ifdef COMPAT_43
213 /*
214 * Historically filesystem types were identified by number. If we
215 * get an integer for the filesystem type instead of a string, we
216 * check to see if it matches one of the historic filesystem types.
217 */
218 fstypenum = (uintptr_t)SCARG(uap, type);
219 if (fstypenum < maxvfsconf) {
220 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
221 if (vfsp->vfc_typenum == fstypenum)
222 break;
223 if (vfsp == NULL) {
224 vput(vp);
225 return (ENODEV);
226 }
227 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
228 } else
229#endif /* COMPAT_43 */
230 if ((error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) != 0) {
231 vput(vp);
232 return (error);
233 }
234 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
235 if (!strcmp(vfsp->vfc_name, fstypename))
236 break;
237 if (vfsp == NULL) {
238 linker_file_t lf;
239
240 /* Only load modules for root (very important!) */
dadab5e9 241 if ((error = suser(td)) != 0) {
984263bc
MD
242 vput(vp);
243 return error;
244 }
245 error = linker_load_file(fstypename, &lf);
246 if (error || lf == NULL) {
247 vput(vp);
248 if (lf == NULL)
249 error = ENODEV;
250 return error;
251 }
252 lf->userrefs++;
253 /* lookup again, see if the VFS was loaded */
254 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
255 if (!strcmp(vfsp->vfc_name, fstypename))
256 break;
257 if (vfsp == NULL) {
258 lf->userrefs--;
259 linker_file_unload(lf);
260 vput(vp);
261 return (ENODEV);
262 }
263 }
264 simple_lock(&vp->v_interlock);
265 if ((vp->v_flag & VMOUNT) != 0 ||
266 vp->v_mountedhere != NULL) {
267 simple_unlock(&vp->v_interlock);
268 vput(vp);
269 return (EBUSY);
270 }
271 vp->v_flag |= VMOUNT;
272 simple_unlock(&vp->v_interlock);
273
274 /*
275 * Allocate and initialize the filesystem.
276 */
277 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK);
278 bzero((char *)mp, (u_long)sizeof(struct mount));
279 TAILQ_INIT(&mp->mnt_nvnodelist);
280 TAILQ_INIT(&mp->mnt_reservedvnlist);
281 mp->mnt_nvnodelistsize = 0;
282 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
dadab5e9 283 (void)vfs_busy(mp, LK_NOWAIT, 0, td);
984263bc
MD
284 mp->mnt_op = vfsp->vfc_vfsops;
285 mp->mnt_vfc = vfsp;
286 vfsp->vfc_refcount++;
287 mp->mnt_stat.f_type = vfsp->vfc_typenum;
288 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
289 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
290 mp->mnt_vnodecovered = vp;
291 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
292 mp->mnt_iosize_max = DFLTPHYS;
dadab5e9 293 VOP_UNLOCK(vp, 0, td);
984263bc
MD
294update:
295 /*
296 * Set the mount level flags.
297 */
298 if (SCARG(uap, flags) & MNT_RDONLY)
299 mp->mnt_flag |= MNT_RDONLY;
300 else if (mp->mnt_flag & MNT_RDONLY)
301 mp->mnt_kern_flag |= MNTK_WANTRDWR;
302 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
303 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
304 MNT_NOSYMFOLLOW | MNT_IGNORE |
305 MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
306 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
307 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
308 MNT_NOSYMFOLLOW | MNT_IGNORE |
309 MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
310 /*
311 * Mount the filesystem.
312 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
313 * get. No freeing of cn_pnbuf.
314 */
dadab5e9 315 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, td);
984263bc
MD
316 if (mp->mnt_flag & MNT_UPDATE) {
317 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
318 mp->mnt_flag &= ~MNT_RDONLY;
319 mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
320 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
321 if (error) {
322 mp->mnt_flag = flag;
323 mp->mnt_kern_flag = flag2;
324 }
325 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
326 if (mp->mnt_syncer == NULL)
327 error = vfs_allocate_syncvnode(mp);
328 } else {
329 if (mp->mnt_syncer != NULL)
330 vrele(mp->mnt_syncer);
331 mp->mnt_syncer = NULL;
332 }
dadab5e9 333 vfs_unbusy(mp, td);
984263bc
MD
334 simple_lock(&vp->v_interlock);
335 vp->v_flag &= ~VMOUNT;
336 simple_unlock(&vp->v_interlock);
337 vrele(vp);
338 return (error);
339 }
dadab5e9 340 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
341 /*
342 * Put the new filesystem on the mount list after root.
343 */
344 cache_purge(vp);
345 if (!error) {
346 simple_lock(&vp->v_interlock);
347 vp->v_flag &= ~VMOUNT;
348 vp->v_mountedhere = mp;
349 simple_unlock(&vp->v_interlock);
350 simple_lock(&mountlist_slock);
351 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
352 simple_unlock(&mountlist_slock);
353 checkdirs(vp);
dadab5e9 354 VOP_UNLOCK(vp, 0, td);
984263bc
MD
355 if ((mp->mnt_flag & MNT_RDONLY) == 0)
356 error = vfs_allocate_syncvnode(mp);
dadab5e9
MD
357 vfs_unbusy(mp, td);
358 if ((error = VFS_START(mp, 0, td)) != 0)
984263bc
MD
359 vrele(vp);
360 } else {
361 simple_lock(&vp->v_interlock);
362 vp->v_flag &= ~VMOUNT;
363 simple_unlock(&vp->v_interlock);
364 mp->mnt_vfc->vfc_refcount--;
dadab5e9 365 vfs_unbusy(mp, td);
984263bc
MD
366 free((caddr_t)mp, M_MOUNT);
367 vput(vp);
368 }
369 return (error);
370}
371
372/*
373 * Scan all active processes to see if any of them have a current
374 * or root directory onto which the new filesystem has just been
375 * mounted. If so, replace them with the new mount point.
376 */
377static void
dadab5e9 378checkdirs(struct vnode *olddp)
984263bc
MD
379{
380 struct filedesc *fdp;
381 struct vnode *newdp;
382 struct proc *p;
383
384 if (olddp->v_usecount == 1)
385 return;
386 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
387 panic("mount: lost mount");
388 LIST_FOREACH(p, &allproc, p_list) {
389 fdp = p->p_fd;
390 if (fdp->fd_cdir == olddp) {
391 vrele(fdp->fd_cdir);
392 VREF(newdp);
393 fdp->fd_cdir = newdp;
394 }
395 if (fdp->fd_rdir == olddp) {
396 vrele(fdp->fd_rdir);
397 VREF(newdp);
398 fdp->fd_rdir = newdp;
399 }
400 }
401 if (rootvnode == olddp) {
402 vrele(rootvnode);
403 VREF(newdp);
404 rootvnode = newdp;
405 }
406 vput(newdp);
407}
408
409/*
410 * Unmount a file system.
411 *
412 * Note: unmount takes a path to the vnode mounted on as argument,
413 * not special file (as before).
414 */
415#ifndef _SYS_SYSPROTO_H_
416struct unmount_args {
417 char *path;
418 int flags;
419};
420#endif
41c20dac
MD
421/*
422 * umount_args(char *path, int flags)
423 */
984263bc
MD
424/* ARGSUSED */
425int
41c20dac 426unmount(struct unmount_args *uap)
984263bc 427{
dadab5e9
MD
428 struct thread *td = curthread;
429 struct proc *p = td->td_proc;
41c20dac 430 struct vnode *vp;
984263bc
MD
431 struct mount *mp;
432 int error;
433 struct nameidata nd;
434
dadab5e9 435 KKASSERT(p);
984263bc 436 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9 437 SCARG(uap, path), td);
984263bc
MD
438 if ((error = namei(&nd)) != 0)
439 return (error);
440 vp = nd.ni_vp;
441 NDFREE(&nd, NDF_ONLY_PNBUF);
442 mp = vp->v_mount;
443
444 /*
445 * Only root, or the user that did the original mount is
446 * permitted to unmount this filesystem.
447 */
448 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
dadab5e9 449 (error = suser(td))) {
984263bc
MD
450 vput(vp);
451 return (error);
452 }
453
454 /*
455 * Don't allow unmounting the root file system.
456 */
457 if (mp->mnt_flag & MNT_ROOTFS) {
458 vput(vp);
459 return (EINVAL);
460 }
461
462 /*
463 * Must be the root of the filesystem
464 */
465 if ((vp->v_flag & VROOT) == 0) {
466 vput(vp);
467 return (EINVAL);
468 }
469 vput(vp);
dadab5e9 470 return (dounmount(mp, SCARG(uap, flags), td));
984263bc
MD
471}
472
473/*
474 * Do the actual file system unmount.
475 */
476int
dadab5e9 477dounmount(struct mount *mp, int flags, struct thread *td)
984263bc
MD
478{
479 struct vnode *coveredvp;
480 int error;
481 int async_flag;
482
483 simple_lock(&mountlist_slock);
484 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
485 simple_unlock(&mountlist_slock);
486 return (EBUSY);
487 }
488 mp->mnt_kern_flag |= MNTK_UNMOUNT;
489 /* Allow filesystems to detect that a forced unmount is in progress. */
490 if (flags & MNT_FORCE)
491 mp->mnt_kern_flag |= MNTK_UNMOUNTF;
492 error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
dadab5e9 493 ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_slock, td);
984263bc
MD
494 if (error) {
495 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
496 if (mp->mnt_kern_flag & MNTK_MWAIT)
497 wakeup((caddr_t)mp);
498 return (error);
499 }
500
501 if (mp->mnt_flag & MNT_EXPUBLIC)
502 vfs_setpublicfs(NULL, NULL, NULL);
503
504 vfs_msync(mp, MNT_WAIT);
505 async_flag = mp->mnt_flag & MNT_ASYNC;
506 mp->mnt_flag &=~ MNT_ASYNC;
507 cache_purgevfs(mp); /* remove cache entries for this file sys */
508 if (mp->mnt_syncer != NULL)
509 vrele(mp->mnt_syncer);
510 if (((mp->mnt_flag & MNT_RDONLY) ||
3b568787 511 (error = VFS_SYNC(mp, MNT_WAIT, td)) == 0) ||
984263bc 512 (flags & MNT_FORCE))
dadab5e9 513 error = VFS_UNMOUNT(mp, flags, td);
984263bc
MD
514 simple_lock(&mountlist_slock);
515 if (error) {
516 if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
517 (void) vfs_allocate_syncvnode(mp);
518 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
519 mp->mnt_flag |= async_flag;
520 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
dadab5e9 521 &mountlist_slock, td);
984263bc
MD
522 if (mp->mnt_kern_flag & MNTK_MWAIT)
523 wakeup((caddr_t)mp);
524 return (error);
525 }
526 TAILQ_REMOVE(&mountlist, mp, mnt_list);
527 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
528 coveredvp->v_mountedhere = (struct mount *)0;
529 vrele(coveredvp);
530 }
531 mp->mnt_vfc->vfc_refcount--;
532 if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
533 panic("unmount: dangling vnode");
dadab5e9 534 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, td);
984263bc
MD
535 if (mp->mnt_kern_flag & MNTK_MWAIT)
536 wakeup((caddr_t)mp);
537 free((caddr_t)mp, M_MOUNT);
538 return (0);
539}
540
541/*
542 * Sync each mounted filesystem.
543 */
544#ifndef _SYS_SYSPROTO_H_
545struct sync_args {
546 int dummy;
547};
548#endif
549
550#ifdef DEBUG
551static int syncprt = 0;
552SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
553#endif
554
555/* ARGSUSED */
556int
41c20dac 557sync(struct sync_args *uap)
984263bc 558{
dadab5e9 559 struct thread *td = curthread;
41c20dac 560 struct mount *mp, *nmp;
984263bc
MD
561 int asyncflag;
562
563 simple_lock(&mountlist_slock);
564 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
dadab5e9 565 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, td)) {
984263bc
MD
566 nmp = TAILQ_NEXT(mp, mnt_list);
567 continue;
568 }
569 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
570 asyncflag = mp->mnt_flag & MNT_ASYNC;
571 mp->mnt_flag &= ~MNT_ASYNC;
572 vfs_msync(mp, MNT_NOWAIT);
3b568787 573 VFS_SYNC(mp, MNT_NOWAIT, td);
984263bc
MD
574 mp->mnt_flag |= asyncflag;
575 }
576 simple_lock(&mountlist_slock);
577 nmp = TAILQ_NEXT(mp, mnt_list);
dadab5e9 578 vfs_unbusy(mp, td);
984263bc
MD
579 }
580 simple_unlock(&mountlist_slock);
581#if 0
582/*
583 * XXX don't call vfs_bufstats() yet because that routine
584 * was not imported in the Lite2 merge.
585 */
586#ifdef DIAGNOSTIC
587 if (syncprt)
588 vfs_bufstats();
589#endif /* DIAGNOSTIC */
590#endif
591 return (0);
592}
593
594/* XXX PRISON: could be per prison flag */
595static int prison_quotas;
596#if 0
597SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
598#endif
599
600/*
41c20dac
MD
601 * quotactl_args(char *path, int fcmd, int uid, caddr_t arg)
602 *
984263bc
MD
603 * Change filesystem quotas.
604 */
984263bc
MD
605/* ARGSUSED */
606int
41c20dac 607quotactl(struct quotactl_args *uap)
984263bc 608{
dadab5e9
MD
609 struct thread *td = curthread;
610 struct proc *p = td->td_proc;
41c20dac 611 struct mount *mp;
984263bc
MD
612 int error;
613 struct nameidata nd;
614
dadab5e9 615 KKASSERT(p);
41c20dac 616 if (p->p_ucred->cr_prison && !prison_quotas)
984263bc 617 return (EPERM);
dadab5e9 618 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
619 if ((error = namei(&nd)) != 0)
620 return (error);
621 mp = nd.ni_vp->v_mount;
622 NDFREE(&nd, NDF_ONLY_PNBUF);
623 vrele(nd.ni_vp);
624 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
dadab5e9 625 SCARG(uap, arg), td));
984263bc
MD
626}
627
628/*
41c20dac
MD
629 * statfs_args(char *path, struct statfs *buf)
630 *
984263bc
MD
631 * Get filesystem statistics.
632 */
984263bc
MD
633/* ARGSUSED */
634int
41c20dac 635statfs(struct statfs_args *uap)
984263bc 636{
dadab5e9 637 struct thread *td = curthread;
41c20dac
MD
638 struct mount *mp;
639 struct statfs *sp;
984263bc
MD
640 int error;
641 struct nameidata nd;
642 struct statfs sb;
643
dadab5e9 644 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
645 if ((error = namei(&nd)) != 0)
646 return (error);
647 mp = nd.ni_vp->v_mount;
648 sp = &mp->mnt_stat;
649 NDFREE(&nd, NDF_ONLY_PNBUF);
650 vrele(nd.ni_vp);
dadab5e9 651 error = VFS_STATFS(mp, sp, td);
984263bc
MD
652 if (error)
653 return (error);
654 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
dadab5e9 655 if (suser(td)) {
984263bc
MD
656 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
657 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
658 sp = &sb;
659 }
660 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
661}
662
663/*
41c20dac
MD
664 * fstatfs_args(int fd, struct statfs *buf)
665 *
984263bc
MD
666 * Get filesystem statistics.
667 */
984263bc
MD
668/* ARGSUSED */
669int
41c20dac 670fstatfs(struct fstatfs_args *uap)
984263bc 671{
dadab5e9
MD
672 struct thread *td = curthread;
673 struct proc *p = td->td_proc;
984263bc
MD
674 struct file *fp;
675 struct mount *mp;
676 register struct statfs *sp;
677 int error;
678 struct statfs sb;
679
dadab5e9 680 KKASSERT(p);
984263bc
MD
681 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
682 return (error);
683 mp = ((struct vnode *)fp->f_data)->v_mount;
684 if (mp == NULL)
685 return (EBADF);
686 sp = &mp->mnt_stat;
dadab5e9 687 error = VFS_STATFS(mp, sp, td);
984263bc
MD
688 if (error)
689 return (error);
690 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
dadab5e9 691 if (suser(td)) {
984263bc
MD
692 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
693 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
694 sp = &sb;
695 }
696 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
697}
698
699/*
41c20dac
MD
700 * getfsstat_args(struct statfs *buf, long bufsize, int flags)
701 *
984263bc
MD
702 * Get statistics on all filesystems.
703 */
41c20dac 704/* ARGSUSED */
984263bc 705int
41c20dac 706getfsstat(struct getfsstat_args *uap)
984263bc 707{
dadab5e9
MD
708 struct thread *td = curthread;
709 struct proc *p = td->td_proc;
41c20dac
MD
710 struct mount *mp, *nmp;
711 struct statfs *sp;
984263bc
MD
712 caddr_t sfsp;
713 long count, maxcount, error;
714
715 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
716 sfsp = (caddr_t)SCARG(uap, buf);
717 count = 0;
718 simple_lock(&mountlist_slock);
719 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
dadab5e9 720 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, td)) {
984263bc
MD
721 nmp = TAILQ_NEXT(mp, mnt_list);
722 continue;
723 }
724 if (sfsp && count < maxcount) {
725 sp = &mp->mnt_stat;
726 /*
727 * If MNT_NOWAIT or MNT_LAZY is specified, do not
728 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
729 * overrides MNT_WAIT.
730 */
731 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
732 (SCARG(uap, flags) & MNT_WAIT)) &&
dadab5e9 733 (error = VFS_STATFS(mp, sp, td))) {
984263bc
MD
734 simple_lock(&mountlist_slock);
735 nmp = TAILQ_NEXT(mp, mnt_list);
dadab5e9 736 vfs_unbusy(mp, td);
984263bc
MD
737 continue;
738 }
739 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
740 error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
741 if (error) {
dadab5e9 742 vfs_unbusy(mp, td);
984263bc
MD
743 return (error);
744 }
745 sfsp += sizeof(*sp);
746 }
747 count++;
748 simple_lock(&mountlist_slock);
749 nmp = TAILQ_NEXT(mp, mnt_list);
dadab5e9 750 vfs_unbusy(mp, td);
984263bc
MD
751 }
752 simple_unlock(&mountlist_slock);
753 if (sfsp && count > maxcount)
754 p->p_retval[0] = maxcount;
755 else
756 p->p_retval[0] = count;
757 return (0);
758}
759
760/*
41c20dac
MD
761 * fchdir_args(int fd)
762 *
984263bc
MD
763 * Change current working directory to a given file descriptor.
764 */
984263bc
MD
765/* ARGSUSED */
766int
41c20dac 767fchdir(struct fchdir_args *uap)
984263bc 768{
dadab5e9
MD
769 struct thread *td = curthread;
770 struct proc *p = td->td_proc;
41c20dac 771 struct filedesc *fdp = p->p_fd;
984263bc
MD
772 struct vnode *vp, *tdp;
773 struct mount *mp;
774 struct file *fp;
775 int error;
776
777 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
778 return (error);
779 vp = (struct vnode *)fp->f_data;
780 VREF(vp);
dadab5e9 781 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
782 if (vp->v_type != VDIR)
783 error = ENOTDIR;
784 else
dadab5e9 785 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, td);
984263bc 786 while (!error && (mp = vp->v_mountedhere) != NULL) {
dadab5e9 787 if (vfs_busy(mp, 0, 0, td))
984263bc
MD
788 continue;
789 error = VFS_ROOT(mp, &tdp);
dadab5e9 790 vfs_unbusy(mp, td);
984263bc
MD
791 if (error)
792 break;
793 vput(vp);
794 vp = tdp;
795 }
796 if (error) {
797 vput(vp);
798 return (error);
799 }
dadab5e9 800 VOP_UNLOCK(vp, 0, td);
984263bc
MD
801 vrele(fdp->fd_cdir);
802 fdp->fd_cdir = vp;
803 return (0);
804}
805
806/*
41c20dac
MD
807 * chdir_args(char *path)
808 *
984263bc
MD
809 * Change current working directory (``.'').
810 */
984263bc
MD
811/* ARGSUSED */
812int
41c20dac 813chdir(struct chdir_args *uap)
984263bc 814{
dadab5e9
MD
815 struct thread *td = curthread;
816 struct proc *p = td->td_proc;
41c20dac 817 struct filedesc *fdp = p->p_fd;
984263bc
MD
818 int error;
819 struct nameidata nd;
820
821 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9
MD
822 SCARG(uap, path), td);
823 if ((error = change_dir(&nd, td)) != 0)
984263bc
MD
824 return (error);
825 NDFREE(&nd, NDF_ONLY_PNBUF);
826 vrele(fdp->fd_cdir);
827 fdp->fd_cdir = nd.ni_vp;
828 return (0);
829}
830
831/*
832 * Helper function for raised chroot(2) security function: Refuse if
833 * any filedescriptors are open directories.
834 */
835static int
836chroot_refuse_vdir_fds(fdp)
837 struct filedesc *fdp;
838{
839 struct vnode *vp;
840 struct file *fp;
841 int error;
842 int fd;
843
844 for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
845 error = getvnode(fdp, fd, &fp);
846 if (error)
847 continue;
848 vp = (struct vnode *)fp->f_data;
849 if (vp->v_type != VDIR)
850 continue;
851 return(EPERM);
852 }
853 return (0);
854}
855
856/*
857 * This sysctl determines if we will allow a process to chroot(2) if it
858 * has a directory open:
859 * 0: disallowed for all processes.
860 * 1: allowed for processes that were not already chroot(2)'ed.
861 * 2: allowed for all processes.
862 */
863
864static int chroot_allow_open_directories = 1;
865
866SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
867 &chroot_allow_open_directories, 0, "");
868
869/*
41c20dac
MD
870 * chroot_args(char *path)
871 *
984263bc
MD
872 * Change notion of root (``/'') directory.
873 */
984263bc
MD
874/* ARGSUSED */
875int
41c20dac 876chroot(struct chroot_args *uap)
984263bc 877{
dadab5e9
MD
878 struct thread *td = curthread;
879 struct proc *p = td->td_proc;
41c20dac 880 struct filedesc *fdp = p->p_fd;
984263bc
MD
881 int error;
882 struct nameidata nd;
883
dadab5e9
MD
884 KKASSERT(p);
885 error = suser_cred(p->p_ucred, PRISON_ROOT);
984263bc
MD
886 if (error)
887 return (error);
888 if (chroot_allow_open_directories == 0 ||
889 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode))
890 error = chroot_refuse_vdir_fds(fdp);
891 if (error)
892 return (error);
893 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9
MD
894 SCARG(uap, path), td);
895 if ((error = change_dir(&nd, td)) != 0)
984263bc
MD
896 return (error);
897 NDFREE(&nd, NDF_ONLY_PNBUF);
898 vrele(fdp->fd_rdir);
899 fdp->fd_rdir = nd.ni_vp;
900 if (!fdp->fd_jdir) {
901 fdp->fd_jdir = nd.ni_vp;
902 VREF(fdp->fd_jdir);
903 }
904 return (0);
905}
906
907/*
908 * Common routine for chroot and chdir.
909 */
910static int
dadab5e9 911change_dir(struct nameidata *ndp, struct thread *td)
984263bc
MD
912{
913 struct vnode *vp;
914 int error;
915
916 error = namei(ndp);
917 if (error)
918 return (error);
919 vp = ndp->ni_vp;
920 if (vp->v_type != VDIR)
921 error = ENOTDIR;
922 else
dadab5e9 923 error = VOP_ACCESS(vp, VEXEC, ndp->ni_cnd.cn_cred, td);
984263bc
MD
924 if (error)
925 vput(vp);
926 else
dadab5e9 927 VOP_UNLOCK(vp, 0, td);
984263bc
MD
928 return (error);
929}
930
931/*
41c20dac
MD
932 * open_args(char *path, int flags, int mode)
933 *
984263bc
MD
934 * Check permissions, allocate an open file structure,
935 * and call the device open routine if any.
936 */
984263bc 937int
41c20dac 938open(struct open_args *uap)
984263bc 939{
dadab5e9
MD
940 struct thread *td = curthread;
941 struct proc *p = td->td_proc;
41c20dac
MD
942 struct filedesc *fdp = p->p_fd;
943 struct file *fp;
944 struct vnode *vp;
984263bc
MD
945 int cmode, flags, oflags;
946 struct file *nfp;
947 int type, indx, error;
948 struct flock lf;
949 struct nameidata nd;
950
951 oflags = SCARG(uap, flags);
952 if ((oflags & O_ACCMODE) == O_ACCMODE)
953 return (EINVAL);
954 flags = FFLAGS(oflags);
955 error = falloc(p, &nfp, &indx);
956 if (error)
957 return (error);
958 fp = nfp;
959 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
dadab5e9 960 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
961 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
962 /*
963 * Bump the ref count to prevent another process from closing
964 * the descriptor while we are blocked in vn_open()
965 */
966 fhold(fp);
967 error = vn_open(&nd, flags, cmode);
968 if (error) {
969 /*
970 * release our own reference
971 */
dadab5e9 972 fdrop(fp, td);
984263bc
MD
973
974 /*
975 * handle special fdopen() case. bleh. dupfdopen() is
976 * responsible for dropping the old contents of ofiles[indx]
977 * if it succeeds.
978 */
979 if ((error == ENODEV || error == ENXIO) &&
980 p->p_dupfd >= 0 && /* XXX from fdopen */
981 (error =
41c20dac 982 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
984263bc
MD
983 p->p_retval[0] = indx;
984 return (0);
985 }
986 /*
987 * Clean up the descriptor, but only if another thread hadn't
988 * replaced or closed it.
989 */
990 if (fdp->fd_ofiles[indx] == fp) {
991 fdp->fd_ofiles[indx] = NULL;
dadab5e9 992 fdrop(fp, td);
984263bc
MD
993 }
994
995 if (error == ERESTART)
996 error = EINTR;
997 return (error);
998 }
999 p->p_dupfd = 0;
1000 NDFREE(&nd, NDF_ONLY_PNBUF);
1001 vp = nd.ni_vp;
1002
1003 /*
1004 * There should be 2 references on the file, one from the descriptor
1005 * table, and one for us.
1006 *
1007 * Handle the case where someone closed the file (via its file
1008 * descriptor) while we were blocked. The end result should look
1009 * like opening the file succeeded but it was immediately closed.
1010 */
1011 if (fp->f_count == 1) {
1012 KASSERT(fdp->fd_ofiles[indx] != fp,
1013 ("Open file descriptor lost all refs"));
dadab5e9 1014 VOP_UNLOCK(vp, 0, td);
3b568787 1015 vn_close(vp, flags & FMASK, td);
dadab5e9 1016 fdrop(fp, td);
984263bc
MD
1017 p->p_retval[0] = indx;
1018 return 0;
1019 }
1020
1021 fp->f_data = (caddr_t)vp;
1022 fp->f_flag = flags & FMASK;
1023 fp->f_ops = &vnops;
1024 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
1025 if (flags & (O_EXLOCK | O_SHLOCK)) {
1026 lf.l_whence = SEEK_SET;
1027 lf.l_start = 0;
1028 lf.l_len = 0;
1029 if (flags & O_EXLOCK)
1030 lf.l_type = F_WRLCK;
1031 else
1032 lf.l_type = F_RDLCK;
1033 type = F_FLOCK;
1034 if ((flags & FNONBLOCK) == 0)
1035 type |= F_WAIT;
dadab5e9 1036 VOP_UNLOCK(vp, 0, td);
984263bc
MD
1037 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
1038 /*
1039 * lock request failed. Normally close the descriptor
1040 * but handle the case where someone might have dup()d
1041 * it when we weren't looking. One reference is
1042 * owned by the descriptor array, the other by us.
1043 */
1044 if (fdp->fd_ofiles[indx] == fp) {
1045 fdp->fd_ofiles[indx] = NULL;
dadab5e9 1046 fdrop(fp, td);
984263bc 1047 }
dadab5e9 1048 fdrop(fp, td);
984263bc
MD
1049 return (error);
1050 }
dadab5e9 1051 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
1052 fp->f_flag |= FHASLOCK;
1053 }
1054 /* assert that vn_open created a backing object if one is needed */
1055 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
1056 ("open: vmio vnode has no backing object after vn_open"));
dadab5e9 1057 VOP_UNLOCK(vp, 0, td);
984263bc
MD
1058
1059 /*
1060 * release our private reference, leaving the one associated with the
1061 * descriptor table intact.
1062 */
dadab5e9 1063 fdrop(fp, td);
984263bc
MD
1064 p->p_retval[0] = indx;
1065 return (0);
1066}
1067
1068#ifdef COMPAT_43
1069/*
41c20dac
MD
1070 * ocreat(char *path, int mode)
1071 *
984263bc
MD
1072 * Create a file.
1073 */
984263bc 1074int
41c20dac 1075ocreat(struct ocreat_args *uap)
984263bc
MD
1076{
1077 struct open_args /* {
1078 syscallarg(char *) path;
1079 syscallarg(int) flags;
1080 syscallarg(int) mode;
1081 } */ nuap;
1082
1083 SCARG(&nuap, path) = SCARG(uap, path);
1084 SCARG(&nuap, mode) = SCARG(uap, mode);
1085 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
41c20dac 1086 return (open(&nuap));
984263bc
MD
1087}
1088#endif /* COMPAT_43 */
1089
1090/*
41c20dac
MD
1091 * mknod_args(char *path, int mode, int dev)
1092 *
984263bc
MD
1093 * Create a special file.
1094 */
984263bc
MD
1095/* ARGSUSED */
1096int
41c20dac 1097mknod(struct mknod_args *uap)
984263bc 1098{
dadab5e9
MD
1099 struct thread *td = curthread;
1100 struct proc *p = td->td_proc;
41c20dac 1101 struct vnode *vp;
984263bc
MD
1102 struct vattr vattr;
1103 int error;
1104 int whiteout = 0;
1105 struct nameidata nd;
1106
dadab5e9
MD
1107 KKASSERT(p);
1108
984263bc
MD
1109 switch (SCARG(uap, mode) & S_IFMT) {
1110 case S_IFCHR:
1111 case S_IFBLK:
dadab5e9 1112 error = suser(td);
984263bc
MD
1113 break;
1114 default:
dadab5e9 1115 error = suser_cred(p->p_ucred, PRISON_ROOT);
984263bc
MD
1116 break;
1117 }
1118 if (error)
1119 return (error);
1120 bwillwrite();
dadab5e9 1121 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1122 if ((error = namei(&nd)) != 0)
1123 return (error);
1124 vp = nd.ni_vp;
1125 if (vp != NULL)
1126 error = EEXIST;
1127 else {
1128 VATTR_NULL(&vattr);
1129 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1130 vattr.va_rdev = SCARG(uap, dev);
1131 whiteout = 0;
1132
1133 switch (SCARG(uap, mode) & S_IFMT) {
1134 case S_IFMT: /* used by badsect to flag bad sectors */
1135 vattr.va_type = VBAD;
1136 break;
1137 case S_IFCHR:
1138 vattr.va_type = VCHR;
1139 break;
1140 case S_IFBLK:
1141 vattr.va_type = VBLK;
1142 break;
1143 case S_IFWHT:
1144 whiteout = 1;
1145 break;
1146 default:
1147 error = EINVAL;
1148 break;
1149 }
1150 }
1151 if (!error) {
dadab5e9 1152 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1153 if (whiteout)
1154 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1155 else {
1156 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1157 &nd.ni_cnd, &vattr);
1158 if (error == 0)
1159 vput(nd.ni_vp);
1160 }
1161 NDFREE(&nd, NDF_ONLY_PNBUF);
1162 vput(nd.ni_dvp);
1163 } else {
1164 NDFREE(&nd, NDF_ONLY_PNBUF);
1165 if (nd.ni_dvp == vp)
1166 vrele(nd.ni_dvp);
1167 else
1168 vput(nd.ni_dvp);
1169 if (vp)
1170 vrele(vp);
1171 }
1172 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1173 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1174 return (error);
1175}
1176
1177/*
41c20dac
MD
1178 * mkfifo_args(char *path, int mode)
1179 *
984263bc
MD
1180 * Create a named pipe.
1181 */
984263bc
MD
1182/* ARGSUSED */
1183int
41c20dac 1184mkfifo(struct mkfifo_args *uap)
984263bc 1185{
dadab5e9
MD
1186 struct thread *td = curthread;
1187 struct proc *p = td->td_proc;
984263bc
MD
1188 struct vattr vattr;
1189 int error;
1190 struct nameidata nd;
1191
1192 bwillwrite();
dadab5e9 1193 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1194 if ((error = namei(&nd)) != 0)
1195 return (error);
1196 if (nd.ni_vp != NULL) {
1197 NDFREE(&nd, NDF_ONLY_PNBUF);
1198 if (nd.ni_dvp == nd.ni_vp)
1199 vrele(nd.ni_dvp);
1200 else
1201 vput(nd.ni_dvp);
1202 vrele(nd.ni_vp);
1203 return (EEXIST);
1204 }
1205 VATTR_NULL(&vattr);
1206 vattr.va_type = VFIFO;
1207 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
dadab5e9 1208 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1209 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1210 if (error == 0)
1211 vput(nd.ni_vp);
1212 NDFREE(&nd, NDF_ONLY_PNBUF);
1213 vput(nd.ni_dvp);
1214 return (error);
1215}
1216
1217/*
41c20dac
MD
1218 * link_args(char *path, char *link)
1219 *
984263bc
MD
1220 * Make a hard file link.
1221 */
984263bc
MD
1222/* ARGSUSED */
1223int
41c20dac 1224link(struct link_args *uap)
984263bc 1225{
dadab5e9
MD
1226 struct thread *td = curthread;
1227 struct proc *p = td->td_proc;
41c20dac 1228 struct vnode *vp;
984263bc
MD
1229 struct nameidata nd;
1230 int error;
1231
1232 bwillwrite();
dadab5e9 1233 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1234 if ((error = namei(&nd)) != 0)
1235 return (error);
1236 NDFREE(&nd, NDF_ONLY_PNBUF);
1237 vp = nd.ni_vp;
1238 if (vp->v_type == VDIR)
1239 error = EPERM; /* POSIX */
1240 else {
dadab5e9 1241 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
984263bc
MD
1242 error = namei(&nd);
1243 if (!error) {
1244 if (nd.ni_vp != NULL) {
1245 if (nd.ni_vp)
1246 vrele(nd.ni_vp);
1247 error = EEXIST;
1248 } else {
dadab5e9 1249 VOP_LEASE(nd.ni_dvp, td, p->p_ucred,
984263bc 1250 LEASE_WRITE);
dadab5e9 1251 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1252 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1253 }
1254 NDFREE(&nd, NDF_ONLY_PNBUF);
1255 if (nd.ni_dvp == nd.ni_vp)
1256 vrele(nd.ni_dvp);
1257 else
1258 vput(nd.ni_dvp);
1259 }
1260 }
1261 vrele(vp);
1262 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1263 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1264 return (error);
1265}
1266
1267/*
41c20dac
MD
1268 * symlink(char *path, char *link)
1269 *
984263bc
MD
1270 * Make a symbolic link.
1271 */
984263bc
MD
1272/* ARGSUSED */
1273int
41c20dac 1274symlink(struct symlink_args *uap)
984263bc 1275{
dadab5e9
MD
1276 struct thread *td = curthread;
1277 struct proc *p = td->td_proc;
984263bc
MD
1278 struct vattr vattr;
1279 char *path;
1280 int error;
1281 struct nameidata nd;
1282
1283 path = zalloc(namei_zone);
1284 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1285 goto out;
1286 bwillwrite();
dadab5e9 1287 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
984263bc
MD
1288 if ((error = namei(&nd)) != 0)
1289 goto out;
1290 if (nd.ni_vp) {
1291 NDFREE(&nd, NDF_ONLY_PNBUF);
1292 if (nd.ni_dvp == nd.ni_vp)
1293 vrele(nd.ni_dvp);
1294 else
1295 vput(nd.ni_dvp);
1296 vrele(nd.ni_vp);
1297 error = EEXIST;
1298 goto out;
1299 }
1300 VATTR_NULL(&vattr);
1301 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
dadab5e9 1302 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1303 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1304 NDFREE(&nd, NDF_ONLY_PNBUF);
1305 if (error == 0)
1306 vput(nd.ni_vp);
1307 vput(nd.ni_dvp);
1308 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1309 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1310out:
1311 zfree(namei_zone, path);
1312 return (error);
1313}
1314
1315/*
41c20dac
MD
1316 * undelete_args(char *path)
1317 *
984263bc
MD
1318 * Delete a whiteout from the filesystem.
1319 */
1320/* ARGSUSED */
1321int
41c20dac 1322undelete(struct undelete_args *uap)
984263bc 1323{
dadab5e9
MD
1324 struct thread *td = curthread;
1325 struct proc *p = td->td_proc;
984263bc
MD
1326 int error;
1327 struct nameidata nd;
1328
1329 bwillwrite();
1330 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
dadab5e9 1331 SCARG(uap, path), td);
984263bc
MD
1332 error = namei(&nd);
1333 if (error)
1334 return (error);
1335
1336 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1337 NDFREE(&nd, NDF_ONLY_PNBUF);
1338 if (nd.ni_dvp == nd.ni_vp)
1339 vrele(nd.ni_dvp);
1340 else
1341 vput(nd.ni_dvp);
1342 if (nd.ni_vp)
1343 vrele(nd.ni_vp);
1344 return (EEXIST);
1345 }
1346
dadab5e9 1347 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1348 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1349 NDFREE(&nd, NDF_ONLY_PNBUF);
1350 vput(nd.ni_dvp);
1351 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1352 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1353 return (error);
1354}
1355
1356/*
41c20dac
MD
1357 * unlink_args(char *path)
1358 *
984263bc
MD
1359 * Delete a name from the filesystem.
1360 */
984263bc 1361int
41c20dac 1362unlink(struct unlink_args *uap)
984263bc 1363{
dadab5e9
MD
1364 struct thread *td = curthread;
1365 struct proc *p = td->td_proc;
41c20dac 1366 struct vnode *vp;
984263bc
MD
1367 int error;
1368 struct nameidata nd;
1369
1370 bwillwrite();
dadab5e9 1371 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1372 if ((error = namei(&nd)) != 0)
1373 return (error);
1374 vp = nd.ni_vp;
dadab5e9
MD
1375 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1376 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
1377
1378 if (vp->v_type == VDIR)
1379 error = EPERM; /* POSIX */
1380 else {
1381 /*
1382 * The root of a mounted filesystem cannot be deleted.
1383 *
1384 * XXX: can this only be a VDIR case?
1385 */
1386 if (vp->v_flag & VROOT)
1387 error = EBUSY;
1388 }
1389
1390 if (!error) {
dadab5e9 1391 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
1392 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1393 }
1394 NDFREE(&nd, NDF_ONLY_PNBUF);
1395 if (nd.ni_dvp == vp)
1396 vrele(nd.ni_dvp);
1397 else
1398 vput(nd.ni_dvp);
1399 if (vp != NULLVP)
1400 vput(vp);
1401 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1402 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1403 return (error);
1404}
1405
1406/*
41c20dac
MD
1407 * lseek_args(int fd, int pad, off_t offset, int whence)
1408 *
984263bc
MD
1409 * Reposition read/write file offset.
1410 */
984263bc 1411int
41c20dac 1412lseek(struct lseek_args *uap)
984263bc 1413{
dadab5e9
MD
1414 struct thread *td = curthread;
1415 struct proc *p = td->td_proc;
41c20dac
MD
1416 struct filedesc *fdp = p->p_fd;
1417 struct file *fp;
984263bc
MD
1418 struct vattr vattr;
1419 int error;
1420
1421 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1422 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1423 return (EBADF);
1424 if (fp->f_type != DTYPE_VNODE)
1425 return (ESPIPE);
1426 switch (SCARG(uap, whence)) {
1427 case L_INCR:
1428 fp->f_offset += SCARG(uap, offset);
1429 break;
1430 case L_XTND:
3b568787 1431 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, td);
984263bc
MD
1432 if (error)
1433 return (error);
1434 fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1435 break;
1436 case L_SET:
1437 fp->f_offset = SCARG(uap, offset);
1438 break;
1439 default:
1440 return (EINVAL);
1441 }
1442 *(off_t *)(p->p_retval) = fp->f_offset;
1443 return (0);
1444}
1445
1446#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1447/*
1448 * Reposition read/write file offset.
41c20dac
MD
1449 *
1450 * olseek_args(int fd, long offset, int whence)
984263bc 1451 */
984263bc 1452int
41c20dac 1453olseek(struct olseek_args *uap)
984263bc
MD
1454{
1455 struct lseek_args /* {
1456 syscallarg(int) fd;
1457 syscallarg(int) pad;
1458 syscallarg(off_t) offset;
1459 syscallarg(int) whence;
1460 } */ nuap;
1461 int error;
1462
1463 SCARG(&nuap, fd) = SCARG(uap, fd);
1464 SCARG(&nuap, offset) = SCARG(uap, offset);
1465 SCARG(&nuap, whence) = SCARG(uap, whence);
41c20dac 1466 error = lseek(&nuap);
984263bc
MD
1467 return (error);
1468}
1469#endif /* COMPAT_43 */
1470
1471/*
41c20dac
MD
1472 * access_args(char *path, int flags)
1473 *
984263bc
MD
1474 * Check access permissions.
1475 */
984263bc 1476int
41c20dac 1477access(struct access_args *uap)
984263bc 1478{
dadab5e9
MD
1479 struct thread *td = curthread;
1480 struct proc *p = td->td_proc;
984263bc 1481 struct ucred *cred, *tmpcred;
41c20dac 1482 struct vnode *vp;
984263bc
MD
1483 int error, flags;
1484 struct nameidata nd;
1485
1486 cred = p->p_ucred;
1487 /*
1488 * Create and modify a temporary credential instead of one that
1489 * is potentially shared. This could also mess up socket
1490 * buffer accounting which can run in an interrupt context.
1491 */
1492 tmpcred = crdup(cred);
41c20dac
MD
1493 tmpcred->cr_uid = p->p_ucred->cr_ruid;
1494 tmpcred->cr_groups[0] = p->p_ucred->cr_rgid;
984263bc
MD
1495 p->p_ucred = tmpcred;
1496 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1497 SCARG(uap, path), td);
984263bc
MD
1498 if ((error = namei(&nd)) != 0)
1499 goto out1;
1500 vp = nd.ni_vp;
1501
1502 /* Flags == 0 means only check for existence. */
1503 if (SCARG(uap, flags)) {
1504 flags = 0;
1505 if (SCARG(uap, flags) & R_OK)
1506 flags |= VREAD;
1507 if (SCARG(uap, flags) & W_OK)
1508 flags |= VWRITE;
1509 if (SCARG(uap, flags) & X_OK)
1510 flags |= VEXEC;
1511 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
dadab5e9 1512 error = VOP_ACCESS(vp, flags, tmpcred, td);
984263bc
MD
1513 }
1514 NDFREE(&nd, NDF_ONLY_PNBUF);
1515 vput(vp);
1516out1:
1517 p->p_ucred = cred;
1518 crfree(tmpcred);
1519 return (error);
1520}
1521
1522#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1523/*
41c20dac
MD
1524 * ostat_args(char *path, struct ostat *ub)
1525 *
984263bc
MD
1526 * Get file status; this version follows links.
1527 */
984263bc
MD
1528/* ARGSUSED */
1529int
41c20dac 1530ostat(struct ostat_args *uap)
984263bc 1531{
dadab5e9 1532 struct thread *td = curthread;
984263bc
MD
1533 struct stat sb;
1534 struct ostat osb;
1535 int error;
1536 struct nameidata nd;
1537
1538 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1539 SCARG(uap, path), td);
984263bc
MD
1540 if ((error = namei(&nd)) != 0)
1541 return (error);
1542 NDFREE(&nd, NDF_ONLY_PNBUF);
dadab5e9 1543 error = vn_stat(nd.ni_vp, &sb, td);
984263bc
MD
1544 vput(nd.ni_vp);
1545 if (error)
1546 return (error);
1547 cvtstat(&sb, &osb);
1548 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1549 return (error);
1550}
1551
1552/*
41c20dac
MD
1553 * olstat_args(char *path, struct ostat *ub)
1554 *
984263bc
MD
1555 * Get file status; this version does not follow links.
1556 */
984263bc
MD
1557/* ARGSUSED */
1558int
41c20dac 1559olstat(struct olstat_args *uap)
984263bc 1560{
dadab5e9 1561 struct thread *td = curthread;
984263bc
MD
1562 struct vnode *vp;
1563 struct stat sb;
1564 struct ostat osb;
1565 int error;
1566 struct nameidata nd;
1567
1568 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1569 SCARG(uap, path), td);
984263bc
MD
1570 if ((error = namei(&nd)) != 0)
1571 return (error);
1572 vp = nd.ni_vp;
dadab5e9 1573 error = vn_stat(vp, &sb, td);
984263bc
MD
1574 NDFREE(&nd, NDF_ONLY_PNBUF);
1575 vput(vp);
1576 if (error)
1577 return (error);
1578 cvtstat(&sb, &osb);
1579 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1580 return (error);
1581}
1582
1583/*
1584 * Convert from an old to a new stat structure.
1585 */
1586void
1587cvtstat(st, ost)
1588 struct stat *st;
1589 struct ostat *ost;
1590{
984263bc
MD
1591 ost->st_dev = st->st_dev;
1592 ost->st_ino = st->st_ino;
1593 ost->st_mode = st->st_mode;
1594 ost->st_nlink = st->st_nlink;
1595 ost->st_uid = st->st_uid;
1596 ost->st_gid = st->st_gid;
1597 ost->st_rdev = st->st_rdev;
1598 if (st->st_size < (quad_t)1 << 32)
1599 ost->st_size = st->st_size;
1600 else
1601 ost->st_size = -2;
1602 ost->st_atime = st->st_atime;
1603 ost->st_mtime = st->st_mtime;
1604 ost->st_ctime = st->st_ctime;
1605 ost->st_blksize = st->st_blksize;
1606 ost->st_blocks = st->st_blocks;
1607 ost->st_flags = st->st_flags;
1608 ost->st_gen = st->st_gen;
1609}
1610#endif /* COMPAT_43 || COMPAT_SUNOS */
1611
1612/*
41c20dac
MD
1613 * stat_args(char *path, struct stat *ub)
1614 *
984263bc
MD
1615 * Get file status; this version follows links.
1616 */
984263bc
MD
1617/* ARGSUSED */
1618int
41c20dac 1619stat(struct stat_args *uap)
984263bc 1620{
dadab5e9 1621 struct thread *td = curthread;
984263bc
MD
1622 struct stat sb;
1623 int error;
1624 struct nameidata nd;
1625
1626 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1627 SCARG(uap, path), td);
984263bc
MD
1628 if ((error = namei(&nd)) != 0)
1629 return (error);
dadab5e9 1630 error = vn_stat(nd.ni_vp, &sb, td);
984263bc
MD
1631 NDFREE(&nd, NDF_ONLY_PNBUF);
1632 vput(nd.ni_vp);
1633 if (error)
1634 return (error);
1635 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1636 return (error);
1637}
1638
1639/*
41c20dac
MD
1640 * lstat_args(char *path, struct stat *ub)
1641 *
984263bc
MD
1642 * Get file status; this version does not follow links.
1643 */
984263bc
MD
1644/* ARGSUSED */
1645int
41c20dac 1646lstat(struct lstat_args *uap)
984263bc 1647{
dadab5e9 1648 struct thread *td = curthread;
984263bc
MD
1649 int error;
1650 struct vnode *vp;
1651 struct stat sb;
1652 struct nameidata nd;
1653
1654 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1655 SCARG(uap, path), td);
984263bc
MD
1656 if ((error = namei(&nd)) != 0)
1657 return (error);
1658 vp = nd.ni_vp;
dadab5e9 1659 error = vn_stat(vp, &sb, td);
984263bc
MD
1660 NDFREE(&nd, NDF_ONLY_PNBUF);
1661 vput(vp);
1662 if (error)
1663 return (error);
1664 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1665 return (error);
1666}
1667
1668void
1669cvtnstat(sb, nsb)
1670 struct stat *sb;
1671 struct nstat *nsb;
1672{
1673 nsb->st_dev = sb->st_dev;
1674 nsb->st_ino = sb->st_ino;
1675 nsb->st_mode = sb->st_mode;
1676 nsb->st_nlink = sb->st_nlink;
1677 nsb->st_uid = sb->st_uid;
1678 nsb->st_gid = sb->st_gid;
1679 nsb->st_rdev = sb->st_rdev;
1680 nsb->st_atimespec = sb->st_atimespec;
1681 nsb->st_mtimespec = sb->st_mtimespec;
1682 nsb->st_ctimespec = sb->st_ctimespec;
1683 nsb->st_size = sb->st_size;
1684 nsb->st_blocks = sb->st_blocks;
1685 nsb->st_blksize = sb->st_blksize;
1686 nsb->st_flags = sb->st_flags;
1687 nsb->st_gen = sb->st_gen;
1688 nsb->st_qspare[0] = sb->st_qspare[0];
1689 nsb->st_qspare[1] = sb->st_qspare[1];
1690}
1691
41c20dac
MD
1692/*
1693 * nstat_args(char *path, struct nstat *ub)
1694 */
984263bc
MD
1695/* ARGSUSED */
1696int
41c20dac 1697nstat(struct nstat_args *uap)
984263bc 1698{
dadab5e9 1699 struct thread *td = curthread;
984263bc
MD
1700 struct stat sb;
1701 struct nstat nsb;
1702 int error;
1703 struct nameidata nd;
1704
1705 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1706 SCARG(uap, path), td);
984263bc
MD
1707 if ((error = namei(&nd)) != 0)
1708 return (error);
1709 NDFREE(&nd, NDF_ONLY_PNBUF);
dadab5e9 1710 error = vn_stat(nd.ni_vp, &sb, td);
984263bc
MD
1711 vput(nd.ni_vp);
1712 if (error)
1713 return (error);
1714 cvtnstat(&sb, &nsb);
1715 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
1716 return (error);
1717}
1718
1719/*
41c20dac
MD
1720 * lstat_args(char *path, struct stat *ub)
1721 *
984263bc
MD
1722 * Get file status; this version does not follow links.
1723 */
984263bc
MD
1724/* ARGSUSED */
1725int
41c20dac 1726nlstat(struct nlstat_args *uap)
984263bc 1727{
dadab5e9 1728 struct thread *td = curthread;
984263bc
MD
1729 int error;
1730 struct vnode *vp;
1731 struct stat sb;
1732 struct nstat nsb;
1733 struct nameidata nd;
1734
1735 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1736 SCARG(uap, path), td);
984263bc
MD
1737 if ((error = namei(&nd)) != 0)
1738 return (error);
1739 vp = nd.ni_vp;
1740 NDFREE(&nd, NDF_ONLY_PNBUF);
dadab5e9 1741 error = vn_stat(vp, &sb, td);
984263bc
MD
1742 vput(vp);
1743 if (error)
1744 return (error);
1745 cvtnstat(&sb, &nsb);
1746 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
1747 return (error);
1748}
1749
1750/*
41c20dac
MD
1751 * pathconf_Args(char *path, int name)
1752 *
984263bc
MD
1753 * Get configurable pathname variables.
1754 */
984263bc
MD
1755/* ARGSUSED */
1756int
41c20dac 1757pathconf(struct pathconf_args *uap)
984263bc 1758{
dadab5e9
MD
1759 struct thread *td = curthread;
1760 struct proc *p = td->td_proc;
984263bc
MD
1761 int error;
1762 struct nameidata nd;
1763
1764 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1765 SCARG(uap, path), td);
984263bc
MD
1766 if ((error = namei(&nd)) != 0)
1767 return (error);
1768 NDFREE(&nd, NDF_ONLY_PNBUF);
1769 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval);
1770 vput(nd.ni_vp);
1771 return (error);
1772}
1773
1774/*
41c20dac
MD
1775 * readlink_args(char *path, char *buf, int count)
1776 *
984263bc
MD
1777 * Return target name of a symbolic link.
1778 */
984263bc
MD
1779/* ARGSUSED */
1780int
41c20dac 1781readlink(struct readlink_args *uap)
984263bc 1782{
dadab5e9
MD
1783 struct thread *td = curthread;
1784 struct proc *p = td->td_proc;
41c20dac 1785 struct vnode *vp;
984263bc
MD
1786 struct iovec aiov;
1787 struct uio auio;
1788 int error;
1789 struct nameidata nd;
1790
1791 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
dadab5e9 1792 SCARG(uap, path), td);
984263bc
MD
1793 if ((error = namei(&nd)) != 0)
1794 return (error);
1795 NDFREE(&nd, NDF_ONLY_PNBUF);
1796 vp = nd.ni_vp;
1797 if (vp->v_type != VLNK)
1798 error = EINVAL;
1799 else {
1800 aiov.iov_base = SCARG(uap, buf);
1801 aiov.iov_len = SCARG(uap, count);
1802 auio.uio_iov = &aiov;
1803 auio.uio_iovcnt = 1;
1804 auio.uio_offset = 0;
1805 auio.uio_rw = UIO_READ;
1806 auio.uio_segflg = UIO_USERSPACE;
dadab5e9 1807 auio.uio_td = td;
984263bc
MD
1808 auio.uio_resid = SCARG(uap, count);
1809 error = VOP_READLINK(vp, &auio, p->p_ucred);
1810 }
1811 vput(vp);
1812 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
1813 return (error);
1814}
1815
1816static int
41c20dac 1817setfflags(struct vnode *vp, int flags)
984263bc 1818{
dadab5e9
MD
1819 struct thread *td = curthread;
1820 struct proc *p = td->td_proc;
984263bc
MD
1821 int error;
1822 struct vattr vattr;
1823
1824 /*
1825 * Prevent non-root users from setting flags on devices. When
1826 * a device is reused, users can retain ownership of the device
1827 * if they are allowed to set flags and programs assume that
1828 * chown can't fail when done as root.
1829 */
1830 if ((vp->v_type == VCHR || vp->v_type == VBLK) &&
dadab5e9 1831 ((error = suser_cred(p->p_ucred, PRISON_ROOT)) != 0))
984263bc
MD
1832 return (error);
1833
dadab5e9
MD
1834 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1835 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
1836 VATTR_NULL(&vattr);
1837 vattr.va_flags = flags;
dadab5e9
MD
1838 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
1839 VOP_UNLOCK(vp, 0, td);
984263bc
MD
1840 return (error);
1841}
1842
1843/*
41c20dac
MD
1844 * chflags(char *path, int flags)
1845 *
984263bc
MD
1846 * Change flags of a file given a path name.
1847 */
984263bc
MD
1848/* ARGSUSED */
1849int
41c20dac 1850chflags(struct chflags_args *uap)
984263bc 1851{
dadab5e9 1852 struct thread *td = curthread;
984263bc
MD
1853 int error;
1854 struct nameidata nd;
1855
dadab5e9 1856 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1857 if ((error = namei(&nd)) != 0)
1858 return (error);
1859 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 1860 error = setfflags(nd.ni_vp, SCARG(uap, flags));
984263bc
MD
1861 vrele(nd.ni_vp);
1862 return error;
1863}
1864
1865/*
41c20dac
MD
1866 * fchflags_args(int fd, int flags)
1867 *
984263bc
MD
1868 * Change flags of a file given a file descriptor.
1869 */
984263bc
MD
1870/* ARGSUSED */
1871int
41c20dac 1872fchflags(struct fchflags_args *uap)
984263bc 1873{
dadab5e9
MD
1874 struct thread *td = curthread;
1875 struct proc *p = td->td_proc;
984263bc
MD
1876 struct file *fp;
1877 int error;
1878
1879 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1880 return (error);
41c20dac 1881 return setfflags((struct vnode *) fp->f_data, SCARG(uap, flags));
984263bc
MD
1882}
1883
1884static int
41c20dac 1885setfmode(struct vnode *vp, int mode)
984263bc 1886{
dadab5e9
MD
1887 struct thread *td = curthread;
1888 struct proc *p = td->td_proc;
984263bc
MD
1889 int error;
1890 struct vattr vattr;
1891
dadab5e9
MD
1892 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1893 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
1894 VATTR_NULL(&vattr);
1895 vattr.va_mode = mode & ALLPERMS;
dadab5e9
MD
1896 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
1897 VOP_UNLOCK(vp, 0, td);
984263bc
MD
1898 return error;
1899}
1900
1901/*
41c20dac
MD
1902 * chmod_args(char *path, int mode)
1903 *
984263bc
MD
1904 * Change mode of a file given path name.
1905 */
984263bc
MD
1906/* ARGSUSED */
1907int
41c20dac 1908chmod(struct chmod_args *uap)
984263bc 1909{
dadab5e9 1910 struct thread *td = curthread;
984263bc
MD
1911 int error;
1912 struct nameidata nd;
1913
dadab5e9 1914 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1915 if ((error = namei(&nd)) != 0)
1916 return (error);
1917 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 1918 error = setfmode(nd.ni_vp, SCARG(uap, mode));
984263bc
MD
1919 vrele(nd.ni_vp);
1920 return error;
1921}
1922
1923/*
41c20dac
MD
1924 * lchmod_args(char *path, int mode)
1925 *
984263bc
MD
1926 * Change mode of a file given path name (don't follow links.)
1927 */
984263bc
MD
1928/* ARGSUSED */
1929int
41c20dac 1930lchmod(struct lchmod_args *uap)
984263bc 1931{
dadab5e9 1932 struct thread *td = curthread;
984263bc
MD
1933 int error;
1934 struct nameidata nd;
1935
dadab5e9 1936 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1937 if ((error = namei(&nd)) != 0)
1938 return (error);
1939 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 1940 error = setfmode(nd.ni_vp, SCARG(uap, mode));
984263bc
MD
1941 vrele(nd.ni_vp);
1942 return error;
1943}
1944
1945/*
41c20dac
MD
1946 * fchmod_args(int fd, int mode)
1947 *
984263bc
MD
1948 * Change mode of a file given a file descriptor.
1949 */
984263bc
MD
1950/* ARGSUSED */
1951int
41c20dac 1952fchmod(struct fchmod_args *uap)
984263bc 1953{
dadab5e9
MD
1954 struct thread *td = curthread;
1955 struct proc *p = td->td_proc;
984263bc
MD
1956 struct file *fp;
1957 int error;
1958
1959 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1960 return (error);
41c20dac 1961 return setfmode((struct vnode *)fp->f_data, SCARG(uap, mode));
984263bc
MD
1962}
1963
1964static int
41c20dac 1965setfown(struct vnode *vp, uid_t uid, gid_t gid)
984263bc 1966{
dadab5e9
MD
1967 struct thread *td = curthread;
1968 struct proc *p = td->td_proc;
984263bc
MD
1969 int error;
1970 struct vattr vattr;
1971
dadab5e9
MD
1972 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1973 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
1974 VATTR_NULL(&vattr);
1975 vattr.va_uid = uid;
1976 vattr.va_gid = gid;
dadab5e9
MD
1977 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
1978 VOP_UNLOCK(vp, 0, td);
984263bc
MD
1979 return error;
1980}
1981
1982/*
41c20dac
MD
1983 * chown(char *path, int uid, int gid)
1984 *
984263bc
MD
1985 * Set ownership given a path name.
1986 */
984263bc
MD
1987/* ARGSUSED */
1988int
41c20dac 1989chown(struct chown_args *uap)
984263bc 1990{
dadab5e9 1991 struct thread *td = curthread;
984263bc
MD
1992 int error;
1993 struct nameidata nd;
1994
dadab5e9 1995 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
1996 if ((error = namei(&nd)) != 0)
1997 return (error);
1998 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 1999 error = setfown(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
984263bc
MD
2000 vrele(nd.ni_vp);
2001 return (error);
2002}
2003
2004/*
41c20dac
MD
2005 * lchown_args(char *path, int uid, int gid)
2006 *
984263bc
MD
2007 * Set ownership given a path name, do not cross symlinks.
2008 */
984263bc
MD
2009/* ARGSUSED */
2010int
41c20dac 2011lchown(struct lchown_args *uap)
984263bc 2012{
dadab5e9 2013 struct thread *td = curthread;
984263bc
MD
2014 int error;
2015 struct nameidata nd;
2016
dadab5e9 2017 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2018 if ((error = namei(&nd)) != 0)
2019 return (error);
2020 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 2021 error = setfown(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
984263bc
MD
2022 vrele(nd.ni_vp);
2023 return (error);
2024}
2025
2026/*
41c20dac
MD
2027 * fchown_args(int fd, int uid, int gid)
2028 *
984263bc
MD
2029 * Set ownership given a file descriptor.
2030 */
984263bc
MD
2031/* ARGSUSED */
2032int
41c20dac 2033fchown(struct fchown_args *uap)
984263bc 2034{
dadab5e9
MD
2035 struct thread *td = curthread;
2036 struct proc *p = td->td_proc;
984263bc
MD
2037 struct file *fp;
2038 int error;
2039
2040 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2041 return (error);
41c20dac 2042 return setfown((struct vnode *)fp->f_data,
984263bc
MD
2043 SCARG(uap, uid), SCARG(uap, gid));
2044}
2045
2046static int
41c20dac 2047getutimes(const struct timeval *usrtvp, struct timespec *tsp)
984263bc
MD
2048{
2049 struct timeval tv[2];
2050 int error;
2051
2052 if (usrtvp == NULL) {
2053 microtime(&tv[0]);
2054 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2055 tsp[1] = tsp[0];
2056 } else {
2057 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2058 return (error);
2059 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2060 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2061 }
2062 return 0;
2063}
2064
2065static int
41c20dac 2066setutimes(struct vnode *vp, const struct timespec *ts, int nullflag)
984263bc 2067{
dadab5e9
MD
2068 struct thread *td = curthread;
2069 struct proc *p = td->td_proc;
984263bc
MD
2070 int error;
2071 struct vattr vattr;
2072
dadab5e9
MD
2073 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2074 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2075 VATTR_NULL(&vattr);
2076 vattr.va_atime = ts[0];
2077 vattr.va_mtime = ts[1];
2078 if (nullflag)
2079 vattr.va_vaflags |= VA_UTIMES_NULL;
dadab5e9
MD
2080 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
2081 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2082 return error;
2083}
2084
2085/*
41c20dac
MD
2086 * utimes_args(char *path, struct timeval *tptr)
2087 *
984263bc
MD
2088 * Set the access and modification times of a file.
2089 */
984263bc
MD
2090/* ARGSUSED */
2091int
41c20dac 2092utimes(struct utimes_args *uap)
984263bc 2093{
dadab5e9 2094 struct thread *td = curthread;
984263bc
MD
2095 struct timespec ts[2];
2096 struct timeval *usrtvp;
2097 int error;
2098 struct nameidata nd;
2099
2100 usrtvp = SCARG(uap, tptr);
2101 if ((error = getutimes(usrtvp, ts)) != 0)
2102 return (error);
dadab5e9 2103 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2104 if ((error = namei(&nd)) != 0)
2105 return (error);
2106 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 2107 error = setutimes(nd.ni_vp, ts, usrtvp == NULL);
984263bc
MD
2108 vrele(nd.ni_vp);
2109 return (error);
2110}
2111
2112/*
41c20dac
MD
2113 * lutimes_args(char *path, struct timeval *tptr)
2114 *
984263bc
MD
2115 * Set the access and modification times of a file.
2116 */
984263bc
MD
2117/* ARGSUSED */
2118int
41c20dac 2119lutimes(struct lutimes_args *uap)
984263bc 2120{
dadab5e9 2121 struct thread *td = curthread;
984263bc
MD
2122 struct timespec ts[2];
2123 struct timeval *usrtvp;
2124 int error;
2125 struct nameidata nd;
2126
2127 usrtvp = SCARG(uap, tptr);
2128 if ((error = getutimes(usrtvp, ts)) != 0)
2129 return (error);
dadab5e9 2130 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2131 if ((error = namei(&nd)) != 0)
2132 return (error);
2133 NDFREE(&nd, NDF_ONLY_PNBUF);
41c20dac 2134 error = setutimes(nd.ni_vp, ts, usrtvp == NULL);
984263bc
MD
2135 vrele(nd.ni_vp);
2136 return (error);
2137}
2138
2139/*
41c20dac
MD
2140 * futimes_args(int fd, struct timeval *tptr)
2141 *
984263bc
MD
2142 * Set the access and modification times of a file.
2143 */
984263bc
MD
2144/* ARGSUSED */
2145int
41c20dac 2146futimes(struct futimes_args *uap)
984263bc 2147{
dadab5e9
MD
2148 struct thread *td = curthread;
2149 struct proc *p = td->td_proc;
984263bc
MD
2150 struct timespec ts[2];
2151 struct file *fp;
2152 struct timeval *usrtvp;
2153 int error;
2154
2155 usrtvp = SCARG(uap, tptr);
2156 if ((error = getutimes(usrtvp, ts)) != 0)
2157 return (error);
2158 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2159 return (error);
41c20dac 2160 return setutimes((struct vnode *)fp->f_data, ts, usrtvp == NULL);
984263bc
MD
2161}
2162
2163/*
41c20dac
MD
2164 * truncate(char *path, int pad, off_t length)
2165 *
984263bc
MD
2166 * Truncate a file given its path name.
2167 */
984263bc
MD
2168/* ARGSUSED */
2169int
41c20dac 2170truncate(struct truncate_args *uap)
984263bc 2171{
dadab5e9
MD
2172 struct thread *td = curthread;
2173 struct proc *p = td->td_proc;
41c20dac 2174 struct vnode *vp;
984263bc
MD
2175 struct vattr vattr;
2176 int error;
2177 struct nameidata nd;
2178
2179 if (uap->length < 0)
2180 return(EINVAL);
dadab5e9 2181 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2182 if ((error = namei(&nd)) != 0)
2183 return (error);
2184 vp = nd.ni_vp;
2185 NDFREE(&nd, NDF_ONLY_PNBUF);
dadab5e9
MD
2186 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2187 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2188 if (vp->v_type == VDIR)
2189 error = EISDIR;
2190 else if ((error = vn_writechk(vp)) == 0 &&
dadab5e9 2191 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, td)) == 0) {
984263bc
MD
2192 VATTR_NULL(&vattr);
2193 vattr.va_size = SCARG(uap, length);
dadab5e9 2194 error = VOP_SETATTR(vp, &vattr, p->p_ucred, td);
984263bc
MD
2195 }
2196 vput(vp);
2197 return (error);
2198}
2199
2200/*
41c20dac
MD
2201 * ftruncate_args(int fd, int pad, off_t length)
2202 *
984263bc
MD
2203 * Truncate a file given a file descriptor.
2204 */
984263bc
MD
2205/* ARGSUSED */
2206int
41c20dac 2207ftruncate(struct ftruncate_args *uap)
984263bc 2208{
dadab5e9
MD
2209 struct thread *td = curthread;
2210 struct proc *p = td->td_proc;
984263bc
MD
2211 struct vattr vattr;
2212 struct vnode *vp;
2213 struct file *fp;
2214 int error;
2215
2216 if (uap->length < 0)
2217 return(EINVAL);
2218 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2219 return (error);
2220 if ((fp->f_flag & FWRITE) == 0)
2221 return (EINVAL);
2222 vp = (struct vnode *)fp->f_data;
dadab5e9
MD
2223 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2224 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2225 if (vp->v_type == VDIR)
2226 error = EISDIR;
2227 else if ((error = vn_writechk(vp)) == 0) {
2228 VATTR_NULL(&vattr);
2229 vattr.va_size = SCARG(uap, length);
dadab5e9 2230 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
984263bc 2231 }
dadab5e9 2232 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2233 return (error);
2234}
2235
2236#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2237/*
41c20dac
MD
2238 * otruncate_args(char *path, long length)
2239 *
984263bc
MD
2240 * Truncate a file given its path name.
2241 */
984263bc
MD
2242/* ARGSUSED */
2243int
41c20dac 2244otruncate(struct otruncate_args *uap)
984263bc
MD
2245{
2246 struct truncate_args /* {
2247 syscallarg(char *) path;
2248 syscallarg(int) pad;
2249 syscallarg(off_t) length;
2250 } */ nuap;
2251
2252 SCARG(&nuap, path) = SCARG(uap, path);
2253 SCARG(&nuap, length) = SCARG(uap, length);
41c20dac 2254 return (truncate(&nuap));
984263bc
MD
2255}
2256
2257/*
41c20dac
MD
2258 * oftruncate_args(int fd, long length)
2259 *
984263bc
MD
2260 * Truncate a file given a file descriptor.
2261 */
984263bc
MD
2262/* ARGSUSED */
2263int
41c20dac 2264oftruncate(struct oftruncate_args *uap)
984263bc
MD
2265{
2266 struct ftruncate_args /* {
2267 syscallarg(int) fd;
2268 syscallarg(int) pad;
2269 syscallarg(off_t) length;
2270 } */ nuap;
2271
2272 SCARG(&nuap, fd) = SCARG(uap, fd);
2273 SCARG(&nuap, length) = SCARG(uap, length);
41c20dac 2274 return (ftruncate(&nuap));
984263bc
MD
2275}
2276#endif /* COMPAT_43 || COMPAT_SUNOS */
2277
2278/*
41c20dac
MD
2279 * fsync(int fd)
2280 *
984263bc
MD
2281 * Sync an open file.
2282 */
984263bc
MD
2283/* ARGSUSED */
2284int
41c20dac 2285fsync(struct fsync_args *uap)
984263bc 2286{
dadab5e9
MD
2287 struct thread *td = curthread;
2288 struct proc *p = td->td_proc;
41c20dac 2289 struct vnode *vp;
984263bc
MD
2290 struct file *fp;
2291 vm_object_t obj;
2292 int error;
2293
2294 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2295 return (error);
2296 vp = (struct vnode *)fp->f_data;
dadab5e9 2297 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2298 if (VOP_GETVOBJECT(vp, &obj) == 0)
2299 vm_object_page_clean(obj, 0, 0, 0);
3b568787 2300 if ((error = VOP_FSYNC(vp, MNT_WAIT, td)) == 0 &&
984263bc
MD
2301 vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP) &&
2302 bioops.io_fsync)
2303 error = (*bioops.io_fsync)(vp);
dadab5e9 2304 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2305 return (error);
2306}
2307
2308/*
41c20dac
MD
2309 * rename_args(char *from, char *to)
2310 *
984263bc
MD
2311 * Rename files. Source and destination must either both be directories,
2312 * or both not be directories. If target is a directory, it must be empty.
2313 */
984263bc
MD
2314/* ARGSUSED */
2315int
41c20dac 2316rename(struct rename_args *uap)
984263bc 2317{
dadab5e9
MD
2318 struct thread *td = curthread;
2319 struct proc *p = td->td_proc;
41c20dac 2320 struct vnode *tvp, *fvp, *tdvp;
984263bc
MD
2321 struct nameidata fromnd, tond;
2322 int error;
2323
2324 bwillwrite();
2325 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
dadab5e9 2326 SCARG(uap, from), td);
984263bc
MD
2327 if ((error = namei(&fromnd)) != 0)
2328 return (error);
2329 fvp = fromnd.ni_vp;
2330 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
dadab5e9 2331 UIO_USERSPACE, SCARG(uap, to), td);
984263bc
MD
2332 if (fromnd.ni_vp->v_type == VDIR)
2333 tond.ni_cnd.cn_flags |= WILLBEDIR;
2334 if ((error = namei(&tond)) != 0) {
2335 /* Translate error code for rename("dir1", "dir2/."). */
2336 if (error == EISDIR && fvp->v_type == VDIR)
2337 error = EINVAL;
2338 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2339 vrele(fromnd.ni_dvp);
2340 vrele(fvp);
2341 goto out1;
2342 }
2343 tdvp = tond.ni_dvp;
2344 tvp = tond.ni_vp;
2345 if (tvp != NULL) {
2346 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2347 error = ENOTDIR;
2348 goto out;
2349 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2350 error = EISDIR;
2351 goto out;
2352 }
2353 }
2354 if (fvp == tdvp)
2355 error = EINVAL;
2356 /*
2357 * If the source is the same as the destination (that is, if they
2358 * are links to the same vnode), then there is nothing to do.
2359 */
2360 if (fvp == tvp)
2361 error = -1;
2362out:
2363 if (!error) {
dadab5e9 2364 VOP_LEASE(tdvp, td, p->p_ucred, LEASE_WRITE);
984263bc 2365 if (fromnd.ni_dvp != tdvp) {
dadab5e9 2366 VOP_LEASE(fromnd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
2367 }
2368 if (tvp) {
dadab5e9 2369 VOP_LEASE(tvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
2370 }
2371 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2372 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2373 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2374 NDFREE(&tond, NDF_ONLY_PNBUF);
2375 } else {
2376 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2377 NDFREE(&tond, NDF_ONLY_PNBUF);
2378 if (tdvp == tvp)
2379 vrele(tdvp);
2380 else
2381 vput(tdvp);
2382 if (tvp)
2383 vput(tvp);
2384 vrele(fromnd.ni_dvp);
2385 vrele(fvp);
2386 }
2387 vrele(tond.ni_startdir);
2388 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2389 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2390 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2391 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2392out1:
2393 if (fromnd.ni_startdir)
2394 vrele(fromnd.ni_startdir);
2395 if (error == -1)
2396 return (0);
2397 return (error);
2398}
2399
2400/*
41c20dac
MD
2401 * mkdir_args(char *path, int mode)
2402 *
984263bc
MD
2403 * Make a directory file.
2404 */
984263bc
MD
2405/* ARGSUSED */
2406int
41c20dac 2407mkdir(struct mkdir_args *uap)
984263bc 2408{
dadab5e9
MD
2409 struct thread *td = curthread;
2410 struct proc *p = td->td_proc;
41c20dac 2411 struct vnode *vp;
984263bc
MD
2412 struct vattr vattr;
2413 int error;
2414 struct nameidata nd;
2415
2416 bwillwrite();
dadab5e9 2417 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2418 nd.ni_cnd.cn_flags |= WILLBEDIR;
2419 if ((error = namei(&nd)) != 0)
2420 return (error);
2421 vp = nd.ni_vp;
2422 if (vp != NULL) {
2423 NDFREE(&nd, NDF_ONLY_PNBUF);
2424 if (nd.ni_dvp == vp)
2425 vrele(nd.ni_dvp);
2426 else
2427 vput(nd.ni_dvp);
2428 vrele(vp);
2429 return (EEXIST);
2430 }
2431 VATTR_NULL(&vattr);
2432 vattr.va_type = VDIR;
2433 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
dadab5e9 2434 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
2435 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2436 NDFREE(&nd, NDF_ONLY_PNBUF);
2437 vput(nd.ni_dvp);
2438 if (!error)
2439 vput(nd.ni_vp);
2440 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2441 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2442 return (error);
2443}
2444
2445/*
41c20dac
MD
2446 * rmdir_args(char *path)
2447 *
984263bc
MD
2448 * Remove a directory file.
2449 */
984263bc
MD
2450/* ARGSUSED */
2451int
41c20dac 2452rmdir(struct rmdir_args *uap)
984263bc 2453{
dadab5e9
MD
2454 struct thread *td = curthread;
2455 struct proc *p = td->td_proc;
41c20dac 2456 struct vnode *vp;
984263bc
MD
2457 int error;
2458 struct nameidata nd;
2459
2460 bwillwrite();
2461 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
dadab5e9 2462 SCARG(uap, path), td);
984263bc
MD
2463 if ((error = namei(&nd)) != 0)
2464 return (error);
2465 vp = nd.ni_vp;
2466 if (vp->v_type != VDIR) {
2467 error = ENOTDIR;
2468 goto out;
2469 }
2470 /*
2471 * No rmdir "." please.
2472 */
2473 if (nd.ni_dvp == vp) {
2474 error = EINVAL;
2475 goto out;
2476 }
2477 /*
2478 * The root of a mounted filesystem cannot be deleted.
2479 */
2480 if (vp->v_flag & VROOT)
2481 error = EBUSY;
2482 else {
dadab5e9
MD
2483 VOP_LEASE(nd.ni_dvp, td, p->p_ucred, LEASE_WRITE);
2484 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
984263bc
MD
2485 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2486 }
2487out:
2488 NDFREE(&nd, NDF_ONLY_PNBUF);
2489 if (nd.ni_dvp == vp)
2490 vrele(nd.ni_dvp);
2491 else
2492 vput(nd.ni_dvp);
2493 if (vp != NULLVP)
2494 vput(vp);
2495 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
2496 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
2497 return (error);
2498}
2499
2500#ifdef COMPAT_43
2501/*
41c20dac
MD
2502 * ogetdirentries_args(int fd, char *buf, u_int count, long *basep)
2503 *
984263bc
MD
2504 * Read a block of directory entries in a file system independent format.
2505 */
984263bc 2506int
41c20dac 2507ogetdirentries(struct ogetdirentries_args *uap)
984263bc 2508{
dadab5e9
MD
2509 struct thread *td = curthread;
2510 struct proc *p = td->td_proc;
984263bc
MD
2511 struct vnode *vp;
2512 struct file *fp;
2513 struct uio auio, kuio;
2514 struct iovec aiov, kiov;
2515 struct dirent *dp, *edp;
2516 caddr_t dirbuf;
2517 int error, eofflag, readcnt;
2518 long loff;
2519
2520 /* XXX arbitrary sanity limit on `count'. */
2521 if (SCARG(uap, count) > 64 * 1024)
2522 return (EINVAL);
2523 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2524 return (error);
2525 if ((fp->f_flag & FREAD) == 0)
2526 return (EBADF);
2527 vp = (struct vnode *)fp->f_data;
2528unionread:
2529 if (vp->v_type != VDIR)
2530 return (EINVAL);
2531 aiov.iov_base = SCARG(uap, buf);
2532 aiov.iov_len = SCARG(uap, count);
2533 auio.uio_iov = &aiov;
2534 auio.uio_iovcnt = 1;
2535 auio.uio_rw = UIO_READ;
2536 auio.uio_segflg = UIO_USERSPACE;
dadab5e9 2537 auio.uio_td = td;
984263bc 2538 auio.uio_resid = SCARG(uap, count);
dadab5e9 2539 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2540 loff = auio.uio_offset = fp->f_offset;
2541# if (BYTE_ORDER != LITTLE_ENDIAN)
2542 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2543 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2544 NULL, NULL);
2545 fp->f_offset = auio.uio_offset;
2546 } else
2547# endif
2548 {
2549 kuio = auio;
2550 kuio.uio_iov = &kiov;
2551 kuio.uio_segflg = UIO_SYSSPACE;
2552 kiov.iov_len = SCARG(uap, count);
2553 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2554 kiov.iov_base = dirbuf;
2555 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2556 NULL, NULL);
2557 fp->f_offset = kuio.uio_offset;
2558 if (error == 0) {
2559 readcnt = SCARG(uap, count) - kuio.uio_resid;
2560 edp = (struct dirent *)&dirbuf[readcnt];
2561 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2562# if (BYTE_ORDER == LITTLE_ENDIAN)
2563 /*
2564 * The expected low byte of
2565 * dp->d_namlen is our dp->d_type.
2566 * The high MBZ byte of dp->d_namlen
2567 * is our dp->d_namlen.
2568 */
2569 dp->d_type = dp->d_namlen;
2570 dp->d_namlen = 0;
2571# else
2572 /*
2573 * The dp->d_type is the high byte
2574 * of the expected dp->d_namlen,
2575 * so must be zero'ed.
2576 */
2577 dp->d_type = 0;
2578# endif
2579 if (dp->d_reclen > 0) {
2580 dp = (struct dirent *)
2581 ((char *)dp + dp->d_reclen);
2582 } else {
2583 error = EIO;
2584 break;
2585 }
2586 }
2587 if (dp >= edp)
2588 error = uiomove(dirbuf, readcnt, &auio);
2589 }
2590 FREE(dirbuf, M_TEMP);
2591 }
dadab5e9 2592 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2593 if (error)
2594 return (error);
2595 if (SCARG(uap, count) == auio.uio_resid) {
2596 if (union_dircheckp) {
dadab5e9 2597 error = union_dircheckp(td, &vp, fp);
984263bc
MD
2598 if (error == -1)
2599 goto unionread;
2600 if (error)
2601 return (error);
2602 }
2603 if ((vp->v_flag & VROOT) &&
2604 (vp->v_mount->mnt_flag & MNT_UNION)) {
2605 struct vnode *tvp = vp;
2606 vp = vp->v_mount->mnt_vnodecovered;
2607 VREF(vp);
2608 fp->f_data = (caddr_t) vp;
2609 fp->f_offset = 0;
2610 vrele(tvp);
2611 goto unionread;
2612 }
2613 }
2614 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2615 sizeof(long));
2616 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2617 return (error);
2618}
2619#endif /* COMPAT_43 */
2620
2621/*
41c20dac
MD
2622 * getdirentries_args(int fd, char *buf, u_int conut, long *basep)
2623 *
984263bc
MD
2624 * Read a block of directory entries in a file system independent format.
2625 */
984263bc 2626int
41c20dac 2627getdirentries(struct getdirentries_args *uap)
984263bc 2628{
dadab5e9
MD
2629 struct thread *td = curthread;
2630 struct proc *p = td->td_proc;
984263bc
MD
2631 struct vnode *vp;
2632 struct file *fp;
2633 struct uio auio;
2634 struct iovec aiov;
2635 long loff;
2636 int error, eofflag;
2637
2638 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2639 return (error);
2640 if ((fp->f_flag & FREAD) == 0)
2641 return (EBADF);
2642 vp = (struct vnode *)fp->f_data;
2643unionread:
2644 if (vp->v_type != VDIR)
2645 return (EINVAL);
2646 aiov.iov_base = SCARG(uap, buf);
2647 aiov.iov_len = SCARG(uap, count);
2648 auio.uio_iov = &aiov;
2649 auio.uio_iovcnt = 1;
2650 auio.uio_rw = UIO_READ;
2651 auio.uio_segflg = UIO_USERSPACE;
dadab5e9 2652 auio.uio_td = td;
984263bc 2653 auio.uio_resid = SCARG(uap, count);
dadab5e9
MD
2654 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
2655 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2656 loff = auio.uio_offset = fp->f_offset;
2657 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2658 fp->f_offset = auio.uio_offset;
dadab5e9 2659 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2660 if (error)
2661 return (error);
2662 if (SCARG(uap, count) == auio.uio_resid) {
2663 if (union_dircheckp) {
dadab5e9 2664 error = union_dircheckp(td, &vp, fp);
984263bc
MD
2665 if (error == -1)
2666 goto unionread;
2667 if (error)
2668 return (error);
2669 }
2670 if ((vp->v_flag & VROOT) &&
2671 (vp->v_mount->mnt_flag & MNT_UNION)) {
2672 struct vnode *tvp = vp;
2673 vp = vp->v_mount->mnt_vnodecovered;
2674 VREF(vp);
2675 fp->f_data = (caddr_t) vp;
2676 fp->f_offset = 0;
2677 vrele(tvp);
2678 goto unionread;
2679 }
2680 }
2681 if (SCARG(uap, basep) != NULL) {
2682 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2683 sizeof(long));
2684 }
2685 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2686 return (error);
2687}
41c20dac
MD
2688
2689/*
2690 * getdents_args(int fd, char *buf, size_t count)
2691 */
984263bc 2692int
41c20dac 2693getdents(struct getdents_args *uap)
984263bc
MD
2694{
2695 struct getdirentries_args ap;
41c20dac 2696
984263bc
MD
2697 ap.fd = uap->fd;
2698 ap.buf = uap->buf;
2699 ap.count = uap->count;
2700 ap.basep = NULL;
41c20dac 2701 return getdirentries(&ap);
984263bc
MD
2702}
2703
2704/*
41c20dac
MD
2705 * umask(int newmask)
2706 *
984263bc
MD
2707 * Set the mode mask for creation of filesystem nodes.
2708 *
2709 * MP SAFE
2710 */
984263bc 2711int
41c20dac 2712umask(struct umask_args *uap)
984263bc 2713{
dadab5e9
MD
2714 struct thread *td = curthread;
2715 struct proc *p = td->td_proc;
41c20dac 2716 struct filedesc *fdp;
984263bc
MD
2717
2718 fdp = p->p_fd;
2719 p->p_retval[0] = fdp->fd_cmask;
2720 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2721 return (0);
2722}
2723
2724/*
41c20dac
MD
2725 * revoke(char *path)
2726 *
984263bc
MD
2727 * Void all references to file by ripping underlying filesystem
2728 * away from vnode.
2729 */
984263bc
MD
2730/* ARGSUSED */
2731int
41c20dac 2732revoke(struct revoke_args *uap)
984263bc 2733{
dadab5e9
MD
2734 struct thread *td = curthread;
2735 struct proc *p = td->td_proc;
41c20dac 2736 struct vnode *vp;
984263bc
MD
2737 struct vattr vattr;
2738 int error;
2739 struct nameidata nd;
2740
dadab5e9 2741 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
2742 if ((error = namei(&nd)) != 0)
2743 return (error);
2744 vp = nd.ni_vp;
2745 NDFREE(&nd, NDF_ONLY_PNBUF);
2746 if (vp->v_type != VCHR && vp->v_type != VBLK) {
2747 error = EINVAL;
2748 goto out;
2749 }
3b568787 2750 if ((error = VOP_GETATTR(vp, &vattr, td)) != 0)
984263bc
MD
2751 goto out;
2752 if (p->p_ucred->cr_uid != vattr.va_uid &&
dadab5e9 2753 (error = suser_cred(p->p_ucred, PRISON_ROOT)))
984263bc
MD
2754 goto out;
2755 if (vcount(vp) > 1)
2756 VOP_REVOKE(vp, REVOKEALL);
2757out:
2758 vrele(vp);
2759 return (error);
2760}
2761
2762/*
2763 * Convert a user file descriptor to a kernel file entry.
2764 */
2765int
41c20dac 2766getvnode(struct filedesc *fdp, int fd, struct file **fpp)
984263bc
MD
2767{
2768 struct file *fp;
2769
2770 if ((u_int)fd >= fdp->fd_nfiles ||
2771 (fp = fdp->fd_ofiles[fd]) == NULL)
2772 return (EBADF);
2773 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2774 return (EINVAL);
2775 *fpp = fp;
2776 return (0);
2777}
2778/*
41c20dac
MD
2779 * getfh_args(char *fname, fhandle_t *fhp)
2780 *
984263bc
MD
2781 * Get (NFS) file handle
2782 */
984263bc 2783int
41c20dac 2784getfh(struct getfh_args *uap)
984263bc 2785{
dadab5e9 2786 struct thread *td = curthread;
984263bc
MD
2787 struct nameidata nd;
2788 fhandle_t fh;
41c20dac 2789 struct vnode *vp;
984263bc
MD
2790 int error;
2791
2792 /*
2793 * Must be super user
2794 */
dadab5e9 2795 error = suser(td);
984263bc
MD
2796 if (error)
2797 return (error);
dadab5e9 2798 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
984263bc
MD
2799 error = namei(&nd);
2800 if (error)
2801 return (error);
2802 NDFREE(&nd, NDF_ONLY_PNBUF);
2803 vp = nd.ni_vp;
2804 bzero(&fh, sizeof(fh));
2805 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2806 error = VFS_VPTOFH(vp, &fh.fh_fid);
2807 vput(vp);
2808 if (error)
2809 return (error);
2810 error = copyout(&fh, uap->fhp, sizeof (fh));
2811 return (error);
2812}
2813
2814/*
41c20dac
MD
2815 * fhopen_args(const struct fhandle *u_fhp, int flags)
2816 *
984263bc
MD
2817 * syscall for the rpc.lockd to use to translate a NFS file handle into
2818 * an open descriptor.
2819 *
2820 * warning: do not remove the suser() call or this becomes one giant
2821 * security hole.
2822 */
984263bc 2823int
41c20dac 2824fhopen(struct fhopen_args *uap)
984263bc 2825{
dadab5e9
MD
2826 struct thread *td = curthread;
2827 struct proc *p = td->td_proc;
984263bc
MD
2828 struct mount *mp;
2829 struct vnode *vp;
2830 struct fhandle fhp;
2831 struct vattr vat;
2832 struct vattr *vap = &vat;
2833 struct flock lf;
2834 struct file *fp;
41c20dac 2835 struct filedesc *fdp = p->p_fd;
984263bc
MD
2836 int fmode, mode, error, type;
2837 struct file *nfp;
2838 int indx;
2839
2840 /*
2841 * Must be super user
2842 */
dadab5e9 2843 error = suser(td);
984263bc
MD
2844 if (error)
2845 return (error);
2846
2847 fmode = FFLAGS(SCARG(uap, flags));
2848 /* why not allow a non-read/write open for our lockd? */
2849 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
2850 return (EINVAL);
2851 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
2852 if (error)
2853 return(error);
2854 /* find the mount point */
2855 mp = vfs_getvfs(&fhp.fh_fsid);
2856 if (mp == NULL)
2857 return (ESTALE);
2858 /* now give me my vnode, it gets returned to me locked */
2859 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
2860 if (error)
2861 return (error);
2862 /*
2863 * from now on we have to make sure not
2864 * to forget about the vnode
2865 * any error that causes an abort must vput(vp)
2866 * just set error = err and 'goto bad;'.
2867 */
2868
2869 /*
2870 * from vn_open
2871 */
2872 if (vp->v_type == VLNK) {
2873 error = EMLINK;
2874 goto bad;
2875 }
2876 if (vp->v_type == VSOCK) {
2877 error = EOPNOTSUPP;
2878 goto bad;
2879 }
2880 mode = 0;
2881 if (fmode & (FWRITE | O_TRUNC)) {
2882 if (vp->v_type == VDIR) {
2883 error = EISDIR;
2884 goto bad;
2885 }
2886 error = vn_writechk(vp);
2887 if (error)
2888 goto bad;
2889 mode |= VWRITE;
2890 }
2891 if (fmode & FREAD)
2892 mode |= VREAD;
2893 if (mode) {
dadab5e9 2894 error = VOP_ACCESS(vp, mode, p->p_ucred, td);
984263bc
MD
2895 if (error)
2896 goto bad;
2897 }
2898 if (fmode & O_TRUNC) {
dadab5e9
MD
2899 VOP_UNLOCK(vp, 0, td); /* XXX */
2900 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
2901 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
984263bc
MD
2902 VATTR_NULL(vap);
2903 vap->va_size = 0;
dadab5e9 2904 error = VOP_SETATTR(vp, vap, p->p_ucred, td);
984263bc
MD
2905 if (error)
2906 goto bad;
2907 }
dadab5e9 2908 error = VOP_OPEN(vp, fmode, p->p_ucred, td);
984263bc
MD
2909 if (error)
2910 goto bad;
2911 /*
2912 * Make sure that a VM object is created for VMIO support.
2913 */
2914 if (vn_canvmio(vp) == TRUE) {
3b568787 2915 if ((error = vfs_object_create(vp, td)) != 0)
984263bc
MD
2916 goto bad;
2917 }
2918 if (fmode & FWRITE)
2919 vp->v_writecount++;
2920
2921 /*
2922 * end of vn_open code
2923 */
2924
2925 if ((error = falloc(p, &nfp, &indx)) != 0) {
2926 if (fmode & FWRITE)
2927 vp->v_writecount--;
2928 goto bad;
2929 }
2930 fp = nfp;
2931
2932 /*
2933 * hold an extra reference to avoid having fp ripped out
2934 * from under us while we block in the lock op.
2935 */
2936 fhold(fp);
2937 nfp->f_data = (caddr_t)vp;
2938 nfp->f_flag = fmode & FMASK;
2939 nfp->f_ops = &vnops;
2940 nfp->f_type = DTYPE_VNODE;
2941 if (fmode & (O_EXLOCK | O_SHLOCK)) {
2942 lf.l_whence = SEEK_SET;
2943 lf.l_start = 0;
2944 lf.l_len = 0;
2945 if (fmode & O_EXLOCK)
2946 lf.l_type = F_WRLCK;
2947 else
2948 lf.l_type = F_RDLCK;
2949 type = F_FLOCK;
2950 if ((fmode & FNONBLOCK) == 0)
2951 type |= F_WAIT;
dadab5e9 2952 VOP_UNLOCK(vp, 0, td);
984263bc
MD
2953 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
2954 /*
2955 * lock request failed. Normally close the descriptor
2956 * but handle the case where someone might have dup()d
2957 * or close()d it when we weren't looking.
2958 */
2959 if (fdp->fd_ofiles[indx] == fp) {
2960 fdp->fd_ofiles[indx] = NULL;
dadab5e9 2961 fdrop(fp, td);
984263bc
MD
2962 }
2963
2964 /*
2965 * release our private reference.
2966 */
dadab5e9 2967 fdrop(fp, td);
984263bc
MD
2968 return (error);
2969 }
dadab5e9 2970 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
984263bc
MD
2971 fp->f_flag |= FHASLOCK;
2972 }
2973 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3b568787 2974 vfs_object_create(vp, td);
984263bc 2975
dadab5e9
MD
2976 VOP_UNLOCK(vp, 0, td);
2977 fdrop(fp, td);
984263bc
MD
2978 p->p_retval[0] = indx;
2979 return (0);
2980
2981bad:
2982 vput(vp);
2983 return (error);
2984}
2985
41c20dac
MD
2986/*
2987 * fhstat_args(struct fhandle *u_fhp, struct stat *sb)
2988 */
984263bc 2989int
41c20dac 2990fhstat(struct fhstat_args *uap)
984263bc 2991{
dadab5e9 2992 struct thread *td = curthread;
984263bc
MD
2993 struct stat sb;
2994 fhandle_t fh;
2995 struct mount *mp;
2996 struct vnode *vp;
2997 int error;
2998
2999 /*
3000 * Must be super user
3001 */
dadab5e9 3002 error = suser(td);
984263bc
MD
3003 if (error)
3004 return (error);
3005
3006 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3007 if (error)
3008 return (error);
3009
3010 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3011 return (ESTALE);
3012 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3013 return (error);
dadab5e9 3014 error = vn_stat(vp, &sb, td);
984263bc
MD
3015 vput(vp);
3016 if (error)
3017 return (error);
3018 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3019 return (error);
3020}
3021
41c20dac
MD
3022/*
3023 * fhstatfs_args(struct fhandle *u_fhp, struct statfs *buf)
3024 */
984263bc 3025int
41c20dac 3026fhstatfs(struct fhstatfs_args *uap)
984263bc 3027{
dadab5e9 3028 struct thread *td = curthread;
984263bc
MD
3029 struct statfs *sp;
3030 struct mount *mp;
3031 struct vnode *vp;
3032 struct statfs sb;
3033 fhandle_t fh;
3034 int error;
3035
3036 /*
3037 * Must be super user
3038 */
dadab5e9 3039 if ((error = suser(td)))
984263bc
MD
3040 return (error);
3041
3042 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3043 return (error);
3044
3045 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3046 return (ESTALE);
3047 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3048 return (error);
3049 mp = vp->v_mount;
3050 sp = &mp->mnt_stat;
3051 vput(vp);
dadab5e9 3052 if ((error = VFS_STATFS(mp, sp, td)) != 0)
984263bc
MD
3053 return (error);
3054 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
dadab5e9 3055 if (suser(td)) {
984263bc
MD
3056 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
3057 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3058 sp = &sb;
3059 }
3060 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3061}
3062
3063/*
3064 * Syscall to push extended attribute configuration information into the
3065 * VFS. Accepts a path, which it converts to a mountpoint, as well as
3066 * a command (int cmd), and attribute name and misc data. For now, the
3067 * attribute name is left in userspace for consumption by the VFS_op.
3068 * It will probably be changed to be copied into sysspace by the
3069 * syscall in the future, once issues with various consumers of the
3070 * attribute code have raised their hands.
3071 *
3072 * Currently this is used only by UFS Extended Attributes.
3073 */
3074int
41c20dac 3075extattrctl(struct extattrctl_args *uap)
984263bc 3076{
dadab5e9 3077 struct thread *td = curthread;
984263bc
MD
3078 struct nameidata nd;
3079 struct mount *mp;
3080 int error;
3081
dadab5e9 3082 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
984263bc
MD
3083 if ((error = namei(&nd)) != 0)
3084 return (error);
3085 mp = nd.ni_vp->v_mount;
3086 NDFREE(&nd, 0);
3087 return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname),
dadab5e9 3088 SCARG(uap, arg), td));
984263bc
MD
3089}
3090
3091/*
3092 * Syscall to set a named extended attribute on a file or directory.
3093 * Accepts attribute name, and a uio structure pointing to the data to set.
3094 * The uio is consumed in the style of writev(). The real work happens
3095 * in VOP_SETEXTATTR().
3096 */
3097int
41c20dac 3098extattr_set_file(struct extattr_set_file_args *uap)
984263bc 3099{
dadab5e9
MD
3100 struct thread *td = curthread;
3101 struct proc *p = td->td_proc;
984263bc
MD
3102 struct nameidata nd;
3103 struct uio auio;
3104 struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3105 char attrname[EXTATTR_MAXNAMELEN];
3106 u_int iovlen, cnt;
3107 int error, i;
3108
3109 error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3110 if (error)
3111 return (error);
3112 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9 3113 SCARG(uap, path), td);
984263bc
MD
3114 if ((error = namei(&nd)) != 0)
3115 return(error);
3116 iovlen = uap->iovcnt * sizeof(struct iovec);
3117 if (uap->iovcnt > UIO_SMALLIOV) {
3118 if (uap->iovcnt > UIO_MAXIOV) {
3119 error = EINVAL;
3120 goto done;
3121 }
3122 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3123 needfree = iov;
3124 } else
3125 iov = aiov;
3126 auio.uio_iov = iov;
3127 auio.uio_iovcnt = uap->iovcnt;
3128 auio.uio_rw = UIO_WRITE;
3129 auio.uio_segflg = UIO_USERSPACE;
dadab5e9 3130 auio.uio_td = td;
984263bc
MD
3131 auio.uio_offset = 0;
3132 if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
3133 goto done;
3134 auio.uio_resid = 0;
3135 for (i = 0; i < uap->iovcnt; i++) {
3136 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3137 error = EINVAL;
3138 goto done;
3139 }
3140 auio.uio_resid += iov->iov_len;
3141 iov++;
3142 }
3143 cnt = auio.uio_resid;
dadab5e9 3144 error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td);
984263bc
MD
3145 cnt -= auio.uio_resid;
3146 p->p_retval[0] = cnt;
3147done:
3148 if (needfree)
3149 FREE(needfree, M_IOV);
3150 NDFREE(&nd, 0);
3151 return (error);
3152}
3153
3154/*
3155 * Syscall to get a named extended attribute on a file or directory.
3156 * Accepts attribute name, and a uio structure pointing to a buffer for the
3157 * data. The uio is consumed in the style of readv(). The real work
3158 * happens in VOP_GETEXTATTR();
3159 */
3160int
41c20dac 3161extattr_get_file(struct extattr_get_file_args *uap)
984263bc 3162{
dadab5e9
MD
3163 struct thread *td = curthread;
3164 struct proc *p = td->td_proc;
984263bc
MD
3165 struct nameidata nd;
3166 struct uio auio;
3167 struct iovec *iov, *needfree, aiov[UIO_SMALLIOV];
3168 char attrname[EXTATTR_MAXNAMELEN];
3169 u_int iovlen, cnt;
3170 int error, i;
3171
3172 error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3173 if (error)
3174 return (error);
3175 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9 3176 SCARG(uap, path), td);
984263bc
MD
3177 if ((error = namei(&nd)) != 0)
3178 return (error);
3179 iovlen = uap->iovcnt * sizeof (struct iovec);
3180 if (uap->iovcnt > UIO_SMALLIOV) {
3181 if (uap->iovcnt > UIO_MAXIOV) {
3182 NDFREE(&nd, 0);
3183 return (EINVAL);
3184 }
3185 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3186 needfree = iov;
3187 } else {
3188 iov = aiov;
3189 needfree = NULL;
3190 }
3191 auio.uio_iov = iov;
3192 auio.uio_iovcnt = uap->iovcnt;
3193 auio.uio_rw = UIO_READ;
3194 auio.uio_segflg = UIO_USERSPACE;
dadab5e9 3195 auio.uio_td = td;
984263bc
MD
3196 auio.uio_offset = 0;
3197 if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
3198 goto done;
3199 auio.uio_resid = 0;
3200 for (i = 0; i < uap->iovcnt; i++) {
3201 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3202 error = EINVAL;
3203 goto done;
3204 }
3205 auio.uio_resid += iov->iov_len;
3206 iov++;
3207 }
3208 cnt = auio.uio_resid;
dadab5e9 3209 error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_ucred, td);
984263bc
MD
3210 cnt -= auio.uio_resid;
3211 p->p_retval[0] = cnt;
3212done:
3213 if (needfree)
3214 FREE(needfree, M_IOV);
3215 NDFREE(&nd, 0);
3216 return(error);
3217}
3218
3219/*
3220 * Syscall to delete a named extended attribute from a file or directory.
3221 * Accepts attribute name. The real work happens in VOP_SETEXTATTR().
3222 */
3223int
41c20dac 3224extattr_delete_file(struct extattr_delete_file_args *uap)
984263bc 3225{
dadab5e9
MD
3226 struct thread *td = curthread;
3227 struct proc *p = td->td_proc;
984263bc
MD
3228 struct nameidata nd;
3229 char attrname[EXTATTR_MAXNAMELEN];
3230 int error;
3231
3232 error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN);
3233 if (error)
3234 return(error);
3235 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
dadab5e9 3236 SCARG(uap, path), td);
984263bc
MD
3237 if ((error = namei(&nd)) != 0)
3238 return(error);
dadab5e9 3239 error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_ucred, td);
984263bc
MD
3240 NDFREE(&nd, 0);
3241 return(error);
3242}