aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-01-08 12:30:49 +0000
committerRon Yorston <rmy@pobox.com>2020-01-08 12:30:49 +0000
commita9271a8e97e6e7be5285330d5f19352decabf807 (patch)
treebf3c4464c369a15a46454792dac167505f74769f /shell
parentb0b7ab792bc1f45963f4b84b94faaf05054e1613 (diff)
parent9ec836c033fc6e55e80f3309b3e05acdf09bb297 (diff)
downloadbusybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.gz
busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.tar.bz2
busybox-w32-a9271a8e97e6e7be5285330d5f19352decabf807.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c14
-rw-r--r--shell/ash_test/ash-redir/redir_stdin1.right3
-rwxr-xr-xshell/ash_test/ash-redir/redir_stdin1.tests7
-rw-r--r--shell/hush.c113
-rw-r--r--shell/hush_test/hush-redir/redir_stdin1.right3
-rwxr-xr-xshell/hush_test/hush-redir/redir_stdin1.tests7
-rw-r--r--shell/math.c35
-rw-r--r--shell/shell_common.c77
8 files changed, 184 insertions, 75 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 8a27d5cc3..95d0aebf0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -638,7 +638,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
638#define random_gen (G_misc.random_gen ) 638#define random_gen (G_misc.random_gen )
639#define backgndpid (G_misc.backgndpid ) 639#define backgndpid (G_misc.backgndpid )
640#define INIT_G_misc() do { \ 640#define INIT_G_misc() do { \
641 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ 641 (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \
642 barrier(); \ 642 barrier(); \
643 curdir = nullstr; \ 643 curdir = nullstr; \
644 physdir = nullstr; \ 644 physdir = nullstr; \
@@ -1693,7 +1693,7 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack;
1693#define g_stacknleft (G_memstack.g_stacknleft) 1693#define g_stacknleft (G_memstack.g_stacknleft)
1694#define stackbase (G_memstack.stackbase ) 1694#define stackbase (G_memstack.stackbase )
1695#define INIT_G_memstack() do { \ 1695#define INIT_G_memstack() do { \
1696 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ 1696 (*(struct globals_memstack**)not_const_pp(&ash_ptr_to_globals_memstack)) = xzalloc(sizeof(G_memstack)); \
1697 barrier(); \ 1697 barrier(); \
1698 g_stackp = &stackbase; \ 1698 g_stackp = &stackbase; \
1699 g_stacknxt = stackbase.space; \ 1699 g_stacknxt = stackbase.space; \
@@ -2316,7 +2316,7 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
2316#endif 2316#endif
2317#define INIT_G_var() do { \ 2317#define INIT_G_var() do { \
2318 unsigned i; \ 2318 unsigned i; \
2319 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ 2319 (*(struct globals_var**)not_const_pp(&ash_ptr_to_globals_var)) = xzalloc(sizeof(G_var)); \
2320 barrier(); \ 2320 barrier(); \
2321 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ 2321 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
2322 varinit[i].flags = varinit_data[i].flags; \ 2322 varinit[i].flags = varinit_data[i].flags; \
@@ -13112,7 +13112,13 @@ checkend: {
13112 for (p = eofmark; STPUTC(c, out), *p; p++) { 13112 for (p = eofmark; STPUTC(c, out), *p; p++) {
13113 if (c != *p) 13113 if (c != *p)
13114 goto more_heredoc; 13114 goto more_heredoc;
13115 13115 /* FIXME: fails for backslash-newlined terminator:
13116 * cat <<EOF
13117 * ...
13118 * EO\
13119 * F
13120 * (see heredoc_bkslash_newline2.tests)
13121 */
13116 c = pgetc_without_PEOA(); 13122 c = pgetc_without_PEOA();
13117 } 13123 }
13118 13124
diff --git a/shell/ash_test/ash-redir/redir_stdin1.right b/shell/ash_test/ash-redir/redir_stdin1.right
new file mode 100644
index 000000000..1c6217e92
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_stdin1.right
@@ -0,0 +1,3 @@
1#Testing that stdin redirect is restored
2read2
3Ok:0
diff --git a/shell/ash_test/ash-redir/redir_stdin1.tests b/shell/ash_test/ash-redir/redir_stdin1.tests
new file mode 100755
index 000000000..f72253f9d
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir_stdin1.tests
@@ -0,0 +1,7 @@
1#Testing that stdin redirect is restored
2echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests
3echo $r
4read r
5echo $r
6'
7echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index 19b97e2a5..97202b953 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -573,7 +573,6 @@ typedef struct HFILE {
573 char *cur; 573 char *cur;
574 char *end; 574 char *end;
575 struct HFILE *next_hfile; 575 struct HFILE *next_hfile;
576 int is_stdin;
577 int fd; 576 int fd;
578 char buf[1024]; 577 char buf[1024];
579} HFILE; 578} HFILE;
@@ -973,6 +972,7 @@ struct globals {
973 unsigned execute_lineno; 972 unsigned execute_lineno;
974#endif 973#endif
975 HFILE *HFILE_list; 974 HFILE *HFILE_list;
975 HFILE *HFILE_stdin;
976 /* Which signals have non-DFL handler (even with no traps set)? 976 /* Which signals have non-DFL handler (even with no traps set)?
977 * Set at the start to: 977 * Set at the start to:
978 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 978 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
@@ -1603,7 +1603,8 @@ static HFILE *hfopen(const char *name)
1603 } 1603 }
1604 1604
1605 fp = xmalloc(sizeof(*fp)); 1605 fp = xmalloc(sizeof(*fp));
1606 fp->is_stdin = (name == NULL); 1606 if (name == NULL)
1607 G.HFILE_stdin = fp;
1607 fp->fd = fd; 1608 fp->fd = fd;
1608 fp->cur = fp->end = fp->buf; 1609 fp->cur = fp->end = fp->buf;
1609 fp->next_hfile = G.HFILE_list; 1610 fp->next_hfile = G.HFILE_list;
@@ -2666,7 +2667,7 @@ static int fgetc_interactive(struct in_str *i)
2666{ 2667{
2667 int ch; 2668 int ch;
2668 /* If it's interactive stdin, get new line. */ 2669 /* If it's interactive stdin, get new line. */
2669 if (G_interactive_fd && i->file->is_stdin) { 2670 if (G_interactive_fd && i->file == G.HFILE_stdin) {
2670 /* Returns first char (or EOF), the rest is in i->p[] */ 2671 /* Returns first char (or EOF), the rest is in i->p[] */
2671 ch = get_user_input(i); 2672 ch = get_user_input(i);
2672 G.promptmode = 1; /* PS2 */ 2673 G.promptmode = 1; /* PS2 */
@@ -3652,9 +3653,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3652 fdprintf(2, "%*s cmd %d assignment_cnt:%d", 3653 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3653 lvl*2, "", prn, 3654 lvl*2, "", prn,
3654 command->assignment_cnt); 3655 command->assignment_cnt);
3655#if ENABLE_HUSH_LINENO_VAR 3656# if ENABLE_HUSH_LINENO_VAR
3656 fdprintf(2, " LINENO:%u", command->lineno); 3657 fdprintf(2, " LINENO:%u", command->lineno);
3657#endif 3658# endif
3658 if (command->group) { 3659 if (command->group) {
3659 fdprintf(2, " group %s: (argv=%p)%s%s\n", 3660 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3660 CMDTYPE[command->cmd_type], 3661 CMDTYPE[command->cmd_type],
@@ -4770,9 +4771,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4770# endif 4771# endif
4771 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); 4772 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1);
4772 4773
4773#if ENABLE_HUSH_INTERACTIVE 4774# if ENABLE_HUSH_INTERACTIVE
4774 G.promptmode = 1; /* PS2 */ 4775 G.promptmode = 1; /* PS2 */
4775#endif 4776# endif
4776 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 4777 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
4777 4778
4778 while (1) { 4779 while (1) {
@@ -4828,13 +4829,13 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4828 syntax_error_unterm_ch(end_ch); 4829 syntax_error_unterm_ch(end_ch);
4829 return 0; 4830 return 0;
4830 } 4831 }
4831#if 0 4832# if 0
4832 if (ch == '\n') { 4833 if (ch == '\n') {
4833 /* "backslash+newline", ignore both */ 4834 /* "backslash+newline", ignore both */
4834 o_delchr(dest); /* undo insertion of '\' */ 4835 o_delchr(dest); /* undo insertion of '\' */
4835 continue; 4836 continue;
4836 } 4837 }
4837#endif 4838# endif
4838 o_addchr(dest, ch); 4839 o_addchr(dest, ch);
4839 //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch); 4840 //bb_error_msg("%s:o_addchr('%c') after '\\'", __func__, ch);
4840 continue; 4841 continue;
@@ -4991,7 +4992,7 @@ static int parse_dollar(o_string *as_string,
4991 if (last_ch == 0) /* error? */ 4992 if (last_ch == 0) /* error? */
4992 return 0; 4993 return 0;
4993#else 4994#else
4994#error Simple code to only allow ${var} is not implemented 4995# error Simple code to only allow ${var} is not implemented
4995#endif 4996#endif
4996 if (as_string) { 4997 if (as_string) {
4997 o_addstr(as_string, dest->data + pos); 4998 o_addstr(as_string, dest->data + pos);
@@ -7605,7 +7606,9 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7605 avoid_fd = 9; 7606 avoid_fd = 9;
7606 7607
7607#if ENABLE_HUSH_INTERACTIVE 7608#if ENABLE_HUSH_INTERACTIVE
7608 if (fd == G_interactive_fd) { 7609 if (fd != 0 /* don't trigger for G_interactive_fd == 0 (that's "not interactive" flag) */
7610 && fd == G_interactive_fd
7611 ) {
7609 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ 7612 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
7610 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); 7613 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd);
7611 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); 7614 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd);
@@ -7619,7 +7622,7 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7619 /* No need to move script fds. 7622 /* No need to move script fds.
7620 * For NOMMU case, it's actively wrong: we'd change ->fd 7623 * For NOMMU case, it's actively wrong: we'd change ->fd
7621 * fields in memory for the parent, but parent's fds 7624 * fields in memory for the parent, but parent's fds
7622 * aren't be moved, it would use wrong fd! 7625 * aren't moved, it would use wrong fd!
7623 * Reproducer: "cmd 3>FILE" in script. 7626 * Reproducer: "cmd 3>FILE" in script.
7624 * If we would call move_HFILEs_on_redirect(), child would: 7627 * If we would call move_HFILEs_on_redirect(), child would:
7625 * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 7628 * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10
@@ -7683,6 +7686,20 @@ static void restore_redirects(struct squirrel *sq)
7683 } 7686 }
7684 free(sq); 7687 free(sq);
7685 } 7688 }
7689 if (G.HFILE_stdin
7690 && G.HFILE_stdin->fd != STDIN_FILENO
7691 ) {
7692 /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r".
7693 * Redirect moves ->fd to e.g. 10,
7694 * and it is not restored above (we do not restore script fds
7695 * after redirects, we just use new, "moved" fds).
7696 * However for stdin, get_user_input() -> read_line_input(),
7697 * and read builtin, depend on fd == STDIN_FILENO.
7698 */
7699 debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd);
7700 xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO);
7701 G.HFILE_stdin->fd = STDIN_FILENO;
7702 }
7686 7703
7687 /* If moved, G_interactive_fd stays on new fd, not restoring it */ 7704 /* If moved, G_interactive_fd stays on new fd, not restoring it */
7688} 7705}
@@ -8684,9 +8701,9 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8684 pi->cmds[i].pid = 0; 8701 pi->cmds[i].pid = 0;
8685 pi->alive_cmds--; 8702 pi->alive_cmds--;
8686 if (!pi->alive_cmds) { 8703 if (!pi->alive_cmds) {
8687#if ENABLE_HUSH_BASH_COMPAT 8704# if ENABLE_HUSH_BASH_COMPAT
8688 G.dead_job_exitcode = job_exited_or_stopped(pi); 8705 G.dead_job_exitcode = job_exited_or_stopped(pi);
8689#endif 8706# endif
8690 if (G_interactive_fd) { 8707 if (G_interactive_fd) {
8691 printf(JOB_STATUS_FORMAT, pi->jobid, 8708 printf(JOB_STATUS_FORMAT, pi->jobid,
8692 "Done", pi->cmdtext); 8709 "Done", pi->cmdtext);
@@ -9824,9 +9841,12 @@ static int set_mode(int state, char mode, const char *o_opt)
9824 IF_HUSH_MODE_X(G_x_mode = state;) 9841 IF_HUSH_MODE_X(G_x_mode = state;)
9825 IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);) 9842 IF_HUSH_MODE_X(if (G.x_mode_fd <= 0) G.x_mode_fd = dup_CLOEXEC(2, 10);)
9826 break; 9843 break;
9844 case 'e':
9845 G.o_opt[OPT_O_ERREXIT] = state;
9846 break;
9827 case 'o': 9847 case 'o':
9828 if (!o_opt) { 9848 if (!o_opt) {
9829 /* "set -+o" without parameter. 9849 /* "set -o" or "set +o" without parameter.
9830 * in bash, set -o produces this output: 9850 * in bash, set -o produces this output:
9831 * pipefail off 9851 * pipefail off
9832 * and set +o: 9852 * and set +o:
@@ -9847,9 +9867,7 @@ static int set_mode(int state, char mode, const char *o_opt)
9847 G.o_opt[idx] = state; 9867 G.o_opt[idx] = state;
9848 break; 9868 break;
9849 } 9869 }
9850 case 'e': 9870 /* fall through to error */
9851 G.o_opt[OPT_O_ERREXIT] = state;
9852 break;
9853 default: 9871 default:
9854 return EXIT_FAILURE; 9872 return EXIT_FAILURE;
9855 } 9873 }
@@ -10213,8 +10231,6 @@ int hush_main(int argc, char **argv)
10213 G_saved_tty_pgrp = 0; 10231 G_saved_tty_pgrp = 0;
10214 } 10232 }
10215 } 10233 }
10216// TODO: track & disallow any attempts of user
10217// to (inadvertently) close/redirect G_interactive_fd
10218 } 10234 }
10219 debug_printf("interactive_fd:%d\n", G_interactive_fd); 10235 debug_printf("interactive_fd:%d\n", G_interactive_fd);
10220 if (G_interactive_fd) { 10236 if (G_interactive_fd) {
@@ -10536,10 +10552,10 @@ static int FAST_FUNC builtin_type(char **argv)
10536 if (0) {} /* make conditional compile easier below */ 10552 if (0) {} /* make conditional compile easier below */
10537 /*else if (find_alias(*argv)) 10553 /*else if (find_alias(*argv))
10538 type = "an alias";*/ 10554 type = "an alias";*/
10539#if ENABLE_HUSH_FUNCTIONS 10555# if ENABLE_HUSH_FUNCTIONS
10540 else if (find_function(*argv)) 10556 else if (find_function(*argv))
10541 type = "a function"; 10557 type = "a function";
10542#endif 10558# endif
10543 else if (find_builtin(*argv)) 10559 else if (find_builtin(*argv))
10544 type = "a shell builtin"; 10560 type = "a shell builtin";
10545 else if ((path = find_in_path(*argv)) != NULL) 10561 else if ((path = find_in_path(*argv)) != NULL)
@@ -10594,11 +10610,11 @@ static int FAST_FUNC builtin_read(char **argv)
10594 * Option string must start with "sr" to match BUILTIN_READ_xxx 10610 * Option string must start with "sr" to match BUILTIN_READ_xxx
10595 */ 10611 */
10596 params.read_flags = getopt32(argv, 10612 params.read_flags = getopt32(argv,
10597#if BASH_READ_D 10613# if BASH_READ_D
10598 "!srn:p:t:u:d:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u, &params.opt_d 10614 "!srn:p:t:u:d:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u, &params.opt_d
10599#else 10615# else
10600 "!srn:p:t:u:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u 10616 "!srn:p:t:u:", &params.opt_n, &params.opt_p, &params.opt_t, &params.opt_u
10601#endif 10617# endif
10602 ); 10618 );
10603 if ((uint32_t)params.read_flags == (uint32_t)-1) 10619 if ((uint32_t)params.read_flags == (uint32_t)-1)
10604 return EXIT_FAILURE; 10620 return EXIT_FAILURE;
@@ -10771,24 +10787,24 @@ static int FAST_FUNC builtin_export(char **argv)
10771{ 10787{
10772 unsigned opt_unexport; 10788 unsigned opt_unexport;
10773 10789
10774#if ENABLE_HUSH_EXPORT_N 10790# if ENABLE_HUSH_EXPORT_N
10775 /* "!": do not abort on errors */ 10791 /* "!": do not abort on errors */
10776 opt_unexport = getopt32(argv, "!n"); 10792 opt_unexport = getopt32(argv, "!n");
10777 if (opt_unexport == (uint32_t)-1) 10793 if (opt_unexport == (uint32_t)-1)
10778 return EXIT_FAILURE; 10794 return EXIT_FAILURE;
10779 argv += optind; 10795 argv += optind;
10780#else 10796# else
10781 opt_unexport = 0; 10797 opt_unexport = 0;
10782 argv++; 10798 argv++;
10783#endif 10799# endif
10784 10800
10785 if (argv[0] == NULL) { 10801 if (argv[0] == NULL) {
10786 char **e = environ; 10802 char **e = environ;
10787 if (e) { 10803 if (e) {
10788 while (*e) { 10804 while (*e) {
10789#if 0 10805# if 0
10790 puts(*e++); 10806 puts(*e++);
10791#else 10807# else
10792 /* ash emits: export VAR='VAL' 10808 /* ash emits: export VAR='VAL'
10793 * bash: declare -x VAR="VAL" 10809 * bash: declare -x VAR="VAL"
10794 * we follow ash example */ 10810 * we follow ash example */
@@ -10801,7 +10817,7 @@ static int FAST_FUNC builtin_export(char **argv)
10801 printf("export %.*s", (int)(p - s) + 1, s); 10817 printf("export %.*s", (int)(p - s) + 1, s);
10802 print_escaped(p + 1); 10818 print_escaped(p + 1);
10803 putchar('\n'); 10819 putchar('\n');
10804#endif 10820# endif
10805 } 10821 }
10806 /*fflush_all(); - done after each builtin anyway */ 10822 /*fflush_all(); - done after each builtin anyway */
10807 } 10823 }
@@ -10931,8 +10947,10 @@ static int FAST_FUNC builtin_set(char **argv)
10931 if (arg[0] != '+' && arg[0] != '-') 10947 if (arg[0] != '+' && arg[0] != '-')
10932 break; 10948 break;
10933 for (n = 1; arg[n]; ++n) { 10949 for (n = 1; arg[n]; ++n) {
10934 if (set_mode((arg[0] == '-'), arg[n], argv[1])) 10950 if (set_mode((arg[0] == '-'), arg[n], argv[1])) {
10935 goto error; 10951 bb_error_msg("%s: %s: invalid option", "set", arg);
10952 return EXIT_FAILURE;
10953 }
10936 if (arg[n] == 'o' && argv[1]) 10954 if (arg[n] == 'o' && argv[1])
10937 argv++; 10955 argv++;
10938 } 10956 }
@@ -10962,11 +10980,6 @@ static int FAST_FUNC builtin_set(char **argv)
10962 G.global_argc = 1 + string_array_len(pp + 1); 10980 G.global_argc = 1 + string_array_len(pp + 1);
10963 10981
10964 return EXIT_SUCCESS; 10982 return EXIT_SUCCESS;
10965
10966 /* Nothing known, so abort */
10967 error:
10968 bb_error_msg("%s: %s: invalid option", "set", arg);
10969 return EXIT_FAILURE;
10970} 10983}
10971#endif 10984#endif
10972 10985
@@ -11459,9 +11472,9 @@ static int FAST_FUNC builtin_kill(char **argv)
11459 11472
11460#if ENABLE_HUSH_WAIT 11473#if ENABLE_HUSH_WAIT
11461/* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ 11474/* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */
11462#if !ENABLE_HUSH_JOB 11475# if !ENABLE_HUSH_JOB
11463# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) 11476# define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid)
11464#endif 11477# endif
11465static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid) 11478static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid)
11466{ 11479{
11467 int ret = 0; 11480 int ret = 0;
@@ -11493,7 +11506,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
11493/* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */ 11506/* Can't pass waitfor_pipe into checkjobs(): it won't be interruptible */
11494 ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */ 11507 ret = checkjobs(NULL, waitfor_pid); /* waitpid(WNOHANG) inside */
11495 debug_printf_exec("checkjobs:%d\n", ret); 11508 debug_printf_exec("checkjobs:%d\n", ret);
11496#if ENABLE_HUSH_JOB 11509# if ENABLE_HUSH_JOB
11497 if (waitfor_pipe) { 11510 if (waitfor_pipe) {
11498 int rcode = job_exited_or_stopped(waitfor_pipe); 11511 int rcode = job_exited_or_stopped(waitfor_pipe);
11499 debug_printf_exec("job_exited_or_stopped:%d\n", rcode); 11512 debug_printf_exec("job_exited_or_stopped:%d\n", rcode);
@@ -11503,7 +11516,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
11503 break; 11516 break;
11504 } 11517 }
11505 } 11518 }
11506#endif 11519# endif
11507 /* if ECHILD, there are no children (ret is -1 or 0) */ 11520 /* if ECHILD, there are no children (ret is -1 or 0) */
11508 /* if ret == 0, no children changed state */ 11521 /* if ret == 0, no children changed state */
11509 /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */ 11522 /* if ret != 0, it's exitcode+1 of exited waitfor_pid child */
@@ -11511,12 +11524,12 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
11511 ret--; 11524 ret--;
11512 if (ret < 0) /* if ECHILD, may need to fix "ret" */ 11525 if (ret < 0) /* if ECHILD, may need to fix "ret" */
11513 ret = 0; 11526 ret = 0;
11514#if ENABLE_HUSH_BASH_COMPAT 11527# if ENABLE_HUSH_BASH_COMPAT
11515 if (waitfor_pid == -1 && errno == ECHILD) { 11528 if (waitfor_pid == -1 && errno == ECHILD) {
11516 /* exitcode of "wait -n" with no children is 127, not 0 */ 11529 /* exitcode of "wait -n" with no children is 127, not 0 */
11517 ret = 127; 11530 ret = 127;
11518 } 11531 }
11519#endif 11532# endif
11520 sigprocmask(SIG_SETMASK, &oldset, NULL); 11533 sigprocmask(SIG_SETMASK, &oldset, NULL);
11521 break; 11534 break;
11522 } 11535 }
@@ -11545,14 +11558,14 @@ static int FAST_FUNC builtin_wait(char **argv)
11545 int status; 11558 int status;
11546 11559
11547 argv = skip_dash_dash(argv); 11560 argv = skip_dash_dash(argv);
11548#if ENABLE_HUSH_BASH_COMPAT 11561# if ENABLE_HUSH_BASH_COMPAT
11549 if (argv[0] && strcmp(argv[0], "-n") == 0) { 11562 if (argv[0] && strcmp(argv[0], "-n") == 0) {
11550 /* wait -n */ 11563 /* wait -n */
11551 /* (bash accepts "wait -n PID" too and ignores PID) */ 11564 /* (bash accepts "wait -n PID" too and ignores PID) */
11552 G.dead_job_exitcode = -1; 11565 G.dead_job_exitcode = -1;
11553 return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/); 11566 return wait_for_child_or_signal(NULL, -1 /*no job, wait for one job*/);
11554 } 11567 }
11555#endif 11568# endif
11556 if (argv[0] == NULL) { 11569 if (argv[0] == NULL) {
11557 /* Don't care about wait results */ 11570 /* Don't care about wait results */
11558 /* Note 1: must wait until there are no more children */ 11571 /* Note 1: must wait until there are no more children */
@@ -11576,7 +11589,7 @@ static int FAST_FUNC builtin_wait(char **argv)
11576 do { 11589 do {
11577 pid_t pid = bb_strtou(*argv, NULL, 10); 11590 pid_t pid = bb_strtou(*argv, NULL, 10);
11578 if (errno || pid <= 0) { 11591 if (errno || pid <= 0) {
11579#if ENABLE_HUSH_JOB 11592# if ENABLE_HUSH_JOB
11580 if (argv[0][0] == '%') { 11593 if (argv[0][0] == '%') {
11581 struct pipe *wait_pipe; 11594 struct pipe *wait_pipe;
11582 ret = 127; /* bash compat for bad jobspecs */ 11595 ret = 127; /* bash compat for bad jobspecs */
@@ -11593,7 +11606,7 @@ static int FAST_FUNC builtin_wait(char **argv)
11593 /* else: parse_jobspec() already emitted error msg */ 11606 /* else: parse_jobspec() already emitted error msg */
11594 continue; 11607 continue;
11595 } 11608 }
11596#endif 11609# endif
11597 /* mimic bash message */ 11610 /* mimic bash message */
11598 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv); 11611 bb_error_msg("wait: '%s': not a pid or valid job spec", *argv);
11599 ret = EXIT_FAILURE; 11612 ret = EXIT_FAILURE;
@@ -11615,7 +11628,7 @@ static int FAST_FUNC builtin_wait(char **argv)
11615 ret = G.last_bg_pid_exitcode; 11628 ret = G.last_bg_pid_exitcode;
11616 } else { 11629 } else {
11617 /* Example: "wait 1". mimic bash message */ 11630 /* Example: "wait 1". mimic bash message */
11618 bb_error_msg("wait: pid %d is not a child of this shell", (int)pid); 11631 bb_error_msg("wait: pid %u is not a child of this shell", (unsigned)pid);
11619 } 11632 }
11620 } else { 11633 } else {
11621 /* ??? */ 11634 /* ??? */
diff --git a/shell/hush_test/hush-redir/redir_stdin1.right b/shell/hush_test/hush-redir/redir_stdin1.right
new file mode 100644
index 000000000..1c6217e92
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_stdin1.right
@@ -0,0 +1,3 @@
1#Testing that stdin redirect is restored
2read2
3Ok:0
diff --git a/shell/hush_test/hush-redir/redir_stdin1.tests b/shell/hush_test/hush-redir/redir_stdin1.tests
new file mode 100755
index 000000000..f72253f9d
--- /dev/null
+++ b/shell/hush_test/hush-redir/redir_stdin1.tests
@@ -0,0 +1,7 @@
1#Testing that stdin redirect is restored
2echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests
3echo $r
4read r
5echo $r
6'
7echo Ok:$?
diff --git a/shell/math.c b/shell/math.c
index eaf4f2453..aac5017d0 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -537,11 +537,40 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
537 base = (unsigned)n; 537 base = (unsigned)n;
538 n = 0; 538 n = 0;
539 nptr = *endptr + 1; 539 nptr = *endptr + 1;
540 /* bash allows "N#" (empty "nnnn" part) */ 540 for (;;) {
541 while (isdigit(*nptr)) { 541 unsigned digit = (unsigned)*nptr - '0';
542 if (digit >= 10 /* not 0..9 */
543 && digit <= 'z' - '0' /* needed to reject e.g. $((64#~)) */
544 ) {
545 /* in bases up to 36, case does not matter for a-z */
546 digit = (unsigned)(*nptr | 0x20) - ('a' - 10);
547 if (base > 36 && *nptr <= '_') {
548 /* otherwise, A-Z,@,_ are 36-61,62,63 */
549 if (*nptr == '_')
550 digit = 63;
551 else if (*nptr == '@')
552 digit = 62;
553 else if (digit < 36) /* A-Z */
554 digit += 36 - 10;
555 else
556 break; /* error: one of [\]^ */
557 }
558 //bb_error_msg("ch:'%c'%d digit:%u", *nptr, *nptr, digit);
559 //if (digit < 10) - example where we need this?
560 // break;
561 }
562 if (digit >= base)
563 break;
542 /* bash does not check for overflows */ 564 /* bash does not check for overflows */
543 n = n * base + (*nptr++ - '0'); 565 n = n * base + digit;
566 nptr++;
544 } 567 }
568 /* Note: we do not set errno on bad chars, we just set a pointer
569 * to the first invalid char. For example, this allows
570 * "N#" (empty "nnnn" part): 64#+1 is a valid expression,
571 * it means 64# + 1, whereas 64#~... is not, since ~ is not a valid
572 * operator.
573 */
545 *endptr = (char*)nptr; 574 *endptr = (char*)nptr;
546 return n; 575 return n;
547} 576}
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 06a6b6e5f..be69ff249 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -371,52 +371,91 @@ shell_builtin_read(struct builtin_read_params *params)
371struct limits { 371struct limits {
372 uint8_t cmd; /* RLIMIT_xxx fit into it */ 372 uint8_t cmd; /* RLIMIT_xxx fit into it */
373 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 373 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
374 const char *name;
375}; 374};
376 375
377static const struct limits limits_tbl[] = { 376static const struct limits limits_tbl[] = {
378 { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c 377 { RLIMIT_CORE, 9, }, // -c
379 { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d 378 { RLIMIT_DATA, 10, }, // -d
380 { RLIMIT_NICE, 0, "scheduling priority" }, // -e 379 { RLIMIT_NICE, 0, }, // -e
381 { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f 380 { RLIMIT_FSIZE, 9, }, // -f
382#define LIMIT_F_IDX 3 381#define LIMIT_F_IDX 3
383#ifdef RLIMIT_SIGPENDING 382#ifdef RLIMIT_SIGPENDING
384 { RLIMIT_SIGPENDING, 0, "pending signals" }, // -i 383 { RLIMIT_SIGPENDING, 0, }, // -i
385#endif 384#endif
386#ifdef RLIMIT_MEMLOCK 385#ifdef RLIMIT_MEMLOCK
387 { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" }, // -l 386 { RLIMIT_MEMLOCK, 10, }, // -l
388#endif 387#endif
389#ifdef RLIMIT_RSS 388#ifdef RLIMIT_RSS
390 { RLIMIT_RSS, 10, "max memory size (kb)" }, // -m 389 { RLIMIT_RSS, 10, }, // -m
391#endif 390#endif
392#ifdef RLIMIT_NOFILE 391#ifdef RLIMIT_NOFILE
393 { RLIMIT_NOFILE, 0, "open files" }, // -n 392 { RLIMIT_NOFILE, 0, }, // -n
394#endif 393#endif
395#ifdef RLIMIT_MSGQUEUE 394#ifdef RLIMIT_MSGQUEUE
396 { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" }, // -q 395 { RLIMIT_MSGQUEUE, 0, }, // -q
397#endif 396#endif
398#ifdef RLIMIT_RTPRIO 397#ifdef RLIMIT_RTPRIO
399 { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r 398 { RLIMIT_RTPRIO, 0, }, // -r
400#endif 399#endif
401#ifdef RLIMIT_STACK 400#ifdef RLIMIT_STACK
402 { RLIMIT_STACK, 10, "stack size (kb)" }, // -s 401 { RLIMIT_STACK, 10, }, // -s
403#endif 402#endif
404#ifdef RLIMIT_CPU 403#ifdef RLIMIT_CPU
405 { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t 404 { RLIMIT_CPU, 0, }, // -t
406#endif 405#endif
407#ifdef RLIMIT_NPROC 406#ifdef RLIMIT_NPROC
408 { RLIMIT_NPROC, 0, "max user processes" }, // -u 407 { RLIMIT_NPROC, 0, }, // -u
409#endif 408#endif
410#ifdef RLIMIT_AS 409#ifdef RLIMIT_AS
411 { RLIMIT_AS, 10, "virtual memory (kb)" }, // -v 410 { RLIMIT_AS, 10, }, // -v
412#endif 411#endif
413#ifdef RLIMIT_LOCKS 412#ifdef RLIMIT_LOCKS
414 { RLIMIT_LOCKS, 0, "file locks" }, // -x 413 { RLIMIT_LOCKS, 0, }, // -x
415#endif 414#endif
416}; 415};
417// bash also shows: 416// bash also shows:
418//pipe size (512 bytes, -p) 8 417//pipe size (512 bytes, -p) 8
419 418
419static const char limits_help[] ALIGN1 =
420 "core file size (blocks)" // -c
421 "\0""data seg size (kb)" // -d
422 "\0""scheduling priority" // -e
423 "\0""file size (blocks)" // -f
424#ifdef RLIMIT_SIGPENDING
425 "\0""pending signals" // -i
426#endif
427#ifdef RLIMIT_MEMLOCK
428 "\0""max locked memory (kb)" // -l
429#endif
430#ifdef RLIMIT_RSS
431 "\0""max memory size (kb)" // -m
432#endif
433#ifdef RLIMIT_NOFILE
434 "\0""open files" // -n
435#endif
436#ifdef RLIMIT_MSGQUEUE
437 "\0""POSIX message queues (bytes)" // -q
438#endif
439#ifdef RLIMIT_RTPRIO
440 "\0""real-time priority" // -r
441#endif
442#ifdef RLIMIT_STACK
443 "\0""stack size (kb)" // -s
444#endif
445#ifdef RLIMIT_CPU
446 "\0""cpu time (seconds)" // -t
447#endif
448#ifdef RLIMIT_NPROC
449 "\0""max user processes" // -u
450#endif
451#ifdef RLIMIT_AS
452 "\0""virtual memory (kb)" // -v
453#endif
454#ifdef RLIMIT_LOCKS
455 "\0""file locks" // -x
456#endif
457;
458
420static const char limit_chars[] ALIGN1 = 459static const char limit_chars[] ALIGN1 =
421 "c" 460 "c"
422 "d" 461 "d"
@@ -607,10 +646,12 @@ shell_builtin_ulimit(char **argv)
607 if (!(opts & (OPT_hard | OPT_soft))) 646 if (!(opts & (OPT_hard | OPT_soft)))
608 opts |= (OPT_hard | OPT_soft); 647 opts |= (OPT_hard | OPT_soft);
609 if (opts & OPT_all) { 648 if (opts & OPT_all) {
649 const char *help = limits_help;
610 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) { 650 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
611 getrlimit(limits_tbl[i].cmd, &limit); 651 getrlimit(limits_tbl[i].cmd, &limit);
612 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); 652 printf("%-32s(-%c) ", help, limit_chars[i]);
613 printlim(opts, &limit, &limits_tbl[i]); 653 printlim(opts, &limit, &limits_tbl[i]);
654 help += strlen(help) + 1;
614 } 655 }
615 return EXIT_SUCCESS; 656 return EXIT_SUCCESS;
616 } 657 }
@@ -641,7 +682,7 @@ shell_builtin_ulimit(char **argv)
641 getrlimit(limits_tbl[i].cmd, &limit); 682 getrlimit(limits_tbl[i].cmd, &limit);
642 if (!val_str) { 683 if (!val_str) {
643 if (opt_cnt > 1) 684 if (opt_cnt > 1)
644 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]); 685 printf("%-32s(-%c) ", nth_string(limits_help, i), limit_chars[i]);
645 printlim(opts, &limit, &limits_tbl[i]); 686 printlim(opts, &limit, &limits_tbl[i]);
646 } else { 687 } else {
647 rlim_t val = RLIM_INFINITY; 688 rlim_t val = RLIM_INFINITY;