aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordequis <dx@dxzone.com.ar>2015-10-27 03:07:02 -0300
committerdequis <dx@dxzone.com.ar>2015-10-30 07:31:09 -0300
commit2e99039dbc86bbf04320fdb2cf652e9c71a58af2 (patch)
tree044249e8a9bc961cf9783d160033813b83c5d65f
parentad8a81000e874dc3f20c8d97ef698604a67ead4b (diff)
Avoid propagating shutdown signal to all subprocesses
This was a sort-of-regression with 7233f68 While this behavior might seem desirable in some cases, multi-user installs like public servers would rather not kill children while upgrading. Turns out that pipes are inherited by forks, and writing in one side means there might be more than one listener that calls bitlbee_shutdown(). If the parent gets it, the children will get it too. If a child gets it, the parent and the other children get it too. This adds a sighandler_shutdown_setup() function that closes any previously existing pipes and disconnects the events from them, to create a new one. This is called again after forking each child process. While I'm sure this fixes the issue, I still don't understand why it *didn't* kill the forked processes in some cases. Worrying.
-rw-r--r--bitlbee.c3
-rw-r--r--bitlbee.h2
-rw-r--r--unix.c35
3 files changed, 31 insertions, 9 deletions
diff --git a/bitlbee.c b/bitlbee.c
index 98f2d9c9..fa8c6795 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -310,6 +310,9 @@ static gboolean bitlbee_io_new_client(gpointer data, gint fd, b_input_condition
close(global.listen_socket);
b_event_remove(global.listen_watch_source_id);
+ /* Make a new pipe for the shutdown signal handler */
+ sighandler_shutdown_setup();
+
/* Make the connection. */
irc = irc_new(new_socket);
diff --git a/bitlbee.h b/bitlbee.h
index 49a5496a..447e2e64 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -157,6 +157,8 @@ typedef struct global {
int restart;
} global_t;
+void sighandler_shutdown_setup(void);
+
int bitlbee_daemon_init(void);
int bitlbee_inetd_init(void);
diff --git a/unix.c b/unix.c
index 30451241..298c8427 100644
--- a/unix.c
+++ b/unix.c
@@ -47,7 +47,11 @@
global_t global; /* Against global namespace pollution */
-static int signal_shutdown_pipe[2] = { -1, -1 };
+static struct {
+ int fd[2];
+ int tag;
+} shutdown_pipe = {{-1 , -1}, 0};
+
static void sighandler_shutdown(int signal);
static void sighandler_crash(int signal);
@@ -155,13 +159,11 @@ int main(int argc, char *argv[])
sig.sa_handler = sighandler_crash;
sigaction(SIGSEGV, &sig, &old);
- /* Use a pipe for SIGTERM/SIGINT so the actual signal handler doesn't do anything unsafe */
- if (pipe(signal_shutdown_pipe) == 0) {
- b_input_add(signal_shutdown_pipe[0], B_EV_IO_READ, bitlbee_shutdown, NULL);
- sig.sa_handler = sighandler_shutdown;
- sigaction(SIGINT, &sig, &old);
- sigaction(SIGTERM, &sig, &old);
- }
+ sighandler_shutdown_setup();
+
+ sig.sa_handler = sighandler_shutdown;
+ sigaction(SIGINT, &sig, &old);
+ sigaction(SIGTERM, &sig, &old);
if (!getuid() || !geteuid()) {
log_message(LOGLVL_WARNING, "BitlBee is running with root privileges. Why?");
@@ -255,12 +257,27 @@ static int crypt_main(int argc, char *argv[])
return 0;
}
+/* Set up a pipe for SIGTERM/SIGINT so the actual signal handler doesn't do anything unsafe */
+void sighandler_shutdown_setup()
+{
+ if (shutdown_pipe.fd[0] != -1) {
+ /* called again from a forked process, clean up to avoid propagating the signal */
+ b_event_remove(shutdown_pipe.tag);
+ close(shutdown_pipe.fd[0]);
+ close(shutdown_pipe.fd[1]);
+ }
+
+ if (pipe(shutdown_pipe.fd) == 0) {
+ shutdown_pipe.tag = b_input_add(shutdown_pipe.fd[0], B_EV_IO_READ, bitlbee_shutdown, NULL);
+ }
+}
+
/* Signal handler for SIGTERM and SIGINT */
static void sighandler_shutdown(int signal)
{
/* Write a single null byte to the pipe, just to send a message to the main loop.
* This gets handled by bitlbee_shutdown (the b_input_add callback for this pipe) */
- write(signal_shutdown_pipe[1], "", 1);
+ write(shutdown_pipe.fd[1], "", 1);
}
/* Signal handler for SIGSEGV