master-service.c revision 885e1b36da370a674c0fd3b85db53740d7dcbd9b
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (C) 2005-2009 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "lib-signals.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "env-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "home-expand.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "restrict-access.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include "fd-close-on-exec.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include "settings-parser.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include "syslog-util.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include "master-service-private.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include "master-service-settings.h"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include <stdlib.h>
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include <unistd.h>
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include <sys/stat.h>
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#include <syslog.h>
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
afd0d073a0afd1c8cf6473b4ae76919586eaa1faTimo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
75e8db37023fde9ac15550bf426be8719d94a821Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstruct master_service *master_service;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstatic void io_listeners_add(struct master_service *service);
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainenstatic void master_status_update(struct master_service *service);
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainenconst char *master_service_getopt_string(void)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return "c:ko:Os:L";
e627cdc5ef30d87959f9510832427e33a2f1d84aTimo Sirainen}
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct master_service *service = context;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen which is too common at least while testing :) */
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (si->si_signo != SIGINT) {
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen si->si_signo, dec2str(si->si_pid),
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen dec2str(si->si_uid),
1727610dbc69920b7f0d0622b4e5d7127c59093dTimo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_stop(service->ioloop);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (service->version_string != NULL &&
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_fatal("Dovecot version mismatch: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen "(if you don't care, set version_ignore=yes)",
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen service->name, service->version_string);
1727610dbc69920b7f0d0622b4e5d7127c59093dTimo Sirainen }
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstruct master_service *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen int argc, char *argv[])
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen{
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen struct master_service *service;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen const char *str;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen i_assert(name != NULL);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen#ifdef DEBUG
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (getenv("GDB") == NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int count;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = getenv("SOCKET_COUNT");
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen count = str == NULL ? 0 : atoi(str);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen restrict_access_by_env() is called */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_init();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen is properly initialized */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen service = i_new(struct master_service, 1);
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen service->argc = argc;
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen service->argv = argv;
ec77cd41241208345efd51c1fcce9030be30aa9bTimo Sirainen service->name = i_strdup(name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->flags = flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->ioloop = io_loop_create();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->service_count_left = (unsigned int)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->config_fd = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (service->config_path == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->socket_count = 1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen } else {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen service->version_string = PACKAGE_VERSION;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen str = getenv("SOCKET_COUNT");
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (str != NULL)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen service->socket_count = atoi(str);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen str = getenv("SSL_SOCKET_COUNT");
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (str != NULL)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen service->ssl_socket_count = atoi(str);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen /* set up some kind of logging until we know exactly how and where
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen we want to log */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_set_failure_internal();
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (getenv("USER") != NULL) {
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen name, getenv("USER")));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen } else {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen master_service_verify_version(service);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return service;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned int max_lines_per_sec)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen const char *path;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_set_failure_file("/dev/stderr", "");
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* logging via log service */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_set_failure_internal();
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_set_failure_prefix(prefix);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return;
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (service->set == NULL) {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen i_set_failure_file("/dev/stderr", prefix);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*service->set->log_path == '\0') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* log to syslog */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen int facility;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &facility))
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen facility = LOG_MAIL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_set_failure_prefix(prefix);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen /* log to file or stderr */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen path = home_expand(service->set->log_path);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_set_failure_file(path, prefix);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen }
24ec3e51a1bd7aaf09c92a7ff7498e225796d7e0Timo Sirainen
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen path = home_expand(service->set->info_log_path);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (*path != '\0')
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen i_set_info_file(path);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen}
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainenbool master_service_parse_option(struct master_service *service,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen int opt, const char *arg)
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen{
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen int i;
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen switch (opt) {
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen case 'c':
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen service->config_path = arg;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen case 'k':
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen service->keep_environment = TRUE;
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen break;
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen case 'o':
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (!array_is_created(&service->config_overrides))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_array_init(&service->config_overrides, 16);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&service->config_overrides, &arg, 1);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 'O':
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen service->default_settings = TRUE;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen break;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen case 's':
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if ((i = atoi(arg)) < 0)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_fatal("Invalid socket count: %s", arg);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen service->socket_count = i;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen break;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen case 'L':
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen service->log_directly = TRUE;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen break;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen default:
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return FALSE;
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen }
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen return TRUE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainenstatic void master_service_error(struct master_service *service)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen{
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (service->master_status.available_count ==
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen service->total_available_count)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen master_service_stop(service);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_listeners_remove(service);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstatic void master_status_error(void *context)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen{
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen struct master_service *service = context;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen master wants us to die (or died itself). don't die until all
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen service connections are finished. */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen io_remove(&service->io_status_error);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* the log fd may also be closed already, don't die when trying to
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen log later */
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen i_set_failure_ignore_errors(TRUE);
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen master_service_error(service);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid master_service_init_finish(struct master_service *service)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen{
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen struct stat st;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *value;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(service->total_available_count == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen /* set default signal handlers */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen lib_signals_init();
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
c24c0f0a208e5ffc35dc8be19a9b504a5326467aTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
c24c0f0a208e5ffc35dc8be19a9b504a5326467aTimo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_fatal("Must be started by dovecot master process");
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* initialize master_status structure */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = getenv(MASTER_UID_ENV);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (value == NULL)
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen i_fatal(MASTER_UID_ENV" not set");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->master_status.pid = getpid();
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen service->master_status.uid =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* set the default limit */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen count = value == NULL ? 0 :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen if (count == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" not set");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_set_client_limit(service, count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* set the default service count */
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen value = getenv(MASTER_SERVICE_COUNT_ENV);
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen count = value == NULL ? 0 :
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (count > 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_set_service_count(service, count);
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen /* start listening errors for status fd, it means master died */
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_status_error, service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_set_client_limit(service, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_set_service_count(service, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen io_listeners_add(service);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen /* we already have a connection to be served */
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->master_status.available_count--;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen }
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen master_status_update(service);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen}
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid master_service_env_clean(bool preserve_home)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen{
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen const char *user, *tz, *home;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen#ifdef DEBUG
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen bool gdb = getenv("GDB") != NULL;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen#endif
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen user = getenv("USER");
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (user != NULL)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen user = t_strconcat("USER=", user, NULL);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen tz = getenv("TZ");
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (tz != NULL)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen home = preserve_home ? getenv("HOME") : NULL;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (home != NULL)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen home = t_strconcat("HOME=", home, NULL);
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen /* Note that if the original environment was set with env_put(), the
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen environment strings will be invalid after env_clean(). That's why
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen we t_strconcat() them above. */
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen env_clean();
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (user != NULL) env_put(user);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (tz != NULL) env_put(tz);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (home != NULL) env_put(home);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen#ifdef DEBUG
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (gdb) env_put("GDB=1");
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen#endif
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen}
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen unsigned int client_limit)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen{
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen unsigned int used;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen i_assert(service->master_status.available_count ==
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->total_available_count);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen used = service->total_available_count -
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->master_status.available_count;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen i_assert(client_limit >= used);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->total_available_count = client_limit;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->master_status.available_count = client_limit - used;
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen}
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen{
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen return service->total_available_count;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen}
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainenvoid master_service_set_service_count(struct master_service *service,
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen unsigned int count)
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen{
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen unsigned int used;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen used = service->total_available_count -
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen service->master_status.available_count;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen i_assert(count >= used);
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen if (service->total_available_count > count) {
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen service->total_available_count = count;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen service->master_status.available_count = count - used;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen service->service_count_left = count;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return service->service_count_left;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return service->socket_count;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return service->config_path;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return service->version_string;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenconst char *master_service_get_name(struct master_service *service)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return service->name;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenvoid master_service_run(struct master_service *service,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen master_service_connection_callback_t *callback)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen service->callback = callback;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen io_loop_run(service->ioloop);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen service->callback = NULL;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid master_service_stop(struct master_service *service)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen{
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen io_loop_stop(service->ioloop);
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen}
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
44c5e644cb413a6559bf2d4179cbe48f9a82f366Timo Sirainen{
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen ssize_t ret;
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen
44c5e644cb413a6559bf2d4179cbe48f9a82f366Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen return;
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen if (ret < 0)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_error("write(anvil) failed: %m");
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen else if (ret == 0)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_error("write(anvil) failed: EOF");
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen else {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_assert((size_t)ret == strlen(cmd));
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen}
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* we can listen again */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen io_listeners_add(service);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen i_assert(service->total_available_count > 0);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (service->service_count_left != service->total_available_count) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(service->master_status.available_count <
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen service->total_available_count);
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen service->master_status.available_count++;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* we have only limited amount of service requests left */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(service->service_count_left > 0);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen service->service_count_left--;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen service->total_available_count--;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (service->service_count_left == 0) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_assert(service->master_status.available_count ==
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen service->total_available_count);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen master_service_stop(service);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen master_status_update(service);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if ((service->io_status_error == NULL || service->listeners == NULL) &&
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen service->master_status.available_count ==
e49e973f363a56ad186fce372310d5ec6d83d8faTimo Sirainen service->total_available_count) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* we've finished handling all clients, and
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen a) master has closed the connection
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen b) there are no listeners (std-client?) */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen master_service_stop(service);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenvoid master_service_deinit(struct master_service **_service)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen{
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen struct master_service *service = *_service;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen *_service = NULL;
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen io_listeners_remove(service);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen if (service->io_status_error != NULL)
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen io_remove(&service->io_status_error);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen if (service->io_status_write != NULL)
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen io_remove(&service->io_status_write);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen if (array_is_created(&service->config_overrides))
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen array_free(&service->config_overrides);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen if (service->set_parser != NULL) {
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen settings_parser_deinit(&service->set_parser);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen pool_unref(&service->set_pool);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen }
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen lib_signals_deinit();
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen io_loop_destroy(&service->ioloop);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen i_free(service->name);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen i_free(service);
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen lib_deinit();
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen}
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainen
c4db5f0fb7cea8160dc10b5f0ab57ab7c02bf8a5Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen{
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen struct master_service_connection conn;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen if (l->service->master_status.available_count == 0) {
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen /* we are full. stop listening for now. */
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen io_listeners_remove(l->service);
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen return;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen }
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen memset(&conn, 0, sizeof(conn));
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen conn.listen_fd = l->fd;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen if (conn.fd < 0) {
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen if (conn.fd == -1)
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen return;
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen
dd9712b013e5a14939deed84b2e391d89897d2cfTimo Sirainen if (errno != ENOTSOCK) {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen i_error("net_accept() failed: %m");
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen master_service_error(l->service);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* it's not a socket. probably a fifo. use the "listener"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen as the connection fd and stop the listener. */
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen conn.fd = l->fd;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen conn.listen_fd = l->fd;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen conn.fifo = TRUE;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen io_remove(&l->io);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen l->fd = -1;
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen }
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen conn.ssl = l->ssl;
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen net_set_nonblock(conn.fd, TRUE);
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen l->service->master_status.available_count--;
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen master_status_update(l->service);
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen l->service->callback(&conn);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen}
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainenstatic void io_listeners_init(struct master_service *service)
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen{
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen unsigned int i;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen if (service->socket_count == 0)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen service->listeners =
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_new(struct master_service_listener, service->socket_count);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen for (i = 0; i < service->socket_count; i++) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct master_service_listener *l = &service->listeners[i];
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen l->service = service;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen l->fd = MASTER_LISTEN_FD_FIRST + i;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen l->ssl = TRUE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic void io_listeners_add(struct master_service *service)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen unsigned int i;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (service->listeners == NULL)
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen io_listeners_init(service);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen for (i = 0; i < service->socket_count; i++) {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen struct master_service_listener *l = &service->listeners[i];
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen if (l->io == NULL && l->fd != -1) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen master_service_listen, l);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen}
44c5e644cb413a6559bf2d4179cbe48f9a82f366Timo Sirainen
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainenstatic void io_listeners_remove(struct master_service *service)
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen{
44c5e644cb413a6559bf2d4179cbe48f9a82f366Timo Sirainen unsigned int i;
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen
5278c93bd7105c32ac7ec37f36015d5950f6cbcaTimo Sirainen if (service->listeners != NULL) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen for (i = 0; i < service->socket_count; i++) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (service->listeners[i].io != NULL)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen io_remove(&service->listeners[i].io);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen }
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen }
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen}
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (service->master_status.available_count == 0)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen return TRUE;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (!service->initial_status_sent)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return TRUE;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return FALSE;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenstatic void master_status_update(struct master_service *service)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen ssize_t ret;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (service->master_status.pid == 0)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen return; /* closed */
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen sizeof(service->master_status));
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (ret > 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen /* success */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (service->io_status_write != NULL) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen /* delayed important update sent successfully */
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen io_remove(&service->io_status_write);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen service->initial_status_sent = TRUE;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen } else if (ret == 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen /* shouldn't happen? */
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen i_error("write(master_status_fd) returned 0");
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen service->master_status.pid = 0;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else if (errno != EAGAIN) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* failure */
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen if (errno != EPIPE)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen i_error("write(master_status_fd) failed: %m");
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen service->master_status.pid = 0;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else if (master_status_update_is_important(service)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* reader is busy, but it's important to get this notification
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen through. send it when possible. */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (service->io_status_write == NULL) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen service->io_status_write =
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen io_add(MASTER_STATUS_FD, IO_WRITE,
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen master_status_update, service);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen }
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen