From: Timo Sirainen Date: Sat, 14 Nov 2020 18:30:39 +0000 (+0200) Subject: master: Support %{pid} in unix_listener paths X-Git-Tag: 2.4.0~4556 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=56cfb459a63bfd3da0cc19e00239e3ff549869e1;p=thirdparty%2Fdovecot%2Fcore.git master: Support %{pid} in unix_listener paths This allows each process to have their own private UNIX socket listener. --- diff --git a/src/master/service-process.c b/src/master/service-process.c index 34d23ff55d..a9a9e8ee37 100644 --- a/src/master/service-process.c +++ b/src/master/service-process.c @@ -17,6 +17,7 @@ #include "restrict-access.h" #include "restrict-process-size.h" #include "eacces-error.h" +#include "var-expand.h" #include "master-service.h" #include "master-service-settings.h" #include "dup2-array.h" @@ -51,6 +52,19 @@ static void service_reopen_inet_listeners(struct service *service) } } +static int +service_unix_pid_listener_get_path(struct service_listener *l, pid_t pid, + string_t *path, const char **error_r) +{ + struct var_expand_table var_table[] = { + { '\0', dec2str(pid), "pid" }, + { '\0', NULL, NULL }, + }; + + str_truncate(path, 0); + return var_expand(path, l->set.fileset.set->path, var_table, error_r); +} + static void service_dup_fds(struct service *service) { @@ -113,6 +127,36 @@ service_dup_fds(struct service *service) socket_listener_count++; } } + if (array_is_created(&service->unix_pid_listeners)) { + struct service_listener *const *listenerp, *l; + string_t *path = t_str_new(128); + const char *error; + int ret; + pid_t pid = getpid(); + + array_foreach(&service->unix_pid_listeners, listenerp) { + l = *listenerp; + ret = service_unix_pid_listener_get_path(l, pid, path, &error); + if (ret > 0) { + ret = service_unix_listener_listen(l, + str_c(path), FALSE, &error); + } + if (ret <= 0) { + i_fatal("Failed to create per-PID unix_listener %s: %s", + l->name, error); + } + + str_truncate(listener_settings, 0); + str_append_tabescaped(listener_settings, l->name); + str_append(listener_settings, "\tpid"); + dup2_append(&dups, l->fd, fd++); + + env_put(t_strdup_printf("SOCKET%d_SETTINGS", + socket_listener_count), + str_c(listener_settings)); + socket_listener_count++; + } + } if (service->login_notify_fd != -1) { dup2_append(&dups, service->login_notify_fd, @@ -388,6 +432,19 @@ void service_process_destroy(struct service_process *process) struct service *service = process->service; struct service_list *service_list = service->list; + if (array_is_created(&service->unix_pid_listeners)) { + struct service_listener *const *listenerp; + string_t *path = t_str_new(128); + const char *error; + + array_foreach(&service->unix_pid_listeners, listenerp) { + str_truncate(path, 0); + if (service_unix_pid_listener_get_path(*listenerp, + process->pid, path, &error) > 0) + i_unlink_if_exists(str_c(path)); + } + } + DLLIST_REMOVE(&service->processes, process); hash_table_remove(service_pids, POINTER_CAST(process->pid)); diff --git a/src/master/service.c b/src/master/service.c index 74e6fa5bb7..0064c5b66a 100644 --- a/src/master/service.c +++ b/src/master/service.c @@ -319,7 +319,9 @@ service_create(pool_t pool, const struct service_settings *set, p_array_init(&service->listeners, pool, unix_count + fifo_count + inet_count); - + if (unix_count > 0) + p_array_init(&service->unix_pid_listeners, pool, 1); + for (i = 0; i < unix_count; i++) { if (unix_listeners[i]->mode == 0) { /* disabled */ @@ -330,7 +332,11 @@ service_create(pool_t pool, const struct service_settings *set, unix_listeners[i], error_r); if (l == NULL) return NULL; - array_push_back(&service->listeners, &l); + + if (strstr(unix_listeners[i]->path, "%{pid}") == NULL) + array_push_back(&service->listeners, &l); + else + array_push_back(&service->unix_pid_listeners, &l); } for (i = 0; i < fifo_count; i++) { if (fifo_listeners[i]->mode == 0) { diff --git a/src/master/service.h b/src/master/service.h index 441264185e..834324a040 100644 --- a/src/master/service.h +++ b/src/master/service.h @@ -58,6 +58,8 @@ struct service { /* all listeners, even those that aren't currently listening */ ARRAY(struct service_listener *) listeners; + /* per-process unix_listeners */ + ARRAY(struct service_listener *) unix_pid_listeners; /* linked list of all processes belonging to this service */ struct service_process *processes;