You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  1. /*
  2. * Copyright (c) 2009-2012, Vsevolod Stakhov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "config.h"
  25. #include "main.h"
  26. #include "cfg_file.h"
  27. #include "util.h"
  28. #include "lmtp.h"
  29. #include "smtp.h"
  30. #include "map.h"
  31. #include "fuzzy_storage.h"
  32. #include "kvstorage_server.h"
  33. #include "cfg_xml.h"
  34. #include "symbols_cache.h"
  35. #include "lua/lua_common.h"
  36. #ifdef HAVE_OPENSSL
  37. #include <openssl/rand.h>
  38. #include <openssl/err.h>
  39. #include <openssl/evp.h>
  40. #endif
  41. /* 2 seconds to fork new process in place of dead one */
  42. #define SOFT_FORK_TIME 2
  43. /* 10 seconds after getting termination signal to terminate all workers with SIGKILL */
  44. #define HARD_TERMINATION_TIME 10
  45. static struct rspamd_worker *fork_worker (struct rspamd_main *, struct worker_conf *);
  46. static gboolean load_rspamd_config (struct config_file *cfg, gboolean init_modules);
  47. static void init_cfg_cache (struct config_file *cfg);
  48. sig_atomic_t do_restart = 0;
  49. sig_atomic_t do_reopen_log = 0;
  50. sig_atomic_t do_terminate = 0;
  51. sig_atomic_t child_dead = 0;
  52. sig_atomic_t got_alarm = 0;
  53. #ifdef HAVE_SA_SIGINFO
  54. GQueue *signals_info = NULL;
  55. #endif
  56. static gboolean config_test = FALSE;
  57. static gboolean no_fork = FALSE;
  58. static gchar **cfg_names = NULL;
  59. static gchar **lua_tests = NULL;
  60. static gchar *rspamd_user = NULL;
  61. static gchar *rspamd_group = NULL;
  62. static gchar *rspamd_pidfile = NULL;
  63. static gboolean dump_vars = FALSE;
  64. static gboolean dump_cache = FALSE;
  65. static gboolean is_debug = FALSE;
  66. static gboolean is_insecure = FALSE;
  67. /* List of workers that are pending to start */
  68. static GList *workers_pending = NULL;
  69. /* List of unrelated forked processes */
  70. static GArray *other_workers = NULL;
  71. /* List of active listen sockets indexed by worker type */
  72. static GHashTable *listen_sockets = NULL;
  73. struct rspamd_main *rspamd_main;
  74. /* Commandline options */
  75. static GOptionEntry entries[] =
  76. {
  77. { "config-test", 't', 0, G_OPTION_ARG_NONE, &config_test, "Do config test and exit", NULL },
  78. { "no-fork", 'f', 0, G_OPTION_ARG_NONE, &no_fork, "Do not daemonize main process", NULL },
  79. { "config", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, &cfg_names, "Specify config file(s)", NULL },
  80. { "user", 'u', 0, G_OPTION_ARG_STRING, &rspamd_user, "User to run rspamd as", NULL },
  81. { "group", 'g', 0, G_OPTION_ARG_STRING, &rspamd_group, "Group to run rspamd as", NULL },
  82. { "pid", 'p', 0, G_OPTION_ARG_STRING, &rspamd_pidfile, "Path to pidfile", NULL },
  83. { "dump-vars", 'V', 0, G_OPTION_ARG_NONE, &dump_vars, "Print all rspamd variables and exit", NULL },
  84. { "dump-cache", 'C', 0, G_OPTION_ARG_NONE, &dump_cache, "Dump symbols cache stats and exit", NULL },
  85. { "debug", 'd', 0, G_OPTION_ARG_NONE, &is_debug, "Force debug output", NULL },
  86. { "insecure", 'i', 0, G_OPTION_ARG_NONE, &is_insecure, "Ignore running workers as privileged users (insecure)", NULL },
  87. { "test-lua", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &lua_tests, "Specify lua file(s) to test", NULL },
  88. { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
  89. };
  90. #ifndef HAVE_SA_SIGINFO
  91. static void
  92. sig_handler (gint signo)
  93. #else
  94. static void
  95. sig_handler (gint signo, siginfo_t *info, void *unused)
  96. #endif
  97. {
  98. #ifdef HAVE_SA_SIGINFO
  99. siginfo_t *new_info;
  100. new_info = g_malloc (sizeof (siginfo_t));
  101. memcpy (new_info, info, sizeof (siginfo_t));
  102. g_queue_push_head (signals_info, new_info);
  103. #endif
  104. switch (signo) {
  105. case SIGHUP:
  106. do_restart = 1;
  107. break;
  108. case SIGINT:
  109. case SIGTERM:
  110. do_terminate = 1;
  111. break;
  112. case SIGCHLD:
  113. child_dead = 1;
  114. break;
  115. case SIGUSR1:
  116. do_reopen_log = 1;
  117. break;
  118. case SIGUSR2:
  119. /* Do nothing */
  120. break;
  121. case SIGALRM:
  122. got_alarm = 1;
  123. break;
  124. }
  125. }
  126. #ifdef HAVE_SA_SIGINFO
  127. static const gchar *
  128. chldsigcode (gint code) {
  129. switch (code) {
  130. #ifdef CLD_EXITED
  131. case CLD_EXITED:
  132. return "Child exited normally";
  133. case CLD_KILLED:
  134. return "Child has terminated abnormally but did not create a core file";
  135. case CLD_DUMPED:
  136. return "Child has terminated abnormally and created a core file";
  137. case CLD_TRAPPED:
  138. return "Traced child has trapped";
  139. #endif
  140. default:
  141. return "Unknown reason";
  142. }
  143. }
  144. /* Prints info about incoming signals by parsing siginfo structures */
  145. static void
  146. print_signals_info (void)
  147. {
  148. siginfo_t *inf;
  149. while ((inf = g_queue_pop_head (signals_info))) {
  150. if (inf->si_signo == SIGCHLD) {
  151. msg_info ("got SIGCHLD from child: %P; reason: '%s'",
  152. inf->si_pid, chldsigcode (inf->si_code));
  153. }
  154. else {
  155. msg_info ("got signal: '%s'; received from pid: %P; uid: %ul",
  156. g_strsignal (inf->si_signo), inf->si_pid, (gulong)inf->si_uid);
  157. }
  158. g_free (inf);
  159. }
  160. }
  161. #endif
  162. static void
  163. read_cmd_line (gint argc, gchar **argv, struct config_file *cfg)
  164. {
  165. GError *error = NULL;
  166. GOptionContext *context;
  167. guint i, cfg_num;
  168. pid_t r;
  169. context = g_option_context_new ("- run rspamd daemon");
  170. g_option_context_set_summary (context, "Summary:\n Rspamd daemon version " RVERSION "\n Release id: " RID);
  171. g_option_context_add_main_entries (context, entries, NULL);
  172. if (!g_option_context_parse (context, &argc, &argv, &error)) {
  173. fprintf (stderr, "option parsing failed: %s\n", error->message);
  174. exit (1);
  175. }
  176. cfg->no_fork = no_fork;
  177. cfg->config_test = config_test;
  178. cfg->rspamd_user = rspamd_user;
  179. cfg->rspamd_group = rspamd_group;
  180. cfg_num = cfg_names != NULL ? g_strv_length (cfg_names) : 0;
  181. if (cfg_num == 0) {
  182. cfg->cfg_name = FIXED_CONFIG_FILE;
  183. }
  184. else {
  185. cfg->cfg_name = cfg_names[0];
  186. }
  187. for (i = 1; i < cfg_num; i ++) {
  188. r = fork ();
  189. if (r == 0) {
  190. /* Spawning new main process */
  191. cfg->cfg_name = cfg_names[i];
  192. (void)setsid ();
  193. }
  194. else if (r == -1) {
  195. fprintf (stderr, "fork failed while spawning process for %s configuration file: %s\n", cfg_names[i], strerror (errno));
  196. }
  197. else {
  198. /* Save pid to the list of other main processes, we need it to ignore SIGCHLD from them */
  199. g_array_append_val (other_workers, r);
  200. }
  201. }
  202. cfg->pid_file = rspamd_pidfile;
  203. }
  204. /* Detect privilleged mode */
  205. static void
  206. detect_priv (struct rspamd_main *rspamd)
  207. {
  208. struct passwd *pwd;
  209. struct group *grp;
  210. uid_t euid;
  211. euid = geteuid ();
  212. if (euid == 0) {
  213. if (!rspamd->cfg->rspamd_user && !is_insecure) {
  214. msg_err ("cannot run rspamd workers as root user, please add -u and -g options to select a proper unprivilleged user or specify --insecure flag");
  215. exit (EXIT_FAILURE);
  216. }
  217. else if (is_insecure) {
  218. rspamd->is_privilleged = TRUE;
  219. rspamd->workers_uid = 0;
  220. rspamd->workers_gid = 0;
  221. }
  222. else {
  223. rspamd->is_privilleged = TRUE;
  224. pwd = getpwnam (rspamd->cfg->rspamd_user);
  225. if (pwd == NULL) {
  226. msg_err ("user specified does not exists (%s), aborting", strerror (errno));
  227. exit (-errno);
  228. }
  229. if (rspamd->cfg->rspamd_group) {
  230. grp = getgrnam (rspamd->cfg->rspamd_group);
  231. if (grp == NULL) {
  232. msg_err ("group specified does not exists (%s), aborting", strerror (errno));
  233. exit (-errno);
  234. }
  235. rspamd->workers_gid = grp->gr_gid;
  236. }
  237. else {
  238. rspamd->workers_gid = -1;
  239. }
  240. rspamd->workers_uid = pwd->pw_uid;
  241. }
  242. }
  243. else {
  244. rspamd->is_privilleged = FALSE;
  245. rspamd->workers_uid = -1;
  246. rspamd->workers_gid = -1;
  247. }
  248. }
  249. static void
  250. drop_priv (struct rspamd_main *rspamd)
  251. {
  252. if (rspamd->is_privilleged) {
  253. if (setgid (rspamd->workers_gid) == -1) {
  254. msg_err ("cannot setgid to %d (%s), aborting", (gint)rspamd->workers_gid, strerror (errno));
  255. exit (-errno);
  256. }
  257. if (rspamd->cfg->rspamd_user &&
  258. initgroups (rspamd->cfg->rspamd_user, rspamd->workers_gid) == -1) {
  259. msg_err ("initgroups failed (%s), aborting", strerror (errno));
  260. exit (-errno);
  261. }
  262. if (setuid (rspamd->workers_uid) == -1) {
  263. msg_err ("cannot setuid to %d (%s), aborting", (gint)rspamd->workers_uid, strerror (errno));
  264. exit (-errno);
  265. }
  266. }
  267. }
  268. static void
  269. config_logger (struct rspamd_main *rspamd, GQuark type, gboolean is_fatal)
  270. {
  271. rspamd_set_logger (rspamd->cfg->log_type, type, rspamd);
  272. if (open_log_priv (rspamd->logger, rspamd->workers_uid, rspamd->workers_gid) == -1) {
  273. if (is_fatal) {
  274. fprintf (stderr, "Fatal error, cannot open logfile, exiting\n");
  275. exit (EXIT_FAILURE);
  276. }
  277. else {
  278. msg_err ("cannot log to file, logfile unaccessable");
  279. }
  280. }
  281. }
  282. static void
  283. parse_filters_str (struct config_file *cfg, const gchar *str)
  284. {
  285. gchar **strvec, **p;
  286. struct filter *cur;
  287. module_t **pmodule;
  288. if (str == NULL) {
  289. return;
  290. }
  291. strvec = g_strsplit_set (str, ",", 0);
  292. if (strvec == NULL) {
  293. return;
  294. }
  295. p = strvec;
  296. while (*p) {
  297. cur = NULL;
  298. /* Search modules from known C modules */
  299. pmodule = &modules[0];
  300. while (*pmodule) {
  301. g_strstrip (*p);
  302. if ((*pmodule)->name != NULL && g_ascii_strcasecmp ((*pmodule)->name, *p) == 0) {
  303. cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter));
  304. cur->type = C_FILTER;
  305. msg_debug ("found C filter %s", *p);
  306. cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p);
  307. cur->module = (*pmodule);
  308. cfg->filters = g_list_prepend (cfg->filters, cur);
  309. break;
  310. }
  311. pmodule ++;
  312. }
  313. if (cur != NULL) {
  314. /* Go to next iteration */
  315. p++;
  316. continue;
  317. }
  318. p++;
  319. }
  320. g_strfreev (strvec);
  321. }
  322. static void
  323. reread_config (struct rspamd_main *rspamd)
  324. {
  325. struct config_file *tmp_cfg;
  326. gchar *cfg_file;
  327. GList *l;
  328. struct filter *filt;
  329. GQuark type;
  330. tmp_cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
  331. if (tmp_cfg) {
  332. bzero (tmp_cfg, sizeof (struct config_file));
  333. tmp_cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
  334. init_defaults (tmp_cfg);
  335. cfg_file = memory_pool_strdup (tmp_cfg->cfg_pool, rspamd->cfg->cfg_name);
  336. /* Save some variables */
  337. tmp_cfg->cfg_name = cfg_file;
  338. tmp_cfg->lua_state = init_lua (tmp_cfg);
  339. memory_pool_add_destructor (tmp_cfg->cfg_pool, (pool_destruct_func)lua_close, tmp_cfg->lua_state);
  340. if (! load_rspamd_config (tmp_cfg, FALSE)) {
  341. msg_err ("cannot parse new config file, revert to old one");
  342. free_config (tmp_cfg);
  343. }
  344. else {
  345. msg_debug ("replacing config");
  346. free_config (rspamd->cfg);
  347. close_log (rspamd->logger);
  348. g_free (rspamd->cfg);
  349. rspamd->cfg = tmp_cfg;
  350. /* Force debug log */
  351. if (is_debug) {
  352. rspamd->cfg->log_level = G_LOG_LEVEL_DEBUG;
  353. }
  354. type = g_quark_try_string ("main");
  355. config_logger (rspamd, type, FALSE);
  356. /* Pre-init of cache */
  357. rspamd->cfg->cache = g_new0 (struct symbols_cache, 1);
  358. rspamd->cfg->cache->static_pool = memory_pool_new (memory_pool_get_size ());
  359. rspamd->cfg->cache->cfg = rspamd->cfg;
  360. /* Perform modules configuring */
  361. l = g_list_first (rspamd->cfg->filters);
  362. while (l) {
  363. filt = l->data;
  364. if (filt->module) {
  365. (void)filt->module->module_reconfig_func (rspamd->cfg);
  366. msg_debug ("reconfig of %s", filt->module->name);
  367. }
  368. l = g_list_next (l);
  369. }
  370. init_lua_filters (rspamd->cfg);
  371. init_cfg_cache (rspamd->cfg);
  372. msg_info ("config rereaded successfully");
  373. }
  374. }
  375. }
  376. static void
  377. set_worker_limits (struct worker_conf *cf)
  378. {
  379. struct rlimit rlmt;
  380. if (cf->rlimit_nofile != 0) {
  381. rlmt.rlim_cur = (rlim_t) cf->rlimit_nofile;
  382. rlmt.rlim_max = (rlim_t) cf->rlimit_nofile;
  383. if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
  384. msg_warn ("cannot set files rlimit: %d, %s", cf->rlimit_nofile, strerror (errno));
  385. }
  386. }
  387. if (cf->rlimit_maxcore != 0) {
  388. rlmt.rlim_cur = (rlim_t) cf->rlimit_maxcore;
  389. rlmt.rlim_max = (rlim_t) cf->rlimit_maxcore;
  390. if (setrlimit(RLIMIT_CORE, &rlmt) == -1) {
  391. msg_warn ("cannot set max core rlimit: %d, %s", cf->rlimit_maxcore, strerror (errno));
  392. }
  393. }
  394. }
  395. static struct rspamd_worker *
  396. fork_worker (struct rspamd_main *rspamd, struct worker_conf *cf)
  397. {
  398. struct rspamd_worker *cur;
  399. /* Starting worker process */
  400. cur = (struct rspamd_worker *)g_malloc (sizeof (struct rspamd_worker));
  401. if (cur) {
  402. bzero (cur, sizeof (struct rspamd_worker));
  403. cur->srv = rspamd;
  404. cur->type = cf->type;
  405. cur->pid = fork ();
  406. cur->cf = g_malloc (sizeof (struct worker_conf));
  407. memcpy (cur->cf, cf, sizeof (struct worker_conf));
  408. cur->pending = FALSE;
  409. cur->ctx = cf->ctx;
  410. switch (cur->pid) {
  411. case 0:
  412. /* Update pid for logging */
  413. update_log_pid (cf->type, rspamd->logger);
  414. /* Lock statfile pool if possible */
  415. statfile_pool_lockall (rspamd->statfile_pool);
  416. /* Drop privilleges */
  417. drop_priv (rspamd);
  418. /* Set limits */
  419. set_worker_limits (cf);
  420. setproctitle ("%s process", cf->worker->name);
  421. rspamd_pidfile_close (rspamd->pfh);
  422. /* Do silent log reopen to avoid collisions */
  423. close_log (rspamd->logger);
  424. open_log (rspamd->logger);
  425. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
  426. # if (GLIB_MINOR_VERSION > 20)
  427. /* Ugly hack for old glib */
  428. if (!g_thread_get_initialized ()) {
  429. g_thread_init (NULL);
  430. }
  431. # else
  432. g_thread_init (NULL);
  433. # endif
  434. #endif
  435. msg_info ("starting %s process %P", cf->worker->name, getpid ());
  436. cf->worker->worker_start_func (cur);
  437. break;
  438. case -1:
  439. msg_err ("cannot fork main process. %s", strerror (errno));
  440. rspamd_pidfile_remove (rspamd->pfh);
  441. exit (-errno);
  442. break;
  443. default:
  444. /* Insert worker into worker's table, pid is index */
  445. g_hash_table_insert (rspamd->workers, GSIZE_TO_POINTER (cur->pid), cur);
  446. break;
  447. }
  448. }
  449. return cur;
  450. }
  451. static void
  452. set_alarm (guint seconds)
  453. {
  454. #ifdef HAVE_SETITIMER
  455. static struct itimerval itv;
  456. itv.it_interval.tv_sec = 0;
  457. itv.it_interval.tv_usec = 0;
  458. itv.it_value.tv_sec = seconds;
  459. itv.it_value.tv_usec = 0;
  460. if (setitimer (ITIMER_REAL, &itv, NULL) == -1) {
  461. msg_err ("set alarm failed: %s", strerror (errno));
  462. }
  463. #else
  464. (void)alarm (seconds);
  465. #endif
  466. }
  467. static void
  468. delay_fork (struct worker_conf *cf)
  469. {
  470. workers_pending = g_list_prepend (workers_pending, cf);
  471. set_alarm (SOFT_FORK_TIME);
  472. }
  473. static void
  474. dump_module_variables (gpointer key, gpointer value, gpointer data)
  475. {
  476. GList *cur_opt;
  477. struct module_opt *cur;
  478. cur_opt = (GList *) value;
  479. while (cur_opt) {
  480. cur = cur_opt->data;
  481. if (cur->value) {
  482. printf ("$%s = \"%s\"\n", cur->param, cur->value);
  483. }
  484. cur_opt = g_list_next (cur_opt);
  485. }
  486. }
  487. static void
  488. dump_all_variables (gpointer key, gpointer value, gpointer data)
  489. {
  490. printf ("$%s = \"%s\"\n", (gchar *)key, (gchar *)value);
  491. }
  492. static void
  493. dump_cfg_vars (struct config_file *cfg)
  494. {
  495. g_hash_table_foreach (cfg->variables, dump_all_variables, NULL);
  496. }
  497. static GList *
  498. create_listen_socket (const gchar *addr, gint port, gint family, gint listen_type)
  499. {
  500. gint listen_sock = -1;
  501. GList *result, *cur;
  502. /* Create listen sockets */
  503. result = make_universal_sockets_list (addr, port, listen_type, TRUE, TRUE, TRUE);
  504. cur = result;
  505. while (cur != NULL) {
  506. listen_sock = GPOINTER_TO_INT (cur->data);
  507. if (listen_sock != -1) {
  508. if (listen (listen_sock, -1) == -1) {
  509. msg_err ("cannot listen on socket. %s", strerror (errno));
  510. }
  511. }
  512. cur = g_list_next (cur);
  513. }
  514. return result;
  515. }
  516. static void
  517. fork_delayed (struct rspamd_main *rspamd)
  518. {
  519. GList *cur;
  520. struct worker_conf *cf;
  521. while (workers_pending != NULL) {
  522. cur = workers_pending;
  523. cf = cur->data;
  524. workers_pending = g_list_remove_link (workers_pending, cur);
  525. fork_worker (rspamd, cf);
  526. g_list_free_1 (cur);
  527. }
  528. }
  529. static inline uintptr_t
  530. make_listen_key (const gchar *addr, gint port, gint family)
  531. {
  532. uintptr_t res = 0;
  533. res = murmur32_hash (addr, strlen (addr));
  534. res ^= murmur32_hash ((guchar *)&port, sizeof (gint));
  535. return res;
  536. }
  537. static void
  538. spawn_workers (struct rspamd_main *rspamd)
  539. {
  540. GList *cur, *ls;
  541. struct worker_conf *cf;
  542. gint i;
  543. gpointer p;
  544. cur = rspamd->cfg->workers;
  545. while (cur) {
  546. cf = cur->data;
  547. if (cf->worker == NULL) {
  548. msg_err ("type of worker is unspecified, skip spawning");
  549. }
  550. else {
  551. if (cf->worker->has_socket) {
  552. if ((p = g_hash_table_lookup (listen_sockets, GINT_TO_POINTER (
  553. make_listen_key (cf->bind_addr, cf->bind_port, cf->bind_family)))) == NULL) {
  554. /* Create listen socket */
  555. ls = create_listen_socket (cf->bind_addr, cf->bind_port, cf->bind_family,
  556. cf->worker->listen_type);
  557. if (ls == NULL) {
  558. exit (-errno);
  559. }
  560. g_hash_table_insert (listen_sockets, GINT_TO_POINTER (
  561. make_listen_key (cf->bind_addr, cf->bind_port, cf->bind_family)),
  562. ls);
  563. }
  564. else {
  565. /* We had socket for this type of worker */
  566. ls = p;
  567. }
  568. cf->listen_socks = ls;
  569. }
  570. if (cf->worker->unique) {
  571. if (cf->count > 1) {
  572. msg_err ("cannot spawn more than 1 %s worker, so spawn one", cf->worker->name);
  573. }
  574. fork_worker (rspamd, cf);
  575. }
  576. else if (cf->worker->threaded) {
  577. fork_worker (rspamd, cf);
  578. }
  579. else {
  580. for (i = 0; i < cf->count; i++) {
  581. fork_worker (rspamd, cf);
  582. }
  583. }
  584. }
  585. cur = g_list_next (cur);
  586. }
  587. }
  588. static void
  589. kill_old_workers (gpointer key, gpointer value, gpointer unused)
  590. {
  591. struct rspamd_worker *w = value;
  592. kill (w->pid, SIGUSR2);
  593. msg_info ("send signal to worker %P", w->pid);
  594. }
  595. static gboolean
  596. wait_for_workers (gpointer key, gpointer value, gpointer unused)
  597. {
  598. struct rspamd_worker *w = value;
  599. gint res = 0;
  600. if (got_alarm) {
  601. got_alarm = 0;
  602. /* Set alarm for hard termination but with less time */
  603. set_alarm (HARD_TERMINATION_TIME / 10);
  604. }
  605. if (waitpid (w->pid, &res, 0) == -1) {
  606. if (errno == EINTR) {
  607. got_alarm = 1;
  608. if (w->cf->worker->killable) {
  609. msg_info ("terminate worker %P with SIGKILL", w->pid);
  610. kill (w->pid, SIGKILL);
  611. }
  612. else {
  613. msg_info ("waiting for workers to sync");
  614. wait_for_workers (key, value, unused);
  615. return TRUE;
  616. }
  617. }
  618. }
  619. msg_info ("%s process %P terminated %s", g_quark_to_string (w->type), w->pid,
  620. got_alarm ? "hardly" : "softly");
  621. g_free (w->cf);
  622. g_free (w);
  623. return TRUE;
  624. }
  625. static void
  626. reopen_log_handler (gpointer key, gpointer value, gpointer unused)
  627. {
  628. struct rspamd_worker *w = value;
  629. if (kill (w->pid, SIGUSR1) == -1) {
  630. msg_err ("kill failed for pid %P: %s", w->pid, strerror (errno));
  631. }
  632. }
  633. static void
  634. preload_statfiles (struct rspamd_main *rspamd)
  635. {
  636. struct classifier_config *cf;
  637. struct statfile *st;
  638. stat_file_t *stf;
  639. GList *cur_cl, *cur_st;
  640. cur_cl = rspamd->cfg->classifiers;
  641. while (cur_cl) {
  642. /* Open all statfiles */
  643. cf = cur_cl->data;
  644. cur_st = cf->statfiles;
  645. while (cur_st) {
  646. st = cur_st->data;
  647. stf = statfile_pool_open (rspamd->statfile_pool, st->path, st->size, FALSE);
  648. if (stf == NULL) {
  649. msg_warn ("preload of %s from %s failed", st->symbol, st->path);
  650. }
  651. cur_st = g_list_next (cur_st);
  652. }
  653. cur_cl = g_list_next (cur_cl);
  654. }
  655. }
  656. static gboolean
  657. load_rspamd_config (struct config_file *cfg, gboolean init_modules)
  658. {
  659. GList *l;
  660. struct filter *filt;
  661. struct module_ctx *cur_module = NULL;
  662. if (! read_xml_config (cfg, cfg->cfg_name)) {
  663. return FALSE;
  664. }
  665. /* Strictly set temp dir */
  666. if (!cfg->temp_dir) {
  667. msg_warn ("tempdir is not set, trying to use $TMPDIR");
  668. cfg->temp_dir = memory_pool_strdup (cfg->cfg_pool, getenv ("TMPDIR"));
  669. if (!cfg->temp_dir) {
  670. msg_warn ("$TMPDIR is empty too, using /tmp as default");
  671. cfg->temp_dir = memory_pool_strdup (cfg->cfg_pool, "/tmp");
  672. }
  673. }
  674. /* Do post-load actions */
  675. post_load_config (cfg);
  676. parse_filters_str (cfg, cfg->filters_str);
  677. if (init_modules) {
  678. /* Init C modules */
  679. l = g_list_first (cfg->filters);
  680. while (l) {
  681. filt = l->data;
  682. if (filt->module) {
  683. cur_module = memory_pool_alloc (cfg->cfg_pool, sizeof (struct module_ctx));
  684. if (filt->module->module_init_func (cfg, &cur_module) == 0) {
  685. g_hash_table_insert (cfg->c_modules, (gpointer) filt->module->name, cur_module);
  686. }
  687. }
  688. l = g_list_next (l);
  689. }
  690. }
  691. return TRUE;
  692. }
  693. static void
  694. init_cfg_cache (struct config_file *cfg)
  695. {
  696. if (!init_symbols_cache (cfg->cfg_pool, cfg->cache, cfg, cfg->cache_filename, FALSE)) {
  697. exit (EXIT_FAILURE);
  698. }
  699. }
  700. static void
  701. print_symbols_cache (struct config_file *cfg)
  702. {
  703. GList *cur;
  704. struct cache_item *item;
  705. gint i;
  706. if (!init_symbols_cache (cfg->cfg_pool, cfg->cache, cfg, cfg->cache_filename, TRUE)) {
  707. exit (EXIT_FAILURE);
  708. }
  709. if (cfg->cache) {
  710. printf ("Symbols cache\n");
  711. printf ("-----------------------------------------------------------------\n");
  712. printf ("| Pri | Symbol | Weight | Frequency | Avg. time |\n");
  713. i = 0;
  714. cur = cfg->cache->negative_items;
  715. while (cur) {
  716. item = cur->data;
  717. if (!item->is_callback) {
  718. printf ("-----------------------------------------------------------------\n");
  719. printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time);
  720. }
  721. cur = g_list_next (cur);
  722. i ++;
  723. }
  724. cur = cfg->cache->static_items;
  725. while (cur) {
  726. item = cur->data;
  727. if (!item->is_callback) {
  728. printf ("-----------------------------------------------------------------\n");
  729. printf ("| %3d | %22s | %6.1f | %9d | %9.3f |\n", i, item->s->symbol, item->s->weight, item->s->frequency, item->s->avg_time);
  730. }
  731. cur = g_list_next (cur);
  732. i ++;
  733. }
  734. printf ("-----------------------------------------------------------------\n");
  735. }
  736. }
  737. static gint
  738. perform_lua_tests (struct config_file *cfg)
  739. {
  740. gint i, tests_num, res = EXIT_SUCCESS;
  741. gchar *cur_script;
  742. lua_State *L = cfg->lua_state;
  743. tests_num = g_strv_length (lua_tests);
  744. for (i = 0; i < tests_num; i ++) {
  745. if (luaL_loadfile (L, lua_tests[i]) != 0) {
  746. msg_err ("load of %s failed: %s", lua_tests[i], lua_tostring (L, -1));
  747. res = EXIT_FAILURE;
  748. continue;
  749. }
  750. cur_script = g_strdup (lua_tests[i]);
  751. lua_pushstring (L, cur_script);
  752. lua_setglobal (L, "test_script");
  753. lua_pushstring (L, dirname (cur_script));
  754. lua_setglobal (L, "test_dir");
  755. g_free (cur_script);
  756. /* do the call (0 arguments, N result) */
  757. if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
  758. msg_info ("init of %s failed: %s", lua_tests[i], lua_tostring (L, -1));
  759. res = EXIT_FAILURE;
  760. continue;
  761. }
  762. if (lua_gettop (L) != 0) {
  763. if (lua_tonumber (L, -1) == -1) {
  764. msg_info ("%s returned -1 that indicates configuration error", lua_tests[i]);
  765. res = EXIT_FAILURE;
  766. continue;
  767. }
  768. lua_pop (L, lua_gettop (L));
  769. }
  770. }
  771. return res;
  772. }
  773. gint
  774. main (gint argc, gchar **argv, gchar **env)
  775. {
  776. gint res = 0, i;
  777. struct sigaction signals;
  778. struct rspamd_worker *cur;
  779. struct rlimit rlim;
  780. struct filter *filt;
  781. pid_t wrk;
  782. GList *l;
  783. worker_t **pworker;
  784. GQuark type;
  785. #ifdef HAVE_OPENSSL
  786. gchar rand_bytes[sizeof (guint32)];
  787. guint32 rand_seed;
  788. #endif
  789. #ifdef HAVE_SA_SIGINFO
  790. signals_info = g_queue_new ();
  791. #endif
  792. #if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
  793. g_thread_init (NULL);
  794. #endif
  795. rspamd_main = (struct rspamd_main *)g_malloc (sizeof (struct rspamd_main));
  796. memset (rspamd_main, 0, sizeof (struct rspamd_main));
  797. rspamd_main->server_pool = memory_pool_new (memory_pool_get_size ());
  798. rspamd_main->cfg = (struct config_file *)g_malloc (sizeof (struct config_file));
  799. if (!rspamd_main || !rspamd_main->cfg) {
  800. fprintf (stderr, "Cannot allocate memory\n");
  801. exit (-errno);
  802. }
  803. #ifndef HAVE_SETPROCTITLE
  804. init_title (argc, argv, env);
  805. #endif
  806. rspamd_main->stat = memory_pool_alloc_shared (rspamd_main->server_pool, sizeof (struct rspamd_stat));
  807. memset (rspamd_main->stat, 0, sizeof (struct rspamd_stat));
  808. memset (rspamd_main->cfg, 0, sizeof (struct config_file));
  809. rspamd_main->cfg->cfg_pool = memory_pool_new (memory_pool_get_size ());
  810. init_defaults (rspamd_main->cfg);
  811. memset (&signals, 0, sizeof (struct sigaction));
  812. other_workers = g_array_new (FALSE, TRUE, sizeof (pid_t));
  813. read_cmd_line (argc, argv, rspamd_main->cfg);
  814. if (rspamd_main->cfg->config_test || is_debug) {
  815. rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
  816. }
  817. else {
  818. rspamd_main->cfg->log_level = G_LOG_LEVEL_CRITICAL;
  819. }
  820. type = g_quark_from_static_string ("main");
  821. #ifdef HAVE_SETLOCALE
  822. /* Set locale setting to C locale to avoid problems in future */
  823. setlocale (LC_ALL, "C");
  824. setlocale (LC_CTYPE, "C");
  825. setlocale (LC_MESSAGES, "C");
  826. setlocale (LC_TIME, "C");
  827. #endif
  828. #ifdef HAVE_OPENSSL
  829. ERR_load_crypto_strings ();
  830. /* Init random generator */
  831. if (RAND_bytes (rand_bytes, sizeof (rand_bytes)) != 1) {
  832. msg_err ("cannot seed random generator using openssl: %s, using time", ERR_error_string (ERR_get_error (), NULL));
  833. g_random_set_seed (time (NULL));
  834. }
  835. else {
  836. memcpy (&rand_seed, rand_bytes, sizeof (guint32));
  837. g_random_set_seed (rand_seed);
  838. }
  839. OpenSSL_add_all_algorithms ();
  840. OpenSSL_add_all_ciphers ();
  841. #endif
  842. /* First set logger to console logger */
  843. rspamd_set_logger (RSPAMD_LOG_CONSOLE, type, rspamd_main);
  844. (void)open_log (rspamd_main->logger);
  845. g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
  846. detect_priv (rspamd_main);
  847. rspamd_main->cfg->lua_state = init_lua (rspamd_main->cfg);
  848. memory_pool_add_destructor (rspamd_main->cfg->cfg_pool, (pool_destruct_func)lua_close, rspamd_main->cfg->lua_state);
  849. pworker = &workers[0];
  850. while (*pworker) {
  851. /* Init string quarks */
  852. (void)g_quark_from_static_string ((*pworker)->name);
  853. pworker ++;
  854. }
  855. /* Init counters */
  856. rspamd_main->counters = rspamd_hash_new_shared (rspamd_main->server_pool, rspamd_str_hash, rspamd_str_equal, 64);
  857. /* Init listen sockets hash */
  858. listen_sockets = g_hash_table_new (g_direct_hash, g_direct_equal);
  859. /* Init classifiers options */
  860. register_classifier_opt ("bayes", "min_tokens");
  861. register_classifier_opt ("winnow", "min_tokens");
  862. register_classifier_opt ("bayes", "max_tokens");
  863. register_classifier_opt ("winnow", "max_tokens");
  864. register_classifier_opt ("winnow", "learn_threshold");
  865. /* Pre-init of cache */
  866. rspamd_main->cfg->cache = g_new0 (struct symbols_cache, 1);
  867. rspamd_main->cfg->cache->static_pool = memory_pool_new (memory_pool_get_size ());
  868. rspamd_main->cfg->cache->cfg = rspamd_main->cfg;
  869. rspamd_main->cfg->cache->items_by_symbol = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  870. /* If we want to test lua skip everything except it */
  871. if (lua_tests != NULL && lua_tests[0] != NULL) {
  872. exit (perform_lua_tests (rspamd_main->cfg));
  873. }
  874. /* Load config */
  875. if (! load_rspamd_config (rspamd_main->cfg, TRUE)) {
  876. exit (EXIT_FAILURE);
  877. }
  878. /* Force debug log */
  879. if (is_debug) {
  880. rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
  881. }
  882. if (rspamd_main->cfg->config_test || dump_vars || dump_cache) {
  883. /* Init events to test modules */
  884. event_init ();
  885. res = TRUE;
  886. if (! init_lua_filters (rspamd_main->cfg)) {
  887. res = FALSE;
  888. }
  889. if (!check_modules_config (rspamd_main->cfg)) {
  890. res = FALSE;
  891. }
  892. /* Perform modules configuring */
  893. l = g_list_first (rspamd_main->cfg->filters);
  894. while (l) {
  895. filt = l->data;
  896. if (filt->module) {
  897. if (!filt->module->module_config_func (rspamd_main->cfg)) {
  898. res = FALSE;
  899. }
  900. }
  901. l = g_list_next (l);
  902. }
  903. /* Insert classifiers symbols */
  904. (void)insert_classifier_symbols (rspamd_main->cfg);
  905. if (! validate_cache (rspamd_main->cfg->cache, rspamd_main->cfg, FALSE)) {
  906. res = FALSE;
  907. }
  908. if (dump_vars) {
  909. dump_cfg_vars (rspamd_main->cfg);
  910. }
  911. if (dump_cache) {
  912. print_symbols_cache (rspamd_main->cfg);
  913. exit (EXIT_SUCCESS);
  914. }
  915. fprintf (stderr, "syntax %s\n", res ? "OK" : "BAD");
  916. return res ? EXIT_SUCCESS : EXIT_FAILURE;
  917. }
  918. /* Set stack size for pcre */
  919. getrlimit (RLIMIT_STACK, &rlim);
  920. rlim.rlim_cur = 100 * 1024 * 1024;
  921. setrlimit (RLIMIT_STACK, &rlim);
  922. config_logger (rspamd_main, type, TRUE);
  923. /* Create rolling history */
  924. rspamd_main->history = rspamd_roll_history_new (rspamd_main->server_pool);
  925. msg_info ("rspamd " RVERSION " is starting, build id: " RID);
  926. rspamd_main->cfg->cfg_name = memory_pool_strdup (rspamd_main->cfg->cfg_pool, rspamd_main->cfg->cfg_name);
  927. /* Daemonize */
  928. if (!rspamd_main->cfg->no_fork && daemon (0, 0) == -1) {
  929. fprintf (stderr, "Cannot daemonize\n");
  930. exit (-errno);
  931. }
  932. /* Write info */
  933. rspamd_main->pid = getpid ();
  934. rspamd_main->type = type;
  935. init_signals (&signals, sig_handler);
  936. if (write_pid (rspamd_main) == -1) {
  937. msg_err ("cannot write pid file %s", rspamd_main->cfg->pid_file);
  938. exit (-errno);
  939. }
  940. /* Block signals to use sigsuspend in future */
  941. sigprocmask (SIG_BLOCK, &signals.sa_mask, NULL);
  942. setproctitle ("main process");
  943. /* Init statfile pool */
  944. rspamd_main->statfile_pool = statfile_pool_new (rspamd_main->server_pool, rspamd_main->cfg->max_statfile_size, rspamd_main->cfg->mlock_statfile_pool);
  945. event_init ();
  946. g_mime_init (0);
  947. /* Init lua filters */
  948. if (! init_lua_filters (rspamd_main->cfg)) {
  949. msg_err ("error loading lua plugins");
  950. exit (EXIT_FAILURE);
  951. }
  952. /* Check configuration for modules */
  953. (void)check_modules_config (rspamd_main->cfg);
  954. /* Insert classifiers symbols */
  955. (void)insert_classifier_symbols (rspamd_main->cfg);
  956. /* Perform modules configuring */
  957. l = g_list_first (rspamd_main->cfg->filters);
  958. while (l) {
  959. filt = l->data;
  960. if (filt->module) {
  961. if (!filt->module->module_config_func (rspamd_main->cfg)) {
  962. res = FALSE;
  963. }
  964. }
  965. l = g_list_next (l);
  966. }
  967. /* Init config cache */
  968. init_cfg_cache (rspamd_main->cfg);
  969. /* Validate cache */
  970. (void)validate_cache (rspamd_main->cfg->cache, rspamd_main->cfg, FALSE);
  971. /* Flush log */
  972. flush_log_buf (rspamd_main->logger);
  973. /* Preload all statfiles */
  974. preload_statfiles (rspamd_main);
  975. /* Maybe read roll history */
  976. if (rspamd_main->cfg->history_file) {
  977. rspamd_roll_history_load (rspamd_main->history, rspamd_main->cfg->history_file);
  978. }
  979. /* Spawn workers */
  980. rspamd_main->workers = g_hash_table_new (g_direct_hash, g_direct_equal);
  981. spawn_workers (rspamd_main);
  982. /* Signal processing cycle */
  983. for (;;) {
  984. msg_debug ("calling sigsuspend");
  985. sigemptyset (&signals.sa_mask);
  986. sigsuspend (&signals.sa_mask);
  987. #ifdef HAVE_SA_SIGINFO
  988. print_signals_info ();
  989. #endif
  990. if (do_terminate) {
  991. do_terminate = 0;
  992. msg_info ("catch termination signal, waiting for children");
  993. pass_signal_worker (rspamd_main->workers, SIGTERM);
  994. break;
  995. }
  996. if (child_dead) {
  997. child_dead = 0;
  998. msg_debug ("catch SIGCHLD signal, finding terminated worker");
  999. /* Remove dead child form children list */
  1000. wrk = waitpid (0, &res, 0);
  1001. if ((cur = g_hash_table_lookup (rspamd_main->workers, GSIZE_TO_POINTER (wrk))) != NULL) {
  1002. /* Unlink dead process from queue and hash table */
  1003. g_hash_table_remove (rspamd_main->workers, GSIZE_TO_POINTER (wrk));
  1004. if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
  1005. /* Normal worker termination, do not fork one more */
  1006. msg_info ("%s process %P terminated normally", g_quark_to_string (cur->type), cur->pid);
  1007. }
  1008. else {
  1009. if (WIFSIGNALED (res)) {
  1010. msg_warn ("%s process %P terminated abnormally by signal: %d", g_quark_to_string (cur->type), cur->pid, WTERMSIG (res));
  1011. }
  1012. else {
  1013. msg_warn ("%s process %P terminated abnormally", g_quark_to_string (cur->type), cur->pid);
  1014. }
  1015. /* Fork another worker in replace of dead one */
  1016. delay_fork (cur->cf);
  1017. }
  1018. g_free (cur);
  1019. }
  1020. else {
  1021. for (i = 0; i < (gint)other_workers->len; i ++) {
  1022. if (g_array_index (other_workers, pid_t, i) == wrk) {
  1023. g_array_remove_index_fast (other_workers, i);
  1024. msg_info ("related process %P terminated", wrk);
  1025. }
  1026. }
  1027. }
  1028. }
  1029. if (do_restart) {
  1030. do_restart = 0;
  1031. reopen_log_priv (rspamd_main->logger, rspamd_main->workers_uid, rspamd_main->workers_gid);
  1032. msg_info ("rspamd " RVERSION " is restarting");
  1033. g_hash_table_foreach (rspamd_main->workers, kill_old_workers, NULL);
  1034. remove_all_maps (rspamd_main->cfg);
  1035. reread_config (rspamd_main);
  1036. spawn_workers (rspamd_main);
  1037. }
  1038. if (do_reopen_log) {
  1039. do_reopen_log = 0;
  1040. reopen_log_priv (rspamd_main->logger, rspamd_main->workers_uid, rspamd_main->workers_gid);
  1041. g_hash_table_foreach (rspamd_main->workers, reopen_log_handler, NULL);
  1042. }
  1043. if (got_alarm) {
  1044. got_alarm = 0;
  1045. fork_delayed (rspamd_main);
  1046. }
  1047. }
  1048. /* Restore some signals */
  1049. sigemptyset (&signals.sa_mask);
  1050. sigaddset (&signals.sa_mask, SIGALRM);
  1051. sigaddset (&signals.sa_mask, SIGINT);
  1052. sigaddset (&signals.sa_mask, SIGTERM);
  1053. sigaction (SIGALRM, &signals, NULL);
  1054. sigaction (SIGTERM, &signals, NULL);
  1055. sigaction (SIGINT, &signals, NULL);
  1056. sigprocmask (SIG_UNBLOCK, &signals.sa_mask, NULL);
  1057. /* Set alarm for hard termination */
  1058. set_alarm (HARD_TERMINATION_TIME);
  1059. /* Wait for workers termination */
  1060. g_hash_table_foreach_remove (rspamd_main->workers, wait_for_workers, NULL);
  1061. /* Maybe save roll history */
  1062. if (rspamd_main->cfg->history_file) {
  1063. rspamd_roll_history_save (rspamd_main->history, rspamd_main->cfg->history_file);
  1064. }
  1065. msg_info ("terminating...");
  1066. statfile_pool_delete (rspamd_main->statfile_pool);
  1067. close_log (rspamd_main->logger);
  1068. free_config (rspamd_main->cfg);
  1069. g_free (rspamd_main->cfg);
  1070. g_free (rspamd_main);
  1071. #ifdef HAVE_OPENSSL
  1072. EVP_cleanup ();
  1073. ERR_free_strings ();
  1074. #endif
  1075. return (res);
  1076. }
  1077. /*
  1078. * vi:ts=4
  1079. */