diff --git a/TODO b/TODO
index 663e4fedd8..ae9f066ac6 100644
--- a/TODO
+++ b/TODO
@@ -686,9 +686,7 @@ Features:
- honor timezone efi variables for default timezone selection (if there are any?)
- change bootctl to be backed by systemd-bootd to control temporary and persistent default boot goal plus efi variables
* bootctl
- - verify that the files boot entries point to exist
- recognize the case when not booted on EFI
- - specify paths for boot entries
* maybe do not install getty@tty1.service symlink in /etc but in /usr?
diff --git a/man/rules/meson.build b/man/rules/meson.build
index d949900ddc..6f9f4c4443 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -101,6 +101,7 @@ manpages = [
'SD_ID128_MAKE',
'SD_ID128_MAKE_STR',
'SD_ID128_NULL',
+ 'SD_ID128_UUID_FORMAT_STR',
'sd_id128_equal',
'sd_id128_is_null',
'sd_id128_t'],
diff --git a/man/sd-id128.xml b/man/sd-id128.xml
index 74d838df2e..22d5e0e3ed 100644
--- a/man/sd-id128.xml
+++ b/man/sd-id128.xml
@@ -24,6 +24,7 @@
SD_ID128_NULL
SD_ID128_CONST_STR
SD_ID128_FORMAT_STR
+ SD_ID128_UUID_FORMAT_STR
SD_ID128_FORMAT_VAL
sd_id128_equal
sd_id128_is_null
@@ -119,6 +120,11 @@ int main(int argc, char **argv) {
return 0;
}
+ SD_ID128_UUID_FORMAT_STR() is similar to
+ SD_ID128_FORMAT_STR() but includes separating hyphens to conform to the
+ "canonical representation".
+
+
Use sd_id128_equal() to compare two 128-bit IDs:
int main(int argc, char *argv[]) {
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index a7de3800fc..9df181a10c 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -220,7 +220,7 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
printf(" ESP: %s", esp_path);
if (!sd_id128_is_null(partition))
- printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(partition));
+ printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
printf("\n");
r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
@@ -262,7 +262,8 @@ static int print_efi_option(uint16_t id, bool in_order) {
printf(" Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
printf(" ID: 0x%04X\n", id);
printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
+ printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
+ SD_ID128_FORMAT_VAL(partition));
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
printf("\n");
@@ -309,21 +310,57 @@ static int status_variables(void) {
return 0;
}
+static int boot_entry_file_check(const char *root, const char *p) {
+ _cleanup_free_ char *path;
+
+ path = path_join(root, p);
+ if (!path)
+ return log_oom();
+
+ if (access(path, F_OK) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static void boot_entry_file_list(const char *field, const char *root, const char *p, int *ret_status) {
+ int status = boot_entry_file_check(root, p);
+
+ printf("%13s%s", strempty(field), field ? ":" : " ");
+ if (status < 0) {
+ errno = -status;
+ printf("%s%s%s (%m)\n", ansi_highlight_red(), p, ansi_normal());
+ } else
+ printf("%s\n", p);
+
+ if (*ret_status == 0 && status < 0)
+ *ret_status = status;
+}
+
static int boot_entry_show(const BootEntry *e, bool show_as_default) {
+ int status = 0;
+
+ /* Returns 0 on success, negative on processing error, and positive if something is wrong with the
+ boot entry itself. */
+
assert(e);
- printf(" title: %s%s%s%s%s%s\n"
- " type: %s\n",
- ansi_highlight(),
- boot_entry_title(e),
- ansi_normal(),
- ansi_highlight_green(),
- show_as_default ? " (default)" : "",
- ansi_normal(),
- boot_entry_type_to_string(e->type));
+ printf(" title: %s%s%s" "%s%s%s\n",
+ ansi_highlight(), boot_entry_title(e), ansi_normal(),
+ ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal());
if (e->id)
printf(" id: %s\n", e->id);
+ if (e->path) {
+ _cleanup_free_ char *link = NULL;
+
+ /* Let's urlify the link to make it easy to view in an editor, but only if it is a text
+ * file. Unified images are binary ELFs, and EFI variables are not pure text either. */
+ if (e->type == BOOT_ENTRY_CONF)
+ (void) terminal_urlify_path(e->path, NULL, &link);
+
+ printf(" source: %s\n", link ?: e->path);
+ }
if (e->version)
printf(" version: %s\n", e->version);
if (e->machine_id)
@@ -331,16 +368,14 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
if (e->architecture)
printf(" architecture: %s\n", e->architecture);
if (e->kernel)
- printf(" linux: %s\n", e->kernel);
- if (!strv_isempty(e->initrd)) {
- _cleanup_free_ char *t;
+ boot_entry_file_list("linux", e->root, e->kernel, &status);
- t = strv_join(e->initrd, " ");
- if (!t)
- return log_oom();
-
- printf(" initrd: %s\n", t);
- }
+ char **s;
+ STRV_FOREACH(s, e->initrd)
+ boot_entry_file_list(s == e->initrd ? "initrd" : NULL,
+ e->root,
+ *s,
+ &status);
if (!strv_isempty(e->options)) {
_cleanup_free_ char *t;
@@ -351,9 +386,9 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
printf(" options: %s\n", t);
}
if (e->device_tree)
- printf(" devicetree: %s\n", e->device_tree);
+ boot_entry_file_list("devicetree", e->root, e->device_tree, &status);
- return 0;
+ return -status;
}
static int status_entries(
@@ -380,7 +415,8 @@ static int status_entries(
printf("Boot Loader Entries:\n"
" $BOOT: %s", dollar_boot_path);
if (!sd_id128_is_null(dollar_boot_partition_uuid))
- printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
+ printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")",
+ SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
printf("\n\n");
r = boot_entries_load_config(esp_path, xbootldr_path, &config);
@@ -392,7 +428,11 @@ static int status_entries(
else {
printf("Default Boot Loader Entry:\n");
- boot_entry_show(config.entries + config.default_entry, false);
+ r = boot_entry_show(config.entries + config.default_entry, false);
+ if (r > 0)
+ /* < 0 is already logged by the function itself, let's just emit an extra warning if
+ the default entry is broken */
+ printf("\nWARNING: default boot entry is broken\n");
}
return 0;
@@ -1150,7 +1190,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
if (stub)
printf(" Stub: %s\n", stub);
if (!sd_id128_is_null(loader_part_uuid))
- printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
SD_ID128_FORMAT_VAL(loader_part_uuid));
else
printf(" ESP: n/a\n");
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index 65f14ab252..82a69a77f3 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -10,9 +10,6 @@
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
-/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
-#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
-
bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format {
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index 9a0dc29153..3bd14d7372 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -755,7 +755,7 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
n_allocated = config->n_entries;
STRV_FOREACH(i, found_by_loader) {
- _cleanup_free_ char *c = NULL, *t = NULL;
+ _cleanup_free_ char *c = NULL, *t = NULL, *p = NULL;
char **a, **b;
if (boot_config_has_entry(config, *i))
@@ -776,6 +776,10 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
break;
}
+ p = efi_variable_path(EFI_VENDOR_LOADER, "LoaderEntries");
+ if (!p)
+ return log_oom();
+
if (!GREEDY_REALLOC0(config->entries, n_allocated, config->n_entries + 1))
return log_oom();
@@ -783,6 +787,7 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
.type = BOOT_ENTRY_LOADER,
.id = TAKE_PTR(c),
.title = TAKE_PTR(t),
+ .path = TAKE_PTR(p),
};
}
@@ -1418,11 +1423,3 @@ found:
return 0;
}
-
-static const char* const boot_entry_type_table[_BOOT_ENTRY_MAX] = {
- [BOOT_ENTRY_CONF] = "conf",
- [BOOT_ENTRY_UNIFIED] = "unified",
- [BOOT_ENTRY_LOADER] = "loader",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(boot_entry_type, BootEntryType);
diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h
index 45e1fc37c6..b35eaf1110 100644
--- a/src/shared/bootspec.h
+++ b/src/shared/bootspec.h
@@ -79,6 +79,3 @@ static inline const char* boot_entry_title(const BootEntry *entry) {
int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid);
int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid);
-
-const char* boot_entry_type_to_string(BootEntryType t) _const_;
-BootEntryType boot_entry_type_from_string(const char *s) _pure_;
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index 4f32163bba..fc884dedf0 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -193,6 +193,17 @@ int efi_set_reboot_to_firmware(bool value) {
return 0;
}
+char* efi_variable_path(sd_id128_t vendor, const char *name) {
+ char *p;
+
+ if (asprintf(&p,
+ "/sys/firmware/efi/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
+ name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+ return NULL;
+
+ return p;
+}
+
int efi_get_variable(
sd_id128_t vendor,
const char *name,
@@ -211,9 +222,8 @@ int efi_get_variable(
assert(value);
assert(size);
- if (asprintf(&p,
- "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+ p = efi_variable_path(vendor, name);
+ if (!p)
return -ENOMEM;
fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
@@ -293,9 +303,8 @@ int efi_set_variable(
assert(name);
assert(value || size == 0);
- if (asprintf(&p,
- "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+ p = efi_variable_path(vendor, name);
+ if (!p)
return -ENOMEM;
/* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect
@@ -772,7 +781,7 @@ int efi_loader_get_device_part_uuid(sd_id128_t *u) {
if (r < 0)
return r;
- if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
&parsed[4], &parsed[5], &parsed[6], &parsed[7],
&parsed[8], &parsed[9], &parsed[10], &parsed[11],
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index d8f18aae90..49d1b338fb 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -33,6 +33,7 @@ int efi_reboot_to_firmware_supported(void);
int efi_get_reboot_to_firmware(void);
int efi_set_reboot_to_firmware(bool value);
+char* efi_variable_path(sd_id128_t vendor, const char *name);
int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
diff --git a/src/shared/id128-print.c b/src/shared/id128-print.c
index 1b20b8f644..febe3635ba 100644
--- a/src/shared/id128-print.c
+++ b/src/shared/id128-print.c
@@ -33,7 +33,7 @@ int id128_pretty_print(sd_id128_t id, bool pretty) {
printf("As string:\n"
"%s" SD_ID128_FORMAT_STR "%s\n\n"
"As UUID:\n"
- "%s%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n\n"
+ "%s" SD_ID128_UUID_FORMAT_STR "%s\n\n"
"As %s macro:\n"
"%s#define MESSAGE_XYZ SD_ID128_MAKE(",
on, SD_ID128_FORMAT_VAL(id), off,
diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h
index bdf88ed53f..c5fbe0a4f1 100644
--- a/src/systemd/sd-id128.h
+++ b/src/systemd/sd-id128.h
@@ -63,6 +63,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
+/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
+#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+
#define SD_ID128_CONST_STR(x) \
((const char[SD_ID128_STRING_MAX]) { \
((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 8840788310..eea0765b7a 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
assert_se(streq(q, UUID_WALDI));
b = mfree(b);
- assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36);
+ assert_se(asprintf(&b, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36);
printf("waldi4: %s\n", b);
assert_se(streq(q, b));