• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 24319958878

12 Apr 2026 08:20PM UTC coverage: 72.107% (+1.6%) from 70.514%
24319958878

push

github

bluca
nss-systemd: fix off-by-one in nss_pack_group_record_shadow()

nss_count_strv() counts trailing NULL pointers in n. The pointer area
then used (n + 1), reserving one slot more than the size check
accounted for.

Drop the + 1 since n already includes the trailing NULLs, unlike the
non-shadow nss_pack_group_record() where n does not.

Fixes: https://github.com/systemd/systemd/issues/41591

0 of 1 new or added line in 1 file covered. (0.0%)

1275 existing lines in 56 files now uncovered.

319881 of 443617 relevant lines covered (72.11%)

1260063.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.06
/src/bootctl/bootctl.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/stat.h>
4

5
#include "sd-varlink.h"
6

7
#include "blockdev-util.h"
8
#include "boot-entry.h"
9
#include "bootctl.h"
10
#include "bootctl-cleanup.h"
11
#include "bootctl-install.h"
12
#include "bootctl-random-seed.h"
13
#include "bootctl-reboot-to-firmware.h"
14
#include "bootctl-set-efivar.h"
15
#include "bootctl-status.h"
16
#include "bootctl-uki.h"
17
#include "bootctl-unlink.h"
18
#include "build.h"
19
#include "devnum-util.h"
20
#include "dissect-image.h"
21
#include "efi-loader.h"
22
#include "efivars.h"
23
#include "escape.h"
24
#include "find-esp.h"
25
#include "format-table.h"
26
#include "image-policy.h"
27
#include "log.h"
28
#include "loop-util.h"
29
#include "main-func.h"
30
#include "mount-util.h"
31
#include "openssl-util.h"
32
#include "options.h"
33
#include "pager.h"
34
#include "parse-argument.h"
35
#include "path-util.h"
36
#include "pretty-print.h"
37
#include "string-table.h"
38
#include "string-util.h"
39
#include "strv.h"
40
#include "utf8.h"
41
#include "varlink-io.systemd.BootControl.h"
42
#include "varlink-util.h"
43
#include "verbs.h"
44
#include "virt.h"
45

46
static GracefulMode _arg_graceful = ARG_GRACEFUL_NO;
47

48
char *arg_esp_path = NULL;
49
char *arg_xbootldr_path = NULL;
50
bool arg_print_esp_path = false;
51
bool arg_print_dollar_boot_path = false;
52
bool arg_print_loader_path = false;
53
bool arg_print_stub_path = false;
54
unsigned arg_print_root_device = 0;
55
int arg_touch_variables = -1;
56
bool arg_install_random_seed = true;
57
PagerFlags arg_pager_flags = 0;
58
bool arg_quiet = false;
59
int arg_make_entry_directory = false; /* tri-state: < 0 for automatic logic */
60
sd_id128_t arg_machine_id = SD_ID128_NULL;
61
char *arg_install_layout = NULL;
62
BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
63
char *arg_entry_token = NULL;
64
sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
65
bool arg_arch_all = false;
66
char *arg_root = NULL;
67
char *arg_image = NULL;
68
InstallSource arg_install_source = INSTALL_SOURCE_AUTO;
69
char *arg_efi_boot_option_description = NULL;
70
bool arg_efi_boot_option_description_with_device = false;
71
bool arg_dry_run = false;
72
ImagePolicy *arg_image_policy = NULL;
73
bool arg_varlink = false;
74
bool arg_secure_boot_auto_enroll = false;
75
char *arg_certificate = NULL;
76
CertificateSourceType arg_certificate_source_type = OPENSSL_CERTIFICATE_SOURCE_FILE;
77
char *arg_certificate_source = NULL;
78
char *arg_private_key = NULL;
79
KeySourceType arg_private_key_source_type = OPENSSL_KEY_SOURCE_FILE;
80
char *arg_private_key_source = NULL;
81

82
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
298✔
83
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
298✔
84
STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep);
298✔
85
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
298✔
86
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
298✔
87
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
298✔
88
STATIC_DESTRUCTOR_REGISTER(arg_efi_boot_option_description, freep);
298✔
89
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
298✔
90
STATIC_DESTRUCTOR_REGISTER(arg_certificate, freep);
298✔
91
STATIC_DESTRUCTOR_REGISTER(arg_certificate_source, freep);
298✔
92
STATIC_DESTRUCTOR_REGISTER(arg_private_key, freep);
298✔
93
STATIC_DESTRUCTOR_REGISTER(arg_private_key_source, freep);
298✔
94

95
static const char* const install_source_table[_INSTALL_SOURCE_MAX] = {
96
        [INSTALL_SOURCE_IMAGE] = "image",
97
        [INSTALL_SOURCE_HOST]  = "host",
98
        [INSTALL_SOURCE_AUTO]  = "auto",
99
};
100

UNCOV
101
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(install_source, InstallSource);
×
102

103
int acquire_esp(
257✔
104
                int unprivileged_mode,
105
                bool graceful,
106
                uint32_t *ret_part,
107
                uint64_t *ret_pstart,
108
                uint64_t *ret_psize,
109
                sd_id128_t *ret_uuid,
110
                dev_t *ret_devid) {
111

112
        char *np;
257✔
113
        int r;
257✔
114

115
        /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
116
         * its own, except for ENOKEY (which is good, we want to show our own message in that case,
117
         * suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
118
         * we simply eat up the error here, so that --list and --status work too, without noise about
119
         * this). */
120

121
        r = find_esp_and_warn_full(arg_root, arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid, ret_devid);
257✔
122
        if (r == -ENOKEY) {
257✔
123
                if (graceful)
5✔
UNCOV
124
                        return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_INFO, r,
×
125
                                              "Couldn't find EFI system partition, skipping.");
126

127
                return log_error_errno(r,
5✔
128
                                       "Couldn't find EFI system partition. It is recommended to mount it to /boot/ or /efi/.\n"
129
                                       "Alternatively, use --esp-path= to specify path to mount point.");
130
        }
131
        if (r < 0)
252✔
132
                return r;
133

134
        free_and_replace(arg_esp_path, np);
251✔
135
        log_debug("Using EFI System Partition at %s.", arg_esp_path);
251✔
136

137
        return 0;
138
}
139

140
int acquire_xbootldr(
204✔
141
                int unprivileged_mode,
142
                sd_id128_t *ret_uuid,
143
                dev_t *ret_devid) {
144

145
        char *np;
204✔
146
        int r;
204✔
147

148
        r = find_xbootldr_and_warn_full(arg_root, arg_xbootldr_path, unprivileged_mode, &np, ret_uuid, ret_devid);
204✔
149
        if (r == -ENOKEY || path_equal(np, arg_esp_path)) {
204✔
150
                log_debug("Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
157✔
151
                arg_xbootldr_path = mfree(arg_xbootldr_path);
157✔
152

153
                if (ret_uuid)
157✔
154
                        *ret_uuid = SD_ID128_NULL;
15✔
155
                if (ret_devid)
157✔
156
                        *ret_devid = 0;
20✔
157
                return 0;
157✔
158
        }
159
        if (r < 0)
47✔
160
                return r;
161

162
        free_and_replace(arg_xbootldr_path, np);
46✔
163
        log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path);
46✔
164

165
        return 1;
166
}
167

168
static int print_loader_or_stub_path(void) {
6✔
169
        _cleanup_free_ char *p = NULL;
6✔
170
        sd_id128_t uuid;
6✔
171
        int r;
6✔
172

173
        if (arg_print_loader_path) {
6✔
174
                r = efi_loader_get_device_part_uuid(&uuid);
×
175
                if (r == -ENOENT)
×
176
                        return log_error_errno(r, "No loader partition UUID passed.");
×
177
                if (r < 0)
×
UNCOV
178
                        return log_error_errno(r, "Unable to determine loader partition UUID: %m");
×
179

180
                r = efi_get_variable_path(EFI_LOADER_VARIABLE_STR("LoaderImageIdentifier"), &p);
×
181
                if (r == -ENOENT)
×
182
                        return log_error_errno(r, "No loader EFI binary path passed.");
×
183
                if (r < 0)
×
UNCOV
184
                        return log_error_errno(r, "Unable to determine loader EFI binary path: %m");
×
185
        } else {
186
                assert(arg_print_stub_path);
6✔
187

188
                r = efi_stub_get_device_part_uuid(&uuid);
6✔
189
                if (r == -ENOENT)
6✔
UNCOV
190
                        return log_error_errno(r, "No stub partition UUID passed.");
×
191
                if (r < 0)
6✔
UNCOV
192
                        return log_error_errno(r, "Unable to determine stub partition UUID: %m");
×
193

194
                r = efi_get_variable_path(EFI_LOADER_VARIABLE_STR("StubImageIdentifier"), &p);
6✔
195
                if (r == -ENOENT)
6✔
UNCOV
196
                        return log_error_errno(r, "No stub EFI binary path passed.");
×
197
                if (r < 0)
6✔
UNCOV
198
                        return log_error_errno(r, "Unable to determine stub EFI binary path: %m");
×
199
        }
200

201
        sd_id128_t esp_uuid;
6✔
202
        r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false,
6✔
203
                        /* ret_part= */ NULL, /* ret_pstart= */ NULL, /* ret_psize= */ NULL,
204
                        &esp_uuid, /* ret_devid= */ NULL);
205
        if (r < 0)
6✔
206
                return r;
207

208
        const char *found_path = NULL;
6✔
209
        if (sd_id128_equal(esp_uuid, uuid))
6✔
210
                found_path = arg_esp_path;
6✔
211
        else if (arg_print_stub_path) { /* In case of the stub, also look for things in the xbootldr partition */
×
UNCOV
212
                sd_id128_t xbootldr_uuid;
×
213

214
                r = acquire_xbootldr(/* unprivileged_mode= */ false, &xbootldr_uuid, /* ret_devid= */ NULL);
×
215
                if (r < 0)
×
UNCOV
216
                        return r;
×
217

218
                if (sd_id128_equal(xbootldr_uuid, uuid))
×
UNCOV
219
                        found_path = arg_xbootldr_path;
×
220
        }
221

222
        if (!found_path)
6✔
UNCOV
223
                return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover partition " SD_ID128_FORMAT_STR " among mounted boot partitions.", SD_ID128_FORMAT_VAL(uuid));
×
224

225
        _cleanup_free_ char *j = path_join(found_path, p);
12✔
226
        if (!j)
6✔
UNCOV
227
                return log_oom();
×
228

229
        puts(j);
6✔
230
        return 0;
231
}
232

233
GracefulMode arg_graceful(void) {
290✔
234
        static bool chroot_checked = false;
290✔
235

236
        if (!chroot_checked && running_in_chroot() > 0) {
290✔
237
                if (_arg_graceful == ARG_GRACEFUL_NO)
×
UNCOV
238
                        log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Running in a chroot, enabling --graceful.");
×
239

UNCOV
240
                _arg_graceful = ARG_GRACEFUL_FORCE;
×
241
        }
242

243
        chroot_checked = true;
290✔
244

245
        return _arg_graceful;
290✔
246
}
247

248
static int help(void) {
3✔
249
        _cleanup_free_ char *link = NULL;
3✔
250
        int r;
3✔
251

252
        pager_open(arg_pager_flags);
3✔
253

254
        r = terminal_urlify_man("bootctl", "1", &link);
3✔
255
        if (r < 0)
3✔
UNCOV
256
                return log_oom();
×
257

258
        static const char *const verb_groups[] = {
3✔
259
                "Generic EFI Firmware/Boot Loader Commands",
260
                "Boot Loader Specification Commands",
261
                "Boot Loader Interface Commands",
262
                "systemd-boot Commands",
263
                "Kernel Image Commands",
264
        };
265

266
        static const char *const option_groups[] = {
3✔
267
                "Block Device Discovery Commands",
268
                "Options",
269
        };
270

271
        _cleanup_(table_unref_many) Table *verb_tables[ELEMENTSOF(verb_groups) + 1] = {};
3✔
272
        _cleanup_(table_unref_many) Table *option_tables[ELEMENTSOF(option_groups) + 1] = {};
3✔
273

274
        for (size_t i = 0; i < ELEMENTSOF(verb_groups); i++) {
18✔
275
                r = verbs_get_help_table_group(verb_groups[i], &verb_tables[i]);
15✔
276
                if (r < 0)
15✔
277
                        return r;
278
        }
279

280
        for (size_t i = 0; i < ELEMENTSOF(option_groups); i++) {
9✔
281
                r = option_parser_get_help_table_group(option_groups[i], &option_tables[i]);
6✔
282
                if (r < 0)
6✔
283
                        return r;
284
        }
285

286
        (void) table_sync_column_widths(0,
3✔
287
                                        verb_tables[0], verb_tables[1], verb_tables[2],
288
                                        verb_tables[3], verb_tables[4],
289
                                        option_tables[0], option_tables[1]);
290

291
        printf("%s [OPTIONS...] COMMAND ...\n"
6✔
292
               "\n%sControl EFI firmware boot settings and manage boot loader.%s\n",
293
               program_invocation_short_name,
294
               ansi_highlight(),
295
               ansi_normal());
296

297
        for (size_t i = 0; i < ELEMENTSOF(verb_groups); i++) {
18✔
298
                printf("\n%s%s:%s\n", ansi_underline(), verb_groups[i], ansi_normal());
45✔
299

300
                r = table_print_or_warn(verb_tables[i]);
15✔
301
                if (r < 0)
15✔
302
                        return r;
303
        }
304

305
        for (size_t i = 0; i < ELEMENTSOF(option_groups); i++) {
9✔
306
                printf("\n%s%s:%s\n", ansi_underline(), option_groups[i], ansi_normal());
18✔
307

308
                r = table_print_or_warn(option_tables[i]);
6✔
309
                if (r < 0)
6✔
310
                        return r;
311
        }
312

313
        printf("\nSee the %s for details.\n", link);
3✔
314
        return 0;
315
}
316

UNCOV
317
VERB_COMMON_HELP(help);
×
318

319
VERB_GROUP("Generic EFI Firmware/Boot Loader Commands");
320

321
VERB_SCOPE(, verb_status, "status", NULL, VERB_ANY, 1, VERB_DEFAULT,
322
           "Show status of installed boot loader and EFI variables");
323

324
VERB_SCOPE(, verb_reboot_to_firmware, "reboot-to-firmware", "[BOOL]", VERB_ANY, 2, 0,
325
           "Query or set reboot-to-firmware EFI flag");
326

327
VERB_GROUP("Boot Loader Specification Commands");
328

329
VERB_SCOPE_NOARG(, verb_list, "list",
330
           "List boot loader entries");
331

332
VERB_SCOPE(, verb_unlink, "unlink", "ID", 2, 2, 0,
333
           "Remove boot loader entry");
334

335
VERB_SCOPE_NOARG(, verb_cleanup, "cleanup",
336
           "Remove files in ESP not referenced in any boot entry");
337

338
VERB_GROUP("Boot Loader Interface Commands");
339

340
VERB_SCOPE(, verb_set_efivar, "set-default", "ID", 2, 2, 0,
341
           "Set default boot loader entry");
342

343
VERB_SCOPE(, verb_set_efivar, "set-oneshot", "ID", 2, 2, 0,
344
           "Set default boot loader entry, for next boot only");
345

346
VERB_SCOPE(, verb_set_efivar, "set-sysfail", "ID", 2, 2, 0,
347
           "Set boot loader entry used in case of a system failure");
348

349
VERB_SCOPE(, verb_set_efivar, "set-timeout", "SECONDS", 2, 2, 0,
350
           "Set the menu timeout");
351

352
VERB_SCOPE(, verb_set_efivar, "set-timeout-oneshot", "SECONDS", 2, 2, 0,
353
           "Set the menu timeout for the next boot only");
354

355
VERB_SCOPE(, verb_set_efivar, "set-preferred", "ID", 2, 2, 0,
356
           /* help= */ NULL);
357

358
VERB_GROUP("systemd-boot Commands");
359

360
VERB_SCOPE(, verb_install, "install", NULL, VERB_ANY, 1, 0,
361
           "Install systemd-boot to the ESP and EFI variables");
362

363
VERB_SCOPE(, verb_install, "update", NULL, VERB_ANY, 1, 0,
364
           "Update systemd-boot in the ESP and EFI variables");
365

366
VERB_SCOPE_NOARG(, verb_remove, "remove",
367
           "Remove systemd-boot from the ESP and EFI variables");
368

369
VERB_SCOPE_NOARG(, verb_is_installed, "is-installed",
370
           "Test whether systemd-boot is installed in the ESP");
371

372
VERB_SCOPE_NOARG(, verb_random_seed, "random-seed",
373
           "Initialize or refresh random seed in ESP and EFI variables");
374

375
VERB_GROUP("Kernel Image Commands");
376

377
VERB_SCOPE(, verb_kernel_identify, "kernel-identify", "KERNEL-IMAGE", 2, 2, 0,
378
           "Identify kernel image type");
379

380
VERB_SCOPE(, verb_kernel_inspect, "kernel-inspect", "KERNEL-IMAGE", 2, 2, 0,
381
           "Prints details about the kernel image");
382

383
static int parse_argv(int argc, char *argv[], char ***ret_args) {
298✔
384
        int r;
298✔
385

386
        assert(argc >= 0);
298✔
387
        assert(argv);
298✔
388

389
        OptionParser state = { argc, argv };
298✔
390
        const char *arg;
298✔
391

392
        FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
1,327✔
393
                switch (c) {
439✔
394

395
                OPTION_GROUP("Block Device Discovery Commands"):
396
                        break;
397

398
                OPTION('p', "print-esp-path", NULL, "Print path to the EFI System Partition mount point"): {}
47✔
399
                OPTION_LONG("print-path", NULL, /* help= */ NULL):  /* Compatibility alias */
47✔
400
                        arg_print_esp_path = true;
47✔
401
                        break;
47✔
402

403
                OPTION('x', "print-boot-path", NULL, "Print path to the $BOOT partition mount point"):
8✔
404
                        arg_print_dollar_boot_path = true;
8✔
405
                        break;
8✔
406

UNCOV
407
                OPTION_LONG("print-loader-path", NULL, "Print path to currently booted boot loader binary"):
×
UNCOV
408
                        arg_print_loader_path = true;
×
UNCOV
409
                        break;
×
410

411
                OPTION_LONG("print-stub-path", NULL, "Print path to currently booted unified kernel binary"):
6✔
412
                        arg_print_stub_path = true;
6✔
413
                        break;
6✔
414

415
                OPTION('R', "print-root-device", NULL,
7✔
416
                       "Print path to the block device node backing the root file system"
417
                       " (returns e.g. /dev/nvme0n1p5)"): {}
7✔
418
                OPTION_HELP_VERBATIM("-RR",
7✔
419
                                     "Print path to the whole disk block device node backing the root FS"
420
                                     " (returns e.g. /dev/nvme0n1)"):
421
                        arg_print_root_device++;
7✔
422
                        break;
7✔
423

424
                OPTION_GROUP("Options"):
425
                        break;
426

427
                OPTION_COMMON_HELP:
3✔
428
                        return help();
3✔
429

430
                OPTION_COMMON_VERSION:
3✔
431
                        return version();
3✔
432

433
                OPTION_LONG("esp-path", "PATH", "Path to the EFI System Partition (ESP)"): {}
3✔
434
                OPTION_LONG("path", "PATH", /* help= */ NULL):  /* Compatibility alias */
3✔
435
                        r = free_and_strdup(&arg_esp_path, arg);
3✔
436
                        if (r < 0)
3✔
UNCOV
437
                                return log_oom();
×
438
                        break;
439

440
                OPTION_LONG("boot-path", "PATH", "Path to the $BOOT partition"):
3✔
441
                        r = free_and_strdup(&arg_xbootldr_path, arg);
3✔
442
                        if (r < 0)
3✔
UNCOV
443
                                return log_oom();
×
444
                        break;
445

446
                OPTION_LONG("root", "PATH", "Operate on an alternate filesystem root"):
34✔
447
                        r = parse_path_argument(arg, /* suppress_root= */ true, &arg_root);
34✔
448
                        if (r < 0)
34✔
449
                                return r;
450
                        break;
451

452
                OPTION_LONG("image", "PATH", "Operate on disk image as filesystem root"):
29✔
453
                        r = parse_path_argument(arg, /* suppress_root= */ false, &arg_image);
29✔
454
                        if (r < 0)
29✔
455
                                return r;
456
                        break;
457

UNCOV
458
                OPTION_LONG("image-policy", "POLICY", "Specify disk image dissection policy"):
×
UNCOV
459
                        r = parse_image_policy_argument(arg, &arg_image_policy);
×
UNCOV
460
                        if (r < 0)
×
461
                                return r;
462
                        break;
463

UNCOV
464
                OPTION_LONG("install-source", "SOURCE",
×
465
                            "Where to pick files when using --root=/--image= (auto, image, host)"): {
UNCOV
466
                        InstallSource is = install_source_from_string(arg);
×
UNCOV
467
                        if (is < 0)
×
468
                                return log_error_errno(is, "Unexpected parameter for --install-source=: %s", arg);
×
469

470
                        arg_install_source = is;
×
UNCOV
471
                        break;
×
472
                }
473

474
                OPTION_LONG("variables", "BOOL", "Whether to modify EFI variables"):
119✔
475
                        r = parse_tristate_argument_with_auto("--variables=", arg, &arg_touch_variables);
119✔
476
                        if (r < 0)
119✔
477
                                return r;
478
#if !ENABLE_EFI
479
                        if (arg_touch_variables > 0)
480
                                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
481
                                                       "Compiled without support for EFI, --variables=%s cannot be specified.", arg);
482
#endif
483
                        break;
484

UNCOV
485
                OPTION_LONG("no-variables", NULL, /* help= */ NULL):  /* Compatibility alias */
×
UNCOV
486
                        arg_touch_variables = false;
×
UNCOV
487
                        break;
×
488

UNCOV
489
                OPTION_LONG("random-seed", "BOOL", "Whether to create random-seed file during install"):
×
UNCOV
490
                        r = parse_boolean_argument("--random-seed=", arg, &arg_install_random_seed);
×
491
                        if (r < 0)
×
492
                                return r;
493
                        break;
494

UNCOV
495
                OPTION_COMMON_NO_PAGER:
×
UNCOV
496
                        arg_pager_flags |= PAGER_DISABLE;
×
UNCOV
497
                        break;
×
498

499
                OPTION_LONG("graceful", NULL,
137✔
500
                            "Don't fail when the ESP cannot be found or EFI variables cannot be written"):
501
                        _arg_graceful = ARG_GRACEFUL_YES;
137✔
502
                        break;
137✔
503

504
                OPTION('q', "quiet", NULL, "Suppress output"):
6✔
505
                        arg_quiet = true;
6✔
506
                        break;
6✔
507

UNCOV
508
                OPTION_LONG("entry-token", "TOKEN",
×
509
                            "Entry token to use for this installation"
510
                            " (machine-id, os-id, os-image-id, auto, literal:…)"):
UNCOV
511
                        r = parse_boot_entry_token_type(arg, &arg_entry_token_type, &arg_entry_token);
×
UNCOV
512
                        if (r < 0)
×
513
                                return r;
514
                        break;
515

516
                OPTION_LONG("make-entry-directory", "yes|no|auto", "Create $BOOT/ENTRY-TOKEN/ directory"): {}
13✔
517
                OPTION_LONG("make-machine-id-directory", "BOOL", /* help= */ NULL):  /* Compatibility alias */
13✔
518
                        if (streq(arg, "auto"))  /* retained for backwards compatibility */
13✔
519
                                arg_make_entry_directory = -1; /* yes if machine-id is permanent */
×
520
                        else {
521
                                r = parse_boolean_argument("--make-entry-directory=", arg, NULL);
13✔
522
                                if (r < 0)
13✔
523
                                        return r;
524

525
                                arg_make_entry_directory = r;
13✔
526
                        }
527
                        break;
528

529
                OPTION_COMMON_JSON:
6✔
530
                        r = parse_json_argument(arg, &arg_json_format_flags);
6✔
531
                        if (r <= 0)
6✔
532
                                return r;
533
                        break;
534

535
                OPTION_LONG("all-architectures", NULL, "Install all supported EFI architectures"):
12✔
536
                        arg_arch_all = true;
12✔
537
                        break;
12✔
538

UNCOV
539
                OPTION_LONG("efi-boot-option-description", "DESCRIPTION",
×
540
                            "Description of the entry in the boot option list"):
UNCOV
541
                        if (isempty(arg) || !(string_is_safe(arg) && utf8_is_valid(arg))) {
×
UNCOV
542
                                _cleanup_free_ char *escaped = cescape(arg);
×
UNCOV
543
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
544
                                                       "Invalid --efi-boot-option-description=: %s", strna(escaped));
545
                        }
UNCOV
546
                        if (strlen(arg) > EFI_BOOT_OPTION_DESCRIPTION_MAX)
×
UNCOV
547
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
548
                                                       "--efi-boot-option-description= too long: %zu > %zu",
549
                                                       strlen(arg), EFI_BOOT_OPTION_DESCRIPTION_MAX);
UNCOV
550
                        r = free_and_strdup_warn(&arg_efi_boot_option_description, arg);
×
UNCOV
551
                        if (r < 0)
×
552
                                return r;
553
                        break;
554

UNCOV
555
                OPTION_LONG("efi-boot-option-description-with-device", "BOOL",
×
556
                            "Suffix description with disk vendor/model/serial"):
UNCOV
557
                        r = parse_boolean_argument("--efi-boot-option-description-with-device=", arg,
×
558
                                                   &arg_efi_boot_option_description_with_device);
UNCOV
559
                        if (r < 0)
×
560
                                return r;
561
                        break;
562

UNCOV
563
                OPTION_LONG("dry-run", NULL, "Dry run (unlink and cleanup)"):
×
564
                        arg_dry_run = true;
×
565
                        break;
×
566

567
                OPTION_LONG("secure-boot-auto-enroll", "BOOL", "Set up secure boot auto-enrollment"):
1✔
568
                        r = parse_boolean_argument("--secure-boot-auto-enroll=", arg,
1✔
569
                                                   &arg_secure_boot_auto_enroll);
570
                        if (r < 0)
1✔
571
                                return r;
572
                        break;
573

574
                OPTION_LONG("private-key", "PATH|URI",
1✔
575
                            "Private key for Secure Boot auto-enrollment"):
576
                        r = free_and_strdup_warn(&arg_private_key, arg);
1✔
577
                        if (r < 0)
1✔
578
                                return r;
579
                        break;
580

581
                OPTION_LONG("private-key-source", "SOURCE",
×
582
                            "Specify how to use the private key "
583
                            "(file, provider:PROVIDER, engine:ENGINE)"):
UNCOV
584
                        r = parse_openssl_key_source_argument(arg,
×
585
                                                              &arg_private_key_source,
586
                                                              &arg_private_key_source_type);
587
                        if (r < 0)
×
588
                                return r;
589
                        break;
590

591
                OPTION_LONG("certificate", "PATH|URI",
1✔
592
                            "PEM certificate to use when setting up Secure Boot auto-enrollment, "
593
                            "or a provider specific designation if --certificate-source= is used"):
594
                        r = free_and_strdup_warn(&arg_certificate, arg);
1✔
595
                        if (r < 0)
1✔
596
                                return r;
597
                        break;
598

UNCOV
599
                OPTION_LONG("certificate-source", "SOURCE",
×
600
                            "Specify how to interpret the certificate from --certificate=. "
601
                            "Allows the certificate to be loaded from an OpenSSL provider "
602
                            "(file, provider:PROVIDER)"):
603
                        r = parse_openssl_certificate_source_argument(arg,
×
604
                                                                      &arg_certificate_source,
605
                                                                      &arg_certificate_source_type);
UNCOV
606
                        if (r < 0)
×
607
                                return r;
608
                        break;
609
                }
610

611
        char **args = option_parser_get_args(&state);
292✔
612

613
        if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) + arg_print_loader_path + arg_print_stub_path > 1)
292✔
UNCOV
614
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
615
                                                       "--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R, --print-loader-path, --print-stub-path cannot be combined.");
616

617
        if ((arg_root || arg_image) && args[0] && !STR_IN_SET(args[0], "status", "list",
292✔
618
                        "install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
619
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
620
                                       "Options --root= and --image= are not supported with verb %s.",
621
                                       args[0]);
622

623
        if (arg_root && arg_image)
292✔
UNCOV
624
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
×
625

626
        if (arg_install_source != INSTALL_SOURCE_AUTO && !arg_root && !arg_image)
292✔
UNCOV
627
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--install-from-host is only supported with --root= or --image=.");
×
628

629
        if (arg_dry_run && args[0] && !STR_IN_SET(args[0], "unlink", "cleanup"))
292✔
630
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--dry-run is only supported with --unlink or --cleanup");
×
631

632
        if (arg_secure_boot_auto_enroll) {
292✔
633
#if HAVE_OPENSSL
634
                if (!arg_certificate)
1✔
635
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Secure boot auto-enrollment requested but no certificate provided.");
×
636

637
                if (!arg_private_key)
1✔
UNCOV
638
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Secure boot auto-enrollment requested but no private key provided.");
×
639
#else
640
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Secure boot auto-enrollment requested but OpenSSL support is disabled.");
641
#endif
642
        }
643

644
        r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
292✔
645
        if (r < 0)
292✔
UNCOV
646
                return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
×
647
        if (r > 0) {
292✔
648
                arg_varlink = true;
14✔
649
                arg_pager_flags |= PAGER_DISABLE;
14✔
650
        }
651

652
        *ret_args = args;
292✔
653
        return 1;
292✔
654
}
655

656
static int vl_server(void) {
14✔
657
        _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
14✔
658
        int r;
14✔
659

660
        /* Invocation as Varlink service */
661

662
        r = varlink_server_new(
14✔
663
                        &varlink_server,
664
                        SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT,
665
                        /* userdata= */ NULL);
666
        if (r < 0)
14✔
667
                return log_error_errno(r, "Failed to allocate Varlink server: %m");
×
668

669
        r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_BootControl);
14✔
670
        if (r < 0)
14✔
UNCOV
671
                return log_error_errno(r, "Failed to add Varlink interface: %m");
×
672

673
        r = sd_varlink_server_bind_method_many(
14✔
674
                        varlink_server,
675
                        "io.systemd.BootControl.ListBootEntries",     vl_method_list_boot_entries,
676
                        "io.systemd.BootControl.SetRebootToFirmware", vl_method_set_reboot_to_firmware,
677
                        "io.systemd.BootControl.GetRebootToFirmware", vl_method_get_reboot_to_firmware,
678
                        "io.systemd.BootControl.Install",             vl_method_install);
679
        if (r < 0)
14✔
UNCOV
680
                return log_error_errno(r, "Failed to bind Varlink methods: %m");
×
681

682
        r = sd_varlink_server_loop_auto(varlink_server);
14✔
683
        if (r < 0)
14✔
UNCOV
684
                return log_error_errno(r, "Failed to run Varlink event loop: %m");
×
685

686
        return 0;
687
}
688

689
static int run(int argc, char *argv[]) {
298✔
690
        _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
298✔
691
        _cleanup_(umount_and_freep) char *mounted_dir = NULL;
298✔
692
        int r;
298✔
693

694
        log_setup();
298✔
695

696
        char **args = NULL;
298✔
697
        r = parse_argv(argc, argv, &args);
298✔
698
        if (r <= 0)
298✔
699
                return r;
700

701
        if (arg_varlink)
292✔
702
                return vl_server();
14✔
703

704
        if (arg_print_root_device > 0) {
278✔
705
                _cleanup_free_ char *path = NULL;
5✔
706
                dev_t devno;
5✔
707

708
                r = blockdev_get_root(LOG_ERR, &devno);
5✔
709
                if (r < 0)
5✔
710
                        return r;
711
                if (r == 0) {
5✔
UNCOV
712
                        log_error("Root file system not backed by a (single) whole block device.");
×
UNCOV
713
                        return 80; /* some recognizable error code */
×
714
                }
715

716
                if (arg_print_root_device > 1) {
5✔
717
                        r = block_get_whole_disk(devno, &devno);
2✔
718
                        if (r < 0)
2✔
UNCOV
719
                                log_debug_errno(r, "Unable to find whole block device for root block device, ignoring: %m");
×
720
                }
721

722
                r = device_path_make_canonical(S_IFBLK, devno, &path);
5✔
723
                if (r < 0)
5✔
UNCOV
724
                        return log_error_errno(r,
×
725
                                               "Failed to format canonical device path for devno '" DEVNUM_FORMAT_STR "': %m",
726
                                               DEVNUM_FORMAT_VAL(devno));
727

728
                puts(path);
5✔
729
                return 0;
730
        }
731

732
        if (arg_print_loader_path || arg_print_stub_path)
273✔
733
                return print_loader_or_stub_path();
6✔
734

735
        /* Open up and mount the image */
736
        if (arg_image) {
267✔
737
                assert(!arg_root);
26✔
738

739
                r = mount_image_privately_interactively(
26✔
740
                                arg_image,
741
                                arg_image_policy,
742
                                DISSECT_IMAGE_GENERIC_ROOT |
743
                                DISSECT_IMAGE_USR_NO_ROOT |
744
                                DISSECT_IMAGE_RELAX_VAR_CHECK |
745
                                DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
746
                                &mounted_dir,
747
                                /* ret_dir_fd= */ NULL,
748
                                &loop_device);
749
                if (r < 0)
26✔
750
                        return r;
751

752
                arg_root = strdup(mounted_dir);
26✔
753
                if (!arg_root)
26✔
UNCOV
754
                        return log_oom();
×
755
        }
756

757
        return dispatch_verb_with_args(args, NULL);
267✔
758
}
759

760
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
298✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc