master-service.c revision 0c96e2994ab4e25c9042ce21e9d39ca5054df3b6
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi/* when we're full of connections, how often to check if login state has
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi changed. we normally notice it immediately because of a signal, so this is
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi just a fallback against race conditions. */
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi/* If die callback hasn't managed to stop the service for this many seconds,
2b8ff102f5117f917248f98ccbdc8e6a6af83c87Aki Tuomi force it. */
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen return "c:i:ko:OL";
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen want to log it in either case.*/
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
e376693bfa3985232c41df99c7010fca22612c89Timo Sirainen /* never die when idling */
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen /* SIGINT came from master. die only if we're not handling
09c3a491f4f6ccebe290c7709bdc0d79a187610bTimo Sirainen any clients currently. */
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
659fe5d24825b160cae512538088020d97a60239Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen "(if you don't care, set version_ignore=yes)",
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
d1baa8c6f97cdb1b3c2c44a73cc21f9dfc7a963fTimo Sirainen int *argc, char **argv[], const char *getopt_str)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen unsigned int count;
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
7212243efb0d8fa1cd8b2e37b7498323540b9e97Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen /* make sure we can dump core, at least until
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen privileges are dropped. (i'm not really sure why this
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen is needed, because doing the same just before exec
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen doesn't help, and exec shouldn't affect this with
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen non-setuid/gid binaries..) */
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen /* NOTE: we start rooted, so keep the code minimal until
4253a4a66323bc5ff1103af7d7f77fe7c78b9b2bTimo Sirainen restrict_access_by_env() is called */
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen is properly initialized */
515f81466f673c1b4f72e053f1a9686e6fca6b61Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
93d08c32afb545ba32e9a1d973b34756c4b01983Timo Sirainen /* ignore these signals as early as possible */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* keep getopt_str first in case it contains "+" */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen service->service_count_left = (unsigned int)-1;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen service->config_path = i_strdup(getenv(MASTER_CONFIG_FILE_ENV));
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen service->config_path = i_strdup(DEFAULT_CONFIG_FILE_PATH);
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen str_array_length((void *)service->listener_names);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen /* set up some kind of logging until we know exactly how and where
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen we want to log */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
5e88e4624aa6d482b5b195acd2f4e02aeb385f20Timo Sirainen /* initialize master_status structure */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* set the default limit */
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
9e6d83a3ef6abb393eeebca423cfd0d8cb08d430Timo Sirainen master_service_set_client_limit(service, count);
3b426f49d36187895debdda67fff09f97941881cTimo Sirainen /* seve the process limit */
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* set the default service count */
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen master_service_set_service_count(service, count);
1279090ba03f9c176976a69ab7718f0ed77b19afTimo Sirainen /* set the idle kill timeout */
5ada3f57a970f226eb29956d30f66afc3537200dTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen master_service_verify_version_string(service);
439942f89a77180719644e7af3752a8329259eb9Timo Sirainenint master_getopt(struct master_service *service)
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen while ((c = getopt(service->argc, service->argv,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!master_service_parse_option(service, c, optarg))
5d1833b98fa85d8061626aa986f38dcbcd70553eTimo Sirainenvoid master_service_init_log(struct master_service *service,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* logging via log service */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
9404a7b90dcb80d31bd37ee2493f03751acdb1bdTimo Sirainen /* error logging goes to file or stderr */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* something gets logged to syslog */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen /* set error handlers back to file */
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen path = home_expand(service->set->info_log_path);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen path = home_expand(service->set->debug_log_path);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen void (*callback)(void))
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenvoid master_service_set_idle_die_callback(struct master_service *service,
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen bool (*callback)(void))
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenstatic bool get_instance_config(const char *name, const char **config_path_r)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen list = master_instance_list_init(MASTER_INSTANCE_PATH);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen inst = master_instance_list_find_by_name(list, name);
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen path = t_strdup_printf("%s/dovecot.conf", inst->base_dir);
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainenbool master_service_parse_option(struct master_service *service,
return FALSE;
return TRUE;
service);
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;
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();
return TRUE;
return TRUE;
return FALSE;
bool important_update;
used_count));
} T_END;
!important_update) {
service);
} else if (ret >= 0) {
} else if (important_update) {
unsigned major_version)
bool ret;
return FALSE;
return FALSE;
T_BEGIN {
} T_END;
return ret;