]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
importd: add bus/varlink api for downloading OCIs
authorLennart Poettering <lennart@amutable.com>
Tue, 25 Nov 2025 14:33:36 +0000 (15:33 +0100)
committerLennart Poettering <lennart@amutable.com>
Thu, 19 Feb 2026 14:05:15 +0000 (15:05 +0100)
man/org.freedesktop.import1.xml
src/import/importd.c
src/import/meson.build
src/import/org.freedesktop.import1.conf
src/shared/import-util.c
src/shared/import-util.h

index cece4cad0b44f02d1141f40dcac6fe950c595b7c..95ecbd79e6a19b49f126b2986e82af4146c01935 100644 (file)
@@ -136,6 +136,12 @@ node /org/freedesktop/import1 {
                 in  t flags,
                 out u transfer_id,
                 out o transfer_path);
+      PullOci(in  s ref,
+              in  s local_name,
+              in  s class,
+              in  t flags,
+              out u transfer_id,
+              out o transfer_path);
       ListTransfers(out a(usssdo) transfers);
       ListTransfersEx(in  s class,
                       in  t flags,
@@ -191,6 +197,8 @@ node /org/freedesktop/import1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="PullRawEx()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="PullOci()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="ListTransfers()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="ListTransfersEx()"/>
@@ -290,6 +298,19 @@ node /org/freedesktop/import1 {
       export calls above, these calls return a pair of transfer identifier and object path for the ongoing
       download.</para>
 
+      <para><function>PullOci()</function> is similar to <function>PullTarEx()</function> or
+      <function>PullRawEx()</function> and may be used to download and import an OCI container image from an
+      OCI registry. It takes an OCI container reference as argument. The second argument is a local name for
+      the image (which will be generated as
+      <citerefentry><refentrytitle>systemd.mstack</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+      directory referencing the OCI layers). It should be suitable as a hostname, similarly to the matching
+      argument of the <function>PullTar()</function>/<function>PullTarEx()</function> and
+      <function>PullRaw()</function>/<function>PullRawEx()</function> methods above. The last argument is a
+      64bit flags parameter, where bit 0 controls the <literal>force</literal> flag, bit 1 is a
+      <literal>read_only</literal> flag that controls whether the created image shall be marked
+      read-only. Like the pull calls above, this call return a pair of transfer identifier and object path
+      for the ongoing download.</para>
+
       <para><function>ImportFileSystem()</function>/<function>ImportFileSystemEx()</function> are similar to
       <function>ImportTar()</function>/<function>ImportTarEx()</function> but import a directory tree. The
       first argument must refer to a directory file descriptor for the source hierarchy to import.</para>
@@ -464,6 +485,7 @@ node /org/freedesktop/import1/transfer/_1 {
       <function>ExportRawEx()</function>, <function>PullTarEx()</function>, <function>PullRawEx()</function>,
       <function>ListTransfersEx()</function>, <function>ListImages()</function> were added in version
       256.</para>
+      <para><function>PullOci()</function> was added in version 260.</para>
     </refsect2>
     <refsect2>
       <title>Transfer Objects</title>
index 280aa88d46b03a5dbc4a9dbc6e6d446d27b75dbe..d3363d446cb67b60ad36bee909003c12e6c4dc2e 100644 (file)
@@ -29,6 +29,7 @@
 #include "json-util.h"
 #include "main-func.h"
 #include "notify-recv.h"
+#include "oci-util.h"
 #include "os-util.h"
 #include "parse-util.h"
 #include "path-lookup.h"
@@ -58,6 +59,7 @@ typedef enum TransferType {
         TRANSFER_EXPORT_RAW,
         TRANSFER_PULL_TAR,
         TRANSFER_PULL_RAW,
+        TRANSFER_PULL_OCI,
         _TRANSFER_TYPE_MAX,
         _TRANSFER_TYPE_INVALID = -EINVAL,
 } TransferType;
@@ -127,6 +129,7 @@ static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
         [TRANSFER_EXPORT_RAW] = "export-raw",
         [TRANSFER_PULL_TAR]   = "pull-tar",
         [TRANSFER_PULL_RAW]   = "pull-raw",
+        [TRANSFER_PULL_OCI]   = "pull-oci",
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
@@ -497,6 +500,7 @@ static int transfer_start(Transfer *t) {
 
                 case TRANSFER_PULL_TAR:
                 case TRANSFER_PULL_RAW:
+                case TRANSFER_PULL_OCI:
                         cmd[k++] = SYSTEMD_PULL_PATH;
                         break;
 
@@ -518,6 +522,10 @@ static int transfer_start(Transfer *t) {
                         cmd[k++] = "raw";
                         break;
 
+                case TRANSFER_PULL_OCI:
+                        cmd[k++] = "oci";
+                        break;
+
                 case TRANSFER_IMPORT_FS:
                         cmd[k++] = "run";
                         break;
@@ -1053,7 +1061,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
         return 1;
 }
 
-static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_pull_tar_or_raw_or_oci(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
         _cleanup_(transfer_unrefp) Transfer *t = NULL;
         ImageClass class = _IMAGE_CLASS_INVALID;
         const char *remote, *local, *verify;
@@ -1078,7 +1086,24 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
                         return 1; /* Will call us back */
         }
 
-        if (endswith(sd_bus_message_get_member(msg), "Ex")) {
+        if (streq(sd_bus_message_get_member(msg), "PullOci")) {
+                const char *sclass;
+
+                r = sd_bus_message_read(msg, "ssst", &remote, &local, &sclass, &flags);
+                if (r < 0)
+                        return r;
+
+                class = image_class_from_string(sclass);
+                if (class < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Image class '%s' not known", sclass);
+
+                if (flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Flags 0x%" PRIx64 " invalid", flags);
+
+                verify = NULL;
+        } else if (endswith(sd_bus_message_get_member(msg), "Ex")) {
                 const char *sclass;
 
                 r = sd_bus_message_read(msg, "sssst", &remote, &local, &sclass, &verify, &flags);
@@ -1106,9 +1131,21 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
                 SET_FLAG(flags, IMPORT_FORCE, force);
         }
 
-        if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
+        type = startswith(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR :
+                startswith(sd_bus_message_get_member(msg), "PullRaw") ? TRANSFER_PULL_RAW :
+                streq(sd_bus_message_get_member(msg), "PullOci") ? TRANSFER_PULL_OCI : _TRANSFER_TYPE_INVALID;
+        assert(type >= 0);
+
+        if (type == TRANSFER_PULL_OCI) {
+                r = oci_ref_valid(remote);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Reference '%s' is invalid", remote);
+        } else if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
-                                         "URL %s is invalid", remote);
+                                         "URL '%s' is invalid", remote);
 
         if (isempty(local))
                 local = NULL;
@@ -1116,13 +1153,16 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                          "Local image name %s is invalid", local);
 
-        if (isempty(verify))
+        if (type == TRANSFER_PULL_OCI)
+                v = _IMPORT_VERIFY_INVALID;
+        else if (isempty(verify))
                 v = IMPORT_VERIFY_SIGNATURE;
-        else
+        else {
                 v = import_verify_from_string(verify);
-        if (v < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
-                                         "Unknown verification mode %s", verify);
+                if (v < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Unknown verification mode %s", verify);
+        }
 
         if (class == IMAGE_MACHINE) {
                 r = image_setup_pool(m->runtime_scope, class, m->use_btrfs_subvol, m->use_btrfs_quota);
@@ -1130,9 +1170,6 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
                         return sd_bus_error_set_errnof(error, r, "Failed to set up machine pool: %m");
         }
 
-        type = startswith(sd_bus_message_get_member(msg), "PullTar") ?
-                TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
-
         if (manager_find(m, type, remote))
                 return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS,
                                          "Transfer for %s already in progress.", remote);
@@ -1613,52 +1650,53 @@ static const sd_bus_vtable manager_vtable[] = {
                                  SD_BUS_PARAM(transfer_path),
                                  method_export_tar_or_raw,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PullTar",
-                                 "sssb",
-                                 SD_BUS_PARAM(url)
-                                 SD_BUS_PARAM(local_name)
-                                 SD_BUS_PARAM(verify_mode)
-                                 SD_BUS_PARAM(force),
-                                 "uo",
-                                 SD_BUS_PARAM(transfer_id)
-                                 SD_BUS_PARAM(transfer_path),
-                                 method_pull_tar_or_raw,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PullTarEx",
-                                 "sssst",
-                                 SD_BUS_PARAM(url)
-                                 SD_BUS_PARAM(local_name)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(verify_mode)
-                                 SD_BUS_PARAM(flags),
-                                 "uo",
-                                 SD_BUS_PARAM(transfer_id)
-                                 SD_BUS_PARAM(transfer_path),
-                                 method_pull_tar_or_raw,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PullRaw",
-                                 "sssb",
-                                 SD_BUS_PARAM(url)
-                                 SD_BUS_PARAM(local_name)
-                                 SD_BUS_PARAM(verify_mode)
-                                 SD_BUS_PARAM(force),
-                                 "uo",
-                                 SD_BUS_PARAM(transfer_id)
-                                 SD_BUS_PARAM(transfer_path),
-                                 method_pull_tar_or_raw,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD_WITH_NAMES("PullRawEx",
-                                 "sssst",
-                                 SD_BUS_PARAM(url)
-                                 SD_BUS_PARAM(local_name)
-                                 SD_BUS_PARAM(class)
-                                 SD_BUS_PARAM(verify_mode)
-                                 SD_BUS_PARAM(flags),
-                                 "uo",
-                                 SD_BUS_PARAM(transfer_id)
-                                 SD_BUS_PARAM(transfer_path),
-                                 method_pull_tar_or_raw,
-                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PullTar",
+                                SD_BUS_ARGS("s", url,
+                                            "s", local_name,
+                                            "s", verify_mode,
+                                            "b", force),
+                                SD_BUS_RESULT("u", transfer_id,
+                                              "o", transfer_path),
+                                method_pull_tar_or_raw_or_oci,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PullTarEx",
+                                SD_BUS_ARGS("s", url,
+                                            "s", local_name,
+                                            "s", class,
+                                            "s", verify_mode,
+                                            "t", flags),
+                                SD_BUS_RESULT("u", transfer_id,
+                                              "o", transfer_path),
+                                method_pull_tar_or_raw_or_oci,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PullRaw",
+                                SD_BUS_ARGS("s", url,
+                                            "s", local_name,
+                                            "s", verify_mode,
+                                            "b", force),
+                                SD_BUS_RESULT("u", transfer_id,
+                                              "o", transfer_path),
+                                method_pull_tar_or_raw_or_oci,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PullRawEx",
+                                SD_BUS_ARGS("s", url,
+                                            "s", local_name,
+                                            "s", class,
+                                            "s", verify_mode,
+                                            "t", flags),
+                                SD_BUS_RESULT("u", transfer_id,
+                                              "o", transfer_path),
+                                method_pull_tar_or_raw_or_oci,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("PullOci",
+                                SD_BUS_ARGS("s", ref,
+                                            "s", local_name,
+                                            "s", class,
+                                            "t", flags),
+                                SD_BUS_RESULT("u", transfer_id,
+                                              "o", transfer_path),
+                                method_pull_tar_or_raw_or_oci,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_NAMES("ListTransfers",
                                  NULL,,
                                  "a(usssdo)",
@@ -1864,7 +1902,13 @@ static int vl_method_pull(sd_varlink *link, sd_json_variant *parameters, sd_varl
         if (r != 0)
                 return r;
 
-        if (!http_url_is_valid(p.remote) && !file_url_is_valid(p.remote))
+        if (p.type == IMPORT_OCI) {
+                r = oci_ref_valid(p.remote);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_varlink_error_invalid_parameter_name(link, "remote");
+        } else if (!http_url_is_valid(p.remote) && !file_url_is_valid(p.remote))
                 return sd_varlink_error_invalid_parameter_name(link, "remote");
 
         if (p.local && !image_name_is_valid(p.local))
@@ -1874,8 +1918,8 @@ static int vl_method_pull(sd_varlink *link, sd_json_variant *parameters, sd_varl
 
         TransferType tt =
                 p.type == IMPORT_TAR ? TRANSFER_PULL_TAR :
-                p.type == IMPORT_RAW ? TRANSFER_PULL_RAW : _TRANSFER_TYPE_INVALID;
-
+                p.type == IMPORT_RAW ? TRANSFER_PULL_RAW :
+                p.type == IMPORT_OCI ? TRANSFER_PULL_OCI : _TRANSFER_TYPE_INVALID;
         assert(tt >= 0);
 
         if (manager_find(m, tt, p.remote))
index 7735db7ff5efe2f87fdc97aba62832e6b9cb0c25..334c05368d3f3e0db9943e7fc098ec56ea051e33 100644 (file)
@@ -18,6 +18,7 @@ executables += [
                 'dbus' : true,
                 'sources' : files(
                         'importd.c',
+                        'oci-util.c',
                 ),
                 'extract' : files(
                         'oci-util.c',
index f99ec56c79750fe04006d88d12d93b744f24a691..d8b82388d50e9cf48beb73fefd023109324d0cd5 100644 (file)
                        send_interface="org.freedesktop.import1.Manager"
                        send_member="PullRawEx"/>
 
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Manager"
+                       send_member="PullOci"/>
+
                 <allow send_destination="org.freedesktop.import1"
                        send_interface="org.freedesktop.import1.Transfer"
                        send_member="Cancel"/>
index 2644f59fda18031c2b83111f6b456e2cf565ed1c..35079a653786c5fc3c0772eb34e08a10e6b7c0d5 100644 (file)
@@ -125,6 +125,7 @@ int import_url_change_suffix(
 static const char* const import_type_table[_IMPORT_TYPE_MAX] = {
         [IMPORT_RAW] = "raw",
         [IMPORT_TAR] = "tar",
+        [IMPORT_OCI] = "oci",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(import_type, ImportType);
index 2a594e1e6143bac6c4f8aa7e3c553f30fa4eb561..a982d159ca91f6ea369588b445b2a6eba283aa1f 100644 (file)
@@ -6,6 +6,7 @@
 typedef enum ImportType {
         IMPORT_RAW,
         IMPORT_TAR,
+        IMPORT_OCI,
         _IMPORT_TYPE_MAX,
         _IMPORT_TYPE_INVALID = -EINVAL,
 } ImportType;