bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen/* when we're full of connections, how often to check if login state has
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen just a fallback against race conditions. */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainenmaster_status_send(struct master_service *service, bool important_update);
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen return "c:i:ko:OL";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen want to log it in either case.*/
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen /* never die when idling */
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen /* SIGINT came from master. die only if we're not handling
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen any clients currently. */
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen /* we don't want to die - send a notification to master
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen so it doesn't think we're ignoring it completely. */
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainenstatic void sig_close_listeners(const siginfo_t *si ATTR_UNUSED, void *context)
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen /* We're in a signal handler: Close listeners immediately so master
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen can successfully restart. We can safely close only those listeners
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen that don't have an io, but this shouldn't be a big problem. If there
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen is an active io, the service is unlikely to be unresposive for
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen longer periods of time, so the listener gets closed soon enough via
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen master_status_error().
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen For extra safety we don't actually close() the fd, but instead
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen replace it with /dev/null. This way it won't be replaced with some
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen other new fd and attempted to be used in unexpected ways. */
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen for (unsigned int i = 0; i < service->socket_count; i++) {
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen if (dup2(dev_null_fd, service->listeners[i].fd) < 0)
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen lib_signals_syscall_error("signal: dup2(/dev/null, listener) failed: ");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(if you don't care, set version_ignore=yes)",
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainenstatic void master_service_init_socket_listeners(struct master_service *service)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen unsigned int i;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen i_new(struct master_service_listener, service->socket_count);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen struct master_service_listener *l = &service->listeners[i];
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen value = getenv(t_strdup_printf("SOCKET%u_SETTINGS", i));
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen } else if (strcmp(*settings, "haproxy") == 0) {
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen service->want_ssl_settings = have_ssl_sockets ||
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_USE_SSL_SETTINGS) != 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen int *argc, char **argv[], const char *getopt_str)
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (value == NULL || str_to_uint(value, &count) < 0)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* make sure we can dump core, at least until
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen privileges are dropped. (i'm not really sure why this
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen is needed, because doing the same just before exec
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen doesn't help, and exec shouldn't affect this with
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen non-setuid/gid binaries..) */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen restrict_access_by_env() is called */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen is properly initialized */
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen /* make sure all the data stack allocations during init will be freed
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen before we get to ioloop. the corresponding t_pop() is in
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen master_service_init_finish(). */
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME) == 0)
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen /* ignore these signals as early as possible */
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen /* keep getopt_str first in case it contains "+" */
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
28bf8f762fcd21c57bf71822cf818447babce9a0Timo Sirainen service->datastack_frame_id = datastack_frame_id;
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen service->config_path = i_strdup(getenv(MASTER_CONFIG_FILE_ENV));
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen service->config_path = i_strdup(DEFAULT_CONFIG_FILE_PATH);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* listener configuration */
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (value != NULL && str_to_uint(value, &service->socket_count) < 0)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen master_service_init_socket_listeners(service);
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi /* load SSL module if necessary */
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi if (service->want_ssl_settings && ssl_module_load(&error) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set up some kind of logging until we know exactly how and where
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we want to log */
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s(%s): ", name, getenv("USER"));
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen /* Initialize debug logging */
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen struct event_filter *filter = event_filter_create();
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen if (master_service_log_debug_parse(filter, value, &error) < 0) {
1fd856f1177990003ec3829267b9e490c095d836Timo Sirainen i_error("Invalid "DOVECOT_LOG_DEBUG_ENV" - ignoring: %s",
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* initialize master_status structure */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* set the default limit */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen master_service_set_client_limit(service, count);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* seve the process limit */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* set the default service count */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen master_service_set_service_count(service, count);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen /* set the idle kill timeout */
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0)
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN) != 0) {
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen /* since we're going to keep the config socket open anyway,
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen open it now so we can read settings even after privileges
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen are dropped. */
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen master_service_config_socket_try_open(service);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen master_service_verify_version_string(service);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainenint master_getopt(struct master_service *service)
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen i_assert(master_getopt_str_is_valid(service->getopt_str));
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen while ((c = getopt(service->argc, service->argv,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (!master_service_parse_option(service, c, optarg))
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainenbool master_getopt_str_is_valid(const char *str)
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen unsigned int i, j;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen /* make sure there are no duplicates. there are few enough characters
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen that this should be fast enough. */
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if (str[i] == ':' || str[i] == '+' || str[i] == '-')
61eec37dd74af9434ff876bc739a4cbe4a0ba8b4Timo Sirainenmaster_service_try_init_log(struct master_service *service,
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* logging via log service */
61eec37dd74af9434ff876bc739a4cbe4a0ba8b4Timo Sirainen /* may be called again after we have settings */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* error logging goes to file or stderr */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* something gets logged to syslog */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* set error handlers back to file */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen path = home_expand(service->set->info_log_path);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen path = home_expand(service->set->debug_log_path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
61eec37dd74af9434ff876bc739a4cbe4a0ba8b4Timo Sirainenvoid master_service_init_log(struct master_service *service,
61eec37dd74af9434ff876bc739a4cbe4a0ba8b4Timo Sirainen /* change only the prefix */
61eec37dd74af9434ff876bc739a4cbe4a0ba8b4Timo Sirainen if (master_service_try_init_log(service, prefix))
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainenvoid master_service_init_stats_client(struct master_service *service,
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen service->set->stats_writer_socket_path[0] != '\0') T_BEGIN {
f6f23086d0259d50cde3bd5d4180d67d820d293dTimo Sirainen stats_client_init(path, silent_notfound_errors);
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen void (*callback)(void))
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainenvoid master_service_set_idle_die_callback(struct master_service *service,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen bool (*callback)(void))
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenstatic bool get_instance_config(const char *name, const char **config_path_r)
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen /* note that we don't have any settings yet. we're just finding out
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen which dovecot.conf we even want to read! so we must use the
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen hardcoded state_dir path. */
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen instance_path = t_strconcat(PKG_STATEDIR"/"MASTER_INSTANCE_FNAME, NULL);
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen list = master_instance_list_init(instance_path);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen inst = master_instance_list_find_by_name(list, name);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen path = t_strdup_printf("%s/dovecot.conf", inst->base_dir);
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi if (t_readlink(path, config_path_r, &error) < 0)
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi i_fatal("t_readlink(%s) failed: %s", path, error);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool master_service_parse_option(struct master_service *service,
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen service->config_path_changed_with_param = TRUE;
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen service->config_path_changed_with_param = TRUE;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (!array_is_created(&service->config_overrides))
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen array_append(&service->config_overrides, &arg, 1);
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenstatic void master_service_error(struct master_service *service)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen service->total_available_count || service->die_with_master) {
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainenstatic void master_status_error(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master wants us to die (or died itself). don't die until all
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service connections are finished. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the log fd may also be closed already, don't die when trying to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_init_finish(struct master_service *service)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen enum libsig_flags sigint_flags = LIBSIG_FLAG_DELAYED;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set default signal handlers */
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGINT, sigint_flags, sig_die, service);
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAG_DELAYED, sig_die, service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Must be started by dovecot master process");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* start listening errors for status fd, it means master died */
cbcba924a745c938260fd39cb284175b75f8eaf2Timo Sirainen service->io_status_error = io_add(MASTER_DEAD_FD, IO_ERROR,
4cbe2b4ee234317331eadd1768d9ce433adb60e1Timo Sirainen lib_signals_set_handler(SIGQUIT, 0, sig_close_listeners, service);
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_NO_SSL_INIT) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we already have a connection to be served */
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen /* close data stack frame opened by master_service_init() */
28bf8f762fcd21c57bf71822cf818447babce9a0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME) == 0) {
c6dfc77cb24ba1bb72437896080d3177b653e2afTimo Sirainenstatic void master_service_import_environment_real(const char *import_environment)
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen /* preserve existing DOVECOT_PRESERVE_ENVS */
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen /* add new environments */
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen envs = t_strsplit_spaces(import_environment, " ");
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen value = t_strarray_join(array_idx(&keys, 0), " ");
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen env_put(t_strconcat(DOVECOT_PRESERVE_ENVS_ENV"=", value, NULL));
c6dfc77cb24ba1bb72437896080d3177b653e2afTimo Sirainenvoid master_service_import_environment(const char *import_environment)
c6dfc77cb24ba1bb72437896080d3177b653e2afTimo Sirainen master_service_import_environment_real(import_environment);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen const char *value = getenv(DOVECOT_PRESERVE_ENVS_ENV);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen value = t_strconcat(value, " "DOVECOT_PRESERVE_ENVS_ENV, NULL);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen env_clean_except(t_strsplit_spaces(value, " "));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count = client_limit;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen service->master_status.available_count = client_limit - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainenunsigned int master_service_get_process_limit(struct master_service *service)
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainenunsigned int master_service_get_process_min_avail(struct master_service *service)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainenunsigned int master_service_get_idle_kill_secs(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = count - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenconst char *master_service_get_socket_name(struct master_service *service,
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen unsigned int i;
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen i_assert(listen_fd >= MASTER_LISTEN_FD_FIRST);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen void (*callback)(void))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenconst char *master_service_get_name(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_run(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_connection_callback_t *callback)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_stop(struct master_service *service)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* make sure we stop after servicing current connections */
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen current_count = service->total_available_count -
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen service->total_available_count = current_count;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* notify master that we're not accepting any more
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen connections */
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenbool master_service_is_killed(struct master_service *service)
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainenbool master_service_is_master_stopped(struct master_service *service)
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen (service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* anvil process was probably recreated, don't bother
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen logging an error about losing connection to it */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen } else if (ret == 0)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainenvoid master_service_client_connection_created(struct master_service *service)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen i_assert(service->master_status.available_count > 0);
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainenstatic bool master_service_want_listener(struct master_service *service)
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen if (service->master_status.available_count > 0) {
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen /* more concurrent clients can still be added */
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen /* after handling this client, the whole process will stop. */
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen if (service->avail_overflow_callback != NULL) {
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen /* overflow callback is set. it's possible that the current
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen existing client may be replaced by a new client, which needs
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen the listener to try to accept new connections. */
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen /* the listener isn't needed until the current client is disconnected */
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenvoid master_service_client_connection_handled(struct master_service *service,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen i_error("close(service connection) failed: %m");
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_destroyed(service);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen /* reading FIFOs stays open forever, don't count them
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen as real clients */
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_destroyed(service);
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen /* we're not going to accept any more connections after
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen this. go ahead and close the connection early. don't
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen do this before calling callback, because it may want
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen to access the listen_fd (e.g. to check socket
d2c41d6587f973d3b215e035288a07619bc22c2aTimo Sirainen permissions). */
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenvoid master_service_client_connection_callback(struct master_service *service,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_handled(service, conn);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* we can listen again */
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (service->service_count_left == service->total_available_count) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen i_assert(service->master_status.available_count <
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen i_assert(service->master_status.available_count ==
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen } else if ((service->io_status_error == NULL ||
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen /* we've finished handling all clients, and
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen a) master has closed the connection
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen b) there are no listeners (std-client?) */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&service->to_overflow_state);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->master_status.available_count > 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* some processes should now be able to handle new connections,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen although we can't. but there may be race conditions, so
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen make sure that we'll check again soon if the state has
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen changed to "full" without our knowledge. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* make sure we're listening for more connections */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Invalid master login state: %d", state);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainenvoid master_service_close_config_fd(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_deinit(struct master_service **_service)
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen unsigned int i;
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&service->to_overflow_state);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (array_is_created(&service->config_overrides))
41789540204ce091b2c06629d9a31788082e5da8Timo Sirainen /* run atexit callbacks before destroying ioloop */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->master_status.available_count == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* we are full. stop listening for now, unless overflow
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen callback destroys one of the existing connections */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->master_status.available_count == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* it's not a socket. should be a fifo. */
56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54Timo Sirainen (fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* BSDI fails accept(fifo) with EINVAL. */
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen /* try again later after one of the existing
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen connections has died */
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* use the "listener" as the connection fd and stop the
13f4d4d4a69d7dff2f71363d189d048abb04b6c6Timo Sirainen conn.name = master_service_get_socket_name(service, conn.listen_fd);
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch (void)net_getsockname(conn.fd, &conn.local_ip, &conn.local_port);
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen master_service_client_connection_created(service);
8761992b5aa05862e7ec3a460cdc17af41a4a0f5Timo Sirainen master_service_client_connection_callback(service, &conn);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenvoid master_service_io_listeners_add(struct master_service *service)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen unsigned int i;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen struct master_service_listener *l = &service->listeners[i];
04a6e51325d52a8f6046389406b2f606159a61e3Timo Sirainen if (l->io == NULL && l->fd != -1 && !l->closed) {
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainenvoid master_service_io_listeners_remove(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainenvoid master_service_ssl_io_listeners_remove(struct master_service *service)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen unsigned int i;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen unsigned int i;
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen /* close via listeners. some fds might be pipes that are
71056e0f5e1f68cb9ac002a7827eb98435c40d62Timo Sirainen currently handled as clients. we don't want to close them. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->master_status.available_count == 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenmaster_status_send(struct master_service *service, bool important_update)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* success */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen } else if (ret >= 0) {
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* shouldn't happen? */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen i_error("write(master_status_fd) returned %d", (int)ret);
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* failure */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen i_error("write(master_status_fd) failed: %m");
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* reader is busy, but it's important to get this notification
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen through. send it when possible. */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenvoid master_status_update(struct master_service *service)
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_UPDATE_PROCTITLE) != 0 &&
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen service->set != NULL && service->set->verbose_proctitle) T_BEGIN {
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen unsigned int used_count = service->total_available_count -
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen process_title_set(t_strdup_printf("[%u connections]",
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen important_update = master_status_update_is_important(service);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* a) closed, b) updating to same state */
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (ioloop_time == service->last_sent_status_time &&
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* don't spam master */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen master_status_send(service, important_update);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenbool version_string_verify(const char *line, const char *service_name,
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return version_string_verify_full(line, service_name,
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenbool version_string_verify_full(const char *line, const char *service_name,
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t service_name_len = strlen(service_name);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (strncmp(line, service_name, service_name_len) != 0 ||
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen ret = str_uint_equals(t_strdup_until(line, p),
754896551f0422cda5d78500b26700eec5343c5bAki Tuomibool master_service_is_ssl_module_loaded(struct master_service *service)
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi /* if this is TRUE, then ssl module is loaded by init */