aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c70
1 files changed, 49 insertions, 21 deletions
diff --git a/shell/hush.c b/shell/hush.c
index e9cec1cc9..ab7263381 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -63,7 +63,6 @@
63 * reserved words: function select 63 * reserved words: function select
64 * advanced test: [[ ]] 64 * advanced test: [[ ]]
65 * process substitution: <(list) and >(list) 65 * process substitution: <(list) and >(list)
66 * =~: regex operator
67 * let EXPR [EXPR...] 66 * let EXPR [EXPR...]
68 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION) 67 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION)
69 * If the last arg evaluates to 0, let returns 1; 0 otherwise. 68 * If the last arg evaluates to 0, let returns 1; 0 otherwise.
@@ -84,13 +83,12 @@
84 * [[ args ]] are CMD_SINGLEWORD_NOGLOB: 83 * [[ args ]] are CMD_SINGLEWORD_NOGLOB:
85 * v='a b'; [[ $v = 'a b' ]]; echo 0:$? 84 * v='a b'; [[ $v = 'a b' ]]; echo 0:$?
86 * [[ /bin/n* ]]; echo 0:$? 85 * [[ /bin/n* ]]; echo 0:$?
86 * = is glob match operator, not equality operator: STR = GLOB
87 * == same as =
88 * =~ is regex match operator: STR =~ REGEX
87 * TODO: 89 * TODO:
88 * &&/|| are AND/OR ops, -a/-o are not
89 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) 90 * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc)
90 * = is glob match operator, not equality operator: STR = GLOB 91 * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*"
91 * (in GLOB, quoting is significant on char-by-char basis: a*cd"*")
92 * == same as =
93 * add =~ regex match operator: STR =~ REGEX
94 */ 92 */
95//config:config HUSH 93//config:config HUSH
96//config: bool "hush (68 kb)" 94//config: bool "hush (68 kb)"
@@ -651,14 +649,16 @@ struct command {
651 smallint cmd_type; /* CMD_xxx */ 649 smallint cmd_type; /* CMD_xxx */
652#define CMD_NORMAL 0 650#define CMD_NORMAL 0
653#define CMD_SUBSHELL 1 651#define CMD_SUBSHELL 1
654#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY 652#if BASH_TEST2
655/* used for "[[ EXPR ]]", and to prevent word splitting and globbing in 653/* used for "[[ EXPR ]]" */
656 * "export v=t*" 654# define CMD_TEST2_SINGLEWORD_NOGLOB 2
657 */ 655#endif
658# define CMD_SINGLEWORD_NOGLOB 2 656#if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
657/* used to prevent word splitting and globbing in "export v=t*" */
658# define CMD_SINGLEWORD_NOGLOB 3
659#endif 659#endif
660#if ENABLE_HUSH_FUNCTIONS 660#if ENABLE_HUSH_FUNCTIONS
661# define CMD_FUNCDEF 3 661# define CMD_FUNCDEF 4
662#endif 662#endif
663 663
664 smalluint cmd_exitcode; 664 smalluint cmd_exitcode;
@@ -4112,6 +4112,14 @@ static int done_word(struct parse_context *ctx)
4112 ctx->ctx_dsemicolon = 0; 4112 ctx->ctx_dsemicolon = 0;
4113 } else 4113 } else
4114# endif 4114# endif
4115# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4116 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
4117 && strcmp(ctx->word.data, "]]") == 0
4118 ) {
4119 /* allow "[[ ]] >file" etc */
4120 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4121 } else
4122# endif
4115 if (!command->argv /* if it's the first word... */ 4123 if (!command->argv /* if it's the first word... */
4116# if ENABLE_HUSH_LOOPS 4124# if ENABLE_HUSH_LOOPS
4117 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ 4125 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
@@ -4146,11 +4154,13 @@ static int done_word(struct parse_context *ctx)
4146 (ctx->ctx_res_w == RES_SNTX)); 4154 (ctx->ctx_res_w == RES_SNTX));
4147 return (ctx->ctx_res_w == RES_SNTX); 4155 return (ctx->ctx_res_w == RES_SNTX);
4148 } 4156 }
4157# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
4158 if (strcmp(ctx->word.data, "[[") == 0) {
4159 command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB;
4160 } else
4161# endif
4149# if defined(CMD_SINGLEWORD_NOGLOB) 4162# if defined(CMD_SINGLEWORD_NOGLOB)
4150 if (0 4163 if (0
4151# if BASH_TEST2
4152 || strcmp(ctx->word.data, "[[") == 0
4153# endif
4154 /* In bash, local/export/readonly are special, args 4164 /* In bash, local/export/readonly are special, args
4155 * are assignments and therefore expansion of them 4165 * are assignments and therefore expansion of them
4156 * should be "one-word" expansion: 4166 * should be "one-word" expansion:
@@ -4172,7 +4182,8 @@ static int done_word(struct parse_context *ctx)
4172 ) { 4182 ) {
4173 command->cmd_type = CMD_SINGLEWORD_NOGLOB; 4183 command->cmd_type = CMD_SINGLEWORD_NOGLOB;
4174 } 4184 }
4175 /* fall through */ 4185# else
4186 { /* empty block to pair "if ... else" */ }
4176# endif 4187# endif
4177 } 4188 }
4178#endif /* HAS_KEYWORDS */ 4189#endif /* HAS_KEYWORDS */
@@ -5354,9 +5365,15 @@ static struct pipe *parse_stream(char **pstring,
5354 if (ch != '\n') 5365 if (ch != '\n')
5355 next = i_peek_and_eat_bkslash_nl(input); 5366 next = i_peek_and_eat_bkslash_nl(input);
5356 5367
5357 is_special = "{}<>;&|()#" /* special outside of "str" */ 5368 is_special = "{}<>&|();#" /* special outside of "str" */
5358 "$\"" IF_HUSH_TICK("`") /* always special */ 5369 "$\"" IF_HUSH_TICK("`") /* always special */
5359 SPECIAL_VAR_SYMBOL_STR; 5370 SPECIAL_VAR_SYMBOL_STR;
5371#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
5372 if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
5373 /* In [[ ]], {}<>&|() are not special */
5374 is_special += 8;
5375 } else
5376#endif
5360 /* Are { and } special here? */ 5377 /* Are { and } special here? */
5361 if (ctx.command->argv /* word [word]{... - non-special */ 5378 if (ctx.command->argv /* word [word]{... - non-special */
5362 || ctx.word.length /* word{... - non-special */ 5379 || ctx.word.length /* word{... - non-special */
@@ -6953,7 +6970,7 @@ static char **expand_strvec_to_strvec(char **argv)
6953 return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); 6970 return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS);
6954} 6971}
6955 6972
6956#if defined(CMD_SINGLEWORD_NOGLOB) 6973#if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB)
6957static char **expand_strvec_to_strvec_singleword_noglob(char **argv) 6974static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
6958{ 6975{
6959 return expand_variables(argv, EXP_FLAG_SINGLEWORD); 6976 return expand_variables(argv, EXP_FLAG_SINGLEWORD);
@@ -8698,9 +8715,15 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8698 */ 8715 */
8699 if (WIFSIGNALED(status)) { 8716 if (WIFSIGNALED(status)) {
8700 int sig = WTERMSIG(status); 8717 int sig = WTERMSIG(status);
8701 if (i == fg_pipe->num_cmds-1) 8718 if (G.run_list_level == 1
8702 /* TODO: use strsignal() instead for bash compat? but that's bloat... */ 8719 /* ^^^^^ Do not print in nested contexts, example:
8703 puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); 8720 * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137"
8721 */
8722 && i == fg_pipe->num_cmds-1
8723 ) {
8724 /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */
8725 puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig));
8726 }
8704 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 8727 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
8705 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 8728 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
8706 * Maybe we need to use sig | 128? */ 8729 * Maybe we need to use sig | 128? */
@@ -9127,6 +9150,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
9127 } 9150 }
9128 9151
9129 /* Expand the rest into (possibly) many strings each */ 9152 /* Expand the rest into (possibly) many strings each */
9153#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
9154 if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB)
9155 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);
9156 else
9157#endif
9130#if defined(CMD_SINGLEWORD_NOGLOB) 9158#if defined(CMD_SINGLEWORD_NOGLOB)
9131 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) 9159 if (command->cmd_type == CMD_SINGLEWORD_NOGLOB)
9132 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); 9160 argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt);