aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c385
1 files changed, 310 insertions, 75 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 708555ac4..8f1017e3c 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -47,17 +47,13 @@
47 * follow IFS rules more precisely, including update semantics 47 * follow IFS rules more precisely, including update semantics
48 * tilde expansion 48 * tilde expansion
49 * aliases 49 * aliases
50 * builtins mandated by standards we don't support: 50 * "command" missing features:
51 * [un]alias, command, fc: 51 * command -p CMD: run CMD using default $PATH
52 * command -v CMD: print "/path/to/CMD" 52 * (can use this to override standalone shell as well?)
53 * prints "CMD" for builtins
54 * prints "alias ALIAS='EXPANSION'" for aliases
55 * prints nothing and sets $? to 1 if not found
56 * command -V CMD: print "CMD is /path/CMD|a shell builtin|etc"
57 * command [-p] CMD: run CMD, even if a function CMD also exists
58 * (can use this to override standalone shell as well)
59 * -p: use default $PATH
60 * command BLTIN: disables special-ness (e.g. errors do not abort) 53 * command BLTIN: disables special-ness (e.g. errors do not abort)
54 * command -V CMD1 CMD2 CMD3 (multiple args) (not in standard)
55 * builtins mandated by standards we don't support:
56 * [un]alias, fc:
61 * fc -l[nr] [BEG] [END]: list range of commands in history 57 * fc -l[nr] [BEG] [END]: list range of commands in history
62 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands 58 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
63 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP 59 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
@@ -124,6 +120,18 @@
124//config: help 120//config: help
125//config: Enable {abc,def} extension. 121//config: Enable {abc,def} extension.
126//config: 122//config:
123//config:config HUSH_LINENO_VAR
124//config: bool "$LINENO variable"
125//config: default y
126//config: depends on HUSH_BASH_COMPAT
127//config:
128//config:config HUSH_BASH_SOURCE_CURDIR
129//config: bool "'source' and '.' builtins search current directory after $PATH"
130//config: default n # do not encourage non-standard behavior
131//config: depends on HUSH_BASH_COMPAT
132//config: help
133//config: This is not compliant with standards. Avoid if possible.
134//config:
127//config:config HUSH_INTERACTIVE 135//config:config HUSH_INTERACTIVE
128//config: bool "Interactive mode" 136//config: bool "Interactive mode"
129//config: default y 137//config: default y
@@ -253,6 +261,11 @@
253//config: default y 261//config: default y
254//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 262//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
255//config: 263//config:
264//config:config HUSH_COMMAND
265//config: bool "command builtin"
266//config: default y
267//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
268//config:
256//config:config HUSH_TRAP 269//config:config HUSH_TRAP
257//config: bool "trap builtin" 270//config: bool "trap builtin"
258//config: default y 271//config: default y
@@ -462,7 +475,10 @@
462# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3) 475# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3)
463#endif 476#endif
464 477
465#define SPECIAL_VAR_SYMBOL 3 478#define SPECIAL_VAR_SYMBOL_STR "\3"
479#define SPECIAL_VAR_SYMBOL 3
480/* The "variable" with name "\1" emits string "\3". Testcase: "echo ^C" */
481#define SPECIAL_VAR_QUOTED_SVS 1
466 482
467struct variable; 483struct variable;
468 484
@@ -608,6 +624,9 @@ typedef enum redir_type {
608struct command { 624struct command {
609 pid_t pid; /* 0 if exited */ 625 pid_t pid; /* 0 if exited */
610 int assignment_cnt; /* how many argv[i] are assignments? */ 626 int assignment_cnt; /* how many argv[i] are assignments? */
627#if ENABLE_HUSH_LINENO_VAR
628 unsigned lineno;
629#endif
611 smallint cmd_type; /* CMD_xxx */ 630 smallint cmd_type; /* CMD_xxx */
612#define CMD_NORMAL 0 631#define CMD_NORMAL 0
613#define CMD_SUBSHELL 1 632#define CMD_SUBSHELL 1
@@ -927,6 +946,10 @@ struct globals {
927 unsigned handled_SIGCHLD; 946 unsigned handled_SIGCHLD;
928 smallint we_have_children; 947 smallint we_have_children;
929#endif 948#endif
949#if ENABLE_HUSH_LINENO_VAR
950 unsigned lineno;
951 char *lineno_var;
952#endif
930 struct FILE_list *FILE_list; 953 struct FILE_list *FILE_list;
931 /* Which signals have non-DFL handler (even with no traps set)? 954 /* Which signals have non-DFL handler (even with no traps set)?
932 * Set at the start to: 955 * Set at the start to:
@@ -1924,7 +1947,7 @@ static void hush_exit(int exitcode)
1924 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) { 1947 if (G.exiting <= 0 && G_traps && G_traps[0] && G_traps[0][0]) {
1925 char *argv[3]; 1948 char *argv[3];
1926 /* argv[0] is unused */ 1949 /* argv[0] is unused */
1927 argv[1] = G_traps[0]; 1950 argv[1] = xstrdup(G_traps[0]); /* copy, since EXIT trap handler may modify G_traps[0] */
1928 argv[2] = NULL; 1951 argv[2] = NULL;
1929 G.exiting = 1; /* prevent EXIT trap recursion */ 1952 G.exiting = 1; /* prevent EXIT trap recursion */
1930 /* Note: G_traps[0] is not cleared! 1953 /* Note: G_traps[0] is not cleared!
@@ -1985,10 +2008,12 @@ static int check_and_run_traps(void)
1985 smalluint save_rcode; 2008 smalluint save_rcode;
1986 char *argv[3]; 2009 char *argv[3];
1987 /* argv[0] is unused */ 2010 /* argv[0] is unused */
1988 argv[1] = G_traps[sig]; 2011 argv[1] = xstrdup(G_traps[sig]);
2012 /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */
1989 argv[2] = NULL; 2013 argv[2] = NULL;
1990 save_rcode = G.last_exitcode; 2014 save_rcode = G.last_exitcode;
1991 builtin_eval(argv); 2015 builtin_eval(argv);
2016 free(argv[1]);
1992//FIXME: shouldn't it be set to 128 + sig instead? 2017//FIXME: shouldn't it be set to 128 + sig instead?
1993 G.last_exitcode = save_rcode; 2018 G.last_exitcode = save_rcode;
1994 last_sig = sig; 2019 last_sig = sig;
@@ -2131,6 +2156,13 @@ static int set_local_var(char *str, unsigned flags)
2131 } 2156 }
2132 2157
2133 name_len = eq_sign - str + 1; /* including '=' */ 2158 name_len = eq_sign - str + 1; /* including '=' */
2159#if ENABLE_HUSH_LINENO_VAR
2160 if (G.lineno_var) {
2161 if (name_len == 7 && strncmp("LINENO", str, 6) == 0)
2162 G.lineno_var = NULL;
2163 }
2164#endif
2165
2134 var_pp = &G.top_var; 2166 var_pp = &G.top_var;
2135 while ((cur = *var_pp) != NULL) { 2167 while ((cur = *var_pp) != NULL) {
2136 if (strncmp(cur->varstr, str, name_len) != 0) { 2168 if (strncmp(cur->varstr, str, name_len) != 0) {
@@ -2252,10 +2284,16 @@ static int unset_local_var_len(const char *name, int name_len)
2252 2284
2253 if (!name) 2285 if (!name)
2254 return EXIT_SUCCESS; 2286 return EXIT_SUCCESS;
2287
2255#if ENABLE_HUSH_GETOPTS 2288#if ENABLE_HUSH_GETOPTS
2256 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0) 2289 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
2257 G.getopt_count = 0; 2290 G.getopt_count = 0;
2258#endif 2291#endif
2292#if ENABLE_HUSH_LINENO_VAR
2293 if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0)
2294 G.lineno_var = NULL;
2295#endif
2296
2259 var_pp = &G.top_var; 2297 var_pp = &G.top_var;
2260 while ((cur = *var_pp) != NULL) { 2298 while ((cur = *var_pp) != NULL) {
2261 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') { 2299 if (strncmp(cur->varstr, name, name_len) == 0 && cur->varstr[name_len] == '=') {
@@ -2278,7 +2316,7 @@ static int unset_local_var_len(const char *name, int name_len)
2278 return EXIT_SUCCESS; 2316 return EXIT_SUCCESS;
2279} 2317}
2280 2318
2281#if ENABLE_HUSH_UNSET 2319#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2282static int unset_local_var(const char *name) 2320static int unset_local_var(const char *name)
2283{ 2321{
2284 return unset_local_var_len(name, strlen(name)); 2322 return unset_local_var_len(name, strlen(name));
@@ -2300,7 +2338,7 @@ static void unset_vars(char **strings)
2300 free(strings); 2338 free(strings);
2301} 2339}
2302 2340
2303#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ 2341#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ || ENABLE_HUSH_GETOPTS
2304static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2342static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2305{ 2343{
2306 char *var = xasprintf("%s=%s", name, val); 2344 char *var = xasprintf("%s=%s", name, val);
@@ -2574,6 +2612,12 @@ static int i_getch(struct in_str *i)
2574 out: 2612 out:
2575 debug_printf("file_get: got '%c' %d\n", ch, ch); 2613 debug_printf("file_get: got '%c' %d\n", ch, ch);
2576 i->last_char = ch; 2614 i->last_char = ch;
2615#if ENABLE_HUSH_LINENO_VAR
2616 if (ch == '\n') {
2617 G.lineno++;
2618 debug_printf_parse("G.lineno++ = %u\n", G.lineno);
2619 }
2620#endif
2577 return ch; 2621 return ch;
2578} 2622}
2579 2623
@@ -3374,8 +3418,13 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3374 3418
3375 pin = 0; 3419 pin = 0;
3376 while (pi) { 3420 while (pi) {
3377 fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", 3421 fdprintf(2, "%*spipe %d %sres_word=%s followup=%d %s\n",
3378 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); 3422 lvl*2, "",
3423 pin,
3424 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3425 RES[pi->res_word],
3426 pi->followup, PIPE[pi->followup]
3427 );
3379 prn = 0; 3428 prn = 0;
3380 while (prn < pi->num_cmds) { 3429 while (prn < pi->num_cmds) {
3381 struct command *command = &pi->cmds[prn]; 3430 struct command *command = &pi->cmds[prn];
@@ -3384,6 +3433,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3384 fdprintf(2, "%*s cmd %d assignment_cnt:%d", 3433 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3385 lvl*2, "", prn, 3434 lvl*2, "", prn,
3386 command->assignment_cnt); 3435 command->assignment_cnt);
3436#if ENABLE_HUSH_LINENO_VAR
3437 fdprintf(2, " LINENO:%u", command->lineno);
3438#endif
3387 if (command->group) { 3439 if (command->group) {
3388 fdprintf(2, " group %s: (argv=%p)%s%s\n", 3440 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3389 CMDTYPE[command->cmd_type], 3441 CMDTYPE[command->cmd_type],
@@ -3456,6 +3508,10 @@ static int done_command(struct parse_context *ctx)
3456 ctx->command = command = &pi->cmds[pi->num_cmds]; 3508 ctx->command = command = &pi->cmds[pi->num_cmds];
3457 clear_and_ret: 3509 clear_and_ret:
3458 memset(command, 0, sizeof(*command)); 3510 memset(command, 0, sizeof(*command));
3511#if ENABLE_HUSH_LINENO_VAR
3512 command->lineno = G.lineno;
3513 debug_printf_parse("command->lineno = G.lineno (%u)\n", G.lineno);
3514#endif
3459 return pi->num_cmds; /* used only for 0/nonzero check */ 3515 return pi->num_cmds; /* used only for 0/nonzero check */
3460} 3516}
3461 3517
@@ -3643,9 +3699,9 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
3643 } 3699 }
3644 return NULL; 3700 return NULL;
3645} 3701}
3646/* Return 0: not a keyword, 1: keyword 3702/* Return NULL: not a keyword, else: keyword
3647 */ 3703 */
3648static int reserved_word(o_string *word, struct parse_context *ctx) 3704static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx)
3649{ 3705{
3650# if ENABLE_HUSH_CASE 3706# if ENABLE_HUSH_CASE
3651 static const struct reserved_combo reserved_match = { 3707 static const struct reserved_combo reserved_match = {
@@ -3658,7 +3714,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3658 return 0; 3714 return 0;
3659 r = match_reserved_word(word); 3715 r = match_reserved_word(word);
3660 if (!r) 3716 if (!r)
3661 return 0; 3717 return r; /* NULL */
3662 3718
3663 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 3719 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
3664# if ENABLE_HUSH_CASE 3720# if ENABLE_HUSH_CASE
@@ -3673,7 +3729,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3673 ctx->ctx_res_w = RES_SNTX; 3729 ctx->ctx_res_w = RES_SNTX;
3674 } 3730 }
3675 ctx->ctx_inverted = 1; 3731 ctx->ctx_inverted = 1;
3676 return 1; 3732 return r;
3677 } 3733 }
3678 if (r->flag & FLAG_START) { 3734 if (r->flag & FLAG_START) {
3679 struct parse_context *old; 3735 struct parse_context *old;
@@ -3685,7 +3741,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3685 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 3741 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
3686 syntax_error_at(word->data); 3742 syntax_error_at(word->data);
3687 ctx->ctx_res_w = RES_SNTX; 3743 ctx->ctx_res_w = RES_SNTX;
3688 return 1; 3744 return r;
3689 } else { 3745 } else {
3690 /* "{...} fi" is ok. "{...} if" is not 3746 /* "{...} fi" is ok. "{...} if" is not
3691 * Example: 3747 * Example:
@@ -3735,7 +3791,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3735 *ctx = *old; /* physical copy */ 3791 *ctx = *old; /* physical copy */
3736 free(old); 3792 free(old);
3737 } 3793 }
3738 return 1; 3794 return r;
3739} 3795}
3740#endif /* HAS_KEYWORDS */ 3796#endif /* HAS_KEYWORDS */
3741 3797
@@ -3801,9 +3857,26 @@ static int done_word(o_string *word, struct parse_context *ctx)
3801 && ctx->ctx_res_w != RES_CASE 3857 && ctx->ctx_res_w != RES_CASE
3802# endif 3858# endif
3803 ) { 3859 ) {
3804 int reserved = reserved_word(word, ctx); 3860 const struct reserved_combo *reserved;
3805 debug_printf_parse("checking for reserved-ness: %d\n", reserved); 3861 reserved = reserved_word(word, ctx);
3862 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
3806 if (reserved) { 3863 if (reserved) {
3864# if ENABLE_HUSH_LINENO_VAR
3865/* Case:
3866 * "while ...; do
3867 * cmd ..."
3868 * If we don't close the pipe _now_, immediately after "do", lineno logic
3869 * sees "cmd" as starting at "do" - i.e., at the previous line.
3870 */
3871 if (0
3872 IF_HUSH_IF(|| reserved->res == RES_THEN)
3873 IF_HUSH_IF(|| reserved->res == RES_ELIF)
3874 IF_HUSH_IF(|| reserved->res == RES_ELSE)
3875 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
3876 ) {
3877 done_pipe(ctx, PIPE_SEQ);
3878 }
3879# endif
3807 o_reset_to_empty_unquoted(word); 3880 o_reset_to_empty_unquoted(word);
3808 debug_printf_parse("done_word return %d\n", 3881 debug_printf_parse("done_word return %d\n",
3809 (ctx->ctx_res_w == RES_SNTX)); 3882 (ctx->ctx_res_w == RES_SNTX));
@@ -3840,21 +3913,6 @@ static int done_word(o_string *word, struct parse_context *ctx)
3840 word->o_assignment = MAYBE_ASSIGNMENT; 3913 word->o_assignment = MAYBE_ASSIGNMENT;
3841 } 3914 }
3842 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); 3915 debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]);
3843
3844 if (word->has_quoted_part
3845 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
3846 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
3847 /* (otherwise it's known to be not empty and is already safe) */
3848 ) {
3849 /* exclude "$@" - it can expand to no word despite "" */
3850 char *p = word->data;
3851 while (p[0] == SPECIAL_VAR_SYMBOL
3852 && (p[1] & 0x7f) == '@'
3853 && p[2] == SPECIAL_VAR_SYMBOL
3854 ) {
3855 p += 3;
3856 }
3857 }
3858 command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); 3916 command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
3859 debug_print_strings("word appended to argv", command->argv); 3917 debug_print_strings("word appended to argv", command->argv);
3860 } 3918 }
@@ -4503,9 +4561,10 @@ static int parse_dollar(o_string *as_string,
4503 4561
4504 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); 4562 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch);
4505 if (isalpha(ch)) { 4563 if (isalpha(ch)) {
4564 make_var:
4506 ch = i_getch(input); 4565 ch = i_getch(input);
4507 nommu_addchr(as_string, ch); 4566 nommu_addchr(as_string, ch);
4508 make_var: 4567 /*make_var1:*/
4509 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4568 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4510 while (1) { 4569 while (1) {
4511 debug_printf_parse(": '%c'\n", ch); 4570 debug_printf_parse(": '%c'\n", ch);
@@ -4698,19 +4757,22 @@ static int parse_dollar(o_string *as_string,
4698 } 4757 }
4699#endif 4758#endif
4700 case '_': 4759 case '_':
4760 goto make_var;
4761#if 0
4762 /* TODO: $_ and $-: */
4763 /* $_ Shell or shell script name; or last argument of last command
4764 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
4765 * but in command's env, set to full pathname used to invoke it */
4766 /* $- Option flags set by set builtin or shell options (-i etc) */
4701 ch = i_getch(input); 4767 ch = i_getch(input);
4702 nommu_addchr(as_string, ch); 4768 nommu_addchr(as_string, ch);
4703 ch = i_peek_and_eat_bkslash_nl(input); 4769 ch = i_peek_and_eat_bkslash_nl(input);
4704 if (isalnum(ch)) { /* it's $_name or $_123 */ 4770 if (isalnum(ch)) { /* it's $_name or $_123 */
4705 ch = '_'; 4771 ch = '_';
4706 goto make_var; 4772 goto make_var1;
4707 } 4773 }
4708 /* else: it's $_ */ 4774 /* else: it's $_ */
4709 /* TODO: $_ and $-: */ 4775#endif
4710 /* $_ Shell or shell script name; or last argument of last command
4711 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
4712 * but in command's env, set to full pathname used to invoke it */
4713 /* $- Option flags set by set builtin or shell options (-i etc) */
4714 default: 4776 default:
4715 o_addQchr(dest, '$'); 4777 o_addQchr(dest, '$');
4716 } 4778 }
@@ -4914,7 +4976,8 @@ static struct pipe *parse_stream(char **pstring,
4914 next = i_peek(input); 4976 next = i_peek(input);
4915 4977
4916 is_special = "{}<>;&|()#'" /* special outside of "str" */ 4978 is_special = "{}<>;&|()#'" /* special outside of "str" */
4917 "\\$\"" IF_HUSH_TICK("`"); /* always special */ 4979 "\\$\"" IF_HUSH_TICK("`") /* always special */
4980 SPECIAL_VAR_SYMBOL_STR;
4918 /* Are { and } special here? */ 4981 /* Are { and } special here? */
4919 if (ctx.command->argv /* word [word]{... - non-special */ 4982 if (ctx.command->argv /* word [word]{... - non-special */
4920 || dest.length /* word{... - non-special */ 4983 || dest.length /* word{... - non-special */
@@ -4948,6 +5011,22 @@ static struct pipe *parse_stream(char **pstring,
4948 } 5011 }
4949 5012
4950 if (is_blank) { 5013 if (is_blank) {
5014#if ENABLE_HUSH_LINENO_VAR
5015/* Case:
5016 * "while ...; do<whitespace><newline>
5017 * cmd ..."
5018 * would think that "cmd" starts in <whitespace> -
5019 * i.e., at the previous line.
5020 * We need to skip all whitespace before newlines.
5021 */
5022 while (ch != '\n') {
5023 next = i_peek(input);
5024 if (next != ' ' && next != '\t' && next != '\n')
5025 break; /* next char is not ws */
5026 ch = i_getch(input);
5027 }
5028 /* ch == last eaten whitespace char */
5029#endif
4951 if (done_word(&dest, &ctx)) { 5030 if (done_word(&dest, &ctx)) {
4952 goto parse_error; 5031 goto parse_error;
4953 } 5032 }
@@ -5186,8 +5265,14 @@ static struct pipe *parse_stream(char **pstring,
5186 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ 5265 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */
5187 5266
5188 switch (ch) { 5267 switch (ch) {
5189 case '#': /* non-comment #: "echo a#b" etc */ 5268 case SPECIAL_VAR_SYMBOL:
5190 o_addQchr(&dest, ch); 5269 /* Convert raw ^C to corresponding special variable reference */
5270 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5271 o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS);
5272 /* fall through */
5273 case '#':
5274 /* non-comment #: "echo a#b" etc */
5275 o_addchr(&dest, ch);
5191 break; 5276 break;
5192 case '\\': 5277 case '\\':
5193 if (next == EOF) { 5278 if (next == EOF) {
@@ -5229,6 +5314,11 @@ static struct pipe *parse_stream(char **pstring,
5229 nommu_addchr(&ctx.as_string, ch); 5314 nommu_addchr(&ctx.as_string, ch);
5230 if (ch == '\'') 5315 if (ch == '\'')
5231 break; 5316 break;
5317 if (ch == SPECIAL_VAR_SYMBOL) {
5318 /* Convert raw ^C to corresponding special variable reference */
5319 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5320 o_addchr(&dest, SPECIAL_VAR_QUOTED_SVS);
5321 }
5232 o_addqchr(&dest, ch); 5322 o_addqchr(&dest, ch);
5233 } 5323 }
5234 } 5324 }
@@ -5534,7 +5624,7 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha
5534static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) 5624static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash)
5535{ 5625{
5536#if !BASH_PATTERN_SUBST 5626#if !BASH_PATTERN_SUBST
5537 const int do_unbackslash = 1; 5627 enum { do_unbackslash = 1 };
5538#endif 5628#endif
5539 char *exp_str; 5629 char *exp_str;
5540 struct in_str input; 5630 struct in_str input;
@@ -5610,6 +5700,10 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
5610 unsigned res_len = 0; 5700 unsigned res_len = 0;
5611 unsigned repl_len = strlen(repl); 5701 unsigned repl_len = strlen(repl);
5612 5702
5703 /* Null pattern never matches, including if "var" is empty */
5704 if (!pattern[0])
5705 return result; /* NULL, no replaces happened */
5706
5613 while (1) { 5707 while (1) {
5614 int size; 5708 int size;
5615 char *s = strstr_pattern(val, pattern, &size); 5709 char *s = strstr_pattern(val, pattern, &size);
@@ -5640,9 +5734,9 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
5640 */ 5734 */
5641static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) 5735static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp)
5642{ 5736{
5643 const char *val = NULL; 5737 const char *val;
5644 char *to_be_freed = NULL; 5738 char *to_be_freed;
5645 char *p = *pp; 5739 char *p;
5646 char *var; 5740 char *var;
5647 char first_char; 5741 char first_char;
5648 char exp_op; 5742 char exp_op;
@@ -5651,6 +5745,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5651 char *exp_word = exp_word; /* for compiler */ 5745 char *exp_word = exp_word; /* for compiler */
5652 char arg0; 5746 char arg0;
5653 5747
5748 val = NULL;
5749 to_be_freed = NULL;
5750 p = *pp;
5654 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */ 5751 *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */
5655 var = arg; 5752 var = arg;
5656 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; 5753 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
@@ -5773,8 +5870,6 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5773 * and if // is used, it is encoded as \: 5870 * and if // is used, it is encoded as \:
5774 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> 5871 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
5775 */ 5872 */
5776 /* Empty variable always gives nothing: */
5777 // "v=''; echo ${v/*/w}" prints "", not "w"
5778 if (val && val[0]) { 5873 if (val && val[0]) {
5779 /* pattern uses non-standard expansion. 5874 /* pattern uses non-standard expansion.
5780 * repl should be unbackslashed and globbed 5875 * repl should be unbackslashed and globbed
@@ -5810,6 +5905,13 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5810 val = to_be_freed; 5905 val = to_be_freed;
5811 free(pattern); 5906 free(pattern);
5812 free(repl); 5907 free(repl);
5908 } else {
5909 /* Empty variable always gives nothing */
5910 // "v=''; echo ${v/*/w}" prints "", not "w"
5911 /* Just skip "replace" part */
5912 *p++ = SPECIAL_VAR_SYMBOL;
5913 p = strchr(p, SPECIAL_VAR_SYMBOL);
5914 *p = '\0';
5813 } 5915 }
5814 } 5916 }
5815#endif /* BASH_PATTERN_SUBST */ 5917#endif /* BASH_PATTERN_SUBST */
@@ -6041,6 +6143,11 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6041 arg++; 6143 arg++;
6042 cant_be_null = 0x80; 6144 cant_be_null = 0x80;
6043 break; 6145 break;
6146 case SPECIAL_VAR_QUOTED_SVS:
6147 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_QUOTED_SVS><SPECIAL_VAR_SYMBOL> */
6148 arg++;
6149 val = SPECIAL_VAR_SYMBOL_STR;
6150 break;
6044#if ENABLE_HUSH_TICK 6151#if ENABLE_HUSH_TICK
6045 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 6152 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
6046 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 6153 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
@@ -6199,7 +6306,7 @@ static char *expand_string_to_string(const char *str, int do_unbackslash)
6199 return (char*)list; 6306 return (char*)list;
6200} 6307}
6201 6308
6202/* Used for "eval" builtin and case string */ 6309#if ENABLE_HUSH_CASE
6203static char* expand_strvec_to_string(char **argv) 6310static char* expand_strvec_to_string(char **argv)
6204{ 6311{
6205 char **list; 6312 char **list;
@@ -6221,6 +6328,7 @@ static char* expand_strvec_to_string(char **argv)
6221 debug_printf_expand("strvec_to_string='%s'\n", (char*)list); 6328 debug_printf_expand("strvec_to_string='%s'\n", (char*)list);
6222 return (char*)list; 6329 return (char*)list;
6223} 6330}
6331#endif
6224 6332
6225static char **expand_assignments(char **argv, int count) 6333static char **expand_assignments(char **argv, int count)
6226{ 6334{
@@ -6513,8 +6621,17 @@ static void parse_and_run_string(const char *s)
6513static void parse_and_run_file(FILE *f) 6621static void parse_and_run_file(FILE *f)
6514{ 6622{
6515 struct in_str input; 6623 struct in_str input;
6624#if ENABLE_HUSH_LINENO_VAR
6625 unsigned sv;
6626
6627 sv = G.lineno;
6628 G.lineno = 1;
6629#endif
6516 setup_file_in_str(&input, f); 6630 setup_file_in_str(&input, f);
6517 parse_and_run_stream(&input, ';'); 6631 parse_and_run_stream(&input, ';');
6632#if ENABLE_HUSH_LINENO_VAR
6633 G.lineno = sv;
6634#endif
6518} 6635}
6519 6636
6520#if ENABLE_HUSH_TICK 6637#if ENABLE_HUSH_TICK
@@ -7330,6 +7447,32 @@ static void dump_cmd_in_x_mode(char **argv)
7330# define dump_cmd_in_x_mode(argv) ((void)0) 7447# define dump_cmd_in_x_mode(argv) ((void)0)
7331#endif 7448#endif
7332 7449
7450#if ENABLE_HUSH_COMMAND
7451static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
7452{
7453 char *to_free;
7454
7455 if (!opt_vV)
7456 return;
7457
7458 to_free = NULL;
7459 if (!explanation) {
7460 char *path = getenv("PATH");
7461 explanation = to_free = find_executable(cmd, &path); /* path == NULL is ok */
7462 if (!explanation)
7463 _exit(1); /* PROG was not found */
7464 if (opt_vV != 'V')
7465 cmd = to_free; /* -v PROG prints "/path/to/PROG" */
7466 }
7467 printf((opt_vV == 'V') ? "%s is %s\n" : "%s\n", cmd, explanation);
7468 free(to_free);
7469 fflush_all();
7470 _exit(0);
7471}
7472#else
7473# define if_command_vV_print_and_exit(a,b,c) ((void)0)
7474#endif
7475
7333#if BB_MMU 7476#if BB_MMU
7334#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ 7477#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
7335 pseudo_exec_argv(argv, assignment_cnt, argv_expanded) 7478 pseudo_exec_argv(argv, assignment_cnt, argv_expanded)
@@ -7350,7 +7493,11 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7350 char **argv, int assignment_cnt, 7493 char **argv, int assignment_cnt,
7351 char **argv_expanded) 7494 char **argv_expanded)
7352{ 7495{
7496 const struct built_in_command *x;
7353 char **new_env; 7497 char **new_env;
7498#if ENABLE_HUSH_COMMAND
7499 char opt_vV = 0;
7500#endif
7354 7501
7355 new_env = expand_assignments(argv, assignment_cnt); 7502 new_env = expand_assignments(argv, assignment_cnt);
7356 dump_cmd_in_x_mode(new_env); 7503 dump_cmd_in_x_mode(new_env);
@@ -7399,21 +7546,58 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7399 } 7546 }
7400#endif 7547#endif
7401 7548
7549#if ENABLE_HUSH_COMMAND
7550 /* "command BAR": run BAR without looking it up among functions
7551 * "command -v BAR": print "BAR" or "/path/to/BAR"; or exit 1
7552 * "command -V BAR": print "BAR is {a function,a shell builtin,/path/to/BAR}"
7553 */
7554 while (strcmp(argv[0], "command") == 0 && argv[1]) {
7555 char *p;
7556
7557 argv++;
7558 p = *argv;
7559 if (p[0] != '-' || !p[1])
7560 continue; /* bash allows "command command command [-OPT] BAR" */
7561
7562 for (;;) {
7563 p++;
7564 switch (*p) {
7565 case '\0':
7566 argv++;
7567 p = *argv;
7568 if (p[0] != '-' || !p[1])
7569 goto after_opts;
7570 continue; /* next arg is also -opts, process it too */
7571 case 'v':
7572 case 'V':
7573 opt_vV = *p;
7574 continue;
7575 default:
7576 bb_error_msg_and_die("%s: %s: invalid option", "command", argv[0]);
7577 }
7578 }
7579 }
7580 after_opts:
7581# if ENABLE_HUSH_FUNCTIONS
7582 if (opt_vV && find_function(argv[0]))
7583 if_command_vV_print_and_exit(opt_vV, argv[0], "a function");
7584# endif
7585#endif
7586
7402 /* Check if the command matches any of the builtins. 7587 /* Check if the command matches any of the builtins.
7403 * Depending on context, this might be redundant. But it's 7588 * Depending on context, this might be redundant. But it's
7404 * easier to waste a few CPU cycles than it is to figure out 7589 * easier to waste a few CPU cycles than it is to figure out
7405 * if this is one of those cases. 7590 * if this is one of those cases.
7406 */ 7591 */
7407 { 7592 /* Why "BB_MMU ? :" difference in logic? -
7408 /* On NOMMU, it is more expensive to re-execute shell 7593 * On NOMMU, it is more expensive to re-execute shell
7409 * just in order to run echo or test builtin. 7594 * just in order to run echo or test builtin.
7410 * It's better to skip it here and run corresponding 7595 * It's better to skip it here and run corresponding
7411 * non-builtin later. */ 7596 * non-builtin later. */
7412 const struct built_in_command *x; 7597 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]);
7413 x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]); 7598 if (x) {
7414 if (x) { 7599 if_command_vV_print_and_exit(opt_vV, argv[0], "a shell builtin");
7415 exec_builtin(&nommu_save->argv_from_re_execing, x, argv); 7600 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
7416 }
7417 } 7601 }
7418 7602
7419#if ENABLE_FEATURE_SH_STANDALONE 7603#if ENABLE_FEATURE_SH_STANDALONE
@@ -7421,6 +7605,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7421 { 7605 {
7422 int a = find_applet_by_name(argv[0]); 7606 int a = find_applet_by_name(argv[0]);
7423 if (a >= 0) { 7607 if (a >= 0) {
7608 if_command_vV_print_and_exit(opt_vV, argv[0], "an applet");
7424# if BB_MMU /* see above why on NOMMU it is not allowed */ 7609# if BB_MMU /* see above why on NOMMU it is not allowed */
7425 if (APPLET_IS_NOEXEC(a)) { 7610 if (APPLET_IS_NOEXEC(a)) {
7426 /* Do not leak open fds from opened script files etc. 7611 /* Do not leak open fds from opened script files etc.
@@ -7450,6 +7635,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7450#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU 7635#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU
7451 skip: 7636 skip:
7452#endif 7637#endif
7638 if_command_vV_print_and_exit(opt_vV, argv[0], NULL);
7453 execvp_or_die(argv); 7639 execvp_or_die(argv);
7454} 7640}
7455 7641
@@ -7992,6 +8178,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
7992 char **new_env = NULL; 8178 char **new_env = NULL;
7993 struct variable *old_vars = NULL; 8179 struct variable *old_vars = NULL;
7994 8180
8181#if ENABLE_HUSH_LINENO_VAR
8182 if (G.lineno_var)
8183 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8184#endif
8185
7995 if (argv[command->assignment_cnt] == NULL) { 8186 if (argv[command->assignment_cnt] == NULL) {
7996 /* Assignments, but no command */ 8187 /* Assignments, but no command */
7997 /* Ensure redirects take effect (that is, create files). 8188 /* Ensure redirects take effect (that is, create files).
@@ -8139,7 +8330,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8139 return rcode; 8330 return rcode;
8140 } 8331 }
8141 8332
8142 if (ENABLE_FEATURE_SH_NOFORK) { 8333 if (ENABLE_FEATURE_SH_NOFORK && NUM_APPLETS > 1) {
8143 int n = find_applet_by_name(argv_expanded[0]); 8334 int n = find_applet_by_name(argv_expanded[0]);
8144 if (n >= 0 && APPLET_IS_NOFORK(n)) { 8335 if (n >= 0 && APPLET_IS_NOFORK(n)) {
8145 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded); 8336 rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded);
@@ -8196,6 +8387,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
8196 if (cmd_no < pi->num_cmds) 8387 if (cmd_no < pi->num_cmds)
8197 xpiped_pair(pipefds); 8388 xpiped_pair(pipefds);
8198 8389
8390#if ENABLE_HUSH_LINENO_VAR
8391 if (G.lineno_var)
8392 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8393#endif
8394
8199 command->pid = BB_MMU ? fork() : vfork(); 8395 command->pid = BB_MMU ? fork() : vfork();
8200 if (!command->pid) { /* child */ 8396 if (!command->pid) { /* child */
8201#if ENABLE_HUSH_JOB 8397#if ENABLE_HUSH_JOB
@@ -8387,7 +8583,10 @@ static int run_list(struct pipe *pi)
8387 rword, cond_code, last_rword); 8583 rword, cond_code, last_rword);
8388 8584
8389 sv_errexit_depth = G.errexit_depth; 8585 sv_errexit_depth = G.errexit_depth;
8390 if (IF_HAS_KEYWORDS(rword == RES_IF || rword == RES_ELIF ||) 8586 if (
8587#if ENABLE_HUSH_IF
8588 rword == RES_IF || rword == RES_ELIF ||
8589#endif
8391 pi->followup != PIPE_SEQ 8590 pi->followup != PIPE_SEQ
8392 ) { 8591 ) {
8393 G.errexit_depth++; 8592 G.errexit_depth++;
@@ -8828,17 +9027,19 @@ int hush_main(int argc, char **argv)
8828#if !BB_MMU 9027#if !BB_MMU
8829 G.argv0_for_re_execing = argv[0]; 9028 G.argv0_for_re_execing = argv[0];
8830#endif 9029#endif
9030
8831 /* Deal with HUSH_VERSION */ 9031 /* Deal with HUSH_VERSION */
9032 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
9033 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
8832 shell_ver = xzalloc(sizeof(*shell_ver)); 9034 shell_ver = xzalloc(sizeof(*shell_ver));
8833 shell_ver->flg_export = 1; 9035 shell_ver->flg_export = 1;
8834 shell_ver->flg_read_only = 1; 9036 shell_ver->flg_read_only = 1;
8835 /* Code which handles ${var<op>...} needs writable values for all variables, 9037 /* Code which handles ${var<op>...} needs writable values for all variables,
8836 * therefore we xstrdup: */ 9038 * therefore we xstrdup: */
8837 shell_ver->varstr = xstrdup(hush_version_str); 9039 shell_ver->varstr = xstrdup(hush_version_str);
9040
8838 /* Create shell local variables from the values 9041 /* Create shell local variables from the values
8839 * currently living in the environment */ 9042 * currently living in the environment */
8840 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
8841 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
8842 G.top_var = shell_ver; 9043 G.top_var = shell_ver;
8843 cur_var = G.top_var; 9044 cur_var = G.top_var;
8844 e = environ; 9045 e = environ;
@@ -8904,6 +9105,14 @@ int hush_main(int argc, char **argv)
8904 */ 9105 */
8905#endif 9106#endif
8906 9107
9108#if ENABLE_HUSH_LINENO_VAR
9109 if (ENABLE_HUSH_LINENO_VAR) {
9110 char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), "");
9111 set_local_var(p, /*flags*/ 0);
9112 G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */
9113 }
9114#endif
9115
8907#if ENABLE_FEATURE_EDITING 9116#if ENABLE_FEATURE_EDITING
8908 G.line_input_state = new_line_input_t(FOR_SHELL); 9117 G.line_input_state = new_line_input_t(FOR_SHELL);
8909#endif 9118#endif
@@ -9346,13 +9555,34 @@ static int FAST_FUNC builtin_eval(char **argv)
9346 int rcode = EXIT_SUCCESS; 9555 int rcode = EXIT_SUCCESS;
9347 9556
9348 argv = skip_dash_dash(argv); 9557 argv = skip_dash_dash(argv);
9349 if (*argv) { 9558 if (argv[0]) {
9350 char *str = expand_strvec_to_string(argv); 9559 char *str = NULL;
9560
9561 if (argv[1]) {
9562 /* "The eval utility shall construct a command by
9563 * concatenating arguments together, separating
9564 * each with a <space> character."
9565 */
9566 char *p;
9567 unsigned len = 0;
9568 char **pp = argv;
9569 do
9570 len += strlen(*pp) + 1;
9571 while (*++pp);
9572 str = p = xmalloc(len);
9573 pp = argv;
9574 do {
9575 p = stpcpy(p, *pp);
9576 *p++ = ' ';
9577 } while (*++pp);
9578 p[-1] = '\0';
9579 }
9580
9351 /* bash: 9581 /* bash:
9352 * eval "echo Hi; done" ("done" is syntax error): 9582 * eval "echo Hi; done" ("done" is syntax error):
9353 * "echo Hi" will not execute too. 9583 * "echo Hi" will not execute too.
9354 */ 9584 */
9355 parse_and_run_string(str); 9585 parse_and_run_string(str ? str : argv[0]);
9356 free(str); 9586 free(str);
9357 rcode = G.last_exitcode; 9587 rcode = G.last_exitcode;
9358 } 9588 }
@@ -9855,7 +10085,7 @@ static int FAST_FUNC builtin_set(char **argv)
9855 10085
9856 /* Nothing known, so abort */ 10086 /* Nothing known, so abort */
9857 error: 10087 error:
9858 bb_error_msg("set: %s: invalid option", arg); 10088 bb_error_msg("%s: %s: invalid option", "set", arg);
9859 return EXIT_FAILURE; 10089 return EXIT_FAILURE;
9860} 10090}
9861#endif 10091#endif
@@ -10038,6 +10268,11 @@ static int FAST_FUNC builtin_source(char **argv)
10038 arg_path = find_in_path(filename); 10268 arg_path = find_in_path(filename);
10039 if (arg_path) 10269 if (arg_path)
10040 filename = arg_path; 10270 filename = arg_path;
10271 else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) {
10272 errno = ENOENT;
10273 bb_simple_perror_msg(filename);
10274 return EXIT_FAILURE;
10275 }
10041 } 10276 }
10042 input = remember_FILE(fopen_or_warn(filename, "r")); 10277 input = remember_FILE(fopen_or_warn(filename, "r"));
10043 free(arg_path); 10278 free(arg_path);