From 2d7a4d61bfa10e3f462053936dcf7fd416b629d0 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 2 Feb 2012 17:07:35 +0100 Subject: [PATCH] Fix signal handling. Using signal() to set the disposition of a signal is always a bad idea as POSIX does not specify whether a system call which was interrupted should be restarted or not. For interactive sessions, the Linux behaviour is to automatically restart slow system calls, specifically read(2) in case nothing had been read before the interrupt arrived. This is rather unfortunate as adu calls fgets(3) (hence read(2)) in an endless loop to read the user input. Therefore automatically restarted read() calls result in interactive sessions that can not be terminated easily, as was noticed by Sebastian Stark. This patch makes the signal initialization code call sigaction() instead of signal() to set up the handlers. This buys us well-defined semantics across all operating systems, namely to *not* restart slow system calls. As a side effect of this change, interactive sessions can now be terminated by sending SIGINT (e.g., by pressing CTRL+C). --- adu.c | 22 ++++++++++++++++------ error.h | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/adu.c b/adu.c index 7d8c9ab..0bb5aad 100644 --- a/adu.c +++ b/adu.c @@ -165,14 +165,24 @@ void check_signals(void) exit(EXIT_FAILURE); } +static int catch_signal(int sig) +{ + struct sigaction act; + + act.sa_handler = signal_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + return sigaction(sig, &act, NULL); +} + static int init_signals(void) { - if (signal(SIGINT, &signal_handler) == SIG_ERR) - return -E_SIGNAL_SIG_ERR; - if (signal(SIGTERM, &signal_handler) == SIG_ERR) - return -E_SIGNAL_SIG_ERR; - if (signal(SIGPIPE, &signal_handler) == SIG_ERR) - return -E_SIGNAL_SIG_ERR; + if (catch_signal(SIGINT) < 0) + return -E_SIGACTION; + if (catch_signal(SIGTERM) < 0) + return -E_SIGACTION; + if (catch_signal(SIGPIPE) == SIG_ERR) + return -E_SIGACTION; return 1; } diff --git a/error.h b/error.h index 5a5aefb..9849916 100644 --- a/error.h +++ b/error.h @@ -33,7 +33,7 @@ _ERROR(EMPTY, "file empty") \ _ERROR(MMAP, "mmap error") \ _ERROR(OSL, "osl error") \ - _ERROR(SIGNAL_SIG_ERR, "signal() returned SIG_ERR") \ + _ERROR(SIGACTION, "could not install signal handler") \ _ERROR(OUTPUT, "error writing output") \ _ERROR(MALFORMED_FORMAT, "malformed format string") \ _ERROR(BAD_ALIGN_SPEC, "bad alignment specifier") \ -- 2.39.5