diff options
author | Karel Zak | 2015-06-17 13:25:46 +0200 |
---|---|---|
committer | Karel Zak | 2015-06-17 13:25:46 +0200 |
commit | d35ffe808a0e42967cf69d4651582cd0b7ed1e08 (patch) | |
tree | 2e426fec5f81a641cdf253c822ce4dc99ab854aa /term-utils/script.c | |
parent | script: debug poll() results (diff) | |
download | kernel-qcow2-util-linux-d35ffe808a0e42967cf69d4651582cd0b7ed1e08.tar.gz kernel-qcow2-util-linux-d35ffe808a0e42967cf69d4651582cd0b7ed1e08.tar.xz kernel-qcow2-util-linux-d35ffe808a0e42967cf69d4651582cd0b7ed1e08.zip |
script: cleanup signals usage
* don't call anything from assert()
* fork() block cleanup to make it more readable
* restore original signal mask in child (do_shell())
* close signal FD in child (do_shell())
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'term-utils/script.c')
-rw-r--r-- | term-utils/script.c | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/term-utils/script.c b/term-utils/script.c index bf03b6297..74539c1c5 100644 --- a/term-utils/script.c +++ b/term-utils/script.c @@ -124,6 +124,7 @@ struct script_control { die:1; /* terminate program */ sigset_t sigset; /* catch SIGCHLD and SIGWINCH with signalfd() */ + sigset_t sigorg; /* original signal mask */ int sigfd; /* file descriptor for signalfd() */ }; @@ -315,7 +316,11 @@ static void handle_signal(struct script_control *ctl, int fd) DBG(SIGNAL, ul_debug("signal FD %d active", fd)); bytes = read(fd, &info, sizeof(info)); - assert(bytes == sizeof(info)); + if (bytes != sizeof(info)) { + if (errno == EAGAIN) + return; + fail(ctl); + } switch (info.ssi_signo) { case SIGCHLD: @@ -442,7 +447,7 @@ static void getslave(struct script_control *ctl) ioctl(ctl->slave, TIOCSCTTY, 0); } -static void __attribute__((__noreturn__)) doshell(struct script_control *ctl) +static void __attribute__((__noreturn__)) do_shell(struct script_control *ctl) { char *shname; @@ -450,6 +455,7 @@ static void __attribute__((__noreturn__)) doshell(struct script_control *ctl) /* close things irrelevant for this process */ close(ctl->master); + close(ctl->sigfd); dup2(ctl->slave, STDIN_FILENO); dup2(ctl->slave, STDOUT_FILENO); @@ -464,6 +470,8 @@ static void __attribute__((__noreturn__)) doshell(struct script_control *ctl) else shname = ctl->shell; + sigprocmask(SIG_SETMASK, &ctl->sigorg, NULL); + /* * When invoked from within /etc/csh.login, script spawns a csh shell * that spawns programs that cannot be killed with a SIGTERM. This is @@ -663,10 +671,13 @@ int main(int argc, char **argv) utempter_add_record(ctl.master, NULL); #endif /* setup signal handler */ - assert(sigemptyset(&ctl.sigset) == 0); - assert(sigaddset(&ctl.sigset, SIGCHLD) == 0); - assert(sigaddset(&ctl.sigset, SIGWINCH) == 0); - assert(sigprocmask(SIG_BLOCK, &ctl.sigset, NULL) == 0); + sigemptyset(&ctl.sigset); + sigaddset(&ctl.sigset, SIGCHLD); + sigaddset(&ctl.sigset, SIGWINCH); + + /* block signals used for signalfd() to prevent the signals being + * handled according to their default dispositions */ + sigprocmask(SIG_BLOCK, &ctl.sigset, &ctl.sigorg); if ((ctl.sigfd = signalfd(-1, &ctl.sigset, 0)) < 0) err(EXIT_FAILURE, _("cannot set signal handler")); @@ -676,13 +687,19 @@ int main(int argc, char **argv) fflush(stdout); ctl.child = fork(); - if (ctl.child < 0) { + switch (ctl.child) { + case -1: /* error */ warn(_("fork failed")); fail(&ctl); + break; + case 0: /* child */ + do_shell(&ctl); + break; + default: /* parent */ + do_io(&ctl); + break; } - if (ctl.child == 0) - doshell(&ctl); - do_io(&ctl); - /* should not happen, do_io() calls done() */ + + /* should not happen, all used functions are non-return */ return EXIT_FAILURE; } |