diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-03 04:28:28 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-03 04:28:28 +0200 |
commit | 08d8b3cee1329d390f91bce419e2b4dadf484952 (patch) | |
tree | 4c8d4ed50792a9f1712dd914e7fcef62234b5f49 /shell | |
parent | 3e47cfec90fbe358692b3b960f7fa2303e465c2f (diff) | |
download | busybox-w32-08d8b3cee1329d390f91bce419e2b4dadf484952.tar.gz busybox-w32-08d8b3cee1329d390f91bce419e2b4dadf484952.tar.bz2 busybox-w32-08d8b3cee1329d390f91bce419e2b4dadf484952.zip |
ash: fix redirection of fd 0 in scripts are sourced from interactive ash
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 35 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/signal5.right | 4 | ||||
-rwxr-xr-x | shell/ash_test/ash-signals/signal5.tests | 2 |
3 files changed, 28 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c index 08ad0f451..067feb13d 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -1070,7 +1070,7 @@ ash_vmsg(const char *msg, va_list ap) | |||
1070 | if (commandname) { | 1070 | if (commandname) { |
1071 | if (strcmp(arg0, commandname)) | 1071 | if (strcmp(arg0, commandname)) |
1072 | fprintf(stderr, "%s: ", commandname); | 1072 | fprintf(stderr, "%s: ", commandname); |
1073 | if (!iflag || g_parsefile->fd) | 1073 | if (!iflag || g_parsefile->fd > 0) |
1074 | fprintf(stderr, "line %d: ", startlinno); | 1074 | fprintf(stderr, "line %d: ", startlinno); |
1075 | } | 1075 | } |
1076 | vfprintf(stderr, msg, ap); | 1076 | vfprintf(stderr, msg, ap); |
@@ -5063,15 +5063,26 @@ static int is_hidden_fd(struct redirtab *rp, int fd) | |||
5063 | 5063 | ||
5064 | if (fd == -1) | 5064 | if (fd == -1) |
5065 | return 0; | 5065 | return 0; |
5066 | /* Check open scripts' fds */ | ||
5066 | pf = g_parsefile; | 5067 | pf = g_parsefile; |
5067 | while (pf) { | 5068 | while (pf) { |
5068 | if (fd == pf->fd) { | 5069 | /* We skip fd == 0 case because of the following case: |
5070 | * $ ash # running ash interactively | ||
5071 | * $ . ./script.sh | ||
5072 | * and in script.sh: "exec 9>&0". | ||
5073 | * Even though top-level fd _is_ 0, | ||
5074 | * it's still ok to use it: "read" builtin uses it, | ||
5075 | * why should we cripple "exec" builtin? | ||
5076 | */ | ||
5077 | if (pf->fd > 0 && fd == pf->fd) { | ||
5069 | return 1; | 5078 | return 1; |
5070 | } | 5079 | } |
5071 | pf = pf->prev; | 5080 | pf = pf->prev; |
5072 | } | 5081 | } |
5082 | |||
5073 | if (!rp) | 5083 | if (!rp) |
5074 | return 0; | 5084 | return 0; |
5085 | /* Check saved fds of redirects */ | ||
5075 | fd |= COPYFD_RESTORE; | 5086 | fd |= COPYFD_RESTORE; |
5076 | for (i = 0; i < rp->pair_count; i++) { | 5087 | for (i = 0; i < rp->pair_count; i++) { |
5077 | if (rp->two_fd[i].copy == fd) { | 5088 | if (rp->two_fd[i].copy == fd) { |
@@ -5084,9 +5095,7 @@ static int is_hidden_fd(struct redirtab *rp, int fd) | |||
5084 | /* | 5095 | /* |
5085 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, | 5096 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, |
5086 | * old file descriptors are stashed away so that the redirection can be | 5097 | * old file descriptors are stashed away so that the redirection can be |
5087 | * undone by calling popredir. If the REDIR_BACKQ flag is set, then the | 5098 | * undone by calling popredir. |
5088 | * standard output, and the standard error if it becomes a duplicate of | ||
5089 | * stdout, is saved in memory. | ||
5090 | */ | 5099 | */ |
5091 | /* flags passed to redirect */ | 5100 | /* flags passed to redirect */ |
5092 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ | 5101 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ |
@@ -5132,13 +5141,15 @@ redirect(union node *redir, int flags) | |||
5132 | } | 5141 | } |
5133 | 5142 | ||
5134 | do { | 5143 | do { |
5144 | int right_fd = -1; | ||
5135 | fd = redir->nfile.fd; | 5145 | fd = redir->nfile.fd; |
5136 | if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { | 5146 | if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { |
5137 | int right_fd = redir->ndup.dupfd; | 5147 | right_fd = redir->ndup.dupfd; |
5148 | //bb_error_msg("doing %d > %d", fd, right_fd); | ||
5138 | /* redirect from/to same file descriptor? */ | 5149 | /* redirect from/to same file descriptor? */ |
5139 | if (right_fd == fd) | 5150 | if (right_fd == fd) |
5140 | continue; | 5151 | continue; |
5141 | /* echo >&10 and 10 is a fd opened to the sh script? */ | 5152 | /* "echo >&10" and 10 is a fd opened to a sh script? */ |
5142 | if (is_hidden_fd(sv, right_fd)) { | 5153 | if (is_hidden_fd(sv, right_fd)) { |
5143 | errno = EBADF; /* as if it is closed */ | 5154 | errno = EBADF; /* as if it is closed */ |
5144 | ash_msg_and_raise_error("%d: %m", right_fd); | 5155 | ash_msg_and_raise_error("%d: %m", right_fd); |
@@ -5160,7 +5171,10 @@ redirect(union node *redir, int flags) | |||
5160 | #endif | 5171 | #endif |
5161 | if (need_to_remember(sv, fd)) { | 5172 | if (need_to_remember(sv, fd)) { |
5162 | /* Copy old descriptor */ | 5173 | /* Copy old descriptor */ |
5163 | i = fcntl(fd, F_DUPFD, 10); | 5174 | /* Careful to not accidentally "save" |
5175 | * to the same fd as right side fd in N>&M */ | ||
5176 | int minfd = right_fd < 10 ? 10 : right_fd + 1; | ||
5177 | i = fcntl(fd, F_DUPFD, minfd); | ||
5164 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds | 5178 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
5165 | * are closed in popredir() in the child, preventing them from leaking | 5179 | * are closed in popredir() in the child, preventing them from leaking |
5166 | * into child. (popredir() also cleans up the mess in case of failures) | 5180 | * into child. (popredir() also cleans up the mess in case of failures) |
@@ -12994,8 +13008,9 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
12994 | * Ensure we don't falsely claim that 0 (stdin) | 13008 | * Ensure we don't falsely claim that 0 (stdin) |
12995 | * is one of stacked source fds. | 13009 | * is one of stacked source fds. |
12996 | * Testcase: ash -c 'exec 1>&0' must not complain. */ | 13010 | * Testcase: ash -c 'exec 1>&0' must not complain. */ |
12997 | if (!sflag) | 13011 | // if (!sflag) g_parsefile->fd = -1; |
12998 | g_parsefile->fd = -1; | 13012 | // ^^ not necessary since now we special-case fd 0 |
13013 | // in is_hidden_fd() to not be considered "hidden fd" | ||
12999 | evalstring(minusc, 0); | 13014 | evalstring(minusc, 0); |
13000 | } | 13015 | } |
13001 | 13016 | ||
diff --git a/shell/ash_test/ash-signals/signal5.right b/shell/ash_test/ash-signals/signal5.right index 162f56bbc..7cfd4110e 100644 --- a/shell/ash_test/ash-signals/signal5.right +++ b/shell/ash_test/ash-signals/signal5.right | |||
@@ -1,5 +1,5 @@ | |||
1 | sleeping for 3 sec | 1 | Sleeping |
2 | sleeping for 2 sec | 2 | Sleeping |
3 | Waiting | 3 | Waiting |
4 | 2 sec passed, sending USR1 to parent | 4 | 2 sec passed, sending USR1 to parent |
5 | USR1 received | 5 | USR1 received |
diff --git a/shell/ash_test/ash-signals/signal5.tests b/shell/ash_test/ash-signals/signal5.tests index 371120e95..179bcdd80 100755 --- a/shell/ash_test/ash-signals/signal5.tests +++ b/shell/ash_test/ash-signals/signal5.tests | |||
@@ -1,6 +1,6 @@ | |||
1 | trap "echo USR1 received" USR1 | 1 | trap "echo USR1 received" USR1 |
2 | stub() { | 2 | stub() { |
3 | echo "sleeping for $1 sec" | 3 | echo "Sleeping" |
4 | sleep $1 | 4 | sleep $1 |
5 | echo "$1 sec passed, sending USR1 to parent" | 5 | echo "$1 sec passed, sending USR1 to parent" |
6 | kill -USR1 $$ | 6 | kill -USR1 $$ |