Bug Summary

File:build-scan/../src/basic/string-util.h
Warning:line 63, column 13
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bootctl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I bootctl.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/boot/bootctl.c

../src/boot/bootctl.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <blkid.h>
4#include <ctype.h>
5#include <dirent.h>
6#include <errno(*__errno_location ()).h>
7#include <ftw.h>
8#include <getopt.h>
9#include <limits.h>
10#include <linux1/magic.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <sys/statfs.h>
18#include <unistd.h>
19
20#include "sd-id128.h"
21
22#include "alloc-util.h"
23#include "blkid-util.h"
24#include "bootspec.h"
25#include "copy.h"
26#include "dirent-util.h"
27#include "efivars.h"
28#include "fd-util.h"
29#include "fileio.h"
30#include "fs-util.h"
31#include "locale-util.h"
32#include "parse-util.h"
33#include "rm-rf.h"
34#include "stat-util.h"
35#include "string-util.h"
36#include "strv.h"
37#include "terminal-util.h"
38#include "umask-util.h"
39#include "util.h"
40#include "verbs.h"
41#include "virt.h"
42
43static char *arg_path = NULL((void*)0);
44static bool_Bool arg_print_path = false0;
45static bool_Bool arg_touch_variables = true1;
46
47static int acquire_esp(
48 bool_Bool unprivileged_mode,
49 uint32_t *ret_part,
50 uint64_t *ret_pstart,
51 uint64_t *ret_psize,
52 sd_id128_t *ret_uuid) {
53
54 char *np;
55 int r;
56
57 /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
58 * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
59 * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
60 * --list and --status work too, without noise about this). */
61
62 r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
63 if (r == -ENOKEY126)
64 return log_error_errno(r,({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 66, __func__, "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
"Alternatively, use --path= to specify path to mount point."
) : -abs(_e); })
65 "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 66, __func__, "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
"Alternatively, use --path= to specify path to mount point."
) : -abs(_e); })
66 "Alternatively, use --path= to specify path to mount point.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 66, __func__, "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
"Alternatively, use --path= to specify path to mount point."
) : -abs(_e); })
;
67 if (r < 0)
68 return r;
69
70 free_and_replace(arg_path, np)({ free(arg_path); (arg_path) = (np); (np) = ((void*)0); 0; }
)
;
71
72 log_debug("Using EFI System Partition at %s.", arg_path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 72, __func__, "Using EFI System Partition at %s."
, arg_path) : -abs(_e); })
;
73
74 return 0;
75}
76
77/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
78static int get_file_version(int fd, char **v) {
79 struct stat st;
80 char *buf;
81 const char *s, *e;
82 char *x = NULL((void*)0);
83 int r = 0;
84
85 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/boot/bootctl.c", 85
, __PRETTY_FUNCTION__); } while (0)
;
27
Taking false branch
28
Loop condition is false. Exiting loop
86 assert(v)do { if ((__builtin_expect(!!(!(v)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("v"), "../src/boot/bootctl.c", 86, __PRETTY_FUNCTION__
); } while (0)
;
29
Taking false branch
30
Loop condition is false. Exiting loop
87
88 if (fstat(fd, &st) < 0)
31
Assuming the condition is true
32
Taking true branch
89 return log_error_errno(errno, "Failed to stat EFI binary: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 89, __func__, "Failed to stat EFI binary: %m"
) : -abs(_e); })
;
33
Assuming the condition is false
34
'?' condition is false
35
Returning without writing to '*v'
90
91 if (st.st_size < 27) {
92 *v = NULL((void*)0);
93 return 0;
94 }
95
96 buf = mmap(NULL((void*)0), st.st_size, PROT_READ0x1, MAP_PRIVATE0x02, fd, 0);
97 if (buf == MAP_FAILED((void *) -1))
98 return log_error_errno(errno, "Failed to memory map EFI binary: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 98, __func__, "Failed to memory map EFI binary: %m"
) : -abs(_e); })
;
99
100 s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
101 if (!s)
102 goto finish;
103 s += 17;
104
105 e = memmem(s, st.st_size - (s - buf), " ####", 5);
106 if (!e || e - s < 3) {
107 log_error("Malformed version string.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 107, __func__, "Malformed version string."
) : -abs(_e); })
;
108 r = -EINVAL22;
109 goto finish;
110 }
111
112 x = strndup(s, e - s);
113 if (!x) {
114 r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 114
, __func__)
;
115 goto finish;
116 }
117 r = 1;
118
119finish:
120 (void) munmap(buf, st.st_size);
121 *v = x;
122 return r;
123}
124
125static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
126 char *p;
127 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
128 struct dirent *de;
129 int r = 0, c = 0;
130
131 p = strjoina(esp_path, "/", path)({ const char *_appendees_[] = { esp_path, "/", path }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
132 d = opendir(p);
133 if (!d) {
134 if (errno(*__errno_location ()) == ENOENT2)
135 return 0;
136
137 return log_error_errno(errno, "Failed to read \"%s\": %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 137, __func__, "Failed to read \"%s\": %m"
, p) : -abs(_e); })
;
138 }
139
140 FOREACH_DIRENT(de, d, break)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { break; } break; } else if (hidden_or_backup_file
((de)->d_name)) continue; else
{
141 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
142 _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0);
143
144 if (!endswith_no_case(de->d_name, ".efi"))
145 continue;
146
147 if (prefix && !startswith_no_case(de->d_name, prefix))
148 continue;
149
150 fd = openat(dirfd(d), de->d_name, O_RDONLY00|O_CLOEXEC02000000);
151 if (fd < 0)
152 return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 152, __func__, "Failed to open \"%s/%s\" for reading: %m"
, p, de->d_name) : -abs(_e); })
;
153
154 r = get_file_version(fd, &v);
155 if (r < 0)
156 return r;
157 if (r > 0)
158 printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT), path, de->d_name, v);
159 else
160 printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT), path, de->d_name);
161 c++;
162 }
163
164 return c;
165}
166
167static int status_binaries(const char *esp_path, sd_id128_t partition) {
168 int r;
169
170 printf("Boot Loader Binaries:\n");
171
172 if (!esp_path) {
173 printf(" ESP: Cannot find or access mount point of ESP.\n\n");
174 return -ENOENT2;
175 }
176
177 printf(" ESP: %s", esp_path);
178 if (!sd_id128_is_null(partition))
179 printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(partition)(partition).bytes[0], (partition).bytes[1], (partition).bytes
[2], (partition).bytes[3], (partition).bytes[4], (partition).
bytes[5], (partition).bytes[6], (partition).bytes[7], (partition
).bytes[8], (partition).bytes[9], (partition).bytes[10], (partition
).bytes[11], (partition).bytes[12], (partition).bytes[13], (partition
).bytes[14], (partition).bytes[15]
);
180 printf("\n");
181
182 r = enumerate_binaries(esp_path, "EFI/systemd", NULL((void*)0));
183 if (r == 0)
184 log_error("systemd-boot not installed in ESP.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 184, __func__, "systemd-boot not installed in ESP."
) : -abs(_e); })
;
185 else if (r < 0)
186 return r;
187
188 r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
189 if (r == 0)
190 log_error("No default/fallback boot loader installed in ESP.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 190, __func__, "No default/fallback boot loader installed in ESP."
) : -abs(_e); })
;
191 else if (r < 0)
192 return r;
193
194 printf("\n");
195
196 return 0;
197}
198
199static int print_efi_option(uint16_t id, bool_Bool in_order) {
200 _cleanup_free___attribute__((cleanup(freep))) char *title = NULL((void*)0);
201 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0);
202 sd_id128_t partition;
203 bool_Bool active;
204 int r = 0;
205
206 r = efi_get_boot_option(id, &title, &partition, &path, &active);
207 if (r < 0)
208 return r;
209
210 /* print only configured entries with partition information */
211 if (!path || sd_id128_is_null(partition))
212 return 0;
213
214 efi_tilt_backslashes(path);
215
216 printf(" Title: %s\n", strna(title));
217 printf(" ID: 0x%04X\n", id);
218 printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
219 printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition)(partition).bytes[0], (partition).bytes[1], (partition).bytes
[2], (partition).bytes[3], (partition).bytes[4], (partition).
bytes[5], (partition).bytes[6], (partition).bytes[7], (partition
).bytes[8], (partition).bytes[9], (partition).bytes[10], (partition
).bytes[11], (partition).bytes[12], (partition).bytes[13], (partition
).bytes[14], (partition).bytes[15]
);
220 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), path);
221 printf("\n");
222
223 return 0;
224}
225
226static int status_variables(void) {
227 int n_options, n_order;
228 _cleanup_free___attribute__((cleanup(freep))) uint16_t *options = NULL((void*)0), *order = NULL((void*)0);
229 int i;
230
231 n_options = efi_get_boot_options(&options);
232 if (n_options == -ENOENT2)
233 return log_error_errno(n_options,({ int _level = ((3)), _e = ((n_options)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 235, __func__, "Failed to access EFI variables, efivarfs"
" needs to be available at /sys/firmware/efi/efivars/.") : -
abs(_e); })
234 "Failed to access EFI variables, efivarfs"({ int _level = ((3)), _e = ((n_options)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 235, __func__, "Failed to access EFI variables, efivarfs"
" needs to be available at /sys/firmware/efi/efivars/.") : -
abs(_e); })
235 " needs to be available at /sys/firmware/efi/efivars/.")({ int _level = ((3)), _e = ((n_options)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 235, __func__, "Failed to access EFI variables, efivarfs"
" needs to be available at /sys/firmware/efi/efivars/.") : -
abs(_e); })
;
236 if (n_options < 0)
237 return log_error_errno(n_options, "Failed to read EFI boot entries: %m")({ int _level = ((3)), _e = ((n_options)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 237, __func__, "Failed to read EFI boot entries: %m"
) : -abs(_e); })
;
238
239 n_order = efi_get_boot_order(&order);
240 if (n_order == -ENOENT2)
241 n_order = 0;
242 else if (n_order < 0)
243 return log_error_errno(n_order, "Failed to read EFI boot order.")({ int _level = ((3)), _e = ((n_order)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 243, __func__, "Failed to read EFI boot order."
) : -abs(_e); })
;
244
245 /* print entries in BootOrder first */
246 printf("Boot Loader Entries in EFI Variables:\n");
247 for (i = 0; i < n_order; i++)
248 print_efi_option(order[i], true1);
249
250 /* print remaining entries */
251 for (i = 0; i < n_options; i++) {
252 int j;
253
254 for (j = 0; j < n_order; j++)
255 if (options[i] == order[j])
256 goto next_option;
257
258 print_efi_option(options[i], false0);
259
260 next_option:
261 continue;
262 }
263
264 return 0;
265}
266
267static int status_entries(const char *esp_path, sd_id128_t partition) {
268 int r;
269
270 _cleanup_(boot_config_free)__attribute__((cleanup(boot_config_free))) BootConfig config = {};
271
272 printf("Default Boot Entry:\n");
273
274 r = boot_entries_load_config(esp_path, &config);
275 if (r < 0)
276 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m",({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 277, __func__, "Failed to load bootspec config from \"%s/loader\": %m"
, esp_path) : -abs(_e); })
277 esp_path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 277, __func__, "Failed to load bootspec config from \"%s/loader\": %m"
, esp_path) : -abs(_e); })
;
278
279 if (config.default_entry < 0)
280 printf("%zu entries, no entry suitable as default\n", config.n_entries);
281 else {
282 const BootEntry *e = &config.entries[config.default_entry];
283
284 printf(" title: %s\n", boot_entry_title(e));
285 if (e->version)
286 printf(" version: %s\n", e->version);
287 if (e->kernel)
288 printf(" linux: %s\n", e->kernel);
289 if (!strv_isempty(e->initrd)) {
290 _cleanup_free___attribute__((cleanup(freep))) char *t;
291
292 t = strv_join(e->initrd, " ");
293 if (!t)
294 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 294
, __func__)
;
295
296 printf(" initrd: %s\n", t);
297 }
298 if (!strv_isempty(e->options)) {
299 _cleanup_free___attribute__((cleanup(freep))) char *t;
300
301 t = strv_join(e->options, " ");
302 if (!t)
303 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 303
, __func__)
;
304
305 printf(" options: %s\n", t);
306 }
307 if (e->device_tree)
308 printf(" devicetree: %s\n", e->device_tree);
309 puts("");
310 }
311
312 return 0;
313}
314
315static int compare_product(const char *a, const char *b) {
316 size_t x, y;
317
318 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/boot/bootctl.c", 318, __PRETTY_FUNCTION__
); } while (0)
;
319 assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("b"), "../src/boot/bootctl.c", 319, __PRETTY_FUNCTION__
); } while (0)
;
320
321 x = strcspn(a, " ");
322 y = strcspn(b, " ");
323 if (x != y)
324 return x < y ? -1 : x > y ? 1 : 0;
325
326 return strncmp(a, b, x);
327}
328
329static int compare_version(const char *a, const char *b) {
330 assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("a"), "../src/boot/bootctl.c", 330, __PRETTY_FUNCTION__
); } while (0)
;
331 assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("b"), "../src/boot/bootctl.c", 331, __PRETTY_FUNCTION__
); } while (0)
;
332
333 a += strcspn(a, " ");
334 a += strspn(a, " ");
335 b += strcspn(b, " ");
336 b += strspn(b, " ");
337
338 return strverscmp(a, b);
339}
340
341static int version_check(int fd_from, const char *from, int fd_to, const char *to) {
342 _cleanup_free___attribute__((cleanup(freep))) char *a = NULL((void*)0), *b = NULL((void*)0);
343 int r;
344
345 assert(fd_from >= 0)do { if ((__builtin_expect(!!(!(fd_from >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd_from >= 0"), "../src/boot/bootctl.c"
, 345, __PRETTY_FUNCTION__); } while (0)
;
346 assert(from)do { if ((__builtin_expect(!!(!(from)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("from"), "../src/boot/bootctl.c", 346, __PRETTY_FUNCTION__
); } while (0)
;
347 assert(fd_to >= 0)do { if ((__builtin_expect(!!(!(fd_to >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd_to >= 0"), "../src/boot/bootctl.c"
, 347, __PRETTY_FUNCTION__); } while (0)
;
348 assert(to)do { if ((__builtin_expect(!!(!(to)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("to"), "../src/boot/bootctl.c", 348, __PRETTY_FUNCTION__
); } while (0)
;
349
350 r = get_file_version(fd_from, &a);
351 if (r < 0)
352 return r;
353 if (r == 0) {
354 log_error("Source file \"%s\" does not carry version information!", from)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 354, __func__, "Source file \"%s\" does not carry version information!"
, from) : -abs(_e); })
;
355 return -EINVAL22;
356 }
357
358 r = get_file_version(fd_to, &b);
359 if (r < 0)
360 return r;
361 if (r == 0 || compare_product(a, b) != 0) {
362 log_notice("Skipping \"%s\", since it's owned by another boot loader.", to)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 362, __func__, "Skipping \"%s\", since it's owned by another boot loader."
, to) : -abs(_e); })
;
363 return -EEXIST17;
364 }
365
366 if (compare_version(a, b) < 0) {
367 log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 367, __func__, "Skipping \"%s\", since a newer boot loader version exists already."
, to) : -abs(_e); })
;
368 return -ESTALE116;
369 }
370
371 return 0;
372}
373
374static int copy_file_with_version_check(const char *from, const char *to, bool_Bool force) {
375 _cleanup_close___attribute__((cleanup(closep))) int fd_from = -1, fd_to = -1;
376 _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0);
377 int r;
378
379 fd_from = open(from, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400);
380 if (fd_from < 0)
381 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", from)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 381, __func__, "Failed to open \"%s\" for reading: %m"
, from) : -abs(_e); })
;
382
383 if (!force) {
384 fd_to = open(to, O_RDONLY00|O_CLOEXEC02000000|O_NOCTTY0400);
385 if (fd_to < 0) {
386 if (errno(*__errno_location ()) != -ENOENT2)
387 return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 387, __func__, "Failed to open \"%s\" for reading: %m"
, to) : -abs(_e); })
;
388 } else {
389 r = version_check(fd_from, from, fd_to, to);
390 if (r < 0)
391 return r;
392
393 if (lseek(fd_from, 0, SEEK_SET0) == (off_t) -1)
394 return log_error_errno(errno, "Failed to seek in \"%s\": %m", from)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 394, __func__, "Failed to seek in \"%s\": %m"
, from) : -abs(_e); })
;
395
396 fd_to = safe_close(fd_to);
397 }
398 }
399
400 r = tempfn_random(to, NULL((void*)0), &t);
401 if (r < 0)
402 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 402
, __func__)
;
403
404 RUN_WITH_UMASK(0000)for (__attribute__((cleanup(_reset_umask_))) struct _umask_struct_
_saved_umask_ = { umask(0000), 0 }; !_saved_umask_.quit ; _saved_umask_
.quit = 1)
{
405 fd_to = open(t, O_WRONLY01|O_CREAT0100|O_CLOEXEC02000000|O_EXCL0200|O_NOFOLLOW0400000, 0644);
406 if (fd_to < 0)
407 return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", t)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 407, __func__, "Failed to open \"%s\" for writing: %m"
, t) : -abs(_e); })
;
408 }
409
410 r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
411 if (r < 0) {
412 (void) unlink(t);
413 return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 413, __func__, "Failed to copy data from \"%s\" to \"%s\": %m"
, from, t) : -abs(_e); })
;
414 }
415
416 (void) copy_times(fd_from, fd_to);
417
418 if (fsync(fd_to) < 0) {
419 (void) unlink_noerrno(t);
420 return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 420, __func__, "Failed to copy data from \"%s\" to \"%s\": %m"
, from, t) : -abs(_e); })
;
421 }
422
423 (void) fsync_directory_of_file(fd_to);
424
425 if (renameat(AT_FDCWD-100, t, AT_FDCWD-100, to) < 0) {
426 (void) unlink_noerrno(t);
427 return log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", t, to)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 427, __func__, "Failed to rename \"%s\" to \"%s\": %m"
, t, to) : -abs(_e); })
;
428 }
429
430 log_info("Copied \"%s\" to \"%s\".", from, to)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 430, __func__, "Copied \"%s\" to \"%s\"."
, from, to) : -abs(_e); })
;
431
432 return 0;
433}
434
435static int mkdir_one(const char *prefix, const char *suffix) {
436 char *p;
437
438 p = strjoina(prefix, "/", suffix)({ const char *_appendees_[] = { prefix, "/", suffix }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
439 if (mkdir(p, 0700) < 0) {
440 if (errno(*__errno_location ()) != EEXIST17)
441 return log_error_errno(errno, "Failed to create \"%s\": %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 441, __func__, "Failed to create \"%s\": %m"
, p) : -abs(_e); })
;
442 } else
443 log_info("Created \"%s\".", p)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 443, __func__, "Created \"%s\".", p
) : -abs(_e); })
;
444
445 return 0;
446}
447
448static const char *efi_subdirs[] = {
449 "EFI",
450 "EFI/systemd",
451 "EFI/BOOT",
452 "loader",
453 "loader/entries",
454 NULL((void*)0)
455};
456
457static int create_dirs(const char *esp_path) {
458 const char **i;
459 int r;
460
461 STRV_FOREACH(i, efi_subdirs)for ((i) = (efi_subdirs); (i) && *(i); (i)++) {
462 r = mkdir_one(esp_path, *i);
463 if (r < 0)
464 return r;
465 }
466
467 return 0;
468}
469
470static int copy_one_file(const char *esp_path, const char *name, bool_Bool force) {
471 char *p, *q;
472 int r;
473
474 p = strjoina(BOOTLIBDIR "/", name)({ const char *_appendees_[] = { "/usr/lib/systemd/boot/efi" "/"
, name }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (
_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
475 q = strjoina(esp_path, "/EFI/systemd/", name)({ const char *_appendees_[] = { esp_path, "/EFI/systemd/", name
}; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ =
0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
476 r = copy_file_with_version_check(p, q, force);
477
478 if (startswith(name, "systemd-boot")) {
479 int k;
480 char *v;
481
482 /* Create the EFI default boot loader name (specified for removable devices) */
483 v = strjoina(esp_path, "/EFI/BOOT/BOOT",({ const char *_appendees_[] = { esp_path, "/EFI/BOOT/BOOT", name
+ (sizeof("""systemd-boot""") - 1) }; char *_d_, *_p_; size_t
_len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_
), typeof(&*(_appendees_))), sizeof(_appendees_)/sizeof((
_appendees_)[0]), ((void)0))) && _appendees_[_i_]; _i_
++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
484 name + STRLEN("systemd-boot"))({ const char *_appendees_[] = { esp_path, "/EFI/BOOT/BOOT", name
+ (sizeof("""systemd-boot""") - 1) }; char *_d_, *_p_; size_t
_len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_
), typeof(&*(_appendees_))), sizeof(_appendees_)/sizeof((
_appendees_)[0]), ((void)0))) && _appendees_[_i_]; _i_
++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
485 ascii_strupper(strrchr(v, '/') + 1);
486
487 k = copy_file_with_version_check(p, v, force);
488 if (k < 0 && r == 0)
489 r = k;
490 }
491
492 return r;
493}
494
495static int install_binaries(const char *esp_path, bool_Bool force) {
496 struct dirent *de;
497 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
498 int r = 0;
499
500 if (force) {
501 /* Don't create any of these directories when we are
502 * just updating. When we update we'll drop-in our
503 * files (unless there are newer ones already), but we
504 * won't create the directories for them in the first
505 * place. */
506 r = create_dirs(esp_path);
507 if (r < 0)
508 return r;
509 }
510
511 d = opendir(BOOTLIBDIR"/usr/lib/systemd/boot/efi");
512 if (!d)
513 return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 513, __func__, "Failed to open \""
"/usr/lib/systemd/boot/efi""\": %m") : -abs(_e); })
;
514
515 FOREACH_DIRENT(de, d, break)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { break; } break; } else if (hidden_or_backup_file
((de)->d_name)) continue; else
{
516 int k;
517
518 if (!endswith_no_case(de->d_name, ".efi"))
519 continue;
520
521 k = copy_one_file(esp_path, de->d_name, force);
522 if (k < 0 && r == 0)
523 r = k;
524 }
525
526 return r;
527}
528
529static bool_Bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
530 _cleanup_free___attribute__((cleanup(freep))) char *opath = NULL((void*)0);
531 sd_id128_t ouuid;
532 int r;
533
534 r = efi_get_boot_option(id, NULL((void*)0), &ouuid, &opath, NULL((void*)0));
535 if (r < 0)
536 return false0;
537 if (!sd_id128_equal(uuid, ouuid))
538 return false0;
539 if (!streq_ptr(path, opath))
540 return false0;
541
542 return true1;
543}
544
545static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
546 _cleanup_free___attribute__((cleanup(freep))) uint16_t *options = NULL((void*)0);
547 int n, i;
548
549 n = efi_get_boot_options(&options);
550 if (n < 0)
551 return n;
552
553 /* find already existing systemd-boot entry */
554 for (i = 0; i < n; i++)
555 if (same_entry(options[i], uuid, path)) {
556 *id = options[i];
557 return 1;
558 }
559
560 /* find free slot in the sorted BootXXXX variable list */
561 for (i = 0; i < n; i++)
562 if (i != options[i]) {
563 *id = i;
564 return 1;
565 }
566
567 /* use the next one */
568 if (i == 0xffff)
569 return -ENOSPC28;
570 *id = i;
571 return 0;
572}
573
574static int insert_into_order(uint16_t slot, bool_Bool first) {
575 _cleanup_free___attribute__((cleanup(freep))) uint16_t *order = NULL((void*)0);
576 uint16_t *t;
577 int n, i;
578
579 n = efi_get_boot_order(&order);
580 if (n <= 0)
581 /* no entry, add us */
582 return efi_set_boot_order(&slot, 1);
583
584 /* are we the first and only one? */
585 if (n == 1 && order[0] == slot)
586 return 0;
587
588 /* are we already in the boot order? */
589 for (i = 0; i < n; i++) {
590 if (order[i] != slot)
591 continue;
592
593 /* we do not require to be the first one, all is fine */
594 if (!first)
595 return 0;
596
597 /* move us to the first slot */
598 memmove(order + 1, order, i * sizeof(uint16_t));
599 order[0] = slot;
600 return efi_set_boot_order(order, n);
601 }
602
603 /* extend array */
604 t = realloc(order, (n + 1) * sizeof(uint16_t));
605 if (!t)
606 return -ENOMEM12;
607 order = t;
608
609 /* add us to the top or end of the list */
610 if (first) {
611 memmove(order + 1, order, n * sizeof(uint16_t));
612 order[0] = slot;
613 } else
614 order[n] = slot;
615
616 return efi_set_boot_order(order, n + 1);
617}
618
619static int remove_from_order(uint16_t slot) {
620 _cleanup_free___attribute__((cleanup(freep))) uint16_t *order = NULL((void*)0);
621 int n, i;
622
623 n = efi_get_boot_order(&order);
624 if (n <= 0)
625 return n;
626
627 for (i = 0; i < n; i++) {
628 if (order[i] != slot)
629 continue;
630
631 if (i + 1 < n)
632 memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
633 return efi_set_boot_order(order, n - 1);
634 }
635
636 return 0;
637}
638
639static int install_variables(const char *esp_path,
640 uint32_t part, uint64_t pstart, uint64_t psize,
641 sd_id128_t uuid, const char *path,
642 bool_Bool first) {
643 char *p;
644 uint16_t slot;
645 int r;
646
647 if (!is_efi_boot()) {
648 log_warning("Not booted with EFI, skipping EFI variable setup.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 648, __func__, "Not booted with EFI, skipping EFI variable setup."
) : -abs(_e); })
;
649 return 0;
650 }
651
652 p = strjoina(esp_path, path)({ const char *_appendees_[] = { esp_path, path }; char *_d_,
*_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
653 if (access(p, F_OK0) < 0) {
654 if (errno(*__errno_location ()) == ENOENT2)
655 return 0;
656
657 return log_error_errno(errno, "Cannot access \"%s\": %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 657, __func__, "Cannot access \"%s\": %m"
, p) : -abs(_e); })
;
658 }
659
660 r = find_slot(uuid, path, &slot);
661 if (r < 0)
662 return log_error_errno(r,({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 665, __func__, r == -2 ? "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?"
: "Failed to determine current boot order: %m") : -abs(_e); }
)
663 r == -ENOENT ?({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 665, __func__, r == -2 ? "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?"
: "Failed to determine current boot order: %m") : -abs(_e); }
)
664 "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 665, __func__, r == -2 ? "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?"
: "Failed to determine current boot order: %m") : -abs(_e); }
)
665 "Failed to determine current boot order: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 665, __func__, r == -2 ? "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?"
: "Failed to determine current boot order: %m") : -abs(_e); }
)
;
666
667 if (first || r == 0) {
668 r = efi_add_boot_option(slot, "Linux Boot Manager",
669 part, pstart, psize,
670 uuid, path);
671 if (r < 0)
672 return log_error_errno(r, "Failed to create EFI Boot variable entry: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 672, __func__, "Failed to create EFI Boot variable entry: %m"
) : -abs(_e); })
;
673
674 log_info("Created EFI boot entry \"Linux Boot Manager\".")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 674, __func__, "Created EFI boot entry \"Linux Boot Manager\"."
) : -abs(_e); })
;
675 }
676
677 return insert_into_order(slot, first);
678}
679
680static int remove_boot_efi(const char *esp_path) {
681 char *p;
682 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
683 struct dirent *de;
684 int r, c = 0;
685
686 p = strjoina(esp_path, "/EFI/BOOT")({ const char *_appendees_[] = { esp_path, "/EFI/BOOT" }; char
*_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
7
Loop condition is false. Execution continues on line 686
8
Loop condition is false. Execution continues on line 686
687 d = opendir(p);
688 if (!d) {
9
Assuming 'd' is non-null
10
Taking false branch
689 if (errno(*__errno_location ()) == ENOENT2)
690 return 0;
691
692 return log_error_errno(errno, "Failed to open directory \"%s\": %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 692, __func__, "Failed to open directory \"%s\": %m"
, p) : -abs(_e); })
;
693 }
694
695 FOREACH_DIRENT(de, d, break)for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { break; } break; } else if (hidden_or_backup_file
((de)->d_name)) continue; else
{
11
Loop condition is true. Entering loop body
12
Assuming 'de' is non-null
13
Taking false branch
14
Assuming the condition is false
15
Taking false branch
696 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
697 _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0);
16
'v' initialized to a null pointer value
698
699 if (!endswith_no_case(de->d_name, ".efi"))
17
Assuming the condition is false
18
Taking false branch
700 continue;
701
702 if (!startswith_no_case(de->d_name, "boot"))
19
Calling 'startswith_no_case'
22
Returning from 'startswith_no_case'
23
Taking false branch
703 continue;
704
705 fd = openat(dirfd(d), de->d_name, O_RDONLY00|O_CLOEXEC02000000);
706 if (fd < 0)
24
Assuming 'fd' is >= 0
25
Taking false branch
707 return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 707, __func__, "Failed to open \"%s/%s\" for reading: %m"
, p, de->d_name) : -abs(_e); })
;
708
709 r = get_file_version(fd, &v);
26
Calling 'get_file_version'
36
Returning from 'get_file_version'
710 if (r < 0)
37
Assuming 'r' is >= 0
38
Taking false branch
711 return r;
712 if (r > 0 && startswith(v, "systemd-boot ")) {
39
Assuming 'r' is > 0
40
Passing null pointer value via 1st parameter 's'
41
Calling 'startswith'
713 r = unlinkat(dirfd(d), de->d_name, 0);
714 if (r < 0)
715 return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 715, __func__, "Failed to remove \"%s/%s\": %m"
, p, de->d_name) : -abs(_e); })
;
716
717 log_info("Removed \"%s/%s\".", p, de->d_name)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 717, __func__, "Removed \"%s/%s\"."
, p, de->d_name) : -abs(_e); })
;
718 }
719
720 c++;
721 }
722
723 return c;
724}
725
726static int rmdir_one(const char *prefix, const char *suffix) {
727 char *p;
728
729 p = strjoina(prefix, "/", suffix)({ const char *_appendees_[] = { prefix, "/", suffix }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
730 if (rmdir(p) < 0) {
731 if (!IN_SET(errno, ENOENT, ENOTEMPTY)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){2, 39})/sizeof(int)]; switch((*__errno_location
())) { case 2: case 39: _found = 1; break; default: break; }
_found; })
)
732 return log_error_errno(errno, "Failed to remove \"%s\": %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/boot/bootctl.c", 732, __func__, "Failed to remove \"%s\": %m"
, p) : -abs(_e); })
;
733 } else
734 log_info("Removed \"%s\".", p)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 734, __func__, "Removed \"%s\".", p
) : -abs(_e); })
;
735
736 return 0;
737}
738
739static int remove_binaries(const char *esp_path) {
740 char *p;
741 int r, q;
742 unsigned i;
743
744 p = strjoina(esp_path, "/EFI/systemd")({ const char *_appendees_[] = { esp_path, "/EFI/systemd" }; char
*_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
4
Loop condition is false. Execution continues on line 744
5
Loop condition is false. Execution continues on line 744
745 r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
746
747 q = remove_boot_efi(esp_path);
6
Calling 'remove_boot_efi'
748 if (q < 0 && r == 0)
749 r = q;
750
751 for (i = ELEMENTSOF(efi_subdirs)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(efi_subdirs), typeof(&*(efi_subdirs))), sizeof(efi_subdirs
)/sizeof((efi_subdirs)[0]), ((void)0)))
-1; i > 0; i--) {
752 q = rmdir_one(esp_path, efi_subdirs[i-1]);
753 if (q < 0 && r == 0)
754 r = q;
755 }
756
757 return r;
758}
759
760static int remove_variables(sd_id128_t uuid, const char *path, bool_Bool in_order) {
761 uint16_t slot;
762 int r;
763
764 if (!is_efi_boot())
765 return 0;
766
767 r = find_slot(uuid, path, &slot);
768 if (r != 1)
769 return 0;
770
771 r = efi_remove_boot_option(slot);
772 if (r < 0)
773 return r;
774
775 if (in_order)
776 return remove_from_order(slot);
777
778 return 0;
779}
780
781static int install_loader_config(const char *esp_path) {
782
783 char machine_string[SD_ID128_STRING_MAX33];
784 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *t = NULL((void*)0);
785 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
786 sd_id128_t machine_id;
787 const char *p;
788 int r, fd;
789
790 r = sd_id128_get_machine(&machine_id);
791 if (r < 0)
792 return log_error_errno(r, "Failed to get machine id: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 792, __func__, "Failed to get machine id: %m"
) : -abs(_e); })
;
793
794 p = strjoina(esp_path, "/loader/loader.conf")({ const char *_appendees_[] = { esp_path, "/loader/loader.conf"
}; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ =
0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
795
796 if (access(p, F_OK0) >= 0) /* Silently skip creation if the file already exists (early check) */
797 return 0;
798
799 fd = open_tmpfile_linkable(p, O_WRONLY01|O_CLOEXEC02000000, &t);
800 if (fd < 0)
801 return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p)({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 801, __func__, "Failed to open \"%s\" for writing: %m"
, p) : -abs(_e); })
;
802
803 f = fdopen(fd, "we");
804 if (!f) {
805 safe_close(fd);
806 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 806
, __func__)
;
807 }
808
809 fprintf(f, "#timeout 3\n");
810 fprintf(f, "#console-mode keep\n");
811 fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
812
813 r = fflush_sync_and_check(f);
814 if (r < 0)
815 return log_error_errno(r, "Failed to write \"%s\": %m", p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 815, __func__, "Failed to write \"%s\": %m"
, p) : -abs(_e); })
;
816
817 r = link_tmpfile(fd, t, p);
818 if (r == -EEXIST17)
819 return 0; /* Silently skip creation if the file exists now (recheck) */
820 if (r < 0)
821 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 821, __func__, "Failed to move \"%s\" into place: %m"
, p) : -abs(_e); })
;
822
823 t = mfree(t);
824
825 return 1;
826}
827
828static int help(int argc, char *argv[], void *userdata) {
829
830 printf("%s [COMMAND] [OPTIONS...]\n"
831 "\n"
832 "Install, update or remove the systemd-boot EFI boot manager.\n\n"
833 " -h --help Show this help\n"
834 " --version Print version\n"
835 " --path=PATH Path to the EFI System Partition (ESP)\n"
836 " -p --print-path Print path to the EFI partition\n"
837 " --no-variables Don't touch EFI variables\n"
838 "\n"
839 "Commands:\n"
840 " status Show status of installed systemd-boot and EFI variables\n"
841 " list List boot entries\n"
842 " install Install systemd-boot to the ESP and EFI variables\n"
843 " update Update systemd-boot in the ESP and EFI variables\n"
844 " remove Remove systemd-boot from the ESP and EFI variables\n",
845 program_invocation_short_name);
846
847 return 0;
848}
849
850static int parse_argv(int argc, char *argv[]) {
851 enum {
852 ARG_PATH = 0x100,
853 ARG_VERSION,
854 ARG_NO_VARIABLES,
855 };
856
857 static const struct option options[] = {
858 { "help", no_argument0, NULL((void*)0), 'h' },
859 { "version", no_argument0, NULL((void*)0), ARG_VERSION },
860 { "path", required_argument1, NULL((void*)0), ARG_PATH },
861 { "print-path", no_argument0, NULL((void*)0), 'p' },
862 { "no-variables", no_argument0, NULL((void*)0), ARG_NO_VARIABLES },
863 { NULL((void*)0), 0, NULL((void*)0), 0 }
864 };
865
866 int c, r;
867
868 assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/boot/bootctl.c"
, 868, __PRETTY_FUNCTION__); } while (0)
;
869 assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("argv"), "../src/boot/bootctl.c", 869, __PRETTY_FUNCTION__
); } while (0)
;
870
871 while ((c = getopt_long(argc, argv, "hp", options, NULL((void*)0))) >= 0)
872 switch (c) {
873
874 case 'h':
875 help(0, NULL((void*)0), NULL((void*)0));
876 return 0;
877
878 case ARG_VERSION:
879 return version();
880
881 case ARG_PATH:
882 r = free_and_strdup(&arg_path, optarg);
883 if (r < 0)
884 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 884
, __func__)
;
885 break;
886
887 case 'p':
888 arg_print_path = true1;
889 break;
890
891 case ARG_NO_VARIABLES:
892 arg_touch_variables = false0;
893 break;
894
895 case '?':
896 return -EINVAL22;
897
898 default:
899 assert_not_reached("Unknown option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unknown option"), "../src/boot/bootctl.c", 899, __PRETTY_FUNCTION__
); } while (0)
;
900 }
901
902 return 1;
903}
904
905static void read_loader_efi_var(const char *name, char **var) {
906 int r;
907
908 r = efi_get_variable_string(EFI_VENDOR_LOADER((const sd_id128_t) { .bytes = { 0x4a, 0x67, 0xb0, 0x82, 0x0a
, 0x4c, 0x41, 0xcf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c,
0x4f }})
, name, var);
909 if (r < 0 && r != -ENOENT2)
910 log_warning_errno(r, "Failed to read EFI variable %s: %m", name)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 910, __func__, "Failed to read EFI variable %s: %m"
, name) : -abs(_e); })
;
911}
912
913static int verb_status(int argc, char *argv[], void *userdata) {
914
915 sd_id128_t uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
916 int r, k;
917
918 r = acquire_esp(geteuid() != 0, NULL((void*)0), NULL((void*)0), NULL((void*)0), &uuid);
919
920 if (arg_print_path) {
921 if (r == -EACCES13) /* If we couldn't acquire the ESP path, log about access errors (which is the only
922 * error the find_esp_and_warn() won't log on its own) */
923 return log_error_errno(r, "Failed to determine ESP: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 923, __func__, "Failed to determine ESP: %m"
) : -abs(_e); })
;
924 if (r < 0)
925 return r;
926
927 puts(arg_path);
928 return 0;
929 }
930
931 r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
932 * can show */
933
934 if (is_efi_boot()) {
935 _cleanup_free___attribute__((cleanup(freep))) char *fw_type = NULL((void*)0), *fw_info = NULL((void*)0), *loader = NULL((void*)0), *loader_path = NULL((void*)0), *stub = NULL((void*)0);
936 sd_id128_t loader_part_uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
937
938 read_loader_efi_var("LoaderFirmwareType", &fw_type);
939 read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
940 read_loader_efi_var("LoaderInfo", &loader);
941 read_loader_efi_var("StubInfo", &stub);
942 read_loader_efi_var("LoaderImageIdentifier", &loader_path);
943
944 if (loader_path)
945 efi_tilt_backslashes(loader_path);
946
947 k = efi_loader_get_device_part_uuid(&loader_part_uuid);
948 if (k < 0 && k != -ENOENT2)
949 r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m")({ int _level = ((4)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 949, __func__, "Failed to read EFI variable LoaderDevicePartUUID: %m"
) : -abs(_e); })
;
950
951 printf("System:\n");
952 printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
953
954 k = is_efi_secure_boot();
955 if (k < 0)
956 r = log_warning_errno(k, "Failed to query secure boot status: %m")({ int _level = ((4)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 956, __func__, "Failed to query secure boot status: %m"
) : -abs(_e); })
;
957 else
958 printf(" Secure Boot: %sd\n", enable_disable(k));
959
960 k = is_efi_secure_boot_setup_mode();
961 if (k < 0)
962 r = log_warning_errno(k, "Failed to query secure boot mode: %m")({ int _level = ((4)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 962, __func__, "Failed to query secure boot mode: %m"
) : -abs(_e); })
;
963 else
964 printf(" Setup Mode: %s\n", k ? "setup" : "user");
965 printf("\n");
966
967 printf("Current Loader:\n");
968 printf(" Product: %s\n", strna(loader));
969 if (stub)
970 printf(" Stub: %s\n", stub);
971 if (!sd_id128_is_null(loader_part_uuid))
972 printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
973 SD_ID128_FORMAT_VAL(loader_part_uuid)(loader_part_uuid).bytes[0], (loader_part_uuid).bytes[1], (loader_part_uuid
).bytes[2], (loader_part_uuid).bytes[3], (loader_part_uuid).bytes
[4], (loader_part_uuid).bytes[5], (loader_part_uuid).bytes[6]
, (loader_part_uuid).bytes[7], (loader_part_uuid).bytes[8], (
loader_part_uuid).bytes[9], (loader_part_uuid).bytes[10], (loader_part_uuid
).bytes[11], (loader_part_uuid).bytes[12], (loader_part_uuid)
.bytes[13], (loader_part_uuid).bytes[14], (loader_part_uuid).
bytes[15]
);
974 else
975 printf(" ESP: n/a\n");
976 printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
977 printf("\n");
978 } else
979 printf("System:\n Not booted with EFI\n\n");
980
981 if (arg_path) {
982 k = status_binaries(arg_path, uuid);
983 if (k < 0)
984 r = k;
985 }
986
987 if (is_efi_boot()) {
988 k = status_variables();
989 if (k < 0)
990 r = k;
991 }
992
993 if (arg_path) {
994 k = status_entries(arg_path, uuid);
995 if (k < 0)
996 r = k;
997 }
998
999 return r;
1000}
1001
1002static int verb_list(int argc, char *argv[], void *userdata) {
1003 _cleanup_(boot_config_free)__attribute__((cleanup(boot_config_free))) BootConfig config = {};
1004 sd_id128_t uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
1005 unsigned n;
1006 int r;
1007
1008 /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
1009 * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
1010 * the latter but not the former, hence request the mode, and log about EACCES. */
1011
1012 r = acquire_esp(geteuid() != 0, NULL((void*)0), NULL((void*)0), NULL((void*)0), &uuid);
1013 if (r == -EACCES13) /* We really need the ESP path for this call, hence also log about access errors */
1014 return log_error_errno(r, "Failed to determine ESP: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 1014, __func__, "Failed to determine ESP: %m"
) : -abs(_e); })
;
1015 if (r < 0)
1016 return r;
1017
1018 r = boot_entries_load_config(arg_path, &config);
1019 if (r < 0)
1020 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m",({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 1021, __func__, "Failed to load bootspec config from \"%s/loader\": %m"
, arg_path) : -abs(_e); })
1021 arg_path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/boot/bootctl.c", 1021, __func__, "Failed to load bootspec config from \"%s/loader\": %m"
, arg_path) : -abs(_e); })
;
1022
1023 printf("Available boot entries:\n");
1024
1025 for (n = 0; n < config.n_entries; n++) {
1026 const BootEntry *e = &config.entries[n];
1027
1028 printf(" title: %s%s%s%s%s%s\n",
1029 ansi_highlight(),
1030 boot_entry_title(e),
1031 ansi_normal(),
1032 ansi_highlight_green(),
1033 n == (unsigned) config.default_entry ? " (default)" : "",
1034 ansi_normal());
1035 if (e->version)
1036 printf(" version: %s\n", e->version);
1037 if (e->machine_id)
1038 printf(" machine-id: %s\n", e->machine_id);
1039 if (e->architecture)
1040 printf(" architecture: %s\n", e->architecture);
1041 if (e->kernel)
1042 printf(" linux: %s\n", e->kernel);
1043 if (!strv_isempty(e->initrd)) {
1044 _cleanup_free___attribute__((cleanup(freep))) char *t;
1045
1046 t = strv_join(e->initrd, " ");
1047 if (!t)
1048 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 1048
, __func__)
;
1049
1050 printf(" initrd: %s\n", t);
1051 }
1052 if (!strv_isempty(e->options)) {
1053 _cleanup_free___attribute__((cleanup(freep))) char *t;
1054
1055 t = strv_join(e->options, " ");
1056 if (!t)
1057 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/boot/bootctl.c", 1057
, __func__)
;
1058
1059 printf(" options: %s\n", t);
1060 }
1061 if (e->device_tree)
1062 printf(" devicetree: %s\n", e->device_tree);
1063
1064 puts("");
1065 }
1066
1067 return 0;
1068}
1069
1070static int verb_install(int argc, char *argv[], void *userdata) {
1071
1072 sd_id128_t uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
1073 uint64_t pstart = 0, psize = 0;
1074 uint32_t part = 0;
1075 bool_Bool install;
1076 int r;
1077
1078 r = acquire_esp(false0, &part, &pstart, &psize, &uuid);
1079 if (r < 0)
1080 return r;
1081
1082 install = streq(argv[0], "install")(strcmp((argv[0]),("install")) == 0);
1083
1084 RUN_WITH_UMASK(0002)for (__attribute__((cleanup(_reset_umask_))) struct _umask_struct_
_saved_umask_ = { umask(0002), 0 }; !_saved_umask_.quit ; _saved_umask_
.quit = 1)
{
1085 r = install_binaries(arg_path, install);
1086 if (r < 0)
1087 return r;
1088
1089 if (install) {
1090 r = install_loader_config(arg_path);
1091 if (r < 0)
1092 return r;
1093 }
1094 }
1095
1096 if (arg_touch_variables)
1097 r = install_variables(arg_path,
1098 part, pstart, psize, uuid,
1099 "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME"x64" ".efi",
1100 install);
1101
1102 return r;
1103}
1104
1105static int verb_remove(int argc, char *argv[], void *userdata) {
1106 sd_id128_t uuid = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }});
1107 int r;
1108
1109 r = acquire_esp(false0, NULL((void*)0), NULL((void*)0), NULL((void*)0), &uuid);
1110 if (r < 0)
1
Assuming 'r' is >= 0
2
Taking false branch
1111 return r;
1112
1113 r = remove_binaries(arg_path);
3
Calling 'remove_binaries'
1114
1115 if (arg_touch_variables) {
1116 int q;
1117
1118 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME"x64" ".efi", true1);
1119 if (q < 0 && r == 0)
1120 r = q;
1121 }
1122
1123 return r;
1124}
1125
1126static int bootctl_main(int argc, char *argv[]) {
1127
1128 static const Verb verbs[] = {
1129 { "help", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, help },
1130 { "status", VERB_ANY((unsigned) -1), 1, VERB_DEFAULT, verb_status },
1131 { "list", VERB_ANY((unsigned) -1), 1, 0, verb_list },
1132 { "install", VERB_ANY((unsigned) -1), 1, VERB_MUST_BE_ROOT, verb_install },
1133 { "update", VERB_ANY((unsigned) -1), 1, VERB_MUST_BE_ROOT, verb_install },
1134 { "remove", VERB_ANY((unsigned) -1), 1, VERB_MUST_BE_ROOT, verb_remove },
1135 {}
1136 };
1137
1138 return dispatch_verb(argc, argv, verbs, NULL((void*)0));
1139}
1140
1141int main(int argc, char *argv[]) {
1142 int r;
1143
1144 log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD);
1145 log_open();
1146
1147 /* If we run in a container, automatically turn of EFI file system access */
1148 if (detect_container() > 0)
1149 arg_touch_variables = false0;
1150
1151 r = parse_argv(argc, argv);
1152 if (r <= 0)
1153 goto finish;
1154
1155 r = bootctl_main(argc, argv);
1156
1157 finish:
1158 free(arg_path);
1159 return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0;
1160}

../src/basic/string-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <string.h>
8
9#include "macro.h"
10
11/* What is interpreted as whitespace? */
12#define WHITESPACE" \t\n\r" " \t\n\r"
13#define NEWLINE"\n\r" "\n\r"
14#define QUOTES"\"\'" "\"\'"
15#define COMMENTS"#;" "#;"
16#define GLOB_CHARS"*?[" "*?["
17#define DIGITS"0123456789" "0123456789"
18#define LOWERCASE_LETTERS"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
19#define UPPERCASE_LETTERS"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
20#define LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" LOWERCASE_LETTERS"abcdefghijklmnopqrstuvwxyz" UPPERCASE_LETTERS"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21#define ALPHANUMERICAL"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" DIGITS"0123456789"
22#define HEXDIGITS"0123456789" "abcdefABCDEF" DIGITS"0123456789" "abcdefABCDEF"
23
24#define streq(a,b)(strcmp((a),(b)) == 0) (strcmp((a),(b)) == 0)
25#define strneq(a, b, n)(strncmp((a), (b), (n)) == 0) (strncmp((a), (b), (n)) == 0)
26#define strcaseeq(a,b)(strcasecmp((a),(b)) == 0) (strcasecmp((a),(b)) == 0)
27#define strncaseeq(a, b, n)(strncasecmp((a), (b), (n)) == 0) (strncasecmp((a), (b), (n)) == 0)
28
29int strcmp_ptr(const char *a, const char *b) _pure___attribute__ ((pure));
30
31static inline bool_Bool streq_ptr(const char *a, const char *b) {
32 return strcmp_ptr(a, b) == 0;
33}
34
35static inline const char* strempty(const char *s) {
36 return s ?: "";
37}
38
39static inline const char* strnull(const char *s) {
40 return s ?: "(null)";
41}
42
43static inline const char *strna(const char *s) {
44 return s ?: "n/a";
45}
46
47static inline bool_Bool isempty(const char *p) {
48 return !p || !p[0];
49}
50
51static inline const char *empty_to_null(const char *p) {
52 return isempty(p) ? NULL((void*)0) : p;
53}
54
55static inline const char *empty_to_dash(const char *str) {
56 return isempty(str) ? "-" : str;
57}
58
59static inline char *startswith(const char *s, const char *prefix) {
60 size_t l;
61
62 l = strlen(prefix);
63 if (strncmp(s, prefix, l) == 0)
42
Null pointer passed to 1st parameter expecting 'nonnull'
64 return (char*) s + l;
65
66 return NULL((void*)0);
67}
68
69static inline char *startswith_no_case(const char *s, const char *prefix) {
70 size_t l;
71
72 l = strlen(prefix);
73 if (strncasecmp(s, prefix, l) == 0)
20
Taking true branch
74 return (char*) s + l;
21
Returning pointer, which participates in a condition later
75
76 return NULL((void*)0);
77}
78
79char *endswith(const char *s, const char *postfix) _pure___attribute__ ((pure));
80char *endswith_no_case(const char *s, const char *postfix) _pure___attribute__ ((pure));
81
82char *first_word(const char *s, const char *word) _pure___attribute__ ((pure));
83
84const char* split(const char **state, size_t *l, const char *separator, bool_Bool quoted);
85
86#define FOREACH_WORD(word, length, s, state)for ((state) = (s), (word) = split(&(state), &(length
), (" \t\n\r"), (0)); (word); (word) = split(&(state), &
(length), (" \t\n\r"), (0)))
\
87 _FOREACH_WORD(word, length, s, WHITESPACE, false, state)for ((state) = (s), (word) = split(&(state), &(length
), (" \t\n\r"), (0)); (word); (word) = split(&(state), &
(length), (" \t\n\r"), (0)))
88
89#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (0)); (word); (word) = split(&(state), &
(length), (separator), (0)))
\
90 _FOREACH_WORD(word, length, s, separator, false, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (0)); (word); (word) = split(&(state), &
(length), (separator), (0)))
91
92#define _FOREACH_WORD(word, length, s, separator, quoted, state)for ((state) = (s), (word) = split(&(state), &(length
), (separator), (quoted)); (word); (word) = split(&(state
), &(length), (separator), (quoted)))
\
93 for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
94
95char *strappend(const char *s, const char *suffix);
96char *strnappend(const char *s, const char *suffix, size_t length);
97
98char *strjoin_real(const char *x, ...) _sentinel___attribute__ ((sentinel));
99#define strjoin(a, ...)strjoin_real((a), ..., ((void*)0)) strjoin_real((a), __VA_ARGS__, NULL((void*)0))
100
101#define strjoina(a, ...)({ const char *_appendees_[] = { a, ... }; char *_d_, *_p_; size_t
_len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (
__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_
), typeof(&*(_appendees_))), sizeof(_appendees_)/sizeof((
_appendees_)[0]), ((void)0))) && _appendees_[_i_]; _i_
++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
\
102 ({ \
103 const char *_appendees_[] = { a, __VA_ARGS__ }; \
104 char *_d_, *_p_; \
105 size_t _len_ = 0; \
106 size_t _i_; \
107 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0)))
&& _appendees_[_i_]; _i_++) \
108 _len_ += strlen(_appendees_[_i_]); \
109 _p_ = _d_ = alloca(_len_ + 1)__builtin_alloca (_len_ + 1); \
110 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0)))
&& _appendees_[_i_]; _i_++) \
111 _p_ = stpcpy(_p_, _appendees_[_i_]); \
112 *_p_ = 0; \
113 _d_; \
114 })
115
116char *strstrip(char *s);
117char *delete_chars(char *s, const char *bad);
118char *delete_trailing_chars(char *s, const char *bad);
119char *truncate_nl(char *s);
120
121static inline char *skip_leading_chars(const char *s, const char *bad) {
122
123 if (!s)
124 return NULL((void*)0);
125
126 if (!bad)
127 bad = WHITESPACE" \t\n\r";
128
129 return (char*) s + strspn(s, bad);
130}
131
132char ascii_tolower(char x);
133char *ascii_strlower(char *s);
134char *ascii_strlower_n(char *s, size_t n);
135
136char ascii_toupper(char x);
137char *ascii_strupper(char *s);
138
139int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
140int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
141
142bool_Bool chars_intersect(const char *a, const char *b) _pure___attribute__ ((pure));
143
144static inline bool_Bool _pure___attribute__ ((pure)) in_charset(const char *s, const char* charset) {
145 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/string-util.h", 145,
__PRETTY_FUNCTION__); } while (0)
;
146 assert(charset)do { if ((__builtin_expect(!!(!(charset)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("charset"), "../src/basic/string-util.h"
, 146, __PRETTY_FUNCTION__); } while (0)
;
147 return s[strspn(s, charset)] == '\0';
148}
149
150bool_Bool string_has_cc(const char *p, const char *ok) _pure___attribute__ ((pure));
151
152char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
153static inline char *ellipsize(const char *s, size_t length, unsigned percent) {
154 return ellipsize_mem(s, strlen(s), length, percent);
155}
156
157char *cellescape(char *buf, size_t len, const char *s);
158
159/* This limit is arbitrary, enough to give some idea what the string contains */
160#define CELLESCAPE_DEFAULT_LENGTH64 64
161
162bool_Bool nulstr_contains(const char *nulstr, const char *needle);
163
164char* strshorten(char *s, size_t l);
165
166char *strreplace(const char *text, const char *old_string, const char *new_string);
167
168char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
169
170char *strextend_with_separator(char **x, const char *separator, ...) _sentinel___attribute__ ((sentinel));
171
172#define strextend(x, ...)strextend_with_separator(x, ((void*)0), ...) strextend_with_separator(x, NULL((void*)0), __VA_ARGS__)
173
174char *strrep(const char *s, unsigned n);
175
176int split_pair(const char *s, const char *sep, char **l, char **r);
177
178int free_and_strdup(char **p, const char *s);
179int free_and_strndup(char **p, const char *s, size_t l);
180
181/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
182static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
183
184 if (needlelen <= 0)
185 return (void*) haystack;
186
187 if (haystacklen < needlelen)
188 return NULL((void*)0);
189
190 assert(haystack)do { if ((__builtin_expect(!!(!(haystack)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("haystack"), "../src/basic/string-util.h"
, 190, __PRETTY_FUNCTION__); } while (0)
;
191 assert(needle)do { if ((__builtin_expect(!!(!(needle)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("needle"), "../src/basic/string-util.h",
191, __PRETTY_FUNCTION__); } while (0)
;
192
193 return memmem(haystack, haystacklen, needle, needlelen);
194}
195
196#if !HAVE_EXPLICIT_BZERO1
197void explicit_bzero(void *p, size_t l);
198#endif
199
200char *string_erase(char *x);
201
202char *string_free_erase(char *s);
203DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase)static inline void string_free_erasep(char * *p) { if (*p) string_free_erase
(*p); }
;
204#define _cleanup_string_free_erase___attribute__((cleanup(string_free_erasep))) _cleanup_(string_free_erasep)__attribute__((cleanup(string_free_erasep)))
205
206bool_Bool string_is_safe(const char *p) _pure___attribute__ ((pure));
207
208static inline size_t strlen_ptr(const char *s) {
209 if (!s)
210 return 0;
211
212 return strlen(s);
213}
214
215/* Like startswith(), but operates on arbitrary memory blocks */
216static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
217 size_t n;
218
219 assert(token)do { if ((__builtin_expect(!!(!(token)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("token"), "../src/basic/string-util.h", 219
, __PRETTY_FUNCTION__); } while (0)
;
220
221 n = strlen(token);
222 if (sz < n)
223 return NULL((void*)0);
224
225 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/string-util.h", 225,
__PRETTY_FUNCTION__); } while (0)
;
226
227 if (memcmp(p, token, n) != 0)
228 return NULL((void*)0);
229
230 return (uint8_t*) p + n;
231}