chiark / gitweb /
use streq instead of strcmp
[elogind.git] / src / boot / boot-efi.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 Kay Sievers
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 <stdlib.h>
23 #include <stdbool.h>
24 #include <unistd.h>
25 #include <getopt.h>
26 #include <locale.h>
27 #include <string.h>
28 #include <fnmatch.h>
29 #include <fcntl.h>
30 #include <sys/timex.h>
31
32 #include "boot.h"
33 #include "boot-loader.h"
34 #include "build.h"
35 #include "util.h"
36 #include "strv.h"
37 #include "efivars.h"
38 #include "conf-files.h"
39
40 static char *tilt_slashes(char *s) {
41         char *p;
42
43         if (!s)
44                 return NULL;
45
46         for (p = s; *p; p++)
47                 if (*p == '\\')
48                         *p = '/';
49         return s;
50 }
51
52 static int get_boot_entries(struct boot_info *info) {
53         uint16_t *list;
54         int i, n;
55         int err = 0;
56
57         n = efi_get_boot_options(&list);
58         if (n < 0)
59                 return n;
60
61         for (i = 0; i < n; i++) {
62                 struct boot_info_entry *e;
63
64                 e = realloc(info->fw_entries, (info->fw_entries_count+1) * sizeof(struct boot_info_entry));
65                 if (!e) {
66                         err = -ENOMEM;
67                                 break;
68                 }
69                 info->fw_entries = e;
70
71                 e = &info->fw_entries[info->fw_entries_count];
72                 memset(e, 0, sizeof(struct boot_info_entry));
73                 e->order = -1;
74
75                 err = efi_get_boot_option(list[i], &e->title, &e->part_uuid, &e->path);
76                 if (err < 0)
77                         continue;
78                 tilt_slashes(e->path);
79                 e->id = list[i];
80                 info->fw_entries_count++;
81         }
82
83         free(list);
84         return err;
85 }
86
87 static int find_active_entry(struct boot_info *info) {
88         uint16_t boot_cur;
89         void *buf;
90         size_t l;
91         size_t i;
92         int err = -ENOENT;
93
94         err = efi_get_variable(EFI_VENDOR_GLOBAL, "BootCurrent", NULL, &buf, &l);
95         if (err < 0)
96                 return err;
97
98         memcpy(&boot_cur, buf, sizeof(uint16_t));
99         for (i = 0; i < info->fw_entries_count; i++) {
100                 if (info->fw_entries[i].id != boot_cur)
101                         continue;
102                 info->fw_entry_active = i;
103                 err = 0;
104                 break;
105         }
106         free(buf);
107         return err;
108 }
109
110 static int get_boot_order(struct boot_info *info) {
111         size_t i, k;
112         int r;
113
114         r = efi_get_boot_order(&info->fw_entries_order);
115         if (r < 0)
116                 return r;
117
118         info->fw_entries_order_count = r;
119
120         for (i = 0; i < info->fw_entries_order_count; i++) {
121                 for (k = 0; k < info->fw_entries_count; k++) {
122                         if (info->fw_entries[k].id != info->fw_entries_order[i])
123                                 continue;
124                         info->fw_entries[k].order = i;
125                         break;
126                 }
127         }
128
129         return 0;
130 }
131
132 static int entry_cmp(const void *a, const void *b) {
133         const struct boot_info_entry *e1 = a;
134         const struct boot_info_entry *e2 = b;
135
136         /* boot order of active entries */
137         if (e1->order > 0 && e2->order > 0)
138                 return e1->order - e2->order;
139
140         /* sort active entries before inactive ones */
141         if (e1->order > 0)
142                 return 1;
143         if (e2->order > 0)
144                 return -1;
145
146         /* order of inactive entries */
147         return e1->id - e2->id;
148 }
149
150 int boot_info_query(struct boot_info *info) {
151         char str[64];
152         char buf[64];
153         char *loader_active = NULL;
154
155         efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info->loader);
156
157         get_boot_entries(info);
158         if (info->fw_entries_count > 0) {
159                 get_boot_order(info);
160                 qsort(info->fw_entries, info->fw_entries_count, sizeof(struct boot_info_entry), entry_cmp);
161                 find_active_entry(info);
162         }
163
164         efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &info->fw_type);
165         efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &info->fw_info);
166         efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &info->loader_image_path);
167         tilt_slashes(info->loader_image_path);
168         efi_get_loader_device_part_uuid(&info->loader_part_uuid);
169
170         boot_loader_read_entries(info);
171         efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntrySelected", &loader_active);
172         if (loader_active) {
173                 boot_loader_find_active_entry(info, loader_active);
174                 free(loader_active);
175         }
176
177         snprintf(str, sizeof(str), "LoaderEntryOptions-%s", sd_id128_to_string(info->machine_id, buf));
178         efi_get_variable_string(EFI_VENDOR_LOADER, str, &info->loader_options_added);
179
180         return 0;
181 }