]> git.ozlabs.org Git - petitboot/blobdiff - discover/device-handler.c
travis: Enable ppc64le Travis builds
[petitboot] / discover / device-handler.c
index ec4a6f611ff289ee9d4bc61182401897c41ff1ba..569e65290bd7e98cef518b078a16f76547ecb564 100644 (file)
@@ -1,4 +1,5 @@
 #include <assert.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #include <unistd.h>
@@ -18,6 +19,7 @@
 #include <process/process.h>
 #include <url/url.h>
 #include <i18n/i18n.h>
+#include <pb-config/pb-config.h>
 
 #include <sys/sysmacros.h>
 #include <sys/types.h>
@@ -84,6 +86,10 @@ struct device_handler {
 
        struct list             progress;
        unsigned int            n_progress;
+
+       struct plugin_option    **plugins;
+       unsigned int            n_plugins;
+       bool                    plugin_installing;
 };
 
 static int mount_device(struct discover_device *dev);
@@ -126,6 +132,28 @@ const struct discover_device *device_handler_get_device(
        return handler->devices[index];
 }
 
+/**
+ * device_handler_get_plugin_count - Get the count of current handler plugins.
+ */
+int device_handler_get_plugin_count(const struct device_handler *handler)
+{
+       return handler->n_plugins;
+}
+
+/**
+ * discover_handler_get_plugin - Get a handler plugin by index.
+ */
+const struct plugin_option *device_handler_get_plugin(
+       const struct device_handler *handler, unsigned int index)
+{
+       if (index >= handler->n_plugins) {
+               assert(0 && "bad index");
+               return NULL;
+       }
+
+       return handler->plugins[index];
+}
+
 struct network *device_handler_get_network(
                const struct device_handler *handler)
 {
@@ -312,6 +340,22 @@ const char *discover_device_get_param(struct discover_device *device,
        return NULL;
 }
 
+static void set_env_variables(const struct config *config)
+{
+       if (config->http_proxy)
+               setenv("http_proxy", config->http_proxy, 1);
+       else
+               unsetenv("http_proxy");
+
+       if (config->https_proxy)
+               setenv("https_proxy", config->https_proxy, 1);
+       else
+               unsetenv("https_proxy");
+
+       /* Reduce noise in the log from LVM listing open file descriptors */
+       setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
+}
+
 struct device_handler *device_handler_init(struct discover_server *server,
                struct waitset *waitset, int dry_run)
 {
@@ -336,6 +380,8 @@ struct device_handler *device_handler_init(struct discover_server *server,
        if (config_get()->safe_mode)
                return handler;
 
+       set_env_variables(config_get());
+
        rc = device_handler_init_sources(handler);
        if (rc) {
                talloc_free(handler);
@@ -349,6 +395,7 @@ void device_handler_reinit(struct device_handler *handler)
 {
        struct discover_boot_option *opt, *tmp;
        struct ramdisk_device *ramdisk;
+       struct config *config;
        unsigned int i;
 
        device_handler_cancel_default(handler);
@@ -385,6 +432,25 @@ void device_handler_reinit(struct device_handler *handler)
        handler->ramdisks = NULL;
        handler->n_ramdisks = 0;
 
+       /* drop any known plugins */
+       for (i = 0; i < handler->n_plugins; i++)
+               talloc_free(handler->plugins[i]);
+       talloc_free(handler->plugins);
+       handler->plugins = NULL;
+       handler->n_plugins = 0;
+
+       discover_server_notify_plugins_remove(handler->server);
+
+       set_env_variables(config_get());
+
+       /* If the safe mode warning was active disable it now */
+       if (config_get()->safe_mode) {
+               config = config_copy(handler, config_get());
+               config->safe_mode = false;
+               config_set(config);
+               discover_server_notify_config(handler->server, config);
+       }
+
        device_handler_reinit_sources(handler);
 }
 
@@ -588,7 +654,7 @@ void device_handler_status_download(struct device_handler *handler,
                        unit++;
                }
                update = talloc_asprintf(handler,
-                               _("%u %s downloading: %.0f%% - %lu%cB"),
+                               _("%u %s downloading: %.0f%% - %" PRIu64 "%cB"),
                                handler->n_progress,
                                ngettext("item", "items", handler->n_progress),
                                (current / total) * 100, current_converted,
@@ -603,6 +669,21 @@ void device_handler_status_download(struct device_handler *handler,
        }
 }
 
+static void device_handler_plugin_scan_device(struct device_handler *handler,
+               struct discover_device *dev)
+{
+       int rc;
+
+       pb_debug("Scanning %s for plugin files\n", dev->device->id);
+
+       rc = process_run_simple(handler, pb_system_apps.pb_plugin,
+                               "scan", dev->mount_path,
+                               NULL);
+       if (rc)
+               pb_log("Error from pb-plugin scan %s\n",
+                               dev->mount_path);
+}
+
 void device_handler_status_download_remove(struct device_handler *handler,
                struct process_info *procinfo)
 {
@@ -751,6 +832,9 @@ static enum default_priority default_option_priority(
                int boot_match = autoboot_option_priority(config, opt);
                if (boot_match > 0)
                        return boot_match;
+       } else {
+               /* If there is no specific boot order, boot any device */
+               return DEFAULT_PRIORITY_LOCAL_FIRST;
        }
 
        /* If the option didn't match any entry in the array, it is disabled */
@@ -1069,6 +1153,9 @@ int device_handler_discover(struct device_handler *handler,
        device_handler_discover_context_commit(handler, ctx);
 
        process_boot_option_queue(handler);
+
+       /* Check this device for pb-plugins */
+       device_handler_plugin_scan_device(handler, dev);
 out:
        talloc_unlink(handler, ctx);
 
@@ -1273,7 +1360,7 @@ static void process_url_cb(struct load_url_result *result, void *data)
 
        mac = event_get_param(event, "mac");
        char *url = talloc_asprintf(event, "file://%s", result->local);
-       event_set_param(event, "pxeconffile", url);
+       event_set_param(event, "pxeconffile-local", url);
 
        dev = discover_device_create(handler, mac, event->device);
        ctx = device_handler_discover_context_create(handler, dev);
@@ -1354,6 +1441,61 @@ void device_handler_process_url(struct device_handler *handler,
        talloc_unlink(handler, ctx);
 }
 
+static void plugin_install_cb(struct process *process)
+{
+       struct device_handler *handler = process->data;
+
+       if (!handler) {
+               pb_log("%s: Missing data!\n", __func__);
+               return;
+       }
+
+       handler->plugin_installing = false;
+       if (process->exit_status) {
+               device_handler_status_err(handler, "Plugin failed to install!");
+               pb_log("Failed to install plugin:\n%s\n", process->stdout_buf);
+       }
+}
+
+void device_handler_install_plugin(struct device_handler *handler,
+               const char *plugin_file)
+{
+       struct process *p;
+       int result;
+
+       if (handler->plugin_installing) {
+               pb_log("Plugin install cancelled - install already running");
+               return;
+       }
+
+       p = process_create(handler);
+       if (!p) {
+               pb_log("install_plugin: Failed to create process\n");
+               return;
+       }
+
+       const char *argv[] = {
+               pb_system_apps.pb_plugin,
+               "install",
+               "auto",
+               plugin_file,
+               NULL
+       };
+
+       p->path = pb_system_apps.pb_plugin;
+       p->argv = argv;
+       p->exit_cb = plugin_install_cb;
+       p->data = handler;
+       p->keep_stdout = true;
+
+       result = process_run_async(p);
+
+       if (result)
+               device_handler_status_err(handler, "Could not install plugin");
+       else
+               handler->plugin_installing = true;
+}
+
 #ifndef PETITBOOT_TEST
 
 /**
@@ -1408,6 +1550,35 @@ void device_handler_discover_context_commit(struct device_handler *handler,
        }
 }
 
+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 &&
+                               strcmp(opt->version, tmp->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;
@@ -1425,6 +1596,10 @@ static void device_handler_update_lang(const char *lang)
 static int device_handler_init_sources(struct device_handler *handler)
 {
        /* init our device sources: udev, network and user events */
+       handler->user_event = user_event_init(handler, handler->waitset);
+       if (!handler->user_event)
+               return -1;
+
        handler->network = network_init(handler, handler->waitset,
                        handler->dry_run);
        if (!handler->network)
@@ -1434,10 +1609,6 @@ static int device_handler_init_sources(struct device_handler *handler)
        if (!handler->udev)
                return -1;
 
-       handler->user_event = user_event_init(handler, handler->waitset);
-       if (!handler->user_event)
-               return -1;
-
        return 0;
 }
 
@@ -1624,6 +1795,20 @@ static int mount_device(struct discover_device *dev)
        rc = try_mount(device_path, dev->mount_path, fstype,
                       MS_RDONLY | MS_SILENT, dev->ramdisk);
 
+       /* If mount fails clean up any snapshot and try again */
+       if (rc && dev->ramdisk) {
+               pb_log("couldn't mount snapshot for %s: mount failed: %s\n",
+                               device_path, strerror(errno));
+               pb_log("falling back to actual device\n");
+
+               devmapper_destroy_snapshot(dev);
+
+               device_path = get_device_path(dev);
+               pb_log("mounting device %s read-only\n", dev->device_path);
+               rc = try_mount(device_path, dev->mount_path, fstype,
+                              MS_RDONLY | MS_SILENT, dev->ramdisk);
+       }
+
        if (!rc) {
                dev->mounted = true;
                dev->mounted_rw = false;
@@ -1635,9 +1820,6 @@ static int mount_device(struct discover_device *dev)
        pb_log("couldn't mount device %s: mount failed: %s\n",
                        device_path, strerror(errno));
 
-       /* If mount fails clean up any snapshot */
-       devmapper_destroy_snapshot(dev);
-
        pb_rmdir_recursive(mount_base(), dev->mount_path);
 err_free:
        talloc_free(dev->mount_path);