diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c index 665e819..a7ea8f2 100644 --- a/arch/sandbox/os/common.c +++ b/arch/sandbox/os/common.c @@ -94,7 +94,7 @@ return 0; } -int ctrlc(void) +int arch_ctrlc(void) { char chr; diff --git a/commands/timeout.c b/commands/timeout.c index d197ced..db88900 100644 --- a/commands/timeout.c +++ b/commands/timeout.c @@ -61,7 +61,7 @@ return COMMAND_ERROR_USAGE; timeout = simple_strtoul(argv[optind], NULL, 0); - ret = console_countdown(timeout, flags, str); + ret = console_countdown(timeout, flags, NULL, str); if (varname && str[0]) setenv(varname, str); diff --git a/common/console.c b/common/console.c index 47ccf2e..406722a 100644 --- a/common/console.c +++ b/common/console.c @@ -574,18 +574,60 @@ } EXPORT_SYMBOL(console_flush); -#ifndef ARCH_HAS_CTRLC -/* test if ctrl-c was pressed */ -int ctrlc (void) +static int ctrlc_abort; +static int ctrlc_allowed; + +void ctrlc_handled(void) { + ctrlc_abort = 0; +} + +/* test if ctrl-c was pressed */ +int ctrlc(void) +{ + int ret = 0; + + if (!ctrlc_allowed) + return 0; + + if (ctrlc_abort) + return 1; + poller_call(); +#ifdef ARCH_HAS_CTRLC + ret = arch_ctrlc(); +#else if (tstc() && getchar() == 3) - return 1; - return 0; + ret = 1; +#endif + + if (ret) + ctrlc_abort = 1; + + return ret; } EXPORT_SYMBOL(ctrlc); -#endif /* ARCH_HAS_CTRC */ + +static int console_ctrlc_init(void) +{ + globalvar_add_simple_bool("console.ctrlc_allowed", &ctrlc_allowed); + return 0; +} +device_initcall(console_ctrlc_init); + +void console_ctrlc_allow(void) +{ + ctrlc_allowed = 1; +} + +void console_ctrlc_forbid(void) +{ + ctrlc_allowed = 0; +} + +BAREBOX_MAGICVAR_NAMED(global_console_ctrlc_allowed, global.console.ctrlc_allowed, + "If true, scripts can be aborted with ctrl-c"); BAREBOX_MAGICVAR_NAMED(global_linux_bootargs_console, global.linux.bootargs.console, "console= argument for Linux from the stdout-path property in /chosen node"); diff --git a/common/console_countdown.c b/common/console_countdown.c index 36da1ce..8d09894 100644 --- a/common/console_countdown.c +++ b/common/console_countdown.c @@ -30,7 +30,22 @@ console_countdown_timeout_abort = true; } -int console_countdown(int timeout_s, unsigned flags, char *out_key) +static int key_in_list(char key, const char *keys) +{ + if (!keys) + return false; + + while (*keys) { + if (key == *keys) + return true; + keys++; + } + + return false; +} + +int console_countdown(int timeout_s, unsigned flags, const char *keys, + char *out_key) { uint64_t start, second; int countdown, ret = -EINTR; @@ -48,6 +63,8 @@ if (tstc()) { key = getchar(); if (key >= 0) { + if (key_in_list(key, keys)) + goto out; if (flags & CONSOLE_COUNTDOWN_ANYKEY) goto out; if (flags & CONSOLE_COUNTDOWN_RETURN && key == '\n') diff --git a/common/hush.c b/common/hush.c index d2f9cc7..dab9b04 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1734,7 +1734,7 @@ return 1; } b_free(&temp); - } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ + } while (!ctrlc() && rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ return code; } @@ -1932,6 +1932,7 @@ login(); do { + ctrlc_handled(); setup_file_in_str(&input); rcode = parse_stream_outer(&ctx, &input, FLAG_PARSE_SEMICOLON); if (rcode < -1) { diff --git a/common/parser.c b/common/parser.c index 397d268..fb9ef42 100644 --- a/common/parser.c +++ b/common/parser.c @@ -283,6 +283,7 @@ /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } + ctrlc_handled(); } } return 0; diff --git a/common/startup.c b/common/startup.c index 28edee4..9fac0ea 100644 --- a/common/startup.c +++ b/common/startup.c @@ -42,6 +42,9 @@ #include #include #include +#include +#include +#include extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], __barebox_initcalls_end[]; @@ -143,16 +146,172 @@ environment_initcall(load_environment); #endif +static int global_autoboot_abort_key; +static const char * const global_autoboot_abort_keys[] = { + "any", + "ctrl-c", +}; +static int global_autoboot_timeout = 3; +static char *global_boot_default; +static char *global_editcmd; +static char *global_linux_bootargs_base; +static char *global_linux_bootargs_console; +static char *global_linux_bootargs_dyn_ip; +static char *global_linux_bootargs_dyn_root; +static char *global_user; + +static bool test_abort(void) +{ + bool do_abort = false; + int c, ret; + char key; + + while (tstc()) { + c = getchar(); + if (tolower(c) == 'q' || c == 3) + do_abort = true; + } + + if (!do_abort) + return false; + + printf("Abort init sequence? (y/n)\n" + "Will continue with init sequence in:"); + + ret = console_countdown(5, CONSOLE_COUNTDOWN_EXTERN, "yYnN", &key); + if (!ret) + return false; + + if (tolower(key) == 'y') + return true; + + return false; +} + +static int run_init(void) +{ + DIR *dir; + struct dirent *d; + const char *initfile = "/env/bin/init"; + const char *initdir = "/env/init"; + const char *menufile = "/env/menu/mainmenu"; + struct stat s; + unsigned flags = CONSOLE_COUNTDOWN_EXTERN; + unsigned char outkey; + int ret; + bool menu_exists; + bool env_bin_init_exists; + char *abortkeys = NULL; + + setenv("PATH", "/env/bin"); + + /* Run legacy /env/bin/init if it exists */ + env_bin_init_exists = stat(initfile, &s) == 0; + if (env_bin_init_exists) { + pr_info("running %s...\n", initfile); + run_command(initfile); + return 0; + } + + global_editcmd = xstrdup("sedit"); + global_user = xstrdup("none"); + globalvar_add_simple_string("user", &global_user); + global_boot_default = xstrdup("net"); + + globalvar_add_simple_enum("autoboot_abort_key", + &global_autoboot_abort_key, + global_autoboot_abort_keys, + ARRAY_SIZE(global_autoboot_abort_keys)); + globalvar_add_simple_int("autoboot_timeout", + &global_autoboot_timeout, "%u"); + globalvar_add_simple_string("boot.default", &global_boot_default); + globalvar_add_simple_string("editcmd", &global_editcmd); + globalvar_add_simple_string("linux.bootargs.base", + &global_linux_bootargs_base); + globalvar_add_simple_string("linux.bootargs.console", + &global_linux_bootargs_console); + globalvar_add_simple_string("linux.bootargs.dyn.ip", + &global_linux_bootargs_dyn_ip); + globalvar_add_simple_string("linux.bootargs.dyn.root", + &global_linux_bootargs_dyn_root); + + /* Unblank console cursor */ + printf("\e[?25h"); + + if (test_abort()) { + pr_info("Init sequence aborted\n"); + return -EINTR; + } + + /* Run scripts in /env/init/ */ + dir = opendir(initdir); + if (dir) { + char *scr; + + while ((d = readdir(dir))) { + if (*d->d_name == '.') + continue; + + pr_debug("Executing '%s/%s'...\n", initdir, d->d_name); + scr = basprintf("source %s/%s", initdir, d->d_name); + run_command(scr); + free(scr); + } + + closedir(dir); + } + + menu_exists = stat(menufile, &s) == 0; + + if (menu_exists) { + printf("\nHit m for menu or %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + abortkeys = "m"; + } else { + printf("\nHit %s to stop autoboot: ", + global_autoboot_abort_keys[global_autoboot_abort_key]); + } + + switch (global_autoboot_abort_key) { + case 0: + flags |= CONSOLE_COUNTDOWN_ANYKEY; + break; + case 1: + flags |= CONSOLE_COUNTDOWN_CTRLC; + break; + default: + break; + } + + ret = console_countdown(global_autoboot_timeout, flags, abortkeys, + &outkey); + + if (ret == 0) + run_command("boot"); + + console_ctrlc_allow(); + + if (menu_exists) { + if (outkey == 'm') + run_command(menufile); + + printf("Enter 'exit' to get back to the menu\n"); + run_shell(); + run_command(menufile); + } + + return 0; +} + int (*barebox_main)(void); void __noreturn start_barebox(void) { initcall_t *initcall; int result; - struct stat s; - if (!IS_ENABLED(CONFIG_SHELL_NONE)) - barebox_main = run_shell; + if (!IS_ENABLED(CONFIG_SHELL_NONE) && IS_ENABLED(CONFIG_COMMAND_SUPPORT)) + barebox_main = run_init; for (initcall = __barebox_initcalls_start; initcall < __barebox_initcalls_end; initcall++) { @@ -165,25 +324,16 @@ pr_debug("initcalls done\n"); - if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { - pr_info("running /env/bin/init...\n"); - - if (!stat("/env/bin/init", &s)) - run_command("source /env/bin/init"); - else - pr_err("/env/bin/init not found\n"); - } - - if (!barebox_main) { - pr_err("No main function! aborting.\n"); - hang(); - } - - /* main_loop() can return to retry autoboot, if so just run it again. */ - for (;;) + if (barebox_main) barebox_main(); - /* NOTREACHED - no way out of command loop except booting */ + if (IS_ENABLED(CONFIG_SHELL_NONE)) { + pr_err("Nothing left to do\n"); + hang(); + } else { + while (1) + run_shell(); + } } void __noreturn hang (void) diff --git a/defaultenv/defaultenv-2-base/bin/init b/defaultenv/defaultenv-2-base/bin/init deleted file mode 100644 index 8d02e3d..0000000 --- a/defaultenv/defaultenv-2-base/bin/init +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/sh - -export PATH=/env/bin - -global hostname -global user -global autoboot_timeout -global autoboot_abort_key -global boot.default -global linux.bootargs.base -global linux.bootargs.console -#linux.bootargs.dyn.* will be cleared at the beginning of boot -global linux.bootargs.dyn.ip -global linux.bootargs.dyn.root -global editcmd - -[ -z "${global.hostname}" ] && global.hostname=generic -[ -z "${global.user}" ] && global.user=none -magicvar -a global.user "username (used in network filenames)" -[ -z "${global.autoboot_timeout}" ] && global.autoboot_timeout=3 -magicvar -a global.autoboot_timeout "timeout in seconds before automatic booting" -[ -z "${global.autoboot_abort_key}" ] && global.autoboot_abort_key=any -magicvar -a global.autoboot_abort_key "key to abort automatic booting (valid options: any, ctrl-c)" -[ -z "${global.boot.default}" ] && global.boot.default=net -[ -z "${global.editcmd}" ] && global.editcmd=sedit - -[ -e /env/config-board ] && /env/config-board -/env/config - -# allow to stop the boot before execute the /env/init/* -# but without waiting -timeout -s -a -v key 0 -autoboot="$?" - -echo -e -n "\e[?25h" -if [ "${key}" = "q" ]; then - exit -fi - -for i in /env/init/*; do - . $i -done - -if [ "${global.autoboot_abort_key}" = "ctrl-c" ]; then - abort_string="ctrl-c" - abort_args="-c" -else - abort_string="any key" - abort_args="-a" -fi - -if [ -e /env/menu ]; then - echo -e -n "\nHit m for menu or $abort_string to stop autoboot: " -else - echo -e -n "\nHit $abort_string to stop autoboot: " -fi - -if [ "$autoboot" = 0 ]; then - timeout $abort_args $global.autoboot_timeout -v key - autoboot="$?" -fi - -if [ "${key}" = "q" ]; then - exit -fi - -if [ "$autoboot" = 0 ]; then - boot -fi - -if [ -e /env/menu ]; then - if [ "${key}" != "m" ]; then - echo -e "\ntype exit to get to the menu" - sh - fi - /env/menu/mainmenu -fi diff --git a/include/common.h b/include/common.h index 11d26cb..723b9c7 100644 --- a/include/common.h +++ b/include/common.h @@ -68,7 +68,9 @@ long get_ram_size (volatile long *, long); /* common/console.c */ -int ctrlc (void); +int ctrlc(void); +int arch_ctrlc(void); +void ctrlc_handled(void); #ifdef ARCH_HAS_STACK_DUMP void dump_stack(void); diff --git a/include/console.h b/include/console.h index 6739213..4062e5a 100644 --- a/include/console.h +++ b/include/console.h @@ -207,4 +207,7 @@ bool console_allow_color(void); +void console_ctrlc_allow(void); +void console_ctrlc_forbid(void); + #endif diff --git a/include/console_countdown.h b/include/console_countdown.h index c6c2d5c..88cadf1 100644 --- a/include/console_countdown.h +++ b/include/console_countdown.h @@ -7,7 +7,7 @@ #define CONSOLE_COUNTDOWN_CTRLC (1 << 4) #define CONSOLE_COUNTDOWN_EXTERN (1 << 5) -int console_countdown(int timeout_s, unsigned flags, char *out_key); +int console_countdown(int timeout_s, unsigned flags, const char *keys, char *out_key); void console_countdown_abort(void); #endif /* __CONSOLE_COUNTDOWN_H */