master-service.c revision 835ba470fb6a73b74e258e12678236106d0df09e
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib-signals.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "ioloop.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "array.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "env-util.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "home-expand.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "process-title.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "restrict-access.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "fd-close-on-exec.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "settings-parser.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "syslog-util.h"
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include "master-login.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "master-service-private.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include "master-service-settings.h"
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include <stdlib.h>
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include <unistd.h>
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen#include <sys/stat.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <syslog.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen/* when we're full of connections, how often to check if login state has
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen changed. we normally notice it immediately because of a signal, so this is
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen just a fallback against race conditions. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen#define MASTER_SERVICE_STATE_CHECK_MSECS 1000
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen force it. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstruct master_service *master_service;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenconst char *master_service_getopt_string(void)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return "c:ko:Os:L";
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen}
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen{
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen struct master_service *service = context;
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen want to log it in either case.*/
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen if (si->si_signo != SIGINT) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen si->si_signo, dec2str(si->si_pid),
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen dec2str(si->si_uid),
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen /* never die when idling */
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen return;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen /* SIGINT came from master. die only if we're not handling
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen any clients currently. */
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen if (service->master_status.available_count !=
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen service->total_available_count)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->killed = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen io_loop_stop(service->ioloop);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct master_service *service = context;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen master_service_refresh_login_state(service);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (service->version_string != NULL &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("Dovecot version mismatch: "
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen "(if you don't care, set version_ignore=yes)",
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen service->version_string, service->name);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen }
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen}
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenstruct master_service *
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen int *argc, char **argv[], const char *getopt_str)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen{
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen struct master_service *service;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen const char *str;
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen i_assert(name != NULL);
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen#ifdef DEBUG
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (getenv("GDB") == NULL &&
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen str = getenv("SOCKET_COUNT");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen count = str == NULL ? 0 : atoi(str);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen#endif
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* make sure we can dump core, at least until
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen privileges are dropped. (i'm not really sure why this
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen is needed, because doing the same just before exec
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen doesn't help, and exec shouldn't affect this with
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen non-setuid/gid binaries..) */
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen restrict_access_allow_coredumps(TRUE);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen restrict_access_by_env() is called */
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen lib_init();
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen is properly initialized */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* ignore these signals as early as possible */
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
556f95092c3bc850517d5ab2bb502024a55645f1Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen process_title_init(argv);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen service = i_new(struct master_service, 1);
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen service->argc = *argc;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen service->argv = *argv;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen service->name = i_strdup(name);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* keep getopt_str first in case it contains "+" */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->getopt_str = getopt_str == NULL ?
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_strdup(master_service_getopt_string()) :
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->flags = flags;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen service->ioloop = io_loop_create();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->service_count_left = (unsigned int)-1;
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen service->config_fd = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->config_path == NULL) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->config_path_is_default = TRUE;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen }
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen service->socket_count = 1;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen } else {
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen service->version_string = PACKAGE_VERSION;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str = getenv("SOCKET_COUNT");
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (str != NULL)
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen service->socket_count = atoi(str);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen str = getenv("SSL_SOCKET_COUNT");
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (str != NULL)
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen service->ssl_socket_count = atoi(str);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* set up some kind of logging until we know exactly how and where
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen we want to log */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_set_failure_internal();
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (getenv("USER") != NULL) {
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen name, getenv("USER")));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen master_service_verify_version_string(service);
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen return service;
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen}
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenint master_getopt(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen int c;
5238111c460098d9cc8cc22527026138a278b9a4Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen while ((c = getopt(service->argc, service->argv,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->getopt_str)) > 0) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (!master_service_parse_option(service, c, optarg))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen break;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return c;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainenvoid master_service_init_log(struct master_service *service,
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen const char *prefix)
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen{
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen const char *path;
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_set_failure_file("/dev/stderr", "");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* logging via log service */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_failure_internal();
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen i_set_failure_prefix(prefix);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (service->set == NULL) {
8f32e59200da904613506f5649ffa4d9f5989cebTimo Sirainen i_set_failure_file("/dev/stderr", prefix);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen return;
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen /* error logging goes to file or stderr */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen path = home_expand(service->set->log_path);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_set_failure_file(path, prefix);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen /* something gets logged to syslog */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen int facility;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen &facility))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen facility = LOG_MAIL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen i_set_failure_prefix(prefix);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* set error handlers back to file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_fatal_handler(NULL);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen i_set_error_handler(NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen }
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen if (*service->set->info_log_path != '\0' &&
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen path = home_expand(service->set->info_log_path);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (*path != '\0')
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_set_info_file(path);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (*service->set->debug_log_path != '\0' &&
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen path = home_expand(service->set->debug_log_path);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen if (*path != '\0')
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen i_set_debug_file(path);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen }
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen bool set)
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen{
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen service->die_with_master = set;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen}
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen void (*callback)(void))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen{
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen service->die_callback = callback;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen}
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenbool master_service_parse_option(struct master_service *service,
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen int opt, const char *arg)
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen{
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen switch (opt) {
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen case 'c':
555ebb032f9b8f0cdb66f27ce7374734833e7cacTimo Sirainen service->config_path = arg;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->config_path_is_default = FALSE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen case 'k':
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->keep_environment = TRUE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen case 'o':
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!array_is_created(&service->config_overrides))
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_array_init(&service->config_overrides, 16);
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen array_append(&service->config_overrides, &arg, 1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen case 'O':
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen break;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen case 'L':
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen service->log_directly = TRUE;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen break;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen default:
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return FALSE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen return TRUE;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen}
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void master_service_error(struct master_service *service)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen master_service_stop_new_connections(service);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (service->master_status.available_count ==
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->total_available_count || service->die_with_master) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (service->die_callback == NULL)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen master_service_stop(service);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen else {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->to_die =
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen timeout_add(MASTER_SERVICE_DIE_TIMEOUT_MSECS,
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen master_service_stop,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->die_callback();
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void master_status_error(void *context)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen struct master_service *service = context;
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen master wants us to die (or died itself). don't die until all
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen service connections are finished. */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen io_remove(&service->io_status_error);
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen /* the log fd may also be closed already, don't die when trying to
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen log later */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_set_failure_ignore_errors(TRUE);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen master_service_error(service);
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen}
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainenvoid master_service_init_finish(struct master_service *service)
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainen{
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen struct stat st;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen const char *value;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int count;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(service->total_available_count == 0);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set default signal handlers */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen lib_signals_init();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen lib_signals_set_handler(SIGUSR1, TRUE,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen sig_state_changed, service);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_fatal("Must be started by dovecot master process");
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen /* initialize master_status structure */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen value = getenv(MASTER_UID_ENV);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (value == NULL ||
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_fatal(MASTER_UID_ENV" missing");
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen service->master_status.pid = getpid();
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set the default limit */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen count == 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" missing");
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_set_client_limit(service, count);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set the default service count */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen value = getenv(MASTER_SERVICE_COUNT_ENV);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen count > 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_set_service_count(service, count);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* start listening errors for status fd, it means master died */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_status_error, service);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen } else {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen master_service_set_client_limit(service, 1);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_set_service_count(service, 1);
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen }
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_io_listeners_add(service);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen /* we already have a connection to be served */
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen service->master_status.available_count--;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_status_update(service);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainenvoid master_service_env_clean(bool preserve_home)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen const char *user, *tz, *home;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen#ifdef DEBUG
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen bool gdb = getenv("GDB") != NULL;
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen#endif
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen user = getenv("USER");
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen if (user != NULL)
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen user = t_strconcat("USER=", user, NULL);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen tz = getenv("TZ");
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (tz != NULL)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen home = preserve_home ? getenv("HOME") : NULL;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (home != NULL)
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen home = t_strconcat("HOME=", home, NULL);
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen /* Note that if the original environment was set with env_put(), the
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen environment strings will be invalid after env_clean(). That's why
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen we t_strconcat() them above. */
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen env_clean();
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen if (user != NULL) env_put(user);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen if (tz != NULL) env_put(tz);
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (home != NULL) env_put(home);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen#ifdef DEBUG
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen if (gdb) env_put("GDB=1");
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen#endif
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen}
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainenvoid master_service_set_client_limit(struct master_service *service,
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen unsigned int client_limit)
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen{
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen unsigned int used;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen i_assert(service->master_status.available_count ==
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen service->total_available_count);
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen used = service->total_available_count -
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen service->master_status.available_count;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen i_assert(client_limit >= used);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen service->total_available_count = client_limit;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen service->master_status.available_count = client_limit - used;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen}
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return service->total_available_count;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen}
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen unsigned int count)
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen{
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen unsigned int used;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen used = service->total_available_count -
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen service->master_status.available_count;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_assert(count >= used);
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen
71da447014454c84828d9dface77219875554d7dTimo Sirainen if (service->total_available_count > count) {
71da447014454c84828d9dface77219875554d7dTimo Sirainen service->total_available_count = count;
71da447014454c84828d9dface77219875554d7dTimo Sirainen service->master_status.available_count = count - used;
71da447014454c84828d9dface77219875554d7dTimo Sirainen }
71da447014454c84828d9dface77219875554d7dTimo Sirainen service->service_count_left = count;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return service->service_count_left;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return service->socket_count;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen void (*callback)(void))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->avail_overflow_callback = callback;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return service->config_path;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return service->version_string;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_name(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return service->name;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_run(struct master_service *service,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_connection_callback_t *callback)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->callback = callback;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen io_loop_run(service->ioloop);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->callback = NULL;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_stop(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen io_loop_stop(service->ioloop);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen unsigned int current_count;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->stopping)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return;
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen
2d2ebe91d56e9a158de000c9d0026f65600fbcfaTimo Sirainen service->stopping = TRUE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_io_listeners_remove(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_io_listeners_close(service);
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* make sure we stop after servicing current connections */
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen current_count = service->total_available_count -
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen service->master_status.available_count;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen service->service_count_left = current_count;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen service->total_available_count = current_count;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (current_count == 0)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen master_service_stop(service);
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen else {
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* notify master that we're not accepting any more
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen connections */
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen service->master_status.available_count = 0;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen master_status_update(service);
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen }
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen if (service->login != NULL)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen master_login_stop(service->login);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenbool master_service_is_killed(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return service->killed;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ssize_t ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ret < 0) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (errno == EPIPE) {
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* anvil process was probably recreated, don't bother
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen logging an error about losing connection to it */
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen return;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen }
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen i_error("write(anvil) failed: %m");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else if (ret == 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_error("write(anvil) failed: EOF");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen else {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert((size_t)ret == strlen(cmd));
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen conn->accepted = TRUE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* we can listen again */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_io_listeners_add(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(service->total_available_count > 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_assert(service->service_count_left > 0);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->service_count_left == service->total_available_count) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->total_available_count--;
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen service->service_count_left--;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->service_count_left != (unsigned int)-1)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->service_count_left--;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen i_assert(service->master_status.available_count <
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->total_available_count);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->master_status.available_count++;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen }
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (service->service_count_left == 0) {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen i_assert(service->master_status.available_count ==
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->total_available_count);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen master_service_stop(service);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen } else if ((service->io_status_error == NULL ||
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->listeners == NULL) &&
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->master_status.available_count ==
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->total_available_count) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* we've finished handling all clients, and
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen a) master has closed the connection
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen b) there are no listeners (std-client?) */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_stop(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else {
d78be924ad150840e018eda6a8a7d5e46a39bda2Timo Sirainen master_status_update(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen enum master_login_state state)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->to_overflow_state != NULL)
46631c1d903c409444b1b1c4a1d41a033c09ee37Timo Sirainen timeout_remove(&service->to_overflow_state);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen switch (state) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen case MASTER_LOGIN_STATE_NONFULL:
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->call_avail_overflow = FALSE;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->master_status.available_count > 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* some processes should now be able to handle new connections,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen although we can't. but there may be race conditions, so
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen make sure that we'll check again soon if the state has
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen changed to "full" without our knowledge. */
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen service->to_overflow_state =
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen timeout_add(MASTER_SERVICE_STATE_CHECK_MSECS,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_refresh_login_state,
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen return;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen case MASTER_LOGIN_STATE_FULL:
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* make sure we're listening for more connections */
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen service->call_avail_overflow = TRUE;
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen master_service_io_listeners_add(service);
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen return;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_error("Invalid master login state: %d", state);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen int ret;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (ret < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_error("lseek(login notify fd) failed: %m");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen else
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_set_login_state(service, ret);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_close_config_fd(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->config_fd != -1) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (close(service->config_fd) < 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_error("close(master config fd) failed: %m");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen service->config_fd = -1;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen }
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen}
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_deinit(struct master_service **_service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen{
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen struct master_service *service = *_service;
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen *_service = NULL;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_io_listeners_remove(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_close_config_fd(service);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->to_die != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen timeout_remove(&service->to_die);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->to_overflow_state != NULL)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen timeout_remove(&service->to_overflow_state);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->to_status != NULL)
71da447014454c84828d9dface77219875554d7dTimo Sirainen timeout_remove(&service->to_status);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (service->io_status_error != NULL)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen io_remove(&service->io_status_error);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (service->io_status_write != NULL)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen io_remove(&service->io_status_write);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (array_is_created(&service->config_overrides))
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen array_free(&service->config_overrides);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen if (service->set_parser != NULL) {
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen settings_parser_deinit(&service->set_parser);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen pool_unref(&service->set_pool);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen }
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen lib_signals_deinit();
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen io_loop_destroy(&service->ioloop);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen i_free(service->listeners);
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen i_free(service->getopt_str);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen i_free(service->name);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen i_free(service);
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen lib_deinit();
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen}
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen{
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct master_service *service = l->service;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen struct master_service_connection conn;
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen if (service->master_status.available_count == 0) {
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainen /* we are full. stop listening for now, unless overflow
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen callback destroys one of the existing connections */
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (service->call_avail_overflow &&
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->avail_overflow_callback != NULL)
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen service->avail_overflow_callback();
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen if (service->master_status.available_count == 0) {
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen master_service_io_listeners_remove(service);
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen return;
}
}
memset(&conn, 0, sizeof(conn));
conn.listen_fd = l->fd;
conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
if (conn.fd < 0) {
struct stat st;
int orig_errno = errno;
if (conn.fd == -1)
return;
if (errno == ENOTSOCK) {
/* it's not a socket. should be a fifo. */
} else if (errno == EINVAL &&
(fstat(l->fd, &st) < 0 || !S_ISFIFO(st.st_mode))) {
/* BSDI fails accept(fifo) with EINVAL. */
} else {
errno = orig_errno;
i_error("net_accept() failed: %m");
master_service_error(service);
return;
}
/* use the "listener" as the connection fd and stop the
listener. */
conn.fd = l->fd;
conn.listen_fd = l->fd;
conn.fifo = TRUE;
io_remove(&l->io);
l->fd = -1;
}
conn.ssl = l->ssl;
net_set_nonblock(conn.fd, TRUE);
i_assert(service->master_status.available_count > 0);
service->master_status.available_count--;
master_status_update(service);
service->callback(&conn);
if (!conn.accepted) {
if (close(conn.fd) < 0)
i_error("close(service connection) failed: %m");
master_service_client_connection_destroyed(service);
}
}
static void io_listeners_init(struct master_service *service)
{
unsigned int i;
if (service->socket_count == 0)
return;
service->listeners =
i_new(struct master_service_listener, service->socket_count);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
l->service = service;
l->fd = MASTER_LISTEN_FD_FIRST + i;
if (i >= service->socket_count - service->ssl_socket_count)
l->ssl = TRUE;
}
}
void master_service_io_listeners_add(struct master_service *service)
{
unsigned int i;
if (service->stopping)
return;
if (service->listeners == NULL)
io_listeners_init(service);
for (i = 0; i < service->socket_count; i++) {
struct master_service_listener *l = &service->listeners[i];
if (l->io == NULL && l->fd != -1) {
l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
master_service_listen, l);
}
}
}
void master_service_io_listeners_remove(struct master_service *service)
{
unsigned int i;
if (service->listeners != NULL) {
for (i = 0; i < service->socket_count; i++) {
if (service->listeners[i].io != NULL)
io_remove(&service->listeners[i].io);
}
}
}
static void master_service_io_listeners_close(struct master_service *service)
{
unsigned int i;
if (service->listeners != NULL) {
/* close via listeners. some fds might be pipes that are
currently handled as clients. we don't want to close them. */
for (i = 0; i < service->socket_count; i++) {
if (service->listeners[i].fd != -1) {
if (close(service->listeners[i].fd) < 0) {
i_error("close(listener %d) failed: %m",
service->listeners[i].fd);
}
}
}
} else {
for (i = 0; i < service->socket_count; i++) {
int fd = MASTER_LISTEN_FD_FIRST + i;
if (close(fd) < 0)
i_error("close(listener %d) failed: %m", fd);
}
}
}
static bool master_status_update_is_important(struct master_service *service)
{
if (service->master_status.available_count == 0)
return TRUE;
if (!service->initial_status_sent)
return TRUE;
return FALSE;
}
void master_status_update(struct master_service *service)
{
ssize_t ret;
bool important_update;
important_update = master_status_update_is_important(service);
if (service->master_status.pid == 0 ||
service->master_status.available_count ==
service->last_sent_status_avail_count) {
/* a) closed, b) updating to same state */
if (service->to_status != NULL)
timeout_remove(&service->to_status);
if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
return;
}
if (ioloop_time == service->last_sent_status_time &&
!important_update) {
/* don't spam master */
if (service->to_status != NULL)
timeout_reset(service->to_status);
else {
service->to_status =
timeout_add(1000, master_status_update,
service);
}
if (service->io_status_write != NULL)
io_remove(&service->io_status_write);
return;
}
if (service->to_status != NULL)
timeout_remove(&service->to_status);
ret = write(MASTER_STATUS_FD, &service->master_status,
sizeof(service->master_status));
if (ret == sizeof(service->master_status)) {
/* success */
if (service->io_status_write != NULL) {
/* delayed important update sent successfully */
io_remove(&service->io_status_write);
}
service->last_sent_status_time = ioloop_time;
service->last_sent_status_avail_count =
service->master_status.available_count;
service->initial_status_sent = TRUE;
} else if (ret >= 0) {
/* shouldn't happen? */
i_error("write(master_status_fd) returned %d", (int)ret);
service->master_status.pid = 0;
} else if (errno != EAGAIN) {
/* failure */
if (errno != EPIPE)
i_error("write(master_status_fd) failed: %m");
service->master_status.pid = 0;
} else if (important_update) {
/* reader is busy, but it's important to get this notification
through. send it when possible. */
if (service->io_status_write == NULL) {
service->io_status_write =
io_add(MASTER_STATUS_FD, IO_WRITE,
master_status_update, service);
}
}
}
bool version_string_verify(const char *line, const char *service_name,
unsigned major_version)
{
unsigned int service_name_len = strlen(service_name);
bool ret;
if (strncmp(line, "VERSION\t", 8) != 0)
return FALSE;
line += 8;
if (strncmp(line, service_name, service_name_len) != 0 ||
line[service_name_len] != '\t')
return FALSE;
line += service_name_len + 1;
T_BEGIN {
ret = str_uint_equals(t_strcut(line, '\t'), major_version);
} T_END;
return ret;
}