Re: [PATCH 4/4] defaultenv: Convert init script to C

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux