aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c183
1 files changed, 98 insertions, 85 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 752efd0c8..75083dc2e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8,6 +8,8 @@
8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org> 8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
9 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com> 9 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com>
10 * 10 *
11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
12 *
11 * Credits: 13 * Credits:
12 * The parser routines proper are all original material, first 14 * The parser routines proper are all original material, first
13 * written Dec 2000 and Jan 2001 by Larry Doolittle. The 15 * written Dec 2000 and Jan 2001 by Larry Doolittle. The
@@ -50,7 +52,6 @@
50 * 52 *
51 * Bash compat TODO: 53 * Bash compat TODO:
52 * redirection of stdout+stderr: &> and >& 54 * redirection of stdout+stderr: &> and >&
53 * brace expansion: one/{two,three,four}
54 * reserved words: function select 55 * reserved words: function select
55 * advanced test: [[ ]] 56 * advanced test: [[ ]]
56 * process substitution: <(list) and >(list) 57 * process substitution: <(list) and >(list)
@@ -63,7 +64,9 @@
63 * The EXPR is evaluated according to ARITHMETIC EVALUATION. 64 * The EXPR is evaluated according to ARITHMETIC EVALUATION.
64 * This is exactly equivalent to let "EXPR". 65 * This is exactly equivalent to let "EXPR".
65 * $[EXPR]: synonym for $((EXPR)) 66 * $[EXPR]: synonym for $((EXPR))
66 * export builtin should be special, its arguments are assignments 67 *
68 * Won't do:
69 * In bash, export builtin is special, its arguments are assignments
67 * and therefore expansion of them should be "one-word" expansion: 70 * and therefore expansion of them should be "one-word" expansion:
68 * $ export i=`echo 'a b'` # export has one arg: "i=a b" 71 * $ export i=`echo 'a b'` # export has one arg: "i=a b"
69 * compare with: 72 * compare with:
@@ -77,8 +80,6 @@
77 * aaa bbb 80 * aaa bbb
78 * $ "export" i=`echo 'aaa bbb'`; echo "$i" 81 * $ "export" i=`echo 'aaa bbb'`; echo "$i"
79 * aaa 82 * aaa
80 *
81 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
82 */ 83 */
83#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
84#include <malloc.h> /* for malloc_trim */ 85#include <malloc.h> /* for malloc_trim */
@@ -119,8 +120,8 @@
119//config: 120//config:
120//config: It will compile and work on no-mmu systems. 121//config: It will compile and work on no-mmu systems.
121//config: 122//config:
122//config: It does not handle select, aliases, brace expansion, 123//config: It does not handle select, aliases, tilde expansion,
123//config: tilde expansion, &>file and >&file redirection of stdout+stderr. 124//config: &>file and >&file redirection of stdout+stderr.
124//config: 125//config:
125//config:config HUSH_BASH_COMPAT 126//config:config HUSH_BASH_COMPAT
126//config: bool "bash-compatible extensions" 127//config: bool "bash-compatible extensions"
@@ -129,6 +130,13 @@
129//config: help 130//config: help
130//config: Enable bash-compatible extensions. 131//config: Enable bash-compatible extensions.
131//config: 132//config:
133//config:config HUSH_BRACE_EXPANSION
134//config: bool "Brace expansion"
135//config: default y
136//config: depends on HUSH_BASH_COMPAT
137//config: help
138//config: Enable {abc,def} extension.
139//config:
132//config:config HUSH_HELP 140//config:config HUSH_HELP
133//config: bool "help builtin" 141//config: bool "help builtin"
134//config: default y 142//config: default y
@@ -391,18 +399,10 @@ enum {
391 RES_SNTX 399 RES_SNTX
392}; 400};
393 401
394enum {
395 EXP_FLAG_GLOB = 0x200,
396 EXP_FLAG_ESC_GLOB_CHARS = 0x100,
397 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
398};
399
400typedef struct o_string { 402typedef struct o_string {
401 char *data; 403 char *data;
402 int length; /* position where data is appended */ 404 int length; /* position where data is appended */
403 int maxlen; 405 int maxlen;
404 /* Protect newly added chars against globbing
405 * (by prepending \ to *, ?, [, \) */
406 int o_expflags; 406 int o_expflags;
407 /* At least some part of the string was inside '' or "", 407 /* At least some part of the string was inside '' or "",
408 * possibly empty one: word"", wo''rd etc. */ 408 * possibly empty one: word"", wo''rd etc. */
@@ -411,10 +411,18 @@ typedef struct o_string {
411 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ 411 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
412} o_string; 412} o_string;
413enum { 413enum {
414 MAYBE_ASSIGNMENT = 0, 414 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
415 EXP_FLAG_GLOB = 0x2,
416 /* Protect newly added chars against globbing
417 * by prepending \ to *, ?, [, \ */
418 EXP_FLAG_ESC_GLOB_CHARS = 0x1,
419};
420enum {
421 MAYBE_ASSIGNMENT = 0,
415 DEFINITELY_ASSIGNMENT = 1, 422 DEFINITELY_ASSIGNMENT = 1,
416 NOT_ASSIGNMENT = 2, 423 NOT_ASSIGNMENT = 2,
417 WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */ 424 /* Not an assigment, but next word may be: "if v=xyz cmd;" */
425 WORD_IS_KEYWORD = 3,
418}; 426};
419/* Used for initialization: o_string foo = NULL_O_STRING; */ 427/* Used for initialization: o_string foo = NULL_O_STRING; */
420#define NULL_O_STRING { NULL } 428#define NULL_O_STRING { NULL }
@@ -707,8 +715,7 @@ struct globals {
707#endif 715#endif
708 const char *ifs; 716 const char *ifs;
709 const char *cwd; 717 const char *cwd;
710 struct variable *top_var; /* = &G.shell_ver (set in main()) */ 718 struct variable *top_var;
711 struct variable shell_ver;
712 char **expanded_assignments; 719 char **expanded_assignments;
713#if ENABLE_HUSH_FUNCTIONS 720#if ENABLE_HUSH_FUNCTIONS
714 struct function *top_func; 721 struct function *top_func;
@@ -2001,26 +2008,8 @@ static void o_addstr_with_NUL(o_string *o, const char *str)
2001 o_addblock(o, str, strlen(str) + 1); 2008 o_addblock(o, str, strlen(str) + 1);
2002} 2009}
2003 2010
2004static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
2005{
2006 while (len) {
2007 len--;
2008 o_addchr(o, *str);
2009 if (*str++ == '\\') {
2010 /* \z -> \\\z; \<eol> -> \\<eol> */
2011 o_addchr(o, '\\');
2012 if (len) {
2013 len--;
2014 o_addchr(o, '\\');
2015 o_addchr(o, *str++);
2016 }
2017 }
2018 }
2019}
2020
2021#undef HUSH_BRACE_EXP
2022/* 2011/*
2023 * HUSH_BRACE_EXP code needs corresponding quoting on variable expansion side. 2012 * HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
2024 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v. 2013 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v.
2025 * Apparently, on unquoted $v bash still does globbing 2014 * Apparently, on unquoted $v bash still does globbing
2026 * ("v='*.txt'; echo $v" prints all .txt files), 2015 * ("v='*.txt'; echo $v" prints all .txt files),
@@ -2030,7 +2019,7 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
2030 * We have only second one. 2019 * We have only second one.
2031 */ 2020 */
2032 2021
2033#ifdef HUSH_BRACE_EXP 2022#if ENABLE_HUSH_BRACE_EXPANSION
2034# define MAYBE_BRACES "{}" 2023# define MAYBE_BRACES "{}"
2035#else 2024#else
2036# define MAYBE_BRACES "" 2025# define MAYBE_BRACES ""
@@ -2198,7 +2187,7 @@ static int o_get_last_ptr(o_string *o, int n)
2198 return ((int)(uintptr_t)list[n-1]) + string_start; 2187 return ((int)(uintptr_t)list[n-1]) + string_start;
2199} 2188}
2200 2189
2201#ifdef HUSH_BRACE_EXP 2190#if ENABLE_HUSH_BRACE_EXPANSION
2202/* There in a GNU extension, GLOB_BRACE, but it is not usable: 2191/* There in a GNU extension, GLOB_BRACE, but it is not usable:
2203 * first, it processes even {a} (no commas), second, 2192 * first, it processes even {a} (no commas), second,
2204 * I didn't manage to make it return strings when they don't match 2193 * I didn't manage to make it return strings when they don't match
@@ -2394,7 +2383,7 @@ static int perform_glob(o_string *o, int n)
2394 return n; 2383 return n;
2395} 2384}
2396 2385
2397#else /* !HUSH_BRACE_EXP */ 2386#else /* !HUSH_BRACE_EXPANSION */
2398 2387
2399/* Helper */ 2388/* Helper */
2400static int glob_needed(const char *s) 2389static int glob_needed(const char *s)
@@ -2471,7 +2460,7 @@ static int perform_glob(o_string *o, int n)
2471 return n; 2460 return n;
2472} 2461}
2473 2462
2474#endif /* !HUSH_BRACE_EXP */ 2463#endif /* !HUSH_BRACE_EXPANSION */
2475 2464
2476/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered. 2465/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered.
2477 * Otherwise, just finish current list[] and start new */ 2466 * Otherwise, just finish current list[] and start new */
@@ -4388,6 +4377,37 @@ static int process_command_subs(o_string *dest, const char *s);
4388 * followed by strings themselves. 4377 * followed by strings themselves.
4389 * Caller can deallocate entire list by single free(list). */ 4378 * Caller can deallocate entire list by single free(list). */
4390 4379
4380/* A horde of its helpers come first: */
4381
4382static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
4383{
4384 while (--len >= 0) {
4385 char c = *str++;
4386
4387#if ENABLE_HUSH_BRACE_EXPANSION
4388 if (c == '{' || c == '}') {
4389 /* { -> \{, } -> \} */
4390 o_addchr(o, '\\');
4391 /* And now we want to add { or } and continue:
4392 * o_addchr(o, c);
4393 * continue;
4394 * luckily, just falling throught achieves this.
4395 */
4396 }
4397#endif
4398 o_addchr(o, c);
4399 if (c == '\\') {
4400 /* \z -> \\\z; \<eol> -> \\<eol> */
4401 o_addchr(o, '\\');
4402 if (len) {
4403 len--;
4404 o_addchr(o, '\\');
4405 o_addchr(o, *str++);
4406 }
4407 }
4408 }
4409}
4410
4391/* Store given string, finalizing the word and starting new one whenever 4411/* Store given string, finalizing the word and starting new one whenever
4392 * we encounter IFS char(s). This is used for expanding variable values. 4412 * we encounter IFS char(s). This is used for expanding variable values.
4393 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4413 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
@@ -4396,9 +4416,9 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
4396 while (1) { 4416 while (1) {
4397 int word_len = strcspn(str, G.ifs); 4417 int word_len = strcspn(str, G.ifs);
4398 if (word_len) { 4418 if (word_len) {
4399 if (!(output->o_expflags & EXP_FLAG_GLOB)) 4419 if (!(output->o_expflags & EXP_FLAG_GLOB)) {
4400 o_addblock(output, str, word_len); 4420 o_addblock(output, str, word_len);
4401 else { 4421 } else {
4402 /* Protect backslashes against globbing up :) 4422 /* Protect backslashes against globbing up :)
4403 * Example: "v='\*'; echo b$v" prints "b\*" 4423 * Example: "v='\*'; echo b$v" prints "b\*"
4404 * (and does not try to glob on "*") 4424 * (and does not try to glob on "*")
@@ -4461,18 +4481,22 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
4461} 4481}
4462 4482
4463#if ENABLE_SH_MATH_SUPPORT 4483#if ENABLE_SH_MATH_SUPPORT
4464static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) 4484static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
4465{ 4485{
4466 arith_eval_hooks_t hooks; 4486 arith_state_t math_state;
4467 arith_t res; 4487 arith_t res;
4468 char *exp_str; 4488 char *exp_str;
4469 4489
4470 hooks.lookupvar = get_local_var_value; 4490 math_state.lookupvar = get_local_var_value;
4471 hooks.setvar = set_local_var_from_halves; 4491 math_state.setvar = set_local_var_from_halves;
4472 //hooks.endofname = endofname; 4492 //math_state.endofname = endofname;
4473 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 4493 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
4474 res = arith(exp_str ? exp_str : arg, errcode_p, &hooks); 4494 res = arith(&math_state, exp_str ? exp_str : arg);
4475 free(exp_str); 4495 free(exp_str);
4496 if (errmsg_p)
4497 *errmsg_p = math_state.errmsg;
4498 if (math_state.errmsg)
4499 die_if_script(math_state.errmsg);
4476 return res; 4500 return res;
4477} 4501}
4478#endif 4502#endif
@@ -4713,24 +4737,28 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4713 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> 4737 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
4714 */ 4738 */
4715 arith_t beg, len; 4739 arith_t beg, len;
4716 int errcode = 0; 4740 const char *errmsg;
4717 4741
4718 beg = expand_and_evaluate_arith(exp_word, &errcode); 4742 beg = expand_and_evaluate_arith(exp_word, &errmsg);
4743 if (errmsg)
4744 goto arith_err;
4719 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); 4745 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
4720 *p++ = SPECIAL_VAR_SYMBOL; 4746 *p++ = SPECIAL_VAR_SYMBOL;
4721 exp_word = p; 4747 exp_word = p;
4722 p = strchr(p, SPECIAL_VAR_SYMBOL); 4748 p = strchr(p, SPECIAL_VAR_SYMBOL);
4723 *p = '\0'; 4749 *p = '\0';
4724 len = expand_and_evaluate_arith(exp_word, &errcode); 4750 len = expand_and_evaluate_arith(exp_word, &errmsg);
4751 if (errmsg)
4752 goto arith_err;
4725 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); 4753 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
4726 4754 if (len >= 0) { /* bash compat: len < 0 is illegal */
4727 if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
4728 if (beg < 0) /* bash compat */ 4755 if (beg < 0) /* bash compat */
4729 beg = 0; 4756 beg = 0;
4730 debug_printf_varexp("from val:'%s'\n", val); 4757 debug_printf_varexp("from val:'%s'\n", val);
4731 if (len == 0 || !val || beg >= strlen(val)) 4758 if (len == 0 || !val || beg >= strlen(val)) {
4732 val = ""; 4759 arith_err:
4733 else { 4760 val = NULL;
4761 } else {
4734 /* Paranoia. What if user entered 9999999999999 4762 /* Paranoia. What if user entered 9999999999999
4735 * which fits in arith_t but not int? */ 4763 * which fits in arith_t but not int? */
4736 if (len >= INT_MAX) 4764 if (len >= INT_MAX)
@@ -4742,7 +4770,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4742#endif 4770#endif
4743 { 4771 {
4744 die_if_script("malformed ${%s:...}", var); 4772 die_if_script("malformed ${%s:...}", var);
4745 val = ""; 4773 val = NULL;
4746 } 4774 }
4747 } else { /* one of "-=+?" */ 4775 } else { /* one of "-=+?" */
4748 /* Standard-mandated substitution ops: 4776 /* Standard-mandated substitution ops:
@@ -4925,30 +4953,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
4925#if ENABLE_SH_MATH_SUPPORT 4953#if ENABLE_SH_MATH_SUPPORT
4926 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 4954 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
4927 arith_t res; 4955 arith_t res;
4928 int errcode;
4929 4956
4930 arg++; /* skip '+' */ 4957 arg++; /* skip '+' */
4931 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 4958 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
4932 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); 4959 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
4933 res = expand_and_evaluate_arith(arg, &errcode); 4960 res = expand_and_evaluate_arith(arg, NULL);
4934 4961 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
4935 if (errcode < 0) { 4962 sprintf(arith_buf, ARITH_FMT, res);
4936 const char *msg = "error in arithmetic";
4937 switch (errcode) {
4938 case -3:
4939 msg = "exponent less than 0";
4940 break;
4941 case -2:
4942 msg = "divide by 0";
4943 break;
4944 case -5:
4945 msg = "expression recursion loop detected";
4946 break;
4947 }
4948 die_if_script(msg);
4949 }
4950 debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
4951 sprintf(arith_buf, arith_t_fmt, res);
4952 val = arith_buf; 4963 val = arith_buf;
4953 break; 4964 break;
4954 } 4965 }
@@ -7346,6 +7357,7 @@ int hush_main(int argc, char **argv)
7346 unsigned builtin_argc; 7357 unsigned builtin_argc;
7347 char **e; 7358 char **e;
7348 struct variable *cur_var; 7359 struct variable *cur_var;
7360 struct variable shell_ver;
7349 7361
7350 INIT_G(); 7362 INIT_G();
7351 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ 7363 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */
@@ -7354,12 +7366,13 @@ int hush_main(int argc, char **argv)
7354 G.argv0_for_re_execing = argv[0]; 7366 G.argv0_for_re_execing = argv[0];
7355#endif 7367#endif
7356 /* Deal with HUSH_VERSION */ 7368 /* Deal with HUSH_VERSION */
7357 G.shell_ver.flg_export = 1; 7369 memset(&shell_ver, 0, sizeof(shell_ver));
7358 G.shell_ver.flg_read_only = 1; 7370 shell_ver.flg_export = 1;
7371 shell_ver.flg_read_only = 1;
7359 /* Code which handles ${var<op>...} needs writable values for all variables, 7372 /* Code which handles ${var<op>...} needs writable values for all variables,
7360 * therefore we xstrdup: */ 7373 * therefore we xstrdup: */
7361 G.shell_ver.varstr = xstrdup(hush_version_str), 7374 shell_ver.varstr = xstrdup(hush_version_str),
7362 G.top_var = &G.shell_ver; 7375 G.top_var = &shell_ver;
7363 /* Create shell local variables from the values 7376 /* Create shell local variables from the values
7364 * currently living in the environment */ 7377 * currently living in the environment */
7365 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 7378 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
@@ -7378,8 +7391,8 @@ int hush_main(int argc, char **argv)
7378 e++; 7391 e++;
7379 } 7392 }
7380 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ 7393 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */
7381 debug_printf_env("putenv '%s'\n", G.shell_ver.varstr); 7394 debug_printf_env("putenv '%s'\n", shell_ver.varstr);
7382 putenv(G.shell_ver.varstr); 7395 putenv(shell_ver.varstr);
7383 7396
7384 /* Export PWD */ 7397 /* Export PWD */
7385 set_pwd_var(/*exp:*/ 1); 7398 set_pwd_var(/*exp:*/ 1);