]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
importd: add command to list downloaded images
authorLennart Poettering <lennart@poettering.net>
Tue, 27 Feb 2024 10:08:49 +0000 (11:08 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 1 Mar 2024 21:25:42 +0000 (22:25 +0100)
It's a bit weird we allow importing/pulling/exporting images, but we
have no scheme for showing what#s already downloaded. Hence let's add
this, it's easy to add after all.

src/import/importctl.c
src/import/importd.c
src/import/org.freedesktop.import1.conf

index 7ada0e51df0be65adf74122e895b525b7ebbba47..5f6f9261358c44c256f1a841db0fde4a96fd8c3d 100644 (file)
@@ -884,6 +884,98 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int list_images(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(table_unrefp) Table *t = NULL;
+        sd_bus *bus = ASSERT_PTR(userdata);
+        int r;
+
+        pager_open(arg_pager_flags);
+
+        r = bus_call_method(bus, bus_import_mgr, "ListImages", &error, &reply, "st", image_class_to_string(arg_image_class), UINT64_C(0));
+        if (r < 0)
+                return log_error_errno(r, "Could not list images: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, 'a', "(ssssbtttttt)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        t = table_new("class", "name", "type", "path", "ro", "crtime", "mtime", "usage", "usage-exclusive", "limit", "limit-exclusive");
+        if (!t)
+                return log_oom();
+
+        (void) table_set_sort(t, (size_t) 0, (size_t) 1);
+        table_set_ersatz_string(t, TABLE_ERSATZ_DASH);
+
+        /* Hide the exclusive columns for now */
+        (void) table_hide_column_from_display(t, 8);
+        (void) table_hide_column_from_display(t, 10);
+
+        for (;;) {
+                uint64_t crtime, mtime, usage, usage_exclusive, limit, limit_exclusive;
+                const char *class, *name, *type, *path;
+                int read_only;
+
+                r = sd_bus_message_read(reply, "(ssssbtttttt)", &class, &name, &type, &path, &read_only, &crtime, &mtime, &usage, &usage_exclusive, &limit, &limit_exclusive);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+                if (r == 0)
+                        break;
+
+                r = table_add_many(
+                                t,
+                                TABLE_STRING, class,
+                                TABLE_STRING, name,
+                                TABLE_STRING, type,
+                                TABLE_PATH, path);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
+                        r = table_add_many(
+                                        t,
+                                        TABLE_STRING, read_only ? "ro" : "rw",
+                                        TABLE_SET_COLOR, read_only ? ANSI_HIGHLIGHT_RED : ANSI_HIGHLIGHT_GREEN);
+                else
+                        r = table_add_many(
+                                        t,
+                                        TABLE_BOOLEAN, read_only);
+                if (r < 0)
+                        return table_log_add_error(r);
+
+                r = table_add_many(
+                                t,
+                                TABLE_TIMESTAMP, crtime,
+                                TABLE_TIMESTAMP, mtime,
+                                TABLE_SIZE, usage,
+                                TABLE_SIZE, usage_exclusive,
+                                TABLE_SIZE, limit,
+                                TABLE_SIZE, limit_exclusive);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        if (!table_isempty(t)) {
+                r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to output table: %m");
+        }
+
+        if (arg_legend) {
+                if (!table_isempty(t))
+                        printf("\n%zu images listed.\n", table_get_rows(t) - 1);
+                else
+                        printf("No images.\n");
+        }
+
+        return 0;
+}
+
 static int help(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -906,6 +998,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  export-raw NAME [FILE]      Export a RAW container or VM image locally\n"
                "  list-transfers              Show list of transfers in progress\n"
                "  cancel-transfer [ID...]     Cancel a transfer\n"
+               "  list-images                 Show list of installed images\n"
                "\n%3$sOptions:%4$s\n"
                "  -h --help                   Show this help\n"
                "     --version                Show package version\n"
@@ -1122,6 +1215,7 @@ static int importctl_main(int argc, char *argv[], sd_bus *bus) {
                 { "pull-raw",        2,        3,        0,            pull_raw          },
                 { "list-transfers",  VERB_ANY, 1,        VERB_DEFAULT, list_transfers    },
                 { "cancel-transfer", 2,        VERB_ANY, 0,            cancel_transfer   },
+                { "list-images",     VERB_ANY, 1,        0,            list_images       },
                 {}
         };
 
index 36d327bcf64639529b780d15052915b9a401c4e1..4bba46984ae0211329a9904fccb975b89e5939cd 100644 (file)
@@ -1296,6 +1296,86 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
         return sd_bus_reply_method_return(msg, NULL);
 }
 
+static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        ImageClass class = _IMAGE_CLASS_INVALID;
+        int r;
+
+        assert(msg);
+
+        const char *sclass;
+        uint64_t flags;
+
+        r = sd_bus_message_read(msg, "st", &sclass, &flags);
+        if (r < 0)
+                return r;
+
+        if (!isempty(sclass)) {
+                class = image_class_from_string(sclass);
+                if (class < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Image class '%s' not known", sclass);
+        }
+
+        if (flags != 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Flags 0x%" PRIx64 " invalid", flags);
+
+        r = sd_bus_message_new_method_return(msg, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(ssssbtttttt)");
+        if (r < 0)
+                return r;
+
+        for (ImageClass c = class < 0 ? 0 : class;
+             class < 0 ? (c < _IMAGE_CLASS_MAX) : (c == class);
+             c++) {
+
+                _cleanup_(hashmap_freep) Hashmap *h = NULL;
+
+                h = hashmap_new(&image_hash_ops);
+                if (!h)
+                        return -ENOMEM;
+
+                r = image_discover(c, /* root= */ NULL, h);
+                if (r < 0) {
+                        if (class >= 0)
+                                return r;
+
+                        log_warning_errno(r, "Failed to discover images of type %s: %m", image_class_to_string(c));
+                        continue;
+                }
+
+                Image *i;
+                HASHMAP_FOREACH(i, h) {
+                        r = sd_bus_message_append(
+                                        reply,
+                                        "(ssssbtttttt)",
+                                        image_class_to_string(i->class),
+                                        i->name,
+                                        image_type_to_string(i->type),
+                                        i->path,
+                                        i->read_only,
+                                        i->crtime,
+                                        i->mtime,
+                                        i->usage,
+                                        i->usage_exclusive,
+                                        i->limit,
+                                        i->limit_exclusive);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
+}
+
 static int property_get_progress(
                 sd_bus *bus,
                 const char *path,
@@ -1592,6 +1672,14 @@ static const sd_bus_vtable manager_vtable[] = {
                                  NULL,,
                                  method_cancel_transfer,
                                  SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_NAMES("ListImages",
+                                 "st",
+                                 SD_BUS_PARAM(class)
+                                 SD_BUS_PARAM(flags),
+                                 "a(ssssbtttttt)",
+                                 SD_BUS_PARAM(images),
+                                 method_list_images,
+                                 SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
                                  "uo",
index f775aa061c1d548757e8af1883eba85b3b9f77bc..f99ec56c79750fe04006d88d12d93b744f24a691 100644 (file)
                        send_interface="org.freedesktop.import1.Transfer"
                        send_member="Cancel"/>
 
+                <allow send_destination="org.freedesktop.import1"
+                       send_interface="org.freedesktop.import1.Transfer"
+                       send_member="ListImages"/>
+
                 <allow receive_sender="org.freedesktop.import1"/>
         </policy>