xref: /freebsd/sys/kern/vfs_mountroot.c (revision e25daafbb68ed084aa9861e42691a09a4242d7d0)
124e01f59SMarcel Moolenaar /*-
2*e25daafbSMarcel Moolenaar  * Copyright (c) 2010 Marcel Moolenaar
324e01f59SMarcel Moolenaar  * Copyright (c) 1999-2004 Poul-Henning Kamp
424e01f59SMarcel Moolenaar  * Copyright (c) 1999 Michael Smith
524e01f59SMarcel Moolenaar  * Copyright (c) 1989, 1993
624e01f59SMarcel Moolenaar  *      The Regents of the University of California.  All rights reserved.
724e01f59SMarcel Moolenaar  * (c) UNIX System Laboratories, Inc.
824e01f59SMarcel Moolenaar  * All or some portions of this file are derived from material licensed
924e01f59SMarcel Moolenaar  * to the University of California by American Telephone and Telegraph
1024e01f59SMarcel Moolenaar  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
1124e01f59SMarcel Moolenaar  * the permission of UNIX System Laboratories, Inc.
1224e01f59SMarcel Moolenaar  *
1324e01f59SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
1424e01f59SMarcel Moolenaar  * modification, are permitted provided that the following conditions
1524e01f59SMarcel Moolenaar  * are met:
1624e01f59SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
1724e01f59SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
1824e01f59SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
1924e01f59SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
2024e01f59SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
2124e01f59SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
2224e01f59SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
2324e01f59SMarcel Moolenaar  *    without specific prior written permission.
2424e01f59SMarcel Moolenaar  *
2524e01f59SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2624e01f59SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2724e01f59SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2824e01f59SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2924e01f59SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3024e01f59SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3124e01f59SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3224e01f59SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3324e01f59SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3424e01f59SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3524e01f59SMarcel Moolenaar  * SUCH DAMAGE.
3624e01f59SMarcel Moolenaar  */
3724e01f59SMarcel Moolenaar 
38*e25daafbSMarcel Moolenaar #include "opt_rootdevname.h"
39*e25daafbSMarcel Moolenaar 
4024e01f59SMarcel Moolenaar #include <sys/cdefs.h>
4124e01f59SMarcel Moolenaar __FBSDID("$FreeBSD$");
4224e01f59SMarcel Moolenaar 
4324e01f59SMarcel Moolenaar #include <sys/param.h>
4424e01f59SMarcel Moolenaar #include <sys/conf.h>
4524e01f59SMarcel Moolenaar #include <sys/fcntl.h>
4624e01f59SMarcel Moolenaar #include <sys/jail.h>
4724e01f59SMarcel Moolenaar #include <sys/kernel.h>
4824e01f59SMarcel Moolenaar #include <sys/libkern.h>
4924e01f59SMarcel Moolenaar #include <sys/malloc.h>
50*e25daafbSMarcel Moolenaar #include <sys/mdioctl.h>
5124e01f59SMarcel Moolenaar #include <sys/mount.h>
5224e01f59SMarcel Moolenaar #include <sys/mutex.h>
5324e01f59SMarcel Moolenaar #include <sys/namei.h>
5424e01f59SMarcel Moolenaar #include <sys/priv.h>
5524e01f59SMarcel Moolenaar #include <sys/proc.h>
5624e01f59SMarcel Moolenaar #include <sys/filedesc.h>
5724e01f59SMarcel Moolenaar #include <sys/reboot.h>
58*e25daafbSMarcel Moolenaar #include <sys/stat.h>
5924e01f59SMarcel Moolenaar #include <sys/syscallsubr.h>
6024e01f59SMarcel Moolenaar #include <sys/sysproto.h>
6124e01f59SMarcel Moolenaar #include <sys/sx.h>
6224e01f59SMarcel Moolenaar #include <sys/sysctl.h>
6324e01f59SMarcel Moolenaar #include <sys/sysent.h>
6424e01f59SMarcel Moolenaar #include <sys/systm.h>
6524e01f59SMarcel Moolenaar #include <sys/vnode.h>
6624e01f59SMarcel Moolenaar 
6724e01f59SMarcel Moolenaar #include <geom/geom.h>
6824e01f59SMarcel Moolenaar 
6924e01f59SMarcel Moolenaar /*
7024e01f59SMarcel Moolenaar  * The root filesystem is detailed in the kernel environment variable
7124e01f59SMarcel Moolenaar  * vfs.root.mountfrom, which is expected to be in the general format
7224e01f59SMarcel Moolenaar  *
7324e01f59SMarcel Moolenaar  * <vfsname>:[<path>][	<vfsname>:[<path>] ...]
7424e01f59SMarcel Moolenaar  * vfsname   := the name of a VFS known to the kernel and capable
7524e01f59SMarcel Moolenaar  *              of being mounted as root
7624e01f59SMarcel Moolenaar  * path      := disk device name or other data used by the filesystem
7724e01f59SMarcel Moolenaar  *              to locate its physical store
7824e01f59SMarcel Moolenaar  *
7924e01f59SMarcel Moolenaar  * If the environment variable vfs.root.mountfrom is a space separated list,
8024e01f59SMarcel Moolenaar  * each list element is tried in turn and the root filesystem will be mounted
8124e01f59SMarcel Moolenaar  * from the first one that suceeds.
8224e01f59SMarcel Moolenaar  *
8324e01f59SMarcel Moolenaar  * The environment variable vfs.root.mountfrom.options is a comma delimited
8424e01f59SMarcel Moolenaar  * set of string mount options.  These mount options must be parseable
8524e01f59SMarcel Moolenaar  * by nmount() in the kernel.
8624e01f59SMarcel Moolenaar  */
8724e01f59SMarcel Moolenaar 
88*e25daafbSMarcel Moolenaar static int parse_mount(char **);
89*e25daafbSMarcel Moolenaar static struct mntarg *parse_mountroot_options(struct mntarg *, const char *);
9024e01f59SMarcel Moolenaar 
91*e25daafbSMarcel Moolenaar /*
92*e25daafbSMarcel Moolenaar  * The vnode of the system's root (/ in the filesystem, without chroot
93*e25daafbSMarcel Moolenaar  * active.)
94*e25daafbSMarcel Moolenaar  */
95*e25daafbSMarcel Moolenaar struct vnode *rootvnode;
96*e25daafbSMarcel Moolenaar 
9724e01f59SMarcel Moolenaar char *rootdevnames[2] = {NULL, NULL};
9824e01f59SMarcel Moolenaar 
9924e01f59SMarcel Moolenaar struct root_hold_token {
10024e01f59SMarcel Moolenaar 	const char			*who;
10124e01f59SMarcel Moolenaar 	LIST_ENTRY(root_hold_token)	list;
10224e01f59SMarcel Moolenaar };
10324e01f59SMarcel Moolenaar 
10424e01f59SMarcel Moolenaar static LIST_HEAD(, root_hold_token)	root_holds =
10524e01f59SMarcel Moolenaar     LIST_HEAD_INITIALIZER(root_holds);
10624e01f59SMarcel Moolenaar 
107*e25daafbSMarcel Moolenaar enum action {
108*e25daafbSMarcel Moolenaar 	A_CONTINUE,
109*e25daafbSMarcel Moolenaar 	A_PANIC,
110*e25daafbSMarcel Moolenaar 	A_REBOOT,
111*e25daafbSMarcel Moolenaar 	A_RETRY
112*e25daafbSMarcel Moolenaar };
113*e25daafbSMarcel Moolenaar 
114*e25daafbSMarcel Moolenaar static enum action root_mount_onfail = A_CONTINUE;
115*e25daafbSMarcel Moolenaar 
116*e25daafbSMarcel Moolenaar static int root_mount_mddev;
11724e01f59SMarcel Moolenaar static int root_mount_complete;
11824e01f59SMarcel Moolenaar 
119*e25daafbSMarcel Moolenaar /* By default wait up to 3 seconds for devices to appear. */
120*e25daafbSMarcel Moolenaar static int root_mount_timeout = 3;
121*e25daafbSMarcel Moolenaar 
12224e01f59SMarcel Moolenaar struct root_hold_token *
12324e01f59SMarcel Moolenaar root_mount_hold(const char *identifier)
12424e01f59SMarcel Moolenaar {
12524e01f59SMarcel Moolenaar 	struct root_hold_token *h;
12624e01f59SMarcel Moolenaar 
12724e01f59SMarcel Moolenaar 	if (root_mounted())
12824e01f59SMarcel Moolenaar 		return (NULL);
12924e01f59SMarcel Moolenaar 
13024e01f59SMarcel Moolenaar 	h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
13124e01f59SMarcel Moolenaar 	h->who = identifier;
13224e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
13324e01f59SMarcel Moolenaar 	LIST_INSERT_HEAD(&root_holds, h, list);
13424e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
13524e01f59SMarcel Moolenaar 	return (h);
13624e01f59SMarcel Moolenaar }
13724e01f59SMarcel Moolenaar 
13824e01f59SMarcel Moolenaar void
13924e01f59SMarcel Moolenaar root_mount_rel(struct root_hold_token *h)
14024e01f59SMarcel Moolenaar {
14124e01f59SMarcel Moolenaar 
14224e01f59SMarcel Moolenaar 	if (h == NULL)
14324e01f59SMarcel Moolenaar 		return;
14424e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
14524e01f59SMarcel Moolenaar 	LIST_REMOVE(h, list);
14624e01f59SMarcel Moolenaar 	wakeup(&root_holds);
14724e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
14824e01f59SMarcel Moolenaar 	free(h, M_DEVBUF);
14924e01f59SMarcel Moolenaar }
15024e01f59SMarcel Moolenaar 
15124e01f59SMarcel Moolenaar int
15224e01f59SMarcel Moolenaar root_mounted(void)
15324e01f59SMarcel Moolenaar {
15424e01f59SMarcel Moolenaar 
15524e01f59SMarcel Moolenaar 	/* No mutex is acquired here because int stores are atomic. */
15624e01f59SMarcel Moolenaar 	return (root_mount_complete);
15724e01f59SMarcel Moolenaar }
15824e01f59SMarcel Moolenaar 
15924e01f59SMarcel Moolenaar void
16024e01f59SMarcel Moolenaar root_mount_wait(void)
16124e01f59SMarcel Moolenaar {
16224e01f59SMarcel Moolenaar 
16324e01f59SMarcel Moolenaar 	/*
16424e01f59SMarcel Moolenaar 	 * Panic on an obvious deadlock - the function can't be called from
16524e01f59SMarcel Moolenaar 	 * a thread which is doing the whole SYSINIT stuff.
16624e01f59SMarcel Moolenaar 	 */
16724e01f59SMarcel Moolenaar 	KASSERT(curthread->td_proc->p_pid != 0,
16824e01f59SMarcel Moolenaar 	    ("root_mount_wait: cannot be called from the swapper thread"));
16924e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
17024e01f59SMarcel Moolenaar 	while (!root_mount_complete) {
17124e01f59SMarcel Moolenaar 		msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait",
17224e01f59SMarcel Moolenaar 		    hz);
17324e01f59SMarcel Moolenaar 	}
17424e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
17524e01f59SMarcel Moolenaar }
17624e01f59SMarcel Moolenaar 
17724e01f59SMarcel Moolenaar static void
17824e01f59SMarcel Moolenaar set_rootvnode(void)
17924e01f59SMarcel Moolenaar {
18024e01f59SMarcel Moolenaar 	struct proc *p;
18124e01f59SMarcel Moolenaar 
18224e01f59SMarcel Moolenaar 	if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
18324e01f59SMarcel Moolenaar 		panic("Cannot find root vnode");
18424e01f59SMarcel Moolenaar 
18524e01f59SMarcel Moolenaar 	VOP_UNLOCK(rootvnode, 0);
18624e01f59SMarcel Moolenaar 
18724e01f59SMarcel Moolenaar 	p = curthread->td_proc;
18824e01f59SMarcel Moolenaar 	FILEDESC_XLOCK(p->p_fd);
18924e01f59SMarcel Moolenaar 
19024e01f59SMarcel Moolenaar 	if (p->p_fd->fd_cdir != NULL)
19124e01f59SMarcel Moolenaar 		vrele(p->p_fd->fd_cdir);
19224e01f59SMarcel Moolenaar 	p->p_fd->fd_cdir = rootvnode;
19324e01f59SMarcel Moolenaar 	VREF(rootvnode);
19424e01f59SMarcel Moolenaar 
19524e01f59SMarcel Moolenaar 	if (p->p_fd->fd_rdir != NULL)
19624e01f59SMarcel Moolenaar 		vrele(p->p_fd->fd_rdir);
19724e01f59SMarcel Moolenaar 	p->p_fd->fd_rdir = rootvnode;
19824e01f59SMarcel Moolenaar 	VREF(rootvnode);
19924e01f59SMarcel Moolenaar 
20024e01f59SMarcel Moolenaar 	FILEDESC_XUNLOCK(p->p_fd);
20124e01f59SMarcel Moolenaar 
20224e01f59SMarcel Moolenaar 	EVENTHANDLER_INVOKE(mountroot);
20324e01f59SMarcel Moolenaar }
20424e01f59SMarcel Moolenaar 
205*e25daafbSMarcel Moolenaar static int
206*e25daafbSMarcel Moolenaar vfs_mountroot_devfs(struct thread *td, struct mount **mpp)
20724e01f59SMarcel Moolenaar {
20824e01f59SMarcel Moolenaar 	struct vfsoptlist *opts;
20924e01f59SMarcel Moolenaar 	struct vfsconf *vfsp;
210*e25daafbSMarcel Moolenaar 	struct mount *mp;
21124e01f59SMarcel Moolenaar 	int error;
21224e01f59SMarcel Moolenaar 
213*e25daafbSMarcel Moolenaar 	*mpp = NULL;
214*e25daafbSMarcel Moolenaar 
21524e01f59SMarcel Moolenaar 	vfsp = vfs_byname("devfs");
21624e01f59SMarcel Moolenaar 	KASSERT(vfsp != NULL, ("Could not find devfs by name"));
21724e01f59SMarcel Moolenaar 	if (vfsp == NULL)
218*e25daafbSMarcel Moolenaar 		return (ENOENT);
21924e01f59SMarcel Moolenaar 
22024e01f59SMarcel Moolenaar 	mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred);
22124e01f59SMarcel Moolenaar 
22224e01f59SMarcel Moolenaar 	error = VFS_MOUNT(mp);
22324e01f59SMarcel Moolenaar 	KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error));
22424e01f59SMarcel Moolenaar 	if (error)
225*e25daafbSMarcel Moolenaar 		return (error);
22624e01f59SMarcel Moolenaar 
22724e01f59SMarcel Moolenaar 	opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
22824e01f59SMarcel Moolenaar 	TAILQ_INIT(opts);
22924e01f59SMarcel Moolenaar 	mp->mnt_opt = opts;
23024e01f59SMarcel Moolenaar 
23124e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
23224e01f59SMarcel Moolenaar 	TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
23324e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
23424e01f59SMarcel Moolenaar 
235*e25daafbSMarcel Moolenaar 	*mpp = mp;
23624e01f59SMarcel Moolenaar 	set_rootvnode();
23724e01f59SMarcel Moolenaar 
23824e01f59SMarcel Moolenaar 	error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
23924e01f59SMarcel Moolenaar 	if (error)
24024e01f59SMarcel Moolenaar 		printf("kern_symlink /dev -> / returns %d\n", error);
241*e25daafbSMarcel Moolenaar 
242*e25daafbSMarcel Moolenaar 	return (error);
24324e01f59SMarcel Moolenaar }
24424e01f59SMarcel Moolenaar 
245*e25daafbSMarcel Moolenaar static int
246*e25daafbSMarcel Moolenaar vfs_mountroot_shuffle(struct thread *td, struct mount *mpdevfs)
24724e01f59SMarcel Moolenaar {
24824e01f59SMarcel Moolenaar 	struct nameidata nd;
249*e25daafbSMarcel Moolenaar 	struct mount *mporoot, *mpnroot;
250*e25daafbSMarcel Moolenaar 	struct vnode *vp, *vporoot, *vpdevfs;
251*e25daafbSMarcel Moolenaar 	char *fspath;
25224e01f59SMarcel Moolenaar 	int error;
25324e01f59SMarcel Moolenaar 
254*e25daafbSMarcel Moolenaar 	mpnroot = TAILQ_NEXT(mpdevfs, mnt_list);
255*e25daafbSMarcel Moolenaar 
256*e25daafbSMarcel Moolenaar 	/* Shuffle the mountlist. */
25724e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
258*e25daafbSMarcel Moolenaar 	mporoot = TAILQ_FIRST(&mountlist);
259*e25daafbSMarcel Moolenaar 	TAILQ_REMOVE(&mountlist, mpdevfs, mnt_list);
260*e25daafbSMarcel Moolenaar 	if (mporoot != mpdevfs) {
261*e25daafbSMarcel Moolenaar 		TAILQ_REMOVE(&mountlist, mpnroot, mnt_list);
262*e25daafbSMarcel Moolenaar 		TAILQ_INSERT_HEAD(&mountlist, mpnroot, mnt_list);
263*e25daafbSMarcel Moolenaar 	}
264*e25daafbSMarcel Moolenaar 	TAILQ_INSERT_TAIL(&mountlist, mpdevfs, mnt_list);
26524e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
26624e01f59SMarcel Moolenaar 
267*e25daafbSMarcel Moolenaar 	cache_purgevfs(mporoot);
268*e25daafbSMarcel Moolenaar 	if (mporoot != mpdevfs)
269*e25daafbSMarcel Moolenaar 		cache_purgevfs(mpdevfs);
27024e01f59SMarcel Moolenaar 
271*e25daafbSMarcel Moolenaar 	VFS_ROOT(mporoot, LK_EXCLUSIVE, &vporoot);
272*e25daafbSMarcel Moolenaar 
273*e25daafbSMarcel Moolenaar 	VI_LOCK(vporoot);
274*e25daafbSMarcel Moolenaar 	vporoot->v_iflag &= ~VI_MOUNT;
275*e25daafbSMarcel Moolenaar 	VI_UNLOCK(vporoot);
276*e25daafbSMarcel Moolenaar 	vporoot->v_mountedhere = NULL;
277*e25daafbSMarcel Moolenaar 	mporoot->mnt_flag &= ~MNT_ROOTFS;
278*e25daafbSMarcel Moolenaar 	mporoot->mnt_vnodecovered = NULL;
279*e25daafbSMarcel Moolenaar 	vput(vporoot);
280*e25daafbSMarcel Moolenaar 
281*e25daafbSMarcel Moolenaar 	/* Set up the new rootvnode, and purge the cache */
282*e25daafbSMarcel Moolenaar 	mpnroot->mnt_vnodecovered = NULL;
28324e01f59SMarcel Moolenaar 	set_rootvnode();
28424e01f59SMarcel Moolenaar 	cache_purgevfs(rootvnode->v_mount);
28524e01f59SMarcel Moolenaar 
286*e25daafbSMarcel Moolenaar 	if (mporoot != mpdevfs) {
287*e25daafbSMarcel Moolenaar 		/* Remount old root under /.mount or /mnt */
288*e25daafbSMarcel Moolenaar 		fspath = "/.mount";
289*e25daafbSMarcel Moolenaar 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
290*e25daafbSMarcel Moolenaar 		    fspath, td);
29124e01f59SMarcel Moolenaar 		error = namei(&nd);
29224e01f59SMarcel Moolenaar 		if (error) {
293*e25daafbSMarcel Moolenaar 			NDFREE(&nd, NDF_ONLY_PNBUF);
294*e25daafbSMarcel Moolenaar 			fspath = "/mnt";
295*e25daafbSMarcel Moolenaar 			NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
296*e25daafbSMarcel Moolenaar 			    fspath, td);
297*e25daafbSMarcel Moolenaar 			error = namei(&nd);
298*e25daafbSMarcel Moolenaar 		}
299*e25daafbSMarcel Moolenaar 		if (!error) {
300*e25daafbSMarcel Moolenaar 			vp = nd.ni_vp;
301*e25daafbSMarcel Moolenaar 			error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
302*e25daafbSMarcel Moolenaar 			if (!error)
303*e25daafbSMarcel Moolenaar 				error = vinvalbuf(vp, V_SAVE, 0, 0);
304*e25daafbSMarcel Moolenaar 			if (!error) {
305*e25daafbSMarcel Moolenaar 				cache_purge(vp);
306*e25daafbSMarcel Moolenaar 				mporoot->mnt_vnodecovered = vp;
307*e25daafbSMarcel Moolenaar 				vp->v_mountedhere = mporoot;
308*e25daafbSMarcel Moolenaar 				strlcpy(mporoot->mnt_stat.f_mntonname,
309*e25daafbSMarcel Moolenaar 				    fspath, MNAMELEN);
310*e25daafbSMarcel Moolenaar 				VOP_UNLOCK(vp, 0);
311*e25daafbSMarcel Moolenaar 			} else
312*e25daafbSMarcel Moolenaar 				vput(vp);
31324e01f59SMarcel Moolenaar 		}
31424e01f59SMarcel Moolenaar 		NDFREE(&nd, NDF_ONLY_PNBUF);
31524e01f59SMarcel Moolenaar 
316*e25daafbSMarcel Moolenaar 		if (error && bootverbose)
317*e25daafbSMarcel Moolenaar 			printf("mountroot: unable to remount previous root "
318*e25daafbSMarcel Moolenaar 			    "under /.mount or /mnt (error %d).\n", error);
319*e25daafbSMarcel Moolenaar 	}
320*e25daafbSMarcel Moolenaar 
321*e25daafbSMarcel Moolenaar 	/* Remount devfs under /dev */
322*e25daafbSMarcel Moolenaar 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td);
323*e25daafbSMarcel Moolenaar 	error = namei(&nd);
324*e25daafbSMarcel Moolenaar 	if (!error) {
325*e25daafbSMarcel Moolenaar 		vp = nd.ni_vp;
326*e25daafbSMarcel Moolenaar 		error = (vp->v_type == VDIR) ? 0 : ENOTDIR;
327*e25daafbSMarcel Moolenaar 		if (!error)
328*e25daafbSMarcel Moolenaar 			error = vinvalbuf(vp, V_SAVE, 0, 0);
329*e25daafbSMarcel Moolenaar 		if (!error) {
330*e25daafbSMarcel Moolenaar 			vpdevfs = mpdevfs->mnt_vnodecovered;
331*e25daafbSMarcel Moolenaar 			if (vpdevfs != NULL) {
332*e25daafbSMarcel Moolenaar 				cache_purge(vpdevfs);
333*e25daafbSMarcel Moolenaar 				vpdevfs->v_mountedhere = NULL;
334*e25daafbSMarcel Moolenaar 				vrele(vpdevfs);
335*e25daafbSMarcel Moolenaar 			}
336*e25daafbSMarcel Moolenaar 			mpdevfs->mnt_vnodecovered = vp;
337*e25daafbSMarcel Moolenaar 			vp->v_mountedhere = mpdevfs;
338*e25daafbSMarcel Moolenaar 			VOP_UNLOCK(vp, 0);
339*e25daafbSMarcel Moolenaar 		} else
340*e25daafbSMarcel Moolenaar 			vput(vp);
341*e25daafbSMarcel Moolenaar 	}
342*e25daafbSMarcel Moolenaar 	if (error && bootverbose)
343*e25daafbSMarcel Moolenaar 		printf("mountroot: unable to remount devfs under /dev "
344*e25daafbSMarcel Moolenaar 		    "(error %d).\n", error);
345*e25daafbSMarcel Moolenaar 	NDFREE(&nd, NDF_ONLY_PNBUF);
346*e25daafbSMarcel Moolenaar 
347*e25daafbSMarcel Moolenaar 	if (mporoot == mpdevfs) {
348*e25daafbSMarcel Moolenaar 		vfs_unbusy(mpdevfs);
34924e01f59SMarcel Moolenaar 		/* Unlink the no longer needed /dev/dev -> / symlink */
35024e01f59SMarcel Moolenaar 		error = kern_unlink(td, "/dev/dev", UIO_SYSSPACE);
351*e25daafbSMarcel Moolenaar 		if (error && bootverbose)
352*e25daafbSMarcel Moolenaar 			printf("mountroot: unable to unlink /dev/dev "
353*e25daafbSMarcel Moolenaar 			    "(error %d)\n", error);
354*e25daafbSMarcel Moolenaar 	}
355*e25daafbSMarcel Moolenaar 
356*e25daafbSMarcel Moolenaar 	return (0);
357*e25daafbSMarcel Moolenaar }
358*e25daafbSMarcel Moolenaar 
359*e25daafbSMarcel Moolenaar /*
360*e25daafbSMarcel Moolenaar  * Configuration parser.
361*e25daafbSMarcel Moolenaar  */
362*e25daafbSMarcel Moolenaar 
363*e25daafbSMarcel Moolenaar /* Parser character classes. */
364*e25daafbSMarcel Moolenaar #define	CC_WHITESPACE		-1
365*e25daafbSMarcel Moolenaar #define	CC_NONWHITESPACE	-2
366*e25daafbSMarcel Moolenaar 
367*e25daafbSMarcel Moolenaar /* Parse errors. */
368*e25daafbSMarcel Moolenaar #define	PE_EOF			-1
369*e25daafbSMarcel Moolenaar #define	PE_EOL			-2
370*e25daafbSMarcel Moolenaar 
371*e25daafbSMarcel Moolenaar static __inline int
372*e25daafbSMarcel Moolenaar parse_peek(char **conf)
373*e25daafbSMarcel Moolenaar {
374*e25daafbSMarcel Moolenaar 
375*e25daafbSMarcel Moolenaar 	return (**conf);
376*e25daafbSMarcel Moolenaar }
377*e25daafbSMarcel Moolenaar 
378*e25daafbSMarcel Moolenaar static __inline void
379*e25daafbSMarcel Moolenaar parse_poke(char **conf, int c)
380*e25daafbSMarcel Moolenaar {
381*e25daafbSMarcel Moolenaar 
382*e25daafbSMarcel Moolenaar 	**conf = c;
383*e25daafbSMarcel Moolenaar }
384*e25daafbSMarcel Moolenaar 
385*e25daafbSMarcel Moolenaar static __inline void
386*e25daafbSMarcel Moolenaar parse_advance(char **conf)
387*e25daafbSMarcel Moolenaar {
388*e25daafbSMarcel Moolenaar 
389*e25daafbSMarcel Moolenaar 	(*conf)++;
390*e25daafbSMarcel Moolenaar }
391*e25daafbSMarcel Moolenaar 
392*e25daafbSMarcel Moolenaar static __inline int
393*e25daafbSMarcel Moolenaar parse_isspace(int c)
394*e25daafbSMarcel Moolenaar {
395*e25daafbSMarcel Moolenaar 
396*e25daafbSMarcel Moolenaar 	return ((c == ' ' || c == '\t' || c == '\n') ? 1 : 0);
397*e25daafbSMarcel Moolenaar }
398*e25daafbSMarcel Moolenaar 
399*e25daafbSMarcel Moolenaar static int
400*e25daafbSMarcel Moolenaar parse_skipto(char **conf, int mc)
401*e25daafbSMarcel Moolenaar {
402*e25daafbSMarcel Moolenaar 	int c, match;
403*e25daafbSMarcel Moolenaar 
404*e25daafbSMarcel Moolenaar 	while (1) {
405*e25daafbSMarcel Moolenaar 		c = parse_peek(conf);
406*e25daafbSMarcel Moolenaar 		if (c == 0)
407*e25daafbSMarcel Moolenaar 			return (PE_EOF);
408*e25daafbSMarcel Moolenaar 		switch (mc) {
409*e25daafbSMarcel Moolenaar 		case CC_WHITESPACE:
410*e25daafbSMarcel Moolenaar 			match = (c == ' ' || c == '\t' || c == '\n') ? 1 : 0;
411*e25daafbSMarcel Moolenaar 			break;
412*e25daafbSMarcel Moolenaar 		case CC_NONWHITESPACE:
413*e25daafbSMarcel Moolenaar 			if (c == '\n')
414*e25daafbSMarcel Moolenaar 				return (PE_EOL);
415*e25daafbSMarcel Moolenaar 			match = (c != ' ' && c != '\t') ? 1 : 0;
416*e25daafbSMarcel Moolenaar 			break;
417*e25daafbSMarcel Moolenaar 		default:
418*e25daafbSMarcel Moolenaar 			match = (c == mc) ? 1 : 0;
419*e25daafbSMarcel Moolenaar 			break;
420*e25daafbSMarcel Moolenaar 		}
421*e25daafbSMarcel Moolenaar 		if (match)
422*e25daafbSMarcel Moolenaar 			break;
423*e25daafbSMarcel Moolenaar 		parse_advance(conf);
424*e25daafbSMarcel Moolenaar 	}
425*e25daafbSMarcel Moolenaar 	return (0);
426*e25daafbSMarcel Moolenaar }
427*e25daafbSMarcel Moolenaar 
428*e25daafbSMarcel Moolenaar static int
429*e25daafbSMarcel Moolenaar parse_token(char **conf, char **tok)
430*e25daafbSMarcel Moolenaar {
431*e25daafbSMarcel Moolenaar 	char *p;
432*e25daafbSMarcel Moolenaar 	size_t len;
433*e25daafbSMarcel Moolenaar 	int error;
434*e25daafbSMarcel Moolenaar 
435*e25daafbSMarcel Moolenaar 	*tok = NULL;
436*e25daafbSMarcel Moolenaar 	error = parse_skipto(conf, CC_NONWHITESPACE);
43724e01f59SMarcel Moolenaar 	if (error)
438*e25daafbSMarcel Moolenaar 		return (error);
439*e25daafbSMarcel Moolenaar 	p = *conf;
440*e25daafbSMarcel Moolenaar 	error = parse_skipto(conf, CC_WHITESPACE);
441*e25daafbSMarcel Moolenaar 	len = *conf - p;
442*e25daafbSMarcel Moolenaar 	*tok = malloc(len + 1, M_TEMP, M_WAITOK | M_ZERO);
443*e25daafbSMarcel Moolenaar 	bcopy(p, *tok, len);
444*e25daafbSMarcel Moolenaar 	return (0);
445*e25daafbSMarcel Moolenaar }
446*e25daafbSMarcel Moolenaar 
447*e25daafbSMarcel Moolenaar static void
448*e25daafbSMarcel Moolenaar parse_dir_ask_printenv(const char *var)
449*e25daafbSMarcel Moolenaar {
450*e25daafbSMarcel Moolenaar 	char *val;
451*e25daafbSMarcel Moolenaar 
452*e25daafbSMarcel Moolenaar 	val = getenv(var);
453*e25daafbSMarcel Moolenaar 	if (val != NULL) {
454*e25daafbSMarcel Moolenaar 		printf("  %s=%s\n", var, val);
455*e25daafbSMarcel Moolenaar 		freeenv(val);
456*e25daafbSMarcel Moolenaar 	}
457*e25daafbSMarcel Moolenaar }
458*e25daafbSMarcel Moolenaar 
459*e25daafbSMarcel Moolenaar static int
460*e25daafbSMarcel Moolenaar parse_dir_ask(char **conf)
461*e25daafbSMarcel Moolenaar {
462*e25daafbSMarcel Moolenaar 	char name[80];
463*e25daafbSMarcel Moolenaar 	char *mnt;
464*e25daafbSMarcel Moolenaar 	int error;
465*e25daafbSMarcel Moolenaar 
466*e25daafbSMarcel Moolenaar 	printf("\nLoader variables:\n");
467*e25daafbSMarcel Moolenaar 	parse_dir_ask_printenv("vfs.root.mountfrom");
468*e25daafbSMarcel Moolenaar 	parse_dir_ask_printenv("vfs.root.mountfrom.options");
469*e25daafbSMarcel Moolenaar 
470*e25daafbSMarcel Moolenaar 	printf("\nManual root filesystem specification:\n");
471*e25daafbSMarcel Moolenaar 	printf("  <fstype>:<device> [options]\n");
472*e25daafbSMarcel Moolenaar 	printf("      Mount <device> using filesystem <fstype>\n");
473*e25daafbSMarcel Moolenaar 	printf("      and with the specified (optional) option list.\n");
474*e25daafbSMarcel Moolenaar 	printf("\n");
475*e25daafbSMarcel Moolenaar 	printf("    eg. ufs:/dev/da0s1a\n");
476*e25daafbSMarcel Moolenaar 	printf("        zfs:tank\n");
477*e25daafbSMarcel Moolenaar 	printf("        cd9660:/dev/acd0 ro\n");
478*e25daafbSMarcel Moolenaar 	printf("          (which is equivalent to: ");
479*e25daafbSMarcel Moolenaar 	printf("mount -t cd9660 -o ro /dev/acd0 /)\n");
480*e25daafbSMarcel Moolenaar 	printf("\n");
481*e25daafbSMarcel Moolenaar 	printf("  ?               List valid disk boot devices\n");
482*e25daafbSMarcel Moolenaar 	printf("  .               Yield 1 second (for background tasks)\n");
483*e25daafbSMarcel Moolenaar 	printf("  <empty line>    Abort manual input\n");
484*e25daafbSMarcel Moolenaar 
485*e25daafbSMarcel Moolenaar  again:
486*e25daafbSMarcel Moolenaar 	printf("\nmountroot> ");
487*e25daafbSMarcel Moolenaar 	gets(name, sizeof(name), 1);
488*e25daafbSMarcel Moolenaar 	if (name[0] == '\0')
489*e25daafbSMarcel Moolenaar 		return (0);
490*e25daafbSMarcel Moolenaar 	if (name[0] == '?') {
491*e25daafbSMarcel Moolenaar 		printf("\nList of GEOM managed disk devices:\n  ");
492*e25daafbSMarcel Moolenaar 		g_dev_print();
493*e25daafbSMarcel Moolenaar 		goto again;
494*e25daafbSMarcel Moolenaar 	}
495*e25daafbSMarcel Moolenaar 	if (name[0] == '.') {
496*e25daafbSMarcel Moolenaar 		pause("rmask", hz);
497*e25daafbSMarcel Moolenaar 		goto again;
498*e25daafbSMarcel Moolenaar 	}
499*e25daafbSMarcel Moolenaar 	mnt = name;
500*e25daafbSMarcel Moolenaar 	error = parse_mount(&mnt);
501*e25daafbSMarcel Moolenaar 	if (error == -1) {
502*e25daafbSMarcel Moolenaar 		printf("Invalid specification.\n");
503*e25daafbSMarcel Moolenaar 		goto again;
504*e25daafbSMarcel Moolenaar 	}
505*e25daafbSMarcel Moolenaar 	return (error);
506*e25daafbSMarcel Moolenaar }
507*e25daafbSMarcel Moolenaar 
508*e25daafbSMarcel Moolenaar static int
509*e25daafbSMarcel Moolenaar parse_dir_md(char **conf)
510*e25daafbSMarcel Moolenaar {
511*e25daafbSMarcel Moolenaar 	struct stat sb;
512*e25daafbSMarcel Moolenaar 	struct thread *td;
513*e25daafbSMarcel Moolenaar 	struct md_ioctl *mdio;
514*e25daafbSMarcel Moolenaar 	char *path, *tok;
515*e25daafbSMarcel Moolenaar 	int error, fd, len;
516*e25daafbSMarcel Moolenaar 
517*e25daafbSMarcel Moolenaar 	td = curthread;
518*e25daafbSMarcel Moolenaar 
519*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &tok);
520*e25daafbSMarcel Moolenaar 	if (error)
521*e25daafbSMarcel Moolenaar 		return (error);
522*e25daafbSMarcel Moolenaar 
523*e25daafbSMarcel Moolenaar 	len = strlen(tok);
524*e25daafbSMarcel Moolenaar 	mdio = malloc(sizeof(*mdio) + len + 1, M_TEMP, M_WAITOK | M_ZERO);
525*e25daafbSMarcel Moolenaar 	path = (void *)(mdio + 1);
526*e25daafbSMarcel Moolenaar 	bcopy(tok, path, len);
527*e25daafbSMarcel Moolenaar 	free(tok, M_TEMP);
528*e25daafbSMarcel Moolenaar 
529*e25daafbSMarcel Moolenaar 	/* Get file status. */
530*e25daafbSMarcel Moolenaar 	error = kern_stat(td, path, UIO_SYSSPACE, &sb);
531*e25daafbSMarcel Moolenaar 	if (error)
532*e25daafbSMarcel Moolenaar 		goto out;
533*e25daafbSMarcel Moolenaar 
534*e25daafbSMarcel Moolenaar 	/* Open /dev/mdctl so that we can attach/detach. */
535*e25daafbSMarcel Moolenaar 	error = kern_open(td, "/dev/" MDCTL_NAME, UIO_SYSSPACE, O_RDWR, 0);
536*e25daafbSMarcel Moolenaar 	if (error)
537*e25daafbSMarcel Moolenaar 		goto out;
538*e25daafbSMarcel Moolenaar 
539*e25daafbSMarcel Moolenaar 	fd = td->td_retval[0];
540*e25daafbSMarcel Moolenaar 	mdio->md_version = MDIOVERSION;
541*e25daafbSMarcel Moolenaar 	mdio->md_type = MD_VNODE;
542*e25daafbSMarcel Moolenaar 
543*e25daafbSMarcel Moolenaar 	if (root_mount_mddev != -1) {
544*e25daafbSMarcel Moolenaar 		mdio->md_unit = root_mount_mddev;
545*e25daafbSMarcel Moolenaar 		DROP_GIANT();
546*e25daafbSMarcel Moolenaar 		error = kern_ioctl(td, fd, MDIOCDETACH, (void *)mdio);
547*e25daafbSMarcel Moolenaar 		PICKUP_GIANT();
548*e25daafbSMarcel Moolenaar 		/* Ignore errors. We don't care. */
549*e25daafbSMarcel Moolenaar 		root_mount_mddev = -1;
550*e25daafbSMarcel Moolenaar 	}
551*e25daafbSMarcel Moolenaar 
552*e25daafbSMarcel Moolenaar 	mdio->md_file = (void *)(mdio + 1);
553*e25daafbSMarcel Moolenaar 	mdio->md_options = MD_AUTOUNIT | MD_READONLY;
554*e25daafbSMarcel Moolenaar 	mdio->md_mediasize = sb.st_size;
555*e25daafbSMarcel Moolenaar 	mdio->md_unit = 0;
556*e25daafbSMarcel Moolenaar 	DROP_GIANT();
557*e25daafbSMarcel Moolenaar 	error = kern_ioctl(td, fd, MDIOCATTACH, (void *)mdio);
558*e25daafbSMarcel Moolenaar 	PICKUP_GIANT();
559*e25daafbSMarcel Moolenaar 	if (error)
560*e25daafbSMarcel Moolenaar 		goto out;
561*e25daafbSMarcel Moolenaar 
562*e25daafbSMarcel Moolenaar 	if (mdio->md_unit > 9) {
563*e25daafbSMarcel Moolenaar 		printf("rootmount: too many md units\n");
564*e25daafbSMarcel Moolenaar 		mdio->md_file = NULL;
565*e25daafbSMarcel Moolenaar 		mdio->md_options = 0;
566*e25daafbSMarcel Moolenaar 		mdio->md_mediasize = 0;
567*e25daafbSMarcel Moolenaar 		DROP_GIANT();
568*e25daafbSMarcel Moolenaar 		error = kern_ioctl(td, fd, MDIOCDETACH, (void *)mdio);
569*e25daafbSMarcel Moolenaar 		PICKUP_GIANT();
570*e25daafbSMarcel Moolenaar 		/* Ignore errors. We don't care. */
571*e25daafbSMarcel Moolenaar 		error = ERANGE;
572*e25daafbSMarcel Moolenaar 		goto out;
573*e25daafbSMarcel Moolenaar 	}
574*e25daafbSMarcel Moolenaar 
575*e25daafbSMarcel Moolenaar 	root_mount_mddev = mdio->md_unit;
576*e25daafbSMarcel Moolenaar 	printf(MD_NAME "%u attached to %s\n", root_mount_mddev, mdio->md_file);
577*e25daafbSMarcel Moolenaar 
578*e25daafbSMarcel Moolenaar 	error = kern_close(td, fd);
579*e25daafbSMarcel Moolenaar 
580*e25daafbSMarcel Moolenaar  out:
581*e25daafbSMarcel Moolenaar 	free(mdio, M_TEMP);
582*e25daafbSMarcel Moolenaar 	return (error);
583*e25daafbSMarcel Moolenaar }
584*e25daafbSMarcel Moolenaar 
585*e25daafbSMarcel Moolenaar static int
586*e25daafbSMarcel Moolenaar parse_dir_onfail(char **conf)
587*e25daafbSMarcel Moolenaar {
588*e25daafbSMarcel Moolenaar 	char *action;
589*e25daafbSMarcel Moolenaar 	int error;
590*e25daafbSMarcel Moolenaar 
591*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &action);
592*e25daafbSMarcel Moolenaar 	if (error)
593*e25daafbSMarcel Moolenaar 		return (error);
594*e25daafbSMarcel Moolenaar 
595*e25daafbSMarcel Moolenaar 	if (!strcmp(action, "continue"))
596*e25daafbSMarcel Moolenaar 		root_mount_onfail = A_CONTINUE;
597*e25daafbSMarcel Moolenaar 	else if (!strcmp(action, "panic"))
598*e25daafbSMarcel Moolenaar 		root_mount_onfail = A_PANIC;
599*e25daafbSMarcel Moolenaar 	else if (!strcmp(action, "reboot"))
600*e25daafbSMarcel Moolenaar 		root_mount_onfail = A_REBOOT;
601*e25daafbSMarcel Moolenaar 	else if (!strcmp(action, "retry"))
602*e25daafbSMarcel Moolenaar 		root_mount_onfail = A_RETRY;
603*e25daafbSMarcel Moolenaar 	else {
604*e25daafbSMarcel Moolenaar 		printf("rootmount: %s: unknown action\n", action);
605*e25daafbSMarcel Moolenaar 		error = EINVAL;
606*e25daafbSMarcel Moolenaar 	}
607*e25daafbSMarcel Moolenaar 
608*e25daafbSMarcel Moolenaar 	free(action, M_TEMP);
609*e25daafbSMarcel Moolenaar 	return (0);
610*e25daafbSMarcel Moolenaar }
611*e25daafbSMarcel Moolenaar 
612*e25daafbSMarcel Moolenaar static int
613*e25daafbSMarcel Moolenaar parse_dir_timeout(char **conf)
614*e25daafbSMarcel Moolenaar {
615*e25daafbSMarcel Moolenaar 	char *tok, *endtok;
616*e25daafbSMarcel Moolenaar 	long secs;
617*e25daafbSMarcel Moolenaar 	int error;
618*e25daafbSMarcel Moolenaar 
619*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &tok);
620*e25daafbSMarcel Moolenaar 	if (error)
621*e25daafbSMarcel Moolenaar 		return (error);
622*e25daafbSMarcel Moolenaar 
623*e25daafbSMarcel Moolenaar 	secs = strtol(tok, &endtok, 0);
624*e25daafbSMarcel Moolenaar 	error = (secs < 0 || *endtok != '\0') ? EINVAL : 0;
625*e25daafbSMarcel Moolenaar 	if (!error)
626*e25daafbSMarcel Moolenaar 		root_mount_timeout = secs;
627*e25daafbSMarcel Moolenaar 	free(tok, M_TEMP);
628*e25daafbSMarcel Moolenaar 	return (error);
629*e25daafbSMarcel Moolenaar }
630*e25daafbSMarcel Moolenaar 
631*e25daafbSMarcel Moolenaar static int
632*e25daafbSMarcel Moolenaar parse_directive(char **conf)
633*e25daafbSMarcel Moolenaar {
634*e25daafbSMarcel Moolenaar 	char *dir;
635*e25daafbSMarcel Moolenaar 	int error;
636*e25daafbSMarcel Moolenaar 
637*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &dir);
638*e25daafbSMarcel Moolenaar 	if (error)
639*e25daafbSMarcel Moolenaar 		return (error);
640*e25daafbSMarcel Moolenaar 
641*e25daafbSMarcel Moolenaar 	if (strcmp(dir, ".ask") == 0)
642*e25daafbSMarcel Moolenaar 		error = parse_dir_ask(conf);
643*e25daafbSMarcel Moolenaar 	else if (strcmp(dir, ".md") == 0)
644*e25daafbSMarcel Moolenaar 		error = parse_dir_md(conf);
645*e25daafbSMarcel Moolenaar 	else if (strcmp(dir, ".onfail") == 0)
646*e25daafbSMarcel Moolenaar 		error = parse_dir_onfail(conf);
647*e25daafbSMarcel Moolenaar 	else if (strcmp(dir, ".timeout") == 0)
648*e25daafbSMarcel Moolenaar 		error = parse_dir_timeout(conf);
649*e25daafbSMarcel Moolenaar 	else {
650*e25daafbSMarcel Moolenaar 		printf("mountroot: invalid directive `%s'\n", dir);
651*e25daafbSMarcel Moolenaar 		/* Ignore the rest of the line. */
652*e25daafbSMarcel Moolenaar 		(void)parse_skipto(conf, '\n');
653*e25daafbSMarcel Moolenaar 		error = EINVAL;
654*e25daafbSMarcel Moolenaar 	}
655*e25daafbSMarcel Moolenaar 	free(dir, M_TEMP);
656*e25daafbSMarcel Moolenaar 	return (error);
657*e25daafbSMarcel Moolenaar }
658*e25daafbSMarcel Moolenaar 
659*e25daafbSMarcel Moolenaar static int
660*e25daafbSMarcel Moolenaar parse_mount_dev_present(const char *dev)
661*e25daafbSMarcel Moolenaar {
662*e25daafbSMarcel Moolenaar 	struct nameidata nd;
663*e25daafbSMarcel Moolenaar 	int error;
664*e25daafbSMarcel Moolenaar 
665*e25daafbSMarcel Moolenaar 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, dev, curthread);
666*e25daafbSMarcel Moolenaar 	error = namei(&nd);
667*e25daafbSMarcel Moolenaar 	if (!error)
668*e25daafbSMarcel Moolenaar 		vput(nd.ni_vp);
669*e25daafbSMarcel Moolenaar 	NDFREE(&nd, NDF_ONLY_PNBUF);
670*e25daafbSMarcel Moolenaar 	return (error != 0) ? 0 : 1;
671*e25daafbSMarcel Moolenaar }
672*e25daafbSMarcel Moolenaar 
673*e25daafbSMarcel Moolenaar static int
674*e25daafbSMarcel Moolenaar parse_mount(char **conf)
675*e25daafbSMarcel Moolenaar {
676*e25daafbSMarcel Moolenaar 	char errmsg[255];
677*e25daafbSMarcel Moolenaar 	struct mntarg *ma;
678*e25daafbSMarcel Moolenaar 	char *dev, *fs, *opts, *tok;
679*e25daafbSMarcel Moolenaar 	int delay, error, timeout;
680*e25daafbSMarcel Moolenaar 
681*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &tok);
682*e25daafbSMarcel Moolenaar 	if (error)
683*e25daafbSMarcel Moolenaar 		return (error);
684*e25daafbSMarcel Moolenaar 	fs = tok;
685*e25daafbSMarcel Moolenaar 	error = parse_skipto(&tok, ':');
686*e25daafbSMarcel Moolenaar 	if (error) {
687*e25daafbSMarcel Moolenaar 		free(fs, M_TEMP);
688*e25daafbSMarcel Moolenaar 		return (error);
689*e25daafbSMarcel Moolenaar 	}
690*e25daafbSMarcel Moolenaar 	parse_poke(&tok, '\0');
691*e25daafbSMarcel Moolenaar 	parse_advance(&tok);
692*e25daafbSMarcel Moolenaar 	dev = tok;
693*e25daafbSMarcel Moolenaar 
694*e25daafbSMarcel Moolenaar 	if (root_mount_mddev != -1) {
695*e25daafbSMarcel Moolenaar 		/* Handle substitution for the md unit number. */
696*e25daafbSMarcel Moolenaar 		tok = strstr(dev, "md#");
697*e25daafbSMarcel Moolenaar 		if (tok != NULL)
698*e25daafbSMarcel Moolenaar 			tok[2] = '0' + root_mount_mddev;
699*e25daafbSMarcel Moolenaar 	}
700*e25daafbSMarcel Moolenaar 
701*e25daafbSMarcel Moolenaar 	/* Parse options. */
702*e25daafbSMarcel Moolenaar 	error = parse_token(conf, &tok);
703*e25daafbSMarcel Moolenaar 	opts = (error == 0) ? tok : NULL;
704*e25daafbSMarcel Moolenaar 
705*e25daafbSMarcel Moolenaar 	printf("Trying to mount root from %s:%s [%s]...\n", fs, dev,
706*e25daafbSMarcel Moolenaar 	    (opts != NULL) ? opts : "");
707*e25daafbSMarcel Moolenaar 
708*e25daafbSMarcel Moolenaar 	bzero(errmsg, sizeof(errmsg));
709*e25daafbSMarcel Moolenaar 
710*e25daafbSMarcel Moolenaar 	if (vfs_byname(fs) == NULL) {
711*e25daafbSMarcel Moolenaar 		strlcpy(errmsg, "unknown file system", sizeof(errmsg));
712*e25daafbSMarcel Moolenaar 		error = ENOENT;
713*e25daafbSMarcel Moolenaar 		goto out;
714*e25daafbSMarcel Moolenaar 	}
715*e25daafbSMarcel Moolenaar 
716*e25daafbSMarcel Moolenaar 	if (dev[0] != '\0' && !parse_mount_dev_present(dev)) {
717*e25daafbSMarcel Moolenaar 		printf("mountroot: waiting for device %s ...\n", dev);
718*e25daafbSMarcel Moolenaar 		delay = hz / 10;
719*e25daafbSMarcel Moolenaar 		timeout = root_mount_timeout * hz;
720*e25daafbSMarcel Moolenaar 		do {
721*e25daafbSMarcel Moolenaar 			pause("rmdev", delay);
722*e25daafbSMarcel Moolenaar 			timeout -= delay;
723*e25daafbSMarcel Moolenaar 		} while (timeout > 0 && !parse_mount_dev_present(dev));
724*e25daafbSMarcel Moolenaar 		if (timeout <= 0) {
725*e25daafbSMarcel Moolenaar 			error = ENODEV;
726*e25daafbSMarcel Moolenaar 			goto out;
727*e25daafbSMarcel Moolenaar 		}
728*e25daafbSMarcel Moolenaar 	}
729*e25daafbSMarcel Moolenaar 
730*e25daafbSMarcel Moolenaar 	ma = NULL;
731*e25daafbSMarcel Moolenaar 	ma = mount_arg(ma, "fstype", fs, -1);
732*e25daafbSMarcel Moolenaar 	ma = mount_arg(ma, "fspath", "/", -1);
733*e25daafbSMarcel Moolenaar 	ma = mount_arg(ma, "from", dev, -1);
734*e25daafbSMarcel Moolenaar 	ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg));
735*e25daafbSMarcel Moolenaar 	ma = mount_arg(ma, "ro", NULL, 0);
736*e25daafbSMarcel Moolenaar 	ma = parse_mountroot_options(ma, opts);
737*e25daafbSMarcel Moolenaar 	error = kernel_mount(ma, MNT_ROOTFS);
738*e25daafbSMarcel Moolenaar 
739*e25daafbSMarcel Moolenaar  out:
740*e25daafbSMarcel Moolenaar 	if (error) {
741*e25daafbSMarcel Moolenaar 		printf("Mounting from %s:%s failed with error %d",
742*e25daafbSMarcel Moolenaar 		    fs, dev, error);
743*e25daafbSMarcel Moolenaar 		if (errmsg[0] != '\0')
744*e25daafbSMarcel Moolenaar 			printf(": %s", errmsg);
745*e25daafbSMarcel Moolenaar 		printf(".\n");
746*e25daafbSMarcel Moolenaar 	}
747*e25daafbSMarcel Moolenaar 	free(fs, M_TEMP);
748*e25daafbSMarcel Moolenaar 	if (opts != NULL)
749*e25daafbSMarcel Moolenaar 		free(opts, M_TEMP);
750*e25daafbSMarcel Moolenaar 	/* kernel_mount can return -1 on error. */
751*e25daafbSMarcel Moolenaar 	return ((error < 0) ? EDOOFUS : error);
752*e25daafbSMarcel Moolenaar }
753*e25daafbSMarcel Moolenaar 
754*e25daafbSMarcel Moolenaar static int
755*e25daafbSMarcel Moolenaar vfs_mountroot_parse(struct sbuf *sb, struct mount *mpdevfs)
756*e25daafbSMarcel Moolenaar {
757*e25daafbSMarcel Moolenaar 	struct mount *mp;
758*e25daafbSMarcel Moolenaar 	char *conf;
759*e25daafbSMarcel Moolenaar 	int error;
760*e25daafbSMarcel Moolenaar 
761*e25daafbSMarcel Moolenaar 	root_mount_mddev = -1;
762*e25daafbSMarcel Moolenaar 
763*e25daafbSMarcel Moolenaar retry:
764*e25daafbSMarcel Moolenaar 	conf = sbuf_data(sb);
765*e25daafbSMarcel Moolenaar 	mp = TAILQ_NEXT(mpdevfs, mnt_list);
766*e25daafbSMarcel Moolenaar 	error = (mp == NULL) ? 0 : EDOOFUS;
767*e25daafbSMarcel Moolenaar 	root_mount_onfail = A_CONTINUE;
768*e25daafbSMarcel Moolenaar 	while (mp == NULL) {
769*e25daafbSMarcel Moolenaar 		error = parse_skipto(&conf, CC_NONWHITESPACE);
770*e25daafbSMarcel Moolenaar 		if (error == PE_EOL) {
771*e25daafbSMarcel Moolenaar 			parse_advance(&conf);
772*e25daafbSMarcel Moolenaar 			continue;
773*e25daafbSMarcel Moolenaar 		}
774*e25daafbSMarcel Moolenaar 		if (error < 0)
775*e25daafbSMarcel Moolenaar 			break;
776*e25daafbSMarcel Moolenaar 		switch (parse_peek(&conf)) {
777*e25daafbSMarcel Moolenaar 		case '#':
778*e25daafbSMarcel Moolenaar 			error = parse_skipto(&conf, '\n');
779*e25daafbSMarcel Moolenaar 			break;
780*e25daafbSMarcel Moolenaar 		case '.':
781*e25daafbSMarcel Moolenaar 			error = parse_directive(&conf);
782*e25daafbSMarcel Moolenaar 			break;
783*e25daafbSMarcel Moolenaar 		default:
784*e25daafbSMarcel Moolenaar 			error = parse_mount(&conf);
785*e25daafbSMarcel Moolenaar 			break;
786*e25daafbSMarcel Moolenaar 		}
787*e25daafbSMarcel Moolenaar 		if (error < 0)
788*e25daafbSMarcel Moolenaar 			break;
789*e25daafbSMarcel Moolenaar 		/* Ignore any trailing garbage on the line. */
790*e25daafbSMarcel Moolenaar 		if (parse_peek(&conf) != '\n') {
791*e25daafbSMarcel Moolenaar 			printf("mountroot: advancing to next directive...\n");
792*e25daafbSMarcel Moolenaar 			(void)parse_skipto(&conf, '\n');
793*e25daafbSMarcel Moolenaar 		}
794*e25daafbSMarcel Moolenaar 		mp = TAILQ_NEXT(mpdevfs, mnt_list);
795*e25daafbSMarcel Moolenaar 	}
796*e25daafbSMarcel Moolenaar 	if (mp != NULL)
797*e25daafbSMarcel Moolenaar 		return (0);
798*e25daafbSMarcel Moolenaar 
799*e25daafbSMarcel Moolenaar 	/*
800*e25daafbSMarcel Moolenaar 	 * We failed to mount (a new) root.
801*e25daafbSMarcel Moolenaar 	 */
802*e25daafbSMarcel Moolenaar 	switch (root_mount_onfail) {
803*e25daafbSMarcel Moolenaar 	case A_CONTINUE:
804*e25daafbSMarcel Moolenaar 		break;
805*e25daafbSMarcel Moolenaar 	case A_PANIC:
806*e25daafbSMarcel Moolenaar 		panic("mountroot: unable to (re-)mount root.");
807*e25daafbSMarcel Moolenaar 		/* NOTREACHED */
808*e25daafbSMarcel Moolenaar 	case A_RETRY:
809*e25daafbSMarcel Moolenaar 		goto retry;
810*e25daafbSMarcel Moolenaar 	case A_REBOOT:
811*e25daafbSMarcel Moolenaar 		kern_reboot(RB_NOSYNC);
812*e25daafbSMarcel Moolenaar 		/* NOTREACHED */
813*e25daafbSMarcel Moolenaar 	}
814*e25daafbSMarcel Moolenaar 
815*e25daafbSMarcel Moolenaar 	return (error);
816*e25daafbSMarcel Moolenaar }
817*e25daafbSMarcel Moolenaar 
818*e25daafbSMarcel Moolenaar static void
819*e25daafbSMarcel Moolenaar vfs_mountroot_conf0(struct sbuf *sb)
820*e25daafbSMarcel Moolenaar {
821*e25daafbSMarcel Moolenaar 	char *s, *tok, *mnt, *opt;
822*e25daafbSMarcel Moolenaar 	int error;
823*e25daafbSMarcel Moolenaar 
824*e25daafbSMarcel Moolenaar 	sbuf_printf(sb, ".onfail panic\n");
825*e25daafbSMarcel Moolenaar 	sbuf_printf(sb, ".timeout %d\n", root_mount_timeout);
826*e25daafbSMarcel Moolenaar 	if (boothowto & RB_ASKNAME)
827*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, ".ask\n");
828*e25daafbSMarcel Moolenaar #ifdef ROOTDEVNAME
829*e25daafbSMarcel Moolenaar 	if (boothowto & RB_DFLTROOT)
830*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "%s\n", ROOTDEVNAME);
831*e25daafbSMarcel Moolenaar #endif
832*e25daafbSMarcel Moolenaar 	if (boothowto & RB_CDROM) {
833*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "cd9660:cd0\n");
834*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, ".timeout 0\n");
835*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "cd9660:acd0\n");
836*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, ".timeout %d\n", root_mount_timeout);
837*e25daafbSMarcel Moolenaar 	}
838*e25daafbSMarcel Moolenaar 	s = getenv("vfs.root.mountfrom");
839*e25daafbSMarcel Moolenaar 	if (s != NULL) {
840*e25daafbSMarcel Moolenaar 		opt = getenv("vfs.root.mountfrom.options");
841*e25daafbSMarcel Moolenaar 		tok = s;
842*e25daafbSMarcel Moolenaar 		error = parse_token(&tok, &mnt);
843*e25daafbSMarcel Moolenaar 		while (!error) {
844*e25daafbSMarcel Moolenaar 			sbuf_printf(sb, "%s %s\n", mnt,
845*e25daafbSMarcel Moolenaar 			    (opt != NULL) ? opt : "");
846*e25daafbSMarcel Moolenaar 			free(mnt, M_TEMP);
847*e25daafbSMarcel Moolenaar 			error = parse_token(&tok, &mnt);
848*e25daafbSMarcel Moolenaar 		}
849*e25daafbSMarcel Moolenaar 		if (opt != NULL)
850*e25daafbSMarcel Moolenaar 			freeenv(opt);
851*e25daafbSMarcel Moolenaar 		freeenv(s);
852*e25daafbSMarcel Moolenaar 	}
853*e25daafbSMarcel Moolenaar 	if (rootdevnames[0] != NULL)
854*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "%s\n", rootdevnames[0]);
855*e25daafbSMarcel Moolenaar 	if (rootdevnames[1] != NULL)
856*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "%s\n", rootdevnames[1]);
857*e25daafbSMarcel Moolenaar #ifdef ROOTDEVNAME
858*e25daafbSMarcel Moolenaar 	if (!(boothowto & RB_DFLTROOT))
859*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "%s\n", ROOTDEVNAME);
860*e25daafbSMarcel Moolenaar #endif
861*e25daafbSMarcel Moolenaar 	if (!(boothowto & RB_ASKNAME))
862*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, ".ask\n");
863*e25daafbSMarcel Moolenaar }
864*e25daafbSMarcel Moolenaar 
865*e25daafbSMarcel Moolenaar static int
866*e25daafbSMarcel Moolenaar vfs_mountroot_readconf(struct thread *td, struct sbuf *sb)
867*e25daafbSMarcel Moolenaar {
868*e25daafbSMarcel Moolenaar 	static char buf[128];
869*e25daafbSMarcel Moolenaar 	struct nameidata nd;
870*e25daafbSMarcel Moolenaar 	off_t ofs;
871*e25daafbSMarcel Moolenaar 	int error, flags;
872*e25daafbSMarcel Moolenaar 	int len, resid;
873*e25daafbSMarcel Moolenaar 	int vfslocked;
874*e25daafbSMarcel Moolenaar 
875*e25daafbSMarcel Moolenaar 	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE,
876*e25daafbSMarcel Moolenaar 	    "/.mount.conf", td);
877*e25daafbSMarcel Moolenaar 	flags = FREAD;
878*e25daafbSMarcel Moolenaar 	error = vn_open(&nd, &flags, 0, NULL);
879*e25daafbSMarcel Moolenaar 	if (error)
880*e25daafbSMarcel Moolenaar 		return (error);
881*e25daafbSMarcel Moolenaar 
882*e25daafbSMarcel Moolenaar 	vfslocked = NDHASGIANT(&nd);
883*e25daafbSMarcel Moolenaar 	NDFREE(&nd, NDF_ONLY_PNBUF);
884*e25daafbSMarcel Moolenaar 	ofs = 0;
885*e25daafbSMarcel Moolenaar 	len = sizeof(buf) - 1;
886*e25daafbSMarcel Moolenaar 	while (1) {
887*e25daafbSMarcel Moolenaar 		error = vn_rdwr(UIO_READ, nd.ni_vp, buf, len, ofs,
888*e25daafbSMarcel Moolenaar 		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred,
889*e25daafbSMarcel Moolenaar 		    NOCRED, &resid, td);
890*e25daafbSMarcel Moolenaar 		if (error)
891*e25daafbSMarcel Moolenaar 			break;
892*e25daafbSMarcel Moolenaar 		if (resid == len)
893*e25daafbSMarcel Moolenaar 			break;
894*e25daafbSMarcel Moolenaar 		buf[len - resid] = 0;
895*e25daafbSMarcel Moolenaar 		sbuf_printf(sb, "%s", buf);
896*e25daafbSMarcel Moolenaar 		ofs += len - resid;
897*e25daafbSMarcel Moolenaar 	}
898*e25daafbSMarcel Moolenaar 
899*e25daafbSMarcel Moolenaar 	VOP_UNLOCK(nd.ni_vp, 0);
900*e25daafbSMarcel Moolenaar 	vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
901*e25daafbSMarcel Moolenaar 	VFS_UNLOCK_GIANT(vfslocked);
902*e25daafbSMarcel Moolenaar 	return (error);
903*e25daafbSMarcel Moolenaar }
904*e25daafbSMarcel Moolenaar 
905*e25daafbSMarcel Moolenaar static void
906*e25daafbSMarcel Moolenaar vfs_mountroot_wait(void)
907*e25daafbSMarcel Moolenaar {
908*e25daafbSMarcel Moolenaar 	struct root_hold_token *h;
909*e25daafbSMarcel Moolenaar 	struct timeval lastfail;
910*e25daafbSMarcel Moolenaar 	int curfail;
911*e25daafbSMarcel Moolenaar 
912*e25daafbSMarcel Moolenaar 	curfail = 0;
913*e25daafbSMarcel Moolenaar 	while (1) {
914*e25daafbSMarcel Moolenaar 		DROP_GIANT();
915*e25daafbSMarcel Moolenaar 		g_waitidle();
916*e25daafbSMarcel Moolenaar 		PICKUP_GIANT();
917*e25daafbSMarcel Moolenaar 		mtx_lock(&mountlist_mtx);
918*e25daafbSMarcel Moolenaar 		if (LIST_EMPTY(&root_holds)) {
919*e25daafbSMarcel Moolenaar 			mtx_unlock(&mountlist_mtx);
920*e25daafbSMarcel Moolenaar 			break;
921*e25daafbSMarcel Moolenaar 		}
922*e25daafbSMarcel Moolenaar 		if (ppsratecheck(&lastfail, &curfail, 1)) {
923*e25daafbSMarcel Moolenaar 			printf("Root mount waiting for:");
924*e25daafbSMarcel Moolenaar 			LIST_FOREACH(h, &root_holds, list)
925*e25daafbSMarcel Moolenaar 				printf(" %s", h->who);
926*e25daafbSMarcel Moolenaar 			printf("\n");
927*e25daafbSMarcel Moolenaar 		}
928*e25daafbSMarcel Moolenaar 		msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold",
929*e25daafbSMarcel Moolenaar 		    hz);
930*e25daafbSMarcel Moolenaar 	}
93124e01f59SMarcel Moolenaar }
93224e01f59SMarcel Moolenaar 
93324e01f59SMarcel Moolenaar void
93424e01f59SMarcel Moolenaar vfs_mountroot(void)
93524e01f59SMarcel Moolenaar {
936*e25daafbSMarcel Moolenaar 	struct mount *mp;
937*e25daafbSMarcel Moolenaar 	struct sbuf *sb;
938*e25daafbSMarcel Moolenaar 	struct thread *td;
939*e25daafbSMarcel Moolenaar 	time_t timebase;
940*e25daafbSMarcel Moolenaar 	int error;
94124e01f59SMarcel Moolenaar 
942*e25daafbSMarcel Moolenaar 	td = curthread;
94324e01f59SMarcel Moolenaar 
944*e25daafbSMarcel Moolenaar 	vfs_mountroot_wait();
94524e01f59SMarcel Moolenaar 
946*e25daafbSMarcel Moolenaar 	sb = sbuf_new_auto();
947*e25daafbSMarcel Moolenaar 	vfs_mountroot_conf0(sb);
948*e25daafbSMarcel Moolenaar 	sbuf_finish(sb);
94924e01f59SMarcel Moolenaar 
950*e25daafbSMarcel Moolenaar 	error = vfs_mountroot_devfs(td, &mp);
951*e25daafbSMarcel Moolenaar 	while (!error) {
952*e25daafbSMarcel Moolenaar 		error = vfs_mountroot_parse(sb, mp);
953*e25daafbSMarcel Moolenaar 		if (!error) {
954*e25daafbSMarcel Moolenaar 			error = vfs_mountroot_shuffle(td, mp);
955*e25daafbSMarcel Moolenaar 			if (!error) {
956*e25daafbSMarcel Moolenaar 				sbuf_clear(sb);
957*e25daafbSMarcel Moolenaar 				error = vfs_mountroot_readconf(td, sb);
958*e25daafbSMarcel Moolenaar 				sbuf_finish(sb);
95924e01f59SMarcel Moolenaar 			}
96024e01f59SMarcel Moolenaar 		}
96124e01f59SMarcel Moolenaar 	}
96224e01f59SMarcel Moolenaar 
963*e25daafbSMarcel Moolenaar 	sbuf_delete(sb);
964*e25daafbSMarcel Moolenaar 
96524e01f59SMarcel Moolenaar 	/*
966*e25daafbSMarcel Moolenaar 	 * Iterate over all currently mounted file systems and use
967*e25daafbSMarcel Moolenaar 	 * the time stamp found to check and/or initialize the RTC.
968*e25daafbSMarcel Moolenaar 	 * Call inittodr() only once and pass it the largest of the
969*e25daafbSMarcel Moolenaar 	 * timestamps we encounter.
97024e01f59SMarcel Moolenaar 	 */
971*e25daafbSMarcel Moolenaar 	timebase = 0;
972*e25daafbSMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
973*e25daafbSMarcel Moolenaar 	mp = TAILQ_FIRST(&mountlist);
974*e25daafbSMarcel Moolenaar 	while (mp != NULL) {
975*e25daafbSMarcel Moolenaar 		if (mp->mnt_time > timebase)
976*e25daafbSMarcel Moolenaar 			timebase = mp->mnt_time;
977*e25daafbSMarcel Moolenaar 		mp = TAILQ_NEXT(mp, mnt_list);
97824e01f59SMarcel Moolenaar 	}
979*e25daafbSMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
980*e25daafbSMarcel Moolenaar 	inittodr(timebase);
98124e01f59SMarcel Moolenaar 
982*e25daafbSMarcel Moolenaar 	/* Keep prison0's root in sync with the global rootvnode. */
983*e25daafbSMarcel Moolenaar 	mtx_lock(&prison0.pr_mtx);
984*e25daafbSMarcel Moolenaar 	prison0.pr_root = rootvnode;
985*e25daafbSMarcel Moolenaar 	vref(prison0.pr_root);
986*e25daafbSMarcel Moolenaar 	mtx_unlock(&prison0.pr_mtx);
98724e01f59SMarcel Moolenaar 
988*e25daafbSMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
989*e25daafbSMarcel Moolenaar 	atomic_store_rel_int(&root_mount_complete, 1);
990*e25daafbSMarcel Moolenaar 	wakeup(&root_mount_complete);
991*e25daafbSMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
99224e01f59SMarcel Moolenaar }
99324e01f59SMarcel Moolenaar 
99424e01f59SMarcel Moolenaar static struct mntarg *
99524e01f59SMarcel Moolenaar parse_mountroot_options(struct mntarg *ma, const char *options)
99624e01f59SMarcel Moolenaar {
99724e01f59SMarcel Moolenaar 	char *p;
99824e01f59SMarcel Moolenaar 	char *name, *name_arg;
99924e01f59SMarcel Moolenaar 	char *val, *val_arg;
100024e01f59SMarcel Moolenaar 	char *opts;
100124e01f59SMarcel Moolenaar 
100224e01f59SMarcel Moolenaar 	if (options == NULL || options[0] == '\0')
100324e01f59SMarcel Moolenaar 		return (ma);
100424e01f59SMarcel Moolenaar 
100524e01f59SMarcel Moolenaar 	p = opts = strdup(options, M_MOUNT);
100624e01f59SMarcel Moolenaar 	if (opts == NULL) {
100724e01f59SMarcel Moolenaar 		return (ma);
100824e01f59SMarcel Moolenaar 	}
100924e01f59SMarcel Moolenaar 
101024e01f59SMarcel Moolenaar 	while((name = strsep(&p, ",")) != NULL) {
101124e01f59SMarcel Moolenaar 		if (name[0] == '\0')
101224e01f59SMarcel Moolenaar 			break;
101324e01f59SMarcel Moolenaar 
101424e01f59SMarcel Moolenaar 		val = strchr(name, '=');
101524e01f59SMarcel Moolenaar 		if (val != NULL) {
101624e01f59SMarcel Moolenaar 			*val = '\0';
101724e01f59SMarcel Moolenaar 			++val;
101824e01f59SMarcel Moolenaar 		}
101924e01f59SMarcel Moolenaar 		if( strcmp(name, "rw") == 0 ||
102024e01f59SMarcel Moolenaar 		    strcmp(name, "noro") == 0) {
102124e01f59SMarcel Moolenaar 			/*
102224e01f59SMarcel Moolenaar 			 * The first time we mount the root file system,
102324e01f59SMarcel Moolenaar 			 * we need to mount 'ro', so We need to ignore
102424e01f59SMarcel Moolenaar 			 * 'rw' and 'noro' mount options.
102524e01f59SMarcel Moolenaar 			 */
102624e01f59SMarcel Moolenaar 			continue;
102724e01f59SMarcel Moolenaar 		}
102824e01f59SMarcel Moolenaar 		name_arg = strdup(name, M_MOUNT);
102924e01f59SMarcel Moolenaar 		val_arg = NULL;
103024e01f59SMarcel Moolenaar 		if (val != NULL)
103124e01f59SMarcel Moolenaar 			val_arg = strdup(val, M_MOUNT);
103224e01f59SMarcel Moolenaar 
103324e01f59SMarcel Moolenaar 		ma = mount_arg(ma, name_arg, val_arg,
103424e01f59SMarcel Moolenaar 		    (val_arg != NULL ? -1 : 0));
103524e01f59SMarcel Moolenaar 	}
103624e01f59SMarcel Moolenaar 	free(opts, M_MOUNT);
103724e01f59SMarcel Moolenaar 	return (ma);
103824e01f59SMarcel Moolenaar }
1039