/src/rauc/src/bootloaders/efi.c
Line | Count | Source |
1 | | #include "efi.h" |
2 | | #include "bootchooser.h" |
3 | | #include "context.h" |
4 | | #include "utils.h" |
5 | | |
6 | 0 | #define EFIBOOTMGR_NAME "efibootmgr" |
7 | | |
8 | | typedef struct { |
9 | | gchar *num; |
10 | | gchar *name; |
11 | | gboolean active; |
12 | | } efi_bootentry; |
13 | | |
14 | | static void efi_bootentry_free(efi_bootentry *entry) |
15 | 0 | { |
16 | 0 | if (!entry) |
17 | 0 | return; |
18 | | |
19 | 0 | g_free(entry->num); |
20 | 0 | g_free(entry->name); |
21 | 0 | g_free(entry); |
22 | 0 | } |
23 | | |
24 | | G_DEFINE_AUTOPTR_CLEANUP_FUNC(efi_bootentry, efi_bootentry_free); |
25 | | |
26 | | static gboolean efi_bootorder_set(gchar *order, GError **error) |
27 | 0 | { |
28 | 0 | g_autoptr(GSubprocess) sub = NULL; |
29 | 0 | GError *ierror = NULL; |
30 | |
|
31 | 0 | g_return_val_if_fail(order, FALSE); |
32 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
33 | | |
34 | 0 | sub = r_subprocess_new(G_SUBPROCESS_FLAGS_NONE, &ierror, EFIBOOTMGR_NAME, |
35 | 0 | "--bootorder", order, NULL); |
36 | |
|
37 | 0 | if (!sub) { |
38 | 0 | g_propagate_prefixed_error( |
39 | 0 | error, |
40 | 0 | ierror, |
41 | 0 | "Failed to start " EFIBOOTMGR_NAME ": "); |
42 | 0 | return FALSE; |
43 | 0 | } |
44 | | |
45 | 0 | if (!g_subprocess_wait_check(sub, NULL, &ierror)) { |
46 | 0 | g_propagate_prefixed_error( |
47 | 0 | error, |
48 | 0 | ierror, |
49 | 0 | "Failed to run " EFIBOOTMGR_NAME ": "); |
50 | 0 | return FALSE; |
51 | 0 | } |
52 | | |
53 | 0 | return TRUE; |
54 | 0 | } |
55 | | |
56 | | static gboolean efi_set_bootnext(gchar *bootnumber, GError **error) |
57 | 0 | { |
58 | 0 | g_autoptr(GSubprocess) sub = NULL; |
59 | 0 | GError *ierror = NULL; |
60 | |
|
61 | 0 | g_return_val_if_fail(bootnumber, FALSE); |
62 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
63 | | |
64 | 0 | sub = r_subprocess_new(G_SUBPROCESS_FLAGS_NONE, &ierror, EFIBOOTMGR_NAME, |
65 | 0 | "--bootnext", bootnumber, NULL); |
66 | |
|
67 | 0 | if (!sub) { |
68 | 0 | g_propagate_prefixed_error( |
69 | 0 | error, |
70 | 0 | ierror, |
71 | 0 | "Failed to start " EFIBOOTMGR_NAME ": "); |
72 | 0 | return FALSE; |
73 | 0 | } |
74 | | |
75 | 0 | if (!g_subprocess_wait_check(sub, NULL, &ierror)) { |
76 | 0 | g_propagate_prefixed_error( |
77 | 0 | error, |
78 | 0 | ierror, |
79 | 0 | "Failed to run " EFIBOOTMGR_NAME ": "); |
80 | 0 | return FALSE; |
81 | 0 | } |
82 | | |
83 | 0 | return TRUE; |
84 | 0 | } |
85 | | |
86 | | static efi_bootentry *get_efi_entry_by_bootnum(GList *entries, const gchar *bootnum) |
87 | 0 | { |
88 | 0 | efi_bootentry *found_entry = NULL; |
89 | |
|
90 | 0 | g_return_val_if_fail(entries, NULL); |
91 | 0 | g_return_val_if_fail(bootnum, NULL); |
92 | | |
93 | 0 | for (GList *entry = entries; entry != NULL; entry = entry->next) { |
94 | 0 | efi_bootentry *ptr = entry->data; |
95 | 0 | if (g_strcmp0(bootnum, ptr->num) == 0) { |
96 | 0 | found_entry = ptr; |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | } |
100 | |
|
101 | 0 | return found_entry; |
102 | 0 | } |
103 | | |
104 | | /* Parses output of efibootmgr and returns information obtained. |
105 | | * |
106 | | * Note that this function can return two lists, pointing to the same elements. |
107 | | * The allocated efi_bootentry structs are owned by the all_entries list, so |
108 | | * that parameter is mandatory. |
109 | | * |
110 | | * @param bootorder_entries Return location for List (of efi_bootentry |
111 | | * elements) of slots that are currently in EFI 'BootOrder' |
112 | | * @param all_entries Return location for List (of efi_bootentry element) of |
113 | | * all EFI boot entries |
114 | | * @param bootnext Return location for EFI boot slot currently selected as |
115 | | * 'BootNext' (if any) |
116 | | * @param error Return location for a GError |
117 | | */ |
118 | | static gboolean efi_bootorder_get(GList **bootorder_entries, GList **all_entries, efi_bootentry **bootnext, efi_bootentry **bootcurrent, GError **error) |
119 | 0 | { |
120 | 0 | g_autoptr(GSubprocess) sub = NULL; |
121 | 0 | GError *ierror = NULL; |
122 | 0 | g_autoptr(GBytes) stdout_bytes = NULL; |
123 | 0 | g_autofree gchar *stdout_str = NULL; |
124 | 0 | gboolean res = FALSE; |
125 | 0 | gint ret; |
126 | 0 | GRegex *regex = NULL; |
127 | 0 | GMatchInfo *match = NULL; |
128 | 0 | g_autofree gchar *matched = NULL; |
129 | 0 | g_autolist(efi_bootentry) entries = NULL; |
130 | 0 | g_autoptr(GList) returnorder = NULL; |
131 | 0 | g_auto(GStrv) bootnumorder = NULL; |
132 | |
|
133 | 0 | g_return_val_if_fail(bootorder_entries == NULL || *bootorder_entries == NULL, FALSE); |
134 | 0 | g_return_val_if_fail(all_entries != NULL && *all_entries == NULL, FALSE); |
135 | 0 | g_return_val_if_fail(bootnext == NULL || *bootnext == NULL, FALSE); |
136 | 0 | g_return_val_if_fail(bootcurrent == NULL || *bootcurrent == NULL, FALSE); |
137 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
138 | | |
139 | 0 | sub = r_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, &ierror, |
140 | 0 | EFIBOOTMGR_NAME, NULL); |
141 | 0 | if (!sub) { |
142 | 0 | g_propagate_prefixed_error( |
143 | 0 | error, |
144 | 0 | ierror, |
145 | 0 | "Failed to start " EFIBOOTMGR_NAME ": "); |
146 | 0 | goto out; |
147 | 0 | } |
148 | | |
149 | 0 | res = g_subprocess_communicate(sub, NULL, NULL, &stdout_bytes, NULL, &ierror); |
150 | 0 | if (!res) { |
151 | 0 | g_propagate_prefixed_error( |
152 | 0 | error, |
153 | 0 | ierror, |
154 | 0 | EFIBOOTMGR_NAME " communication failed: "); |
155 | 0 | goto out; |
156 | 0 | } |
157 | | |
158 | 0 | res = g_subprocess_get_if_exited(sub); |
159 | 0 | if (!res) { |
160 | 0 | g_set_error_literal( |
161 | 0 | error, |
162 | 0 | G_SPAWN_ERROR, |
163 | 0 | G_SPAWN_ERROR_FAILED, |
164 | 0 | EFIBOOTMGR_NAME " did not exit normally"); |
165 | 0 | goto out; |
166 | 0 | } |
167 | | |
168 | 0 | ret = g_subprocess_get_exit_status(sub); |
169 | 0 | if (ret != 0) { |
170 | 0 | g_set_error( |
171 | 0 | error, |
172 | 0 | G_SPAWN_EXIT_ERROR, |
173 | 0 | ret, |
174 | 0 | EFIBOOTMGR_NAME " failed with exit code: %i", ret); |
175 | 0 | res = FALSE; |
176 | 0 | goto out; |
177 | 0 | } |
178 | | |
179 | 0 | stdout_str = r_bytes_unref_to_string(&stdout_bytes); |
180 | | |
181 | | /* Obtain mapping of efi boot numbers to bootnames */ |
182 | 0 | regex = g_regex_new("^Boot([0-9a-fA-F]{4})[\\* ] (.+)$", G_REGEX_MULTILINE, 0, NULL); |
183 | 0 | if (!g_regex_match(regex, stdout_str, 0, &match)) { |
184 | 0 | g_set_error( |
185 | 0 | error, |
186 | 0 | R_BOOTCHOOSER_ERROR, |
187 | 0 | R_BOOTCHOOSER_ERROR_FAILED, |
188 | 0 | "Regex matching failed!"); |
189 | 0 | res = FALSE; |
190 | 0 | goto out; |
191 | 0 | } |
192 | | |
193 | 0 | while (g_match_info_matches(match)) { |
194 | 0 | gchar *tab_point = NULL; |
195 | 0 | efi_bootentry *entry = g_new0(efi_bootentry, 1); |
196 | 0 | entry->num = g_match_info_fetch(match, 1); |
197 | 0 | entry->name = g_match_info_fetch(match, 2); |
198 | | |
199 | | /* Remove anything after a tab, as it is most likely path |
200 | | * information which we don't need */ |
201 | 0 | tab_point = strchr(entry->name, '\t'); |
202 | 0 | if (tab_point) |
203 | 0 | *tab_point = '\0'; |
204 | |
|
205 | 0 | entries = g_list_append(entries, entry); |
206 | 0 | g_match_info_next(match, NULL); |
207 | 0 | g_debug("Detected EFI boot entry %s: %s", entry->num, entry->name); |
208 | 0 | } |
209 | |
|
210 | 0 | g_clear_pointer(®ex, g_regex_unref); |
211 | 0 | g_clear_pointer(&match, g_match_info_free); |
212 | | |
213 | | /* Obtain bootnext */ |
214 | 0 | regex = g_regex_new("^BootNext: ([0-9a-fA-F]{4})$", G_REGEX_MULTILINE, 0, NULL); |
215 | 0 | if (g_regex_match(regex, stdout_str, 0, &match)) { |
216 | 0 | if (bootnext) { |
217 | 0 | g_clear_pointer(&matched, g_free); |
218 | 0 | matched = g_match_info_fetch(match, 1); |
219 | 0 | *bootnext = get_efi_entry_by_bootnum(entries, matched); |
220 | 0 | } |
221 | 0 | } |
222 | |
|
223 | 0 | g_clear_pointer(®ex, g_regex_unref); |
224 | 0 | g_clear_pointer(&match, g_match_info_free); |
225 | | |
226 | | /* Obtain bootorder */ |
227 | 0 | regex = g_regex_new("^BootOrder: (\\S+)$", G_REGEX_MULTILINE, 0, NULL); |
228 | 0 | if (!g_regex_match(regex, stdout_str, 0, &match)) { |
229 | 0 | g_set_error( |
230 | 0 | error, |
231 | 0 | R_BOOTCHOOSER_ERROR, |
232 | 0 | R_BOOTCHOOSER_ERROR_FAILED, |
233 | 0 | "unable to obtain boot order!"); |
234 | 0 | res = FALSE; |
235 | 0 | goto out; |
236 | 0 | } |
237 | | |
238 | 0 | g_clear_pointer(&matched, g_free); |
239 | 0 | matched = g_match_info_fetch(match, 1); |
240 | 0 | bootnumorder = g_strsplit(matched, ",", 0); |
241 | | |
242 | | /* Iterate over boot entries list in bootorder */ |
243 | 0 | for (gchar **element = bootnumorder; *element; element++) { |
244 | 0 | efi_bootentry *bentry = get_efi_entry_by_bootnum(entries, *element); |
245 | 0 | if (bentry) |
246 | 0 | returnorder = g_list_append(returnorder, bentry); |
247 | 0 | } |
248 | |
|
249 | 0 | g_clear_pointer(®ex, g_regex_unref); |
250 | 0 | g_clear_pointer(&match, g_match_info_free); |
251 | | |
252 | | /* Obtain boot current */ |
253 | 0 | regex = g_regex_new("^BootCurrent: ([0-9a-fA-F]{4})$", G_REGEX_MULTILINE, 0, NULL); |
254 | 0 | if (g_regex_match(regex, stdout_str, 0, &match)) { |
255 | 0 | if (bootcurrent) { |
256 | 0 | g_clear_pointer(&matched, g_free); |
257 | 0 | matched = g_match_info_fetch(match, 1); |
258 | 0 | *bootcurrent = get_efi_entry_by_bootnum(entries, matched); |
259 | 0 | } |
260 | 0 | } |
261 | |
|
262 | 0 | if (bootorder_entries) |
263 | 0 | *bootorder_entries = g_steal_pointer(&returnorder); |
264 | 0 | *all_entries = g_steal_pointer(&entries); |
265 | |
|
266 | 0 | out: |
267 | 0 | g_clear_pointer(®ex, g_regex_unref); |
268 | 0 | g_clear_pointer(&match, g_match_info_free); |
269 | |
|
270 | 0 | return res; |
271 | 0 | } |
272 | | |
273 | | static gboolean efi_set_temp_primary(RaucSlot *slot, GError **error) |
274 | 0 | { |
275 | 0 | g_autolist(efi_bootentry) entries = NULL; |
276 | 0 | GError *ierror = NULL; |
277 | 0 | efi_bootentry *efi_slot_entry = NULL; |
278 | |
|
279 | 0 | if (!efi_bootorder_get(NULL, &entries, NULL, NULL, &ierror)) { |
280 | 0 | g_propagate_error(error, ierror); |
281 | 0 | return FALSE; |
282 | 0 | } |
283 | | |
284 | | /* Lookup efi boot entry matching slot */ |
285 | 0 | for (GList *entry = entries; entry != NULL; entry = entry->next) { |
286 | 0 | efi_bootentry *efi = entry->data; |
287 | 0 | if (g_strcmp0(efi->name, slot->bootname) == 0) { |
288 | 0 | efi_slot_entry = efi; |
289 | 0 | break; |
290 | 0 | } |
291 | 0 | } |
292 | |
|
293 | 0 | if (!efi_slot_entry) { |
294 | 0 | g_set_error( |
295 | 0 | error, |
296 | 0 | R_BOOTCHOOSER_ERROR, |
297 | 0 | R_BOOTCHOOSER_ERROR_FAILED, |
298 | 0 | "Did not find efi entry for bootname '%s'!", slot->bootname); |
299 | 0 | return FALSE; |
300 | 0 | } |
301 | | |
302 | 0 | if (!efi_set_bootnext(efi_slot_entry->num, &ierror)) { |
303 | 0 | g_propagate_prefixed_error(error, ierror, "Setting bootnext failed: "); |
304 | 0 | return FALSE; |
305 | 0 | } |
306 | | |
307 | 0 | return TRUE; |
308 | 0 | } |
309 | | |
310 | | /* Deletes given slot from efi bootorder list. |
311 | | * Prepends it to bootorder list if prepend argument is set to TRUE */ |
312 | | static gboolean efi_modify_persistent_bootorder(RaucSlot *slot, gboolean prepend, GError **error) |
313 | 0 | { |
314 | 0 | g_autoptr(GList) entries = NULL; |
315 | 0 | g_autolist(efi_bootentry) all_entries = NULL; |
316 | 0 | g_autoptr(GPtrArray) bootorder = NULL; |
317 | 0 | g_autofree gchar *order = NULL; |
318 | 0 | GError *ierror = NULL; |
319 | 0 | efi_bootentry *efi_slot_entry = NULL; |
320 | |
|
321 | 0 | g_return_val_if_fail(slot, FALSE); |
322 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
323 | | |
324 | 0 | if (!efi_bootorder_get(&entries, &all_entries, NULL, NULL, &ierror)) { |
325 | 0 | g_propagate_error(error, ierror); |
326 | 0 | return FALSE; |
327 | 0 | } |
328 | | |
329 | | /* Iterate over bootorder list until reaching boot entry to remove (if available) */ |
330 | 0 | for (GList *entry = entries; entry != NULL; entry = entry->next) { |
331 | 0 | efi_bootentry *efi = entry->data; |
332 | 0 | if (g_strcmp0(efi->name, slot->bootname) == 0) { |
333 | 0 | entries = g_list_remove(entries, efi); |
334 | 0 | break; |
335 | 0 | } |
336 | 0 | } |
337 | |
|
338 | 0 | if (prepend) { |
339 | | /* Iterate over full list to get entry to prepend to bootorder */ |
340 | 0 | for (GList *entry = all_entries; entry != NULL; entry = entry->next) { |
341 | 0 | efi_bootentry *efi = entry->data; |
342 | 0 | if (g_strcmp0(efi->name, slot->bootname) == 0) { |
343 | 0 | efi_slot_entry = efi; |
344 | 0 | break; |
345 | 0 | } |
346 | 0 | } |
347 | |
|
348 | 0 | if (!efi_slot_entry) { |
349 | 0 | g_set_error( |
350 | 0 | error, |
351 | 0 | R_BOOTCHOOSER_ERROR, |
352 | 0 | R_BOOTCHOOSER_ERROR_FAILED, |
353 | 0 | "No entry for bootname '%s' found", slot->bootname); |
354 | 0 | return FALSE; |
355 | 0 | } |
356 | | |
357 | 0 | entries = g_list_prepend(entries, efi_slot_entry); |
358 | 0 | } |
359 | | |
360 | 0 | bootorder = g_ptr_array_sized_new(g_list_length(entries)); |
361 | | /* Construct bootorder string out of boot entry list */ |
362 | 0 | for (GList *entry = entries; entry != NULL; entry = entry->next) { |
363 | 0 | efi_bootentry *efi = entry->data; |
364 | 0 | g_ptr_array_add(bootorder, efi->num); |
365 | 0 | } |
366 | 0 | g_ptr_array_add(bootorder, NULL); |
367 | |
|
368 | 0 | order = g_strjoinv(",", (gchar**)bootorder->pdata); |
369 | |
|
370 | 0 | if (!efi_bootorder_set(order, NULL)) { |
371 | 0 | g_propagate_prefixed_error(error, ierror, "Modifying bootorder failed: "); |
372 | 0 | return FALSE; |
373 | 0 | } |
374 | | |
375 | 0 | return TRUE; |
376 | 0 | } |
377 | | |
378 | | gboolean r_efi_set_state(RaucSlot *slot, gboolean good, GError **error) |
379 | 0 | { |
380 | 0 | GError *ierror = NULL; |
381 | |
|
382 | 0 | g_return_val_if_fail(slot, FALSE); |
383 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
384 | | |
385 | 0 | if (!efi_modify_persistent_bootorder(slot, good, &ierror)) { |
386 | 0 | g_propagate_error(error, ierror); |
387 | 0 | return FALSE; |
388 | 0 | } |
389 | | |
390 | 0 | return TRUE; |
391 | 0 | } |
392 | | |
393 | | RaucSlot *r_efi_get_primary(GError **error) |
394 | 0 | { |
395 | 0 | g_autoptr(GList) bootorder_entries = NULL; |
396 | 0 | g_autolist(efi_bootentry) all_entries = NULL; |
397 | 0 | GError *ierror = NULL; |
398 | 0 | efi_bootentry *bootnext = NULL; |
399 | 0 | RaucSlot *primary = NULL; |
400 | 0 | RaucSlot *slot; |
401 | 0 | GHashTableIter iter; |
402 | |
|
403 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
404 | | |
405 | 0 | if (!efi_bootorder_get(&bootorder_entries, &all_entries, &bootnext, NULL, &ierror)) { |
406 | 0 | g_propagate_error(error, ierror); |
407 | 0 | return NULL; |
408 | 0 | } |
409 | | |
410 | | /* We prepend the content of BootNext if set */ |
411 | 0 | if (bootnext) { |
412 | 0 | g_debug("Detected BootNext set to %s", bootnext->name); |
413 | 0 | bootorder_entries = g_list_prepend(bootorder_entries, bootnext); |
414 | 0 | } |
415 | |
|
416 | 0 | for (GList *entry = bootorder_entries; entry != NULL; entry = entry->next) { |
417 | 0 | efi_bootentry *bootentry = entry->data; |
418 | | |
419 | | /* Find matching slot entry */ |
420 | 0 | g_hash_table_iter_init(&iter, r_context()->config->slots); |
421 | 0 | while (g_hash_table_iter_next(&iter, NULL, (gpointer*) &slot)) { |
422 | 0 | if (g_strcmp0(bootentry->name, slot->bootname) == 0) { |
423 | 0 | primary = slot; |
424 | 0 | break; |
425 | 0 | } |
426 | 0 | } |
427 | |
|
428 | 0 | if (primary) |
429 | 0 | break; |
430 | 0 | } |
431 | |
|
432 | 0 | if (!primary) { |
433 | 0 | g_set_error( |
434 | 0 | error, |
435 | 0 | R_BOOTCHOOSER_ERROR, |
436 | 0 | R_BOOTCHOOSER_ERROR_PARSE_FAILED, |
437 | 0 | "Did not find primary boot entry!"); |
438 | 0 | return NULL; |
439 | 0 | } |
440 | | |
441 | 0 | return primary; |
442 | 0 | } |
443 | | |
444 | | gboolean r_efi_set_primary(RaucSlot *slot, GError **error) |
445 | 0 | { |
446 | 0 | GError *ierror = NULL; |
447 | |
|
448 | 0 | g_return_val_if_fail(slot, FALSE); |
449 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
450 | | |
451 | 0 | if (r_context()->config->efi_use_bootnext) { |
452 | 0 | if (!efi_set_temp_primary(slot, &ierror)) { |
453 | 0 | g_propagate_error(error, ierror); |
454 | 0 | return FALSE; |
455 | 0 | } |
456 | | |
457 | 0 | return TRUE; |
458 | 0 | } |
459 | | |
460 | 0 | if (!efi_modify_persistent_bootorder(slot, TRUE, &ierror)) { |
461 | 0 | g_propagate_error(error, ierror); |
462 | 0 | return FALSE; |
463 | 0 | } |
464 | | |
465 | 0 | return TRUE; |
466 | 0 | } |
467 | | |
468 | | /* We assume bootstate to be good if slot is listed in 'bootorder', otherwise |
469 | | * bad */ |
470 | | gboolean r_efi_get_state(RaucSlot *slot, gboolean *good, GError **error) |
471 | 0 | { |
472 | 0 | efi_bootentry *found_entry = NULL; |
473 | 0 | GError *ierror = NULL; |
474 | 0 | g_autoptr(GList) bootorder_entries = NULL; |
475 | 0 | g_autolist(efi_bootentry) all_entries = NULL; |
476 | |
|
477 | 0 | g_return_val_if_fail(slot, FALSE); |
478 | 0 | g_return_val_if_fail(good, FALSE); |
479 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, FALSE); |
480 | | |
481 | 0 | if (!efi_bootorder_get(&bootorder_entries, &all_entries, NULL, NULL, &ierror)) { |
482 | 0 | g_propagate_error(error, ierror); |
483 | 0 | return FALSE; |
484 | 0 | } |
485 | | |
486 | | /* Scan bootorder list for given slot */ |
487 | 0 | for (GList *entry = bootorder_entries; entry != NULL; entry = entry->next) { |
488 | 0 | efi_bootentry *ptr = entry->data; |
489 | 0 | if (g_strcmp0(slot->bootname, ptr->name) == 0) { |
490 | 0 | found_entry = ptr; |
491 | 0 | break; |
492 | 0 | } |
493 | 0 | } |
494 | |
|
495 | 0 | *good = found_entry ? TRUE : FALSE; |
496 | |
|
497 | 0 | return TRUE; |
498 | 0 | } |
499 | | |
500 | | gchar *r_efi_get_current_bootname(RaucConfig *config, GError **error) |
501 | 0 | { |
502 | 0 | g_autolist(efi_bootentry) all_entries = NULL; |
503 | 0 | GError *ierror = NULL; |
504 | 0 | efi_bootentry *bootcurrent = NULL; |
505 | 0 | RaucSlot *slot = NULL; |
506 | 0 | GHashTableIter iter; |
507 | |
|
508 | 0 | if (!efi_bootorder_get(NULL, &all_entries, NULL, &bootcurrent, &ierror)) { |
509 | 0 | g_propagate_error(error, ierror); |
510 | 0 | return NULL; |
511 | 0 | } |
512 | | |
513 | 0 | g_hash_table_iter_init(&iter, config->slots); |
514 | 0 | while (g_hash_table_iter_next(&iter, NULL, (gpointer*) &slot)) { |
515 | 0 | if (g_strcmp0(slot->bootname, bootcurrent->name) == 0) { |
516 | 0 | return slot->bootname; |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | 0 | g_set_error(error, |
521 | 0 | R_BOOTCHOOSER_ERROR, |
522 | 0 | R_BOOTCHOOSER_ERROR_FAILED, |
523 | 0 | "Current EFI bootentry not known to rauc!"); |
524 | |
|
525 | | return NULL; |
526 | 0 | } |