summaryrefslogtreecommitdiffstats
path: root/term-utils/script.c
diff options
context:
space:
mode:
authorSami Kerola2014-12-26 18:43:49 +0100
committerSami Kerola2015-06-08 22:52:51 +0200
commit89a859d433fbba81cd70ba5e42fc86e971233dce (patch)
tree400c4477517f9e55442054f372773d68ee7fb20c /term-utils/script.c
parentscript: merge doinput() and output() functions to do_io() (diff)
downloadkernel-qcow2-util-linux-89a859d433fbba81cd70ba5e42fc86e971233dce.tar.gz
kernel-qcow2-util-linux-89a859d433fbba81cd70ba5e42fc86e971233dce.tar.xz
kernel-qcow2-util-linux-89a859d433fbba81cd70ba5e42fc86e971233dce.zip
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 <wolf@cs.cmu.edu> CC: Ruediger Meier <ruediger.meier@ga-group.nl> Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'term-utils/script.c')
-rw-r--r--term-utils/script.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/term-utils/script.c b/term-utils/script.c
index ea776cf72..391aa9e5e 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;