From acf79f9913e4cf9b2889404af6758ec8a0d6b090 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 16:12:06 +0100 Subject: ash: use pgetc_eatbnl() in more places, take 2 Adding previously skipped "readtoken1(pgetc_eatbnl(), DQSYNTAX..." changes from upstream commit: Date: Thu Mar 8 08:37:11 2018 +0100 Author: Harald van Dijk parser: use pgetc_eatbnl() in more places dash has a pgetc_eatbnl function in parser.c which skips any backslash-newline combinations. It's not used everywhere it could be. There is also some duplicated backslash-newline handling elsewhere in parser.c. Replace most of the calls to pgetc() with calls to pgetc_eatbnl() and remove the duplicated backslash-newline handling. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index fb4028219..c177ac038 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12194,7 +12194,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) } USTPUTC(c, out); nlprompt(); - c = pgetc(); + c = synstack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); @@ -12226,8 +12226,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) USTPUTC(CTLESC, out); USTPUTC('\\', out); pungetc(); - } else if (c == '\n') { - nlprompt(); } else { if (pssyntax && c == '$') { USTPUTC(CTLESC, out); @@ -12347,7 +12345,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) IF_ASH_ALIAS(if (c != PEOA)) USTPUTC(c, out); } - c = pgetc(); + c = synstack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); } /* for (;;) */ endword: @@ -13093,8 +13091,10 @@ parseheredoc(void) while (here) { tokpushback = 0; setprompt_if(needprompt, 2); - readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, - here->eofmark, here->striptabs); + if (here->here->type == NHERE) + readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs); + else + readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs); n = stzalloc(sizeof(struct narg)); n->narg.type = NARG; /*n->narg.next = NULL; - stzalloc did it */ -- cgit v1.2.3-55-g6feb From f7eea8c235dea6699a21c7b26c218e6c0dc1bf95 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 16:16:34 +0100 Subject: ash: parser: Fix incorrect eating of backslash newlines Keeping up with upstream (in our case, 'before patch' code is not buggy). Upstream commit: Date: Fri, 11 May 2018 23:41:25 +0800 parser: Fix incorrect eating of backslash newlines With the introduction of synstack->syntax, a number of references to the syntax variable was missed during the conversion. This causes backslash newlines to be incorrectly removed in single quote context. This patch also combines these calls into a new helper function pgetc_top. Fixes: ab1cecb40478 ("parser: Add syntax stack for recursive...") Reported-by: Leah Neukirchen Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index c177ac038..a300061a2 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10829,6 +10829,12 @@ struct synstack { struct synstack *next; }; +static int +pgetc_top(struct synstack *stack) +{ + return stack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); +} + static void synstack_push(struct synstack **stack, struct synstack *next, int syntax) { @@ -12194,7 +12200,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) } USTPUTC(c, out); nlprompt(); - c = synstack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); + c = pgetc_top(synstack); goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); @@ -12345,7 +12351,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) IF_ASH_ALIAS(if (c != PEOA)) USTPUTC(c, out); } - c = synstack->syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); + c = pgetc_top(synstack); } /* for (;;) */ endword: -- cgit v1.2.3-55-g6feb From 4ccddc8fb37b7f585c2d62f6e61ad17295399aff Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 17:27:18 +0100 Subject: ash: [BUILTIN] Exit without arguments in a trap should use status outside traps Upstream commit: Date: Mon Oct 6 10:39:47 2014 +0800 [BUILTIN] Exit without arguments in a trap should use status outside traps POSIX now requires that exit without arguments in a trap should return the last command status prior to executing traps. This patch implements this behaviour. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 43 +++++++++++++++++++--------- shell/ash_test/ash-misc/exitcode_trap1.right | 2 ++ shell/ash_test/ash-misc/exitcode_trap1.tests | 6 ++++ 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 shell/ash_test/ash-misc/exitcode_trap1.right create mode 100755 shell/ash_test/ash-misc/exitcode_trap1.tests diff --git a/shell/ash.c b/shell/ash.c index a300061a2..270a338d9 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -384,6 +384,7 @@ struct globals_misc { uint8_t exitstatus; /* exit status of last command */ uint8_t back_exitstatus;/* exit status of backquoted command */ smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ + int savestatus; /* exit status of last command outside traps */ int rootpid; /* pid of main shell */ /* shell level: 0 for the main shell, 1 for its children, and so on */ int shlvl; @@ -466,6 +467,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; #define exitstatus (G_misc.exitstatus ) #define back_exitstatus (G_misc.back_exitstatus ) #define job_warning (G_misc.job_warning) +#define savestatus (G_misc.savestatus ) #define rootpid (G_misc.rootpid ) #define shlvl (G_misc.shlvl ) #define errlinno (G_misc.errlinno ) @@ -491,6 +493,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; #define INIT_G_misc() do { \ (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ barrier(); \ + savestatus = -1; \ curdir = nullstr; \ physdir = nullstr; \ trap_ptr = trap; \ @@ -9055,12 +9058,17 @@ dotrap(void) { uint8_t *g; int sig; - uint8_t last_status; + int status, last_status; if (!pending_sig) return; - last_status = exitstatus; + status = savestatus; + last_status = status; + if (status < 0) { + status = exitstatus; + savestatus = status; + } pending_sig = 0; barrier(); @@ -9087,8 +9095,10 @@ dotrap(void) if (!p) continue; evalstring(p, 0); + exitstatus = status; } - exitstatus = last_status; + + savestatus = last_status; TRACE(("dotrap returns\n")); } @@ -13416,8 +13426,15 @@ exitcmd(int argc UNUSED_PARAM, char **argv) { if (stoppedjobs()) return 0; - if (argv[1]) - exitstatus = number(argv[1]); + + if (argv[1]) { + int status = number(argv[1]); + + exitstatus = status; + if (savestatus >= 0) + savestatus = status; + } + raise_exception(EXEXIT); /* NOTREACHED */ } @@ -14077,19 +14094,15 @@ exitshell(void) { struct jmploc loc; char *p; - int status; #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT if (line_input_state) save_history(line_input_state); #endif - status = exitstatus; - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc.loc)) { - if (exception_type == EXEXIT) - status = exitstatus; + savestatus = exitstatus; + TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); + if (setjmp(loc.loc)) goto out; - } exception_handler = &loc; p = trap[0]; if (p) { @@ -14104,7 +14117,7 @@ exitshell(void) */ setjobctl(0); flush_stdout_stderr(); - _exit(status); + _exit(savestatus); /* NOTREACHED */ } @@ -14280,6 +14293,10 @@ reset(void) /* from eval.c: */ evalskip = 0; loopnest = 0; + if (savestatus >= 0) { + exitstatus = savestatus; + savestatus = -1; + } /* from expand.c: */ ifsfree(); diff --git a/shell/ash_test/ash-misc/exitcode_trap1.right b/shell/ash_test/ash-misc/exitcode_trap1.right new file mode 100644 index 000000000..5f76f68da --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap1.right @@ -0,0 +1,2 @@ +Trapped +One:1 diff --git a/shell/ash_test/ash-misc/exitcode_trap1.tests b/shell/ash_test/ash-misc/exitcode_trap1.tests new file mode 100755 index 000000000..c35b6b391 --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap1.tests @@ -0,0 +1,6 @@ +# "exit" in trap should not use last command's exitcode, +# but exitcode on entering the trap. +(trap "echo Trapped; exit" EXIT + (exit 1) +) +echo One:$? -- cgit v1.2.3-55-g6feb From 970470e235fd2a00d4b020378ddccf769ce534ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 17:32:22 +0100 Subject: ash: main: Only set savestatus in exitcmd Upstream commit: Date: Sat, 19 May 2018 02:39:38 +0800 main: Only set savestatus in exitcmd Currently exitcmd sets exitstatus and then savestatus if the latter was previously set. In fact, as exitcmd always raises an exception and will either end up in the setjmp call in main() or exitshell(), where exitstatus is always replaced by savestatus if set, we only need to set savestatus. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 270a338d9..db7dffc72 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13427,13 +13427,8 @@ exitcmd(int argc UNUSED_PARAM, char **argv) if (stoppedjobs()) return 0; - if (argv[1]) { - int status = number(argv[1]); - - exitstatus = status; - if (savestatus >= 0) - savestatus = status; - } + if (argv[1]) + savestatus = number(argv[1]); raise_exception(EXEXIT); /* NOTREACHED */ -- cgit v1.2.3-55-g6feb From 3f7fb2c89ad75bbdd3b69e302124c8179c273bb4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:06:20 +0100 Subject: ash: output: Fix fmtstr return value Upstream commit: Date: Sat, 19 May 2018 02:39:44 +0800 output: Fix fmtstr return value The function fmtstr is meant to return the actual length of output produced, rather than the untruncated length. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index db7dffc72..a006a1c26 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -713,7 +713,7 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...) ret = vsnprintf(outbuf, length, fmt, ap); va_end(ap); INT_ON; - return ret; + return ret > (int)length ? length : ret; } static void -- cgit v1.2.3-55-g6feb From 2bad3a305b5934d17e817a8fbb9c42ee04dc5a3c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:23:43 +0100 Subject: ash: jobs: Replace some uses of fmtstr with stpcpy/stpncpy Upstream commit: Date: Sat, 19 May 2018 02:39:45 +0800 jobs: Replace some uses of fmtstr with stpcpy/stpncpy Some uses of fmtstr, particularly the ones without a format string, can be replaced with stpcpy or stpncpy. This patch does that so we don't have to introduce unnecessary format strings in order to silence compiler warnings. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index a006a1c26..75edebd8d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4203,12 +4203,11 @@ fg_bgcmd(int argc UNUSED_PARAM, char **argv) #endif static int -sprint_status48(char *s, int status, int sigonly) +sprint_status48(char *os, int status, int sigonly) { - int col; + char *s = os; int st; - col = 0; if (!WIFEXITED(status)) { #if JOBS if (WIFSTOPPED(status)) @@ -4226,17 +4225,17 @@ sprint_status48(char *s, int status, int sigonly) } st &= 0x7f; //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata - col = fmtstr(s, 32, strsignal(st)); + //s = stpncpy(s, strsignal(st), 32); //not all libc have stpncpy() + s += fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { - strcpy(s + col, " (core dumped)"); - col += sizeof(" (core dumped)")-1; + s = stpcpy(s, " (core dumped)"); } } else if (!sigonly) { st = WEXITSTATUS(status); - col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st); + s += fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st); } out: - return col; + return s - os; } static int -- cgit v1.2.3-55-g6feb From a7b97e367c44d8a6890397848dcf59f4e190d4f9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:29:52 +0100 Subject: ash: builtin: Mark more regular built-ins Upstream commit: Date: Sat, 19 May 2018 02:39:49 +0800 builtin: Mark more regular built-ins This patch marks the following built-ins as regular, meaning that they cannot be overriden using PATH search: hash pwd type ulimit Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 75edebd8d..78ca1d99c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9962,7 +9962,7 @@ static const struct builtincmd builtintab[] = { #if ENABLE_ASH_GETOPTS { BUILTIN_REGULAR "getopts" , getoptscmd }, #endif - { BUILTIN_NOSPEC "hash" , hashcmd }, + { BUILTIN_REGULAR "hash" , hashcmd }, #if ENABLE_ASH_HELP { BUILTIN_NOSPEC "help" , helpcmd }, #endif @@ -9980,7 +9980,7 @@ static const struct builtincmd builtintab[] = { #if ENABLE_ASH_PRINTF { BUILTIN_REGULAR "printf" , printfcmd }, #endif - { BUILTIN_NOSPEC "pwd" , pwdcmd }, + { BUILTIN_REGULAR "pwd" , pwdcmd }, { BUILTIN_REGULAR "read" , readcmd }, { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, { BUILTIN_SPEC_REG "return" , returncmd }, @@ -9995,8 +9995,8 @@ static const struct builtincmd builtintab[] = { { BUILTIN_SPEC_REG "times" , timescmd }, { BUILTIN_SPEC_REG "trap" , trapcmd }, { BUILTIN_REGULAR "true" , truecmd }, - { BUILTIN_NOSPEC "type" , typecmd }, - { BUILTIN_NOSPEC "ulimit" , ulimitcmd }, + { BUILTIN_REGULAR "type" , typecmd }, + { BUILTIN_REGULAR "ulimit" , ulimitcmd }, { BUILTIN_REGULAR "umask" , umaskcmd }, #if ENABLE_ASH_ALIAS { BUILTIN_REGULAR "unalias" , unaliascmd }, -- cgit v1.2.3-55-g6feb From e880b1fea8442b623d45a8f62227fc35cbcac7ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:31:05 +0100 Subject: ash: expand: Use HOME in tilde expansion when it is empty Upstream commit: Date: Sun, 27 May 2018 17:31:57 +0800 expand: Use HOME in tilde expansion when it is empty Currently if HOME is set to empty tilde expansion will fail, i.e., it will remain as a literal tilde. This patch changes it to return the empty string as required by POSIX. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index 78ca1d99c..138f19abd 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6440,7 +6440,7 @@ exptilde(char *startp, char *p, int flags) goto lose; home = pw->pw_dir; } - if (!home || !*home) + if (!home) goto lose; *p = c; strtodest(home, SQSYNTAX, quotes); -- cgit v1.2.3-55-g6feb From 226b8a143d5632180bef05f728bb497b8318294f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:57:53 +0100 Subject: ash: main: Print \n upon EOF (CTRL-D) when run interactively Upstream comment: Date: Fri, 7 Sep 2018 10:34:14 +0200 main: Print \n upon EOF (CTRL-D) when run interactively Exiting dash via a ^D instead of with "exit" causes dash to forget to print a newline. sh-3.1$ sh sh-3.1$ ^D sh-3.1$ dash $ sh-3.1$ It is more neat and tidy to send a newline similarly to what bash does, so it doesn't make the next prompt of the parent shell look ugly. Suggested by jidanni. Signed-off-by: Gerrit Pape Signed-off-by: Jonathan Nieder [reworded the patch description] Signed-off-by: Andrej Shadura Bug-Debian: http://bugs.debian.org/476422 Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index 138f19abd..3958db123 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13302,8 +13302,12 @@ cmdloop(int top) if (!top || numeof >= 50) break; if (!stoppedjobs()) { - if (!Iflag) + if (!Iflag) { + if (iflag) { + newline_and_flush(stderr); + } break; + } out2str("\nUse \"exit\" to leave shell.\n"); } numeof++; -- cgit v1.2.3-55-g6feb From 4ace38580927b3b402b6b35ab50893dbfd5f77c3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 18:42:50 +0100 Subject: ash: expand: Fix skipping of command substitution when trimming in evalvar Upstream commit: Date: Mon, 28 May 2018 17:09:48 +0800 expand: Fix skipping of command substitution when trimming in evalvar When we are trimming an unset variable in evalvar, any embedded command substitution that should have been skipped are not. This can cause them to be evaluated later should there be other command substitutions in the same input word. Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/ash.c b/shell/ash.c index 3958db123..97c7f4ef5 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7506,6 +7506,8 @@ evalvar(char *p, int flag) goto record; } + varlen = 0; + end: if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; -- cgit v1.2.3-55-g6feb From e368d851e78a2eb2aee50b8bad29dcc301feec65 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 19:02:22 +0100 Subject: ash: eval: Use the correct expansion mode for fd redirection Upstream comment: Date: Mon, 19 Nov 2018 18:00:32 +0800 eval: Use the correct expansion mode for fd redirection It has been reported that echo test >&$EMPTY_VARIABLE causes dash to segfault. This is a symptom of the bigger problem that dash tries to perform pathname expansion as well as field splitting on the word after >& and <&. This is wrong and this patch fixes it to use the same expansions as done on a normal redirection. Reported-by: Andrej Shadura Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 97c7f4ef5..a43b65680 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9445,11 +9445,10 @@ expredir(union node *n) case NFROMFD: case NTOFD: /* >& */ if (redir->ndup.vname) { - expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); + expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR); if (fn.list == NULL) ash_msg_and_raise_error("redir error"); #if BASH_REDIR_OUTPUT -//FIXME: we used expandarg with different args! if (!isdigit_str9(fn.list->text)) { /* >&file, not >&fd */ if (redir->nfile.fd != 1) /* 123>&file - BAD */ -- cgit v1.2.3-55-g6feb From 3f4847b6d9198a359e98933271af4630b3c41f0a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 16 Feb 2020 19:06:42 +0100 Subject: ash: shell: Fix clang warnings about "string plus integer" Upstream commit: Date: Sat, 15 Dec 2018 18:49:31 +0100 shell: Fix clang warnings about "string plus integer" Building with clang results in some warnings about integer values being added to strings. While the code itself is fine and the warnings are indeed harmless, fixing them also makes the semantic more explicit: what it is actually being increased is the address which points to the start of the string in order to skip the initial character when some conditions are met. Signed-off-by: Antonio Ospite Signed-off-by: Herbert Xu Signed-off-by: Denys Vlasenko --- shell/ash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index a43b65680..a25d14de0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4799,7 +4799,8 @@ cmdputs(const char *s) str = "${"; goto dostr; case CTLENDVAR: - str = "\"}" + !(quoted & 1); + str = "\"}"; + str += !(quoted & 1); quoted >>= 1; subtype = 0; goto dostr; -- cgit v1.2.3-55-g6feb