aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c270
1 files changed, 239 insertions, 31 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 9f946d82f..cdc3a8618 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -48,7 +48,7 @@
48 * tilde expansion 48 * tilde expansion
49 * aliases 49 * aliases
50 * builtins mandated by standards we don't support: 50 * builtins mandated by standards we don't support:
51 * [un]alias, command, fc, getopts, times: 51 * [un]alias, command, fc:
52 * command -v CMD: print "/path/to/CMD" 52 * command -v CMD: print "/path/to/CMD"
53 * prints "CMD" for builtins 53 * prints "CMD" for builtins
54 * prints "alias ALIAS='EXPANSION'" for aliases 54 * prints "alias ALIAS='EXPANSION'" for aliases
@@ -58,8 +58,6 @@
58 * (can use this to override standalone shell as well) 58 * (can use this to override standalone shell as well)
59 * -p: use default $PATH 59 * -p: use default $PATH
60 * command BLTIN: disables special-ness (e.g. errors do not abort) 60 * command BLTIN: disables special-ness (e.g. errors do not abort)
61 * getopts: getopt() for shells
62 * times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime
63 * fc -l[nr] [BEG] [END]: list range of commands in history 61 * fc -l[nr] [BEG] [END]: list range of commands in history
64 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands 62 * fc [-e EDITOR] [BEG] [END]: edit/rerun range of commands
65 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP 63 * fc -s [PAT=REP] [CMD]: rerun CMD, replacing PAT with REP
@@ -265,6 +263,11 @@
265//config: default y 263//config: default y
266//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 264//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
267//config: 265//config:
266//config:config HUSH_TIMES
267//config: bool "times builtin"
268//config: default y
269//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
270//config:
268//config:config HUSH_READ 271//config:config HUSH_READ
269//config: bool "read builtin" 272//config: bool "read builtin"
270//config: default y 273//config: default y
@@ -290,6 +293,11 @@
290//config: default y 293//config: default y
291//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 294//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
292//config: 295//config:
296//config:config HUSH_GETOPTS
297//config: bool "getopts builtin"
298//config: default y
299//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH
300//config:
293//config:config HUSH_MEMLEAK 301//config:config HUSH_MEMLEAK
294//config: bool "memleak builtin (debugging)" 302//config: bool "memleak builtin (debugging)"
295//config: default n 303//config: default n
@@ -325,6 +333,7 @@
325#if ENABLE_HUSH_CASE 333#if ENABLE_HUSH_CASE
326# include <fnmatch.h> 334# include <fnmatch.h>
327#endif 335#endif
336#include <sys/times.h>
328#include <sys/utsname.h> /* for setting $HOSTNAME */ 337#include <sys/utsname.h> /* for setting $HOSTNAME */
329 338
330#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 339#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
@@ -352,6 +361,7 @@
352#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT 361#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
353#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT 362#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
354#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) 363#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
364#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
355 365
356 366
357/* Build knobs */ 367/* Build knobs */
@@ -977,6 +987,9 @@ static int builtin_readonly(char **argv) FAST_FUNC;
977static int builtin_fg_bg(char **argv) FAST_FUNC; 987static int builtin_fg_bg(char **argv) FAST_FUNC;
978static int builtin_jobs(char **argv) FAST_FUNC; 988static int builtin_jobs(char **argv) FAST_FUNC;
979#endif 989#endif
990#if ENABLE_HUSH_GETOPTS
991static int builtin_getopts(char **argv) FAST_FUNC;
992#endif
980#if ENABLE_HUSH_HELP 993#if ENABLE_HUSH_HELP
981static int builtin_help(char **argv) FAST_FUNC; 994static int builtin_help(char **argv) FAST_FUNC;
982#endif 995#endif
@@ -1010,6 +1023,9 @@ static int builtin_trap(char **argv) FAST_FUNC;
1010#if ENABLE_HUSH_TYPE 1023#if ENABLE_HUSH_TYPE
1011static int builtin_type(char **argv) FAST_FUNC; 1024static int builtin_type(char **argv) FAST_FUNC;
1012#endif 1025#endif
1026#if ENABLE_HUSH_TIMES
1027static int builtin_times(char **argv) FAST_FUNC;
1028#endif
1013static int builtin_true(char **argv) FAST_FUNC; 1029static int builtin_true(char **argv) FAST_FUNC;
1014#if ENABLE_HUSH_UMASK 1030#if ENABLE_HUSH_UMASK
1015static int builtin_umask(char **argv) FAST_FUNC; 1031static int builtin_umask(char **argv) FAST_FUNC;
@@ -1070,6 +1086,9 @@ static const struct built_in_command bltins1[] = {
1070#if ENABLE_HUSH_JOB 1086#if ENABLE_HUSH_JOB
1071 BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"), 1087 BLTIN("fg" , builtin_fg_bg , "Bring job to foreground"),
1072#endif 1088#endif
1089#if ENABLE_HUSH_GETOPTS
1090 BLTIN("getopts" , builtin_getopts , NULL),
1091#endif
1073#if ENABLE_HUSH_HELP 1092#if ENABLE_HUSH_HELP
1074 BLTIN("help" , builtin_help , NULL), 1093 BLTIN("help" , builtin_help , NULL),
1075#endif 1094#endif
@@ -1104,6 +1123,9 @@ static const struct built_in_command bltins1[] = {
1104#if BASH_SOURCE 1123#if BASH_SOURCE
1105 BLTIN("source" , builtin_source , NULL), 1124 BLTIN("source" , builtin_source , NULL),
1106#endif 1125#endif
1126#if ENABLE_HUSH_TIMES
1127 BLTIN("times" , builtin_times , NULL),
1128#endif
1107#if ENABLE_HUSH_TRAP 1129#if ENABLE_HUSH_TRAP
1108 BLTIN("trap" , builtin_trap , "Trap signals"), 1130 BLTIN("trap" , builtin_trap , "Trap signals"),
1109#endif 1131#endif
@@ -1272,7 +1294,7 @@ static void xxfree(void *ptr)
1272 * HUSH_DEBUG >= 2 prints line number in this file where it was detected. 1294 * HUSH_DEBUG >= 2 prints line number in this file where it was detected.
1273 */ 1295 */
1274#if HUSH_DEBUG < 2 1296#if HUSH_DEBUG < 2
1275# define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) 1297# define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__)
1276# define syntax_error(lineno, msg) syntax_error(msg) 1298# define syntax_error(lineno, msg) syntax_error(msg)
1277# define syntax_error_at(lineno, msg) syntax_error_at(msg) 1299# define syntax_error_at(lineno, msg) syntax_error_at(msg)
1278# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) 1300# define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch)
@@ -1280,7 +1302,16 @@ static void xxfree(void *ptr)
1280# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) 1302# define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
1281#endif 1303#endif
1282 1304
1283static void die_if_script(unsigned lineno, const char *fmt, ...) 1305static void die_if_script(void)
1306{
1307 if (!G_interactive_fd) {
1308 if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */
1309 xfunc_error_retval = G.last_exitcode;
1310 xfunc_die();
1311 }
1312}
1313
1314static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
1284{ 1315{
1285 va_list p; 1316 va_list p;
1286 1317
@@ -1290,8 +1321,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...)
1290 va_start(p, fmt); 1321 va_start(p, fmt);
1291 bb_verror_msg(fmt, p, NULL); 1322 bb_verror_msg(fmt, p, NULL);
1292 va_end(p); 1323 va_end(p);
1293 if (!G_interactive_fd) 1324 die_if_script();
1294 xfunc_die();
1295} 1325}
1296 1326
1297static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) 1327static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
@@ -1300,16 +1330,20 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
1300 bb_error_msg("syntax error: %s", msg); 1330 bb_error_msg("syntax error: %s", msg);
1301 else 1331 else
1302 bb_error_msg("syntax error"); 1332 bb_error_msg("syntax error");
1333 die_if_script();
1303} 1334}
1304 1335
1305static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) 1336static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
1306{ 1337{
1307 bb_error_msg("syntax error at '%s'", msg); 1338 bb_error_msg("syntax error at '%s'", msg);
1339 die_if_script();
1308} 1340}
1309 1341
1310static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) 1342static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
1311{ 1343{
1312 bb_error_msg("syntax error: unterminated %s", s); 1344 bb_error_msg("syntax error: unterminated %s", s);
1345//? source4.tests fails: in bash, echo ${^} in script does not terminate the script
1346// die_if_script();
1313} 1347}
1314 1348
1315static void syntax_error_unterm_ch(unsigned lineno, char ch) 1349static void syntax_error_unterm_ch(unsigned lineno, char ch)
@@ -1327,17 +1361,18 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
1327 bb_error_msg("hush.c:%u", lineno); 1361 bb_error_msg("hush.c:%u", lineno);
1328#endif 1362#endif
1329 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); 1363 bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
1364 die_if_script();
1330} 1365}
1331 1366
1332#if HUSH_DEBUG < 2 1367#if HUSH_DEBUG < 2
1333# undef die_if_script 1368# undef msg_and_die_if_script
1334# undef syntax_error 1369# undef syntax_error
1335# undef syntax_error_at 1370# undef syntax_error_at
1336# undef syntax_error_unterm_ch 1371# undef syntax_error_unterm_ch
1337# undef syntax_error_unterm_str 1372# undef syntax_error_unterm_str
1338# undef syntax_error_unexpected_ch 1373# undef syntax_error_unexpected_ch
1339#else 1374#else
1340# define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) 1375# define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__)
1341# define syntax_error(msg) syntax_error(__LINE__, msg) 1376# define syntax_error(msg) syntax_error(__LINE__, msg)
1342# define syntax_error_at(msg) syntax_error_at(__LINE__, msg) 1377# define syntax_error_at(msg) syntax_error_at(__LINE__, msg)
1343# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) 1378# define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch)
@@ -1800,7 +1835,7 @@ static void restore_ttypgrp_and__exit(void)
1800 * echo END_OF_SCRIPT 1835 * echo END_OF_SCRIPT
1801 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". 1836 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT".
1802 * This makes "echo END_OF_SCRIPT" executed twice. 1837 * This makes "echo END_OF_SCRIPT" executed twice.
1803 * Similar problems can be seen with die_if_script() -> xfunc_die() 1838 * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die()
1804 * and in `cmd` handling. 1839 * and in `cmd` handling.
1805 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): 1840 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
1806 */ 1841 */
@@ -1966,6 +2001,9 @@ static int check_and_run_traps(void)
1966 break; 2001 break;
1967#if ENABLE_HUSH_JOB 2002#if ENABLE_HUSH_JOB
1968 case SIGHUP: { 2003 case SIGHUP: {
2004//TODO: why are we doing this? ash and dash don't do this,
2005//they have no handler for SIGHUP at all,
2006//they rely on kernel to send SIGHUP+SIGCONT to orphaned process groups
1969 struct pipe *job; 2007 struct pipe *job;
1970 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig); 2008 debug_printf_exec("%s: sig:%d default SIGHUP handler\n", __func__, sig);
1971 /* bash is observed to signal whole process groups, 2009 /* bash is observed to signal whole process groups,
@@ -2411,18 +2449,17 @@ static int get_user_input(struct in_str *i)
2411 /* buglet: SIGINT will not make new prompt to appear _at once_, 2449 /* buglet: SIGINT will not make new prompt to appear _at once_,
2412 * only after <Enter>. (^C works immediately) */ 2450 * only after <Enter>. (^C works immediately) */
2413 r = read_line_input(G.line_input_state, prompt_str, 2451 r = read_line_input(G.line_input_state, prompt_str,
2414 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, 2452 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
2415 /*timeout*/ -1
2416 ); 2453 );
2417 /* read_line_input intercepts ^C, "convert" it to SIGINT */ 2454 /* read_line_input intercepts ^C, "convert" it to SIGINT */
2418 if (r == 0) { 2455 if (r == 0)
2419 write(STDOUT_FILENO, "^C", 2);
2420 raise(SIGINT); 2456 raise(SIGINT);
2421 }
2422 check_and_run_traps(); 2457 check_and_run_traps();
2423 if (r != 0 && !G.flag_SIGINT) 2458 if (r != 0 && !G.flag_SIGINT)
2424 break; 2459 break;
2425 /* ^C or SIGINT: repeat */ 2460 /* ^C or SIGINT: repeat */
2461 /* bash prints ^C even on real SIGINT (non-kbd generated) */
2462 write(STDOUT_FILENO, "^C", 2);
2426 G.last_exitcode = 128 + SIGINT; 2463 G.last_exitcode = 128 + SIGINT;
2427 } 2464 }
2428 if (r < 0) { 2465 if (r < 0) {
@@ -3384,7 +3421,7 @@ static int done_command(struct parse_context *ctx)
3384#if 0 /* Instead we emit error message at run time */ 3421#if 0 /* Instead we emit error message at run time */
3385 if (ctx->pending_redirect) { 3422 if (ctx->pending_redirect) {
3386 /* For example, "cmd >" (no filename to redirect to) */ 3423 /* For example, "cmd >" (no filename to redirect to) */
3387 die_if_script("syntax error: %s", "invalid redirect"); 3424 syntax_error("invalid redirect");
3388 ctx->pending_redirect = NULL; 3425 ctx->pending_redirect = NULL;
3389 } 3426 }
3390#endif 3427#endif
@@ -3950,7 +3987,7 @@ static int parse_redirect(struct parse_context *ctx,
3950#if 0 /* Instead we emit error message at run time */ 3987#if 0 /* Instead we emit error message at run time */
3951 if (ctx->pending_redirect) { 3988 if (ctx->pending_redirect) {
3952 /* For example, "cmd > <file" */ 3989 /* For example, "cmd > <file" */
3953 die_if_script("syntax error: %s", "invalid redirect"); 3990 syntax_error("invalid redirect");
3954 } 3991 }
3955#endif 3992#endif
3956 /* Set ctx->pending_redirect, so we know what to do at the 3993 /* Set ctx->pending_redirect, so we know what to do at the
@@ -5022,10 +5059,16 @@ static struct pipe *parse_stream(char **pstring,
5022 else 5059 else
5023 o_free_unsafe(&ctx.as_string); 5060 o_free_unsafe(&ctx.as_string);
5024#endif 5061#endif
5025 debug_leave(); 5062 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
5063 /* Example: bare "{ }", "()" */
5064 G.last_exitcode = 2; /* bash compat */
5065 syntax_error_unexpected_ch(ch);
5066 goto parse_error2;
5067 }
5026 debug_printf_parse("parse_stream return %p: " 5068 debug_printf_parse("parse_stream return %p: "
5027 "end_trigger char found\n", 5069 "end_trigger char found\n",
5028 ctx.list_head); 5070 ctx.list_head);
5071 debug_leave();
5029 return ctx.list_head; 5072 return ctx.list_head;
5030 } 5073 }
5031 } 5074 }
@@ -5283,8 +5326,8 @@ static struct pipe *parse_stream(char **pstring,
5283 /* proper use of this character is caught by end_trigger: 5326 /* proper use of this character is caught by end_trigger:
5284 * if we see {, we call parse_group(..., end_trigger='}') 5327 * if we see {, we call parse_group(..., end_trigger='}')
5285 * and it will match } earlier (not here). */ 5328 * and it will match } earlier (not here). */
5286 syntax_error_unexpected_ch(ch);
5287 G.last_exitcode = 2; 5329 G.last_exitcode = 2;
5330 syntax_error_unexpected_ch(ch);
5288 goto parse_error2; 5331 goto parse_error2;
5289 default: 5332 default:
5290 if (HUSH_DEBUG) 5333 if (HUSH_DEBUG)
@@ -5514,7 +5557,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
5514 if (errmsg_p) 5557 if (errmsg_p)
5515 *errmsg_p = math_state.errmsg; 5558 *errmsg_p = math_state.errmsg;
5516 if (math_state.errmsg) 5559 if (math_state.errmsg)
5517 die_if_script(math_state.errmsg); 5560 msg_and_die_if_script(math_state.errmsg);
5518 return res; 5561 return res;
5519} 5562}
5520#endif 5563#endif
@@ -5781,7 +5824,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5781 /* in bash, len=-n means strlen()-n */ 5824 /* in bash, len=-n means strlen()-n */
5782 len = (arith_t)strlen(val) - beg + len; 5825 len = (arith_t)strlen(val) - beg + len;
5783 if (len < 0) /* bash compat */ 5826 if (len < 0) /* bash compat */
5784 die_if_script("%s: substring expression < 0", var); 5827 msg_and_die_if_script("%s: substring expression < 0", var);
5785 } 5828 }
5786 if (len <= 0 || !val || beg >= strlen(val)) { 5829 if (len <= 0 || !val || beg >= strlen(val)) {
5787 arith_err: 5830 arith_err:
@@ -5795,7 +5838,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5795 } 5838 }
5796 debug_printf_varexp("val:'%s'\n", val); 5839 debug_printf_varexp("val:'%s'\n", val);
5797#else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ 5840#else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */
5798 die_if_script("malformed ${%s:...}", var); 5841 msg_and_die_if_script("malformed ${%s:...}", var);
5799 val = NULL; 5842 val = NULL;
5800#endif 5843#endif
5801 } else { /* one of "-=+?" */ 5844 } else { /* one of "-=+?" */
@@ -5832,7 +5875,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5832 exp_word = to_be_freed; 5875 exp_word = to_be_freed;
5833 if (exp_op == '?') { 5876 if (exp_op == '?') {
5834 /* mimic bash message */ 5877 /* mimic bash message */
5835 die_if_script("%s: %s", 5878 msg_and_die_if_script("%s: %s",
5836 var, 5879 var,
5837 exp_word[0] 5880 exp_word[0]
5838 ? exp_word 5881 ? exp_word
@@ -5849,7 +5892,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5849 /* ${var=[word]} or ${var:=[word]} */ 5892 /* ${var=[word]} or ${var:=[word]} */
5850 if (isdigit(var[0]) || var[0] == '#') { 5893 if (isdigit(var[0]) || var[0] == '#') {
5851 /* mimic bash message */ 5894 /* mimic bash message */
5852 die_if_script("$%s: cannot assign in this way", var); 5895 msg_and_die_if_script("$%s: cannot assign in this way", var);
5853 val = NULL; 5896 val = NULL;
5854 } else { 5897 } else {
5855 char *new_var = xasprintf("%s=%s", var, val); 5898 char *new_var = xasprintf("%s=%s", var, val);
@@ -6698,7 +6741,8 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6698 int moved_to; 6741 int moved_to;
6699 int i; 6742 int i;
6700 6743
6701 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { 6744 i = 0;
6745 if (sq) for (; sq[i].orig_fd >= 0; i++) {
6702 /* If we collide with an already moved fd... */ 6746 /* If we collide with an already moved fd... */
6703 if (fd == sq[i].moved_to) { 6747 if (fd == sq[i].moved_to) {
6704 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); 6748 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd);
@@ -6726,7 +6770,8 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
6726{ 6770{
6727 int i; 6771 int i;
6728 6772
6729 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { 6773 i = 0;
6774 if (sq) for (; sq[i].orig_fd >= 0; i++) {
6730 /* If we collide with an already moved fd... */ 6775 /* If we collide with an already moved fd... */
6731 if (fd == sq[i].orig_fd) { 6776 if (fd == sq[i].orig_fd) {
6732 /* Examples: 6777 /* Examples:
@@ -6863,7 +6908,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6863 * "cmd >" (no filename) 6908 * "cmd >" (no filename)
6864 * "cmd > <file" (2nd redirect starts too early) 6909 * "cmd > <file" (2nd redirect starts too early)
6865 */ 6910 */
6866 die_if_script("syntax error: %s", "invalid redirect"); 6911 syntax_error("invalid redirect");
6867 continue; 6912 continue;
6868 } 6913 }
6869 mode = redir_table[redir->rd_type].mode; 6914 mode = redir_table[redir->rd_type].mode;
@@ -7363,8 +7408,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7363 */ 7408 */
7364 close_saved_fds_and_FILE_fds(); 7409 close_saved_fds_and_FILE_fds();
7365//FIXME: should also close saved redir fds 7410//FIXME: should also close saved redir fds
7411 /* Without this, "rm -i FILE" can't be ^C'ed: */
7412 switch_off_special_sigs(G.special_sig_mask);
7366 debug_printf_exec("running applet '%s'\n", argv[0]); 7413 debug_printf_exec("running applet '%s'\n", argv[0]);
7367 run_applet_no_and_exit(a, argv[0], argv); 7414 run_noexec_applet_and_exit(a, argv[0], argv);
7368 } 7415 }
7369# endif 7416# endif
7370 /* Re-exec ourselves */ 7417 /* Re-exec ourselves */
@@ -8045,6 +8092,24 @@ static NOINLINE int run_pipe(struct pipe *pi)
8045 add_vars(old_vars); 8092 add_vars(old_vars);
8046/* clean_up_and_ret0: */ 8093/* clean_up_and_ret0: */
8047 restore_redirects(squirrel); 8094 restore_redirects(squirrel);
8095 /*
8096 * Try "usleep 99999999" + ^C + "echo $?"
8097 * with FEATURE_SH_NOFORK=y.
8098 */
8099 if (!funcp) {
8100 /* It was builtin or nofork.
8101 * if this would be a real fork/execed program,
8102 * it should have died if a fatal sig was received.
8103 * But OTOH, there was no separate process,
8104 * the sig was sent to _shell_, not to non-existing
8105 * child.
8106 * Let's just handle ^C only, this one is obvious:
8107 * we aren't ok with exitcode 0 when ^C was pressed
8108 * during builtin/nofork.
8109 */
8110 if (sigismember(&G.pending_set, SIGINT))
8111 rcode = 128 + SIGINT;
8112 }
8048 clean_up_and_ret1: 8113 clean_up_and_ret1:
8049 free(argv_expanded); 8114 free(argv_expanded);
8050 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 8115 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -8060,6 +8125,14 @@ static NOINLINE int run_pipe(struct pipe *pi)
8060 if (rcode == 0) { 8125 if (rcode == 0) {
8061 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", 8126 debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
8062 argv_expanded[0], argv_expanded[1]); 8127 argv_expanded[0], argv_expanded[1]);
8128 /*
8129 * Note: signals (^C) can't interrupt here.
8130 * We remember them and they will be acted upon
8131 * after applet returns.
8132 * This makes applets which can run for a long time
8133 * and/or wait for user input ineligible for NOFORK:
8134 * for example, "yes" or "rm" (rm -i waits for input).
8135 */
8063 rcode = run_nofork_applet(n, argv_expanded); 8136 rcode = run_nofork_applet(n, argv_expanded);
8064 } 8137 }
8065 goto clean_up_and_ret; 8138 goto clean_up_and_ret;
@@ -8491,7 +8564,7 @@ static int run_list(struct pipe *pi)
8491 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid; 8564 G.last_bg_pid = pi->cmds[pi->num_cmds - 1].pid;
8492 G.last_bg_pid_exitcode = 0; 8565 G.last_bg_pid_exitcode = 0;
8493 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); 8566 debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
8494/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash says 0 */ 8567/* Check pi->pi_inverted? "! sleep 1 & echo $?": bash says 1. dash and ash say 0 */
8495 rcode = EXIT_SUCCESS; 8568 rcode = EXIT_SUCCESS;
8496 goto check_traps; 8569 goto check_traps;
8497 } else { 8570 } else {
@@ -8600,6 +8673,10 @@ static void install_sighandlers(unsigned mask)
8600 */ 8673 */
8601 if (sig == SIGCHLD) 8674 if (sig == SIGCHLD)
8602 continue; 8675 continue;
8676 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
8677 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
8678 */
8679 //if (sig == SIGHUP) continue; - TODO?
8603 if (old_handler == SIG_IGN) { 8680 if (old_handler == SIG_IGN) {
8604 /* oops... restore back to IGN, and record this fact */ 8681 /* oops... restore back to IGN, and record this fact */
8605 install_sighandler(sig, old_handler); 8682 install_sighandler(sig, old_handler);
@@ -9381,13 +9458,20 @@ static int FAST_FUNC builtin_read(char **argv)
9381 char *opt_p = NULL; 9458 char *opt_p = NULL;
9382 char *opt_t = NULL; 9459 char *opt_t = NULL;
9383 char *opt_u = NULL; 9460 char *opt_u = NULL;
9461 char *opt_d = NULL; /* optimized out if !BASH */
9384 const char *ifs; 9462 const char *ifs;
9385 int read_flags; 9463 int read_flags;
9386 9464
9387 /* "!": do not abort on errors. 9465 /* "!": do not abort on errors.
9388 * Option string must start with "sr" to match BUILTIN_READ_xxx 9466 * Option string must start with "sr" to match BUILTIN_READ_xxx
9389 */ 9467 */
9390 read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); 9468 read_flags = getopt32(argv,
9469#if BASH_READ_D
9470 "!srn:p:t:u:d:", &opt_n, &opt_p, &opt_t, &opt_u, &opt_d
9471#else
9472 "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u
9473#endif
9474 );
9391 if (read_flags == (uint32_t)-1) 9475 if (read_flags == (uint32_t)-1)
9392 return EXIT_FAILURE; 9476 return EXIT_FAILURE;
9393 argv += optind; 9477 argv += optind;
@@ -9401,7 +9485,8 @@ static int FAST_FUNC builtin_read(char **argv)
9401 opt_n, 9485 opt_n,
9402 opt_p, 9486 opt_p,
9403 opt_t, 9487 opt_t,
9404 opt_u 9488 opt_u,
9489 opt_d
9405 ); 9490 );
9406 9491
9407 if ((uintptr_t)r == 1 && errno == EINTR) { 9492 if ((uintptr_t)r == 1 && errno == EINTR) {
@@ -9786,6 +9871,93 @@ static int FAST_FUNC builtin_shift(char **argv)
9786 return EXIT_FAILURE; 9871 return EXIT_FAILURE;
9787} 9872}
9788 9873
9874#if ENABLE_HUSH_GETOPTS
9875static int FAST_FUNC builtin_getopts(char **argv)
9876{
9877/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html
9878
9879TODO:
9880If a required argument is not found, and getopts is not silent,
9881a question mark (?) is placed in VAR, OPTARG is unset, and a
9882diagnostic message is printed. If getopts is silent, then a
9883colon (:) is placed in VAR and OPTARG is set to the option
9884character found.
9885
9886Test that VAR is a valid variable name?
9887
9888"Whenever the shell is invoked, OPTIND shall be initialized to 1"
9889*/
9890 char cbuf[2];
9891 const char *cp, *optstring, *var;
9892 int c, exitcode;
9893
9894 optstring = *++argv;
9895 if (!optstring || !(var = *++argv)) {
9896 bb_error_msg("usage: getopts OPTSTRING VAR [ARGS]");
9897 return EXIT_FAILURE;
9898 }
9899
9900 c = 0;
9901 if (optstring[0] != ':') {
9902 cp = get_local_var_value("OPTERR");
9903 /* 0 if "OPTERR=0", 1 otherwise */
9904 c = (!cp || NOT_LONE_CHAR(cp, '0'));
9905 }
9906 opterr = c;
9907 cp = get_local_var_value("OPTIND");
9908 optind = cp ? atoi(cp) : 0;
9909 optarg = NULL;
9910 cbuf[1] = '\0';
9911
9912 /* getopts stops on first non-option. Add "+" to force that */
9913 /*if (optstring[0] != '+')*/ {
9914 char *s = alloca(strlen(optstring) + 2);
9915 sprintf(s, "+%s", optstring);
9916 optstring = s;
9917 }
9918
9919 if (argv[1])
9920 argv[0] = G.global_argv[0]; /* for error messages */
9921 else
9922 argv = G.global_argv;
9923 c = getopt(string_array_len(argv), argv, optstring);
9924
9925 /* Set OPTARG */
9926 /* Always set or unset, never left as-is, even on exit/error:
9927 * "If no option was found, or if the option that was found
9928 * does not have an option-argument, OPTARG shall be unset."
9929 */
9930 cp = optarg;
9931 if (c == '?') {
9932 /* If ":optstring" and unknown option is seen,
9933 * it is stored to OPTARG.
9934 */
9935 if (optstring[1] == ':') {
9936 cbuf[0] = optopt;
9937 cp = cbuf;
9938 }
9939 }
9940 if (cp)
9941 set_local_var_from_halves("OPTARG", cp);
9942 else
9943 unset_local_var("OPTARG");
9944
9945 /* Convert -1 to "?" */
9946 exitcode = EXIT_SUCCESS;
9947 if (c < 0) { /* -1: end of options */
9948 exitcode = EXIT_FAILURE;
9949 c = '?';
9950 }
9951
9952 /* Set VAR and OPTIND */
9953 cbuf[0] = c;
9954 set_local_var_from_halves(var, cbuf);
9955 set_local_var_from_halves("OPTIND", utoa(optind));
9956
9957 return exitcode;
9958}
9959#endif
9960
9789static int FAST_FUNC builtin_source(char **argv) 9961static int FAST_FUNC builtin_source(char **argv)
9790{ 9962{
9791 char *arg_path, *filename; 9963 char *arg_path, *filename;
@@ -10178,6 +10350,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
10178 /* So, did we get a signal? */ 10350 /* So, did we get a signal? */
10179 sig = check_and_run_traps(); 10351 sig = check_and_run_traps();
10180 if (sig /*&& sig != SIGCHLD - always true */) { 10352 if (sig /*&& sig != SIGCHLD - always true */) {
10353 /* Do this for any (non-ignored) signal, not only for ^C */
10181 ret = 128 + sig; 10354 ret = 128 + sig;
10182 break; 10355 break;
10183 } 10356 }
@@ -10344,6 +10517,41 @@ static int FAST_FUNC builtin_return(char **argv)
10344} 10517}
10345#endif 10518#endif
10346 10519
10520#if ENABLE_HUSH_TIMES
10521static int FAST_FUNC builtin_times(char **argv UNUSED_PARAM)
10522{
10523 static const uint8_t times_tbl[] ALIGN1 = {
10524 ' ', offsetof(struct tms, tms_utime),
10525 '\n', offsetof(struct tms, tms_stime),
10526 ' ', offsetof(struct tms, tms_cutime),
10527 '\n', offsetof(struct tms, tms_cstime),
10528 0
10529 };
10530 const uint8_t *p;
10531 unsigned clk_tck;
10532 struct tms buf;
10533
10534 clk_tck = bb_clk_tck();
10535
10536 times(&buf);
10537 p = times_tbl;
10538 do {
10539 unsigned sec, frac;
10540 unsigned long t;
10541 t = *(clock_t *)(((char *) &buf) + p[1]);
10542 sec = t / clk_tck;
10543 frac = t % clk_tck;
10544 printf("%um%u.%03us%c",
10545 sec / 60, sec % 60,
10546 (frac * 1000) / clk_tck,
10547 p[0]);
10548 p += 2;
10549 } while (*p);
10550
10551 return EXIT_SUCCESS;
10552}
10553#endif
10554
10347#if ENABLE_HUSH_MEMLEAK 10555#if ENABLE_HUSH_MEMLEAK
10348static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM) 10556static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
10349{ 10557{