+
+/**
+ * context_commit - Commit a temporary discovery context to the handler,
+ * and notify the clients about any new options / devices
+ */
+void device_handler_discover_context_commit(struct device_handler *handler,
+ struct discover_context *ctx)
+{
+ struct discover_device *dev = ctx->device;
+ struct discover_boot_option *opt, *tmp;
+
+ if (!device_lookup_by_uuid(handler, dev->uuid))
+ device_handler_add_device(handler, dev);
+
+ /* move boot options from the context to the device */
+ list_for_each_entry_safe(&ctx->boot_options, opt, tmp, list) {
+ list_remove(&opt->list);
+
+ /* All boot options need at least a kernel image */
+ if (!opt->boot_image || !opt->boot_image->url) {
+ pb_log("boot option %s is missing boot image, ignoring\n",
+ opt->option->id);
+ talloc_free(opt);
+ continue;
+ }
+
+ if (boot_option_resolve(opt, handler)) {
+ pb_log("boot option %s is resolved, "
+ "sending to clients\n",
+ opt->option->id);
+ list_add_tail(&dev->boot_options, &opt->list);
+ talloc_steal(dev, opt);
+ boot_option_finalise(handler, opt);
+ notify_boot_option(handler, opt);
+ } else {
+ if (!opt->source->resolve_resource) {
+ pb_log("parser %s gave us an unresolved "
+ "resource (%s), but no way to "
+ "resolve it\n",
+ opt->source->name, opt->option->id);
+ talloc_free(opt);
+ } else {
+ pb_log("boot option %s is unresolved, "
+ "adding to queue\n",
+ opt->option->id);
+ list_add(&handler->unresolved_boot_options,
+ &opt->list);
+ talloc_steal(handler, opt);
+ }
+ }
+ }
+}
+
+void device_handler_add_plugin_option(struct device_handler *handler,
+ struct plugin_option *opt)
+{
+ struct plugin_option *tmp;
+ unsigned int i;
+
+ for (i = 0; i < handler->n_plugins; i++) {
+ tmp = handler->plugins[i];
+ /* If both id and version match, ignore */
+ if (strncmp(opt->id, tmp->id, strlen(opt->id)) == 0 &&
+ strncmp(opt->version, tmp->version,
+ strlen(opt->version) == 0)) {
+ pb_log("discover: Plugin '%s' already exists, ignoring\n",
+ opt->id);
+ return;
+ }
+ }
+
+ handler->plugins = talloc_realloc(handler, handler->plugins,
+ struct plugin_option *, handler->n_plugins + 1);
+ if (!handler->plugins) {
+ pb_log("Failed to allocate memory for new plugin\n");
+ handler->n_plugins = 0;
+ return;
+ }
+
+ handler->plugins[handler->n_plugins++] = opt;
+ discover_server_notify_plugin_option_add(handler->server, opt);
+}
+
+static void device_handler_update_lang(const char *lang)
+{
+ const char *cur_lang;
+
+ if (!lang)
+ return;
+
+ cur_lang = setlocale(LC_ALL, NULL);
+ if (cur_lang && !strcmp(cur_lang, lang))
+ return;
+
+ setlocale(LC_ALL, lang);
+}
+
+static int device_handler_init_sources(struct device_handler *handler)
+{
+ /* init our device sources: udev, network and user events */
+ handler->network = network_init(handler, handler->waitset,
+ handler->dry_run);
+ if (!handler->network)
+ return -1;
+
+ handler->udev = udev_init(handler, handler->waitset);
+ if (!handler->udev)
+ return -1;
+
+ handler->user_event = user_event_init(handler, handler->waitset);
+ if (!handler->user_event)
+ return -1;
+
+ return 0;
+}
+
+static void device_handler_reinit_sources(struct device_handler *handler)
+{
+ /* if we haven't initialised sources previously (becuase we started in
+ * safe mode), then init once here. */
+ if (!(handler->udev || handler->network || handler->user_event)) {
+ device_handler_init_sources(handler);
+ return;
+ }
+
+ system_info_reinit();
+
+ network_shutdown(handler->network);
+ handler->network = network_init(handler, handler->waitset,
+ handler->dry_run);
+
+ udev_reinit(handler->udev);
+}
+
+static inline const char *get_device_path(struct discover_device *dev)
+{
+ return dev->ramdisk ? dev->ramdisk->snapshot : dev->device_path;
+}
+
+static char *check_subvols(struct discover_device *dev)
+{
+ const char *fstype = discover_device_get_param(dev, "ID_FS_TYPE");
+ struct stat sb;
+ char *path;
+ int rc;
+
+ if (strncmp(fstype, "btrfs", strlen("btrfs")))
+ return dev->mount_path;
+
+ /* On btrfs a device's root may be under a subvolume path */
+ path = join_paths(dev, dev->mount_path, "@");
+ rc = stat(path, &sb);
+ if (!rc && S_ISDIR(sb.st_mode)) {
+ pb_debug("Using '%s' for btrfs root path\n", path);
+ return path;
+ }
+
+ talloc_free(path);
+ return dev->mount_path;
+}
+