From: Timo Sirainen Date: Wed, 4 Jan 2023 21:49:58 +0000 (+0200) Subject: lib-master: Add master_service_settings_get[_or_fatal]() and master_service_settings_... X-Git-Tag: 2.4.0~2344 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b406419c413bc95ef51b1ce9d4cbe3022bb86656;p=thirdparty%2Fdovecot%2Fcore.git lib-master: Add master_service_settings_get[_or_fatal]() and master_service_settings_parser_get() These will become the only way to access settings read by lib-master. --- diff --git a/src/lib-master/master-service-settings.c b/src/lib-master/master-service-settings.c index 7791155c3b..b23033bf4a 100644 --- a/src/lib-master/master-service-settings.c +++ b/src/lib-master/master-service-settings.c @@ -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) { diff --git a/src/lib-master/master-service-settings.h b/src/lib-master/master-service-settings.h index fc950e1f49..618ddf9a90 100644 --- a/src/lib-master/master-service-settings.h +++ b/src/lib-master/master-service-settings.h @@ -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, diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h index 289ece2f89..c1b1f2d7a1 100644 --- a/src/lib-settings/settings-parser.h +++ b/src/lib-settings/settings-parser.h @@ -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;