mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
importd: add command to list downloaded images
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.
This commit is contained in:
parent
5a985dd05a
commit
5b7bfe0637
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -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",
|
||||
|
@ -110,6 +110,10 @@
|
||||
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>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user