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