]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: Use parse_number16 for boot counter parsing 23691/head
authorJan Janssen <medhefgo@web.de>
Thu, 2 Jun 2022 09:23:12 +0000 (11:23 +0200)
committerJan Janssen <medhefgo@web.de>
Fri, 10 Jun 2022 09:50:13 +0000 (11:50 +0200)
src/boot/efi/boot.c

index 7d881fc75255b0799d68ec964cc57c3b528d1e12..ea80c1875dd5b9cf6ae12b616b697af8b107da98 100644 (file)
@@ -65,8 +65,8 @@ typedef struct {
         CHAR16 **initrd;
         CHAR16 key;
         EFI_STATUS (*call)(void);
-        UINTN tries_done;
-        UINTN tries_left;
+        int tries_done;
+        int tries_left;
         CHAR16 *path;
         CHAR16 *current_name;
         CHAR16 *next_name;
@@ -567,9 +567,9 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) {
                 ps_string(L"       options: %s\n", entry->options);
                   ps_bool(L" internal call: %s\n", !!entry->call);
 
-                  ps_bool(L"counting boots: %s\n", entry->tries_left != UINTN_MAX);
-                if (entry->tries_left != UINTN_MAX) {
-                    Print(L"         tries: %" PRIuN L" done, %" PRIuN L" left\n", entry->tries_done, entry->tries_left);
+                  ps_bool(L"counting boots: %s\n", entry->tries_left >= 0);
+                if (entry->tries_left >= 0) {
+                    Print(L"         tries: %u left, %u done\n", entry->tries_left, entry->tries_done);
                     Print(L"  current path: %s\\%s\n",  entry->path, entry->current_name);
                     Print(L"     next path: %s\\%s\n",  entry->path, entry->next_name);
                 }
@@ -1262,12 +1262,10 @@ static void config_entry_parse_tries(
                 const CHAR16 *file,
                 const CHAR16 *suffix) {
 
-        UINTN left = UINTN_MAX, done = UINTN_MAX, factor = 1, i, next_left, next_done;
-        _cleanup_freepool_ CHAR16 *prefix = NULL;
-
         assert(entry);
         assert(path);
         assert(file);
+        assert(suffix);
 
         /*
          * Parses a suffix of two counters (one going down, one going up) in the form "+LEFT-DONE" from the end of the
@@ -1280,99 +1278,46 @@ static void config_entry_parse_tries(
          * foobar+4-0.efi → foobar+3-1.efi → foobar+2-2.efi → foobar+1-3.efi → foobar+0-4.efi → STOP!
          */
 
-        i = strlen16(file);
-
-        /* Chop off any suffix such as ".conf" or ".efi" */
-        if (suffix) {
-                UINTN suffix_length;
-
-                suffix_length = strlen16(suffix);
-                if (i < suffix_length)
-                        return;
-
-                i -= suffix_length;
-        }
-
-        /* Go backwards through the string and parse everything we encounter */
+        const char16_t *counter = NULL;
         for (;;) {
-                if (i == 0)
-                        return;
-
-                i--;
-
-                switch (file[i]) {
-
-                case '+':
-                        if (left == UINTN_MAX) /* didn't read at least one digit for 'left'? */
-                                return;
-
-                        if (done == UINTN_MAX) /* no 'done' counter? If so, it's equivalent to 0 */
-                                done = 0;
-
-                        goto good;
-
-                case '-':
-                        if (left == UINTN_MAX) /* didn't parse any digit yet? */
-                                return;
-
-                        if (done != UINTN_MAX) /* already encountered a dash earlier? */
-                                return;
-
-                        /* So we encountered a dash. This means this counter is of the form +LEFT-DONE. Let's assign
-                         * what we already parsed to 'done', and start fresh for the 'left' part. */
-
-                        done = left;
-                        left = UINTN_MAX;
-                        factor = 1;
+                char16_t *plus = strchr16(counter ?: file, '+');
+                if (plus) {
+                        /* We want the last "+". */
+                        counter = plus + 1;
+                        continue;
+                }
+                if (counter)
                         break;
 
-                case '0'...'9': {
-                        UINTN new_factor;
-
-                        if (left == UINTN_MAX)
-                                left = file[i] - '0';
-                        else {
-                                UINTN new_left, digit;
-
-                                digit = file[i] - '0';
-                                if (digit > UINTN_MAX / factor) /* overflow check */
-                                        return;
-
-                                new_left = left + digit * factor;
-                                if (new_left < left) /* overflow check */
-                                        return;
-
-                                if (new_left == UINTN_MAX) /* don't allow us to be confused */
-                                        return;
-                        }
+                /* No boot counter found. */
+                return;
+        }
 
-                        new_factor = factor * 10;
-                        if (new_factor < factor) /* overflow check */
-                                return;
+        uint64_t tries_left, tries_done = 0;
+        size_t prefix_len = counter - file;
 
-                        factor = new_factor;
-                        break;
-                }
+        if (!parse_number16(counter, &tries_left, &counter) || tries_left > INT_MAX)
+                return;
 
-                default:
-                        return;
-                }
-        }
+        /* Parse done counter only if present. */
+        if (*counter == '-' && (!parse_number16(counter + 1, &tries_done, &counter) || tries_done > INT_MAX))
+                return;
 
-good:
-        entry->tries_left = left;
-        entry->tries_done = done;
+        /* Boot counter in the middle of the name? */
+        if (!streq16(counter, suffix))
+                return;
 
+        entry->tries_left = tries_left;
+        entry->tries_done = tries_done;
         entry->path = xstrdup16(path);
         entry->current_name = xstrdup16(file);
-
-        next_left = left <= 0 ? 0 : left - 1;
-        next_done = done >= (UINTN) -2 ? (UINTN) -2 : done + 1;
-
-        prefix = xstrdup16(file);
-        prefix[i] = 0;
-
-        entry->next_name = xpool_print(L"%s+%" PRIuN L"-%" PRIuN L"%s", prefix, next_left, next_done, strempty(suffix));
+        entry->next_name = xpool_print(
+                        L"%.*s%u-%u%s",
+                        prefix_len,
+                        file,
+                        LESS_BY(tries_left, 1u),
+                        MIN(tries_done + 1, (uint64_t) INT_MAX),
+                        suffix);
 }
 
 static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
@@ -1385,7 +1330,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
         assert(entry);
         assert(root_dir);
 
-        if (entry->tries_left == UINTN_MAX)
+        if (entry->tries_left < 0)
                 return;
 
         if (!entry->path || !entry->current_name || !entry->next_name)
@@ -1448,8 +1393,8 @@ static void config_entry_add_type1(
 
         entry = xnew(ConfigEntry, 1);
         *entry = (ConfigEntry) {
-                .tries_done = UINTN_MAX,
-                .tries_left = UINTN_MAX,
+                .tries_done = -1,
+                .tries_left = -1,
         };
 
         while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
@@ -1706,7 +1651,7 @@ static int config_entry_compare(const ConfigEntry *a, const ConfigEntry *b) {
         if (r != 0)
                 return r;
 
-        if (a->tries_left == UINTN_MAX || b->tries_left == UINTN_MAX)
+        if (a->tries_left < 0 || b->tries_left < 0)
                 return 0;
 
         /* If both items have boot counting, and otherwise are identical, put the entry with more tries left first */
@@ -1927,8 +1872,8 @@ static ConfigEntry *config_entry_add_loader_auto(
                 .device = device,
                 .loader = xstrdup16(loader),
                 .key = key,
-                .tries_done = UINTN_MAX,
-                .tries_left = UINTN_MAX,
+                .tries_done = -1,
+                .tries_left = -1,
         };
 
         config_add_entry(config, entry);
@@ -2216,8 +2161,8 @@ static void config_entry_add_unified(
                         .loader = xpool_print(L"\\EFI\\Linux\\%s", f->FileName),
                         .sort_key = xstrdup16(good_sort_key),
                         .key = 'l',
-                        .tries_done = UINTN_MAX,
-                        .tries_left = UINTN_MAX,
+                        .tries_done = -1,
+                        .tries_left = -1,
                 };
 
                 strtolower16(entry->id);
@@ -2560,8 +2505,8 @@ static void config_load_all_entries(
                         .id = xstrdup16(u"auto-reboot-to-firmware-setup"),
                         .title = xstrdup16(u"Reboot Into Firmware Interface"),
                         .call = reboot_into_firmware,
-                        .tries_done = UINTN_MAX,
-                        .tries_left = UINTN_MAX,
+                        .tries_done = -1,
+                        .tries_left = -1,
                 };
                 config_add_entry(config, entry);
         }