master-service.c revision c444eeaa2866152cf62652698aa11b125e8454bc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2011 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen/* when we're full of connections, how often to check if login state has
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen just a fallback against race conditions. */
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
697ff56bf3cdc9e7989ea2a70accf866b14b64d1Timo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen return "c:ko:Os:L";
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen want to log it in either case.*/
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* never die when idling */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* SIGINT came from master. die only if we're not handling
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen any clients currently. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen "(if you don't care, set version_ignore=yes)",
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen int *argc, char **argv[], const char *getopt_str)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* make sure we can dump core, at least until
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen privileges are dropped. (i'm not really sure why this
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen is needed, because doing the same just before exec
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen doesn't help, and exec shouldn't affect this with
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
ac2defed599a97c4a71a9e90ba185929dfe59226Josef 'Jeff' Sipek restrict_access_by_env() is called */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen is properly initialized */
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* ignore these signals as early as possible */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* keep getopt_str first in case it contains "+" */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->service_count_left = (unsigned int)-1;
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set up some kind of logging until we know exactly how and where
5214b67a7dabab87da74e04bb8b227f94b95bce4Timo Sirainen we want to log */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* initialize master_status structure */
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen /* set the default limit */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk master_service_set_client_limit(service, count);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* seve the process limit */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (value != NULL && str_to_uint(value, &count) == 0 &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set the default service count */
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen master_service_set_service_count(service, count);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen master_service_verify_version_string(service);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenint master_getopt(struct master_service *service)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen while ((c = getopt(service->argc, service->argv,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (!master_service_parse_option(service, c, optarg))
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenvoid master_service_init_log(struct master_service *service,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* logging via log service */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* error logging goes to file or stderr */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen /* something gets logged to syslog */
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* set error handlers back to file */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen path = home_expand(service->set->info_log_path);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen path = home_expand(service->set->debug_log_path);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainenvoid master_service_set_die_callback(struct master_service *service,
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen void (*callback)(void))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenvoid master_service_set_idle_die_callback(struct master_service *service,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen bool (*callback)(void))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenbool master_service_parse_option(struct master_service *service,
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen if (!array_is_created(&service->config_overrides))
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen array_append(&service->config_overrides, &arg, 1);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainenstatic void master_service_error(struct master_service *service)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen service->total_available_count || service->die_with_master) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* status fd is a write-only pipe, so if we're here it means the
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen master wants us to die (or died itself). don't die until all
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen service connections are finished. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* the log fd may also be closed already, don't die when trying to
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainenvoid master_service_init_finish(struct master_service *service)
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen enum libsig_flags sigint_flags = LIBSIG_FLAG_DELAYED;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* set default signal handlers */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen lib_signals_set_handler(SIGINT, sigint_flags, sig_die, service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAG_DELAYED, sig_die, service);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen i_fatal("Must be started by dovecot master process");
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* start listening errors for status fd, it means master died */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen service->io_status_error = io_add(MASTER_DEAD_FD, IO_ERROR,
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* we already have a connection to be served */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen const char *value = getenv(DOVECOT_PRESERVE_ENVS_ENV);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen value = t_strconcat(value, " "DOVECOT_PRESERVE_ENVS_ENV, NULL);
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen env_clean_except(t_strsplit_spaces(value, " "));
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen unsigned int used;
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen i_assert(service->master_status.available_count ==
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen service->total_available_count = client_limit;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = client_limit - used;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenunsigned int master_service_get_process_limit(struct master_service *service)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int count)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = count - used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen void (*callback)(void))
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_config_path(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_version_string(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenconst char *master_service_get_name(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_run(struct master_service *service,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen master_service_connection_callback_t *callback)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_stop(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* make sure we stop after servicing current connections */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen current_count = service->total_available_count -
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen service->total_available_count = current_count;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* notify master that we're not accepting any more
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen connections */
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainenbool master_service_is_killed(struct master_service *service)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* anvil process was probably recreated, don't bother
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen logging an error about losing connection to it */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen } else if (ret == 0)
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainenvoid master_service_client_connection_created(struct master_service *service)
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen i_assert(service->master_status.available_count > 0);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* we can listen again */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (service->service_count_left == service->total_available_count) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->service_count_left != (unsigned int)-1)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(service->master_status.available_count <
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(service->master_status.available_count ==
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if ((service->io_status_error == NULL ||
d3e5a14ea363264dcc7640ca7226249d0c27a793Timo Sirainen /* we've finished handling all clients, and
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen a) master has closed the connection
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen b) there are no listeners (std-client?) */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenstatic void master_service_set_login_state(struct master_service *service,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (service->master_status.available_count > 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* some processes should now be able to handle new connections,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen although we can't. but there may be race conditions, so
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen make sure that we'll check again soon if the state has
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen changed to "full" without our knowledge. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* make sure we're listening for more connections */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen i_error("Invalid master login state: %d", state);
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_close_config_fd(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_error("close(master config fd) failed: %m");
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenvoid master_service_deinit(struct master_service **_service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (array_is_created(&service->config_overrides))
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen if (service->master_status.available_count == 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* we are full. stop listening for now, unless overflow
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen callback destroys one of the existing connections */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->master_status.available_count == 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* it's not a socket. should be a fifo. */
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen (fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* BSDI fails accept(fifo) with EINVAL. */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* use the "listener" as the connection fd and stop the
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_client_connection_created(service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_error("close(service connection) failed: %m");
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen master_service_client_connection_destroyed(service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* reading FIFOs stays open forever, don't count them
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen as real clients */
8ca217bf3aa23c7922d0d4aa44fcd2320416d61cMartti Rannanjärvi master_service_client_connection_destroyed(service);
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenstatic void io_listeners_init(struct master_service *service)
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen unsigned int i;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_new(struct master_service_listener, service->socket_count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen struct master_service_listener *l = &service->listeners[i];
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenvoid master_service_io_listeners_add(struct master_service *service)
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen unsigned int i;
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen struct master_service_listener *l = &service->listeners[i];
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenvoid master_service_io_listeners_remove(struct master_service *service)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenstatic void master_service_io_listeners_close(struct master_service *service)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen unsigned int i;
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen /* close via listeners. some fds might be pipes that are
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen currently handled as clients. we don't want to close them. */
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (service->master_status.available_count == 0)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenvoid master_status_update(struct master_service *service)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_UPDATE_PROCTITLE) != 0 &&
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->set != NULL && service->set->verbose_proctitle) T_BEGIN {
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen unsigned int used_count = service->total_available_count -
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen process_title_set(t_strdup_printf("[%u connections]",
e353d03d3643f380dc7e6dc29a512dec86b8a3deTimo Sirainen important_update = master_status_update_is_important(service);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* a) closed, b) updating to same state */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen if (ioloop_time == service->last_sent_status_time &&
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* don't spam master */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen /* success */
b7c7a04bc5edb8eebea3837ff624441d9fa3721cTimo Sirainen /* delayed important update sent successfully */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen } else if (ret >= 0) {
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen /* shouldn't happen? */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_error("write(master_status_fd) returned %d", (int)ret);
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen /* failure */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_error("write(master_status_fd) failed: %m");
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* reader is busy, but it's important to get this notification
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen through. send it when possible. */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainenbool version_string_verify(const char *line, const char *service_name,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen unsigned int service_name_len = strlen(service_name);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (strncmp(line, service_name, service_name_len) != 0 ||