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