/* 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)
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;
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;
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);
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);
}
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. */
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));