ash: fix bug where redirection of closed fd was leaving it open afterwards.

redirect                                             983    1024     +41
bb_echo                                              276     301     +25
popredir                                             118     132     +14
evalcommand                                         1163    1176     +13
bbunpack                                             358     366      +8
echocmd                                               13       5      -8
echo_main                                             13       5      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/2 up/down: 101/-16)            Total: 85 bytes
   text    data     bss     dec     hex filename
 774999     962    9236  785197   bfb2d busybox_old
 775084     962    9236  785282   bfb82 busybox_unstripped

diff --git a/shell/ash.c b/shell/ash.c
index bb930f5..4113ce8 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4567,6 +4567,7 @@
  */
 
 #define EMPTY -2                /* marks an unused slot in redirtab */
+#define CLOSED -3               /* marks a slot of previously-closed fd */
 #ifndef PIPE_BUF
 # define PIPESIZE 4096          /* amount of buffering in a pipe */
 #else
@@ -4791,7 +4792,7 @@
 	int i;
 	int fd;
 	int newfd;
-	int *p;
+
 	nullredirs++;
 	if (!redir) {
 		return;
@@ -4799,15 +4800,13 @@
 	sv = NULL;
 	INT_OFF;
 	if (flags & REDIR_PUSH) {
-		struct redirtab *q;
-		q = ckmalloc(sizeof(struct redirtab));
-		q->next = redirlist;
-		redirlist = q;
-		q->nullredirs = nullredirs - 1;
+		sv = ckmalloc(sizeof(*sv));
+		sv->next = redirlist;
+		redirlist = sv;
+		sv->nullredirs = nullredirs - 1;
 		for (i = 0; i < 10; i++)
-			q->renamed[i] = EMPTY;
+			sv->renamed[i] = EMPTY;
 		nullredirs = 0;
-		sv = q;
 	}
 	n = redir;
 	do {
@@ -4817,9 +4816,14 @@
 			continue; /* redirect from/to same file descriptor */
 
 		newfd = openredirect(n);
-		if (fd == newfd)
+		if (fd == newfd) {
+			/* Descriptor wasn't open before redirect.
+			 * Mark it for close in the future */
+			if (sv && sv->renamed[fd] == EMPTY)
+				sv->renamed[fd] = CLOSED;
 			continue;
-		if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
+		}
+		if (sv && sv->renamed[fd] == EMPTY) {
 			i = fcntl(fd, F_DUPFD, 10);
 
 			if (i == -1) {
@@ -4831,7 +4835,7 @@
 					/* NOTREACHED */
 				}
 			} else {
-				*p = i;
+				sv->renamed[fd] = i;
 				close(fd);
 			}
 		} else {
@@ -4840,7 +4844,7 @@
 		dupredirect(n, newfd);
 	} while ((n = n->nfile.next));
 	INT_ON;
-	if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
+	if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0)
 		preverrout_fd = sv->renamed[2];
 }
 
@@ -4858,6 +4862,11 @@
 	INT_OFF;
 	rp = redirlist;
 	for (i = 0; i < 10; i++) {
+		if (rp->renamed[i] == CLOSED) {
+			if (!drop)
+				close(i);
+			continue;
+		}
 		if (rp->renamed[i] != EMPTY) {
 			if (!drop) {
 				close(i);
@@ -10994,7 +11003,7 @@
 static int
 echocmd(int argc, char **argv)
 {
-	return bb_echo(argv);
+	return bb_echo(argc, argv);
 }
 #endif
 
diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right
new file mode 100644
index 0000000..2a02d41
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir.right
@@ -0,0 +1 @@
+TEST
diff --git a/shell/ash_test/ash-redir/redir.tests b/shell/ash_test/ash-redir/redir.tests
new file mode 100644
index 0000000..7a1a668
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir.tests
@@ -0,0 +1,6 @@
+# test: closed fds should stay closed
+exec 1>&-
+echo TEST >TEST
+echo JUNK # lost: stdout is closed
+cat TEST >&2
+rm TEST