master-service.c revision 3eeaad7297f63f643ebb3fb2a0f7a03b20ffc120
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2005-2010 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) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo 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)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen const char *str;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* make sure we can dump core, at least until
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen privileges are dropped. (i'm not really sure why this
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen is needed, because doing the same just before exec
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen doesn't help, and exec shouldn't affect this with
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo 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));
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen /* ignore these signals as early as possible */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* keep getopt_str first in case it contains "+" */
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen service->service_count_left = (unsigned int)-1;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* set up some kind of logging until we know exactly how and where
27586e4785d56aeb76e1fd96af8db799688dc64aTimo 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));
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen master_service_verify_version_string(service);
f0d09be40bd0c4423873128ae2f88a4020075dc4Timo Sirainenint master_getopt(struct master_service *service)
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen while ((c = getopt(service->argc, service->argv,
917498e6f84969d2b93410c1e479735abe8e0ed7Timo Sirainen if (!master_service_parse_option(service, c, optarg))
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainenvoid master_service_init_log(struct master_service *service,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk const char *path;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen /* logging via log service */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* error logging goes to file or stderr */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* something gets logged to syslog */
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen /* set error handlers back to file */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen path = home_expand(service->set->info_log_path);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen path = home_expand(service->set->debug_log_path);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Boschvoid master_service_set_die_callback(struct master_service *service,
33525312d3f45995686aa0b538dea1cd6eb936e2Timo Sirainen void (*callback)(void))
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenbool master_service_parse_option(struct master_service *service,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!array_is_created(&service->config_overrides))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen array_append(&service->config_overrides, &arg, 1);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic void master_service_error(struct master_service *service)
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen service->total_available_count || service->die_with_master) {
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen master wants us to die (or died itself). don't die until all
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen service connections are finished. */
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen /* the log fd may also be closed already, don't die when trying to
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenvoid master_service_init_finish(struct master_service *service)
fa780a18c41881036af582f7a3473d6399e9d34dTimo Sirainen unsigned int count;
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen i_assert(service->total_available_count == 0);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
12b4dbf933ee54f7b96968ba150095baa985fdafTimo Sirainen /* set default signal handlers */
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen i_fatal("Must be started by dovecot master process");
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* initialize master_status structure */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* set the default limit */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen master_service_set_client_limit(service, count);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* set the default service count */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen master_service_set_service_count(service, count);
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen /* start listening errors for status fd, it means master died */
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* we already have a connection to be served */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenvoid master_service_env_clean(bool preserve_home)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen static const char *preserve_envs[] = {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int i;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen t_array_init(&envs, N_ELEMENTS(preserve_envs));
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen /* Note that if the original environment was set with env_put(), the
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen environment strings will be invalid after env_clean(). That's why
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen we t_strconcat() them above. */
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenvoid master_service_set_client_limit(struct master_service *service,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_assert(service->master_status.available_count ==
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->total_available_count = client_limit;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = client_limit - used;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainen unsigned int count)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen unsigned int used;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen service->master_status.available_count = count - used;
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo 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)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* make sure we stop after servicing current connections */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen current_count = service->total_available_count -
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen service->total_available_count = current_count;
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen /* notify master that we're not accepting any more
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen connections */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainenbool master_service_is_killed(struct master_service *service)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* anvil process was probably recreated, don't bother
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen logging an error about losing connection to it */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen } else if (ret == 0)
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo 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 */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (service->service_count_left == service->total_available_count) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (service->service_count_left != (unsigned int)-1)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_assert(service->master_status.available_count <
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen i_assert(service->master_status.available_count ==
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else if ((service->io_status_error == NULL ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* we've finished handling all clients, and
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen a) master has closed the connection
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen b) there are no listeners (std-client?) */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
a4e2101473cfd7ce960fc49b3ce097c3f89ec2adTimo 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 */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_error("Invalid master login state: %d", state);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo 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))
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen if (service->master_status.available_count == 0) {
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* we are full. stop listening for now, unless overflow
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo 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);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* it's not a socket. should be a fifo. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen (fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen /* BSDI fails accept(fifo) with EINVAL. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* use the "listener" as the connection fd and stop the
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen i_assert(service->master_status.available_count > 0);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen i_error("close(service connection) failed: %m");
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen master_service_client_connection_destroyed(service);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic void io_listeners_init(struct master_service *service)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen unsigned int i;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen i_new(struct master_service_listener, service->socket_count);
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen struct master_service_listener *l = &service->listeners[i];
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid master_service_io_listeners_add(struct master_service *service)
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainen unsigned int i;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen struct master_service_listener *l = &service->listeners[i];
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenvoid master_service_io_listeners_remove(struct master_service *service)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo 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)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (service->master_status.available_count == 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenvoid master_status_update(struct master_service *service)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen important_update = master_status_update_is_important(service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* a) closed, b) updating to same state */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ioloop_time == service->last_sent_status_time &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* don't spam master */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch ret = write(MASTER_STATUS_FD, &service->master_status,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* success */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* delayed important update sent successfully */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen } else if (ret >= 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* shouldn't happen? */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen i_error("write(master_status_fd) returned %d", (int)ret);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* failure */
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen i_error("write(master_status_fd) failed: %m");
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* reader is busy, but it's important to get this notification
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen through. send it when possible. */
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainenbool version_string_verify(const char *line, const char *service_name,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen unsigned int service_name_len = strlen(service_name);
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen if (strncmp(line, service_name, service_name_len) != 0 ||