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