master-service.c revision 86791365b10f45982c88e70f2eb94fd6c3fea151
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib-signals.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "env-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "home-expand.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "process-title.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "restrict-access.h"
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#include "fd-close-on-exec.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "settings-parser.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "syslog-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "master-service-private.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "master-service-settings.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <syslog.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen
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. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#define MASTER_SERVICE_STATE_CHECK_MSECS 1000
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen force it. */
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct master_service *master_service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
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
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_getopt_string(void)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return "c:ko:Os:L";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct master_service *service = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
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 if (si->si_signo != SIGINT) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen si->si_signo, dec2str(si->si_pid),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dec2str(si->si_uid),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_loop_stop(service->ioloop);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct master_service *service = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_service_refresh_login_state(service);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (service->version_string != NULL &&
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen i_fatal("Dovecot version mismatch: "
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen "(if you don't care, set version_ignore=yes)",
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen service->name, service->version_string);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstruct master_service *
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int *argc, char **argv[], const char *getopt_str)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen extern char **environ;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct master_service *service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(name != NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#ifdef DEBUG
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (getenv("GDB") == NULL &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = getenv("SOCKET_COUNT");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count = str == NULL ? 0 : atoi(str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen restrict_access_by_env() is called */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_init();
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));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen process_title_init(argv, environ);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen service = i_new(struct master_service, 1);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen service->argc = *argc;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen service->argv = *argv;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen service->name = i_strdup(name);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* keep getopt_str first in case it contains "+" */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->getopt_str = getopt_str == NULL ?
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_strdup(master_service_getopt_string()) :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->flags = flags;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->ioloop = io_loop_create();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->service_count_left = (unsigned int)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->config_fd = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (service->config_path == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->socket_count = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->version_string = PACKAGE_VERSION;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = getenv("SOCKET_COUNT");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str != NULL)
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen service->socket_count = atoi(str);
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen str = getenv("SSL_SOCKET_COUNT");
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen if (str != NULL)
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen service->ssl_socket_count = atoi(str);
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen /* set up some kind of logging until we know exactly how and where
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen we want to log */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_internal();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (getenv("USER") != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen name, getenv("USER")));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_verify_version(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return service;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint master_getopt(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int c;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen while ((c = getopt(service->argc, service->argv,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->getopt_str)) > 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!master_service_parse_option(service, c, optarg))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return c;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_init_log(struct master_service *service,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *prefix)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *path;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_file("/dev/stderr", "");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* logging via log service */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_internal();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(prefix);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (service->set == NULL) {
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen i_set_failure_file("/dev/stderr", prefix);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen return;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen }
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (*service->set->log_path == '\0') {
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen /* log to syslog */
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen int facility;
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &facility))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen facility = LOG_MAIL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_prefix(prefix);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* log to file or stderr */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen path = home_expand(service->set->log_path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_file(path, prefix);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen path = home_expand(service->set->info_log_path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*path != '\0')
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_info_file(path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path = home_expand(service->set->debug_log_path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*path != '\0')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_debug_file(path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool set)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->die_with_master = set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void (*callback)(void))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
7f13786e6a18a846376e46d77349528d99935871Timo Sirainen service->die_callback = callback;
7f13786e6a18a846376e46d77349528d99935871Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool master_service_parse_option(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int opt, const char *arg)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (opt) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'c':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->config_path = arg;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'k':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->keep_environment = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'o':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!array_is_created(&service->config_overrides))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_array_init(&service->config_overrides, 16);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append(&service->config_overrides, &arg, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'O':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 's':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((i = atoi(arg)) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Invalid socket count: %s", arg);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->socket_count = i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case 'L':
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->log_directly = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen default:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_error(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_listeners_remove(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count || service->die_with_master) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->die_callback == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_stop(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->to_die =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_add(MASTER_SERVICE_DIE_TIMEOUT_MSECS,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_stop,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->die_callback();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_status_error(void *context)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_service *service = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
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. */
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen io_remove(&service->io_status_error);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* the log fd may also be closed already, don't die when trying to
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen log later */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_ignore_errors(TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_service_error(service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_init_finish(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *value;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(service->total_available_count == 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set default signal handlers */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signals_init();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
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) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signals_set_handler(SIGUSR1, TRUE,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sig_state_changed, service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* initialize master_status structure */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen value = getenv(MASTER_UID_ENV);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (value == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal(MASTER_UID_ENV" not set");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.pid = getpid();
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.uid =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set the default limit */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen count = value == NULL ? 0 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (count == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" not set");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_client_limit(service, count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set the default service count */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen value = getenv(MASTER_SERVICE_COUNT_ENV);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen count = value == NULL ? 0 :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (count > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_service_count(service, count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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 master_status_error, service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_client_limit(service, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_service_count(service, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_io_listeners_add(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we already have a connection to be served */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->master_status.available_count--;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_status_update(service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_env_clean(bool preserve_home)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *user, *tz, *home;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#ifdef DEBUG
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen bool gdb = getenv("GDB") != NULL;
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen#endif
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen user = getenv("USER");
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen if (user != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen user = t_strconcat("USER=", user, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen tz = getenv("TZ");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (tz != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen home = preserve_home ? getenv("HOME") : NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (home != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen home = t_strconcat("HOME=", home, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
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. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen env_clean();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (user != NULL) env_put(user);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (tz != NULL) env_put(tz);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (home != NULL) env_put(home);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#ifdef DEBUG
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (gdb) env_put("GDB=1");
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#endif
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen unsigned int client_limit)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen unsigned int used;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen i_assert(service->master_status.available_count ==
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service->total_available_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen used = service->total_available_count -
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(client_limit >= used);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen service->total_available_count = client_limit;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = client_limit - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return service->total_available_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen used = service->total_available_count -
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(count >= used);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->total_available_count > count) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count = count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = count - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->service_count_left = count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return service->service_count_left;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return service->socket_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen void (*callback)(void))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->avail_overflow_callback = callback;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen{
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen return service->config_path;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen{
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen return service->version_string;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_name(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return service->name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_run(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_connection_callback_t *callback)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->callback = callback;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_loop_run(service->ioloop);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->callback = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_stop(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_loop_stop(service->ioloop);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ssize_t ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno == EPIPE) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* anvil process was probably recreated, don't bother
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen logging an error about losing connection to it */
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen return;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_error("write(anvil) failed: %m");
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen } else if (ret == 0)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_error("write(anvil) failed: EOF");
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen else {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen i_assert((size_t)ret == strlen(cmd));
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we can listen again */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_io_listeners_add(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->total_available_count > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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 service->total_available_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we have only limited amount of service requests left */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->service_count_left > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->service_count_left--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->service_count_left == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_stop(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen master_status_update(service);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->io_status_error == NULL || service->listeners == NULL) &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count) {
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 Sirainen master_service_stop(service);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen }
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen}
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenstatic void master_service_set_login_state(struct master_service *service,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen enum master_login_state state)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen{
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (service->to_overflow_state != NULL)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen timeout_remove(&service->to_overflow_state);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen switch (state) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen case MASTER_LOGIN_STATE_NONFULL:
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen service->call_avail_overflow = FALSE;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (service->master_status.available_count > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
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 service->to_overflow_state =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_add(MASTER_SERVICE_STATE_CHECK_MSECS,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_refresh_login_state,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case MASTER_LOGIN_STATE_FULL:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we're listening for more connections */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->call_avail_overflow = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_io_listeners_add(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("Invalid master login state: %d", state);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("lseek(login notify fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_set_login_state(service, ret);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_close_config_fd(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->config_fd != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (close(service->config_fd) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("close(master config fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->config_fd = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_deinit(struct master_service **_service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_service *service = *_service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *_service = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_listeners_remove(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_close_config_fd(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->to_die != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&service->to_die);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->to_overflow_state != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&service->to_overflow_state);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->io_status_error != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_remove(&service->io_status_error);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
if (array_is_created(&service->config_overrides))
array_free(&service->config_overrides);
if (service->set_parser != NULL) {
settings_parser_deinit(&service->set_parser);
pool_unref(&service->set_pool);
}
lib_signals_deinit();
io_loop_destroy(&service->ioloop);
i_free(service->listeners);
i_free(service->getopt_str);
i_free(service->name);
i_free(service);
lib_deinit();
}
static void master_service_listen(struct master_service_listener *l)
{
struct master_service *service = l->service;
struct master_service_connection conn;
if (service->master_status.available_count == 0) {
/* we are full. stop listening for now, unless overflow
callback destroys one of the existing connections */
if (service->call_avail_overflow &&
service->avail_overflow_callback != NULL) {
service->delay_status_updates = TRUE;
service->avail_overflow_callback();
service->delay_status_updates = FALSE;
}
if (service->master_status.available_count == 0) {
io_listeners_remove(service);
return;
}
}
memset(&conn, 0, sizeof(conn));
conn.listen_fd = l->fd;
conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
if (conn.fd < 0) {
if (conn.fd == -1)
return;
if (errno != ENOTSOCK) {
i_error("net_accept() failed: %m");
master_service_error(service);
return;
}
/* it's not a socket. probably a fifo. use the "listener"
as the connection fd and stop the listener. */
conn.fd = l->fd;
conn.listen_fd = l->fd;
conn.fifo = TRUE;
io_remove(&l->io);
l->fd = -1;
}
conn.ssl = l->ssl;
net_set_nonblock(conn.fd, TRUE);
service->master_status.available_count--;
master_status_update(service);
service->callback(&conn);
if (service->master_status.available_count == 0 &&
service->service_count_left == 1) {
/* we're dying as soon as this connection closes. */
master_service_close_config_fd(service);
}
}
static void io_listeners_init(struct master_service *service)
{
unsigned int i;
if (service->socket_count == 0)
return;
service->listeners =
i_new(struct master_service_listener, service->socket_count);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
l->service = service;
l->fd = MASTER_LISTEN_FD_FIRST + i;
if (i >= service->socket_count - service->ssl_socket_count)
l->ssl = TRUE;
}
}
void master_service_io_listeners_add(struct master_service *service)
{
unsigned int i;
if (service->listeners == NULL)
io_listeners_init(service);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
if (l->io == NULL && l->fd != -1) {
l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
master_service_listen, l);
}
}
}
static void io_listeners_remove(struct master_service *service)
{
unsigned int i;
if (service->listeners != NULL) {
for (i = 0; i < service->socket_count; i++) {
if (service->listeners[i].io != NULL)
io_remove(&service->listeners[i].io);
}
}
}
static bool master_status_update_is_important(struct master_service *service)
{
if (service->master_status.available_count == 0)
return TRUE;
if (!service->initial_status_sent)
return TRUE;
return FALSE;
}
static void master_status_update(struct master_service *service)
{
ssize_t ret;
if (service->master_status.pid == 0 || service->delay_status_updates)
return; /* closed */
ret = write(MASTER_STATUS_FD, &service->master_status,
sizeof(service->master_status));
if (ret > 0) {
/* success */
if (service->io_status_write != NULL) {
/* delayed important update sent successfully */
io_remove(&service->io_status_write);
}
service->initial_status_sent = TRUE;
} else if (ret == 0) {
/* shouldn't happen? */
i_error("write(master_status_fd) returned 0");
service->master_status.pid = 0;
} else if (errno != EAGAIN) {
/* failure */
if (errno != EPIPE)
i_error("write(master_status_fd) failed: %m");
service->master_status.pid = 0;
} else if (master_status_update_is_important(service)) {
/* reader is busy, but it's important to get this notification
through. send it when possible. */
if (service->io_status_write == NULL) {
service->io_status_write =
io_add(MASTER_STATUS_FD, IO_WRITE,
master_status_update, service);
}
}
}