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

systemd / systemd / 23966986054

03 Apr 2026 09:22PM UTC coverage: 72.107% (-0.3%) from 72.362%
23966986054

push

github

daandemeyer
fd-util: Add missing assert()

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

7891 existing lines in 120 files now uncovered.

318256 of 441368 relevant lines covered (72.11%)

1186882.96 hits per line

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

0.0
/src/kernel-install/kernel-install.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <getopt.h>
4
#include <stdlib.h>
5
#include <sys/utsname.h>
6
#include <unistd.h>
7

8
#include "argv-util.h"
9
#include "boot-entry.h"
10
#include "bootspec.h"
11
#include "build.h"
12
#include "chase.h"
13
#include "conf-files.h"
14
#include "dirent-util.h"
15
#include "dissect-image.h"
16
#include "env-file.h"
17
#include "env-util.h"
18
#include "exec-util.h"
19
#include "extract-word.h"
20
#include "fd-util.h"
21
#include "fileio.h"
22
#include "find-esp.h"
23
#include "format-table.h"
24
#include "fs-util.h"
25
#include "id128-util.h"
26
#include "image-policy.h"
27
#include "kernel-config.h"
28
#include "kernel-image.h"
29
#include "loop-util.h"
30
#include "main-func.h"
31
#include "mount-util.h"
32
#include "parse-argument.h"
33
#include "path-util.h"
34
#include "pretty-print.h"
35
#include "recurse-dir.h"
36
#include "rm-rf.h"
37
#include "stat-util.h"
38
#include "string-table.h"
39
#include "string-util.h"
40
#include "strv.h"
41
#include "tmpfile-util.h"
42
#include "verbs.h"
43

44
static bool arg_verbose = false;
45
static char *arg_esp_path = NULL;
46
static char *arg_xbootldr_path = NULL;
47
static int arg_make_entry_directory = -1; /* tristate */
48
static PagerFlags arg_pager_flags = 0;
49
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
50
static char *arg_root = NULL;
51
static char *arg_image = NULL;
52
static ImagePolicy *arg_image_policy = NULL;
53
static bool arg_legend = true;
54
static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
55
static char *arg_entry_token = NULL;
56
static BootEntryType arg_boot_entry_type = _BOOT_ENTRY_TYPE_INVALID;
57

58
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
×
59
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
×
60
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
×
61
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
×
62
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
×
63
STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep);
×
64

65
typedef enum Action {
66
        ACTION_ADD,
67
        ACTION_REMOVE,
68
        ACTION_INSPECT,
69
        _ACTION_MAX,
70
        _ACTION_INVALID = -EINVAL,
71
} Action;
72

73
typedef enum Layout {
74
        LAYOUT_AUTO,
75
        LAYOUT_UKI,
76
        LAYOUT_BLS,
77
        LAYOUT_OTHER,
78
        _LAYOUT_MAX,
79
        _LAYOUT_INVALID = -EINVAL,
80
} Layout;
81

82
static const char * const layout_table[_LAYOUT_MAX] = {
83
        [LAYOUT_AUTO]  = "auto",
84
        [LAYOUT_UKI]   = "uki",
85
        [LAYOUT_BLS]   = "bls",
86
        [LAYOUT_OTHER] = "other",
87
};
88

89
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(layout, Layout);
×
90

91
typedef struct Context {
92
        int rfd;
93
        Action action;
94
        sd_id128_t machine_id;
95
        bool machine_id_is_random;
96
        BootEntryType entry_type;
97
        KernelImageType kernel_image_type;
98
        Layout layout;
99
        char *layout_other;
100
        char *conf_root;
101
        char *boot_root;
102
        BootEntryTokenType entry_token_type;
103
        char *entry_token;
104
        char *entry_dir;
105
        char *version;
106
        char *kernel;
107
        char **initrds;
108
        char *initrd_generator;
109
        char *uki_generator;
110
        char *staging_area;
111
        char **plugins;
112
        char **argv;
113
        char **envp;
114
} Context;
115

116
#define CONTEXT_NULL                                                    \
117
        (Context) {                                                     \
118
                .rfd = XAT_FDROOT,                                      \
119
                .action = _ACTION_INVALID,                              \
120
                .kernel_image_type = _KERNEL_IMAGE_TYPE_INVALID,        \
121
                .layout = _LAYOUT_INVALID,                              \
122
                .entry_type = _BOOT_ENTRY_TYPE_INVALID,                 \
123
                .entry_token_type = _BOOT_ENTRY_TOKEN_TYPE_INVALID,     \
124
        }
125

126
static void context_done(Context *c) {
×
127
        assert(c);
×
128

129
        free(c->layout_other);
×
130
        free(c->conf_root);
×
131
        free(c->boot_root);
×
132
        free(c->entry_token);
×
133
        free(c->entry_dir);
×
134
        free(c->version);
×
135
        free(c->kernel);
×
136
        strv_free(c->initrds);
×
137
        free(c->initrd_generator);
×
138
        free(c->uki_generator);
×
139
        if (c->action == ACTION_INSPECT)
×
140
                free(c->staging_area);
×
141
        else
142
                rm_rf_physical_and_free(c->staging_area);
×
143
        strv_free(c->plugins);
×
144
        strv_free(c->argv);
×
145
        strv_free(c->envp);
×
146

147
        safe_close(c->rfd);
×
148
}
×
149

150
static int context_copy(const Context *source, Context *ret) {
×
151
        int r;
×
152

153
        assert(source);
×
154
        assert(ret);
×
155
        assert(source->rfd >= 0 || source->rfd == AT_FDCWD || source->rfd == XAT_FDROOT);
×
156

157
        _cleanup_(context_done) Context copy = (Context) {
×
158
                .rfd = source->rfd,
×
159
                .action = source->action,
×
160
                .machine_id = source->machine_id,
161
                .machine_id_is_random = source->machine_id_is_random,
×
162
                .kernel_image_type = source->kernel_image_type,
×
163
                .layout = source->layout,
×
164
                .entry_token_type = source->entry_token_type,
×
165
        };
166

167
        if (source->rfd >= 0) {
×
168
                copy.rfd = fd_reopen(source->rfd, O_CLOEXEC|O_DIRECTORY|O_PATH);
×
169
                if (copy.rfd < 0)
×
170
                        return copy.rfd;
171
        }
172

173
        r = strdup_to(&copy.layout_other, source->layout_other);
×
174
        if (r < 0)
×
175
                return r;
176
        r = strdup_to(&copy.conf_root, source->conf_root);
×
177
        if (r < 0)
×
178
                return r;
179
        r = strdup_to(&copy.boot_root, source->boot_root);
×
180
        if (r < 0)
×
181
                return r;
182
        r = strdup_to(&copy.entry_token, source->entry_token);
×
183
        if (r < 0)
×
184
                return r;
185
        r = strdup_to(&copy.entry_dir, source->entry_dir);
×
186
        if (r < 0)
×
187
                return r;
188
        r = strdup_to(&copy.version, source->version);
×
189
        if (r < 0)
×
190
                return r;
191
        r = strdup_to(&copy.kernel, source->kernel);
×
192
        if (r < 0)
×
193
                return r;
194
        r = strv_copy_unless_empty(source->initrds, &copy.initrds);
×
195
        if (r < 0)
×
196
                return r;
197
        r = strdup_to(&copy.initrd_generator, source->initrd_generator);
×
198
        if (r < 0)
×
199
                return r;
200
        r = strdup_to(&copy.uki_generator, source->uki_generator);
×
201
        if (r < 0)
×
202
                return r;
203
        r = strdup_to(&copy.staging_area, source->staging_area);
×
204
        if (r < 0)
×
205
                return r;
206
        r = strv_copy_unless_empty(source->plugins, &copy.plugins);
×
207
        if (r < 0)
×
208
                return r;
209
        r = strv_copy_unless_empty(source->argv, &copy.argv);
×
210
        if (r < 0)
×
211
                return r;
212
        r = strv_copy_unless_empty(source->envp, &copy.envp);
×
213
        if (r < 0)
×
214
                return r;
215

216
        *ret = copy;
×
217
        copy = CONTEXT_NULL;
×
218

219
        return 0;
×
220
}
221

222
static int context_open_root(Context *c) {
×
223
        int r;
×
224

225
        assert(c);
×
226
        assert(c->rfd < 0);
×
227

228
        if (isempty(arg_root))
×
229
                return 0;
230

231
        r = path_is_root(arg_root);
×
232
        if (r < 0)
×
233
                return log_error_errno(r, "Failed to determine if '%s' is the root directory: %m", arg_root);
×
234
        if (r > 0)
×
235
                return 0;
236

237
        c->rfd = open(arg_root, O_CLOEXEC | O_DIRECTORY | O_PATH);
×
238
        if (c->rfd < 0)
×
239
                return log_error_errno(errno, "Failed to open root directory '%s': %m", arg_root);
×
240

241
        return 0;
242
}
243

244
static const char* context_get_layout(const Context *c) {
×
245
        assert(c);
×
246
        assert(c->layout >= 0);
×
247

248
        return c->layout_other ?: layout_to_string(c->layout);
×
249
}
250

251
static int context_set_layout(Context *c, const char *s, const char *source) {
×
252
        Layout t;
×
253

254
        assert(c);
×
255
        assert(source);
×
256

257
        if (c->layout >= 0 || !s)
×
258
                return 0;
259

260
        assert(!c->layout_other);
×
261

262
        t = layout_from_string(s);
×
263
        if (t >= 0)
×
264
                c->layout = t;
×
265
        else if (isempty(s))
×
266
                c->layout = LAYOUT_AUTO;
×
267
        else {
268
                c->layout_other = strdup(s);
×
269
                if (!c->layout_other)
×
270
                        return log_oom();
×
271

272
                c->layout = LAYOUT_OTHER;
×
273
        }
274

275
        log_debug("layout=%s set via %s", context_get_layout(c), source);
×
276
        return 1;
277
}
278

279
static int context_set_machine_id(Context *c, const char *s, const char *source) {
×
280
        int r;
×
281

282
        assert(c);
×
283
        assert(source);
×
284

285
        if (!sd_id128_is_null(c->machine_id) || !s)
×
286
                return 0;
×
287

288
        r = sd_id128_from_string(s, &c->machine_id);
×
289
        if (r < 0)
×
290
                return log_warning_errno(r, "Failed to parse machine ID specified via %s, ignoring.", source);
×
291

292
        if (sd_id128_is_null(c->machine_id))
×
293
                return 0;
×
294

295
        log_debug("MACHINE_ID=%s set via %s.", SD_ID128_TO_STRING(c->machine_id), source);
×
296
        return 1;
×
297
}
298

299
static int context_set_string(const char *s, const char *source, const char *name, char **dest) {
×
300
        char *p;
×
301

302
        assert(source);
×
303
        assert(name);
×
304
        assert(dest);
×
305

306
        if (*dest || !s)
×
307
                return 0;
308

309
        p = strdup(s);
×
310
        if (!p)
×
311
                return log_oom();
×
312

313
        log_debug("%s (%s) set via %s.", name, p, source);
×
314

315
        *dest = p;
×
316
        return 1;
×
317
}
318

319
static int context_set_initrd_generator(Context *c, const char *s, const char *source) {
×
320
        assert(c);
×
321
        return context_set_string(s, source, "INITRD_GENERATOR", &c->initrd_generator);
×
322
}
323

324
static int context_set_uki_generator(Context *c, const char *s, const char *source) {
×
325
        assert(c);
×
326
        return context_set_string(s, source, "UKI_GENERATOR", &c->uki_generator);
×
327
}
328

329
static int context_set_version(Context *c, const char *s) {
×
330
        assert(c);
×
331

332
        if (s && !filename_is_valid(s))
×
333
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid version specified: %s", s);
×
334

335
        return context_set_string(s, "command line", "kernel version", &c->version);
×
336
}
337

338
static int context_set_path(Context *c, const char *s, const char *source, const char *name, char **dest) {
×
339
        char *p;
×
340
        int r;
×
341

342
        assert(c);
×
343
        assert(source);
×
344
        assert(name);
×
345
        assert(dest);
×
346

347
        if (*dest || !s)
×
348
                return 0;
×
349

350
        if (c->rfd >= 0) {
×
351
                r = chaseat(c->rfd, s, CHASE_AT_RESOLVE_IN_ROOT, &p, /* ret_fd= */ NULL);
×
352
                if (r < 0)
×
353
                        return log_warning_errno(r, "Failed to chase path %s for %s specified via %s, ignoring: %m",
×
354
                                                 s, name, source);
355
        } else {
356
                r = path_make_absolute_cwd(s, &p);
×
357
                if (r < 0)
×
358
                        return log_warning_errno(r, "Failed to make path '%s' for %s specified via %s absolute, ignoring: %m",
×
359
                                                 s, name, source);
360
        }
361

362
        log_debug("%s (%s) set via %s.", name, p, source);
×
363

364
        *dest = p;
×
365
        return 1;
×
366
}
367

368
static int context_set_boot_root(Context *c, const char *s, const char *source) {
×
369
        assert(c);
×
370
        return context_set_path(c, s, source, "BOOT_ROOT", &c->boot_root);
×
371
}
372

373
static int context_set_conf_root(Context *c, const char *s, const char *source) {
×
374
        assert(c);
×
375
        return context_set_path(c, s, source, "CONF_ROOT", &c->conf_root);
×
376
}
377

378
static int context_set_kernel(Context *c, const char *s) {
×
379
        assert(c);
×
380
        return context_set_path(c, s, "command line", "kernel image file", &c->kernel);
×
381
}
382

383
static int context_set_path_strv(Context *c, char* const* strv, const char *source, const char *name, char ***dest) {
×
384
        _cleanup_strv_free_ char **w = NULL;
×
385
        int r;
×
386

387
        assert(c);
×
388
        assert(source);
×
389
        assert(name);
×
390
        assert(dest);
×
391

392
        if (*dest)
×
393
                return 0;
394

395
        STRV_FOREACH(s, strv) {
×
396
                char *p;
×
397

398
                if (c->rfd >= 0) {
×
399
                        r = chaseat(c->rfd, *s, CHASE_AT_RESOLVE_IN_ROOT, &p, /* ret_fd= */ NULL);
×
400
                        if (r < 0)
×
401
                                return log_warning_errno(r, "Failed to chase path %s for %s specified via %s: %m",
×
402
                                                         *s, name, source);
403
                } else {
404
                        r = path_make_absolute_cwd(*s, &p);
×
405
                        if (r < 0)
×
406
                                return log_warning_errno(r, "Failed to make path '%s' for %s specified via %s absolute, ignoring: %m",
×
407
                                                         *s, name, source);
408
                }
409
                r = strv_consume(&w, p);
×
410
                if (r < 0)
×
411
                        return log_oom();
×
412
        }
413

414
        if (strv_isempty(w))
×
415
                return 0;
416

417
        log_debug("%s set via %s", name, source);
×
418

419
        *dest = TAKE_PTR(w);
×
420
        return 1;
×
421
}
422

423
static int context_set_plugins(Context *c, const char *s, const char *source) {
×
424
        _cleanup_strv_free_ char **v = NULL;
×
425
        int r;
×
426

427
        assert(c);
×
428

429
        if (c->plugins || !s)
×
430
                return 0;
431

432
        r = strv_split_full(&v, s, NULL, EXTRACT_UNQUOTE);
×
433
        if (r < 0)
×
434
                return log_error_errno(r, "Failed to parse plugin paths from %s: %m", source);
×
435

436
        return context_set_path_strv(c, v, source, "plugins", &c->plugins);
×
437
}
438

439
static int context_set_initrds(Context *c, char* const* strv) {
×
440
        assert(c);
×
441
        return context_set_path_strv(c, strv, "command line", "initrds", &c->initrds);
×
442
}
443

444
static int context_load_environment(Context *c) {
×
445
        assert(c);
×
446

447
        (void) context_set_machine_id(c, getenv("MACHINE_ID"), "environment");
×
448
        (void) context_set_boot_root(c, getenv("BOOT_ROOT"), "environment");
×
449
        (void) context_set_conf_root(c, getenv("KERNEL_INSTALL_CONF_ROOT"), "environment");
×
450
        (void) context_set_plugins(c, getenv("KERNEL_INSTALL_PLUGINS"), "environment");
×
451
        return 0;
×
452
}
453

454
static int context_load_install_conf(Context *c) {
×
455
        _cleanup_free_ char *machine_id = NULL, *boot_root = NULL, *layout = NULL,
×
456
                            *initrd_generator = NULL, *uki_generator = NULL;
×
457
        int r;
×
458

459
        assert(c);
×
460

461
        r = load_kernel_install_conf_at(
×
462
                        c->conf_root ? NULL : arg_root,
463
                        c->conf_root ? XAT_FDROOT : c->rfd,
464
                        c->conf_root,
×
465
                        &machine_id,
466
                        &boot_root,
467
                        &layout,
468
                        &initrd_generator,
469
                        &uki_generator);
470
        if (r <= 0)
×
471
                return r;
472

473
        (void) context_set_machine_id(c, machine_id, "config");
×
474
        (void) context_set_boot_root(c, boot_root, "config");
×
475
        (void) context_set_layout(c, layout, "config");
×
476
        (void) context_set_initrd_generator(c, initrd_generator, "config");
×
477
        (void) context_set_uki_generator(c, uki_generator, "config");
×
478

479
        log_debug("Loaded config.");
×
480
        return 0;
481
}
482

483
static int context_load_machine_info(Context *c) {
×
484
        _cleanup_fclose_ FILE *f = NULL;
×
485
        _cleanup_free_ char *machine_id = NULL, *layout = NULL;
×
486
        static const char *path = "/etc/machine-info";
×
487
        int r;
×
488

489
        assert(c);
×
490

491
        /* If the user configured an explicit machine ID in /etc/machine-info to use for our purpose, we'll
492
         * use that instead (for compatibility). */
493

494
        if (!sd_id128_is_null(c->machine_id) && c->layout >= 0)
×
495
                return 0;
496

497
        /* For testing. To make not read host's /etc/machine-info. */
498
        r = getenv_bool("KERNEL_INSTALL_READ_MACHINE_INFO");
×
499
        if (r < 0 && r != -ENXIO)
×
500
                log_warning_errno(r, "Failed to read $KERNEL_INSTALL_READ_MACHINE_INFO, assuming yes: %m");
×
501
        if (r == 0) {
×
502
                log_debug("Skipping reading of /etc/machine-info.");
×
503
                return 0;
×
504
        }
505

506
        r = chase_and_fopenat_unlocked(c->rfd, path, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
×
507
        if (r == -ENOENT)
×
508
                return 0;
509
        if (r < 0)
×
510
                return log_error_errno(r, "Failed to chase %s: %m", path);
×
511

512
        log_debug("Loading %s…", path);
×
513

514
        r = parse_env_file(f, path,
×
515
                           "KERNEL_INSTALL_MACHINE_ID", &machine_id,
516
                           "KERNEL_INSTALL_LAYOUT", &layout);
517
        if (r < 0)
×
518
                return log_error_errno(r, "Failed to parse '%s': %m", path);
×
519

520
        (void) context_set_machine_id(c, machine_id, path);
×
521
        (void) context_set_layout(c, layout, path);
×
522
        return 0;
523
}
524

525
static int context_load_machine_id(Context *c) {
×
526
        int r;
×
527

528
        assert(c);
×
529

530
        r = id128_get_machine_at(c->rfd, &c->machine_id);
×
531
        if (ERRNO_IS_NEG_MACHINE_ID_UNSET(r))
×
532
                return 0;
533
        if (r < 0)
×
534
                return log_error_errno(r, "Failed to load machine ID from /etc/machine-id: %m");
×
535

536
        log_debug("MACHINE_ID=%s set via /etc/machine-id.", SD_ID128_TO_STRING(c->machine_id));
×
537
        return 1; /* loaded */
×
538
}
539

540
static int context_ensure_machine_id(Context *c) {
×
541
        int r;
×
542

543
        assert(c);
×
544

545
        if (!sd_id128_is_null(c->machine_id))
×
546
                return 0;
×
547

548
        /* If /etc/machine-id is initialized we'll use it. */
549
        r = context_load_machine_id(c);
×
550
        if (r != 0)
×
551
                return r;
552

553
        /* Otherwise we'll use a freshly generated one. */
554
        r = sd_id128_randomize(&c->machine_id);
×
555
        if (r < 0)
×
556
                return log_error_errno(r, "Failed to generate random ID: %m");
×
557

558
        c->machine_id_is_random = true;
×
559
        log_debug("New machine ID '%s' generated.", SD_ID128_TO_STRING(c->machine_id));
×
560
        return 0;
×
561
}
562

563
static int context_acquire_xbootldr(Context *c) {
×
564
        int r;
×
565

566
        assert(c);
×
567
        assert(!c->boot_root);
×
568

569
        r = find_xbootldr_and_warn_at(
×
570
                        /* rfd= */ c->rfd,
571
                        /* path= */ arg_xbootldr_path,
572
                        /* unprivileged_mode= */ -1,
573
                        /* ret_path= */ &c->boot_root);
574
        if (r == -ENOKEY) {
×
575
                log_debug_errno(r, "Couldn't find an XBOOTLDR partition.");
×
576
                return 0;
×
577
        }
578
        if (r == -EACCES && geteuid() != 0)
×
579
                return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
×
580
        if (r < 0)
×
581
                return r;
582

583
        log_debug("Using XBOOTLDR partition at %s as $BOOT_ROOT.", c->boot_root);
×
584
        return 1; /* found */
585
}
586

587
static int context_acquire_esp(Context *c) {
×
588
        int r;
×
589

590
        assert(c);
×
591
        assert(!c->boot_root);
×
592

593
        r = find_esp_and_warn_at(
×
594
                        /* rfd= */ c->rfd,
595
                        /* path= */ arg_esp_path,
596
                        /* unprivileged_mode= */ -1,
597
                        /* ret_path= */ &c->boot_root);
598
        if (r == -ENOKEY) {
×
599
                log_debug_errno(r, "Couldn't find EFI system partition, ignoring.");
×
600
                return 0;
×
601
        }
602
        if (r == -EACCES && geteuid() != 0)
×
603
                return log_error_errno(r, "Failed to determine EFI system partition: %m");
×
604
        if (r < 0)
×
605
                return r;
606

607
        log_debug("Using EFI System Partition at %s as $BOOT_ROOT.", c->boot_root);
×
608
        return 1; /* found */
609
}
610

611
static int context_ensure_boot_root(Context *c) {
×
612
        int r;
×
613

614
        assert(c);
×
615

616
        /* If BOOT_ROOT is specified via environment or install.conf, then use it. */
617
        if (c->boot_root)
×
618
                return 0;
619

620
        /* Otherwise, use XBOOTLDR partition, if mounted. */
621
        r = context_acquire_xbootldr(c);
×
622
        if (r != 0)
×
623
                return r;
624

625
        /* Otherwise, use EFI system partition, if mounted. */
626
        r = context_acquire_esp(c);
×
627
        if (r != 0)
×
628
                return r;
629

630
        /* If all else fails, use /boot. */
631
        if (c->rfd >= 0) {
×
632
                r = chaseat(c->rfd, "/boot", CHASE_AT_RESOLVE_IN_ROOT, &c->boot_root, /* ret_fd= */ NULL);
×
633
                if (r < 0)
×
634
                        return log_error_errno(r, "Failed to chase '/boot/': %m");
×
635
        } else {
636
                c->boot_root = strdup("/boot");
×
637
                if (!c->boot_root)
×
638
                        return log_oom();
×
639
        }
640

641
        log_debug("KERNEL_INSTALL_BOOT_ROOT autodetection yielded no candidates, using \"%s\".", c->boot_root);
×
642
        return 0;
643
}
644

645
static int context_ensure_entry_token(Context *c) {
×
646
        int r;
×
647

648
        assert(c);
×
649

650
        /* Now that we determined the machine ID to use, let's determine the "token" for the boot loader
651
         * entry to generate. We use that for naming the directory below $BOOT where we want to place the
652
         * kernel/initrd and related resources, as well for naming the .conf boot loader spec entry.
653
         * Typically this is just the machine ID, but it can be anything else, too, if we are told so. */
654

655
        r = boot_entry_token_ensure_at(
×
656
                        c->rfd,
657
                        c->conf_root,
×
658
                        c->machine_id,
659
                        c->machine_id_is_random,
×
660
                        &c->entry_token_type,
661
                        &c->entry_token);
662
        if (r < 0)
×
663
                return r;
664

665
        log_debug("Using entry token: %s", c->entry_token);
×
666
        return 0;
667
}
668

669
static int context_load_plugins(Context *c) {
×
670
        int r;
×
671

672
        assert(c);
×
673

674
        if (c->plugins)
×
675
                return 0;
×
676

677
        r = conf_files_list_strv_at(
×
678
                        &c->plugins,
679
                        ".install",
680
                        c->rfd,
681
                        CONF_FILES_EXECUTABLE | CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED | CONF_FILES_WARN,
682
                        STRV_MAKE_CONST("/etc/kernel/install.d", "/usr/lib/kernel/install.d"));
×
683
        if (r < 0)
×
684
                return log_error_errno(r, "Failed to find plugins: %m");
×
685

686
        return 0;
687
}
688

689
static int context_setup(Context *c) {
×
690
        int r;
×
691

692
        assert(c);
×
693

694
        if (c->kernel_image_type < 0)
×
695
                c->kernel_image_type = KERNEL_IMAGE_TYPE_UNKNOWN;
×
696
        if (c->entry_token_type < 0)
×
697
                c->entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
×
698

699
        r = context_open_root(c);
×
700
        if (r < 0)
×
701
                return r;
702

703
        r = context_load_environment(c);
×
704
        if (r < 0)
×
705
                return r;
706

707
        r = context_load_install_conf(c);
×
708
        if (r < 0)
×
709
                return r;
710

711
        r = context_load_machine_info(c);
×
712
        if (r < 0)
×
713
                return r;
714

715
        r = context_ensure_machine_id(c);
×
716
        if (r < 0)
×
717
                return r;
718

719
        r = context_ensure_boot_root(c);
×
720
        if (r < 0)
×
721
                return r;
722

723
        r = context_ensure_entry_token(c);
×
724
        if (r < 0)
×
725
                return r;
726

727
        r = context_load_plugins(c);
×
728
        if (r < 0)
×
729
                return r;
×
730

731
        return 0;
732
}
733

734
static int context_from_cmdline(Context *c, Action action) {
×
735
        int r;
×
736

737
        assert(c);
×
738

739
        c->action = action;
×
740

741
        c->entry_type = arg_boot_entry_type;
×
742

743
        r = free_and_strdup_warn(&c->entry_token, arg_entry_token);
×
744
        if (r < 0)
×
745
                return r;
746

747
        c->entry_token_type = arg_entry_token_type;
×
748

749
        return context_setup(c);
×
750
}
751

752
static int context_inspect_kernel(Context *c) {
×
753
        int r;
×
754

755
        assert(c);
×
756

UNCOV
757
        if (!c->kernel)
×
758
                return 0;
759

UNCOV
760
        r = inspect_kernel(
×
761
                        c->rfd,
762
                        c->kernel,
763
                        &c->kernel_image_type);
764
        if (r < 0)
×
765
                return log_error_errno(r, "Failed to inspect kernel image '%s': %m", c->kernel);
×
766

767
        return 0;
768
}
769

UNCOV
770
static int context_ensure_layout(Context *c) {
×
UNCOV
771
        int r;
×
772

UNCOV
773
        assert(c);
×
774
        assert(c->boot_root);
×
775
        assert(c->entry_token);
×
776

UNCOV
777
        if (c->layout >= 0 && c->layout != LAYOUT_AUTO)
×
778
                return 0;
×
779

780
        /* No layout configured by the administrator. Let's try to figure it out automatically from metadata
781
         * already contained in $BOOT_ROOT. */
782

783
        if (c->kernel_image_type == KERNEL_IMAGE_TYPE_UKI) {
×
UNCOV
784
                c->layout = LAYOUT_UKI;
×
785
                log_debug("Kernel image type is %s, using layout=%s.",
×
786
                          kernel_image_type_to_string(c->kernel_image_type), layout_to_string(c->layout));
787
                return 0;
×
788
        }
789

UNCOV
790
        _cleanup_free_ char *srel_path = path_join(c->boot_root, "loader/entries.srel");
×
791
        if (!srel_path)
×
UNCOV
792
                return log_oom();
×
793

794
        _cleanup_fclose_ FILE *f = NULL;
×
795
        r = chase_and_fopenat_unlocked(c->rfd, srel_path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
×
UNCOV
796
        if (r < 0) {
×
797
                if (r != -ENOENT)
×
UNCOV
798
                        return log_error_errno(r, "Failed to open '%s': %m", srel_path);
×
799
        } else {
UNCOV
800
                _cleanup_free_ char *srel = NULL;
×
801

UNCOV
802
                r = read_line(f, LONG_LINE_MAX, &srel);
×
UNCOV
803
                if (r < 0)
×
UNCOV
804
                        return log_error_errno(r, "Failed to read %s: %m", srel_path);
×
805

806
                if (streq(srel, "type1"))
×
807
                        /* The loader/entries.srel file clearly indicates that the installed boot loader
808
                         * implements the proper standard upstream boot loader spec for Type #1 entries.
809
                         * Let's default to that, then. */
UNCOV
810
                        c->layout = LAYOUT_BLS;
×
811
                else
812
                        /* The loader/entries.srel file indicates some other spec is implemented and owns the
813
                         * /loader/entries/ directory. Since we have no idea what that means, let's stay away
814
                         * from it by default. */
UNCOV
815
                        c->layout = LAYOUT_OTHER;
×
816

817
                log_debug("%s with '%s' found, using layout=%s.", srel_path, srel, layout_to_string(c->layout));
×
818
                return 0;
×
819
        }
820

UNCOV
821
        _cleanup_free_ char *entry_token_path = path_join(c->boot_root, c->entry_token);
×
UNCOV
822
        if (!entry_token_path)
×
823
                return log_oom();
×
824

825
        r = chaseat(c->rfd, entry_token_path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, /* ret_fd= */ NULL);
×
UNCOV
826
        if (r < 0) {
×
UNCOV
827
                if (!IN_SET(r, -ENOENT, -ENOTDIR))
×
UNCOV
828
                        return log_error_errno(r, "Failed to check if '%s' exists and is a directory: %m", entry_token_path);
×
829
        } else {
830
                /* If the metadata in $BOOT_ROOT doesn't tell us anything, then check if the entry token
831
                 * directory already exists. If so, let's assume it's the standard boot loader spec, too. */
UNCOV
832
                c->layout = LAYOUT_BLS;
×
UNCOV
833
                log_debug("%s exists, using layout=%s.", entry_token_path, layout_to_string(c->layout));
×
UNCOV
834
                return 0;
×
835
        }
836

837
        /* There's no metadata in $BOOT_ROOT, and apparently no entry token directory installed? Then we
838
         * really don't know anything. */
UNCOV
839
        c->layout = LAYOUT_OTHER;
×
840
        log_debug("Entry-token directory %s not found, using layout=%s.",
×
841
                  entry_token_path,
842
                  layout_to_string(c->layout));
843
        return 0;
844
}
845

846
static int context_set_up_staging_area(Context *c) {
×
847
        int r;
×
848

UNCOV
849
        assert(c);
×
850

851
        if (c->staging_area)
×
852
                return 0;
×
853

854
        const char *d;
×
UNCOV
855
        r = var_tmp_dir(&d);
×
856
        if (r < 0)
×
UNCOV
857
                return log_error_errno(r, "Failed to determine temporary directory location: %m");
×
858

859
        _cleanup_free_ char *template = path_join(d, "kernel-install.staging.XXXXXX");
×
860
        if (!template)
×
UNCOV
861
                return log_oom();
×
862

UNCOV
863
        if (c->action == ACTION_INSPECT)
×
864
                /* This is only used for display. The directory will not be created. */
UNCOV
865
                c->staging_area = TAKE_PTR(template);
×
866
        else {
867
                r = mkdtemp_malloc(template, &c->staging_area);
×
868
                if (r < 0)
×
869
                        return log_error_errno(r, "Failed to create staging area: %m");
×
870
        }
871

872
        return 0;
873
}
874

875
static int context_build_entry_dir(Context *c) {
×
876
        assert(c);
×
877
        assert(c->boot_root);
×
UNCOV
878
        assert(c->entry_token);
×
879
        assert(c->version || c->action == ACTION_INSPECT);
×
880

UNCOV
881
        if (c->entry_dir)
×
882
                return 0;
883

884
        c->entry_dir = path_join(c->boot_root, c->entry_token, c->version ?: "KERNEL_VERSION");
×
UNCOV
885
        if (!c->entry_dir)
×
UNCOV
886
                return log_oom();
×
887

UNCOV
888
        log_debug("Using ENTRY_DIR=%s", c->entry_dir);
×
889
        return 0;
890
}
891

892
static bool context_should_make_entry_dir(Context *c) {
×
UNCOV
893
        assert(c);
×
894

895
        /* Compatibility with earlier versions that used the presence of $BOOT_ROOT/$ENTRY_TOKEN to signal to
896
         * 00-entry-directory to create $ENTRY_DIR to serve as the indication to use or to not use the BLS */
897

898
        if (arg_make_entry_directory < 0)
×
899
                return c->layout == LAYOUT_BLS;
×
900

901
        return arg_make_entry_directory;
×
902
}
903

904
static int context_make_entry_dir(Context *c) {
×
UNCOV
905
        _cleanup_close_ int fd = -EBADF;
×
906

907
        assert(c);
×
908
        assert(c->entry_dir);
×
909

910
        if (c->action != ACTION_ADD)
×
911
                return 0;
912

UNCOV
913
        if (!context_should_make_entry_dir(c))
×
914
                return 0;
915

916
        log_debug("mkdir -p %s", c->entry_dir);
×
917
        fd = chase_and_openat(c->rfd, c->entry_dir, CHASE_AT_RESOLVE_IN_ROOT | CHASE_MKDIR_0755,
×
918
                              O_CLOEXEC | O_CREAT | O_DIRECTORY | O_PATH, NULL);
919
        if (fd < 0)
×
920
                return log_error_errno(fd, "Failed to make directory '%s': %m", c->entry_dir);
×
921

922
        return 0;
923
}
924

925
static int context_remove_entry_dir(Context *c) {
×
UNCOV
926
        _cleanup_free_ char *p = NULL;
×
UNCOV
927
        _cleanup_close_ int fd = -EBADF;
×
928
        struct stat st;
×
UNCOV
929
        int r;
×
930

931
        assert(c);
×
932
        assert(c->entry_dir);
×
933

934
        if (c->action != ACTION_REMOVE)
×
935
                return 0;
936

UNCOV
937
        if (!context_should_make_entry_dir(c))
×
938
                return 0;
939

940
        log_debug("rm -rf %s", c->entry_dir);
×
UNCOV
941
        fd = chase_and_openat(c->rfd, c->entry_dir, CHASE_AT_RESOLVE_IN_ROOT, O_CLOEXEC | O_DIRECTORY, &p);
×
942
        if (fd < 0) {
×
943
                if (IN_SET(fd, -ENOTDIR, -ENOENT))
×
944
                        return 0;
UNCOV
945
                return log_debug_errno(fd, "Failed to chase and open %s, ignoring: %m", c->entry_dir);
×
946
        }
947

UNCOV
948
        if (fstat(fd, &st) < 0)
×
UNCOV
949
                return log_debug_errno(errno, "Failed to stat %s: %m", p);
×
950

UNCOV
951
        r = rm_rf_children(TAKE_FD(fd), REMOVE_PHYSICAL|REMOVE_MISSING_OK|REMOVE_CHMOD, &st);
×
952
        if (r < 0)
×
953
                log_debug_errno(r, "Failed to remove children of %s, ignoring: %m", p);
×
954

955
        if (unlinkat(c->rfd, p, AT_REMOVEDIR) < 0)
×
UNCOV
956
                log_debug_errno(errno, "Failed to remove %s, ignoring: %m", p);
×
957

958
        return 0;
959
}
960

UNCOV
961
static int context_build_arguments(Context *c) {
×
UNCOV
962
        _cleanup_strv_free_ char **a = NULL;
×
963
        const char *verb;
×
964
        int r;
×
965

966
        assert(c);
×
UNCOV
967
        assert(c->entry_dir);
×
968

UNCOV
969
        if (c->argv)
×
970
                return 0;
971

972
        switch (c->action) {
×
973
        case ACTION_ADD:
×
UNCOV
974
                assert(c->version);
×
UNCOV
975
                assert(c->kernel);
×
976
                verb = "add";
977
                break;
978

UNCOV
979
        case ACTION_REMOVE:
×
UNCOV
980
                assert(c->version);
×
981
                assert(!c->kernel);
×
982
                assert(!c->initrds);
×
983
                verb = "remove";
984
                break;
985

986
        case ACTION_INSPECT:
987
                verb = "add|remove";
988
                break;
989

990
        default:
×
UNCOV
991
                assert_not_reached();
×
992
        }
993

994
        a = strv_new("dummy-arg", /* to make strv_free() works for this variable. */
×
995
                     verb,
996
                     c->version ?: "KERNEL_VERSION",
997
                     c->entry_dir);
998
        if (!a)
×
999
                return log_oom();
×
1000

1001
        if (c->action == ACTION_ADD) {
×
1002
                r = strv_extend(&a, c->kernel);
×
UNCOV
1003
                if (r < 0)
×
UNCOV
1004
                        return log_oom();
×
1005

1006
                r = strv_extend_strv(&a, c->initrds, /* filter_duplicates= */ false);
×
1007
                if (r < 0)
×
UNCOV
1008
                        return log_oom();
×
1009

1010
        } else if (c->action == ACTION_INSPECT) {
×
1011
                r = strv_extend_many(
×
1012
                                &a,
1013
                                c->kernel ?: "[KERNEL_IMAGE]",
1014
                                "[INITRD...]");
1015
                if (r < 0)
×
1016
                        return log_oom();
×
1017
        }
1018

UNCOV
1019
        c->argv = TAKE_PTR(a);
×
1020
        return 0;
×
1021
}
1022

1023
static int context_build_environment(Context *c) {
×
UNCOV
1024
        _cleanup_strv_free_ char **e = NULL;
×
UNCOV
1025
        int r;
×
1026

UNCOV
1027
        assert(c);
×
1028

UNCOV
1029
        if (c->envp)
×
1030
                return 0;
1031

UNCOV
1032
        r = strv_env_assign_many(&e,
×
1033
                                 "LC_COLLATE",                      SYSTEMD_DEFAULT_LOCALE,
1034
                                 "KERNEL_INSTALL_VERBOSE",          one_zero(arg_verbose),
1035
                                 "KERNEL_INSTALL_IMAGE_TYPE",       kernel_image_type_to_string(c->kernel_image_type),
1036
                                 "KERNEL_INSTALL_MACHINE_ID",       SD_ID128_TO_STRING(c->machine_id),
1037
                                 "KERNEL_INSTALL_ENTRY_TOKEN",      c->entry_token,
1038
                                 "KERNEL_INSTALL_BOOT_ROOT",        c->boot_root,
1039
                                 "KERNEL_INSTALL_LAYOUT",           context_get_layout(c),
1040
                                 "KERNEL_INSTALL_INITRD_GENERATOR", strempty(c->initrd_generator),
1041
                                 "KERNEL_INSTALL_UKI_GENERATOR",    strempty(c->uki_generator),
1042
                                 "KERNEL_INSTALL_BOOT_ENTRY_TYPE",  boot_entry_type_to_string(c->entry_type),
1043
                                 "KERNEL_INSTALL_STAGING_AREA",     c->staging_area);
UNCOV
1044
        if (r < 0)
×
1045
                return log_error_errno(r, "Failed to build environment variables for plugins: %m");
×
1046

1047
        c->envp = TAKE_PTR(e);
×
1048
        return 0;
×
1049
}
1050

1051
static int context_prepare_execution(Context *c) {
×
1052
        int r;
×
1053

UNCOV
1054
        assert(c);
×
1055

1056
        r = context_inspect_kernel(c);
×
UNCOV
1057
        if (r < 0)
×
1058
                return r;
1059

1060
        r = context_ensure_layout(c);
×
UNCOV
1061
        if (r < 0)
×
1062
                return r;
1063

1064
        r = context_set_up_staging_area(c);
×
UNCOV
1065
        if (r < 0)
×
1066
                return r;
1067

1068
        r = context_build_entry_dir(c);
×
1069
        if (r < 0)
×
1070
                return r;
1071

UNCOV
1072
        r = context_build_arguments(c);
×
UNCOV
1073
        if (r < 0)
×
1074
                return r;
1075

UNCOV
1076
        r = context_build_environment(c);
×
1077
        if (r < 0)
×
UNCOV
1078
                return r;
×
1079

1080
        return 0;
1081
}
1082

1083
static int context_execute(Context *c) {
×
1084
        int r, ret;
×
1085

UNCOV
1086
        assert(c);
×
1087

1088
        r = context_make_entry_dir(c);
×
UNCOV
1089
        if (r < 0)
×
1090
                return r;
1091

UNCOV
1092
        if (DEBUG_LOGGING) {
×
UNCOV
1093
                _cleanup_free_ char *x = strv_join_full(c->plugins, "", "\n  ", /* escape_separator= */ false);
×
1094
                log_debug("Using plugins: %s", strna(x));
×
1095

1096
                _cleanup_free_ char *y = strv_join_full(c->envp, "", "\n  ", /* escape_separator= */ false);
×
UNCOV
1097
                log_debug("Plugin environment: %s", strna(y));
×
1098

UNCOV
1099
                _cleanup_free_ char *z = strv_join(strv_skip(c->argv, 1), " ");
×
UNCOV
1100
                log_debug("Plugin arguments: %s", strna(z));
×
1101
        }
1102

UNCOV
1103
        ret = execute_strv(
×
1104
                        "plugins",
1105
                        c->plugins,
×
1106
                        /* root= */ NULL,
1107
                        USEC_INFINITY,
1108
                        /* callbacks= */ NULL,
1109
                        /* callback_args= */ NULL,
1110
                        c->argv,
1111
                        c->envp,
1112
                        EXEC_DIR_SKIP_REMAINING);
1113

1114
        r = context_remove_entry_dir(c);
×
UNCOV
1115
        if (r < 0)
×
UNCOV
1116
                return r;
×
1117

1118
        /* This returns 0 on success, positive exit code on plugin failure, negative errno on other failures. */
1119
        return ret;
1120
}
1121

UNCOV
1122
static bool bypass(void) {
×
1123
        return should_bypass("KERNEL_INSTALL");
×
1124
}
1125

UNCOV
1126
static int kernel_from_version(const char *version, char **ret_kernel) {
×
1127
        _cleanup_free_ char *vmlinuz = NULL;
×
1128
        int r;
×
1129

1130
        assert(version);
×
1131

UNCOV
1132
        vmlinuz = path_join("/usr/lib/modules/", version, "/vmlinuz");
×
1133
        if (!vmlinuz)
×
1134
                return log_oom();
×
1135

UNCOV
1136
        r = access_nofollow(vmlinuz, F_OK);
×
1137
        if (r == -ENOENT)
×
UNCOV
1138
                return log_error_errno(r, "Kernel image not installed to '%s', specify kernel kernel image path explicitly.", vmlinuz);
×
UNCOV
1139
        if (r < 0)
×
UNCOV
1140
                return log_error_errno(r, "Failed to determine if kernel image is installed to '%s': %m", vmlinuz);
×
1141

UNCOV
1142
        *ret_kernel = TAKE_PTR(vmlinuz);
×
1143
        return 0;
×
1144
}
1145

UNCOV
1146
static int do_add(
×
1147
                Context *c,
1148
                const char *version,
1149
                const char *kernel,
1150
                char **initrds) {
1151

UNCOV
1152
        int r;
×
1153

1154
        assert(c);
×
1155

1156
        struct utsname un;
×
UNCOV
1157
        if (!version) {
×
UNCOV
1158
                assert_se(uname(&un) >= 0);
×
1159
                version = un.release;
1160
        }
1161

1162
        _cleanup_free_ char *vmlinuz = NULL;
×
1163
        if (!kernel) {
×
UNCOV
1164
                r = kernel_from_version(version, &vmlinuz);
×
UNCOV
1165
                if (r < 0)
×
1166
                        return r;
1167

UNCOV
1168
                kernel = vmlinuz;
×
1169
        }
1170

1171
        r = context_set_version(c, version);
×
UNCOV
1172
        if (r < 0)
×
1173
                return r;
1174

1175
        r = context_set_kernel(c, kernel);
×
UNCOV
1176
        if (r < 0)
×
1177
                return r;
1178

UNCOV
1179
        r = context_set_initrds(c, initrds);
×
UNCOV
1180
        if (r < 0)
×
1181
                return r;
1182

1183
        r = context_prepare_execution(c);
×
1184
        if (r < 0)
×
1185
                return r;
1186

UNCOV
1187
        return context_execute(c);
×
1188
}
1189

UNCOV
1190
static int verb_add(int argc, char *argv[], uintptr_t _data, void *userdata) {
×
1191
        const char *version, *kernel;
×
UNCOV
1192
        char **initrds;
×
UNCOV
1193
        int r;
×
1194

1195
        assert(argv);
×
1196

UNCOV
1197
        if (arg_root)
×
UNCOV
1198
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "'add' does not support --root= or --image=.");
×
1199

UNCOV
1200
        if (bypass())
×
1201
                return 0;
1202

1203
        _cleanup_(context_done) Context c = CONTEXT_NULL;
×
1204
        r = context_from_cmdline(&c, ACTION_ADD);
×
1205
        if (r < 0)
×
1206
                return r;
1207

1208
        /* We use the same order of arguments that "inspect" introduced, i.e. if only on argument is
1209
         * specified we take it as the kernel path, not the version, i.e. it's the first argument that is
1210
         * optional, not the 2nd. */
1211
        version = argc > 2 ? empty_or_dash_to_null(argv[1]) : NULL;
×
1212
        kernel = argc > 2 ? empty_or_dash_to_null(argv[2]) :
×
1213
                (argc > 1 ? empty_or_dash_to_null(argv[1]) : NULL);
×
UNCOV
1214
        initrds = strv_skip(argv, 3);
×
1215

UNCOV
1216
        return do_add(&c, version, kernel, initrds);
×
1217
}
1218

UNCOV
1219
static int verb_add_all(int argc, char *argv[], uintptr_t _data, void *userdata) {
×
1220
        _cleanup_close_ int fd = -EBADF;
×
UNCOV
1221
        size_t n = 0;
×
UNCOV
1222
        int ret = 0, r;
×
1223

1224
        assert(argv);
×
1225

UNCOV
1226
        if (arg_root)
×
UNCOV
1227
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "'add-all' does not support --root= or --image=.");
×
1228

1229
        if (bypass())
×
1230
                return 0;
1231

1232
        _cleanup_(context_done) Context c = CONTEXT_NULL;
×
1233
        r = context_from_cmdline(&c, ACTION_ADD);
×
1234
        if (r < 0)
×
1235
                return r;
1236

1237
        fd = chase_and_openat(c.rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
×
1238
        if (fd < 0)
×
1239
                return log_error_errno(fd, "Failed to open %s/usr/lib/modules/: %m", strempty(arg_root));
×
1240

1241
        _cleanup_free_ DirectoryEntries *de = NULL;
×
1242
        r = readdir_all(fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de);
×
UNCOV
1243
        if (r < 0)
×
UNCOV
1244
                return log_error_errno(r, "Failed to numerate /usr/lib/modules/ contents: %m");
×
1245

1246
        FOREACH_ARRAY(d, de->entries, de->n_entries) {
×
UNCOV
1247
                r = dirent_ensure_type(fd, *d);
×
1248
                if (r < 0) {
×
1249
                        if (r != -ENOENT) /* don't log if just gone by now */
×
1250
                                log_debug_errno(r, "Failed to check if '%s/usr/lib/modules/%s' is a directory, ignoring: %m", strempty(arg_root), (*d)->d_name);
×
UNCOV
1251
                        continue;
×
1252
                }
1253

1254
                if ((*d)->d_type != DT_DIR)
×
UNCOV
1255
                        continue;
×
1256

1257
                _cleanup_free_ char *fn = path_join((*d)->d_name, "vmlinuz");
×
UNCOV
1258
                if (!fn)
×
UNCOV
1259
                        return log_oom();
×
1260

UNCOV
1261
                if (faccessat(fd, fn, F_OK, AT_SYMLINK_NOFOLLOW) < 0) {
×
1262
                        if (errno != ENOENT)
×
1263
                                log_debug_errno(errno, "Failed to check if '%s/usr/lib/modules/%s/vmlinuz' exists, ignoring: %m", strempty(arg_root), (*d)->d_name);
×
1264

UNCOV
1265
                        log_notice("Not adding version '%s', because kernel image not found.", (*d)->d_name);
×
UNCOV
1266
                        continue;
×
1267
                }
1268

1269
                _cleanup_(context_done) Context copy = CONTEXT_NULL;
×
1270

UNCOV
1271
                r = context_copy(&c, &copy);
×
1272
                if (r < 0)
×
1273
                        return log_error_errno(r, "Failed to copy execution context: %m");
×
1274

1275
                /* do_add() will look up the path in the correct root directory so we don't need to prefix it
1276
                 * with arg_root here. */
1277
                _cleanup_free_ char *full = path_join("/usr/lib/modules/", fn);
×
1278
                if (!full)
×
1279
                        return log_oom();
×
1280

UNCOV
1281
                r = do_add(&copy,
×
1282
                           /* version= */ (*d)->d_name,
×
1283
                           /* kernel= */ full,
1284
                           /* initrds= */ NULL);
1285
                if (r == 0)
×
UNCOV
1286
                        n++;
×
UNCOV
1287
                else if (ret == 0)
×
UNCOV
1288
                        ret = r;
×
1289
        }
1290

UNCOV
1291
        if (n > 0)
×
UNCOV
1292
                log_debug("Installed %zu kernel(s).", n);
×
UNCOV
1293
        else if (ret == 0)
×
1294
                ret = log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No kernels to install found.");
×
1295

1296
        return ret;
1297
}
1298

UNCOV
1299
static int run_as_installkernel(int argc, char *argv[]) {
×
1300
        /* kernel's install.sh invokes us as
1301
         *   /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
1302
         * We ignore the last two arguments. */
1303
        if (optind + 2 > argc)
×
1304
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'installkernel' command requires at least two arguments.");
×
1305

1306
        return verb_add(3, STRV_MAKE("add", argv[optind], argv[optind+1]), /* data= */ 0, /* userdata= */ NULL);
×
1307
}
1308

1309
static int verb_remove(int argc, char *argv[], uintptr_t _data, void *userdata) {
×
1310
        int r;
×
1311

UNCOV
1312
        assert(argc >= 2);
×
1313
        assert(argv);
×
1314

UNCOV
1315
        if (arg_root)
×
1316
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "'remove' does not support --root= or --image=.");
×
1317

1318
        if (argc > 2)
×
UNCOV
1319
                log_debug("Too many arguments specified. 'kernel-install remove' takes only kernel version. "
×
1320
                          "Ignoring residual arguments.");
1321

UNCOV
1322
        if (bypass())
×
1323
                return 0;
1324

1325
        _cleanup_(context_done) Context c = CONTEXT_NULL;
×
1326
        r = context_from_cmdline(&c, ACTION_REMOVE);
×
UNCOV
1327
        if (r < 0)
×
1328
                return r;
1329

1330
        /* Note, we do not automatically derive the kernel version to remove from uname() here (unlike we do
1331
         * it for the "add" verb), since we don't want to make it too easy to uninstall your running
1332
         * kernel, as a safety precaution */
1333

UNCOV
1334
        r = context_set_version(&c, argv[1]);
×
UNCOV
1335
        if (r < 0)
×
1336
                return r;
1337

1338
        r = context_prepare_execution(&c);
×
1339
        if (r < 0)
×
1340
                return r;
1341

1342
        return context_execute(&c);
×
1343
}
1344

1345
static int verb_inspect(int argc, char *argv[], uintptr_t _data, void *userdata) {
×
1346
        _cleanup_(table_unrefp) Table *t = NULL;
×
UNCOV
1347
        _cleanup_free_ char *vmlinuz = NULL;
×
UNCOV
1348
        const char *version, *kernel;
×
UNCOV
1349
        char **initrds;
×
UNCOV
1350
        struct utsname un;
×
UNCOV
1351
        int r;
×
1352

UNCOV
1353
        _cleanup_(context_done) Context c = CONTEXT_NULL;
×
1354
        r = context_from_cmdline(&c, ACTION_INSPECT);
×
1355
        if (r < 0)
×
1356
                return r;
1357

1358
        /* When only a single parameter is specified 'inspect' it's the kernel image path, and not the kernel
1359
         * version. i.e. it's the first argument that is optional, not the 2nd. That's a bit unfortunate, but
1360
         * we keep the behaviour for compatibility. If users want to specify only the version (and have the
1361
         * kernel image path derived automatically), then they may specify an empty string or "dash" as
1362
         * kernel image path. */
UNCOV
1363
        version = argc > 2 ? empty_or_dash_to_null(argv[1]) : NULL;
×
1364
        kernel = argc > 2 ? empty_or_dash_to_null(argv[2]) :
×
1365
                (argc > 1 ? empty_or_dash_to_null(argv[1]) : NULL);
×
1366
        initrds = strv_skip(argv, 3);
×
1367

UNCOV
1368
        if (!version && !arg_root) {
×
1369
                assert_se(uname(&un) >= 0);
×
1370
                version = un.release;
1371
        }
1372

1373
        if (!kernel && version) {
×
UNCOV
1374
                r = kernel_from_version(version, &vmlinuz);
×
UNCOV
1375
                if (r < 0)
×
1376
                        return r;
1377

UNCOV
1378
                kernel = vmlinuz;
×
1379
        }
1380

1381
        r = context_set_version(&c, version);
×
UNCOV
1382
        if (r < 0)
×
1383
                return r;
1384

1385
        r = context_set_kernel(&c, kernel);
×
UNCOV
1386
        if (r < 0)
×
1387
                return r;
1388

1389
        r = context_set_initrds(&c, initrds);
×
1390
        if (r < 0)
×
1391
                return r;
1392

UNCOV
1393
        r = context_prepare_execution(&c);
×
UNCOV
1394
        if (r < 0)
×
1395
                return r;
1396

UNCOV
1397
        t = table_new_vertical();
×
UNCOV
1398
        if (!t)
×
UNCOV
1399
                return log_oom();
×
1400

UNCOV
1401
        r = table_add_many(t,
×
1402
                           TABLE_FIELD, "Machine ID",
1403
                           TABLE_ID128, c.machine_id,
1404
                           TABLE_FIELD, "Kernel Image Type",
1405
                           TABLE_STRING, kernel_image_type_to_string(c.kernel_image_type),
1406
                           TABLE_FIELD, "Layout",
1407
                           TABLE_STRING, context_get_layout(&c),
1408
                           TABLE_FIELD, "Boot Root",
1409
                           TABLE_STRING, c.boot_root,
1410
                           TABLE_FIELD, "Entry Token Type",
1411
                           TABLE_STRING, boot_entry_token_type_to_string(c.entry_token_type),
1412
                           TABLE_FIELD, "Entry Token",
1413
                           TABLE_STRING, c.entry_token,
1414
                           TABLE_FIELD, "Entry Directory",
1415
                           TABLE_STRING, c.entry_dir,
1416
                           TABLE_FIELD, "Kernel Version",
1417
                           TABLE_VERSION, c.version,
1418
                           TABLE_FIELD, "Kernel",
1419
                           TABLE_STRING, c.kernel,
1420
                           TABLE_FIELD, "Initrds",
1421
                           TABLE_STRV, c.initrds,
1422
                           TABLE_FIELD, "Initrd Generator",
1423
                           TABLE_STRING, c.initrd_generator,
1424
                           TABLE_FIELD, "UKI Generator",
1425
                           TABLE_STRING, c.uki_generator,
1426
                           TABLE_FIELD, "Plugins",
1427
                           TABLE_STRV, c.plugins,
1428
                           TABLE_FIELD, "Plugin Environment",
1429
                           TABLE_STRV, c.envp);
UNCOV
1430
        if (r < 0)
×
UNCOV
1431
                return table_log_add_error(r);
×
1432

UNCOV
1433
        if (!sd_json_format_enabled(arg_json_format_flags)) {
×
1434
                r = table_add_many(t,
×
1435
                                   TABLE_FIELD, "Plugin Arguments",
1436
                                   TABLE_STRV, strv_skip(c.argv, 1));
1437
                if (r < 0)
×
1438
                        return table_log_add_error(r);
×
1439
        }
1440

1441
        table_set_ersatz_string(t, TABLE_ERSATZ_UNSET);
×
1442

1443
        for (size_t row = 1; row < table_get_rows(t); row++) {
×
UNCOV
1444
                _cleanup_free_ char *name = NULL;
×
1445

1446
                name = strdup(table_get_at(t, row, 0));
×
UNCOV
1447
                if (!name)
×
UNCOV
1448
                        return log_oom();
×
1449

1450
                r = table_set_json_field_name(t, row - 1, delete_chars(name, " "));
×
1451
                if (r < 0)
×
UNCOV
1452
                        return log_error_errno(r, "Failed to set JSON field name: %m");
×
1453
        }
1454

1455
        return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, /* show_header= */ false);
×
1456
}
1457

1458
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
×
1459
        _cleanup_close_ int fd = -EBADF;
×
1460
        int r;
×
1461

1462
        _cleanup_(context_done) Context c = CONTEXT_NULL;
×
1463
        r = context_from_cmdline(&c, ACTION_INSPECT);
×
1464
        if (r < 0)
×
1465
                return r;
1466

1467
        fd = chase_and_openat(c.rfd, "/usr/lib/modules", CHASE_AT_RESOLVE_IN_ROOT, O_DIRECTORY|O_RDONLY|O_CLOEXEC, NULL);
×
1468
        if (fd < 0)
×
1469
                return log_error_errno(fd, "Failed to open %s/usr/lib/modules/: %m", strempty(arg_root));
×
1470

UNCOV
1471
        _cleanup_free_ DirectoryEntries *de = NULL;
×
1472
        r = readdir_all(fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de);
×
1473
        if (r < 0)
×
1474
                return log_error_errno(r, "Failed to numerate /usr/lib/modules/ contents: %m");
×
1475

1476
        _cleanup_(table_unrefp) Table *table = NULL;
×
1477
        table = table_new("version", "has kernel", "path");
×
1478
        if (!table)
×
1479
                return log_oom();
×
1480

1481
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
×
1482
        table_set_align_percent(table, table_get_cell(table, 0, 1), 100);
×
1483
        (void) table_set_sort(table, (size_t) 0);
×
1484

1485
        FOREACH_ARRAY(d, de->entries, de->n_entries) {
×
UNCOV
1486
                _cleanup_free_ char *j = path_join("/usr/lib/modules/", (*d)->d_name);
×
UNCOV
1487
                if (!j)
×
1488
                        return log_oom();
×
1489

UNCOV
1490
                r = dirent_ensure_type(fd, *d);
×
1491
                if (r < 0) {
×
1492
                        if (r != -ENOENT) /* don't log if just gone by now */
×
1493
                                log_debug_errno(r, "Failed to check if '%s/%s' is a directory, ignoring: %m", strempty(arg_root), j);
×
UNCOV
1494
                        continue;
×
1495
                }
1496

1497
                if ((*d)->d_type != DT_DIR)
×
1498
                        continue;
×
1499

UNCOV
1500
                _cleanup_free_ char *fn = path_join((*d)->d_name, "vmlinuz");
×
UNCOV
1501
                if (!fn)
×
UNCOV
1502
                        return log_oom();
×
1503

1504
                bool exists;
×
UNCOV
1505
                if (faccessat(fd, fn, F_OK, AT_SYMLINK_NOFOLLOW) < 0) {
×
UNCOV
1506
                        if (errno != ENOENT)
×
UNCOV
1507
                                log_debug_errno(errno, "Failed to check if '%s/usr/lib/modules/%s/vmlinuz' exists, ignoring: %m", strempty(arg_root), (*d)->d_name);
×
1508

1509
                        exists = false;
1510
                } else
1511
                        exists = true;
1512

1513
                r = table_add_many(table,
×
1514
                                   TABLE_VERSION, (*d)->d_name,
1515
                                   TABLE_BOOLEAN_CHECKMARK, exists,
1516
                                   TABLE_SET_COLOR, ansi_highlight_green_red(exists),
1517
                                   TABLE_PATH, j);
1518
                if (r < 0)
×
UNCOV
1519
                        return table_log_add_error(r);
×
1520
        }
1521

1522
        return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
×
1523
}
1524

UNCOV
1525
static int help(void) {
×
UNCOV
1526
        _cleanup_free_ char *link = NULL;
×
UNCOV
1527
        int r;
×
1528

UNCOV
1529
        r = terminal_urlify_man("kernel-install", "8", &link);
×
UNCOV
1530
        if (r < 0)
×
UNCOV
1531
                return log_oom();
×
1532

UNCOV
1533
        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
×
1534
               "%5$sAdd and remove kernel and initrd images to and from the boot partition.%6$s\n"
1535
               "\n%3$sUsage:%4$s\n"
1536
               "  kernel-install [OPTIONS...] add [[[KERNEL-VERSION] KERNEL-IMAGE] [INITRD ...]]\n"
1537
               "  kernel-install [OPTIONS...] add-all\n"
1538
               "  kernel-install [OPTIONS...] remove KERNEL-VERSION\n"
1539
               "  kernel-install [OPTIONS...] inspect [[[KERNEL-VERSION] KERNEL-IMAGE]\n"
1540
               "                                      [INITRD ...]]\n"
1541
               "  kernel-install [OPTIONS...] list\n"
1542
               "\n%3$sOptions:%4$s\n"
1543
               "  -h --help                    Show this help\n"
1544
               "     --version                 Show package version\n"
1545
               "  -v --verbose                 Increase verbosity\n"
1546
               "     --esp-path=PATH           Path to the EFI System Partition (ESP)\n"
1547
               "     --boot-path=PATH          Path to the $BOOT partition\n"
1548
               "     --make-entry-directory=yes|no|auto\n"
1549
               "                               Create $BOOT/ENTRY-TOKEN/ directory\n"
1550
               "     --entry-type=type1|type2|all\n"
1551
               "                               Operate only on the specified bootloader\n"
1552
               "                               entry type\n"
1553
               "     --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n"
1554
               "                               Entry token to be used for this installation\n"
1555
               "     --no-pager                Do not pipe inspect output into a pager\n"
1556
               "     --json=pretty|short|off   Generate JSON output\n"
1557
               "     --no-legend               Do not show the headers and footers\n"
1558
               "     --root=PATH               Operate on an alternate filesystem root\n"
1559
               "     --image=PATH              Operate on disk image as filesystem root\n"
1560
               "     --image-policy=POLICY     Specify disk image dissection policy\n"
1561
               "\n"
1562
               "This program may also be invoked as 'installkernel':\n"
1563
               "  installkernel  [OPTIONS...] VERSION VMLINUZ [MAP] [INSTALLATION-DIR]\n"
1564
               "(The optional arguments are passed by kernel build system, but ignored.)\n"
1565
               "\n"
1566
               "See the %2$s for details.\n",
1567
               program_invocation_short_name,
1568
               link,
1569
               ansi_underline(),
1570
               ansi_normal(),
1571
               ansi_highlight(),
1572
               ansi_normal());
1573

1574
        return 0;
1575
}
1576

UNCOV
1577
static int parse_argv(int argc, char *argv[]) {
×
UNCOV
1578
        enum {
×
1579
                ARG_VERSION = 0x100,
1580
                ARG_NO_LEGEND,
1581
                ARG_ESP_PATH,
1582
                ARG_BOOT_PATH,
1583
                ARG_MAKE_ENTRY_DIRECTORY,
1584
                ARG_ENTRY_TOKEN,
1585
                ARG_NO_PAGER,
1586
                ARG_JSON,
1587
                ARG_ROOT,
1588
                ARG_IMAGE,
1589
                ARG_IMAGE_POLICY,
1590
                ARG_BOOT_ENTRY_TYPE,
1591
        };
UNCOV
1592
        static const struct option options[] = {
×
1593
                { "help",                 no_argument,       NULL, 'h'                      },
1594
                { "version",              no_argument,       NULL, ARG_VERSION              },
1595
                { "verbose",              no_argument,       NULL, 'v'                      },
1596
                { "esp-path",             required_argument, NULL, ARG_ESP_PATH             },
1597
                { "boot-path",            required_argument, NULL, ARG_BOOT_PATH            },
1598
                { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY },
1599
                { "entry-token",          required_argument, NULL, ARG_ENTRY_TOKEN          },
1600
                { "no-pager",             no_argument,       NULL, ARG_NO_PAGER             },
1601
                { "json",                 required_argument, NULL, ARG_JSON                 },
1602
                { "root",                 required_argument, NULL, ARG_ROOT                 },
1603
                { "image",                required_argument, NULL, ARG_IMAGE                },
1604
                { "image-policy",         required_argument, NULL, ARG_IMAGE_POLICY         },
1605
                { "no-legend",            no_argument,       NULL, ARG_NO_LEGEND            },
1606
                { "entry-type",           required_argument, NULL, ARG_BOOT_ENTRY_TYPE      },
1607
                {}
1608
        };
UNCOV
1609
        int t, r;
×
1610

1611
        assert(argc >= 0);
×
UNCOV
1612
        assert(argv);
×
1613

1614
        while ((t = getopt_long(argc, argv, "hv", options, NULL)) >= 0)
×
1615
                switch (t) {
×
UNCOV
1616
                case 'h':
×
1617
                        return help();
×
1618

1619
                case ARG_VERSION:
×
1620
                        return version();
×
1621

1622
                case ARG_NO_LEGEND:
×
1623
                        arg_legend = false;
×
1624
                        break;
×
1625

UNCOV
1626
                case 'v':
×
UNCOV
1627
                        log_set_max_level(LOG_DEBUG);
×
1628
                        arg_verbose = true;
×
1629
                        break;
×
1630

1631
                case ARG_ESP_PATH:
×
UNCOV
1632
                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_esp_path);
×
UNCOV
1633
                        if (r < 0)
×
1634
                                return log_oom();
×
1635
                        break;
1636

UNCOV
1637
                case ARG_BOOT_PATH:
×
1638
                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_xbootldr_path);
×
1639
                        if (r < 0)
×
UNCOV
1640
                                return log_oom();
×
1641
                        break;
1642

UNCOV
1643
                case ARG_MAKE_ENTRY_DIRECTORY:
×
UNCOV
1644
                        if (streq(optarg, "auto"))
×
UNCOV
1645
                                arg_make_entry_directory = -1;
×
1646
                        else {
1647
                                r = parse_boolean_argument("--make-entry-directory=", optarg, NULL);
×
1648
                                if (r < 0)
×
1649
                                        return r;
1650

UNCOV
1651
                                arg_make_entry_directory = r;
×
1652
                        }
1653
                        break;
1654

UNCOV
1655
                case ARG_ENTRY_TOKEN:
×
1656
                        r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
×
1657
                        if (r < 0)
×
1658
                                return r;
1659
                        break;
1660

UNCOV
1661
                case ARG_NO_PAGER:
×
1662
                        arg_pager_flags |= PAGER_DISABLE;
×
1663
                        break;
×
1664

UNCOV
1665
                case ARG_JSON:
×
UNCOV
1666
                        r = parse_json_argument(optarg, &arg_json_format_flags);
×
UNCOV
1667
                        if (r <= 0)
×
1668
                                return r;
1669
                        break;
1670

UNCOV
1671
                case ARG_ROOT:
×
UNCOV
1672
                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root);
×
UNCOV
1673
                        if (r < 0)
×
1674
                                return r;
1675
                        break;
1676

UNCOV
1677
                case ARG_IMAGE:
×
UNCOV
1678
                        r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
×
UNCOV
1679
                        if (r < 0)
×
1680
                                return r;
1681
                        break;
1682

1683
                case ARG_IMAGE_POLICY:
×
UNCOV
1684
                        r = parse_image_policy_argument(optarg, &arg_image_policy);
×
UNCOV
1685
                        if (r < 0)
×
1686
                                return r;
1687
                        break;
1688

1689
                case ARG_BOOT_ENTRY_TYPE: {
×
1690
                        if (isempty(optarg) || streq(optarg, "all")) {
×
UNCOV
1691
                                arg_boot_entry_type = _BOOT_ENTRY_TYPE_INVALID;
×
UNCOV
1692
                                break;
×
1693
                        }
1694

UNCOV
1695
                        BootEntryType e = boot_entry_type_from_string(optarg);
×
1696
                        if (e < 0)
×
1697
                                return log_error_errno(e, "Invalid entry type: %s", optarg);
×
UNCOV
1698
                        arg_boot_entry_type = e;
×
UNCOV
1699
                        break;
×
1700
                }
1701

1702
                case '?':
1703
                        return -EINVAL;
1704

UNCOV
1705
                default:
×
1706
                        assert_not_reached();
×
1707
                }
1708

UNCOV
1709
        if (arg_image && arg_root)
×
UNCOV
1710
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
×
1711

1712
        return 1;
1713
}
1714

UNCOV
1715
static int kernel_install_main(int argc, char *argv[]) {
×
1716
        static const Verb verbs[] = {
×
1717
                { "add",     1, VERB_ANY, 0,            verb_add     },
1718
                { "add-all", 1, 1,        0,            verb_add_all },
1719
                { "remove",  2, VERB_ANY, 0,            verb_remove  },
1720
                { "inspect", 1, VERB_ANY, VERB_DEFAULT, verb_inspect },
1721
                { "list",    1, 1,        0,            verb_list    },
1722
                {}
1723
        };
1724

1725
        return dispatch_verb(argc, argv, verbs, /* userdata= */ NULL);
×
1726
}
1727

1728
static int run(int argc, char* argv[]) {
×
1729
        int r;
×
1730

1731
        log_setup();
×
1732

1733
        r = parse_argv(argc, argv);
×
UNCOV
1734
        if (r <= 0)
×
UNCOV
1735
                return r;
×
1736

UNCOV
1737
        _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
×
UNCOV
1738
        _cleanup_(umount_and_freep) char *mounted_dir = NULL;
×
UNCOV
1739
        if (arg_image) {
×
UNCOV
1740
                assert(!arg_root);
×
1741

UNCOV
1742
                r = mount_image_privately_interactively(
×
1743
                                arg_image,
1744
                                arg_image_policy,
1745
                                DISSECT_IMAGE_GENERIC_ROOT |
1746
                                DISSECT_IMAGE_REQUIRE_ROOT |
1747
                                DISSECT_IMAGE_RELAX_VAR_CHECK |
1748
                                DISSECT_IMAGE_VALIDATE_OS |
1749
                                DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
1750
                                &mounted_dir,
1751
                                /* ret_dir_fd= */ NULL,
1752
                                &loop_device);
1753
                if (r < 0)
×
1754
                        return r;
1755

UNCOV
1756
                arg_root = strdup(mounted_dir);
×
UNCOV
1757
                if (!arg_root)
×
1758
                        return log_oom();
×
1759
        }
1760

UNCOV
1761
        if (invoked_as(argv, "installkernel"))
×
UNCOV
1762
                return run_as_installkernel(argc, argv);
×
1763

UNCOV
1764
        return kernel_install_main(argc, argv);
×
1765
}
1766

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

© 2026 Coveralls, Inc