From 6f97b30a904407c1f1701d937d9258ca9175c6ab Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 29 Sep 2017 18:17:25 +0200 Subject: use %m printf specifier where appropriate function old new delta out 85 75 -10 udhcpd_main 1472 1461 -11 open_stdio_to_tty 98 85 -13 init_exec 245 232 -13 udhcpc_main 2763 2749 -14 do_cmd 4771 4755 -16 status_line_bold_errno 32 14 -18 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/7 up/down: 0/-95) Total: -95 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 3fa7f4d9f..39705a350 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -1312,16 +1312,9 @@ ash_msg_and_raise_error(const char *msg, ...) } /* - * Use '%m' to append error string on platforms that support it, '%s' and - * strerror() on those that don't. - * * 'fmt' must be a string literal. */ -#ifdef HAVE_PRINTF_PERCENTM -#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %m", ##__VA_ARGS__) -#else -#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %s", ##__VA_ARGS__, strerror(errno)) -#endif +#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": "STRERROR_FMT, ##__VA_ARGS__ STRERROR_ERRNO) static void raise_error_syntax(const char *) NORETURN; static void -- cgit v1.2.3-55-g6feb From a2e32b324eb7440f0cd4992f54f7a5822c145e91 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 12 Oct 2017 19:20:13 +0200 Subject: ash: survive failures in $PS1 expansion. Closes 10371 function old new delta expandstr 120 209 +89 Signed-off-by: Denys Vlasenko --- shell/ash.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 39705a350..ef81ea70f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12656,7 +12656,24 @@ expandstr(const char *ps, int syntax_type) saveprompt = doprompt; doprompt = 0; - readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); + + /* readtoken1() might die horribly. + * Try a prompt with syntacticallyt wrong command: + * PS1='$(date "+%H:%M:%S) > ' + */ + { + volatile int saveint; + struct jmploc *volatile savehandler = exception_handler; + struct jmploc jmploc; + SAVE_INT(saveint); + if (setjmp(jmploc.loc) == 0) { + exception_handler = &jmploc; + readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); + } + exception_handler = savehandler; + RESTORE_INT(saveint); + } + doprompt = saveprompt; popfile(); -- cgit v1.2.3-55-g6feb From 3c183a8758e83f6809f77355e019ab98e5fd596b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 12 Oct 2017 19:35:42 +0200 Subject: typo fix Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index ef81ea70f..f60daefc1 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12658,7 +12658,7 @@ expandstr(const char *ps, int syntax_type) doprompt = 0; /* readtoken1() might die horribly. - * Try a prompt with syntacticallyt wrong command: + * Try a prompt with syntactically wrong command: * PS1='$(date "+%H:%M:%S) > ' */ { -- cgit v1.2.3-55-g6feb From 14c85eb7db918daa1914a0e60081b1d3ca12ae04 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 12 Oct 2017 19:40:47 +0200 Subject: whitespace fixes Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index f60daefc1..88e607f08 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12742,7 +12742,7 @@ evalstring(char *s, int flags) exception_handler = savehandler; if (ex) - longjmp(exception_handler->loc, ex); + longjmp(exception_handler->loc, ex); return status; } @@ -13556,8 +13556,8 @@ umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } } else { char *modestr = *argptr; - /* numeric umasks are taken as-is */ - /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ + /* numeric umasks are taken as-is */ + /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ if (!isdigit(modestr[0])) mask ^= 0777; mask = bb_parse_mode(modestr, mask); -- cgit v1.2.3-55-g6feb From 25f3b737dc04bb84fb593ace33a5c360163bd4e4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 22 Oct 2017 15:55:48 +0200 Subject: hush: fix comment parsing in `cmd`, closes 10421 function old new delta parse_stream 2692 2690 -2 Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-parsing/comment2.right | 4 ++++ shell/ash_test/ash-parsing/comment2.tests | 13 +++++++++++++ shell/hush.c | 17 +++++++++++++---- shell/hush_test/hush-parsing/comment2.right | 4 ++++ shell/hush_test/hush-parsing/comment2.tests | 13 +++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 shell/ash_test/ash-parsing/comment2.right create mode 100755 shell/ash_test/ash-parsing/comment2.tests create mode 100644 shell/hush_test/hush-parsing/comment2.right create mode 100755 shell/hush_test/hush-parsing/comment2.tests (limited to 'shell') diff --git a/shell/ash_test/ash-parsing/comment2.right b/shell/ash_test/ash-parsing/comment2.right new file mode 100644 index 000000000..ee6e49a5a --- /dev/null +++ b/shell/ash_test/ash-parsing/comment2.right @@ -0,0 +1,4 @@ +Ok1 +Ok2 +Ok5 +Ok6 diff --git a/shell/ash_test/ash-parsing/comment2.tests b/shell/ash_test/ash-parsing/comment2.tests new file mode 100755 index 000000000..b7adad96a --- /dev/null +++ b/shell/ash_test/ash-parsing/comment2.tests @@ -0,0 +1,13 @@ +echo "`echo Ok1 #comment is ignored`" +echo `echo Ok2 #comment is ignored` +# +# Surprisingly, bash does not handle comments in $() +# the same way as in ``. "#" causes the rest of the line, _including_ )", +# to be ignored. These lines would cause an error: +#echo "$(echo Ok3 #comment is ignored)" +#echo $(echo Ok4 #comment is ignored) +# +echo "$(echo Ok5 #comment is ignored +)" +echo $(echo Ok6 #comment is ignored +) diff --git a/shell/hush.c b/shell/hush.c index d27550ba0..708555ac4 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -5140,14 +5140,23 @@ static struct pipe *parse_stream(char **pstring, case '#': if (dest.length == 0 && !dest.has_quoted_part) { /* skip "#comment" */ + /* note: we do not add it to &ctx.as_string */ +/* TODO: in bash: + * comment inside $() goes to the next \n, even inside quoted string (!): + * cmd "$(cmd2 #comment)" - syntax error + * cmd "`cmd2 #comment`" - ok + * We accept both (comment ends where command subst ends, in both cases). + */ while (1) { ch = i_peek(input); - if (ch == EOF || ch == '\n') + if (ch == '\n') { + nommu_addchr(&ctx.as_string, '\n'); + break; + } + ch = i_getch(input); + if (ch == EOF) break; - i_getch(input); - /* note: we do not add it to &ctx.as_string */ } - nommu_addchr(&ctx.as_string, '\n'); continue; /* back to top of while (1) */ } break; diff --git a/shell/hush_test/hush-parsing/comment2.right b/shell/hush_test/hush-parsing/comment2.right new file mode 100644 index 000000000..ee6e49a5a --- /dev/null +++ b/shell/hush_test/hush-parsing/comment2.right @@ -0,0 +1,4 @@ +Ok1 +Ok2 +Ok5 +Ok6 diff --git a/shell/hush_test/hush-parsing/comment2.tests b/shell/hush_test/hush-parsing/comment2.tests new file mode 100755 index 000000000..b7adad96a --- /dev/null +++ b/shell/hush_test/hush-parsing/comment2.tests @@ -0,0 +1,13 @@ +echo "`echo Ok1 #comment is ignored`" +echo `echo Ok2 #comment is ignored` +# +# Surprisingly, bash does not handle comments in $() +# the same way as in ``. "#" causes the rest of the line, _including_ )", +# to be ignored. These lines would cause an error: +#echo "$(echo Ok3 #comment is ignored)" +#echo $(echo Ok4 #comment is ignored) +# +echo "$(echo Ok5 #comment is ignored +)" +echo $(echo Ok6 #comment is ignored +) -- cgit v1.2.3-55-g6feb From 9c143ce52da11ec3d21a3491c3749841d3dc10f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 2 Nov 2017 12:56:24 +0100 Subject: ash: retain envvars with bad names in initial environment. Closes 10231 Reworks "ash: [VAR] Sanitise environment variable names on entry" commit. Signed-off-by: Denys Vlasenko --- shell/ash.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 88e607f08..7a0b88c68 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10863,9 +10863,17 @@ showvars(const char *sep_prefix, int on, int off) const char *p; const char *q; - p = strchrnul(*ep, '='); + p = endofname(*ep); +/* Used to have simple "p = strchrnul(*ep, '=')" here instead, but this + * makes "export -p" to have output not suitable for "eval": + * import os + * os.environ["test-test"]="test" + * if os.fork() == 0: + * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this + * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) + */ q = nullstr; - if (*p) + if (*p == '=') q = single_quote(++p); out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); } @@ -13639,8 +13647,18 @@ init(void) initvar(); for (envp = environ; envp && *envp; envp++) { - p = endofname(*envp); - if (p != *envp && *p == '=') { +/* Used to have + * p = endofname(*envp); + * if (p != *envp && *p == '=') { + * here to weed out badly-named variables, but this breaks + * scenarios where people do want them passed to children: + * import os + * os.environ["test-test"]="test" + * if os.fork() == 0: + * os.execv("ash", [ 'ash', '-c', 'eval $(export -p); echo OK' ]) # fixes this + * os.execv("ash", [ 'ash', '-c', 'env | grep test-test' ]) # breaks this + */ + if (strchr(*envp, '=')) { setvareq(*envp, VEXPORT|VTEXTFIXED); } } -- cgit v1.2.3-55-g6feb From a5060b8364faa7c677c8950f1315c451403b0660 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 3 Nov 2017 14:16:25 +0100 Subject: ash: fix nofork bug where environment is not properly passed to a command function old new delta listvars 144 252 +108 evalcommand 1500 1546 +46 showvars 142 147 +5 shellexec 242 245 +3 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 162/0) Total: 162 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 45 +++++++++++++++++++++--- shell/ash_test/ash-standalone/nofork_env.right | 9 +++++ shell/ash_test/ash-standalone/nofork_env.tests | 15 ++++++++ shell/hush_test/hush-standalone/nofork_env.right | 9 +++++ shell/hush_test/hush-standalone/nofork_env.tests | 15 ++++++++ 5 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 shell/ash_test/ash-standalone/nofork_env.right create mode 100755 shell/ash_test/ash-standalone/nofork_env.tests create mode 100644 shell/hush_test/hush-standalone/nofork_env.right create mode 100755 shell/hush_test/hush-standalone/nofork_env.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 7a0b88c68..e69ddb4ff 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2380,8 +2380,11 @@ listsetvar(struct strlist *list_set_var, int flags) /* * Generate a list of variables satisfying the given conditions. */ +#if !ENABLE_FEATURE_SH_NOFORK +# define listvars(on, off, lp, end) listvars(on, off, end) +#endif static char ** -listvars(int on, int off, char ***end) +listvars(int on, int off, struct strlist *lp, char ***end) { struct var **vpp; struct var *vp; @@ -2394,12 +2397,40 @@ listvars(int on, int off, char ***end) do { for (vp = *vpp; vp; vp = vp->next) { if ((vp->flags & mask) == on) { +#if ENABLE_FEATURE_SH_NOFORK + /* If variable with the same name is both + * exported and temporarily set for a command: + * export ZVAR=5 + * ZVAR=6 printenv + * then "ZVAR=6" will be both in vartab and + * lp lists. Do not pass it twice to printenv. + */ + struct strlist *lp1 = lp; + while (lp1) { + if (strcmp(lp1->text, vp->var_text) == 0) + goto skip; + lp1 = lp1->next; + } +#endif if (ep == stackstrend()) ep = growstackstr(); *ep++ = (char*)vp->var_text; +#if ENABLE_FEATURE_SH_NOFORK + skip: ; +#endif } } } while (++vpp < vartab + VTABSIZE); + +#if ENABLE_FEATURE_SH_NOFORK + while (lp) { + if (ep == stackstrend()) + ep = growstackstr(); + *ep++ = lp->text; + lp = lp->next; + } +#endif + if (ep == stackstrend()) ep = growstackstr(); if (end) @@ -7860,7 +7891,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) int exerrno; int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ - envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); + envp = listvars(VEXPORT, VUNSET, /*strlist:*/ NULL, /*end:*/ NULL); if (strchr(prog, '/') != NULL #if ENABLE_FEATURE_SH_STANDALONE || (applet_no = find_applet_by_name(prog)) >= 0 @@ -9930,7 +9961,11 @@ evalcommand(union node *cmd, int flags) /* find_command() encodes applet_no as (-2 - applet_no) */ int applet_no = (- cmdentry.u.index - 2); if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { - listsetvar(varlist.list, VEXPORT|VSTACK); + char **sv_environ; + + INT_OFF; + sv_environ = environ; + environ = listvars(VEXPORT, VUNSET, varlist.list, /*end:*/ NULL); /* * Run _main(). * Signals (^C) can't interrupt here. @@ -9939,8 +9974,8 @@ evalcommand(union node *cmd, int flags) * and/or wait for user input ineligible for NOFORK: * for example, "yes" or "rm" (rm -i waits for input). */ - INT_OFF; status = run_nofork_applet(applet_no, argv); + environ = sv_environ; /* * Try enabling NOFORK for "yes" applet. * ^C _will_ stop it (write returns EINTR), @@ -10854,7 +10889,7 @@ showvars(const char *sep_prefix, int on, int off) const char *sep; char **ep, **epend; - ep = listvars(on, off, &epend); + ep = listvars(on, off, /*strlist:*/ NULL, &epend); qsort(ep, epend - ep, sizeof(char *), vpcmp); sep = *sep_prefix ? " " : sep_prefix; diff --git a/shell/ash_test/ash-standalone/nofork_env.right b/shell/ash_test/ash-standalone/nofork_env.right new file mode 100644 index 000000000..3f16ff458 --- /dev/null +++ b/shell/ash_test/ash-standalone/nofork_env.right @@ -0,0 +1,9 @@ +ZVAR=1 +ZVAR=2 +ZVAR=3 +ZVAR=4 +ZVAR=5 +ZVAR=6 +ZVAR=7 +ZVAR=8 +Ok:0 diff --git a/shell/ash_test/ash-standalone/nofork_env.tests b/shell/ash_test/ash-standalone/nofork_env.tests new file mode 100755 index 000000000..111e564d2 --- /dev/null +++ b/shell/ash_test/ash-standalone/nofork_env.tests @@ -0,0 +1,15 @@ +# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables + +(export ZVAR=1; printenv) | grep ^ZVAR= +(ZVAR=2 printenv) | grep ^ZVAR= + +(export ZVAR=3; env) | grep ^ZVAR= +(ZVAR=4 env) | grep ^ZVAR= + +export ZVAR=5; printenv | grep ^ZVAR= +ZVAR=6 printenv | grep ^ZVAR= + +export ZVAR=7; env | grep ^ZVAR= +ZVAR=8 env | grep ^ZVAR= + +echo Ok:$? diff --git a/shell/hush_test/hush-standalone/nofork_env.right b/shell/hush_test/hush-standalone/nofork_env.right new file mode 100644 index 000000000..3f16ff458 --- /dev/null +++ b/shell/hush_test/hush-standalone/nofork_env.right @@ -0,0 +1,9 @@ +ZVAR=1 +ZVAR=2 +ZVAR=3 +ZVAR=4 +ZVAR=5 +ZVAR=6 +ZVAR=7 +ZVAR=8 +Ok:0 diff --git a/shell/hush_test/hush-standalone/nofork_env.tests b/shell/hush_test/hush-standalone/nofork_env.tests new file mode 100755 index 000000000..111e564d2 --- /dev/null +++ b/shell/hush_test/hush-standalone/nofork_env.tests @@ -0,0 +1,15 @@ +# ash had a bug where NOFORKed applet (env/printenv) was not seeing new exported variables + +(export ZVAR=1; printenv) | grep ^ZVAR= +(ZVAR=2 printenv) | grep ^ZVAR= + +(export ZVAR=3; env) | grep ^ZVAR= +(ZVAR=4 env) | grep ^ZVAR= + +export ZVAR=5; printenv | grep ^ZVAR= +ZVAR=6 printenv | grep ^ZVAR= + +export ZVAR=7; env | grep ^ZVAR= +ZVAR=8 env | grep ^ZVAR= + +echo Ok:$? -- cgit v1.2.3-55-g6feb