diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/exec.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/Src/exec.c b/Src/exec.c index 1d07bffcf..cdd765113 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1663,8 +1663,23 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag, } else if (!mfds[fd1] || unset(MULTIOS)) { if(!mfds[fd1]) { /* starting a new multio */ mfds[fd1] = (struct multio *) zhalloc(sizeof(struct multio)); - if (!forked && save[fd1] == -2) - save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1); + if (!forked && save[fd1] == -2) { + if (fd1 == fd2) + save[fd1] = -1; + else { + int fdN = movefd(fd1); + /* + * fd1 may already be closed here, so + * ignore bad file descriptor error + */ + if (fdN < 0 && errno != EBADF) { + zerr("cannot duplicate fd %d: %e", fd1, errno); + closemnodes(mfds); + return; + } + save[fd1] = fdN; + } + } } if (!varid) redup(fd2, fd1); @@ -1674,22 +1689,41 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag, } else { if (mfds[fd1]->rflag != rflag) { zerr("file mode mismatch on fd %d", fd1); + closemnodes(mfds); return; } if (mfds[fd1]->ct == 1) { /* split the stream */ - mfds[fd1]->fds[0] = movefd(fd1); - mfds[fd1]->fds[1] = movefd(fd2); + int fdN = movefd(fd1); + if (fdN < 0) { + zerr("multio failed for fd %d: %e", fd1, errno); + closemnodes(mfds); + return; + } + mfds[fd1]->fds[0] = fdN; + fdN = movefd(fd2); + if (fdN < 0) { + zerr("multio failed for fd %d: %e", fd2, errno); + closemnodes(mfds); + return; + } + mfds[fd1]->fds[1] = fdN; mpipe(pipes); mfds[fd1]->pipe = pipes[1 - rflag]; redup(pipes[rflag], fd1); mfds[fd1]->ct = 2; } else { /* add another fd to an already split stream */ + int fdN; if(!(mfds[fd1]->ct % MULTIOUNIT)) { int new = sizeof(struct multio) + sizeof(int) * mfds[fd1]->ct; int old = new - sizeof(int) * MULTIOUNIT; mfds[fd1] = hrealloc((char *)mfds[fd1], old, new); } - mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2); + if ((fdN = movefd(fd2)) < 0) { + zerr("multio failed for fd %d: %e", fd2, errno); + closemnodes(mfds); + return; + } + mfds[fd1]->fds[mfds[fd1]->ct++] = fdN; } } if (subsh_close >= 0 && fdtable[subsh_close] == FDT_UNUSED) |