]>
Commit | Line | Data |
---|---|---|
f1c7b511 JP |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Peter Jones <pjones@redhat.com> | |
36121927 | 3 | Date: Tue, 22 Jan 2013 06:31:38 +0100 |
f1c7b511 JP |
4 | Subject: [PATCH] blscfg: add blscfg module to parse Boot Loader Specification |
5 | snippets | |
36121927 | 6 | |
f1c7b511 JP |
7 | The BootLoaderSpec (BLS) defines a scheme where different bootloaders can |
8 | share a format for boot items and a configuration directory that accepts | |
9 | these common configurations as drop-in files. | |
36121927 | 10 | |
f1c7b511 JP |
11 | Signed-off-by: Peter Jones <pjones@redhat.com> |
12 | Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> | |
13 | [wjt: some cleanups and fixes] | |
14 | Signed-off-by: Will Thompson <wjt@endlessm.com> | |
36121927 | 15 | --- |
f1c7b511 JP |
16 | grub-core/Makefile.core.def | 11 + |
17 | grub-core/commands/blscfg.c | 1096 ++++++++++++++++++++++++++++++++++++++++ | |
18 | grub-core/commands/legacycfg.c | 5 +- | |
19 | grub-core/commands/loadenv.c | 77 +-- | |
20 | grub-core/commands/menuentry.c | 20 +- | |
21 | grub-core/normal/main.c | 6 + | |
22 | grub-core/commands/loadenv.h | 93 ++++ | |
23 | include/grub/compiler.h | 2 + | |
24 | include/grub/menu.h | 13 + | |
25 | include/grub/normal.h | 2 +- | |
26 | 10 files changed, 1243 insertions(+), 82 deletions(-) | |
36121927 | 27 | create mode 100644 grub-core/commands/blscfg.c |
f1c7b511 | 28 | create mode 100644 grub-core/commands/loadenv.h |
36121927 ER |
29 | |
30 | diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def | |
f1c7b511 | 31 | index 41b5e16a3ce..57e253ab1a1 100644 |
36121927 ER |
32 | --- a/grub-core/Makefile.core.def |
33 | +++ b/grub-core/Makefile.core.def | |
f1c7b511 JP |
34 | @@ -811,6 +811,16 @@ module = { |
35 | common = commands/blocklist.c; | |
36121927 ER |
36 | }; |
37 | ||
f1c7b511 | 38 | +module = { |
36121927 ER |
39 | + name = blscfg; |
40 | + common = commands/blscfg.c; | |
f1c7b511 JP |
41 | + common = commands/loadenv.h; |
42 | + enable = powerpc_ieee1275; | |
43 | + enable = efi; | |
36121927 | 44 | + enable = i386_pc; |
f1c7b511 | 45 | + enable = emu; |
36121927 ER |
46 | +}; |
47 | + | |
f1c7b511 | 48 | module = { |
36121927 ER |
49 | name = boot; |
50 | common = commands/boot.c; | |
f1c7b511 JP |
51 | @@ -988,6 +998,7 @@ module = { |
52 | module = { | |
53 | name = loadenv; | |
54 | common = commands/loadenv.c; | |
55 | + common = commands/loadenv.h; | |
56 | common = lib/envblk.c; | |
57 | }; | |
58 | ||
36121927 ER |
59 | diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c |
60 | new file mode 100644 | |
f1c7b511 | 61 | index 00000000000..54458b14518 |
36121927 ER |
62 | --- /dev/null |
63 | +++ b/grub-core/commands/blscfg.c | |
f1c7b511 | 64 | @@ -0,0 +1,1096 @@ |
36121927 ER |
65 | +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ |
66 | + | |
67 | +/* bls.c - implementation of the boot loader spec */ | |
68 | + | |
69 | +/* | |
70 | + * GRUB -- GRand Unified Bootloader | |
71 | + * | |
72 | + * GRUB is free software: you can redistribute it and/or modify | |
73 | + * it under the terms of the GNU General Public License as published by | |
74 | + * the Free Software Foundation, either version 3 of the License, or | |
75 | + * (at your option) any later version. | |
76 | + * | |
77 | + * GRUB is distributed in the hope that it will be useful, | |
78 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
79 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
80 | + * GNU General Public License for more details. | |
81 | + * | |
82 | + * You should have received a copy of the GNU General Public License | |
83 | + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
84 | + */ | |
85 | + | |
f1c7b511 | 86 | +#include <grub/list.h> |
36121927 ER |
87 | +#include <grub/types.h> |
88 | +#include <grub/misc.h> | |
89 | +#include <grub/mm.h> | |
90 | +#include <grub/err.h> | |
91 | +#include <grub/dl.h> | |
92 | +#include <grub/extcmd.h> | |
93 | +#include <grub/i18n.h> | |
94 | +#include <grub/fs.h> | |
95 | +#include <grub/env.h> | |
96 | +#include <grub/file.h> | |
97 | +#include <grub/normal.h> | |
f1c7b511 JP |
98 | +#include <grub/lib/envblk.h> |
99 | + | |
100 | +#include <stdbool.h> | |
36121927 ER |
101 | + |
102 | +GRUB_MOD_LICENSE ("GPLv3+"); | |
103 | + | |
f1c7b511 JP |
104 | +#include "loadenv.h" |
105 | + | |
36121927 | 106 | +#define GRUB_BLS_CONFIG_PATH "/loader/entries/" |
f1c7b511 JP |
107 | +#ifdef GRUB_MACHINE_EMU |
108 | +#define GRUB_BOOT_DEVICE "/boot" | |
109 | +#else | |
36121927 ER |
110 | +#define GRUB_BOOT_DEVICE "($root)" |
111 | +#endif | |
112 | + | |
f1c7b511 JP |
113 | +struct keyval |
114 | +{ | |
115 | + const char *key; | |
116 | + char *val; | |
117 | +}; | |
118 | + | |
119 | +static struct bls_entry *entries = NULL; | |
120 | + | |
121 | +#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) | |
122 | + | |
123 | +static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) | |
124 | +{ | |
125 | + char *k, *v; | |
126 | + struct keyval **kvs, *kv; | |
127 | + int new_n = entry->nkeyvals + 1; | |
128 | + | |
129 | + kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *)); | |
130 | + if (!kvs) | |
131 | + return grub_error (GRUB_ERR_OUT_OF_MEMORY, | |
132 | + "couldn't find space for BLS entry"); | |
133 | + entry->keyvals = kvs; | |
134 | + | |
135 | + kv = grub_malloc (sizeof (struct keyval)); | |
136 | + if (!kv) | |
137 | + return grub_error (GRUB_ERR_OUT_OF_MEMORY, | |
138 | + "couldn't find space for BLS entry"); | |
139 | + | |
140 | + k = grub_strdup (key); | |
141 | + if (!k) | |
142 | + { | |
143 | + grub_free (kv); | |
144 | + return grub_error (GRUB_ERR_OUT_OF_MEMORY, | |
145 | + "couldn't find space for BLS entry"); | |
146 | + } | |
147 | + | |
148 | + v = grub_strdup (val); | |
149 | + if (!v) | |
150 | + { | |
151 | + grub_free (k); | |
152 | + grub_free (kv); | |
153 | + return grub_error (GRUB_ERR_OUT_OF_MEMORY, | |
154 | + "couldn't find space for BLS entry"); | |
155 | + } | |
156 | + | |
157 | + kv->key = k; | |
158 | + kv->val = v; | |
159 | + | |
160 | + entry->keyvals[entry->nkeyvals] = kv; | |
161 | + grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v); | |
162 | + entry->nkeyvals = new_n; | |
163 | + | |
164 | + return 0; | |
165 | +} | |
166 | + | |
167 | +/* Find they value of the key named by keyname. If there are allowed to be | |
168 | + * more than one, pass a pointer to an int set to -1 the first time, and pass | |
169 | + * the same pointer through each time after, and it'll return them in sorted | |
170 | + * order as defined in the BLS fragment file */ | |
171 | +static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last) | |
172 | +{ | |
173 | + int idx, start = 0; | |
174 | + struct keyval *kv = NULL; | |
175 | + | |
176 | + if (last) | |
177 | + start = *last + 1; | |
178 | + | |
179 | + for (idx = start; idx < entry->nkeyvals; idx++) { | |
180 | + kv = entry->keyvals[idx]; | |
181 | + | |
182 | + if (!grub_strcmp (keyname, kv->key)) | |
183 | + break; | |
184 | + } | |
185 | + | |
186 | + if (idx == entry->nkeyvals) { | |
187 | + if (last) | |
188 | + *last = -1; | |
189 | + return NULL; | |
190 | + } | |
191 | + | |
192 | + if (last) | |
193 | + *last = idx; | |
194 | + | |
195 | + return kv->val; | |
196 | +} | |
197 | + | |
198 | +#define goto_return(x) ({ ret = (x); goto finish; }) | |
199 | + | |
200 | +/* compare alpha and numeric segments of two versions */ | |
201 | +/* return 1: a is newer than b */ | |
202 | +/* 0: a and b are the same version */ | |
203 | +/* -1: b is newer than a */ | |
204 | +static int vercmp(const char * a, const char * b) | |
205 | +{ | |
206 | + char oldch1, oldch2; | |
207 | + char *abuf, *bbuf; | |
208 | + char *str1, *str2; | |
209 | + char * one, * two; | |
210 | + int rc; | |
211 | + int isnum; | |
212 | + int ret = 0; | |
213 | + | |
214 | + grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b); | |
215 | + if (!grub_strcmp(a, b)) | |
216 | + return 0; | |
217 | + | |
218 | + abuf = grub_malloc(grub_strlen(a) + 1); | |
219 | + bbuf = grub_malloc(grub_strlen(b) + 1); | |
220 | + str1 = abuf; | |
221 | + str2 = bbuf; | |
222 | + grub_strcpy(str1, a); | |
223 | + grub_strcpy(str2, b); | |
224 | + | |
225 | + one = str1; | |
226 | + two = str2; | |
227 | + | |
228 | + /* loop through each version segment of str1 and str2 and compare them */ | |
229 | + while (*one || *two) { | |
230 | + while (*one && !grub_isalnum(*one) && *one != '~') one++; | |
231 | + while (*two && !grub_isalnum(*two) && *two != '~') two++; | |
232 | + | |
233 | + /* handle the tilde separator, it sorts before everything else */ | |
234 | + if (*one == '~' || *two == '~') { | |
235 | + if (*one != '~') goto_return (1); | |
236 | + if (*two != '~') goto_return (-1); | |
237 | + one++; | |
238 | + two++; | |
239 | + continue; | |
240 | + } | |
241 | + | |
242 | + /* If we ran to the end of either, we are finished with the loop */ | |
243 | + if (!(*one && *two)) break; | |
244 | + | |
245 | + str1 = one; | |
246 | + str2 = two; | |
247 | + | |
248 | + /* grab first completely alpha or completely numeric segment */ | |
249 | + /* leave one and two pointing to the start of the alpha or numeric */ | |
250 | + /* segment and walk str1 and str2 to end of segment */ | |
251 | + if (grub_isdigit(*str1)) { | |
252 | + while (*str1 && grub_isdigit(*str1)) str1++; | |
253 | + while (*str2 && grub_isdigit(*str2)) str2++; | |
254 | + isnum = 1; | |
255 | + } else { | |
256 | + while (*str1 && grub_isalpha(*str1)) str1++; | |
257 | + while (*str2 && grub_isalpha(*str2)) str2++; | |
258 | + isnum = 0; | |
259 | + } | |
260 | + | |
261 | + /* save character at the end of the alpha or numeric segment */ | |
262 | + /* so that they can be restored after the comparison */ | |
263 | + oldch1 = *str1; | |
264 | + *str1 = '\0'; | |
265 | + oldch2 = *str2; | |
266 | + *str2 = '\0'; | |
267 | + | |
268 | + /* this cannot happen, as we previously tested to make sure that */ | |
269 | + /* the first string has a non-null segment */ | |
270 | + if (one == str1) goto_return(-1); /* arbitrary */ | |
271 | + | |
272 | + /* take care of the case where the two version segments are */ | |
273 | + /* different types: one numeric, the other alpha (i.e. empty) */ | |
274 | + /* numeric segments are always newer than alpha segments */ | |
275 | + /* XXX See patch #60884 (and details) from bugzilla #50977. */ | |
276 | + if (two == str2) goto_return (isnum ? 1 : -1); | |
277 | + | |
278 | + if (isnum) { | |
279 | + grub_size_t onelen, twolen; | |
280 | + /* this used to be done by converting the digit segments */ | |
281 | + /* to ints using atoi() - it's changed because long */ | |
282 | + /* digit segments can overflow an int - this should fix that. */ | |
283 | + | |
284 | + /* throw away any leading zeros - it's a number, right? */ | |
285 | + while (*one == '0') one++; | |
286 | + while (*two == '0') two++; | |
287 | + | |
288 | + /* whichever number has more digits wins */ | |
289 | + onelen = grub_strlen(one); | |
290 | + twolen = grub_strlen(two); | |
291 | + if (onelen > twolen) goto_return (1); | |
292 | + if (twolen > onelen) goto_return (-1); | |
293 | + } | |
294 | + | |
295 | + /* grub_strcmp will return which one is greater - even if the two */ | |
296 | + /* segments are alpha or if they are numeric. don't return */ | |
297 | + /* if they are equal because there might be more segments to */ | |
298 | + /* compare */ | |
299 | + rc = grub_strcmp(one, two); | |
300 | + if (rc) goto_return (rc < 1 ? -1 : 1); | |
301 | + | |
302 | + /* restore character that was replaced by null above */ | |
303 | + *str1 = oldch1; | |
304 | + one = str1; | |
305 | + *str2 = oldch2; | |
306 | + two = str2; | |
307 | + } | |
308 | + | |
309 | + /* this catches the case where all numeric and alpha segments have */ | |
310 | + /* compared identically but the segment sepparating characters were */ | |
311 | + /* different */ | |
312 | + if ((!*one) && (!*two)) goto_return (0); | |
313 | + | |
314 | + /* whichever version still has characters left over wins */ | |
315 | + if (!*one) goto_return (-1); else goto_return (1); | |
316 | + | |
317 | +finish: | |
318 | + grub_free (abuf); | |
319 | + grub_free (bbuf); | |
320 | + return ret; | |
321 | +} | |
322 | + | |
323 | +/* returns name/version/release */ | |
324 | +/* NULL string pointer returned if nothing found */ | |
325 | +static void | |
326 | +split_package_string (char *package_string, char **name, | |
327 | + char **version, char **release) | |
328 | +{ | |
329 | + char *package_version, *package_release; | |
330 | + | |
331 | + /* Release */ | |
332 | + package_release = grub_strrchr (package_string, '-'); | |
333 | + | |
334 | + if (package_release != NULL) | |
335 | + *package_release++ = '\0'; | |
336 | + | |
337 | + *release = package_release; | |
338 | + | |
339 | + if (name == NULL) | |
340 | + { | |
341 | + *version = package_string; | |
342 | + } | |
343 | + else | |
344 | + { | |
345 | + /* Version */ | |
346 | + package_version = grub_strrchr(package_string, '-'); | |
347 | + | |
348 | + if (package_version != NULL) | |
349 | + *package_version++ = '\0'; | |
350 | + | |
351 | + *version = package_version; | |
352 | + /* Name */ | |
353 | + *name = package_string; | |
354 | + } | |
355 | + | |
356 | + /* Bubble up non-null values from release to name */ | |
357 | + if (name != NULL && *name == NULL) | |
358 | + { | |
359 | + *name = (*version == NULL ? *release : *version); | |
360 | + *version = *release; | |
361 | + *release = NULL; | |
362 | + } | |
363 | + if (*version == NULL) | |
364 | + { | |
365 | + *version = *release; | |
366 | + *release = NULL; | |
367 | + } | |
368 | +} | |
369 | + | |
370 | +static int | |
371 | +split_cmp(char *nvr0, char *nvr1, int has_name) | |
372 | +{ | |
373 | + int ret = 0; | |
374 | + char *name0, *version0, *release0; | |
375 | + char *name1, *version1, *release1; | |
376 | + | |
377 | + split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); | |
378 | + split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); | |
379 | + | |
380 | + if (has_name) | |
381 | + { | |
382 | + ret = vercmp(name0 == NULL ? "" : name0, | |
383 | + name1 == NULL ? "" : name1); | |
384 | + if (ret != 0) | |
385 | + return ret; | |
386 | + } | |
387 | + | |
388 | + ret = vercmp(version0 == NULL ? "" : version0, | |
389 | + version1 == NULL ? "" : version1); | |
390 | + if (ret != 0) | |
391 | + return ret; | |
392 | + | |
393 | + ret = vercmp(release0 == NULL ? "" : release0, | |
394 | + release1 == NULL ? "" : release1); | |
395 | + return ret; | |
396 | +} | |
397 | + | |
398 | +/* return 1: e0 is newer than e1 */ | |
399 | +/* 0: e0 and e1 are the same version */ | |
400 | +/* -1: e1 is newer than e0 */ | |
401 | +static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1) | |
402 | +{ | |
403 | + char *id0, *id1; | |
404 | + int r; | |
405 | + | |
406 | + id0 = grub_strdup(e0->filename); | |
407 | + id1 = grub_strdup(e1->filename); | |
408 | + | |
409 | + r = split_cmp(id0, id1, 1); | |
410 | + | |
411 | + grub_free(id0); | |
412 | + grub_free(id1); | |
413 | + | |
414 | + return r; | |
415 | +} | |
416 | + | |
417 | +static void list_add_tail(struct bls_entry *head, struct bls_entry *item) | |
418 | +{ | |
419 | + item->next = head; | |
420 | + if (head->prev) | |
421 | + head->prev->next = item; | |
422 | + item->prev = head->prev; | |
423 | + head->prev = item; | |
424 | +} | |
425 | + | |
426 | +static int bls_add_entry(struct bls_entry *entry) | |
427 | +{ | |
428 | + struct bls_entry *e, *last = NULL; | |
429 | + int rc; | |
430 | + | |
431 | + if (!entries) { | |
432 | + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); | |
433 | + entries = entry; | |
434 | + return 0; | |
435 | + } | |
436 | + | |
437 | + FOR_BLS_ENTRIES(e) { | |
438 | + rc = bls_cmp(entry, e); | |
439 | + | |
440 | + if (!rc) | |
441 | + return GRUB_ERR_BAD_ARGUMENT; | |
442 | + | |
443 | + if (rc == 1) { | |
444 | + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); | |
445 | + list_add_tail (e, entry); | |
446 | + if (e == entries) { | |
447 | + entries = entry; | |
448 | + entry->prev = NULL; | |
449 | + } | |
450 | + return 0; | |
451 | + } | |
452 | + last = e; | |
453 | + } | |
454 | + | |
455 | + if (last) { | |
456 | + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); | |
457 | + last->next = entry; | |
458 | + entry->prev = last; | |
459 | + } | |
460 | + | |
461 | + return 0; | |
462 | +} | |
463 | + | |
464 | +struct read_entry_info { | |
465 | + const char *devid; | |
466 | + const char *dirname; | |
467 | + grub_file_t file; | |
468 | +}; | |
469 | + | |
470 | +static int read_entry ( | |
36121927 | 471 | + const char *filename, |
f1c7b511 JP |
472 | + const struct grub_dirhook_info *dirhook_info UNUSED, |
473 | + void *data) | |
36121927 | 474 | +{ |
f1c7b511 JP |
475 | + grub_size_t m = 0, n, clip = 0; |
476 | + int rc = 0; | |
477 | + char *p = NULL; | |
36121927 | 478 | + grub_file_t f = NULL; |
f1c7b511 JP |
479 | + struct bls_entry *entry; |
480 | + struct read_entry_info *info = (struct read_entry_info *)data; | |
36121927 | 481 | + |
f1c7b511 | 482 | + grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); |
36121927 ER |
483 | + |
484 | + n = grub_strlen (filename); | |
36121927 | 485 | + |
f1c7b511 JP |
486 | + if (info->file) |
487 | + { | |
488 | + f = info->file; | |
489 | + } | |
490 | + else | |
491 | + { | |
492 | + if (filename[0] == '.') | |
493 | + return 0; | |
494 | + | |
495 | + if (n <= 5) | |
496 | + return 0; | |
497 | + | |
498 | + if (grub_strcmp (filename + n - 5, ".conf") != 0) | |
499 | + return 0; | |
36121927 | 500 | + |
f1c7b511 | 501 | + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); |
36121927 | 502 | + |
f1c7b511 JP |
503 | + f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); |
504 | + if (!f) | |
505 | + goto finish; | |
506 | + } | |
507 | + | |
508 | + entry = grub_zalloc (sizeof (*entry)); | |
509 | + if (!entry) | |
36121927 ER |
510 | + goto finish; |
511 | + | |
f1c7b511 JP |
512 | + if (info->file) |
513 | + { | |
514 | + char *slash; | |
515 | + | |
516 | + if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) | |
517 | + clip = 5; | |
518 | + | |
519 | + slash = grub_strrchr (filename, '/'); | |
520 | + if (!slash) | |
521 | + slash = grub_strrchr (filename, '\\'); | |
522 | + | |
523 | + while (*slash == '/' || *slash == '\\') | |
524 | + slash++; | |
525 | + | |
526 | + m = slash ? slash - filename : 0; | |
527 | + } | |
528 | + else | |
529 | + { | |
530 | + m = 0; | |
531 | + clip = 5; | |
532 | + } | |
533 | + n -= m; | |
534 | + | |
535 | + entry->filename = grub_strndup(filename + m, n - clip); | |
536 | + if (!entry->filename) | |
36121927 ER |
537 | + goto finish; |
538 | + | |
f1c7b511 JP |
539 | + entry->filename[n - 5] = '\0'; |
540 | + | |
36121927 ER |
541 | + for (;;) |
542 | + { | |
543 | + char *buf; | |
f1c7b511 | 544 | + char *separator; |
36121927 ER |
545 | + |
546 | + buf = grub_file_getline (f); | |
547 | + if (!buf) | |
548 | + break; | |
549 | + | |
f1c7b511 JP |
550 | + while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t')) |
551 | + buf++; | |
552 | + if (buf[0] == '#') | |
553 | + continue; | |
554 | + | |
555 | + separator = grub_strchr (buf, ' '); | |
556 | + | |
557 | + if (!separator) | |
558 | + separator = grub_strchr (buf, '\t'); | |
559 | + | |
560 | + if (!separator || separator[1] == '\0') | |
36121927 | 561 | + { |
f1c7b511 JP |
562 | + grub_free (buf); |
563 | + break; | |
36121927 | 564 | + } |
f1c7b511 JP |
565 | + |
566 | + separator[0] = '\0'; | |
567 | + | |
568 | + do { | |
569 | + separator++; | |
570 | + } while (*separator == ' ' || *separator == '\t'); | |
571 | + | |
572 | + rc = bls_add_keyval (entry, buf, separator); | |
573 | + grub_free (buf); | |
574 | + if (rc < 0) | |
575 | + break; | |
576 | + } | |
577 | + | |
578 | + if (!rc) | |
579 | + bls_add_entry(entry); | |
580 | + | |
581 | +finish: | |
582 | + if (p) | |
583 | + grub_free (p); | |
584 | + | |
585 | + if (f) | |
586 | + grub_file_close (f); | |
587 | + | |
588 | + return 0; | |
589 | +} | |
590 | + | |
591 | +static grub_envblk_t saved_env = NULL; | |
592 | + | |
593 | +static int UNUSED | |
594 | +save_var (const char *name, const char *value, void *whitelist UNUSED) | |
595 | +{ | |
596 | + const char *val = grub_env_get (name); | |
597 | + grub_dprintf("blscfg", "saving \"%s\"\n", name); | |
598 | + | |
599 | + if (val) | |
600 | + grub_envblk_set (saved_env, name, value); | |
601 | + | |
602 | + return 0; | |
603 | +} | |
604 | + | |
605 | +static int UNUSED | |
606 | +unset_var (const char *name, const char *value UNUSED, void *whitelist) | |
607 | +{ | |
608 | + grub_dprintf("blscfg", "restoring \"%s\"\n", name); | |
609 | + if (! whitelist) | |
610 | + { | |
611 | + grub_env_unset (name); | |
612 | + return 0; | |
613 | + } | |
614 | + | |
615 | + if (test_whitelist_membership (name, | |
616 | + (const grub_env_whitelist_t *) whitelist)) | |
617 | + grub_env_unset (name); | |
618 | + | |
619 | + return 0; | |
620 | +} | |
621 | + | |
622 | +static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) | |
623 | +{ | |
624 | + int last = -1; | |
625 | + char *val; | |
626 | + | |
627 | + int nlist = 0; | |
628 | + char **list = NULL; | |
629 | + | |
630 | + list = grub_malloc (sizeof (char *)); | |
631 | + if (!list) | |
632 | + return NULL; | |
633 | + list[0] = NULL; | |
634 | + | |
635 | + while (1) | |
636 | + { | |
637 | + char **new; | |
638 | + | |
639 | + val = bls_get_val (entry, key, &last); | |
640 | + if (!val) | |
641 | + break; | |
642 | + | |
643 | + new = grub_realloc (list, (nlist + 2) * sizeof (char *)); | |
644 | + if (!new) | |
645 | + break; | |
646 | + | |
647 | + list = new; | |
648 | + list[nlist++] = val; | |
649 | + list[nlist] = NULL; | |
650 | + } | |
651 | + | |
652 | + if (num) | |
653 | + *num = nlist; | |
654 | + | |
655 | + return list; | |
656 | +} | |
657 | + | |
658 | +static char *field_append(bool is_var, char *buffer, char *start, char *end) | |
659 | +{ | |
660 | + char *temp = grub_strndup(start, end - start + 1); | |
661 | + const char *field = temp; | |
662 | + | |
663 | + if (is_var) { | |
664 | + field = grub_env_get (temp); | |
665 | + if (!field) | |
666 | + return buffer; | |
667 | + } | |
668 | + | |
669 | + if (!buffer) { | |
670 | + buffer = grub_strdup(field); | |
671 | + if (!buffer) | |
672 | + return NULL; | |
673 | + } else { | |
674 | + buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field)); | |
675 | + if (!buffer) | |
676 | + return NULL; | |
677 | + | |
678 | + grub_stpcpy (buffer + grub_strlen(buffer), field); | |
679 | + } | |
680 | + | |
681 | + return buffer; | |
682 | +} | |
683 | + | |
684 | +static char *expand_val(char *value) | |
685 | +{ | |
686 | + char *buffer = NULL; | |
687 | + char *start = value; | |
688 | + char *end = value; | |
689 | + bool is_var = false; | |
690 | + | |
691 | + if (!value) | |
692 | + return NULL; | |
693 | + | |
694 | + while (*value) { | |
695 | + if (*value == '$') { | |
696 | + if (start != end) { | |
697 | + buffer = field_append(is_var, buffer, start, end); | |
698 | + if (!buffer) | |
699 | + return NULL; | |
700 | + } | |
701 | + | |
702 | + is_var = true; | |
703 | + start = value + 1; | |
704 | + } else if (is_var) { | |
705 | + if (!grub_isalnum(*value) && *value != '_') { | |
706 | + buffer = field_append(is_var, buffer, start, end); | |
707 | + is_var = false; | |
708 | + start = value; | |
709 | + } | |
710 | + } | |
711 | + | |
712 | + end = value; | |
713 | + value++; | |
714 | + } | |
715 | + | |
716 | + if (start != end) { | |
717 | + buffer = field_append(is_var, buffer, start, end); | |
718 | + if (!buffer) | |
719 | + return NULL; | |
720 | + } | |
721 | + | |
722 | + return buffer; | |
723 | +} | |
724 | + | |
725 | +static char **early_initrd_list (const char *initrd) | |
726 | +{ | |
727 | + int nlist = 0; | |
728 | + char **list = NULL; | |
729 | + char *separator; | |
730 | + | |
731 | + while ((separator = grub_strchr (initrd, ' '))) | |
732 | + { | |
733 | + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); | |
734 | + if (!list) | |
735 | + return NULL; | |
736 | + | |
737 | + list[nlist++] = grub_strndup(initrd, separator - initrd); | |
738 | + list[nlist] = NULL; | |
739 | + initrd = separator + 1; | |
740 | + } | |
741 | + | |
742 | + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); | |
743 | + if (!list) | |
744 | + return NULL; | |
745 | + | |
746 | + list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); | |
747 | + list[nlist] = NULL; | |
748 | + | |
749 | + return list; | |
750 | +} | |
751 | + | |
752 | +static void create_entry (struct bls_entry *entry) | |
753 | +{ | |
754 | + int argc = 0; | |
755 | + const char **argv = NULL; | |
756 | + | |
757 | + char *title = NULL; | |
758 | + char *clinux = NULL; | |
759 | + char *options = NULL; | |
760 | + char **initrds = NULL; | |
761 | + char *initrd = NULL; | |
762 | + const char *early_initrd = NULL; | |
763 | + char **early_initrds = NULL; | |
764 | + char *initrd_prefix = NULL; | |
765 | + char *id = entry->filename; | |
766 | + char *dotconf = id; | |
767 | + char *hotkey = NULL; | |
768 | + | |
769 | + char *users = NULL; | |
770 | + char **classes = NULL; | |
771 | + | |
772 | + char **args = NULL; | |
773 | + | |
774 | + char *src = NULL; | |
775 | + int i, index; | |
776 | + | |
777 | + grub_dprintf("blscfg", "%s got here\n", __func__); | |
778 | + clinux = bls_get_val (entry, "linux", NULL); | |
779 | + if (!clinux) | |
780 | + { | |
781 | + grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename); | |
782 | + goto finish; | |
783 | + } | |
784 | + | |
785 | + /* | |
786 | + * strip the ".conf" off the end before we make it our "id" field. | |
787 | + */ | |
788 | + do | |
789 | + { | |
790 | + dotconf = grub_strstr(dotconf, ".conf"); | |
791 | + } while (dotconf != NULL && dotconf[5] != '\0'); | |
792 | + if (dotconf) | |
793 | + dotconf[0] = '\0'; | |
794 | + | |
795 | + title = bls_get_val (entry, "title", NULL); | |
796 | + options = expand_val (bls_get_val (entry, "options", NULL)); | |
797 | + | |
798 | + if (!options) | |
799 | + options = expand_val (grub_env_get("default_kernelopts")); | |
800 | + | |
801 | + initrds = bls_make_list (entry, "initrd", NULL); | |
802 | + | |
803 | + hotkey = bls_get_val (entry, "grub_hotkey", NULL); | |
804 | + users = expand_val (bls_get_val (entry, "grub_users", NULL)); | |
805 | + classes = bls_make_list (entry, "grub_class", NULL); | |
806 | + args = bls_make_list (entry, "grub_arg", &argc); | |
807 | + | |
808 | + argc += 1; | |
809 | + argv = grub_malloc ((argc + 1) * sizeof (char *)); | |
810 | + argv[0] = title ? title : clinux; | |
811 | + for (i = 1; i < argc; i++) | |
812 | + argv[i] = args[i-1]; | |
813 | + argv[argc] = NULL; | |
814 | + | |
815 | + early_initrd = grub_env_get("early_initrd"); | |
816 | + | |
817 | + grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n", | |
818 | + title, id); | |
819 | + if (early_initrd) | |
820 | + { | |
821 | + early_initrds = early_initrd_list(early_initrd); | |
822 | + if (!early_initrds) | |
823 | + { | |
824 | + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); | |
825 | + goto finish; | |
826 | + } | |
827 | + | |
828 | + if (initrds != NULL && initrds[0] != NULL) | |
36121927 | 829 | + { |
f1c7b511 JP |
830 | + initrd_prefix = grub_strrchr (initrds[0], '/'); |
831 | + initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1); | |
36121927 | 832 | + } |
f1c7b511 | 833 | + else |
36121927 | 834 | + { |
f1c7b511 JP |
835 | + initrd_prefix = grub_strrchr (clinux, '/'); |
836 | + initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1); | |
36121927 | 837 | + } |
f1c7b511 JP |
838 | + |
839 | + if (!initrd_prefix) | |
36121927 | 840 | + { |
f1c7b511 JP |
841 | + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); |
842 | + goto finish; | |
36121927 | 843 | + } |
36121927 ER |
844 | + } |
845 | + | |
f1c7b511 | 846 | + if (early_initrds || initrds) |
36121927 | 847 | + { |
f1c7b511 JP |
848 | + int initrd_size = sizeof ("initrd"); |
849 | + char *tmp; | |
850 | + | |
851 | + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) | |
852 | + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ | |
853 | + + grub_strlen(initrd_prefix) \ | |
854 | + + grub_strlen (early_initrds[i]) + 1; | |
855 | + | |
856 | + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) | |
857 | + initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ | |
858 | + + grub_strlen (initrds[i]) + 1; | |
859 | + initrd_size += 1; | |
860 | + | |
861 | + initrd = grub_malloc (initrd_size); | |
862 | + if (!initrd) | |
863 | + { | |
864 | + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); | |
865 | + goto finish; | |
866 | + } | |
36121927 | 867 | + |
f1c7b511 JP |
868 | + |
869 | + tmp = grub_stpcpy(initrd, "initrd"); | |
870 | + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) | |
871 | + { | |
872 | + grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); | |
873 | + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); | |
874 | + tmp = grub_stpcpy (tmp, initrd_prefix); | |
875 | + tmp = grub_stpcpy (tmp, early_initrds[i]); | |
876 | + grub_free(early_initrds[i]); | |
877 | + } | |
878 | + | |
879 | + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) | |
880 | + { | |
881 | + grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); | |
882 | + tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); | |
883 | + tmp = grub_stpcpy (tmp, initrds[i]); | |
884 | + } | |
885 | + tmp = grub_stpcpy (tmp, "\n"); | |
886 | + } | |
36121927 ER |
887 | + |
888 | + src = grub_xasprintf ("load_video\n" | |
f1c7b511 | 889 | + "set gfxpayload=keep\n" |
36121927 | 890 | + "insmod gzio\n" |
f1c7b511 JP |
891 | + "linux %s%s%s%s\n" |
892 | + "%s", | |
36121927 | 893 | + GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "", |
f1c7b511 | 894 | + initrd ? initrd : ""); |
36121927 | 895 | + |
f1c7b511 JP |
896 | + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); |
897 | + grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); | |
36121927 ER |
898 | + |
899 | +finish: | |
36121927 | 900 | + grub_free (initrd); |
f1c7b511 JP |
901 | + grub_free (initrd_prefix); |
902 | + grub_free (early_initrds); | |
903 | + grub_free (initrds); | |
904 | + grub_free (options); | |
905 | + grub_free (classes); | |
906 | + grub_free (args); | |
907 | + grub_free (argv); | |
36121927 | 908 | + grub_free (src); |
f1c7b511 | 909 | +} |
36121927 | 910 | + |
f1c7b511 JP |
911 | +struct find_entry_info { |
912 | + const char *dirname; | |
913 | + const char *devid; | |
914 | + grub_device_t dev; | |
915 | + grub_fs_t fs; | |
916 | +}; | |
917 | + | |
918 | +/* | |
919 | + * info: the filesystem object the file is on. | |
920 | + */ | |
921 | +static int find_entry (struct find_entry_info *info) | |
922 | +{ | |
923 | + struct read_entry_info read_entry_info; | |
924 | + grub_fs_t blsdir_fs = NULL; | |
925 | + grub_device_t blsdir_dev = NULL; | |
926 | + const char *blsdir = info->dirname; | |
927 | + int fallback = 0; | |
928 | + int r = 0; | |
929 | + | |
930 | + if (!blsdir) { | |
931 | + blsdir = grub_env_get ("blsdir"); | |
932 | + if (!blsdir) | |
933 | + blsdir = GRUB_BLS_CONFIG_PATH; | |
934 | + } | |
935 | + | |
936 | + read_entry_info.file = NULL; | |
937 | + read_entry_info.dirname = blsdir; | |
938 | + | |
939 | + grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir); | |
940 | + | |
941 | + blsdir_dev = info->dev; | |
942 | + blsdir_fs = info->fs; | |
943 | + read_entry_info.devid = info->devid; | |
944 | + | |
945 | +read_fallback: | |
946 | + r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, | |
947 | + &read_entry_info); | |
948 | + if (r != 0) { | |
949 | + grub_dprintf ("blscfg", "read_entry returned error\n"); | |
950 | + grub_err_t e; | |
951 | + do | |
952 | + { | |
953 | + e = grub_error_pop(); | |
954 | + } while (e); | |
955 | + } | |
956 | + | |
957 | + if (r && !info->dirname && !fallback) { | |
958 | + read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH; | |
959 | + grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n", | |
960 | + blsdir, read_entry_info.dirname); | |
961 | + fallback = 1; | |
962 | + goto read_fallback; | |
963 | + } | |
36121927 ER |
964 | + |
965 | + return 0; | |
966 | +} | |
967 | + | |
968 | +static grub_err_t | |
f1c7b511 | 969 | +bls_load_entries (const char *path) |
36121927 | 970 | +{ |
f1c7b511 | 971 | + grub_size_t len; |
36121927 ER |
972 | + grub_fs_t fs; |
973 | + grub_device_t dev; | |
974 | + static grub_err_t r; | |
f1c7b511 JP |
975 | + const char *devid = NULL; |
976 | + char *blsdir = NULL; | |
977 | + struct find_entry_info info = { | |
978 | + .dev = NULL, | |
979 | + .fs = NULL, | |
980 | + .dirname = NULL, | |
981 | + }; | |
982 | + struct read_entry_info rei = { | |
983 | + .devid = NULL, | |
984 | + .dirname = NULL, | |
985 | + }; | |
986 | + | |
987 | + if (path) { | |
988 | + len = grub_strlen (path); | |
989 | + if (grub_strcmp (path + len - 5, ".conf") == 0) { | |
990 | + rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); | |
991 | + if (!rei.file) | |
992 | + return grub_errno; | |
993 | + /* | |
994 | + * read_entry() closes the file | |
995 | + */ | |
996 | + return read_entry(path, NULL, &rei); | |
997 | + } else if (path[0] == '(') { | |
998 | + devid = path + 1; | |
999 | + | |
1000 | + blsdir = grub_strchr (path, ')'); | |
1001 | + if (!blsdir) | |
1002 | + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct")); | |
36121927 | 1003 | + |
f1c7b511 JP |
1004 | + *blsdir = '\0'; |
1005 | + blsdir = blsdir + 1; | |
1006 | + } | |
1007 | + } | |
1008 | + | |
1009 | + if (!devid) { | |
1010 | +#ifdef GRUB_MACHINE_EMU | |
1011 | + devid = "host"; | |
1012 | +#elif defined(GRUB_MACHINE_EFI) | |
1013 | + devid = grub_env_get ("root"); | |
1014 | +#else | |
1015 | + devid = grub_env_get ("boot"); | |
1016 | +#endif | |
1017 | + if (!devid) | |
1018 | + return grub_error (GRUB_ERR_FILE_NOT_FOUND, | |
1019 | + N_("variable `%s' isn't set"), "boot"); | |
1020 | + } | |
36121927 | 1021 | + |
f1c7b511 | 1022 | + grub_dprintf ("blscfg", "opening %s\n", devid); |
36121927 ER |
1023 | + dev = grub_device_open (devid); |
1024 | + if (!dev) | |
1025 | + return grub_errno; | |
1026 | + | |
f1c7b511 | 1027 | + grub_dprintf ("blscfg", "probing fs\n"); |
36121927 ER |
1028 | + fs = grub_fs_probe (dev); |
1029 | + if (!fs) | |
1030 | + { | |
1031 | + r = grub_errno; | |
1032 | + goto finish; | |
1033 | + } | |
1034 | + | |
f1c7b511 JP |
1035 | + info.dirname = blsdir; |
1036 | + info.devid = devid; | |
1037 | + info.dev = dev; | |
1038 | + info.fs = fs; | |
1039 | + find_entry(&info); | |
36121927 ER |
1040 | + |
1041 | +finish: | |
1042 | + if (dev) | |
1043 | + grub_device_close (dev); | |
1044 | + | |
1045 | + return r; | |
1046 | +} | |
1047 | + | |
f1c7b511 JP |
1048 | +static bool |
1049 | +is_default_entry(const char *def_entry, struct bls_entry *entry, int idx) | |
1050 | +{ | |
1051 | + const char *title; | |
1052 | + int def_idx; | |
1053 | + | |
1054 | + if (!def_entry) | |
1055 | + return false; | |
1056 | + | |
1057 | + if (grub_strcmp(def_entry, entry->filename) == 0) | |
1058 | + return true; | |
1059 | + | |
1060 | + title = bls_get_val(entry, "title", NULL); | |
1061 | + | |
1062 | + if (title && grub_strcmp(def_entry, title) == 0) | |
1063 | + return true; | |
1064 | + | |
1065 | + def_idx = (int)grub_strtol(def_entry, NULL, 0); | |
1066 | + if (grub_errno == GRUB_ERR_BAD_NUMBER) { | |
1067 | + grub_errno = GRUB_ERR_NONE; | |
1068 | + return false; | |
1069 | + } | |
1070 | + | |
1071 | + if (def_idx == idx) | |
1072 | + return true; | |
1073 | + | |
1074 | + return false; | |
1075 | +} | |
1076 | + | |
1077 | +static grub_err_t | |
1078 | +bls_create_entries (bool show_default, bool show_non_default, char *entry_id) | |
1079 | +{ | |
1080 | + const char *def_entry = NULL; | |
1081 | + struct bls_entry *entry = NULL; | |
1082 | + int idx = 0; | |
1083 | + | |
1084 | + def_entry = grub_env_get("default"); | |
1085 | + | |
1086 | + grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__); | |
1087 | + FOR_BLS_ENTRIES(entry) { | |
1088 | + if (entry->visible) { | |
1089 | + idx++; | |
1090 | + continue; | |
1091 | + } | |
1092 | + | |
1093 | + if ((show_default && is_default_entry(def_entry, entry, idx)) || | |
1094 | + (show_non_default && !is_default_entry(def_entry, entry, idx)) || | |
1095 | + (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { | |
1096 | + create_entry(entry); | |
1097 | + entry->visible = 1; | |
1098 | + } | |
1099 | + idx++; | |
1100 | + } | |
1101 | + | |
1102 | + return GRUB_ERR_NONE; | |
1103 | +} | |
1104 | + | |
1105 | +static grub_err_t | |
1106 | +grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED, | |
1107 | + int argc, char **args) | |
1108 | +{ | |
1109 | + grub_err_t r; | |
1110 | + char *path = NULL; | |
1111 | + char *entry_id = NULL; | |
1112 | + bool show_default = true; | |
1113 | + bool show_non_default = true; | |
1114 | + | |
1115 | + if (argc == 1) { | |
1116 | + if (grub_strcmp (args[0], "default") == 0) { | |
1117 | + show_non_default = false; | |
1118 | + } else if (grub_strcmp (args[0], "non-default") == 0) { | |
1119 | + show_default = false; | |
1120 | + } else if (args[0][0] == '(') { | |
1121 | + path = args[0]; | |
1122 | + } else { | |
1123 | + entry_id = args[0]; | |
1124 | + show_default = false; | |
1125 | + show_non_default = false; | |
1126 | + } | |
1127 | + } | |
1128 | + | |
1129 | + r = bls_load_entries(path); | |
1130 | + if (r) | |
1131 | + return r; | |
1132 | + | |
1133 | + return bls_create_entries(show_default, show_non_default, entry_id); | |
1134 | +} | |
1135 | + | |
36121927 | 1136 | +static grub_extcmd_t cmd; |
f1c7b511 | 1137 | +static grub_extcmd_t oldcmd; |
36121927 | 1138 | + |
f1c7b511 | 1139 | +GRUB_MOD_INIT(blscfg) |
36121927 | 1140 | +{ |
f1c7b511 JP |
1141 | + grub_dprintf("blscfg", "%s got here\n", __func__); |
1142 | + cmd = grub_register_extcmd ("blscfg", | |
1143 | + grub_cmd_blscfg, | |
36121927 ER |
1144 | + 0, |
1145 | + NULL, | |
1146 | + N_("Import Boot Loader Specification snippets."), | |
1147 | + NULL); | |
f1c7b511 JP |
1148 | + oldcmd = grub_register_extcmd ("bls_import", |
1149 | + grub_cmd_blscfg, | |
1150 | + 0, | |
1151 | + NULL, | |
1152 | + N_("Import Boot Loader Specification snippets."), | |
1153 | + NULL); | |
36121927 ER |
1154 | +} |
1155 | + | |
f1c7b511 | 1156 | +GRUB_MOD_FINI(blscfg) |
36121927 ER |
1157 | +{ |
1158 | + grub_unregister_extcmd (cmd); | |
f1c7b511 | 1159 | + grub_unregister_extcmd (oldcmd); |
36121927 | 1160 | +} |
f1c7b511 JP |
1161 | diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c |
1162 | index db7a8f00273..891eac5a33f 100644 | |
1163 | --- a/grub-core/commands/legacycfg.c | |
1164 | +++ b/grub-core/commands/legacycfg.c | |
1165 | @@ -133,7 +133,7 @@ legacy_file (const char *filename) | |
1166 | args[0] = oldname; | |
1167 | grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", | |
1168 | NULL, NULL, | |
1169 | - entrysrc, 0); | |
1170 | + entrysrc, 0, NULL, NULL); | |
1171 | grub_free (args); | |
1172 | entrysrc[0] = 0; | |
1173 | grub_free (oldname); | |
1174 | @@ -186,7 +186,8 @@ legacy_file (const char *filename) | |
1175 | } | |
1176 | args[0] = entryname; | |
1177 | grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, | |
1178 | - NULL, NULL, entrysrc, 0); | |
1179 | + NULL, NULL, entrysrc, 0, NULL, | |
1180 | + NULL); | |
1181 | grub_free (args); | |
1182 | } | |
1183 | ||
1184 | diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c | |
1185 | index 3fd664aac33..163b9a09042 100644 | |
1186 | --- a/grub-core/commands/loadenv.c | |
1187 | +++ b/grub-core/commands/loadenv.c | |
1188 | @@ -28,6 +28,8 @@ | |
1189 | #include <grub/extcmd.h> | |
1190 | #include <grub/i18n.h> | |
1191 | ||
1192 | +#include "loadenv.h" | |
1193 | + | |
1194 | GRUB_MOD_LICENSE ("GPLv3+"); | |
1195 | ||
1196 | static const struct grub_arg_option options[] = | |
1197 | @@ -79,81 +81,6 @@ open_envblk_file (char *filename, | |
1198 | return file; | |
1199 | } | |
1200 | ||
1201 | -static grub_envblk_t | |
1202 | -read_envblk_file (grub_file_t file) | |
1203 | -{ | |
1204 | - grub_off_t offset = 0; | |
1205 | - char *buf; | |
1206 | - grub_size_t size = grub_file_size (file); | |
1207 | - grub_envblk_t envblk; | |
1208 | - | |
1209 | - buf = grub_malloc (size); | |
1210 | - if (! buf) | |
1211 | - return 0; | |
1212 | - | |
1213 | - while (size > 0) | |
1214 | - { | |
1215 | - grub_ssize_t ret; | |
1216 | - | |
1217 | - ret = grub_file_read (file, buf + offset, size); | |
1218 | - if (ret <= 0) | |
1219 | - { | |
1220 | - grub_free (buf); | |
1221 | - return 0; | |
1222 | - } | |
1223 | - | |
1224 | - size -= ret; | |
1225 | - offset += ret; | |
1226 | - } | |
1227 | - | |
1228 | - envblk = grub_envblk_open (buf, offset); | |
1229 | - if (! envblk) | |
1230 | - { | |
1231 | - grub_free (buf); | |
1232 | - grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); | |
1233 | - return 0; | |
1234 | - } | |
1235 | - | |
1236 | - return envblk; | |
1237 | -} | |
1238 | - | |
1239 | -struct grub_env_whitelist | |
1240 | -{ | |
1241 | - grub_size_t len; | |
1242 | - char **list; | |
1243 | -}; | |
1244 | -typedef struct grub_env_whitelist grub_env_whitelist_t; | |
1245 | - | |
1246 | -static int | |
1247 | -test_whitelist_membership (const char* name, | |
1248 | - const grub_env_whitelist_t* whitelist) | |
1249 | -{ | |
1250 | - grub_size_t i; | |
1251 | - | |
1252 | - for (i = 0; i < whitelist->len; i++) | |
1253 | - if (grub_strcmp (name, whitelist->list[i]) == 0) | |
1254 | - return 1; /* found it */ | |
1255 | - | |
1256 | - return 0; /* not found */ | |
1257 | -} | |
1258 | - | |
1259 | -/* Helper for grub_cmd_load_env. */ | |
1260 | -static int | |
1261 | -set_var (const char *name, const char *value, void *whitelist) | |
1262 | -{ | |
1263 | - if (! whitelist) | |
1264 | - { | |
1265 | - grub_env_set (name, value); | |
1266 | - return 0; | |
1267 | - } | |
1268 | - | |
1269 | - if (test_whitelist_membership (name, | |
1270 | - (const grub_env_whitelist_t *) whitelist)) | |
1271 | - grub_env_set (name, value); | |
1272 | - | |
1273 | - return 0; | |
1274 | -} | |
1275 | - | |
1276 | static grub_err_t | |
1277 | grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) | |
1278 | { | |
1279 | diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c | |
1280 | index 2c5363da7f5..9faf2be0f64 100644 | |
1281 | --- a/grub-core/commands/menuentry.c | |
1282 | +++ b/grub-core/commands/menuentry.c | |
1283 | @@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args, | |
1284 | char **classes, const char *id, | |
1285 | const char *users, const char *hotkey, | |
1286 | const char *prefix, const char *sourcecode, | |
1287 | - int submenu) | |
1288 | + int submenu, int *index, struct bls_entry *bls) | |
1289 | { | |
1290 | int menu_hotkey = 0; | |
1291 | char **menu_args = NULL; | |
1292 | @@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args, | |
1293 | if (! menu_title) | |
1294 | goto fail; | |
1295 | ||
1296 | + grub_dprintf ("menu", "id:\"%s\"\n", id); | |
1297 | + grub_dprintf ("menu", "title:\"%s\"\n", menu_title); | |
1298 | menu_id = grub_strdup (id ? : menu_title); | |
1299 | if (! menu_id) | |
1300 | goto fail; | |
1301 | + grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id); | |
1302 | ||
1303 | /* Save argc, args to pass as parameters to block arg later. */ | |
41468086 | 1304 | menu_args = grub_calloc (argc + 1, sizeof (char *)); |
f1c7b511 JP |
1305 | @@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args, |
1306 | } | |
1307 | ||
1308 | /* Add the menu entry at the end of the list. */ | |
1309 | + int ind=0; | |
1310 | while (*last) | |
1311 | - last = &(*last)->next; | |
1312 | + { | |
1313 | + ind++; | |
1314 | + last = &(*last)->next; | |
1315 | + } | |
1316 | ||
1317 | *last = grub_zalloc (sizeof (**last)); | |
1318 | if (! *last) | |
1319 | @@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args, | |
1320 | (*last)->args = menu_args; | |
1321 | (*last)->sourcecode = menu_sourcecode; | |
1322 | (*last)->submenu = submenu; | |
1323 | + (*last)->bls = bls; | |
1324 | ||
1325 | menu->size++; | |
1326 | + if (index) | |
1327 | + *index = ind; | |
1328 | return GRUB_ERR_NONE; | |
1329 | ||
1330 | fail: | |
1331 | @@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) | |
1332 | users, | |
1333 | ctxt->state[2].arg, 0, | |
1334 | ctxt->state[3].arg, | |
1335 | - ctxt->extcmd->cmd->name[0] == 's'); | |
1336 | + ctxt->extcmd->cmd->name[0] == 's', | |
1337 | + NULL, NULL); | |
1338 | ||
1339 | src = args[argc - 1]; | |
1340 | args[argc - 1] = NULL; | |
1341 | @@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) | |
1342 | ctxt->state[0].args, ctxt->state[4].arg, | |
1343 | users, | |
1344 | ctxt->state[2].arg, prefix, src + 1, | |
1345 | - ctxt->extcmd->cmd->name[0] == 's'); | |
1346 | + ctxt->extcmd->cmd->name[0] == 's', NULL, | |
1347 | + NULL); | |
1348 | ||
1349 | src[len - 1] = ch; | |
1350 | args[argc - 1] = src; | |
1351 | diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c | |
1352 | index 9ef98481f70..a326b192c89 100644 | |
1353 | --- a/grub-core/normal/main.c | |
1354 | +++ b/grub-core/normal/main.c | |
1355 | @@ -20,6 +20,7 @@ | |
41468086 | 1356 | #include <grub/net.h> |
f1c7b511 JP |
1357 | #include <grub/normal.h> |
1358 | #include <grub/dl.h> | |
1359 | +#include <grub/menu.h> | |
1360 | #include <grub/misc.h> | |
1361 | #include <grub/file.h> | |
1362 | #include <grub/mm.h> | |
1363 | @@ -70,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu) | |
1364 | grub_free (entry->args); | |
1365 | } | |
1366 | ||
1367 | + if (entry->bls) | |
1368 | + { | |
1369 | + entry->bls->visible = 0; | |
1370 | + } | |
1371 | + | |
1372 | grub_free ((void *) entry->id); | |
1373 | grub_free ((void *) entry->users); | |
1374 | grub_free ((void *) entry->title); | |
1375 | diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h | |
1376 | new file mode 100644 | |
1377 | index 00000000000..952f46121bd | |
1378 | --- /dev/null | |
1379 | +++ b/grub-core/commands/loadenv.h | |
1380 | @@ -0,0 +1,93 @@ | |
1381 | +/* loadenv.c - command to load/save environment variable. */ | |
1382 | +/* | |
1383 | + * GRUB -- GRand Unified Bootloader | |
1384 | + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. | |
1385 | + * | |
1386 | + * GRUB is free software: you can redistribute it and/or modify | |
1387 | + * it under the terms of the GNU General Public License as published by | |
1388 | + * the Free Software Foundation, either version 3 of the License, or | |
1389 | + * (at your option) any later version. | |
1390 | + * | |
1391 | + * GRUB is distributed in the hope that it will be useful, | |
1392 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1393 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1394 | + * GNU General Public License for more details. | |
1395 | + * | |
1396 | + * You should have received a copy of the GNU General Public License | |
1397 | + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
1398 | + */ | |
1399 | + | |
1400 | +static grub_envblk_t UNUSED | |
1401 | +read_envblk_file (grub_file_t file) | |
1402 | +{ | |
1403 | + grub_off_t offset = 0; | |
1404 | + char *buf; | |
1405 | + grub_size_t size = grub_file_size (file); | |
1406 | + grub_envblk_t envblk; | |
1407 | + | |
1408 | + buf = grub_malloc (size); | |
1409 | + if (! buf) | |
1410 | + return 0; | |
1411 | + | |
1412 | + while (size > 0) | |
1413 | + { | |
1414 | + grub_ssize_t ret; | |
1415 | + | |
1416 | + ret = grub_file_read (file, buf + offset, size); | |
1417 | + if (ret <= 0) | |
1418 | + { | |
1419 | + grub_free (buf); | |
1420 | + return 0; | |
1421 | + } | |
1422 | + | |
1423 | + size -= ret; | |
1424 | + offset += ret; | |
1425 | + } | |
1426 | + | |
1427 | + envblk = grub_envblk_open (buf, offset); | |
1428 | + if (! envblk) | |
1429 | + { | |
1430 | + grub_free (buf); | |
1431 | + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); | |
1432 | + return 0; | |
1433 | + } | |
1434 | + | |
1435 | + return envblk; | |
1436 | +} | |
1437 | + | |
1438 | +struct grub_env_whitelist | |
1439 | +{ | |
1440 | + grub_size_t len; | |
1441 | + char **list; | |
1442 | +}; | |
1443 | +typedef struct grub_env_whitelist grub_env_whitelist_t; | |
1444 | + | |
1445 | +static int UNUSED | |
1446 | +test_whitelist_membership (const char* name, | |
1447 | + const grub_env_whitelist_t* whitelist) | |
1448 | +{ | |
1449 | + grub_size_t i; | |
1450 | + | |
1451 | + for (i = 0; i < whitelist->len; i++) | |
1452 | + if (grub_strcmp (name, whitelist->list[i]) == 0) | |
1453 | + return 1; /* found it */ | |
1454 | + | |
1455 | + return 0; /* not found */ | |
1456 | +} | |
1457 | + | |
1458 | +/* Helper for grub_cmd_load_env. */ | |
1459 | +static int UNUSED | |
1460 | +set_var (const char *name, const char *value, void *whitelist) | |
1461 | +{ | |
1462 | + if (! whitelist) | |
1463 | + { | |
1464 | + grub_env_set (name, value); | |
1465 | + return 0; | |
1466 | + } | |
1467 | + | |
1468 | + if (test_whitelist_membership (name, | |
1469 | + (const grub_env_whitelist_t *) whitelist)) | |
1470 | + grub_env_set (name, value); | |
1471 | + | |
1472 | + return 0; | |
1473 | +} | |
1474 | diff --git a/include/grub/compiler.h b/include/grub/compiler.h | |
1475 | index c9e1d7a73dc..9859ff4cc79 100644 | |
1476 | --- a/include/grub/compiler.h | |
1477 | +++ b/include/grub/compiler.h | |
1478 | @@ -48,4 +48,6 @@ | |
41468086 | 1479 | # define CLANG_PREREQ(maj,min) 0 |
f1c7b511 JP |
1480 | #endif |
1481 | ||
1482 | +#define UNUSED __attribute__((__unused__)) | |
1483 | + | |
1484 | #endif /* ! GRUB_COMPILER_HEADER */ | |
1485 | diff --git a/include/grub/menu.h b/include/grub/menu.h | |
1486 | index ee2b5e91045..0acdc2aa6bf 100644 | |
1487 | --- a/include/grub/menu.h | |
1488 | +++ b/include/grub/menu.h | |
1489 | @@ -20,6 +20,16 @@ | |
1490 | #ifndef GRUB_MENU_HEADER | |
1491 | #define GRUB_MENU_HEADER 1 | |
1492 | ||
1493 | +struct bls_entry | |
1494 | +{ | |
1495 | + struct bls_entry *next; | |
1496 | + struct bls_entry *prev; | |
1497 | + struct keyval **keyvals; | |
1498 | + int nkeyvals; | |
1499 | + char *filename; | |
1500 | + int visible; | |
1501 | +}; | |
1502 | + | |
1503 | struct grub_menu_entry_class | |
1504 | { | |
1505 | char *name; | |
1506 | @@ -60,6 +70,9 @@ struct grub_menu_entry | |
1507 | ||
1508 | /* The next element. */ | |
1509 | struct grub_menu_entry *next; | |
1510 | + | |
1511 | + /* BLS used to populate the entry */ | |
1512 | + struct bls_entry *bls; | |
1513 | }; | |
1514 | typedef struct grub_menu_entry *grub_menu_entry_t; | |
1515 | ||
1516 | diff --git a/include/grub/normal.h b/include/grub/normal.h | |
1517 | index 218cbabccaf..8839ad85a19 100644 | |
1518 | --- a/include/grub/normal.h | |
1519 | +++ b/include/grub/normal.h | |
1520 | @@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, | |
1521 | const char *id, | |
1522 | const char *users, const char *hotkey, | |
1523 | const char *prefix, const char *sourcecode, | |
1524 | - int submenu); | |
1525 | + int submenu, int *index, struct bls_entry *bls); | |
1526 | ||
1527 | grub_err_t | |
1528 | grub_normal_set_password (const char *user, const char *password); |