ash,hush: show 'c' in $- if run in "sh -c CMD"

function                                             old     new   delta
options                                              552     599     +47
expand_one_var                                      2375    2385     +10
optletters_optnames                                   60      64      +4
hush_main                                           1108    1111      +3
ash_main                                            1150    1152      +2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 66/0)               Total: 66 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2019-06-03 12:21:04 +02:00
parent 897475ab02
commit f3634584d0
2 changed files with 50 additions and 25 deletions

View File

@ -315,17 +315,18 @@ static const char *const optletters_optnames[] = {
"e" "errexit", "e" "errexit",
"f" "noglob", "f" "noglob",
"I" "ignoreeof", "I" "ignoreeof",
/* The below allows this invocation: /* The below allowed this invocation:
* ash -c 'set -i; echo $-; sleep 5; echo $-' * ash -c 'set -i; echo $-; sleep 5; echo $-'
* to be ^C-ed and get to interactive ash prompt. * to be ^C-ed and get to interactive ash prompt.
* bash does not support this "set -i". bash also has no * bash does not support such "set -i".
* "set -o interactive". * In our code, this is denoted by empty long name:
*/ */
"i" "interactive", "i" "",
"m" "monitor", "m" "monitor",
"n" "noexec", "n" "noexec",
/* Ditto: bash has no "set -s" and "set -o stdin" */ /* Ditto: bash has no "set -s" */
"s" "stdin", "s" "",
"c" "",
"x" "xtrace", "x" "xtrace",
"v" "verbose", "v" "verbose",
"C" "noclobber", "C" "noclobber",
@ -359,7 +360,6 @@ static const char *const optletters_optnames[] = {
#define optletters(n) optletters_optnames[n][0] #define optletters(n) optletters_optnames[n][0]
#define optnames(n) (optletters_optnames[n] + 1) #define optnames(n) (optletters_optnames[n] + 1)
enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
@ -419,21 +419,22 @@ struct globals_misc {
#define mflag optlist[4] #define mflag optlist[4]
#define nflag optlist[5] #define nflag optlist[5]
#define sflag optlist[6] #define sflag optlist[6]
#define xflag optlist[7] #define cflag optlist[7]
#define vflag optlist[8] #define xflag optlist[8]
#define Cflag optlist[9] #define vflag optlist[9]
#define aflag optlist[10] #define Cflag optlist[10]
#define bflag optlist[11] #define aflag optlist[11]
#define uflag optlist[12] #define bflag optlist[12]
#define viflag optlist[13] #define uflag optlist[13]
#define viflag optlist[14]
#if BASH_PIPEFAIL #if BASH_PIPEFAIL
# define pipefail optlist[14] # define pipefail optlist[15]
#else #else
# define pipefail 0 # define pipefail 0
#endif #endif
#if DEBUG #if DEBUG
# define nolog optlist[14 + BASH_PIPEFAIL] # define nolog optlist[15 + BASH_PIPEFAIL]
# define debug optlist[15 + BASH_PIPEFAIL] # define debug optlist[16 + BASH_PIPEFAIL]
#endif #endif
/* trap handler commands */ /* trap handler commands */
@ -11104,7 +11105,7 @@ setoption(int flag, int val)
int i; int i;
for (i = 0; i < NOPTS; i++) { for (i = 0; i < NOPTS; i++) {
if (optletters(i) == flag) { if (optletters(i) == flag && optnames(i)[0] != '\0') {
optlist[i] = val; optlist[i] = val;
return; return;
} }
@ -11150,6 +11151,15 @@ options(int *login_sh)
/* bash 3.2 indeed handles -c CMD and +c CMD the same */ /* bash 3.2 indeed handles -c CMD and +c CMD the same */
if (c == 'c') { if (c == 'c') {
minusc = p; /* command is after shell args */ 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; continue;
} }
if (c == 'l') { if (c == 'l') {
@ -14170,8 +14180,13 @@ procargs(char **argv)
ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
sflag = 1; 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; iflag = 1;
}
if (mflag == 2) if (mflag == 2)
mflag = iflag; mflag = iflag;
for (i = 0; i < NOPTS; i++) 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) * Ensure we don't falsely claim that 0 (stdin)
* is one of stacked source fds. * is one of stacked source fds.
* Testcase: ash -c 'exec 1>&0' must not complain. */ * Testcase: ash -c 'exec 1>&0' must not complain. */
// if (!sflag) g_parsefile->pf_fd = -1; // if (!sflag) g_parsefile->pf_fd = -1;
// ^^ not necessary since now we special-case fd 0 // ^^ not necessary since now we special-case fd 0
// in save_fd_on_redirect() // 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) { if (sflag || minusc == NULL) {

View File

@ -903,6 +903,7 @@ struct globals {
# define G_x_mode 0 # define G_x_mode 0
#endif #endif
char opt_s; char opt_s;
char opt_c;
#if ENABLE_HUSH_INTERACTIVE #if ENABLE_HUSH_INTERACTIVE
smallint promptmode; /* 0: PS1, 1: PS2 */ smallint promptmode; /* 0: PS1, 1: PS2 */
#endif #endif
@ -1009,7 +1010,7 @@ struct globals {
int debug_indent; int debug_indent;
#endif #endif
struct sigaction sa; struct sigaction sa;
char optstring_buf[sizeof("eixs")]; char optstring_buf[sizeof("eixcs")];
#if BASH_EPOCH_VARS #if BASH_EPOCH_VARS
char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3];
#endif #endif
@ -6414,9 +6415,10 @@ static NOINLINE int expand_one_var(o_string *output, int n,
* commands read but are not executed, * commands read but are not executed,
* so $- can not execute too, 'n' is never seen in $-. * so $- can not execute too, 'n' is never seen in $-.
*/ */
if (G.opt_c)
*cp++ = 'c';
if (G.opt_s) if (G.opt_s)
*cp++ = 's'; *cp++ = 's';
//TODO: show 'c' if executed via "hush -c 'CMDS'" (bash only, not ash)
*cp = '\0'; *cp = '\0';
break; break;
} }
@ -9859,7 +9861,6 @@ int hush_main(int argc, char **argv)
{ {
enum { enum {
OPT_login = (1 << 0), OPT_login = (1 << 0),
OPT_s = (1 << 1),
}; };
unsigned flags; unsigned flags;
unsigned builtin_argc; unsigned builtin_argc;
@ -10029,6 +10030,7 @@ int hush_main(int argc, char **argv)
} }
goto final_return; goto final_return;
} }
G.opt_c = 1;
if (!G.global_argv[0]) { if (!G.global_argv[0]) {
/* -c 'script' (no params): prevent empty $0 */ /* -c 'script' (no params): prevent empty $0 */
G.global_argv--; /* points to argv[i] of 'script' */ G.global_argv--; /* points to argv[i] of 'script' */
@ -10044,7 +10046,7 @@ int hush_main(int argc, char **argv)
/* G_interactive_fd++; */ /* G_interactive_fd++; */
break; break;
case 's': case 's':
flags |= OPT_s; G.opt_s = 1;
break; break;
case 'l': case 'l':
flags |= OPT_login; flags |= OPT_login;
@ -10154,7 +10156,7 @@ int hush_main(int argc, char **argv)
} }
/* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ /* -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; HFILE *input;
/* /*
* "bash <script>" (which is never interactive (unless -i?)) * "bash <script>" (which is never interactive (unless -i?))
@ -10178,6 +10180,7 @@ int hush_main(int argc, char **argv)
#endif #endif
goto final_return; goto final_return;
} }
/* "implicit" -s: bare interactive hush shows 's' in $- */
G.opt_s = 1; G.opt_s = 1;
/* Up to here, shell was non-interactive. Now it may become one. /* Up to here, shell was non-interactive. Now it may become one.