master-service.c revision 01230de017cd273de41143d88e9c18df1243ae8a
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* 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"
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void io_listeners_add(struct master_service *service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void master_status_update(struct master_service *service);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return "c:ko:s:L";
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen which is too common at least while testing :) */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
49621bf0ef1d55aaaa2dc7d76011cbfeabdcfbe1Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(if you don't care, set version_ignore=yes)",
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen const char *str;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen restrict_access_by_env() is called */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch /* Set a logging prefix temporarily. This will be ignored once the log
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen is properly initialized */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->service_count_left = (unsigned int)-1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo 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): ",
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_LOG_TO_STDERR) != 0) {
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen /* logging via log service */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* log to syslog */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* log to file or stderr */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen path = home_expand(service->set->info_log_path);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainenbool master_service_parse_option(struct master_service *service,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!array_is_created(&service->config_overrides))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen array_append(&service->config_overrides, &arg, 1);
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
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service connections are finished. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo 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);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set default signal handlers */
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i_fatal("Must be started by dovecot master process");
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* initialize master_status structure */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* set the default limit */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen master_service_set_client_limit(service, count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* start listening errors for status fd, it means master died */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen /* we already have a connection to be served */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid master_service_env_clean(bool preserve_home)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo 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. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(service->master_status.available_count ==
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen service->total_available_count = client_limit;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen service->master_status.available_count = client_limit;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int count)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int used;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen service->master_status.available_count = count - used;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_run(struct master_service *service,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_service_connection_callback_t *callback)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_stop(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen else if (ret == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we can listen again */
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (service->service_count_left != service->total_available_count) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we have only limited amount of service requests left */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(service->master_status.available_count ==
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen /* master has closed the connection and we have nothing else
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen to do anymore. */
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenvoid master_service_deinit(struct master_service **_service)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (array_is_created(&service->config_overrides))
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (l->service->master_status.available_count == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we are full. stop listening for now. */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* it's not a socket. probably a fifo. use the "listener"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen as the connection fd */
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainenstatic void io_listeners_add(struct master_service *service)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen unsigned int i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_new(struct master_service_listener, service->socket_count);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct master_service_listener *l = &service->listeners[i];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void io_listeners_remove(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen unsigned int i;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen if (service->master_status.available_count == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void master_status_update(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return; /* closed */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* success */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* delayed important update sent successfully */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen } else if (ret == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* shouldn't happen? */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_error("write(master_status_fd) returned 0");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* failure */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_error("write(master_status_fd) failed: %m");
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen } else if (master_status_update_is_important(service)) {
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen /* reader is busy, but it's important to get this notification
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen through. send it when possible. */