]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efi-loader.c
rpm: restart services in %posttrans
[thirdparty/systemd.git] / src / shared / efi-loader.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdlib.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include "alloc-util.h"
8 #include "dirent-util.h"
9 #include "efi-loader.h"
10 #include "efivars.h"
11 #include "fd-util.h"
12 #include "io-util.h"
13 #include "parse-util.h"
14 #include "sort-util.h"
15 #include "stat-util.h"
16 #include "stdio-util.h"
17 #include "string-util.h"
18 #include "utf8.h"
19 #include "virt.h"
20
21 #if ENABLE_EFI
22
23 #define LOAD_OPTION_ACTIVE 0x00000001
24 #define MEDIA_DEVICE_PATH 0x04
25 #define MEDIA_HARDDRIVE_DP 0x01
26 #define MEDIA_FILEPATH_DP 0x04
27 #define SIGNATURE_TYPE_GUID 0x02
28 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
29 #define END_DEVICE_PATH_TYPE 0x7f
30 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
31 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
32
33 #define boot_option__contents \
34 { \
35 uint32_t attr; \
36 uint16_t path_len; \
37 uint16_t title[]; \
38 }
39
40 struct boot_option boot_option__contents;
41 struct boot_option__packed boot_option__contents _packed_;
42 assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title));
43 /* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
44 * the *size* of the structure should not be used anywhere below. */
45
46 struct drive_path {
47 uint32_t part_nr;
48 uint64_t part_start;
49 uint64_t part_size;
50 char signature[16];
51 uint8_t mbr_type;
52 uint8_t signature_type;
53 } _packed_;
54
55 #define device_path__contents \
56 { \
57 uint8_t type; \
58 uint8_t sub_type; \
59 uint16_t length; \
60 union { \
61 uint16_t path[0]; \
62 struct drive_path drive; \
63 }; \
64 }
65
66 struct device_path device_path__contents;
67 struct device_path__packed device_path__contents _packed_;
68 assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
69
70 int efi_reboot_to_firmware_supported(void) {
71 _cleanup_free_ void *v = NULL;
72 static int cache = -1;
73 uint64_t b;
74 size_t s;
75 int r;
76
77 if (cache > 0)
78 return 0;
79 if (cache == 0)
80 return -EOPNOTSUPP;
81
82 if (!is_efi_boot())
83 goto not_supported;
84
85 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
86 if (r == -ENOENT)
87 goto not_supported; /* variable doesn't exist? it's not supported then */
88 if (r < 0)
89 return r;
90 if (s != sizeof(uint64_t))
91 return -EINVAL;
92
93 b = *(uint64_t*) v;
94 if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
95 goto not_supported; /* bit unset? it's not supported then */
96
97 cache = 1;
98 return 0;
99
100 not_supported:
101 cache = 0;
102 return -EOPNOTSUPP;
103 }
104
105 static int get_os_indications(uint64_t *ret) {
106 static struct stat cache_stat = {};
107 _cleanup_free_ void *v = NULL;
108 _cleanup_free_ char *fn = NULL;
109 static uint64_t cache;
110 struct stat new_stat;
111 size_t s;
112 int r;
113
114 assert(ret);
115
116 /* Let's verify general support first */
117 r = efi_reboot_to_firmware_supported();
118 if (r < 0)
119 return r;
120
121 fn = efi_variable_path(EFI_VENDOR_GLOBAL, "OsIndications");
122 if (!fn)
123 return -ENOMEM;
124
125 /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
126 if (stat(fn, &new_stat) < 0) {
127 if (errno != ENOENT)
128 return -errno;
129
130 /* Doesn't exist? Then we can exit early (also see below) */
131 *ret = 0;
132 return 0;
133
134 } else if (stat_inode_unmodified(&new_stat, &cache_stat)) {
135 /* inode didn't change, we can return the cached value */
136 *ret = cache;
137 return 0;
138 }
139
140 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
141 if (r == -ENOENT) {
142 /* Some firmware implementations that do support OsIndications and report that with
143 * OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
144 * pretend it's 0 then, to hide this implementation detail. Note that this call will return
145 * -ENOENT then only if the support for OsIndications is missing entirely, as determined by
146 * efi_reboot_to_firmware_supported() above. */
147 *ret = 0;
148 return 0;
149 }
150 if (r < 0)
151 return r;
152 if (s != sizeof(uint64_t))
153 return -EINVAL;
154
155 cache_stat = new_stat;
156 *ret = cache = *(uint64_t *)v;
157 return 0;
158 }
159
160 int efi_get_reboot_to_firmware(void) {
161 int r;
162 uint64_t b;
163
164 r = get_os_indications(&b);
165 if (r < 0)
166 return r;
167
168 return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
169 }
170
171 int efi_set_reboot_to_firmware(bool value) {
172 int r;
173 uint64_t b, b_new;
174
175 r = get_os_indications(&b);
176 if (r < 0)
177 return r;
178
179 b_new = UPDATE_FLAG(b, EFI_OS_INDICATIONS_BOOT_TO_FW_UI, value);
180
181 /* Avoid writing to efi vars store if we can due to firmware bugs. */
182 if (b != b_new)
183 return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
184
185 return 0;
186 }
187
188 static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
189 size_t l = 0;
190
191 /* Returns the size of the string in bytes without the terminating two zero bytes */
192
193 if (buf_len_bytes % sizeof(uint16_t) != 0)
194 return -EINVAL;
195
196 while (l < buf_len_bytes / sizeof(uint16_t)) {
197 if (s[l] == 0)
198 return (l + 1) * sizeof(uint16_t);
199 l++;
200 }
201
202 return -EINVAL; /* The terminator was not found */
203 }
204
205 struct guid {
206 uint32_t u1;
207 uint16_t u2;
208 uint16_t u3;
209 uint8_t u4[8];
210 } _packed_;
211
212 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
213 uint32_t u1;
214 uint16_t u2, u3;
215 const struct guid *uuid = guid;
216
217 memcpy(&u1, &uuid->u1, sizeof(uint32_t));
218 id128->bytes[0] = (u1 >> 24) & 0xff;
219 id128->bytes[1] = (u1 >> 16) & 0xff;
220 id128->bytes[2] = (u1 >> 8) & 0xff;
221 id128->bytes[3] = u1 & 0xff;
222 memcpy(&u2, &uuid->u2, sizeof(uint16_t));
223 id128->bytes[4] = (u2 >> 8) & 0xff;
224 id128->bytes[5] = u2 & 0xff;
225 memcpy(&u3, &uuid->u3, sizeof(uint16_t));
226 id128->bytes[6] = (u3 >> 8) & 0xff;
227 id128->bytes[7] = u3 & 0xff;
228 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
229 }
230
231 int efi_get_boot_option(
232 uint16_t id,
233 char **title,
234 sd_id128_t *part_uuid,
235 char **path,
236 bool *active) {
237
238 char boot_id[9];
239 _cleanup_free_ uint8_t *buf = NULL;
240 size_t l;
241 struct boot_option *header;
242 ssize_t title_size;
243 _cleanup_free_ char *s = NULL, *p = NULL;
244 sd_id128_t p_uuid = SD_ID128_NULL;
245 int r;
246
247 if (!is_efi_boot())
248 return -EOPNOTSUPP;
249
250 xsprintf(boot_id, "Boot%04X", id);
251 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
252 if (r < 0)
253 return r;
254 if (l < offsetof(struct boot_option, title))
255 return -ENOENT;
256
257 header = (struct boot_option *)buf;
258 title_size = utf16_size(header->title, l - offsetof(struct boot_option, title));
259 if (title_size < 0)
260 return title_size;
261
262 if (title) {
263 s = utf16_to_utf8(header->title, title_size);
264 if (!s)
265 return -ENOMEM;
266 }
267
268 if (header->path_len > 0) {
269 uint8_t *dbuf;
270 size_t dnext, doff;
271
272 doff = offsetof(struct boot_option, title) + title_size;
273 dbuf = buf + doff;
274 if (header->path_len > l - doff)
275 return -EINVAL;
276
277 dnext = 0;
278 while (dnext < header->path_len) {
279 struct device_path *dpath;
280
281 dpath = (struct device_path *)(dbuf + dnext);
282 if (dpath->length < 4)
283 break;
284
285 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
286 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
287 break;
288
289 dnext += dpath->length;
290
291 /* Type 0x04 – Media Device Path */
292 if (dpath->type != MEDIA_DEVICE_PATH)
293 continue;
294
295 /* Sub-Type 1 – Hard Drive */
296 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
297 /* 0x02 – GUID Partition Table */
298 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
299 continue;
300
301 /* 0x02 – GUID signature */
302 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
303 continue;
304
305 if (part_uuid)
306 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
307 continue;
308 }
309
310 /* Sub-Type 4 – File Path */
311 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
312 p = utf16_to_utf8(dpath->path, dpath->length-4);
313 if (!p)
314 return -ENOMEM;
315
316 efi_tilt_backslashes(p);
317 continue;
318 }
319 }
320 }
321
322 if (title)
323 *title = TAKE_PTR(s);
324 if (part_uuid)
325 *part_uuid = p_uuid;
326 if (path)
327 *path = TAKE_PTR(p);
328 if (active)
329 *active = header->attr & LOAD_OPTION_ACTIVE;
330
331 return 0;
332 }
333
334 static void to_utf16(uint16_t *dest, const char *src) {
335 int i;
336
337 for (i = 0; src[i] != '\0'; i++)
338 dest[i] = src[i];
339 dest[i] = '\0';
340 }
341
342 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
343 struct guid uuid = {
344 .u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3],
345 .u2 = id.bytes[4] << 8 | id.bytes[5],
346 .u3 = id.bytes[6] << 8 | id.bytes[7],
347 };
348 memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4));
349 memcpy(guid, &uuid, sizeof(uuid));
350 }
351
352 static uint16_t *tilt_slashes(uint16_t *s) {
353 uint16_t *p;
354
355 for (p = s; *p; p++)
356 if (*p == '/')
357 *p = '\\';
358
359 return s;
360 }
361
362 int efi_add_boot_option(
363 uint16_t id,
364 const char *title,
365 uint32_t part,
366 uint64_t pstart,
367 uint64_t psize,
368 sd_id128_t part_uuid,
369 const char *path) {
370
371 size_t size, title_len, path_len;
372 _cleanup_free_ char *buf = NULL;
373 struct boot_option *option;
374 struct device_path *devicep;
375 char boot_id[9];
376
377 if (!is_efi_boot())
378 return -EOPNOTSUPP;
379
380 title_len = (strlen(title)+1) * 2;
381 path_len = (strlen(path)+1) * 2;
382
383 buf = malloc0(offsetof(struct boot_option, title) + title_len +
384 sizeof(struct drive_path) +
385 sizeof(struct device_path) + path_len);
386 if (!buf)
387 return -ENOMEM;
388
389 /* header */
390 option = (struct boot_option *)buf;
391 option->attr = LOAD_OPTION_ACTIVE;
392 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
393 offsetof(struct device_path, path) + path_len +
394 offsetof(struct device_path, path);
395 to_utf16(option->title, title);
396 size = offsetof(struct boot_option, title) + title_len;
397
398 /* partition info */
399 devicep = (struct device_path *)(buf + size);
400 devicep->type = MEDIA_DEVICE_PATH;
401 devicep->sub_type = MEDIA_HARDDRIVE_DP;
402 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
403 memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t));
404 memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t));
405 memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t));
406 id128_to_efi_guid(part_uuid, devicep->drive.signature);
407 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
408 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
409 size += devicep->length;
410
411 /* path to loader */
412 devicep = (struct device_path *)(buf + size);
413 devicep->type = MEDIA_DEVICE_PATH;
414 devicep->sub_type = MEDIA_FILEPATH_DP;
415 devicep->length = offsetof(struct device_path, path) + path_len;
416 to_utf16(devicep->path, path);
417 tilt_slashes(devicep->path);
418 size += devicep->length;
419
420 /* end of path */
421 devicep = (struct device_path *)(buf + size);
422 devicep->type = END_DEVICE_PATH_TYPE;
423 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
424 devicep->length = offsetof(struct device_path, path);
425 size += devicep->length;
426
427 xsprintf(boot_id, "Boot%04X", id);
428 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
429 }
430
431 int efi_remove_boot_option(uint16_t id) {
432 char boot_id[9];
433
434 if (!is_efi_boot())
435 return -EOPNOTSUPP;
436
437 xsprintf(boot_id, "Boot%04X", id);
438 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
439 }
440
441 int efi_get_boot_order(uint16_t **order) {
442 _cleanup_free_ void *buf = NULL;
443 size_t l;
444 int r;
445
446 if (!is_efi_boot())
447 return -EOPNOTSUPP;
448
449 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
450 if (r < 0)
451 return r;
452
453 if (l <= 0)
454 return -ENOENT;
455
456 if (l % sizeof(uint16_t) > 0 ||
457 l / sizeof(uint16_t) > INT_MAX)
458 return -EINVAL;
459
460 *order = TAKE_PTR(buf);
461 return (int) (l / sizeof(uint16_t));
462 }
463
464 int efi_set_boot_order(uint16_t *order, size_t n) {
465
466 if (!is_efi_boot())
467 return -EOPNOTSUPP;
468
469 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
470 }
471
472 static int boot_id_hex(const char s[static 4]) {
473 int id = 0, i;
474
475 assert(s);
476
477 for (i = 0; i < 4; i++)
478 if (s[i] >= '0' && s[i] <= '9')
479 id |= (s[i] - '0') << (3 - i) * 4;
480 else if (s[i] >= 'A' && s[i] <= 'F')
481 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
482 else
483 return -EINVAL;
484
485 return id;
486 }
487
488 static int cmp_uint16(const uint16_t *a, const uint16_t *b) {
489 return CMP(*a, *b);
490 }
491
492 int efi_get_boot_options(uint16_t **options) {
493 _cleanup_closedir_ DIR *dir = NULL;
494 _cleanup_free_ uint16_t *list = NULL;
495 struct dirent *de;
496 size_t alloc = 0;
497 int count = 0;
498
499 assert(options);
500
501 if (!is_efi_boot())
502 return -EOPNOTSUPP;
503
504 dir = opendir("/sys/firmware/efi/efivars/");
505 if (!dir)
506 return -errno;
507
508 FOREACH_DIRENT(de, dir, return -errno) {
509 int id;
510
511 if (strncmp(de->d_name, "Boot", 4) != 0)
512 continue;
513
514 if (strlen(de->d_name) != 45)
515 continue;
516
517 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
518 continue;
519
520 id = boot_id_hex(de->d_name + 4);
521 if (id < 0)
522 continue;
523
524 if (!GREEDY_REALLOC(list, alloc, count + 1))
525 return -ENOMEM;
526
527 list[count++] = id;
528 }
529
530 typesafe_qsort(list, count, cmp_uint16);
531
532 *options = TAKE_PTR(list);
533
534 return count;
535 }
536
537 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
538 _cleanup_free_ char *j = NULL;
539 int r;
540 uint64_t x = 0;
541
542 assert(name);
543 assert(u);
544
545 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
546 if (r < 0)
547 return r;
548
549 r = safe_atou64(j, &x);
550 if (r < 0)
551 return r;
552
553 *u = x;
554 return 0;
555 }
556
557 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
558 uint64_t x, y;
559 int r;
560
561 assert(firmware);
562 assert(loader);
563
564 if (!is_efi_boot())
565 return -EOPNOTSUPP;
566
567 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
568 if (r < 0)
569 return log_debug_errno(r, "Failed to read LoaderTimeInitUSec: %m");
570
571 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
572 if (r < 0)
573 return log_debug_errno(r, "Failed to read LoaderTimeExecUSec: %m");
574
575 if (y == 0 || y < x || y - x > USEC_PER_HOUR)
576 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
577 "Bad LoaderTimeInitUSec=%"PRIu64", LoaderTimeExecUSec=%" PRIu64"; refusing.",
578 x, y);
579
580 *firmware = x;
581 *loader = y;
582
583 return 0;
584 }
585
586 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
587 _cleanup_free_ char *p = NULL;
588 int r, parsed[16];
589
590 if (!is_efi_boot())
591 return -EOPNOTSUPP;
592
593 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
594 if (r < 0)
595 return r;
596
597 if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
598 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
599 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
600 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
601 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
602 return -EIO;
603
604 if (u) {
605 unsigned i;
606
607 for (i = 0; i < ELEMENTSOF(parsed); i++)
608 u->bytes[i] = parsed[i];
609 }
610
611 return 0;
612 }
613
614 int efi_loader_get_entries(char ***ret) {
615 _cleanup_free_ char16_t *entries = NULL;
616 _cleanup_strv_free_ char **l = NULL;
617 size_t size, i, start;
618 int r;
619
620 assert(ret);
621
622 if (!is_efi_boot())
623 return -EOPNOTSUPP;
624
625 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntries", NULL, (void**) &entries, &size);
626 if (r < 0)
627 return r;
628
629 /* The variable contains a series of individually NUL terminated UTF-16 strings. */
630
631 for (i = 0, start = 0;; i++) {
632 _cleanup_free_ char *decoded = NULL;
633 bool end;
634
635 /* Is this the end of the variable's data? */
636 end = i * sizeof(char16_t) >= size;
637
638 /* Are we in the middle of a string? (i.e. not at the end of the variable, nor at a NUL terminator?) If
639 * so, let's go to the next entry. */
640 if (!end && entries[i] != 0)
641 continue;
642
643 /* We reached the end of a string, let's decode it into UTF-8 */
644 decoded = utf16_to_utf8(entries + start, (i - start) * sizeof(char16_t));
645 if (!decoded)
646 return -ENOMEM;
647
648 if (efi_loader_entry_name_valid(decoded)) {
649 r = strv_consume(&l, TAKE_PTR(decoded));
650 if (r < 0)
651 return r;
652 } else
653 log_debug("Ignoring invalid loader entry '%s'.", decoded);
654
655 /* We reached the end of the variable */
656 if (end)
657 break;
658
659 /* Continue after the NUL byte */
660 start = i + 1;
661 }
662
663 *ret = TAKE_PTR(l);
664 return 0;
665 }
666
667 int efi_loader_get_features(uint64_t *ret) {
668 _cleanup_free_ void *v = NULL;
669 size_t s;
670 int r;
671
672 if (!is_efi_boot()) {
673 *ret = 0;
674 return 0;
675 }
676
677 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderFeatures", NULL, &v, &s);
678 if (r == -ENOENT) {
679 _cleanup_free_ char *info = NULL;
680
681 /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */
682 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info);
683 if (r < 0) {
684 if (r != -ENOENT)
685 return r;
686
687 /* Variable not set, definitely means not systemd-boot */
688
689 } else if (first_word(info, "systemd-boot")) {
690
691 /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty
692 * static in all its versions. */
693
694 *ret = EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
695 EFI_LOADER_FEATURE_ENTRY_DEFAULT |
696 EFI_LOADER_FEATURE_ENTRY_ONESHOT;
697
698 return 0;
699 }
700
701 /* No features supported */
702 *ret = 0;
703 return 0;
704 }
705 if (r < 0)
706 return r;
707
708 if (s != sizeof(uint64_t))
709 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
710 "LoaderFeatures EFI variable doesn't have the right size.");
711
712 memcpy(ret, v, sizeof(uint64_t));
713 return 0;
714 }
715
716 int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
717 _cleanup_free_ char *v = NULL, *fn = NULL;
718 static struct stat cache_stat = {};
719 struct stat new_stat;
720 static usec_t cache;
721 uint64_t sec;
722 int r;
723
724 assert(ret);
725
726 fn = efi_variable_path(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot");
727 if (!fn)
728 return -ENOMEM;
729
730 /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
731 if (stat(fn, &new_stat) < 0)
732 return -errno;
733
734 if (stat_inode_unmodified(&new_stat, &cache_stat)) {
735 *ret = cache;
736 return 0;
737 }
738
739 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", &v);
740 if (r < 0)
741 return r;
742
743 r = safe_atou64(v, &sec);
744 if (r < 0)
745 return r;
746 if (sec > USEC_INFINITY / USEC_PER_SEC)
747 return -ERANGE;
748
749 cache_stat = new_stat;
750 *ret = cache = sec * USEC_PER_SEC; /* return in µs */
751 return 0;
752 }
753
754 int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat) {
755 _cleanup_free_ char *fn = NULL, *v = NULL;
756 struct stat new_stat;
757 int r;
758
759 assert(cache);
760 assert(cache_stat);
761
762 fn = efi_variable_path(EFI_VENDOR_LOADER, "LoaderEntryOneShot");
763 if (!fn)
764 return -ENOMEM;
765
766 /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
767 if (stat(fn, &new_stat) < 0)
768 return -errno;
769
770 if (stat_inode_unmodified(&new_stat, cache_stat))
771 return 0;
772
773 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &v);
774 if (r < 0)
775 return r;
776
777 if (!efi_loader_entry_name_valid(v))
778 return -EINVAL;
779
780 *cache_stat = new_stat;
781 free_and_replace(*cache, v);
782
783 return 0;
784 }
785
786 #endif
787
788 bool efi_loader_entry_name_valid(const char *s) {
789 if (isempty(s))
790 return false;
791
792 if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */
793 return false;
794
795 return in_charset(s, ALPHANUMERICAL "+-_.");
796 }
797
798 char *efi_tilt_backslashes(char *s) {
799 char *p;
800
801 for (p = s; *p; p++)
802 if (*p == '\\')
803 *p = '/';
804
805 return s;
806 }