summaryrefslogtreecommitdiffstats
path: root/src/hci
diff options
context:
space:
mode:
Diffstat (limited to 'src/hci')
-rw-r--r--src/hci/commands/autoboot_cmd.c8
-rw-r--r--src/hci/commands/cert_cmd.c19
-rw-r--r--src/hci/commands/config_cmd.c6
-rw-r--r--src/hci/commands/console_cmd.c18
-rw-r--r--src/hci/commands/dhcp_cmd.c13
-rw-r--r--src/hci/commands/digest_cmd.c92
-rw-r--r--src/hci/commands/dynui_cmd.c (renamed from src/hci/commands/menu_cmd.c)212
-rw-r--r--src/hci/commands/efimap_cmd.c7
-rw-r--r--src/hci/commands/fcmgmt_cmd.c12
-rw-r--r--src/hci/commands/fdt_cmd.c91
-rw-r--r--src/hci/commands/gdbstub_cmd.c7
-rw-r--r--src/hci/commands/ibmgmt_cmd.c7
-rw-r--r--src/hci/commands/ifmgmt_cmd.c28
-rw-r--r--src/hci/commands/image_archive_cmd.c7
-rw-r--r--src/hci/commands/image_cmd.c72
-rw-r--r--src/hci/commands/image_crypt_cmd.c120
-rw-r--r--src/hci/commands/image_mem_cmd.c10
-rw-r--r--src/hci/commands/image_trust_cmd.c14
-rw-r--r--src/hci/commands/ipstat_cmd.c8
-rw-r--r--src/hci/commands/iwmgmt_cmd.c12
-rw-r--r--src/hci/commands/login_cmd.c6
-rw-r--r--src/hci/commands/lotest_cmd.c5
-rw-r--r--src/hci/commands/neighbour_cmd.c8
-rw-r--r--src/hci/commands/nslookup_cmd.c6
-rw-r--r--src/hci/commands/ntp_cmd.c6
-rw-r--r--src/hci/commands/nvo_cmd.c28
-rw-r--r--src/hci/commands/param_cmd.c13
-rw-r--r--src/hci/commands/pci_cmd.c9
-rw-r--r--src/hci/commands/ping_cmd.c6
-rw-r--r--src/hci/commands/poweroff_cmd.c6
-rw-r--r--src/hci/commands/profstat_cmd.c8
-rw-r--r--src/hci/commands/reboot_cmd.c17
-rw-r--r--src/hci/commands/route_cmd.c8
-rw-r--r--src/hci/commands/sanboot_cmd.c18
-rw-r--r--src/hci/commands/shim_cmd.c8
-rw-r--r--src/hci/commands/sync_cmd.c6
-rw-r--r--src/hci/commands/time_cmd.c6
-rw-r--r--src/hci/commands/usb_cmd.c119
-rw-r--r--src/hci/commands/vlan_cmd.c13
-rw-r--r--src/hci/editstring.c154
-rw-r--r--src/hci/jumpscroll.c76
-rw-r--r--src/hci/keymap/keymap_al.c1
-rw-r--r--src/hci/keymap/keymap_by.c1
-rw-r--r--src/hci/keymap/keymap_cf.c1
-rw-r--r--src/hci/keymap/keymap_cz.c1
-rw-r--r--src/hci/keymap/keymap_de.c1
-rw-r--r--src/hci/keymap/keymap_dk.c1
-rw-r--r--src/hci/keymap/keymap_es.c1
-rw-r--r--src/hci/keymap/keymap_et.c1
-rw-r--r--src/hci/keymap/keymap_fi.c1
-rw-r--r--src/hci/keymap/keymap_fr.c1
-rw-r--r--src/hci/keymap/keymap_gr.c1
-rw-r--r--src/hci/keymap/keymap_hu.c1
-rw-r--r--src/hci/keymap/keymap_il.c1
-rw-r--r--src/hci/keymap/keymap_it.c1
-rw-r--r--src/hci/keymap/keymap_lt.c1
-rw-r--r--src/hci/keymap/keymap_mk.c1
-rw-r--r--src/hci/keymap/keymap_mt.c1
-rw-r--r--src/hci/keymap/keymap_nl.c1
-rw-r--r--src/hci/keymap/keymap_no-latin1.c1
-rw-r--r--src/hci/keymap/keymap_no.c1
-rw-r--r--src/hci/keymap/keymap_pl.c1
-rw-r--r--src/hci/keymap/keymap_pt.c1
-rw-r--r--src/hci/keymap/keymap_ro.c1
-rw-r--r--src/hci/keymap/keymap_ru.c1
-rw-r--r--src/hci/keymap/keymap_se.c1
-rw-r--r--src/hci/keymap/keymap_sg.c1
-rw-r--r--src/hci/keymap/keymap_sr-latin.c1
-rw-r--r--src/hci/keymap/keymap_ua.c1
-rw-r--r--src/hci/keymap/keymap_uk.c1
-rw-r--r--src/hci/keymap/keymap_us.c1
-rw-r--r--src/hci/mucurses/ansi_screen.c1
-rw-r--r--src/hci/mucurses/clear.c1
-rw-r--r--src/hci/mucurses/cursor.h1
-rw-r--r--src/hci/mucurses/mucurses.c1
-rw-r--r--src/hci/mucurses/mucurses.h1
-rw-r--r--src/hci/mucurses/print.c1
-rw-r--r--src/hci/mucurses/widgets/editbox.c69
-rw-r--r--src/hci/mucurses/winattrs.c1
-rw-r--r--src/hci/mucurses/wininit.c1
-rw-r--r--src/hci/readline.c49
-rw-r--r--src/hci/shell.c11
-rw-r--r--src/hci/strerror.c1
-rw-r--r--src/hci/tui/form_ui.c545
-rw-r--r--src/hci/tui/login_ui.c152
-rw-r--r--src/hci/tui/menu_ui.c126
-rw-r--r--src/hci/tui/message.c110
-rw-r--r--src/hci/tui/settings_ui.c150
88 files changed, 1681 insertions, 859 deletions
diff --git a/src/hci/commands/autoboot_cmd.c b/src/hci/commands/autoboot_cmd.c
index 56f39a1ce..a61333a9d 100644
--- a/src/hci/commands/autoboot_cmd.c
+++ b/src/hci/commands/autoboot_cmd.c
@@ -30,6 +30,7 @@
#include <usr/autoboot.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -73,9 +74,4 @@ static int autoboot_exec ( int argc, char **argv ) {
}
/** Booting commands */
-struct command autoboot_commands[] __command = {
- {
- .name = "autoboot",
- .exec = autoboot_exec,
- },
-};
+COMMAND ( autoboot, autoboot_exec );
diff --git a/src/hci/commands/cert_cmd.c b/src/hci/commands/cert_cmd.c
index 24b18bf5c..ebd9a25cd 100644
--- a/src/hci/commands/cert_cmd.c
+++ b/src/hci/commands/cert_cmd.c
@@ -22,8 +22,10 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
+#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/x509.h>
@@ -288,17 +290,6 @@ static int certfree_exec ( int argc, char **argv ) {
}
/** Certificate management commands */
-struct command certmgmt_commands[] __command = {
- {
- .name = "certstat",
- .exec = certstat_exec,
- },
- {
- .name = "certstore",
- .exec = certstore_exec,
- },
- {
- .name = "certfree",
- .exec = certfree_exec,
- },
-};
+COMMAND ( certstat, certstat_exec );
+COMMAND ( certstore, certstore_exec );
+COMMAND ( certfree, certfree_exec );
diff --git a/src/hci/commands/config_cmd.c b/src/hci/commands/config_cmd.c
index ad415e045..cc21ad3fe 100644
--- a/src/hci/commands/config_cmd.c
+++ b/src/hci/commands/config_cmd.c
@@ -31,6 +31,7 @@
#include <ipxe/settings_ui.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -79,7 +80,4 @@ static int config_exec ( int argc, char **argv ) {
}
/** Configuration UI commands */
-struct command config_command __command = {
- .name = "config",
- .exec = config_exec,
-};
+COMMAND ( config, config_exec );
diff --git a/src/hci/commands/console_cmd.c b/src/hci/commands/console_cmd.c
index bd5647261..479e14efc 100644
--- a/src/hci/commands/console_cmd.c
+++ b/src/hci/commands/console_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -253,17 +254,6 @@ static int cpair_exec ( int argc, char **argv ) {
}
/** Console management commands */
-struct command console_commands[] __command = {
- {
- .name = "console",
- .exec = console_exec,
- },
- {
- .name = "colour",
- .exec = colour_exec,
- },
- {
- .name = "cpair",
- .exec = cpair_exec,
- },
-};
+COMMAND ( console, console_exec );
+COMMAND ( colour, colour_exec );
+COMMAND ( cpair, cpair_exec );
diff --git a/src/hci/commands/dhcp_cmd.c b/src/hci/commands/dhcp_cmd.c
index 45a922b51..ccc115b87 100644
--- a/src/hci/commands/dhcp_cmd.c
+++ b/src/hci/commands/dhcp_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <stdint.h>
@@ -92,13 +93,5 @@ static int pxebs_exec ( int argc, char **argv ) {
}
/** DHCP management commands */
-struct command dhcp_commands[] __command = {
- {
- .name = "dhcp",
- .exec = ifconf_exec, /* synonym for "ifconf" */
- },
- {
- .name = "pxebs",
- .exec = pxebs_exec,
- },
-};
+COMMAND ( dhcp, ifconf_exec ); /* synonym for "ifconf" */
+COMMAND ( pxebs, pxebs_exec );
diff --git a/src/hci/commands/digest_cmd.c b/src/hci/commands/digest_cmd.c
index 71308064f..4d7da0385 100644
--- a/src/hci/commands/digest_cmd.c
+++ b/src/hci/commands/digest_cmd.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <string.h>
@@ -26,10 +27,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/image.h>
+#include <ipxe/settings.h>
#include <ipxe/crypto.h>
#include <ipxe/md5.h>
#include <ipxe/sha1.h>
#include <usr/imgmgmt.h>
+#include <hci/digest_cmd.h>
/** @file
*
@@ -38,10 +41,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/** "digest" options */
-struct digest_options {};
+struct digest_options {
+ /** Setting */
+ struct named_setting setting;
+};
/** "digest" option list */
-static struct option_descriptor digest_opts[] = {};
+static struct option_descriptor digest_opts[] = {
+ OPTION_DESC ( "set", 's', required_argument, struct digest_options,
+ setting, parse_autovivified_setting ),
+};
/** "digest" command descriptor */
static struct command_descriptor digest_cmd =
@@ -56,54 +65,62 @@ static struct command_descriptor digest_cmd =
* @v digest Digest algorithm
* @ret rc Return status code
*/
-static int digest_exec ( int argc, char **argv,
- struct digest_algorithm *digest ) {
+int digest_exec ( int argc, char **argv, struct digest_algorithm *digest ) {
struct digest_options opts;
struct image *image;
- uint8_t digest_ctx[digest->ctxsize];
- uint8_t digest_out[digest->digestsize];
- uint8_t buf[128];
- size_t offset;
- size_t len;
- size_t frag_len;
+ uint8_t ctx[digest->ctxsize];
+ uint8_t out[digest->digestsize];
+ unsigned int j;
int i;
- unsigned j;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &digest_cmd, &opts ) ) != 0 )
return rc;
+ /* Use default setting type, if not specified */
+ if ( ! opts.setting.setting.type )
+ opts.setting.setting.type = &setting_type_hexraw;
+
+ /* Calculate digests for each image */
for ( i = optind ; i < argc ; i++ ) {
/* Acquire image */
if ( ( rc = imgacquire ( argv[i], 0, &image ) ) != 0 )
- continue;
- offset = 0;
- len = image->len;
-
- /* calculate digest */
- digest_init ( digest, digest_ctx );
- while ( len ) {
- frag_len = len;
- if ( frag_len > sizeof ( buf ) )
- frag_len = sizeof ( buf );
- copy_from_user ( buf, image->data, offset, frag_len );
- digest_update ( digest, digest_ctx, buf, frag_len );
- len -= frag_len;
- offset += frag_len;
+ return rc;
+
+ /* Calculate digest */
+ digest_init ( digest, ctx );
+ digest_update ( digest, ctx, image->data, image->len );
+ digest_final ( digest, ctx, out );
+
+ /* Display or store digest as directed */
+ if ( opts.setting.settings ) {
+
+ /* Store digest */
+ if ( ( rc = store_setting ( opts.setting.settings,
+ &opts.setting.setting, out,
+ sizeof ( out ) ) ) != 0 ) {
+ printf ( "Could not store \"%s\": %s\n",
+ opts.setting.setting.name,
+ strerror ( rc ) );
+ return rc;
+ }
+
+ } else {
+
+ /* Print digest */
+ for ( j = 0 ; j < sizeof ( out ) ; j++ )
+ printf ( "%02x", out[j] );
+ printf ( " %s\n", image->name );
}
- digest_final ( digest, digest_ctx, digest_out );
-
- for ( j = 0 ; j < sizeof ( digest_out ) ; j++ )
- printf ( "%02x", digest_out[j] );
-
- printf ( " %s\n", image->name );
}
return 0;
}
+/* Include "md5sum" and "sha1sum" commands unconditionally */
+
static int md5sum_exec ( int argc, char **argv ) {
return digest_exec ( argc, argv, &md5_algorithm );
}
@@ -112,12 +129,9 @@ static int sha1sum_exec ( int argc, char **argv ) {
return digest_exec ( argc, argv, &sha1_algorithm );
}
-struct command md5sum_command __command = {
- .name = "md5sum",
- .exec = md5sum_exec,
-};
+COMMAND ( md5sum, md5sum_exec );
+COMMAND ( sha1sum, sha1sum_exec );
-struct command sha1sum_command __command = {
- .name = "sha1sum",
- .exec = sha1sum_exec,
-};
+/* Drag in commands for any other enabled algorithms */
+REQUIRING_SYMBOL ( digest_exec );
+REQUIRE_OBJECT ( config_digest_cmd );
diff --git a/src/hci/commands/menu_cmd.c b/src/hci/commands/dynui_cmd.c
index c8692f1a7..b70211050 100644
--- a/src/hci/commands/menu_cmd.c
+++ b/src/hci/commands/dynui_cmd.c
@@ -22,10 +22,11 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
- * Menu commands
+ * Dynamic user interface commands
*
*/
@@ -34,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <getopt.h>
-#include <ipxe/menu.h>
+#include <ipxe/dynui.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/settings.h>
@@ -42,42 +43,42 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FEATURE ( FEATURE_MISC, "Menu", DHCP_EB_FEATURE_MENU, 1 );
-/** "menu" options */
-struct menu_options {
+/** "dynui" options */
+struct dynui_options {
/** Name */
char *name;
/** Delete */
int delete;
};
-/** "menu" option list */
-static struct option_descriptor menu_opts[] = {
+/** "dynui" option list */
+static struct option_descriptor dynui_opts[] = {
OPTION_DESC ( "name", 'n', required_argument,
- struct menu_options, name, parse_string ),
+ struct dynui_options, name, parse_string ),
OPTION_DESC ( "delete", 'd', no_argument,
- struct menu_options, delete, parse_flag ),
+ struct dynui_options, delete, parse_flag ),
};
-/** "menu" command descriptor */
-static struct command_descriptor menu_cmd =
- COMMAND_DESC ( struct menu_options, menu_opts, 0, MAX_ARGUMENTS,
+/** "dynui" command descriptor */
+static struct command_descriptor dynui_cmd =
+ COMMAND_DESC ( struct dynui_options, dynui_opts, 0, MAX_ARGUMENTS,
"[<title>]" );
/**
- * The "menu" command
+ * The "dynui" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
-static int menu_exec ( int argc, char **argv ) {
- struct menu_options opts;
- struct menu *menu;
+static int dynui_exec ( int argc, char **argv ) {
+ struct dynui_options opts;
+ struct dynamic_ui *dynui;
char *title;
int rc;
/* Parse options */
- if ( ( rc = parse_options ( argc, argv, &menu_cmd, &opts ) ) != 0 )
+ if ( ( rc = parse_options ( argc, argv, &dynui_cmd, &opts ) ) != 0 )
goto err_parse_options;
/* Parse title */
@@ -87,21 +88,21 @@ static int menu_exec ( int argc, char **argv ) {
goto err_parse_title;
}
- /* Create menu */
- menu = create_menu ( opts.name, title );
- if ( ! menu ) {
+ /* Create dynamic user interface */
+ dynui = create_dynui ( opts.name, title );
+ if ( ! dynui ) {
rc = -ENOMEM;
- goto err_create_menu;
+ goto err_create_dynui;
}
- /* Destroy menu, if applicable */
+ /* Destroy dynamic user interface, if applicable */
if ( opts.delete )
- destroy_menu ( menu );
+ destroy_dynui ( dynui );
/* Success */
rc = 0;
- err_create_menu:
+ err_create_dynui:
free ( title );
err_parse_title:
err_parse_options:
@@ -110,12 +111,14 @@ static int menu_exec ( int argc, char **argv ) {
/** "item" options */
struct item_options {
- /** Menu name */
- char *menu;
+ /** Dynamic user interface name */
+ char *dynui;
/** Shortcut key */
unsigned int key;
/** Use as default */
int is_default;
+ /** Value is a secret */
+ int is_secret;
/** Use as a separator */
int is_gap;
/** Don't show; hotkey only */
@@ -125,11 +128,15 @@ struct item_options {
/** "item" option list */
static struct option_descriptor item_opts[] = {
OPTION_DESC ( "menu", 'm', required_argument,
- struct item_options, menu, parse_string ),
+ struct item_options, dynui, parse_string ),
+ OPTION_DESC ( "form", 'f', required_argument,
+ struct item_options, dynui, parse_string ),
OPTION_DESC ( "key", 'k', required_argument,
struct item_options, key, parse_key ),
OPTION_DESC ( "default", 'd', no_argument,
struct item_options, is_default, parse_flag ),
+ OPTION_DESC ( "secret", 's', no_argument,
+ struct item_options, is_secret, parse_flag ),
OPTION_DESC ( "gap", 'g', no_argument,
struct item_options, is_gap, parse_flag ),
OPTION_DESC ( "hidden", 'i', no_argument,
@@ -139,7 +146,7 @@ static struct option_descriptor item_opts[] = {
/** "item" command descriptor */
static struct command_descriptor item_cmd =
COMMAND_DESC ( struct item_options, item_opts, 0, MAX_ARGUMENTS,
- "[<label> [<text>]]" );
+ "[<name> [<text>]]" );
/**
* The "item" command
@@ -150,9 +157,10 @@ static struct command_descriptor item_cmd =
*/
static int item_exec ( int argc, char **argv ) {
struct item_options opts;
- struct menu *menu;
- struct menu_item *item;
- char *label = NULL;
+ struct dynamic_ui *dynui;
+ struct dynamic_item *item;
+ unsigned int flags = 0;
+ char *name = NULL;
char *text = NULL;
int rc;
@@ -160,12 +168,12 @@ static int item_exec ( int argc, char **argv ) {
if ( ( rc = parse_options ( argc, argv, &item_cmd, &opts ) ) != 0 )
goto err_parse_options;
- /* Parse label, if present */
+ /* Parse name, if present */
if ( ! opts.is_gap )
- label = argv[optind++]; /* May be NULL */
+ name = argv[optind++]; /* May be NULL */
/* Hidden entry without label and shortcut is pointless */
- if ( opts.is_hidden && ( ! opts.key || ! label || ! *label ) ) {
+ if ( opts.is_hidden && ( ! opts.key || ! name || ! *name ) ) {
rc = -EINVAL;
goto err_invalid_argument;
}
@@ -179,23 +187,29 @@ static int item_exec ( int argc, char **argv ) {
}
}
- /* Identify menu */
- if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 )
- goto err_parse_menu;
-
- /* Add menu item */
- item = add_menu_item ( menu, label, ( text ? text : "" ),
- opts.key, opts.is_default, opts.is_hidden );
+ /* Identify dynamic user interface */
+ if ( ( rc = parse_dynui ( opts.dynui, &dynui ) ) != 0 )
+ goto err_parse_dynui;
+
+ /* Add dynamic user interface item */
+ if ( opts.is_default )
+ flags |= DYNUI_DEFAULT;
+ if ( opts.is_secret )
+ flags |= DYNUI_SECRET;
+ if ( opts.is_hidden )
+ flags |= DYNUI_HIDDEN;
+ item = add_dynui_item ( dynui, name, ( text ? text : "" ), flags,
+ opts.key );
if ( ! item ) {
rc = -ENOMEM;
- goto err_add_menu_item;
+ goto err_add_dynui_item;
}
/* Success */
rc = 0;
- err_add_menu_item:
- err_parse_menu:
+ err_add_dynui_item:
+ err_parse_dynui:
free ( text );
err_parse_text:
err_invalid_argument:
@@ -205,24 +219,28 @@ static int item_exec ( int argc, char **argv ) {
/** "choose" options */
struct choose_options {
- /** Menu name */
- char *menu;
- /** Timeout */
+ /** Dynamic user interface name */
+ char *dynui;
+ /** Initial timeout */
unsigned long timeout;
+ /** Post-activity timeout */
+ unsigned long retimeout;
/** Default selection */
char *select;
- /** Keep menu */
+ /** Keep dynamic user interface */
int keep;
};
/** "choose" option list */
static struct option_descriptor choose_opts[] = {
OPTION_DESC ( "menu", 'm', required_argument,
- struct choose_options, menu, parse_string ),
+ struct choose_options, dynui, parse_string ),
OPTION_DESC ( "default", 'd', required_argument,
struct choose_options, select, parse_string ),
OPTION_DESC ( "timeout", 't', required_argument,
struct choose_options, timeout, parse_timeout ),
+ OPTION_DESC ( "retimeout", 'r', required_argument,
+ struct choose_options, retimeout, parse_timeout ),
OPTION_DESC ( "keep", 'k', no_argument,
struct choose_options, keep, parse_flag ),
};
@@ -241,8 +259,8 @@ static struct command_descriptor choose_cmd =
static int choose_exec ( int argc, char **argv ) {
struct choose_options opts;
struct named_setting setting;
- struct menu *menu;
- struct menu_item *item;
+ struct dynamic_ui *dynui;
+ struct dynamic_item *item;
int rc;
/* Parse options */
@@ -254,12 +272,13 @@ static int choose_exec ( int argc, char **argv ) {
&setting ) ) != 0 )
goto err_parse_setting;
- /* Identify menu */
- if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 )
- goto err_parse_menu;
+ /* Identify dynamic user interface */
+ if ( ( rc = parse_dynui ( opts.dynui, &dynui ) ) != 0 )
+ goto err_parse_dynui;
- /* Show menu */
- if ( ( rc = show_menu ( menu, opts.timeout, opts.select, &item ) ) != 0)
+ /* Show as menu */
+ if ( ( rc = show_menu ( dynui, opts.timeout, opts.retimeout,
+ opts.select, &item ) ) != 0 )
goto err_show_menu;
/* Apply default type if necessary */
@@ -268,7 +287,7 @@ static int choose_exec ( int argc, char **argv ) {
/* Store setting */
if ( ( rc = storef_setting ( setting.settings, &setting.setting,
- item->label ) ) != 0 ) {
+ item->name ) ) != 0 ) {
printf ( "Could not store \"%s\": %s\n",
setting.setting.name, strerror ( rc ) );
goto err_store;
@@ -279,27 +298,74 @@ static int choose_exec ( int argc, char **argv ) {
err_store:
err_show_menu:
- /* Destroy menu, if applicable */
+ /* Destroy dynamic user interface, if applicable */
if ( ! opts.keep )
- destroy_menu ( menu );
- err_parse_menu:
+ destroy_dynui ( dynui );
+ err_parse_dynui:
err_parse_setting:
err_parse_options:
return rc;
}
-/** Menu commands */
-struct command menu_commands[] __command = {
- {
- .name = "menu",
- .exec = menu_exec,
- },
- {
- .name = "item",
- .exec = item_exec,
- },
- {
- .name = "choose",
- .exec = choose_exec,
- },
+/** "present" options */
+struct present_options {
+ /** Dynamic user interface name */
+ char *dynui;
+ /** Keep dynamic user interface */
+ int keep;
};
+
+/** "present" option list */
+static struct option_descriptor present_opts[] = {
+ OPTION_DESC ( "form", 'f', required_argument,
+ struct present_options, dynui, parse_string ),
+ OPTION_DESC ( "keep", 'k', no_argument,
+ struct present_options, keep, parse_flag ),
+};
+
+/** "present" command descriptor */
+static struct command_descriptor present_cmd =
+ COMMAND_DESC ( struct present_options, present_opts, 0, 0, NULL );
+
+/**
+ * The "present" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+static int present_exec ( int argc, char **argv ) {
+ struct present_options opts;
+ struct dynamic_ui *dynui;
+ int rc;
+
+ /* Parse options */
+ if ( ( rc = parse_options ( argc, argv, &present_cmd, &opts ) ) != 0 )
+ goto err_parse_options;
+
+ /* Identify dynamic user interface */
+ if ( ( rc = parse_dynui ( opts.dynui, &dynui ) ) != 0 )
+ goto err_parse_dynui;
+
+ /* Show as form */
+ if ( ( rc = show_form ( dynui ) ) != 0 )
+ goto err_show_form;
+
+ /* Success */
+ rc = 0;
+
+ err_show_form:
+ /* Destroy dynamic user interface, if applicable */
+ if ( ! opts.keep )
+ destroy_dynui ( dynui );
+ err_parse_dynui:
+ err_parse_options:
+ return rc;
+}
+
+/** Dynamic user interface commands */
+COMMAND ( menu, dynui_exec );
+COMMAND ( form, dynui_exec );
+COMMAND ( item, item_exec );
+COMMAND ( choose, choose_exec );
+COMMAND ( present, present_exec );
diff --git a/src/hci/commands/efimap_cmd.c b/src/hci/commands/efimap_cmd.c
index c183cbc30..7e8bdb19f 100644
--- a/src/hci/commands/efimap_cmd.c
+++ b/src/hci/commands/efimap_cmd.c
@@ -69,9 +69,4 @@ static int efimap_exec ( int argc, char **argv ) {
}
/** EFIMAP command */
-struct command efimap_commands[] __command = {
- {
- .name = "efimap",
- .exec = efimap_exec,
- },
-};
+COMMAND ( efimap, efimap_exec );
diff --git a/src/hci/commands/fcmgmt_cmd.c b/src/hci/commands/fcmgmt_cmd.c
index 97f10f4dd..c03ebb05f 100644
--- a/src/hci/commands/fcmgmt_cmd.c
+++ b/src/hci/commands/fcmgmt_cmd.c
@@ -207,13 +207,5 @@ static int fcels_exec ( int argc, char **argv ) {
}
/** Fibre Channel management commands */
-struct command fcmgmt_commands[] __command = {
- {
- .name = "fcstat",
- .exec = fcstat_exec,
- },
- {
- .name = "fcels",
- .exec = fcels_exec,
- },
-};
+COMMAND ( fcstat, fcstat_exec );
+COMMAND ( fcels, fcels_exec );
diff --git a/src/hci/commands/fdt_cmd.c b/src/hci/commands/fdt_cmd.c
new file mode 100644
index 000000000..7cd39279b
--- /dev/null
+++ b/src/hci/commands/fdt_cmd.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+#include <usr/fdtmgmt.h>
+
+/** @file
+ *
+ * Flattened Device Tree commands
+ *
+ */
+
+/** "fdt" options */
+struct fdt_options {
+ /** Download timeout */
+ unsigned long timeout;
+};
+
+/** "fdt" option list */
+static struct option_descriptor fdt_opts[] = {
+ OPTION_DESC ( "timeout", 't', required_argument,
+ struct fdt_options, timeout, parse_timeout ),
+};
+
+/** "fdt" command descriptor */
+static struct command_descriptor fdt_cmd =
+ COMMAND_DESC ( struct fdt_options, fdt_opts, 0, 1, "[<uri>]" );
+
+/**
+ * The "fdt" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+static int fdt_exec ( int argc, char **argv ) {
+ struct fdt_options opts;
+ struct image *image = NULL;
+ char *name_uri;
+ int rc;
+
+ /* Parse options */
+ if ( ( rc = parse_options ( argc, argv, &fdt_cmd, &opts ) ) != 0 )
+ goto err_parse;
+
+ /* Parse name/URI string */
+ name_uri = argv[optind];
+
+ /* Acquire image, if applicable */
+ if ( name_uri && ( ( rc = imgacquire ( name_uri, opts.timeout,
+ &image ) ) != 0 ) ) {
+ goto err_image;
+ }
+
+ /* (Un)register as FDT */
+ if ( ( rc = imgfdt ( image ) ) != 0 )
+ goto err_fdt;
+
+ err_fdt:
+ err_image:
+ err_parse:
+ return rc;
+}
+
+/** Flattened Device Tree commands */
+COMMAND ( fdt, fdt_exec );
diff --git a/src/hci/commands/gdbstub_cmd.c b/src/hci/commands/gdbstub_cmd.c
index c4a831e7a..ba5edde3a 100644
--- a/src/hci/commands/gdbstub_cmd.c
+++ b/src/hci/commands/gdbstub_cmd.c
@@ -107,9 +107,4 @@ static int gdbstub_exec ( int argc, char **argv ) {
}
/** GDB stub commands */
-struct command gdbstub_commands[] __command = {
- {
- .name = "gdbstub",
- .exec = gdbstub_exec,
- },
-};
+COMMAND ( gdbstub, gdbstub_exec );
diff --git a/src/hci/commands/ibmgmt_cmd.c b/src/hci/commands/ibmgmt_cmd.c
index 1154d749e..be8b58cc2 100644
--- a/src/hci/commands/ibmgmt_cmd.c
+++ b/src/hci/commands/ibmgmt_cmd.c
@@ -71,9 +71,4 @@ static int ibstat_exec ( int argc, char **argv ) {
}
/** Infiniband commands */
-struct command ibmgmt_commands[] __command = {
- {
- .name = "ibstat",
- .exec = ibstat_exec,
- },
-};
+COMMAND ( ibstat, ibstat_exec );
diff --git a/src/hci/commands/ifmgmt_cmd.c b/src/hci/commands/ifmgmt_cmd.c
index 591cb3da8..f4b9fef3a 100644
--- a/src/hci/commands/ifmgmt_cmd.c
+++ b/src/hci/commands/ifmgmt_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <errno.h>
@@ -303,25 +304,8 @@ static int iflinkwait_exec ( int argc, char **argv ) {
}
/** Interface management commands */
-struct command ifmgmt_commands[] __command = {
- {
- .name = "ifopen",
- .exec = ifopen_exec,
- },
- {
- .name = "ifclose",
- .exec = ifclose_exec,
- },
- {
- .name = "ifstat",
- .exec = ifstat_exec,
- },
- {
- .name = "ifconf",
- .exec = ifconf_exec,
- },
- {
- .name = "iflinkwait",
- .exec = iflinkwait_exec,
- },
-};
+COMMAND ( ifopen, ifopen_exec );
+COMMAND ( ifclose, ifclose_exec );
+COMMAND ( ifstat, ifstat_exec );
+COMMAND ( ifconf, ifconf_exec );
+COMMAND ( iflinkwait, iflinkwait_exec );
diff --git a/src/hci/commands/image_archive_cmd.c b/src/hci/commands/image_archive_cmd.c
index a2212aecf..6b907830e 100644
--- a/src/hci/commands/image_archive_cmd.c
+++ b/src/hci/commands/image_archive_cmd.c
@@ -97,9 +97,4 @@ static int imgextract_exec ( int argc, char **argv ) {
}
/** Archive image commands */
-struct command image_archive_commands[] __command = {
- {
- .name = "imgextract",
- .exec = imgextract_exec,
- },
-};
+COMMAND ( imgextract, imgextract_exec );
diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c
index bf97b4deb..aaed0ea9b 100644
--- a/src/hci/commands/image_cmd.c
+++ b/src/hci/commands/image_cmd.c
@@ -22,10 +22,12 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/image.h>
@@ -392,54 +394,22 @@ static int imgfree_exec ( int argc, char **argv ) {
return imgmulti_exec ( argc, argv, unregister_image );
}
-/** Image management commands */
-struct command image_commands[] __command = {
- {
- .name = "imgfetch",
- .exec = imgfetch_exec,
- },
- {
- .name = "module",
- .exec = imgfetch_exec, /* synonym for "imgfetch" */
- },
- {
- .name = "initrd",
- .exec = imgfetch_exec, /* synonym for "imgfetch" */
- },
- {
- .name = "kernel",
- .exec = imgselect_exec, /* synonym for "imgselect" */
- },
- {
- .name = "chain",
- .exec = imgexec_exec, /* synonym for "imgexec" */
- },
- {
- .name = "imgselect",
- .exec = imgselect_exec,
- },
- {
- .name = "imgload",
- .exec = imgselect_exec, /* synonym for "imgselect" */
- },
- {
- .name = "imgargs",
- .exec = imgargs_exec,
- },
- {
- .name = "imgexec",
- .exec = imgexec_exec,
- },
- {
- .name = "boot", /* synonym for "imgexec" */
- .exec = imgexec_exec,
- },
- {
- .name = "imgstat",
- .exec = imgstat_exec,
- },
- {
- .name = "imgfree",
- .exec = imgfree_exec,
- },
-};
+/* "imgfetch" and synonyms */
+COMMAND ( imgfetch, imgfetch_exec );
+COMMAND ( module, imgfetch_exec );
+COMMAND ( initrd, imgfetch_exec );
+
+/* "imgselect" and synonyms */
+COMMAND ( imgselect, imgselect_exec );
+COMMAND ( imgload, imgselect_exec );
+COMMAND ( kernel, imgselect_exec );
+
+/* "imgexec" and synonyms */
+COMMAND ( imgexec, imgexec_exec );
+COMMAND ( chain, imgexec_exec );
+COMMAND ( boot, imgexec_exec );
+
+/* Other image management commands */
+COMMAND ( imgargs, imgargs_exec );
+COMMAND ( imgstat, imgstat_exec );
+COMMAND ( imgfree, imgfree_exec );
diff --git a/src/hci/commands/image_crypt_cmd.c b/src/hci/commands/image_crypt_cmd.c
new file mode 100644
index 000000000..54568cc28
--- /dev/null
+++ b/src/hci/commands/image_crypt_cmd.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <ipxe/image.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+#include <usr/imgcrypt.h>
+
+/** @file
+ *
+ * Image encryption management commands
+ *
+ */
+
+/** "imgdecrypt" options */
+struct imgdecrypt_options {
+ /** Decrypted image name */
+ char *name;
+ /** Keep envelope after decryption */
+ int keep;
+ /** Download timeout */
+ unsigned long timeout;
+};
+
+/** "imgdecrypt" option list */
+static struct option_descriptor imgdecrypt_opts[] = {
+ OPTION_DESC ( "name", 'n', required_argument,
+ struct imgdecrypt_options, name, parse_string ),
+ OPTION_DESC ( "keep", 'k', no_argument,
+ struct imgdecrypt_options, keep, parse_flag ),
+ OPTION_DESC ( "timeout", 't', required_argument,
+ struct imgdecrypt_options, timeout, parse_timeout),
+};
+
+/** "imgdecrypt" command descriptor */
+static struct command_descriptor imgdecrypt_cmd =
+ COMMAND_DESC ( struct imgdecrypt_options, imgdecrypt_opts, 2, 2,
+ "<uri|image> <envelope uri|image>" );
+
+/**
+ * The "imgdecrypt" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+static int imgdecrypt_exec ( int argc, char **argv ) {
+ struct imgdecrypt_options opts;
+ const char *image_name_uri;
+ const char *envelope_name_uri;
+ struct image *image;
+ struct image *envelope;
+ int rc;
+
+ /* Parse options */
+ if ( ( rc = parse_options ( argc, argv, &imgdecrypt_cmd, &opts ) ) != 0)
+ return rc;
+
+ /* Parse image name/URI string */
+ image_name_uri = argv[optind];
+
+ /* Parse envelope name/URI string */
+ envelope_name_uri = argv[ optind + 1 ];
+
+ /* Acquire the image */
+ if ( ( rc = imgacquire ( image_name_uri, opts.timeout, &image ) ) != 0 )
+ goto err_acquire_image;
+
+ /* Acquire the envelope image */
+ if ( ( rc = imgacquire ( envelope_name_uri, opts.timeout,
+ &envelope ) ) != 0 )
+ goto err_acquire_envelope;
+
+ /* Decrypt image */
+ if ( ( rc = imgdecrypt ( image, envelope, opts.name ) ) != 0 ) {
+ printf ( "Could not decrypt: %s\n", strerror ( rc ) );
+ goto err_decrypt;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_decrypt:
+ /* Discard envelope unless --keep was specified */
+ if ( ! opts.keep )
+ unregister_image ( envelope );
+ err_acquire_envelope:
+ err_acquire_image:
+ return rc;
+}
+
+/** Image encryption management commands */
+COMMAND ( imgdecrypt, imgdecrypt_exec );
diff --git a/src/hci/commands/image_mem_cmd.c b/src/hci/commands/image_mem_cmd.c
index c8bfab1ad..60c0bf92a 100644
--- a/src/hci/commands/image_mem_cmd.c
+++ b/src/hci/commands/image_mem_cmd.c
@@ -24,6 +24,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <getopt.h>
+#include <ipxe/uaccess.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/imgmgmt.h>
@@ -81,16 +82,11 @@ static int imgmem_exec ( int argc, char **argv ) {
return rc;
/* Create image */
- if ( ( rc = imgmem ( opts.name, phys_to_user ( data ), len ) ) != 0 )
+ if ( ( rc = imgmem ( opts.name, phys_to_virt ( data ), len ) ) != 0 )
return rc;
return 0;
}
/** Read memory command */
-struct command imgmem_commands[] __command = {
- {
- .name = "imgmem",
- .exec = imgmem_exec,
- },
-};
+COMMAND ( imgmem, imgmem_exec );
diff --git a/src/hci/commands/image_trust_cmd.c b/src/hci/commands/image_trust_cmd.c
index b34378f93..a8ec5784e 100644
--- a/src/hci/commands/image_trust_cmd.c
+++ b/src/hci/commands/image_trust_cmd.c
@@ -22,9 +22,11 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <stdio.h>
+#include <string.h>
#include <getopt.h>
#include <ipxe/image.h>
#include <ipxe/command.h>
@@ -162,13 +164,5 @@ static int imgverify_exec ( int argc, char **argv ) {
}
/** Image trust management commands */
-struct command image_trust_commands[] __command = {
- {
- .name = "imgtrust",
- .exec = imgtrust_exec,
- },
- {
- .name = "imgverify",
- .exec = imgverify_exec,
- },
-};
+COMMAND ( imgtrust, imgtrust_exec );
+COMMAND ( imgverify, imgverify_exec );
diff --git a/src/hci/commands/ipstat_cmd.c b/src/hci/commands/ipstat_cmd.c
index 763e4dfd6..fc454c57d 100644
--- a/src/hci/commands/ipstat_cmd.c
+++ b/src/hci/commands/ipstat_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <getopt.h>
@@ -66,9 +67,4 @@ static int ipstat_exec ( int argc, char **argv ) {
}
/** Routing table management commands */
-struct command ipstat_commands[] __command = {
- {
- .name = "ipstat",
- .exec = ipstat_exec,
- },
-};
+COMMAND ( ipstat, ipstat_exec );
diff --git a/src/hci/commands/iwmgmt_cmd.c b/src/hci/commands/iwmgmt_cmd.c
index b61ee8c7b..b430353d9 100644
--- a/src/hci/commands/iwmgmt_cmd.c
+++ b/src/hci/commands/iwmgmt_cmd.c
@@ -113,13 +113,5 @@ static int iwlist_exec ( int argc, char **argv ) {
}
/** Wireless interface management commands */
-struct command iwmgmt_commands[] __command = {
- {
- .name = "iwstat",
- .exec = iwstat_exec,
- },
- {
- .name = "iwlist",
- .exec = iwlist_exec,
- },
-};
+COMMAND ( iwstat, iwstat_exec );
+COMMAND ( iwlist, iwlist_exec );
diff --git a/src/hci/commands/login_cmd.c b/src/hci/commands/login_cmd.c
index 6ed76c6f2..faa8d9852 100644
--- a/src/hci/commands/login_cmd.c
+++ b/src/hci/commands/login_cmd.c
@@ -29,6 +29,7 @@
#include <ipxe/login_ui.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -78,7 +79,4 @@ static int login_exec ( int argc, char **argv ) {
}
/** Login commands */
-struct command login_command __command = {
- .name = "login",
- .exec = login_exec,
-};
+COMMAND ( login, login_exec );
diff --git a/src/hci/commands/lotest_cmd.c b/src/hci/commands/lotest_cmd.c
index 393b3c36e..ee3b0d3b5 100644
--- a/src/hci/commands/lotest_cmd.c
+++ b/src/hci/commands/lotest_cmd.c
@@ -100,7 +100,4 @@ static int lotest_exec ( int argc, char **argv ) {
}
/** Loopback testing commands */
-struct command lotest_command __command = {
- .name = "lotest",
- .exec = lotest_exec,
-};
+COMMAND ( lotest, lotest_exec );
diff --git a/src/hci/commands/neighbour_cmd.c b/src/hci/commands/neighbour_cmd.c
index 816e87357..870024ee0 100644
--- a/src/hci/commands/neighbour_cmd.c
+++ b/src/hci/commands/neighbour_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -65,9 +66,4 @@ static int nstat_exec ( int argc, char **argv ) {
}
/** Neighbour management commands */
-struct command neighbour_commands[] __command = {
- {
- .name = "nstat",
- .exec = nstat_exec,
- },
-};
+COMMAND ( nstat, nstat_exec );
diff --git a/src/hci/commands/nslookup_cmd.c b/src/hci/commands/nslookup_cmd.c
index 265afdc3d..b13127dd4 100644
--- a/src/hci/commands/nslookup_cmd.c
+++ b/src/hci/commands/nslookup_cmd.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <getopt.h>
@@ -73,7 +74,4 @@ static int nslookup_exec ( int argc, char **argv ) {
}
/** The "nslookup" command */
-struct command nslookup_command __command = {
- .name = "nslookup",
- .exec = nslookup_exec,
-};
+COMMAND ( nslookup, nslookup_exec );
diff --git a/src/hci/commands/ntp_cmd.c b/src/hci/commands/ntp_cmd.c
index 8f741a512..d7604227a 100644
--- a/src/hci/commands/ntp_cmd.c
+++ b/src/hci/commands/ntp_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <string.h>
@@ -75,7 +76,4 @@ static int ntp_exec ( int argc, char **argv ) {
}
/** NTP command */
-struct command ntp_command __command = {
- .name = "ntp",
- .exec = ntp_exec,
-};
+COMMAND ( ntp, ntp_exec );
diff --git a/src/hci/commands/nvo_cmd.c b/src/hci/commands/nvo_cmd.c
index 6ad7e7428..70086afce 100644
--- a/src/hci/commands/nvo_cmd.c
+++ b/src/hci/commands/nvo_cmd.c
@@ -34,6 +34,7 @@
#include <readline/readline.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -356,25 +357,8 @@ static int inc_exec ( int argc, char **argv ) {
}
/** Non-volatile option commands */
-struct command nvo_commands[] __command = {
- {
- .name = "show",
- .exec = show_exec,
- },
- {
- .name = "set",
- .exec = set_exec,
- },
- {
- .name = "clear",
- .exec = clear_exec,
- },
- {
- .name = "read",
- .exec = read_exec,
- },
- {
- .name = "inc",
- .exec = inc_exec,
- },
-};
+COMMAND ( show, show_exec );
+COMMAND ( set, set_exec );
+COMMAND ( clear, clear_exec );
+COMMAND ( read, read_exec );
+COMMAND ( inc, inc_exec );
diff --git a/src/hci/commands/param_cmd.c b/src/hci/commands/param_cmd.c
index dad99f840..ed57c5eaa 100644
--- a/src/hci/commands/param_cmd.c
+++ b/src/hci/commands/param_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -163,13 +164,5 @@ static int param_exec ( int argc, char **argv ) {
}
/** Request parameter commands */
-struct command param_commands[] __command = {
- {
- .name = "params",
- .exec = params_exec,
- },
- {
- .name = "param",
- .exec = param_exec,
- },
-};
+COMMAND ( params, params_exec );
+COMMAND ( param, param_exec );
diff --git a/src/hci/commands/pci_cmd.c b/src/hci/commands/pci_cmd.c
index 5bae66fbe..2e9505752 100644
--- a/src/hci/commands/pci_cmd.c
+++ b/src/hci/commands/pci_cmd.c
@@ -22,6 +22,7 @@
*/
#include <stdio.h>
+#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/pci.h>
@@ -29,6 +30,7 @@
#include <ipxe/parseopt.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -114,9 +116,4 @@ static int pciscan_exec ( int argc, char **argv ) {
}
/** PCI commands */
-struct command pci_commands[] __command = {
- {
- .name = "pciscan",
- .exec = pciscan_exec,
- },
-};
+COMMAND ( pciscan, pciscan_exec );
diff --git a/src/hci/commands/ping_cmd.c b/src/hci/commands/ping_cmd.c
index ab271e75a..e132fb457 100644
--- a/src/hci/commands/ping_cmd.c
+++ b/src/hci/commands/ping_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <stdlib.h>
@@ -107,7 +108,4 @@ static int ping_exec ( int argc, char **argv ) {
}
/** Ping command */
-struct command ping_command __command = {
- .name = "ping",
- .exec = ping_exec,
-};
+COMMAND ( ping, ping_exec );
diff --git a/src/hci/commands/poweroff_cmd.c b/src/hci/commands/poweroff_cmd.c
index afdf12dde..63aeb3d5b 100644
--- a/src/hci/commands/poweroff_cmd.c
+++ b/src/hci/commands/poweroff_cmd.c
@@ -29,6 +29,7 @@
#include <ipxe/reboot.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -70,7 +71,4 @@ static int poweroff_exec ( int argc, char **argv ) {
}
/** "poweroff" command */
-struct command poweroff_command __command = {
- .name = "poweroff",
- .exec = poweroff_exec,
-};
+COMMAND ( poweroff, poweroff_exec );
diff --git a/src/hci/commands/profstat_cmd.c b/src/hci/commands/profstat_cmd.c
index dc6f649e3..3303ebcf3 100644
--- a/src/hci/commands/profstat_cmd.c
+++ b/src/hci/commands/profstat_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <getopt.h>
@@ -66,9 +67,4 @@ static int profstat_exec ( int argc, char **argv ) {
}
/** Profiling commands */
-struct command profstat_commands[] __command = {
- {
- .name = "profstat",
- .exec = profstat_exec,
- },
-};
+COMMAND ( profstat, profstat_exec );
diff --git a/src/hci/commands/reboot_cmd.c b/src/hci/commands/reboot_cmd.c
index 45d54cc2c..daef92dc0 100644
--- a/src/hci/commands/reboot_cmd.c
+++ b/src/hci/commands/reboot_cmd.c
@@ -27,6 +27,7 @@
#include <ipxe/reboot.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -38,12 +39,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct reboot_options {
/** Perform a warm reboot */
int warm;
+ /** Reboot to firmware setup */
+ int setup;
};
/** "reboot" option list */
static struct option_descriptor reboot_opts[] = {
OPTION_DESC ( "warm", 'w', no_argument,
struct reboot_options, warm, parse_flag ),
+ OPTION_DESC ( "setup", 's', no_argument,
+ struct reboot_options, setup, parse_flag ),
};
/** "reboot" command descriptor */
@@ -59,6 +64,7 @@ static struct command_descriptor reboot_cmd =
*/
static int reboot_exec ( int argc, char **argv ) {
struct reboot_options opts;
+ int flags = 0;
int rc;
/* Parse options */
@@ -66,13 +72,14 @@ static int reboot_exec ( int argc, char **argv ) {
return rc;
/* Reboot system */
- reboot ( opts.warm );
+ if ( opts.warm )
+ flags |= REBOOT_WARM;
+ if ( opts.setup )
+ flags |= REBOOT_SETUP;
+ reboot ( flags );
return 0;
}
/** "reboot" command */
-struct command reboot_command __command = {
- .name = "reboot",
- .exec = reboot_exec,
-};
+COMMAND ( reboot, reboot_exec );
diff --git a/src/hci/commands/route_cmd.c b/src/hci/commands/route_cmd.c
index 8aa535363..ff841ec15 100644
--- a/src/hci/commands/route_cmd.c
+++ b/src/hci/commands/route_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <getopt.h>
@@ -66,9 +67,4 @@ static int route_exec ( int argc, char **argv ) {
}
/** Routing table management commands */
-struct command route_commands[] __command = {
- {
- .name = "route",
- .exec = route_exec,
- },
-};
+COMMAND ( route, route_exec );
diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c
index 6ab9e8844..7bc60e641 100644
--- a/src/hci/commands/sanboot_cmd.c
+++ b/src/hci/commands/sanboot_cmd.c
@@ -32,6 +32,7 @@
#include <usr/autoboot.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -204,17 +205,6 @@ static int sanunhook_exec ( int argc, char **argv ) {
}
/** SAN commands */
-struct command sanboot_commands[] __command = {
- {
- .name = "sanhook",
- .exec = sanhook_exec,
- },
- {
- .name = "sanboot",
- .exec = sanboot_exec,
- },
- {
- .name = "sanunhook",
- .exec = sanunhook_exec,
- },
-};
+COMMAND ( sanhook, sanhook_exec );
+COMMAND ( sanboot, sanboot_exec );
+COMMAND ( sanunhook, sanunhook_exec );
diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c
index 11956290a..1566af4e9 100644
--- a/src/hci/commands/shim_cmd.c
+++ b/src/hci/commands/shim_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <getopt.h>
#include <ipxe/command.h>
@@ -123,9 +124,4 @@ static int shim_exec ( int argc, char **argv ) {
}
/** Shim commands */
-struct command shim_commands[] __command = {
- {
- .name = "shim",
- .exec = shim_exec,
- },
-};
+COMMAND ( shim, shim_exec );
diff --git a/src/hci/commands/sync_cmd.c b/src/hci/commands/sync_cmd.c
index 54799d422..e3b97298c 100644
--- a/src/hci/commands/sync_cmd.c
+++ b/src/hci/commands/sync_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <stdio.h>
@@ -77,7 +78,4 @@ static int sync_exec ( int argc, char **argv ) {
}
/** Sync commands */
-struct command sync_command __command = {
- .name = "sync",
- .exec = sync_exec,
-};
+COMMAND ( sync, sync_exec );
diff --git a/src/hci/commands/time_cmd.c b/src/hci/commands/time_cmd.c
index 08148bf38..2199321c7 100644
--- a/src/hci/commands/time_cmd.c
+++ b/src/hci/commands/time_cmd.c
@@ -21,6 +21,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <stdlib.h>
@@ -77,7 +78,4 @@ static int time_exec ( int argc, char **argv ) {
}
/** "time" command */
-struct command time_command __command = {
- .name = "time",
- .exec = time_exec,
-};
+COMMAND ( time, time_exec );
diff --git a/src/hci/commands/usb_cmd.c b/src/hci/commands/usb_cmd.c
new file mode 100644
index 000000000..17affc0d7
--- /dev/null
+++ b/src/hci/commands/usb_cmd.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/usb.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * USB commands
+ *
+ */
+
+/** "usbscan" options */
+struct usbscan_options {};
+
+/** "usbscan" option list */
+static struct option_descriptor usbscan_opts[] = {};
+
+/** "usbscan" command descriptor */
+static struct command_descriptor usbscan_cmd =
+ COMMAND_DESC ( struct usbscan_options, usbscan_opts, 1, 1,
+ "<setting>" );
+
+/**
+ * "usbscan" command
+ *
+ * @v argc Argument count
+ * @v argv Argument list
+ * @ret rc Return status code
+ */
+static int usbscan_exec ( int argc, char **argv ) {
+ struct usbscan_options opts;
+ struct named_setting setting;
+ struct usb_device *usb;
+ unsigned long prev;
+ uint16_t busdev;
+ int len;
+ int rc;
+
+ /* Parse options */
+ if ( ( rc = parse_options ( argc, argv, &usbscan_cmd, &opts ) ) != 0 )
+ goto err_parse_options;
+
+ /* Parse setting name */
+ if ( ( rc = parse_autovivified_setting ( argv[optind],
+ &setting ) ) != 0 )
+ goto err_parse_setting;
+
+ /* Determine starting bus:dev.fn address */
+ if ( ( len = fetchn_setting ( setting.settings, &setting.setting,
+ NULL, &setting.setting, &prev ) ) < 0 ) {
+ /* Setting not yet defined: start searching from 00:00 */
+ busdev = 0;
+ } else {
+ /* Setting is defined: start searching from next location */
+ busdev = ( prev + 1 );
+ if ( ! busdev ) {
+ rc = -ENOENT;
+ goto err_end;
+ }
+ }
+
+ /* Find next existent USB device */
+ if ( ( rc = usb_find_next ( &usb, &busdev ) ) != 0 )
+ goto err_find_next;
+
+ /* Apply default type if necessary. Use ":uint16" rather than
+ * ":hex" to allow for easy inclusion within a
+ * "${usb/${location}....}" constructed setting.
+ */
+ if ( ! setting.setting.type )
+ setting.setting.type = &setting_type_uint16;
+
+ /* Store setting */
+ if ( ( rc = storen_setting ( setting.settings, &setting.setting,
+ busdev ) ) != 0 ) {
+ printf ( "Could not store \"%s\": %s\n",
+ setting.setting.name, strerror ( rc ) );
+ goto err_store;
+ }
+
+ err_store:
+ err_end:
+ err_find_next:
+ err_parse_setting:
+ err_parse_options:
+ return rc;
+}
+
+/** USB commands */
+COMMAND ( usbscan, usbscan_exec );
diff --git a/src/hci/commands/vlan_cmd.c b/src/hci/commands/vlan_cmd.c
index 8a2f0c749..69aef9f3c 100644
--- a/src/hci/commands/vlan_cmd.c
+++ b/src/hci/commands/vlan_cmd.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <stdlib.h>
@@ -131,13 +132,5 @@ static int vdestroy_exec ( int argc, char **argv ) {
}
/** VLAN commands */
-struct command vlan_commands[] __command = {
- {
- .name = "vcreate",
- .exec = vcreate_exec,
- },
- {
- .name = "vdestroy",
- .exec = vdestroy_exec,
- },
-};
+COMMAND ( vcreate, vcreate_exec );
+COMMAND ( vdestroy, vdestroy_exec );
diff --git a/src/hci/editstring.c b/src/hci/editstring.c
index 8cbce0767..f88b81f7f 100644
--- a/src/hci/editstring.c
+++ b/src/hci/editstring.c
@@ -22,10 +22,13 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <assert.h>
+#include <errno.h>
#include <string.h>
#include <ctype.h>
+#include <stdlib.h>
#include <ipxe/keys.h>
#include <ipxe/editstring.h>
@@ -35,17 +38,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-static void insert_delete ( struct edit_string *string, size_t delete_len,
- const char *insert_text )
- __attribute__ (( nonnull (1) ));
-static void insert_character ( struct edit_string *string,
- unsigned int character ) __nonnull;
-static void delete_character ( struct edit_string *string ) __nonnull;
-static void backspace ( struct edit_string *string ) __nonnull;
-static void previous_word ( struct edit_string *string ) __nonnull;
-static void kill_word ( struct edit_string *string ) __nonnull;
-static void kill_sol ( struct edit_string *string ) __nonnull;
-static void kill_eol ( struct edit_string *string ) __nonnull;
+static __attribute__ (( nonnull ( 1 ) )) int
+insert_delete ( struct edit_string *string, size_t delete_len,
+ const char *insert_text );
+static __nonnull int insert_character ( struct edit_string *string,
+ unsigned int character );
+static __nonnull void delete_character ( struct edit_string *string );
+static __nonnull void backspace ( struct edit_string *string );
+static __nonnull void previous_word ( struct edit_string *string );
+static __nonnull void kill_word ( struct edit_string *string );
+static __nonnull void kill_sol ( struct edit_string *string );
+static __nonnull void kill_eol ( struct edit_string *string );
/**
* Insert and/or delete text within an editable string
@@ -53,35 +56,57 @@ static void kill_eol ( struct edit_string *string ) __nonnull;
* @v string Editable string
* @v delete_len Length of text to delete from current cursor position
* @v insert_text Text to insert at current cursor position, or NULL
+ * @ret rc Return status code
*/
-static void insert_delete ( struct edit_string *string, size_t delete_len,
- const char *insert_text ) {
- size_t old_len, max_delete_len, insert_len, max_insert_len, new_len;
+static int insert_delete ( struct edit_string *string, size_t delete_len,
+ const char *insert_text ) {
+ size_t old_len, max_delete_len, move_len, insert_len, new_len;
+ char *buf;
+ char *tmp;
+
+ /* Prepare edit history */
+ string->mod_start = string->cursor;
+ string->mod_end = string->cursor;
/* Calculate lengths */
- old_len = strlen ( string->buf );
+ buf = *(string->buf);
+ old_len = ( buf ? strlen ( buf ) : 0 );
assert ( string->cursor <= old_len );
max_delete_len = ( old_len - string->cursor );
if ( delete_len > max_delete_len )
delete_len = max_delete_len;
+ move_len = ( max_delete_len - delete_len );
insert_len = ( insert_text ? strlen ( insert_text ) : 0 );
- max_insert_len = ( ( string->len - 1 ) - ( old_len - delete_len ) );
- if ( insert_len > max_insert_len )
- insert_len = max_insert_len;
new_len = ( old_len - delete_len + insert_len );
- /* Fill in edit history */
- string->mod_start = string->cursor;
- string->mod_end = ( ( new_len > old_len ) ? new_len : old_len );
+ /* Delete existing text */
+ memmove ( ( buf + string->cursor ),
+ ( buf + string->cursor + delete_len ), move_len );
+
+ /* Reallocate string, ignoring failures if shrinking */
+ tmp = realloc ( buf, ( new_len + 1 /* NUL */ ) );
+ if ( tmp ) {
+ buf = tmp;
+ *(string->buf) = buf;
+ } else if ( ( new_len > old_len ) || ( ! buf ) ) {
+ return -ENOMEM;
+ }
- /* Move data following the cursor */
- memmove ( ( string->buf + string->cursor + insert_len ),
- ( string->buf + string->cursor + delete_len ),
- ( max_delete_len + 1 - delete_len ) );
+ /* Create space for inserted text */
+ memmove ( ( buf + string->cursor + insert_len ),
+ ( buf + string->cursor ), move_len );
/* Copy inserted text to cursor position */
- memcpy ( ( string->buf + string->cursor ), insert_text, insert_len );
+ memcpy ( ( buf + string->cursor ), insert_text, insert_len );
string->cursor += insert_len;
+
+ /* Terminate string */
+ buf[new_len] = '\0';
+
+ /* Update edit history */
+ string->mod_end = ( ( new_len > old_len ) ? new_len : old_len );
+
+ return 0;
}
/**
@@ -89,11 +114,13 @@ static void insert_delete ( struct edit_string *string, size_t delete_len,
*
* @v string Editable string
* @v character Character to insert
+ * @ret rc Return status code
*/
-static void insert_character ( struct edit_string *string,
+static int insert_character ( struct edit_string *string,
unsigned int character ) {
char insert_text[2] = { character, '\0' };
- insert_delete ( string, 0, insert_text );
+
+ return insert_delete ( string, 0, insert_text );
}
/**
@@ -102,7 +129,10 @@ static void insert_character ( struct edit_string *string,
* @v string Editable string
*/
static void delete_character ( struct edit_string *string ) {
- insert_delete ( string, 1, NULL );
+ int rc;
+
+ rc = insert_delete ( string, 1, NULL );
+ assert ( ( rc == 0 ) || ( *(string->buf) == NULL ) );
}
/**
@@ -111,6 +141,7 @@ static void delete_character ( struct edit_string *string ) {
* @v string Editable string
*/
static void backspace ( struct edit_string *string ) {
+
if ( string->cursor > 0 ) {
string->cursor--;
delete_character ( string );
@@ -123,14 +154,16 @@ static void backspace ( struct edit_string *string ) {
* @v string Editable string
*/
static void previous_word ( struct edit_string *string ) {
- while ( string->cursor &&
- isspace ( string->buf[ string->cursor - 1 ] ) ) {
- string->cursor--;
+ const char *buf = *(string->buf);
+ size_t cursor = string->cursor;
+
+ while ( cursor && isspace ( buf[ cursor - 1 ] ) ) {
+ cursor--;
}
- while ( string->cursor &&
- ( ! isspace ( string->buf[ string->cursor - 1 ] ) ) ) {
- string->cursor--;
+ while ( cursor && ( ! isspace ( buf[ cursor - 1 ] ) ) ) {
+ cursor--;
}
+ string->cursor = cursor;
}
/**
@@ -140,8 +173,11 @@ static void previous_word ( struct edit_string *string ) {
*/
static void kill_word ( struct edit_string *string ) {
size_t old_cursor = string->cursor;
+ int rc;
+
previous_word ( string );
- insert_delete ( string, ( old_cursor - string->cursor ), NULL );
+ rc = insert_delete ( string, ( old_cursor - string->cursor ), NULL );
+ assert ( ( rc == 0 ) || ( *(string->buf) == NULL ) );
}
/**
@@ -151,8 +187,11 @@ static void kill_word ( struct edit_string *string ) {
*/
static void kill_sol ( struct edit_string *string ) {
size_t old_cursor = string->cursor;
+ int rc;
+
string->cursor = 0;
- insert_delete ( string, old_cursor, NULL );
+ rc = insert_delete ( string, old_cursor, NULL );
+ assert ( ( rc == 0 ) || ( *(string->buf) == NULL ) );
}
/**
@@ -161,18 +200,36 @@ static void kill_sol ( struct edit_string *string ) {
* @v string Editable string
*/
static void kill_eol ( struct edit_string *string ) {
- insert_delete ( string, ~( ( size_t ) 0 ), NULL );
+ int rc;
+
+ rc = insert_delete ( string, ~( ( size_t ) 0 ), NULL );
+ assert ( ( rc == 0 ) || ( *(string->buf) == NULL ) );
}
/**
* Replace editable string
*
* @v string Editable string
- * @v replacement Replacement string
+ * @v replacement Replacement string, or NULL to empty the string
+ * @ret rc Return status code
+ *
+ * Replace the entire content of the editable string and update the
+ * edit history to allow the caller to bring the display into sync
+ * with the string content.
+ *
+ * This function does not itself update the display in any way.
+ *
+ * Upon success, the string buffer is guaranteed to be non-NULL (even
+ * if the replacement string is NULL or empty).
+ *
+ * Errors may safely be ignored if it is deemed that subsequently
+ * failing to update the display will provide sufficient feedback to
+ * the user.
*/
-void replace_string ( struct edit_string *string, const char *replacement ) {
+int replace_string ( struct edit_string *string, const char *replacement ) {
+
string->cursor = 0;
- insert_delete ( string, ~( ( size_t ) 0 ), replacement );
+ return insert_delete ( string, ~( ( size_t ) 0 ), replacement );
}
/**
@@ -180,21 +237,26 @@ void replace_string ( struct edit_string *string, const char *replacement ) {
*
* @v string Editable string
* @v key Key pressed by user
- * @ret key Key returned to application, or zero
+ * @ret key Key returned to application, zero, or negative error
*
* Handles keypresses and updates the content of the editable string.
* Basic line editing facilities (delete/insert/cursor) are supported.
* If edit_string() understands and uses the keypress it will return
* zero, otherwise it will return the original key.
*
- * This function does not update the display in any way.
- *
* The string's edit history will be updated to allow the caller to
* efficiently bring the display into sync with the string content.
+ *
+ * This function does not itself update the display in any way.
+ *
+ * Errors may safely be ignored if it is deemed that subsequently
+ * failing to update the display will provide sufficient feedback to
+ * the user.
*/
int edit_string ( struct edit_string *string, int key ) {
+ const char *buf = *(string->buf);
+ size_t len = ( buf ? strlen ( buf ) : 0 );
int retval = 0;
- size_t len = strlen ( string->buf );
/* Prepare edit history */
string->last_cursor = string->cursor;
@@ -204,7 +266,7 @@ int edit_string ( struct edit_string *string, int key ) {
/* Interpret key */
if ( ( key >= 0x20 ) && ( key <= 0x7e ) ) {
/* Printable character; insert at current position */
- insert_character ( string, key );
+ retval = insert_character ( string, key );
} else switch ( key ) {
case KEY_BACKSPACE:
/* Backspace */
diff --git a/src/hci/jumpscroll.c b/src/hci/jumpscroll.c
index dd6bcac2b..c6ee5bda0 100644
--- a/src/hci/jumpscroll.c
+++ b/src/hci/jumpscroll.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Jump scrolling
@@ -39,7 +40,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v key Key pressed by user
* @ret move Scroller movement, or zero
*/
-int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
+unsigned int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
+ unsigned int flags = 0;
+ int16_t delta;
/* Sanity checks */
assert ( scroll->rows != 0 );
@@ -52,20 +55,32 @@ int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
/* Handle key, if applicable */
switch ( key ) {
case KEY_UP:
- return -1;
+ delta = -1;
+ break;
+ case TAB:
+ flags = SCROLL_WRAP;
+ /* fall through */
case KEY_DOWN:
- return +1;
+ delta = +1;
+ break;
case KEY_PPAGE:
- return ( scroll->first - scroll->current - 1 );
+ delta = ( scroll->first - scroll->current - 1 );
+ break;
case KEY_NPAGE:
- return ( scroll->first - scroll->current + scroll->rows );
+ delta = ( scroll->first - scroll->current + scroll->rows );
+ break;
case KEY_HOME:
- return -( scroll->count );
+ delta = -( scroll->count );
+ break;
case KEY_END:
- return +( scroll->count );
+ delta = +( scroll->count );
+ break;
default:
- return 0;
+ delta = 0;
+ break;
}
+
+ return ( SCROLL ( delta ) | flags );
}
/**
@@ -75,7 +90,9 @@ int jump_scroll_key ( struct jump_scroller *scroll, int key ) {
* @v move Scroller movement
* @ret move Continuing scroller movement (if applicable)
*/
-int jump_scroll_move ( struct jump_scroller *scroll, int move ) {
+unsigned int jump_scroll_move ( struct jump_scroller *scroll,
+ unsigned int move ) {
+ int16_t delta = SCROLL_DELTA ( move );
int current = scroll->current;
int last = ( scroll->count - 1 );
@@ -84,30 +101,35 @@ int jump_scroll_move ( struct jump_scroller *scroll, int move ) {
assert ( scroll->count != 0 );
/* Move to the new current item */
- current += move;
+ current += delta;
+
+ /* Default to continuing movement in the same direction */
+ delta = ( ( delta >= 0 ) ? +1 : -1 );
/* Check for start/end of list */
- if ( current < 0 ) {
- /* We have attempted to move before the start of the
- * list. Move to the start of the list and continue
- * moving forwards (if applicable).
- */
- scroll->current = 0;
- return +1;
- } else if ( current > last ) {
- /* We have attempted to move after the end of the
- * list. Move to the end of the list and continue
- * moving backwards (if applicable).
+ if ( ( current >= 0 ) && ( current <= last ) ) {
+ /* We are still within the list. Update the current
+ * item and continue moving in the same direction (if
+ * applicable).
*/
- scroll->current = last;
- return -1;
+ scroll->current = current;
} else {
- /* Update the current item and continue moving in the
- * same direction (if applicable).
+ /* We have attempted to move outside the list. If we
+ * are wrapping around, then continue in the same
+ * direction (if applicable), otherwise reverse.
*/
- scroll->current = current;
- return ( ( move > 0 ) ? +1 : -1 );
+ if ( ! ( move & SCROLL_WRAP ) )
+ delta = -delta;
+
+ /* Move to start or end of list as appropriate */
+ if ( delta >= 0 ) {
+ scroll->current = 0;
+ } else {
+ scroll->current = last;
+ }
}
+
+ return ( SCROLL ( delta ) | ( move & SCROLL_FLAGS ) );
}
/**
diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c
index ad4792b9b..dba123b76 100644
--- a/src/hci/keymap/keymap_al.c
+++ b/src/hci/keymap/keymap_al.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c
index 9af6c966d..78b1ca84c 100644
--- a/src/hci/keymap/keymap_by.c
+++ b/src/hci/keymap/keymap_by.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_cf.c b/src/hci/keymap/keymap_cf.c
index 7ecfc4448..62d5d1bcc 100644
--- a/src/hci/keymap/keymap_cf.c
+++ b/src/hci/keymap/keymap_cf.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_cz.c b/src/hci/keymap/keymap_cz.c
index dd793a8d0..1ecf80978 100644
--- a/src/hci/keymap/keymap_cz.c
+++ b/src/hci/keymap/keymap_cz.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c
index fb1136dc7..c32421ddc 100644
--- a/src/hci/keymap/keymap_de.c
+++ b/src/hci/keymap/keymap_de.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c
index 45cdeb25d..401bf715b 100644
--- a/src/hci/keymap/keymap_dk.c
+++ b/src/hci/keymap/keymap_dk.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c
index c1c55b348..3bfcae49a 100644
--- a/src/hci/keymap/keymap_es.c
+++ b/src/hci/keymap/keymap_es.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c
index 4d763266f..e859f3b91 100644
--- a/src/hci/keymap/keymap_et.c
+++ b/src/hci/keymap/keymap_et.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c
index 8bcd0c393..54eab6586 100644
--- a/src/hci/keymap/keymap_fi.c
+++ b/src/hci/keymap/keymap_fi.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c
index 23a0837fb..5718f5d3b 100644
--- a/src/hci/keymap/keymap_fr.c
+++ b/src/hci/keymap/keymap_fr.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c
index 4826c26c2..fdd142490 100644
--- a/src/hci/keymap/keymap_gr.c
+++ b/src/hci/keymap/keymap_gr.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_hu.c b/src/hci/keymap/keymap_hu.c
index 771671408..251a70ca7 100644
--- a/src/hci/keymap/keymap_hu.c
+++ b/src/hci/keymap/keymap_hu.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c
index b11e7ce71..9a8c46ec4 100644
--- a/src/hci/keymap/keymap_il.c
+++ b/src/hci/keymap/keymap_il.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c
index bb14ae1bd..3a938050c 100644
--- a/src/hci/keymap/keymap_it.c
+++ b/src/hci/keymap/keymap_it.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_lt.c b/src/hci/keymap/keymap_lt.c
index f8e60a5c5..1091203ac 100644
--- a/src/hci/keymap/keymap_lt.c
+++ b/src/hci/keymap/keymap_lt.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c
index 4b90ef799..e6b845dfc 100644
--- a/src/hci/keymap/keymap_mk.c
+++ b/src/hci/keymap/keymap_mk.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_mt.c b/src/hci/keymap/keymap_mt.c
index 0997bfe93..be6dde3a9 100644
--- a/src/hci/keymap/keymap_mt.c
+++ b/src/hci/keymap/keymap_mt.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c
index 97c7e8b5d..fef5ac798 100644
--- a/src/hci/keymap/keymap_nl.c
+++ b/src/hci/keymap/keymap_nl.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c
index 80df84889..9db333bcd 100644
--- a/src/hci/keymap/keymap_no-latin1.c
+++ b/src/hci/keymap/keymap_no-latin1.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c
index 0a624c3ab..aafcf1723 100644
--- a/src/hci/keymap/keymap_no.c
+++ b/src/hci/keymap/keymap_no.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c
index a76181fbc..f1ad81327 100644
--- a/src/hci/keymap/keymap_pl.c
+++ b/src/hci/keymap/keymap_pl.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c
index 3133c1561..8fcfb3bcf 100644
--- a/src/hci/keymap/keymap_pt.c
+++ b/src/hci/keymap/keymap_pt.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_ro.c b/src/hci/keymap/keymap_ro.c
index 620450001..7767bf2fb 100644
--- a/src/hci/keymap/keymap_ro.c
+++ b/src/hci/keymap/keymap_ro.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c
index 2aafcf9bd..2a025f815 100644
--- a/src/hci/keymap/keymap_ru.c
+++ b/src/hci/keymap/keymap_ru.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_se.c b/src/hci/keymap/keymap_se.c
index 2bac96985..fad24fffe 100644
--- a/src/hci/keymap/keymap_se.c
+++ b/src/hci/keymap/keymap_se.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c
index c4200099a..8fd943309 100644
--- a/src/hci/keymap/keymap_sg.c
+++ b/src/hci/keymap/keymap_sg.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c
index 7e55714a2..f6b8eb7a6 100644
--- a/src/hci/keymap/keymap_sr-latin.c
+++ b/src/hci/keymap/keymap_sr-latin.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c
index 44e82cb2d..bbd390079 100644
--- a/src/hci/keymap/keymap_ua.c
+++ b/src/hci/keymap/keymap_ua.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_uk.c b/src/hci/keymap/keymap_uk.c
index 28cf7aac4..a1f23a7a8 100644
--- a/src/hci/keymap/keymap_uk.c
+++ b/src/hci/keymap/keymap_uk.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/keymap/keymap_us.c b/src/hci/keymap/keymap_us.c
index b8e604a48..d178f189a 100644
--- a/src/hci/keymap/keymap_us.c
+++ b/src/hci/keymap/keymap_us.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
+FILE_SECBOOT ( PERMITTED );
#include <ipxe/keymap.h>
diff --git a/src/hci/mucurses/ansi_screen.c b/src/hci/mucurses/ansi_screen.c
index 1cf3309dd..7c607b5cc 100644
--- a/src/hci/mucurses/ansi_screen.c
+++ b/src/hci/mucurses/ansi_screen.c
@@ -4,6 +4,7 @@
#include <ipxe/console.h>
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
static void ansiscr_reset(struct _curses_screen *scr) __nonnull;
static void ansiscr_movetoyx(struct _curses_screen *scr,
diff --git a/src/hci/mucurses/clear.c b/src/hci/mucurses/clear.c
index 2054f72cc..d93e9630e 100644
--- a/src/hci/mucurses/clear.c
+++ b/src/hci/mucurses/clear.c
@@ -9,6 +9,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Clear a window to the bottom from current cursor position
diff --git a/src/hci/mucurses/cursor.h b/src/hci/mucurses/cursor.h
index 2e0c896a6..6f47becae 100644
--- a/src/hci/mucurses/cursor.h
+++ b/src/hci/mucurses/cursor.h
@@ -8,6 +8,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
struct cursor_pos {
unsigned int y, x;
diff --git a/src/hci/mucurses/mucurses.c b/src/hci/mucurses/mucurses.c
index 98a8a2c59..7f1779e8f 100644
--- a/src/hci/mucurses/mucurses.c
+++ b/src/hci/mucurses/mucurses.c
@@ -8,6 +8,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
static void _wupdcurs ( WINDOW *win ) __nonnull;
void _wputch ( WINDOW *win, chtype ch, int wrap ) __nonnull;
diff --git a/src/hci/mucurses/mucurses.h b/src/hci/mucurses/mucurses.h
index 270394787..dc6187741 100644
--- a/src/hci/mucurses/mucurses.h
+++ b/src/hci/mucurses/mucurses.h
@@ -8,6 +8,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#define WRAP 0
#define NOWRAP 1
diff --git a/src/hci/mucurses/print.c b/src/hci/mucurses/print.c
index e8831c58f..f7e0c8483 100644
--- a/src/hci/mucurses/print.c
+++ b/src/hci/mucurses/print.c
@@ -11,6 +11,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Add a single-byte character and rendition to a window and advance
diff --git a/src/hci/mucurses/widgets/editbox.c b/src/hci/mucurses/widgets/editbox.c
index 210de4481..5dab3ac5c 100644
--- a/src/hci/mucurses/widgets/editbox.c
+++ b/src/hci/mucurses/widgets/editbox.c
@@ -22,9 +22,11 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <assert.h>
+#include <ipxe/ansicol.h>
#include <ipxe/editbox.h>
/** @file
@@ -36,38 +38,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define EDITBOX_MIN_CHARS 3
/**
- * Initialise text box widget
- *
- * @v box Editable text box widget
- * @v buf Text buffer
- * @v len Size of text buffer
- * @v win Containing window
- * @v row Row
- * @v col Starting column
- * @v width Width
- * @v flags Flags
- */
-void init_editbox ( struct edit_box *box, char *buf, size_t len,
- WINDOW *win, unsigned int row, unsigned int col,
- unsigned int width, unsigned int flags ) {
- memset ( box, 0, sizeof ( *box ) );
- init_editstring ( &box->string, buf, len );
- box->string.cursor = strlen ( buf );
- box->win = ( win ? win : stdscr );
- box->row = row;
- box->col = col;
- box->width = width;
- box->flags = flags;
-}
-
-/**
* Draw text box widget
*
- * @v box Editable text box widget
- *
+ * @v widget Text widget
*/
-void draw_editbox ( struct edit_box *box ) {
- size_t width = box->width;
+static void draw_editbox ( struct widget *widget ) {
+ struct edit_box *box = container_of ( widget, struct edit_box, widget );
+ const char *content = *(box->string.buf);
+ size_t width = widget->width;
char buf[ width + 1 ];
signed int cursor_offset, underflow, overflow, first;
size_t len;
@@ -90,18 +68,37 @@ void draw_editbox ( struct edit_box *box ) {
/* Construct underscore-padded string portion */
memset ( buf, '_', width );
buf[width] = '\0';
- len = ( strlen ( box->string.buf ) - first );
+ len = ( content ? ( strlen ( content ) - first ) : 0 );
if ( len > width )
len = width;
- if ( box->flags & EDITBOX_STARS ) {
+ if ( widget->flags & WIDGET_SECRET ) {
memset ( buf, '*', len );
} else {
- memcpy ( buf, ( box->string.buf + first ), len );
+ memcpy ( buf, ( content + first ), len );
}
/* Print box content and move cursor */
- if ( ! box->win )
- box->win = stdscr;
- mvwprintw ( box->win, box->row, box->col, "%s", buf );
- wmove ( box->win, box->row, ( box->col + cursor_offset ) );
+ color_set ( CPAIR_EDIT, NULL );
+ mvprintw ( widget->row, widget->col, "%s", buf );
+ move ( widget->row, ( widget->col + cursor_offset ) );
+ color_set ( CPAIR_NORMAL, NULL );
}
+
+/**
+ * Edit text box widget
+ *
+ * @v widget Text widget
+ * @v key Key pressed by user
+ * @ret key Key returned to application, or zero
+ */
+static int edit_editbox ( struct widget *widget, int key ) {
+ struct edit_box *box = container_of ( widget, struct edit_box, widget );
+
+ return edit_string ( &box->string, key );
+}
+
+/** Text box widget operations */
+struct widget_operations editbox_operations = {
+ .draw = draw_editbox,
+ .edit = edit_editbox,
+};
diff --git a/src/hci/mucurses/winattrs.c b/src/hci/mucurses/winattrs.c
index 97a5a18b3..e78025543 100644
--- a/src/hci/mucurses/winattrs.c
+++ b/src/hci/mucurses/winattrs.c
@@ -7,6 +7,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Get the background rendition attributes for a window
diff --git a/src/hci/mucurses/wininit.c b/src/hci/mucurses/wininit.c
index dd84d2f1d..1b651123e 100644
--- a/src/hci/mucurses/wininit.c
+++ b/src/hci/mucurses/wininit.c
@@ -8,6 +8,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Initialise console environment
diff --git a/src/hci/readline.c b/src/hci/readline.c
index ecc72d43f..3d0330a62 100644
--- a/src/hci/readline.c
+++ b/src/hci/readline.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <string.h>
@@ -38,8 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-#define READLINE_MAX 1024
-
/**
* Synchronise console with edited string
*
@@ -49,7 +48,8 @@ static void sync_console ( struct edit_string *string ) {
unsigned int mod_start = string->mod_start;
unsigned int mod_end = string->mod_end;
unsigned int cursor = string->last_cursor;
- size_t len = strlen ( string->buf );
+ const char *buf = *(string->buf);
+ size_t len = strlen ( buf );
/* Expand region back to old cursor position if applicable */
if ( mod_start > string->last_cursor )
@@ -67,7 +67,7 @@ static void sync_console ( struct edit_string *string ) {
/* Print modified region */
while ( cursor < mod_end ) {
- putchar ( ( cursor >= len ) ? ' ' : string->buf[cursor] );
+ putchar ( ( cursor >= len ) ? ' ' : buf[cursor] );
cursor++;
}
@@ -259,15 +259,11 @@ int readline_history ( const char *prompt, const char *prefill,
struct readline_history *history, unsigned long timeout,
char **line ) {
struct edit_string string;
- char *buf;
int key;
int move_by;
const char *new_string;
int rc;
- /* Avoid returning uninitialised data on error */
- *line = NULL;
-
/* Display prompt, if applicable */
if ( prompt )
printf ( "%s", prompt );
@@ -275,20 +271,15 @@ int readline_history ( const char *prompt, const char *prefill,
/* Ensure cursor is visible */
printf ( "\033[?25h" );
- /* Allocate buffer and initialise editable string */
- buf = zalloc ( READLINE_MAX );
- if ( ! buf ) {
- rc = -ENOMEM;
- goto done;
- }
+ /* Initialise editable string */
+ *line = NULL;
memset ( &string, 0, sizeof ( string ) );
- init_editstring ( &string, buf, READLINE_MAX );
+ init_editstring ( &string, line );
- /* Prefill string, if applicable */
- if ( prefill ) {
- replace_string ( &string, prefill );
- sync_console ( &string );
- }
+ /* Prefill string */
+ if ( ( rc = replace_string ( &string, prefill ) ) != 0 )
+ goto error;
+ sync_console ( &string );
while ( 1 ) {
@@ -296,7 +287,7 @@ int readline_history ( const char *prompt, const char *prefill,
key = getkey ( timeout );
if ( key < 0 ) {
rc = -ETIMEDOUT;
- goto done;
+ goto error;
}
timeout = 0;
@@ -307,17 +298,11 @@ int readline_history ( const char *prompt, const char *prefill,
switch ( key ) {
case CR:
case LF:
- /* Shrink string (ignoring failures) */
- *line = realloc ( buf,
- ( strlen ( buf ) + 1 /* NUL */ ) );
- if ( ! *line )
- *line = buf;
- buf = NULL;
rc = 0;
goto done;
case CTRL_C:
rc = -ECANCELED;
- goto done;
+ goto error;
case KEY_UP:
move_by = 1;
break;
@@ -325,13 +310,13 @@ int readline_history ( const char *prompt, const char *prefill,
move_by = -1;
break;
default:
- /* Do nothing */
+ /* Do nothing for unrecognised keys or edit errors */
break;
}
/* Handle history movement, if applicable */
if ( move_by && history ) {
- new_string = history_move ( history, move_by, buf );
+ new_string = history_move ( history, move_by, *line );
if ( new_string ) {
replace_string ( &string, new_string );
sync_console ( &string );
@@ -339,9 +324,11 @@ int readline_history ( const char *prompt, const char *prefill,
}
}
+ error:
+ free ( *line );
+ *line = NULL;
done:
putchar ( '\n' );
- free ( buf );
if ( history ) {
if ( *line && (*line)[0] )
history_append ( history, *line );
diff --git a/src/hci/shell.c b/src/hci/shell.c
index 8ecf73a6f..cc7910eb8 100644
--- a/src/hci/shell.c
+++ b/src/hci/shell.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <stdlib.h>
@@ -72,10 +73,7 @@ static int help_exec ( int argc __unused, char **argv __unused ) {
}
/** "help" command */
-struct command help_command __command = {
- .name = "help",
- .exec = help_exec,
-};
+COMMAND ( help, help_exec );
/**
* Start command shell
@@ -137,7 +135,4 @@ static int shell_exec ( int argc, char **argv ) {
}
/** "shell" command */
-struct command shell_command __command = {
- .name = "shell",
- .exec = shell_exec,
-};
+COMMAND ( shell, shell_exec );
diff --git a/src/hci/strerror.c b/src/hci/strerror.c
index 1bba8c620..48091b413 100644
--- a/src/hci/strerror.c
+++ b/src/hci/strerror.c
@@ -20,6 +20,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Find error description
diff --git a/src/hci/tui/form_ui.c b/src/hci/tui/form_ui.c
new file mode 100644
index 000000000..7d8026f16
--- /dev/null
+++ b/src/hci/tui/form_ui.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * Text widget forms
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/ansicol.h>
+#include <ipxe/dynui.h>
+#include <ipxe/jumpscroll.h>
+#include <ipxe/settings.h>
+#include <ipxe/editbox.h>
+#include <ipxe/message.h>
+
+/** Form title row */
+#define TITLE_ROW 1U
+
+/** Starting control row */
+#define START_ROW 3U
+
+/** Ending control row */
+#define END_ROW ( LINES - 3U )
+
+/** Instructions row */
+#define INSTRUCTION_ROW ( LINES - 2U )
+
+/** Padding between instructions */
+#define INSTRUCTION_PAD " "
+
+/** Input field width */
+#define INPUT_WIDTH ( COLS / 2U )
+
+/** Input field column */
+#define INPUT_COL ( ( COLS - INPUT_WIDTH ) / 2U )
+
+/** A form */
+struct form {
+ /** Dynamic user interface */
+ struct dynamic_ui *dynui;
+ /** Jump scroller */
+ struct jump_scroller scroll;
+ /** Array of form controls */
+ struct form_control *controls;
+};
+
+/** A form control */
+struct form_control {
+ /** Dynamic user interface item */
+ struct dynamic_item *item;
+ /** Settings block */
+ struct settings *settings;
+ /** Setting */
+ struct setting setting;
+ /** Label row */
+ unsigned int row;
+ /** Editable text box */
+ struct edit_box editbox;
+ /** Modifiable setting name */
+ char *name;
+ /** Modifiable setting value */
+ char *value;
+ /** Most recent error in saving */
+ int rc;
+};
+
+/**
+ * Allocate form
+ *
+ * @v dynui Dynamic user interface
+ * @ret form Form, or NULL on error
+ */
+static struct form * alloc_form ( struct dynamic_ui *dynui ) {
+ struct form *form;
+ struct form_control *control;
+ struct dynamic_item *item;
+ char *name;
+ size_t len;
+
+ /* Calculate total length */
+ len = sizeof ( *form );
+ list_for_each_entry ( item, &dynui->items, list ) {
+ len += sizeof ( *control );
+ if ( item->name )
+ len += ( strlen ( item->name ) + 1 /* NUL */ );
+ }
+
+ /* Allocate and initialise structure */
+ form = zalloc ( len );
+ if ( ! form )
+ return NULL;
+ control = ( ( ( void * ) form ) + sizeof ( *form ) );
+ name = ( ( ( void * ) control ) +
+ ( dynui->count * sizeof ( *control ) ) );
+ form->dynui = dynui;
+ form->controls = control;
+ list_for_each_entry ( item, &dynui->items, list ) {
+ control->item = item;
+ if ( item->name ) {
+ control->name = name;
+ name = ( stpcpy ( name, item->name ) + 1 /* NUL */ );
+ }
+ control++;
+ }
+ assert ( ( ( void * ) name ) == ( ( ( void * ) form ) + len ) );
+
+ return form;
+}
+
+/**
+ * Free form
+ *
+ * @v form Form
+ */
+static void free_form ( struct form *form ) {
+ unsigned int i;
+
+ /* Free input value buffers */
+ for ( i = 0 ; i < form->dynui->count ; i++ )
+ free ( form->controls[i].value );
+
+ /* Free form */
+ free ( form );
+}
+
+/**
+ * Assign form rows
+ *
+ * @v form Form
+ * @ret rc Return status code
+ */
+static int layout_form ( struct form *form ) {
+ struct form_control *control;
+ struct dynamic_item *item;
+ unsigned int labels = 0;
+ unsigned int inputs = 0;
+ unsigned int pad_control = 0;
+ unsigned int pad_label = 0;
+ unsigned int minimum;
+ unsigned int remaining;
+ unsigned int between;
+ unsigned int row;
+ unsigned int flags;
+ unsigned int i;
+
+ /* Count labels and inputs */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+ item = control->item;
+ if ( item->text[0] )
+ labels++;
+ if ( item->name ) {
+ if ( ! inputs )
+ form->scroll.current = i;
+ inputs++;
+ if ( item->flags & DYNUI_DEFAULT )
+ form->scroll.current = i;
+ form->scroll.count = ( i + 1 );
+ }
+ }
+ form->scroll.rows = form->scroll.count;
+ DBGC ( form, "FORM %p has %d controls (%d labels, %d inputs)\n",
+ form, form->dynui->count, labels, inputs );
+
+ /* Refuse to create forms with no inputs */
+ if ( ! inputs )
+ return -EINVAL;
+
+ /* Calculate minimum number of rows */
+ minimum = ( labels + ( inputs * 2 /* edit box and error message */ ) );
+ remaining = ( END_ROW - START_ROW );
+ DBGC ( form, "FORM %p has %d (of %d) usable rows\n",
+ form, remaining, LINES );
+ if ( minimum > remaining )
+ return -ERANGE;
+ remaining -= minimum;
+
+ /* Insert blank row between controls, if space exists */
+ between = ( form->dynui->count - 1 );
+ if ( between <= remaining ) {
+ pad_control = 1;
+ remaining -= between;
+ DBGC ( form, "FORM %p padding between controls\n", form );
+ }
+
+ /* Insert blank row after label, if space exists */
+ if ( labels <= remaining ) {
+ pad_label = 1;
+ remaining -= labels;
+ DBGC ( form, "FORM %p padding after labels\n", form );
+ }
+
+ /* Centre on screen */
+ DBGC ( form, "FORM %p has %d spare rows\n", form, remaining );
+ row = ( START_ROW + ( remaining / 2 ) );
+
+ /* Position each control */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+ item = control->item;
+ if ( item->text[0] ) {
+ control->row = row;
+ row++; /* Label text */
+ row += pad_label;
+ }
+ if ( item->name ) {
+ flags = ( ( item->flags & DYNUI_SECRET ) ?
+ WIDGET_SECRET : 0 );
+ init_editbox ( &control->editbox, row, INPUT_COL,
+ INPUT_WIDTH, flags, &control->value );
+ row++; /* Edit box */
+ row++; /* Error message (if any) */
+ }
+ row += pad_control;
+ }
+ assert ( row <= END_ROW );
+
+ return 0;
+}
+
+/**
+ * Draw form
+ *
+ * @v form Form
+ */
+static void draw_form ( struct form *form ) {
+ struct form_control *control;
+ unsigned int i;
+
+ /* Clear screen */
+ color_set ( CPAIR_NORMAL, NULL );
+ erase();
+
+ /* Draw title, if any */
+ attron ( A_BOLD );
+ if ( form->dynui->title )
+ msg ( TITLE_ROW, "%s", form->dynui->title );
+ attroff ( A_BOLD );
+
+ /* Draw controls */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+
+ /* Draw label, if any */
+ if ( control->row )
+ msg ( control->row, "%s", control->item->text );
+
+ /* Draw input, if any */
+ if ( control->name )
+ draw_widget ( &control->editbox.widget );
+ }
+
+ /* Draw instructions */
+ msg ( INSTRUCTION_ROW, "%s", "Ctrl-X - save changes"
+ INSTRUCTION_PAD "Ctrl-C - discard changes" );
+}
+
+/**
+ * Draw (or clear) error messages
+ *
+ * @v form Form
+ */
+static void draw_errors ( struct form *form ) {
+ struct form_control *control;
+ unsigned int row;
+ unsigned int i;
+
+ /* Draw (or clear) errors */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+
+ /* Skip non-input controls */
+ if ( ! control->name )
+ continue;
+
+ /* Draw or clear error message as appropriate */
+ row = ( control->editbox.widget.row + 1 );
+ if ( control->rc != 0 ) {
+ color_set ( CPAIR_ALERT, NULL );
+ msg ( row, " %s ", strerror ( control->rc ) );
+ color_set ( CPAIR_NORMAL, NULL );
+ } else {
+ clearmsg ( row );
+ }
+ }
+}
+
+/**
+ * Parse setting names
+ *
+ * @v form Form
+ * @ret rc Return status code
+ */
+static int parse_names ( struct form *form ) {
+ struct form_control *control;
+ unsigned int i;
+ int rc;
+
+ /* Parse all setting names */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+
+ /* Skip labels */
+ if ( ! control->name ) {
+ DBGC ( form, "FORM %p item %d is a label\n", form, i );
+ continue;
+ }
+
+ /* Parse setting name */
+ DBGC ( form, "FORM %p item %d is for %s\n",
+ form, i, control->name );
+ if ( ( rc = parse_setting_name ( control->name,
+ autovivify_child_settings,
+ &control->settings,
+ &control->setting ) ) != 0 )
+ return rc;
+
+ /* Apply default type if necessary */
+ if ( ! control->setting.type )
+ control->setting.type = &setting_type_string;
+ }
+
+ return 0;
+}
+
+/**
+ * Load current input values
+ *
+ * @v form Form
+ */
+static void load_values ( struct form *form ) {
+ struct form_control *control;
+ unsigned int i;
+
+ /* Fetch all current setting values */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+ if ( ! control->name )
+ continue;
+ fetchf_setting_copy ( control->settings, &control->setting,
+ NULL, &control->setting,
+ &control->value );
+ }
+}
+
+/**
+ * Store current input values
+ *
+ * @v form Form
+ * @ret rc Return status code
+ */
+static int save_values ( struct form *form ) {
+ struct form_control *control;
+ unsigned int i;
+ int rc = 0;
+
+ /* Store all current setting values */
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ control = &form->controls[i];
+ if ( ! control->name )
+ continue;
+ control->rc = storef_setting ( control->settings,
+ &control->setting,
+ control->value );
+ if ( control->rc != 0 )
+ rc = control->rc;
+ }
+
+ return rc;
+}
+
+/**
+ * Submit form
+ *
+ * @v form Form
+ * @ret rc Return status code
+ */
+static int submit_form ( struct form *form ) {
+ int rc;
+
+ /* Attempt to save values */
+ rc = save_values ( form );
+
+ /* Draw (or clear) errors */
+ draw_errors ( form );
+
+ return rc;
+}
+
+/**
+ * Form main loop
+ *
+ * @v form Form
+ * @ret rc Return status code
+ */
+static int form_loop ( struct form *form ) {
+ struct jump_scroller *scroll = &form->scroll;
+ struct form_control *control;
+ struct dynamic_item *item;
+ unsigned int move;
+ unsigned int i;
+ int key;
+ int rc;
+
+ /* Main loop */
+ while ( 1 ) {
+
+ /* Draw current input */
+ control = &form->controls[scroll->current];
+ draw_widget ( &control->editbox.widget );
+
+ /* Process keypress */
+ key = edit_widget ( &control->editbox.widget, getkey ( 0 ) );
+
+ /* Handle scroll keys */
+ move = jump_scroll_key ( &form->scroll, key );
+
+ /* Handle special keys */
+ switch ( key ) {
+ case CTRL_C:
+ case ESC:
+ /* Cancel form */
+ return -ECANCELED;
+ case KEY_ENTER:
+ /* Attempt to do the most intuitive thing when
+ * Enter is pressed. If we are on the last
+ * input, then submit the form. If we are
+ * editing an input which failed, then
+ * resubmit the form. Otherwise, move to the
+ * next input.
+ */
+ if ( ( control->rc == 0 ) &&
+ ( scroll->current < ( scroll->count - 1 ) ) ) {
+ move = SCROLL_DOWN;
+ break;
+ }
+ /* fall through */
+ case CTRL_X:
+ /* Submit form */
+ if ( ( rc = submit_form ( form ) ) == 0 )
+ return 0;
+ /* If current input is not the problem, move
+ * to the first input that needs fixing.
+ */
+ if ( control->rc == 0 ) {
+ for ( i = 0 ; i < form->dynui->count ; i++ ) {
+ if ( form->controls[i].rc != 0 ) {
+ scroll->current = i;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ /* Move to input with matching shortcut key, if any */
+ item = dynui_shortcut ( form->dynui, key );
+ if ( item && ( item->flags & DYNUI_HIDDEN ) == 0 ) {
+ scroll->current = item->index;
+ if ( ! item->name )
+ move = SCROLL_DOWN;
+ }
+ break;
+ }
+
+ /* Move selection, if applicable */
+ while ( move ) {
+ move = jump_scroll_move ( &form->scroll, move );
+ control = &form->controls[scroll->current];
+ if ( control->name )
+ break;
+ }
+ }
+}
+
+/**
+ * Show form
+ *
+ * @v dynui Dynamic user interface
+ * @ret rc Return status code
+ */
+int show_form ( struct dynamic_ui *dynui ) {
+ struct form *form;
+ int rc;
+
+ /* Allocate and initialise structure */
+ form = alloc_form ( dynui );
+ if ( ! form ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Parse setting names and load current values */
+ if ( ( rc = parse_names ( form ) ) != 0 )
+ goto err_parse_names;
+ load_values ( form );
+
+ /* Lay out form on screen */
+ if ( ( rc = layout_form ( form ) ) != 0 )
+ goto err_layout;
+
+ /* Draw initial form */
+ initscr();
+ start_color();
+ draw_form ( form );
+
+ /* Run main loop */
+ if ( ( rc = form_loop ( form ) ) != 0 )
+ goto err_loop;
+
+ err_loop:
+ color_set ( CPAIR_NORMAL, NULL );
+ endwin();
+ err_layout:
+ err_parse_names:
+ free_form ( form );
+ err_alloc:
+ return rc;
+}
diff --git a/src/hci/tui/login_ui.c b/src/hci/tui/login_ui.c
index 56fc2fa97..e265f81b0 100644
--- a/src/hci/tui/login_ui.c
+++ b/src/hci/tui/login_ui.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -29,117 +30,56 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-#include <string.h>
-#include <errno.h>
-#include <curses.h>
-#include <ipxe/console.h>
-#include <ipxe/settings.h>
-#include <ipxe/editbox.h>
-#include <ipxe/keys.h>
-#include <ipxe/ansicol.h>
+#include <ipxe/dynui.h>
#include <ipxe/login_ui.h>
-/* Screen layout */
-#define USERNAME_LABEL_ROW ( ( LINES / 2U ) - 4U )
-#define USERNAME_ROW ( ( LINES / 2U ) - 2U )
-#define PASSWORD_LABEL_ROW ( ( LINES / 2U ) + 2U )
-#define PASSWORD_ROW ( ( LINES / 2U ) + 4U )
-#define LABEL_COL ( ( COLS / 2U ) - 4U )
-#define EDITBOX_COL ( ( COLS / 2U ) - 10U )
-#define EDITBOX_WIDTH 20U
+static struct dynamic_item username;
+static struct dynamic_item password;
-int login_ui ( int nouser ) {
- char username[64];
- char password[64];
- struct edit_box username_box;
- struct edit_box password_box;
- struct edit_box *current_box = nouser ? &password_box : &username_box;
- int key;
- int rc = -EINPROGRESS;
-
- /* Fetch current setting values */
- fetch_string_setting ( NULL, &username_setting, username,
- sizeof ( username ) );
- fetch_string_setting ( NULL, &password_setting, password,
- sizeof ( password ) );
-
- /* Initialise UI */
- initscr();
- start_color();
- init_editbox ( &username_box, username, sizeof ( username ), NULL,
- USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 );
- init_editbox ( &password_box, password, sizeof ( password ), NULL,
- PASSWORD_ROW, EDITBOX_COL, EDITBOX_WIDTH,
- EDITBOX_STARS );
-
- /* Draw initial UI */
- color_set ( CPAIR_NORMAL, NULL );
- erase();
- attron ( A_BOLD );
- if ( ! nouser ) {
- mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" );
- }
- mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" );
- attroff ( A_BOLD );
- color_set ( CPAIR_EDIT, NULL );
- if ( ! nouser ) {
- draw_editbox ( &username_box );
- }
- draw_editbox ( &password_box );
+static struct dynamic_ui login = {
+ .items = {
+ .prev = &password.list,
+ .next = &username.list,
+ },
+ .hidden_items = {
+ .prev = &login.hidden_items,
+ .next = &login.hidden_items,
+ },
+ .count = 2,
+};
- /* Main loop */
- while ( rc == -EINPROGRESS ) {
+static struct dynamic_item username = {
+ .list = {
+ .prev = &login.items,
+ .next = &password.list,
+ },
+ .name = "username",
+ .text = "Username",
+ .index = 0,
+};
- draw_editbox ( current_box );
+static struct dynamic_item password = {
+ .list = {
+ .prev = &username.list,
+ .next = &login.items,
+ },
+ .name = "password",
+ .text = "Password",
+ .index = 1,
+ .flags = DYNUI_SECRET,
+};
- key = getkey ( 0 );
- switch ( key ) {
- case KEY_DOWN:
- current_box = &password_box;
- break;
- case KEY_UP:
- if ( ! nouser ) {
- current_box = &username_box;
- }
- break;
- case TAB:
- if ( ! nouser ) {
- current_box = ( ( current_box == &username_box ) ?
- &password_box : &username_box );
- }
- break;
- case KEY_ENTER:
- if ( current_box == &username_box ) {
- current_box = &password_box;
- } else {
- rc = 0;
- }
- break;
- case CTRL_C:
- case ESC:
- rc = -ECANCELED;
- break;
- default:
- edit_editbox ( current_box, key );
- break;
- }
+int login_ui ( int nouser ) {
+ if ( nouser ) {
+ password.index = 0;
+ password.list.prev = &login.items;
+ login.count = 1;
+ login.items.next = &password.list;
+ } else {
+ password.index = 1;
+ password.list.prev = &username.list;
+ login.count = 2;
+ login.items.next = &username.list;
}
-
- /* Terminate UI */
- color_set ( CPAIR_NORMAL, NULL );
- erase();
- endwin();
-
- if ( rc != 0 )
- return rc;
-
- /* Store settings */
- if ( ( rc = store_setting ( NULL, &username_setting, username,
- strlen ( username ) ) ) != 0 )
- return rc;
- if ( ( rc = store_setting ( NULL, &password_setting, password,
- strlen ( password ) ) ) != 0 )
- return rc;
-
- return 0;
+ return show_form ( &login );
}
diff --git a/src/hci/tui/menu_ui.c b/src/hci/tui/menu_ui.c
index cb4edbbc8..e8672ed08 100644
--- a/src/hci/tui/menu_ui.c
+++ b/src/hci/tui/menu_ui.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -37,7 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/console.h>
#include <ipxe/ansicol.h>
#include <ipxe/jumpscroll.h>
-#include <ipxe/menu.h>
+#include <ipxe/dynui.h>
/* Screen layout */
#define TITLE_ROW 1U
@@ -49,40 +50,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** A menu user interface */
struct menu_ui {
- /** Menu */
- struct menu *menu;
+ /** Dynamic user interface */
+ struct dynamic_ui *dynui;
/** Jump scroller */
struct jump_scroller scroll;
- /** Timeout (0=indefinite) */
+ /** Remaining timeout (0=indefinite) */
unsigned long timeout;
+ /** Post-activity timeout (0=indefinite) */
+ unsigned long retimeout;
};
/**
- * Return a numbered menu item
- *
- * @v menu Menu
- * @v index Index
- * @ret item Menu item, or NULL
- */
-static struct menu_item * menu_item ( struct menu *menu, unsigned int index ) {
- struct menu_item *item;
-
- list_for_each_entry ( item, &menu->items, list ) {
- if ( index-- == 0 )
- return item;
- }
-
- return NULL;
-}
-
-/**
* Draw a numbered menu item
*
* @v ui Menu user interface
* @v index Index
*/
static void draw_menu_item ( struct menu_ui *ui, unsigned int index ) {
- struct menu_item *item;
+ struct dynamic_item *item;
unsigned int row_offset;
char buf[ MENU_COLS + 1 /* NUL */ ];
char timeout_buf[6]; /* "(xxx)" + NUL */
@@ -95,11 +80,11 @@ static void draw_menu_item ( struct menu_ui *ui, unsigned int index ) {
move ( ( MENU_ROW + row_offset ), MENU_COL );
/* Get menu item */
- item = menu_item ( ui->menu, index );
+ item = dynui_item ( ui->dynui, index );
if ( item ) {
/* Draw separators in a different colour */
- if ( ! item->label )
+ if ( ! item->name )
color_set ( CPAIR_SEPARATOR, NULL );
/* Highlight if this is the selected item */
@@ -171,13 +156,12 @@ static void draw_menu_items ( struct menu_ui *ui ) {
* @ret selected Selected item
* @ret rc Return status code
*/
-static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
- struct menu_item *item;
+static int menu_loop ( struct menu_ui *ui, struct dynamic_item **selected ) {
+ struct dynamic_item *item;
unsigned long timeout;
unsigned int previous;
+ unsigned int move;
int key;
- int i;
- int move;
int chosen = 0;
int rc = 0;
@@ -192,15 +176,15 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
ui->timeout -= timeout;
/* Get key */
- move = 0;
+ move = SCROLL_NONE;
key = getkey ( timeout );
if ( key < 0 ) {
/* Choose default if we finally time out */
if ( ui->timeout == 0 )
chosen = 1;
} else {
- /* Cancel any timeout */
- ui->timeout = 0;
+ /* Reset timeout after activity */
+ ui->timeout = ui->retimeout;
/* Handle scroll keys */
move = jump_scroll_key ( &ui->scroll, key );
@@ -216,31 +200,17 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
chosen = 1;
break;
default:
- i = 0;
-
- /* Check for shortcut. Visible items */
- list_for_each_entry ( item, &ui->menu->items,
- list ) {
- if ( ! ( item->shortcut &&
- ( item->shortcut == key ) ) ) {
- i++;
- continue;
+ item = dynui_shortcut ( ui->dynui, key );
+ if ( item ) {
+ ui->scroll.current = item->index;
+ if ( item->flags & DYNUI_HIDDEN ) {
+ *selected = item;
+ goto hidden_entry_selected;
}
- ui->scroll.current = i;
- if ( item->label ) {
+ if ( item->name ) {
chosen = 1;
} else {
- move = +1;
- }
- }
-
- /* Hidden items */
- list_for_each_entry ( item, &ui->menu->hidden_items,
- list ) {
- if ( item->shortcut &&
- ( item->shortcut == key ) ) {
- *selected = item;
- goto hidden_entry_selected;
+ move = SCROLL_DOWN;
}
}
break;
@@ -250,8 +220,8 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
/* Move selection, if applicable */
while ( move ) {
move = jump_scroll_move ( &ui->scroll, move );
- item = menu_item ( ui->menu, ui->scroll.current );
- if ( item->label )
+ item = dynui_item ( ui->dynui, ui->scroll.current );
+ if ( item->name )
break;
}
@@ -264,9 +234,9 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
}
/* Record selection */
- item = menu_item ( ui->menu, ui->scroll.current );
+ item = dynui_item ( ui->dynui, ui->scroll.current );
assert ( item != NULL );
- assert ( item->label != NULL );
+ assert ( item->name != NULL );
*selected = item;
} while ( ( rc == 0 ) && ! chosen );
@@ -278,43 +248,47 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
/**
* Show menu
*
- * @v menu Menu
- * @v timeout Timeout period, in ticks (0=indefinite)
+ * @v dynui Dynamic user interface
+ * @v timeout Initial timeout period, in ticks (0=indefinite)
+ * @v retimeout Post-activity timeout period, in ticks (0=indefinite)
* @ret selected Selected item
* @ret rc Return status code
*/
-int show_menu ( struct menu *menu, unsigned long timeout,
- const char *select, struct menu_item **selected ) {
- struct menu_item *item;
+int show_menu ( struct dynamic_ui *dynui, unsigned long timeout,
+ unsigned long retimeout, const char *select,
+ struct dynamic_item **selected ) {
+ struct dynamic_item *item;
struct menu_ui ui;
char buf[ MENU_COLS + 1 /* NUL */ ];
- int labelled_count = 0;
+ int named_count = 0;
int rc;
/* Initialise UI */
memset ( &ui, 0, sizeof ( ui ) );
- ui.menu = menu;
+ ui.dynui = dynui;
ui.scroll.rows = MENU_ROWS;
ui.timeout = timeout;
- list_for_each_entry ( item, &menu->items, list ) {
- if ( item->label ) {
- if ( ! labelled_count )
+ ui.retimeout = retimeout;
+
+ list_for_each_entry ( item, &dynui->items, list ) {
+ if ( item->name ) {
+ if ( ! named_count )
ui.scroll.current = ui.scroll.count;
- labelled_count++;
+ named_count++;
if ( select ) {
- if ( strcmp ( select, item->label ) == 0 )
+ if ( strcmp ( select, item->name ) == 0 )
ui.scroll.current = ui.scroll.count;
} else {
- if ( item->is_default )
+ if ( item->flags & DYNUI_DEFAULT )
ui.scroll.current = ui.scroll.count;
}
}
ui.scroll.count++;
}
- if ( ! labelled_count ) {
- /* Menus with no labelled items cannot be selected
- * from, and will seriously confuse the navigation
- * logic. Refuse to display any such menus.
+ if ( ! named_count ) {
+ /* Menus with no named items cannot be selected from,
+ * and will seriously confuse the navigation logic.
+ * Refuse to display any such menus.
*/
return -ENOENT;
}
@@ -328,7 +302,7 @@ int show_menu ( struct menu *menu, unsigned long timeout,
/* Draw initial content */
attron ( A_BOLD );
- snprintf ( buf, sizeof ( buf ), "%s", ui.menu->title );
+ snprintf ( buf, sizeof ( buf ), "%s", ui.dynui->title );
mvprintw ( TITLE_ROW, ( ( COLS - strlen ( buf ) ) / 2 ), "%s", buf );
attroff ( A_BOLD );
jump_scroll ( &ui.scroll );
diff --git a/src/hci/tui/message.c b/src/hci/tui/message.c
new file mode 100644
index 000000000..89c6f7703
--- /dev/null
+++ b/src/hci/tui/message.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * Message printing
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ipxe/ansicol.h>
+#include <ipxe/message.h>
+
+/**
+ * Print message centred on specified row
+ *
+ * @v row Row
+ * @v fmt printf() format string
+ * @v args printf() argument list
+ */
+static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
+ char buf[COLS];
+ size_t len;
+
+ len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
+ mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
+}
+
+/**
+ * Print message centred on specified row
+ *
+ * @v row Row
+ * @v fmt printf() format string
+ * @v .. printf() arguments
+ */
+void msg ( unsigned int row, const char *fmt, ... ) {
+ va_list args;
+
+ va_start ( args, fmt );
+ vmsg ( row, fmt, args );
+ va_end ( args );
+}
+
+/**
+ * Clear message on specified row
+ *
+ * @v row Row
+ */
+void clearmsg ( unsigned int row ) {
+ move ( row, 0 );
+ clrtoeol();
+}
+
+/**
+ * Show alert message
+ *
+ * @v row Row
+ * @v fmt printf() format string
+ * @v args printf() argument list
+ */
+static void valert ( unsigned int row, const char *fmt, va_list args ) {
+
+ clearmsg ( row );
+ color_set ( CPAIR_ALERT, NULL );
+ vmsg ( row, fmt, args );
+ sleep ( 2 );
+ color_set ( CPAIR_NORMAL, NULL );
+ clearmsg ( row );
+}
+
+/**
+ * Show alert message
+ *
+ * @v row Row
+ * @v fmt printf() format string
+ * @v ... printf() arguments
+ */
+void alert ( unsigned int row, const char *fmt, ... ) {
+ va_list args;
+
+ va_start ( args, fmt );
+ valert ( row, fmt, args );
+ va_end ( args );
+}
diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c
index be421cc0a..a069c527d 100644
--- a/src/hci/tui/settings_ui.c
+++ b/src/hci/tui/settings_ui.c
@@ -22,9 +22,11 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <curses.h>
@@ -34,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/keys.h>
#include <ipxe/ansicol.h>
#include <ipxe/jumpscroll.h>
+#include <ipxe/message.h>
#include <ipxe/settings_ui.h>
#include <config/branding.h>
@@ -58,12 +61,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
char start[0]; \
char pad1[1]; \
union { \
- char settings[ cols - 1 - 1 - 1 - 1 ]; \
+ struct { \
+ char name[ cols - 1 - 1 - 1 - 1 - 1 ]; \
+ char pad2[1]; \
+ } __attribute__ (( packed )) settings; \
struct { \
char name[15]; \
char pad2[1]; \
char value[ cols - 1 - 15 - 1 - 1 - 1 - 1 ]; \
- } setting; \
+ } __attribute__ (( packed )) setting; \
} u; \
char pad3[1]; \
char nul; \
@@ -92,8 +98,8 @@ struct settings_ui_row {
struct edit_box editbox;
/** Editing in progress flag */
int editing;
- /** Buffer for setting's value */
- char value[256]; /* enough size for a DHCP string */
+ /** Dynamically allocated buffer for setting's value */
+ char *buf;
};
/** A settings user interface */
@@ -121,24 +127,22 @@ static unsigned int select_setting_row ( struct settings_ui *ui,
struct setting *previous = NULL;
unsigned int count = 0;
+ /* Free any previous setting value */
+ free ( ui->row.buf );
+ ui->row.buf = NULL;
+
/* Initialise structure */
memset ( &ui->row, 0, sizeof ( ui->row ) );
ui->row.row = ( SETTINGS_LIST_ROW + index - ui->scroll.first );
/* Include parent settings block, if applicable */
- if ( ui->settings->parent && ( count++ == index ) ) {
+ if ( ui->settings->parent && ( count++ == index ) )
ui->row.settings = ui->settings->parent;
- snprintf ( ui->row.value, sizeof ( ui->row.value ),
- "../" );
- }
/* Include any child settings blocks, if applicable */
list_for_each_entry ( settings, &ui->settings->children, siblings ) {
- if ( count++ == index ) {
+ if ( count++ == index )
ui->row.settings = settings;
- snprintf ( ui->row.value, sizeof ( ui->row.value ),
- "%s/", settings->name );
- }
}
/* Include any applicable settings */
@@ -155,18 +159,18 @@ static unsigned int select_setting_row ( struct settings_ui *ui,
/* Read current setting value and origin */
if ( count++ == index ) {
- fetchf_setting ( ui->settings, setting, &ui->row.origin,
- &ui->row.setting, ui->row.value,
- sizeof ( ui->row.value ) );
+ fetchf_setting_copy ( ui->settings, setting,
+ &ui->row.origin,
+ &ui->row.setting, &ui->row.buf );
}
}
/* Initialise edit box */
- init_editbox ( &ui->row.editbox, ui->row.value,
- sizeof ( ui->row.value ), NULL, ui->row.row,
+ memset ( &ui->row.editbox, 0, sizeof ( ui->row.editbox ) );
+ init_editbox ( &ui->row.editbox, ui->row.row,
( SETTINGS_LIST_COL +
offsetof ( typeof ( *text ), u.setting.value ) ),
- sizeof ( text->u.setting.value ), 0 );
+ sizeof ( text->u.setting.value ), 0, &ui->row.buf );
return count;
}
@@ -197,7 +201,7 @@ static size_t string_copy ( char *dest, const char *src, size_t len ) {
static void draw_setting_row ( struct settings_ui *ui ) {
SETTING_ROW_TEXT ( COLS ) text;
unsigned int curs_offset;
- char *value;
+ const char *value;
/* Fill row with spaces */
memset ( &text, ' ', sizeof ( text ) );
@@ -207,10 +211,12 @@ static void draw_setting_row ( struct settings_ui *ui ) {
if ( ui->row.settings ) {
/* Construct space-padded name */
- curs_offset = ( offsetof ( typeof ( text ), u.settings ) +
- string_copy ( text.u.settings,
- ui->row.value,
- sizeof ( text.u.settings ) ) );
+ value = ( ( ui->row.settings == ui->settings->parent ) ?
+ ".." : ui->row.settings->name );
+ curs_offset = string_copy ( text.u.settings.name, value,
+ sizeof ( text.u.settings.name ) );
+ text.u.settings.name[curs_offset] = '/';
+ curs_offset += offsetof ( typeof ( text ), u.settings );
} else {
@@ -221,12 +227,12 @@ static void draw_setting_row ( struct settings_ui *ui ) {
sizeof ( text.u.setting.name ) );
/* Construct space-padded value */
- value = ui->row.value;
- if ( ! *value )
+ value = ui->row.buf;
+ if ( ! ( value && value[0] ) )
value = "<not specified>";
- curs_offset = ( offsetof ( typeof ( text ), u.setting.value ) +
- string_copy ( text.u.setting.value, value,
- sizeof ( text.u.setting.value )));
+ curs_offset = string_copy ( text.u.setting.value, value,
+ sizeof ( text.u.setting.value ) );
+ curs_offset += offsetof ( typeof ( text ), u.setting.value );
}
/* Print row */
@@ -247,7 +253,7 @@ static void draw_setting_row ( struct settings_ui *ui ) {
static int edit_setting ( struct settings_ui *ui, int key ) {
assert ( ui->row.setting.name != NULL );
ui->row.editing = 1;
- return edit_editbox ( &ui->row.editbox, key );
+ return edit_widget ( &ui->row.editbox.widget, key );
}
/**
@@ -257,76 +263,7 @@ static int edit_setting ( struct settings_ui *ui, int key ) {
*/
static int save_setting ( struct settings_ui *ui ) {
assert ( ui->row.setting.name != NULL );
- return storef_setting ( ui->settings, &ui->row.setting, ui->row.value );
-}
-
-/**
- * Print message centred on specified row
- *
- * @v row Row
- * @v fmt printf() format string
- * @v args printf() argument list
- */
-static void vmsg ( unsigned int row, const char *fmt, va_list args ) {
- char buf[COLS];
- size_t len;
-
- len = vsnprintf ( buf, sizeof ( buf ), fmt, args );
- mvprintw ( row, ( ( COLS - len ) / 2 ), "%s", buf );
-}
-
-/**
- * Print message centred on specified row
- *
- * @v row Row
- * @v fmt printf() format string
- * @v .. printf() arguments
- */
-static void msg ( unsigned int row, const char *fmt, ... ) {
- va_list args;
-
- va_start ( args, fmt );
- vmsg ( row, fmt, args );
- va_end ( args );
-}
-
-/**
- * Clear message on specified row
- *
- * @v row Row
- */
-static void clearmsg ( unsigned int row ) {
- move ( row, 0 );
- clrtoeol();
-}
-
-/**
- * Print alert message
- *
- * @v fmt printf() format string
- * @v args printf() argument list
- */
-static void valert ( const char *fmt, va_list args ) {
- clearmsg ( ALERT_ROW );
- color_set ( CPAIR_ALERT, NULL );
- vmsg ( ALERT_ROW, fmt, args );
- sleep ( 2 );
- color_set ( CPAIR_NORMAL, NULL );
- clearmsg ( ALERT_ROW );
-}
-
-/**
- * Print alert message
- *
- * @v fmt printf() format string
- * @v ... printf() arguments
- */
-static void alert ( const char *fmt, ... ) {
- va_list args;
-
- va_start ( args, fmt );
- valert ( fmt, args );
- va_end ( args );
+ return storef_setting ( ui->settings, &ui->row.setting, ui->row.buf );
}
/**
@@ -443,8 +380,8 @@ static void select_settings ( struct settings_ui *ui,
static int main_loop ( struct settings *settings ) {
struct settings_ui ui;
unsigned int previous;
+ unsigned int move;
int redraw = 1;
- int move;
int key;
int rc;
@@ -474,17 +411,17 @@ static int main_loop ( struct settings *settings ) {
assert ( ui.row.setting.name != NULL );
/* Redraw edit box */
- color_set ( CPAIR_EDIT, NULL );
- draw_editbox ( &ui.row.editbox );
- color_set ( CPAIR_NORMAL, NULL );
+ draw_widget ( &ui.row.editbox.widget );
/* Process keypress */
key = edit_setting ( &ui, getkey ( 0 ) );
switch ( key ) {
case CR:
case LF:
- if ( ( rc = save_setting ( &ui ) ) != 0 )
- alert ( " %s ", strerror ( rc ) );
+ if ( ( rc = save_setting ( &ui ) ) != 0 ) {
+ alert ( ALERT_ROW, " %s ",
+ strerror ( rc ) );
+ }
/* Fall through */
case CTRL_C:
select_setting_row ( &ui, ui.scroll.current );
@@ -521,12 +458,13 @@ static int main_loop ( struct settings *settings ) {
break;
if ( ( rc = delete_setting ( ui.settings,
&ui.row.setting ) ) != 0 ){
- alert ( " %s ", strerror ( rc ) );
+ alert ( ALERT_ROW, " %s ", strerror ( rc ) );
}
select_setting_row ( &ui, ui.scroll.current );
redraw = 1;
break;
case CTRL_X:
+ select_setting_row ( &ui, -1U );
return 0;
case CR:
case LF: