]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-master: Add master_service_settings_get[_or_fatal]() and master_service_settings_...
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 4 Jan 2023 21:49:58 +0000 (23:49 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 20 Nov 2023 12:11:40 +0000 (14:11 +0200)
These will become the only way to access settings read by lib-master.

src/lib-master/master-service-settings.c
src/lib-master/master-service-settings.h
src/lib-settings/settings-parser.h

index 7791155c3b0724980b44c2d2f093e5e199d7d07b..b23033bf4a44dad9586d3eb9e53a1f580d59889d 100644 (file)
@@ -12,6 +12,7 @@
 #include "eacces-error.h"
 #include "env-util.h"
 #include "execv-const.h"
+#include "var-expand.h"
 #include "settings-parser.h"
 #include "stats-client.h"
 #include "master-service-private.h"
@@ -867,6 +868,108 @@ static pool_t master_settings_pool_create(struct master_settings_mmap *mmap)
        return &mpool->pool;
 }
 
+static void
+master_service_var_expand_init(struct event *event,
+                              const struct var_expand_table **tab_r,
+                              const struct var_expand_func_table **func_tab_r,
+                              void **func_context_r)
+{
+       *tab_r = NULL;
+       *func_tab_r = NULL;
+
+       while (event != NULL) {
+               master_service_settings_var_expand_t *callback =
+                       event_get_ptr(event, MASTER_SERVICE_VAR_EXPAND_CALLBACK);
+               if (callback != NULL) {
+                       callback(event, tab_r, func_tab_r);
+                       break;
+               }
+
+               *tab_r = event_get_ptr(event, MASTER_SERVICE_VAR_EXPAND_TABLE);
+               *func_tab_r = event_get_ptr(event, MASTER_SERVICE_VAR_EXPAND_FUNC_TABLE);
+               if (*tab_r != NULL || *func_tab_r != NULL)
+                       break;
+               event = event_get_parent(event);
+       }
+       if (*tab_r == NULL)
+               *tab_r = t_new(struct var_expand_table, 1);
+       *func_context_r = event == NULL ? NULL :
+               event_get_ptr(event, MASTER_SERVICE_VAR_EXPAND_FUNC_CONTEXT);
+}
+
+#undef master_service_settings_parser_get
+int master_service_settings_parser_get(struct event *event,
+                                      struct setting_parser_context *set_parser,
+                                      const struct setting_parser_info *info,
+                                      enum master_service_settings_get_flags flags,
+                                      const void **set_r, const char **error_r)
+{
+       int ret;
+
+       i_assert(info->pool_offset1 != 0);
+
+       pool_t set_pool = pool_alloconly_create("master service settings parser", 1024);
+       void *set = settings_parser_get_root_set(set_parser, info);
+       set = settings_dup_with_pointers(info, set, set_pool);
+
+       pool_t *pool_p = PTR_OFFSET(set, info->pool_offset1 - 1);
+       *pool_p = set_pool;
+       pool_ref(*pool_p);
+
+       if ((flags & MASTER_SERVICE_SETTINGS_GET_FLAG_NO_CHECK) == 0) {
+               if (!settings_check(info, *pool_p, set, error_r)) {
+                       *error_r = t_strdup_printf("Invalid %s settings: %s",
+                                                  info->module_name, *error_r);
+                       return -1;
+               }
+       }
+
+       if ((flags & MASTER_SERVICE_SETTINGS_GET_FLAG_NO_EXPAND) != 0)
+               ret = 1;
+       else T_BEGIN {
+               const struct var_expand_table *tab;
+               const struct var_expand_func_table *func_tab;
+               void *func_context;
+
+               master_service_var_expand_init(event, &tab, &func_tab,
+                                              &func_context);
+               ret = settings_var_expand_with_funcs(info, set, *pool_p, tab,
+                                                    func_tab, func_context,
+                                                    error_r);
+       } T_END_PASS_STR_IF(ret <= 0, error_r);
+       if (ret <= 0) {
+               *error_r = t_strdup_printf(
+                       "Failed to expand %s setting variables: %s",
+                       info->module_name, *error_r);
+               return -1;
+       }
+
+       *set_r = set;
+       return 0;
+}
+
+#undef master_service_settings_get
+int master_service_settings_get(struct event *event,
+                               const struct setting_parser_info *info,
+                               enum master_service_settings_get_flags flags,
+                               const void **set_r, const char **error_r)
+{
+       return master_service_settings_parser_get(event,
+               master_service->set_parser, info, flags, set_r, error_r);
+}
+
+const void *
+master_service_settings_get_or_fatal(struct event *event,
+                                    const struct setting_parser_info *info)
+{
+       const void *set;
+       const char *error;
+
+       if (master_service_settings_get(event, info, 0, &set, &error) < 0)
+               i_fatal("%s", error);
+       return set;
+}
+
 void *master_service_settings_get_root_set(struct master_service *service,
                                           const struct setting_parser_info *root)
 {
index fc950e1f49e5de976daa4ef29e36816f1d62f7b0..618ddf9a908fe4f242d5b1107f37f9fbc7f85591 100644 (file)
@@ -3,11 +3,20 @@
 
 #include "net.h"
 
+struct var_expand_table;
+struct var_expand_func_table;
 struct setting_parser_info;
 struct setting_parser_context;
 struct master_service;
 struct master_settings_mmap;
 
+enum master_service_settings_get_flags {
+       /* Don't call check_func()s */
+       MASTER_SERVICE_SETTINGS_GET_FLAG_NO_CHECK = BIT(0),
+       /* Don't expand %variables in settings */
+       MASTER_SERVICE_SETTINGS_GET_FLAG_NO_EXPAND = BIT(1),
+};
+
 struct master_service_settings {
        const char *base_dir;
        const char *state_dir;
@@ -63,6 +72,49 @@ struct master_service_settings_output {
        bool permission_denied:1;
 };
 
+/* Set struct var_expand_table to be used for settings expansion. The table is
+   expected to be accessible until the event is freed or the table is cleared
+   from the event. Usage:
+
+   event_set_ptr(event, MASTER_SERVICE_VAR_EXPAND_TABLE, var_expand_table);
+*/
+#define MASTER_SERVICE_VAR_EXPAND_TABLE \
+       "master_service_var_expand_table"
+/* Set struct var_expand_func_table and its function context pointer to be used
+   for settings expansion. The table is expected to be accessible until the
+   event is freed or the table is cleared from the event. Usage:
+
+   event_set_ptr(event, MASTER_SERVICE_VAR_EXPAND_FUNC_TABLE, func_table);
+   event_set_ptr(event, MASTER_SERVICE_VAR_EXPAND_FUNC_CONTEXT, func_context);
+
+   You can set either or both of MASTER_SERVICE_VAR_EXPAND_TABLE and
+   MASTER_SERVICE_VAR_EXPAND_FUNC_TABLE for the same event. The parent events
+   won't be searched for either of them if either one is set.
+*/
+#define MASTER_SERVICE_VAR_EXPAND_FUNC_TABLE \
+       "master_service_var_expand_func_table"
+#define MASTER_SERVICE_VAR_EXPAND_FUNC_CONTEXT \
+       "master_service_var_expand_func_context"
+
+/* Set a master_service_settings_var_expand_t callback that returns
+   var_expand_[func_]table for settings expansion. This can be used instead of
+   MASTER_SERVICE_VAR_EXPAND_[FUNC_]TABLE to dynamically generate the table
+   on-demand. If this is found from the event, all other MASTER_SERVICE_VAR_*
+   fields are ignored in this and the parent events. Usage:
+
+   event_set_ptr(event, MASTER_SERVICE_VAR_EXPAND_CALLBACK, callback);
+   event_set_ptr(event, MASTER_SERVICE_VAR_EXPAND_FUNC_CONTEXT, func_context);
+*/
+#define MASTER_SERVICE_VAR_EXPAND_CALLBACK \
+       "master_service_var_expand_callback"
+/* Callback function used with MASTER_SERVICE_VAR_EXPAND_CALLBACK. The function
+   can return either or both of tab_r and func_tab_r, using NULL for the field
+   that isn't needed. */
+typedef void
+master_service_settings_var_expand_t(struct event *event,
+                                    const struct var_expand_table **tab_r,
+                                    const struct var_expand_func_table **func_tab_r);
+
 extern const struct setting_parser_info master_service_setting_parser_info;
 
 void master_settings_mmap_ref(struct master_settings_mmap *mmap);
@@ -82,6 +134,65 @@ pool_t master_service_settings_detach(struct master_service *service);
 
 const struct master_service_settings *
 master_service_get_service_settings(struct master_service *service);
+
+/* Get the wanted settings and check that the settings are valid.
+   The settings struct must have pool_t (info->pool_offset1), which the caller
+   must unreference when done with the settings. master_service_settings_free()
+   macro can be used to do the freeing in a nice way.
+
+   Settings have their %variables expanded, unless
+   MASTER_SERVICE_SETTINGS_GET_FLAG_NO_EXPAND is used. The event and its
+   parents are scanned for MASTER_SERVICE_VAR_EXPAND_* pointers. The first
+   callback or tables that are found in the event hierarchy are used for the
+   expansion. See MASTER_SERVICE_VAR_EXPAND_* macros for more details. */
+int master_service_settings_get(struct event *event,
+                               const struct setting_parser_info *info,
+                               enum master_service_settings_get_flags flags,
+                               const void **set_r, const char **error_r);
+#ifdef HAVE_TYPE_CHECKS
+#  define master_service_settings_get(event, info, flags, set_r, error_r) \
+       master_service_settings_get(event, info, flags, (void *)set_r, 1 ? (error_r) : \
+       COMPILE_ERROR_IF_TRUE( \
+               !__builtin_types_compatible_p(typeof((*set_r)->pool), pool_t)))
+#else
+#  define master_service_settings_get(event, info, flags, set_r, error_r) \
+       master_service_settings_get(event, info, flags, (void *)set_r, error_r)
+#endif
+
+/* Like master_service_settings_get(), but get settings from the specified
+   parser. */
+int master_service_settings_parser_get(struct event *event,
+                                      struct setting_parser_context *set_parser,
+                                      const struct setting_parser_info *info,
+                                      enum master_service_settings_get_flags flags,
+                                      const void **set_r, const char **error_r);
+#ifdef HAVE_TYPE_CHECKS
+#  define master_service_settings_parser_get(event, set_parser, \
+               info, flags, set_r, error_r) \
+       master_service_settings_parser_get(event, set_parser, \
+               info, flags, (void *)set_r, 1 ? (error_r) : \
+       COMPILE_ERROR_IF_TRUE( \
+               !__builtin_types_compatible_p(typeof((*set_r)->pool), pool_t)))
+#else
+#  define master_service_settings_parser_get(event, set_parser, \
+               info, flags, set_r, error_r) \
+       master_service_settings_parser_get(event, set_parser, \
+               info, flags, (void *)set_r, error_r)
+#endif
+
+/* Like master_service_settings_get(), but i_fatal() if there are any errors
+   in settings. */
+const void *
+master_service_settings_get_or_fatal(struct event *event,
+                                    const struct setting_parser_info *info);
+#define master_service_settings_free(set) \
+       STMT_START { \
+               if ((set) != NULL) { \
+                       pool_t pool_copy = set->pool; \
+                       pool_unref(&pool_copy); \
+                       (set) = NULL; \
+               } \
+       } STMT_END
 void *master_service_settings_get_root_set(struct master_service *service,
                                           const struct setting_parser_info *root);
 void *master_service_settings_get_root_set_dup(struct master_service *service,
index 289ece2f896209e6b8a48d398eeafc98cf424828..c1b1f2d7a1bdc59faeae5b39cbbad0b0dff4e144 100644 (file)
@@ -108,6 +108,8 @@ struct setting_parser_info {
        size_t parent_offset1; /* parent_offset+1. 0=nonexistent. */
        const struct setting_parser_info *parent;
 
+       size_t pool_offset1; /* pool_offset+1. 0=nonexistent. */
+
        bool (*check_func)(void *set, pool_t pool, const char **error_r);
        bool (*expand_check_func)(void *set, pool_t pool, const char **error_r);
        const struct setting_parser_info *const *dependencies;