diff options
author | Federico Simoncelli <fsimonce@redhat.com> | 2013-01-28 06:59:47 -0500 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2013-02-22 21:21:08 +0100 |
commit | 8599ea4c42c098d2657ed632ad569f7a665706a4 (patch) | |
tree | 222e583e7637c55dac0f75e86bf00be64116b092 /qemu-img.c | |
parent | c6bb9ad198c2caa9c7c8ba360a07630b5c10e4a8 (diff) | |
download | qemu-8599ea4c42c098d2657ed632ad569f7a665706a4.tar.gz qemu-8599ea4c42c098d2657ed632ad569f7a665706a4.tar.bz2 qemu-8599ea4c42c098d2657ed632ad569f7a665706a4.zip |
qemu-img: add json output option to the check command
This option --output=[human|json] makes qemu-img check output a human
or JSON representation at the choice of the user.
Signed-off-by: Federico Simoncelli <fsimonce@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'qemu-img.c')
-rw-r--r-- | qemu-img.c | 232 |
1 files changed, 169 insertions, 63 deletions
diff --git a/qemu-img.c b/qemu-img.c index e80c1c55fd..34249fee12 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -42,6 +42,16 @@ typedef struct img_cmd_t { int (*handler)(int argc, char **argv); } img_cmd_t; +enum { + OPTION_OUTPUT = 256, + OPTION_BACKING_CHAIN = 257, +}; + +typedef enum OutputFormat { + OFORMAT_JSON, + OFORMAT_HUMAN, +} OutputFormat; + /* Default to cache=writeback as data integrity is not important for qemu-tcg. */ #define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_DEFAULT_CACHE "writeback" @@ -375,6 +385,96 @@ static int img_create(int argc, char **argv) return 0; } +static void dump_json_image_check(ImageCheck *check) +{ + Error *errp = NULL; + QString *str; + QmpOutputVisitor *ov = qmp_output_visitor_new(); + QObject *obj; + visit_type_ImageCheck(qmp_output_get_visitor(ov), + &check, NULL, &errp); + obj = qmp_output_get_qobject(ov); + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); + qobject_decref(obj); + qmp_output_visitor_cleanup(ov); + QDECREF(str); +} + +static void dump_human_image_check(ImageCheck *check) +{ + if (!(check->corruptions || check->leaks || check->check_errors)) { + printf("No errors were found on the image.\n"); + } else { + if (check->corruptions) { + printf("\n%" PRId64 " errors were found on the image.\n" + "Data may be corrupted, or further writes to the image " + "may corrupt it.\n", + check->corruptions); + } + + if (check->leaks) { + printf("\n%" PRId64 " leaked clusters were found on the image.\n" + "This means waste of disk space, but no harm to data.\n", + check->leaks); + } + + if (check->check_errors) { + printf("\n%" PRId64 " internal errors have occurred during the check.\n", + check->check_errors); + } + } + + if (check->total_clusters != 0 && check->allocated_clusters != 0) { + printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n", + check->allocated_clusters, check->total_clusters, + check->allocated_clusters * 100.0 / check->total_clusters, + check->fragmented_clusters * 100.0 / check->allocated_clusters); + } + + if (check->image_end_offset) { + printf("Image end offset: %" PRId64 "\n", check->image_end_offset); + } +} + +static int collect_image_check(BlockDriverState *bs, + ImageCheck *check, + const char *filename, + const char *fmt, + int fix) +{ + int ret; + BdrvCheckResult result; + + ret = bdrv_check(bs, &result, fix); + if (ret < 0) { + return ret; + } + + check->filename = g_strdup(filename); + check->format = g_strdup(bdrv_get_format_name(bs)); + check->check_errors = result.check_errors; + check->corruptions = result.corruptions; + check->has_corruptions = result.corruptions != 0; + check->leaks = result.leaks; + check->has_leaks = result.leaks != 0; + check->corruptions_fixed = result.corruptions_fixed; + check->has_corruptions_fixed = result.corruptions != 0; + check->leaks_fixed = result.leaks_fixed; + check->has_leaks_fixed = result.leaks != 0; + check->image_end_offset = result.image_end_offset; + check->has_image_end_offset = result.image_end_offset != 0; + check->total_clusters = result.bfi.total_clusters; + check->has_total_clusters = result.bfi.total_clusters != 0; + check->allocated_clusters = result.bfi.allocated_clusters; + check->has_allocated_clusters = result.bfi.allocated_clusters != 0; + check->fragmented_clusters = result.bfi.fragmented_clusters; + check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0; + + return 0; +} + /* * Checks an image for consistency. Exit codes: * @@ -386,15 +486,26 @@ static int img_create(int argc, char **argv) static int img_check(int argc, char **argv) { int c, ret; - const char *filename, *fmt; + OutputFormat output_format = OFORMAT_HUMAN; + const char *filename, *fmt, *output; BlockDriverState *bs; - BdrvCheckResult result; int fix = 0; int flags = BDRV_O_FLAGS | BDRV_O_CHECK; + ImageCheck *check; fmt = NULL; + output = NULL; for(;;) { - c = getopt(argc, argv, "f:hr:"); + int option_index = 0; + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"format", required_argument, 0, 'f'}, + {"repair", no_argument, 0, 'r'}, + {"output", required_argument, 0, OPTION_OUTPUT}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "f:hr:", + long_options, &option_index); if (c == -1) { break; } @@ -417,6 +528,9 @@ static int img_check(int argc, char **argv) help(); } break; + case OPTION_OUTPUT: + output = optarg; + break; } } if (optind >= argc) { @@ -424,77 +538,79 @@ static int img_check(int argc, char **argv) } filename = argv[optind++]; + if (output && !strcmp(output, "json")) { + output_format = OFORMAT_JSON; + } else if (output && !strcmp(output, "human")) { + output_format = OFORMAT_HUMAN; + } else if (output) { + error_report("--output must be used with human or json as argument."); + return 1; + } + bs = bdrv_new_open(filename, fmt, flags, true); if (!bs) { return 1; } - ret = bdrv_check(bs, &result, fix); + + check = g_new0(ImageCheck, 1); + ret = collect_image_check(bs, check, filename, fmt, fix); if (ret == -ENOTSUP) { - error_report("This image format does not support checks"); - bdrv_delete(bs); - return 1; + if (output_format == OFORMAT_HUMAN) { + error_report("This image format does not support checks"); + } + ret = 1; + goto fail; } - if (result.corruptions_fixed || result.leaks_fixed) { - printf("The following inconsistencies were found and repaired:\n\n" - " %d leaked clusters\n" - " %d corruptions\n\n" - "Double checking the fixed image now...\n", - result.leaks_fixed, - result.corruptions_fixed); - ret = bdrv_check(bs, &result, 0); - } + if (check->corruptions_fixed || check->leaks_fixed) { + int corruptions_fixed, leaks_fixed; - if (!(result.corruptions || result.leaks || result.check_errors)) { - printf("No errors were found on the image.\n"); - } else { - if (result.corruptions) { - printf("\n%d errors were found on the image.\n" - "Data may be corrupted, or further writes to the image " - "may corrupt it.\n", - result.corruptions); - } + leaks_fixed = check->leaks_fixed; + corruptions_fixed = check->corruptions_fixed; - if (result.leaks) { - printf("\n%d leaked clusters were found on the image.\n" - "This means waste of disk space, but no harm to data.\n", - result.leaks); + if (output_format == OFORMAT_HUMAN) { + printf("The following inconsistencies were found and repaired:\n\n" + " %" PRId64 " leaked clusters\n" + " %" PRId64 " corruptions\n\n" + "Double checking the fixed image now...\n", + check->leaks_fixed, + check->corruptions_fixed); } - if (result.check_errors) { - printf("\n%d internal errors have occurred during the check.\n", - result.check_errors); - } - } + ret = collect_image_check(bs, check, filename, fmt, 0); - if (result.bfi.total_clusters != 0 && result.bfi.allocated_clusters != 0) { - printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n", - result.bfi.allocated_clusters, result.bfi.total_clusters, - result.bfi.allocated_clusters * 100.0 / result.bfi.total_clusters, - result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters); + check->leaks_fixed = leaks_fixed; + check->corruptions_fixed = corruptions_fixed; } - if (result.image_end_offset > 0) { - printf("Image end offset: %" PRId64 "\n", result.image_end_offset); + switch (output_format) { + case OFORMAT_HUMAN: + dump_human_image_check(check); + break; + case OFORMAT_JSON: + dump_json_image_check(check); + break; } - bdrv_delete(bs); - - if (ret < 0 || result.check_errors) { - printf("\nAn error has occurred during the check: %s\n" - "The check is not complete and may have missed error.\n", - strerror(-ret)); - return 1; + if (ret || check->check_errors) { + ret = 1; + goto fail; } - if (result.corruptions) { - return 2; - } else if (result.leaks) { - return 3; + if (check->corruptions) { + ret = 2; + } else if (check->leaks) { + ret = 3; } else { - return 0; + ret = 0; } + +fail: + qapi_free_ImageCheck(check); + bdrv_delete(bs); + + return ret; } static int img_commit(int argc, char **argv) @@ -1396,16 +1512,6 @@ err: return NULL; } -enum { - OPTION_OUTPUT = 256, - OPTION_BACKING_CHAIN = 257, -}; - -typedef enum OutputFormat { - OFORMAT_JSON, - OFORMAT_HUMAN, -} OutputFormat; - static int img_info(int argc, char **argv) { int c; |