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 <[email protected]>
> ---
>  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
> [email protected]
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Roland Hieber                     | [email protected]     |
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
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to