From: Daniel Wagner <[email protected]>

This prevents a deadlog while writing to syslog and then
we receive a signal to write syslog.
---
 src/log.c |   87 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/src/log.c b/src/log.c
index 04e61f3..de3a067 100644
--- a/src/log.c
+++ b/src/log.c
@@ -32,6 +32,7 @@
 #include <syslog.h>
 #include <execinfo.h>
 #include <dlfcn.h>
+#include <sys/signalfd.h>
 
 #include "connman.h"
 
@@ -212,30 +213,80 @@ static void print_backtrace(unsigned int offset)
        close(infd[0]);
 }
 
-static void signal_handler(int signo)
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
 {
-       connman_error("Aborting (signal %d) [%s]", signo, program_exec);
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
 
-       print_backtrace(2);
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGBUS:
+       case SIGILL:
+       case SIGFPE:
+       case SIGSEGV:
+       case SIGABRT:
+       case SIGPIPE:
+               connman_error("Aborting (signal %d) [%s]",
+                               si.ssi_signo, program_exec);
+
+               print_backtrace(2);
+
+               exit(EXIT_FAILURE);
+               break;
+       }
 
-       exit(EXIT_FAILURE);
+       return TRUE;
 }
 
-static void signal_setup(sighandler_t handler)
+static guint setup_signalfd(void)
 {
-       struct sigaction sa;
+       GIOChannel *channel;
+       guint source;
        sigset_t mask;
+       int fd;
 
        sigemptyset(&mask);
-       sa.sa_handler = handler;
-       sa.sa_mask = mask;
-       sa.sa_flags = 0;
-       sigaction(SIGBUS, &sa, NULL);
-       sigaction(SIGILL, &sa, NULL);
-       sigaction(SIGFPE, &sa, NULL);
-       sigaction(SIGSEGV, &sa, NULL);
-       sigaction(SIGABRT, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
+       sigaddset(&mask, SIGBUS);
+       sigaddset(&mask, SIGILL);
+       sigaddset(&mask, SIGFPE);
+       sigaddset(&mask, SIGSEGV);
+       sigaddset(&mask, SIGABRT);
+       sigaddset(&mask, SIGPIPE);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
 }
 
 extern struct connman_debug_desc __start___debug[];
@@ -315,6 +366,8 @@ void __connman_log_enable(struct connman_debug_desc *start,
        }
 }
 
+static guint signal_watch;
+
 int __connman_log_init(const char *program, const char *debug,
                                                connman_bool_t detach)
 {
@@ -332,7 +385,7 @@ int __connman_log_init(const char *program, const char 
*debug,
        if (detach == FALSE)
                option |= LOG_PERROR;
 
-       signal_setup(signal_handler);
+       signal_watch = setup_signalfd();
 
        openlog(basename(program), option, LOG_DAEMON);
 
@@ -347,7 +400,7 @@ void __connman_log_cleanup(void)
 
        closelog();
 
-       signal_setup(SIG_DFL);
+       g_source_remove(signal_watch);
 
        g_strfreev(enabled);
 }
-- 
1.7.6.4

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to