Skip to content

Commit

Permalink
hush: fix a case when redirect to a closed fd tias#1 is not restoring…
Browse files Browse the repository at this point in the history
… (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]>
  • Loading branch information
Denys Vlasenko committed Jul 24, 2017
1 parent b72f1ef commit 621fc50
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
34 changes: 27 additions & 7 deletions shell/hush.c
Original file line number Diff line number Diff line change
Expand Up @@ -6643,8 +6643,18 @@ struct squirrel {
/* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
};

static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved)
{
sq = xrealloc(sq, (i + 2) * sizeof(sq[0]));
sq[i].orig_fd = orig;
sq[i].moved_to = moved;
sq[i+1].orig_fd = -1; /* end marker */
return sq;
}

static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
{
int moved_to;
int i = 0;

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

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

/* fd: redirect wants this fd to be used (e.g. 3>file).
Expand Down Expand Up @@ -6778,6 +6785,19 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
*/
return 1;
}
if (openfd == redir->rd_fd && sqp) {
/* open() gave us precisely the fd we wanted.
* This means that this fd was not busy
* (not opened to anywhere).
* Remember to close it on restore:
*/
struct squirrel *sq = *sqp;
int i = 0;
if (sq) while (sq[i].orig_fd >= 0)
i++;
*sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */
debug_printf_redir("redir to previously closed fd %d\n", openfd);
}
} else {
/* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
openfd = redir->rd_dup;
Expand Down
2 changes: 2 additions & 0 deletions shell/hush_test/hush-redir/redir.right
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
hush: write error: Bad file descriptor
TEST
6 changes: 6 additions & 0 deletions shell/hush_test/hush-redir/redir.tests
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 621fc50

Please sign in to comment.