master-service.c revision 86791365b10f45982c88e70f2eb94fd6c3fea151
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen/* when we're full of connections, how often to check if login state has
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen just a fallback against race conditions. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_status_update(struct master_service *service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return "c:ko:Os:L";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen which is too common at least while testing :) */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen "(if you don't care, set version_ignore=yes)",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int *argc, char **argv[], const char *getopt_str)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen extern char **environ;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen restrict_access_by_env() is called */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen is properly initialized */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* keep getopt_str first in case it contains "+" */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->service_count_left = (unsigned int)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* set up some kind of logging until we know exactly how and where
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen we want to log */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint master_getopt(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while ((c = getopt(service->argc, service->argv,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!master_service_parse_option(service, c, optarg))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_init_log(struct master_service *service,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* logging via log service */
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen /* log to syslog */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* log to file or stderr */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen path = home_expand(service->set->info_log_path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path = home_expand(service->set->debug_log_path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void (*callback)(void))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool master_service_parse_option(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!array_is_created(&service->config_overrides))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append(&service->config_overrides, &arg, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_error(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count || service->die_with_master) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master wants us to die (or died itself). don't die until all
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen service connections are finished. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the log fd may also be closed already, don't die when trying to
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_init_finish(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(service->total_available_count == 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set default signal handlers */
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Must be started by dovecot master process");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* initialize master_status structure */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set the default limit */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_client_limit(service, count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set the default service count */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_service_count(service, count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* start listening errors for status fd, it means master died */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we already have a connection to be served */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_env_clean(bool preserve_home)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Note that if the original environment was set with env_put(), the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen environment strings will be invalid after env_clean(). That's why
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we t_strconcat() them above. */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen unsigned int used;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_assert(service->master_status.available_count ==
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen service->total_available_count = client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = client_limit - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = count - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void (*callback)(void))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_name(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_run(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_connection_callback_t *callback)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_stop(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* anvil process was probably recreated, don't bother
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen logging an error about losing connection to it */
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen } else if (ret == 0)
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we can listen again */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->service_count_left != service->total_available_count) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count <
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we have only limited amount of service requests left */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->io_status_error == NULL || service->listeners == NULL) &&
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* we've finished handling all clients, and
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen a) master has closed the connection
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen b) there are no listeners (std-client?) */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenstatic void master_service_set_login_state(struct master_service *service,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (service->master_status.available_count > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* some processes should now be able to handle new connections,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen although we can't. but there may be race conditions, so
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen make sure that we'll check again soon if the state has
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen changed to "full" without our knowledge. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we're listening for more connections */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Invalid master login state: %d", state);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_close_config_fd(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("close(master config fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_deinit(struct master_service **_service)
lib_deinit();
return TRUE;
return TRUE;
return FALSE;
if (ret > 0) {
} else if (ret == 0) {