]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysupdate: Add --transfer-source=
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 8 Sep 2024 14:09:19 +0000 (16:09 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 9 Sep 2024 14:41:52 +0000 (16:41 +0200)
In mkosi, I want to add a sysupdate verb to wrap systemd-sysupdate.
The definitions will be picked up from mkosi.sysupdate/ and passed
to systemd-sysupdate. I want users to be able to write transfer
definitions that are independent of the output directory used by
mkosi. To make this possible, it should be possible to specify the
directory that transfer sources should be looked up in on the sysupdate
command line. Let's allow this via a new --transfer-source= option.

Additionally, transfer sources that want to take advantage of this
feature should specify PathRelativeTo=directory to indicate the configured
Path= is interpreted relative to the tranfer source directory specified
on the CLI.

This allows for the following transfer definition to be put in
mkosi.sysupdate:

"""
[Transfer]
ProtectVersion=%A

[Source]
Type=regular-file
Path=/
PathRelativeTo=directory
MatchPattern=ParticleOS_@v.usr-%a.@u.raw

[Target]
Type=partition
Path=auto
MatchPattern=ParticleOS_@v
MatchPartitionType=usr
PartitionFlags=0
ReadOnly=1
"""

man/systemd-sysupdate.xml
man/sysupdate.d.xml
src/sysupdate/sysupdate-resource.c
src/sysupdate/sysupdate-resource.h
src/sysupdate/sysupdate-transfer.c
src/sysupdate/sysupdate.c
src/sysupdate/sysupdate.h

index f57a17b79ac608e7342bc130788e22312b73f329..f7f1521a5d4207fcafef427413ffc0c3bdf2f5ba 100644 (file)
         <xi:include href="version-info.xml" xpointer="v257"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--transfer-source=</option></term>
+
+        <listitem><para>Takes a path as its argument. When specified, all transfer sources configured with
+        <varname>PathRelativeTo=explicit</varname> will be interpreted relative to the specified path.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="no-legend" />
       <xi:include href="standard-options.xml" xpointer="json" />
index ef3b21d29d4e2b386863b32f9d66704e52f2a1ee..070d630735579f4289a51a6c174183fde4f7bd7a 100644 (file)
       <varlistentry>
         <term><varname>PathRelativeTo=</varname></term>
 
-        <listitem><para>Specifies what partition <varname>Path=</varname> should be relative to. Takes one of
-        <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>, or <constant>boot</constant>.
-        If unspecified, defaults to <constant>root</constant>.</para>
+        <listitem><para>Specifies what anchor point <varname>Path=</varname> should be relative to. Takes one
+        of <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,
+        <constant>boot</constant> or <constant>directory</constant>. If unspecified, defaults to
+        <constant>root</constant>.</para>
+
+        <para>If set to <constant>root</constant>, <constant>esp</constant>, <constant>xbootldr</constant>,
+        the specified <varname>Path=</varname> will be resolved relative to the mount point of the
+        corresponding partition, as defined by the
+        <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
+        Specification</ulink>.</para>
 
         <para>If set to <constant>boot</constant>, the specified <varname>Path=</varname> will be resolved
         relative to the mount point of the $BOOT partition (i.e. the ESP or XBOOTLDR), as defined by the
         <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
         Specification</ulink>.</para>
 
+        <para>If set to <constant>explicit</constant>, the specified <varname>Path=</varname> will be
+        resolved relative to the directory specified with <option>--transfer-source=</option> when invoking
+        <command>systemd-sysupdate</command>.</para>
+
         <para>The values <constant>esp</constant>, <constant>xbootldr</constant>, and
         <constant>boot</constant> are only supported when <varname>Type=</varname> is set to
         <constant>regular-file</constant> or <constant>directory</constant>.</para>
index 94308998971221822dddb22d6b1cad2231ec199a..2f7a0880924a860ecf627b67e47a19faa49430d2 100644 (file)
@@ -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);
index 76795db0d80edcf73c946f21b60d2a310303bf00..1bcbe0f8e5df0b632e52a97c565e33ee0a60a119 100644 (file)
@@ -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_;
index cbf3f77f5bfd903fe9afd13b5a3083133298ea04..508fd73355f6b98f5708e99fff34cab6675f179d 100644 (file)
@@ -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;
 
index 04fd003299ea2495a04d3eeb93cc840dc97dedc0..a80599c796928100a217b955bb08c29d5e191e2e 100644 (file)
@@ -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;
 
index 011b351375fcb9947ef392e8f56ac3ad1f39ea69..572b4305c72df11025d061c0987383562ebcabc6 100644 (file)
@@ -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;