master-service.c revision 56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib-signals.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "env-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "home-expand.h"
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen#include "process-title.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "restrict-access.h"
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen#include "fd-close-on-exec.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "settings-parser.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "syslog-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-login.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "master-service-private.h"
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#include "master-service-settings.h"
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#include <stdlib.h>
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#include <unistd.h>
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#include <sys/stat.h>
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen#include <syslog.h>
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* when we're full of connections, how often to check if login state has
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen just a fallback against race conditions. */
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen#define MASTER_SERVICE_STATE_CHECK_MSECS 1000
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen force it. */
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct master_service *master_service;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenconst char *master_service_getopt_string(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "c:ko:Os:L";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen{
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen struct master_service *service = context;
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen want to log it in either case.*/
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen if (si->si_signo != SIGINT) {
98922c5675bbbfadc84d58768bef867fe82256c2Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen si->si_signo, dec2str(si->si_pid),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen dec2str(si->si_uid),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen /* never die when idling */
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen /* SIGINT came from master. die only if we're not handling
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen any clients currently. */
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (service->master_status.available_count !=
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen service->total_available_count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen service->killed = TRUE;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen io_loop_stop(service->ioloop);
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen}
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
fc40a9a002458e372ff4b9f6f4e15239520c0bcdTimo Sirainenstatic void
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen{
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen struct master_service *service = context;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen master_service_refresh_login_state(service);
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen}
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen{
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen if (service->version_string != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("Dovecot version mismatch: "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen "(if you don't care, set version_ignore=yes)",
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen service->version_string, service->name);
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen }
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen}
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainenstruct master_service *
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen int *argc, char **argv[], const char *getopt_str)
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen{
c60d1eda4df179d83d531647732d5e3e45064219Timo Sirainen struct master_service *service;
f0a2d04321ba456e5c5ba821c0d1ed9e8e0e2e08Timo Sirainen const char *str;
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(name != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen#ifdef DEBUG
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (getenv("GDB") == NULL &&
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen int count;
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen str = getenv("SOCKET_COUNT");
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen count = str == NULL ? 0 : atoi(str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen }
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen#endif
ebe6df72f1309135f02b6a4d2aef1e81a073f91cTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen /* make sure we can dump core, at least until
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen privileges are dropped. (i'm not really sure why this
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen is needed, because doing the same just before exec
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen doesn't help, and exec shouldn't affect this with
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen non-setuid/gid binaries..) */
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen restrict_access_allow_coredumps(TRUE);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen restrict_access_by_env() is called */
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen lib_init();
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
ee1a3e217279dcd0f1cccbd3442e481b7dc90f05Timo Sirainen is properly initialized */
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen /* ignore these signals as early as possible */
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
e9d29ae46d435aee85514decfe6ee27399ebf794Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainen process_title_init(argv);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service = i_new(struct master_service, 1);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->argc = *argc;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->argv = *argv;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->name = i_strdup(name);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* keep getopt_str first in case it contains "+" */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->getopt_str = getopt_str == NULL ?
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_strdup(master_service_getopt_string()) :
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->flags = flags;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->ioloop = io_loop_create();
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->service_count_left = (unsigned int)-1;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->config_fd = -1;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (service->config_path == NULL) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->config_path_is_default = TRUE;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen }
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->socket_count = 1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->version_string = PACKAGE_VERSION;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen str = getenv("SOCKET_COUNT");
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (str != NULL)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->socket_count = atoi(str);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen str = getenv("SSL_SOCKET_COUNT");
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (str != NULL)
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen service->ssl_socket_count = atoi(str);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen /* set up some kind of logging until we know exactly how and where
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen we want to log */
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (getenv("LOG_SERVICE") != NULL)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_set_failure_internal();
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (getenv("USER") != NULL) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
51078c3413b7ed4811bc725acbb1289723361ba9Timo Sirainen name, getenv("USER")));
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen } else {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen }
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen master_service_verify_version_string(service);
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen return service;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen}
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainenint master_getopt(struct master_service *service)
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen int c;
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen while ((c = getopt(service->argc, service->argv,
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen service->getopt_str)) > 0) {
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen if (!master_service_parse_option(service, c, optarg))
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen break;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen }
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen return c;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen}
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainenvoid master_service_init_log(struct master_service *service,
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen const char *prefix)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen const char *path;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen i_set_failure_file("/dev/stderr", "");
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen return;
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen }
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen
9334fbad0aabb2fed88f40b2205d0d6f80bdffa2Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen /* logging via log service */
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen i_set_failure_internal();
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen i_set_failure_prefix(prefix);
3ec2c1f31631bb5ff86f5fc93a563c33e5cae90dTimo Sirainen return;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (service->set == NULL) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_set_failure_file("/dev/stderr", prefix);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen return;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* error logging goes to file or stderr */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen path = home_expand(service->set->log_path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_failure_file(path, prefix);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* something gets logged to syslog */
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen int facility;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
8b58939517a381db55670089c0984da39fc0f099Timo Sirainen &facility))
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen facility = LOG_MAIL;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_set_failure_prefix(prefix);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen /* set error handlers back to file */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen i_set_fatal_handler(NULL);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_error_handler(NULL);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (*service->set->info_log_path != '\0' &&
d22301419109ed4a38351715e6760011421dadecTimo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen path = home_expand(service->set->info_log_path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (*path != '\0')
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_info_file(path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (*service->set->debug_log_path != '\0' &&
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen path = home_expand(service->set->debug_log_path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (*path != '\0')
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_debug_file(path);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
236bedf76e31651ea9fca63fbdc25be673819526Timo Sirainen bool set)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen{
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen service->die_with_master = set;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenvoid master_service_set_die_callback(struct master_service *service,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen void (*callback)(void))
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen{
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen service->die_callback = callback;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainenbool master_service_parse_option(struct master_service *service,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen int opt, const char *arg)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen switch (opt) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 'c':
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->config_path = arg;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen service->config_path_is_default = FALSE;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen break;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen case 'k':
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->keep_environment = TRUE;
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen break;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen case 'o':
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (!array_is_created(&service->config_overrides))
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen i_array_init(&service->config_overrides, 16);
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen array_append(&service->config_overrides, &arg, 1);
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen break;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen case 'O':
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 'L':
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->log_directly = TRUE;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen break;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen default:
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return FALSE;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen return TRUE;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen}
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainenstatic void master_service_error(struct master_service *service)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen master_service_stop_new_connections(service);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (service->master_status.available_count ==
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->total_available_count || service->die_with_master) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (service->die_callback == NULL)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen master_service_stop(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->to_die =
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen timeout_add(MASTER_SERVICE_DIE_TIMEOUT_MSECS,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_stop,
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->die_callback();
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenstatic void master_status_error(void *context)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen struct master_service *service = context;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* status fd is a write-only pipe, so if we're here it means the
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen master wants us to die (or died itself). don't die until all
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service connections are finished. */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen io_remove(&service->io_status_error);
55b6e3105184ad6a2f987346380966f556300055Timo Sirainen
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen /* the log fd may also be closed already, don't die when trying to
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen log later */
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen i_set_failure_ignore_errors(TRUE);
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen master_service_error(service);
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen}
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainenvoid master_service_init_finish(struct master_service *service)
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen{
2ff23d6fb7e2ff85aa23b7f4769aeac1d0316a1bTimo Sirainen struct stat st;
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen const char *value;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen unsigned int count;
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen i_assert(service->total_available_count == 0);
63aaafe7e6b201d6633f8c25610ecd30c9cda99cTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen
2ff23d6fb7e2ff85aa23b7f4769aeac1d0316a1bTimo Sirainen /* set default signal handlers */
cf49fc07f541c0f74578ac6c3b334ddade143aa1Timo Sirainen lib_signals_init();
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
7aeaf23f760d86aad525d831efcac9f860a55a39Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen lib_signals_set_handler(SIGUSR1, TRUE,
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen sig_state_changed, service);
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen }
18065635d4e79dd96eb3b3215718abd12f6a6808Timo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_fatal("Must be started by dovecot master process");
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* initialize master_status structure */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen value = getenv(MASTER_UID_ENV);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (value == NULL ||
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_fatal(MASTER_UID_ENV" missing");
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen service->master_status.pid = getpid();
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* set the default limit */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen count == 0)
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" missing");
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen master_service_set_client_limit(service, count);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* set the default service count */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen value = getenv(MASTER_SERVICE_COUNT_ENV);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen count > 0)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen master_service_set_service_count(service, count);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* start listening errors for status fd, it means master died */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen master_status_error, service);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen } else {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen master_service_set_client_limit(service, 1);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen master_service_set_service_count(service, 1);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen master_service_io_listeners_add(service);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen /* we already have a connection to be served */
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen service->master_status.available_count--;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen }
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen master_status_update(service);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid master_service_env_clean(bool preserve_home)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen const char *user, *tz, *home;
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen#ifdef DEBUG
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen bool gdb = getenv("GDB") != NULL;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen#endif
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen user = getenv("USER");
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (user != NULL)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen user = t_strconcat("USER=", user, NULL);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen tz = getenv("TZ");
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (tz != NULL)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen tz = t_strconcat("TZ=", tz, NULL);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen home = preserve_home ? getenv("HOME") : NULL;
9fdd27b307347a06871ddab74b165122c878553cTimo Sirainen if (home != NULL)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen home = t_strconcat("HOME=", home, NULL);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen /* Note that if the original environment was set with env_put(), the
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen environment strings will be invalid after env_clean(). That's why
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen we t_strconcat() them above. */
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen env_clean();
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (user != NULL) env_put(user);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (tz != NULL) env_put(tz);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (home != NULL) env_put(home);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen#ifdef DEBUG
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen if (gdb) env_put("GDB=1");
3eb63515855f386449c22233d1f1baf1ddfe8a2dTimo Sirainen#endif
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenvoid master_service_set_client_limit(struct master_service *service,
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen unsigned int client_limit)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen unsigned int used;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_assert(service->master_status.available_count ==
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->total_available_count);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen used = service->total_available_count -
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->master_status.available_count;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen i_assert(client_limit >= used);
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->total_available_count = client_limit;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen service->master_status.available_count = client_limit - used;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen{
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen return service->total_available_count;
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen}
97eb53ade9057e6966dbb77289ad0204c7e1657bTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid master_service_set_service_count(struct master_service *service,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int count)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen{
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen unsigned int used;
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen used = service->total_available_count -
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen service->master_status.available_count;
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen i_assert(count >= used);
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen if (service->total_available_count > count) {
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen service->total_available_count = count;
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen service->master_status.available_count = count - used;
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen }
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen service->service_count_left = count;
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen}
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen{
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return service->service_count_left;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen}
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen{
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen return service->socket_count;
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen}
e4e7475f646d66a257d682738fbff1f206ce4924Timo Sirainen
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen void (*callback)(void))
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen{
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen service->avail_overflow_callback = callback;
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen}
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
24cd47a2c8f7507e555459b7e841de771ba3c318Timo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return service->config_path;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen}
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen{
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen return service->version_string;
b142deb9a831c89b1bb9129ada655f3e56b9d4ccTimo Sirainen}
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainenconst char *master_service_get_name(struct master_service *service)
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen{
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen return service->name;
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen}
129cc29ae6d8ad64d6d2b72f18da18fa134d0f3eTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid master_service_run(struct master_service *service,
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen master_service_connection_callback_t *callback)
e76c494ad6535d3de314cc0d3ac7a44b06e53c4bTimo Sirainen{
e76c494ad6535d3de314cc0d3ac7a44b06e53c4bTimo Sirainen service->callback = callback;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen io_loop_run(service->ioloop);
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen service->callback = NULL;
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen}
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainenvoid master_service_stop(struct master_service *service)
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen{
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen io_loop_stop(service->ioloop);
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen}
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainen
89fb98e9eb7e95255a579c8e9d865383c2334a74Timo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
0d73d91d1a1809f173d433023ccf97e6ec5ba629Timo Sirainen{
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen unsigned int current_count;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen if (service->stopping)
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen return;
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->stopping = TRUE;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen master_service_io_listeners_remove(service);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen master_service_io_listeners_close(service);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure we stop after servicing current connections */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen current_count = service->total_available_count -
d22301419109ed4a38351715e6760011421dadecTimo Sirainen service->master_status.available_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->service_count_left = current_count;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen service->total_available_count = current_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (current_count == 0)
b6a7e0a7899e7f5d60c23cdaa50e025e4c67d05fTimo Sirainen master_service_stop(service);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen else {
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen /* notify master that we're not accepting any more
910fa4e4204a73d3d24c03f3059dd24e727ca057Timo Sirainen connections */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->master_status.available_count = 0;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen master_status_update(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (service->login != NULL)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen master_login_stop(service->login);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainenbool master_service_is_killed(struct master_service *service)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen{
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen return service->killed;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen}
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen{
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen ssize_t ret;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen return;
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if (ret < 0) {
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen if (errno == EPIPE) {
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen /* anvil process was probably recreated, don't bother
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen logging an error about losing connection to it */
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen return;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen }
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen i_error("write(anvil) failed: %m");
d22301419109ed4a38351715e6760011421dadecTimo Sirainen } else if (ret == 0)
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen i_error("write(anvil) failed: EOF");
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen else {
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen i_assert((size_t)ret == strlen(cmd));
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen }
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen}
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen{
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen conn->accepted = TRUE;
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen}
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen{
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen /* we can listen again */
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen master_service_io_listeners_add(service);
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen i_assert(service->total_available_count > 0);
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen i_assert(service->service_count_left > 0);
e0645d5232900a5c574780ef0c0362a5b7581abaTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (service->service_count_left == service->total_available_count) {
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen service->total_available_count--;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen service->service_count_left--;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen } else {
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen if (service->service_count_left != (unsigned int)-1)
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen service->service_count_left--;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen i_assert(service->master_status.available_count <
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen service->total_available_count);
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen service->master_status.available_count++;
8c9e48cd6de80da0fa32b9c0dee003472c9a7c0dTimo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen if (service->service_count_left == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(service->master_status.available_count ==
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen service->total_available_count);
a12399903f415a7e14c2816cffa2f7a09dcbb097Timo Sirainen master_service_stop(service);
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen } else if ((service->io_status_error == NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->listeners == NULL) &&
439980f88f421039dea8335e92d3fa82b3f470a1Timo Sirainen service->master_status.available_count ==
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen service->total_available_count) {
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen /* we've finished handling all clients, and
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen a) master has closed the connection
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen b) there are no listeners (std-client?) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_stop(service);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen } else {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen master_status_update(service);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen }
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen}
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
87460b08cb97b31cde640d4975a6aa2c1d0e7226Timo Sirainen enum master_login_state state)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
366d6311c9d5bac6613e3cd64619eb878adce9ecTimo Sirainen if (service->to_overflow_state != NULL)
9af6cc9ebc9986c1275ebdfa29c39e152af1557eTimo Sirainen timeout_remove(&service->to_overflow_state);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen switch (state) {
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen case MASTER_LOGIN_STATE_NONFULL:
225e82df5dd1e765f4e52b80c954558f00e5a7dfTimo Sirainen service->call_avail_overflow = FALSE;
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen if (service->master_status.available_count > 0)
61e27995aadbc2f97927d3635f98d1d4ac4751e0Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
/* some processes should now be able to handle new connections,
although we can't. but there may be race conditions, so
make sure that we'll check again soon if the state has
changed to "full" without our knowledge. */
service->to_overflow_state =
timeout_add(MASTER_SERVICE_STATE_CHECK_MSECS,
master_service_refresh_login_state,
service);
return;
case MASTER_LOGIN_STATE_FULL:
/* make sure we're listening for more connections */
service->call_avail_overflow = TRUE;
master_service_io_listeners_add(service);
return;
}
i_error("Invalid master login state: %d", state);
}
static void master_service_refresh_login_state(struct master_service *service)
{
int ret;
ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
if (ret < 0)
i_error("lseek(login notify fd) failed: %m");
else
master_service_set_login_state(service, ret);
}
void master_service_close_config_fd(struct master_service *service)
{
if (service->config_fd != -1) {
if (close(service->config_fd) < 0)
i_error("close(master config fd) failed: %m");
service->config_fd = -1;
}
}
void master_service_deinit(struct master_service **_service)
{
struct master_service *service = *_service;
*_service = NULL;
master_service_io_listeners_remove(service);
master_service_close_config_fd(service);
if (service->to_die != NULL)
timeout_remove(&service->to_die);
if (service->to_overflow_state != NULL)
timeout_remove(&service->to_overflow_state);
if (service->to_status != NULL)
timeout_remove(&service->to_status);
if (service->io_status_error != NULL)
io_remove(&service->io_status_error);
if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
if (array_is_created(&service->config_overrides))
array_free(&service->config_overrides);
if (service->set_parser != NULL) {
settings_parser_deinit(&service->set_parser);
pool_unref(&service->set_pool);
}
lib_signals_deinit();
io_loop_destroy(&service->ioloop);
i_free(service->listeners);
i_free(service->getopt_str);
i_free(service->name);
i_free(service);
lib_deinit();
}
static void master_service_listen(struct master_service_listener *l)
{
struct master_service *service = l->service;
struct master_service_connection conn;
if (service->master_status.available_count == 0) {
/* we are full. stop listening for now, unless overflow
callback destroys one of the existing connections */
if (service->call_avail_overflow &&
service->avail_overflow_callback != NULL)
service->avail_overflow_callback();
if (service->master_status.available_count == 0) {
master_service_io_listeners_remove(service);
return;
}
}
memset(&conn, 0, sizeof(conn));
conn.listen_fd = l->fd;
conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
if (conn.fd < 0) {
struct stat st;
int orig_errno = errno;
if (conn.fd == -1)
return;
if (errno == ENOTSOCK) {
/* it's not a socket. should be a fifo. */
} else if (errno == EINVAL &&
(fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
/* BSDI fails accept(fifo) with EINVAL. */
} else {
errno = orig_errno;
i_error("net_accept() failed: %m");
master_service_error(service);
return;
}
/* use the "listener" as the connection fd and stop the
listener. */
conn.fd = l->fd;
conn.listen_fd = l->fd;
conn.fifo = TRUE;
io_remove(&l->io);
l->fd = -1;
}
conn.ssl = l->ssl;
net_set_nonblock(conn.fd, TRUE);
i_assert(service->master_status.available_count > 0);
service->master_status.available_count--;
master_status_update(service);
service->callback(&conn);
if (!conn.accepted) {
if (close(conn.fd) < 0)
i_error("close(service connection) failed: %m");
master_service_client_connection_destroyed(service);
}
}
static void io_listeners_init(struct master_service *service)
{
unsigned int i;
if (service->socket_count == 0)
return;
service->listeners =
i_new(struct master_service_listener, service->socket_count);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
l->service = service;
l->fd = MASTER_LISTEN_FD_FIRST + i;
if (i >= service->socket_count - service->ssl_socket_count)
l->ssl = TRUE;
}
}
void master_service_io_listeners_add(struct master_service *service)
{
unsigned int i;
if (service->stopping)
return;
if (service->listeners == NULL)
io_listeners_init(service);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
if (l->io == NULL && l->fd != -1) {
l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
master_service_listen, l);
}
}
}
void master_service_io_listeners_remove(struct master_service *service)
{
unsigned int i;
if (service->listeners != NULL) {
for (i = 0; i < service->socket_count; i++) {
if (service->listeners[i].io != NULL)
io_remove(&service->listeners[i].io);
}
}
}
static void master_service_io_listeners_close(struct master_service *service)
{
unsigned int i;
if (service->listeners != NULL) {
/* close via listeners. some fds might be pipes that are
currently handled as clients. we don't want to close them. */
for (i = 0; i < service->socket_count; i++) {
if (service->listeners[i].fd != -1) {
if (close(service->listeners[i].fd) < 0) {
i_error("close(listener %d) failed: %m",
service->listeners[i].fd);
}
}
}
} else {
for (i = 0; i < service->socket_count; i++) {
int fd = MASTER_LISTEN_FD_FIRST + i;
if (close(fd) < 0)
i_error("close(listener %d) failed: %m", fd);
}
}
}
static bool master_status_update_is_important(struct master_service *service)
{
if (service->master_status.available_count == 0)
return TRUE;
if (!service->initial_status_sent)
return TRUE;
return FALSE;
}
void master_status_update(struct master_service *service)
{
ssize_t ret;
bool important_update;
important_update = master_status_update_is_important(service);
if (service->master_status.pid == 0 ||
service->master_status.available_count ==
service->last_sent_status_avail_count) {
/* a) closed, b) updating to same state */
if (service->to_status != NULL)
timeout_remove(&service->to_status);
if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
return;
}
if (ioloop_time == service->last_sent_status_time &&
!important_update) {
/* don't spam master */
if (service->to_status != NULL)
timeout_reset(service->to_status);
else {
service->to_status =
timeout_add(1000, master_status_update,
service);
}
if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
return;
}
if (service->to_status != NULL)
timeout_remove(&service->to_status);
ret = write(MASTER_STATUS_FD, &service->master_status,
sizeof(service->master_status));
if (ret == sizeof(service->master_status)) {
/* success */
if (service->io_status_write != NULL) {
/* delayed important update sent successfully */
io_remove(&service->io_status_write);
}
service->last_sent_status_time = ioloop_time;
service->last_sent_status_avail_count =
service->master_status.available_count;
service->initial_status_sent = TRUE;
} else if (ret >= 0) {
/* shouldn't happen? */
i_error("write(master_status_fd) returned %d", (int)ret);
service->master_status.pid = 0;
} else if (errno != EAGAIN) {
/* failure */
if (errno != EPIPE)
i_error("write(master_status_fd) failed: %m");
service->master_status.pid = 0;
} else if (important_update) {
/* reader is busy, but it's important to get this notification
through. send it when possible. */
if (service->io_status_write == NULL) {
service->io_status_write =
io_add(MASTER_STATUS_FD, IO_WRITE,
master_status_update, service);
}
}
}
bool version_string_verify(const char *line, const char *service_name,
unsigned major_version)
{
unsigned int service_name_len = strlen(service_name);
bool ret;
if (strncmp(line, "VERSION\t", 8) != 0)
return FALSE;
line += 8;
if (strncmp(line, service_name, service_name_len) != 0 ||
line[service_name_len] != '\t')
return FALSE;
line += service_name_len + 1;
T_BEGIN {
ret = str_uint_equals(t_strcut(line, '\t'), major_version);
} T_END;
return ret;
}