The boot command supports specifying a preselection by index, but this
is not so useful when the boot entries come from external media as the
order may easily change.

Add thus the ability to preselect an entry by file path as well via the
-M option. Unlike -M 1337 which would usually leads to a normal error, a
non-existent file path will just be silently ignored and the menu shown
anyway without preselection.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 commands/boot.c   | 62 +++++++++++++++++++++++++++++++++++++----------
 include/fnmatch.h |  9 +++++++
 2 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/commands/boot.c b/commands/boot.c
index 9cfb7c6b0d5e..555667ee098c 100644
--- a/commands/boot.c
+++ b/commands/boot.c
@@ -7,6 +7,7 @@
 #include <malloc.h>
 #include <boot.h>
 #include <bootm.h>
+#include <fnmatch.h>
 #include <complete.h>
 
 #include <linux/stat.h>
@@ -55,12 +56,41 @@ static int boot_add_override(struct bootm_overrides 
*overrides, char *var)
        return 0;
 }
 
+static int bootentries_get_default_menu_entry(struct bootentries *entries,
+                                             char *id)
+{
+       struct bootentry *entry;
+       int ret, idx = 1;
+
+       if (!id)
+               return 0;
+
+       /* To simplify scripting, an empty string is treated as 1 */
+       if (*id == '\0')
+               return 1;
+
+       ret = kstrtouint(id, 0, &idx);
+       if (!ret)
+               return idx;
+       if (ret != -EINVAL)
+               return ret;
+
+       bootentries_for_each_entry(entries, entry) {
+               if ((IS_ENABLED(CONFIG_FNMATCH) && !fnmatch(id, entry->path, 
0)) ||
+                   streq_ptr(id, entry->path))
+                       return idx;
+               idx++;
+       }
+
+       return 0;
+}
+
 static int do_boot(int argc, char *argv[])
 {
        char *freep = NULL;
        int opt, ret = 0, do_list = 0, do_menu = 0;
        int dryrun = 0, verbose = 0, timeout = -1;
-       unsigned default_menu_entry = 0;
+       char *default_menu_entry = NULL;
        struct bootentries *entries;
        struct bootentry *entry;
        struct bootm_overrides overrides = {};
@@ -80,14 +110,7 @@ static int do_boot(int argc, char *argv[])
                        dryrun++;
                        break;
                case 'M':
-                       /* To simplify scripting, an empty string is treated as 
1 */
-                       if (*optarg == '\0') {
-                               default_menu_entry = 1;
-                       } else {
-                               ret = kstrtouint(optarg, 0, 
&default_menu_entry);
-                               if (ret)
-                                       return ret;
-                       }
+                       default_menu_entry = optarg;
                        fallthrough;
                case 'm':
                        do_menu = 1;
@@ -152,10 +175,17 @@ static int do_boot(int argc, char *argv[])
                goto out;
        }
 
-       if (do_list)
+       if (do_list) {
                bootsources_list(entries);
-       else if (do_menu)
-               bootsources_menu(entries, default_menu_entry, timeout);
+       } else if (do_menu) {
+               int idx;
+
+               idx = bootentries_get_default_menu_entry(entries, 
default_menu_entry);
+               if (idx < 0)
+                       return idx;
+
+               bootsources_menu(entries, idx, timeout);
+       }
 
        ret = 0;
 out:
@@ -189,6 +219,12 @@ BAREBOX_CMD_HELP_TEXT("- \"storage.removable\": boot from 
removable media")
 BAREBOX_CMD_HELP_TEXT("- \"storage.builtin\": boot from non-removable media")
 BAREBOX_CMD_HELP_TEXT("- \"storage\": boot from any available media")
 #endif
+BAREBOX_CMD_HELP_TEXT("DEFAULT can be:")
+BAREBOX_CMD_HELP_TEXT("- the numeric index of the menu entry to choose")
+BAREBOX_CMD_HELP_TEXT("- the path to the file backing the entry (e.g. bootspec 
config file)")
+#ifdef CONFIG_FNMATCH
+BAREBOX_CMD_HELP_TEXT("  with wildcards allowed")
+#endif
 BAREBOX_CMD_HELP_TEXT("")
 BAREBOX_CMD_HELP_TEXT("Multiple bootsources may be given which are probed in 
order until")
 BAREBOX_CMD_HELP_TEXT("one succeeds.")
@@ -198,7 +234,7 @@ BAREBOX_CMD_HELP_OPT ("-v","Increase verbosity")
 BAREBOX_CMD_HELP_OPT ("-d","Dryrun. See what happens but do no actually boot 
(pass twice to run scripts)")
 BAREBOX_CMD_HELP_OPT ("-l","List available boot sources")
 BAREBOX_CMD_HELP_OPT ("-m","Show a menu with boot options")
-BAREBOX_CMD_HELP_OPT ("-M INDEX","Show a menu with boot options with entry 
INDEX preselected")
+BAREBOX_CMD_HELP_OPT ("-M DEFAULT","Show a menu with boot options with entry 
DEFAULT preselected")
 BAREBOX_CMD_HELP_OPT ("-w SECS","Start watchdog with timeout SECS before 
booting")
 #ifdef CONFIG_BOOT_OVERRIDE
 BAREBOX_CMD_HELP_OPT ("-o VAR[=VAL]","override VAR (bootm.{oftree,initrd}) 
with VAL")
diff --git a/include/fnmatch.h b/include/fnmatch.h
index 1bc2cf87391a..b4895e8d8467 100644
--- a/include/fnmatch.h
+++ b/include/fnmatch.h
@@ -17,8 +17,17 @@
 /* Value returned by `fnmatch' if STRING does not match PATTERN.  */
 #define        FNM_NOMATCH     1
 
+#ifdef CONFIG_FNMATCH
+
 /* Match NAME against the filename pattern PATTERN,
    returning zero if it matches, FNM_NOMATCH if not.  */
 extern int fnmatch(const char *pattern, const char *name, int flags);
 
+#else
+static inline int fnmatch(const char *pattern, const char *name, int flags)
+{
+       return 0;
+}
+#endif
+
 #endif /* fnmatch.h */
-- 
2.47.3


Reply via email to