]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/portable/portabled-image-bus.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / portable / portabled-image-bus.c
index 595fe8a60a4fd7a9fec381d972ce3f6a85194295..7d393476a0f5d9a981afdd6c0b3668683b42a479 100644 (file)
@@ -102,14 +102,12 @@ int bus_image_common_get_metadata(
                 Image *image,
                 sd_bus_error *error) {
 
+        _cleanup_ordered_hashmap_free_ OrderedHashmap *extension_releases = NULL;
         _cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
         _cleanup_strv_free_ char **matches = NULL, **extension_images = NULL;
         _cleanup_hashmap_free_ Hashmap *unit_files = NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ PortableMetadata **sorted = NULL;
-        /* Unused for now, but added to the DBUS methods for future-proofing */
-        uint64_t input_flags = 0;
-        size_t i;
         int r;
 
         assert(name_or_path || image);
@@ -120,8 +118,10 @@ int bus_image_common_get_metadata(
                 m = image->userdata;
         }
 
-        if (sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
-            sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions")) {
+        bool have_exti = sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
+                         sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions");
+
+        if (have_exti) {
                 r = sd_bus_message_read_strv(message, &extension_images);
                 if (r < 0)
                         return r;
@@ -131,13 +131,14 @@ int bus_image_common_get_metadata(
         if (r < 0)
                 return r;
 
-        if (sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") ||
-            sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions")) {
+        if (have_exti) {
+                uint64_t input_flags = 0;
+
                 r = sd_bus_message_read(message, "t", &input_flags);
                 if (r < 0)
                         return r;
-                /* Let clients know that this version doesn't support any flags */
-                if (input_flags != 0)
+
+                if ((input_flags & ~_PORTABLE_MASK_PUBLIC) != 0)
                         return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS,
                                                           "Invalid 'flags' parameter '%" PRIu64 "'",
                                                           input_flags);
@@ -161,7 +162,9 @@ int bus_image_common_get_metadata(
                         matches,
                         extension_images,
                         &os_release,
+                        &extension_releases,
                         &unit_files,
+                        NULL,
                         error);
         if (r < 0)
                 return r;
@@ -182,11 +185,45 @@ int bus_image_common_get_metadata(
         if (r < 0)
                 return r;
 
+        /* If it was requested, also send back the extension path and the content
+         * of each extension-release file. Behind a flag, as it's an incompatible
+         * change. */
+        if (have_exti) {
+                PortableMetadata *extension_release;
+
+                r = sd_bus_message_open_container(reply, 'a', "{say}");
+                if (r < 0)
+                        return r;
+
+                ORDERED_HASHMAP_FOREACH(extension_release, extension_releases) {
+
+                        r = sd_bus_message_open_container(reply, 'e', "say");
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_append(reply, "s", extension_release->image_path);
+                        if (r < 0)
+                                return r;
+
+                        r = append_fd(reply, extension_release);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_close_container(reply);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = sd_bus_message_close_container(reply);
+                if (r < 0)
+                        return r;
+        }
+
         r = sd_bus_message_open_container(reply, 'a', "{say}");
         if (r < 0)
                 return r;
 
-        for (i = 0; i < hashmap_size(unit_files); i++) {
+        for (size_t i = 0; i < hashmap_size(unit_files); i++) {
 
                 r = sd_bus_message_open_container(reply, 'e', "say");
                 if (r < 0)
@@ -221,16 +258,35 @@ static int bus_image_method_get_state(
                 void *userdata,
                 sd_bus_error *error) {
 
-        Image *image = userdata;
+        _cleanup_strv_free_ char **extension_images = NULL;
+        Image *image = ASSERT_PTR(userdata);
         PortableState state;
         int r;
 
         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);
@@ -351,15 +407,13 @@ static int bus_image_method_detach(
 
         _cleanup_strv_free_ char **extension_images = NULL;
         PortableChange *changes = NULL;
-        Image *image = userdata;
-        Manager *m = image->userdata;
+        Image *image = ASSERT_PTR(userdata);
+        Manager *m = ASSERT_PTR(image->userdata);
         PortableFlags flags = 0;
         size_t n_changes = 0;
         int r;
 
         assert(message);
-        assert(image);
-        assert(m);
 
         if (sd_bus_message_is_method_call(message, NULL, "DetachWithExtensions")) {
                 r = sd_bus_message_read_strv(message, &extension_images);
@@ -461,6 +515,7 @@ int bus_image_common_remove(
         r = portable_get_state(
                         sd_bus_message_get_bus(message),
                         image->path,
+                        NULL,
                         0,
                         &state,
                         error);
@@ -837,6 +892,7 @@ const sd_bus_vtable image_vtable[] = {
                                             "t", flags),
                                 SD_BUS_RESULT("s", image,
                                               "ay", os_release,
+                                              "a{say}", extensions,
                                               "a{say}", units),
                                 bus_image_method_get_metadata,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
@@ -845,6 +901,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,
@@ -980,19 +1042,23 @@ int bus_image_acquire(
                 /* If it's a short name, let's search for it */
                 r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded);
                 if (r == -ENOENT)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path);
+                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE,
+                                                 "No image '%s' found.", name_or_path);
 
                 /* other errors are handled below… */
         } else {
                 /* Don't accept path if this is always forbidden */
                 if (mode == BUS_IMAGE_REFUSE_BY_PATH)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Expected image name, not path in place of '%s'.", name_or_path);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Expected image name, not path in place of '%s'.", name_or_path);
 
                 if (!path_is_absolute(name_or_path))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is not valid or not a valid path.", name_or_path);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Image name '%s' is not valid or not a valid path.", name_or_path);
 
                 if (!path_is_normalized(name_or_path))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image path '%s' is not normalized.", name_or_path);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Image path '%s' is not normalized.", name_or_path);
 
                 if (mode == BUS_IMAGE_AUTHENTICATE_BY_PATH) {
                         r = bus_verify_polkit_async(
@@ -1015,7 +1081,9 @@ int bus_image_acquire(
                 r = image_from_path(name_or_path, &loaded);
         }
         if (r == -EMEDIUMTYPE) {
-                sd_bus_error_setf(error, BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE, "Typ of image '%s' not recognized; supported image types are directories/btrfs subvolumes, block devices, and raw disk image files with suffix '.raw'.", name_or_path);
+                sd_bus_error_setf(error, BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE,
+                                  "Type of image '%s' not recognized; supported image types are directories/btrfs subvolumes, block devices, and raw disk image files with suffix '.raw'.",
+                                  name_or_path);
                 return r;
         }
         if (r < 0)
@@ -1055,6 +1123,9 @@ int bus_image_object_find(
                 return 0;
         if (r == 0)
                 goto not_found;
+        if (isempty(e))
+                /* The path is "/org/freedesktop/portable1/image" itself */
+                goto not_found;
 
         r = bus_image_acquire(m, sd_bus_get_current_message(bus), e, NULL, BUS_IMAGE_REFUSE_BY_PATH, NULL, &image, error);
         if (r == -ENOENT)
@@ -1073,8 +1144,8 @@ not_found:
 int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
         _cleanup_hashmap_free_ Hashmap *images = NULL;
         _cleanup_strv_free_ char **l = NULL;
-        size_t n_allocated = 0, n = 0;
         Manager *m = userdata;
+        size_t n = 0;
         Image *image;
         int r;
 
@@ -1097,7 +1168,7 @@ int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, cha
                 if (r < 0)
                         return r;
 
-                if (!GREEDY_REALLOC(l, n_allocated, n+2)) {
+                if (!GREEDY_REALLOC(l, n+2)) {
                         free(p);
                         return -ENOMEM;
                 }