mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/4] Shell: Handle aborting loops better
@ 2019-04-24 10:26 Sascha Hauer
  2019-04-24 10:26 ` [PATCH 2/4] console: forbid ctrlc during startup Sascha Hauer
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Sascha Hauer @ 2019-04-24 10:26 UTC (permalink / raw)
  To: Barebox List

It's easy to get stuck in an infinite loop in the hush shell:

while true; do sleep 1; done

The 'sleep' command will check for ctrl-c with the ctrlc() function. This
will abort the sleep command. Hush then checks for ctrl-c again in the
loop. The ctrl-c in the buffer has already been eaten by the sleep
command, so the loop will continue.

With this patch we remember the presence of a ctrl-c character in a
variable instead of checking for a new character each time. The
variable must be resetted explicitly by calling ctrlc_handled() which
will be called by the shell in the outer loop.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/sandbox/os/common.c |  2 +-
 common/console.c         | 28 +++++++++++++++++++++++-----
 common/hush.c            |  3 ++-
 common/parser.c          |  1 +
 include/common.h         |  4 +++-
 5 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 665e8194ef..a7ea8f2d3b 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -94,7 +94,7 @@ int linux_tstc(int fd)
 	return 0;
 }
 
-int ctrlc(void)
+int arch_ctrlc(void)
 {
 	char chr;
 
diff --git a/common/console.c b/common/console.c
index 47ccf2e54d..b6685ecf6a 100644
--- a/common/console.c
+++ b/common/console.c
@@ -574,18 +574,36 @@ void console_flush(void)
 }
 EXPORT_SYMBOL(console_flush);
 
-#ifndef ARCH_HAS_CTRLC
+static int ctrlc_abort;
+
+void ctrlc_handled(void)
+{
+	ctrlc_abort = 0;
+}
+
 /* test if ctrl-c was pressed */
-int ctrlc (void)
+int ctrlc(void)
 {
+	int ret = 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 */
 
 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/hush.c b/common/hush.c
index d2f9cc70f5..dab9b04081 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -1734,7 +1734,7 @@ static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int fla
 			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 @@ int run_shell(void)
 	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 397d268da1..fb9ef42e7f 100644
--- a/common/parser.c
+++ b/common/parser.c
@@ -283,6 +283,7 @@ int run_shell(void)
 				/* invalid command or not repeatable, forget it */
 				lastcommand[0] = 0;
 			}
+			ctrlc_handled();
 		}
 	}
 	return 0;
diff --git a/include/common.h b/include/common.h
index 11d26cb3db..723b9c706c 100644
--- a/include/common.h
+++ b/include/common.h
@@ -68,7 +68,9 @@ int	readline	(const char *prompt, char *buf, int len);
 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);
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/4] console: forbid ctrlc during startup
  2019-04-24 10:26 [PATCH 1/4] Shell: Handle aborting loops better Sascha Hauer
@ 2019-04-24 10:26 ` Sascha Hauer
  2019-04-24 10:26 ` [PATCH 3/4] console_countdown: Add pattern list Sascha Hauer
  2019-04-24 10:26 ` [PATCH 4/4] defaultenv: Convert init script to C Sascha Hauer
  2 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2019-04-24 10:26 UTC (permalink / raw)
  To: Barebox List

When global.autoboot_abort_key is set to ctrl-c then the user is
expected to press ctrl-c to get to the prompt. The user might press
ctrl-c before the init script runs the "timeout" command. In this
case the init script is aborted at arbitrary places which leads to
inconsistent results depending on the place it is aborted.

This patch introduces the global.console.ctrlc_allowed variable.
When this variable is set to false ctrl-c is ignored entirely.
The variable is set to false by default and changed to true in
the init script.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/console.c                      | 24 ++++++++++++++++++++++++
 defaultenv/defaultenv-2-base/bin/init |  2 ++
 include/console.h                     |  3 +++
 3 files changed, 29 insertions(+)

diff --git a/common/console.c b/common/console.c
index b6685ecf6a..406722a1da 100644
--- a/common/console.c
+++ b/common/console.c
@@ -575,6 +575,7 @@ void console_flush(void)
 EXPORT_SYMBOL(console_flush);
 
 static int ctrlc_abort;
+static int ctrlc_allowed;
 
 void ctrlc_handled(void)
 {
@@ -586,6 +587,9 @@ int ctrlc(void)
 {
 	int ret = 0;
 
+	if (!ctrlc_allowed)
+		return 0;
+
 	if (ctrlc_abort)
 		return 1;
 
@@ -605,5 +609,25 @@ int ctrlc(void)
 }
 EXPORT_SYMBOL(ctrlc);
 
+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/defaultenv/defaultenv-2-base/bin/init b/defaultenv/defaultenv-2-base/bin/init
index 8d02e3d3ab..a5d3a984f7 100644
--- a/defaultenv/defaultenv-2-base/bin/init
+++ b/defaultenv/defaultenv-2-base/bin/init
@@ -60,6 +60,8 @@ if [ "$autoboot" = 0 ]; then
 	autoboot="$?"
 fi
 
+global.console.ctrlc_allowed=true
+
 if [ "${key}" = "q" ]; then
 	exit
 fi
diff --git a/include/console.h b/include/console.h
index 673921331d..4062e5abf6 100644
--- a/include/console.h
+++ b/include/console.h
@@ -207,4 +207,7 @@ static inline void pbl_set_putc(void (*putcf)(void *ctx, int c), void *ctx) {}
 
 bool console_allow_color(void);
 
+void console_ctrlc_allow(void);
+void console_ctrlc_forbid(void);
+
 #endif
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/4] console_countdown: Add pattern list
  2019-04-24 10:26 [PATCH 1/4] Shell: Handle aborting loops better Sascha Hauer
  2019-04-24 10:26 ` [PATCH 2/4] console: forbid ctrlc during startup Sascha Hauer
@ 2019-04-24 10:26 ` Sascha Hauer
  2019-04-24 10:26 ` [PATCH 4/4] defaultenv: Convert init script to C Sascha Hauer
  2 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2019-04-24 10:26 UTC (permalink / raw)
  To: Barebox List

This adds an optional string argument to console_countdown() which can
hold a list of keys which also abort the countdown.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/timeout.c          |  2 +-
 common/console_countdown.c  | 19 ++++++++++++++++++-
 include/console_countdown.h |  2 +-
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/commands/timeout.c b/commands/timeout.c
index d197cedd8b..db88900287 100644
--- a/commands/timeout.c
+++ b/commands/timeout.c
@@ -61,7 +61,7 @@ static int do_timeout(int argc, char *argv[])
 		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_countdown.c b/common/console_countdown.c
index 36da1ce577..8d09894c30 100644
--- a/common/console_countdown.c
+++ b/common/console_countdown.c
@@ -30,7 +30,22 @@ void console_countdown_abort(void)
 	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 @@ int console_countdown(int timeout_s, unsigned flags, char *out_key)
 		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/include/console_countdown.h b/include/console_countdown.h
index c6c2d5c00e..88cadf11ec 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 */
-- 
2.20.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 4/4] defaultenv: Convert init script to C
  2019-04-24 10:26 [PATCH 1/4] Shell: Handle aborting loops better Sascha Hauer
  2019-04-24 10:26 ` [PATCH 2/4] console: forbid ctrlc during startup Sascha Hauer
  2019-04-24 10:26 ` [PATCH 3/4] console_countdown: Add pattern list Sascha Hauer
@ 2019-04-24 10:26 ` Sascha Hauer
  2019-04-26 12:37   ` Roland Hieber
  2 siblings, 1 reply; 6+ messages in thread
From: Sascha Hauer @ 2019-04-24 10:26 UTC (permalink / raw)
  To: Barebox List

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@pengutronix.de>
---
 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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/4] defaultenv: Convert init script to C
  2019-04-24 10:26 ` [PATCH 4/4] defaultenv: Convert init script to C Sascha Hauer
@ 2019-04-26 12:37   ` Roland Hieber
  2019-04-29  6:57     ` Sascha Hauer
  0 siblings, 1 reply; 6+ messages in thread
From: Roland Hieber @ 2019-04-26 12:37 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

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@pengutronix.de>
> ---
>  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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Roland Hieber                     | r.hieber@pengutronix.de     |
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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/4] defaultenv: Convert init script to C
  2019-04-26 12:37   ` Roland Hieber
@ 2019-04-29  6:57     ` Sascha Hauer
  0 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2019-04-29  6:57 UTC (permalink / raw)
  To: Roland Hieber; +Cc: Barebox List

On Fri, Apr 26, 2019 at 02:37:05PM +0200, Roland Hieber wrote:
> 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.

Do you have a better example? You shouldn't run dhcp in an init script.

> 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?

You can't abort the init sequence, but you can prevent it from being
executed at all. So when you are in such a situation, reset the board
and use ctrl-c or 'q' to not run the init sequence.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-04-29  6:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-24 10:26 [PATCH 1/4] Shell: Handle aborting loops better Sascha Hauer
2019-04-24 10:26 ` [PATCH 2/4] console: forbid ctrlc during startup Sascha Hauer
2019-04-24 10:26 ` [PATCH 3/4] console_countdown: Add pattern list Sascha Hauer
2019-04-24 10:26 ` [PATCH 4/4] defaultenv: Convert init script to C Sascha Hauer
2019-04-26 12:37   ` Roland Hieber
2019-04-29  6:57     ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox