blob: 01c0c4ed59b4cfa8cef3e19a49d06bad033f50d3 [file] [log] [blame]
Klaus Heinrich Kiwid1cd8c52020-02-27 12:43:47 -03001From c8c56d06e2bba0a743a88033d00d8472e84923b4 Mon Sep 17 00:00:00 2001
2From: Jeremy Kerr <jk@ozlabs.org>
3Date: Mon, 11 Nov 2019 17:10:30 +0800
4Subject: [PATCH 10/18] discover/grub2: add support for grub2-style path
5 specifiers in resources
6
7This change incorporates the grub2-style (device)/path specifiers in the
8grub2 parser's resource code. This allows the boot option paths to use
9device-specific references.
10
11Device names are looked-up using the UUID and kernel IDs, but with the
12lookup logic specific to a new function (grub2_lookup_device), so that
13can be extended in a future change.
14
15Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
16(cherry picked from commit 9fc2ac627df17ddc8e7c2735053aeb9e1252ff6e)
17Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
18---
19 discover/grub2/blscfg.c | 19 +++----
20 discover/grub2/builtins.c | 15 ++----
21 discover/grub2/grub2.c | 56 +++++++++++++++-----
22 discover/grub2/grub2.h | 5 +-
23 test/parser/Makefile.am | 1 +
24 test/parser/test-grub2-devpath.c | 88 ++++++++++++++++++++++++++++++++
25 6 files changed, 147 insertions(+), 37 deletions(-)
26 create mode 100644 test/parser/test-grub2-devpath.c
27
28diff --git a/discover/grub2/blscfg.c b/discover/grub2/blscfg.c
29index d4754aa..d08f8f0 100644
30--- a/discover/grub2/blscfg.c
31+++ b/discover/grub2/blscfg.c
32@@ -166,7 +166,6 @@ static void bls_finish(struct conf_context *conf)
33 struct discover_context *dc = conf->dc;
34 struct discover_boot_option *opt = state->opt;
35 struct boot_option *option = opt->option;
36- const char *root;
37 char *filename;
38
39 if (!state->image) {
40@@ -192,23 +191,21 @@ static void bls_finish(struct conf_context *conf)
41 else
42 option->name = talloc_strdup(option, state->image);
43
44- root = script_env_get(state->script, "root");
45-
46- opt->boot_image = create_grub2_resource(opt, conf->dc->device,
47- root, state->image);
48+ opt->boot_image = create_grub2_resource(state->script, opt,
49+ state->image);
50
51 if (state->initrd)
52- opt->initrd = create_grub2_resource(opt, conf->dc->device,
53- root, state->initrd);
54+ opt->initrd = create_grub2_resource(state->script, opt,
55+ state->initrd);
56
57 if (state->dtb)
58- opt->dtb = create_grub2_resource(opt, conf->dc->device,
59- root, state->dtb);
60+ opt->dtb = create_grub2_resource(state->script, opt,
61+ state->dtb);
62
63 char* args_sigfile_default = talloc_asprintf(opt,
64 "%s.cmdline.sig", state->image);
65- opt->args_sig_file = create_grub2_resource(opt, conf->dc->device,
66- root, args_sigfile_default);
67+ opt->args_sig_file = create_grub2_resource(state->script, opt,
68+ args_sigfile_default);
69 talloc_free(args_sigfile_default);
70
71 option->is_default = option_is_default(state, option);
72diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
73index 7cac9f1..765c4d7 100644
74--- a/discover/grub2/builtins.c
75+++ b/discover/grub2/builtins.c
76@@ -46,7 +46,6 @@ static int builtin_linux(struct grub2_script *script,
77 int argc, char *argv[])
78 {
79 struct discover_boot_option *opt = script->opt;
80- const char *root;
81 int i;
82
83 if (!opt) {
84@@ -61,10 +60,7 @@ static int builtin_linux(struct grub2_script *script,
85 return -1;
86 }
87
88- root = script_env_get(script, "root");
89-
90- opt->boot_image = create_grub2_resource(opt, script->ctx->device,
91- root, argv[1]);
92+ opt->boot_image = create_grub2_resource(script, opt, argv[1]);
93 opt->option->boot_args = NULL;
94
95 if (argc > 2)
96@@ -77,8 +73,8 @@ static int builtin_linux(struct grub2_script *script,
97
98 char* args_sigfile_default = talloc_asprintf(opt,
99 "%s.cmdline.sig", argv[1]);
100- opt->args_sig_file = create_grub2_resource(opt, script->ctx->device,
101- root, args_sigfile_default);
102+ opt->args_sig_file = create_grub2_resource(script, opt,
103+ args_sigfile_default);
104 talloc_free(args_sigfile_default);
105 return 0;
106 }
107@@ -88,7 +84,6 @@ static int builtin_initrd(struct grub2_script *script,
108 int argc, char *argv[])
109 {
110 struct discover_boot_option *opt = script->opt;
111- const char *root;
112
113 if (!opt) {
114 pb_log("grub2 syntax error: 'initrd' statement outside "
115@@ -102,9 +97,7 @@ static int builtin_initrd(struct grub2_script *script,
116 return -1;
117 }
118
119- root = script_env_get(script, "root");
120- opt->initrd = create_grub2_resource(opt, script->ctx->device,
121- root, argv[1]);
122+ opt->initrd = create_grub2_resource(script, opt, argv[1]);
123
124 return 0;
125 }
126diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
127index 3873720..a08a320 100644
128--- a/discover/grub2/grub2.c
129+++ b/discover/grub2/grub2.c
130@@ -33,13 +33,35 @@ static const char *const grub2_conf_files[] = {
131 NULL
132 };
133
134+static struct discover_device *grub2_lookup_device(
135+ struct device_handler *handler, const char *desc)
136+{
137+ struct discover_device *dev;
138+
139+ if (!desc || !*desc)
140+ return NULL;
141+
142+ dev = device_lookup_by_id(handler, desc);
143+ if (dev)
144+ return dev;
145+
146+ /* for now, only lookup by UUID */
147+ dev = device_lookup_by_uuid(handler, desc);
148+ if (dev)
149+ return dev;
150+
151+ return NULL;
152+}
153+
154 /* we use slightly different resources for grub2 */
155-struct resource *create_grub2_resource(struct discover_boot_option *opt,
156- struct discover_device *orig_device,
157- const char *root, const char *path)
158+struct resource *create_grub2_resource(struct grub2_script *script,
159+ struct discover_boot_option *opt,
160+ const char *path)
161 {
162+ struct discover_device *dev;
163 struct grub2_file *file;
164 struct resource *res;
165+ const char *root;
166
167 if (strstr(path, "://")) {
168 struct pb_url *url = pb_url_parse(opt, path);
169@@ -47,18 +69,29 @@ struct resource *create_grub2_resource(struct discover_boot_option *opt,
170 return create_url_resource(opt, url);
171 }
172
173+ file = grub2_parse_file(script, path);
174+ if (!file)
175+ return NULL;
176+
177 res = talloc(opt, struct resource);
178+ root = script_env_get(script, "root");
179
180- if (root) {
181- file = talloc(res, struct grub2_file);
182+ if (!file->dev && root && strlen(root))
183 file->dev = talloc_strdup(file, root);
184- file->path = talloc_strdup(file, path);
185
186- res->resolved = false;
187- res->info = file;
188+ /* if we don't have a device specified, or the lookup succeeds now,
189+ * then we can resolve the resource right away */
190+ if (file->dev)
191+ dev = grub2_lookup_device(script->ctx->handler, file->dev);
192+ else
193+ dev = script->ctx->device;
194
195- } else
196- resolve_resource_against_device(res, orig_device, path);
197+ if (dev) {
198+ resolve_resource_against_device(res, dev, file->path);
199+ } else {
200+ res->resolved = false;
201+ res->info = talloc_steal(opt, file);
202+ }
203
204 return res;
205 }
206@@ -71,8 +104,7 @@ bool resolve_grub2_resource(struct device_handler *handler,
207
208 assert(!res->resolved);
209
210- dev = device_lookup_by_uuid(handler, file->dev);
211-
212+ dev = grub2_lookup_device(handler, file->dev);
213 if (!dev)
214 return false;
215
216diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
217index 8c4839b..ef32d4b 100644
218--- a/discover/grub2/grub2.h
219+++ b/discover/grub2/grub2.h
220@@ -191,9 +191,8 @@ void script_register_function(struct grub2_script *script,
221 void register_builtins(struct grub2_script *script);
222
223 /* resources */
224-struct resource *create_grub2_resource(struct discover_boot_option *opt,
225- struct discover_device *orig_device,
226- const char *root, const char *path);
227+struct resource *create_grub2_resource(struct grub2_script *script,
228+ struct discover_boot_option *opt, const char *path);
229
230 bool resolve_grub2_resource(struct device_handler *handler,
231 struct resource *res);
232diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
233index f5985d6..0378317 100644
234--- a/test/parser/Makefile.am
235+++ b/test/parser/Makefile.am
236@@ -32,6 +32,7 @@ parser_TESTS = \
237 test/parser/test-grub2-search-args \
238 test/parser/test-grub2-search-uuid \
239 test/parser/test-grub2-search-label \
240+ test/parser/test-grub2-devpath \
241 test/parser/test-grub2-load-env \
242 test/parser/test-grub2-save-env \
243 test/parser/test-grub2-save-env-dash-f \
244diff --git a/test/parser/test-grub2-devpath.c b/test/parser/test-grub2-devpath.c
245new file mode 100644
246index 0000000..d1d00f1
247--- /dev/null
248+++ b/test/parser/test-grub2-devpath.c
249@@ -0,0 +1,88 @@
250+/* check grub2 device+path string parsing */
251+
252+#include "parser-test.h"
253+
254+#if 0 /* PARSER_EMBEDDED_CONFIG */
255+
256+# local
257+menuentry a {
258+ linux /vmlinux
259+}
260+
261+# local, specified by root env var
262+root=00000000-0000-0000-0000-000000000001
263+menuentry b {
264+ linux /vmlinux
265+}
266+
267+# remote, specified by root env var
268+root=00000000-0000-0000-0000-000000000002
269+menuentry c {
270+ linux /vmlinux
271+}
272+
273+# local, full dev+path spec
274+menuentry d {
275+ linux (00000000-0000-0000-0000-000000000001)/vmlinux
276+}
277+
278+# remote, full dev+path spec
279+menuentry e {
280+ linux (00000000-0000-0000-0000-000000000002)/vmlinux
281+}
282+
283+# invalid: incomplete dev+path spec
284+menuentry f {
285+ linux (00000000-0000-0000-0000-000000000001
286+}
287+
288+# invalid: no path
289+menuentry g {
290+ linux (00000000-0000-0000-0000-000000000001)
291+}
292+
293+
294+#endif
295+
296+void run_test(struct parser_test *test)
297+{
298+ struct discover_device *dev1, *dev2;
299+ struct discover_boot_option *opt;
300+ struct discover_context *ctx;
301+
302+ ctx = test->ctx;
303+
304+ /* set local uuid */
305+ dev1 = test->ctx->device;
306+ dev1->uuid = "00000000-0000-0000-0000-000000000001";
307+
308+ dev2 = test_create_device(test, "extdev");
309+ dev2->uuid = "00000000-0000-0000-0000-000000000002";
310+ device_handler_add_device(ctx->handler, dev2);
311+
312+ test_read_conf_embedded(test, "/grub/grub.cfg");
313+
314+ test_run_parser(test, "grub2");
315+
316+ check_boot_option_count(ctx, 5);
317+
318+ opt = get_boot_option(ctx, 0);
319+ check_name(opt, "a");
320+ check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
321+
322+ opt = get_boot_option(ctx, 1);
323+ check_name(opt, "b");
324+ check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
325+
326+ opt = get_boot_option(ctx, 2);
327+ check_name(opt, "c");
328+ check_resolved_local_resource(opt->boot_image, dev2, "/vmlinux");
329+
330+ opt = get_boot_option(ctx, 3);
331+ check_name(opt, "d");
332+ check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
333+
334+ opt = get_boot_option(ctx, 4);
335+ check_name(opt, "e");
336+ check_resolved_local_resource(opt->boot_image, dev2, "/vmlinux");
337+}
338--
3392.17.1
340