diff --git a/src/sysupdate/meson.build b/src/sysupdate/meson.build index b6f9436606..ec87326904 100644 --- a/src/sysupdate/meson.build +++ b/src/sysupdate/meson.build @@ -3,6 +3,7 @@ systemd_sysupdate_sources = files( 'sysupdate-cache.c', 'sysupdate-cleanup.c', + 'sysupdate-config.c', 'sysupdate-feature.c', 'sysupdate-instance.c', 'sysupdate-partition.c', diff --git a/src/sysupdate/sysupdate-config.c b/src/sysupdate/sysupdate-config.c new file mode 100644 index 0000000000..7f553a95f0 --- /dev/null +++ b/src/sysupdate/sysupdate-config.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "log.h" +#include "specifier.h" +#include "string-util.h" +#include "strv.h" +#include "sysupdate-config.h" +#include "web-util.h" + +int config_parse_url_specifiers( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *root = userdata; + char **s = ASSERT_PTR(data); + int r; + + assert(rvalue); + + if (isempty(rvalue)) { + *s = mfree(*s); + return 0; + } + + _cleanup_free_ char *resolved = NULL; + r = specifier_printf(rvalue, NAME_MAX, system_and_tmp_specifier_table, root, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to expand specifiers in %s=, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (!http_url_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "%s= URL is not valid, ignoring: %s", lvalue, rvalue); + return 0; + } + + return free_and_replace(*s, resolved); +} + +int config_parse_url_specifiers_many( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *root = userdata; + char ***s = ASSERT_PTR(data); + int r; + + assert(rvalue); + + if (isempty(rvalue)) { + *s = strv_free(*s); + return 0; + } + + _cleanup_free_ char *resolved = NULL; + r = specifier_printf(rvalue, NAME_MAX, system_and_tmp_specifier_table, root, NULL, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to expand specifiers in %s=, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (!http_url_is_valid(resolved)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "%s= URL is not valid, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (strv_consume(s, TAKE_PTR(resolved)) < 0) + return log_oom(); + + return 0; +} diff --git a/src/sysupdate/sysupdate-config.h b/src/sysupdate/sysupdate-config.h new file mode 100644 index 0000000000..bd972d598d --- /dev/null +++ b/src/sysupdate/sysupdate-config.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "conf-parser-forward.h" + +CONFIG_PARSER_PROTOTYPE(config_parse_url_specifiers); +CONFIG_PARSER_PROTOTYPE(config_parse_url_specifiers_many); diff --git a/src/sysupdate/sysupdate-feature.c b/src/sysupdate/sysupdate-feature.c index 0c9bb112fe..49c2e77988 100644 --- a/src/sysupdate/sysupdate-feature.c +++ b/src/sysupdate/sysupdate-feature.c @@ -5,9 +5,8 @@ #include "hash-funcs.h" #include "path-util.h" #include "string-util.h" -#include "sysupdate.h" +#include "sysupdate-config.h" #include "sysupdate-feature.h" -#include "web-util.h" static Feature *feature_free(Feature *f) { if (!f) @@ -42,45 +41,6 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(feature_hash_ops, char, string_hash_func, string_compare_func, Feature, feature_unref); -static int config_parse_url_specifiers( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - char **s = ASSERT_PTR(data); - const char *root = ASSERT_PTR(userdata); - _cleanup_free_ char *resolved = NULL; - int r; - - assert(rvalue); - - if (isempty(rvalue)) { - *s = mfree(*s); - return 0; - } - - r = specifier_printf(rvalue, NAME_MAX, specifier_table, root, NULL, &resolved); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to expand specifiers in %s=, ignoring: %s", lvalue, rvalue); - return 0; - } - - if (!http_url_is_valid(resolved)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s= URL is not valid, ignoring: %s", lvalue, rvalue); - return 0; - } - - return free_and_replace(*s, resolved); -} - int feature_read_definition(Feature *f, const char *root, const char *path, const char *const *dirs) { assert(f); diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index c79743cad6..2a29448836 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -36,6 +36,7 @@ #include "sync-util.h" #include "sysupdate.h" #include "sysupdate-cleanup.h" +#include "sysupdate-config.h" #include "sysupdate-feature.h" #include "sysupdate-instance.h" #include "sysupdate-pattern.h" @@ -127,7 +128,7 @@ static int config_parse_protect_version( assert(rvalue); - r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved); + r = specifier_printf(rvalue, NAME_MAX, system_and_tmp_specifier_table, t->context->root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in ProtectVersion=, ignoring: %s", rvalue); @@ -166,7 +167,7 @@ static int config_parse_min_version( assert(rvalue); - r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved); + r = specifier_printf(rvalue, NAME_MAX, system_and_tmp_specifier_table, t->context->root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in MinVersion=, ignoring: %s", rvalue); @@ -182,7 +183,7 @@ static int config_parse_min_version( return free_and_replace(*version, resolved); } -static int config_parse_url_specifiers( +static int config_parse_transfer_url_specifiers_many( const char *unit, const char *filename, unsigned line, @@ -193,36 +194,13 @@ static int config_parse_url_specifiers( const char *rvalue, void *data, void *userdata) { - char ***s = ASSERT_PTR(data); + Transfer *t = ASSERT_PTR(userdata); - _cleanup_free_ char *resolved = NULL; - int r; - assert(rvalue); + /* Here we expect userdata to point to our Transfer object, but config_parse_url_specifiers() wants + * the root dir there, hence fix this up */ - if (isempty(rvalue)) { - *s = strv_free(*s); - return 0; - } - - r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to expand specifiers in %s=, ignoring: %s", lvalue, rvalue); - return 0; - } - - if (!http_url_is_valid(resolved)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s= URL is not valid, ignoring: %s", lvalue, rvalue); - return 0; - } - - r = strv_push(s, TAKE_PTR(resolved)); - if (r < 0) - return log_oom(); - - return 0; + return config_parse_url_specifiers_many(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, t->context->root); } static int config_parse_current_symlink( @@ -244,7 +222,7 @@ static int config_parse_current_symlink( assert(rvalue); - r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved); + r = specifier_printf(rvalue, NAME_MAX, system_and_tmp_specifier_table, t->context->root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in CurrentSymlink=, ignoring: %s", rvalue); @@ -333,7 +311,7 @@ static int config_parse_resource_pattern( if (r == 0) break; - r = specifier_printf(word, NAME_MAX, specifier_table, t->context->root, NULL, &resolved); + r = specifier_printf(word, NAME_MAX, system_and_tmp_specifier_table, t->context->root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in MatchPattern=, ignoring: %s", rvalue); @@ -377,7 +355,7 @@ static int config_parse_resource_path( return 0; } - r = specifier_printf(rvalue, PATH_MAX-1, specifier_table, t->context->root, NULL, &resolved); + r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, t->context->root, NULL, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to expand specifiers in Path=, ignoring: %s", rvalue); @@ -510,33 +488,33 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H assert(t); ConfigTableItem table[] = { - { "Transfer", "MinVersion", config_parse_min_version, 0, &t->min_version }, - { "Transfer", "ProtectVersion", config_parse_protect_version, 0, &t->protected_versions }, - { "Transfer", "Verify", config_parse_bool, 0, &t->verify }, - { "Transfer", "ChangeLog", config_parse_url_specifiers, 0, &t->changelog }, - { "Transfer", "AppStream", config_parse_url_specifiers, 0, &t->appstream }, - { "Transfer", "Features", config_parse_strv, 0, &t->features }, - { "Transfer", "RequisiteFeatures", config_parse_strv, 0, &t->requisite_features }, - { "Source", "Type", config_parse_resource_type, 0, &t->source.type }, - { "Source", "Path", config_parse_resource_path, 0, &t->source }, - { "Source", "PathRelativeTo", config_parse_resource_path_relto, 0, &t->source.path_relative_to }, - { "Source", "MatchPattern", config_parse_resource_pattern, 0, &t->source.patterns }, - { "Target", "Type", config_parse_resource_type, 0, &t->target.type }, - { "Target", "Path", config_parse_resource_path, 0, &t->target }, - { "Target", "PathRelativeTo", config_parse_resource_path_relto, 0, &t->target.path_relative_to }, - { "Target", "MatchPattern", config_parse_resource_pattern, 0, &t->target.patterns }, - { "Target", "MatchPartitionType", config_parse_resource_ptype, 0, &t->target }, - { "Target", "PartitionUUID", config_parse_partition_uuid, 0, t }, - { "Target", "PartitionFlags", config_parse_partition_flags, 0, t }, - { "Target", "PartitionNoAuto", config_parse_tristate, 0, &t->no_auto }, - { "Target", "PartitionGrowFileSystem", config_parse_tristate, 0, &t->growfs }, - { "Target", "ReadOnly", config_parse_tristate, 0, &t->read_only }, - { "Target", "Mode", config_parse_mode, 0, &t->mode }, - { "Target", "TriesLeft", config_parse_uint64, 0, &t->tries_left }, - { "Target", "TriesDone", config_parse_uint64, 0, &t->tries_done }, - { "Target", "InstancesMax", config_parse_instances_max, 0, &t->instances_max }, - { "Target", "RemoveTemporary", config_parse_bool, 0, &t->remove_temporary }, - { "Target", "CurrentSymlink", config_parse_current_symlink, 0, &t->current_symlink }, + { "Transfer", "MinVersion", config_parse_min_version, 0, &t->min_version }, + { "Transfer", "ProtectVersion", config_parse_protect_version, 0, &t->protected_versions }, + { "Transfer", "Verify", config_parse_bool, 0, &t->verify }, + { "Transfer", "ChangeLog", config_parse_transfer_url_specifiers_many, 0, &t->changelog }, + { "Transfer", "AppStream", config_parse_transfer_url_specifiers_many, 0, &t->appstream }, + { "Transfer", "Features", config_parse_strv, 0, &t->features }, + { "Transfer", "RequisiteFeatures", config_parse_strv, 0, &t->requisite_features }, + { "Source", "Type", config_parse_resource_type, 0, &t->source.type }, + { "Source", "Path", config_parse_resource_path, 0, &t->source }, + { "Source", "PathRelativeTo", config_parse_resource_path_relto, 0, &t->source.path_relative_to }, + { "Source", "MatchPattern", config_parse_resource_pattern, 0, &t->source.patterns }, + { "Target", "Type", config_parse_resource_type, 0, &t->target.type }, + { "Target", "Path", config_parse_resource_path, 0, &t->target }, + { "Target", "PathRelativeTo", config_parse_resource_path_relto, 0, &t->target.path_relative_to }, + { "Target", "MatchPattern", config_parse_resource_pattern, 0, &t->target.patterns }, + { "Target", "MatchPartitionType", config_parse_resource_ptype, 0, &t->target }, + { "Target", "PartitionUUID", config_parse_partition_uuid, 0, t }, + { "Target", "PartitionFlags", config_parse_partition_flags, 0, t }, + { "Target", "PartitionNoAuto", config_parse_tristate, 0, &t->no_auto }, + { "Target", "PartitionGrowFileSystem", config_parse_tristate, 0, &t->growfs }, + { "Target", "ReadOnly", config_parse_tristate, 0, &t->read_only }, + { "Target", "Mode", config_parse_mode, 0, &t->mode }, + { "Target", "TriesLeft", config_parse_uint64, 0, &t->tries_left }, + { "Target", "TriesDone", config_parse_uint64, 0, &t->tries_done }, + { "Target", "InstancesMax", config_parse_instances_max, 0, &t->instances_max }, + { "Target", "RemoveTemporary", config_parse_bool, 0, &t->remove_temporary }, + { "Target", "CurrentSymlink", config_parse_current_symlink, 0, &t->current_symlink }, {} }; diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index e5af39849c..2a277026b0 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -34,7 +34,6 @@ #include "pretty-print.h" #include "runtime-scope.h" #include "sort-util.h" -#include "specifier.h" #include "string-util.h" #include "strv.h" #include "sysupdate.h" @@ -74,19 +73,13 @@ STATIC_DESTRUCTOR_REGISTER(arg_component, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); STATIC_DESTRUCTOR_REGISTER(arg_transfer_source, freep); -const Specifier specifier_table[] = { - COMMON_SYSTEM_SPECIFIERS, - COMMON_TMP_SPECIFIERS, - {} -}; - -#define CONTEXT_NULL \ - (Context) { \ - .sync = true, \ - .instances_max = UINT64_MAX, \ - .verify = -1, \ - .cleanup = -1, \ - .installdb_fd = -EBADF, \ +#define CONTEXT_NULL \ + (Context) { \ + .sync = true, \ + .instances_max = UINT64_MAX, \ + .verify = -1, \ + .cleanup = -1, \ + .installdb_fd = -EBADF, \ .target_identifier.class = _TARGET_CLASS_INVALID, \ } @@ -186,7 +179,50 @@ static void server_done(Server *s) { static DEFINE_POINTER_ARRAY_FREE_FUNC(Transfer*, transfer_free); -static int read_definitions( +static int read_features( + Context *c, + const char **dirs) { + + int r; + + assert(c); + + ConfFile **files = NULL; + size_t n_files = 0; + CLEANUP_ARRAY(files, n_files, conf_file_free_array); + + r = conf_files_list_strv_full( + ".feature", + c->root, + CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, + dirs, + &files, + &n_files); + if (r < 0) + return log_error_errno(r, "Failed to enumerate sysupdate.d/*.feature definitions: %m"); + + FOREACH_ARRAY(i, files, n_files) { + ConfFile *e = *i; + + _cleanup_(feature_unrefp) Feature *f = feature_new(); + if (!f) + return log_oom(); + + r = feature_read_definition(f, c->root, e->result, dirs); + if (r < 0) + return r; + + r = hashmap_ensure_put(&c->features, &feature_hash_ops, f->id, f); + if (r < 0) + return log_error_errno(r, "Failed to insert feature '%s' into map: %m", f->id); + + TAKE_PTR(f); + } + + return 0; +} + +static int read_transfers( Context *c, const char **dirs, const char *suffix, @@ -279,42 +315,17 @@ static int context_read_definitions(Context *c, const char* node, ReadDefinition if (!dirs) return log_oom(); - ConfFile **files = NULL; - size_t n_files = 0; - - CLEANUP_ARRAY(files, n_files, conf_file_free_array); - - r = conf_files_list_strv_full(".feature", c->root, - CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN, - (const char**) dirs, &files, &n_files); + r = read_features(c, (const char**) dirs); if (r < 0) - return log_error_errno(r, "Failed to enumerate sysupdate.d/*.feature definitions: %m"); + return r; - FOREACH_ARRAY(i, files, n_files) { - _cleanup_(feature_unrefp) Feature *f = NULL; - ConfFile *e = *i; - - f = feature_new(); - if (!f) - return log_oom(); - - r = feature_read_definition(f, c->root, e->result, (const char**) dirs); - if (r < 0) - return r; - - r = hashmap_ensure_put(&c->features, &feature_hash_ops, f->id, f); - if (r < 0) - return log_error_errno(r, "Failed to insert feature '%s' into map: %m", f->id); - TAKE_PTR(f); - } - - r = read_definitions(c, (const char**) dirs, ".transfer", node); + r = read_transfers(c, (const char**) dirs, ".transfer", node); if (r < 0) return r; if (c->n_transfers + c->n_disabled_transfers == 0) { /* Backwards-compat: If no .transfer defs are found, fall back to trying .conf! */ - r = read_definitions(c, (const char**) dirs, ".conf", node); + r = read_transfers(c, (const char**) dirs, ".conf", node); if (r < 0) return r; @@ -2155,11 +2166,12 @@ static int context_list_components(Context *context, char ***ret_component_names /* Does the system have at least one transfer file in /etc/sysupdate.d, which can be considered a * TARGET_HOST? See target_get_argument() in sysupdated.c */ if (ret_has_default_component) - *ret_has_default_component = (!context->definitions && - !context->component && - !context->root && - !context->image && - context->n_transfers > 0); + *ret_has_default_component = + !context->definitions && + !context->component && + !context->root && + !context->image && + context->n_transfers > 0; return 0; } diff --git a/src/sysupdate/sysupdate.h b/src/sysupdate/sysupdate.h index 02a9f7c8f3..3dcaae527d 100644 --- a/src/sysupdate/sysupdate.h +++ b/src/sysupdate/sysupdate.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "specifier.h" #include "sysupdate-forward.h" #include "sysupdate-target.h" @@ -46,5 +45,3 @@ typedef struct Context { } Context; void context_done(Context *c); - -extern const Specifier specifier_table[];