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