master-service.c revision 9240d99920783c56405dda74a1f6c7ff1ebed8e6
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2005-2009 Timo Sirainen */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "lib-signals.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen#include "env-util.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "home-expand.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "restrict-access.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fd-close-on-exec.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "syslog-util.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "master-service-private.h"
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#include "master-service-settings.h"
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainen#include <stdlib.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <unistd.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <sys/stat.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include <syslog.h>
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void io_listeners_add(struct master_service *service);
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_status_update(struct master_service *service);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenconst char *master_service_getopt_string(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return "c:ko:s:L";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct master_service *service = context;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen which is too common at least while testing :) */
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen if (si->si_signo != SIGINT) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen si->si_signo, dec2str(si->si_pid),
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen dec2str(si->si_uid),
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen io_loop_stop(service->ioloop);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen{
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen if (service->version_string != NULL &&
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen i_fatal("Dovecot version mismatch: "
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen "(if you don't care, set version_ignore=yes)",
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen service->name, service->version_string);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen}
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstruct master_service *
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int argc, char *argv[])
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct master_service *service;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen const char *str;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen i_assert(name != NULL);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen#ifdef DEBUG
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (getenv("GDB") == NULL) {
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen int count;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen str = getenv("SOCKET_COUNT");
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen count = str == NULL ? 0 : atoi(str);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen }
f1743785713e7632459d623d5df2108f4b93accbTimo Sirainen#endif
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen /* NOTE: we start rooted, so keep the code minimal until
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen restrict_access_by_env() is called */
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen lib_init();
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen is properly initialized */
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service = i_new(struct master_service, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->argc = argc;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->argv = argv;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->name = i_strdup(name);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->flags = flags;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->ioloop = io_loop_create();
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->service_count_left = (unsigned int)-1;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen if (service->config_path == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen service->socket_count = 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen service->version_string = PACKAGE_VERSION;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen str = getenv("SOCKET_COUNT");
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen if (str != NULL)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen service->socket_count = atoi(str);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen str = getenv("SSL_SOCKET_COUNT");
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (str != NULL)
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen service->ssl_socket_count = atoi(str);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen /* set up some kind of logging until we know exactly how and where
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen we want to log */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (getenv("LOG_SERVICE") != NULL)
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_set_failure_internal();
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen if (getenv("USER") != NULL) {
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen name, getenv("USER")));
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen } else {
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen }
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen master_service_verify_version(service);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen return service;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen unsigned int max_lines_per_sec)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
2584e86cc2d8c31ba30a4109cf4ba09d1e37e28aTimo Sirainen const char *path;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
4b41116563110d00330896a568eff1078c382827Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_LOG_TO_STDERR) != 0) {
4b41116563110d00330896a568eff1078c382827Timo Sirainen i_set_failure_file("/dev/stderr", "");
4b41116563110d00330896a568eff1078c382827Timo Sirainen return;
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen }
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen /* logging via log service */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_set_failure_internal();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_set_failure_prefix(prefix);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen }
b2c1349cf07410aefab0f5b17153af9e5cfcf48fTimo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen if (service->set == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_set_failure_file("/dev/stderr", prefix);
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen return;
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen }
48270badadd82279bfe50ae3d187aea8b0b2b30eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*service->set->log_path == '\0') {
61f5256ef248d35459b53534ae428bf6d016e1c5Timo Sirainen /* log to syslog */
cb05ecbd96ddb5e53c1850d27434541138a3f284Timo Sirainen int facility;
cb05ecbd96ddb5e53c1850d27434541138a3f284Timo Sirainen
cb05ecbd96ddb5e53c1850d27434541138a3f284Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
14ab4610b6038da6c5d0814fecabc6b74bc81a6bTimo Sirainen &facility))
14ab4610b6038da6c5d0814fecabc6b74bc81a6bTimo Sirainen facility = LOG_MAIL;
14ab4610b6038da6c5d0814fecabc6b74bc81a6bTimo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen i_set_failure_prefix(prefix);
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen } else {
e3796bfd2bc0fd5ba664893d346df9334a5b3af0Timo Sirainen /* log to file or stderr */
e3796bfd2bc0fd5ba664893d346df9334a5b3af0Timo Sirainen path = home_expand(service->set->log_path);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_set_failure_file(path, prefix);
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen }
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen
408e5be344c9131fdebe771718a5bf49f88cc51cTimo Sirainen path = home_expand(service->set->info_log_path);
408e5be344c9131fdebe771718a5bf49f88cc51cTimo Sirainen if (*path != '\0')
408e5be344c9131fdebe771718a5bf49f88cc51cTimo Sirainen i_set_info_file(path);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen}
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenbool master_service_parse_option(struct master_service *service,
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen int opt, const char *arg)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen int i;
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen switch (opt) {
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen case 'c':
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen service->config_path = arg;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen break;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen case 'k':
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->keep_environment = TRUE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen case 'o':
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (!array_is_created(&service->config_overrides))
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_array_init(&service->config_overrides, 16);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen array_append(&service->config_overrides, &arg, 1);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen case 's':
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if ((i = atoi(arg)) < 0)
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen i_fatal("Invalid socket count: %s", arg);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen service->socket_count = i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen case 'L':
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen service->log_directly = TRUE;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen default:
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen return FALSE;
f3bb2fbe87425dc89a839908985af496f7f65702Timo Sirainen }
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen return TRUE;
bd1b2615928a1e8be190cb0405754f0aec8cac2fTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainenstatic void master_status_error(void *context)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen struct master_service *service = context;
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen master wants us to die (or died itself). don't die until all
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen service connections are finished. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_remove(&service->io_status_error);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* the log fd may also be closed already, don't die when trying to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log later */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_set_failure_ignore_errors(TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (service->master_status.available_count ==
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen service->total_available_count)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen master_service_stop(service);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_init_finish(struct master_service *service)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen struct stat st;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen const char *value;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen i_assert(service->total_available_count == 0);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* set default signal handlers */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_init();
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_fatal("Must be started by dovecot master process");
64b5dcc136d6eb7ad90463e6cba9e16880ab52adTimo Sirainen
64b5dcc136d6eb7ad90463e6cba9e16880ab52adTimo Sirainen /* initialize master_status structure */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen value = getenv(MASTER_UID_ENV);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (value == NULL)
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen i_fatal(MASTER_UID_ENV" not set");
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen service->master_status.pid = getpid();
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen service->master_status.uid =
f23ede27743c1aa03eacbfc634d6a10de9110c91Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
f23ede27743c1aa03eacbfc634d6a10de9110c91Timo Sirainen
f23ede27743c1aa03eacbfc634d6a10de9110c91Timo Sirainen /* set the default limit */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen count = value == NULL ? 0 :
47001341950b8588c5f3a96b75864dab48e279aeTimo Sirainen (unsigned int)strtoul(value, NULL, 10);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (count == 0)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" not set");
47001341950b8588c5f3a96b75864dab48e279aeTimo Sirainen master_service_set_client_limit(service, count);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen /* start listening errors for status fd, it means master died */
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen master_status_error, service);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen } else {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen master_service_set_client_limit(service, 1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen master_service_set_service_count(service, 1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen io_listeners_add(service);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* we already have a connection to be served */
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen service->master_status.available_count--;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen }
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen master_status_update(service);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainenvoid master_service_env_clean(bool preserve_home)
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen{
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen const char *user, *tz, *home;
6b0d8106ae51ffc6ce45636b34d2e21cbefca7fdTimo Sirainen#ifdef DEBUG
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen bool gdb = getenv("GDB") != NULL;
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen#endif
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen user = getenv("USER");
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (user != NULL)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen user = t_strconcat("USER=", user, NULL);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen tz = getenv("TZ");
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen if (tz != NULL)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen home = preserve_home ? getenv("HOME") : NULL;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (home != NULL)
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen home = t_strconcat("HOME=", home, NULL);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* Note that if the original environment was set with env_put(), the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen environment strings will be invalid after env_clean(). That's why
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen we t_strconcat() them above. */
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen env_clean();
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (user != NULL) env_put(user);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (tz != NULL) env_put(tz);
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen if (home != NULL) env_put(home);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen#ifdef DEBUG
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (gdb) env_put("GDB=1");
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen#endif
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid master_service_set_client_limit(struct master_service *service,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int client_limit)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(service->master_status.available_count ==
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->total_available_count);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->total_available_count = client_limit;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->master_status.available_count = client_limit;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return service->total_available_count;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen unsigned int count)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen{
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen unsigned int used;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen used = service->total_available_count -
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen service->master_status.available_count;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_assert(count >= used);
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen if (service->total_available_count > count) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen service->total_available_count = count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen service->master_status.available_count = count - used;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen service->service_count_left = count;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return service->service_count_left;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen{
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainen return service->socket_count;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenconst char *master_service_get_config_path(struct master_service *service)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen{
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen return service->config_path;
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen}
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen{
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen return service->version_string;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen}
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenvoid master_service_run(struct master_service *service,
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen master_service_connection_callback_t *callback)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen{
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen service->callback = callback;
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen io_loop_run(service->ioloop);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen service->callback = NULL;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid master_service_stop(struct master_service *service)
e4c90f0b88e40a8f92b8f5e1f1a3ea701e5c965cTimo Sirainen{
defb12ecd360df672ffb2f4dbf4d1218a0a9549cTimo Sirainen io_loop_stop(service->ioloop);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ssize_t ret;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen if (ret < 0)
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen i_error("write(anvil) failed: %m");
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen else if (ret == 0)
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen i_error("write(anvil) failed: EOF");
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen else {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_assert((size_t)ret == strlen(cmd));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen}
eb0816090cf5a549280ad783b9aa6fec199d36baTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (service->listeners == NULL) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we can listen again */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_listeners_add(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(service->total_available_count > 0);
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen if (service->service_count_left != service->total_available_count) {
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen service->master_status.available_count++;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen } else {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* we have only limited amount of service requests left */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_assert(service->service_count_left > 0);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen service->service_count_left--;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen service->total_available_count--;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (service->service_count_left == 0) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_assert(service->master_status.available_count ==
a3ee5ce6ecc8e228ee69300fdd562d7ac8be89a7Timo Sirainen service->total_available_count);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen master_service_stop(service);
f4616f1875297fb2f583d913c0f01b075bdecd5bTimo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen master_status_update(service);
4321f6c969e7b8f6b243ff5bb6b8d297921676f6Timo Sirainen
d54ab8987e482a8df250615b44f41fa040c38741Timo Sirainen if (service->io_status_error == NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->master_status.available_count ==
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->total_available_count) {
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen /* master has closed the connection and we have nothing else
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen to do anymore. */
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen master_service_stop(service);
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen }
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen}
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenvoid master_service_deinit(struct master_service **_service)
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen{
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen struct master_service *service = *_service;
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen *_service = NULL;
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen
0cce885512b836ce021260a58e7b4f099b36d0f1Timo Sirainen io_listeners_remove(service);
e050e5c9b1688765f1fdfce9b7141f7b614383fdTimo Sirainen
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen if (service->io_status_error != NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_remove(&service->io_status_error);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (service->io_status_write != NULL)
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen io_remove(&service->io_status_write);
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen if (array_is_created(&service->config_overrides))
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen array_free(&service->config_overrides);
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen lib_signals_deinit();
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen io_loop_destroy(&service->ioloop);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen i_free(service->name);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_free(service);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
cfb86adbda733e4945db44c6be27f8fda142c0a3Timo Sirainen lib_deinit();
de58be41126e5d68008d2ea706d62ccdc1f29337Timo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct master_service_connection conn;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (l->service->master_status.available_count == 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* we are full. stop listening for now. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen io_listeners_remove(l->service);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen }
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen memset(&conn, 0, sizeof(conn));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn.listen_fd = l->fd;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (conn.fd < 0) {
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (conn.fd == -1)
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno != ENOTSOCK) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("net_accept() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_listeners_remove(l->service);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen /* it's not a socket. probably a fifo. use the "listener"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen as the connection fd */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen io_remove(&l->io);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen conn.fd = l->fd;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen conn.ssl = l->ssl;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen net_set_nonblock(conn.fd, TRUE);
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen l->service->master_status.available_count--;
4bbd396aa6198c84f3f7763b6e8a63a26e97e141Timo Sirainen master_status_update(l->service);
b83deefd2cf1e293373673eefb4d5cf60907978cTimo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen l->service->callback(&conn);
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen}
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic void io_listeners_add(struct master_service *service)
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen{
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen unsigned int i;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
b3b4f3875850099c9292ad74d08bb385c3988f8fTimo Sirainen if (service->socket_count == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 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;
l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
master_service_listen, l);
if (i >= service->socket_count - service->ssl_socket_count)
l->ssl = TRUE;
}
}
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);
}
i_free_and_null(service->listeners);
}
}
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)
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);
}
}
}