Skip to content

Commit 3b21fd0

Browse files
authored
Merge pull request #12219 from keszybz/bootctl-check-entries
bootctl: check entries when showing them
2 parents 1e5d2d6 + cce9457 commit 3b21fd0

File tree

12 files changed

+101
-52
lines changed

12 files changed

+101
-52
lines changed

TODO

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,9 +686,7 @@ Features:
686686
- honor timezone efi variables for default timezone selection (if there are any?)
687687
- change bootctl to be backed by systemd-bootd to control temporary and persistent default boot goal plus efi variables
688688
* bootctl
689-
- verify that the files boot entries point to exist
690689
- recognize the case when not booted on EFI
691-
- specify paths for boot entries
692690

693691
* maybe do not install [email protected] symlink in /etc but in /usr?
694692

man/rules/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ manpages = [
101101
'SD_ID128_MAKE',
102102
'SD_ID128_MAKE_STR',
103103
'SD_ID128_NULL',
104+
'SD_ID128_UUID_FORMAT_STR',
104105
'sd_id128_equal',
105106
'sd_id128_is_null',
106107
'sd_id128_t'],

man/sd-id128.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<refname>SD_ID128_NULL</refname>
2525
<refname>SD_ID128_CONST_STR</refname>
2626
<refname>SD_ID128_FORMAT_STR</refname>
27+
<refname>SD_ID128_UUID_FORMAT_STR</refname>
2728
<refname>SD_ID128_FORMAT_VAL</refname>
2829
<refname>sd_id128_equal</refname>
2930
<refname>sd_id128_is_null</refname>
@@ -119,6 +120,11 @@ int main(int argc, char **argv) {
119120
return 0;
120121
}</programlisting>
121122

123+
<para><function>SD_ID128_UUID_FORMAT_STR()</function> is similar to
124+
<function>SD_ID128_FORMAT_STR()</function> but includes separating hyphens to conform to the
125+
"<ulink url="https://en.wikipedia.org/wiki/Universally_unique_identifier#Format">canonical representation</ulink>".
126+
</para>
127+
122128
<para>Use <function>sd_id128_equal()</function> to compare two 128-bit IDs:</para>
123129

124130
<programlisting>int main(int argc, char *argv[]) {

src/boot/bootctl.c

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
220220

221221
printf(" ESP: %s", esp_path);
222222
if (!sd_id128_is_null(partition))
223-
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));
223+
printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")", SD_ID128_FORMAT_VAL(partition));
224224
printf("\n");
225225

226226
r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
@@ -262,7 +262,8 @@ static int print_efi_option(uint16_t id, bool in_order) {
262262
printf(" Title: %s%s%s\n", ansi_highlight(), strna(title), ansi_normal());
263263
printf(" ID: 0x%04X\n", id);
264264
printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
265-
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));
265+
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
266+
SD_ID128_FORMAT_VAL(partition));
266267
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path);
267268
printf("\n");
268269

@@ -309,38 +310,72 @@ static int status_variables(void) {
309310
return 0;
310311
}
311312

313+
static int boot_entry_file_check(const char *root, const char *p) {
314+
_cleanup_free_ char *path;
315+
316+
path = path_join(root, p);
317+
if (!path)
318+
return log_oom();
319+
320+
if (access(path, F_OK) < 0)
321+
return -errno;
322+
323+
return 0;
324+
}
325+
326+
static void boot_entry_file_list(const char *field, const char *root, const char *p, int *ret_status) {
327+
int status = boot_entry_file_check(root, p);
328+
329+
printf("%13s%s", strempty(field), field ? ":" : " ");
330+
if (status < 0) {
331+
errno = -status;
332+
printf("%s%s%s (%m)\n", ansi_highlight_red(), p, ansi_normal());
333+
} else
334+
printf("%s\n", p);
335+
336+
if (*ret_status == 0 && status < 0)
337+
*ret_status = status;
338+
}
339+
312340
static int boot_entry_show(const BootEntry *e, bool show_as_default) {
341+
int status = 0;
342+
343+
/* Returns 0 on success, negative on processing error, and positive if something is wrong with the
344+
boot entry itself. */
345+
313346
assert(e);
314347

315-
printf(" title: %s%s%s%s%s%s\n"
316-
" type: %s\n",
317-
ansi_highlight(),
318-
boot_entry_title(e),
319-
ansi_normal(),
320-
ansi_highlight_green(),
321-
show_as_default ? " (default)" : "",
322-
ansi_normal(),
323-
boot_entry_type_to_string(e->type));
348+
printf(" title: %s%s%s" "%s%s%s\n",
349+
ansi_highlight(), boot_entry_title(e), ansi_normal(),
350+
ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal());
324351

325352
if (e->id)
326353
printf(" id: %s\n", e->id);
354+
if (e->path) {
355+
_cleanup_free_ char *link = NULL;
356+
357+
/* Let's urlify the link to make it easy to view in an editor, but only if it is a text
358+
* file. Unified images are binary ELFs, and EFI variables are not pure text either. */
359+
if (e->type == BOOT_ENTRY_CONF)
360+
(void) terminal_urlify_path(e->path, NULL, &link);
361+
362+
printf(" source: %s\n", link ?: e->path);
363+
}
327364
if (e->version)
328365
printf(" version: %s\n", e->version);
329366
if (e->machine_id)
330367
printf(" machine-id: %s\n", e->machine_id);
331368
if (e->architecture)
332369
printf(" architecture: %s\n", e->architecture);
333370
if (e->kernel)
334-
printf(" linux: %s\n", e->kernel);
335-
if (!strv_isempty(e->initrd)) {
336-
_cleanup_free_ char *t;
337-
338-
t = strv_join(e->initrd, " ");
339-
if (!t)
340-
return log_oom();
341-
342-
printf(" initrd: %s\n", t);
343-
}
371+
boot_entry_file_list("linux", e->root, e->kernel, &status);
372+
373+
char **s;
374+
STRV_FOREACH(s, e->initrd)
375+
boot_entry_file_list(s == e->initrd ? "initrd" : NULL,
376+
e->root,
377+
*s,
378+
&status);
344379
if (!strv_isempty(e->options)) {
345380
_cleanup_free_ char *t;
346381

@@ -351,9 +386,9 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
351386
printf(" options: %s\n", t);
352387
}
353388
if (e->device_tree)
354-
printf(" devicetree: %s\n", e->device_tree);
389+
boot_entry_file_list("devicetree", e->root, e->device_tree, &status);
355390

356-
return 0;
391+
return -status;
357392
}
358393

359394
static int status_entries(
@@ -380,7 +415,8 @@ static int status_entries(
380415
printf("Boot Loader Entries:\n"
381416
" $BOOT: %s", dollar_boot_path);
382417
if (!sd_id128_is_null(dollar_boot_partition_uuid))
383-
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));
418+
printf(" (/dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR ")",
419+
SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
384420
printf("\n\n");
385421

386422
r = boot_entries_load_config(esp_path, xbootldr_path, &config);
@@ -392,7 +428,11 @@ static int status_entries(
392428
else {
393429
printf("Default Boot Loader Entry:\n");
394430

395-
boot_entry_show(config.entries + config.default_entry, false);
431+
r = boot_entry_show(config.entries + config.default_entry, false);
432+
if (r > 0)
433+
/* < 0 is already logged by the function itself, let's just emit an extra warning if
434+
the default entry is broken */
435+
printf("\nWARNING: default boot entry is broken\n");
396436
}
397437

398438
return 0;
@@ -1150,7 +1190,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
11501190
if (stub)
11511191
printf(" Stub: %s\n", stub);
11521192
if (!sd_id128_is_null(loader_part_uuid))
1153-
printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1193+
printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
11541194
SD_ID128_FORMAT_VAL(loader_part_uuid));
11551195
else
11561196
printf(" ESP: n/a\n");

src/libsystemd/sd-id128/id128-util.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
1212

13-
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
14-
#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
15-
1613
bool id128_is_valid(const char *s) _pure_;
1714

1815
typedef enum Id128Format {

src/shared/bootspec.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
755755
n_allocated = config->n_entries;
756756

757757
STRV_FOREACH(i, found_by_loader) {
758-
_cleanup_free_ char *c = NULL, *t = NULL;
758+
_cleanup_free_ char *c = NULL, *t = NULL, *p = NULL;
759759
char **a, **b;
760760

761761
if (boot_config_has_entry(config, *i))
@@ -776,13 +776,18 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
776776
break;
777777
}
778778

779+
p = efi_variable_path(EFI_VENDOR_LOADER, "LoaderEntries");
780+
if (!p)
781+
return log_oom();
782+
779783
if (!GREEDY_REALLOC0(config->entries, n_allocated, config->n_entries + 1))
780784
return log_oom();
781785

782786
config->entries[config->n_entries++] = (BootEntry) {
783787
.type = BOOT_ENTRY_LOADER,
784788
.id = TAKE_PTR(c),
785789
.title = TAKE_PTR(t),
790+
.path = TAKE_PTR(p),
786791
};
787792
}
788793

@@ -1418,11 +1423,3 @@ int find_xbootldr_and_warn(
14181423

14191424
return 0;
14201425
}
1421-
1422-
static const char* const boot_entry_type_table[_BOOT_ENTRY_MAX] = {
1423-
[BOOT_ENTRY_CONF] = "conf",
1424-
[BOOT_ENTRY_UNIFIED] = "unified",
1425-
[BOOT_ENTRY_LOADER] = "loader",
1426-
};
1427-
1428-
DEFINE_STRING_TABLE_LOOKUP(boot_entry_type, BootEntryType);

src/shared/bootspec.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,3 @@ static inline const char* boot_entry_title(const BootEntry *entry) {
7979

8080
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);
8181
int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid);
82-
83-
const char* boot_entry_type_to_string(BootEntryType t) _const_;
84-
BootEntryType boot_entry_type_from_string(const char *s) _pure_;

src/shared/efivars.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,17 @@ int efi_set_reboot_to_firmware(bool value) {
193193
return 0;
194194
}
195195

196+
char* efi_variable_path(sd_id128_t vendor, const char *name) {
197+
char *p;
198+
199+
if (asprintf(&p,
200+
"/sys/firmware/efi/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
201+
name, SD_ID128_FORMAT_VAL(vendor)) < 0)
202+
return NULL;
203+
204+
return p;
205+
}
206+
196207
int efi_get_variable(
197208
sd_id128_t vendor,
198209
const char *name,
@@ -211,9 +222,8 @@ int efi_get_variable(
211222
assert(value);
212223
assert(size);
213224

214-
if (asprintf(&p,
215-
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
216-
name, SD_ID128_FORMAT_VAL(vendor)) < 0)
225+
p = efi_variable_path(vendor, name);
226+
if (!p)
217227
return -ENOMEM;
218228

219229
fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
@@ -293,9 +303,8 @@ int efi_set_variable(
293303
assert(name);
294304
assert(value || size == 0);
295305

296-
if (asprintf(&p,
297-
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
298-
name, SD_ID128_FORMAT_VAL(vendor)) < 0)
306+
p = efi_variable_path(vendor, name);
307+
if (!p)
299308
return -ENOMEM;
300309

301310
/* 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) {
772781
if (r < 0)
773782
return r;
774783

775-
if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
784+
if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
776785
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
777786
&parsed[4], &parsed[5], &parsed[6], &parsed[7],
778787
&parsed[8], &parsed[9], &parsed[10], &parsed[11],

src/shared/efivars.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ int efi_reboot_to_firmware_supported(void);
3333
int efi_get_reboot_to_firmware(void);
3434
int efi_set_reboot_to_firmware(bool value);
3535

36+
char* efi_variable_path(sd_id128_t vendor, const char *name);
3637
int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
3738
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
3839
int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);

src/shared/id128-print.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ int id128_pretty_print(sd_id128_t id, bool pretty) {
3333
printf("As string:\n"
3434
"%s" SD_ID128_FORMAT_STR "%s\n\n"
3535
"As UUID:\n"
36-
"%s%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n\n"
36+
"%s" SD_ID128_UUID_FORMAT_STR "%s\n\n"
3737
"As %s macro:\n"
3838
"%s#define MESSAGE_XYZ SD_ID128_MAKE(",
3939
on, SD_ID128_FORMAT_VAL(id), off,

src/systemd/sd-id128.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
6363
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
6464
#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]
6565

66+
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
67+
#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
68+
6669
#define SD_ID128_CONST_STR(x) \
6770
((const char[SD_ID128_STRING_MAX]) { \
6871
((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \

src/test/test-id128.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
5252
assert_se(streq(q, UUID_WALDI));
5353

5454
b = mfree(b);
55-
assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36);
55+
assert_se(asprintf(&b, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36);
5656
printf("waldi4: %s\n", b);
5757
assert_se(streq(q, b));
5858

0 commit comments

Comments
 (0)