master-service.c revision 85b4143f07c504294dd4e5b168e9bfb293515c31
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
1e9296de32c9ddda40f33c06556cd568ddadf71fTimo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* when we're full of connections, how often to check if login state has
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch changed. we normally notice it immediately because of a signal, so this is
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch just a fallback against race conditions. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* If die callback hasn't managed to stop the service for this many seconds,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic void master_service_io_listeners_close(struct master_service *service);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic void master_service_refresh_login_state(struct master_service *service);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschmaster_status_send(struct master_service *service, bool important_update);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch return "c:i:ko:OL";
1e9296de32c9ddda40f33c06556cd568ddadf71fTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen want to log it in either case.*/
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen /* never die when idling */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* SIGINT came from master. die only if we're not handling
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch any clients currently. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* we don't want to die - send a notification to master
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch so it doesn't think we're ignoring it completely. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschsig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic void master_service_verify_version_string(struct master_service *service)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch strcmp(service->version_string, PACKAGE_VERSION) != 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch "(if you don't care, set version_ignore=yes)",
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainenstatic void master_service_init_socket_listeners(struct master_service *service)
85f3bd5926fff0e70b6d259a5c8074bd8cdeb9adTimo Sirainen unsigned int i;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_new(struct master_service_listener, service->socket_count);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct master_service_listener *l = &service->listeners[i];
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch value = getenv(t_strdup_printf("SOCKET%u_SETTINGS", i));
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch const char *const *settings =
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch } else if (strcmp(*settings, "haproxy") == 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch service->want_ssl_settings = have_ssl_sockets ||
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (service->flags & MASTER_SERVICE_FLAG_USE_SSL_SETTINGS) != 0;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschmaster_service_init(const char *name, enum master_service_flags flags,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch int *argc, char **argv[], const char *getopt_str)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int count;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (value == NULL || str_to_uint(value, &count) < 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* make sure we can dump core, at least until
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch privileges are dropped. (i'm not really sure why this
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch is needed, because doing the same just before exec
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch doesn't help, and exec shouldn't affect this with
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch non-setuid/gid binaries..) */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* NOTE: we start rooted, so keep the code minimal until
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch restrict_access_by_env() is called */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* Set a logging prefix temporarily. This will be ignored once the log
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen is properly initialized */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* make sure all the data stack allocations during init will be freed
faa8995f1d300e7a8917407a52bbd1b98e10bf25Timo Sirainen before we get to ioloop. the corresponding t_pop() is in
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch master_service_init_finish(). */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if ((flags & MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME) == 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* ignore these signals as early as possible */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch /* keep getopt_str first in case it contains "+" */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_strconcat(getopt_str, master_service_getopt_string(), NULL);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch service->config_path = i_strdup(getenv(MASTER_CONFIG_FILE_ENV));
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen service->config_path = i_strdup(DEFAULT_CONFIG_FILE_PATH);
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
95e0b82fdff1bb511067d703bb8b67c22f242c38Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
T_BEGIN {
} T_END;
count == 0)
count > 0)
count > 0)
count > 0)
return service;
return FALSE;
return TRUE;
const char *prefix)
int facility;
&facility))
bool set)
void (*callback)(void))
bool (*callback)(void))
which dovecot.conf we even want to read! so we must use the
const char *path;
switch (opt) {
return FALSE;
return TRUE;
service);
t_pop();
void master_service_env_clean(void)
env_clean();
else T_BEGIN {
} T_END;
unsigned int client_limit)
unsigned int used;
unsigned int count)
unsigned int used;
int listen_fd)
void (*callback)(void))
unsigned int current_count;
if (current_count == 0)
if (ret < 0) {
} else if (ret == 0)
switch (state) {
service);
case MASTER_LOGIN_STATE_FULL:
int ret;
if (ret < 0)
lib_deinit();
if (l->haproxy)
return TRUE;
return TRUE;
return FALSE;
} else if (ret >= 0) {
} else if (important_update) {
bool important_update;
used_count));
} T_END;
!important_update) {
service);
unsigned major_version)
unsigned int minor_version;
unsigned major_version,
unsigned int *minor_version_r)
bool ret;
return FALSE;
return FALSE;
T_BEGIN {
if (p == NULL)
} T_END;
return ret;