chiark / gitweb /
efi: fix Usec vs. USec
[elogind.git] / src / shared / efivars.c
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
31 bool is_efiboot(void) {
32         return access("/sys/firmware/efi", F_OK) >= 0;
33 }
34
35 int 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
96 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
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
118         *u = x;
119         return 0;
120 }
121
122 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
123         uint64_t x, y;
124         int r;
125
126         assert(firmware);
127         assert(loader);
128
129         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
130         if (r < 0)
131                 return r;
132
133         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
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
149 int 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 }
184
185 int 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 }