aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-06-03 04:28:28 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-06-03 04:28:28 +0200
commit08d8b3cee1329d390f91bce419e2b4dadf484952 (patch)
tree4c8d4ed50792a9f1712dd914e7fcef62234b5f49 /shell
parent3e47cfec90fbe358692b3b960f7fa2303e465c2f (diff)
downloadbusybox-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.c35
-rw-r--r--shell/ash_test/ash-signals/signal5.right4
-rwxr-xr-xshell/ash_test/ash-signals/signal5.tests2
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 @@
1sleeping for 3 sec 1Sleeping
2sleeping for 2 sec 2Sleeping
3Waiting 3Waiting
42 sec passed, sending USR1 to parent 42 sec passed, sending USR1 to parent
5USR1 received 5USR1 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 @@
1trap "echo USR1 received" USR1 1trap "echo USR1 received" USR1
2stub() { 2stub() {
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 $$