The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/common/boot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3c0b38cbb7710e200c7d53713db5ac55


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.