aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c278
1 files changed, 200 insertions, 78 deletions
diff --git a/shell/hush.c b/shell/hush.c
index d0225edb9..9f946d82f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1454,11 +1454,11 @@ static int fcntl_F_DUPFD(int fd, int avoid_fd)
1454 return newfd; 1454 return newfd;
1455} 1455}
1456 1456
1457static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd) 1457static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1458{ 1458{
1459 int newfd; 1459 int newfd;
1460 repeat: 1460 repeat:
1461 newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, avoid_fd + 1); 1461 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1462 if (newfd < 0) { 1462 if (newfd < 0) {
1463 if (errno == EBUSY) 1463 if (errno == EBUSY)
1464 goto repeat; 1464 goto repeat;
@@ -1469,6 +1469,8 @@ static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd)
1469 return fd; 1469 return fd;
1470 xfunc_die(); 1470 xfunc_die();
1471 } 1471 }
1472 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1473 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1472 close(fd); 1474 close(fd);
1473 return newfd; 1475 return newfd;
1474} 1476}
@@ -1507,7 +1509,7 @@ static int save_FILEs_on_redirect(int fd, int avoid_fd)
1507 while (fl) { 1509 while (fl) {
1508 if (fd == fl->fd) { 1510 if (fd == fl->fd) {
1509 /* We use it only on script files, they are all CLOEXEC */ 1511 /* We use it only on script files, they are all CLOEXEC */
1510 fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC, avoid_fd); 1512 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1511 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd); 1513 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1512 return 1; 1514 return 1;
1513 } 1515 }
@@ -1544,6 +1546,16 @@ static void close_all_FILE_list(void)
1544 } 1546 }
1545} 1547}
1546#endif 1548#endif
1549static int fd_in_FILEs(int fd)
1550{
1551 struct FILE_list *fl = G.FILE_list;
1552 while (fl) {
1553 if (fl->fd == fd)
1554 return 1;
1555 fl = fl->next;
1556 }
1557 return 0;
1558}
1547 1559
1548 1560
1549/* Helpers for setting new $n and restoring them back 1561/* Helpers for setting new $n and restoring them back
@@ -4001,24 +4013,34 @@ static char *fetch_till_str(o_string *as_string,
4001 ch = i_getch(input); 4013 ch = i_getch(input);
4002 if (ch != EOF) 4014 if (ch != EOF)
4003 nommu_addchr(as_string, ch); 4015 nommu_addchr(as_string, ch);
4004 if ((ch == '\n' || ch == EOF) 4016 if (ch == '\n' || ch == EOF) {
4005 && ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') 4017 check_heredoc_end:
4006 ) { 4018 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
4007 if (strcmp(heredoc.data + past_EOL, word) == 0) { 4019 if (strcmp(heredoc.data + past_EOL, word) == 0) {
4008 heredoc.data[past_EOL] = '\0'; 4020 heredoc.data[past_EOL] = '\0';
4009 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); 4021 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data);
4010 return heredoc.data; 4022 return heredoc.data;
4011 } 4023 }
4012 while (ch == '\n') { 4024 if (ch == '\n') {
4013 o_addchr(&heredoc, ch); 4025 /* This is a new line.
4014 prev = ch; 4026 * Remember position and backslash-escaping status.
4027 */
4028 o_addchr(&heredoc, ch);
4029 prev = ch;
4015 jump_in: 4030 jump_in:
4016 past_EOL = heredoc.length; 4031 past_EOL = heredoc.length;
4017 do { 4032 /* Get 1st char of next line, possibly skipping leading tabs */
4018 ch = i_getch(input); 4033 do {
4019 if (ch != EOF) 4034 ch = i_getch(input);
4020 nommu_addchr(as_string, ch); 4035 if (ch != EOF)
4021 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t'); 4036 nommu_addchr(as_string, ch);
4037 } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
4038 /* If this immediately ended the line,
4039 * go back to end-of-line checks.
4040 */
4041 if (ch == '\n')
4042 goto check_heredoc_end;
4043 }
4022 } 4044 }
4023 } 4045 }
4024 if (ch == EOF) { 4046 if (ch == EOF) {
@@ -6674,9 +6696,9 @@ static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, in
6674static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) 6696static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6675{ 6697{
6676 int moved_to; 6698 int moved_to;
6677 int i = 0; 6699 int i;
6678 6700
6679 if (sq) while (sq[i].orig_fd >= 0) { 6701 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
6680 /* If we collide with an already moved fd... */ 6702 /* If we collide with an already moved fd... */
6681 if (fd == sq[i].moved_to) { 6703 if (fd == sq[i].moved_to) {
6682 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); 6704 sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd);
@@ -6690,7 +6712,6 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6690 debug_printf_redir("redirect_fd %d: already moved\n", fd); 6712 debug_printf_redir("redirect_fd %d: already moved\n", fd);
6691 return sq; 6713 return sq;
6692 } 6714 }
6693 i++;
6694 } 6715 }
6695 6716
6696 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ 6717 /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
@@ -6701,18 +6722,41 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6701 return append_squirrel(sq, i, fd, moved_to); 6722 return append_squirrel(sq, i, fd, moved_to);
6702} 6723}
6703 6724
6725static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
6726{
6727 int i;
6728
6729 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
6730 /* If we collide with an already moved fd... */
6731 if (fd == sq[i].orig_fd) {
6732 /* Examples:
6733 * "echo 3>FILE 3>&- 3>FILE"
6734 * "echo 3>&- 3>FILE"
6735 * No need for last redirect to insert
6736 * another "need to close 3" indicator.
6737 */
6738 debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
6739 return sq;
6740 }
6741 }
6742
6743 debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd);
6744 return append_squirrel(sq, i, fd, -1);
6745}
6746
6704/* fd: redirect wants this fd to be used (e.g. 3>file). 6747/* fd: redirect wants this fd to be used (e.g. 3>file).
6705 * Move all conflicting internally used fds, 6748 * Move all conflicting internally used fds,
6706 * and remember them so that we can restore them later. 6749 * and remember them so that we can restore them later.
6707 */ 6750 */
6708static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) 6751static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
6709{ 6752{
6710 if (avoid_fd < 9) /* the important case here is that it can be -1 */ 6753 if (avoid_fd < 9) /* the important case here is that it can be -1 */
6711 avoid_fd = 9; 6754 avoid_fd = 9;
6712 6755
6713#if ENABLE_HUSH_INTERACTIVE 6756#if ENABLE_HUSH_INTERACTIVE
6714 if (fd != 0 && fd == G.interactive_fd) { 6757 if (fd == G.interactive_fd) {
6715 G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC, avoid_fd); 6758 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
6759 G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd);
6716 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); 6760 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd);
6717 return 1; /* "we closed fd" */ 6761 return 1; /* "we closed fd" */
6718 } 6762 }
@@ -6738,10 +6782,9 @@ static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
6738 6782
6739static void restore_redirects(struct squirrel *sq) 6783static void restore_redirects(struct squirrel *sq)
6740{ 6784{
6741
6742 if (sq) { 6785 if (sq) {
6743 int i = 0; 6786 int i;
6744 while (sq[i].orig_fd >= 0) { 6787 for (i = 0; sq[i].orig_fd >= 0; i++) {
6745 if (sq[i].moved_to >= 0) { 6788 if (sq[i].moved_to >= 0) {
6746 /* We simply die on error */ 6789 /* We simply die on error */
6747 debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd); 6790 debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd);
@@ -6751,7 +6794,6 @@ static void restore_redirects(struct squirrel *sq)
6751 debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd); 6794 debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd);
6752 close(sq[i].orig_fd); 6795 close(sq[i].orig_fd);
6753 } 6796 }
6754 i++;
6755 } 6797 }
6756 free(sq); 6798 free(sq);
6757 } 6799 }
@@ -6761,17 +6803,47 @@ static void restore_redirects(struct squirrel *sq)
6761 restore_redirected_FILEs(); 6803 restore_redirected_FILEs();
6762} 6804}
6763 6805
6806#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
6807static void close_saved_fds_and_FILE_fds(void)
6808{
6809 if (G_interactive_fd)
6810 close(G_interactive_fd);
6811 close_all_FILE_list();
6812}
6813#endif
6814
6815static int internally_opened_fd(int fd, struct squirrel *sq)
6816{
6817 int i;
6818
6819#if ENABLE_HUSH_INTERACTIVE
6820 if (fd == G.interactive_fd)
6821 return 1;
6822#endif
6823 /* If this one of script's fds? */
6824 if (fd_in_FILEs(fd))
6825 return 1;
6826
6827 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
6828 if (fd == sq[i].moved_to)
6829 return 1;
6830 }
6831 return 0;
6832}
6833
6764/* squirrel != NULL means we squirrel away copies of stdin, stdout, 6834/* squirrel != NULL means we squirrel away copies of stdin, stdout,
6765 * and stderr if they are redirected. */ 6835 * and stderr if they are redirected. */
6766static int setup_redirects(struct command *prog, struct squirrel **sqp) 6836static int setup_redirects(struct command *prog, struct squirrel **sqp)
6767{ 6837{
6768 int openfd, mode;
6769 struct redir_struct *redir; 6838 struct redir_struct *redir;
6770 6839
6771 for (redir = prog->redirects; redir; redir = redir->next) { 6840 for (redir = prog->redirects; redir; redir = redir->next) {
6841 int newfd;
6842 int closed;
6843
6772 if (redir->rd_type == REDIRECT_HEREDOC2) { 6844 if (redir->rd_type == REDIRECT_HEREDOC2) {
6773 /* "rd_fd<<HERE" case */ 6845 /* "rd_fd<<HERE" case */
6774 save_fds_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 6846 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
6775 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 6847 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
6776 * of the heredoc */ 6848 * of the heredoc */
6777 debug_printf_parse("set heredoc '%s'\n", 6849 debug_printf_parse("set heredoc '%s'\n",
@@ -6783,6 +6855,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6783 if (redir->rd_dup == REDIRFD_TO_FILE) { 6855 if (redir->rd_dup == REDIRFD_TO_FILE) {
6784 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */ 6856 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */
6785 char *p; 6857 char *p;
6858 int mode;
6859
6786 if (redir->rd_filename == NULL) { 6860 if (redir->rd_filename == NULL) {
6787 /* 6861 /*
6788 * Examples: 6862 * Examples:
@@ -6794,9 +6868,9 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6794 } 6868 }
6795 mode = redir_table[redir->rd_type].mode; 6869 mode = redir_table[redir->rd_type].mode;
6796 p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1); 6870 p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1);
6797 openfd = open_or_warn(p, mode); 6871 newfd = open_or_warn(p, mode);
6798 free(p); 6872 free(p);
6799 if (openfd < 0) { 6873 if (newfd < 0) {
6800 /* Error message from open_or_warn can be lost 6874 /* Error message from open_or_warn can be lost
6801 * if stderr has been redirected, but bash 6875 * if stderr has been redirected, but bash
6802 * and ash both lose it as well 6876 * and ash both lose it as well
@@ -6804,40 +6878,52 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6804 */ 6878 */
6805 return 1; 6879 return 1;
6806 } 6880 }
6807 if (openfd == redir->rd_fd && sqp) { 6881 if (newfd == redir->rd_fd && sqp) {
6808 /* open() gave us precisely the fd we wanted. 6882 /* open() gave us precisely the fd we wanted.
6809 * This means that this fd was not busy 6883 * This means that this fd was not busy
6810 * (not opened to anywhere). 6884 * (not opened to anywhere).
6811 * Remember to close it on restore: 6885 * Remember to close it on restore:
6812 */ 6886 */
6813 struct squirrel *sq = *sqp; 6887 *sqp = add_squirrel_closed(*sqp, newfd);
6814 int i = 0; 6888 debug_printf_redir("redir to previously closed fd %d\n", newfd);
6815 if (sq) while (sq[i].orig_fd >= 0)
6816 i++;
6817 *sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */
6818 debug_printf_redir("redir to previously closed fd %d\n", openfd);
6819 } 6889 }
6820 } else { 6890 } else {
6821 /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */ 6891 /* "rd_fd>&rd_dup" or "rd_fd>&-" case */
6822 openfd = redir->rd_dup; 6892 newfd = redir->rd_dup;
6823 } 6893 }
6824 6894
6825 if (openfd != redir->rd_fd) { 6895 if (newfd == redir->rd_fd)
6826 int closed = save_fds_on_redirect(redir->rd_fd, /*avoid:*/ openfd, sqp); 6896 continue;
6827 if (openfd == REDIRFD_CLOSE) { 6897
6828 /* "rd_fd >&-" means "close me" */ 6898 /* if "N>FILE": move newfd to redir->rd_fd */
6829 if (!closed) { 6899 /* if "N>&M": dup newfd to redir->rd_fd */
6830 /* ^^^ optimization: saving may already 6900 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */
6831 * have closed it. If not... */ 6901
6832 close(redir->rd_fd); 6902 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp);
6833 } 6903 if (newfd == REDIRFD_CLOSE) {
6834 } else { 6904 /* "N>&-" means "close me" */
6835 xdup2(openfd, redir->rd_fd); 6905 if (!closed) {
6836 if (redir->rd_dup == REDIRFD_TO_FILE) 6906 /* ^^^ optimization: saving may already
6837 /* "rd_fd > FILE" */ 6907 * have closed it. If not... */
6838 close(openfd); 6908 close(redir->rd_fd);
6839 /* else: "rd_fd > rd_dup" */ 6909 }
6910 /* Sometimes we do another close on restore, getting EBADF.
6911 * Consider "echo 3>FILE 3>&-"
6912 * first redirect remembers "need to close 3",
6913 * and second redirect closes 3! Restore code then closes 3 again.
6914 */
6915 } else {
6916 /* if newfd is a script fd or saved fd, simulate EBADF */
6917 if (internally_opened_fd(newfd, sqp ? *sqp : NULL)) {
6918 //errno = EBADF;
6919 //bb_perror_msg_and_die("can't duplicate file descriptor");
6920 newfd = -1; /* same effect as code above */
6840 } 6921 }
6922 xdup2(newfd, redir->rd_fd);
6923 if (redir->rd_dup == REDIRFD_TO_FILE)
6924 /* "rd_fd > FILE" */
6925 close(newfd);
6926 /* else: "rd_fd > rd_dup" */
6841 } 6927 }
6842 } 6928 }
6843 return 0; 6929 return 0;
@@ -7004,11 +7090,34 @@ static void exec_function(char ***to_free,
7004 argv[0] = G.global_argv[0]; 7090 argv[0] = G.global_argv[0];
7005 G.global_argv = argv; 7091 G.global_argv = argv;
7006 G.global_argc = n = 1 + string_array_len(argv + 1); 7092 G.global_argc = n = 1 + string_array_len(argv + 1);
7093
7094// Example when we are here: "cmd | func"
7095// func will run with saved-redirect fds open.
7096// $ f() { echo /proc/self/fd/*; }
7097// $ true | f
7098// /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /proc/self/fd/3
7099// stdio^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G_interactive_fd^ DIR fd for glob
7100// Same in script:
7101// $ . ./SCRIPT
7102// /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /proc/self/fd/3 /proc/self/fd/4
7103// stdio^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ G_interactive_fd^ opened ./SCRIPT DIR fd for glob
7104// They are CLOEXEC so external programs won't see them, but
7105// for "more correctness" we might want to close those extra fds here:
7106//? close_saved_fds_and_FILE_fds();
7107
7108 /* "we are in function, ok to use return" */
7109 G_flag_return_in_progress = -1;
7110 IF_HUSH_LOCAL(G.func_nest_level++;)
7111
7007 /* On MMU, funcp->body is always non-NULL */ 7112 /* On MMU, funcp->body is always non-NULL */
7008 n = run_list(funcp->body); 7113 n = run_list(funcp->body);
7009 fflush_all(); 7114 fflush_all();
7010 _exit(n); 7115 _exit(n);
7011# else 7116# else
7117//? close_saved_fds_and_FILE_fds();
7118
7119//TODO: check whether "true | func_with_return" works
7120
7012 re_execute_shell(to_free, 7121 re_execute_shell(to_free,
7013 funcp->body_as_string, 7122 funcp->body_as_string,
7014 G.global_argv[0], 7123 G.global_argv[0],
@@ -7028,9 +7137,7 @@ static int run_function(const struct function *funcp, char **argv)
7028 /* "we are in function, ok to use return" */ 7137 /* "we are in function, ok to use return" */
7029 sv_flg = G_flag_return_in_progress; 7138 sv_flg = G_flag_return_in_progress;
7030 G_flag_return_in_progress = -1; 7139 G_flag_return_in_progress = -1;
7031# if ENABLE_HUSH_LOCAL 7140 IF_HUSH_LOCAL(G.func_nest_level++;)
7032 G.func_nest_level++;
7033# endif
7034 7141
7035 /* On MMU, funcp->body is always non-NULL */ 7142 /* On MMU, funcp->body is always non-NULL */
7036# if !BB_MMU 7143# if !BB_MMU
@@ -7094,6 +7201,7 @@ static void exec_builtin(char ***to_free,
7094#if BB_MMU 7201#if BB_MMU
7095 int rcode; 7202 int rcode;
7096 fflush_all(); 7203 fflush_all();
7204//? close_saved_fds_and_FILE_fds();
7097 rcode = x->b_function(argv); 7205 rcode = x->b_function(argv);
7098 fflush_all(); 7206 fflush_all();
7099 _exit(rcode); 7207 _exit(rcode);
@@ -7215,6 +7323,16 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7215 goto skip; 7323 goto skip;
7216#endif 7324#endif
7217 7325
7326#if ENABLE_HUSH_FUNCTIONS
7327 /* Check if the command matches any functions (this goes before bltins) */
7328 {
7329 const struct function *funcp = find_function(argv[0]);
7330 if (funcp) {
7331 exec_function(&nommu_save->argv_from_re_execing, funcp, argv);
7332 }
7333 }
7334#endif
7335
7218 /* Check if the command matches any of the builtins. 7336 /* Check if the command matches any of the builtins.
7219 * Depending on context, this might be redundant. But it's 7337 * Depending on context, this might be redundant. But it's
7220 * easier to waste a few CPU cycles than it is to figure out 7338 * easier to waste a few CPU cycles than it is to figure out
@@ -7231,15 +7349,6 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7231 exec_builtin(&nommu_save->argv_from_re_execing, x, argv); 7349 exec_builtin(&nommu_save->argv_from_re_execing, x, argv);
7232 } 7350 }
7233 } 7351 }
7234#if ENABLE_HUSH_FUNCTIONS
7235 /* Check if the command matches any functions */
7236 {
7237 const struct function *funcp = find_function(argv[0]);
7238 if (funcp) {
7239 exec_function(&nommu_save->argv_from_re_execing, funcp, argv);
7240 }
7241 }
7242#endif
7243 7352
7244#if ENABLE_FEATURE_SH_STANDALONE 7353#if ENABLE_FEATURE_SH_STANDALONE
7245 /* Check if the command matches any busybox applets */ 7354 /* Check if the command matches any busybox applets */
@@ -7248,8 +7357,12 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
7248 if (a >= 0) { 7357 if (a >= 0) {
7249# if BB_MMU /* see above why on NOMMU it is not allowed */ 7358# if BB_MMU /* see above why on NOMMU it is not allowed */
7250 if (APPLET_IS_NOEXEC(a)) { 7359 if (APPLET_IS_NOEXEC(a)) {
7251 /* Do not leak open fds from opened script files etc */ 7360 /* Do not leak open fds from opened script files etc.
7252 close_all_FILE_list(); 7361 * Testcase: interactive "ls -l /proc/self/fd"
7362 * should not show tty fd open.
7363 */
7364 close_saved_fds_and_FILE_fds();
7365//FIXME: should also close saved redir fds
7253 debug_printf_exec("running applet '%s'\n", argv[0]); 7366 debug_printf_exec("running applet '%s'\n", argv[0]);
7254 run_applet_no_and_exit(a, argv[0], argv); 7367 run_applet_no_and_exit(a, argv[0], argv);
7255 } 7368 }
@@ -7886,12 +7999,13 @@ static NOINLINE int run_pipe(struct pipe *pi)
7886 return G.last_exitcode; 7999 return G.last_exitcode;
7887 } 8000 }
7888 8001
7889 x = find_builtin(argv_expanded[0]);
7890#if ENABLE_HUSH_FUNCTIONS 8002#if ENABLE_HUSH_FUNCTIONS
7891 funcp = NULL; 8003 /* Check if argv[0] matches any functions (this goes before bltins) */
7892 if (!x) 8004 funcp = find_function(argv_expanded[0]);
7893 funcp = find_function(argv_expanded[0]);
7894#endif 8005#endif
8006 x = NULL;
8007 if (!funcp)
8008 x = find_builtin(argv_expanded[0]);
7895 if (x || funcp) { 8009 if (x || funcp) {
7896 if (!funcp) { 8010 if (!funcp) {
7897 if (x->b_function == builtin_exec && argv_expanded[1] == NULL) { 8011 if (x->b_function == builtin_exec && argv_expanded[1] == NULL) {
@@ -9158,6 +9272,14 @@ static int FAST_FUNC builtin_exec(char **argv)
9158 if (G_saved_tty_pgrp && getpid() == G.root_pid) 9272 if (G_saved_tty_pgrp && getpid() == G.root_pid)
9159 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); 9273 tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp);
9160 9274
9275 /* Saved-redirect fds, script fds and G_interactive_fd are still
9276 * open here. However, they are all CLOEXEC, and execv below
9277 * closes them. Try interactive "exec ls -l /proc/self/fd",
9278 * it should show no extra open fds in the "ls" process.
9279 * If we'd try to run builtins/NOEXECs, this would need improving.
9280 */
9281 //close_saved_fds_and_FILE_fds();
9282
9161 /* TODO: if exec fails, bash does NOT exit! We do. 9283 /* TODO: if exec fails, bash does NOT exit! We do.
9162 * We'll need to undo trap cleanup (it's inside execvp_or_die) 9284 * We'll need to undo trap cleanup (it's inside execvp_or_die)
9163 * and tcsetpgrp, and this is inherently racy. 9285 * and tcsetpgrp, and this is inherently racy.