changeset 3620:3360cc019737 HEAD

Implemented new signal handling framework, which makes handling signals much easier.
author Timo Sirainen <tss@iki.fi>
date Sun, 25 Sep 2005 14:07:32 +0300
parents 86ddbe18538c
children 3ae2df67459c
files src/auth/auth-cache.c src/auth/main.c src/deliver/deliver.c src/imap/main.c src/lib/lib-signals.c src/lib/lib-signals.h src/login-common/main.c src/master/main.c src/pop3/main.c
diffstat 9 files changed, 292 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/src/auth/auth-cache.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/auth/auth-cache.c	Sun Sep 25 14:07:32 2005 +0300
@@ -24,7 +24,6 @@
 
 	size_t size_left;
 	unsigned int ttl_secs;
-	unsigned int hup_count, usr2_count;
 
 	unsigned int hit_count, miss_count;
 };
@@ -97,22 +96,49 @@
 	i_free(node);
 }
 
+static void sig_auth_cache_clear(int signo __attr_unused__, void *context)
+{
+	struct auth_cache *cache = context;
+
+	i_info("SIGHUP received, clearing cache");
+	auth_cache_clear(cache);
+}
+
+static void sig_auth_cache_stats(int signo __attr_unused__, void *context)
+{
+	struct auth_cache *cache = context;
+	unsigned int total_count;
+
+	total_count = cache->hit_count + cache->miss_count;
+	i_info("Authentication cache hits %u/%u (%u%%)",
+	       cache->hit_count, total_count,
+	       cache->hit_count * 100 / total_count);
+
+	/* reset hit counter */
+	cache->hit_count = cache->miss_count = 0;
+}
+
 struct auth_cache *auth_cache_new(size_t max_size, unsigned int ttl_secs)
 {
 	struct auth_cache *cache;
 
 	cache = i_new(struct auth_cache, 1);
-	cache->hup_count = lib_signal_hup_count;
 	cache->hash = hash_create(default_pool, default_pool, 0, str_hash,
 				  (hash_cmp_callback_t *)strcmp);
 	cache->size_left = max_size;
 	cache->ttl_secs = ttl_secs;
+
+	lib_signals_set_handler(SIGHUP, TRUE, sig_auth_cache_clear, cache);
+	lib_signals_set_handler(SIGUSR2, TRUE, sig_auth_cache_stats, cache);
 	return cache;
 }
 
 void auth_cache_free(struct auth_cache *cache)
 {
-        auth_cache_clear(cache);
+	lib_signals_unset_handler(SIGHUP, sig_auth_cache_clear, cache);
+	lib_signals_unset_handler(SIGUSR2, sig_auth_cache_stats, cache);
+
+	auth_cache_clear(cache);
 	hash_destroy(cache->hash);
 	i_free(cache);
 }
@@ -122,8 +148,6 @@
 	while (cache->tail != NULL)
 		auth_cache_node_destroy(cache, cache->tail);
 	hash_clear(cache->hash, FALSE);
-
-	cache->hup_count = lib_signal_hup_count;
 }
 
 const char *auth_cache_lookup(struct auth_cache *cache,
@@ -132,29 +156,9 @@
 {
 	string_t *str;
 	struct cache_node *node;
-	unsigned int total_count;
 
 	*expired_r = FALSE;
 
-	if (cache->hup_count != lib_signal_hup_count) {
-		/* SIGHUP received - clear cache */
-		i_info("SIGHUP received, clearing cache");
-		auth_cache_clear(cache);
-		return NULL;
-	}
-
-	if (cache->usr2_count != lib_signal_usr2_count) {
-		cache->usr2_count = lib_signal_usr2_count;
-
-		total_count = cache->hit_count + cache->miss_count;
-		i_info("Authentication cache hits %u/%u (%u%%)",
-		       cache->hit_count, total_count,
-		       cache->hit_count * 100 / total_count);
-
-		/* reset hit counter */
-		cache->hit_count = cache->miss_count = 0;
-	}
-
 	str = t_str_new(256);
 	var_expand(str, key,
 		   auth_request_get_var_expand_table(request, str_escape));
--- a/src/auth/main.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/auth/main.c	Sun Sep 25 14:07:32 2005 +0300
@@ -34,8 +34,12 @@
 static struct auth *auth;
 static struct auth_worker_client *worker_client;
 
-static void sig_quit(int signo __attr_unused__)
+static void sig_die(int signo, void *context __attr_unused__)
 {
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
 	io_loop_stop(ioloop);
 }
 
@@ -195,7 +199,11 @@
 	struct auth_master_listener *listener;
 
         process_start_time = ioloop_time;
-	lib_init_signals(sig_quit);
+
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
 
 	mech_init();
 	auth_init(auth);
@@ -246,9 +254,6 @@
 
 static void main_deinit(void)
 {
-        if (lib_signal_kill != 0)
-		i_warning("Killed with signal %d", lib_signal_kill);
-
 	if (worker_client != NULL)
 		auth_worker_client_unref(worker_client);
 	else
@@ -263,6 +268,7 @@
         password_schemes_deinit();
 	random_deinit();
 
+	lib_signals_deinit();
 	closelog();
 }
 
--- a/src/deliver/deliver.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/deliver/deliver.c	Sun Sep 25 14:07:32 2005 +0300
@@ -38,8 +38,12 @@
 static struct ioloop *ioloop;
 static int return_value = EX_SOFTWARE;
 
-static void sig_quit(int signo __attr_unused__)
+static void sig_die(int signo, void *context __attr_unused__)
 {
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
 	io_loop_stop(ioloop);
 }
 
@@ -349,7 +353,10 @@
 	const char *str;
 
 	lib_init();
-	lib_init_signals(sig_quit);
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
 	ioloop = io_loop_create(default_pool);
 
 	destination = NULL;
@@ -453,6 +460,7 @@
         mail_storage_destroy(storage);
         mail_storage_deinit();
 	io_loop_destroy(ioloop);
+	lib_signals_deinit();
 	lib_deinit();
 
         return EX_OK;
--- a/src/imap/main.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/imap/main.c	Sun Sep 25 14:07:32 2005 +0300
@@ -50,8 +50,12 @@
 
 string_t *capability_string;
 
-static void sig_quit(int signo __attr_unused__)
+static void sig_die(int signo, void *context __attr_unused__)
 {
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
 	io_loop_stop(ioloop);
 }
 
@@ -130,7 +134,10 @@
 	struct client *client;
 	const char *user, *str;
 
-	lib_init_signals(sig_quit);
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
 
 	user = getenv("USER");
 	if (user == NULL) {
@@ -186,11 +193,6 @@
 
 static void main_deinit(void)
 {
-	/* warn about being killed because of some signal, except SIGINT (^C)
-	   which is too common at least while testing :) */
-	if (lib_signal_kill != 0 && lib_signal_kill != 2)
-		i_warning("Killed with signal %d", lib_signal_kill);
-
 	module_dir_unload(modules);
 
 	commands_deinit();
@@ -201,6 +203,7 @@
 
 	str_free(capability_string);
 
+	lib_signals_deinit();
 	closelog();
 }
 
--- a/src/lib/lib-signals.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/lib/lib-signals.c	Sun Sep 25 14:07:32 2005 +0300
@@ -1,96 +1,196 @@
 /* Copyright (c) 2001-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "ioloop.h"
+#include "fd-close-on-exec.h"
 #include "lib-signals.h"
 
-#include <stdio.h>
 #include <signal.h>
+#include <unistd.h>
+
+#define MAX_SIGNAL_VALUE 31
+
+struct signal_handler {
+	signal_handler_t *handler;
+	void *context;
 
-int lib_signal_kill;
-unsigned int lib_signal_hup_count;
-unsigned int lib_signal_usr1_count, lib_signal_usr2_count;
+	int delayed;
+        struct signal_handler *next;
+};
 
-static void (*quit_handler) (int);
+/* Remember that these are accessed inside signal handler which may be called
+   even while we're initializing/deinitializing. Try hard to keep everything
+   in consistent state. */
+static struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1];
+static int sig_pipe_fd[2];
 
-static void sig_counter(int signo)
+static struct io *io_sig;
+
+static void sig_handler(int signo)
 {
-#ifndef HAVE_SIGACTION
-	/* some systems may have changed the signal handler to default one */
-        signal(signo, sig_counter);
-#endif
+	struct signal_handler *h;
+	int delayed_sent = FALSE;
+
+	if (signo < 0 || signo > MAX_SIGNAL_VALUE)
+		return;
+
+	/* remember that we're inside a signal handler which might have been
+	   called at any time. don't do anything that's unsafe. */
+	for (h = signal_handlers[signo]; h != NULL; h = h->next) {
+		if (!h->delayed)
+			h->handler(signo, h->context);
+		else if (!delayed_sent) {
+			int saved_errno = errno;
+			unsigned char signo_byte = signo;
+
+			if (write(sig_pipe_fd[1], &signo_byte, 1) != 1)
+				i_error("write(sigpipe) failed: %m");
+			delayed_sent = TRUE;
+			errno = saved_errno;
+		}
+	}
+}
+
+static void signal_read(void *context __attr_unused__)
+{
+	unsigned char signal_buf[512];
+	unsigned char signal_mask[MAX_SIGNAL_VALUE+1];
+	ssize_t i, ret;
+	int signo;
 
-	switch (signo) {
-	case SIGHUP:
-		lib_signal_hup_count++;
-		break;
-	case SIGUSR1:
-		lib_signal_usr1_count++;
-		break;
-	case SIGUSR2:
-		lib_signal_usr2_count++;
-		break;
+	ret = read(sig_pipe_fd[0], signal_buf, sizeof(signal_buf));
+	if (ret > 0) {
+		memset(signal_mask, 0, sizeof(signal_mask));
+
+		/* move them to mask first to avoid calling same handler
+		   multiple times */
+		for (i = 0; i < ret; i++) {
+			signo = signal_buf[i];
+			if (signo > MAX_SIGNAL_VALUE) {
+				i_panic("sigpipe contains signal %d > %d",
+					signo, MAX_SIGNAL_VALUE);
+			}
+			signal_mask[signo] = 1;
+		}
+
+		/* call the delayed handlers */
+		for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
+			if (signal_mask[signo] > 0) {
+				struct signal_handler *h =
+					signal_handlers[signo];
+
+				for (; h != NULL; h = h->next) {
+					if (h->delayed)
+						h->handler(signo, h->context);
+				}
+			}
+		}
+	} else if (ret < 0) {
+		if (errno != EAGAIN)
+			i_fatal("read(sigpipe) failed: %m");
+	} else {
+		i_fatal("read(sigpipe) failed: EOF");
 	}
 }
 
-static void sig_quit(int signo)
+void lib_signals_set_handler(int signo, int delayed,
+			     signal_handler_t *handler, void *context)
 {
-	/* if we get killed after this, just die instead of coming back here. */
-	signal(SIGINT, SIG_DFL);
-	signal(SIGTERM, SIG_DFL);
+	struct signal_handler *h;
+
+	if (signo < 0 || signo > MAX_SIGNAL_VALUE) {
+		i_panic("Trying to set signal %d handler, but max is %d",
+			signo, MAX_SIGNAL_VALUE);
+	}
+
+	if (signal_handlers[signo] == NULL) {
+		/* first handler for this signal */
+		struct sigaction act;
+
+		if (sigemptyset(&act.sa_mask) < 0)
+			i_fatal("sigemptyset(): %m");
+		act.sa_flags = 0;
+		act.sa_handler = handler != NULL ? sig_handler : SIG_IGN;
+		if (sigaction(signo, &act, NULL) < 0)
+			i_fatal("sigaction(%d): %m", signo);
 
-	lib_signal_kill = signo;
-	quit_handler(signo);
+		if (handler == NULL) {
+			/* we're ignoring the handler, just return */
+			return;
+		}
+	}
+	i_assert(sig_handler != NULL);
+
+	if (delayed && sig_pipe_fd[0] == -1) {
+		/* first delayed handler */
+		if (pipe(sig_pipe_fd) < 0)
+			i_fatal("pipe() failed: %m");
+		fd_close_on_exec(sig_pipe_fd[0], TRUE);
+		fd_close_on_exec(sig_pipe_fd[1], TRUE);
+		io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL);
+	}
+
+	h = i_new(struct signal_handler, 1);
+	h->handler = handler;
+	h->context = context;
+	h->delayed = delayed;
+
+	/* atomically set to signal_handlers[] list */
+	h->next = signal_handlers[signo];
+	signal_handlers[signo] = h;
 }
 
-void lib_init_signals(void (*sig_quit_handler) (int))
+void lib_signals_unset_handler(int signo, signal_handler_t *handler,
+			       void *context)
 {
-#ifdef HAVE_SIGACTION
-	struct sigaction act;
-#endif
-
-        lib_signal_kill = 0;
-	lib_signal_hup_count = 0;
-	quit_handler = sig_quit_handler;
+	struct signal_handler *h, **p;
 
-	/* signal() behaviour is a bit inconsistent between systems
-	   after the signal handler has been called. If the signal
-	   isn't ignored, or your handler doesn't kill the program,
-	   sigaction() should be used. */
-#ifdef HAVE_SIGACTION
-	if (sigemptyset(&act.sa_mask) < 0)
-		i_fatal("sigemptyset(): %m");
-	act.sa_flags = 0;
-	act.sa_handler = sig_counter;
-	while (sigaction(SIGHUP, &act, NULL) < 0) {
-		if (errno != EINTR)
-			i_fatal("sigaction(): %m");
-	}
-	while (sigaction(SIGUSR1, &act, NULL) < 0) {
-		if (errno != EINTR)
-			i_fatal("sigaction(): %m");
-	}
-	while (sigaction(SIGUSR2, &act, NULL) < 0) {
-		if (errno != EINTR)
-			i_fatal("sigaction(): %m");
+	for (p = &signal_handlers[signo]; *p != NULL; p = &(*p)->next) {
+		if ((*p)->handler == handler && (*p)->context == context) {
+			h = *p;
+			*p = h->next;
+			i_free(h);
+			return;
+		}
 	}
 
-	/* we want to just ignore SIGALRM, but to get it to abort syscalls
-	   with EINTR we can't just set it to SIG_IGN. sig_counter handler
-	   is good enough. */
-	while (sigaction(SIGALRM, &act, NULL) < 0) {
-		if (errno != EINTR)
-			i_fatal("sigaction(): %m");
+	i_panic("lib_signals_unset_handler(%d, %p, %p): handler not found",
+		signo, (void *)handler, context);
+}
+
+void lib_signals_init(void)
+{
+        sig_pipe_fd[0] = sig_pipe_fd[1] = -1;
+	io_sig = NULL;
+
+	memset(signal_handlers, 0, sizeof(signal_handlers));
+}
+
+void lib_signals_deinit(void)
+{
+	struct signal_handler *handlers, *h;
+	int i;
+
+	for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
+		if (signal_handlers[i] != NULL) {
+			/* atomically remove from signal_handlers[] list */
+			handlers = signal_handlers[i];
+			signal_handlers[i] = NULL;
+
+			while (handlers != NULL) {
+				h = handlers;
+				handlers = h->next;
+				i_free(h);
+			}
+		}
 	}
-#else
-        signal(SIGHUP, sig_counter);
-        signal(SIGUSR1, sig_counter);
-        signal(SIGUSR2, sig_counter);
-        signal(SIGALRM, sig_counter);
-#endif
 
-	/* these signals should be called only once, so it's safe to use
-	   signal() */
-	signal(SIGINT, sig_quit);
-        signal(SIGTERM, sig_quit);
-        signal(SIGPIPE, SIG_IGN);
+	if (io_sig != NULL)
+		io_remove(io_sig);
+	if (sig_pipe_fd[0] != -1) {
+		if (close(sig_pipe_fd[0]) < 0)
+			i_error("close(sigpipe) failed: %m");
+		if (close(sig_pipe_fd[1]) < 0)
+			i_error("close(sigpipe) failed: %m");
+	}
 }
--- a/src/lib/lib-signals.h	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/lib/lib-signals.h	Sun Sep 25 14:07:32 2005 +0300
@@ -1,10 +1,19 @@
 #ifndef __LIB_SIGNALS_H
 #define __LIB_SIGNALS_H
 
-extern int lib_signal_kill;
-extern unsigned int lib_signal_hup_count;
-extern unsigned int lib_signal_usr1_count, lib_signal_usr2_count;
+#include <signal.h>
+
+typedef void signal_handler_t(int signo, void *context);
 
-void lib_init_signals(void (*sig_quit_handler) (int));
+/* Set signal handler for specific signal. If delayed is TRUE, the handler
+   will be called later, ie. not as a real signal handler. If handler is NULL,
+   the signal is ignored. */
+void lib_signals_set_handler(int signo, int delayed,
+			     signal_handler_t *handler, void *context);
+void lib_signals_unset_handler(int signo,
+			       signal_handler_t *handler, void *context);
+
+void lib_signals_init(void);
+void lib_signals_deinit(void);
 
 #endif
--- a/src/login-common/main.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/login-common/main.c	Sun Sep 25 14:07:32 2005 +0300
@@ -74,8 +74,12 @@
 	master_notify_finished();
 }
 
-static void sig_quit(int signo __attr_unused__)
+static void sig_die(int signo, void *context __attr_unused__)
 {
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
 	io_loop_stop(ioloop);
 }
 
@@ -170,7 +174,10 @@
 {
 	const char *value;
 
-	lib_init_signals(sig_quit);
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
 
 	disable_plaintext_auth = getenv("DISABLE_PLAINTEXT_AUTH") != NULL;
 	process_per_connection = getenv("PROCESS_PER_CONNECTION") != NULL;
@@ -238,9 +245,6 @@
 
 static void main_deinit(void)
 {
-        if (lib_signal_kill != 0)
-		i_warning("Killed with signal %d", lib_signal_kill);
-
 	if (io_listen != NULL) io_remove(io_listen);
 	if (io_ssl_listen != NULL) io_remove(io_ssl_listen);
 
@@ -251,6 +255,7 @@
 	clients_deinit();
 	master_deinit();
 
+	lib_signals_deinit();
 	closelog();
 }
 
--- a/src/master/main.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/master/main.c	Sun Sep 25 14:07:32 2005 +0300
@@ -34,8 +34,6 @@
 
 static const char *configfile = SYSCONFDIR "/" PACKAGE ".conf";
 static struct timeout *to;
-static unsigned int settings_reload_hup_count = 0;
-static unsigned int log_reopen_usr1_count = 0;
 static const char *env_tz;
 
 struct ioloop *ioloop;
@@ -95,11 +93,6 @@
 	execv(executable, (char **)argv);
 }
 
-static void sig_quit(int signo __attr_unused__)
-{
-	io_loop_stop(ioloop);
-}
-
 static void set_logfile(struct settings *set)
 {
 	if (set->log_path == NULL)
@@ -134,6 +127,27 @@
 	}
 }
 
+static void sig_die(int signo, void *context __attr_unused__)
+{
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
+	io_loop_stop(ioloop);
+}
+
+static void sig_reload_settings(int signo __attr_unused__,
+				void *context __attr_unused__)
+{
+	settings_reload();
+}
+
+static void sig_reopen_logs(int signo __attr_unused__,
+			    void *context __attr_unused__)
+{
+	set_logfile(settings_root->defaults);
+}
+
 static const char *get_exit_status_message(enum fatal_exit_status status)
 {
 	switch (status) {
@@ -161,15 +175,6 @@
 	pid_t pid;
 	int status, process_type;
 
-	if (lib_signal_hup_count != settings_reload_hup_count) {
-		settings_reload_hup_count = lib_signal_hup_count;
-		settings_reload();
-	}
-	if (lib_signal_usr1_count != log_reopen_usr1_count) {
-		log_reopen_usr1_count = lib_signal_usr1_count;
-                set_logfile(settings_root->defaults);
-	}
-
 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 		/* get the type and remove from hash */
 		process_type = PID_GET_PROCESS_TYPE(pid);
@@ -511,7 +516,12 @@
 
 	log_init();
 
-	lib_init_signals(sig_quit);
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
+        lib_signals_set_handler(SIGHUP, TRUE, sig_reload_settings, NULL);
+        lib_signals_set_handler(SIGUSR1, TRUE, sig_reopen_logs, NULL);
 
 	pids = hash_create(default_pool, default_pool, 128, NULL, NULL);
 	to = timeout_add(100, timeout_handler, NULL);
@@ -526,9 +536,6 @@
 
 static void main_deinit(void)
 {
-        if (lib_signal_kill != 0)
-		i_warning("Killed with signal %d", lib_signal_kill);
-
 	(void)unlink(t_strconcat(settings_root->defaults->base_dir,
 				 "/master.pid", NULL));
 
@@ -545,6 +552,7 @@
 		i_error("close(null_fd) failed: %m");
 
 	hash_destroy(pids);
+	lib_signals_deinit();
 	log_deinit();
 	closelog();
 }
--- a/src/pop3/main.c	Sun Sep 25 13:52:27 2005 +0300
+++ b/src/pop3/main.c	Sun Sep 25 14:07:32 2005 +0300
@@ -45,8 +45,12 @@
 const char *uidl_format, *logout_format;
 enum uidl_keys uidl_keymask;
 
-static void sig_quit(int signo __attr_unused__)
+static void sig_die(int signo, void *context __attr_unused__)
 {
+	/* warn about being killed because of some signal, except SIGINT (^C)
+	   which is too common at least while testing :) */
+	if (signo != SIGINT)
+		i_warning("Killed with signal %d", signo);
 	io_loop_stop(ioloop);
 }
 
@@ -147,7 +151,10 @@
 	struct mail_storage *storage;
 	const char *str, *mail;
 
-	lib_init_signals(sig_quit);
+	lib_signals_init();
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
+        lib_signals_set_handler(SIGPIPE, FALSE, NULL, NULL);
 
 	if (getenv("USER") == NULL)
 		i_fatal("USER environment missing");
@@ -236,17 +243,13 @@
 
 static void main_deinit(void)
 {
-	/* warn about being killed because of some signal, except SIGINT (^C)
-	   which is too common at least while testing :) */
-	if (lib_signal_kill != 0 && lib_signal_kill != 2)
-		i_warning("Killed with signal %d", lib_signal_kill);
-
 	module_dir_unload(modules);
 
 	clients_deinit();
         mail_storage_deinit();
 	random_deinit();
 
+	lib_signals_deinit();
 	closelog();
 }