]> git.tuebingen.mpg.de Git - adu.git/commitdiff
Fix signal handling.
authorAndre Noll <maan@systemlinux.org>
Thu, 2 Feb 2012 16:07:35 +0000 (17:07 +0100)
committerAndre Noll <maan@systemlinux.org>
Thu, 23 Feb 2012 21:31:30 +0000 (22:31 +0100)
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
error.h

diff --git a/adu.c b/adu.c
index 7d8c9abd0191b6d4c84036bcc70e7e91d2cf03f3..0bb5aad08db31a68b52fc69a1f414a07d9c87fb8 100644 (file)
--- a/adu.c
+++ b/adu.c
@@ -165,14 +165,24 @@ void check_signals(void)
        exit(EXIT_FAILURE);
 }
 
        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)
 {
 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;
 }
 
        return 1;
 }
 
diff --git a/error.h b/error.h
index 5a5aefb987dad5f4946844e3153f2c8f12d0f282..9849916c13446fb05da69f6c7b7ddada2fe0dae3 100644 (file)
--- a/error.h
+++ b/error.h
@@ -33,7 +33,7 @@
        _ERROR(EMPTY, "file empty") \
        _ERROR(MMAP, "mmap error") \
        _ERROR(OSL, "osl error") \
        _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") \
        _ERROR(OUTPUT, "error writing output") \
        _ERROR(MALFORMED_FORMAT, "malformed format string") \
        _ERROR(BAD_ALIGN_SPEC, "bad alignment specifier") \