hush: make "set -x" output don't redirectable when fd#2 redirected

function                                             old     new   delta
x_mode_print_optionally_squoted                        -     120    +120
x_mode_flush                                           -      68     +68
save_fd_on_redirect                                  208     243     +35
x_mode_prefix                                          -      27     +27
x_mode_addblock                                        -      23     +23
x_mode_addchr                                          -      17     +17
dump_cmd_in_x_mode                                   110      85     -25
run_pipe                                            1919    1890     -29
print_optionally_squoted                             145       -    -145
------------------------------------------------------------------------------
(add/remove: 5/1 grow/shrink: 1/2 up/down: 290/-199)           Total: 91 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-07-28 12:13:58 +02:00
parent 4b70c926bc
commit aa449c927d

View File

@ -954,9 +954,6 @@ struct globals {
unsigned func_nest_level; /* solely to prevent "local v" in non-functions */
# endif
struct function *top_func;
#endif
#if ENABLE_HUSH_MODE_X
unsigned x_mode_depth;
#endif
/* Signal and trap handling */
#if ENABLE_HUSH_FAST
@ -993,6 +990,15 @@ struct globals {
#if ENABLE_HUSH_MEMLEAK
unsigned long memleak_value;
#endif
#if ENABLE_HUSH_MODE_X
unsigned x_mode_depth;
/* "set -x" output should not be redirectable with subsequent 2>FILE.
* We dup fd#2 to x_mode_fd when "set -x" is executed, and use it
* for all subsequent output.
*/
int x_mode_fd;
o_string x_mode_buf;
#endif
#if HUSH_DEBUG
int debug_indent;
#endif
@ -1660,6 +1666,12 @@ static int move_HFILEs_on_redirect(int fd, int avoid_fd)
}
fl = fl->next_hfile;
}
#if ENABLE_HUSH_MODE_X
if (G.x_mode_fd > 0 && fd == G.x_mode_fd) {
G.x_mode_fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
return 1; /* "found and moved" */
}
#endif
return 0; /* "not in the list" */
}
#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
@ -2903,6 +2915,11 @@ static void o_addstr(o_string *o, const char *str)
o_addblock(o, str, strlen(str));
}
static void o_addstr_with_NUL(o_string *o, const char *str)
{
o_addblock(o, str, strlen(str) + 1);
}
#if !BB_MMU
static void nommu_addchr(o_string *o, int ch)
{
@ -2913,10 +2930,36 @@ static void nommu_addchr(o_string *o, int ch)
# define nommu_addchr(o, str) ((void)0)
#endif
static void o_addstr_with_NUL(o_string *o, const char *str)
#if ENABLE_HUSH_MODE_X
static void x_mode_addchr(int ch)
{
o_addblock(o, str, strlen(str) + 1);
o_addchr(&G.x_mode_buf, ch);
}
static void x_mode_addstr(const char *str)
{
o_addstr(&G.x_mode_buf, str);
}
static void x_mode_addblock(const char *str, int len)
{
o_addblock(&G.x_mode_buf, str, len);
}
static void x_mode_prefix(void)
{
int n = G.x_mode_depth;
do x_mode_addchr('+'); while (--n >= 0);
}
static void x_mode_flush(void)
{
int len = G.x_mode_buf.length;
if (len <= 0)
return;
if (G.x_mode_fd > 0) {
G.x_mode_buf.data[len] = '\n';
full_write(G.x_mode_fd, G.x_mode_buf.data, len + 1);
}
G.x_mode_buf.length = 0;
}
#endif
/*
* HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
@ -8030,31 +8073,26 @@ static void execvp_or_die(char **argv)
}
#if ENABLE_HUSH_MODE_X
static void print_optionally_squoted(FILE *fp, const char *str)
static void x_mode_print_optionally_squoted(const char *str)
{
unsigned len;
const char *cp;
cp = str;
if (str[0] != '{' && str[0] != '(') for (;;) {
if (!*cp) {
/* string has no special chars */
fputs(str, fp);
return;
}
if (*cp == '\\') break;
if (*cp == '\'') break;
if (*cp == '"') break;
if (*cp == '$') break;
if (*cp == '!') break;
if (*cp == '*') break;
if (*cp == '[') break;
if (*cp == ']') break;
#if ENABLE_HUSH_TICK
if (*cp == '`') break;
#endif
if (isspace(*cp)) break;
cp++;
/* the set of chars which-cause-string-to-be-squoted mimics bash */
/* test a char with: bash -c 'set -x; echo "CH"' */
if (str[strcspn(str, "\\\"'`$(){}[]<>;#&|~*?!^"
" " "\001\002\003\004\005\006\007"
"\010\011\012\013\014\015\016\017"
"\020\021\022\023\024\025\026\027"
"\030\031\032\033\034\035\036\037"
)
] == '\0'
) {
/* string has no special chars */
x_mode_addstr(str);
return;
}
cp = str;
@ -8062,13 +8100,16 @@ static void print_optionally_squoted(FILE *fp, const char *str)
/* print '....' up to EOL or first squote */
len = (int)(strchrnul(cp, '\'') - cp);
if (len != 0) {
fprintf(fp, "'%.*s'", len, cp);
x_mode_addchr('\'');
x_mode_addblock(cp, len);
x_mode_addchr('\'');
cp += len;
}
if (*cp == '\0')
break;
/* string contains squote(s), print them as \' */
fprintf(fp, "\\'");
x_mode_addchr('\\');
x_mode_addchr('\'');
cp++;
}
}
@ -8078,19 +8119,19 @@ static void dump_cmd_in_x_mode(char **argv)
unsigned n;
/* "+[+++...][ cmd...]\n\0" */
n = G.x_mode_depth;
do bb_putchar_stderr('+'); while ((int)(--n) >= 0);
x_mode_prefix();
n = 0;
while (argv[n]) {
if (argv[n][0] == '\0')
fputs(" ''", stderr);
else {
bb_putchar_stderr(' ');
print_optionally_squoted(stderr, argv[n]);
x_mode_addchr(' ');
if (argv[n][0] == '\0') {
x_mode_addchr('\'');
x_mode_addchr('\'');
} else {
x_mode_print_optionally_squoted(argv[n]);
}
n++;
}
bb_putchar_stderr('\n');
x_mode_flush();
}
}
#else
@ -8885,17 +8926,14 @@ static NOINLINE int run_pipe(struct pipe *pi)
#if ENABLE_HUSH_MODE_X
if (G_x_mode) {
char *eq;
if (i == 0) {
unsigned n = G.x_mode_depth;
do
bb_putchar_stderr('+');
while ((int)(--n) >= 0);
}
if (i == 0)
x_mode_prefix();
x_mode_addchr(' ');
eq = strchrnul(p, '=');
fprintf(stderr, " %.*s=", (int)(eq - p), p);
if (*eq)
print_optionally_squoted(stderr, eq + 1);
bb_putchar_stderr('\n');
if (*eq) eq++;
x_mode_addblock(p, (eq - p));
x_mode_print_optionally_squoted(eq);
x_mode_flush();
}
#endif
debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
@ -9691,6 +9729,7 @@ static int set_mode(int state, char mode, const char *o_opt)
break;
case 'x':
IF_HUSH_MODE_X(G_x_mode = state;)
IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);)
break;
case 'o':
if (!o_opt) {