ash,hush: show 'c' in $- if run in "sh -c CMD"
No binary (build failed)
—
(log yok)
| @@ -315,17 +315,18 @@ static const char *const optletters_optnames[] = { | |
| "e" "errexit", | |
| "f" "noglob", | |
| "I" "ignoreeof", | |
| - | /* The below allows this invocation: |
| + | /* The below allowed this invocation: |
| * ash -c 'set -i; echo $-; sleep 5; echo $-' | |
| * to be ^C-ed and get to interactive ash prompt. | |
| - | * bash does not support this "set -i". bash also has no |
| - | * "set -o interactive". |
| + | * bash does not support such "set -i". |
| + | * In our code, this is denoted by empty long name: |
| */ | |
| - | "i" "interactive", |
| + | "i" "", |
| "m" "monitor", | |
| "n" "noexec", | |
| - | /* Ditto: bash has no "set -s" and "set -o stdin" */ |
| - | "s" "stdin", |
| + | /* Ditto: bash has no "set -s" */ |
| + | "s" "", |
| + | "c" "", |
| "x" "xtrace", | |
| "v" "verbose", | |
| "C" "noclobber", | |
| @@ -359,7 +360,6 @@ static const char *const optletters_optnames[] = { | |
| #define optletters(n) optletters_optnames[n][0] | |
| #define optnames(n) (optletters_optnames[n] + 1) | |
| - | |
| enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; | |
| @@ -419,21 +419,22 @@ struct globals_misc { | |
| #define mflag optlist[4] | |
| #define nflag optlist[5] | |
| #define sflag optlist[6] | |
| - | #define xflag optlist[7] |
| - | #define vflag optlist[8] |
| - | #define Cflag optlist[9] |
| - | #define aflag optlist[10] |
| - | #define bflag optlist[11] |
| - | #define uflag optlist[12] |
| - | #define viflag optlist[13] |
| + | #define cflag optlist[7] |
| + | #define xflag optlist[8] |
| + | #define vflag optlist[9] |
| + | #define Cflag optlist[10] |
| + | #define aflag optlist[11] |
| + | #define bflag optlist[12] |
| + | #define uflag optlist[13] |
| + | #define viflag optlist[14] |
| #if BASH_PIPEFAIL | |
| - | # define pipefail optlist[14] |
| + | # define pipefail optlist[15] |
| #else | |
| # define pipefail 0 | |
| #endif | |
| #if DEBUG | |
| - | # define nolog optlist[14 + BASH_PIPEFAIL] |
| - | # define debug optlist[15 + BASH_PIPEFAIL] |
| + | # define nolog optlist[15 + BASH_PIPEFAIL] |
| + | # define debug optlist[16 + BASH_PIPEFAIL] |
| #endif | |
| /* trap handler commands */ | |
| @@ -11104,7 +11105,7 @@ setoption(int flag, int val) | |
| int i; | |
| for (i = 0; i < NOPTS; i++) { | |
| - | if (optletters(i) == flag) { |
| + | if (optletters(i) == flag && optnames(i)[0] != '\0') { |
| optlist[i] = val; | |
| return; | |
| } | |
| @@ -11150,6 +11151,15 @@ options(int *login_sh) | |
| /* bash 3.2 indeed handles -c CMD and +c CMD the same */ | |
| if (c == 'c') { | |
| minusc = p; /* command is after shell args */ | |
| + | cflag = 1; |
| + | continue; |
| + | } |
| + | if (c == 's') { /* -s, +s */ |
| + | sflag = 1; |
| + | continue; |
| + | } |
| + | if (c == 'i') { /* -i, +i */ |
| + | iflag = 1; |
| continue; | |
| } | |
| if (c == 'l') { | |
| @@ -14170,8 +14180,13 @@ procargs(char **argv) | |
| ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); | |
| sflag = 1; | |
| } | |
| - | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) |
| + | if (iflag == 2 /* no explicit -i given */ |
| + | && sflag == 1 /* -s given (or implied) */ |
| + | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ |
| + | && isatty(0) && isatty(1) /* we are on tty */ |
| + | ) { |
| iflag = 1; | |
| + | } |
| if (mflag == 2) | |
| mflag = iflag; | |
| for (i = 0; i < NOPTS; i++) | |
| @@ -14359,10 +14374,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |
| * Ensure we don't falsely claim that 0 (stdin) | |
| * is one of stacked source fds. | |
| * Testcase: ash -c 'exec 1>&0' must not complain. */ | |
| + | |
| // if (!sflag) g_parsefile->pf_fd = -1; | |
| // ^^ not necessary since now we special-case fd 0 | |
| // in save_fd_on_redirect() | |
| - | evalstring(minusc, sflag ? 0 : EV_EXIT); |
| + | |
| + | // dash: evalstring(minusc, sflag ? 0 : EV_EXIT); |
| + | // The above makes |
| + | // ash -sc 'echo $-' |
| + | // continue reading input from stdin after running 'echo'. |
| + | // bash does not do this: it prints "hBcs" and exits. |
| + | evalstring(minusc, EV_EXIT); |
| } | |
| if (sflag || minusc == NULL) { | |
| @@ -903,6 +903,7 @@ struct globals { | |
| # define G_x_mode 0 | |
| #endif | |
| char opt_s; | |
| + | char opt_c; |
| #if ENABLE_HUSH_INTERACTIVE | |
| smallint promptmode; /* 0: PS1, 1: PS2 */ | |
| #endif | |
| @@ -1009,7 +1010,7 @@ struct globals { | |
| int debug_indent; | |
| #endif | |
| struct sigaction sa; | |
| - | char optstring_buf[sizeof("eixs")]; |
| + | char optstring_buf[sizeof("eixcs")]; |
| #if BASH_EPOCH_VARS | |
| char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; | |
| #endif | |
| @@ -6414,9 +6415,10 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |
| * commands read but are not executed, | |
| * so $- can not execute too, 'n' is never seen in $-. | |
| */ | |
| + | if (G.opt_c) |
| + | *cp++ = 'c'; |
| if (G.opt_s) | |
| *cp++ = 's'; | |
| - | //TODO: show 'c' if executed via "hush -c 'CMDS'" (bash only, not ash) |
| *cp = '\0'; | |
| break; | |
| } | |
| @@ -9859,7 +9861,6 @@ int hush_main(int argc, char **argv) | |
| { | |
| enum { | |
| OPT_login = (1 << 0), | |
| - | OPT_s = (1 << 1), |
| }; | |
| unsigned flags; | |
| unsigned builtin_argc; | |
| @@ -10029,6 +10030,7 @@ int hush_main(int argc, char **argv) | |
| } | |
| goto final_return; | |
| } | |
| + | G.opt_c = 1; |
| if (!G.global_argv[0]) { | |
| /* -c 'script' (no params): prevent empty $0 */ | |
| G.global_argv--; /* points to argv[i] of 'script' */ | |
| @@ -10044,7 +10046,7 @@ int hush_main(int argc, char **argv) | |
| /* G_interactive_fd++; */ | |
| break; | |
| case 's': | |
| - | flags |= OPT_s; |
| + | G.opt_s = 1; |
| break; | |
| case 'l': | |
| flags |= OPT_login; | |
| @@ -10154,7 +10156,7 @@ int hush_main(int argc, char **argv) | |
| } | |
| /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ | |
| - | if (!(flags & OPT_s) && G.global_argv[1]) { |
| + | if (!G.opt_s && G.global_argv[1]) { |
| HFILE *input; | |
| /* | |
| * "bash <script>" (which is never interactive (unless -i?)) | |
| @@ -10178,6 +10180,7 @@ int hush_main(int argc, char **argv) | |
| #endif | |
| goto final_return; | |
| } | |
| + | /* "implicit" -s: bare interactive hush shows 's' in $- */ |
| G.opt_s = 1; | |
| /* Up to here, shell was non-interactive. Now it may become one. | |