|
|
|
@ -49,7 +49,6 @@
|
|
|
|
|
* [un]alias, command, fc, getopts, newgrp, readonly, times
|
|
|
|
|
* make complex ${var%...} constructs support optional
|
|
|
|
|
* make here documents optional
|
|
|
|
|
* set -e (some ash testsuite entries use it, want to adopt those)
|
|
|
|
|
*
|
|
|
|
|
* Bash compat TODO:
|
|
|
|
|
* redirection of stdout+stderr: &> and >&
|
|
|
|
@ -286,7 +285,7 @@
|
|
|
|
|
* therefore we don't show them either.
|
|
|
|
|
*/
|
|
|
|
|
//usage:#define hush_trivial_usage
|
|
|
|
|
//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
|
|
|
|
|
//usage: "[-enxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
|
|
|
|
|
//usage:#define hush_full_usage "\n\n"
|
|
|
|
|
//usage: "Unix shell interpreter"
|
|
|
|
|
|
|
|
|
@ -747,6 +746,7 @@ struct function {
|
|
|
|
|
static const char o_opt_strings[] ALIGN1 =
|
|
|
|
|
"pipefail\0"
|
|
|
|
|
"noexec\0"
|
|
|
|
|
"errexit\0"
|
|
|
|
|
#if ENABLE_HUSH_MODE_X
|
|
|
|
|
"xtrace\0"
|
|
|
|
|
#endif
|
|
|
|
@ -754,6 +754,7 @@ static const char o_opt_strings[] ALIGN1 =
|
|
|
|
|
enum {
|
|
|
|
|
OPT_O_PIPEFAIL,
|
|
|
|
|
OPT_O_NOEXEC,
|
|
|
|
|
OPT_O_ERREXIT,
|
|
|
|
|
#if ENABLE_HUSH_MODE_X
|
|
|
|
|
OPT_O_XTRACE,
|
|
|
|
|
#endif
|
|
|
|
@ -810,6 +811,25 @@ struct globals {
|
|
|
|
|
#else
|
|
|
|
|
# define G_saved_tty_pgrp 0
|
|
|
|
|
#endif
|
|
|
|
|
/* How deeply are we in context where "set -e" is ignored */
|
|
|
|
|
int errexit_depth;
|
|
|
|
|
/* "set -e" rules (do we follow them correctly?):
|
|
|
|
|
* Exit if pipe, list, or compound command exits with a non-zero status.
|
|
|
|
|
* Shell does not exit if failed command is part of condition in
|
|
|
|
|
* if/while, part of && or || list except the last command, any command
|
|
|
|
|
* in a pipe but the last, or if the command's return value is being
|
|
|
|
|
* inverted with !. If a compound command other than a subshell returns a
|
|
|
|
|
* non-zero status because a command failed while -e was being ignored, the
|
|
|
|
|
* shell does not exit. A trap on ERR, if set, is executed before the shell
|
|
|
|
|
* exits [ERR is a bashism].
|
|
|
|
|
*
|
|
|
|
|
* If a compound command or function executes in a context where -e is
|
|
|
|
|
* ignored, none of the commands executed within are affected by the -e
|
|
|
|
|
* setting. If a compound command or function sets -e while executing in a
|
|
|
|
|
* context where -e is ignored, that setting does not have any effect until
|
|
|
|
|
* the compound command or the command containing the function call completes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char o_opt[NUM_OPT_O];
|
|
|
|
|
#if ENABLE_HUSH_MODE_X
|
|
|
|
|
# define G_x_mode (G.o_opt[OPT_O_XTRACE])
|
|
|
|
@ -5159,7 +5179,7 @@ static struct pipe *parse_stream(char **pstring,
|
|
|
|
|
* and it will match } earlier (not here). */
|
|
|
|
|
syntax_error_unexpected_ch(ch);
|
|
|
|
|
G.last_exitcode = 2;
|
|
|
|
|
goto parse_error1;
|
|
|
|
|
goto parse_error2;
|
|
|
|
|
default:
|
|
|
|
|
if (HUSH_DEBUG)
|
|
|
|
|
bb_error_msg_and_die("BUG: unexpected %c\n", ch);
|
|
|
|
@ -5168,7 +5188,7 @@ static struct pipe *parse_stream(char **pstring,
|
|
|
|
|
|
|
|
|
|
parse_error:
|
|
|
|
|
G.last_exitcode = 1;
|
|
|
|
|
parse_error1:
|
|
|
|
|
parse_error2:
|
|
|
|
|
{
|
|
|
|
|
struct parse_context *pctx;
|
|
|
|
|
IF_HAS_KEYWORDS(struct parse_context *p2;)
|
|
|
|
@ -8021,6 +8041,7 @@ static int run_list(struct pipe *pi)
|
|
|
|
|
/* Go through list of pipes, (maybe) executing them. */
|
|
|
|
|
for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
|
|
|
|
|
int r;
|
|
|
|
|
int sv_errexit_depth;
|
|
|
|
|
|
|
|
|
|
if (G.flag_SIGINT)
|
|
|
|
|
break;
|
|
|
|
@ -8030,6 +8051,13 @@ static int run_list(struct pipe *pi)
|
|
|
|
|
IF_HAS_KEYWORDS(rword = pi->res_word;)
|
|
|
|
|
debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
|
|
|
|
|
rword, cond_code, last_rword);
|
|
|
|
|
|
|
|
|
|
sv_errexit_depth = G.errexit_depth;
|
|
|
|
|
if (IF_HAS_KEYWORDS(rword == RES_IF || rword == RES_ELIF ||)
|
|
|
|
|
pi->followup != PIPE_SEQ
|
|
|
|
|
) {
|
|
|
|
|
G.errexit_depth++;
|
|
|
|
|
}
|
|
|
|
|
#if ENABLE_HUSH_LOOPS
|
|
|
|
|
if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR)
|
|
|
|
|
&& loop_top == NULL /* avoid bumping G.depth_of_loop twice */
|
|
|
|
@ -8243,6 +8271,14 @@ static int run_list(struct pipe *pi)
|
|
|
|
|
check_and_run_traps();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Handle "set -e" */
|
|
|
|
|
if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
|
|
|
|
|
debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
|
|
|
|
|
if (G.errexit_depth == 0)
|
|
|
|
|
hush_exit(rcode);
|
|
|
|
|
}
|
|
|
|
|
G.errexit_depth = sv_errexit_depth;
|
|
|
|
|
|
|
|
|
|
/* Analyze how result affects subsequent commands */
|
|
|
|
|
#if ENABLE_HUSH_IF
|
|
|
|
|
if (rword == RES_IF || rword == RES_ELIF)
|
|
|
|
@ -8422,22 +8458,9 @@ static int set_mode(int state, char mode, const char *o_opt)
|
|
|
|
|
G.o_opt[idx] = state;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* TODO: set -e
|
|
|
|
|
Exit if pipe, list, or compound command exits with a non-zero status.
|
|
|
|
|
Shell does not exit if failed command is part of condition in
|
|
|
|
|
if/while, part of && or || list except the last command, any command
|
|
|
|
|
in a pipe but the last, or if the command's return value is being
|
|
|
|
|
inverted with !. If a compound command other than a subshell returns a
|
|
|
|
|
non-zero status because a command failed while -e was being ignored, the
|
|
|
|
|
shell does not exit. A trap on ERR, if set, is executed before the shell
|
|
|
|
|
exits [ERR is a bashism].
|
|
|
|
|
|
|
|
|
|
If a compound command or function executes in a context where -e is
|
|
|
|
|
ignored, none of the commands executed within are affected by the -e
|
|
|
|
|
setting. If a compound command or function sets -e while executing in a
|
|
|
|
|
context where -e is ignored, that setting does not have any effect until
|
|
|
|
|
the compound command or the command containing the function call completes.
|
|
|
|
|
*/
|
|
|
|
|
case 'e':
|
|
|
|
|
G.o_opt[OPT_O_ERREXIT] = state;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
@ -8564,7 +8587,7 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
|
|
|
|
|
builtin_argc = 0;
|
|
|
|
|
while (1) {
|
|
|
|
|
opt = getopt(argc, argv, "+c:xinsl"
|
|
|
|
|
opt = getopt(argc, argv, "+c:exinsl"
|
|
|
|
|
#if !BB_MMU
|
|
|
|
|
"<:$:R:V:"
|
|
|
|
|
# if ENABLE_HUSH_FUNCTIONS
|
|
|
|
@ -8682,6 +8705,7 @@ int hush_main(int argc, char **argv)
|
|
|
|
|
#endif
|
|
|
|
|
case 'n':
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'e':
|
|
|
|
|
if (set_mode(1, opt, NULL) == 0) /* no error */
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|