hush: bit better comments in redirect code. No logic changes
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 20 Aug 2016 13:16:00 +0000 (15:16 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 20 Aug 2016 13:16:00 +0000 (15:16 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c

index b41d9d04bc4dc711ab471e2feb21ba490fba2836..9b45b312f3103c95d1a46b53f1d14f08880ff95d 100644 (file)
@@ -6099,10 +6099,12 @@ static int setup_redirects(struct command *prog, int squirrel[])
 
        for (redir = prog->redirects; redir; redir = redir->next) {
                if (redir->rd_type == REDIRECT_HEREDOC2) {
-                       /* rd_fd<<HERE case */
-                       if (squirrel && redir->rd_fd < 3
+                       /* "rd_fd<<HERE" case */
+                       if (redir->rd_fd <= 2
+                        && squirrel
                         && squirrel[redir->rd_fd] < 0
                        ) {
+                               /* Save old fds 0..2 if redirect uses them */
                                squirrel[redir->rd_fd] = dup(redir->rd_fd);
                        }
                        /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
@@ -6114,7 +6116,7 @@ static int setup_redirects(struct command *prog, int squirrel[])
                }
 
                if (redir->rd_dup == REDIRFD_TO_FILE) {
-                       /* rd_fd<*>file case (<*> is <,>,>>,<>) */
+                       /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */
                        char *p;
                        if (redir->rd_filename == NULL) {
                                /* Something went wrong in the parse.
@@ -6127,20 +6129,33 @@ static int setup_redirects(struct command *prog, int squirrel[])
                        openfd = open_or_warn(p, mode);
                        free(p);
                        if (openfd < 0) {
-                       /* this could get lost if stderr has been redirected, but
-                        * bash and ash both lose it as well (though zsh doesn't!) */
-//what the above comment tries to say?
+                               /* Error message from open_or_warn can be lost
+                                * if stderr has been redirected, but bash
+                                * and ash both lose it as well
+                                * (though zsh doesn't!)
+                                */
                                return 1;
                        }
                } else {
-                       /* rd_fd<*>rd_dup or rd_fd<*>- cases */
+                       /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
                        openfd = redir->rd_dup;
                }
 
                if (openfd != redir->rd_fd) {
-                       if (squirrel && redir->rd_fd < 3
+                       if (redir->rd_fd <= 2
+                        && squirrel
                         && squirrel[redir->rd_fd] < 0
                        ) {
+                               /* Save old fds 0..2 if redirect uses them */
+//FIXME: script fd's also need this! "sh SCRIPT" and SCRIPT has "echo FOO 3>&-":
+// open("SCRIPT", O_RDONLY)          = 3
+// fcntl(3, F_SETFD, FD_CLOEXEC)     = 0
+// read(3, "echo FOO 3>&-\n....", 4096) = N
+// close(3)                          = 0
+// write(1, "FOO\n", 4)              = 4
+// ...
+// read(3, 0x205f8e0, 4096)          = -1 EBADF <== BUG
+//
                                squirrel[redir->rd_fd] = dup(redir->rd_fd);
                        }
                        if (openfd == REDIRFD_CLOSE) {
@@ -6159,7 +6174,7 @@ static int setup_redirects(struct command *prog, int squirrel[])
 static void restore_redirects(int squirrel[])
 {
        int i, fd;
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i <= 2; i++) {
                fd = squirrel[i];
                if (fd != -1) {
                        /* We simply die on error */
@@ -7144,6 +7159,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
                                if (x->b_function == builtin_exec && argv_expanded[1] == NULL) {
                                        debug_printf("exec with redirects only\n");
                                        rcode = setup_redirects(command, NULL);
+                                       /* rcode=1 can be if redir file can't be opened */
                                        goto clean_up_and_ret1;
                                }
                        }
@@ -7270,9 +7286,20 @@ static NOINLINE int run_pipe(struct pipe *pi)
                        if (pipefds.rd > 1)
                                close(pipefds.rd);
                        /* Like bash, explicit redirects override pipes,
-                        * and the pipe fd is available for dup'ing. */
-                       if (setup_redirects(command, NULL))
+                        * and the pipe fd (fd#1) is available for dup'ing:
+                        * "cmd1 2>&1 | cmd2": fd#1 is duped to fd#2, thus stderr
+                        * of cmd1 goes into pipe.
+                        */
+                       if (setup_redirects(command, NULL)) {
+                               /* Happens when redir file can't be opened:
+                                * $ hush -c 'echo FOO >&2 | echo BAR 3>/qwe/rty; echo BAZ'
+                                * FOO
+                                * hush: can't open '/qwe/rty': No such file or directory
+                                * BAZ
+                                * (echo BAR is not executed, it hits _exit(1) below)
+                                */
                                _exit(1);
+                       }
 
                        /* Stores to nommu_save list of env vars putenv'ed
                         * (NOMMU, on MMU we don't need that) */