ncurses: Fix bad strncmp
[petitboot] / ui / ncurses / nc-cui.c
index 46b783972dbda3a2b9d97621be8425759295620c..20a90483cd07accc318546d9fc26aab48c9f72dc 100644 (file)
 #endif
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <locale.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/reboot.h>
@@ -45,6 +47,7 @@
 #include "nc-statuslog.h"
 #include "nc-subset.h"
 #include "nc-plugin.h"
+#include "console-codes.h"
 
 extern const struct help_text main_menu_help_text;
 extern const struct help_text plugin_menu_help_text;
@@ -54,6 +57,8 @@ static bool cui_detached = false;
 static struct pmenu *main_menu_init(struct cui *cui);
 static struct pmenu *plugin_menu_init(struct cui *cui);
 
+static void cui_cancel_autoboot_on_exit(struct cui *cui);
+
 static bool lockdown_active(void)
 {
        bool lockdown = false;
@@ -96,8 +101,18 @@ static void cui_start(void)
        define_key("\x1b\x4f\x46", KEY_END);
        define_key("OH", KEY_HOME);
        define_key("OF", KEY_END);
+
+       /* Arrow keys in normal cursor mode */
        define_key("\x1b\x5b\x41", KEY_UP);
        define_key("\x1b\x5b\x42", KEY_DOWN);
+       define_key("\x1b\x5b\x43", KEY_RIGHT);
+       define_key("\x1b\x5b\x44", KEY_LEFT);
+       /* Arrow keys in "application" cursor mode */
+       define_key("\x1b\x4f\x41", KEY_UP);
+       define_key("\x1b\x4f\x42", KEY_DOWN);
+       define_key("\x1b\x4f\x43", KEY_RIGHT);
+       define_key("\x1b\x4f\x44", KEY_LEFT);
+
        define_key("\x1b\x5b\x33\x7e", KEY_DC);
 
        while (getch() != ERR)          /* flush stdin */
@@ -151,7 +166,32 @@ void cui_resize(struct cui *cui)
 
 void cui_on_exit(struct pmenu *menu)
 {
-       cui_abort(cui_from_pmenu(menu));
+       struct cui *cui = cui_from_pmenu(menu);
+       char *sh_cmd;
+
+       cui_cancel_autoboot_on_exit(cui);
+
+       sh_cmd = talloc_asprintf(cui,
+               "echo \"Exiting petitboot. Type 'exit' to return.\";\
+                echo \"You may run 'pb-sos' to gather diagnostic data\";\
+                %s", pb_system_apps.sh);
+
+       if (!sh_cmd) {
+               pb_log("Failed to allocate shell arguments\n");
+               return;
+       }
+
+       const char *argv[] = {
+               pb_system_apps.sh,
+               "-c",
+               sh_cmd,
+               NULL
+       };
+
+       cui_run_cmd(cui, argv);
+
+       nc_scr_status_printf(cui->current, _("Returned from shell"));
+       talloc_free(sh_cmd);
 }
 
 /**
@@ -173,6 +213,10 @@ int cui_run_cmd(struct cui *cui, const char **cmd_argv)
 
        nc_scr_status_printf(cui->current, _("Running %s..."), cmd_argv[0]);
 
+       nc_scr_unpost(cui->current);
+       clear();
+       refresh();
+
        def_prog_mode();
        endwin();
 
@@ -182,6 +226,7 @@ int cui_run_cmd(struct cui *cui, const char **cmd_argv)
        refresh();
 
        redrawwin(cui->current->main_ncw);
+       nc_scr_post(cui->current);
 
        if (result) {
                pb_log("%s: failed: '%s'\n", __func__, cmd_argv[0]);
@@ -496,6 +541,9 @@ static bool process_global_keys(struct cui *cui, int key)
 static int cui_process_key(void *arg)
 {
        struct cui *cui = cui_from_arg(arg);
+       unsigned int i;
+       char *sequence;
+       int grab;
 
        assert(cui->current);
 
@@ -507,6 +555,29 @@ static int cui_process_key(void *arg)
                if (c == ERR)
                        break;
 
+               if (c == 27) {
+                       /*
+                        * If this is a console code sequence try to parse it
+                        * and don't treat this as a key press.
+                        */
+                       grab = getch();
+                       if (grab != ERR && grab != 27) {
+                               ungetch(grab);
+                               pb_debug("%s: Caught unhandled command sequence\n",
+                                               __func__);
+                               sequence = handle_control_sequence(cui, c);
+                               pb_debug("Caught sequence ");
+                               if (sequence) {
+                                       pb_debug("(%zu): ", strlen(sequence));
+                                       for (i = 0; i < strlen(sequence); i++)
+                                               pb_debug("0%o ", sequence[i]);
+                                       pb_debug("\n");
+                               } else
+                                       pb_debug("(0): (none)\n");
+                               continue;
+                       }
+               }
+
                if (!cui->has_input) {
                        cui->has_input = true;
                        if (cui->client) {
@@ -893,15 +964,15 @@ fallback:
         * If this option was faked above move the context under
         * the item so it is cleaned up later in cui_plugins_remove().
         */
-       if (strncmp(cod->opt->id, "dummy", strlen("dummy") == 0 &&
-                               cod->dev->type == DEVICE_TYPE_UNKNOWN)) {
+       if (strcmp(cod->opt->id, "dummy") == 0 &&
+                       cod->dev->type == DEVICE_TYPE_UNKNOWN) {
                talloc_steal(item, cod->dev);
                talloc_steal(item, cod->opt);
        }
 
        talloc_free(cod->name);
        /* Name is still tabbed across */
-       cod->name = talloc_asprintf(cod, "  %s [installed]", opt->name);
+       cod->name = talloc_asprintf(cod, _("  %s [installed]"), opt->name);
 
        cod->pd->opt = opt;
        item->on_execute = NULL;
@@ -1172,6 +1243,14 @@ static struct pmenu *main_menu_init(struct cui *cui)
                return NULL;
        }
 
+       m->n_hot_keys = 1;
+       m->hot_keys = talloc_array(m, hot_key_fn, m->n_hot_keys);
+       if (!m->hot_keys) {
+               pb_log("%s: failed to allocate hot_keys\n", __func__);
+               talloc_free(m);
+               return NULL;
+       }
+       m->hot_keys[0] = pmenu_main_hot_keys;
        m->on_new = cui_item_new;
 
        m->scr.frame.ltitle = talloc_asprintf(m,
@@ -1255,9 +1334,8 @@ static struct pmenu *plugin_menu_init(struct cui *cui)
        int result;
 
        m = pmenu_init(cui, 2, cui_plugin_menu_exit);
-       m->on_new = cui_item_new;
        m->scr.frame.ltitle = talloc_asprintf(m, _("Petitboot Plugins"));
-       m->scr.frame.rtitle = talloc_asprintf(m, NULL);
+       m->scr.frame.rtitle = talloc_asprintf(m, "%s", "");
        m->scr.frame.help = talloc_strdup(m,
                _("Enter=install, e=details, x=exit, h=help"));
        m->scr.frame.status = talloc_asprintf(m,
@@ -1268,7 +1346,7 @@ static struct pmenu *plugin_menu_init(struct cui *cui)
        item_opts_off(i->nci, O_SELECTABLE);
        pmenu_item_insert(m, i, 0);
 
-       i = pmenu_item_create(m, ("Return to Main Menu"));
+       i = pmenu_item_create(m, _("Return to Main Menu"));
        i->on_execute = pmenu_exit_cb;
        pmenu_item_insert(m, i, 1);
 
@@ -1301,31 +1379,6 @@ static struct discover_client_ops cui_client_ops = {
        .update_config = cui_update_config,
 };
 
-/* cui_server_wait_on_exit - On exit spin until the server is available.
- *
- * If the program exits before connecting to the server autoboot won't be
- * cancelled even though there has been keyboard activity. This function is
- * called by a child process which will spin until the server is connected and
- * told to cancel autoboot.
- *
- * Processes exiting from this function will not carry out the cui_atexit()
- * steps.
- */
-static void cui_server_wait_on_exit(struct cui *cui)
-{
-       cui_detached = true;
-
-       while (!cui->client) {
-               cui->client = discover_client_init(cui->waitset,
-                               &cui_client_ops, cui);
-               if (!cui->client)
-                       sleep(1);
-       }
-
-       talloc_steal(cui, cui->client);
-       discover_client_cancel_default(cui->client);
-}
-
 /* cui_server_wait - Connect to the discover server.
  * @arg: Pointer to the cui instance.
  *
@@ -1474,6 +1527,41 @@ fail_alloc:
        return NULL;
 }
 
+/**
+ * cui_cancel_autoboot_on_exit - On exit spin until the server is available.
+ *
+ * If the program exits before connecting to the server autoboot won't be
+ * cancelled even though there has been keyboard activity. A child is forked
+ * which will spin until the server is connected and told to cancel autoboot.
+ */
+static void cui_cancel_autoboot_on_exit(struct cui *cui)
+{
+       pid_t pid;
+
+       if (!cui->client) {
+               /* Fork a child to tell the server to cancel autoboot */
+               pid = fork();
+               if (!pid) {
+                       cui_detached = true;
+
+                       /* Loop until connection established */
+                       while (!cui->client) {
+                               cui->client = discover_client_init(cui->waitset,
+                                               &cui_client_ops, cui);
+                               if (!cui->client)
+                                       sleep(1);
+                       }
+
+                       talloc_steal(cui, cui->client);
+                       discover_client_cancel_default(cui->client);
+                       exit(EXIT_SUCCESS);
+               }
+               if (pid < 0)
+                       pb_log("Failed to fork child on exit: %m\n");
+       } else
+               discover_client_cancel_default(cui->client);
+}
+
 /**
  * cui_run - The main cui program loop.
  * @cui: The cui instance.
@@ -1486,9 +1574,8 @@ fail_alloc:
 
 int cui_run(struct cui *cui)
 {
-       pid_t pid;
-
-       assert(main);
+       assert(cui);
+       assert(cui->main);
 
        cui->current = &cui->main->scr;
        cui->default_item = 0;
@@ -1512,18 +1599,9 @@ int cui_run(struct cui *cui)
                }
        }
 
-       cui_atexit();
+       cui_cancel_autoboot_on_exit(cui);
 
-       if (!cui->client) {
-               /* Fork a child to tell the server to cancel autoboot */
-               pid = fork();
-               if (!pid) {
-                       cui_server_wait_on_exit(cui);
-                       exit(EXIT_SUCCESS);
-               }
-               if (pid < 0)
-                       pb_log("Failed to fork child on exit: %m\n");
-       }
+       cui_atexit();
 
        return cui->abort ? 0 : -1;
 }