master-service.c revision 7487ff578435377bbeefffdbfb78ca09ed1292df
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (C) 2005-2009 Timo Sirainen */
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"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void io_listeners_add(struct master_service *service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_status_update(struct master_service *service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return "c:ks: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 Sirainenstatic void master_service_verify_version(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(if you don't care, set version_ignore=yes)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen const char *str;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo 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
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen is properly initialized */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo 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;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set up some kind of logging until we know exactly how and where
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we want to log */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_LOG_TO_STDERR) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* logging via log service */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* log to syslog */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo 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);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool master_service_parse_option(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master wants us to die (or died itself). don't die until all
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service connections are finished. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the log fd may also be closed already, don't die when trying to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_init_finish(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->total_available_count == 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set default signal handlers */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
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 /* 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) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo 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. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count = client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = client_limit;
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)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_run(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_connection_callback_t *callback)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_stop(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo 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) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we have only limited amount of service requests left */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* master has closed the connection and we have nothing else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to do anymore. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_deinit(struct master_service **_service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (l->service->master_status.available_count == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we are full. stop listening for now. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* it's not a socket. probably a fifo. use the "listener"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen as the connection fd */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void io_listeners_add(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_new(struct master_service_listener, service->socket_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_service_listener *l = &service->listeners[i];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void io_listeners_remove(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->master_status.available_count == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_status_update(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return; /* closed */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* success */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* delayed important update sent successfully */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (ret == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* shouldn't happen? */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("write(master_status_fd) returned 0");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* failure */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("write(master_status_fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (master_status_update_is_important(service)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* reader is busy, but it's important to get this notification
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen through. send it when possible. */