master-service.c revision 9240d99920783c56405dda74a1f6c7ff1ebed8e6
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (C) 2005-2009 Timo Sirainen */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void io_listeners_add(struct master_service *service);
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void master_status_update(struct master_service *service);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return "c:ko:s:L";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen which is too common at least while testing :) */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen "(if you don't care, set version_ignore=yes)",
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen const char *str;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen /* NOTE: we start rooted, so keep the code minimal until
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen restrict_access_by_env() is called */
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen is properly initialized */
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen service->service_count_left = (unsigned int)-1;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
fbd918f47f591f8084fd52b207ef29515ddd11b9Timo Sirainen /* set up some kind of logging until we know exactly how and where
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen we want to log */
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
4b41116563110d00330896a568eff1078c382827Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_LOG_TO_STDERR) != 0) {
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen /* logging via log service */
61f5256ef248d35459b53534ae428bf6d016e1c5Timo Sirainen /* log to syslog */
cb05ecbd96ddb5e53c1850d27434541138a3f284Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
14ab4610b6038da6c5d0814fecabc6b74bc81a6bTimo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
e3796bfd2bc0fd5ba664893d346df9334a5b3af0Timo Sirainen /* log to file or stderr */
408e5be344c9131fdebe771718a5bf49f88cc51cTimo Sirainen path = home_expand(service->set->info_log_path);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenbool master_service_parse_option(struct master_service *service,
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (!array_is_created(&service->config_overrides))
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen array_append(&service->config_overrides, &arg, 1);
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen master wants us to die (or died itself). don't die until all
bd4d0a1a7c0626452b8d82f37e3ec07267ac9896Timo Sirainen service connections are finished. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* the log fd may also be closed already, don't die when trying to
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_init_finish(struct master_service *service)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int count;
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen i_assert(service->total_available_count == 0);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* set default signal handlers */
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
ca98d6a1bbe73499da758a36bfab2963375c8d06Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_fatal("Must be started by dovecot master process");
64b5dcc136d6eb7ad90463e6cba9e16880ab52adTimo Sirainen /* initialize master_status structure */
f23ede27743c1aa03eacbfc634d6a10de9110c91Timo Sirainen /* set the default limit */
47001341950b8588c5f3a96b75864dab48e279aeTimo Sirainen master_service_set_client_limit(service, count);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen /* start listening errors for status fd, it means master died */
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen /* we already have a connection to be served */
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainenvoid master_service_env_clean(bool preserve_home)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen /* Note that if the original environment was set with env_put(), the
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen environment strings will be invalid after env_clean(). That's why
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen we t_strconcat() them above. */
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenvoid master_service_set_client_limit(struct master_service *service,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(service->master_status.available_count ==
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->total_available_count = client_limit;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen service->master_status.available_count = client_limit;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen unsigned int count)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen unsigned int used;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen service->master_status.available_count = count - used;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
310767ca33e7636d40ec45dee68a2c319a5fa3c0Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenconst char *master_service_get_config_path(struct master_service *service)
1eb17e61d3d38372674aa0c55caedb0185a985f5Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenvoid master_service_run(struct master_service *service,
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen master_service_connection_callback_t *callback)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid master_service_stop(struct master_service *service)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
194603b35061fea1ee8d171a7104b6985c610966Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen else if (ret == 0)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* we can listen again */
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen if (service->service_count_left != service->total_available_count) {
e63bdfedcf61e1a9ee21990140cbd0d0638da7e1Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* we have only limited amount of service requests left */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_assert(service->master_status.available_count ==
a423d985ba7261661475811c22b21b80ec765a71Timo Sirainen /* master has closed the connection and we have nothing else
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen to do anymore. */
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenvoid master_service_deinit(struct master_service **_service)
4d527c363482be2b65dd0573d878ecda86cbb0bbTimo Sirainen if (array_is_created(&service->config_overrides))
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (l->service->master_status.available_count == 0) {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen /* we are full. stop listening for now. */
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen /* it's not a socket. probably a fifo. use the "listener"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen as the connection fd */
3c493c276f599d9b9cd10764876d648003046954Timo Sirainenstatic void io_listeners_add(struct master_service *service)
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen unsigned int i;
return TRUE;
return TRUE;
return FALSE;
if (ret > 0) {
} else if (ret == 0) {