From 86f76528fa2b3c3603c649835bbc4d0a21ed0a4d Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 20 Jan 2017 12:38:45 +0000 Subject: [PATCH] [Fix] Do not leave parent-less workers processes on fatal errors --- src/libserver/worker_util.c | 41 ++++++++++++++++++++++++++++++++++--- src/libserver/worker_util.h | 6 ++++++ src/rspamd.c | 4 +++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/libserver/worker_util.c b/src/libserver/worker_util.c index d113acc1f..ac87f2870 100644 --- a/src/libserver/worker_util.c +++ b/src/libserver/worker_util.c @@ -530,12 +530,12 @@ rspamd_fork_worker (struct rspamd_main *rspamd_main, if (!rspamd_socketpair (wrk->control_pipe)) { msg_err ("socketpair failure: %s", strerror (errno)); - exit (-errno); + rspamd_hard_terminate (rspamd_main); } if (!rspamd_socketpair (wrk->srv_pipe)) { msg_err ("socketpair failure: %s", strerror (errno)); - exit (-errno); + rspamd_hard_terminate (rspamd_main); } wrk->srv = rspamd_main; @@ -610,7 +610,7 @@ rspamd_fork_worker (struct rspamd_main *rspamd_main, case -1: msg_err_main ("cannot fork main process. %s", strerror (errno)); rspamd_pidfile_remove (rspamd_main->pfh); - exit (-errno); + rspamd_hard_terminate (rspamd_main); break; default: /* Close worker part of socketpair */ @@ -641,3 +641,38 @@ rspamd_worker_block_signals (void) sigaddset (&set, SIGUSR2); sigprocmask (SIG_BLOCK, &set, NULL); } + +void +rspamd_hard_terminate (struct rspamd_main *rspamd_main) +{ + GHashTableIter it; + gpointer k, v; + struct rspamd_worker *w; + sigset_t set; + + /* Block all signals */ + sigemptyset (&set); + sigaddset (&set, SIGTERM); + sigaddset (&set, SIGINT); + sigaddset (&set, SIGHUP); + sigaddset (&set, SIGUSR1); + sigaddset (&set, SIGUSR2); + sigaddset (&set, SIGCHLD); + sigprocmask (SIG_BLOCK, &set, NULL); + + /* We need to terminate all workers that might be already spawned */ + rspamd_worker_block_signals (); + g_hash_table_iter_init (&it, rspamd_main->workers); + + while (g_hash_table_iter_next (&it, &k, &v)) { + w = v; + msg_err_main ("kill worker %p as Rspamd is terminating due to " + "an unrecoverable error", w->pid); + kill (w->pid, SIGKILL); + } + + msg_err_main ("shutting down Rspamd due to fatal error"); + + rspamd_log_close (rspamd_main->logger); + exit (EXIT_FAILURE); +} diff --git a/src/libserver/worker_util.h b/src/libserver/worker_util.h index 2ad312b0e..634ffe67b 100644 --- a/src/libserver/worker_util.h +++ b/src/libserver/worker_util.h @@ -123,6 +123,12 @@ void rspamd_worker_stop_accept (struct rspamd_worker *worker); */ void rspamd_worker_block_signals (void); +/** + * Kill rspamd main and all workers + * @param rspamd_main + */ +void rspamd_hard_terminate (struct rspamd_main *rspamd_main) G_GNUC_NORETURN; + /** * Fork new worker with the specified configuration */ diff --git a/src/rspamd.c b/src/rspamd.c index 877ac00a5..44931dfda 100644 --- a/src/rspamd.c +++ b/src/rspamd.c @@ -588,6 +588,7 @@ spawn_workers (struct rspamd_main *rspamd_main, struct event_base *ev_base) cf->listen_socks = g_list_concat (cf->listen_socks, ls); } } + if (listen_ok) { spawn_worker_type (rspamd_main, ev_base, cf); } @@ -595,7 +596,8 @@ spawn_workers (struct rspamd_main *rspamd_main, struct event_base *ev_base) msg_err_main ("cannot create listen socket for %s at %s", g_quark_to_string (cf->type), cf->bind_conf->name); - exit (EXIT_FAILURE); + rspamd_hard_terminate (rspamd_main); + g_assert_not_reached (); } } else { -- 2.39.5