master-service.c revision 13a0b45c0e4a776d88647346ba900cd5087ba3f0
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* when we're full of connections, how often to check if login state has
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen just a fallback against race conditions. */
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return "c:ko:Os:L";
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen which is too common at least while testing :) */
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "(if you don't care, set version_ignore=yes)",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen int *argc, char **argv[], const char *getopt_str)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen const char *str;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen restrict_access_by_env() is called */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen is properly initialized */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* keep getopt_str first in case it contains "+" */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->service_count_left = (unsigned int)-1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen /* set up some kind of logging until we know exactly how and where
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen we want to log */
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint master_getopt(struct master_service *service)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while ((c = getopt(service->argc, service->argv,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!master_service_parse_option(service, c, optarg))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid master_service_init_log(struct master_service *service,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen /* logging via log service */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* log to syslog */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen /* log to file or stderr */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path = home_expand(service->set->info_log_path);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen path = home_expand(service->set->debug_log_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
836e57b1e7817d008f8ae05cd4b506f420fed80dTimo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void (*callback)(void))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenbool master_service_parse_option(struct master_service *service,
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (!array_is_created(&service->config_overrides))
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen array_append(&service->config_overrides, &arg, 1);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstatic void master_service_error(struct master_service *service)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen service->total_available_count || service->die_with_master) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen master wants us to die (or died itself). don't die until all
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen service connections are finished. */
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen /* the log fd may also be closed already, don't die when trying to
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainenvoid master_service_init_finish(struct master_service *service)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen unsigned int count;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen i_assert(service->total_available_count == 0);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* set default signal handlers */
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
3c40cf45bb10548bf434aea0fca32b99acc99a35Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_fatal("Must be started by dovecot master process");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* initialize master_status structure */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* set the default limit */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen master_service_set_client_limit(service, count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* set the default service count */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen master_service_set_service_count(service, count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* start listening errors for status fd, it means master died */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* we already have a connection to be served */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenvoid master_service_env_clean(bool preserve_home)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* Note that if the original environment was set with env_put(), the
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen environment strings will be invalid after env_clean(). That's why
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen we t_strconcat() them above. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen unsigned int used;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(service->master_status.available_count ==
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->total_available_count = client_limit;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->master_status.available_count = client_limit - used;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen unsigned int count)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int used;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen service->master_status.available_count = count - used;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainen void (*callback)(void))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
553cf4f8a8850efffdc714ec1d1ae45a5fc7905dTimo Sirainenconst char *master_service_get_name(struct master_service *service)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenvoid master_service_run(struct master_service *service,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen master_service_connection_callback_t *callback)
unsigned int current_count;
if (current_count == 0)
if (ret < 0) {
} else if (ret == 0)
switch (state) {
service);
case MASTER_LOGIN_STATE_FULL:
int ret;
if (ret < 0)
lib_deinit();
return TRUE;
return TRUE;
return FALSE;
if (ret > 0) {
} else if (ret == 0) {