master-service.c revision c444eeaa2866152cf62652698aa11b125e8454bc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2011 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib-signals.h"
dfa2201c6ac8ddb2d2798dee15662cfe774e644eMartti Rannanjärvi#include "ioloop.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "array.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "env-util.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "home-expand.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include "process-title.h"
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include "restrict-access.h"
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen#include "fd-close-on-exec.h"
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen#include "settings-parser.h"
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen#include "syslog-util.h"
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen#include "master-login.h"
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen#include "master-service-private.h"
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen#include "master-service-settings.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen#include <stdlib.h>
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen#include <unistd.h>
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen#include <sys/stat.h>
13d98ffa534f2e7d04a832c9d0153fc9c568b878Timo Sirainen#include <syslog.h>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen/* when we're full of connections, how often to check if login state has
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen just a fallback against race conditions. */
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen#define MASTER_SERVICE_STATE_CHECK_MSECS 1000
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen force it. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstruct master_service *master_service;
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenconst char *master_service_getopt_string(void)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return "c:ko:Os:L";
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen}
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen{
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen struct master_service *service = context;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen want to log it in either case.*/
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (si->si_signo != SIGINT) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen si->si_signo, dec2str(si->si_pid),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen dec2str(si->si_uid),
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* never die when idling */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* SIGINT came from master. die only if we're not handling
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen any clients currently. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (service->master_status.available_count !=
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen service->total_available_count)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (service->idle_die_callback != NULL &&
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen !service->idle_die_callback())
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen }
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen service->killed = TRUE;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen io_loop_stop(service->ioloop);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct master_service *service = context;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen master_service_refresh_login_state(service);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (service->version_string != NULL &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_fatal("Dovecot version mismatch: "
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen "(if you don't care, set version_ignore=yes)",
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen service->version_string, service->name);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen}
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstruct master_service *
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen int *argc, char **argv[], const char *getopt_str)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct master_service *service;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen const char *value;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int count;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen i_assert(name != NULL);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#ifdef DEBUG
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek if (getenv("GDB") == NULL &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen int count;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen value = getenv("SOCKET_COUNT");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen count = value == NULL ? 0 : atoi(value);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen#endif
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* make sure we can dump core, at least until
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen privileges are dropped. (i'm not really sure why this
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen is needed, because doing the same just before exec
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen doesn't help, and exec shouldn't affect this with
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek non-setuid/gid binaries..) */
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen restrict_access_allow_coredumps(TRUE);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek restrict_access_by_env() is called */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen lib_init();
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen is properly initialized */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* ignore these signals as early as possible */
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek lib_signals_ignore(SIGPIPE, TRUE);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen process_title_init(argv);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen service = i_new(struct master_service, 1);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen service->argc = *argc;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen service->argv = *argv;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen service->name = i_strdup(name);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* keep getopt_str first in case it contains "+" */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->getopt_str = getopt_str == NULL ?
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_strdup(master_service_getopt_string()) :
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->flags = flags;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->ioloop = io_loop_create();
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->service_count_left = (unsigned int)-1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen service->config_fd = -1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (service->config_path == NULL) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->config_path_is_default = TRUE;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->socket_count = 1;
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen } else {
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen service->version_string = PACKAGE_VERSION;
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen value = getenv("SOCKET_COUNT");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (value != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->socket_count = atoi(value);
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen value = getenv("SSL_SOCKET_COUNT");
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen if (value != NULL)
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen service->ssl_socket_count = atoi(value);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set up some kind of logging until we know exactly how and where
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen we want to log */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_failure_internal();
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (getenv("USER") != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen name, getenv("USER")));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainen
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* initialize master_status structure */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen value = getenv(MASTER_UID_ENV);
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen if (value == NULL ||
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen i_fatal(MASTER_UID_ENV" missing");
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen service->master_status.pid = getpid();
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen /* set the default limit */
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen count == 0)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_fatal(MASTER_CLIENT_LIMIT_ENV" missing");
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk master_service_set_client_limit(service, count);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* seve the process limit */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk value = getenv(MASTER_PROCESS_LIMIT_ENV);
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (value != NULL && str_to_uint(value, &count) == 0 &&
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk count > 0)
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen service->process_limit = count;
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set the default service count */
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen value = getenv(MASTER_SERVICE_COUNT_ENV);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen count > 0)
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen master_service_set_service_count(service, count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else {
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen master_service_set_client_limit(service, 1);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen master_service_set_service_count(service, 1);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen }
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen master_service_verify_version_string(service);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return service;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenint master_getopt(struct master_service *service)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen int c;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen while ((c = getopt(service->argc, service->argv,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen service->getopt_str)) > 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (!master_service_parse_option(service, c, optarg))
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen break;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return c;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenvoid master_service_init_log(struct master_service *service,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *prefix)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen const char *path;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen i_set_failure_file("/dev/stderr", "");
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* logging via log service */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_set_failure_internal();
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_set_failure_prefix(prefix);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (service->set == NULL) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_set_failure_file("/dev/stderr", prefix);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* error logging goes to file or stderr */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen path = home_expand(service->set->log_path);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_set_failure_file(path, prefix);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen /* something gets logged to syslog */
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen int facility;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen &facility))
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen facility = LOG_MAIL;
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen i_set_failure_prefix(prefix);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* set error handlers back to file */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen i_set_fatal_handler(NULL);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen i_set_error_handler(NULL);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (*service->set->info_log_path != '\0' &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen path = home_expand(service->set->info_log_path);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (*path != '\0')
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_info_file(path);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (*service->set->debug_log_path != '\0' &&
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen path = home_expand(service->set->debug_log_path);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (*path != '\0')
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen i_set_debug_file(path);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen}
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen bool set)
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->die_with_master = set;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainenvoid master_service_set_die_callback(struct master_service *service,
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen void (*callback)(void))
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen{
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen service->die_callback = callback;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenvoid master_service_set_idle_die_callback(struct master_service *service,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen bool (*callback)(void))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->idle_die_callback = callback;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenbool master_service_parse_option(struct master_service *service,
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen int opt, const char *arg)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen switch (opt) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen case 'c':
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen service->config_path = arg;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen service->config_path_is_default = FALSE;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen break;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen case 'k':
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen service->keep_environment = TRUE;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen break;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen case 'o':
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen if (!array_is_created(&service->config_overrides))
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen i_array_init(&service->config_overrides, 16);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen array_append(&service->config_overrides, &arg, 1);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen break;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen case 'O':
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen break;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen case 'L':
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen service->log_directly = TRUE;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen break;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen default:
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen return FALSE;
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen }
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen return TRUE;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen}
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainenstatic void master_service_error(struct master_service *service)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen master_service_stop_new_connections(service);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen if (service->master_status.available_count ==
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen service->total_available_count || service->die_with_master) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (service->die_callback == NULL)
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen master_service_stop(service);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen else {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->to_die =
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen timeout_add(MASTER_SERVICE_DIE_TIMEOUT_MSECS,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen master_service_stop,
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen service);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->die_callback();
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen}
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic void master_status_error(void *context)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen{
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen struct master_service *service = context;
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* status fd is a write-only pipe, so if we're here it means the
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen master wants us to die (or died itself). don't die until all
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen service connections are finished. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen io_remove(&service->io_status_error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* the log fd may also be closed already, don't die when trying to
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen log later */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_set_failure_ignore_errors(TRUE);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen master_service_error(service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainenvoid master_service_init_finish(struct master_service *service)
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen{
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen enum libsig_flags sigint_flags = LIBSIG_FLAG_DELAYED;
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen struct stat st;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* set default signal handlers */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen lib_signals_init();
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen sigint_flags |= LIBSIG_FLAG_RESTART;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen lib_signals_set_handler(SIGINT, sigint_flags, sig_die, service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAG_DELAYED, sig_die, service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen sig_state_changed, service);
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_fatal("Must be started by dovecot master process");
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* start listening errors for status fd, it means master died */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen service->io_status_error = io_add(MASTER_DEAD_FD, IO_ERROR,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen master_status_error, service);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen }
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen master_service_io_listeners_add(service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* we already have a connection to be served */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen service->master_status.available_count--;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen master_status_update(service);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainenvoid master_service_env_clean(void)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen const char *value = getenv(DOVECOT_PRESERVE_ENVS_ENV);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (value == NULL || *value == '\0')
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen env_clean();
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen else T_BEGIN {
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen value = t_strconcat(value, " "DOVECOT_PRESERVE_ENVS_ENV, NULL);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen env_clean_except(t_strsplit_spaces(value, " "));
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen } T_END;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen unsigned int client_limit)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen{
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen unsigned int used;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen i_assert(service->master_status.available_count ==
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen service->total_available_count);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen used = service->total_available_count -
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen i_assert(client_limit >= used);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen service->total_available_count = client_limit;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = client_limit - used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return service->total_available_count;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenunsigned int master_service_get_process_limit(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return service->process_limit;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int count)
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int used;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen used = service->total_available_count -
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen service->master_status.available_count;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen i_assert(count >= used);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (service->total_available_count > count) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->total_available_count = count;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = count - used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen service->service_count_left = count;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return service->service_count_left;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen{
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen return service->socket_count;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen void (*callback)(void))
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->avail_overflow_callback = callback;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_config_path(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return service->config_path;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return service->version_string;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_name(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return service->name;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_run(struct master_service *service,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_connection_callback_t *callback)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->callback = callback;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io_loop_run(service->ioloop);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->callback = NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_stop(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io_loop_stop(service->ioloop);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen unsigned int current_count;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->stopping)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen return;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->stopping = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_io_listeners_remove(service);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_io_listeners_close(service);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* make sure we stop after servicing current connections */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen current_count = service->total_available_count -
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->master_status.available_count;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->service_count_left = current_count;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->total_available_count = current_count;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (current_count == 0)
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen master_service_stop(service);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen else {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* notify master that we're not accepting any more
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen connections */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->master_status.available_count = 0;
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen master_status_update(service);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (service->login != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen master_login_stop(service->login);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainenbool master_service_is_killed(struct master_service *service)
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return service->killed;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
9d4c027e7de01ab948d6221bc27c9b45d32d1ea5Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ssize_t ret;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return;
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ret < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (errno == EPIPE) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* anvil process was probably recreated, don't bother
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen logging an error about losing connection to it */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen return;
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen }
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen i_error("write(anvil) failed: %m");
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen } else if (ret == 0)
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen i_error("write(anvil) failed: EOF");
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen else {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen i_assert((size_t)ret == strlen(cmd));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainenvoid master_service_client_connection_created(struct master_service *service)
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen{
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_assert(service->master_status.available_count > 0);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen service->master_status.available_count--;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen master_status_update(service);
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen}
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen conn->accepted = TRUE;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* we can listen again */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_io_listeners_add(service);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(service->total_available_count > 0);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(service->service_count_left > 0);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (service->service_count_left == service->total_available_count) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->total_available_count--;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->service_count_left--;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->service_count_left != (unsigned int)-1)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->service_count_left--;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(service->master_status.available_count <
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->total_available_count);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->master_status.available_count++;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->service_count_left == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(service->master_status.available_count ==
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->total_available_count);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_stop(service);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if ((service->io_status_error == NULL ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->listeners == NULL) &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->master_status.available_count ==
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->total_available_count) {
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen /* we've finished handling all clients, and
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen a) master has closed the connection
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen b) there are no listeners (std-client?) */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen master_service_stop(service);
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen } else {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen master_status_update(service);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenstatic void master_service_set_login_state(struct master_service *service,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen enum master_login_state state)
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen{
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen if (service->to_overflow_state != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen timeout_remove(&service->to_overflow_state);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen switch (state) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen case MASTER_LOGIN_STATE_NONFULL:
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->call_avail_overflow = FALSE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (service->master_status.available_count > 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* some processes should now be able to handle new connections,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen although we can't. but there may be race conditions, so
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen make sure that we'll check again soon if the state has
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen changed to "full" without our knowledge. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->to_overflow_state =
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen timeout_add(MASTER_SERVICE_STATE_CHECK_MSECS,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen master_service_refresh_login_state,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen case MASTER_LOGIN_STATE_FULL:
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* make sure we're listening for more connections */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->call_avail_overflow = TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen master_service_io_listeners_add(service);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen i_error("Invalid master login state: %d", state);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen}
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen{
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen int ret;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen if (ret < 0)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_error("lseek(login notify fd) failed: %m");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen else
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_set_login_state(service, ret);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_close_config_fd(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->config_fd != -1) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (close(service->config_fd) < 0)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_error("close(master config fd) failed: %m");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen service->config_fd = -1;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen}
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_deinit(struct master_service **_service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen{
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct master_service *service = *_service;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen *_service = NULL;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_io_listeners_remove(service);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_close_config_fd(service);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->to_die != NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen timeout_remove(&service->to_die);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->to_overflow_state != NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen timeout_remove(&service->to_overflow_state);
1f4399a277b861419b82758ab0462e90c00a4c41Timo Sirainen if (service->to_status != NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen timeout_remove(&service->to_status);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->io_status_error != NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io_remove(&service->io_status_error);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->io_status_write != NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen io_remove(&service->io_status_write);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (array_is_created(&service->config_overrides))
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen array_free(&service->config_overrides);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->set_parser != NULL) {
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen settings_parser_deinit(&service->set_parser);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen pool_unref(&service->set_pool);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen lib_signals_deinit();
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen io_loop_destroy(&service->ioloop);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_free(service->listeners);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_free(service->getopt_str);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_free(service->name);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen i_free(service);
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen lib_deinit();
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen}
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen{
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen struct master_service *service = l->service;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen struct master_service_connection conn;
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if (service->master_status.available_count == 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* we are full. stop listening for now, unless overflow
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen callback destroys one of the existing connections */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->call_avail_overflow &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->avail_overflow_callback != NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->avail_overflow_callback();
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->master_status.available_count == 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_io_listeners_remove(service);
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen return;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen memset(&conn, 0, sizeof(conn));
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen conn.listen_fd = l->fd;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (conn.fd < 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen struct stat st;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen int orig_errno = errno;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (conn.fd == -1)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen if (errno == ENOTSOCK) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* it's not a socket. should be a fifo. */
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen } else if (errno == EINVAL &&
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen (fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* BSDI fails accept(fifo) with EINVAL. */
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen } else {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen errno = orig_errno;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_error("net_accept() failed: %m");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_error(service);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* use the "listener" as the connection fd and stop the
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen listener. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen conn.fd = l->fd;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen conn.listen_fd = l->fd;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen conn.fifo = TRUE;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen io_remove(&l->io);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen l->fd = -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen conn.ssl = l->ssl;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen net_set_nonblock(conn.fd, TRUE);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_client_connection_created(service);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->callback(&conn);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!conn.accepted) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (close(conn.fd) < 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("close(service connection) failed: %m");
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen master_service_client_connection_destroyed(service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (conn.fifo) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* reading FIFOs stays open forever, don't count them
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen as real clients */
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi master_service_client_connection_destroyed(service);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenstatic void io_listeners_init(struct master_service *service)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen{
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen unsigned int i;
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen if (service->socket_count == 0)
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen return;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen service->listeners =
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_new(struct master_service_listener, service->socket_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen for (i = 0; i < service->socket_count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct master_service_listener *l = &service->listeners[i];
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen l->service = service;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen l->fd = MASTER_LISTEN_FD_FIRST + i;
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen l->ssl = TRUE;
e36574dadcac802d6780fa94ee45951e75594c96Timo Sirainen }
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen}
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenvoid master_service_io_listeners_add(struct master_service *service)
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen{
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen unsigned int i;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen if (service->stopping)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen return;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen if (service->listeners == NULL)
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen io_listeners_init(service);
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen for (i = 0; i < service->socket_count; i++) {
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct master_service_listener *l = &service->listeners[i];
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen if (l->io == NULL && l->fd != -1) {
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen master_service_listen, l);
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen }
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen }
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen}
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenvoid master_service_io_listeners_remove(struct master_service *service)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (service->listeners != NULL) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 0; i < service->socket_count; i++) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (service->listeners[i].io != NULL)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen io_remove(&service->listeners[i].io);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen}
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenstatic void master_service_io_listeners_close(struct master_service *service)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen{
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen unsigned int i;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (service->listeners != NULL) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen /* close via listeners. some fds might be pipes that are
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen currently handled as clients. we don't want to close them. */
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen for (i = 0; i < service->socket_count; i++) {
4b1781e4c64be52e25b5994e5242dbe696cc7d29Timo Sirainen if (service->listeners[i].fd != -1) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (close(service->listeners[i].fd) < 0) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen i_error("close(listener %d) failed: %m",
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen service->listeners[i].fd);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen }
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen } else {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen for (i = 0; i < service->socket_count; i++) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen int fd = MASTER_LISTEN_FD_FIRST + i;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (close(fd) < 0)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen i_error("close(listener %d) failed: %m", fd);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->master_status.available_count == 0)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return TRUE;
15bfe73fb3988bb80e6afe6a60b9a715c7207600Timo Sirainen if (!service->initial_status_sent)
4809537f0c5a2e1cee9559ec842cc869884d2cb7Timo Sirainen return TRUE;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return FALSE;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenvoid master_status_update(struct master_service *service)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ssize_t ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen bool important_update;
8709b2fe6ec2b5ca1d90a63490f8371472062efdTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_UPDATE_PROCTITLE) != 0 &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->set != NULL && service->set->verbose_proctitle) T_BEGIN {
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen unsigned int used_count = service->total_available_count -
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->master_status.available_count;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen process_title_set(t_strdup_printf("[%u connections]",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen used_count));
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen } T_END;
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen important_update = master_status_update_is_important(service);
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen if (service->master_status.pid == 0 ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->master_status.available_count ==
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->last_sent_status_avail_count) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* a) closed, b) updating to same state */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (service->to_status != NULL)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen timeout_remove(&service->to_status);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (service->io_status_write != NULL)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen io_remove(&service->io_status_write);
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen return;
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen }
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen if (ioloop_time == service->last_sent_status_time &&
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen !important_update) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* don't spam master */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen if (service->to_status != NULL)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen timeout_reset(service->to_status);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen else {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen service->to_status =
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen timeout_add(1000, master_status_update,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen service);
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen if (service->io_status_write != NULL)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen io_remove(&service->io_status_write);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (service->to_status != NULL)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen timeout_remove(&service->to_status);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen sizeof(service->master_status));
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (ret == sizeof(service->master_status)) {
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen /* success */
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen if (service->io_status_write != NULL) {
b7c7a04bc5edb8eebea3837ff624441d9fa3721cTimo Sirainen /* delayed important update sent successfully */
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen io_remove(&service->io_status_write);
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen service->last_sent_status_time = ioloop_time;
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen service->last_sent_status_avail_count =
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen service->master_status.available_count;
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen service->initial_status_sent = TRUE;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen } else if (ret >= 0) {
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen /* shouldn't happen? */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_error("write(master_status_fd) returned %d", (int)ret);
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen service->master_status.pid = 0;
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen } else if (errno != EAGAIN) {
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen /* failure */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen if (errno != EPIPE)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_error("write(master_status_fd) failed: %m");
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen service->master_status.pid = 0;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen } else if (important_update) {
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* reader is busy, but it's important to get this notification
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen through. send it when possible. */
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen if (service->io_status_write == NULL) {
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen service->io_status_write =
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen io_add(MASTER_STATUS_FD, IO_WRITE,
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen master_status_update, service);
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen }
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainenbool version_string_verify(const char *line, const char *service_name,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen unsigned major_version)
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen{
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen unsigned int service_name_len = strlen(service_name);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen bool ret;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen if (strncmp(line, "VERSION\t", 8) != 0)
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen return FALSE;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen line += 8;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (strncmp(line, service_name, service_name_len) != 0 ||
e91543761d0b7b97a1dc28e036e44d76405545c2Timo Sirainen line[service_name_len] != '\t')
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return FALSE;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen line += service_name_len + 1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen T_BEGIN {
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen ret = str_uint_equals(t_strcut(line, '\t'), major_version);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen } T_END;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen return ret;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen