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