Klaus Heinrich Kiwi | d1cd8c5 | 2020-02-27 12:43:47 -0300 | [diff] [blame^] | 1 | From c8c56d06e2bba0a743a88033d00d8472e84923b4 Mon Sep 17 00:00:00 2001 |
| 2 | From: Jeremy Kerr <jk@ozlabs.org> |
| 3 | Date: Mon, 11 Nov 2019 17:10:30 +0800 |
| 4 | Subject: [PATCH 10/18] discover/grub2: add support for grub2-style path |
| 5 | specifiers in resources |
| 6 | |
| 7 | This change incorporates the grub2-style (device)/path specifiers in the |
| 8 | grub2 parser's resource code. This allows the boot option paths to use |
| 9 | device-specific references. |
| 10 | |
| 11 | Device names are looked-up using the UUID and kernel IDs, but with the |
| 12 | lookup logic specific to a new function (grub2_lookup_device), so that |
| 13 | can be extended in a future change. |
| 14 | |
| 15 | Signed-off-by: Jeremy Kerr <jk@ozlabs.org> |
| 16 | (cherry picked from commit 9fc2ac627df17ddc8e7c2735053aeb9e1252ff6e) |
| 17 | Signed-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 | |
| 28 | diff --git a/discover/grub2/blscfg.c b/discover/grub2/blscfg.c |
| 29 | index 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); |
| 72 | diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c |
| 73 | index 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 | } |
| 126 | diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c |
| 127 | index 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 | |
| 216 | diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h |
| 217 | index 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); |
| 232 | diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am |
| 233 | index 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 \ |
| 244 | diff --git a/test/parser/test-grub2-devpath.c b/test/parser/test-grub2-devpath.c |
| 245 | new file mode 100644 |
| 246 | index 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 | -- |
| 339 | 2.17.1 |
| 340 | |