From 6c356b6a8bbb6248533a471acc6852a06eb64e47 Mon Sep 17 00:00:00 2001 From: Clayton Craft Date: Wed, 29 Apr 2026 17:35:05 -0700 Subject: [PATCH] bootctl: add after_slot parameter to insert_into_order() 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 | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/bootctl/bootctl-install.c b/src/bootctl/bootctl-install.c index db5d982a58..cb46877e6e 100644 --- a/src/bootctl/bootctl-install.c +++ b/src/bootctl/bootctl-install.c @@ -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;