master-service.c revision 8d7eb4104707c60ca7e9d0228b37c5133476907b
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2005-2009 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "lib-signals.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "env-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "home-expand.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "restrict-access.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fd-close-on-exec.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "settings-parser.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "syslog-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service-settings.h"
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdlib.h>
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#include <unistd.h>
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#include <sys/stat.h>
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen#include <syslog.h>
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstruct master_service *master_service;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void io_listeners_add(struct master_service *service);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenstatic void master_status_update(struct master_service *service);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainenconst char *master_service_getopt_string(void)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen return "c:ko:Os:L";
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct master_service *service = context;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen which is too common at least while testing :) */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (si->si_signo != SIGINT) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen si->si_signo, dec2str(si->si_pid),
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen dec2str(si->si_uid),
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen io_loop_stop(service->ioloop);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen}
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen if (service->version_string != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("Dovecot version mismatch: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen "(if you don't care, set version_ignore=yes)",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->name, service->version_string);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainenstruct master_service *
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen int argc, char *argv[])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct master_service *service;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(name != NULL);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen#ifdef DEBUG
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen if (getenv("GDB") == NULL &&
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen int count;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen str = getenv("SOCKET_COUNT");
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen count = str == NULL ? 0 : atoi(str);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#endif
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen restrict_access_by_env() is called */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen lib_init();
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen is properly initialized */
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen service = i_new(struct master_service, 1);
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen service->argc = argc;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen service->argv = argv;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen service->name = i_strdup(name);
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen service->flags = flags;
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen service->ioloop = io_loop_create();
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen service->service_count_left = (unsigned int)-1;
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen service->config_fd = -1;
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (service->config_path == NULL)
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen service->socket_count = 1;
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen } else {
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen service->version_string = PACKAGE_VERSION;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen }
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen str = getenv("SOCKET_COUNT");
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (str != NULL)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen service->socket_count = atoi(str);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen str = getenv("SSL_SOCKET_COUNT");
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (str != NULL)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen service->ssl_socket_count = atoi(str);
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen /* set up some kind of logging until we know exactly how and where
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen we want to log */
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen i_set_failure_internal();
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen if (getenv("USER") != NULL) {
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen name, getenv("USER")));
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen } else {
a4d209d480d453566d331e870b8d0c99af7716c8Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen master_service_verify_version(service);
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen return service;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen}
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen unsigned int max_lines_per_sec)
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen{
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen const char *path;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen i_set_failure_file("/dev/stderr", "");
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* logging via log service */
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen i_set_failure_internal();
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_failure_prefix(prefix);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen }
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (service->set == NULL) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_set_failure_file("/dev/stderr", prefix);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen return;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (*service->set->log_path == '\0') {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* log to syslog */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int facility;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen &facility))
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen facility = LOG_MAIL;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_failure_prefix(prefix);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* log to file or stderr */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen path = home_expand(service->set->log_path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_failure_file(path, prefix);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen path = home_expand(service->set->info_log_path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (*path != '\0')
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_info_file(path);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenbool master_service_parse_option(struct master_service *service,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen int opt, const char *arg)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen switch (opt) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case 'c':
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen service->config_path = arg;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case 'k':
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->keep_environment = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case 'o':
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (!array_is_created(&service->config_overrides))
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen i_array_init(&service->config_overrides, 16);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen array_append(&service->config_overrides, &arg, 1);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen break;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen case 'O':
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen service->default_settings = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen break;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen case 's':
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if ((i = atoi(arg)) < 0)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_fatal("Invalid socket count: %s", arg);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen service->socket_count = i;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen break;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen case 'L':
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen service->log_directly = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen default:
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return FALSE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenstatic void master_service_error(struct master_service *service)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (service->master_status.available_count ==
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen service->total_available_count)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen master_service_stop(service);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen else
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen io_listeners_remove(service);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainenstatic void master_status_error(void *context)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct master_service *service = context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen master wants us to die (or died itself). don't die until all
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service connections are finished. */
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen io_remove(&service->io_status_error);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* the log fd may also be closed already, don't die when trying to
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen log later */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_set_failure_ignore_errors(TRUE);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen master_service_error(service);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenvoid master_service_init_finish(struct master_service *service)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct stat st;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen const char *value;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(service->total_available_count == 0);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen /* set default signal handlers */
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen lib_signals_init();
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_fatal("Must be started by dovecot master process");
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* initialize master_status structure */
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen value = getenv(MASTER_UID_ENV);
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen if (value == NULL)
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen i_fatal(MASTER_UID_ENV" not set");
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen service->master_status.pid = getpid();
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen service->master_status.uid =
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (unsigned int)strtoul(value, NULL, 10);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* set the default limit */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen count = value == NULL ? 0 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (count == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" not set");
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen master_service_set_client_limit(service, count);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* start listening errors for status fd, it means master died */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen master_status_error, service);
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen } else {
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen master_service_set_client_limit(service, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_set_service_count(service, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen io_listeners_add(service);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen /* we already have a connection to be served */
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen service->master_status.available_count--;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen master_status_update(service);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenvoid master_service_env_clean(bool preserve_home)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const char *user, *tz, *home;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen#ifdef DEBUG
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen bool gdb = getenv("GDB") != NULL;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen#endif
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen user = getenv("USER");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (user != NULL)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen user = t_strconcat("USER=", user, NULL);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen tz = getenv("TZ");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (tz != NULL)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen home = preserve_home ? getenv("HOME") : NULL;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (home != NULL)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen home = t_strconcat("HOME=", home, NULL);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* Note that if the original environment was set with env_put(), the
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen environment strings will be invalid after env_clean(). That's why
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen we t_strconcat() them above. */
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen env_clean();
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (user != NULL) env_put(user);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (tz != NULL) env_put(tz);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (home != NULL) env_put(home);
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen#ifdef DEBUG
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (gdb) env_put("GDB=1");
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen#endif
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen unsigned int client_limit)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen i_assert(service->master_status.available_count ==
c680a6b35b459045e92814778908da5a93922107Timo Sirainen service->total_available_count);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->total_available_count = client_limit;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen service->master_status.available_count = client_limit;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen{
c680a6b35b459045e92814778908da5a93922107Timo Sirainen return service->total_available_count;
096953143c4032bad154637f687551856f7946cbTimo Sirainen}
096953143c4032bad154637f687551856f7946cbTimo Sirainen
096953143c4032bad154637f687551856f7946cbTimo Sirainenvoid master_service_set_service_count(struct master_service *service,
096953143c4032bad154637f687551856f7946cbTimo Sirainen unsigned int count)
c680a6b35b459045e92814778908da5a93922107Timo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen unsigned int used;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen used = service->total_available_count -
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen service->master_status.available_count;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen i_assert(count >= used);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (service->total_available_count > count) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->total_available_count = count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->master_status.available_count = count - used;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen service->service_count_left = count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen}
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen{
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return service->service_count_left;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return service->socket_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return service->config_path;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen{
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return service->version_string;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenconst char *master_service_get_name(struct master_service *service)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return service->name;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid master_service_run(struct master_service *service,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen master_service_connection_callback_t *callback)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen service->callback = callback;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen io_loop_run(service->ioloop);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen service->callback = NULL;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid master_service_stop(struct master_service *service)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen io_loop_stop(service->ioloop);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ssize_t ret;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (ret < 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_error("write(anvil) failed: %m");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen else if (ret == 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_error("write(anvil) failed: EOF");
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert((size_t)ret == strlen(cmd));
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* we can listen again */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen io_listeners_add(service);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(service->total_available_count > 0);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (service->service_count_left != service->total_available_count) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen service->master_status.available_count++;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen } else {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* we have only limited amount of service requests left */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen i_assert(service->service_count_left > 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->service_count_left--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->total_available_count--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (service->service_count_left == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(service->master_status.available_count ==
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->total_available_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_stop(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen master_status_update(service);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if ((service->io_status_error == NULL || service->listeners == NULL) &&
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen service->master_status.available_count ==
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->total_available_count) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we've finished handling all clients, and
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen a) master has closed the connection
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen b) there are no listeners (std-client?) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_stop(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid master_service_deinit(struct master_service **_service)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct master_service *service = *_service;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen *_service = NULL;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen io_listeners_remove(service);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (service->io_status_error != NULL)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen io_remove(&service->io_status_error);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (service->io_status_write != NULL)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen io_remove(&service->io_status_write);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (array_is_created(&service->config_overrides))
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen array_free(&service->config_overrides);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (service->set_parser != NULL) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen settings_parser_deinit(&service->set_parser);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen pool_unref(&service->set_pool);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen lib_signals_deinit();
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen io_loop_destroy(&service->ioloop);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen i_free(service->name);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen i_free(service);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen lib_deinit();
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct master_service_connection conn;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (l->service->master_status.available_count == 0) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* we are full. stop listening for now. */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen io_listeners_remove(l->service);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen memset(&conn, 0, sizeof(conn));
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen conn.listen_fd = l->fd;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (conn.fd < 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (conn.fd == -1)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (errno != ENOTSOCK) {
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen i_error("net_accept() failed: %m");
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen master_service_error(l->service);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* it's not a socket. probably a fifo. use the "listener"
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen as the connection fd and stop the listener. */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen io_remove(&l->io);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen conn.fd = dup(l->fd);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen conn.listen_fd = l->fd;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (conn.fd == -1) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_error("dup() failed: %m");
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen return;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen conn.ssl = l->ssl;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen net_set_nonblock(conn.fd, TRUE);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen l->service->master_status.available_count--;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen master_status_update(l->service);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen l->service->callback(&conn);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainenstatic void io_listeners_init(struct master_service *service)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen{
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen unsigned int i;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (service->socket_count == 0)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen return;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen service->listeners =
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_new(struct master_service_listener, service->socket_count);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen for (i = 0; i < service->socket_count; i++) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen struct master_service_listener *l = &service->listeners[i];
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen l->service = service;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen l->fd = MASTER_LISTEN_FD_FIRST + i;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen l->ssl = TRUE;
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen}
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic void io_listeners_add(struct master_service *service)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen unsigned int i;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (service->listeners == NULL)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen io_listeners_init(service);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen for (i = 0; i < service->socket_count; i++) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen struct master_service_listener *l = &service->listeners[i];
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (l->io == NULL) {
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen master_service_listen, l);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen }
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen }
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen}
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainenstatic void io_listeners_remove(struct master_service *service)
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen{
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen unsigned int i;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen if (service->listeners != NULL) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen for (i = 0; i < service->socket_count; i++) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (service->listeners[i].io != NULL)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen io_remove(&service->listeners[i].io);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (service->master_status.available_count == 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return TRUE;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (!service->initial_status_sent)
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen return TRUE;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen return FALSE;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen}
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainenstatic void master_status_update(struct master_service *service)
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen ssize_t ret;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (service->master_status.pid == 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return; /* closed */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen sizeof(service->master_status));
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (ret > 0) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen /* success */
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (service->io_status_write != NULL) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* delayed important update sent successfully */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen io_remove(&service->io_status_write);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen service->initial_status_sent = TRUE;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen } else if (ret == 0) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* shouldn't happen? */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_error("write(master_status_fd) returned 0");
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen service->master_status.pid = 0;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen } else if (errno != EAGAIN) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen /* failure */
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (errno != EPIPE)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen i_error("write(master_status_fd) failed: %m");
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen service->master_status.pid = 0;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen } else if (master_status_update_is_important(service)) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen /* reader is busy, but it's important to get this notification
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen through. send it when possible. */
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (service->io_status_write == NULL) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen service->io_status_write =
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen io_add(MASTER_STATUS_FD, IO_WRITE,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen master_status_update, service);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen }
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen }
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen}
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen