aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbb/xfuncs_printf.c1
-rw-r--r--shell/ash_test/ash-heredoc/heredocB.right3
-rwxr-xr-xshell/ash_test/ash-heredoc/heredocB.tests12
-rwxr-xr-xshell/ash_test/ash-redir/redir_script.tests4
-rw-r--r--shell/hush.c234
-rw-r--r--shell/hush_test/hush-heredoc/heredocB.right3
-rwxr-xr-xshell/hush_test/hush-heredoc/heredocB.tests12
-rwxr-xr-xshell/hush_test/hush-redir/redir_script.tests4
8 files changed, 175 insertions, 98 deletions
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 7247c915b..6cc60f6c0 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -222,6 +222,7 @@ void FAST_FUNC xdup2(int from, int to)
222{ 222{
223 if (dup2(from, to) != to) 223 if (dup2(from, to) != to)
224 bb_perror_msg_and_die("can't duplicate file descriptor"); 224 bb_perror_msg_and_die("can't duplicate file descriptor");
225 // " %d to %d", from, to);
225} 226}
226 227
227// "Renumber" opened fd 228// "Renumber" opened fd
diff --git a/shell/ash_test/ash-heredoc/heredocB.right b/shell/ash_test/ash-heredoc/heredocB.right
new file mode 100644
index 000000000..43ba0b4f9
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocB.right
@@ -0,0 +1,3 @@
1one - alpha
2two - beta
3three - gamma
diff --git a/shell/ash_test/ash-heredoc/heredocB.tests b/shell/ash_test/ash-heredoc/heredocB.tests
new file mode 100755
index 000000000..45ea4687f
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocB.tests
@@ -0,0 +1,12 @@
1while read line1; do
2 read line2 <&3
3 echo $line1 - $line2
4done <<EOF1 3<<EOF2
5one
6two
7three
8EOF1
9alpha
10beta
11gamma
12EOF2
diff --git a/shell/ash_test/ash-redir/redir_script.tests b/shell/ash_test/ash-redir/redir_script.tests
index 740daa461..a8d93ce4f 100755
--- a/shell/ash_test/ash-redir/redir_script.tests
+++ b/shell/ash_test/ash-redir/redir_script.tests
@@ -27,6 +27,10 @@ test x"$fds1" = x"$fds" \
27test x"$fds1" = x" 10>&- 3>&-" && \ 27test x"$fds1" = x" 10>&- 3>&-" && \
28test x"$fds" = x" 11>&- 3>&-" \ 28test x"$fds" = x" 11>&- 3>&-" \
29&& { echo "Ok: script fd is not closed"; exit 0; } 29&& { echo "Ok: script fd is not closed"; exit 0; }
30# or we see that fd 3 moved to fd 10:
31test x"$fds1" = x" 3>&- 4>&-" && \
32test x"$fds" = x" 10>&- 3>&-" \
33&& { echo "Ok: script fd is not closed"; exit 0; }
30 34
31echo "Bug: script fd is closed" 35echo "Bug: script fd is closed"
32echo "fds1:$fds1" 36echo "fds1:$fds1"
diff --git a/shell/hush.c b/shell/hush.c
index c26484b49..7a1513c24 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -357,6 +357,9 @@
357#else 357#else
358# define CLEAR_RANDOM_T(rnd) ((void)0) 358# define CLEAR_RANDOM_T(rnd) ((void)0)
359#endif 359#endif
360#ifndef O_CLOEXEC
361# define O_CLOEXEC 0
362#endif
360#ifndef F_DUPFD_CLOEXEC 363#ifndef F_DUPFD_CLOEXEC
361# define F_DUPFD_CLOEXEC F_DUPFD 364# define F_DUPFD_CLOEXEC F_DUPFD
362#endif 365#endif
@@ -556,11 +559,27 @@ static const char *const assignment_flag[] = {
556}; 559};
557#endif 560#endif
558 561
562/* We almost can use standard FILE api, but we need an ability to move
563 * its fd when redirects coincide with it. No api exists for that
564 * (RFE for it at https://sourceware.org/bugzilla/show_bug.cgi?id=21902).
565 * HFILE is our internal alternative. Only supports reading.
566 * Since we now can, we incorporate linked list of all opened HFILEs
567 * into the struct (used to be a separate mini-list).
568 */
569typedef struct HFILE {
570 char *cur;
571 char *end;
572 struct HFILE *next_hfile;
573 int is_stdin;
574 int fd;
575 char buf[1024];
576} HFILE;
577
559typedef struct in_str { 578typedef struct in_str {
560 const char *p; 579 const char *p;
561 int peek_buf[2]; 580 int peek_buf[2];
562 int last_char; 581 int last_char;
563 FILE *file; 582 HFILE *file;
564} in_str; 583} in_str;
565 584
566/* The descrip member of this structure is only used to make 585/* The descrip member of this structure is only used to make
@@ -814,14 +833,6 @@ enum {
814 NUM_OPT_O 833 NUM_OPT_O
815}; 834};
816 835
817
818struct FILE_list {
819 struct FILE_list *next;
820 FILE *fp;
821 int fd;
822};
823
824
825/* "Globals" within this file */ 836/* "Globals" within this file */
826/* Sorted roughly by size (smaller offsets == smaller code) */ 837/* Sorted roughly by size (smaller offsets == smaller code) */
827struct globals { 838struct globals {
@@ -954,7 +965,7 @@ struct globals {
954 unsigned lineno; 965 unsigned lineno;
955 char *lineno_var; 966 char *lineno_var;
956#endif 967#endif
957 struct FILE_list *FILE_list; 968 HFILE *HFILE_list;
958 /* Which signals have non-DFL handler (even with no traps set)? 969 /* Which signals have non-DFL handler (even with no traps set)?
959 * Set at the start to: 970 * Set at the start to:
960 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 971 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
@@ -1563,83 +1574,115 @@ static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1563} 1574}
1564 1575
1565 1576
1566/* Manipulating the list of open FILEs */ 1577/* Manipulating HFILEs */
1567static FILE *remember_FILE(FILE *fp) 1578static HFILE *hfopen(const char *name)
1568{ 1579{
1569 if (fp) { 1580 HFILE *fp;
1570 struct FILE_list *n = xmalloc(sizeof(*n)); 1581 int fd;
1571 n->next = G.FILE_list; 1582
1572 G.FILE_list = n; 1583 fd = STDIN_FILENO;
1573 n->fp = fp; 1584 if (name) {
1574 n->fd = fileno(fp); 1585 fd = open(name, O_RDONLY | O_CLOEXEC);
1575 close_on_exec_on(n->fd); 1586 if (fd < 0)
1587 return NULL;
1588 if (O_CLOEXEC == 0) /* ancient libc */
1589 close_on_exec_on(fd);
1576 } 1590 }
1591
1592 fp = xmalloc(sizeof(*fp));
1593 fp->is_stdin = (name == NULL);
1594 fp->fd = fd;
1595 fp->cur = fp->end = fp->buf;
1596 fp->next_hfile = G.HFILE_list;
1597 G.HFILE_list = fp;
1577 return fp; 1598 return fp;
1578} 1599}
1579static void fclose_and_forget(FILE *fp) 1600static void hfclose(HFILE *fp)
1580{ 1601{
1581 struct FILE_list **pp = &G.FILE_list; 1602 HFILE **pp = &G.HFILE_list;
1582 while (*pp) { 1603 while (*pp) {
1583 struct FILE_list *cur = *pp; 1604 HFILE *cur = *pp;
1584 if (cur->fp == fp) { 1605 if (cur == fp) {
1585 *pp = cur->next; 1606 *pp = cur->next_hfile;
1586 free(cur);
1587 break; 1607 break;
1588 } 1608 }
1589 pp = &cur->next; 1609 pp = &cur->next_hfile;
1590 } 1610 }
1591 fclose(fp); 1611 if (fp->fd >= 0)
1612 close(fp->fd);
1613 free(fp);
1592} 1614}
1593static int save_FILEs_on_redirect(int fd, int avoid_fd) 1615static int refill_HFILE_and_getc(HFILE *fp)
1594{ 1616{
1595 struct FILE_list *fl = G.FILE_list; 1617 int n;
1618
1619 if (fp->fd < 0) {
1620 /* Already saw EOF */
1621 return EOF;
1622 }
1623 /* Try to buffer more input */
1624 fp->cur = fp->buf;
1625 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1626 if (n < 0) {
1627 bb_perror_msg("read error");
1628 n = 0;
1629 }
1630 fp->end = fp->buf + n;
1631 if (n == 0) {
1632 /* EOF/error */
1633 close(fp->fd);
1634 fp->fd = -1;
1635 return EOF;
1636 }
1637 return (unsigned char)(*fp->cur++);
1638}
1639/* Inlined for common case of non-empty buffer.
1640 */
1641static ALWAYS_INLINE int hfgetc(HFILE *fp)
1642{
1643 if (fp->cur < fp->end)
1644 return (unsigned char)(*fp->cur++);
1645 /* Buffer empty */
1646 return refill_HFILE_and_getc(fp);
1647}
1648static int move_HFILEs_on_redirect(int fd, int avoid_fd)
1649{
1650 HFILE *fl = G.HFILE_list;
1596 while (fl) { 1651 while (fl) {
1597 if (fd == fl->fd) { 1652 if (fd == fl->fd) {
1598 /* We use it only on script files, they are all CLOEXEC */ 1653 /* We use it only on script files, they are all CLOEXEC */
1599 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd); 1654 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1600 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd); 1655 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1601 return 1; 1656 return 1; /* "found and moved" */
1602 }
1603 fl = fl->next;
1604 }
1605 return 0;
1606}
1607static void restore_redirected_FILEs(void)
1608{
1609 struct FILE_list *fl = G.FILE_list;
1610 while (fl) {
1611 int should_be = fileno(fl->fp);
1612 if (fl->fd != should_be) {
1613 debug_printf_redir("restoring script fd from %d to %d\n", fl->fd, should_be);
1614 xmove_fd(fl->fd, should_be);
1615 fl->fd = should_be;
1616 } 1657 }
1617 fl = fl->next; 1658 fl = fl->next_hfile;
1618 } 1659 }
1660 return 0; /* "not in the list" */
1619} 1661}
1620#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 1662#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
1621static void close_all_FILE_list(void) 1663static void close_all_HFILE_list(void)
1622{ 1664{
1623 struct FILE_list *fl = G.FILE_list; 1665 HFILE *fl = G.HFILE_list;
1624 while (fl) { 1666 while (fl) {
1625 /* fclose would also free FILE object. 1667 /* hfclose would also free HFILE object.
1626 * It is disastrous if we share memory with a vforked parent. 1668 * It is disastrous if we share memory with a vforked parent.
1627 * I'm not sure we never come here after vfork. 1669 * I'm not sure we never come here after vfork.
1628 * Therefore just close fd, nothing more. 1670 * Therefore just close fd, nothing more.
1629 */ 1671 */
1630 /*fclose(fl->fp); - unsafe */ 1672 /*hfclose(fl); - unsafe */
1631 close(fl->fd); 1673 if (fl->fd >= 0)
1632 fl = fl->next; 1674 close(fl->fd);
1675 fl = fl->next_hfile;
1633 } 1676 }
1634} 1677}
1635#endif 1678#endif
1636static int fd_in_FILEs(int fd) 1679static int fd_in_HFILEs(int fd)
1637{ 1680{
1638 struct FILE_list *fl = G.FILE_list; 1681 HFILE *fl = G.HFILE_list;
1639 while (fl) { 1682 while (fl) {
1640 if (fl->fd == fd) 1683 if (fl->fd == fd)
1641 return 1; 1684 return 1;
1642 fl = fl->next; 1685 fl = fl->next_hfile;
1643 } 1686 }
1644 return 0; 1687 return 0;
1645} 1688}
@@ -2580,7 +2623,7 @@ static int get_user_input(struct in_str *i)
2580 } 2623 }
2581 fflush_all(); 2624 fflush_all();
2582//FIXME: here ^C or SIGINT will have effect only after <Enter> 2625//FIXME: here ^C or SIGINT will have effect only after <Enter>
2583 r = fgetc(i->file); 2626 r = hfgetc(i->file);
2584 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, 2627 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input,
2585 * no ^C masking happens during fgetc, no special code for ^C: 2628 * no ^C masking happens during fgetc, no special code for ^C:
2586 * it generates SIGINT as usual. 2629 * it generates SIGINT as usual.
@@ -2600,22 +2643,22 @@ static int fgetc_interactive(struct in_str *i)
2600{ 2643{
2601 int ch; 2644 int ch;
2602 /* If it's interactive stdin, get new line. */ 2645 /* If it's interactive stdin, get new line. */
2603 if (G_interactive_fd && i->file == stdin) { 2646 if (G_interactive_fd && i->file->is_stdin) {
2604 /* Returns first char (or EOF), the rest is in i->p[] */ 2647 /* Returns first char (or EOF), the rest is in i->p[] */
2605 ch = get_user_input(i); 2648 ch = get_user_input(i);
2606 G.promptmode = 1; /* PS2 */ 2649 G.promptmode = 1; /* PS2 */
2607 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 2650 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
2608 } else { 2651 } else {
2609 /* Not stdin: script file, sourced file, etc */ 2652 /* Not stdin: script file, sourced file, etc */
2610 do ch = fgetc(i->file); while (ch == '\0'); 2653 do ch = hfgetc(i->file); while (ch == '\0');
2611 } 2654 }
2612 return ch; 2655 return ch;
2613} 2656}
2614#else 2657#else
2615static inline int fgetc_interactive(struct in_str *i) 2658static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
2616{ 2659{
2617 int ch; 2660 int ch;
2618 do ch = fgetc(i->file); while (ch == '\0'); 2661 do ch = hfgetc(i->file); while (ch == '\0');
2619 return ch; 2662 return ch;
2620} 2663}
2621#endif /* INTERACTIVE */ 2664#endif /* INTERACTIVE */
@@ -2730,7 +2773,7 @@ static int i_peek2(struct in_str *i)
2730 ch = i->peek_buf[1]; 2773 ch = i->peek_buf[1];
2731 if (ch == 0) { 2774 if (ch == 0) {
2732 /* We did not read it yet, get it now */ 2775 /* We did not read it yet, get it now */
2733 do ch = fgetc(i->file); while (ch == '\0'); 2776 do ch = hfgetc(i->file); while (ch == '\0');
2734 i->peek_buf[1] = ch; 2777 i->peek_buf[1] = ch;
2735 } 2778 }
2736 2779
@@ -2774,10 +2817,10 @@ static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2774 } 2817 }
2775} 2818}
2776 2819
2777static void setup_file_in_str(struct in_str *i, FILE *f) 2820static void setup_file_in_str(struct in_str *i, HFILE *fp)
2778{ 2821{
2779 memset(i, 0, sizeof(*i)); 2822 memset(i, 0, sizeof(*i));
2780 i->file = f; 2823 i->file = fp;
2781 /* i->p = NULL; */ 2824 /* i->p = NULL; */
2782} 2825}
2783 2826
@@ -7106,19 +7149,19 @@ static void parse_and_run_string(const char *s)
7106 //IF_HUSH_LINENO_VAR(G.lineno = sv;) 7149 //IF_HUSH_LINENO_VAR(G.lineno = sv;)
7107} 7150}
7108 7151
7109static void parse_and_run_file(FILE *f) 7152static void parse_and_run_file(HFILE *fp)
7110{ 7153{
7111 struct in_str input; 7154 struct in_str input;
7112 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) 7155 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;)
7113 7156
7114 IF_HUSH_LINENO_VAR(G.lineno = 1;) 7157 IF_HUSH_LINENO_VAR(G.lineno = 1;)
7115 setup_file_in_str(&input, f); 7158 setup_file_in_str(&input, fp);
7116 parse_and_run_stream(&input, ';'); 7159 parse_and_run_stream(&input, ';');
7117 IF_HUSH_LINENO_VAR(G.lineno = sv;) 7160 IF_HUSH_LINENO_VAR(G.lineno = sv;)
7118} 7161}
7119 7162
7120#if ENABLE_HUSH_TICK 7163#if ENABLE_HUSH_TICK
7121static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) 7164static int generate_stream_from_string(const char *s, pid_t *pid_p)
7122{ 7165{
7123 pid_t pid; 7166 pid_t pid;
7124 int channel[2]; 7167 int channel[2];
@@ -7220,7 +7263,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
7220 free(to_free); 7263 free(to_free);
7221# endif 7264# endif
7222 close(channel[1]); 7265 close(channel[1]);
7223 return remember_FILE(xfdopen_for_read(channel[0])); 7266 return channel[0];
7224} 7267}
7225 7268
7226/* Return code is exit status of the process that is run. */ 7269/* Return code is exit status of the process that is run. */
@@ -7230,7 +7273,7 @@ static int process_command_subs(o_string *dest, const char *s)
7230 pid_t pid; 7273 pid_t pid;
7231 int status, ch, eol_cnt; 7274 int status, ch, eol_cnt;
7232 7275
7233 fp = generate_stream_from_string(s, &pid); 7276 fp = xfdopen_for_read(generate_stream_from_string(s, &pid));
7234 7277
7235 /* Now send results of command back into original context */ 7278 /* Now send results of command back into original context */
7236 eol_cnt = 0; 7279 eol_cnt = 0;
@@ -7249,7 +7292,7 @@ static int process_command_subs(o_string *dest, const char *s)
7249 } 7292 }
7250 7293
7251 debug_printf("done reading from `cmd` pipe, closing it\n"); 7294 debug_printf("done reading from `cmd` pipe, closing it\n");
7252 fclose_and_forget(fp); 7295 fclose(fp);
7253 /* We need to extract exitcode. Test case 7296 /* We need to extract exitcode. Test case
7254 * "true; echo `sleep 1; false` $?" 7297 * "true; echo `sleep 1; false` $?"
7255 * should print 1 */ 7298 * should print 1 */
@@ -7427,20 +7470,17 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7427 return 1; /* "we closed fd" */ 7470 return 1; /* "we closed fd" */
7428 } 7471 }
7429#endif 7472#endif
7473 /* If this one of script's fds? */
7474 if (move_HFILEs_on_redirect(fd, avoid_fd))
7475 return 1; /* yes. "we closed fd" (actually moved it) */
7476
7430 /* Are we called from setup_redirects(squirrel==NULL)? Two cases: 7477 /* Are we called from setup_redirects(squirrel==NULL)? Two cases:
7431 * (1) Redirect in a forked child. No need to save FILEs' fds, 7478 * (1) Redirect in a forked child.
7432 * we aren't going to use them anymore, ok to trash. 7479 * (2) "exec 3>FILE".
7433 * (2) "exec 3>FILE". Bummer. We can save script FILEs' fds,
7434 * but how are we doing to restore them?
7435 * "fileno(fd) = new_fd" can't be done.
7436 */ 7480 */
7437 if (!sqp) 7481 if (!sqp)
7438 return 0; 7482 return 0;
7439 7483
7440 /* If this one of script's fds? */
7441 if (save_FILEs_on_redirect(fd, avoid_fd))
7442 return 1; /* yes. "we closed fd" */
7443
7444 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */ 7484 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
7445 *sqp = add_squirrel(*sqp, fd, avoid_fd); 7485 *sqp = add_squirrel(*sqp, fd, avoid_fd);
7446 return 0; /* "we did not close fd" */ 7486 return 0; /* "we did not close fd" */
@@ -7465,8 +7505,6 @@ static void restore_redirects(struct squirrel *sq)
7465 } 7505 }
7466 7506
7467 /* If moved, G.interactive_fd stays on new fd, not restoring it */ 7507 /* If moved, G.interactive_fd stays on new fd, not restoring it */
7468
7469 restore_redirected_FILEs();
7470} 7508}
7471 7509
7472#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 7510#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
@@ -7474,7 +7512,7 @@ static void close_saved_fds_and_FILE_fds(void)
7474{ 7512{
7475 if (G_interactive_fd) 7513 if (G_interactive_fd)
7476 close(G_interactive_fd); 7514 close(G_interactive_fd);
7477 close_all_FILE_list(); 7515 close_all_HFILE_list();
7478} 7516}
7479#endif 7517#endif
7480 7518
@@ -7487,7 +7525,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
7487 return 1; 7525 return 1;
7488#endif 7526#endif
7489 /* If this one of script's fds? */ 7527 /* If this one of script's fds? */
7490 if (fd_in_FILEs(fd)) 7528 if (fd_in_HFILEs(fd))
7491 return 1; 7529 return 1;
7492 7530
7493 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { 7531 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
@@ -7512,7 +7550,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
7512 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 7550 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
7513 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 7551 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
7514 * of the heredoc */ 7552 * of the heredoc */
7515 debug_printf_parse("set heredoc '%s'\n", 7553 debug_printf_redir("set heredoc '%s'\n",
7516 redir->rd_filename); 7554 redir->rd_filename);
7517 setup_heredoc(redir); 7555 setup_heredoc(redir);
7518 continue; 7556 continue;
@@ -7524,8 +7562,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
7524 int mode; 7562 int mode;
7525 7563
7526 if (redir->rd_filename == NULL) { 7564 if (redir->rd_filename == NULL) {
7527 /* 7565 /* Examples:
7528 * Examples:
7529 * "cmd >" (no filename) 7566 * "cmd >" (no filename)
7530 * "cmd > <file" (2nd redirect starts too early) 7567 * "cmd > <file" (2nd redirect starts too early)
7531 */ 7568 */
@@ -8706,7 +8743,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8706 } 8743 }
8707#endif 8744#endif
8708 /* { list } */ 8745 /* { list } */
8709 debug_printf("non-subshell group\n"); 8746 debug_printf_exec("non-subshell group\n");
8710 rcode = 1; /* exitcode if redir failed */ 8747 rcode = 1; /* exitcode if redir failed */
8711 if (setup_redirects(command, &squirrel) == 0) { 8748 if (setup_redirects(command, &squirrel) == 0) {
8712 debug_printf_exec(": run_list\n"); 8749 debug_printf_exec(": run_list\n");
@@ -9871,14 +9908,13 @@ int hush_main(int argc, char **argv)
9871 9908
9872 /* If we are login shell... */ 9909 /* If we are login shell... */
9873 if (flags & OPT_login) { 9910 if (flags & OPT_login) {
9874 FILE *input; 9911 HFILE *input;
9875 debug_printf("sourcing /etc/profile\n"); 9912 debug_printf("sourcing /etc/profile\n");
9876 input = fopen_for_read("/etc/profile"); 9913 input = hfopen("/etc/profile");
9877 if (input != NULL) { 9914 if (input != NULL) {
9878 remember_FILE(input);
9879 install_special_sighandlers(); 9915 install_special_sighandlers();
9880 parse_and_run_file(input); 9916 parse_and_run_file(input);
9881 fclose_and_forget(input); 9917 hfclose(input);
9882 } 9918 }
9883 /* bash: after sourcing /etc/profile, 9919 /* bash: after sourcing /etc/profile,
9884 * tries to source (in the given order): 9920 * tries to source (in the given order):
@@ -9891,7 +9927,7 @@ int hush_main(int argc, char **argv)
9891 9927
9892 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ 9928 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */
9893 if (!(flags & OPT_s) && G.global_argv[1]) { 9929 if (!(flags & OPT_s) && G.global_argv[1]) {
9894 FILE *input; 9930 HFILE *input;
9895 /* 9931 /*
9896 * "bash <script>" (which is never interactive (unless -i?)) 9932 * "bash <script>" (which is never interactive (unless -i?))
9897 * sources $BASH_ENV here (without scanning $PATH). 9933 * sources $BASH_ENV here (without scanning $PATH).
@@ -9902,13 +9938,15 @@ int hush_main(int argc, char **argv)
9902 G.global_argv++; 9938 G.global_argv++;
9903 debug_printf("running script '%s'\n", G.global_argv[0]); 9939 debug_printf("running script '%s'\n", G.global_argv[0]);
9904 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */ 9940 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */
9905 input = xfopen_for_read(G.global_argv[0]); 9941 input = hfopen(G.global_argv[0]);
9942 if (!input) {
9943 bb_simple_perror_msg_and_die(G.global_argv[0]);
9944 }
9906 xfunc_error_retval = 1; 9945 xfunc_error_retval = 1;
9907 remember_FILE(input);
9908 install_special_sighandlers(); 9946 install_special_sighandlers();
9909 parse_and_run_file(input); 9947 parse_and_run_file(input);
9910#if ENABLE_FEATURE_CLEAN_UP 9948#if ENABLE_FEATURE_CLEAN_UP
9911 fclose_and_forget(input); 9949 hfclose(input);
9912#endif 9950#endif
9913 goto final_return; 9951 goto final_return;
9914 } 9952 }
@@ -10038,7 +10076,7 @@ int hush_main(int argc, char **argv)
10038 ); 10076 );
10039 } 10077 }
10040 10078
10041 parse_and_run_file(stdin); 10079 parse_and_run_file(hfopen(NULL)); /* stdin */
10042 10080
10043 final_return: 10081 final_return:
10044 hush_exit(G.last_exitcode); 10082 hush_exit(G.last_exitcode);
@@ -10849,7 +10887,7 @@ Test that VAR is a valid variable name?
10849static int FAST_FUNC builtin_source(char **argv) 10887static int FAST_FUNC builtin_source(char **argv)
10850{ 10888{
10851 char *arg_path, *filename; 10889 char *arg_path, *filename;
10852 FILE *input; 10890 HFILE *input;
10853 save_arg_t sv; 10891 save_arg_t sv;
10854 char *args_need_save; 10892 char *args_need_save;
10855#if ENABLE_HUSH_FUNCTIONS 10893#if ENABLE_HUSH_FUNCTIONS
@@ -10873,10 +10911,10 @@ static int FAST_FUNC builtin_source(char **argv)
10873 return EXIT_FAILURE; 10911 return EXIT_FAILURE;
10874 } 10912 }
10875 } 10913 }
10876 input = remember_FILE(fopen_or_warn(filename, "r")); 10914 input = hfopen(filename);
10877 free(arg_path); 10915 free(arg_path);
10878 if (!input) { 10916 if (!input) {
10879 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 10917 bb_perror_msg("%s", filename);
10880 /* POSIX: non-interactive shell should abort here, 10918 /* POSIX: non-interactive shell should abort here,
10881 * not merely fail. So far no one complained :) 10919 * not merely fail. So far no one complained :)
10882 */ 10920 */
@@ -10895,7 +10933,7 @@ static int FAST_FUNC builtin_source(char **argv)
10895 /* "false; . ./empty_line; echo Zero:$?" should print 0 */ 10933 /* "false; . ./empty_line; echo Zero:$?" should print 0 */
10896 G.last_exitcode = 0; 10934 G.last_exitcode = 0;
10897 parse_and_run_file(input); 10935 parse_and_run_file(input);
10898 fclose_and_forget(input); 10936 hfclose(input);
10899 10937
10900 if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */ 10938 if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
10901 restore_G_args(&sv, argv); 10939 restore_G_args(&sv, argv);
diff --git a/shell/hush_test/hush-heredoc/heredocB.right b/shell/hush_test/hush-heredoc/heredocB.right
new file mode 100644
index 000000000..43ba0b4f9
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocB.right
@@ -0,0 +1,3 @@
1one - alpha
2two - beta
3three - gamma
diff --git a/shell/hush_test/hush-heredoc/heredocB.tests b/shell/hush_test/hush-heredoc/heredocB.tests
new file mode 100755
index 000000000..45ea4687f
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocB.tests
@@ -0,0 +1,12 @@
1while read line1; do
2 read line2 <&3
3 echo $line1 - $line2
4done <<EOF1 3<<EOF2
5one
6two
7three
8EOF1
9alpha
10beta
11gamma
12EOF2
diff --git a/shell/hush_test/hush-redir/redir_script.tests b/shell/hush_test/hush-redir/redir_script.tests
index 740daa461..a8d93ce4f 100755
--- a/shell/hush_test/hush-redir/redir_script.tests
+++ b/shell/hush_test/hush-redir/redir_script.tests
@@ -27,6 +27,10 @@ test x"$fds1" = x"$fds" \
27test x"$fds1" = x" 10>&- 3>&-" && \ 27test x"$fds1" = x" 10>&- 3>&-" && \
28test x"$fds" = x" 11>&- 3>&-" \ 28test x"$fds" = x" 11>&- 3>&-" \
29&& { echo "Ok: script fd is not closed"; exit 0; } 29&& { echo "Ok: script fd is not closed"; exit 0; }
30# or we see that fd 3 moved to fd 10:
31test x"$fds1" = x" 3>&- 4>&-" && \
32test x"$fds" = x" 10>&- 3>&-" \
33&& { echo "Ok: script fd is not closed"; exit 0; }
30 34
31echo "Bug: script fd is closed" 35echo "Bug: script fd is closed"
32echo "fds1:$fds1" 36echo "fds1:$fds1"