From patchwork Fri Jul 27 10:20:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wayne Xia X-Patchwork-Id: 173621 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 B522A2C0A5F for ; Fri, 27 Jul 2012 20:22:39 +1000 (EST) Received: from localhost ([::1]:37671 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Suhgp-0000X6-TY for incoming@patchwork.ozlabs.org; Fri, 27 Jul 2012 06:22:35 -0400 Received: from eggs.gnu.org ([208.118.235.92]:58859) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Suhgj-0000X1-6G for qemu-devel@nongnu.org; Fri, 27 Jul 2012 06:22:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Suhgc-0003cU-HJ for qemu-devel@nongnu.org; Fri, 27 Jul 2012 06:22:28 -0400 Received: from e23smtp03.au.ibm.com ([202.81.31.145]:58035) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Suhgb-0003Wz-Hl for qemu-devel@nongnu.org; Fri, 27 Jul 2012 06:22:22 -0400 Received: from /spool/local by e23smtp03.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 27 Jul 2012 20:21:59 +1000 Received: from d23relay03.au.ibm.com (202.81.31.245) by e23smtp03.au.ibm.com (202.81.31.209) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 27 Jul 2012 20:21:56 +1000 Received: from d23av02.au.ibm.com (d23av02.au.ibm.com [9.190.235.138]) by d23relay03.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q6RAM9Z97733456 for ; Fri, 27 Jul 2012 20:22:11 +1000 Received: from d23av02.au.ibm.com (loopback [127.0.0.1]) by d23av02.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q6RAM8fJ029989 for ; Fri, 27 Jul 2012 20:22:09 +1000 Received: from RedHat62GAWSWenchao (wenchaox.cn.ibm.com [9.115.122.114]) by d23av02.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q6RAKrbG026411; Fri, 27 Jul 2012 20:22:07 +1000 From: Wenchao Xia To: qemu-devel@nongnu.org Date: Fri, 27 Jul 2012 18:20:48 +0800 Message-Id: <1343384448-21828-1-git-send-email-xiawenc@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.1 x-cbid: 12072710-6102-0000-0000-000001F4CE72 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 202.81.31.145 Cc: pbonzini@redhat.com, aliguori@us.ibm.com, stefanha@linux.vnet.ibm.com, Wenchao Xia Subject: [Qemu-devel] [PATCH] let qemu-img info genereate json output 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 patch would add option -j in qemu-img info command, which would generate json output in stdout. Signed-off-by: Wenchao Xia --- qemu-img.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 264 insertions(+), 42 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 80cfb9b..a514c17 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -33,6 +33,9 @@ #include #endif +#include "qint.h" +#include "qjson.h" + typedef struct img_cmd_t { const char *name; int (*handler)(int argc, char **argv); @@ -84,6 +87,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" + " '-j' try get json output, which would be in stdout, only valid in info command\n" "\n" "Parameters to check subcommand:\n" " '-r' tries to repair any inconsistencies that are found during the check.\n" @@ -1102,21 +1106,210 @@ static void dump_snapshots(BlockDriverState *bs) g_free(sn_tab); } +/* string must be allocated on heap */ +struct img_infos { + char *filename; + char *fmt; + uint64_t total_sectors; + int64_t allocated_size; + int32 enc_flag; + BlockDriverInfo *bdi; + char *backing_filename; + char *backing_filename_full; + QEMUSnapshotInfo *sn_tab; + int nb_sns; +}; + +static void img_infos_init(struct img_infos *pinfo) +{ + memset(pinfo, 0, sizeof(struct img_infos)); +} + +#define TRY_FREE(p) { \ + if ((p) != NULL) { \ + g_free((p)); \ + (p) = NULL; \ + } \ +} +static void img_infos_uninit(struct img_infos *pinfo) +{ + TRY_FREE(pinfo->filename); + TRY_FREE(pinfo->fmt); + TRY_FREE(pinfo->bdi); + TRY_FREE(pinfo->backing_filename); + TRY_FREE(pinfo->backing_filename_full); + TRY_FREE(pinfo->sn_tab); +} + +static void snapshot_info_to_list(QList *qlist, QEMUSnapshotInfo *sn) +{ + char buf[128]; + QInt *qint; + QString *qstr; + QDict *qdic = qdict_new(); + + qstr = qstring_from_str(sn->id_str); + qdict_put_obj(qdic, "id", QOBJECT(qstr)); + qstr = qstring_from_str(sn->name); + qdict_put_obj(qdic, "name", QOBJECT(qstr)); + + snprintf(buf, sizeof(buf), "%ld", sn->vm_state_size); + qstr = qstring_from_str(buf); + qdict_put_obj(qdic, "vm_state_size", QOBJECT(qstr)); + + qint = qint_from_int(sn->date_sec); + qdict_put_obj(qdic, "date_sec", QOBJECT(qint)); + qint = qint_from_int(sn->date_nsec); + qdict_put_obj(qdic, "date_nsec", QOBJECT(qint)); + snprintf(buf, sizeof(buf), "%ld", sn->vm_clock_nsec); + qstr = qstring_from_str(buf); + qdict_put_obj(qdic, "vm_clock_nsec", QOBJECT(qstr)); + qlist_append(qlist, qdic); +} + +static void img_infos_print_json(struct img_infos *pinfo, int ret) +{ + char buf[128]; + QInt *qint; + QDict *qdic, *qdic_all; + QString *qstr; + QList *qlist; + int i; + + qdic_all = qdict_new(); + + qint = qint_from_int(ret); + qdict_put_obj(qdic_all, "return", QOBJECT(qint)); + if (ret != 0) { + goto print; + } + + qdic = qdict_new(); + if (pinfo->filename != NULL) { + qstr = qstring_from_str(pinfo->filename); + qdict_put_obj(qdic, "filename", QOBJECT(qstr)); + } + if (pinfo->fmt != NULL) { + qstr = qstring_from_str(pinfo->fmt); + qdict_put_obj(qdic, "fmt", QOBJECT(qstr)); + } + snprintf(buf, sizeof(buf), "%ld", pinfo->total_sectors * 512); + qstr = qstring_from_str(buf); + qdict_put_obj(qdic, "virtual_size", QOBJECT(qstr)); + snprintf(buf, sizeof(buf), "%ld", pinfo->allocated_size); + qstr = qstring_from_str(buf); + qdict_put_obj(qdic, "actual_size", QOBJECT(qstr)); + qint = qint_from_int(pinfo->enc_flag); + qdict_put_obj(qdic, "encrypted", QOBJECT(qint)); + + if (pinfo->bdi != NULL) { + qint = qint_from_int(pinfo->bdi->cluster_size); + qdict_put_obj(qdic, "cluster_size", QOBJECT(qint)); + qint = qint_from_int(pinfo->bdi->is_dirty); + qdict_put_obj(qdic, "dirty_flag", QOBJECT(qint)); + } + + if (pinfo->backing_filename != NULL) { + qstr = qstring_from_str(pinfo->backing_filename); + qdict_put_obj(qdic, "backing_filename", QOBJECT(qstr)); + if ((pinfo->backing_filename != NULL) && + (0 != strcmp(pinfo->backing_filename, + pinfo->backing_filename_full)) + ) { + qstr = qstring_from_str(pinfo->backing_filename_full); + qdict_put_obj(qdic, "backing_filename_full", QOBJECT(qstr)); + } + } + + qlist = qlist_new(); + i = 0; + while (i < pinfo->nb_sns) { + snapshot_info_to_list(qlist, &(pinfo->sn_tab[i])); + i++; + } + qdict_put_obj(qdic, "snapshot_list", QOBJECT(qlist)); + + qdict_put_obj(qdic_all, "information", QOBJECT(qdic)); + + print: + qstr = qobject_to_json_pretty(QOBJECT(qdic_all)); + printf("%s\n", qstring_get_str(qstr)); + qobject_decref(QOBJECT(qstr)); + + qobject_decref(QOBJECT(qdic_all)); +} + +static void img_infos_print(struct img_infos *pinfo) +{ + char size_buf[128], dsize_buf[128], buf[256]; + int i; + QEMUSnapshotInfo *sn; + + get_human_readable_size(size_buf, sizeof(size_buf), + pinfo->total_sectors * 512); + if (pinfo->allocated_size < 0) { + snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); + } else { + get_human_readable_size(dsize_buf, sizeof(dsize_buf), + pinfo->allocated_size); + } + + printf("image: %s\n" + "file format: %s\n" + "virtual size: %s (%" PRId64 " bytes)\n" + "disk size: %s\n", + pinfo->filename, pinfo->fmt, size_buf, + (pinfo->total_sectors * 512), + dsize_buf); + + if (pinfo->enc_flag > 0) { + printf("encrypted: yes\n"); + } + + if (pinfo->bdi != NULL) { + if (pinfo->bdi->cluster_size != 0) { + printf("cluster_size: %d\n", pinfo->bdi->cluster_size); + } + if (pinfo->bdi->is_dirty) { + printf("cleanly shut down: no\n"); + } + } + + if (pinfo->backing_filename != NULL) { + printf("backing file: %s", pinfo->backing_filename); + if ((pinfo->backing_filename != NULL) && + (0 != strcmp(pinfo->backing_filename, + pinfo->backing_filename_full)) + ) { + printf(" (actual path: %s)", pinfo->backing_filename_full); + } + putchar('\n'); + } + + if (pinfo->nb_sns <= 0) { + return; + } + + printf("Snapshot list:\n"); + printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL)); + for (i = 0; i < pinfo->nb_sns; i++) { + sn = &(pinfo->sn_tab[i]); + printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn)); + } +} + +#define FILENAME_LEN_MAX (1024) static int img_info(int argc, char **argv) { int c; const char *filename, *fmt; BlockDriverState *bs; - char size_buf[128], dsize_buf[128]; - uint64_t total_sectors; - int64_t allocated_size; - char backing_filename[1024]; - char backing_filename2[1024]; - BlockDriverInfo bdi; + int json_flag = 0, ret = 0; + struct img_infos my_img_infos; fmt = NULL; for(;;) { - c = getopt(argc, argv, "f:h"); + c = getopt(argc, argv, "f:h:j"); if (c == -1) { break; } @@ -1128,6 +1321,9 @@ static int img_info(int argc, char **argv) case 'f': fmt = optarg; break; + case 'j': + json_flag = 1; + break; } } if (optind >= argc) { @@ -1135,50 +1331,76 @@ static int img_info(int argc, char **argv) } filename = argv[optind++]; + img_infos_init(&my_img_infos); + my_img_infos.filename = strdup(filename); + bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING); if (!bs) { - return 1; + ret = 1; + goto output; } - bdrv_get_geometry(bs, &total_sectors); - get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); - allocated_size = bdrv_get_allocated_file_size(bs); - if (allocated_size < 0) { - snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); - } else { - get_human_readable_size(dsize_buf, sizeof(dsize_buf), - allocated_size); + + my_img_infos.fmt = strdup(bdrv_get_format_name(bs)); + + bdrv_get_geometry(bs, &(my_img_infos.total_sectors)); + my_img_infos.allocated_size = bdrv_get_allocated_file_size(bs); + + my_img_infos.enc_flag = bdrv_is_encrypted(bs); + my_img_infos.bdi = g_malloc(sizeof(BlockDriverInfo)); + if (my_img_infos.bdi == NULL) { + ret = -1; + goto output; } - printf("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); - if (bdrv_is_encrypted(bs)) { - printf("encrypted: yes\n"); + if (bdrv_get_info(bs, my_img_infos.bdi) < 0) { + g_free(my_img_infos.bdi); + my_img_infos.bdi = NULL; } - if (bdrv_get_info(bs, &bdi) >= 0) { - if (bdi.cluster_size != 0) { - printf("cluster_size: %d\n", bdi.cluster_size); + + my_img_infos.backing_filename = g_malloc(FILENAME_LEN_MAX); + if (my_img_infos.backing_filename == NULL) { + ret = -1; + goto output; + } + memset(my_img_infos.backing_filename, 0, FILENAME_LEN_MAX); + bdrv_get_backing_filename(bs, my_img_infos.backing_filename, + FILENAME_LEN_MAX); + if (my_img_infos.backing_filename[0] != '\0') { + my_img_infos.backing_filename_full = g_malloc(FILENAME_LEN_MAX); + if (my_img_infos.backing_filename_full == NULL) { + ret = -1; + goto output; } - if (bdi.is_dirty) { - printf("cleanly shut down: no\n"); + memset(my_img_infos.backing_filename_full, 0, FILENAME_LEN_MAX); + bdrv_get_full_backing_filename(bs, my_img_infos.backing_filename_full, + FILENAME_LEN_MAX); + if (my_img_infos.backing_filename_full[0] == '\0') { + g_free(my_img_infos.backing_filename_full); + my_img_infos.backing_filename_full = NULL; } + } else { + g_free(my_img_infos.backing_filename); + my_img_infos.backing_filename = NULL; } - bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename)); - if (backing_filename[0] != '\0') { - bdrv_get_full_backing_filename(bs, backing_filename2, - sizeof(backing_filename2)); - printf("backing file: %s", backing_filename); - if (strcmp(backing_filename, backing_filename2) != 0) { - printf(" (actual path: %s)", backing_filename2); - } - putchar('\n'); + + my_img_infos.nb_sns = bdrv_snapshot_list(bs, &(my_img_infos.sn_tab)); + + output: + if ((ret != 0) && (json_flag == 0)) { + goto clean; } - dump_snapshots(bs); - bdrv_delete(bs); - return 0; + + if (json_flag > 0) { + img_infos_print_json(&my_img_infos, ret); + } else { + img_infos_print(&my_img_infos); + } + + clean: + if (bs != NULL) { + bdrv_delete(bs); + } + img_infos_uninit(&my_img_infos); + return ret; } #define SNAPSHOT_LIST 1