+/**
+ * cui_device_add - Client device_add callback
+ *
+ * For ncurses this is only used to specially handle encrypted devices and
+ * create a special device header for them.
+ * Normal devices are handled as part of the cui_boot_option_add() process.
+ */
+static int cui_device_add(struct device *dev, void *arg)
+{
+ struct cui *cui = cui_from_arg(arg);
+ struct pmenu *menu = cui->main;
+ struct pmenu_item *dev_hdr;
+ unsigned int insert_pt, i;
+ struct cui_opt_data *cod;
+ struct blockdev_info *bd;
+ struct system_info *sys;
+ int result, rows, cols;
+ ITEM *selected;
+ char *name;
+
+ /* Nothing to do */
+ if (dev->type != DEVICE_TYPE_LUKS) {
+ pb_log("Ignoring dev %s with type %s\n",
+ dev->id, device_type_display_name(dev->type));
+ return 0;
+ }
+
+ pb_log("Creating header for encrypted device %s\n", dev->id);
+
+ /* Create a dev_hdr for the encrypted device */
+ /* Find block info */
+ sys = cui->sysinfo;
+ name = NULL;
+ for (i = 0; sys && i < sys->n_blockdevs; i++) {
+ bd = sys->blockdevs[i];
+ if (!strcmp(dev->id, bd->name)) {
+ name = talloc_asprintf(menu, "[%s: %s / %s]",
+ device_type_display_name(dev->type),
+ bd->name, bd->uuid);
+ break;
+ }
+ }
+ if (!name) {
+ name = talloc_asprintf(menu, "[%s: \"%s\"]",
+ device_type_display_name(dev->type),
+ dev->id);
+ }
+
+ dev_hdr = pmenu_item_create(menu, name);
+ if (!dev_hdr) {
+ pb_log_fn("Failed to create header item\n");
+ return -1;
+ }
+ talloc_free(name);
+
+ dev_hdr->on_execute = cui_open_luks_device;
+
+ cod = talloc_zero(dev_hdr, struct cui_opt_data);
+ cod->name = talloc_strdup(dev_hdr, dev->id);
+ cod->dev = dev;
+ dev_hdr->data = cod;
+
+ if (cui->current == &cui->main->scr)
+ nc_scr_unpost(cui->current);
+
+ /* This disconnects items array from menu. */
+ result = set_menu_items(menu->ncm, NULL);
+
+ if (result) {
+ pb_log_fn("set_menu_items failed: %d\n", result);
+ return -1;
+ }
+
+ insert_pt = pmenu_grow(menu, 1);
+ pmenu_item_insert(menu, dev_hdr, insert_pt);
+ pb_log("Added header for encrypted device %s\n", dev->id);
+
+ selected = current_item(menu->ncm);
+ menu_format(menu->ncm, &rows, &cols);
+
+ /* Re-attach the items array. */
+ result = set_menu_items(menu->ncm, menu->items);
+
+ if (result)
+ pb_log_fn("set_menu_items failed: %d\n", result);
+
+ if (!item_visible(selected)) {
+ int idx, top;
+
+ top = top_row(menu->ncm);
+ idx = item_index(selected);
+
+ /* If our index is above the current top row, align
+ * us to the new top. Otherwise, align us to the new
+ * bottom */
+ top = top < idx ? idx - rows + 1 : idx;
+
+ set_top_row(menu->ncm, top);
+ set_current_item(menu->ncm, selected);
+ }
+
+ if (cui->current == &menu->scr)
+ nc_scr_post(cui->current);
+
+ return 0;
+}
+