#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/reboot.h>
#include "log/log.h"
#include "pb-protocol/pb-protocol.h"
#include "nc-sysinfo.h"
#include "nc-lang.h"
#include "nc-helpscreen.h"
+#include "nc-statuslog.h"
#include "nc-subset.h"
extern const struct help_text main_menu_help_text;
+static bool cui_detached = false;
+
static struct pmenu *main_menu_init(struct cui *cui);
+static bool lockdown_active(void)
+{
+ bool lockdown = false;
+ if (access(LOCKDOWN_FILE, F_OK) != -1)
+ lockdown = true;
+ return lockdown;
+}
+
static void cui_start(void)
{
initscr(); /* Initialize ncurses. */
define_key("OF", KEY_END);
define_key("\x1b\x5b\x41", KEY_UP);
define_key("\x1b\x5b\x42", KEY_DOWN);
+ define_key("\x1b\x5b\x33\x7e", KEY_DC);
while (getch() != ERR) /* flush stdin */
(void)0;
static void cui_atexit(void)
{
+ if (cui_detached)
+ return;
+
clear();
refresh();
endwin();
+
+ bool lockdown = lockdown_active();
+
+ while (lockdown) {
+ sync();
+ reboot(RB_AUTOBOOT);
+ }
}
/**
cui_set_current(cui, lang_screen_scr(cui->lang_screen));
}
+static void cui_statuslog_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->statuslog_screen);
+ cui->statuslog_screen = NULL;
+}
+
+void cui_show_statuslog(struct cui *cui)
+{
+ cui->statuslog_screen = statuslog_screen_init(cui, cui_statuslog_exit);
+ cui_set_current(cui, statuslog_screen_scr(cui->statuslog_screen));
+}
+
static void cui_add_url_exit(struct cui *cui)
{
cui_set_current(cui, &cui->main->scr);
cod->bd->initrd = talloc_strdup(cod->bd, opt->initrd_file);
cod->bd->dtb = talloc_strdup(cod->bd, opt->dtb_file);
cod->bd->args = talloc_strdup(cod->bd, opt->boot_args);
+ cod->bd->args_sig_file = talloc_strdup(cod->bd, opt->args_sig_file);
/* This disconnects items array from menu. */
result = set_menu_items(cui->main->ncm, NULL);
pb_log(" image '%s'\n", cod->bd->image);
pb_log(" initrd '%s'\n", cod->bd->initrd);
pb_log(" args '%s'\n", cod->bd->args);
+ pb_log(" argsig '%s'\n", cod->bd->args_sig_file);
/* Re-attach the items array. */
result = set_menu_items(cui->main->ncm, cui->main->items);
nc_scr_post(cui->current);
}
-static void cui_update_status(struct boot_status *status, void *arg)
+static void cui_update_status(struct status *status, void *arg)
{
struct cui *cui = cui_from_arg(arg);
- nc_scr_status_printf(cui->current,
- "%s: %s",
- status->type == BOOT_STATUS_ERROR ?
- _("Error") : _("Info"),
- status->message);
+ statuslog_append_steal(cui, cui->statuslog, status);
+ /* Ignore status messages from the backlog */
+ if (!status->backlog)
+ nc_scr_status_printf(cui->current, "%s", status->message);
}
static void cui_update_mm_title(struct cui *cui)
return 0;
}
+static int menu_statuslog_execute(struct pmenu_item *item)
+{
+ cui_show_statuslog(cui_from_item(item));
+ return 0;
+}
+
static int menu_reinit_execute(struct pmenu_item *item)
{
if (cui_from_item(item)->client)
struct pmenu_item *i;
struct pmenu *m;
int result;
+ bool lockdown = lockdown_active();
- m = pmenu_init(cui, 7, cui_on_exit);
+ m = pmenu_init(cui, 8, cui_on_exit);
if (!m) {
pb_log("%s: failed\n", __func__);
return NULL;
"Petitboot (" PACKAGE_VERSION ")");
m->scr.frame.rtitle = NULL;
m->scr.frame.help = talloc_strdup(m,
- _("Enter=accept, e=edit, n=new, x=exit, l=language, h=help"));
+ _("Enter=accept, e=edit, n=new, x=exit, l=language, g=log, h=help"));
m->scr.frame.status = talloc_strdup(m, _("Welcome to Petitboot"));
/* add a separator */
i->on_execute = menu_config_execute;
pmenu_item_insert(m, i, 2);
+ i = pmenu_item_create(m, _("System status log"));
+ i->on_execute = menu_statuslog_execute;
+ pmenu_item_insert(m, i, 3);
+
/* this label isn't translated, so we don't want a gettext() here */
i = pmenu_item_create(m, "Language");
i->on_execute = menu_lang_execute;
- pmenu_item_insert(m, i, 3);
+ pmenu_item_insert(m, i, 4);
i = pmenu_item_create(m, _("Rescan devices"));
i->on_execute = menu_reinit_execute;
- pmenu_item_insert(m, i, 4);
+ pmenu_item_insert(m, i, 5);
i = pmenu_item_create(m, _("Retrieve config from URL"));
i->on_execute = menu_add_url_execute;
- pmenu_item_insert(m, i, 5);
+ pmenu_item_insert(m, i, 6);
- i = pmenu_item_create(m, _("Exit to shell"));
+ if (lockdown)
+ i = pmenu_item_create(m, _("Reboot"));
+ else
+ i = pmenu_item_create(m, _("Exit to shell"));
i->on_execute = pmenu_exit_cb;
- pmenu_item_insert(m, i, 6);
+ pmenu_item_insert(m, i, 7);
result = pmenu_setup(m);
.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.
*
if (!cui->client) {
waiter_register_timeout(cui->waitset, 1000, cui_server_wait,
cui);
- nc_scr_status_printf(cui->current, "Info: Waiting for server");
+ nc_scr_status_printf(cui->current,
+ "Info: Waiting for device discovery");
} else {
- nc_scr_status_printf(cui->current, "Info: Connected to server!");
+ nc_scr_status_free(cui->current);
talloc_steal(cui, cui->client);
if (cui->has_input) {
- pb_log("Aborting default boot on server connect\n");
+ pb_log("Aborting default boot on pb-discover connect\n");
discover_client_cancel_default(cui->client);
}
}
cui->c_sig = pb_cui_sig;
cui->platform_info = platform_info;
cui->waitset = waitset_create(cui);
+ cui->statuslog = statuslog_init(cui);
process_init(cui, cui->waitset, false);
int cui_run(struct cui *cui)
{
+ pid_t pid;
+
assert(main);
cui->current = &cui->main->scr;
cui_atexit();
+ 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");
+ }
+
return cui->abort ? 0 : -1;
}