]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: add after_slot parameter to insert_into_order()
authorClayton Craft <clayton@craftyguy.net>
Thu, 30 Apr 2026 00:35:05 +0000 (17:35 -0700)
committerClayton Craft <clayton@craftyguy.net>
Thu, 21 May 2026 18:26:59 +0000 (11:26 -0700)
This adds an after_slot parameter that, when not set to UINT16_MAX,
requests that the new slot be placed immediately after the given slot in
BootOrder. When after_slot is set and the new slot already exists in
BootOrder, it will leave its position alone. This is so that if a user
reorders it, we don't stomp on their changes.

src/bootctl/bootctl-install.c

index db5d982a583827dcb7b46fba1d53336986d8cd2c..cb46877e6e1e72637a8265ba26a1237a4ec8f4f2 100644 (file)
@@ -1233,7 +1233,7 @@ static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
         return 0;
 }
 
-static int insert_into_order(InstallContext *c, uint16_t slot) {
+static int insert_into_order(InstallContext *c, uint16_t slot, uint16_t after_slot) {
         _cleanup_free_ uint16_t *order = NULL;
         uint16_t *t;
         int n;
@@ -1255,7 +1255,8 @@ static int insert_into_order(InstallContext *c, uint16_t slot) {
                         continue;
 
                 /* we do not require to be the first one, all is fine */
-                if (c->operation != INSTALL_NEW)
+                /* if after_slot is set, leave existing position alone to preserve user reordering. */
+                if (i == 0 || c->operation != INSTALL_NEW || after_slot != UINT16_MAX)
                         return 0;
 
                 /* move us to the first slot */
@@ -1264,6 +1265,27 @@ static int insert_into_order(InstallContext *c, uint16_t slot) {
                 return efi_set_boot_order(order, n);
         }
 
+        /* slot is not yet in the order, so insert after a specific slot if requested */
+        if (after_slot != UINT16_MAX) {
+                t = reallocarray(order, n + 1, sizeof(uint16_t));
+                if (!t)
+                        return -ENOMEM;
+                order = t;
+
+                for (int i = 0; i < n; i++) {
+                        if (order[i] != after_slot)
+                                continue;
+
+                        memmove(order + i + 2, order + i + 1, (n - i - 1) * sizeof(uint16_t));
+                        order[i + 1] = slot;
+                        return efi_set_boot_order(order, n + 1);
+                }
+
+                log_warning("Boot entry %04" PRIx16 " not found in BootOrder, appending new entry at the end.", after_slot);
+                order[n] = slot;
+                return efi_set_boot_order(order, n + 1);
+        }
+
         /* extend array */
         t = reallocarray(order, n + 1, sizeof(uint16_t));
         if (!t)
@@ -1422,7 +1444,7 @@ static int install_boot_option(
                          description);
         }
 
-        r = insert_into_order(c, slot);
+        r = insert_into_order(c, slot, /* after_slot= */ UINT16_MAX);
         if (r < 0)
                 return r;