diff options
author | Samuel Mendoza-Jonas <sam.mj@au1.ibm.com> | 2015-01-21 16:12:14 +1100 |
---|---|---|
committer | Samuel Mendoza-Jonas <sam.mj@au1.ibm.com> | 2015-05-05 15:03:46 +1000 |
commit | a3e3b66fbcb18174fc54ffd771ef3a38c9f8defd (patch) | |
tree | 50b135545e3c6972b8bf9a9c49634165fc92cc52 /discover | |
parent | ec12bbd7bbfb3dd31dbd987ecff463542d54542f (diff) | |
download | talos-petitboot-a3e3b66fbcb18174fc54ffd771ef3a38c9f8defd.tar.gz talos-petitboot-a3e3b66fbcb18174fc54ffd771ef3a38c9f8defd.zip |
petitboot: Implement ordered boot options
Move petitboot to a more familiar 'boot-order' based autoboot system.
The discover server now reads multiple values from the petitboot,bootdev
parameter and adds them in order to config->autoboot_opts. Boot priority
is determined by the options' position in the list.
On the client, nc-config now recognises the new boot order, and allows
the user to add, remove, and reorder the devices in the list.
Signed-off-by: Samuel Mendoza-Jonas <sam.mj@au1.ibm.com>
Diffstat (limited to 'discover')
-rw-r--r-- | discover/device-handler.c | 55 | ||||
-rw-r--r-- | discover/platform-powerpc.c | 121 | ||||
-rw-r--r-- | discover/platform.c | 32 |
3 files changed, 146 insertions, 62 deletions
diff --git a/discover/device-handler.c b/discover/device-handler.c index f053713..487f2e7 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -40,8 +40,7 @@ enum default_priority { DEFAULT_PRIORITY_REMOTE = 1, - DEFAULT_PRIORITY_LOCAL_UUID = 2, - DEFAULT_PRIORITY_LOCAL_FIRST = 3, + DEFAULT_PRIORITY_LOCAL_FIRST = 2, DEFAULT_PRIORITY_LOCAL_LAST = 0xfe, DEFAULT_PRIORITY_DISABLED = 0xff, }; @@ -462,11 +461,27 @@ static bool ipmi_device_type_matches(enum ipmi_bootdev ipmi_type, return false; } -static bool priority_matches(struct boot_priority *prio, - struct discover_boot_option *opt) +static int autoboot_option_priority(const struct config *config, + struct discover_boot_option *opt) { - return prio->type == opt->device->device->type || - prio->type == DEVICE_TYPE_ANY; + enum device_type type = opt->device->device->type; + const char *uuid = opt->device->uuid; + struct autoboot_option *auto_opt; + unsigned int i; + + for (i = 0; i < config->n_autoboot_opts; i++) { + auto_opt = &config->autoboot_opts[i]; + if (auto_opt->boot_type == BOOT_DEVICE_UUID) + if (!strcmp(auto_opt->uuid, uuid)) + return DEFAULT_PRIORITY_LOCAL_FIRST + i; + + if (auto_opt->boot_type == BOOT_DEVICE_TYPE) + if (auto_opt->type == type || + auto_opt->type == DEVICE_TYPE_ANY) + return DEFAULT_PRIORITY_LOCAL_FIRST + i; + } + + return -1; } /* @@ -478,8 +493,6 @@ static enum default_priority default_option_priority( struct discover_boot_option *opt) { const struct config *config; - const char *dev_str; - unsigned int i; config = config_get(); @@ -498,25 +511,17 @@ static enum default_priority default_option_priority( return DEFAULT_PRIORITY_DISABLED; } - /* Next, allow matching by device UUID. If we have one set but it - * doesn't match, disallow the default entirely */ - dev_str = config->boot_device; - if (dev_str && dev_str[0]) { - if (!strcmp(opt->device->uuid, dev_str)) - return DEFAULT_PRIORITY_LOCAL_UUID; - - pb_debug("handler: disabled default priority due to " - "non-matching UUID\n"); - return DEFAULT_PRIORITY_DISABLED; - } - - /* Lastly, use the local priorities */ - for (i = 0; i < config->n_boot_priorities; i++) { - struct boot_priority *prio = &config->boot_priorities[i]; - if (priority_matches(prio, opt)) - return DEFAULT_PRIORITY_LOCAL_FIRST + prio->priority; + /* Next, try to match the option against the user-defined autoboot + * options, either by device UUID or type. */ + if (config->n_autoboot_opts) { + int boot_match = autoboot_option_priority(config, opt); + if (boot_match > 0) + return boot_match; } + /* If the option didn't match any entry in the array, it is disabled */ + pb_debug("handler: disabled default priority due to " + "non-matching UUID or type\n"); return DEFAULT_PRIORITY_DISABLED; } diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c index 895f0ec..bbffb60 100644 --- a/discover/platform-powerpc.c +++ b/discover/platform-powerpc.c @@ -49,6 +49,7 @@ static const char *known_params[] = { "petitboot,network", "petitboot,timeout", "petitboot,bootdev", + "petitboot,bootdevs", "petitboot,language", "petitboot,debug?", NULL, @@ -431,28 +432,86 @@ static int read_bootdev(void *ctx, char **pos, struct autoboot_option *opt) static void populate_bootdev_config(struct platform_powerpc *platform, struct config *config) - { + struct autoboot_option *opt, *new = NULL; + char *pos, *end, *old_dev = NULL; + const char delim = ' '; + unsigned int n_new = 0; const char *val; + bool conflict; - config->boot_device = NULL; - + /* Check for old-style bootdev */ val = get_param(platform, "petitboot,bootdev"); - if (!val || !strlen(val)) - return; - - if (!strncmp(val, "uuid:", strlen("uuid:"))) { - config->boot_device = talloc_strdup(config, + if (val && strlen(val)) { + pos = talloc_strdup(config, val); + if (!strncmp(val, "uuid:", strlen("uuid:"))) + old_dev = talloc_strdup(config, val + strlen("uuid:")); - - } else if (!strncmp(val, "mac:", strlen("mac:"))) { - config->boot_device = talloc_strdup(config, + else if (!strncmp(val, "mac:", strlen("mac:"))) + old_dev = talloc_strdup(config, val + strlen("mac:")); + } + /* Check for ordered bootdevs */ + val = get_param(platform, "petitboot,bootdevs"); + if (!val || !strlen(val)) { + pos = end = NULL; } else { - pb_log("bootdev config is in an unknown format " - "(expected uuid:... or mac:...)"); + pos = talloc_strdup(config, val); + end = strchr(pos, '\0'); + } + + while (pos && pos < end) { + opt = talloc(config, struct autoboot_option); + + if (read_bootdev(config, &pos, opt)) { + pb_log("bootdev config is in an unknown format " + "(expected uuid:... or mac:...)"); + talloc_free(opt); + if (strchr(pos, delim)) + continue; + return; + } + + new = talloc_realloc(config, new, struct autoboot_option, + n_new + 1); + new[n_new] = *opt; + n_new++; + talloc_free(opt); + } + + if (!n_new && !old_dev) { + /* If autoboot has been disabled, clear the default options */ + if (!config->autoboot_enabled) { + talloc_free(config->autoboot_opts); + config->n_autoboot_opts = 0; + } + return; + } + + conflict = old_dev && (!n_new || + new[0].boot_type == BOOT_DEVICE_TYPE || + /* Canonical UUIDs are 36 characters long */ + strncmp(new[0].uuid, old_dev, 36)); + + if (!conflict) { + talloc_free(config->autoboot_opts); + config->autoboot_opts = new; + config->n_autoboot_opts = n_new; + return; + } + + /* + * Difference detected, defer to old format in case it has been updated + * recently + */ + pb_debug("Old autoboot bootdev detected\n"); + talloc_free(config->autoboot_opts); + config->autoboot_opts = talloc(config, struct autoboot_option); + config->autoboot_opts[0].boot_type = BOOT_DEVICE_UUID; + config->autoboot_opts[0].uuid = talloc_strdup(config, old_dev); + config->n_autoboot_opts = 1; } static void populate_config(struct platform_powerpc *platform, @@ -578,16 +637,40 @@ static void update_network_config(struct platform_powerpc *platform, static void update_bootdev_config(struct platform_powerpc *platform, struct config *config) { - char *val, *tmp = NULL; + char *val = NULL, *boot_str = NULL, *tmp = NULL, *first = NULL; + struct autoboot_option *opt; + const char delim = ' '; + unsigned int i; - if (!config->boot_device) - val = ""; + if (!config->n_autoboot_opts) + first = val = ""; + else if (config->autoboot_opts[0].boot_type == BOOT_DEVICE_UUID) + first = talloc_asprintf(config, "uuid:%s", + config->autoboot_opts[0].uuid); else - tmp = val = talloc_asprintf(platform, - "uuid:%s", config->boot_device); + first = ""; + + for (i = 0; i < config->n_autoboot_opts; i++) { + opt = &config->autoboot_opts[i]; + switch (opt->boot_type) { + case BOOT_DEVICE_TYPE: + boot_str = talloc_asprintf(config, "%s%c", + device_type_name(opt->type), + delim); + break; + case BOOT_DEVICE_UUID: + boot_str = talloc_asprintf(config, "uuid:%s%c", + opt->uuid, delim); + break; + } + tmp = val = talloc_asprintf_append(val, boot_str); + } - update_string_config(platform, "petitboot,bootdev", val); + update_string_config(platform, "petitboot,bootdevs", val); + update_string_config(platform, "petitboot,bootdev", first); talloc_free(tmp); + if (boot_str) + talloc_free(boot_str); } static int update_config(struct platform_powerpc *platform, diff --git a/discover/platform.c b/discover/platform.c index 4451589..74e2a82 100644 --- a/discover/platform.c +++ b/discover/platform.c @@ -62,16 +62,13 @@ static void dump_config(struct config *config) for (i = 0; i < config->network.n_dns_servers; i++) pb_log(" dns server %s\n", config->network.dns_servers[i]); - if (config->boot_device) - pb_log(" boot device %s\n", config->boot_device); - - if (config->n_boot_priorities) - pb_log(" boot priority order:\n"); - - for (i = 0; i < config->n_boot_priorities; i++) { - struct boot_priority *prio = &config->boot_priorities[i]; - pb_log(" %10s: %d\n", device_type_name(prio->type), - prio->priority); + for (i = 0; i < config->n_autoboot_opts; i++) { + if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE) + pb_log(" boot device %d: %s\n", i, + device_type_name(config->autoboot_opts[i].type)); + else + pb_log(" boot device %d: uuid: %s\n", + i, config->autoboot_opts[i].uuid); } pb_log(" IPMI boot device 0x%02x%s\n", config->ipmi_bootdev, @@ -109,17 +106,16 @@ void config_set_defaults(struct config *config) config->network.n_interfaces = 0; config->network.dns_servers = NULL; config->network.n_dns_servers = 0; - config->boot_device = NULL; config->safe_mode = false; config->lang = NULL; - config->n_boot_priorities = 2; - config->boot_priorities = talloc_array(config, struct boot_priority, - config->n_boot_priorities); - config->boot_priorities[0].type = DEVICE_TYPE_NETWORK; - config->boot_priorities[0].priority = 0; - config->boot_priorities[1].type = DEVICE_TYPE_ANY; - config->boot_priorities[1].priority = 1; + config->n_autoboot_opts = 2; + config->autoboot_opts = talloc_array(config, struct autoboot_option, + config->n_autoboot_opts); + config->autoboot_opts[0].boot_type = BOOT_DEVICE_TYPE; + config->autoboot_opts[0].type = DEVICE_TYPE_NETWORK; + config->autoboot_opts[1].boot_type = BOOT_DEVICE_TYPE; + config->autoboot_opts[1].type = DEVICE_TYPE_ANY; config->ipmi_bootdev = 0; config->ipmi_bootdev_persistent = false; |