summaryrefslogtreecommitdiffstats
path: root/ui/ncurses
diff options
context:
space:
mode:
Diffstat (limited to 'ui/ncurses')
-rw-r--r--ui/ncurses/nc-cui.c47
-rw-r--r--ui/ncurses/nc-menu.c155
-rw-r--r--ui/ncurses/nc-menu.h4
3 files changed, 197 insertions, 9 deletions
diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
index 1f163b9..9d788fe 100644
--- a/ui/ncurses/nc-cui.c
+++ b/ui/ncurses/nc-cui.c
@@ -405,12 +405,14 @@ static void cui_handle_resize(struct cui *cui)
static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
void *arg)
{
+ struct pmenu_item *i, *dev_hdr = NULL;
struct cui *cui = cui_from_arg(arg);
struct cui_opt_data *cod;
+ const char *tab = " ";
unsigned int insert_pt;
int result, rows, cols;
- struct pmenu_item *i;
ITEM *selected;
+ char *name;
pb_debug("%s: %p %s\n", __func__, opt, opt->id);
@@ -420,9 +422,16 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
if (cui->current == &cui->main->scr)
nc_scr_unpost(cui->current);
- /* Save the item in opt->ui_info for cui_device_remove() */
+ /* Check if the boot device is new */
+ dev_hdr = pmenu_find_device(cui->main, dev, opt);
+
+ /* All actual boot entries are 'tabbed' across */
+ name = talloc_asprintf(cui->main, "%s%s",
+ tab, opt->name ? : "Unknown Name");
- opt->ui_info = i = pmenu_item_create(cui->main, opt->name);
+ /* Save the item in opt->ui_info for cui_device_remove() */
+ opt->ui_info = i = pmenu_item_create(cui->main, name);
+ talloc_free(name);
if (!i)
return -1;
@@ -448,8 +457,16 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
pb_log("%s: set_menu_items failed: %d\n", __func__, result);
/* Insert new items at insert_pt. */
- insert_pt = pmenu_grow(cui->main, 1);
- pmenu_item_insert(cui->main, i, insert_pt);
+ if (dev_hdr) {
+ insert_pt = pmenu_grow(cui->main, 2);
+ pmenu_item_insert(cui->main, dev_hdr, insert_pt);
+ pb_log("%s: adding new device hierarchy %s\n",
+ __func__,opt->device_id);
+ pmenu_item_insert(cui->main, i, insert_pt+1);
+ } else {
+ insert_pt = pmenu_grow(cui->main, 1);
+ pmenu_item_add(cui->main, i, insert_pt);
+ }
pb_log("%s: adding opt '%s'\n", __func__, cod->name);
pb_log(" image '%s'\n", cod->bd->image);
@@ -499,8 +516,9 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
static void cui_device_remove(struct device *dev, void *arg)
{
struct cui *cui = cui_from_arg(arg);
- int result;
struct boot_option *opt;
+ unsigned int i;
+ int result;
pb_log("%s: %p %s\n", __func__, dev, dev->id);
@@ -515,10 +533,21 @@ static void cui_device_remove(struct device *dev, void *arg)
pb_log("%s: set_menu_items failed: %d\n", __func__, result);
list_for_each_entry(&dev->boot_options, opt, list) {
- struct pmenu_item *i = pmenu_item_from_arg(opt->ui_info);
+ struct pmenu_item *item = pmenu_item_from_arg(opt->ui_info);
+
+ assert(pb_protocol_device_cmp(dev, cod_from_item(item)->dev));
+ pmenu_remove(cui->main, item);
+ }
+
+ /* Manually remove remaining device hierarchy item */
+ for (i=0; i < cui->main->item_count; i++) {
+ struct pmenu_item *item = item_userptr(cui->main->items[i]);
+ if (!item || !item->data )
+ continue;
- assert(pb_protocol_device_cmp(dev, cod_from_item(i)->dev));
- pmenu_remove(cui->main, i);
+ struct cui_opt_data *data = item->data;
+ if (data && data->dev && data->dev == dev)
+ pmenu_remove(cui->main,item);
}
/* Re-attach the items array. */
diff --git a/ui/ncurses/nc-menu.c b/ui/ncurses/nc-menu.c
index 7d4442b..a5794f7 100644
--- a/ui/ncurses/nc-menu.c
+++ b/ui/ncurses/nc-menu.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <stdlib.h>
#include <wctype.h>
+#include <util/util.h>
#include "log/log.h"
#include "talloc/talloc.h"
@@ -163,6 +164,160 @@ void pmenu_item_insert(struct pmenu *menu, struct pmenu_item *item,
menu->items[index] = item->nci;
}
+/**
+ * pmenu_item_add - Insert item into appropriate position
+ *
+ * Inserts boot entry under matching, predefined device header entry,
+ * moving items in the list if necessary
+ */
+
+void pmenu_item_add(struct pmenu *menu, struct pmenu_item *item,
+ unsigned int insert_pt)
+{
+ struct cui_opt_data *cod = item->data;
+ bool found = false;
+ unsigned int dev;
+
+ /* Items array should already be disconnected */
+
+ for (dev = 0; dev < menu->item_count; dev++) {
+ if (!menu->items[dev])
+ continue;
+
+ struct pmenu_item *i = item_userptr(menu->items[dev]);
+ struct cui_opt_data *d = i->data;
+ /* Device header will have opt == NULL */
+ if (d && !d->opt) {
+ if (cod->dev == d->dev) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ assert(dev < insert_pt);
+ /* Shift down entries between header and insert_pt */
+ memmove(menu->items + dev + 2, menu->items + dev + 1,
+ ((menu->items + insert_pt) - (menu->items + dev + 1))
+ * sizeof(menu->items[0]));
+ memset(menu->items + dev + 1, 0, sizeof(menu->items[0]));
+ insert_pt = dev + 1;
+ }
+ /* If for some reason we didn't find the matching device,
+ * at least add it to a valid position */
+ pmenu_item_insert(menu, item, insert_pt);
+}
+
+/**
+ * pmenu_find_device - Determine if a boot option is new, and if
+ * so return a new pmenu_item to represent its parent device
+ */
+
+struct pmenu_item *pmenu_find_device(struct pmenu *menu, struct device *dev,
+ struct boot_option *opt)
+{
+ struct pmenu_item *item, *dev_hdr = NULL;
+ struct cui *cui = cui_from_pmenu(menu);
+ bool newdev = true, matched = false;
+ struct interface_info *intf;
+ struct blockdev_info *bd;
+ struct cui_opt_data *cod;
+ struct system_info *sys;
+ char hwaddr[32];
+ unsigned int i;
+ char buf[256];
+
+ for (i = 0; i < menu->item_count; i++) {
+ item = item_userptr(menu->items[i]);
+ cod = item->data;
+ /* boot entries will have opt defined */
+ if (!cod || cod->opt)
+ continue;
+ if (cod->dev == dev) {
+ pb_debug("%s: opt %s fits under %s\n",__func__,
+ opt->name, opt->device_id);
+ newdev = false;
+ break;
+ }
+ }
+
+ if (!newdev) {
+ pb_debug("%s: No new device\n",__func__);
+ return NULL;
+ }
+
+ /* Create a dummy pmenu_item to represent the dev */
+ pb_debug("%s: Building new item\n",__func__);
+ sys = cui->sysinfo;
+ switch (dev->type) {
+ case DEVICE_TYPE_OPTICAL:
+ case DEVICE_TYPE_DISK:
+ /* Find block info */
+ for (i = 0; sys && i < sys->n_blockdevs; i++) {
+ bd = sys->blockdevs[i];
+ if (!strcmp(opt->device_id, bd->name)) {
+ matched = true;
+ break;
+ }
+ }
+ if (matched) {
+ snprintf(buf,sizeof(buf),"[%s: %s / %s]",
+ dev->type == DEVICE_TYPE_DISK ?
+ "Disk" : "CD/DVD",
+ bd->name, bd->uuid);
+ }
+ break;
+
+ case DEVICE_TYPE_NETWORK:
+ /* Find interface info */
+ for (i = 0; sys && i < sys->n_interfaces; i++) {
+ intf = sys->interfaces[i];
+ if (!strcmp(opt->device_id, intf->name)) {
+ matched = true;
+ break;
+ }
+ }
+ if (matched) {
+ mac_str(intf->hwaddr, intf->hwaddr_size,
+ hwaddr, sizeof(hwaddr));
+ snprintf(buf,sizeof(buf),"[Interface %s / %s]",
+ intf->name, hwaddr);
+ }
+ break;
+
+ default:
+ /* Assume the device may be able to boot */
+ break;
+ }
+ if (!matched) {
+ pb_debug("%s: No matching device found for %s (%s)\n",
+ __func__,opt->device_id, dev->id);
+ snprintf(buf,sizeof(buf),"[Unknown Device: %s]",
+ dev->id);
+ }
+
+ dev_hdr = pmenu_item_create(menu, buf);
+ if (!dev_hdr) {
+ pb_log("%s: Failed to create item\n",__func__);
+ return NULL;
+ }
+
+ dev_hdr->on_execute = NULL;
+ item_opts_off(dev_hdr->nci, O_SELECTABLE);
+
+ /* We identify dev_hdr items as having a valid c->name,
+ * but a NULL c->opt */
+ cod = talloc(dev_hdr, struct cui_opt_data);
+ cod->name = talloc_strdup(dev_hdr, opt->device_id);
+ cod->dev = dev;
+ cod->opt = NULL;
+ dev_hdr->data = cod;
+
+ pb_debug("%s: returning %s\n",__func__,cod->name);
+ return dev_hdr;
+}
+
static int pmenu_item_get_index(const struct pmenu_item *item)
{
unsigned int i;
diff --git a/ui/ncurses/nc-menu.h b/ui/ncurses/nc-menu.h
index 8e9c56b..12eafaf 100644
--- a/ui/ncurses/nc-menu.h
+++ b/ui/ncurses/nc-menu.h
@@ -54,8 +54,12 @@ struct pmenu_item {
};
struct pmenu_item *pmenu_item_create(struct pmenu *menu, const char *name);
+struct pmenu_item *pmenu_find_device(struct pmenu *menu, struct device *dev,
+ struct boot_option *opt);
void pmenu_item_insert(struct pmenu *menu, struct pmenu_item *item,
unsigned int index);
+void pmenu_item_add(struct pmenu *menu, struct pmenu_item *item,
+ unsigned int insert_pt);
void pmenu_item_delete(struct pmenu_item *item);
static inline struct pmenu_item *pmenu_item_from_arg(void *arg)
OpenPOWER on IntegriCloud