summaryrefslogtreecommitdiffstats
path: root/discover/platform-powerpc.c
diff options
context:
space:
mode:
authorSamuel Mendoza-Jonas <sam.mj@au1.ibm.com>2015-01-21 16:12:14 +1100
committerSamuel Mendoza-Jonas <sam.mj@au1.ibm.com>2015-05-05 15:03:46 +1000
commita3e3b66fbcb18174fc54ffd771ef3a38c9f8defd (patch)
tree50b135545e3c6972b8bf9a9c49634165fc92cc52 /discover/platform-powerpc.c
parentec12bbd7bbfb3dd31dbd987ecff463542d54542f (diff)
downloadpetitboot-a3e3b66fbcb18174fc54ffd771ef3a38c9f8defd.zip
petitboot-a3e3b66fbcb18174fc54ffd771ef3a38c9f8defd.tar.gz
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/platform-powerpc.c')
-rw-r--r--discover/platform-powerpc.c121
1 files changed, 102 insertions, 19 deletions
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,
OpenPOWER on IntegriCloud