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