Note that this is not finished yet, but allows to test the image detection patches: Prepare few images: qemu-img create -f qcow2 /tmp/base.qcow2 10M qemu-img create -f qcow2 -b /tmp/base.qcow2 /tmp/overlay1-noformat.qcow2 qemu-img create -f qcow2 -F qcow2 -b /tmp/base.qcow2 /tmp/overlay1-format.qcow2 qemu-img create -f qcow2 -F qcow2 -b /tmp/overlay1-format.qcow2 /tmp/overlay2-format.qcow2 qemu-img create -f qcow2 -b /tmp/overlay1-noformat.qcow2 /tmp/overlay2-noformat.qcow2 qemu-img creage -f qcow2 -b nbd://example/asdf /tmp/nbd-noformat.qcow2 10M (Note that the last one prints error, but that's expected) Probe images: $ ./tests/qemublockprobe -f qcow2 -p /tmp/overlay1-noformat.qcow2 type: file (1) path: /tmp/overlay1-noformat.qcow2 format: qcow2 (14) protocol: none' (0) backing store raw: /tmp/base.qcow2 type: file (1) path: /tmp/base.qcow2 format: qcow2 (14) protocol: none' (0) type: none (0) path: (null) format: none (0) protocol: none' (0) $ ./tests/qemublockprobe -f qcow2 -p /tmp/overlay2-format.qcow2 type: file (1) path: /tmp/overlay2-format.qcow2 format: qcow2 (14) protocol: none' (0) backing store raw: /tmp/overlay1-format.qcow2 type: file (1) path: /tmp/overlay1-format.qcow2 format: qcow2 (14) protocol: none' (0) backing store raw: /tmp/base.qcow2 type: file (1) path: /tmp/base.qcow2 format: qcow2 (14) protocol: none' (0) type: none (0) path: (null) format: none (0) protocol: none' (0) $ ./tests/qemublockprobe -f qcow2 -p /tmp/overlay2-noformat.qcow2 /home/pipo/build/libvirt/gcc/tests/.libs/lt-qemublockprobe: libvirt error: Requested operation is not valid: format of backing image '/tmp/overlay1-noformat.qcow2' of image '/tmp/overlay2-noformat.qcow2' was not specified in the image metadata (See https://libvirt.org/kbase/backing_chains.html for troubleshooting) $ ./tests/qemublockprobe -f qcow2 -p /tmp/nbd-noformat.qcow2 /home/pipo/build/libvirt/gcc/tests/.libs/lt-qemublockprobe: libvirt error: Requested operation is not valid: format of backing image 'nbd://example/asdf' of image '/tmp/nbd-noformat.qcow2' was not specified in the image metadata (See https://libvirt.org/kbase/backing_chains.html for troubleshooting) --- tests/Makefile.am | 13 ++++- tests/qemublockprobe.c | 130 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 tests/qemublockprobe.c diff --git a/tests/Makefile.am b/tests/Makefile.am index ed5255b62d..a47c7eda22 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -291,7 +291,9 @@ test_programs += qemuxml2argvtest qemuxml2xmltest \ qemufirmwaretest \ qemuvhostusertest \ $(NULL) -test_helpers += qemucapsprobe +test_helpers += qemucapsprobe \ + qemublockprobe \ + $(NULL) test_libraries += libqemumonitortestutils.la \ libqemutestdriver.la \ libqemuxml2argvmock.la \ @@ -652,6 +654,14 @@ qemublocktest_LDADD = \ $(qemu_LDADDS) \ $(NULL) +qemublockprobe_SOURCES = \ + qemublockprobe.c \ + $(NULL) +qemublockprobe_LDADD = \ + ../src/libvirt.la \ + $(qemu_LDADDS) \ + $(NULL) + qemudomaincheckpointxml2xmltest_SOURCES = \ qemudomaincheckpointxml2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h @@ -707,6 +717,7 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c \ qemucaps2xmltest.c qemucommandutiltest.c \ qemumemlocktest.c qemucpumock.c testutilshostcpus.h \ qemublocktest.c \ + qemublockprobe.c \ qemumigparamstest.c \ qemusecuritytest.c qemusecuritytest.h \ qemusecuritymock.c \ diff --git a/tests/qemublockprobe.c b/tests/qemublockprobe.c new file mode 100644 index 0000000000..0dbc31028c --- /dev/null +++ b/tests/qemublockprobe.c @@ -0,0 +1,130 @@ +/* + * qemublockprobe.c: image backing chain prober + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdbool.h> + +#include "util/virfile.h" +#include "util/virlog.h" +#include "util/virstoragefile.h" + +#include "virgettext.h" + +#define VIR_FROM_THIS VIR_FROM_QEMU + + +static void +print_source(virStorageSourcePtr src) +{ + size_t i; + + g_print("type: %s (%d)\n", virStorageTypeToString(src->type), src->type); + g_print("path: %s\n", src->path); + g_print("format: %s (%d)\n", virStorageFileFormatTypeToString(src->format), src->format); + g_print("protocol: %s' (%d)\n", virStorageNetProtocolTypeToString(src->protocol), src->protocol); + for (i = 0; i < src->nhosts; i++) { + virStorageNetHostDefPtr h = src->hosts + i; + + g_print("host %zu: name: '%s', port: '%u', transport: '%s'(%d), socket: '%s'\n", + i, h->name, h->port, virStorageNetHostTransportTypeToString(h->transport), + h->transport, h->socket); + } + if (src->sliceStorage) + g_print("slice type: storage, offset: %llu, size: %llu\n", + src->sliceStorage->offset, src->sliceStorage->size); + if (src->backingStoreRaw) + g_print("backing store raw: %s\n", src->backingStoreRaw); + if (src->externalDataStoreRaw) + g_print("external store raw: %s\n", src->externalDataStoreRaw); + if (src->relPath) + g_print("relative path: %s\n", src->relPath); + + g_print("\n"); +} + + +int main(int argc, char **argv) +{ + g_autofree char *path = NULL; + g_autofree char *format = NULL; + g_autoptr(GError) error = NULL; + bool verbose = false; + g_autoptr(virStorageSource) src = NULL; + GOptionContext *ctx; + virStorageSourcePtr n; + int ret = 1; + + GOptionEntry entries[] = { + { "path", 'p', 0, G_OPTION_ARG_STRING, &path, "path to image", "DIR" }, + { "format", 'f', 0, G_OPTION_ARG_STRING, &format, "format of image", "DIR" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", NULL }, + { 0 } + }; + + + ctx = g_option_context_new("- inspect an image"); + g_option_context_add_main_entries(ctx, entries, PACKAGE); + if (!g_option_context_parse(ctx, &argc, &argv, &error)) { + g_printerr("%s: option parsing failed: %s\n", + argv[0], error->message); + return 1; + } + + if (!path) { + g_printerr("%s: missing path\n", argv[0]); + return 1; + } + + if (virErrorInitialize() < 0) { + g_printerr("%s: failed to initialize error handling\n", argv[0]); + return 1; + } + + virLogSetFromEnv(); + virFileActivateDirOverrideForProg(argv[0]); + + if (!(src = virStorageSourceNew())) + goto cleanup; + + src->path = g_steal_pointer(&path); + src->type = VIR_STORAGE_TYPE_FILE; + + if (format && + (src->format = virStorageFileFormatTypeFromString(format)) < 0) { + g_printerr("%s: unknown format '%s'\n", argv[0], format); + goto cleanup; + } + + if (virStorageFileGetMetadata(src, -1, -1, true) < 0) + goto cleanup; + + for (n = src; n; n = n->backingStore) + print_source(n); + + ret = 0; + + cleanup: + if (virGetLastErrorCode() != VIR_ERR_OK) + g_printerr("%s: libvirt error: %s\n", argv[0], virGetLastErrorMessage()); + + return ret; +} -- 2.24.1