xref: /netbsd-src/sys/arch/ia64/stand/common/boot.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: boot.c,v 1.3 2006/07/02 17:28:11 cherry 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/libkern/libkern.h>
39 
40 #include "bootstrap.h"
41 
42 static char	*getbootfile(int try);
43 static int	loadakernel(int try, int argc, char* argv[]);
44 
45 /* List of kernel names to try */
46 static const char *default_bootfiles = "netbsd";
47 
48 static int autoboot_tried;
49 
50 /*
51  * The user wants us to boot.
52  */
53 
54 int
55 command_boot(int argc, char *argv[])
56 {
57     struct preloaded_file	*fp;
58 
59     /*
60      * See if the user has specified an explicit kernel to boot.
61      */
62     if ((argc > 1) && (argv[1][0] != '-')) {
63 
64 	/* XXX maybe we should discard everything and start again? */
65 	if (file_findfile(NULL, NULL) != NULL) {
66 	    sprintf(command_errbuf, "can't boot '%s', kernel module already loaded", argv[1]);
67 	    return(CMD_ERROR);
68 	}
69 
70 	/* find/load the kernel module */
71 	if (file_loadkernel(argv[1], argc - 2, argv + 2) != 0)
72 	    return(CMD_ERROR);
73 
74 	/* we have consumed all arguments */
75 	argc = 1;
76     }
77 
78     /*
79      * See if there is a kernel module already loaded
80      */
81     if (file_findfile(NULL, NULL) == NULL)
82 	if (loadakernel(0, argc - 1, argv + 1))
83 	    /* we have consumed all arguments */
84 	    argc = 1;
85 
86     /*
87      * Loaded anything yet?
88      */
89     if ((fp = file_findfile(NULL, NULL)) == NULL) {
90 	command_errmsg = "no bootable kernel";
91 	return(CMD_ERROR);
92     }
93 
94     /*
95      * If we were given arguments, discard any previous.
96      * XXX should we merge arguments?  Hard to DWIM.
97      */
98     if (argc > 1) {
99 	if (fp->f_args != NULL)
100 	    free(fp->f_args);
101 	fp->f_args = unargv(argc - 1, argv + 1);
102     }
103 
104     /* Hook for platform-specific autoloading of modules */
105     if (archsw.arch_autoload() != 0)
106 	return(CMD_ERROR);
107 
108     /* Call the exec handler from the loader matching the kernel */
109     file_formats[fp->f_loader]->l_exec(fp);
110     command_errmsg = strerror(file_formats[fp->f_loader]->l_exec(fp));
111     return(CMD_ERROR);
112 }
113 
114 
115 /*
116  * Autoboot after a delay
117  */
118 
119 int
120 command_autoboot(int argc, char *argv[])
121 {
122     int		howlong;
123     char	*cp, *prompt;
124 
125     prompt = NULL;
126     howlong = -1;
127     switch(argc) {
128     case 3:
129 	prompt = argv[2];
130 	/* FALLTHROUGH */
131     case 2:
132 	howlong = strtol(argv[1], &cp, 0);
133 	if (*cp != 0) {
134 	    sprintf(command_errbuf, "bad delay '%s'", argv[1]);
135 	    return(CMD_ERROR);
136 	}
137 	/* FALLTHROUGH */
138     case 1:
139 	return(autoboot(howlong, prompt));
140     }
141 
142     command_errmsg = "too many arguments";
143     return(CMD_ERROR);
144 }
145 
146 /*
147  * Called before we go interactive.  If we think we can autoboot, and
148  * we haven't tried already, try now.
149  */
150 void
151 autoboot_maybe()
152 {
153     char	*cp;
154 
155     cp = getenv("autoboot_delay");
156     if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO")))
157 	autoboot(-1, NULL);		/* try to boot automatically */
158 }
159 
160 int
161 autoboot(int timeout, char *prompt)
162 {
163     time_t	when, otime, ntime;
164     int		c, yes;
165     char	*argv[2], *cp, *ep;
166     char	*kernelname;
167 
168     autoboot_tried = 1;
169 
170     if (timeout == -1) {
171 	/* try to get a delay from the environment */
172 	if ((cp = getenv("autoboot_delay"))) {
173 	    timeout = strtol(cp, &ep, 0);
174 	    if (cp == ep)
175 		timeout = -1;
176 	}
177     }
178     if (timeout == -1)		/* all else fails */
179 	timeout = 10;
180 
181     kernelname = getenv("kernelname");
182     if (kernelname == NULL) {
183 	argv[0] = NULL;
184 	loadakernel(0, 0, argv);
185 	kernelname = getenv("kernelname");
186 	if (kernelname == NULL) {
187 	    command_errmsg = "no valid kernel found";
188 	    return(CMD_ERROR);
189 	}
190     }
191 
192     otime = time(NULL);
193     when = otime + timeout;	/* when to boot */
194     yes = 0;
195 
196     printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt);
197 
198     for (;;) {
199 	if (ischar()) {
200 	    c = getchar();
201 	    if ((c == '\r') || (c == '\n'))
202 		yes = 1;
203 	    break;
204 	}
205 	ntime = time(NULL);
206 	if (ntime >= when) {
207 	    yes = 1;
208 	    break;
209 	}
210 
211 	if (ntime != otime) {
212 	    printf("\rBooting [%s] in %d second%s... ",
213 	    		kernelname, (int)(when - ntime),
214 			(when-ntime)==1?"":"s");
215 	    otime = ntime;
216 	}
217     }
218     if (yes)
219 	printf("\rBooting [%s]...               ", kernelname);
220     putchar('\n');
221     if (yes) {
222 	argv[0] = "boot";
223 	argv[1] = NULL;
224 	return(command_boot(1, argv));
225     }
226     return(CMD_OK);
227 }
228 
229 /*
230  * Scrounge for the name of the (try)'th file we will try to boot.
231  */
232 static char *
233 getbootfile(int try)
234 {
235     static char *name = NULL;
236     const char	*spec, *ep;
237     size_t	len;
238 
239     /* we use dynamic storage */
240     if (name != NULL) {
241 	free(name);
242 	name = NULL;
243     }
244 
245     /*
246      * Try $bootfile, then try our builtin default
247      */
248     if ((spec = getenv("bootfile")) == NULL)
249 	spec = default_bootfiles;
250 
251     while ((try > 0) && (spec != NULL)) {
252 	spec = strchr(spec, ';');
253 	if (spec)
254 	    spec++;	/* skip over the leading ';' */
255 	try--;
256     }
257     if (spec != NULL) {
258 	if ((ep = strchr(spec, ';')) != NULL) {
259 	    len = ep - spec;
260 	} else {
261 	    len = strlen(spec);
262 	}
263 	name = alloc(len + 1);
264 	strncpy(name, spec, len);
265 	name[len] = 0;
266     }
267     if (name && name[0] == 0) {
268 	free(name);
269 	name = NULL;
270     }
271     else {
272       setenv("kernelname", name, 1);
273     }
274 
275     return(name);
276 }
277 
278 /*
279  * Try to find the /etc/fstab file on the filesystem (rootdev),
280  * which should be be the root filesystem, and parse it to find
281  * out what the kernel ought to think the root filesystem is.
282  *
283  * If we're successful, set vfs.root.mountfrom to <vfstype>:<path>
284  * so that the kernel can tell both which VFS and which node to use
285  * to mount the device.  If this variable's already set, don't
286  * overwrite it.
287  */
288 int
289 getrootmount(char *rootdev)
290 {
291     char	lbuf[128], *cp, *ep, *dev, *fstyp;
292     int		fd, error;
293 
294     if (getenv("vfs.root.mountfrom") != NULL)
295 	return(0);
296 
297     sprintf(lbuf, "%s/etc/fstab", rootdev);
298     if ((fd = open(lbuf, O_RDONLY)) < 0)
299 	return(1);
300 
301     /* loop reading lines from /etc/fstab    What was that about sscanf again? */
302     error = 1;
303     while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) {
304 	if ((lbuf[0] == 0) || (lbuf[0] == '#'))
305 	    continue;
306 
307 	/* skip device name */
308 	for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++)
309 	    ;
310 	if (*cp == 0)		/* misformatted */
311 	    continue;
312 	/* delimit and save */
313 	*cp++ = 0;
314 	dev = strdup(lbuf);
315 
316 	/* skip whitespace up to mountpoint */
317 	while ((*cp != 0) && isspace(*cp))
318 	    cp++;
319 	/* must have /<space> to be root */
320 	if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1)))
321 	    continue;
322 	/* skip whitespace up to fstype */
323 	cp += 2;
324 	while ((*cp != 0) && isspace(*cp))
325 	    cp++;
326 	if (*cp == 0)		/* misformatted */
327 	    continue;
328 	/* skip text to end of fstype and delimit */
329 	ep = cp;
330 	while ((*cp != 0) && !isspace(*cp))
331 	    cp++;
332 	*cp = 0;
333 	fstyp = strdup(ep);
334 
335 	/* build the final result and save it */
336 	sprintf(lbuf, "%s:%s", fstyp, dev);
337 	free(dev);
338 	free(fstyp);
339 	setenv("vfs.root.mountfrom", lbuf, 0);
340 	error = 0;
341 	break;
342     }
343     close(fd);
344     return(error);
345 }
346 
347 static int
348 loadakernel(int try, int argc, char* argv[])
349 {
350 	char *cp;
351 
352 	for (try = 0; (cp = getbootfile(try)) != NULL; try++)
353 		if (file_loadkernel(cp, argc - 1, argv + 1) != 0)
354 			printf("can't load '%s'\n", cp);
355 		else
356 			return 1;
357 	return 0;
358 }
359 
360