[PATCH RFC 3/3] all: Implement boot order
Samuel Mendoza-Jonas
sam.mj at au1.ibm.com
Tue Dec 16 10:44:01 AEDT 2014
discover: Read comma separated bootdevs, store in list
lib: Update pb-protocol code
ui/ncurses: Update to naively recognise boot_order
Signed-off-by: Samuel Mendoza-Jonas <sam.mj at au1.ibm.com>
---
discover/device-handler.c | 49 ++++++++++++++++++++++-------
discover/platform-powerpc.c | 71 +++++++++++++++++++++++++++++++----------
discover/platform.c | 16 +++++++---
lib/pb-config/pb-config.c | 17 +++++++---
lib/pb-protocol/pb-protocol.c | 38 +++++++++++++++++++---
lib/types/types.h | 3 ++
ui/ncurses/nc-config.c | 73 ++++++++++++++++++++++++++++++++++---------
utils/pb-config.c | 9 +++++-
8 files changed, 220 insertions(+), 56 deletions(-)
diff --git a/discover/device-handler.c b/discover/device-handler.c
index e9c6949..b7c77e5 100644
--- a/discover/device-handler.c
+++ b/discover/device-handler.c
@@ -462,6 +462,33 @@ static bool ipmi_device_type_matches(enum ipmi_bootdev ipmi_type,
return false;
}
+/* TODO: Decide how to order device types */
+static int boot_order_priority(const struct config *config,
+ struct discover_boot_option *boot_opt)
+{
+ enum device_type type = boot_opt->device->device->type;
+ const char *uuid = boot_opt->device->uuid;
+ struct autoboot_option *opt;
+ bool uuid_exists = false;
+
+ list_for_each_entry(config->boot_order, opt, list) {
+ if (opt->boot_type == BOOT_DEVICE_UUID) {
+ uuid_exists = true;
+ if (!strcmp(opt->uuid, uuid))
+ return DEFAULT_PRIORITY_UUID;
+ }
+ if (opt->boot_type == BOOT_DEVICE_TYPE) {
+ if (opt->type == type)
+ return DEFAULT_PRIORITY_NORMAL;
+ }
+ }
+
+ if (uuid_exists)
+ return DEFAULT_PRIORITY_DISABLED;
+
+ return 0;
+}
+
/*
* We have different priorities to resolve conflicts between boot options that
* report to be the default for their device. This function assigns a priority
@@ -471,8 +498,8 @@ static enum default_priority default_option_priority(
struct discover_boot_option *opt)
{
const struct config *config;
- const char *dev_str;
bool ipmi_match;
+ int order_match;
config = config_get();
@@ -483,16 +510,16 @@ static enum default_priority default_option_priority(
if (ipmi_match && !config->ipmi_bootdev_persistent)
return DEFAULT_PRIORITY_IPMI_VOLATILE;
- /* 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_UUID;
-
- pb_debug("handler: disabled default priority due to "
- "non-matching UUID\n");
- return DEFAULT_PRIORITY_DISABLED;
+ /* Next, allow matching by device UUID or type. If we have one set but
+ * it doesn't match, disallow the default entirely */
+ if (config->n_boot_order) {
+ order_match = boot_order_priority(config, opt);
+ if (order_match) {
+ if (order_match == DEFAULT_PRIORITY_DISABLED)
+ pb_debug("handler: disabled default priority "
+ "due to non-matching UUID\n");
+ return order_match;
+ }
}
/* If we don't have a UUID specified, but our IPMI type matches,
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
index 2829066..3ce70c1 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -426,29 +426,51 @@ static int read_bootdev(void *ctx, char **pos, struct autoboot_option *opt)
return rc;
}
+/* bootdevs defined as a comma seperated list of uuids or device types */
static void populate_bootdev_config(struct platform_powerpc *platform,
struct config *config)
-
{
+ struct autoboot_option *opt, *old = NULL;
const char *val;
-
- config->boot_device = NULL;
+ char *pos, *end;
val = get_param(platform, "petitboot,bootdev");
if (!val || !strlen(val))
return;
- if (!strncmp(val, "uuid:", strlen("uuid:"))) {
- config->boot_device = talloc_strdup(config,
- val + strlen("uuid:"));
+ pos = talloc_strdup(config, val);
+ end = strchr(pos, '\0');
+
+ /* If bootdevs are set they override the platform default */
+ opt = list_entry((config->boot_order)->head.next, typeof(*opt),
+ list, config->boot_order);
+ list_init(config->boot_order);
+ config->n_boot_order = 0;
+
+ /* Try at least once for backwards compatability */
+ do {
+ 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, ','))
+ continue;
+ return;
+ }
+
+ list_add_tail(config->boot_order, &opt->list);
+ config->n_boot_order++;
- } else if (!strncmp(val, "mac:", strlen("mac:"))) {
- config->boot_device = talloc_strdup(config,
- val + strlen("mac:"));
+ } while (pos < end);
+ /* Restore default if no bootdevs were found */
+ if (!config->n_boot_order) {
+ list_add(config->boot_order, &old->list);
+ config->n_boot_order = 1;
} else {
- pb_log("bootdev config is in an unknown format "
- "(expected uuid:... or mac:...)");
+ talloc_free(old);
}
}
@@ -575,16 +597,31 @@ 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;
-
- if (!config->boot_device)
+ struct autoboot_option *opt;
+ char *val = NULL, *boot_str = NULL, *tmp = NULL;
+
+ if (config->n_boot_order) {
+ list_for_each_entry(config->boot_order, opt, list) {
+ switch (opt->boot_type) {
+ case BOOT_DEVICE_TYPE:
+ boot_str = talloc_asprintf(config, "%s,",
+ device_type_name(opt->type));
+ break;
+ case BOOT_DEVICE_UUID:
+ boot_str = talloc_asprintf(config, "uuid:%s,",
+ opt->uuid);
+ break;
+ }
+ tmp = val = talloc_asprintf_append(val, boot_str);
+ }
+ } else {
val = "";
- else
- tmp = val = talloc_asprintf(platform,
- "uuid:%s", config->boot_device);
+ }
update_string_config(platform, "petitboot,bootdev", val);
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 c035860..31aab90 100644
--- a/discover/platform.c
+++ b/discover/platform.c
@@ -65,9 +65,16 @@ static void dump_config(struct config *config)
pb_log(" IPMI boot device 0x%02x%s\n", config->ipmi_bootdev,
config->ipmi_bootdev_persistent ? " (persistent)" : "");
- if (config->boot_device)
- pb_log(" boot device %s\n", config->boot_device);
-
+ if (config->n_boot_order) {
+ struct autoboot_option *opt;
+ pb_log(" boot order\n");
+ list_for_each_entry(config->boot_order, opt, list) {
+ if (opt->boot_type == BOOT_DEVICE_TYPE)
+ pb_log(" %s\n", device_type_name(opt->type));
+ else
+ pb_log(" uuid: %s\n", opt->uuid);
+ }
+ }
pb_log(" language: %s\n", config->lang ?: "");
}
@@ -99,7 +106,8 @@ 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->boot_order = talloc(config, struct list);
+ list_init(config->boot_order);
config->safe_mode = false;
config->lang = NULL;
config->ipmi_bootdev = 0;
diff --git a/lib/pb-config/pb-config.c b/lib/pb-config/pb-config.c
index f27833f..611b554 100644
--- a/lib/pb-config/pb-config.c
+++ b/lib/pb-config/pb-config.c
@@ -36,6 +36,7 @@ static struct interface_config *config_copy_interface(struct config *ctx,
struct config *config_copy(void *ctx, const struct config *src)
{
+ struct autoboot_option *src_opt, *opt;
struct config *dest;
unsigned int i;
@@ -62,10 +63,18 @@ struct config *config_copy(void *ctx, const struct config *src)
dest->ipmi_bootdev = src->ipmi_bootdev;
dest->ipmi_bootdev_persistent = src->ipmi_bootdev_persistent;
- if (src->boot_device && strlen(src->boot_device))
- dest->boot_device = talloc_strdup(dest, src->boot_device);
- else
- dest->boot_device = NULL;
+ dest->n_boot_order = src->n_boot_order;
+ dest->boot_order = talloc(dest, struct list);
+ list_init(dest->boot_order);
+ if (src->n_boot_order) {
+ list_for_each_entry(src->boot_order, src_opt, list) {
+ opt = talloc(dest, struct autoboot_option);
+ opt->boot_type = src_opt->boot_type;
+ opt->type = src_opt->type;
+ opt->uuid = src_opt->uuid;
+ list_add_tail(dest->boot_order, &opt->list);
+ }
+ }
if (src->lang && strlen(src->lang))
dest->lang = talloc_strdup(dest, src->lang);
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
index e88fa1a..508794e 100644
--- a/lib/pb-protocol/pb-protocol.c
+++ b/lib/pb-protocol/pb-protocol.c
@@ -264,6 +264,7 @@ static int pb_protocol_interface_config_len(struct interface_config *conf)
int pb_protocol_config_len(const struct config *config)
{
+ struct autoboot_option *opt;
unsigned int i, len;
len = 4 /* config->autoboot_enabled */ +
@@ -281,7 +282,11 @@ int pb_protocol_config_len(const struct config *config)
len += 4 + 4; /* ipmi_bootdev, ipmi_bootdev_persistent */
- len += 4 + optional_strlen(config->boot_device);
+ len += 4; /* n_boot_order */
+ list_for_each_entry(config->boot_order, opt, list) {
+ len += 4 + 4; /* boot_type, type */
+ len += 4 + optional_strlen(opt->uuid);
+ }
len += 4 + optional_strlen(config->lang);
@@ -447,6 +452,7 @@ static int pb_protocol_serialise_config_interface(char *buf,
int pb_protocol_serialise_config(const struct config *config,
char *buf, int buf_len)
{
+ struct autoboot_option *opt;
char *pos = buf;
unsigned int i;
@@ -479,7 +485,15 @@ int pb_protocol_serialise_config(const struct config *config,
*(uint32_t *)pos = config->ipmi_bootdev_persistent;
pos += 4;
- pos += pb_protocol_serialise_string(pos, config->boot_device);
+ *(uint32_t *)pos = config->n_boot_order;
+ pos += 4;
+ list_for_each_entry(config->boot_order, opt, list) {
+ *(uint32_t *)pos = opt->boot_type;
+ pos += 4;
+ *(uint32_t *)pos = opt->type;
+ pos += 4;
+ pos += pb_protocol_serialise_string(pos, opt->uuid);
+ }
pos += pb_protocol_serialise_string(pos, config->lang);
@@ -866,6 +880,7 @@ static int pb_protocol_deserialise_config_interface(const char **buf,
int pb_protocol_deserialise_config(struct config *config,
const struct pb_protocol_message *message)
{
+ struct autoboot_option *opt;
unsigned int len, i, tmp;
const char *pos;
int rc = -1;
@@ -918,10 +933,25 @@ int pb_protocol_deserialise_config(struct config *config,
goto out;
config->ipmi_bootdev_persistent = !!tmp;
- if (read_string(config, &pos, &len, &str))
+
+ if (read_u32(&pos, &len, &config->n_boot_order))
goto out;
+ config->boot_order = talloc(config, struct list);
+ list_init(config->boot_order);
+ for (i = 0; i < config->n_boot_order; i++) {
+ opt = talloc(config, struct autoboot_option);
+ if (read_u32(&pos, &len, &opt->boot_type))
+ goto out;
+
+ if (read_u32(&pos, &len, &opt->type))
+ goto out;
- config->boot_device = str;
+ if (read_string(config, &pos, &len, &str))
+ goto out;
+
+ opt->uuid = str;
+ list_add_tail(config->boot_order, &opt->list);
+ }
if (read_string(config, &pos, &len, &str))
goto out;
diff --git a/lib/types/types.h b/lib/types/types.h
index add81fc..239c344 100644
--- a/lib/types/types.h
+++ b/lib/types/types.h
@@ -137,6 +137,9 @@ struct config {
unsigned int autoboot_timeout_sec;
struct network_config network;
+ unsigned int n_boot_order;
+ struct list *boot_order;
+
unsigned int ipmi_bootdev;
bool ipmi_bootdev_persistent;
diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c
index 17cc380..5342f28 100644
--- a/ui/ncurses/nc-config.c
+++ b/ui/ncurses/nc-config.c
@@ -188,6 +188,7 @@ static int screen_process_form(struct config_screen *screen)
const struct system_info *sysinfo = screen->cui->sysinfo;
enum net_conf_type net_conf_type;
struct interface_config *iface;
+ struct autoboot_option *opt, *nopt, *tmp;
char *str, *end, *uuid;
struct config *config;
int rc, idx;
@@ -199,9 +200,17 @@ static int screen_process_form(struct config_screen *screen)
config->autoboot_enabled = screen->autoboot_type != AUTOBOOT_DISABLED;
+ /* Throw away any other options - the V1 UI only supports one option */
+ list_for_each_entry_safe(config->boot_order, opt, tmp, list)
+ talloc_free(opt);
+ list_init(config->boot_order);
+ config->n_boot_order = 0;
+
uuid = NULL;
+ nopt = opt = NULL;
if (screen->autoboot_type == AUTOBOOT_ONE) {
char mac[20];
+ nopt = talloc(config, struct autoboot_option);
/* if idx is -1 here, we have an unknown UUID selected.
* Otherwise, it's a blockdev index (idx <= n_blockdevs) or an
@@ -213,14 +222,24 @@ static int screen_process_form(struct config_screen *screen)
interfaces[idx - sysinfo->n_blockdevs];
mac_str(info->hwaddr, info->hwaddr_size,
mac, sizeof(mac));
- uuid = mac;
+ uuid = talloc_strdup(config, mac);
} else if (idx != -1) {
uuid = sysinfo->blockdevs[idx]->uuid;
}
+ nopt->uuid = talloc_strdup(config, uuid);
+ nopt->boot_type = BOOT_DEVICE_UUID;
+
+ } else if (screen->autoboot_type == AUTOBOOT_ANY) {
+ nopt = talloc(config, struct autoboot_option);
+ nopt->boot_type = BOOT_DEVICE_TYPE;
+ nopt->type = DEVICE_TYPE_ANY;
}
- talloc_free(config->boot_device);
- config->boot_device = uuid ? talloc_strdup(config, uuid) : NULL;
+ if (nopt) {
+ /* V1: Add nopt as sole autoboot option */
+ list_add(config->boot_order, &nopt->list);
+ config->n_boot_order = 1;
+ }
str = widget_textbox_get_value(screen->widgets.timeout_f);
if (str) {
@@ -592,13 +611,23 @@ static void config_screen_setup_widgets(struct config_screen *screen,
found = false;
+ /* V1: The UI will ignore the boot order, only showing the first
+ * option in the list as the selected option. This will be the
+ * boot option with highest priority
+ */
+ struct autoboot_option *opt = NULL;
+ opt = list_entry((config->boot_order)->head.next, typeof(*opt),
+ list, config->boot_order);
+
for (i = 0; i < sysinfo->n_blockdevs; i++) {
struct blockdev_info *bd = sysinfo->blockdevs[i];
- bool selected;
+ bool selected = false;
char *label;
- selected = config->boot_device &&
- !strcmp(config->boot_device, bd->uuid);
+ if (opt && opt->boot_type == BOOT_DEVICE_UUID &&
+ !strcmp(opt->uuid, bd->uuid))
+ selected = true;
+
if (selected)
found = true;
@@ -612,11 +641,14 @@ static void config_screen_setup_widgets(struct config_screen *screen,
for (i = 0; i < sysinfo->n_interfaces; i++) {
struct interface_info *info = sysinfo->interfaces[i];
char *label, mac[20];
- bool selected;
+ bool selected = false;
mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
- selected = config->boot_device &&
- !strcmp(config->boot_device, mac);
+
+ if (opt && opt->boot_type == BOOT_DEVICE_UUID &&
+ !strcmp(opt->uuid, mac))
+ selected = true;
+
if (selected)
found = true;
@@ -631,8 +663,12 @@ static void config_screen_setup_widgets(struct config_screen *screen,
if (screen->autoboot_type == AUTOBOOT_ONE && !found) {
char *label;
- label = talloc_asprintf(screen, _("Unknown UUID: %s"),
- config->boot_device);
+ if (opt->boot_type == BOOT_DEVICE_UUID)
+ label = talloc_asprintf(screen, _("Unknown UUID: %s"),
+ opt->uuid);
+ else
+ label = talloc_asprintf(screen, _("Unknown option: %d"),
+ opt->type);
widget_select_add_option(screen->widgets.boot_device_f, -1,
label, true);
@@ -774,6 +810,7 @@ static void config_screen_draw(struct config_screen *screen,
const struct config *config,
const struct system_info *sysinfo)
{
+ struct autoboot_option *opt;
bool repost = false;
int height;
@@ -813,11 +850,17 @@ static void config_screen_draw(struct config_screen *screen,
config_screen_setup_empty(screen);
} else {
screen->net_conf_type = find_net_conf_type(config);
- if (!config->autoboot_enabled)
+ if (!config->autoboot_enabled) {
screen->autoboot_type = AUTOBOOT_DISABLED;
- else
- screen->autoboot_type = config->boot_device ?
- AUTOBOOT_ONE : AUTOBOOT_ANY;
+ /* Placeholder for V2: AUTOBOOT_ANY/_ONE will be obselete */
+ } else {
+ screen->autoboot_type = AUTOBOOT_ANY;
+ list_for_each_entry(config->boot_order, opt, list)
+ if (opt->boot_type == BOOT_DEVICE_UUID) {
+ screen->autoboot_type = AUTOBOOT_ONE;
+ break;
+ }
+ }
config_screen_setup_widgets(screen, config, sysinfo);
config_screen_layout_widgets(screen);
diff --git a/utils/pb-config.c b/utils/pb-config.c
index 3bd670c..b689b57 100644
--- a/utils/pb-config.c
+++ b/utils/pb-config.c
@@ -61,7 +61,14 @@ static void print_one_config(void *ctx, const char *req, const char *name,
static void print_config(void *ctx, struct config *config, const char *var)
{
- print_one_config(ctx, var, "bootdev", "%s", config->boot_device);
+ struct autoboot_option *opt;
+ print_one_config(ctx, var, "bootdev", "Boot order:");
+ list_for_each_entry(config->boot_order, opt, list) {
+ if (opt->boot_type == BOOT_DEVICE_TYPE)
+ print_one_config(ctx, var, "bootdev", "type: %d", opt->type);
+ else
+ print_one_config(ctx, var, "bootdev", "uuid: %s", opt->uuid);
+ }
print_one_config(ctx, var, "autoboot", "%s",
config->autoboot_enabled ? "enabled" : "disabled");
print_one_config(ctx, var, "timeout", "%d",
--
1.9.3
More information about the Petitboot
mailing list