From: Sami Kerola Date: Fri, 26 Dec 2014 17:43:49 +0000 (+0000) Subject: script: remove io vs signal race X-Git-Tag: v2.27-rc1~132^2~9^2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=89a859d433fbba81cd70ba5e42fc86e971233dce;p=thirdparty%2Futil-linux.git script: remove io vs signal race Make do_io() to run poll() until all streams are empty. This should remove the signal from child versus io handling race for good. Addresses: https://github.com/karelzak/util-linux/pull/62 Addresses: https://bugs.launchpad.net/bugs/264967 Addresses: https://bugs.debian.org/305808 CC: Wolfgang Richter CC: Ruediger Meier Signed-off-by: Sami Kerola --- diff --git a/term-utils/script.c b/term-utils/script.c index ea776cf72a..391aa9e5ec 100644 --- a/term-utils/script.c +++ b/term-utils/script.c @@ -92,6 +92,7 @@ struct script_control { FILE *timingfp; /* timing file pointer */ int master; /* pseudoterminal master file descriptor */ int slave; /* pseudoterminal slave file descriptor */ + int poll_timeout; /* poll() timeout, used in end of execution */ pid_t child; /* child pid */ int childstatus; /* child process exit value */ struct termios tt; /* slave terminal runtime attributes */ @@ -205,16 +206,11 @@ static void finish(struct script_control *ctl, int wait) { int status; pid_t pid; - int errsv = errno; int options = wait ? 0 : WNOHANG; while ((pid = wait3(&status, options, 0)) > 0) - if (pid == ctl->child) { + if (pid == ctl->child) ctl->childstatus = status; - ctl->die = 1; - } - - errno = errsv; } static void write_output(struct script_control *ctl, char *obuf, @@ -270,13 +266,15 @@ static void do_io(struct script_control *ctl) while (!ctl->die) { /* wait for input or signal */ - ret = poll(pfd, POLLFDS, -1); + ret = poll(pfd, POLLFDS, ctl->poll_timeout); if (ret < 0) { if (errno == EAGAIN) continue; warn(_("poll failed")); fail(ctl); } + if (ret == 0) + ctl->die = 1; for (i = 0; i < POLLFDS; i++) { if (pfd[i].revents == 0) continue; @@ -315,6 +313,13 @@ static void do_io(struct script_control *ctl) switch (info.ssi_signo) { case SIGCHLD: finish(ctl, 0); + ctl->poll_timeout = 10; + if (!ctl->isterm) + /* In situation such as 'date' in + * $ echo date | ./script + * ignore input when shell has + * exited. */ + pfd[0].fd = -1; break; case SIGWINCH: if (ctl->isterm) { @@ -496,6 +501,7 @@ int main(int argc, char **argv) .line = "/dev/ptyXX", #endif .master = -1, + .poll_timeout = -1, 0 }; int ch; diff --git a/tests/ts/script/race b/tests/ts/script/race index 02c8187d6a..65d48e29fd 100755 --- a/tests/ts/script/race +++ b/tests/ts/script/race @@ -27,10 +27,6 @@ ts_init "$*" ts_check_test_command "$TS_CMD_SCRIPT" -# TODO see comments about script design -# https://github.com/karelzak/util-linux/pull/62 -TS_KNOWN_FAIL="yes" - bingofile="$TS_OUTDIR/${TS_TESTNAME}-bingo" count=1000