view src/dict/main.c @ 4390:f0ac35961ae2 HEAD

Make sure the process dies when the master process dies.
author Timo Sirainen <tss@iki.fi>
date Sat, 17 Jun 2006 14:24:10 +0300
parents 545a747d0347
children e661182eab75
line wrap: on
line source

/* Copyright (C) 2005 Timo Sirainen */

#include "lib.h"
#include "lib-signals.h"
#include "ioloop.h"
#include "fd-close-on-exec.h"
#include "restrict-access.h"
#include "randgen.h"
#include "sql-api.h"
#include "dict-sql.h"
#include "dict-client.h"
#include "dict-server.h"
#include "module-dir.h"

#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>

#define DICT_MASTER_LISTENER_FD 3

struct ioloop *ioloop;

static struct io *log_io;
static struct module *modules;
static struct dict_server *dict_server;

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 log_error_callback(void *context __attr_unused__)
{
	io_loop_stop(ioloop);
}

static void drop_privileges(void)
{
	/* Log file or syslog opening probably requires roots */
	i_set_failure_internal();

	/* Maybe needed. Have to open /dev/urandom before possible
	   chrooting. */
	random_init();

	/* Load built-in SQL drivers (if any) */
	sql_drivers_init();
	sql_drivers_register_all();

	restrict_access_by_env(FALSE);
}

static void main_init(void)
{
	const char *path;
	int fd;

	lib_signals_init();
        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
        lib_signals_ignore(SIGPIPE);
        lib_signals_set_handler(SIGALRM, FALSE, NULL, NULL);

	/* If master dies, the log fd gets closed and we'll quit */
	log_io = io_add(STDERR_FILENO, IO_ERROR, log_error_callback, NULL);

	dict_client_register();
	dict_sql_register();

	modules = getenv("MODULE_DIR") == NULL ? NULL :
		module_dir_load(getenv("MODULE_DIR"), NULL, TRUE);

	path = getenv("DICT_LISTEN_FROM_FD");
	fd = path == NULL ? -1 : DICT_MASTER_LISTENER_FD;
	if (path == NULL)
		path = DEFAULT_DICT_SERVER_SOCKET_PATH;

	dict_server = dict_server_init(path, fd);
}

static void main_deinit(void)
{
	io_remove(&log_io);
	dict_server_deinit(dict_server);

	module_dir_unload(&modules);

	dict_sql_unregister();
	dict_client_unregister();

	sql_drivers_deinit();
	random_deinit();
	lib_signals_deinit();
	closelog();
}

int main(void)
{
#ifdef DEBUG
	if (getenv("GDB") == NULL)
		fd_debug_verify_leaks(DICT_MASTER_LISTENER_FD+1, 1024);
#endif

	/* NOTE: we start rooted, so keep the code minimal until
	   restrict_access_by_env() is called */
	lib_init();
	drop_privileges();

	ioloop = io_loop_create(system_pool);

	main_init();
        io_loop_run(ioloop);
	main_deinit();

	io_loop_destroy(&ioloop);
	lib_deinit();

	return 0;
}