From 621fc50e83f7446a060f0b9689dc8dc59ee0743a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 24 Jul 2017 12:42:17 +0200 Subject: 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 --- shell/hush.c | 34 +++++++++++++++++++++++++++------- shell/hush_test/hush-redir/redir.right | 2 ++ shell/hush_test/hush-redir/redir.tests | 6 ++++++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 shell/hush_test/hush-redir/redir.right create mode 100755 shell/hush_test/hush-redir/redir.tests diff --git a/shell/hush.c b/shell/hush.c index 309ed2139..20b092398 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -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) { @@ -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). @@ -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; diff --git a/shell/hush_test/hush-redir/redir.right b/shell/hush_test/hush-redir/redir.right new file mode 100644 index 000000000..4de5ec701 --- /dev/null +++ b/shell/hush_test/hush-redir/redir.right @@ -0,0 +1,2 @@ +hush: write error: Bad file descriptor +TEST diff --git a/shell/hush_test/hush-redir/redir.tests b/shell/hush_test/hush-redir/redir.tests new file mode 100755 index 000000000..7a1a66806 --- /dev/null +++ b/shell/hush_test/hush-redir/redir.tests @@ -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 -- cgit v1.2.3