X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=discover%2Fdevice-handler.c;h=a8df295df1b6e4763516b68de240c6fa907240a7;hp=c661fbe2eb3c5aa9189cb720e5c12e064a296360;hb=5444648fe1ff9b79f3db5ee6feadd51341f59d71;hpb=75b1278f2ab0dad22f393e4a002f797dcb8c8a3b diff --git a/discover/device-handler.c b/discover/device-handler.c index c661fbe..a8df295 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 @@ -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); } @@ -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());