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 <vda.linux@googlemail.com>
This commit is contained in:
parent
b72f1ef17b
commit
621fc50e83
34
shell/hush.c
34
shell/hush.c
@ -6643,8 +6643,18 @@ struct squirrel {
|
|||||||
/* moved_to = -1: fd was opened by redirect; close orig_fd after redir */
|
/* 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)
|
static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
|
||||||
{
|
{
|
||||||
|
int moved_to;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (sq) while (sq[i].orig_fd >= 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++;
|
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 */
|
/* 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);
|
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);
|
debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
|
||||||
if (sq[i].moved_to < 0 && errno != EBADF)
|
if (moved_to < 0 && errno != EBADF)
|
||||||
xfunc_die();
|
xfunc_die();
|
||||||
sq[i+1].orig_fd = -1; /* end marker */
|
return append_squirrel(sq, i, fd, moved_to);
|
||||||
return sq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fd: redirect wants this fd to be used (e.g. 3>file).
|
/* 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;
|
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 {
|
} else {
|
||||||
/* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
|
/* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */
|
||||||
openfd = redir->rd_dup;
|
openfd = redir->rd_dup;
|
||||||
|
2
shell/hush_test/hush-redir/redir.right
Normal file
2
shell/hush_test/hush-redir/redir.right
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
hush: write error: Bad file descriptor
|
||||||
|
TEST
|
6
shell/hush_test/hush-redir/redir.tests
Executable file
6
shell/hush_test/hush-redir/redir.tests
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user