← Commit list

0829fce07

Denys Vlasenko
Denys Vlasenko
2024-07-12
SUCCESS Duration: 155s

Subject

ash: do not abort interactive mode on >&9999 redirect

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

shell/ash.c+16 -4
@@ -5621,10 +5621,13 @@ dup2_or_raise(int from, int to)
newfd = (from != to) ? dup2(from, to) : to;
if (newfd < 0) {
/* Happens when source fd is not open: try "echo >&99" */
- ash_msg_and_raise_perror("%d", from);
+ ash_msg_and_raise_perror("dup2(%d,%d)", from, to);
}
return newfd;
}
+/* The only possible error return is EBADF (fd wasn't open).
+ * Transient errors retry, other errors raise exception.
+ */
static int
dup_CLOEXEC(int fd, int avoid_fd)
{
@@ -5639,6 +5642,16 @@ dup_CLOEXEC(int fd, int avoid_fd)
goto repeat;
if (errno == EINTR)
goto repeat;
+ if (errno != EBADF) {
+ /* "echo >&9999" gets EINVAL trying to save fd 1 to above 9999.
+ * We could try saving it _below_ 9999 instead (how?), but
+ * this probably means that dup2(9999,1) to effectuate >&9999
+ * would also not work: fd 9999 can't exist. Gracefully bail out.
+ * (This differs from "echo >&99" where saving works, but
+ * subsequent dup2(99,1) fails if fd 99 is not open).
+ */
+ ash_msg_and_raise_perror("fcntl(%d,F_DUPFD,%d)", fd, avoid_fd + 1);
+ }
}
return newfd;
}
@@ -5754,7 +5767,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
new_fd = dup_CLOEXEC(fd, avoid_fd);
sq->two_fd[i].moved_to = new_fd;
TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
- if (new_fd < 0) /* what? */
+ if (new_fd < 0) /* EBADF? what? */
xfunc_die();
return 0; /* "we did not close fd" */
}
@@ -5769,8 +5782,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
new_fd = dup_CLOEXEC(fd, avoid_fd);
TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
if (new_fd < 0) {
- if (errno != EBADF)
- xfunc_die();
+ /* EBADF (fd is not open) */
/* new_fd = CLOSED; - already is -1 */
}
sq->two_fd[i].moved_to = new_fd;