xref: /netbsd-src/sys/arch/ia64/stand/common/boot.c (revision cc67c5474ae5f29068c12d176c28e8659afb01f0)
1 /*	$NetBSD: boot.c,v 1.9 2020/08/19 02:19:07 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 /* __FBSDID("$FreeBSD: src/sys/boot/common/boot.c,v 1.29 2003/08/25 23:30:41 obrien Exp $"); */
31 
32 
33 /*
34  * Loading modules, booting the system
35  */
36 
37 #include <lib/libsa/stand.h>
38 #include <lib/libsa/loadfile.h>
39 #include <lib/libkern/libkern.h>
40 
41 #include "bootstrap.h"
42 
43 static char	*getbootfile(int try);
44 static int	loadakernel(int try, int argc, char* argv[]);
45 
46 /* List of kernel names to try */
47 static const char *default_bootfiles = "netbsd";
48 
49 static int autoboot_tried;
50 
51 /*
52  * The user wants us to boot.
53  */
54 
55 int
command_boot(int argc,char * argv[])56 command_boot(int argc, char *argv[])
57 {
58     struct preloaded_file	*fp;
59 
60     /*
61      * See if the user has specified an explicit kernel to boot.
62      */
63     if ((argc > 1) && (argv[1][0] != '-')) {
64 
65 	/* XXX maybe we should discard everything and start again? */
66 	if (file_findfile(NULL, NULL) != NULL) {
67 	    command_seterr("can't boot '%s', kernel module already loaded",
68 		argv[1]);
69 	    return(CMD_ERROR);
70 	}
71 
72 	/* find/load the kernel module */
73 	if (file_loadkernel(argv[1], argc - 2, argv + 2) != 0)
74 	    return(CMD_ERROR);
75 
76 	/* we have consumed all arguments */
77 	argc = 1;
78     }
79 
80     /*
81      * See if there is a kernel module already loaded
82      */
83     if (file_findfile(NULL, NULL) == NULL)
84 	if (loadakernel(0, argc - 1, argv + 1))
85 	    /* we have consumed all arguments */
86 	    argc = 1;
87 
88     /*
89      * Loaded anything yet?
90      */
91     if ((fp = file_findfile(NULL, NULL)) == NULL) {
92 	command_seterr("no bootable kernel");
93 	return(CMD_ERROR);
94     }
95 
96     /*
97      * If we were given arguments, discard any previous.
98      * XXX should we merge arguments?  Hard to DWIM.
99      */
100     if (argc > 1) {
101 	if (fp->f_args != NULL)
102 	    free(fp->f_args);
103 	fp->f_args = unargv(argc - 1, argv + 1);
104     }
105 
106     /* Hook for platform-specific autoloading of modules */
107     if (archsw.arch_autoload() != 0)
108 	return(CMD_ERROR);
109 
110     /* Call the exec handler from the loader matching the kernel */
111     command_seterr("%s", strerror(file_formats[fp->f_loader]->l_exec(fp)));
112     return(CMD_ERROR);
113 }
114 
115 
116 /*
117  * Autoboot after a delay
118  */
119 
120 int
command_autoboot(int argc,char * argv[])121 command_autoboot(int argc, char *argv[])
122 {
123     int		howlong;
124     char	*cp, *prompt;
125 
126     prompt = NULL;
127     howlong = -1;
128     switch(argc) {
129     case 3:
130 	prompt = argv[2];
131 	/* FALLTHROUGH */
132     case 2:
133 	howlong = strtol(argv[1], &cp, 0);
134 	if (*cp != 0) {
135 	    command_seterr("bad delay '%s'", argv[1]);
136 	    return(CMD_ERROR);
137 	}
138 	/* FALLTHROUGH */
139     case 1:
140 	return(autoboot(howlong, prompt));
141     }
142 
143     command_seterr("too many arguments");
144     return(CMD_ERROR);
145 }
146 
147 /*
148  * Called before we go interactive.  If we think we can autoboot, and
149  * we haven't tried already, try now.
150  */
151 void
autoboot_maybe(void)152 autoboot_maybe(void)
153 {
154     char	*cp;
155 
156     cp = getenv("autoboot_delay");
157     if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO")))
158 	autoboot(-1, NULL);		/* try to boot automatically */
159 }
160 
161 int
autoboot(int timeout,char * prompt)162 autoboot(int timeout, char *prompt)
163 {
164     time_t	when, otime, ntime;
165     int		c, yes;
166     char	*argv[2], *cp, *ep;
167     char	*kernelname;
168 
169     autoboot_tried = 1;
170 
171     if (timeout == -1) {
172 	/* try to get a delay from the environment */
173 	if ((cp = getenv("autoboot_delay"))) {
174 	    timeout = strtol(cp, &ep, 0);
175 	    if (cp == ep)
176 		timeout = -1;
177 	}
178     }
179     if (timeout == -1)		/* all else fails */
180 	timeout = 10;
181 
182     kernelname = getenv("kernelname");
183     if (kernelname == NULL) {
184 	argv[0] = NULL;
185 	loadakernel(0, 0, argv);
186 	kernelname = getenv("kernelname");
187 	if (kernelname == NULL) {
188 	    command_seterr("no valid kernel found");
189 	    return(CMD_ERROR);
190 	}
191     }
192 
193     otime = time(NULL);
194     when = otime + timeout;	/* when to boot */
195     yes = 0;
196 
197     printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt);
198 
199     for (;;) {
200 	if (ischar()) {
201 	    c = getchar();
202 	    if ((c == '\r') || (c == '\n'))
203 		yes = 1;
204 	    break;
205 	}
206 	ntime = time(NULL);
207 	if (ntime >= when) {
208 	    yes = 1;
209 	    break;
210 	}
211 
212 	if (ntime != otime) {
213 	    printf("\rBooting [%s] in %d second%s... ",
214 	    		kernelname, (int)(when - ntime),
215 			(when-ntime)==1?"":"s");
216 	    otime = ntime;
217 	}
218     }
219     if (yes)
220 	printf("\rBooting [%s]...               ", kernelname);
221     putchar('\n');
222     if (yes) {
223 	argv[0] = "boot";
224 	argv[1] = NULL;
225 	return(command_boot(1, argv));
226     }
227     return(CMD_OK);
228 }
229 
230 /*
231  * Scrounge for the name of the (try)'th file we will try to boot.
232  */
233 static char *
getbootfile(int try)234 getbootfile(int try)
235 {
236     static char *name = NULL;
237     const char	*spec, *ep;
238     size_t	len;
239 
240     /* we use dynamic storage */
241     if (name != NULL) {
242 	free(name);
243 	name = NULL;
244     }
245 
246     /*
247      * Try $bootfile, then try our builtin default
248      */
249     if ((spec = getenv("bootfile")) == NULL)
250 	spec = default_bootfiles;
251 
252     while ((try > 0) && (spec != NULL)) {
253 	spec = strchr(spec, ';');
254 	if (spec)
255 	    spec++;	/* skip over the leading ';' */
256 	try--;
257     }
258     if (spec != NULL) {
259 	if ((ep = strchr(spec, ';')) != NULL) {
260 	    len = ep - spec;
261 	} else {
262 	    len = strlen(spec);
263 	}
264 	name = alloc(len + 1);
265 	strncpy(name, spec, len);
266 	name[len] = 0;
267     }
268     if (name && name[0] == 0) {
269 	free(name);
270 	name = NULL;
271     }
272     else {
273       setenv("kernelname", name, 1);
274     }
275 
276     return(name);
277 }
278 
279 /*
280  * Try to find the /etc/fstab file on the filesystem (rootdev),
281  * which should be the root filesystem, and parse it to find
282  * out what the kernel ought to think the root filesystem is.
283  *
284  * If we're successful, set vfs.root.mountfrom to <vfstype>:<path>
285  * so that the kernel can tell both which VFS and which node to use
286  * to mount the device.  If this variable's already set, don't
287  * overwrite it.
288  */
289 int
getrootmount(char * rootdev)290 getrootmount(char *rootdev)
291 {
292     char	lbuf[128], *cp, *ep, *dev, *fstyp;
293     int		fd, error;
294 
295     if (getenv("vfs.root.mountfrom") != NULL)
296 	return(0);
297 
298     snprintf(lbuf, sizeof(lbuf), "%s/etc/fstab", rootdev);
299     if ((fd = open(lbuf, O_RDONLY)) < 0)
300 	return(1);
301 
302     /* loop reading lines from /etc/fstab    What was that about sscanf again? */
303     error = 1;
304     while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) {
305 	if ((lbuf[0] == 0) || (lbuf[0] == '#'))
306 	    continue;
307 
308 	/* skip device name */
309 	for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
310 	    ;
311 	if (*cp == 0)		/* misformatted */
312 	    continue;
313 	/* delimit and save */
314 	*cp++ = 0;
315 	dev = strdup(lbuf);
316 
317 	/* skip whitespace up to mountpoint */
318 	while ((*cp != 0) && isspace(*cp))
319 	    cp++;
320 	/* must have /<space> to be root */
321 	if ((*cp != '/') || !isspace(*(cp + 1)))
322 	    continue;
323 	/* skip whitespace up to fstype */
324 	cp += 2;
325 	while ((*cp != 0) && isspace(*cp))
326 	    cp++;
327 	if (*cp == 0)		/* misformatted */
328 	    continue;
329 	/* skip text to end of fstype and delimit */
330 	ep = cp;
331 	while ((*cp != 0) && !isspace(*cp))
332 	    cp++;
333 	*cp = 0;
334 	fstyp = strdup(ep);
335 
336 	/* build the final result and save it */
337 	snprintf(lbuf, sizeof(lbuf), "%s:%s", fstyp, dev);
338 	free(dev);
339 	free(fstyp);
340 	setenv("vfs.root.mountfrom", lbuf, 0);
341 	error = 0;
342 	break;
343     }
344     close(fd);
345     return(error);
346 }
347 
348 static int
loadakernel(int try,int argc,char * argv[])349 loadakernel(int try, int argc, char* argv[])
350 {
351 	char *cp;
352 
353 	for (try = 0; (cp = getbootfile(try)) != NULL; try++)
354 		if (file_loadkernel(cp, argc - 1, argv + 1) != 0)
355 			printf("can't load '%s'\n", cp);
356 		else
357 			return 1;
358 	return 0;
359 }
360 
361