]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Support %{pid} in unix_listener paths
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 14 Nov 2020 18:30:39 +0000 (20:30 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 8 Feb 2022 09:48:24 +0000 (10:48 +0100)
This allows each process to have their own private UNIX socket listener.

src/master/service-process.c
src/master/service.c
src/master/service.h

index 34d23ff55d41edb4b4ffbbb1261ed8a42fbf7da8..a9a9e8ee37feaa03b71243fc18f1205ad48baca1 100644 (file)
@@ -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));
 
index 74e6fa5bb7231513cbcfe4a556d05ff1acf26e2b..0064c5b66a4d84e0ed3ba3aad2d05e209d876caf 100644 (file)
@@ -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) {
index 441264185eef00f9407c57545563c9e63501a26b..834324a04066a4b23e71c3f8dd859be0d7309b8f 100644 (file)
@@ -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;