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