[PATCH V3] ui/ncurses: Add device hierarchy

Samuel Mendoza-Jonas sam.mj at au1.ibm.com
Wed Jul 16 16:23:59 EST 2014


Boot options are now listed under their matching boot device in the
ncurses UI to help differentitate similar boot option names

Signed-off-by: Samuel Mendoza-Jonas <sam.mj at au1.ibm.com>
---
 ui/ncurses/nc-cui.c  |  47 +++++++++++++---
 ui/ncurses/nc-menu.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/ncurses/nc-menu.h |   4 ++
 3 files changed, 197 insertions(+), 9 deletions(-)

diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
index 7200a81..d7050ee 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)
-- 
1.9.3



More information about the Petitboot mailing list