X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fdevice-handler.c;h=6ff70c14b6e2faf0265667ce2749245deb3b8c74;hp=950e730b995b89af52073b0ba8eaf0906d4147a9;hb=5e7c90eddd7ac2e4a3b05a7a5f6e29166edfa161;hpb=5be946cda7b8e2271ade6188ca3f5dc068826619 diff --git a/discover/device-handler.c b/discover/device-handler.c index 950e730..6ff70c1 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -12,11 +12,13 @@ #include #include #include +#include #include "device-handler.h" #include "discover-server.h" #include "event.h" #include "parser.h" +#include "resource.h" #include "udev.h" #include "paths.h" #include "boot.h" @@ -27,8 +29,80 @@ struct device_handler { struct discover_device **devices; unsigned int n_devices; + + struct list unresolved_boot_options; }; +static bool resource_is_resolved(struct resource *res) +{ + return !res || res->resolved; +} + +/* We only use this in an assert, which will disappear if we're compiling + * with NDEBUG, so we need the 'used' attribute for these builds */ +static bool __attribute__((used)) boot_option_is_resolved( + struct discover_boot_option *opt) +{ + return resource_is_resolved(opt->boot_image) && + resource_is_resolved(opt->initrd) && + resource_is_resolved(opt->icon); +} + +static bool resource_resolve(struct resource *res, struct parser *parser, + struct device_handler *handler) +{ + if (resource_is_resolved(res)) + return true; + + parser->resolve_resource(handler, res); + + return res->resolved; +} + +static bool boot_option_resolve(struct discover_boot_option *opt, + struct device_handler *handler) +{ + return resource_resolve(opt->boot_image, opt->source, handler) && + resource_resolve(opt->initrd, opt->source, handler) && + resource_resolve(opt->icon, opt->source, handler); +} + +static void boot_option_finalise(struct discover_boot_option *opt) +{ + assert(boot_option_is_resolved(opt)); + + /* check that the parsers haven't set any of the final data */ + assert(!opt->option->boot_image_file); + assert(!opt->option->initrd_file); + assert(!opt->option->icon_file); + + if (opt->boot_image) + opt->option->boot_image_file = opt->boot_image->url->full; + if (opt->initrd) + opt->option->initrd_file = opt->initrd->url->full; + if (opt->icon) + opt->option->icon_file = opt->icon->url->full; +} + +static void process_boot_option_queue(struct device_handler *handler) +{ + struct discover_boot_option *opt, *tmp; + + list_for_each_entry_safe(&handler->unresolved_boot_options, + opt, tmp, list) { + + if (!boot_option_resolve(opt, handler)) + continue; + + list_remove(&opt->list); + list_add(&opt->device->boot_options, &opt->list); + talloc_steal(opt->device, opt); + boot_option_finalise(opt); + discover_server_notify_boot_option_add(handler->server, + opt->option); + } +} + /** * context_commit - Commit a temporary discovery context to the handler, * and notify the clients about any new options / devices @@ -38,7 +112,7 @@ static void context_commit(struct device_handler *handler, { struct discover_device *dev = ctx->device; struct discover_boot_option *opt, *tmp; - unsigned int i, existing_device; + unsigned int i, existing_device = 0; /* do we already have this device? */ for (i = 0; i < handler->n_devices; i++) { @@ -57,22 +131,34 @@ static void context_commit(struct device_handler *handler, talloc_steal(handler, dev); discover_server_notify_device_add(handler->server, dev->device); + + /* this new device might be able to resolve existing boot + * options */ + process_boot_option_queue(handler); } /* move boot options from the context to the device */ list_for_each_entry_safe(&ctx->boot_options, opt, tmp, list) { list_remove(&opt->list); - list_add(&dev->boot_options, &opt->list); - talloc_steal(dev, opt); - discover_server_notify_boot_option_add(handler->server, - opt->option); + + if (boot_option_resolve(opt, handler)) { + list_add(&dev->boot_options, &opt->list); + talloc_steal(dev, opt); + boot_option_finalise(opt); + discover_server_notify_boot_option_add(handler->server, + opt->option); + } else { + list_add(&handler->unresolved_boot_options, &opt->list); + talloc_steal(handler, opt); + } } } void discover_context_add_boot_option(struct discover_context *ctx, struct discover_boot_option *boot_option) { + boot_option->source = ctx->parser; list_add(&ctx->boot_options, &boot_option->list); talloc_steal(ctx, boot_option); } @@ -302,7 +388,7 @@ static int handle_add_udev_event(struct device_handler *handler, } /* run the parsers. This will populate the ctx's boot_option list. */ - iterate_parsers(ctx); + iterate_parsers(ctx, CONF_METHOD_LOCAL_FILE); /* add discovered stuff to the handler */ context_commit(handler, ctx); @@ -402,6 +488,7 @@ struct device_handler *device_handler_init(struct discover_server *server, handler->n_devices = 0; handler->server = server; handler->dry_run = dry_run; + list_init(&handler->unresolved_boot_options); /* set up our mount point base */ pb_mkdir_recursive(mount_base());