]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/portable/portabled-bus.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / portable / portabled-bus.c
index 20a33dc6716c0931a11b19208389cf5ccad68f59..4f239e2b125eb85bfd8c84f67c2bd5b9bdcda009 100644 (file)
@@ -3,6 +3,7 @@
 #include "alloc-util.h"
 #include "btrfs-util.h"
 #include "bus-common-errors.h"
+#include "bus-object.h"
 #include "bus-polkit.h"
 #include "discover-image.h"
 #include "fd-util.h"
@@ -40,8 +41,8 @@ static int property_get_pool_usage(
                 void *userdata,
                 sd_bus_error *error) {
 
-        _cleanup_close_ int fd = -1;
-        uint64_t usage = (uint64_t) -1;
+        _cleanup_close_ int fd = -EBADF;
+        uint64_t usage = UINT64_MAX;
 
         assert(bus);
         assert(reply);
@@ -66,8 +67,8 @@ static int property_get_pool_limit(
                 void *userdata,
                 sd_bus_error *error) {
 
-        _cleanup_close_ int fd = -1;
-        uint64_t size = (uint64_t) -1;
+        _cleanup_close_ int fd = -EBADF;
+        uint64_t size = UINT64_MAX;
 
         assert(bus);
         assert(reply);
@@ -107,13 +108,12 @@ static int property_get_profiles(
 
 static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         const char *name;
         Image *image;
         int r;
 
         assert(message);
-        assert(m);
 
         r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
@@ -133,12 +133,11 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro
 static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_hashmap_free_ Hashmap *images = NULL;
-        Manager *m = userdata;
+        Manager *m = ASSERT_PTR(userdata);
         Image *image;
         int r;
 
         assert(message);
-        assert(m);
 
         images = hashmap_new(&image_hash_ops);
         if (!images)
@@ -168,6 +167,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);
@@ -224,6 +224,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;
@@ -234,9 +235,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);
@@ -251,30 +271,57 @@ static int method_attach_image(sd_bus_message *message, void *userdata, sd_bus_e
 }
 
 static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **extension_images = NULL;
         PortableChange *changes = NULL;
-        Manager *m = userdata;
+        PortableFlags flags = 0;
+        Manager *m = ASSERT_PTR(userdata);
         size_t n_changes = 0;
         const char *name_or_path;
-        int r, runtime;
+        int r;
 
         assert(message);
-        assert(m);
+
+        CLEANUP_ARRAY(changes, n_changes, portable_changes_free);
 
         /* Note that we do not redirect detaching to the image object here, because we want to allow that users can
          * detach already deleted images too, in case the user already deleted an image before properly detaching
          * it. */
 
-        r = sd_bus_message_read(message, "sb", &name_or_path, &runtime);
+        r = sd_bus_message_read(message, "s", &name_or_path);
         if (r < 0)
                 return r;
 
+        if (sd_bus_message_is_method_call(message, NULL, "DetachImageWithExtensions")) {
+                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;
+
+                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);
+                flags |= input_flags;
+        } else {
+                int runtime;
+
+                r = sd_bus_message_read(message, "b", &runtime);
+                if (r < 0)
+                        return r;
+
+                if (runtime)
+                        flags |= PORTABLE_RUNTIME;
+        }
+
         r = bus_verify_polkit_async(
                         message,
-                        CAP_SYS_ADMIN,
                         "org.freedesktop.portable1.attach-images",
-                        NULL,
-                        false,
-                        UID_INVALID,
+                        /* details= */ NULL,
                         &m->polkit_registry,
                         error);
         if (r < 0)
@@ -285,18 +332,19 @@ static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_e
         r = portable_detach(
                         sd_bus_message_get_bus(message),
                         name_or_path,
-                        runtime ? PORTABLE_RUNTIME : 0,
+                        extension_images,
+                        flags,
                         &changes,
                         &n_changes,
                         error);
         if (r < 0)
-                goto finish;
+                return r;
 
-        r = reply_portable_changes(message, changes, n_changes);
+        return reply_portable_changes(message, changes, n_changes);
+}
 
-finish:
-        portable_changes_free(changes, n_changes);
-        return r;
+static int method_reattach_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return redirect_method_to_image(userdata, message, error, bus_image_common_reattach);
 }
 
 static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -322,15 +370,12 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0)
                 return r;
         if (!FILE_SIZE_VALID_OR_INFINITY(limit))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
+                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
 
         r = bus_verify_polkit_async(
                         message,
-                        CAP_SYS_ADMIN,
                         "org.freedesktop.portable1.manage-images",
-                        NULL,
-                        false,
-                        UID_INVALID,
+                        /* details= */ NULL,
                         &m->polkit_registry,
                         error);
         if (r < 0)
@@ -342,7 +387,7 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
 
         r = btrfs_subvol_set_subtree_quota_limit("/var/lib/portables", 0, limit);
         if (r == -ENOTTY)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
         if (r < 0)
                 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
 
@@ -355,39 +400,154 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
         SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
         SD_BUS_PROPERTY("Profiles", "as", property_get_profiles, 0, 0),
-        SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("ListImages", NULL, "a(ssbtttso)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetImageMetadata", "sas", "saya{say}", method_get_image_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetImageState", "s", "s", method_get_image_state, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("AttachImage", "sassbs", "a(sss)", method_attach_image, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("DetachImage", "sb", "a(sss)", method_detach_image, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImage",
+                                SD_BUS_ARGS("s", image),
+                                SD_BUS_RESULT("o", object),
+                                method_get_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ListImages",
+                                SD_BUS_NO_ARGS,
+                                SD_BUS_RESULT("a(ssbtttso)", images),
+                                method_list_images,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease",
+                                SD_BUS_ARGS("s", image),
+                                SD_BUS_RESULT("a{ss}", os_release),
+                                method_get_image_os_release,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageMetadata",
+                                SD_BUS_ARGS("s", image,
+                                            "as", matches),
+                                SD_BUS_RESULT("s", image,
+                                              "ay", os_release,
+                                              "a{say}", units),
+                                method_get_image_metadata,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageMetadataWithExtensions",
+                                SD_BUS_ARGS("s", image,
+                                            "as", extensions,
+                                            "as", matches,
+                                            "t", flags),
+                                SD_BUS_RESULT("s", image,
+                                              "ay", os_release,
+                                              "a{say}", extensions,
+                                              "a{say}", units),
+                                method_get_image_metadata,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("GetImageState",
+                                SD_BUS_ARGS("s", image),
+                                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,
+                                            "s", profile,
+                                            "b", runtime,
+                                            "s", copy_mode),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_attach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("AttachImageWithExtensions",
+                                SD_BUS_ARGS("s", image,
+                                            "as", extensions,
+                                            "as", matches,
+                                            "s", profile,
+                                            "s", copy_mode,
+                                            "t", flags),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_attach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DetachImage",
+                                SD_BUS_ARGS("s", image,
+                                            "b", runtime),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_detach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("DetachImageWithExtensions",
+                                SD_BUS_ARGS("s", image,
+                                            "as", extensions,
+                                            "t", flags),
+                                SD_BUS_RESULT("a(sss)", changes),
+                                method_detach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReattachImage",
+                                SD_BUS_ARGS("s", image,
+                                            "as", matches,
+                                            "s", profile,
+                                            "b", runtime,
+                                            "s", copy_mode),
+                                SD_BUS_RESULT("a(sss)", changes_removed,
+                                              "a(sss)", changes_updated),
+                                method_reattach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("ReattachImageWithExtensions",
+                                SD_BUS_ARGS("s", image,
+                                            "as", extensions,
+                                            "as", matches,
+                                            "s", profile,
+                                            "s", copy_mode,
+                                            "t", flags),
+                                SD_BUS_RESULT("a(sss)", changes_removed,
+                                              "a(sss)", changes_updated),
+                                method_reattach_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("RemoveImage",
+                                SD_BUS_ARGS("s", image),
+                                SD_BUS_NO_RESULT,
+                                method_remove_image,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly",
+                                SD_BUS_ARGS("s", image,
+                                            "b", read_only),
+                                SD_BUS_NO_RESULT,
+                                method_mark_image_read_only,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetImageLimit",
+                                SD_BUS_ARGS("s", image,
+                                            "t", limit),
+                                SD_BUS_NO_RESULT,
+                                method_set_image_limit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetPoolLimit",
+                                SD_BUS_ARGS("t", limit),
+                                SD_BUS_NO_RESULT,
+                                method_set_pool_limit,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END
 };
 
-int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, size_t n_changes) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+const BusObjectImplementation manager_object = {
+        "/org/freedesktop/portable1",
+        "org.freedesktop.portable1.Manager",
+        .vtables = BUS_VTABLES(manager_vtable),
+        .children = BUS_IMPLEMENTATIONS(&image_object),
+};
+
+static int reply_portable_compose_message(sd_bus_message *reply, const PortableChange *changes, size_t n_changes) {
         size_t i;
         int r;
 
-        assert(m);
+        assert(reply);
         assert(changes || n_changes == 0);
 
-        r = sd_bus_message_new_method_return(m, &reply);
-        if (r < 0)
-                return r;
-
         r = sd_bus_message_open_container(reply, 'a', "(sss)");
         if (r < 0)
                 return r;
 
         for (i = 0; i < n_changes; i++) {
+                if (changes[i].type_or_errno < 0)
+                        continue;
+
                 r = sd_bus_message_append(reply, "(sss)",
-                                          portable_change_type_to_string(changes[i].type),
+                                          portable_change_type_to_string(changes[i].type_or_errno),
                                           changes[i].path,
                                           changes[i].source);
                 if (r < 0)
@@ -398,5 +558,49 @@ int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, siz
         if (r < 0)
                 return r;
 
+        return 0;
+}
+
+int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, size_t n_changes) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        int r;
+
+        assert(m);
+
+        r = sd_bus_message_new_method_return(m, &reply);
+        if (r < 0)
+                return r;
+
+        r = reply_portable_compose_message(reply, changes, n_changes);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
+}
+
+int reply_portable_changes_pair(
+                sd_bus_message *m,
+                const PortableChange *changes_first,
+                size_t n_changes_first,
+                const PortableChange *changes_second,
+                size_t n_changes_second) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        int r;
+
+        assert(m);
+
+        r = sd_bus_message_new_method_return(m, &reply);
+        if (r < 0)
+                return r;
+
+        r = reply_portable_compose_message(reply, changes_first, n_changes_first);
+        if (r < 0)
+                return r;
+
+        r = reply_portable_compose_message(reply, changes_second, n_changes_second);
+        if (r < 0)
+                return r;
+
         return sd_bus_send(NULL, reply, NULL);
 }