]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/efivars.c
Merge pull request #1668 from ssahani/net1
[thirdparty/systemd.git] / src / shared / efivars.c
CommitLineData
2e3d0692
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
7b4d7cc0 23#include <string.h>
2e3d0692
LP
24#include <fcntl.h>
25
3ffd4af2
LP
26#include "efivars.h"
27#include "fd-util.h"
2e3d0692 28#include "utf8.h"
3ffd4af2 29#include "util.h"
5bdf2243 30#include "virt.h"
2e3d0692 31
b872e9a0
LP
32#ifdef ENABLE_EFI
33
0974a682
KS
34#define LOAD_OPTION_ACTIVE 0x00000001
35#define MEDIA_DEVICE_PATH 0x04
36#define MEDIA_HARDDRIVE_DP 0x01
37#define MEDIA_FILEPATH_DP 0x04
38#define SIGNATURE_TYPE_GUID 0x02
39#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
40#define END_DEVICE_PATH_TYPE 0x7f
41#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
5bdf2243 42#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
0974a682
KS
43
44struct boot_option {
45 uint32_t attr;
46 uint16_t path_len;
47 uint16_t title[];
885fdebc 48} _packed_;
0974a682
KS
49
50struct drive_path {
51 uint32_t part_nr;
52 uint64_t part_start;
53 uint64_t part_size;
54 char signature[16];
55 uint8_t mbr_type;
56 uint8_t signature_type;
885fdebc 57} _packed_;
0974a682
KS
58
59struct device_path {
60 uint8_t type;
61 uint8_t sub_type;
62 uint16_t length;
63 union {
64 uint16_t path[0];
65 struct drive_path drive;
66 };
885fdebc 67} _packed_;
0974a682 68
9cde64ff 69bool is_efi_boot(void) {
34e5a31e
LP
70 return access("/sys/firmware/efi", F_OK) >= 0;
71}
72
bc6f2e7c
KS
73static int read_flag(const char *varname) {
74 int r;
b47d419c 75 _cleanup_free_ void *v = NULL;
bc6f2e7c
KS
76 size_t s;
77 uint8_t b;
78
79 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
80 if (r < 0)
81 return r;
82
b47d419c
ZJS
83 if (s != 1)
84 return -EINVAL;
bc6f2e7c
KS
85
86 b = *(uint8_t *)v;
87 r = b > 0;
bc6f2e7c
KS
88 return r;
89}
90
9df49b33
TG
91bool is_efi_secure_boot(void) {
92 return read_flag("SecureBoot") > 0;
bc6f2e7c
KS
93}
94
9df49b33
TG
95bool is_efi_secure_boot_setup_mode(void) {
96 return read_flag("SetupMode") > 0;
bc6f2e7c
KS
97}
98
5bdf2243
JJ
99int efi_reboot_to_firmware_supported(void) {
100 int r;
101 size_t s;
102 uint64_t b;
103 _cleanup_free_ void *v = NULL;
104
75f86906 105 if (!is_efi_boot() || detect_container() > 0)
5bdf2243
JJ
106 return -EOPNOTSUPP;
107
108 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
109 if (r < 0)
110 return r;
111 else if (s != sizeof(uint64_t))
112 return -EINVAL;
113
114 b = *(uint64_t *)v;
115 b &= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
116 return b > 0 ? 0 : -EOPNOTSUPP;
117}
118
119static int get_os_indications(uint64_t *os_indication) {
120 int r;
121 size_t s;
122 _cleanup_free_ void *v = NULL;
123
124 r = efi_reboot_to_firmware_supported();
125 if (r < 0)
126 return r;
127
128 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
6b62bbbc
LP
129 if (r == -ENOENT) {
130 /* Some firmware implementations that do support
131 * OsIndications and report that with
132 * OsIndicationsSupported will remove the
133 * OsIndications variable when it is unset. Let's
134 * pretend it's 0 then, to hide this implementation
135 * detail. Note that this call will return -ENOENT
136 * then only if the support for OsIndications is
137 * missing entirely, as determined by
138 * efi_reboot_to_firmware_supported() above. */
139 *os_indication = 0;
140 return 0;
141 } else if (r < 0)
5bdf2243
JJ
142 return r;
143 else if (s != sizeof(uint64_t))
144 return -EINVAL;
145
146 *os_indication = *(uint64_t *)v;
147 return 0;
148}
149
150int efi_get_reboot_to_firmware(void) {
151 int r;
152 uint64_t b;
153
154 r = get_os_indications(&b);
155 if (r < 0)
156 return r;
157
158 return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
159}
160
161int efi_set_reboot_to_firmware(bool value) {
162 int r;
163 uint64_t b, b_new;
164
165 r = get_os_indications(&b);
166 if (r < 0)
167 return r;
168
169 if (value)
170 b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
171 else
172 b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
173
174 /* Avoid writing to efi vars store if we can due to firmware bugs. */
175 if (b != b_new)
176 return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
177
178 return 0;
179}
180
9cde64ff
LP
181int efi_get_variable(
182 sd_id128_t vendor,
183 const char *name,
184 uint32_t *attribute,
185 void **value,
186 size_t *size) {
187
2e3d0692
LP
188 _cleanup_close_ int fd = -1;
189 _cleanup_free_ char *p = NULL;
190 uint32_t a;
191 ssize_t n;
192 struct stat st;
ad7bcf52 193 _cleanup_free_ void *buf = NULL;
2e3d0692
LP
194
195 assert(name);
196 assert(value);
197 assert(size);
198
199 if (asprintf(&p,
200 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
201 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
202 return -ENOMEM;
203
204 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
205 if (fd < 0)
206 return -errno;
207
208 if (fstat(fd, &st) < 0)
209 return -errno;
210 if (st.st_size < 4)
211 return -EIO;
212 if (st.st_size > 4*1024*1024 + 4)
213 return -E2BIG;
214
215 n = read(fd, &a, sizeof(a));
216 if (n < 0)
9cde64ff 217 return -errno;
2e3d0692
LP
218 if (n != sizeof(a))
219 return -EIO;
220
0797f232
ZJS
221 buf = malloc(st.st_size - 4 + 2);
222 if (!buf)
2e3d0692
LP
223 return -ENOMEM;
224
0797f232
ZJS
225 n = read(fd, buf, (size_t) st.st_size - 4);
226 if (n < 0)
742af54a 227 return -errno;
0797f232 228 if (n != (ssize_t) st.st_size - 4)
2e3d0692 229 return -EIO;
2e3d0692
LP
230
231 /* Always NUL terminate (2 bytes, to protect UTF-16) */
0797f232
ZJS
232 ((char*) buf)[st.st_size - 4] = 0;
233 ((char*) buf)[st.st_size - 4 + 1] = 0;
2e3d0692 234
0797f232
ZJS
235 *value = buf;
236 buf = NULL;
ff47c895 237 *size = (size_t) st.st_size - 4;
2e3d0692
LP
238
239 if (attribute)
240 *attribute = a;
241
242 return 0;
243}
244
0974a682
KS
245int efi_set_variable(
246 sd_id128_t vendor,
247 const char *name,
248 const void *value,
249 size_t size) {
250
251 struct var {
252 uint32_t attr;
253 char buf[];
b7749eb5
ZJS
254 } _packed_ * _cleanup_free_ buf = NULL;
255 _cleanup_free_ char *p = NULL;
256 _cleanup_close_ int fd = -1;
0974a682
KS
257
258 assert(name);
259
260 if (asprintf(&p,
261 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
262 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
263 return -ENOMEM;
264
265 if (size == 0) {
b7749eb5
ZJS
266 if (unlink(p) < 0)
267 return -errno;
268 return 0;
0974a682
KS
269 }
270
271 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
b7749eb5
ZJS
272 if (fd < 0)
273 return -errno;
0974a682
KS
274
275 buf = malloc(sizeof(uint32_t) + size);
b7749eb5
ZJS
276 if (!buf)
277 return -ENOMEM;
0974a682
KS
278
279 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
280 memcpy(buf->buf, value, size);
281
b7749eb5 282 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
0974a682
KS
283}
284
9cde64ff 285int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
7b4d7cc0 286 _cleanup_free_ void *s = NULL;
39883f62 287 size_t ss = 0;
9cde64ff
LP
288 int r;
289 char *x;
7b4d7cc0 290
9cde64ff
LP
291 r = efi_get_variable(vendor, name, NULL, &s, &ss);
292 if (r < 0)
293 return r;
294
295 x = utf16_to_utf8(s, ss);
296 if (!x)
297 return -ENOMEM;
298
299 *p = x;
300 return 0;
7b4d7cc0
KS
301}
302
303static size_t utf16_size(const uint16_t *s) {
304 size_t l = 0;
305
306 while (s[l] > 0)
307 l++;
9cde64ff 308
7b4d7cc0
KS
309 return (l+1) * sizeof(uint16_t);
310}
311
312static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
313 struct uuid {
314 uint32_t u1;
315 uint16_t u2;
316 uint16_t u3;
317 uint8_t u4[8];
318 } _packed_;
319 const struct uuid *uuid = guid;
320
321 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
322 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
323 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
324 id128->bytes[3] = (uuid->u1) & 0xff;
325 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
326 id128->bytes[5] = (uuid->u2) & 0xff;
327 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
328 id128->bytes[7] = (uuid->u3) & 0xff;
329 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
330}
331
9cde64ff
LP
332int efi_get_boot_option(
333 uint16_t id,
334 char **title,
335 sd_id128_t *part_uuid,
0974a682
KS
336 char **path,
337 bool *active) {
7b4d7cc0 338
9cde64ff
LP
339 char boot_id[9];
340 _cleanup_free_ uint8_t *buf = NULL;
7b4d7cc0
KS
341 size_t l;
342 struct boot_option *header;
343 size_t title_size;
b7749eb5 344 _cleanup_free_ char *s = NULL, *p = NULL;
7b4d7cc0 345 sd_id128_t p_uuid = SD_ID128_NULL;
a8436474 346 int r;
7b4d7cc0 347
b7749eb5 348 xsprintf(boot_id, "Boot%04X", id);
a8436474
ZJS
349 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
350 if (r < 0)
351 return r;
7b4d7cc0
KS
352 if (l < sizeof(struct boot_option))
353 return -ENOENT;
354
355 header = (struct boot_option *)buf;
356 title_size = utf16_size(header->title);
357 if (title_size > l - offsetof(struct boot_option, title))
358 return -EINVAL;
359
5483a186
ZJS
360 if (title) {
361 s = utf16_to_utf8(header->title, title_size);
b7749eb5
ZJS
362 if (!s)
363 return -ENOMEM;
7b4d7cc0
KS
364 }
365
366 if (header->path_len > 0) {
9cde64ff 367 uint8_t *dbuf;
7b4d7cc0
KS
368 size_t dnext;
369
370 dbuf = buf + offsetof(struct boot_option, title) + title_size;
371 dnext = 0;
372 while (dnext < header->path_len) {
373 struct device_path *dpath;
374
375 dpath = (struct device_path *)(dbuf + dnext);
376 if (dpath->length < 4)
377 break;
378
379 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
0974a682 380 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
7b4d7cc0
KS
381 break;
382
383 dnext += dpath->length;
384
385 /* Type 0x04 – Media Device Path */
0974a682 386 if (dpath->type != MEDIA_DEVICE_PATH)
7b4d7cc0
KS
387 continue;
388
389 /* Sub-Type 1 – Hard Drive */
0974a682 390 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
7b4d7cc0 391 /* 0x02 – GUID Partition Table */
0974a682 392 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
7b4d7cc0
KS
393 continue;
394
395 /* 0x02 – GUID signature */
0974a682 396 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
7b4d7cc0
KS
397 continue;
398
5483a186
ZJS
399 if (part_uuid)
400 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
7b4d7cc0
KS
401 continue;
402 }
403
404 /* Sub-Type 4 – File Path */
0974a682 405 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
7b4d7cc0 406 p = utf16_to_utf8(dpath->path, dpath->length-4);
0974a682 407 efi_tilt_backslashes(p);
7b4d7cc0
KS
408 continue;
409 }
410 }
411 }
412
b7749eb5 413 if (title) {
9cde64ff 414 *title = s;
b7749eb5
ZJS
415 s = NULL;
416 }
7b4d7cc0
KS
417 if (part_uuid)
418 *part_uuid = p_uuid;
b7749eb5 419 if (path) {
7b4d7cc0 420 *path = p;
b7749eb5
ZJS
421 p = NULL;
422 }
0974a682 423 if (active)
0aa3b783 424 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
9cde64ff 425
7b4d7cc0 426 return 0;
7b4d7cc0
KS
427}
428
0974a682
KS
429static void to_utf16(uint16_t *dest, const char *src) {
430 int i;
431
432 for (i = 0; src[i] != '\0'; i++)
433 dest[i] = src[i];
434 dest[i] = '\0';
435}
436
437struct guid {
438 uint32_t u1;
439 uint16_t u2;
440 uint16_t u3;
441 uint8_t u4[8];
885fdebc 442} _packed_;
0974a682
KS
443
444static void id128_to_efi_guid(sd_id128_t id, void *guid) {
445 struct guid *uuid = guid;
446
447 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
448 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
449 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
450 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
451}
452
453static uint16_t *tilt_slashes(uint16_t *s) {
454 uint16_t *p;
455
456 for (p = s; *p; p++)
457 if (*p == '/')
458 *p = '\\';
459
460 return s;
461}
462
0974a682
KS
463int efi_add_boot_option(uint16_t id, const char *title,
464 uint32_t part, uint64_t pstart, uint64_t psize,
465 sd_id128_t part_uuid, const char *path) {
466 char boot_id[9];
0974a682
KS
467 size_t size;
468 size_t title_len;
469 size_t path_len;
470 struct boot_option *option;
471 struct device_path *devicep;
b7749eb5 472 _cleanup_free_ char *buf = NULL;
0974a682
KS
473
474 title_len = (strlen(title)+1) * 2;
475 path_len = (strlen(path)+1) * 2;
476
477 buf = calloc(sizeof(struct boot_option) + title_len +
478 sizeof(struct drive_path) +
479 sizeof(struct device_path) + path_len, 1);
b7749eb5
ZJS
480 if (!buf)
481 return -ENOMEM;
0974a682
KS
482
483 /* header */
484 option = (struct boot_option *)buf;
485 option->attr = LOAD_OPTION_ACTIVE;
486 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
487 offsetof(struct device_path, path) + path_len +
488 offsetof(struct device_path, path);
489 to_utf16(option->title, title);
490 size = offsetof(struct boot_option, title) + title_len;
491
492 /* partition info */
493 devicep = (struct device_path *)(buf + size);
494 devicep->type = MEDIA_DEVICE_PATH;
495 devicep->sub_type = MEDIA_HARDDRIVE_DP;
496 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
497 devicep->drive.part_nr = part;
498 devicep->drive.part_start = pstart;
920b52e4 499 devicep->drive.part_size = psize;
0974a682
KS
500 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
501 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
502 id128_to_efi_guid(part_uuid, devicep->drive.signature);
503 size += devicep->length;
504
505 /* path to loader */
506 devicep = (struct device_path *)(buf + size);
507 devicep->type = MEDIA_DEVICE_PATH;
508 devicep->sub_type = MEDIA_FILEPATH_DP;
509 devicep->length = offsetof(struct device_path, path) + path_len;
510 to_utf16(devicep->path, path);
511 tilt_slashes(devicep->path);
512 size += devicep->length;
513
514 /* end of path */
515 devicep = (struct device_path *)(buf + size);
516 devicep->type = END_DEVICE_PATH_TYPE;
517 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
518 devicep->length = offsetof(struct device_path, path);
519 size += devicep->length;
520
b7749eb5
ZJS
521 xsprintf(boot_id, "Boot%04X", id);
522 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
0974a682
KS
523}
524
525int efi_remove_boot_option(uint16_t id) {
526 char boot_id[9];
527
b7749eb5 528 xsprintf(boot_id, "Boot%04X", id);
0974a682
KS
529 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
530}
531
9cde64ff 532int efi_get_boot_order(uint16_t **order) {
0797f232 533 _cleanup_free_ void *buf = NULL;
7b4d7cc0 534 size_t l;
9cde64ff 535 int r;
7b4d7cc0 536
9cde64ff
LP
537 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
538 if (r < 0)
539 return r;
7b4d7cc0 540
0797f232 541 if (l <= 0)
7b4d7cc0 542 return -ENOENT;
7b4d7cc0 543
0797f232
ZJS
544 if (l % sizeof(uint16_t) > 0 ||
545 l / sizeof(uint16_t) > INT_MAX)
7b4d7cc0 546 return -EINVAL;
7b4d7cc0
KS
547
548 *order = buf;
0797f232 549 buf = NULL;
9cde64ff
LP
550 return (int) (l / sizeof(uint16_t));
551}
552
0974a682
KS
553int efi_set_boot_order(uint16_t *order, size_t n) {
554 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
555}
556
4d34c495
KS
557static int boot_id_hex(const char s[4]) {
558 int i;
559 int id = 0;
560
561 for (i = 0; i < 4; i++)
562 if (s[i] >= '0' && s[i] <= '9')
563 id |= (s[i] - '0') << (3 - i) * 4;
564 else if (s[i] >= 'A' && s[i] <= 'F')
565 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
566 else
7e8185ef 567 return -EINVAL;
4d34c495
KS
568
569 return id;
570}
571
9db11a99
LP
572static int cmp_uint16(const void *_a, const void *_b) {
573 const uint16_t *a = _a, *b = _b;
574
02a6fc3e 575 return (int)*a - (int)*b;
9db11a99
LP
576}
577
9cde64ff
LP
578int efi_get_boot_options(uint16_t **options) {
579 _cleanup_closedir_ DIR *dir = NULL;
580 struct dirent *de;
b7749eb5 581 _cleanup_free_ uint16_t *list = NULL;
7432b24b 582 size_t alloc = 0;
b7749eb5 583 int count = 0;
9cde64ff
LP
584
585 assert(options);
586
587 dir = opendir("/sys/firmware/efi/efivars/");
588 if (!dir)
589 return -errno;
590
b7749eb5 591 FOREACH_DIRENT(de, dir, return -errno) {
4d34c495 592 int id;
9cde64ff
LP
593
594 if (strncmp(de->d_name, "Boot", 4) != 0)
595 continue;
596
4d34c495 597 if (strlen(de->d_name) != 45)
9cde64ff
LP
598 continue;
599
600 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
601 continue;
602
4d34c495
KS
603 id = boot_id_hex(de->d_name + 4);
604 if (id < 0)
9cde64ff
LP
605 continue;
606
7432b24b 607 if (!GREEDY_REALLOC(list, alloc, count + 1))
b7749eb5 608 return -ENOMEM;
9cde64ff 609
7432b24b 610 list[count++] = id;
9cde64ff
LP
611 }
612
7ff7394d 613 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
9db11a99 614
9cde64ff 615 *options = list;
b7749eb5 616 list = NULL;
9cde64ff 617 return count;
7b4d7cc0
KS
618}
619
5dbe9f53 620static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
2e3d0692 621 _cleanup_free_ char *j = NULL;
2e3d0692 622 int r;
39883f62 623 uint64_t x = 0;
2e3d0692
LP
624
625 assert(name);
626 assert(u);
627
61cc634b 628 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
2e3d0692
LP
629 if (r < 0)
630 return r;
631
2e3d0692
LP
632 r = safe_atou64(j, &x);
633 if (r < 0)
634 return r;
635
5dbe9f53 636 *u = x;
2e3d0692
LP
637 return 0;
638}
639
c51d84dc 640int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
2e3d0692
LP
641 uint64_t x, y;
642 int r;
2e3d0692
LP
643
644 assert(firmware);
645 assert(loader);
646
e9cea16d 647 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
2e3d0692
LP
648 if (r < 0)
649 return r;
650
e9cea16d 651 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
2e3d0692
LP
652 if (r < 0)
653 return r;
654
655 if (y == 0 || y < x)
656 return -EIO;
657
658 if (y > USEC_PER_HOUR)
659 return -EIO;
660
661 *firmware = x;
662 *loader = y;
663
664 return 0;
665}
666
c51d84dc 667int efi_loader_get_device_part_uuid(sd_id128_t *u) {
f4ce2b3e 668 _cleanup_free_ char *p = NULL;
f4ce2b3e 669 int r, parsed[16];
f4ce2b3e 670
61cc634b 671 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
f4ce2b3e
LP
672 if (r < 0)
673 return r;
674
f4ce2b3e
LP
675 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
676 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
677 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
678 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
679 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
680 return -EIO;
681
73b80ec2
LP
682 if (u) {
683 unsigned i;
684
685 for (i = 0; i < ELEMENTSOF(parsed); i++)
686 u->bytes[i] = parsed[i];
687 }
f4ce2b3e
LP
688
689 return 0;
690}
b872e9a0
LP
691
692#endif
b28ce7c6
TG
693
694char *efi_tilt_backslashes(char *s) {
695 char *p;
696
697 for (p = s; *p; p++)
698 if (*p == '\\')
699 *p = '/';
700
701 return s;
702}