master-service.c revision 835ba470fb6a73b74e258e12678236106d0df09e
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8b247780e911909a9fdc47f69ce6d1478902ad98Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
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/* If die callback hasn't managed to stop the service for this many seconds,
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen return "c:ko:Os:L";
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
59e26ff34b05cd971a111f8a42fc60c13d9f688bTimo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
9a48c2243fe98ca8393be7908f84d20c634bcdf9Timo Sirainen want to log it in either case.*/
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
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 */
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. */
571fd6ff94570ee11a72a20b649acfdac2495919Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen "(if you don't care, set version_ignore=yes)",
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen int *argc, char **argv[], const char *getopt_str)
eb98a038ca8b0ef33d1d11794803ce09547496faTimo Sirainen const char *str;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
211ed7806d8715ec2280ffbf5d10f0d6e4f1beb2Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
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..) */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen restrict_access_by_env() is called */
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 /* ignore these signals as early as possible */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* keep getopt_str first in case it contains "+" */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->service_count_left = (unsigned int)-1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
10ff47d5d6146995e16da00d36eca7d162064a7bTimo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* set up some kind of logging until we know exactly how and where
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen we want to log */
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen master_service_verify_version_string(service);
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenint master_getopt(struct master_service *service)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen while ((c = getopt(service->argc, service->argv,
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if (!master_service_parse_option(service, c, optarg))
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainenvoid master_service_init_log(struct master_service *service,
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
de954ff15b495be13007a8aca2c09fd1d356a283Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
3d77cc0d502dc69ffe2afe318605964dd40b7b20Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen /* logging via log service */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
b92e979748a22925b0770d3004eaab043ed69574Timo Sirainen /* error logging goes to file or stderr */
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 */
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen /* set error handlers back to file */
0dbcf4026ff8471b4d6d2e14f7e52321396bf087Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
0ce5f96804e81cb0f857e7df32c0272f1eed9377Timo Sirainen path = home_expand(service->set->info_log_path);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
8b2cf1c1bd8ddcea0525b62fd35ba76e136828a1Timo Sirainen path = home_expand(service->set->debug_log_path);
6cc0546c058f3e6253c6f99727b28dd602712974Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainen void (*callback)(void))
9de176ef7f3d28ff486c2a8805110b84389e4f19Timo Sirainenbool master_service_parse_option(struct master_service *service,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (!array_is_created(&service->config_overrides))
4e8d6d03c2ff85448df79b181a2ea850fb5d4199Timo Sirainen array_append(&service->config_overrides, &arg, 1);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void master_service_error(struct master_service *service)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen service->total_available_count || service->die_with_master) {
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. */
f988b93c2ef773987bcdcbfb4cca39b955e3a392Timo Sirainen /* the log fd may also be closed already, don't die when trying to
98a73e104c7b9c3747053e63113451e24daf7f36Timo Sirainenvoid master_service_init_finish(struct master_service *service)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen unsigned int count;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(service->total_available_count == 0);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set default signal handlers */
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 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");
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen /* initialize master_status structure */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set the default limit */
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_set_client_limit(service, count);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* set the default service count */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen master_service_set_service_count(service, count);
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,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainen /* we already have a connection to be served */
b90fb7f78aca271243c26074ddd6587cce112a1eTimo Sirainenvoid master_service_env_clean(bool preserve_home)
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 Sirainenvoid master_service_set_client_limit(struct master_service *service,
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen unsigned int used;
8cdb3234fe3c77e477c7a0e6934678f58fc54d4dTimo Sirainen i_assert(service->master_status.available_count ==
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen service->total_available_count = client_limit;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainen service->master_status.available_count = client_limit - used;
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
8ab3d88c56dff2f567193f80cc29821a64e576d1Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen unsigned int count)
6adf683655750bcb809275cd65dc75fd12214198Timo Sirainen unsigned int used;
71da447014454c84828d9dface77219875554d7dTimo Sirainen service->master_status.available_count = count - used;
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen void (*callback)(void))
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenconst char *master_service_get_name(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_run(struct master_service *service,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen master_service_connection_callback_t *callback)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_stop(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* make sure we stop after servicing current connections */
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen current_count = service->total_available_count -
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen service->total_available_count = current_count;
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen /* notify master that we're not accepting any more
d691782ae9eb4f6ab06bc42f1617e889e7c18a3bTimo Sirainen connections */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenbool master_service_is_killed(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* anvil process was probably recreated, don't bother
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen logging an error about losing connection to it */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen } else if (ret == 0)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen /* we can listen again */
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->service_count_left == service->total_available_count) {
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->service_count_left != (unsigned int)-1)
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen i_assert(service->master_status.available_count <
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen i_assert(service->master_status.available_count ==
981139bb2e446bb2050c1158614725f8413fd709Timo Sirainen } else if ((service->io_status_error == NULL ||
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?) */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen if (service->master_status.available_count > 0)
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. */
f28583935a4509d3f7932738bba6c548ef455c82Timo Sirainen /* make sure we're listening for more connections */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_error("Invalid master login state: %d", state);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_close_config_fd(struct master_service *service)
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainen i_error("close(master config fd) failed: %m");
e3678f7bfba87b5aa1446a1a7b9928272b4f72a3Timo Sirainenvoid master_service_deinit(struct master_service **_service)
0c1835a90dd1dcedaeaedd1cd91672299cbeb5beTimo Sirainen if (array_is_created(&service->config_overrides))
f4735bf7ec2019fdc730e9ebdb39e5a4ea580405Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
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->master_status.available_count == 0) {
return TRUE;
return TRUE;
return FALSE;
bool important_update;
!important_update) {
service);
} else if (ret >= 0) {
} else if (important_update) {
unsigned major_version)
bool ret;
return FALSE;
return FALSE;
T_BEGIN {
} T_END;
return ret;