Hi Sascha, small note: one might want to interrupt long-running processes during the init sequence, e.g. if an init script contains a "dhcp" call or does some NFS mount, but the board is currently not connected to the network. Now it is no longer possible to interrupt such processes, even when global.autoboot_abort_key is set to anything else than "ctrl-c". Was this use case considered? - Roland On Wed, Apr 24, 2019 at 12:26:50PM +0200, Sascha Hauer wrote: > It's hard to get more complicated things right in hush. This commit > converts the /env/bin/init script to C code. With this we get a better > error handling and better control what is being done. > > If /env/bin/init exists in the environment then it is still executed > instead of the corresponding C code. > > Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > --- > common/startup.c | 188 +++++++++++++++++++++++--- > defaultenv/defaultenv-2-base/bin/init | 79 ----------- > 2 files changed, 169 insertions(+), 98 deletions(-) > delete mode 100644 defaultenv/defaultenv-2-base/bin/init > > diff --git a/common/startup.c b/common/startup.c > index 28edee4fce..9fac0eabbd 100644 > --- a/common/startup.c > +++ b/common/startup.c > @@ -42,6 +42,9 @@ > #include <asm/sections.h> > #include <uncompress.h> > #include <globalvar.h> > +#include <console_countdown.h> > +#include <environment.h> > +#include <linux/ctype.h> > > extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[], > __barebox_initcalls_end[]; > @@ -143,16 +146,172 @@ static int load_environment(void) > 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 @@ void __noreturn start_barebox(void) > > 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) > + barebox_main(); > > - if (!barebox_main) { > - pr_err("No main function! aborting.\n"); > + if (IS_ENABLED(CONFIG_SHELL_NONE)) { > + pr_err("Nothing left to do\n"); > hang(); > + } else { > + while (1) > + run_shell(); > } > - > - /* main_loop() can return to retry autoboot, if so just run it again. */ > - for (;;) > - barebox_main(); > - > - /* NOTREACHED - no way out of command loop except booting */ > } > > 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 a5d3a984f7..0000000000 > --- a/defaultenv/defaultenv-2-base/bin/init > +++ /dev/null > @@ -1,79 +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 > - > -global.console.ctrlc_allowed=true > - > -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 > -- > 2.20.1 > > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox > -- Roland Hieber | r.hieber@xxxxxxxxxxxxxx | Pengutronix e.K. | https://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim | Phone: +49-5121-206917-5086 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox