]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/efivars.c
util: rework load_env_file()
[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>
23#include <fcntl.h>
24
25#include "util.h"
26#include "utf8.h"
27#include "efivars.h"
28
29#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
30
34e5a31e
LP
31bool is_efiboot(void) {
32 return access("/sys/firmware/efi", F_OK) >= 0;
33}
34
2e3d0692
LP
35int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
36 _cleanup_close_ int fd = -1;
37 _cleanup_free_ char *p = NULL;
38 uint32_t a;
39 ssize_t n;
40 struct stat st;
41 void *r;
42
43 assert(name);
44 assert(value);
45 assert(size);
46
47 if (asprintf(&p,
48 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
49 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
50 return -ENOMEM;
51
52 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
53 if (fd < 0)
54 return -errno;
55
56 if (fstat(fd, &st) < 0)
57 return -errno;
58 if (st.st_size < 4)
59 return -EIO;
60 if (st.st_size > 4*1024*1024 + 4)
61 return -E2BIG;
62
63 n = read(fd, &a, sizeof(a));
64 if (n < 0)
65 return (int) n;
66 if (n != sizeof(a))
67 return -EIO;
68
69 r = malloc(st.st_size - 4 + 2);
70 if (!r)
71 return -ENOMEM;
72
73 n = read(fd, r, (size_t) st.st_size - 4);
74 if (n < 0) {
75 free(r);
76 return (int) -n;
77 }
78 if (n != (ssize_t) st.st_size - 4) {
79 free(r);
80 return -EIO;
81 }
82
83 /* Always NUL terminate (2 bytes, to protect UTF-16) */
84 ((char*) r)[st.st_size - 4] = 0;
85 ((char*) r)[st.st_size - 4 + 1] = 0;
86
87 *value = r;
88 *size = (size_t) st.st_size;
89
90 if (attribute)
91 *attribute = a;
92
93 return 0;
94}
95
5dbe9f53 96static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
2e3d0692
LP
97 _cleanup_free_ void *i = NULL;
98 _cleanup_free_ char *j = NULL;
99 size_t is;
100 int r;
101 uint64_t x;
102
103 assert(name);
104 assert(u);
105
106 r = efi_get_variable(EFI_VENDOR_LOADER, name, NULL, &i, &is);
107 if (r < 0)
108 return r;
109
110 j = utf16_to_utf8(i, is);
111 if (!j)
112 return -ENOMEM;
113
114 r = safe_atou64(j, &x);
115 if (r < 0)
116 return r;
117
5dbe9f53 118 *u = x;
2e3d0692
LP
119 return 0;
120}
121
122static int get_boot_usec(usec_t *firmware, usec_t *loader) {
123 uint64_t x, y;
124 int r;
2e3d0692
LP
125
126 assert(firmware);
127 assert(loader);
128
e9cea16d 129 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
2e3d0692
LP
130 if (r < 0)
131 return r;
132
e9cea16d 133 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
2e3d0692
LP
134 if (r < 0)
135 return r;
136
137 if (y == 0 || y < x)
138 return -EIO;
139
140 if (y > USEC_PER_HOUR)
141 return -EIO;
142
143 *firmware = x;
144 *loader = y;
145
146 return 0;
147}
148
149int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
150 usec_t x, y, a;
151 int r;
152 dual_timestamp _n;
153
154 assert(firmware);
155 assert(loader);
156
157 if (!n) {
158 dual_timestamp_get(&_n);
159 n = &_n;
160 }
161
162 r = get_boot_usec(&x, &y);
163 if (r < 0)
164 return r;
165
166 /* Let's convert this to timestamps where the firmware
167 * began/loader began working. To make this more confusing:
168 * since usec_t is unsigned and the kernel's monotonic clock
169 * begins at kernel initialization we'll actually initialize
170 * the monotonic timestamps here as negative of the actual
171 * value. */
172
173 firmware->monotonic = y;
174 loader->monotonic = y - x;
175
176 a = n->monotonic + firmware->monotonic;
177 firmware->realtime = n->realtime > a ? n->realtime - a : 0;
178
179 a = n->monotonic + loader->monotonic;
180 loader->realtime = n->realtime > a ? n->realtime - a : 0;
181
182 return 0;
183}
f4ce2b3e
LP
184
185int efi_get_loader_device_part_uuid(sd_id128_t *u) {
186 _cleanup_free_ void *s = NULL;
187 _cleanup_free_ char *p = NULL;
188 size_t ss;
189 int r, parsed[16];
190 unsigned i;
191
192 assert(u);
193
194 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", NULL, &s, &ss);
195 if (r < 0)
196 return r;
197
198 p = utf16_to_utf8(s, ss);
199 if (!p)
200 return -ENOMEM;
201
202 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
203 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
204 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
205 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
206 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
207 return -EIO;
208
209 for (i = 0; i < ELEMENTSOF(parsed); i++)
210 u->bytes[i] = parsed[i];
211
212 return 0;
213}