Skip to content

Commit 621fc50

Browse files
author
Denys Vlasenko
committed
hush: fix a case when redirect to a closed fd #1 is not restoring (closing) it
function old new delta setup_redirects 200 245 +45 append_squirrel - 41 +41 save_fds_on_redirect 256 221 -35 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 86/-35) Total: 51 bytes Signed-off-by: Denys Vlasenko <[email protected]>
1 parent b72f1ef commit 621fc50

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

shell/hush.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6643,8 +6643,18 @@ struct squirrel {
66436643
/* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
66446644
};
66456645

6646+
static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved)
6647+
{
6648+
sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
6649+
sq[i].orig_fd = orig;
6650+
sq[i].moved_to = moved;
6651+
sq[i+1].orig_fd = -1; /* end marker */
6652+
return sq;
6653+
}
6654+
66466655
static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
66476656
{
6657+
int moved_to;
66486658
int i = 0;
66496659

66506660
if (sq) while (sq[i].orig_fd >= 0) {
@@ -6664,15 +6674,12 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
66646674
i++;
66656675
}
66666676

6667-
sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
6668-
sq[i].orig_fd = fd;
66696677
/* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */
6670-
sq[i].moved_to = fcntl_F_DUPFD(fd, avoid_fd);
6671-
debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, sq[i].moved_to);
6672-
if (sq[i].moved_to < 0 && errno != EBADF)
6678+
moved_to = fcntl_F_DUPFD(fd, avoid_fd);
6679+
debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
6680+
if (moved_to < 0 && errno != EBADF)
66736681
xfunc_die();
6674-
sq[i+1].orig_fd = -1; /* end marker */
6675-
return sq;
6682+
return append_squirrel(sq, i, fd, moved_to);
66766683
}
66776684

66786685
/* fd: redirect wants this fd to be used (e.g. 3>file).
@@ -6778,6 +6785,19 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
67786785
*/
67796786
return 1;
67806787
}
6788+
if (openfd == redir->rd_fd && sqp) {
6789+
/* open() gave us precisely the fd we wanted.
6790+
* This means that this fd was not busy
6791+
* (not opened to anywhere).
6792+
* Remember to close it on restore:
6793+
*/
6794+
struct squirrel *sq = *sqp;
6795+
int i = 0;
6796+
if (sq) while (sq[i].orig_fd >= 0)
6797+
i++;
6798+
*sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */
6799+
debug_printf_redir("redir to previously closed fd %d\n", openfd);
6800+
}
67816801
} else {
67826802
/* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
67836803
openfd = redir->rd_dup;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
hush: write error: Bad file descriptor
2+
TEST
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# test: closed fds should stay closed
2+
exec 1>&-
3+
echo TEST >TEST
4+
echo JUNK # lost: stdout is closed
5+
cat TEST >&2
6+
rm TEST

0 commit comments

Comments
 (0)