From 940c7206c2a4acb386ab47199a6c313c04387f3b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 2 Mar 2011 04:07:14 +0100 Subject: convert "do {...} while (1);" -> "while (1) {...}" Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/ash.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 98d2c7c29..c3c953656 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3539,12 +3539,12 @@ set_curjob(struct job *jp, unsigned mode) /* first remove from list */ jpp = curp = &curjob; - do { + while (1) { jp1 = *jpp; if (jp1 == jp) break; jpp = &jp1->prev_job; - } while (1); + } *jpp = jp1->prev_job; /* Then re-insert in correct position */ @@ -3560,14 +3560,14 @@ set_curjob(struct job *jp, unsigned mode) case CUR_RUNNING: /* newly created job or backgrounded job, put after all stopped jobs. */ - do { + while (1) { jp1 = *jpp; #if JOBS if (!jp1 || jp1->state != JOBSTOPPED) #endif break; jpp = &jp1->prev_job; - } while (1); + } /* FALLTHROUGH */ #if JOBS case CUR_STOPPED: @@ -3740,7 +3740,7 @@ setjobctl(int on) goto out; /* fd is a tty at this point */ close_on_exec_on(fd); - do { /* while we are in the background */ + while (1) { /* while we are in the background */ pgrp = tcgetpgrp(fd); if (pgrp < 0) { out: @@ -3751,7 +3751,7 @@ setjobctl(int on) if (pgrp == getpgrp()) break; killpg(0, SIGTTIN); - } while (1); + } initialpgrp = pgrp; setsignal(SIGTSTP); @@ -5970,7 +5970,7 @@ expari(int quotes) p = expdest - 1; *p = '\0'; p--; - do { + while (1) { int esc; while ((unsigned char)*p != CTLARI) { @@ -5988,7 +5988,7 @@ expari(int quotes) } p -= esc + 1; - } while (1); + } begoff = p - start; -- cgit v1.2.3-55-g6feb From aefe1c260ec5aa691e8b6f773c7fa393bfad0f7b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Mon, 7 Mar 2011 12:02:40 +0100 Subject: ash: fix execution of shell scripts without shebang We were assuming #!/bin/sh, whereas we had to simply re-enter ash. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/ash.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index c3c953656..09db046fe 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7396,8 +7396,6 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ static void tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) { - int repeated = 0; - #if ENABLE_FEATURE_SH_STANDALONE if (applet_no >= 0) { if (APPLET_IS_NOEXEC(applet_no)) { @@ -7421,25 +7419,36 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** #else execve(cmd, argv, envp); #endif - if (repeated) { + if (cmd == (char*) bb_busybox_exec_path) { + /* We already visited ENOEXEC branch below, don't do it again */ +//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? free(argv); return; } if (errno == ENOEXEC) { + /* Run "cmd" as a shell script: + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html + * "If the execve() function fails with ENOEXEC, the shell + * shall execute a command equivalent to having a shell invoked + * with the command name as its first operand, + * with any remaining arguments passed to the new shell" + * + * That is, do not use $SHELL, user's shell, or /bin/sh; + * just call ourselves. + */ char **ap; char **new; for (ap = argv; *ap; ap++) continue; - ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); - ap[1] = cmd; - ap[0] = cmd = (char *)DEFAULT_SHELL; - ap += 2; - argv++; - while ((*ap++ = *argv++) != NULL) + new = ckmalloc((ap - argv + 2) * sizeof(new[0])); + new[0] = (char*) "ash"; + new[1] = cmd; + ap = new + 2; + while ((*ap++ = *++argv) != NULL) continue; + cmd = (char*) bb_busybox_exec_path; argv = new; - repeated++; goto repeat; } } -- cgit v1.2.3-55-g6feb From b0b834342ffece7f3debd8c7199a07ce8a6d942c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Mon, 7 Mar 2011 12:34:59 +0100 Subject: ash/hush: provide help text $ ./busybox ash --help BusyBox v1.19.0.git (2011-03-07 11:25:29 CET) multi-call binary. Usage: ash [-/+OPTCHARS] [-/+o OPTNAME]... [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]] Unix shell interpreter $ ./busybox hush --help BusyBox v1.19.0.git (2011-03-07 11:25:29 CET) multi-call binary. Usage: hush [-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]] Unix shell interpreter function old new delta packed_usage 28163 28212 +49 setcmd 85 78 -7 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 49/-7) Total: 42 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/ash.c | 40 ++++++++++++++++++++++++++-------------- shell/hush.c | 21 ++++++++++++++------- 2 files changed, 40 insertions(+), 21 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 09db046fe..bfbd60d78 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -190,13 +190,6 @@ //config: variable each time it is displayed. //config: -//usage:#define ash_trivial_usage NOUSAGE_STR -//usage:#define ash_full_usage "" -//usage:#define sh_trivial_usage NOUSAGE_STR -//usage:#define sh_full_usage "" -//usage:#define bash_trivial_usage NOUSAGE_STR -//usage:#define bash_full_usage "" - /* ============ Hash table sizes. Configurable. */ @@ -10155,6 +10148,7 @@ setoption(int flag, int val) /* NOTREACHED */ } static int + options(int cmdline) { char *p; @@ -10180,7 +10174,7 @@ options(int cmdline) else if (*argptr == NULL) setparam(argptr); } - break; /* "-" or "--" terminates options */ + break; /* "-" or "--" terminates options */ } } /* first char was + or - */ @@ -10282,10 +10276,10 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!argv[1]) return showvars(nullstr, 0, VUNSET); + INT_OFF; - retval = 1; - if (!options(0)) { /* if no parse error... */ - retval = 0; + retval = options(/*cmdline:*/ 0); + if (retval == 0) { /* if no parse error... */ optschanged(); if (*argptr != NULL) { setparam(argptr); @@ -12938,14 +12932,32 @@ init(void) setvar("PPID", utoa(getppid()), 0); p = lookupvar("PWD"); - if (p) + if (p) { if (*p != '/' || stat(p, &st1) || stat(".", &st2) - || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino + ) { p = '\0'; + } + } setpwd(p, 0); } } + +//usage:#define ash_trivial_usage +//usage: "[-/+OPTCHARS] [-/+o OPTNAME]... [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]]" +//usage:#define ash_full_usage "\n\n" +//usage: "Unix shell interpreter" + +//usage:#if ENABLE_FEATURE_SH_IS_ASH +//usage:# define sh_trivial_usage ash_trivial_usage +//usage:# define sh_full_usage ash_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_ASH +//usage:# define bash_trivial_usage ash_trivial_usage +//usage:# define bash_full_usage ash_full_usage +//usage:#endif + /* * Process the shell command line arguments. */ @@ -12963,7 +12975,7 @@ procargs(char **argv) for (i = 0; i < NOPTS; i++) optlist[i] = 2; argptr = xargv; - if (options(1)) { + if (options(/*cmdline:*/ 1)) { /* it already printed err message */ raise_exception(EXERROR); } diff --git a/shell/hush.c b/shell/hush.c index 4d9e5f8c7..6b3dc46d4 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -255,14 +255,21 @@ * therefore we don't show them either. */ //usage:#define hush_trivial_usage -//usage: "[-nx] [-c SCRIPT]" -//usage:#define hush_full_usage "" +//usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]]" +//usage:#define hush_full_usage "\n\n" +//usage: "Unix shell interpreter" + //usage:#define msh_trivial_usage hush_trivial_usage -//usage:#define msh_full_usage "" -//usage:#define sh_trivial_usage NOUSAGE_STR -//usage:#define sh_full_usage "" -//usage:#define bash_trivial_usage NOUSAGE_STR -//usage:#define bash_full_usage "" +//usage:#define msh_full_usage hush_full_usage + +//usage:#if ENABLE_FEATURE_SH_IS_HUSH +//usage:# define sh_trivial_usage hush_trivial_usage +//usage:# define sh_full_usage hush_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_HUSH +//usage:# define bash_trivial_usage hush_trivial_usage +//usage:# define bash_full_usage hush_full_usage +//usage:#endif /* Build knobs */ -- cgit v1.2.3-55-g6feb From 976ec23da5a335572be9a6130fb4efcc08d62d0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Mon, 7 Mar 2011 13:12:01 +0100 Subject: remove stray empty line Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/ash.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index bfbd60d78..dc50bc102 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10148,7 +10148,6 @@ setoption(int flag, int val) /* NOTREACHED */ } static int - options(int cmdline) { char *p; -- cgit v1.2.3-55-g6feb From 6b6af53426d98ab513972bd710f250e246e7fc98 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Tue, 8 Mar 2011 10:24:17 +0100 Subject: ash/hush: shrink help text Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/ash.c | 2 +- shell/hush.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index dc50bc102..0baf7c8e5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12944,7 +12944,7 @@ init(void) //usage:#define ash_trivial_usage -//usage: "[-/+OPTCHARS] [-/+o OPTNAME]... [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]]" +//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" //usage:#define ash_full_usage "\n\n" //usage: "Unix shell interpreter" diff --git a/shell/hush.c b/shell/hush.c index 6b3dc46d4..64d5e8587 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -255,7 +255,7 @@ * therefore we don't show them either. */ //usage:#define hush_trivial_usage -//usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / SCRIPT_FILE [ARGS]]" +//usage: "[-nx] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" //usage:#define hush_full_usage "\n\n" //usage: "Unix shell interpreter" -- cgit v1.2.3-55-g6feb From 20704f066250744c0c2b84920c27d0fd0aa9e935 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Wed, 23 Mar 2011 17:59:27 +0100 Subject: ash,hush: recheck LANG before every line input Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- include/unicode.h | 4 ++++ libbb/unicode.c | 28 +++++++++++++++++----------- shell/ash.c | 23 +++++++++++++++-------- shell/hush.c | 25 ++++++++++++++++--------- 4 files changed, 52 insertions(+), 28 deletions(-) (limited to 'shell') diff --git a/include/unicode.h b/include/unicode.h index dee02e777..0317a2151 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -27,6 +27,7 @@ enum { # define unicode_strwidth(string) strlen(string) # define unicode_status UNICODE_OFF # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) #else @@ -67,6 +68,7 @@ char* FAST_FUNC unicode_conv_to_printable_fixedwidth(/*uni_stat_t *stats,*/ cons extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # else @@ -75,9 +77,11 @@ void init_unicode(void) FAST_FUNC; # if !ENABLE_FEATURE_CHECK_UNICODE_IN_ENV # define unicode_status UNICODE_ON # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) # else extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # endif # undef MB_CUR_MAX diff --git a/libbb/unicode.c b/libbb/unicode.c index 08a4c7427..d01efd9a2 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -23,37 +23,43 @@ uint8_t unicode_status; /* Unicode support using libc locale support. */ -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG UNUSED_PARAM) { static const char unicode_0x394[] = { 0xce, 0x94, 0 }; size_t width; - if (unicode_status != UNICODE_UNKNOWN) - return; +//TODO: call setlocale(LC_ALL, LANG) here? + /* In unicode, this is a one character string */ // can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused width = mbstowcs(NULL, unicode_0x394, INT_MAX); unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF); } +void FAST_FUNC init_unicode(void) +{ + if (unicode_status == UNICODE_UNKNOWN) + reinit_unicode(NULL /*getenv("LANG")*/); +} + #else /* Homegrown Unicode support. It knows only C and Unicode locales. */ # if ENABLE_FEATURE_CHECK_UNICODE_IN_ENV -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG) { - char *lang; - - if (unicode_status != UNICODE_UNKNOWN) - return; - unicode_status = UNICODE_OFF; - lang = getenv("LANG"); - if (!lang || !(strstr(lang, ".utf") || strstr(lang, ".UTF"))) + if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF"))) return; unicode_status = UNICODE_ON; } + +void FAST_FUNC init_unicode(void) +{ + if (unicode_status == UNICODE_UNKNOWN) + reinit_unicode(getenv("LANG")); +} # endif static size_t wcrtomb_internal(char *s, wchar_t wc) diff --git a/shell/ash.c b/shell/ash.c index 0baf7c8e5..1520c5ae5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -36,12 +36,14 @@ #define JOBS ENABLE_ASH_JOB_CONTROL -#include "busybox.h" /* for applet_names */ #include <paths.h> #include <setjmp.h> #include <fnmatch.h> #include <sys/times.h> +#include "busybox.h" /* for applet_names */ +#include "unicode.h" + #include "shell_common.h" #if ENABLE_SH_MATH_SUPPORT # include "math.h" @@ -72,13 +74,6 @@ # error "Do not even bother, ash will not run on NOMMU machine" #endif -//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) -//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) -//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) - -//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o -//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o - //config:config ASH //config: bool "ash" //config: default y @@ -190,6 +185,13 @@ //config: variable each time it is displayed. //config: +//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o +//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o + /* ============ Hash table sizes. Configurable. */ @@ -9626,6 +9628,11 @@ preadfd(void) # if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); # endif + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + reinit_unicode(lookupvar("LANG")); nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); if (nr == 0) { /* Ctrl+C pressed */ diff --git a/shell/hush.c b/shell/hush.c index 64d5e8587..339f3349a 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -81,7 +81,6 @@ * $ "export" i=`echo 'aaa bbb'`; echo "$i" * aaa */ -#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ || defined(__APPLE__) \ ) @@ -93,6 +92,8 @@ # include <fnmatch.h> #endif +#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ +#include "unicode.h" #include "shell_common.h" #include "math.h" #include "match.h" @@ -105,14 +106,6 @@ # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif -//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) -//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) -//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) -//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) - -//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o -//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o - //config:config HUSH //config: bool "hush" //config: default y @@ -249,6 +242,14 @@ //config: msh is deprecated and will be removed, please migrate to hush. //config: +//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o +//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o + /* -i (interactive) and -s (read stdin) are also accepted, * but currently do nothing, therefore aren't shown in help. * NOMMU-specific options are not meant to be used by users, @@ -1906,6 +1907,12 @@ static void get_user_input(struct in_str *i) /* Enable command line editing only while a command line * is actually being read */ do { + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + reinit_unicode(get_local_var_value("LANG")); + G.flag_SIGINT = 0; /* buglet: SIGINT will not make new prompt to appear _at once_, * only after <Enter>. (^C will work) */ -- cgit v1.2.3-55-g6feb From 68d5cb5dacbc80347119ac9cff365e5f04105ef1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Thu, 24 Mar 2011 02:50:03 +0100 Subject: hush: fix a case where return in sourced file has no effect Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/hush.c | 4 ++++ shell/hush_test/hush-misc/return1.right | 1 + shell/hush_test/hush-misc/return1.tests | 4 ++++ 3 files changed, 9 insertions(+) create mode 100644 shell/hush_test/hush-misc/return1.right create mode 100755 shell/hush_test/hush-misc/return1.tests (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 339f3349a..8154ac47b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -5554,6 +5554,10 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) debug_printf_exec("parse_and_run_stream: run_and_free_list\n"); run_and_free_list(pipe_list); empty = 0; +#if ENABLE_HUSH_FUNCTIONS + if (G.flag_return_in_progress == 1) + break; +#endif } } diff --git a/shell/hush_test/hush-misc/return1.right b/shell/hush_test/hush-misc/return1.right new file mode 100644 index 000000000..7b24a35ff --- /dev/null +++ b/shell/hush_test/hush-misc/return1.right @@ -0,0 +1 @@ +Ok:0 diff --git a/shell/hush_test/hush-misc/return1.tests b/shell/hush_test/hush-misc/return1.tests new file mode 100755 index 000000000..eeb92ef3f --- /dev/null +++ b/shell/hush_test/hush-misc/return1.tests @@ -0,0 +1,4 @@ +echo "true && return; echo Should not be printed" >return_sourced +. ./return_sourced +rm return_sourced +echo Ok:$? -- cgit v1.2.3-55-g6feb From 3eab24e64a65746ed9fcc5bed3e9a19a489b0573 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Thu, 24 Mar 2011 05:25:59 +0100 Subject: hush: make parse errors in sourced file non-fatal in interactive script Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/hush.c | 97 ++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 45 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 8154ac47b..e4c3a7d77 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1095,17 +1095,10 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s) die_if_script(lineno, "syntax error: unterminated %s", s); } -/* It so happens that all such cases are totally fatal - * even if shell is interactive: EOF while looking for closing - * delimiter. There is nowhere to read stuff from after that, - * it's EOF! The only choice is to terminate. - */ -static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; static void syntax_error_unterm_ch(unsigned lineno, char ch) { char msg[2] = { ch, '\0' }; syntax_error_unterm_str(lineno, msg); - xfunc_die(); } static void syntax_error_unexpected_ch(unsigned lineno, int ch) @@ -3539,39 +3532,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx, #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS /* Subroutines for copying $(...) and `...` things */ -static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); /* '...' */ -static void add_till_single_quote(o_string *dest, struct in_str *input) +static int add_till_single_quote(o_string *dest, struct in_str *input) { while (1) { int ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch('\''); - /*xfunc_die(); - redundant */ + return 0; } if (ch == '\'') - return; + return 1; o_addchr(dest, ch); } } /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ -static void add_till_double_quote(o_string *dest, struct in_str *input) +static int add_till_double_quote(o_string *dest, struct in_str *input) { while (1) { int ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch('"'); - /*xfunc_die(); - redundant */ + return 0; } if (ch == '"') - return; + return 1; if (ch == '\\') { /* \x. Copy both chars. */ o_addchr(dest, ch); ch = i_getch(input); } o_addchr(dest, ch); if (ch == '`') { - add_till_backquote(dest, input, /*in_dquote:*/ 1); + if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) + return 0; o_addchr(dest, ch); continue; } @@ -3592,12 +3586,12 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) * Example Output * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST */ -static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) { while (1) { int ch = i_getch(input); if (ch == '`') - return; + return 1; if (ch == '\\') { /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ ch = i_getch(input); @@ -3611,7 +3605,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquo } if (ch == EOF) { syntax_error_unterm_ch('`'); - /*xfunc_die(); - redundant */ + return 0; } o_addchr(dest, ch); } @@ -3647,7 +3641,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch(end_ch); - /*xfunc_die(); - redundant */ + return 0; } if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { if (!dbl) @@ -3661,22 +3655,26 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign o_addchr(dest, ch); if (ch == '(' || ch == '{') { ch = (ch == '(' ? ')' : '}'); - add_till_closing_bracket(dest, input, ch); + if (!add_till_closing_bracket(dest, input, ch)) + return 0; o_addchr(dest, ch); continue; } if (ch == '\'') { - add_till_single_quote(dest, input); + if (!add_till_single_quote(dest, input)) + return 0; o_addchr(dest, ch); continue; } if (ch == '"') { - add_till_double_quote(dest, input); + if (!add_till_double_quote(dest, input)) + return 0; o_addchr(dest, ch); continue; } if (ch == '`') { - add_till_backquote(dest, input, /*in_dquote:*/ 0); + if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) + return 0; o_addchr(dest, ch); continue; } @@ -3685,7 +3683,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch(')'); - /*xfunc_die(); - redundant */ + return 0; } o_addchr(dest, ch); continue; @@ -3756,8 +3754,8 @@ static int parse_dollar(o_string *as_string, ) { bad_dollar_syntax: syntax_error_unterm_str("${name}"); - debug_printf_parse("parse_dollar return 1: unterminated ${name}\n"); - return 1; + debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); + return 0; } nommu_addchr(as_string, ch); ch |= quote_mask; @@ -3813,6 +3811,8 @@ static int parse_dollar(o_string *as_string, pos = dest->length; #if ENABLE_HUSH_DOLLAR_OPS last_ch = add_till_closing_bracket(dest, input, end_ch); + if (last_ch == 0) /* error? */ + return 0; #else #error Simple code to only allow ${var} is not implemented #endif @@ -3857,7 +3857,8 @@ static int parse_dollar(o_string *as_string, o_addchr(dest, /*quote_mask |*/ '+'); if (!BB_MMU) pos = dest->length; - add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); + if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) + return 0; /* error */ if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, ')'); @@ -3872,7 +3873,8 @@ static int parse_dollar(o_string *as_string, o_addchr(dest, quote_mask | '`'); if (!BB_MMU) pos = dest->length; - add_till_closing_bracket(dest, input, ')'); + if (!add_till_closing_bracket(dest, input, ')')) + return 0; /* error */ if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, ')'); @@ -3899,8 +3901,8 @@ static int parse_dollar(o_string *as_string, default: o_addQchr(dest, '$'); } - debug_printf_parse("parse_dollar return 0\n"); - return 0; + debug_printf_parse("parse_dollar return 1 (ok)\n"); + return 1; #undef as_string } @@ -3941,13 +3943,13 @@ static int encode_string(o_string *as_string, if (ch != EOF) nommu_addchr(as_string, ch); if (ch == dquote_end) { /* may be only '"' or EOF */ - debug_printf_parse("encode_string return 0\n"); - return 0; + debug_printf_parse("encode_string return 1 (ok)\n"); + return 1; } /* note: can't move it above ch == dquote_end check! */ if (ch == EOF) { syntax_error_unterm_ch('"'); - /*xfunc_die(); - redundant */ + return 0; /* error */ } next = '\0'; if (ch != '\n') { @@ -3978,10 +3980,10 @@ static int encode_string(o_string *as_string, goto again; } if (ch == '$') { - if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) { - debug_printf_parse("encode_string return 1: " - "parse_dollar returned non-0\n"); - return 1; + if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { + debug_printf_parse("encode_string return 0: " + "parse_dollar returned 0 (error)\n"); + return 0; } goto again; } @@ -3990,7 +3992,8 @@ static int encode_string(o_string *as_string, //unsigned pos = dest->length; o_addchr(dest, SPECIAL_VAR_SYMBOL); o_addchr(dest, 0x80 | '`'); - add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); + if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) + return 0; /* error */ o_addchr(dest, SPECIAL_VAR_SYMBOL); //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); goto again; @@ -4061,8 +4064,8 @@ static struct pipe *parse_stream(char **pstring, /* end_trigger == '}' case errors out earlier, * checking only ')' */ if (end_trigger == ')') { - syntax_error_unterm_ch('('); /* exits */ - /* goto parse_error; */ + syntax_error_unterm_ch('('); + goto parse_error; } if (done_word(&dest, &ctx)) { @@ -4353,9 +4356,9 @@ static struct pipe *parse_stream(char **pstring, dest.has_quoted_part = 1; break; case '$': - if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { + if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { debug_printf_parse("parse_stream parse error: " - "parse_dollar returned non-0\n"); + "parse_dollar returned 0 (error)\n"); goto parse_error; } break; @@ -4365,7 +4368,7 @@ static struct pipe *parse_stream(char **pstring, ch = i_getch(input); if (ch == EOF) { syntax_error_unterm_ch('\''); - /*xfunc_die(); - redundant */ + goto parse_error; } nommu_addchr(&ctx.as_string, ch); if (ch == '\'') @@ -4377,7 +4380,7 @@ static struct pipe *parse_stream(char **pstring, dest.has_quoted_part = 1; if (dest.o_assignment == NOT_ASSIGNMENT) dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; - if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) + if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) goto parse_error; dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; break; @@ -4388,7 +4391,8 @@ static struct pipe *parse_stream(char **pstring, o_addchr(&dest, SPECIAL_VAR_SYMBOL); o_addchr(&dest, '`'); pos = dest.length; - add_till_backquote(&dest, input, /*in_dquote:*/ 0); + if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) + goto parse_error; # if !BB_MMU o_addstr(&ctx.as_string, dest.data + pos); o_addchr(&ctx.as_string, '`'); @@ -4664,6 +4668,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int */ setup_string_in_str(&input, str); encode_string(NULL, &dest, &input, EOF, process_bkslash); +//TODO: error check (encode_string returns 0 on error)? //bb_error_msg("'%s' -> '%s'", str, dest.data); exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); @@ -8625,6 +8630,8 @@ static int FAST_FUNC builtin_source(char **argv) #endif save_and_replace_G_args(&sv, argv); +//TODO: syntax errors in sourced file should never abort the "calling" script. +//Try: bash -c '. ./bad_file; echo YES' parse_and_run_file(input); fclose(input); -- cgit v1.2.3-55-g6feb From c162bcdcd1c5cb000a8ceaf4413d4abdfa6e3dfc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko <vda.linux@googlemail.com> Date: Thu, 24 Mar 2011 05:38:51 +0100 Subject: hush: document a bug about aborting on sourced file error when non-interactive Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> --- shell/hush_test/hush-misc/source1.right | 5 +++++ shell/hush_test/hush-misc/source1.tests | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 shell/hush_test/hush-misc/source1.right create mode 100755 shell/hush_test/hush-misc/source1.tests (limited to 'shell') diff --git a/shell/hush_test/hush-misc/source1.right b/shell/hush_test/hush-misc/source1.right new file mode 100644 index 000000000..d4256034b --- /dev/null +++ b/shell/hush_test/hush-misc/source1.right @@ -0,0 +1,5 @@ +hush: syntax error: unterminated ${name} +line2 +Ok1:0 +hush: syntax error: unterminated ' +Ok2:1 diff --git a/shell/hush_test/hush-misc/source1.tests b/shell/hush_test/hush-misc/source1.tests new file mode 100755 index 000000000..c13888359 --- /dev/null +++ b/shell/hush_test/hush-misc/source1.tests @@ -0,0 +1,10 @@ +echo 'echo ${^} +echo line2' >sourced1 +. ./sourced1 +echo Ok1:$? + +echo "echo '" >sourced1 +. ./sourced1 +echo Ok2:$? + +rm sourced1 -- cgit v1.2.3-55-g6feb