[PATCH 6/7] petitboot: Implement ordered boot options
Samuel Mendoza-Jonas
sam.mj at au1.ibm.com
Wed Apr 1 11:41:05 AEDT 2015
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 at au1.ibm.com>
---
discover/device-handler.c | 54 +++----
discover/platform-powerpc.c | 115 ++++++++++++---
discover/platform.c | 32 ++--
lib/pb-config/pb-config.c | 26 ++--
lib/pb-protocol/pb-protocol.c | 55 ++++---
lib/types/types.h | 15 +-
ui/ncurses/nc-config.c | 334 +++++++++++++++++++++++++++---------------
utils/pb-config.c | 11 +-
8 files changed, 415 insertions(+), 227 deletions(-)
diff --git a/discover/device-handler.c b/discover/device-handler.c
index f053713..e0bae41 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,26 @@ 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)
+ return DEFAULT_PRIORITY_LOCAL_FIRST + i;
+ }
+
+ return -1;
}
/*
@@ -478,8 +492,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 +510,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 e735270..c65c404 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -46,6 +46,7 @@ static const char *known_params[] = {
"petitboot,network",
"petitboot,timeout",
"petitboot,bootdev",
+ "petitboot,bootdevs",
"petitboot,language",
"petitboot,debug?",
NULL,
@@ -428,28 +429,80 @@ 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)
+ 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,
@@ -575,16 +628,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;
diff --git a/lib/pb-config/pb-config.c b/lib/pb-config/pb-config.c
index a2272f4..98a6078 100644
--- a/lib/pb-config/pb-config.c
+++ b/lib/pb-config/pb-config.c
@@ -59,21 +59,21 @@ struct config *config_copy(void *ctx, const struct config *src)
dest->network.dns_servers[i] = talloc_strdup(dest,
src->network.dns_servers[i]);
- dest->n_boot_priorities = src->n_boot_priorities;
- dest->boot_priorities = talloc_array(dest, struct boot_priority,
- src->n_boot_priorities);
-
- for (i = 0; i < src->n_boot_priorities; i++) {
- dest->boot_priorities[i].priority =
- src->boot_priorities[i].priority;
- dest->boot_priorities[i].type = src->boot_priorities[i].type;
+ dest->n_autoboot_opts = src->n_autoboot_opts;
+ dest->autoboot_opts = talloc_array(dest, struct autoboot_option,
+ dest->n_autoboot_opts);
+
+ for (i = 0; i < src->n_autoboot_opts; i++) {
+ dest->autoboot_opts[i].boot_type =
+ src->autoboot_opts[i].boot_type;
+ if (src->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE)
+ dest->autoboot_opts[i].type =
+ src->autoboot_opts[i].type;
+ else
+ dest->autoboot_opts[i].uuid =
+ talloc_strdup(dest, src->autoboot_opts[i].uuid);
}
- if (src->boot_device && strlen(src->boot_device))
- dest->boot_device = talloc_strdup(dest, src->boot_device);
- else
- dest->boot_device = NULL;
-
dest->ipmi_bootdev = src->ipmi_bootdev;
dest->ipmi_bootdev_persistent = src->ipmi_bootdev_persistent;
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
index 4398248..69ea35d 100644
--- a/lib/pb-protocol/pb-protocol.c
+++ b/lib/pb-protocol/pb-protocol.c
@@ -280,9 +280,13 @@ int pb_protocol_config_len(const struct config *config)
len += 4 + optional_strlen(config->network.dns_servers[i]);
len += 4;
- len += config->n_boot_priorities * 8;
-
- len += 4 + optional_strlen(config->boot_device);
+ for (i = 0; i < config->n_autoboot_opts; i++) {
+ if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE)
+ len += 4 + 4;
+ else
+ len += 4 + 4 +
+ optional_strlen(config->autoboot_opts[i].uuid);
+ }
len += 4 + 4; /* ipmi_bootdev, ipmi_bootdev_persistent */
@@ -477,19 +481,22 @@ int pb_protocol_serialise_config(const struct config *config,
config->network.dns_servers[i]);
}
- *(uint32_t *)pos = __cpu_to_be32(config->n_boot_priorities);
+ *(uint32_t *)pos = __cpu_to_be32(config->n_autoboot_opts);
pos += 4;
- for (i = 0; i < config->n_boot_priorities; i++) {
- *(uint32_t *)pos =
- __cpu_to_be32(config->boot_priorities[i].type);
- pos += 4;
+ for (i = 0; i < config->n_autoboot_opts; i++) {
*(uint32_t *)pos =
- __cpu_to_be32(config->boot_priorities[i].priority);
+ __cpu_to_be32(config->autoboot_opts[i].boot_type);
pos += 4;
+ if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE) {
+ *(uint32_t *)pos =
+ __cpu_to_be32(config->autoboot_opts[i].type);
+ pos += 4;
+ } else {
+ pos += pb_protocol_serialise_string(pos,
+ config->autoboot_opts[i].uuid);
+ }
}
- pos += pb_protocol_serialise_string(pos, config->boot_device);
-
*(uint32_t *)pos = __cpu_to_be32(config->ipmi_bootdev);
pos += 4;
*(uint32_t *)pos = config->ipmi_bootdev_persistent;
@@ -925,24 +932,26 @@ int pb_protocol_deserialise_config(struct config *config,
config->network.dns_servers[i] = str;
}
- if (read_u32(&pos, &len, &config->n_boot_priorities))
+ if (read_u32(&pos, &len, &config->n_autoboot_opts))
goto out;
- config->boot_priorities = talloc_array(config, struct boot_priority,
- config->n_boot_priorities);
+ config->autoboot_opts = talloc_array(config, struct autoboot_option,
+ config->n_autoboot_opts);
- for (i = 0; i < config->n_boot_priorities; i++) {
+ for (i = 0; i < config->n_autoboot_opts; i++) {
if (read_u32(&pos, &len, &tmp))
goto out;
- config->boot_priorities[i].priority = (int)tmp;
- if (read_u32(&pos, &len, &tmp))
- goto out;
- config->boot_priorities[i].type = tmp;
+ config->autoboot_opts[i].boot_type = (int)tmp;
+ if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE) {
+ if (read_u32(&pos, &len, &tmp))
+ goto out;
+ config->autoboot_opts[i].type = tmp;
+ } else {
+ if (read_string(config, &pos, &len, &str))
+ goto out;
+ config->autoboot_opts[i].uuid = str;
+ }
}
- if (read_string(config, &pos, &len, &str))
- goto out;
- config->boot_device = str;
-
if (read_u32(&pos, &len, &config->ipmi_bootdev))
goto out;
if (read_u32(&pos, &len, &tmp))
diff --git a/lib/types/types.h b/lib/types/types.h
index e22dbc3..3bb8c9b 100644
--- a/lib/types/types.h
+++ b/lib/types/types.h
@@ -113,15 +113,6 @@ struct network_config {
unsigned int n_dns_servers;
};
-struct boot_priority {
- /* Boot options with higher priority values will take precedence over
- * lower values. Negative priorities signify "don't boot this by
- * default".
- */
- int priority;
- enum device_type type;
-};
-
struct autoboot_option {
enum {
BOOT_DEVICE_TYPE,
@@ -138,10 +129,8 @@ struct config {
unsigned int autoboot_timeout_sec;
struct network_config network;
- struct boot_priority *boot_priorities;
- unsigned int n_boot_priorities;
-
- char *boot_device;
+ struct autoboot_option *autoboot_opts;
+ unsigned int n_autoboot_opts;
unsigned int ipmi_bootdev;
bool ipmi_bootdev_persistent;
diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c
index c45df34..b3f72fb 100644
--- a/ui/ncurses/nc-config.c
+++ b/ui/ncurses/nc-config.c
@@ -33,16 +33,10 @@
#include "nc-config.h"
#include "nc-widgets.h"
-#define N_FIELDS 26
+#define N_FIELDS 29
extern struct help_text config_help_text;
-enum autoboot_type {
- AUTOBOOT_ANY,
- AUTOBOOT_ONE,
- AUTOBOOT_DISABLED,
-};
-
enum net_conf_type {
NET_CONF_TYPE_DHCP_ALL,
NET_CONF_TYPE_DHCP_ONE,
@@ -57,7 +51,9 @@ struct config_screen {
bool exit;
bool show_help;
+ bool show_subset;
bool need_redraw;
+
void (*on_exit)(struct cui *);
int scroll_y;
@@ -67,12 +63,16 @@ struct config_screen {
int network_config_y;
enum net_conf_type net_conf_type;
- enum autoboot_type autoboot_type;
+
+ bool autoboot_enabled;
struct {
- struct nc_widget_select *autoboot_f;
- struct nc_widget_label *autoboot_l;
- struct nc_widget_select *boot_device_f;
+ struct nc_widget_label *boot_order_l;
+ struct nc_widget_subset *boot_order_f;
+ struct nc_widget_label *boot_empty_l;
+ struct nc_widget_button *boot_add_b;
+ struct nc_widget_button *boot_none_b;
+ struct nc_widget_button *boot_any_b;
struct nc_widget_textbox *timeout_f;
struct nc_widget_label *timeout_l;
struct nc_widget_label *timeout_help_l;
@@ -151,7 +151,7 @@ static void config_screen_process_key(struct nc_scr *scr, int key)
cui_show_help(screen->cui, _("System Configuration"),
&config_help_text);
- } else if (handled) {
+ } else if (handled && !screen->show_subset) {
pad_refresh(screen);
}
}
@@ -165,6 +165,7 @@ static void config_screen_resize(struct nc_scr *scr)
static int config_screen_post(struct nc_scr *scr)
{
struct config_screen *screen = config_screen_from_scr(scr);
+ screen->show_subset = false;
widgetset_post(screen->widgetset);
nc_scr_frame_draw(scr);
if (screen->need_redraw) {
@@ -193,40 +194,48 @@ 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;
- char *str, *end, *uuid;
+ char *str, *end;
struct config *config;
- int rc, idx;
+ int i, n_boot_opts, rc, idx;
+ unsigned int *order;
+ char mac[20];
config = config_copy(screen, screen->cui->config);
- screen->autoboot_type =
- widget_select_get_value(screen->widgets.autoboot_f);
-
- config->autoboot_enabled = screen->autoboot_type != AUTOBOOT_DISABLED;
-
- uuid = NULL;
- if (screen->autoboot_type == AUTOBOOT_ONE) {
- char mac[20];
-
- /* if idx is -1 here, we have an unknown UUID selected.
- * Otherwise, it's a blockdev index (idx <= n_blockdevs) or an
- * interface index.
- */
- idx = widget_select_get_value(screen->widgets.boot_device_f);
- if (idx >= (int)sysinfo->n_blockdevs) {
- struct interface_info *info = sysinfo->
- interfaces[idx - sysinfo->n_blockdevs];
- mac_str(info->hwaddr, info->hwaddr_size,
- mac, sizeof(mac));
- uuid = mac;
- } else if (idx != -1) {
- uuid = sysinfo->blockdevs[idx]->uuid;
+ talloc_free(config->autoboot_opts);
+ config->n_autoboot_opts = 0;
+
+ n_boot_opts = widget_subset_get_order(config, &order,
+ screen->widgets.boot_order_f);
+
+ config->autoboot_enabled = n_boot_opts > 0;
+
+ config->n_autoboot_opts = n_boot_opts;
+ config->autoboot_opts = talloc_array(config, struct autoboot_option,
+ n_boot_opts);
+
+ for (i = 0; i < n_boot_opts; i++) {
+ if (order[i] < sysinfo->n_blockdevs) {
+ /* disk uuid */
+ config->autoboot_opts[i].boot_type = BOOT_DEVICE_UUID;
+ config->autoboot_opts[i].uuid = talloc_strdup(config,
+ sysinfo->blockdevs[order[i]]->uuid);
+ } else if(order[i] < (sysinfo->n_blockdevs + sysinfo->n_interfaces)) {
+ /* net uuid */
+ order[i] -= sysinfo->n_blockdevs;
+ config->autoboot_opts[i].boot_type = BOOT_DEVICE_UUID;
+ mac_str(sysinfo->interfaces[order[i]]->hwaddr,
+ sysinfo->interfaces[order[i]]->hwaddr_size,
+ mac, sizeof(mac));
+ config->autoboot_opts[i].uuid = talloc_strdup(config, mac);
+ } else {
+ /* device type */
+ order[i] -= (sysinfo->n_blockdevs + sysinfo->n_interfaces);
+ config->autoboot_opts[i].boot_type = BOOT_DEVICE_TYPE;
+ config->autoboot_opts[i].type = order[i];
}
}
- talloc_free(config->boot_device);
- config->boot_device = uuid ? talloc_strdup(config, uuid) : NULL;
-
str = widget_textbox_get_value(screen->widgets.timeout_f);
if (str) {
unsigned long x;
@@ -367,36 +376,54 @@ static void config_screen_layout_widgets(struct config_screen *screen)
help_x = screen->field_x + 2 +
widget_width(widget_textbox_base(screen->widgets.dns_f));
- y += layout_pair(screen, y, screen->widgets.autoboot_l,
- widget_select_base(screen->widgets.autoboot_f));
+ y += 1;
+
+ wl = widget_label_base(screen->widgets.boot_order_l);
+ widget_set_visible(wl, true);
+ widget_move(wl, y, screen->label_x);
+
+ wf = widget_subset_base(screen->widgets.boot_order_f);
+ widget_move(wf, y, screen->field_x);
+ wl = widget_label_base(screen->widgets.boot_empty_l);
+ widget_move(wl, y, screen->field_x);
- wf = widget_select_base(screen->widgets.boot_device_f);
- if (screen->autoboot_type == AUTOBOOT_ONE) {
+ if (widget_subset_height(screen->widgets.boot_order_f)) {
widget_set_visible(wf, true);
- widget_move(wf, y, screen->field_x + 3);
+ widget_set_visible(wl, false);
y += widget_height(wf);
} else {
+ widget_set_visible(wl, true);
widget_set_visible(wf, false);
+ y += 1;
}
y += 1;
+ widget_move(widget_button_base(screen->widgets.boot_add_b),
+ y, screen->field_x);
+ widget_move(widget_button_base(screen->widgets.boot_any_b),
+ y, screen->field_x + 12);
+ widget_move(widget_button_base(screen->widgets.boot_none_b),
+ y, screen->field_x + 30);
+
+ wf = widget_button_base(screen->widgets.boot_add_b);
+ if (widget_subset_n_inactive(screen->widgets.boot_order_f))
+ widget_set_visible(wf, true);
+ else
+ widget_set_visible(wf, false);
+
+ y += 2;
+
wf = widget_textbox_base(screen->widgets.timeout_f);
wl = widget_label_base(screen->widgets.timeout_l);
wh = widget_label_base(screen->widgets.timeout_help_l);
- if (screen->autoboot_type != AUTOBOOT_DISABLED) {
- widget_set_visible(wl, true);
- widget_set_visible(wf, true);
- widget_set_visible(wh, true);
- widget_move(wl, y, screen->label_x);
- widget_move(wf, y, screen->field_x);
- widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
- y += 2;
- } else {
- widget_set_visible(wl, false);
- widget_set_visible(wf, false);
- widget_set_visible(wh, false);
- }
+ widget_set_visible(wl, screen->autoboot_enabled);
+ widget_set_visible(wf, screen->autoboot_enabled);
+ widget_set_visible(wh, screen->autoboot_enabled);
+ widget_move(wl, y, screen->label_x);
+ widget_move(wf, y, screen->field_x);
+ widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
+ y += 2;
y += layout_pair(screen, y, screen->widgets.network_l,
widget_select_base(screen->widgets.network_f));
@@ -500,15 +527,69 @@ static void config_screen_network_change(void *arg, int value)
widgetset_post(screen->widgetset);
}
-static void config_screen_autoboot_change(void *arg, int value)
+static void config_screen_boot_order_change(void *arg, int value)
+{
+ (void)value;
+ struct config_screen *screen = arg;
+ widgetset_unpost(screen->widgetset);
+ config_screen_layout_widgets(screen);
+ widgetset_post(screen->widgetset);
+}
+
+static void config_screen_add_device(void *arg)
+{
+ struct config_screen *screen = arg;
+
+ screen->show_subset = true;
+ cui_show_subset(screen->cui, _("Select an option"),
+ screen->widgets.boot_order_f);
+}
+
+static void config_screen_autoboot_none(void *arg)
+{
+ struct config_screen *screen = arg;
+ struct nc_widget_subset *subset = screen->widgets.boot_order_f;
+
+ widget_subset_clear_active(subset);
+ screen->autoboot_enabled = false;
+
+ widgetset_unpost(screen->widgetset);
+ config_screen_layout_widgets(screen);
+ widgetset_post(screen->widgetset);
+}
+
+static void config_screen_autoboot_any(void *arg)
{
struct config_screen *screen = arg;
- screen->autoboot_type = value;
+ const struct system_info *sysinfo = screen->cui->sysinfo;
+ struct nc_widget_subset *subset = screen->widgets.boot_order_f;
+ int idx;
+
+ widget_subset_clear_active(subset);
+
+ idx = sysinfo->n_blockdevs + sysinfo->n_interfaces + DEVICE_TYPE_ANY;
+
+ widget_subset_make_active(screen->widgets.boot_order_f, idx);
+
+ screen->autoboot_enabled = true;
+
widgetset_unpost(screen->widgetset);
config_screen_layout_widgets(screen);
widgetset_post(screen->widgetset);
}
+static void config_screen_update_subset(void *arg,
+ struct nc_widget_subset *subset, int idx)
+{
+ struct config_screen *screen = arg;
+
+ if (idx >= 0)
+ widget_subset_make_active(subset, idx);
+ if (!screen->autoboot_enabled)
+ screen->autoboot_enabled = true;
+ config_screen_layout_widgets(screen);
+}
+
static struct interface_config *first_active_interface(
const struct config *config)
{
@@ -550,6 +631,31 @@ static void config_screen_setup_empty(struct config_screen *screen)
cancel_click, screen);
}
+static int find_autoboot_idx(const struct system_info *sysinfo,
+ struct autoboot_option *opt)
+{
+ unsigned int i;
+
+ if (opt->boot_type == BOOT_DEVICE_TYPE)
+ return sysinfo->n_blockdevs + sysinfo->n_interfaces + opt->type;
+
+ for (i = 0; i < sysinfo->n_blockdevs; i++) {
+ if (!strcmp(sysinfo->blockdevs[i]->uuid, opt->uuid))
+ return i;
+ }
+
+ for (i = 0; i < sysinfo->n_interfaces; i++) {
+ struct interface_info *info = sysinfo->interfaces[i];
+ char mac[20];
+
+ mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
+
+ if (!strcmp(mac, opt->uuid))
+ return sysinfo->n_blockdevs + i;
+ }
+
+ return -1;
+}
static void config_screen_setup_widgets(struct config_screen *screen,
const struct config *config,
@@ -560,7 +666,6 @@ static void config_screen_setup_widgets(struct config_screen *screen,
char *str, *ip, *mask, *gw;
enum net_conf_type type;
unsigned int i;
- bool found;
build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
== N_FIELDS);
@@ -568,81 +673,84 @@ static void config_screen_setup_widgets(struct config_screen *screen,
type = screen->net_conf_type;
ifcfg = first_active_interface(config);
- screen->widgets.autoboot_l = widget_new_label(set, 0, 0,
- _("Autoboot:"));
- screen->widgets.autoboot_f = widget_new_select(set, 0, 0, 55);
-
- widget_select_on_change(screen->widgets.autoboot_f,
- config_screen_autoboot_change, screen);
-
- screen->widgets.boot_device_f = widget_new_select(set, 0, 0, 55);
-
- widget_select_add_option(screen->widgets.autoboot_f,
- AUTOBOOT_DISABLED,
- _("Don't autoboot"),
- screen->autoboot_type ==
- AUTOBOOT_DISABLED);
- widget_select_add_option(screen->widgets.autoboot_f,
- AUTOBOOT_ANY,
- _("Autoboot from any "
- "disk/network device"),
- screen->autoboot_type ==
- AUTOBOOT_ANY);
- widget_select_add_option(screen->widgets.autoboot_f,
- AUTOBOOT_ONE,
- _("Only autoboot from a specific "
- "disk/network device"),
- screen->autoboot_type ==
- AUTOBOOT_ONE);
-
- found = false;
+ screen->widgets.boot_add_b = widget_new_button(set, 0, 0, 10,
+ _("Add Device"), config_screen_add_device,
+ screen);
+
+ screen->widgets.boot_none_b = widget_new_button(set, 0, 0, 10,
+ _("Clear"),
+ config_screen_autoboot_none, screen);
+
+ screen->widgets.boot_any_b = widget_new_button(set, 0, 0, 16,
+ _("Clear & Boot Any"), config_screen_autoboot_any,
+ screen);
+
+ screen->widgets.boot_order_l = widget_new_label(set, 0, 0,
+ _("Boot order:"));
+ screen->widgets.boot_order_f = widget_new_subset(set, 0, 0,
+ COLS - screen->field_x,
+ config_screen_update_subset);
+ screen->widgets.boot_empty_l = widget_new_label(set, 0, 0,
+ _("(None)"));
+
+ widget_subset_on_change(screen->widgets.boot_order_f,
+ config_screen_boot_order_change, screen);
for (i = 0; i < sysinfo->n_blockdevs; i++) {
struct blockdev_info *bd = sysinfo->blockdevs[i];
- bool selected;
char *label;
- selected = config->boot_device &&
- !strcmp(config->boot_device, bd->uuid);
- if (selected)
- found = true;
-
label = talloc_asprintf(screen, _("disk: %s [uuid: %s]"),
bd->name, bd->uuid);
- widget_select_add_option(screen->widgets.boot_device_f, i,
- label, selected);
+ widget_subset_add_option(screen->widgets.boot_order_f, label);
}
for (i = 0; i < sysinfo->n_interfaces; i++) {
struct interface_info *info = sysinfo->interfaces[i];
char *label, mac[20];
- bool selected;
mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
- selected = config->boot_device &&
- !strcmp(config->boot_device, mac);
- if (selected)
- found = true;
label = talloc_asprintf(screen, _("net: %s [mac: %s]"),
info->name, mac);
- widget_select_add_option(screen->widgets.boot_device_f,
- i + sysinfo->n_blockdevs,
- label, selected);
+ widget_subset_add_option(screen->widgets.boot_order_f, label);
}
- if (screen->autoboot_type == AUTOBOOT_ONE && !found) {
+ for (i = DEVICE_TYPE_NETWORK; i < DEVICE_TYPE_NETWORK + 4; i++) {
char *label;
- label = talloc_asprintf(screen, _("Unknown UUID: %s"),
- config->boot_device);
+ if (i == DEVICE_TYPE_ANY)
+ label = talloc_asprintf(screen, _("Any Device"));
+ else
+ label = talloc_asprintf(screen, _("Any %s device"),
+ device_type_display_name(i));
- widget_select_add_option(screen->widgets.boot_device_f, -1,
- label, true);
+ widget_subset_add_option(screen->widgets.boot_order_f, label);
}
+ screen->autoboot_enabled = config->n_autoboot_opts;
+ for (i = 0; i < config->n_autoboot_opts; i++) {
+ struct autoboot_option *opt = &config->autoboot_opts[i];
+ int idx;
+
+ idx = find_autoboot_idx(sysinfo, opt);
+
+ if (idx >= 0) {
+ widget_subset_make_active(screen->widgets.boot_order_f,
+ idx);
+ } else {
+ if (opt->boot_type == BOOT_DEVICE_TYPE)
+ pb_log("%s: Unknown autoboot option: %d\n",
+ __func__, opt->type);
+ else
+ pb_log("%s: Unknown autoboot UUID: %s\n",
+ __func__, opt->uuid);
+ }
+ }
+
+
str = talloc_asprintf(screen, "%d", config->autoboot_timeout_sec);
screen->widgets.timeout_l = widget_new_label(set, 0, 0, _("Timeout:"));
screen->widgets.timeout_f = widget_new_textbox(set, 0, 0, 5, str);
@@ -818,12 +926,6 @@ 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)
- screen->autoboot_type = AUTOBOOT_DISABLED;
- else
- screen->autoboot_type = config->boot_device ?
- AUTOBOOT_ONE : AUTOBOOT_ANY;
-
config_screen_setup_widgets(screen, config, sysinfo);
config_screen_layout_widgets(screen);
}
@@ -868,6 +970,8 @@ struct config_screen *config_screen_init(struct cui *cui,
screen->label_x = 2;
screen->field_x = 17;
+ screen->show_subset = false;
+
screen->scr.frame.ltitle = talloc_strdup(screen,
_("Petitboot System Configuration"));
screen->scr.frame.rtitle = NULL;
diff --git a/utils/pb-config.c b/utils/pb-config.c
index 3bd670c..009bec7 100644
--- a/utils/pb-config.c
+++ b/utils/pb-config.c
@@ -61,7 +61,16 @@ 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);
+ unsigned int i;
+
+ for (i = 0; i < config->n_autoboot_opts; i++) {
+ if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE)
+ print_one_config(ctx, var, "bootdev", "%s",
+ device_type_name(config->autoboot_opts[i].type));
+ else
+ print_one_config(ctx, var, "bootdev", "%s",
+ config->autoboot_opts[i].uuid);
+ }
print_one_config(ctx, var, "autoboot", "%s",
config->autoboot_enabled ? "enabled" : "disabled");
print_one_config(ctx, var, "timeout", "%d",
--
2.1.0
More information about the Petitboot
mailing list