boot.c revision 38466
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 * $Id$ 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 38static char *getbootfile(int try); 39 40/* List of kernel names to try (may be overwritten by boot.config) XXX should move from here? */ 41static char *default_bootfiles = "kernel,kernel.old"; 42 43/* 44 * The user wants us to boot. 45 */ 46COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); 47 48static int 49command_boot(int argc, char *argv[]) 50{ 51 struct loaded_module *km; 52 char *cp; 53 int try; 54 55 /* 56 * See if the user has specified an explicit kernel to boot. 57 */ 58 if ((argc > 1) && (argv[1][0] != '-')) { 59 60 /* XXX maybe we should discard everything and start again? */ 61 if (mod_findmodule(NULL, NULL) != NULL) { 62 sprintf(command_errbuf, "can't boot '%s', kernel module already loaded", argv[0]); 63 return(CMD_ERROR); 64 } 65 66 /* find/load the kernel module */ 67 if (mod_load(argv[1], argc - 2, argv + 2) != 0) 68 return(CMD_ERROR); 69 /* we have consumed all arguments */ 70 argc = 1; 71 } 72 73 /* 74 * See if there is a kernel module already loaded 75 */ 76 if (mod_findmodule(NULL, NULL) == NULL) { 77 for (try = 0; (cp = getbootfile(try)) != NULL; try++) { 78 if (mod_load(cp, argc - 1, argv + 1) != 0) { 79 printf("can't load '%s'\n", argv[0]); 80 } else { 81 /* we have consumed all arguments */ 82 argc = 1; 83 break; 84 } 85 } 86 } 87 88 /* 89 * Loaded anything yet? 90 */ 91 if ((km = mod_findmodule(NULL, NULL)) == NULL) { 92 command_errmsg = "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 (km->m_args != NULL) 102 free(km->m_args); 103 km->m_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 archsw.arch_boot(); 110 return(CMD_ERROR); 111} 112 113 114/* 115 * Autoboot after a delay 116 */ 117 118COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", command_autoboot); 119 120/* 121 * XXX note the 'prompt' argument is not really useful until quoting is implemented 122 */ 123static int 124command_autoboot(int argc, char *argv[]) 125{ 126 int howlong; 127 char *cp, *prompt; 128 129 prompt = NULL; 130 howlong = -1; 131 switch(argc) { 132 case 3: 133 prompt = argv[2]; 134 /* FALLTHROUGH */ 135 case 2: 136 howlong = strtol(argv[1], &cp, 0); 137 if (*cp != 0) { 138 sprintf(command_errbuf, "bad delay '%s'", argv[1]); 139 return(CMD_ERROR); 140 } 141 /* FALLTHROUGH */ 142 case 1: 143 return(autoboot(howlong, prompt)); 144 } 145 146 command_errmsg = "too many arguments"; 147 return(CMD_ERROR); 148} 149 150int 151autoboot(int delay, char *prompt) 152{ 153 time_t when, otime, ntime; 154 int c, yes; 155 char *argv[2]; 156 157 if (delay == -1) 158 delay = 5; /* env var? compile-time define? */ 159 160 otime = time(NULL); 161 when = otime + delay; /* when to boot */ 162 yes = 0; 163 164 /* XXX could try to work out what we might boot */ 165 printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt); 166 167 for (;;) { 168 if (ischar()) { 169 c = getchar(); 170 if ((c == '\r') || (c == '\n')) 171 yes = 1; 172 break; 173 } 174 ntime = time(NULL); 175 if (ntime == when) { 176 yes = 1; 177 break; 178 } 179 if (ntime != otime) { 180 printf("\rBooting [%s] in %d seconds...", getbootfile(0), (int)(when - ntime)); 181 otime = ntime; 182 } 183 } 184 printf("\n"); 185 if (yes) { 186 argv[0] = "boot"; 187 argv[1] = NULL; 188 return(command_boot(1, argv)); 189 } 190 return(CMD_OK); 191} 192 193/* 194 * Scrounge for the name of the (try)'th file we will try to boot. 195 */ 196static char * 197getbootfile(int try) 198{ 199 static char *name = NULL; 200 char *spec, *ep; 201 int len; 202 203 /* we use dynamic storage */ 204 if (name != NULL) { 205 free(name); 206 name = NULL; 207 } 208 209 /* 210 * Try $bootfile, then try our builtin default 211 */ 212 if ((spec = getenv("bootfile")) == NULL) 213 spec = default_bootfiles; 214 215 while ((try > 0) && (spec != NULL)) 216 spec = strchr(spec, ','); 217 if (spec != NULL) { 218 if ((ep = strchr(spec, ',')) != NULL) { 219 len = ep - spec; 220 } else { 221 len = strlen(spec); 222 } 223 name = malloc(len + 1); 224 strncpy(name, spec, len); 225 name[len] = 0; 226 } 227 return(name); 228} 229 230