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