diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2016-08-03 08:08:22 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-08-03 08:08:22 +0200 |
commit | 94e7bdcd9a6a477b7bd980ac4cc168b49040884c (patch) | |
tree | 656c0007f385d49c24580f4fe8c512ac100dbe45 /common | |
parent | 7defdbf78f4c4c412632500c51909f08f99baacf (diff) | |
parent | eeaed6eee3d4983564e2e737b29de8fded37caf6 (diff) | |
download | barebox-94e7bdcd9a6a477b7bd980ac4cc168b49040884c.tar.gz barebox-94e7bdcd9a6a477b7bd980ac4cc168b49040884c.tar.xz |
Merge branch 'for-next/boot'
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig | 3 | ||||
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/blspec.c | 343 | ||||
-rw-r--r-- | common/boot.c | 339 | ||||
-rw-r--r-- | common/bootm.c | 3 | ||||
-rw-r--r-- | common/image-fit.c | 2 |
6 files changed, 489 insertions, 202 deletions
diff --git a/common/Kconfig b/common/Kconfig index 6ce2a76afa..832634047f 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -110,6 +110,9 @@ config UBIFORMAT depends on MTD_UBI default y +config BOOT + bool + menu "General Settings" config LOCALVERSION diff --git a/common/Makefile b/common/Makefile index 17fcb5f24a..00bc0e8834 100644 --- a/common/Makefile +++ b/common/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_FIRMWARE) += firmware.o obj-$(CONFIG_UBIFORMAT) += ubiformat.o obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o obj-$(CONFIG_CONSOLE_RATP) += ratp.o +obj-$(CONFIG_BOOT) += boot.o quiet_cmd_pwd_h = PWDH $@ ifdef CONFIG_PASSWORD diff --git a/common/blspec.c b/common/blspec.c index bf98e6b29a..f02f5e9ce3 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -24,7 +24,7 @@ #include <libfile.h> #include <libbb.h> #include <init.h> -#include <boot.h> +#include <bootm.h> #include <net.h> #include <fs.h> #include <of.h> @@ -43,6 +43,84 @@ int blspec_entry_var_set(struct blspec_entry *entry, const char *name, } /* + * blspec_boot - boot an entry + * + * This boots an entry. On success this function does not return. + * In case of an error the error code is returned. This function may + * return 0 in case of a succesful dry run. + */ +static int blspec_boot(struct bootentry *be, int verbose, int dryrun) +{ + struct blspec_entry *entry = container_of(be, struct blspec_entry, entry); + int ret; + const char *abspath, *devicetree, *options, *initrd, *linuximage; + const char *appendroot; + struct bootm_data data = { + .initrd_address = UIMAGE_INVALID_ADDRESS, + .os_address = UIMAGE_SOME_ADDRESS, + .verbose = verbose, + .dryrun = dryrun, + }; + + globalvar_set_match("linux.bootargs.dyn.", ""); + globalvar_set_match("bootm.", ""); + + devicetree = blspec_entry_var_get(entry, "devicetree"); + initrd = blspec_entry_var_get(entry, "initrd"); + options = blspec_entry_var_get(entry, "options"); + linuximage = blspec_entry_var_get(entry, "linux"); + + if (entry->rootpath) + abspath = entry->rootpath; + else + abspath = ""; + + data.os_file = basprintf("%s/%s", abspath, linuximage); + + if (devicetree) { + if (!strcmp(devicetree, "none")) { + struct device_node *node = of_get_root_node(); + if (node) + of_delete_node(node); + } else { + data.oftree_file = basprintf("%s/%s", abspath, + devicetree); + } + } + + if (initrd) + data.initrd_file = basprintf("%s/%s", abspath, initrd); + + globalvar_add_simple("linux.bootargs.dyn.bootentries", options); + + appendroot = blspec_entry_var_get(entry, "linux-appendroot"); + if (appendroot) { + int val; + + ret = strtobool(appendroot, &val); + if (ret) { + pr_err("Invalid value \"%s\" for appendroot option\n", + appendroot); + goto err_out; + } + data.appendroot = val; + } + + pr_info("booting %s from %s\n", blspec_entry_var_get(entry, "title"), + entry->cdev ? dev_name(entry->cdev->dev) : "none"); + + ret = bootm_boot(&data); + if (ret) + pr_err("Booting failed\n"); +err_out: + free((char *)data.oftree_file); + free((char *)data.initrd_file); + free((char *)data.os_file); + + return ret; +} + +/* * blspec_entry_var_get - get the value of a variable */ const char *blspec_entry_var_get(struct blspec_entry *entry, const char *name) @@ -55,10 +133,33 @@ const char *blspec_entry_var_get(struct blspec_entry *entry, const char *name) return ret ? NULL : str; } +static void blspec_entry_free(struct bootentry *be) +{ + struct blspec_entry *entry = container_of(be, struct blspec_entry, entry); + + of_delete_node(entry->node); + free(entry->configpath); + free(entry->rootpath); + free(entry); +} + +static struct blspec_entry *blspec_entry_alloc(struct bootentries *bootentries) +{ + struct blspec_entry *entry; + + entry = xzalloc(sizeof(*entry)); + + entry->node = of_new_node(NULL, NULL); + entry->entry.release = blspec_entry_free; + entry->entry.boot = blspec_boot; + + return entry; +} + /* * blspec_entry_open - open an entry given a path */ -static struct blspec_entry *blspec_entry_open(struct blspec *blspec, +static struct blspec_entry *blspec_entry_open(struct bootentries *bootentries, const char *abspath) { struct blspec_entry *entry; @@ -71,7 +172,7 @@ static struct blspec_entry *blspec_entry_open(struct blspec *blspec, if (!buf) return ERR_PTR(-errno); - entry = blspec_entry_alloc(blspec); + entry = blspec_entry_alloc(bootentries); next = buf; @@ -126,11 +227,13 @@ static struct blspec_entry *blspec_entry_open(struct blspec *blspec, * blspec_have_entry - check if we already have an entry with * a certain path */ -static int blspec_have_entry(struct blspec *blspec, const char *path) +static int blspec_have_entry(struct bootentries *bootentries, const char *path) { + struct bootentry *be; struct blspec_entry *e; - list_for_each_entry(e, &blspec->entries, list) { + list_for_each_entry(be, &bootentries->entries, list) { + e = container_of(be, struct blspec_entry, entry); if (e->configpath && !strcmp(e->configpath, path)) return 1; } @@ -210,7 +313,7 @@ static char *parse_nfs_url(const char *url) if (prevpath) { mountpath = xstrdup(prevpath); } else { - mountpath = basprintf("/mnt/nfs-%s-blspec-%08x", host, + mountpath = basprintf("/mnt/nfs-%s-bootentries-%08x", host, rand()); if (port) options = basprintf("mountport=%s,port=%s", port, @@ -317,11 +420,11 @@ out: /* * blspec_scan_directory - scan over a directory * - * Given a root path collects all blspec entries found under /blspec/entries/. + * Given a root path collects all bootentries entries found under /bootentries/entries/. * * returns the number of entries found or a negative error value otherwise. */ -int blspec_scan_directory(struct blspec *blspec, const char *root) +int blspec_scan_directory(struct bootentries *bootentries, const char *root) { struct blspec_entry *entry; DIR *dir; @@ -329,16 +432,13 @@ int blspec_scan_directory(struct blspec *blspec, const char *root) char *abspath; int ret, found = 0; const char *dirname = "loader/entries"; - char *entry_default = NULL, *entry_once = NULL, *name, *nfspath = NULL; + char *nfspath = NULL; nfspath = parse_nfs_url(root); if (!IS_ERR(nfspath)) root = nfspath; - pr_info("%s: %s %s\n", __func__, root, dirname); - - entry_default = read_file_line("%s/default", root); - entry_once = read_file_line("%s/once", root); + pr_debug("%s: %s %s\n", __func__, root, dirname); abspath = basprintf("%s/%s", root, dirname); @@ -382,12 +482,12 @@ int blspec_scan_directory(struct blspec *blspec, const char *root) continue; } - if (blspec_have_entry(blspec, configname)) { + if (blspec_have_entry(bootentries, configname)) { free(configname); continue; } - entry = blspec_entry_open(blspec, configname); + entry = blspec_entry_open(bootentries, configname); if (IS_ERR(entry)) { free(configname); continue; @@ -398,34 +498,29 @@ int blspec_scan_directory(struct blspec *blspec, const char *root) entry->cdev = get_cdev_by_mountpath(root); if (!entry_is_of_compatible(entry)) { - blspec_entry_free(entry); + blspec_entry_free(&entry->entry); continue; } found++; - name = basprintf("%s/%s", dirname, d->d_name); - if (entry_default && !strcmp(name, entry_default)) - entry->boot_default = true; - if (entry_once && !strcmp(name, entry_once)) - entry->boot_once = true; - free(name); - if (entry->cdev) { devname = xstrdup(dev_name(entry->cdev->dev)); if (entry->cdev->dev->parent) hwdevname = xstrdup(dev_name(entry->cdev->dev->parent)); } - entry->me.display = basprintf("%-20s %-20s %s", - devname ? devname : "", - hwdevname ? hwdevname : "", - blspec_entry_var_get(entry, "title")); - + entry->entry.title = xstrdup(blspec_entry_var_get(entry, "title")); + entry->entry.description = basprintf("blspec entry, device: %s hwdevice: %s", + devname ? devname : "none", + hwdevname ? hwdevname : "none"); free(devname); free(hwdevname); - entry->me.type = MENU_ENTRY_NORMAL; + entry->entry.me.type = MENU_ENTRY_NORMAL; + entry->entry.release = blspec_entry_free; + + bootentries_add_entry(bootentries, &entry->entry); } ret = found; @@ -435,8 +530,6 @@ err_out: if (!IS_ERR(nfspath)) free(nfspath); free(abspath); - free(entry_default); - free(entry_once); return ret; } @@ -444,13 +537,13 @@ err_out: /* * blspec_scan_ubi - scan over a cdev containing UBI volumes * - * This function attaches a cdev as UBI devices and collects all blspec + * This function attaches a cdev as UBI devices and collects all bootentries * entries found in the UBI volumes * * returns the number of entries found or a negative error code if some unexpected * error occured. */ -static int blspec_scan_ubi(struct blspec *blspec, struct cdev *cdev) +static int blspec_scan_ubi(struct bootentries *bootentries, struct cdev *cdev) { struct device_d *child; int ret, found = 0; @@ -462,7 +555,7 @@ static int blspec_scan_ubi(struct blspec *blspec, struct cdev *cdev) return 0; device_for_each_child(cdev->dev, child) { - ret = blspec_scan_device(blspec, child); + ret = blspec_scan_device(bootentries, child); if (ret > 0) found += ret; } @@ -473,13 +566,13 @@ static int blspec_scan_ubi(struct blspec *blspec, struct cdev *cdev) /* * blspec_scan_cdev - scan over a cdev * - * Given a cdev this function mounts the filesystem and collects all blspec - * entries found under /blspec/entries/. + * Given a cdev this function mounts the filesystem and collects all bootentries + * entries found under /bootentries/entries/. * * returns the number of entries found or a negative error code if some unexpected * error occured. */ -static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) +static int blspec_scan_cdev(struct bootentries *bootentries, struct cdev *cdev) { int ret, found = 0; void *buf = xzalloc(512); @@ -502,14 +595,14 @@ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) return -EINVAL; if (filetype == filetype_ubi && IS_ENABLED(CONFIG_MTD_UBI)) { - ret = blspec_scan_ubi(blspec, cdev); + ret = blspec_scan_ubi(bootentries, cdev); if (ret > 0) found += ret; } rootpath = cdev_mount_default(cdev, NULL); if (!IS_ERR(rootpath)) { - ret = blspec_scan_directory(blspec, rootpath); + ret = blspec_scan_directory(bootentries, rootpath); if (ret > 0) found += ret; } @@ -524,7 +617,7 @@ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev) * Returns the number of entries found or a negative error code if some unexpected * error occured. */ -int blspec_scan_devices(struct blspec *blspec) +int blspec_scan_devices(struct bootentries *bootentries) { struct device_d *dev; struct block_device *bdev; @@ -537,7 +630,7 @@ int blspec_scan_devices(struct blspec *blspec) struct cdev *cdev = &bdev->cdev; list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list) { - ret = blspec_scan_cdev(blspec, cdev); + ret = blspec_scan_cdev(bootentries, cdev); if (ret > 0) found += ret; } @@ -550,11 +643,11 @@ int blspec_scan_devices(struct blspec *blspec) * blspec_scan_device - scan a device for child cdevs * * Given a device this functions scans over all child cdevs looking - * for blspec entries. + * for bootentries entries. * Returns the number of entries found or a negative error code if some unexpected * error occured. */ -int blspec_scan_device(struct blspec *blspec, struct device_d *dev) +int blspec_scan_device(struct bootentries *bootentries, struct device_d *dev) { struct device_d *child; struct cdev *cdev; @@ -571,7 +664,7 @@ int blspec_scan_device(struct blspec *blspec, struct device_d *dev) * should be used as $BOOT */ if (cdev->dos_partition_type == 0xea) { - ret = blspec_scan_cdev(blspec, cdev); + ret = blspec_scan_cdev(bootentries, cdev); if (ret == 0) ret = -ENOENT; @@ -590,7 +683,7 @@ int blspec_scan_device(struct blspec *blspec, struct device_d *dev) /* Try child devices */ device_for_each_child(dev, child) { - ret = blspec_scan_device(blspec, child); + ret = blspec_scan_device(bootentries, child); if (ret > 0) return ret; } @@ -600,7 +693,7 @@ int blspec_scan_device(struct blspec *blspec, struct device_d *dev) * by the bootblspec spec). */ list_for_each_entry(cdev, &dev->cdevs, devices_list) { - ret = blspec_scan_cdev(blspec, cdev); + ret = blspec_scan_cdev(bootentries, cdev); if (ret > 0) found += ret; } @@ -612,11 +705,11 @@ int blspec_scan_device(struct blspec *blspec, struct device_d *dev) * blspec_scan_devicename - scan a hardware device for child cdevs * * Given a name of a hardware device this functions scans over all child - * cdevs looking for blspec entries. + * cdevs looking for bootentries entries. * Returns the number of entries found or a negative error code if some unexpected * error occured. */ -int blspec_scan_devicename(struct blspec *blspec, const char *devname) +int blspec_scan_devicename(struct bootentries *bootentries, const char *devname) { struct device_d *dev; struct cdev *cdev; @@ -627,7 +720,7 @@ int blspec_scan_devicename(struct blspec *blspec, const char *devname) cdev = cdev_by_name(devname); if (cdev) { - int ret = blspec_scan_cdev(blspec, cdev); + int ret = blspec_scan_cdev(bootentries, cdev); if (ret > 0) return ret; } @@ -636,155 +729,5 @@ int blspec_scan_devicename(struct blspec *blspec, const char *devname) if (!dev) return -ENODEV; - return blspec_scan_device(blspec, dev); -} - -/* - * blspec_boot - boot an entry - * - * This boots an entry. On success this function does not return. - * In case of an error the error code is returned. This function may - * return 0 in case of a succesful dry run. - */ -int blspec_boot(struct blspec_entry *entry, int verbose, int dryrun) -{ - int ret; - const char *abspath, *devicetree, *options, *initrd, *linuximage; - const char *appendroot; - struct bootm_data data = { - .initrd_address = UIMAGE_INVALID_ADDRESS, - .os_address = UIMAGE_SOME_ADDRESS, - .verbose = verbose, - .dryrun = dryrun, - }; - - globalvar_set_match("linux.bootargs.dyn.", ""); - globalvar_set_match("bootm.", ""); - - devicetree = blspec_entry_var_get(entry, "devicetree"); - initrd = blspec_entry_var_get(entry, "initrd"); - options = blspec_entry_var_get(entry, "options"); - linuximage = blspec_entry_var_get(entry, "linux"); - - if (entry->rootpath) - abspath = entry->rootpath; - else - abspath = ""; - - data.os_file = basprintf("%s/%s", abspath, linuximage); - - if (devicetree) { - if (!strcmp(devicetree, "none")) { - struct device_node *node = of_get_root_node(); - if (node) - of_delete_node(node); - } else { - data.oftree_file = basprintf("%s/%s", abspath, - devicetree); - } - } - - if (initrd) - data.initrd_file = basprintf("%s/%s", abspath, initrd); - - globalvar_add_simple("linux.bootargs.dyn.blspec", options); - - appendroot = blspec_entry_var_get(entry, "linux-appendroot"); - if (appendroot) { - int val; - - ret = strtobool(appendroot, &val); - if (ret) { - pr_err("Invalid value \"%s\" for appendroot option\n", - appendroot); - goto err_out; - } - data.appendroot = val; - } - - pr_info("booting %s from %s\n", blspec_entry_var_get(entry, "title"), - entry->cdev ? dev_name(entry->cdev->dev) : "none"); - - if (entry->boot_once) { - char *s = basprintf("%s/once", abspath); - - ret = unlink(s); - if (ret) - pr_err("unable to unlink 'once': %s\n", strerror(-ret)); - else - pr_info("removed 'once'\n"); - - free(s); - } - - ret = bootm_boot(&data); - if (ret) - pr_err("Booting failed\n"); -err_out: - free((char *)data.oftree_file); - free((char *)data.initrd_file); - free((char *)data.os_file); - - return ret; -} - -/* - * blspec_entry_default - find the entry to load. - * - * return in the order of precendence: - * - The entry specified in the 'once' file - * - The entry specified in the 'default' file - * - The first entry - */ -struct blspec_entry *blspec_entry_default(struct blspec *l) -{ - struct blspec_entry *entry_once = NULL; - struct blspec_entry *entry_default = NULL; - struct blspec_entry *entry_first = NULL; - struct blspec_entry *e; - - list_for_each_entry(e, &l->entries, list) { - if (!entry_first) - entry_first = e; - if (e->boot_once) - entry_once = e; - if (e->boot_default) - entry_default = e; - } - - if (entry_once) - return entry_once; - if (entry_default) - return entry_default; - return entry_first; -} - -/* - * blspec_boot_devicename - scan hardware device for blspec entries and - * start the best one. - */ -int blspec_boot_devicename(const char *devname, int verbose, int dryrun) -{ - struct blspec *blspec; - struct blspec_entry *e; - int ret; - - blspec = blspec_alloc(); - - ret = blspec_scan_devicename(blspec, devname); - if (ret) - return ret; - - e = blspec_entry_default(blspec); - if (!e) { - printf("No bootspec entry found on %s\n", devname); - ret = -ENOENT; - goto out; - } - - ret = blspec_boot(e, verbose, dryrun); -out: - blspec_free(blspec); - - return ret; + return blspec_scan_device(bootentries, dev); } diff --git a/common/boot.c b/common/boot.c new file mode 100644 index 0000000000..e66bacbb0e --- /dev/null +++ b/common/boot.c @@ -0,0 +1,339 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <environment.h> +#include <globalvar.h> +#include <magicvar.h> +#include <watchdog.h> +#include <command.h> +#include <readkey.h> +#include <common.h> +#include <blspec.h> +#include <libgen.h> +#include <malloc.h> +#include <bootm.h> +#include <glob.h> +#include <init.h> +#include <menu.h> +#include <fs.h> + +#include <linux/stat.h> + +int bootentries_add_entry(struct bootentries *entries, struct bootentry *entry) +{ + list_add_tail(&entry->list, &entries->entries); + + return 0; +} + +struct bootentries *bootentries_alloc(void) +{ + struct bootentries *bootentries; + + bootentries = xzalloc(sizeof(*bootentries)); + INIT_LIST_HEAD(&bootentries->entries); + + if (IS_ENABLED(CONFIG_MENU)) { + bootentries->menu = menu_alloc(); + bootentries->menu->display = basprintf("boot"); + } + + return bootentries; +} + +void bootentries_free(struct bootentries *bootentries) +{ + struct bootentry *be, *tmp; + + list_for_each_entry_safe(be, tmp, &bootentries->entries, list) { + list_del(&be->list); + free(be->title); + free(be->description); + free(be->me.display); + be->release(be); + } + + if (bootentries->menu) + free(bootentries->menu->display); + free(bootentries->menu); + free(bootentries); +} + +struct bootentry_script { + struct bootentry entry; + char *scriptpath; +}; + +/* + * Start a single boot script. 'path' is a full path to a boot script. + */ +static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun) +{ + struct bootentry_script *bs = container_of(entry, struct bootentry_script, entry); + int ret; + + struct bootm_data data = {}; + + if (dryrun) { + printf("Would run %s\n", bs->scriptpath); + return 0; + } + + globalvar_set_match("linux.bootargs.dyn.", ""); + + ret = run_command(bs->scriptpath); + if (ret) { + printf("Running %s failed\n", bs->scriptpath); + goto out; + } + + bootm_data_init_defaults(&data); + + if (verbose) + data.verbose = verbose; + if (dryrun) + data.dryrun = dryrun; + + ret = bootm_boot(&data); + if (ret) + pr_err("Booting '%s' failed: %s\n", basename(bs->scriptpath), strerror(-ret)); +out: + return ret; +} + +static unsigned int boot_watchdog_timeout; + +void boot_set_watchdog_timeout(unsigned int timeout) +{ + boot_watchdog_timeout = timeout; +} + +static int init_boot_watchdog_timeout(void) +{ + return globalvar_add_simple_int("boot.watchdog_timeout", + &boot_watchdog_timeout, "%u"); +} +late_initcall(init_boot_watchdog_timeout); + +BAREBOX_MAGICVAR_NAMED(global_watchdog_timeout, global.boot.watchdog_timeout, + "Watchdog enable timeout in seconds before booting"); + +int boot_entry(struct bootentry *be, int verbose, int dryrun) +{ + int ret; + + printf("booting '%s'\n", be->title); + + if (IS_ENABLED(CONFIG_WATCHDOG) && boot_watchdog_timeout) { + ret = watchdog_set_timeout(boot_watchdog_timeout); + if (ret) + pr_warn("Failed to enable watchdog: %s\n", strerror(-ret)); + } + + ret = be->boot(be, verbose, dryrun); + + if (ret) + printf("booting '%s' failed: %s\n", be->title, strerror(-ret)); + + return ret; +} + +static void bootsource_action(struct menu *m, struct menu_entry *me) +{ + struct bootentry *be = container_of(me, struct bootentry, me); + int ret; + + ret = boot_entry(be, 0, 0); + if (ret) + printf("Booting failed with: %s\n", strerror(-ret)); + + printf("Press any key to continue\n"); + + read_key(); +} + +static void bootscript_entry_release(struct bootentry *entry) +{ + struct bootentry_script *bs = container_of(entry, struct bootentry_script, entry); + + free(bs->scriptpath); + free(bs->entry.me.display); + free(bs); +} + +/* + * bootscript_create_entry - create a boot entry from a script name + */ +static int bootscript_create_entry(struct bootentries *bootentries, const char *name) +{ + struct bootentry_script *bs; + enum filetype type; + + type = file_name_detect_type(name); + if (type != filetype_sh) + return -EINVAL; + + bs = xzalloc(sizeof(*bs)); + bs->entry.me.type = MENU_ENTRY_NORMAL; + bs->entry.release = bootscript_entry_release; + bs->entry.boot = bootscript_boot; + bs->scriptpath = xstrdup(name); + bs->entry.title = xstrdup(basename(bs->scriptpath)); + bs->entry.description = basprintf("script: %s", name); + bootentries_add_entry(bootentries, &bs->entry); + + 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 bootentries *bootentries, const char *path) +{ + struct stat s; + char *files; + int ret, i; + int found = 0; + glob_t globb; + + ret = stat(path, &s); + if (ret) + return ret; + + if (!S_ISDIR(s.st_mode)) { + ret = bootscript_create_entry(bootentries, path); + if (ret) + return ret; + return 1; + } + + files = basprintf("%s/*", path); + + glob(files, 0, NULL, &globb); + + for (i = 0; i < globb.gl_pathc; i++) { + char *bootscript_path = globb.gl_pathv[i]; + + if (*basename(bootscript_path) == '.') + continue; + + bootscript_create_entry(bootentries, bootscript_path); + found++; + } + + globfree(&globb); + free(files); + + ret = found; + + return ret; +} + +/* + * bootentry_create_from_name - 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. + */ +int bootentry_create_from_name(struct bootentries *bootentries, + const char *name) +{ + int found = 0, ret; + + if (IS_ENABLED(CONFIG_BLSPEC)) { + ret = blspec_scan_devicename(bootentries, name); + if (ret > 0) + found += ret; + + if (*name == '/') { + ret = blspec_scan_directory(bootentries, name); + if (ret > 0) + found += ret; + } + } + + if (!found) { + char *path; + + if (*name != '/') + path = basprintf("/env/boot/%s", name); + else + path = xstrdup(name); + + ret = bootscript_scan_path(bootentries, path); + if (ret > 0) + found += ret; + + free(path); + } + + return found; +} + +/* + * bootsources_menu - show a menu from an array of names + */ +void bootsources_menu(struct bootentries *bootentries, int timeout) +{ + struct bootentry *entry; + struct menu_entry *back_entry; + + if (!IS_ENABLED(CONFIG_MENU)) { + printf("no menu support available\n"); + return; + } + + bootentries_for_each_entry(bootentries, entry) { + if (!entry->me.display) + entry->me.display = xstrdup(entry->title); + entry->me.action = bootsource_action; + menu_add_entry(bootentries->menu, &entry->me); + } + + back_entry = xzalloc(sizeof(*back_entry)); + back_entry->display = "back"; + back_entry->type = MENU_ENTRY_NORMAL; + back_entry->non_re_ent = 1; + menu_add_entry(bootentries->menu, back_entry); + + if (timeout >= 0) + bootentries->menu->auto_select = timeout; + + menu_show(bootentries->menu); + + free(back_entry); +} + +/* + * bootsources_list - list boot entries from an array of names + */ +void bootsources_list(struct bootentries *bootentries) +{ + struct bootentry *entry; + + printf("%-20s\n", "title"); + printf("%-20s\n", "------"); + + bootentries_for_each_entry(bootentries, entry) + printf("%-20s %s\n", entry->title, entry->description); +} + +BAREBOX_MAGICVAR_NAMED(global_boot_default, global.boot.default, "default boot order"); diff --git a/common/bootm.c b/common/bootm.c index 27d20f2c72..78d04d5806 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -12,7 +12,7 @@ */ #include <common.h> -#include <boot.h> +#include <bootm.h> #include <fs.h> #include <malloc.h> #include <memory.h> @@ -20,6 +20,7 @@ #include <image-fit.h> #include <globalvar.h> #include <init.h> +#include <environment.h> #include <linux/stat.h> #include <magicvar.h> diff --git a/common/image-fit.c b/common/image-fit.c index 9b6c40fbf8..6a01c614cc 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -20,7 +20,7 @@ #define pr_fmt(fmt) "FIT: " fmt #include <common.h> #include <init.h> -#include <boot.h> +#include <bootm.h> #include <libfile.h> #include <fdt.h> #include <digest.h> |