From patchwork Wed Aug 15 14:54:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benoit Canet X-Patchwork-Id: 177681 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 541902C0086 for ; Thu, 16 Aug 2012 00:54:55 +1000 (EST) Received: from localhost ([::1]:41604 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T1ezl-00032X-Cf for incoming@patchwork.ozlabs.org; Wed, 15 Aug 2012 10:54:53 -0400 Received: from eggs.gnu.org ([208.118.235.92]:57926) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T1ezV-0002sE-Dn for qemu-devel@nongnu.org; Wed, 15 Aug 2012 10:54:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1T1ezT-0004yL-Ks for qemu-devel@nongnu.org; Wed, 15 Aug 2012 10:54:37 -0400 Received: from mail-wi0-f181.google.com ([209.85.212.181]:46953) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T1ezT-0004yA-Am for qemu-devel@nongnu.org; Wed, 15 Aug 2012 10:54:35 -0400 Received: by wibhm2 with SMTP id hm2so1161597wib.10 for ; Wed, 15 Aug 2012 07:54:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=5VXg8IYQK2teeZ1CF9kqwMyHB7PLltK931yam1USmTE=; b=S8eUf8fZRXLAkdFkcvTKAmUhxRvIuXLBVQ9ame8rtxo+7e8ld2S9tl+FDXM+ZkF061 QVmhEahdTfplUZ6o5svcB8hj5M7hdS89zDGupWIOZlzFR0xUOFJvIpHwxI8K/XJvaIHR bM70Z8M+nYD1xpdUGe78qiataqW3f+mE00OIxisGrsnAKcZhRkpQBlIzIdd87GIao4Jq odx8hyQsrI3jNnWzeV9EH7nhbMaMWCUAhe0vJfDDekyu2359sH0xI7m0INVwwF2WNO1Q pCqR8GJ07K8MfuLep1RPkGNqjz8Jj9YgSobDNbtTyD1LJwDx7clqlJrkIeBBkwCP4/6m D/oQ== Received: by 10.216.226.31 with SMTP id a31mr9168239weq.41.1345042474332; Wed, 15 Aug 2012 07:54:34 -0700 (PDT) Received: from Laure.box.in.irqsave.net (paradis.irqsave.net. [109.190.18.76]) by mx.google.com with ESMTPS id fb20sm5186009wid.1.2012.08.15.07.54.32 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 15 Aug 2012 07:54:33 -0700 (PDT) From: "=?UTF-8?q?Beno=C3=AEt=20Canet?=" To: qemu-devel@nongnu.org Date: Wed, 15 Aug 2012 16:54:26 +0200 Message-Id: <1345042466-31743-4-git-send-email-benoit@irqsave.net> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1345042466-31743-1-git-send-email-benoit@irqsave.net> References: <1345042466-31743-1-git-send-email-benoit@irqsave.net> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.212.181 Cc: aliguori@us.ibm.com, stefanha@linux.vnet.ibm.com, pbonzini@redhat.com, eblake@redhat.com, xiawenc@linux.vnet.ibm.com, =?UTF-8?q?Beno=C3=AEt=20Canet?= Subject: [Qemu-devel] [PATCH 3/3] qemu-img: Add json output option to the info command. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This additionnal --machine=json option make qemu-img info output on stdout a JSON formated representation of the image informations. --machine=json was choosen instead of --format=json because the info command already have a -f parameter. example: { "snapshots": [ { "name": "truc", "date-sec": 1345034924, "date-nsec": 870405000, "vm-clock-sec": 4647590161, "id": "1", "vm-state-size": 80805256 }, { "name": "onx", "date-sec": 1345034927, "date-nsec": 914633000, "vm-clock-sec": 7065282574, "id": "2", "vm-state-size": 75927370 }, { "name": "list", "date-sec": 1345034939, "date-nsec": 39119000, "vm-clock-sec": 10108695046, "id": "3", "vm-state-size": 75890567 } ], "virtual-size": 1073741824, "filename": "snapshot.img", "cluster-size": 65536, "format": "qcow2", "actual-size": 242614272, "encrypted": false, "backing-filename": "truc5.raw", "dirty-flag": false } Signed-off-by: Benoit Canet --- Makefile | 3 +- qemu-img.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index ab82ef3..9ba064b 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,8 @@ tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ iohandler.o cutils.o iov.o async.o tools-obj-$(CONFIG_POSIX) += compatfd.o -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) +qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) $(qapi-obj-y) \ + qapi-visit.o qapi-types.o qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) diff --git a/qemu-img.c b/qemu-img.c index 80cfb9b..1a80414 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -21,12 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "qapi-visit.h" +#include "qapi/qmp-output-visitor.h" +#include "qjson.h" #include "qemu-common.h" #include "qemu-option.h" #include "qemu-error.h" #include "osdep.h" #include "sysemu.h" #include "block_int.h" +#include #include #ifdef _WIN32 @@ -84,6 +88,7 @@ static void help(void) " '-p' show progress of command (only certain commands)\n" " '-S' indicates the consecutive number of bytes that must contain only zeros\n" " for qemu-img to create a sparse image during conversion\n" + " '-m' or '--machine' takes the format in which the output must be done (json)\n" "\n" "Parameters to check subcommand:\n" " '-r' tries to repair any inconsistencies that are found during the check.\n" @@ -1102,10 +1107,66 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } +static void collect_snapshots(BlockDriverState *bs , ImageInfo *image_info) +{ + int i, sn_count; + QEMUSnapshotInfo *sn_tab; + SnapshotInfoList *sn_info_list, *cur_item = NULL, *head = NULL; + sn_count = bdrv_snapshot_list(bs, &sn_tab); + + for (i = 0; i < sn_count; i++) { + sn_info_list = g_new0(SnapshotInfoList, 1); + + sn_info_list->value = g_new0(SnapshotInfo, 1); + sn_info_list->value->id = g_strdup(sn_tab[i].id_str); + sn_info_list->value->name = g_strdup(sn_tab[i].name); + sn_info_list->value->vm_state_size = sn_tab[i].vm_state_size; + sn_info_list->value->date_sec = sn_tab[i].date_sec; + sn_info_list->value->date_nsec = sn_tab[i].date_nsec; + sn_info_list->value->vm_clock_sec = sn_tab[i].vm_clock_nsec; + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = sn_info_list; + } else { + cur_item->next = sn_info_list; + cur_item = sn_info_list; + } + + } + + g_free(sn_tab); + image_info->snapshots = head; +} + +static void dump_json_image_info(ImageInfo *image_info) +{ + Error *errp = NULL; + QString *str; + QmpOutputVisitor *ov = qmp_output_visitor_new(); + QObject *obj; + visit_type_ImageInfo(qmp_output_get_visitor(ov), + &image_info, NULL, &errp); + obj = qmp_output_get_qobject(ov); + str = qobject_to_json_pretty(obj); + assert(str != NULL); + qstring_append_chr(str, '\n'); + printf("%s", qstring_get_str(str)); + qobject_decref(obj); + qmp_output_visitor_cleanup(ov); + QDECREF(str); +} + +#define PRINTH(human, args...) do { \ + if (human) { \ + printf(args); \ + } } while (0); + static int img_info(int argc, char **argv) { int c; - const char *filename, *fmt; + bool human = true; + const char *filename, *fmt, *machine; BlockDriverState *bs; char size_buf[128], dsize_buf[128]; uint64_t total_sectors; @@ -1113,10 +1174,20 @@ static int img_info(int argc, char **argv) char backing_filename[1024]; char backing_filename2[1024]; BlockDriverInfo bdi; + ImageInfo *image_info; fmt = NULL; + machine = NULL; for(;;) { - c = getopt(argc, argv, "f:h"); + int option_index = 0; + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"format", required_argument, 0, 'f'}, + {"machine", required_argument, 0, 'm'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "f:h", + long_options, &option_index); if (c == -1) { break; } @@ -1128,6 +1199,9 @@ static int img_info(int argc, char **argv) case 'f': fmt = optarg; break; + case 'm': + machine = optarg; + break; } } if (optind >= argc) { @@ -1135,6 +1209,11 @@ static int img_info(int argc, char **argv) } filename = argv[optind++]; + image_info = g_new0(ImageInfo, 1); + if (machine && !strncmp(machine, "json", strlen("json"))) { + human = false; + } + bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING); if (!bs) { return 1; @@ -1148,39 +1227,66 @@ static int img_info(int argc, char **argv) get_human_readable_size(dsize_buf, sizeof(dsize_buf), allocated_size); } - printf("image: %s\n" + PRINTH(human, "image: %s\n" "file format: %s\n" "virtual size: %s (%" PRId64 " bytes)\n" "disk size: %s\n", filename, bdrv_get_format_name(bs), size_buf, (total_sectors * 512), dsize_buf); + image_info->filename = g_strdup(filename); + image_info->format = g_strdup(bdrv_get_format_name(bs)); + image_info->virtual_size = total_sectors * 512; + image_info->actual_size = allocated_size >= 0 ? allocated_size : 0; if (bdrv_is_encrypted(bs)) { - printf("encrypted: yes\n"); + PRINTH(human, "encrypted: yes\n"); + image_info->encrypted = true; + } else { + image_info->encrypted = false; } if (bdrv_get_info(bs, &bdi) >= 0) { if (bdi.cluster_size != 0) { - printf("cluster_size: %d\n", bdi.cluster_size); + PRINTH(human, "cluster_size: %d\n", bdi.cluster_size); + image_info->cluster_size = bdi.cluster_size; } if (bdi.is_dirty) { - printf("cleanly shut down: no\n"); + PRINTH(human, "cleanly shut down: no\n"); + image_info->dirty_flag = true; + } else { + image_info->dirty_flag = false; } } bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); if (backing_filename[0] != '\0') { + image_info->backing_filename = g_strdup(backing_filename); bdrv_get_full_backing_filename(bs, backing_filename2, sizeof(backing_filename2)); - printf("backing file: %s", backing_filename); + PRINTH(human, "backing file: %s", backing_filename); if (strcmp(backing_filename, backing_filename2) != 0) { - printf(" (actual path: %s)", backing_filename2); + PRINTH(human, " (actual path: %s)", backing_filename2); + } + if (human) { + putchar('\n'); } - putchar('\n'); } - dump_snapshots(bs); + + if (human) { + dump_snapshots(bs); + } else { + collect_snapshots(bs, image_info); + } + + if (!human) { + dump_json_image_info(image_info); + } + + qapi_free_ImageInfo(image_info); bdrv_delete(bs); return 0; } +#undef PRINTH + #define SNAPSHOT_LIST 1 #define SNAPSHOT_CREATE 2 #define SNAPSHOT_APPLY 3