diff --git a/man/systemd-sysupdate.xml b/man/systemd-sysupdate.xml index f57a17b79ac..f7f1521a5d4 100644 --- a/man/systemd-sysupdate.xml +++ b/man/systemd-sysupdate.xml @@ -305,6 +305,15 @@ + + + + Takes a path as its argument. When specified, all transfer sources configured with + PathRelativeTo=explicit will be interpreted relative to the specified path. + + + + diff --git a/man/sysupdate.d.xml b/man/sysupdate.d.xml index ef3b21d29d4..070d6307355 100644 --- a/man/sysupdate.d.xml +++ b/man/sysupdate.d.xml @@ -627,15 +627,26 @@ PathRelativeTo= - Specifies what partition Path= should be relative to. Takes one of - root, esp, xbootldr, or boot. - If unspecified, defaults to root. + Specifies what anchor point Path= should be relative to. Takes one + of root, esp, xbootldr, + boot or directory. If unspecified, defaults to + root. + + If set to root, esp, xbootldr, + the specified Path= will be resolved relative to the mount point of the + corresponding partition, as defined by the + Boot Loader + Specification. If set to boot, the specified Path= will be resolved relative to the mount point of the $BOOT partition (i.e. the ESP or XBOOTLDR), as defined by the Boot Loader Specification. + If set to explicit, the specified Path= will be + resolved relative to the directory specified with when invoking + systemd-sysupdate. + The values esp, xbootldr, and boot are only supported when Type= is set to regular-file or directory. diff --git a/src/sysupdate/sysupdate-resource.c b/src/sysupdate/sysupdate-resource.c index 94308998971..2f7a0880924 100644 --- a/src/sysupdate/sysupdate-resource.c +++ b/src/sysupdate/sysupdate-resource.c @@ -555,6 +555,7 @@ Instance* resource_find_instance(Resource *rr, const char *version) { int resource_resolve_path( Resource *rr, const char *root, + const char *relative_to_directory, const char *node) { _cleanup_free_ char *p = NULL; @@ -648,7 +649,13 @@ int resource_resolve_path( _cleanup_free_ char *resolved = NULL, *relative_to = NULL; ChaseFlags chase_flags = CHASE_PREFIX_ROOT; - if (rr->path_relative_to == PATH_RELATIVE_TO_ROOT) { + if (rr->path_relative_to == PATH_RELATIVE_TO_EXPLICIT) { + assert(relative_to_directory); + + relative_to = strdup(relative_to_directory); + if (!relative_to) + return log_oom(); + } else if (rr->path_relative_to == PATH_RELATIVE_TO_ROOT) { relative_to = strdup(empty_to_root(root)); if (!relative_to) return log_oom(); @@ -715,6 +722,7 @@ static const char *path_relative_to_table[_PATH_RELATIVE_TO_MAX] = { [PATH_RELATIVE_TO_ESP] = "esp", [PATH_RELATIVE_TO_XBOOTLDR] = "xbootldr", [PATH_RELATIVE_TO_BOOT] = "boot", + [PATH_RELATIVE_TO_EXPLICIT] = "explicit", }; DEFINE_STRING_TABLE_LOOKUP(path_relative_to, PathRelativeTo); diff --git a/src/sysupdate/sysupdate-resource.h b/src/sysupdate/sysupdate-resource.h index 76795db0d80..1bcbe0f8e5d 100644 --- a/src/sysupdate/sysupdate-resource.h +++ b/src/sysupdate/sysupdate-resource.h @@ -73,6 +73,7 @@ typedef enum PathRelativeTo { PATH_RELATIVE_TO_ESP, PATH_RELATIVE_TO_XBOOTLDR, PATH_RELATIVE_TO_BOOT, /* Refers to $BOOT from the BLS. No direct counterpart in PartitionDesignator */ + PATH_RELATIVE_TO_EXPLICIT, _PATH_RELATIVE_TO_MAX, _PATH_RELATIVE_TO_INVALID = -EINVAL, } PathRelativeTo; @@ -102,7 +103,7 @@ int resource_load_instances(Resource *rr, bool verify, Hashmap **web_cache); Instance* resource_find_instance(Resource *rr, const char *version); -int resource_resolve_path(Resource *rr, const char *root, const char *node); +int resource_resolve_path(Resource *rr, const char *root, const char *relative_to_directory, const char *node); ResourceType resource_type_from_string(const char *s) _pure_; const char* resource_type_to_string(ResourceType t) _const_; diff --git a/src/sysupdate/sysupdate-transfer.c b/src/sysupdate/sysupdate-transfer.c index cbf3f77f5bf..508fd73355f 100644 --- a/src/sysupdate/sysupdate-transfer.c +++ b/src/sysupdate/sysupdate-transfer.c @@ -557,6 +557,14 @@ int transfer_read_definition(Transfer *t, const char *path) { return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), "Source specification lacks Path=."); + if (t->source.path_relative_to == PATH_RELATIVE_TO_EXPLICIT && !arg_transfer_source) + return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), + "PathRelativeTo=explicit requires --transfer-source= to be specified."); + + if (t->target.path_relative_to == PATH_RELATIVE_TO_EXPLICIT) + return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), + "PathRelativeTo=explicit can only be used in source specifications."); + if (t->source.path) { if (RESOURCE_IS_FILESYSTEM(t->source.type) || t->source.type == RESOURCE_PARTITION) if (!path_is_absolute(t->source.path) || !path_is_normalized(t->source.path)) @@ -618,11 +626,11 @@ int transfer_resolve_paths( assert(t); - r = resource_resolve_path(&t->source, root, node); + r = resource_resolve_path(&t->source, root, arg_transfer_source, node); if (r < 0) return r; - r = resource_resolve_path(&t->target, root, node); + r = resource_resolve_path(&t->target, root, /*relative_to_directory=*/ NULL, node); if (r < 0) return r; diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index 04fd003299e..a80599c7969 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -48,12 +48,14 @@ static char *arg_component = NULL; static int arg_verify = -1; static ImagePolicy *arg_image_policy = NULL; static bool arg_offline = false; +char *arg_transfer_source = NULL; STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_component, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); +STATIC_DESTRUCTOR_REGISTER(arg_transfer_source, freep); typedef struct Context { Transfer **transfers; @@ -1436,6 +1438,8 @@ static int verb_help(int argc, char **argv, void *userdata) { " --no-legend Do not show the headers and footers\n" " --json=pretty|short|off\n" " Generate JSON output\n" + " --transfer-source=PATH\n" + " Specify the directory to transfer sources from\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -1462,6 +1466,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_REBOOT, ARG_VERIFY, ARG_OFFLINE, + ARG_TRANSFER_SOURCE, }; static const struct option options[] = { @@ -1480,6 +1485,7 @@ static int parse_argv(int argc, char *argv[]) { { "component", required_argument, NULL, 'C' }, { "verify", required_argument, NULL, ARG_VERIFY }, { "offline", no_argument, NULL, ARG_OFFLINE }, + { "transfer-source", required_argument, NULL, ARG_TRANSFER_SOURCE }, {} }; @@ -1587,6 +1593,13 @@ static int parse_argv(int argc, char *argv[]) { arg_offline = true; break; + case ARG_TRANSFER_SOURCE: + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_transfer_source); + if (r < 0) + return r; + + break; + case '?': return -EINVAL; diff --git a/src/sysupdate/sysupdate.h b/src/sysupdate/sysupdate.h index 011b351375f..572b4305c72 100644 --- a/src/sysupdate/sysupdate.h +++ b/src/sysupdate/sysupdate.h @@ -10,3 +10,4 @@ typedef struct Context Context; extern bool arg_sync; extern uint64_t arg_instances_max; extern char *arg_root; +extern char *arg_transfer_source;