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