xref: /illumos-gate/usr/src/boot/common/boot.c (revision 22028508)
1bc85f3b0SToomas Soome /*
2199767f8SToomas Soome  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3199767f8SToomas Soome  * All rights reserved.
4199767f8SToomas Soome  *
5199767f8SToomas Soome  * Redistribution and use in source and binary forms, with or without
6199767f8SToomas Soome  * modification, are permitted provided that the following conditions
7199767f8SToomas Soome  * are met:
8199767f8SToomas Soome  * 1. Redistributions of source code must retain the above copyright
9199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer.
10199767f8SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11199767f8SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12199767f8SToomas Soome  *    documentation and/or other materials provided with the distribution.
13199767f8SToomas Soome  *
14199767f8SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15199767f8SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16199767f8SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17199767f8SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18199767f8SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19199767f8SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20199767f8SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21199767f8SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22199767f8SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23199767f8SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24199767f8SToomas Soome  * SUCH DAMAGE.
25199767f8SToomas Soome  */
26199767f8SToomas Soome 
27199767f8SToomas Soome #include <sys/cdefs.h>
28199767f8SToomas Soome 
29199767f8SToomas Soome /*
30199767f8SToomas Soome  * Loading modules, booting the system
31199767f8SToomas Soome  */
32199767f8SToomas Soome 
33199767f8SToomas Soome #include <stand.h>
34199767f8SToomas Soome #include <string.h>
35199767f8SToomas Soome 
36199767f8SToomas Soome #include "bootstrap.h"
37199767f8SToomas Soome 
38199767f8SToomas Soome static char	*getbootfile(int try);
39d66a72cfSToomas Soome static int	loadakernel(int try, int argc, char *argv[]);
40199767f8SToomas Soome 
41d66a72cfSToomas Soome /*
42d66a72cfSToomas Soome  * List of kernel names to try (may be overwritten by boot.config)
43d66a72cfSToomas Soome  * XXX should move from here?
44d66a72cfSToomas Soome  */
45199767f8SToomas Soome static const char *default_bootfiles = "kernel";
46199767f8SToomas Soome 
47199767f8SToomas Soome static int autoboot_tried;
48199767f8SToomas Soome 
49199767f8SToomas Soome /*
50199767f8SToomas Soome  * The user wants us to boot.
51199767f8SToomas Soome  */
52199767f8SToomas Soome COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot);
53199767f8SToomas Soome 
54199767f8SToomas Soome static int
command_boot(int argc,char * argv[])55199767f8SToomas Soome command_boot(int argc, char *argv[])
56199767f8SToomas Soome {
57d66a72cfSToomas Soome 	struct preloaded_file *fp;
58d66a72cfSToomas Soome 
59d66a72cfSToomas Soome 	/*
60d66a72cfSToomas Soome 	 * See if the user has specified an explicit kernel to boot.
61d66a72cfSToomas Soome 	 */
62d66a72cfSToomas Soome 	if ((argc > 1) && (argv[1][0] == '/')) {
63d66a72cfSToomas Soome 
64d66a72cfSToomas Soome 		/* XXX maybe we should discard everything and start again? */
65d66a72cfSToomas Soome 		if (file_findfile(NULL, NULL) != NULL) {
66d66a72cfSToomas Soome 			snprintf(command_errbuf, sizeof (command_errbuf),
67d66a72cfSToomas Soome 			    "can't boot '%s', kernel module already loaded",
68d66a72cfSToomas Soome 			    argv[1]);
69d66a72cfSToomas Soome 			return (CMD_ERROR);
70d66a72cfSToomas Soome 		}
71d66a72cfSToomas Soome 
72d66a72cfSToomas Soome 		/* find/load the kernel module */
73d66a72cfSToomas Soome 		if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0)
74d66a72cfSToomas Soome 			return (CMD_ERROR);
75d66a72cfSToomas Soome 		/* we have consumed all arguments */
76d66a72cfSToomas Soome 		argc = 1;
77d66a72cfSToomas Soome 	}
78d66a72cfSToomas Soome 
79d66a72cfSToomas Soome 	/*
80d66a72cfSToomas Soome 	 * See if there is a kernel module already loaded
81d66a72cfSToomas Soome 	 */
82d66a72cfSToomas Soome 	if (file_findfile(NULL, NULL) == NULL)
83d66a72cfSToomas Soome 		if (loadakernel(0, argc - 1, argv + 1)) {
84d66a72cfSToomas Soome 			/* we have consumed all arguments */
85d66a72cfSToomas Soome 			argc = 1;
86d66a72cfSToomas Soome 		}
87d66a72cfSToomas Soome 
88d66a72cfSToomas Soome 	/*
89d66a72cfSToomas Soome 	 * Loaded anything yet?
90d66a72cfSToomas Soome 	 */
91d66a72cfSToomas Soome 	if ((fp = file_findfile(NULL, NULL)) == NULL) {
92d66a72cfSToomas Soome 		command_errmsg = "no bootable kernel";
93d66a72cfSToomas Soome 		return (CMD_ERROR);
94d66a72cfSToomas Soome 	}
95d66a72cfSToomas Soome 
96d66a72cfSToomas Soome 	/*
97d66a72cfSToomas Soome 	 * If we were given arguments, discard any previous.
98d66a72cfSToomas Soome 	 * XXX should we merge arguments?  Hard to DWIM.
99d66a72cfSToomas Soome 	 */
100d66a72cfSToomas Soome 	if (argc > 1) {
101d66a72cfSToomas Soome 		free(fp->f_args);
102d66a72cfSToomas Soome 		fp->f_args = unargv(argc - 1, argv + 1);
103199767f8SToomas Soome 	}
104199767f8SToomas Soome 
105d66a72cfSToomas Soome 	/* Hook for platform-specific autoloading of modules */
106d66a72cfSToomas Soome 	if (archsw.arch_autoload() != 0)
107d66a72cfSToomas Soome 		return (CMD_ERROR);
108d66a72cfSToomas Soome 
109d66a72cfSToomas Soome 	/* Call the exec handler from the loader matching the kernel */
110d66a72cfSToomas Soome 	file_formats[fp->f_loader]->l_exec(fp);
111d66a72cfSToomas Soome 	return (CMD_ERROR);
112199767f8SToomas Soome }
113199767f8SToomas Soome 
114199767f8SToomas Soome 
115199767f8SToomas Soome /*
116199767f8SToomas Soome  * Autoboot after a delay
117199767f8SToomas Soome  */
118199767f8SToomas Soome 
119d66a72cfSToomas Soome COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay",
120d66a72cfSToomas Soome     command_autoboot);
121199767f8SToomas Soome 
122199767f8SToomas Soome static int
command_autoboot(int argc,char * argv[])123199767f8SToomas Soome command_autoboot(int argc, char *argv[])
124199767f8SToomas Soome {
125d66a72cfSToomas Soome 	int howlong;
126d66a72cfSToomas Soome 	char *cp, *prompt;
127d66a72cfSToomas Soome 
128d66a72cfSToomas Soome 	prompt = NULL;
129d66a72cfSToomas Soome 	howlong = -1;
130d66a72cfSToomas Soome 	switch (argc) {
131d66a72cfSToomas Soome 	case 3:
132d66a72cfSToomas Soome 		prompt = argv[2];
133d66a72cfSToomas Soome 		/* FALLTHROUGH */
134d66a72cfSToomas Soome 	case 2:
135d66a72cfSToomas Soome 		howlong = strtol(argv[1], &cp, 0);
136d66a72cfSToomas Soome 		if (*cp != 0) {
137d66a72cfSToomas Soome 			snprintf(command_errbuf, sizeof (command_errbuf),
138d66a72cfSToomas Soome 			    "bad delay '%s'", argv[1]);
139d66a72cfSToomas Soome 			return (CMD_ERROR);
140d66a72cfSToomas Soome 		}
141d66a72cfSToomas Soome 		/* FALLTHROUGH */
142d66a72cfSToomas Soome 	case 1:
143d66a72cfSToomas Soome 		return (autoboot(howlong, prompt));
144199767f8SToomas Soome 	}
145199767f8SToomas Soome 
146d66a72cfSToomas Soome 	command_errmsg = "too many arguments";
147d66a72cfSToomas Soome 	return (CMD_ERROR);
148199767f8SToomas Soome }
149199767f8SToomas Soome 
150199767f8SToomas Soome /*
151199767f8SToomas Soome  * Called before we go interactive.  If we think we can autoboot, and
152199767f8SToomas Soome  * we haven't tried already, try now.
153199767f8SToomas Soome  */
154199767f8SToomas Soome void
autoboot_maybe(void)155199767f8SToomas Soome autoboot_maybe(void)
156199767f8SToomas Soome {
157d66a72cfSToomas Soome 	char *cp;
158d66a72cfSToomas Soome 
159d66a72cfSToomas Soome 	/* compatibility with sparc prom, check for autoboot? */
160d66a72cfSToomas Soome 	cp = getenv("autoboot?");
161d66a72cfSToomas Soome 	if (cp != NULL && strcasecmp(cp, "true") != 0)
162d66a72cfSToomas Soome 		return;
163d66a72cfSToomas Soome 	cp = getenv("autoboot_delay");
164d66a72cfSToomas Soome 	if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO")))
165d66a72cfSToomas Soome 		autoboot(-1, NULL);		/* try to boot automatically */
166199767f8SToomas Soome }
167199767f8SToomas Soome 
168199767f8SToomas Soome int
autoboot(int timeout,char * prompt)169199767f8SToomas Soome autoboot(int timeout, char *prompt)
170199767f8SToomas Soome {
171d66a72cfSToomas Soome 	time_t when, otime, ntime;
172d66a72cfSToomas Soome 	int c, yes;
173d66a72cfSToomas Soome 	char *argv[2], *cp, *ep;
174d66a72cfSToomas Soome 	char *kernelname;
175d66a72cfSToomas Soome 	struct preloaded_file *fp;
176d66a72cfSToomas Soome 
177d66a72cfSToomas Soome 	autoboot_tried = 1;
178d66a72cfSToomas Soome 
179d66a72cfSToomas Soome 	if (timeout == -1) {
180d66a72cfSToomas Soome 		timeout = 10;
181d66a72cfSToomas Soome 		/* try to get a delay from the environment */
182d66a72cfSToomas Soome 		if ((cp = getenv("autoboot_delay"))) {
183d66a72cfSToomas Soome 			timeout = strtol(cp, &ep, 0);
184d66a72cfSToomas Soome 			if (cp == ep)
185d66a72cfSToomas Soome 				timeout = 10;	/* Unparseable? Set default! */
186d66a72cfSToomas Soome 		}
187199767f8SToomas Soome 	}
188199767f8SToomas Soome 
189199767f8SToomas Soome 	fp = file_findfile(NULL, NULL);
190d66a72cfSToomas Soome 	if (fp == NULL) {
191d66a72cfSToomas Soome 		/* no preloaded files, run command start to load all */
192d66a72cfSToomas Soome 		bf_run("start");
193d66a72cfSToomas Soome 		fp = file_findfile(NULL, NULL);
194d66a72cfSToomas Soome 		if (fp == NULL) { /* still nothing? can't boot */
195d66a72cfSToomas Soome 			command_errmsg = "no valid kernel found";
196d66a72cfSToomas Soome 			return (CMD_ERROR);
197d66a72cfSToomas Soome 		}
198d66a72cfSToomas Soome 	}
199d66a72cfSToomas Soome 
200d66a72cfSToomas Soome 	kernelname = fp->f_name;
201d66a72cfSToomas Soome 
202d66a72cfSToomas Soome 	if (timeout >= 0) {
203d66a72cfSToomas Soome 		otime = time(NULL);
204d66a72cfSToomas Soome 		when = otime + timeout;	/* when to boot */
205d66a72cfSToomas Soome 
206d66a72cfSToomas Soome 		yes = 0;
207d66a72cfSToomas Soome 
208d66a72cfSToomas Soome 		printf("%s\n", (prompt == NULL) ?
209d66a72cfSToomas Soome 		    "Hit [Enter] to boot immediately, or any other key "
210d66a72cfSToomas Soome 		    "for command prompt." : prompt);
211d66a72cfSToomas Soome 
212d66a72cfSToomas Soome 		for (;;) {
213d66a72cfSToomas Soome 			if (ischar()) {
214d66a72cfSToomas Soome 				c = getchar();
215d66a72cfSToomas Soome 				if ((c == '\r') || (c == '\n'))
216d66a72cfSToomas Soome 					yes = 1;
217d66a72cfSToomas Soome 				break;
218d66a72cfSToomas Soome 			}
219d66a72cfSToomas Soome 			ntime = time(NULL);
220d66a72cfSToomas Soome 			if (ntime >= when) {
221d66a72cfSToomas Soome 				yes = 1;
222d66a72cfSToomas Soome 				break;
223d66a72cfSToomas Soome 			}
224d66a72cfSToomas Soome 
225d66a72cfSToomas Soome 			if (ntime != otime) {
226d66a72cfSToomas Soome 				printf("\rBooting [%s] in %d second%s... ",
227d66a72cfSToomas Soome 				    kernelname, (int)(when - ntime),
228d66a72cfSToomas Soome 				    (when - ntime) == 1? "":"s");
229d66a72cfSToomas Soome 				otime = ntime;
230d66a72cfSToomas Soome 			}
231d66a72cfSToomas Soome 		}
232d66a72cfSToomas Soome 	} else {
233d66a72cfSToomas Soome 		yes = 1;
234199767f8SToomas Soome 	}
235d66a72cfSToomas Soome 
236d66a72cfSToomas Soome 	if (yes)
237d66a72cfSToomas Soome 		printf("\rBooting [%s]...               ", kernelname);
238d66a72cfSToomas Soome 	putchar('\n');
239d66a72cfSToomas Soome 	if (yes) {
240d66a72cfSToomas Soome 		argv[0] = "boot";
241d66a72cfSToomas Soome 		argv[1] = NULL;
242d66a72cfSToomas Soome 		return (command_boot(1, argv));
243d66a72cfSToomas Soome 	}
244d66a72cfSToomas Soome 	return (CMD_OK);
245199767f8SToomas Soome }
246199767f8SToomas Soome 
247199767f8SToomas Soome /*
248199767f8SToomas Soome  * Scrounge for the name of the (try)'th file we will try to boot.
249199767f8SToomas Soome  */
250199767f8SToomas Soome static char *
getbootfile(int try)251199767f8SToomas Soome getbootfile(int try)
252199767f8SToomas Soome {
253d66a72cfSToomas Soome 	static char *name = NULL;
254d66a72cfSToomas Soome 	const char *spec, *ep;
255d66a72cfSToomas Soome 	size_t len;
256199767f8SToomas Soome 
257d66a72cfSToomas Soome 	/* we use dynamic storage */
258199767f8SToomas Soome 	free(name);
259199767f8SToomas Soome 	name = NULL;
260d66a72cfSToomas Soome 
261d66a72cfSToomas Soome 	/*
262d66a72cfSToomas Soome 	 * Try $bootfile, then try our builtin default
263d66a72cfSToomas Soome 	 */
264d66a72cfSToomas Soome 	if ((spec = getenv("bootfile")) == NULL)
265d66a72cfSToomas Soome 		spec = default_bootfiles;
266d66a72cfSToomas Soome 
267d66a72cfSToomas Soome 	while ((try > 0) && (spec != NULL)) {
268d66a72cfSToomas Soome 		spec = strchr(spec, ';');
269d66a72cfSToomas Soome 		if (spec)
270d66a72cfSToomas Soome 			spec++;	/* skip over the leading ';' */
271d66a72cfSToomas Soome 		try--;
272199767f8SToomas Soome 	}
273d66a72cfSToomas Soome 	if (spec != NULL) {
274d66a72cfSToomas Soome 		if ((ep = strchr(spec, ';')) != NULL) {
275d66a72cfSToomas Soome 			len = ep - spec;
276d66a72cfSToomas Soome 		} else {
277d66a72cfSToomas Soome 			len = strlen(spec);
278d66a72cfSToomas Soome 		}
279d66a72cfSToomas Soome 		name = malloc(len + 1);
280d66a72cfSToomas Soome 		strncpy(name, spec, len);
281d66a72cfSToomas Soome 		name[len] = 0;
282d66a72cfSToomas Soome 	}
283d66a72cfSToomas Soome 	if (name && name[0] == 0) {
284d66a72cfSToomas Soome 		free(name);
285d66a72cfSToomas Soome 		name = NULL;
286d66a72cfSToomas Soome 	}
287d66a72cfSToomas Soome 	return (name);
288199767f8SToomas Soome }
289199767f8SToomas Soome 
290199767f8SToomas Soome /*
291199767f8SToomas Soome  * Try to find the /etc/fstab file on the filesystem (rootdev),
292199767f8SToomas Soome  * which should be be the root filesystem, and parse it to find
293199767f8SToomas Soome  * out what the kernel ought to think the root filesystem is.
294199767f8SToomas Soome  *
295199767f8SToomas Soome  * If we're successful, set vfs.root.mountfrom to <vfstype>:<path>
296199767f8SToomas Soome  * so that the kernel can tell both which VFS and which node to use
297199767f8SToomas Soome  * to mount the device.  If this variable's already set, don't
298199767f8SToomas Soome  * overwrite it.
299199767f8SToomas Soome  */
300199767f8SToomas Soome int
getrootmount(char * rootdev)301199767f8SToomas Soome getrootmount(char *rootdev)
302199767f8SToomas Soome {
303d66a72cfSToomas Soome 	char lbuf[128], *cp, *ep, *dev, *fstyp, *options;
304d66a72cfSToomas Soome 	int fd, error;
305d66a72cfSToomas Soome 
306d66a72cfSToomas Soome 	if (getenv("vfs.root.mountfrom") != NULL)
307d66a72cfSToomas Soome 		return (0);
308d66a72cfSToomas Soome 
309d66a72cfSToomas Soome 	error = 1;
310d66a72cfSToomas Soome 	sprintf(lbuf, "%s/etc/fstab", rootdev);
311d66a72cfSToomas Soome 	if ((fd = open(lbuf, O_RDONLY)) < 0)
312d66a72cfSToomas Soome 		goto notfound;
313d66a72cfSToomas Soome 
314d66a72cfSToomas Soome 	/*
315d66a72cfSToomas Soome 	 * loop reading lines from /etc/fstab
316d66a72cfSToomas Soome 	 * What was that about sscanf again?
317d66a72cfSToomas Soome 	 */
318d66a72cfSToomas Soome 	fstyp = NULL;
319d66a72cfSToomas Soome 	dev = NULL;
320d66a72cfSToomas Soome 	while (fgetstr(lbuf, sizeof (lbuf), fd) >= 0) {
321d66a72cfSToomas Soome 		if ((lbuf[0] == 0) || (lbuf[0] == '#'))
322d66a72cfSToomas Soome 			continue;
323d66a72cfSToomas Soome 
324d66a72cfSToomas Soome 		/* skip device name */
325d66a72cfSToomas Soome 		for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
326d66a72cfSToomas Soome 			;
327d66a72cfSToomas Soome 		if (*cp == 0)		/* misformatted */
328d66a72cfSToomas Soome 			continue;
329d66a72cfSToomas Soome 		/* delimit and save */
330d66a72cfSToomas Soome 		*cp++ = 0;
331d66a72cfSToomas Soome 		free(dev);
332d66a72cfSToomas Soome 		dev = strdup(lbuf);
333d66a72cfSToomas Soome 
334d66a72cfSToomas Soome 		/* skip whitespace up to mountpoint */
335d66a72cfSToomas Soome 		while ((*cp != 0) && isspace(*cp))
336d66a72cfSToomas Soome 			cp++;
337d66a72cfSToomas Soome 		/* must have /<space> to be root */
338d66a72cfSToomas Soome 		if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1)))
339d66a72cfSToomas Soome 			continue;
340d66a72cfSToomas Soome 		/* skip whitespace up to fstype */
341d66a72cfSToomas Soome 		cp += 2;
342d66a72cfSToomas Soome 		while ((*cp != 0) && isspace(*cp))
343d66a72cfSToomas Soome 			cp++;
344d66a72cfSToomas Soome 		if (*cp == 0)		/* misformatted */
345d66a72cfSToomas Soome 			continue;
346d66a72cfSToomas Soome 		/* skip text to end of fstype and delimit */
347d66a72cfSToomas Soome 		ep = cp;
348d66a72cfSToomas Soome 		while ((*cp != 0) && !isspace(*cp))
349d66a72cfSToomas Soome 			cp++;
350d66a72cfSToomas Soome 		*cp = 0;
351d66a72cfSToomas Soome 		free(fstyp);
352d66a72cfSToomas Soome 		fstyp = strdup(ep);
353d66a72cfSToomas Soome 
354d66a72cfSToomas Soome 		/* skip whitespace up to mount options */
355d66a72cfSToomas Soome 		cp += 1;
356d66a72cfSToomas Soome 		while ((*cp != 0) && isspace(*cp))
357d66a72cfSToomas Soome 			cp++;
358d66a72cfSToomas Soome 		if (*cp == 0)		/* misformatted */
359d66a72cfSToomas Soome 			continue;
360d66a72cfSToomas Soome 		/* skip text to end of mount options and delimit */
361d66a72cfSToomas Soome 		ep = cp;
362d66a72cfSToomas Soome 		while ((*cp != 0) && !isspace(*cp))
363d66a72cfSToomas Soome 			cp++;
364d66a72cfSToomas Soome 		*cp = 0;
365d66a72cfSToomas Soome 		options = strdup(ep);
366d66a72cfSToomas Soome 		/*
367d66a72cfSToomas Soome 		 * Build the <fstype>:<device> and save it in
368d66a72cfSToomas Soome 		 * vfs.root.mountfrom
369d66a72cfSToomas Soome 		 */
370d66a72cfSToomas Soome 		sprintf(lbuf, "%s:%s", fstyp, dev);
371d66a72cfSToomas Soome 		setenv("vfs.root.mountfrom", lbuf, 0);
372d66a72cfSToomas Soome 
373d66a72cfSToomas Soome 		/*
374d66a72cfSToomas Soome 		 * Don't override vfs.root.mountfrom.options if it is
375d66a72cfSToomas Soome 		 * already set
376d66a72cfSToomas Soome 		 */
377d66a72cfSToomas Soome 		if (getenv("vfs.root.mountfrom.options") == NULL) {
378d66a72cfSToomas Soome 			/* save mount options */
379d66a72cfSToomas Soome 			setenv("vfs.root.mountfrom.options", options, 0);
380d66a72cfSToomas Soome 		}
381d66a72cfSToomas Soome 		free(options);
382d66a72cfSToomas Soome 		error = 0;
383d66a72cfSToomas Soome 		break;
384d66a72cfSToomas Soome 	}
385d66a72cfSToomas Soome 	close(fd);
386bc85f3b0SToomas Soome 	free(dev);
387bc85f3b0SToomas Soome 	free(fstyp);
388199767f8SToomas Soome 
389199767f8SToomas Soome notfound:
390d66a72cfSToomas Soome 	if (error) {
391d66a72cfSToomas Soome 		const char *currdev;
392d66a72cfSToomas Soome 
393d66a72cfSToomas Soome 		currdev = getenv("currdev");
394d66a72cfSToomas Soome 		if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) {
395d66a72cfSToomas Soome 			cp = strdup(currdev);
396d66a72cfSToomas Soome 			cp[strlen(cp) - 1] = '\0';
397d66a72cfSToomas Soome 			setenv("vfs.root.mountfrom", cp, 0);
398d66a72cfSToomas Soome 			error = 0;
399d66a72cfSToomas Soome 			free(cp);
400d66a72cfSToomas Soome 		}
401199767f8SToomas Soome 	}
402199767f8SToomas Soome 
403d66a72cfSToomas Soome 	return (error);
404199767f8SToomas Soome }
405199767f8SToomas Soome 
406199767f8SToomas Soome static int
loadakernel(int try,int argc,char * argv[])407d66a72cfSToomas Soome loadakernel(int try, int argc, char *argv[])
408199767f8SToomas Soome {
409d66a72cfSToomas Soome 	char *cp;
410199767f8SToomas Soome 
411199767f8SToomas Soome 	for (try = 0; (cp = getbootfile(try)) != NULL; try++)
412d66a72cfSToomas Soome 		if (mod_loadkld(cp, argc - 1, argv + 1) != 0)
413d66a72cfSToomas Soome 			printf("can't load '%s'\n", cp);
414d66a72cfSToomas Soome 		else
415d66a72cfSToomas Soome 			return (1);
416d66a72cfSToomas Soome 	return (0);
417199767f8SToomas Soome }
418