-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <sys/stat.h>
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-label.h"
+#include "bus-object.h"
#include "bus-polkit.h"
#include "bus-util.h"
+#include "discover-image.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
-#include "machine-image.h"
#include "missing_capability.h"
+#include "os-util.h"
#include "portable.h"
#include "portabled-bus.h"
#include "portabled-image-bus.h"
static int append_fd(sd_bus_message *m, PortableMetadata *d) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *buf = NULL;
- size_t n;
+ size_t n = 0;
int r;
assert(m);
- assert(d);
- assert(d->fd >= 0);
- f = take_fdopen(&d->fd, "r");
- if (!f)
- return -errno;
+ if (d) {
+ assert(d->fd >= 0);
- r = read_full_stream(f, &buf, &n);
- if (r < 0)
- return r;
+ f = take_fdopen(&d->fd, "r");
+ if (!f)
+ return -errno;
+
+ r = read_full_stream(f, &buf, &n);
+ if (r < 0)
+ return r;
+ }
return sd_bus_message_append_array(m, 'y', buf, n);
}
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;
- _cleanup_strv_free_ char **matches = NULL;
- size_t i;
int r;
assert(name_or_path || image);
m = image->userdata;
}
+ 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;
+ }
+
r = sd_bus_message_read_strv(message, &matches);
if (r < 0)
return r;
+ if (have_exti) {
+ uint64_t input_flags = 0;
+
+ 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);
+ }
+
r = bus_image_acquire(m,
message,
name_or_path,
r = portable_extract(
image->path,
matches,
+ extension_images,
&os_release,
+ &extension_releases,
&unit_files,
+ NULL,
error);
if (r < 0)
return r;
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)
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);
Image *image,
sd_bus_error *error) {
- _cleanup_strv_free_ char **matches = NULL;
+ _cleanup_strv_free_ char **matches = NULL, **extension_images = NULL;
PortableChange *changes = NULL;
PortableFlags flags = 0;
const char *profile, *copy_mode;
size_t n_changes = 0;
- int runtime, r;
+ int r;
assert(message);
assert(name_or_path || image);
m = image->userdata;
}
+ if (sd_bus_message_is_method_call(message, NULL, "AttachImageWithExtensions") ||
+ sd_bus_message_is_method_call(message, NULL, "AttachWithExtensions")) {
+ r = sd_bus_message_read_strv(message, &extension_images);
+ if (r < 0)
+ return r;
+ }
+
r = sd_bus_message_read_strv(message, &matches);
if (r < 0)
return r;
- r = sd_bus_message_read(message, "sbs", &profile, &runtime, ©_mode);
+ r = sd_bus_message_read(message, "s", &profile);
if (r < 0)
return r;
+ if (sd_bus_message_is_method_call(message, NULL, "AttachImageWithExtensions") ||
+ sd_bus_message_is_method_call(message, NULL, "AttachWithExtensions")) {
+ uint64_t input_flags = 0;
+
+ r = sd_bus_message_read(message, "st", ©_mode, &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, "bs", &runtime, ©_mode);
+ if (r < 0)
+ return r;
+
+ if (runtime)
+ flags |= PORTABLE_RUNTIME;
+ }
+
if (streq(copy_mode, "symlink"))
flags |= PORTABLE_PREFER_SYMLINK;
else if (streq(copy_mode, "copy"))
else if (!isempty(copy_mode))
return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode);
- if (runtime)
- flags |= PORTABLE_RUNTIME;
-
r = bus_image_acquire(m,
message,
name_or_path,
image->path,
matches,
profile,
+ extension_images,
flags,
&changes,
&n_changes,
void *userdata,
sd_bus_error *error) {
+ _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, runtime;
+ int r;
assert(message);
- assert(image);
- assert(m);
- r = sd_bus_message_read(message, "b", &runtime);
- if (r < 0)
- return r;
+ if (sd_bus_message_is_method_call(message, NULL, "DetachWithExtensions")) {
+ r = sd_bus_message_read_strv(message, &extension_images);
+ if (r < 0)
+ return r;
+ }
+
+ if (sd_bus_message_is_method_call(message, NULL, "DetachWithExtensions")) {
+ uint64_t input_flags = 0;
+
+ 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,
r = portable_detach(
sd_bus_message_get_bus(message),
image->path,
- runtime ? PORTABLE_RUNTIME : 0,
+ extension_images,
+ flags,
&changes,
&n_changes,
error);
}
if (m->n_operations >= OPERATIONS_MAX)
- return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+ return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
r = bus_image_acquire(m,
message,
r = portable_get_state(
sd_bus_message_get_bus(message),
image->path,
+ NULL,
0,
&state,
error);
return bus_image_common_remove(NULL, message, NULL, userdata, error);
}
+/* Given two PortableChange arrays, return a new array that has all elements of the first that are
+ * not also present in the second, comparing the basename of the path values. */
+static int normalize_portable_changes(
+ const PortableChange *changes_attached,
+ size_t n_changes_attached,
+ const PortableChange *changes_detached,
+ size_t n_changes_detached,
+ PortableChange **ret_changes,
+ size_t *ret_n_changes) {
+
+ PortableChange *changes = NULL;
+ size_t n_changes = 0;
+ int r = 0;
+
+ assert(ret_n_changes);
+ assert(ret_changes);
+
+ if (n_changes_detached == 0)
+ return 0; /* Nothing to do */
+
+ changes = new0(PortableChange, n_changes_attached + n_changes_detached);
+ if (!changes)
+ return -ENOMEM;
+
+ /* Corner case: only detached, nothing attached */
+ if (n_changes_attached == 0) {
+ memcpy(changes, changes_detached, sizeof(PortableChange) * n_changes_detached);
+ *ret_changes = TAKE_PTR(changes);
+ *ret_n_changes = n_changes_detached;
+
+ return 0;
+ }
+
+ for (size_t i = 0; i < n_changes_detached; ++i) {
+ bool found = false;
+
+ for (size_t j = 0; j < n_changes_attached; ++j)
+ if (streq(basename(changes_detached[i].path), basename(changes_attached[j].path))) {
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ _cleanup_free_ char *path = NULL, *source = NULL;
+
+ path = strdup(changes_detached[i].path);
+ if (!path) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ if (changes_detached[i].source) {
+ source = strdup(changes_detached[i].source);
+ if (!source) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ changes[n_changes++] = (PortableChange) {
+ .type_or_errno = changes_detached[i].type_or_errno,
+ .path = TAKE_PTR(path),
+ .source = TAKE_PTR(source),
+ };
+ }
+ }
+
+ *ret_n_changes = n_changes;
+ *ret_changes = TAKE_PTR(changes);
+
+ return 0;
+
+fail:
+ portable_changes_free(changes, n_changes);
+ return r;
+}
+
+int bus_image_common_reattach(
+ Manager *m,
+ sd_bus_message *message,
+ const char *name_or_path,
+ Image *image,
+ sd_bus_error *error) {
+
+ PortableChange *changes_detached = NULL, *changes_attached = NULL, *changes_gone = NULL;
+ size_t n_changes_detached = 0, n_changes_attached = 0, n_changes_gone = 0;
+ _cleanup_strv_free_ char **matches = NULL, **extension_images = NULL;
+ PortableFlags flags = PORTABLE_REATTACH;
+ const char *profile, *copy_mode;
+ int r;
+
+ assert(message);
+ assert(name_or_path || image);
+
+ if (!m) {
+ assert(image);
+ m = image->userdata;
+ }
+
+ if (sd_bus_message_is_method_call(message, NULL, "ReattachImageWithExtensions") ||
+ sd_bus_message_is_method_call(message, NULL, "ReattachWithExtensions")) {
+ r = sd_bus_message_read_strv(message, &extension_images);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_read_strv(message, &matches);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read(message, "s", &profile);
+ if (r < 0)
+ return r;
+
+ if (sd_bus_message_is_method_call(message, NULL, "ReattachImageWithExtensions") ||
+ sd_bus_message_is_method_call(message, NULL, "ReattachWithExtensions")) {
+ uint64_t input_flags = 0;
+
+ r = sd_bus_message_read(message, "st", ©_mode, &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, "bs", &runtime, ©_mode);
+ if (r < 0)
+ return r;
+
+ if (runtime)
+ flags |= PORTABLE_RUNTIME;
+ }
+
+ if (streq(copy_mode, "symlink"))
+ flags |= PORTABLE_PREFER_SYMLINK;
+ else if (streq(copy_mode, "copy"))
+ flags |= PORTABLE_PREFER_COPY;
+ else if (!isempty(copy_mode))
+ return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode);
+
+ r = bus_image_acquire(m,
+ message,
+ name_or_path,
+ image,
+ BUS_IMAGE_AUTHENTICATE_ALL,
+ "org.freedesktop.portable1.attach-images",
+ &image,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0) /* Will call us back */
+ return 1;
+
+ r = portable_detach(
+ sd_bus_message_get_bus(message),
+ image->path,
+ extension_images,
+ flags,
+ &changes_detached,
+ &n_changes_detached,
+ error);
+ if (r < 0)
+ goto finish;
+
+ r = portable_attach(
+ sd_bus_message_get_bus(message),
+ image->path,
+ matches,
+ profile,
+ extension_images,
+ flags,
+ &changes_attached,
+ &n_changes_attached,
+ error);
+ if (r < 0)
+ goto finish;
+
+ /* We want to return the list of units really removed by the detach,
+ * and not added again by the attach */
+ r = normalize_portable_changes(changes_attached, n_changes_attached,
+ changes_detached, n_changes_detached,
+ &changes_gone, &n_changes_gone);
+ if (r < 0)
+ goto finish;
+
+ /* First, return the units that are gone (so that the caller can stop them)
+ * Then, return the units that are changed/added (so that the caller can
+ * start/restart/enable them) */
+ r = reply_portable_changes_pair(message,
+ changes_gone, n_changes_gone,
+ changes_attached, n_changes_attached);
+ if (r < 0)
+ goto finish;
+
+finish:
+ portable_changes_free(changes_detached, n_changes_detached);
+ portable_changes_free(changes_attached, n_changes_attached);
+ portable_changes_free(changes_gone, n_changes_gone);
+ return r;
+}
+
+static int bus_image_method_reattach(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_image_common_reattach(NULL, message, NULL, userdata, error);
+}
+
int bus_image_common_mark_read_only(
Manager *m,
sd_bus_message *message,
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_image_acquire(m,
message,
SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
- SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetMetadata", "as", "saya{say}", bus_image_method_get_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetState", NULL, "s", bus_image_method_get_state, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Attach", "assbs", "a(sss)", bus_image_method_attach, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Detach", "b", "a(sss)", bus_image_method_detach, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
+ SD_BUS_NO_ARGS,
+ SD_BUS_RESULT("a{ss}", os_release),
+ bus_image_method_get_os_release,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("GetMetadata",
+ SD_BUS_ARGS("as", matches),
+ SD_BUS_RESULT("s", image,
+ "ay", os_release,
+ "a{say}", units),
+ bus_image_method_get_metadata,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("GetMetadataWithExtensions",
+ SD_BUS_ARGS("as", extensions,
+ "as", matches,
+ "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),
+ SD_BUS_METHOD_WITH_ARGS("GetState",
+ SD_BUS_NO_ARGS,
+ 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,
+ "b", runtime,
+ "s", copy_mode),
+ SD_BUS_RESULT("a(sss)", changes),
+ bus_image_method_attach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("AttachWithExtensions",
+ SD_BUS_ARGS("as", extensions,
+ "as", matches,
+ "s", profile,
+ "s", copy_mode,
+ "t", flags),
+ SD_BUS_RESULT("a(sss)", changes),
+ bus_image_method_attach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("Detach",
+ SD_BUS_ARGS("b", runtime),
+ SD_BUS_RESULT("a(sss)", changes),
+ bus_image_method_detach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("DetachWithExtensions",
+ SD_BUS_ARGS("as", extensions,
+ "t", flags),
+ SD_BUS_RESULT("a(sss)", changes),
+ bus_image_method_detach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("Reattach",
+ SD_BUS_ARGS("as", matches,
+ "s", profile,
+ "b", runtime,
+ "s", copy_mode),
+ SD_BUS_RESULT("a(sss)", changes_removed,
+ "a(sss)", changes_updated),
+ bus_image_method_reattach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("ReattacheWithExtensions",
+ SD_BUS_ARGS("as", extensions,
+ "as", matches,
+ "s", profile,
+ "s", copy_mode,
+ "t", flags),
+ SD_BUS_RESULT("a(sss)", changes_removed,
+ "a(sss)", changes_updated),
+ bus_image_method_reattach,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("Remove",
+ SD_BUS_NO_ARGS,
+ SD_BUS_NO_RESULT,
+ bus_image_method_remove,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("MarkReadOnly",
+ SD_BUS_ARGS("b", read_only),
+ SD_BUS_NO_RESULT,
+ bus_image_method_mark_read_only,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD_WITH_ARGS("SetLimit",
+ SD_BUS_ARGS("t", limit),
+ SD_BUS_NO_RESULT,
+ bus_image_method_set_limit,
+ SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
if (image_name_is_valid(name_or_path)) {
/* If it's a short name, let's search for it */
- r = image_find(IMAGE_PORTABLE, name_or_path, &loaded);
+ 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(
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)
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)
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;
if (r < 0)
return r;
- if (!GREEDY_REALLOC(l, n_allocated, n+2)) {
+ if (!GREEDY_REALLOC(l, n+2)) {
free(p);
return -ENOMEM;
}
return 1;
}
+
+const BusObjectImplementation image_object = {
+ "/org/freedesktop/portable1/image",
+ "org.freedesktop.portable1.Image",
+ .fallback_vtables = BUS_FALLBACK_VTABLES({image_vtable, bus_image_object_find}),
+ .node_enumerator = bus_image_node_enumerator,
+};