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