]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-program-client: Add program_client_create_auto()
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 12 Aug 2024 11:53:58 +0000 (14:53 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Jan 2025 08:39:59 +0000 (10:39 +0200)
src/lib-program-client/Makefile.am
src/lib-program-client/program-client.c
src/lib-program-client/program-client.h

index 4198606d67d5b77ef571c31e45ffa108ea5d301a..cf0cb44e1b1ceb2c54ff7b2d340cb02ab678b7ba 100644 (file)
@@ -4,7 +4,9 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-test \
        -I$(top_srcdir)/src/lib-dns \
-       -I$(top_srcdir)/src/lib-mail
+       -I$(top_srcdir)/src/lib-mail \
+       -I$(top_srcdir)/src/lib-settings \
+       -DPKG_RUNDIR=\""$(rundir)"\"
 
 libprogram_client_la_SOURCES = \
        program-client.c \
@@ -32,6 +34,7 @@ test_libs = \
        ../lib-dns/libdns.la  \
        ../lib-test/libtest.la \
        ../lib-mail/libmail.la \
+       ../lib-settings/libsettings.la  \
        ../lib-charset/libcharset.la \
        ../lib/liblib.la \
        $(MODULE_LIBS)
index 4c2ac82b1fd29dfa52dcef6fb38d81f3dc7793fa..8299338b7d278bc8ca1530b46237a7ce5bda2881 100644 (file)
@@ -13,6 +13,8 @@
 #include "iostream-pump.h"
 #include "iostream-temp.h"
 #include "lib-signals.h"
+#include "settings.h"
+#include "settings-parser.h"
 
 #include "program-client-private.h"
 
 #define MAX_OUTPUT_BUFFER_SIZE 16384
 #define MAX_OUTPUT_MEMORY_BUFFER (1024*128)
 
+static bool program_client_settings_check(void *_set, pool_t pool,
+                                         const char **error_r);
+
+#undef DEF
+#define DEF(type, name) \
+       SETTING_DEFINE_STRUCT_##type(#name, name, struct program_client_settings)
+static const struct setting_define program_client_setting_defines[] = {
+       { .type = SET_FILTER_ARRAY, .key = "execute",
+         .offset = offsetof(struct program_client_settings, execute),
+         .filter_array_field_name = "execute_name", },
+       DEF(STR, execute_name),
+       DEF(ENUM, execute_driver),
+       DEF(STR, execute_args),
+
+       DEF(STR, execute_local_path),
+       DEF(STR, execute_unix_socket_path),
+       DEF(STR, execute_tcp_host),
+       DEF(IN_PORT, execute_tcp_port),
+
+       SETTING_DEFINE_STRUCT_STR_HIDDEN("base_dir", base_dir,
+                                        struct program_client_settings),
+
+       SETTING_DEFINE_LIST_END
+};
+
+static const struct program_client_settings program_client_default_settings = {
+       .execute = ARRAY_INIT,
+       .execute_name = "",
+       .execute_driver = "unix:local:tcp",
+       .execute_args = "",
+
+       .execute_local_path = "",
+       .execute_unix_socket_path = "",
+       .execute_tcp_host = "",
+       .execute_tcp_port = 0,
+
+       .base_dir = PKG_RUNDIR,
+};
+const struct setting_parser_info program_client_setting_parser_info = {
+       .name = "execute",
+
+       .defines = program_client_setting_defines,
+       .defaults = &program_client_default_settings,
+
+       .struct_size = sizeof(struct program_client_settings),
+       .pool_offset1 = 1 + offsetof(struct program_client_settings, pool),
+
+       .check_func = program_client_settings_check,
+};
+
 void program_client_set_label(struct program_client *pclient,
                              const char *label)
 {
@@ -694,6 +746,118 @@ int program_client_create(struct event *event, const char *uri,
        }
 }
 
+static bool
+program_client_settings_check(void *_set, pool_t pool, const char **error_r)
+{
+       struct program_client_settings *set = _set;
+
+       if (strcmp(set->execute_driver, "unix") == 0) {
+               if (set->execute_unix_socket_path[0] == '\0')
+                       set->execute_unix_socket_path = set->execute_name;
+               if (set->execute_unix_socket_path[0] != '/') {
+                       set->execute_unix_socket_path = p_strconcat(pool,
+                               set->base_dir, "/",
+                               set->execute_unix_socket_path, NULL);
+               }
+       } else if (strcmp(set->execute_driver, "local") == 0) {
+               if (set->execute_local_path[0] == '\0')
+                       set->execute_local_path = set->execute_name;
+       } else if (strcmp(set->execute_driver, "tcp") == 0) {
+               if (set->execute_tcp_host[0] == '\0' &&
+                   set->execute_name[0] != '\0') {
+                       const char *host;
+                       if (net_str2hostport(set->execute_name, 0, &host,
+                                            &set->execute_tcp_port) < 0) {
+                               *error_r = t_strdup_printf(
+                                       "Failed to parse execute_tcp_host:port from execute_name=%s",
+                                       set->execute_name);
+                               return FALSE;
+                       }
+                       set->execute_tcp_host = p_strdup(pool, host);
+               }
+               if (set->execute_tcp_port == 0) {
+                       *error_r = "execute_tcp_port must not be 0 with execute_driver=tcp";
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+static int
+program_client_create_filter_auto(struct event *event, const char *execute_name,
+                                 const struct program_client_parameters *params,
+                                 struct program_client **pc_r, const char **error_r)
+{
+       const struct program_client_settings *set;
+
+       /* Get settings for the first execute list filter */
+       event = event_create(event);
+       event_add_str(event, "execute", execute_name);
+       if (settings_get(event, &program_client_setting_parser_info, 0,
+                        &set, error_r) < 0) {
+               event_unref(&event);
+               return -1;
+       }
+
+       const char *const *args = t_strsplit_spaces(set->execute_args, " ");
+       if (strcmp(set->execute_driver, "unix") == 0) {
+               *pc_r = program_client_unix_create(event,
+                               set->execute_unix_socket_path, args, params);
+       } else if (strcmp(set->execute_driver, "local") == 0) {
+               *pc_r = program_client_local_create(event,
+                               set->execute_local_path, args, params);
+       } else if (strcmp(set->execute_driver, "tcp") == 0) {
+               *pc_r = program_client_net_create(event, set->execute_tcp_host,
+                                                 set->execute_tcp_port,
+                                                 args, params);
+       } else {
+               /* should have been caught by settings enum checking already */
+               i_unreached();
+       }
+
+       event_unref(&event);
+       settings_free(set);
+       return 0;
+}
+
+int program_client_create_auto(struct event *event,
+                              const struct program_client_parameters *params,
+                              struct program_client **pc_r, const char **error_r)
+{
+       struct program_client_settings *set;
+
+       i_assert(event != NULL);
+
+       if (settings_get(event, &program_client_setting_parser_info, 0,
+                        &set, error_r) < 0)
+               return -1;
+       if (array_is_empty(&set->execute)) {
+               *error_r = "execute { .. } named list filter is missing";
+               settings_free(set);
+               return 0;
+       }
+       const char *execute_name_first =
+               t_strdup(array_idx_elem(&set->execute, 0));
+       if (array_count(&set->execute) > 1) {
+               /* Only one execution supported for now. */
+               const char *execute_name_extra =
+                       array_idx_elem(&set->execute, 1);
+               *error_r = t_strdup_printf(
+                               "Extra execute %s { .. } named list filter - "
+                               "only one execution is allowed for now "
+                               "(previous: execute %s { .. })",
+                               execute_name_extra, execute_name_first);
+               settings_free(set);
+               return -1;
+       }
+       settings_free(set);
+
+       if (program_client_create_filter_auto(event, execute_name_first,
+                                             params, pc_r, error_r) < 0)
+               return -1;
+       return 1;
+}
+
 static void
 program_client_run_callback(int result, int *context)
 {
index e5083ff5c84bf7641574fad4eee6d907795d79ea..f81a5aa3284f0f48b8136a4cd213f63f1030e61b 100644 (file)
@@ -26,6 +26,24 @@ struct program_client_parameters {
        bool no_reply:1;
 };
 
+struct program_client_settings {
+       pool_t pool;
+       /* Currently only a single execution is allowed */
+       ARRAY_TYPE(const_string) execute;
+       const char *execute_name;
+       const char *execute_driver;
+       const char *execute_args;
+
+       /* driver-specific: */
+       const char *execute_local_path;
+       const char *execute_unix_socket_path;
+       const char *execute_tcp_host;
+       in_port_t execute_tcp_port;
+
+       const char *base_dir;
+};
+extern const struct setting_parser_info program_client_setting_parser_info;
+
 typedef void program_client_fd_callback_t(void *context, struct istream *input);
 typedef void program_client_callback_t(enum program_client_exit_status status,
                                       void *context);
@@ -53,6 +71,9 @@ int program_client_create(struct event *event, const char *uri,
                          const char *const *args,
                          const struct program_client_parameters *params,
                          struct program_client **pc_r, const char **error_r);
+int program_client_create_auto(struct event *event,
+                              const struct program_client_parameters *params,
+                              struct program_client **pc_r, const char **error_r);
 
 void program_client_destroy(struct program_client **_pclient);