aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--shell/hush.c130
1 files changed, 62 insertions, 68 deletions
diff --git a/shell/hush.c b/shell/hush.c
index bcd4dffee..a56d3b280 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -82,35 +82,6 @@
82 * $ "export" i=`echo 'aaa bbb'`; echo "$i" 82 * $ "export" i=`echo 'aaa bbb'`; echo "$i"
83 * aaa 83 * aaa
84 */ 84 */
85#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
86 || defined(__APPLE__) \
87 )
88# include <malloc.h> /* for malloc_trim */
89#endif
90#include <glob.h>
91/* #include <dmalloc.h> */
92#if ENABLE_HUSH_CASE
93# include <fnmatch.h>
94#endif
95#include <sys/utsname.h> /* for setting $HOSTNAME */
96
97#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
98#include "unicode.h"
99#include "shell_common.h"
100#include "math.h"
101#include "match.h"
102#if ENABLE_HUSH_RANDOM_SUPPORT
103# include "random.h"
104#else
105# define CLEAR_RANDOM_T(rnd) ((void)0)
106#endif
107#ifndef F_DUPFD_CLOEXEC
108# define F_DUPFD_CLOEXEC F_DUPFD
109#endif
110#ifndef PIPE_BUF
111# define PIPE_BUF 4096 /* amount of buffering in a pipe */
112#endif
113
114//config:config HUSH 85//config:config HUSH
115//config: bool "hush" 86//config: bool "hush"
116//config: default y 87//config: default y
@@ -128,7 +99,7 @@
128//config:config HUSH_BASH_COMPAT 99//config:config HUSH_BASH_COMPAT
129//config: bool "bash-compatible extensions" 100//config: bool "bash-compatible extensions"
130//config: default y 101//config: default y
131//config: depends on HUSH 102//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
132//config: help 103//config: help
133//config: Enable bash-compatible extensions. 104//config: Enable bash-compatible extensions.
134//config: 105//config:
@@ -142,14 +113,14 @@
142//config:config HUSH_HELP 113//config:config HUSH_HELP
143//config: bool "help builtin" 114//config: bool "help builtin"
144//config: default y 115//config: default y
145//config: depends on HUSH 116//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
146//config: help 117//config: help
147//config: Enable help builtin in hush. Code size + ~1 kbyte. 118//config: Enable help builtin in hush. Code size + ~1 kbyte.
148//config: 119//config:
149//config:config HUSH_INTERACTIVE 120//config:config HUSH_INTERACTIVE
150//config: bool "Interactive mode" 121//config: bool "Interactive mode"
151//config: default y 122//config: default y
152//config: depends on HUSH 123//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
153//config: help 124//config: help
154//config: Enable interactive mode (prompt and command editing). 125//config: Enable interactive mode (prompt and command editing).
155//config: Without this, hush simply reads and executes commands 126//config: Without this, hush simply reads and executes commands
@@ -177,35 +148,35 @@
177//config:config HUSH_TICK 148//config:config HUSH_TICK
178//config: bool "Process substitution" 149//config: bool "Process substitution"
179//config: default y 150//config: default y
180//config: depends on HUSH 151//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
181//config: help 152//config: help
182//config: Enable process substitution `command` and $(command) in hush. 153//config: Enable process substitution `command` and $(command) in hush.
183//config: 154//config:
184//config:config HUSH_IF 155//config:config HUSH_IF
185//config: bool "Support if/then/elif/else/fi" 156//config: bool "Support if/then/elif/else/fi"
186//config: default y 157//config: default y
187//config: depends on HUSH 158//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
188//config: help 159//config: help
189//config: Enable if/then/elif/else/fi in hush. 160//config: Enable if/then/elif/else/fi in hush.
190//config: 161//config:
191//config:config HUSH_LOOPS 162//config:config HUSH_LOOPS
192//config: bool "Support for, while and until loops" 163//config: bool "Support for, while and until loops"
193//config: default y 164//config: default y
194//config: depends on HUSH 165//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
195//config: help 166//config: help
196//config: Enable for, while and until loops in hush. 167//config: Enable for, while and until loops in hush.
197//config: 168//config:
198//config:config HUSH_CASE 169//config:config HUSH_CASE
199//config: bool "Support case ... esac statement" 170//config: bool "Support case ... esac statement"
200//config: default y 171//config: default y
201//config: depends on HUSH 172//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
202//config: help 173//config: help
203//config: Enable case ... esac statement in hush. +400 bytes. 174//config: Enable case ... esac statement in hush. +400 bytes.
204//config: 175//config:
205//config:config HUSH_FUNCTIONS 176//config:config HUSH_FUNCTIONS
206//config: bool "Support funcname() { commands; } syntax" 177//config: bool "Support funcname() { commands; } syntax"
207//config: default y 178//config: default y
208//config: depends on HUSH 179//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
209//config: help 180//config: help
210//config: Enable support for shell functions in hush. +800 bytes. 181//config: Enable support for shell functions in hush. +800 bytes.
211//config: 182//config:
@@ -219,7 +190,7 @@
219//config:config HUSH_RANDOM_SUPPORT 190//config:config HUSH_RANDOM_SUPPORT
220//config: bool "Pseudorandom generator and $RANDOM variable" 191//config: bool "Pseudorandom generator and $RANDOM variable"
221//config: default y 192//config: default y
222//config: depends on HUSH 193//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
223//config: help 194//config: help
224//config: Enable pseudorandom generator and dynamic variable "$RANDOM". 195//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
225//config: Each read of "$RANDOM" will generate a new pseudorandom value. 196//config: Each read of "$RANDOM" will generate a new pseudorandom value.
@@ -227,14 +198,14 @@
227//config:config HUSH_EXPORT_N 198//config:config HUSH_EXPORT_N
228//config: bool "Support 'export -n' option" 199//config: bool "Support 'export -n' option"
229//config: default y 200//config: default y
230//config: depends on HUSH 201//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
231//config: help 202//config: help
232//config: export -n unexports variables. It is a bash extension. 203//config: export -n unexports variables. It is a bash extension.
233//config: 204//config:
234//config:config HUSH_MODE_X 205//config:config HUSH_MODE_X
235//config: bool "Support 'hush -x' option and 'set -x' command" 206//config: bool "Support 'hush -x' option and 'set -x' command"
236//config: default y 207//config: default y
237//config: depends on HUSH 208//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
238//config: help 209//config: help
239//config: This instructs hush to print commands before execution. 210//config: This instructs hush to print commands before execution.
240//config: Adds ~300 bytes. 211//config: Adds ~300 bytes.
@@ -245,14 +216,15 @@
245//config: select HUSH 216//config: select HUSH
246//config: help 217//config: help
247//config: msh is deprecated and will be removed, please migrate to hush. 218//config: msh is deprecated and will be removed, please migrate to hush.
248//config:
249 219
250//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) 220//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP))
251//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) 221//applet:IF_MSH(APPLET_ODDNAME(msh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
252//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) 222//applet:IF_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
253//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) 223//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
254 224
255//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 225//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o
226//kbuild:lib-$(CONFIG_SH_IS_HUSH) += hush.o match.o shell_common.o
227//kbuild:lib-$(CONFIG_BASH_IS_HUSH) += hush.o match.o shell_common.o
256//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 228//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o
257 229
258/* -i (interactive) and -s (read stdin) are also accepted, 230/* -i (interactive) and -s (read stdin) are also accepted,
@@ -265,17 +237,34 @@
265//usage:#define hush_full_usage "\n\n" 237//usage:#define hush_full_usage "\n\n"
266//usage: "Unix shell interpreter" 238//usage: "Unix shell interpreter"
267 239
268//usage:#define msh_trivial_usage hush_trivial_usage 240#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
269//usage:#define msh_full_usage hush_full_usage 241 || defined(__APPLE__) \
242 )
243# include <malloc.h> /* for malloc_trim */
244#endif
245#include <glob.h>
246/* #include <dmalloc.h> */
247#if ENABLE_HUSH_CASE
248# include <fnmatch.h>
249#endif
250#include <sys/utsname.h> /* for setting $HOSTNAME */
270 251
271//usage:#if ENABLE_FEATURE_SH_IS_HUSH 252#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
272//usage:# define sh_trivial_usage hush_trivial_usage 253#include "unicode.h"
273//usage:# define sh_full_usage hush_full_usage 254#include "shell_common.h"
274//usage:#endif 255#include "math.h"
275//usage:#if ENABLE_FEATURE_BASH_IS_HUSH 256#include "match.h"
276//usage:# define bash_trivial_usage hush_trivial_usage 257#if ENABLE_HUSH_RANDOM_SUPPORT
277//usage:# define bash_full_usage hush_full_usage 258# include "random.h"
278//usage:#endif 259#else
260# define CLEAR_RANDOM_T(rnd) ((void)0)
261#endif
262#ifndef F_DUPFD_CLOEXEC
263# define F_DUPFD_CLOEXEC F_DUPFD
264#endif
265#ifndef PIPE_BUF
266# define PIPE_BUF 4096 /* amount of buffering in a pipe */
267#endif
279 268
280 269
281/* Build knobs */ 270/* Build knobs */
@@ -1148,6 +1137,9 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
1148 char msg[2]; 1137 char msg[2];
1149 msg[0] = ch; 1138 msg[0] = ch;
1150 msg[1] = '\0'; 1139 msg[1] = '\0';
1140#if HUSH_DEBUG >= 2
1141 bb_error_msg("hush.c:%u", lineno);
1142#endif
1151 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); 1143 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
1152} 1144}
1153 1145
@@ -1574,9 +1566,8 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler)
1574} 1566}
1575 1567
1576static void hush_exit(int exitcode) NORETURN; 1568static void hush_exit(int exitcode) NORETURN;
1577static void fflush_and__exit(void) NORETURN;
1578static void restore_ttypgrp_and__exit(void) NORETURN;
1579 1569
1570static void restore_ttypgrp_and__exit(void) NORETURN;
1580static void restore_ttypgrp_and__exit(void) 1571static void restore_ttypgrp_and__exit(void)
1581{ 1572{
1582 /* xfunc has failed! die die die */ 1573 /* xfunc has failed! die die die */
@@ -1585,6 +1576,8 @@ static void restore_ttypgrp_and__exit(void)
1585 hush_exit(xfunc_error_retval); 1576 hush_exit(xfunc_error_retval);
1586} 1577}
1587 1578
1579#if ENABLE_HUSH_JOB
1580
1588/* Needed only on some libc: 1581/* Needed only on some libc:
1589 * It was observed that on exit(), fgetc'ed buffered data 1582 * It was observed that on exit(), fgetc'ed buffered data
1590 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). 1583 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR).
@@ -1598,14 +1591,13 @@ static void restore_ttypgrp_and__exit(void)
1598 * and in `cmd` handling. 1591 * and in `cmd` handling.
1599 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): 1592 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
1600 */ 1593 */
1594static void fflush_and__exit(void) NORETURN;
1601static void fflush_and__exit(void) 1595static void fflush_and__exit(void)
1602{ 1596{
1603 fflush_all(); 1597 fflush_all();
1604 _exit(xfunc_error_retval); 1598 _exit(xfunc_error_retval);
1605} 1599}
1606 1600
1607#if ENABLE_HUSH_JOB
1608
1609/* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 1601/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
1610# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) 1602# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
1611/* After [v]fork, in parent: restore tty pgrp on xfunc death */ 1603/* After [v]fork, in parent: restore tty pgrp on xfunc death */
@@ -4011,7 +4003,7 @@ static int i_peek_and_eat_bkslash_nl(struct in_str *input)
4011 } 4003 }
4012} 4004}
4013 4005
4014#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS 4006#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4015/* Subroutines for copying $(...) and `...` things */ 4007/* Subroutines for copying $(...) and `...` things */
4016static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); 4008static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
4017/* '...' */ 4009/* '...' */
@@ -4179,7 +4171,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4179 } 4171 }
4180 return ch; 4172 return ch;
4181} 4173}
4182#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ 4174#endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */
4183 4175
4184/* Return code: 0 for OK, 1 for syntax error */ 4176/* Return code: 0 for OK, 1 for syntax error */
4185#if BB_MMU 4177#if BB_MMU
@@ -4333,13 +4325,13 @@ static int parse_dollar(o_string *as_string,
4333 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4325 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4334 break; 4326 break;
4335 } 4327 }
4336#if ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_TICK 4328#if ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_TICK
4337 case '(': { 4329 case '(': {
4338 unsigned pos; 4330 unsigned pos;
4339 4331
4340 ch = i_getch(input); 4332 ch = i_getch(input);
4341 nommu_addchr(as_string, ch); 4333 nommu_addchr(as_string, ch);
4342# if ENABLE_SH_MATH_SUPPORT 4334# if ENABLE_FEATURE_SH_MATH
4343 if (i_peek_and_eat_bkslash_nl(input) == '(') { 4335 if (i_peek_and_eat_bkslash_nl(input) == '(') {
4344 ch = i_getch(input); 4336 ch = i_getch(input);
4345 nommu_addchr(as_string, ch); 4337 nommu_addchr(as_string, ch);
@@ -5008,7 +5000,8 @@ static struct pipe *parse_stream(char **pstring,
5008 * if we see {, we call parse_group(..., end_trigger='}') 5000 * if we see {, we call parse_group(..., end_trigger='}')
5009 * and it will match } earlier (not here). */ 5001 * and it will match } earlier (not here). */
5010 syntax_error_unexpected_ch(ch); 5002 syntax_error_unexpected_ch(ch);
5011 goto parse_error; 5003 G.last_exitcode = 2;
5004 goto parse_error1;
5012 default: 5005 default:
5013 if (HUSH_DEBUG) 5006 if (HUSH_DEBUG)
5014 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 5007 bb_error_msg_and_die("BUG: unexpected %c\n", ch);
@@ -5016,6 +5009,8 @@ static struct pipe *parse_stream(char **pstring,
5016 } /* while (1) */ 5009 } /* while (1) */
5017 5010
5018 parse_error: 5011 parse_error:
5012 G.last_exitcode = 1;
5013 parse_error1:
5019 { 5014 {
5020 struct parse_context *pctx; 5015 struct parse_context *pctx;
5021 IF_HAS_KEYWORDS(struct parse_context *p2;) 5016 IF_HAS_KEYWORDS(struct parse_context *p2;)
@@ -5049,7 +5044,6 @@ static struct pipe *parse_stream(char **pstring,
5049 } while (HAS_KEYWORDS && pctx); 5044 } while (HAS_KEYWORDS && pctx);
5050 5045
5051 o_free(&dest); 5046 o_free(&dest);
5052 G.last_exitcode = 1;
5053#if !BB_MMU 5047#if !BB_MMU
5054 if (pstring) 5048 if (pstring)
5055 *pstring = NULL; 5049 *pstring = NULL;
@@ -5217,7 +5211,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
5217 return exp_str; 5211 return exp_str;
5218} 5212}
5219 5213
5220#if ENABLE_SH_MATH_SUPPORT 5214#if ENABLE_FEATURE_SH_MATH
5221static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) 5215static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
5222{ 5216{
5223 arith_state_t math_state; 5217 arith_state_t math_state;
@@ -5469,7 +5463,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5469 } 5463 }
5470#endif 5464#endif
5471 else if (exp_op == ':') { 5465 else if (exp_op == ':') {
5472#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT 5466#if ENABLE_HUSH_BASH_COMPAT && ENABLE_FEATURE_SH_MATH
5473 /* It's ${var:N[:M]} bashism. 5467 /* It's ${var:N[:M]} bashism.
5474 * Note that in encoded form it has TWO parts: 5468 * Note that in encoded form it has TWO parts:
5475 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> 5469 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
@@ -5604,7 +5598,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5604#if ENABLE_HUSH_TICK 5598#if ENABLE_HUSH_TICK
5605 o_string subst_result = NULL_O_STRING; 5599 o_string subst_result = NULL_O_STRING;
5606#endif 5600#endif
5607#if ENABLE_SH_MATH_SUPPORT 5601#if ENABLE_FEATURE_SH_MATH
5608 char arith_buf[sizeof(arith_t)*3 + 2]; 5602 char arith_buf[sizeof(arith_t)*3 + 2];
5609#endif 5603#endif
5610 5604
@@ -5698,7 +5692,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
5698 val = subst_result.data; 5692 val = subst_result.data;
5699 goto store_val; 5693 goto store_val;
5700#endif 5694#endif
5701#if ENABLE_SH_MATH_SUPPORT 5695#if ENABLE_FEATURE_SH_MATH
5702 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 5696 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
5703 arith_t res; 5697 arith_t res;
5704 5698