diff options
-rw-r--r-- | commands/boot.c | 321 |
1 files changed, 194 insertions, 127 deletions
diff --git a/commands/boot.c b/commands/boot.c index 21623655ed..1bec406ee3 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -28,25 +28,68 @@ #include <linux/stat.h> -static int boot_script(char *path); - static int verbose; static int dryrun; -static void bootsource_action(struct menu *m, struct menu_entry *me) +/* + * Start a single boot script. 'path' is a full path to a boot script. + */ +static int boot_script(char *path) +{ + int ret; + struct bootm_data data = { + .os_address = UIMAGE_SOME_ADDRESS, + .initrd_address = UIMAGE_SOME_ADDRESS, + }; + + globalvar_set_match("linux.bootargs.dyn.", ""); + globalvar_set_match("bootm.", ""); + + ret = run_command(path, 0); + if (ret) { + printf("Running %s failed\n", path); + goto out; + } + + data.initrd_address = UIMAGE_INVALID_ADDRESS; + data.os_address = UIMAGE_SOME_ADDRESS; + data.oftree_file = getenv_nonempty("global.bootm.oftree"); + data.os_file = getenv_nonempty("global.bootm.image"); + getenv_ul("global.bootm.image.loadaddr", &data.os_address); + getenv_ul("global.bootm.initrd.loadaddr", &data.initrd_address); + data.initrd_file = getenv_nonempty("global.bootm.initrd"); + data.verbose = verbose; + data.dryrun = dryrun; + + ret = bootm_boot(&data); + if (ret) + pr_err("Booting %s failed: %s\n", basename(path), strerror(-ret)); +out: + return ret; +} + +static int boot_entry(struct blspec_entry *be) { - struct blspec_entry *be = container_of(me, struct blspec_entry, me); int ret; if (be->scriptpath) { ret = boot_script(be->scriptpath); } else { if (IS_ENABLED(CONFIG_BLSPEC)) - ret = blspec_boot(be, 0, 0); + ret = blspec_boot(be, verbose, dryrun); else ret = -ENOSYS; } + return ret; +} + +static void bootsource_action(struct menu *m, struct menu_entry *me) +{ + struct blspec_entry *be = container_of(me, struct blspec_entry, me); + int ret; + + ret = boot_entry(be); if (ret) printf("Booting failed with: %s\n", strerror(-ret)); @@ -55,46 +98,140 @@ static void bootsource_action(struct menu *m, struct menu_entry *me) read_key(); } -static int bootsources_menu_env_entries(struct blspec *blspec) +/* + * bootscript_create_entry - create a boot entry from a script name + */ +static int bootscript_create_entry(struct blspec *blspec, const char *name) +{ + struct blspec_entry *be; + + be = blspec_entry_alloc(blspec); + be->me.type = MENU_ENTRY_NORMAL; + be->scriptpath = xstrdup(name); + be->me.display = xstrdup(basename(be->scriptpath)); + + return 0; +} + +/* + * bootscript_scan_path - create boot entries from a path + * + * path can either be a full path to a bootscript or a full path to a diretory + * containing bootscripts. + */ +static int bootscript_scan_path(struct blspec *blspec, const char *path) { - const char *path = "/env/boot"; + struct stat s; DIR *dir; struct dirent *d; - struct blspec_entry *be; + int ret; + int found = 0; + + ret = stat(path, &s); + if (ret) + return ret; + + if (!S_ISDIR(s.st_mode)) { + ret = bootscript_create_entry(blspec, path); + if (ret) + return ret; + return 1; + } dir = opendir(path); if (!dir) return -errno; while ((d = readdir(dir))) { + char *bootscript_path; if (*d->d_name == '.') continue; - be = blspec_entry_alloc(blspec); - be->me.type = MENU_ENTRY_NORMAL; - be->scriptpath = asprintf("/env/boot/%s", d->d_name); - be->me.display = xstrdup(d->d_name); + bootscript_path = asprintf("%s/%s", path, d->d_name); + bootscript_create_entry(blspec, bootscript_path); + found++; + free(bootscript_path); } + ret = found; + closedir(dir); - return 0; + return ret; +} + +/* + * bootentry_parse_one - create boot entries from a name + * + * name can be: + * - a name of a boot script under /env/boot + * - a full path of a boot script + * - a device name + * - a cdev name + * - a full path of a directory containing bootloader spec entries + * - a full path of a directory containing bootscripts + * + * Returns the number of entries found or a negative error code. + */ +static int bootentry_parse_one(struct blspec *blspec, const char *name) +{ + int found = 0, ret; + + if (IS_ENABLED(CONFIG_BLSPEC)) { + ret = blspec_scan_devicename(blspec, name); + if (ret > 0) + found += ret; + ret = blspec_scan_directory(blspec, name); + if (ret > 0) + found += ret; + } + + if (!found) { + char *path; + + if (*name != '/') + path = asprintf("/env/boot/%s", name); + else + path = xstrdup(name); + + ret = bootscript_scan_path(blspec, path); + if (ret > 0) + found += ret; + + free(path); + } + + return found; } -static struct blspec *bootentries_collect(void) +/* + * bootentries_collect - collect bootentries from an array of names + */ +static struct blspec *bootentries_collect(char *entries[], int num_entries) { struct blspec *blspec; + int i; blspec = blspec_alloc(); blspec->menu->display = asprintf("boot"); - bootsources_menu_env_entries(blspec); - if (IS_ENABLED(CONFIG_BLSPEC)) + + if (!num_entries) + bootscript_scan_path(blspec, "/env/boot"); + + if (IS_ENABLED(CONFIG_BLSPEC) && !num_entries) blspec_scan_devices(blspec); + + for (i = 0; i < num_entries; i++) + bootentry_parse_one(blspec, entries[i]); + return blspec; } -static void bootsources_menu(void) +/* + * bootsources_menu - show a menu from an array of names + */ +static void bootsources_menu(char *entries[], int num_entries) { struct blspec *blspec = NULL; struct blspec_entry *entry; @@ -105,7 +242,7 @@ static void bootsources_menu(void) return; } - blspec = bootentries_collect(); + blspec = bootentries_collect(entries, num_entries); blspec_for_each_entry(blspec, entry) { entry->me.action = bootsource_action; @@ -125,12 +262,15 @@ static void bootsources_menu(void) blspec_free(blspec); } -static void bootsources_list(void) +/* + * bootsources_list - list boot entries from an array of names + */ +static void bootsources_list(char *entries[], int num_entries) { struct blspec *blspec; struct blspec_entry *entry; - blspec = bootentries_collect(); + blspec = bootentries_collect(entries, num_entries); printf("%-20s %-20s %s\n", "device", "hwdevice", "title"); printf("%-20s %-20s %s\n", "------", "--------", "-----"); @@ -146,118 +286,41 @@ static void bootsources_list(void) } /* - * Start a single boot script. 'path' is a full path to a boot script. - */ -static int boot_script(char *path) -{ - int ret; - struct bootm_data data = { - .os_address = UIMAGE_SOME_ADDRESS, - .initrd_address = UIMAGE_SOME_ADDRESS, - }; - - printf("booting %s...\n", basename(path)); - - globalvar_set_match("linux.bootargs.dyn.", ""); - globalvar_set_match("bootm.", ""); - - ret = run_command(path, 0); - if (ret) { - printf("Running %s failed\n", path); - goto out; - } - - data.initrd_address = UIMAGE_INVALID_ADDRESS; - data.os_address = UIMAGE_SOME_ADDRESS; - data.oftree_file = getenv_nonempty("global.bootm.oftree"); - data.os_file = getenv_nonempty("global.bootm.image"); - getenv_ul("global.bootm.image.loadaddr", &data.os_address); - getenv_ul("global.bootm.initrd.loadaddr", &data.initrd_address); - data.initrd_file = getenv_nonempty("global.bootm.initrd"); - data.verbose = verbose; - data.dryrun = dryrun; - - ret = bootm_boot(&data); - if (ret) - pr_err("Booting %s failed: %s\n", basename(path), strerror(-ret)); -out: - return ret; -} - -/* - * boot a script. 'name' can either be a filename under /env/boot/, - * a full path to a boot script or a path to a directory. This function - * returns a negative error on failure, or 0 on a successful dryrun boot. + * boot a script or a bootspec entry. 'name' can be: + * - a filename under /env/boot/ + * - a full path to a boot script + * - a device name + * - a partition name under /dev/ + * - a full path to a directory which + * - contains boot scripts, or + * - contains a loader/entries/ directory containing bootspec entries + * + * Returns a negative error on failure, or 0 on a successful dryrun boot. */ static int boot(const char *name) { - char *path; - DIR *dir; - struct dirent *d; - struct stat s; - int ret; - - if (*name == '/') - path = xstrdup(name); - else - path = asprintf("/env/boot/%s", name); - - ret = stat(path, &s); - if (ret) { - if (!IS_ENABLED(CONFIG_BLSPEC)) { - pr_err("%s: %s\n", path, strerror(-ret)); - goto out; - } - - ret = blspec_boot_devicename(name, verbose, dryrun); - pr_err("%s: %s\n", name, strerror(-ret)); - goto out; - } + struct blspec *blspec; + struct blspec_entry *entry; + int ret = -ENOENT; - if (S_ISREG(s.st_mode)) { - ret = boot_script(path); - goto out; - } + blspec = blspec_alloc(); + ret = bootentry_parse_one(blspec, name); + if (ret < 0) + return ret; - dir = opendir(path); - if (!dir) { - ret = -errno; - printf("cannot open %s: %s\n", path, strerror(-errno)); - goto out; + if (!ret) { + printf("Nothing bootable found on %s\n", name); + return -ENOENT; } - while ((d = readdir(dir))) { - char *file; - struct stat s; - - if (*d->d_name == '.') - continue; - - file = asprintf("%s/%s", path, d->d_name); - - ret = stat(file, &s); - if (ret) { - free(file); - continue; - } - - if (!S_ISREG(s.st_mode)) { - free(file); - continue; - } - - ret = boot_script(file); - - free(file); - + blspec_for_each_entry(blspec, entry) { + printf("booting %s\n", entry->me.display); + ret = boot_entry(entry); if (!ret) break; + printf("booting %s failed: %s\n", entry->me.display, strerror(-ret)); } - closedir(dir); -out: - free(path); - return ret; } @@ -288,12 +351,12 @@ static int do_boot(int argc, char *argv[]) } if (do_list) { - bootsources_list(); + bootsources_list(&argv[optind], argc - optind); return 0; } if (do_menu) { - bootsources_menu(); + bootsources_menu(&argv[optind], argc - optind); return 0; } @@ -337,10 +400,14 @@ BAREBOX_CMD_HELP_START(boot) BAREBOX_CMD_HELP_USAGE("boot [OPTIONS] [BOOTSRC...]\n") BAREBOX_CMD_HELP_SHORT("Boot an operating system.\n") BAREBOX_CMD_HELP_SHORT("[BOOTSRC...] can be:\n") -BAREBOX_CMD_HELP_SHORT("- a filename from /env/boot/\n") -BAREBOX_CMD_HELP_SHORT("- a full path to a file\n") -BAREBOX_CMD_HELP_SHORT("- a path to a directory. All files in this directory are treated\n") -BAREBOX_CMD_HELP_SHORT(" as boot scripts.\n") +BAREBOX_CMD_HELP_SHORT("- a filename under /env/boot/\n") +BAREBOX_CMD_HELP_SHORT("- a full path to a boot script\n") +BAREBOX_CMD_HELP_SHORT("- a device name\n") +BAREBOX_CMD_HELP_SHORT("- a partition name under /dev/\n") +BAREBOX_CMD_HELP_SHORT("- a full path to a directory which\n") +BAREBOX_CMD_HELP_SHORT(" - contains boot scripts, or\n") +BAREBOX_CMD_HELP_SHORT(" - contains a loader/entries/ directory containing bootspec entries\n") +BAREBOX_CMD_HELP_SHORT("\n") BAREBOX_CMD_HELP_SHORT("Multiple bootsources may be given which are probed in order until\n") BAREBOX_CMD_HELP_SHORT("one succeeds.\n") BAREBOX_CMD_HELP_SHORT("\nOptions:\n") |