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