diff --git a/man/org.freedesktop.portable1.xml b/man/org.freedesktop.portable1.xml index 4842885c0c..10f7c21367 100644 --- a/man/org.freedesktop.portable1.xml +++ b/man/org.freedesktop.portable1.xml @@ -54,6 +54,7 @@ node /org/freedesktop/portable1 { in t flags, out s image, out ay os_release, + out a{say} extensions, out a{say} units); GetImageState(in s image, out s state); @@ -189,19 +190,12 @@ node /org/freedesktop/portable1 { and a list of portable units contained in the image, in the form of a string (unit name) and an array of bytes with the content. - GetImageMetadataWithExtensions() retrieves metadata associated with an image. - This method is a superset of GetImageMetadata() with the addition of - a list of extensions as input parameter, which were overlaid on top of the main - image via AttachImageWithExtensions(). - The flag parameter can be used to request that, before the units, the path of - each extension and an array of bytes with the content of the respective extension-release file - are sent. One such structure will be sent for each extension named in the input arguments. The - flag value to enable this functionality is defined as follows: - - -#define PORTABLE_INSPECT_EXTENSION_RELEASES (UINT64_C(1) << 1) - - + GetImageMetadataWithExtensions() retrieves metadata associated with an + image. This method is a superset of GetImageMetadata() with the addition of a list + of extensions as input parameter, which were overlaid on top of the main image via + AttachImageWithExtensions(). The path of each extension and an array of bytes with + the content of the respective extension-release file are returned, one such structure for each + extension named in the input arguments. GetImageState() retrieves the image state as one of the following strings: @@ -352,6 +346,7 @@ node /org/freedesktop/portable1 { in t flags, out s image, out ay os_release, + out a{say} extensions, out a{say} units); GetState(out s state); GetStateWithExtensions(in as extensions, diff --git a/src/portable/portable.h b/src/portable/portable.h index 62e1cb7032..c6061cc589 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -21,14 +21,13 @@ typedef struct PortableMetadata { #define PORTABLE_METADATA_IS_UNIT(m) (!IN_SET((m)->name[0], 0, '/')) typedef enum PortableFlags { - PORTABLE_RUNTIME = 1 << 0, - PORTABLE_INSPECT_EXTENSION_RELEASES = 1 << 1, /* Public API via DBUS, do not change */ - PORTABLE_PREFER_COPY = 1 << 2, - PORTABLE_PREFER_SYMLINK = 1 << 3, - PORTABLE_REATTACH = 1 << 4, - _PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME | PORTABLE_INSPECT_EXTENSION_RELEASES, + PORTABLE_RUNTIME = 1 << 0, /* Public API via DBUS, do not change */ + PORTABLE_PREFER_COPY = 1 << 1, + PORTABLE_PREFER_SYMLINK = 1 << 2, + PORTABLE_REATTACH = 1 << 3, + _PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME, _PORTABLE_TYPE_MAX, - _PORTABLE_TYPE_INVALID = -EINVAL, + _PORTABLE_TYPE_INVALID = -EINVAL, } PortableFlags; /* This enum is anonymous, since we usually store it in an 'int', as we overload it with negative errno diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index 7e222870bc..46e60310fc 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -260,7 +260,7 @@ static int maybe_reload(sd_bus **bus) { static int get_image_metadata(sd_bus *bus, const char *image, char **matches, sd_bus_message **reply) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - PortableFlags flags = PORTABLE_INSPECT_EXTENSION_RELEASES; + uint64_t flags = 0; const char *method; int r; @@ -362,71 +362,78 @@ static int inspect_image(int argc, char *argv[], void *userdata) { strna(pretty_os)); } - r = sd_bus_message_enter_container(reply, 'a', "{say}"); - if (r < 0) - return bus_log_parse_error(r); + if (!strv_isempty(arg_extension_images)) { + /* If we specified any extensions, we'll first get back exactly the paths (and + * extension-release content) for each one of the arguments. */ - /* If we specified any extensions, we'll first get back exactly the - * paths (and extension-release content) for each one of the arguments. */ - for (size_t i = 0; i < strv_length(arg_extension_images); ++i) { - const char *name; - - r = sd_bus_message_enter_container(reply, 'e', "say"); - if (r < 0) - return bus_log_parse_error(r); - if (r == 0) - break; - - r = sd_bus_message_read(reply, "s", &name); + r = sd_bus_message_enter_container(reply, 'a', "{say}"); if (r < 0) return bus_log_parse_error(r); - r = sd_bus_message_read_array(reply, 'y', &data, &sz); - if (r < 0) - return bus_log_parse_error(r); + for (size_t i = 0; i < strv_length(arg_extension_images); ++i) { + const char *name; - if (arg_cat) { - if (nl) - fputc('\n', stdout); - - printf("%s-- Extension Release: %s --%s\n", ansi_highlight(), name, ansi_normal()); - fwrite(data, sz, 1, stdout); - fflush(stdout); - nl = true; - } else { - _cleanup_free_ char *pretty_portable = NULL, *pretty_os = NULL, *sysext_level = NULL, - *id = NULL, *version_id = NULL, *sysext_scope = NULL, *portable_prefixes = NULL; - _cleanup_fclose_ FILE *f = NULL; - - f = fmemopen_unlocked((void*) data, sz, "re"); - if (!f) - return log_error_errno(errno, "Failed to open extension-release buffer: %m"); - - r = parse_env_file(f, name, - "ID", &id, - "VERSION_ID", &version_id, - "SYSEXT_SCOPE", &sysext_scope, - "SYSEXT_LEVEL", &sysext_level, - "PORTABLE_PRETTY_NAME", &pretty_portable, - "PORTABLE_PREFIXES", &portable_prefixes, - "PRETTY_NAME", &pretty_os); + r = sd_bus_message_enter_container(reply, 'e', "say"); if (r < 0) - return log_error_errno(r, "Failed to parse extension release from '%s': %m", name); + return bus_log_parse_error(r); + if (r == 0) + break; - printf("Extension:\n\t%s\n" - "\tExtension Scope:\n\t\t%s\n" - "\tExtension Compatibility Level:\n\t\t%s\n" - "\tPortable Service:\n\t\t%s\n" - "\tPortable Prefixes:\n\t\t%s\n" - "\tOperating System:\n\t\t%s (%s %s)\n", - name, - strna(sysext_scope), - strna(sysext_level), - strna(pretty_portable), - strna(portable_prefixes), - strna(pretty_os), - strna(id), - strna(version_id)); + r = sd_bus_message_read(reply, "s", &name); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read_array(reply, 'y', &data, &sz); + if (r < 0) + return bus_log_parse_error(r); + + if (arg_cat) { + if (nl) + fputc('\n', stdout); + + printf("%s-- Extension Release: %s --%s\n", ansi_highlight(), name, ansi_normal()); + fwrite(data, sz, 1, stdout); + fflush(stdout); + nl = true; + } else { + _cleanup_free_ char *pretty_portable = NULL, *pretty_os = NULL, *sysext_level = NULL, + *id = NULL, *version_id = NULL, *sysext_scope = NULL, *portable_prefixes = NULL; + _cleanup_fclose_ FILE *f = NULL; + + f = fmemopen_unlocked((void*) data, sz, "re"); + if (!f) + return log_error_errno(errno, "Failed to open extension-release buffer: %m"); + + r = parse_env_file(f, name, + "ID", &id, + "VERSION_ID", &version_id, + "SYSEXT_SCOPE", &sysext_scope, + "SYSEXT_LEVEL", &sysext_level, + "PORTABLE_PRETTY_NAME", &pretty_portable, + "PORTABLE_PREFIXES", &portable_prefixes, + "PRETTY_NAME", &pretty_os); + if (r < 0) + return log_error_errno(r, "Failed to parse extension release from '%s': %m", name); + + printf("Extension:\n\t%s\n" + "\tExtension Scope:\n\t\t%s\n" + "\tExtension Compatibility Level:\n\t\t%s\n" + "\tPortable Service:\n\t\t%s\n" + "\tPortable Prefixes:\n\t\t%s\n" + "\tOperating System:\n\t\t%s (%s %s)\n", + name, + strna(sysext_scope), + strna(sysext_level), + strna(pretty_portable), + strna(portable_prefixes), + strna(pretty_os), + strna(id), + strna(version_id)); + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); } r = sd_bus_message_exit_container(reply); @@ -434,6 +441,10 @@ static int inspect_image(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); } + r = sd_bus_message_enter_container(reply, 'a', "{say}"); + if (r < 0) + return bus_log_parse_error(r); + for (;;) { const char *name; @@ -764,18 +775,17 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) { if (r < 0) return bus_log_parse_error(r); - r = sd_bus_message_enter_container(reply, 'a', "{say}"); - if (r < 0) - return bus_log_parse_error(r); - - /* If we specified any extensions, we'll first get back exactly the - * paths (and extension-release content) for each one of the arguments. */ - for (size_t i = 0; i < strv_length(arg_extension_images); ++i) { - r = sd_bus_message_skip(reply, "{say}"); + /* If we specified any extensions, we'll first an array of extension-release metadata. */ + if (!strv_isempty(arg_extension_images)) { + r = sd_bus_message_skip(reply, "a{say}"); if (r < 0) return bus_log_parse_error(r); } + r = sd_bus_message_enter_container(reply, 'a', "{say}"); + if (r < 0) + return bus_log_parse_error(r); + for (;;) { const char *name; diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c index 214fdb5b30..8f8a8fbdcf 100644 --- a/src/portable/portabled-bus.c +++ b/src/portable/portabled-bus.c @@ -441,6 +441,7 @@ const sd_bus_vtable manager_vtable[] = { "t", flags), SD_BUS_RESULT("s", image, "ay", os_release, + "a{say}", extensions, "a{say}", units), method_get_image_metadata, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index 43d69d30e1..3fe0eca4c5 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -108,7 +108,6 @@ int bus_image_common_get_metadata( _cleanup_hashmap_free_ Hashmap *unit_files = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ PortableMetadata **sorted = NULL; - PortableFlags flags = 0; int r; assert(name_or_path || image); @@ -119,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; @@ -130,8 +131,7 @@ 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); @@ -142,7 +142,6 @@ int bus_image_common_get_metadata( return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Invalid 'flags' parameter '%" PRIu64 "'", input_flags); - flags |= input_flags; } r = bus_image_acquire(m, @@ -186,16 +185,16 @@ int bus_image_common_get_metadata( if (r < 0) return r; - r = sd_bus_message_open_container(reply, 'a', "{say}"); - 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 (FLAGS_SET(flags, PORTABLE_INSPECT_EXTENSION_RELEASES)) { + 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"); @@ -214,8 +213,16 @@ int bus_image_common_get_metadata( 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 (size_t i = 0; i < hashmap_size(unit_files); i++) { r = sd_bus_message_open_container(reply, 'e', "say"); @@ -888,6 +895,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),