From: Timo Sirainen Date: Fri, 9 Dec 2022 22:13:26 +0000 (+0200) Subject: master, log: Pass config fd from master to log process X-Git-Tag: 2.4.0~3066 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1955e81a2ffe023f937d87f2b555bcec0fb4aee9;p=thirdparty%2Fdovecot%2Fcore.git master, log: Pass config fd from master to log process The log process must not depend on the config process, because they would have a circular dependency. Previously the configuration was sent to the log process via environment filled by the master process. Now that we have the full config available in a file descriptor, pass that config fd instead. --- diff --git a/src/lib-master/master-interface.h b/src/lib-master/master-interface.h index 9966bec405..0c3ab6909d 100644 --- a/src/lib-master/master-interface.h +++ b/src/lib-master/master-interface.h @@ -102,13 +102,15 @@ enum master_login_state { /* Pipe to master, used to detect when it dies. (MASTER_STATUS_FD would have been fine for this, except it's inefficient in Linux) */ #define MASTER_DEAD_FD 6 +/* Configuration file descriptor. */ +#define MASTER_CONFIG_FD 7 /* First file descriptor where process is expected to be listening. The file descriptor count is given in -s parameter, defaulting to 1. master_status.available_count reports how many accept()s we're still accepting. Once no children are listening, master will do it and create new child processes when needed. */ -#define MASTER_LISTEN_FD_FIRST 7 +#define MASTER_LISTEN_FD_FIRST 8 /* Timeouts: base everything on how long we can wait for login clients. */ #define MASTER_LOGIN_TIMEOUT_SECS (3*60) diff --git a/src/master/common.h b/src/master/common.h index f88a496910..5f644e14d1 100644 --- a/src/master/common.h +++ b/src/master/common.h @@ -16,6 +16,7 @@ extern bool have_proc_sys_kernel_core_pattern; extern const char *ssl_manual_key_password; extern int global_master_dead_pipe_fd[2]; extern struct log_error_buffer *log_error_buffer; +extern int global_config_fd; extern struct service_list *services; extern bool startup_finished; diff --git a/src/master/main.c b/src/master/main.c index afc0b000fa..37f1f9eb3f 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -62,6 +62,7 @@ bool have_proc_sys_kernel_core_pattern; const char *ssl_manual_key_password; int global_master_dead_pipe_fd[2]; struct log_error_buffer *log_error_buffer; +int global_config_fd = -1; struct service_list *services; bool startup_finished = FALSE; @@ -420,12 +421,16 @@ sig_settings_reload(const siginfo_t *si ATTR_UNUSED, input.config_path = services_get_config_socket_path(services); input.never_exec = TRUE; input.reload_config = TRUE; + input.return_config_fd = TRUE; if (master_service_settings_read(master_service, &input, &output, &error) < 0) { i_error("Error reading configuration: %s", error); i_sd_notify(0, "READY=1"); return; } + i_close_fd(&global_config_fd); + global_config_fd = output.config_fd; + fd_close_on_exec(global_config_fd, TRUE); set = master_service_settings_get_root_set(master_service, &master_setting_parser_info); @@ -500,9 +505,12 @@ static struct master_settings *master_settings_read(void) input.roots = set_roots; input.preserve_environment = TRUE; input.always_exec = TRUE; + input.return_config_fd = TRUE; if (master_service_settings_read(master_service, &input, &output, &error) < 0) i_fatal("Error reading configuration: %s", error); + global_config_fd = output.config_fd; + fd_close_on_exec(global_config_fd, TRUE); return master_service_settings_get_root_set(master_service, &master_setting_parser_info); } diff --git a/src/master/service-process.c b/src/master/service-process.c index be42627ae3..206ae65fa2 100644 --- a/src/master/service-process.c +++ b/src/master/service-process.c @@ -218,6 +218,18 @@ service_dup_fds(struct service *service) i_set_failure_internal(); } + if (service->type == SERVICE_TYPE_LOG) { + /* Pass our config fd to the log process, so it won't depend + on config process. Note that we don't want to do this for + other processes, since it prevents config reload. */ + i_assert(global_config_fd != -1); + fd_close_on_exec(global_config_fd, FALSE); + if (lseek(global_config_fd, 0, SEEK_SET) < 0) + i_fatal("lseek(config fd, 0) failed: %m"); + dup2_append(&dups, global_config_fd, MASTER_CONFIG_FD); + env_put(DOVECOT_CONFIG_FD_ENV, dec2str(MASTER_CONFIG_FD)); + } + /* Switch log writing back to stderr before the log fds are closed. There's no guarantee that writing to stderr is visible anywhere, but it's better than the process just dying with FATAL_LOGWRITE. */ @@ -270,26 +282,10 @@ drop_privileges(struct service *service) static void service_process_setup_config_environment(struct service *service) { - const struct master_service_settings *set = service->list->service_set; - switch (service->type) { case SERVICE_TYPE_CONFIG: env_put(MASTER_CONFIG_FILE_ENV, service->config_file_path); break; - case SERVICE_TYPE_LOG: - /* give the log's configuration directly, so it won't depend - on config process */ - env_put("DOVECONF_ENV", "1"); - env_put("LOG_PATH", set->log_path); - env_put("INFO_LOG_PATH", set->info_log_path); - env_put("DEBUG_LOG_PATH", set->debug_log_path); - env_put("LOG_TIMESTAMP", set->log_timestamp); - env_put("SYSLOG_FACILITY", set->syslog_facility); - env_put("INSTANCE_NAME", set->instance_name); - if (set->verbose_proctitle) - env_put("VERBOSE_PROCTITLE", "1"); - env_put("SSL", "no"); - break; default: env_put(MASTER_CONFIG_FILE_ENV, services_get_config_socket_path(service->list));