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