int main(int argc, char *argv[]) { const char *path, *error; master_service = master_service_init("config", 0, &argc, &argv, NULL); if (master_getopt(master_service) > 0) return FATAL_DEFAULT; master_service_init_log(master_service, "config: "); restrict_access_by_env(NULL, FALSE); restrict_access_allow_coredumps(TRUE); master_service_init_finish(master_service); config_parse_load_modules(); path = master_service_get_config_path(master_service); if (config_parse_file(path, TRUE, "", &error) <= 0) i_fatal("%s", error); master_service_run(master_service, client_connected); config_connections_destroy_all(); config_filter_deinit(&config_filter); module_dir_unload(&modules); master_service_deinit(&master_service); return 0; }
int main(int argc, char *argv[]) { const char *path, *error; master_service = master_service_init("config", 0, &argc, &argv, ""); if (master_getopt(master_service) > 0) return FATAL_DEFAULT; master_service_init_log(master_service, "config: "); restrict_access_by_env(NULL, FALSE); restrict_access_allow_coredumps(TRUE); config_parse_load_modules(); path = master_service_get_config_path(master_service); if (config_parse_file(path, TRUE, NULL, &error) <= 0) i_fatal("%s", error); /* notify about our success only after successfully parsing the config file, so if the parsing fails, master won't immediately just recreate this process (and fail again and so on). */ master_service_init_finish(master_service); master_service_run(master_service, client_connected); config_connections_destroy_all(); config_filter_deinit(&config_filter); module_dir_unload(&modules); master_service_deinit(&master_service); return 0; }
static int master_service_open_config(struct master_service *service, const struct master_service_settings_input *input, const char **path_r, const char **error_r) { struct stat st; const char *path; int fd; *path_r = path = input->config_path != NULL ? input->config_path : master_service_get_config_path(service); if (service->config_fd != -1 && input->config_path == NULL && !service->config_path_changed_with_param) { /* use the already opened config socket */ fd = service->config_fd; service->config_fd = -1; return fd; } if (!service->config_path_from_master && !service->config_path_changed_with_param && input->config_path == NULL) { /* first try to connect to the default config socket. configuration may contain secrets, so in default config this fails because the socket is 0600. it's useful for developers though. :) */ fd = net_connect_unix(DOVECOT_CONFIG_SOCKET_PATH); if (fd >= 0) { *path_r = DOVECOT_CONFIG_SOCKET_PATH; net_set_nonblock(fd, FALSE); return fd; } /* fallback to executing doveconf */ } if (stat(path, &st) < 0) { *error_r = errno == EACCES ? eacces_error_get("stat", path) : t_strdup_printf("stat(%s) failed: %m", path); return -1; } if (!S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) { /* it's not an UNIX socket, don't even try to connect */ fd = -1; errno = ENOTSOCK; } else { fd = net_connect_unix_with_retries(path, 1000); } if (fd < 0) { *error_r = t_strdup_printf("net_connect_unix(%s) failed: %m", path); config_exec_fallback(service, input); return -1; } net_set_nonblock(fd, FALSE); return fd; }
static void config_exec_fallback(struct master_service *service, const struct master_service_settings_input *input) { const char *path; struct stat st; int saved_errno = errno; if (input->never_exec) return; path = input->config_path != NULL ? input->config_path : master_service_get_config_path(service); if (stat(path, &st) == 0 && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode)) { /* it's a file, not a socket/pipe */ master_service_exec_config(service, input); } errno = saved_errno; }
static int config_connection_request(struct config_connection *conn, const char *const *args) { struct config_export_context *ctx; struct master_service_settings_output output; struct config_filter filter; const char *path, *error, *module = ""; /* [<args>] */ memset(&filter, 0, sizeof(filter)); for (; *args != NULL; args++) { if (strncmp(*args, "service=", 8) == 0) filter.service = *args + 8; else if (strncmp(*args, "module=", 7) == 0) module = *args + 7; else if (strncmp(*args, "lname=", 6) == 0) filter.local_name = *args + 6; else if (strncmp(*args, "lip=", 4) == 0) { if (net_addr2ip(*args + 4, &filter.local_net) == 0) { filter.local_bits = IPADDR_IS_V4(&filter.local_net) ? 32 : 128; } } else if (strncmp(*args, "rip=", 4) == 0) { if (net_addr2ip(*args + 4, &filter.remote_net) == 0) { filter.remote_bits = IPADDR_IS_V4(&filter.remote_net) ? 32 : 128; } } } if (strcmp(module, "master") == 0) { /* master reads configuration only when reloading settings */ path = master_service_get_config_path(master_service); if (config_parse_file(path, TRUE, "", &error) <= 0) { o_stream_send_str(conn->output, t_strconcat("ERROR ", error, "\n", NULL)); config_connection_destroy(conn); return -1; } } o_stream_cork(conn->output); ctx = config_export_init(module, CONFIG_DUMP_SCOPE_SET, 0, config_request_output, conn->output); config_export_by_filter(ctx, &filter); config_export_get_output(ctx, &output); if (output.specific_services != NULL) { const char *const *s; for (s = output.specific_services; *s != NULL; s++) { o_stream_send_str(conn->output, t_strdup_printf("service=%s\t", *s)); } } if (output.service_uses_local) o_stream_send_str(conn->output, "service-uses-local\t"); if (output.service_uses_remote) o_stream_send_str(conn->output, "service-uses-remote\t"); if (output.used_local) o_stream_send_str(conn->output, "used-local\t"); if (output.used_remote) o_stream_send_str(conn->output, "used-remote\t"); o_stream_send_str(conn->output, "\n"); if (config_export_finish(&ctx) < 0) { config_connection_destroy(conn); return -1; } o_stream_send_str(conn->output, "\n"); o_stream_uncork(conn->output); return 0; }