portable: add GetImageStateWithExtensions method
authorLuca Boccassi <luca.boccassi@microsoft.com>
Mon, 24 Jan 2022 17:42:32 +0000 (17:42 +0000)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 24 Jan 2022 21:44:27 +0000 (06:44 +0900)
Allow to correctly query a layered portable service for
attached/detached state.

man/org.freedesktop.portable1.xml
src/portable/portable.c
src/portable/portable.h
src/portable/portablectl.c
src/portable/portabled-bus.c
src/portable/portabled-image-bus.c
test/units/testsuite-29.sh

index 53c960206ed22b34d394aa1f38e79940b73ae1c8..a63b6aeebe98ab3b7a49622fef6923489ff97c2a 100644 (file)
@@ -57,6 +57,10 @@ node /org/freedesktop/portable1 {
                                      out a{say} units);
       GetImageState(in  s image,
                     out s state);
+      GetImageStateWithExtensions(in  s image,
+                                  in  as extensions,
+                                  in  t flags,
+                                  out s state);
       AttachImage(in  s image,
                   in  as matches,
                   in  s profile,
@@ -132,6 +136,8 @@ node /org/freedesktop/portable1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="GetImageState()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="GetImageStateWithExtensions()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="AttachImage()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachImageWithExtensions()"/>
@@ -207,6 +213,12 @@ node /org/freedesktop/portable1 {
         <listitem><para>running-runtime</para></listitem>
       </itemizedlist></para>
 
+      <para><function>GetImageStateWithExtensions()</function> is a superset of
+      <function>GetImageState()</function>, with additional support for a list of extensions
+      as input parameters, which is necessary to query the state in case the image was attached
+      in that particular way. The <varname>flag</varname> parameter is currently unused and
+      reserved for future purposes.</para>
+
       <para><function>AttachImage()</function> attaches a portable image to the system.
       This method takes an image path or name, a list of strings that will be used to search for
       unit files inside the image (partial or complete matches), a string indicating which
@@ -334,6 +346,9 @@ node /org/freedesktop/portable1 {
                                 out ay os_release,
                                 out a{say} units);
       GetState(out s state);
+      GetStateWithExtensions(in  as extensions,
+                             in  t flags,
+                             out s state);
       Attach(in  as matches,
              in  s profile,
              in  b runtime,
@@ -402,6 +417,8 @@ node /org/freedesktop/portable1 {
 
     <!--method GetState is not documented!-->
 
+    <!--method GetStateWithExtensions is not documented!-->
+
     <!--method Attach is not documented!-->
 
     <!--method AttachWithExtensions is not documented!-->
@@ -434,6 +451,8 @@ node /org/freedesktop/portable1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="GetState()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="GetStateWithExtensions()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="Attach()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="AttachWithExtensions()"/>
index b79992b2459140b3c4e361ac59c6663ebfefca66..f460a6b2242e7cb92c3299fe4aba462980149f79 100644 (file)
@@ -1662,6 +1662,7 @@ not_found:
 static int portable_get_state_internal(
                 sd_bus *bus,
                 const char *name_or_path,
+                char **extension_image_paths,
                 PortableFlags flags,
                 PortableState *ret,
                 sd_bus_error *error) {
@@ -1706,7 +1707,7 @@ static int portable_get_state_internal(
                 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
                         continue;
 
-                r = test_chroot_dropin(d, where, de->d_name, name_or_path, NULL, NULL);
+                r = test_chroot_dropin(d, where, de->d_name, name_or_path, extension_image_paths, NULL);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1739,6 +1740,7 @@ static int portable_get_state_internal(
 int portable_get_state(
                 sd_bus *bus,
                 const char *name_or_path,
+                char **extension_image_paths,
                 PortableFlags flags,
                 PortableState *ret,
                 sd_bus_error *error) {
@@ -1752,12 +1754,12 @@ int portable_get_state(
         /* We look for matching units twice: once in the regular directories, and once in the runtime directories — but
          * the latter only if we didn't find anything in the former. */
 
-        r = portable_get_state_internal(bus, name_or_path, flags & ~PORTABLE_RUNTIME, &state, error);
+        r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags & ~PORTABLE_RUNTIME, &state, error);
         if (r < 0)
                 return r;
 
         if (state == PORTABLE_DETACHED) {
-                r = portable_get_state_internal(bus, name_or_path, flags | PORTABLE_RUNTIME, &state, error);
+                r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error);
                 if (r < 0)
                         return r;
         }
index 2837e8b2869ed1af1c8b9fa2a4f72301d63bffbc..fddb4e46ce5eae520d1fbbaf9cbd8b98b38894ab 100644 (file)
@@ -70,7 +70,7 @@ int portable_extract(const char *image, char **matches, char **extension_image_p
 int portable_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
 int portable_detach(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error);
 
-int portable_get_state(sd_bus *bus, const char *name_or_path, PortableFlags flags, PortableState *ret, sd_bus_error *error);
+int portable_get_state(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error);
 
 int portable_get_profiles(char ***ret);
 
index 60feac6f5dba3acc53190e06ff85a4e234f9105b..27883eb867dd2b46db0e974f344920c5c45ee6d4 100644 (file)
@@ -1034,11 +1034,11 @@ static int set_limit(int argc, char *argv[], void *userdata) {
 }
 
 static int is_image_attached(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_free_ char *image = NULL;
-        const char *state;
+        const char *state, *method;
         int r;
 
         r = determine_image(argv[1], true, &image);
@@ -1049,9 +1049,29 @@ static int is_image_attached(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = bus_call_method(bus, bus_portable_mgr, "GetImageState", &error, &reply, "s", image);
+        method = strv_isempty(arg_extension_images) ? "GetImageState" : "GetImageStateWithExtensions";
+
+        r = bus_message_new_method_call(bus, &m, bus_portable_mgr, method);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "s", image);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = attach_extensions_to_message(m, arg_extension_images);
+        if (r < 0)
+                return r;
+
+        if (!strv_isempty(arg_extension_images)) {
+                r = sd_bus_message_append(m, "t", 0);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        r = sd_bus_call(bus, m, 0, &error, &reply);
         if (r < 0)
-                return log_error_errno(r, "Failed to get image state: %s", bus_error_message(&error, r));
+                return log_error_errno(r, "%s failed: %s", method, bus_error_message(&error, r));
 
         r = sd_bus_message_read(reply, "s", &state);
         if (r < 0)
index 5b992d9df83937b0777076700be2f8cedfbbeb6a..214fdb5b30abe3c1d3c756fb6b5ffe8a97f034ac 100644 (file)
@@ -169,6 +169,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
                 r = portable_get_state(
                                 sd_bus_message_get_bus(message),
                                 image->path,
+                                NULL,
                                 0,
                                 &state,
                                 &error_state);
@@ -225,6 +226,7 @@ static int method_get_image_metadata(sd_bus_message *message, void *userdata, sd
 }
 
 static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **extension_images = NULL;
         const char *name_or_path;
         PortableState state;
         int r;
@@ -235,9 +237,28 @@ static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bu
         if (r < 0)
                 return r;
 
+        if (sd_bus_message_is_method_call(message, NULL, "GetImageStateWithExtensions")) {
+                uint64_t input_flags = 0;
+
+                r = sd_bus_message_read_strv(message, &extension_images);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(message, "t", &input_flags);
+                if (r < 0)
+                        return r;
+
+                /* No flags are supported by this method for now. */
+                if (input_flags != 0)
+                        return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS,
+                                                          "Invalid 'flags' parameter '%" PRIu64 "'",
+                                                          input_flags);
+        }
+
         r = portable_get_state(
                         sd_bus_message_get_bus(message),
                         name_or_path,
+                        extension_images,
                         0,
                         &state,
                         error);
@@ -428,6 +449,13 @@ const sd_bus_vtable manager_vtable[] = {
                                 SD_BUS_RESULT("s", state),
                                 method_get_image_state,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageStateWithExtensions",
+                                SD_BUS_ARGS("s", image,
+                                            "as", extensions,
+                                            "t", flags),
+                                SD_BUS_RESULT("s", state),
+                                method_get_image_state,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("AttachImage",
                                 SD_BUS_ARGS("s", image,
                                             "as", matches,
index ede062dbfb4e5de274cbaf0c1a92843dd367499c..4a1798ac528f72238e5e5f3d2b42dcd19450ef04 100644 (file)
@@ -222,6 +222,7 @@ static int bus_image_method_get_state(
                 void *userdata,
                 sd_bus_error *error) {
 
+        _cleanup_strv_free_ char **extension_images = NULL;
         Image *image = userdata;
         PortableState state;
         int r;
@@ -229,9 +230,28 @@ static int bus_image_method_get_state(
         assert(message);
         assert(image);
 
+        if (sd_bus_message_is_method_call(message, NULL, "GetStateWithExtensions")) {
+                uint64_t input_flags = 0;
+
+                r = sd_bus_message_read_strv(message, &extension_images);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(message, "t", &input_flags);
+                if (r < 0)
+                        return r;
+
+                /* No flags are supported by this method for now. */
+                if (input_flags != 0)
+                        return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS,
+                                                          "Invalid 'flags' parameter '%" PRIu64 "'",
+                                                          input_flags);
+        }
+
         r = portable_get_state(
                         sd_bus_message_get_bus(message),
                         image->path,
+                        extension_images,
                         0,
                         &state,
                         error);
@@ -462,6 +482,7 @@ int bus_image_common_remove(
         r = portable_get_state(
                         sd_bus_message_get_bus(message),
                         image->path,
+                        NULL,
                         0,
                         &state,
                         error);
@@ -846,6 +867,12 @@ const sd_bus_vtable image_vtable[] = {
                                 SD_BUS_RESULT("s", state),
                                 bus_image_method_get_state,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetStateWithExtensions",
+                                SD_BUS_ARGS("as", extensions,
+                                            "t", flags),
+                                SD_BUS_RESULT("s", state),
+                                bus_image_method_get_state,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("Attach",
                                 SD_BUS_ARGS("as", matches,
                                             "s", profile,
index 5008a1b44c8aba6e783aa09f5bb4667ab39342c2..b4e41495a30d370d3d7fd28da973faeb02b9d876 100755 (executable)
@@ -84,20 +84,28 @@ portablectl list | grep -q -F "No images."
 portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_0.raw app0
 
 systemctl is-active app0.service
+status="$(portablectl is-attached --extension app0 minimal_0)"
+[[ "${status}" == "running-runtime" ]]
 
 portablectl "${ARGS[@]}" reattach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_1.raw app0
 
 systemctl is-active app0.service
+status="$(portablectl is-attached --extension app0 minimal_1)"
+[[ "${status}" == "running-runtime" ]]
 
 portablectl detach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_1.raw app0
 
 portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1
 
 systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1 minimal_0)"
+[[ "${status}" == "running-runtime" ]]
 
 portablectl "${ARGS[@]}" reattach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1
 
 systemctl is-active app1.service
+status="$(portablectl is-attached --extension app1 minimal_1)"
+[[ "${status}" == "running-runtime" ]]
 
 portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1