diff --git a/commands/boot.c b/commands/boot.c index bb8d07f..4a83979 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -106,6 +106,11 @@ static int bootscript_create_entry(struct blspec *blspec, const char *name) { struct blspec_entry *be; + enum filetype type; + + type = file_name_detect_type(name); + if (type != filetype_sh) + return -EINVAL; be = blspec_entry_alloc(blspec); be->me.type = MENU_ENTRY_NORMAL; @@ -238,7 +243,7 @@ static void bootsources_menu(char *entries[], int num_entries) { struct blspec *blspec = NULL; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; struct menu_entry *back_entry; if (!IS_ENABLED(CONFIG_MENU)) { @@ -247,10 +252,16 @@ } blspec = bootentries_collect(entries, num_entries); + if (blspec) + return; + + entry_default = blspec_entry_default(blspec); blspec_for_each_entry(blspec, entry) { entry->me.action = bootsource_action; menu_add_entry(blspec->menu, &entry->me); + if (entry == entry_default) + menu_set_selected_entry(blspec->menu, &entry->me); } back_entry = xzalloc(sizeof(*back_entry)); @@ -275,14 +286,23 @@ static void bootsources_list(char *entries[], int num_entries) { struct blspec *blspec; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; blspec = bootentries_collect(entries, num_entries); + if (!blspec) + return; - printf("%-20s %-20s %s\n", "device", "hwdevice", "title"); - printf("%-20s %-20s %s\n", "------", "--------", "-----"); + entry_default = blspec_entry_default(blspec); + + printf(" %-20s %-20s %s\n", "device", "hwdevice", "title"); + printf(" %-20s %-20s %s\n", "------", "--------", "-----"); blspec_for_each_entry(blspec, entry) { + if (entry == entry_default) + printf("* "); + else + printf(" "); + if (entry->scriptpath) printf("%-40s %s\n", basename(entry->scriptpath), entry->me.display); else @@ -307,7 +327,7 @@ static int boot(const char *name) { struct blspec *blspec; - struct blspec_entry *entry; + struct blspec_entry *entry, *entry_default; int ret; blspec = blspec_alloc(); @@ -320,7 +340,19 @@ return -ENOENT; } + entry_default = blspec_entry_default(blspec); + if (entry_default) { + ret = boot_entry(entry_default); + if (!ret) + return ret; + printf("booting %s failed: %s\n", entry_default->me.display, + strerror(-ret)); + } + blspec_for_each_entry(blspec, entry) { + if (entry == entry_default) + continue; + printf("booting %s\n", entry->me.display); ret = boot_entry(entry); if (!ret) @@ -333,9 +365,11 @@ static int do_boot(int argc, char *argv[]) { - const char *sources = NULL; - char *source, *freep; + char *freep = NULL; int opt, ret = 0, do_list = 0, do_menu = 0; + char **sources; + int num_sources; + int i; verbose = 0; dryrun = 0; @@ -361,47 +395,62 @@ } } + if (optind < argc) { + num_sources = argc - optind; + sources = xmemdup(&argv[optind], sizeof(char *) * num_sources); + } else { + const char *def; + char *sep; + + def = getenv("global.boot.default"); + if (!def) + return 0; + + sep = freep = xstrdup(def); + + num_sources = 0; + + while (1) { + num_sources++; + + sep = strchr(sep, ' '); + if (!sep) + break; + sep++; + } + + sources = xmalloc(sizeof(char *) * num_sources); + + sep = freep; + + for (i = 0; i < num_sources; i++) { + sources[i] = sep; + sep = strchr(sep, ' '); + if (sep) + *sep = 0; + sep++; + } + } + if (do_list) { - bootsources_list(&argv[optind], argc - optind); - return 0; + bootsources_list(sources, num_sources); + goto out; } if (do_menu) { - bootsources_menu(&argv[optind], argc - optind); - return 0; + bootsources_menu(sources, num_sources); + goto out; } - if (optind < argc) { - while (optind < argc) { - source = argv[optind]; - optind++; - ret = boot(source); - if (!ret) - break; - } - return ret; - } - - sources = getenv("global.boot.default"); - if (!sources) - return 0; - - freep = source = xstrdup(sources); - - while (1) { - char *sep = strchr(source, ' '); - if (sep) - *sep = 0; - ret = boot(source); + for (i = 0; i < num_sources; i++) { + ret = boot(sources[i]); if (!ret) break; - - if (sep) - source = sep + 1; - else - break; + goto out; } +out: + free(sources); free(freep); return ret; diff --git a/common/blspec.c b/common/blspec.c index 9b4b096..f165b77 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -235,6 +235,78 @@ } /* + * entry_is_of_compatible - check if a bootspec entry is compatible with + * the current machine. + * + * returns true is the entry is compatible, false otherwise + */ +static bool entry_is_of_compatible(struct blspec_entry *entry) +{ + const char *devicetree; + const char *abspath; + size_t size; + void *fdt = NULL; + int ret; + struct device_node *root = NULL, *barebox_root; + const char *compat; + char *filename; + + /* If we don't have a root node every entry is compatible */ + barebox_root = of_get_root_node(); + if (!barebox_root) + return true; + + ret = of_property_read_string(barebox_root, "compatible", &compat); + if (ret) + return false; + + if (entry->rootpath) + abspath = entry->rootpath; + else + abspath = ""; + + /* If the entry doesn't specifiy a devicetree we are compatible */ + devicetree = blspec_entry_var_get(entry, "devicetree"); + if (!devicetree) + return true; + + if (!strcmp(devicetree, "none")) + return true; + + filename = asprintf("%s/%s", abspath, devicetree); + + fdt = read_file(filename, &size); + if (!fdt) { + ret = false; + goto out; + } + + root = of_unflatten_dtb(NULL, fdt); + if (IS_ERR(root)) { + ret = PTR_ERR(root); + goto out; + } + + if (of_device_is_compatible(root, compat)) { + ret = true; + goto out; + } + + pr_info("ignoring entry with incompatible devicetree \"%s\"\n", + (char *)of_get_property(root, "compatible", &size)); + + ret = false; + +out: + if (root) + of_delete_node(root); + free(filename); + free(fdt); + + return ret; +} + +/* * blspec_scan_directory - scan over a directory * * Given a root path collects all blspec entries found under /blspec/entries/. @@ -313,12 +385,17 @@ continue; } - found++; - entry->rootpath = xstrdup(root); entry->configpath = configname; entry->cdev = get_cdev_by_mountpath(root); + if (!entry_is_of_compatible(entry)) { + blspec_entry_free(entry); + continue; + } + + found++; + name = asprintf("%s/%s", dirname, d->d_name); if (entry_default && !strcmp(name, entry_default)) entry->boot_default = true; diff --git a/include/blspec.h b/include/blspec.h index 66d2e84..afac5ed 100644 --- a/include/blspec.h +++ b/include/blspec.h @@ -35,7 +35,6 @@ int blspec_scan_devices(struct blspec *blspec); -struct blspec_entry *blspec_entry_default(struct blspec *l); int blspec_scan_devicename(struct blspec *blspec, const char *devname); int blspec_scan_directory(struct blspec *blspec, const char *root); @@ -91,4 +90,13 @@ free(blspec); } +#ifdef CONFIG_BLSPEC +struct blspec_entry *blspec_entry_default(struct blspec *l); +#else +static inline struct blspec_entry *blspec_entry_default(struct blspec *l) +{ + return NULL; +} +#endif + #endif /* __LOADER_H__ */