@@ -46,9 +46,9 @@ STEXI
ETEXI
DEF("dd", img_dd,
- "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [seek=blocks] [conv=convs] [iflag=flags] [oflag=flags] if=input of=output")
+ "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [seek=blocks] [conv=convs] [iflag=flags] [oflag=flags] [status=level] if=input of=output")
STEXI
- @item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [seek=@var{blocks}] [conv=@var{convs}] [iflag=@var{flags}] [oflag=@var{flags}] if=@var{input} of=@var{output}
+ @item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [seek=@var{blocks}] [conv=@var{convs}] [iflag=@var{flags}] [oflag=@var{flags}] [status=@var{level}] if=@var{input} of=@var{output}
ETEXI
DEF("info", img_info,
@@ -178,7 +178,11 @@ static void QEMU_NORETURN help(void)
" 'seek=N' seek N bs-sized blocks at the start of output\n"
" 'conv=CONVS' do not truncate the output file\n"
" 'iflags=FLAGS' read using the comma-separated flags list\n"
- " 'oflags=FLAGS' read using the comma-separated flags list\n\n"
+ " 'oflags=FLAGS' read using the comma-separated flags list\n"
+ " 'status=LEVEL' the LEVEL of information to print to stderr\n\n"
+ "List of LEVELS for dd:\n"
+ " 'none' surpresses everything but error messages\n"
+ " 'noxfer' surpresses the final transfer statistics\n\n"
"List of CONVS for dd:\n"
" 'notrunc' do not truncate the output file\n"
" 'noerror' continue in the event of read errors\n"
@@ -3832,11 +3836,13 @@ out:
#define C_CONV 0100
#define C_IFLAG 0200
#define C_OFLAG 0400
+#define C_STATUS 01000
struct DdInfo {
unsigned int flags;
int64_t count;
unsigned int conv;
+ unsigned status;
};
struct DdIo {
@@ -4077,6 +4083,31 @@ static int img_dd_oflag(const char *arg,
return ret;
}
+#define C_STATUS_DEFAULT 00
+#define C_STATUS_NONE 01
+#define C_STATUS_NOXFER 02
+
+static int img_dd_status(const char *arg,
+ struct DdIo *in, struct DdIo *out,
+ struct DdInfo *dd)
+{
+ const struct DdSymbols dd_status[] = {
+ { "none", C_STATUS_NONE },
+ { "noxfer", C_STATUS_NOXFER },
+ { NULL, 0 }
+ };
+
+ for (int j = 0; dd_status[j].name != NULL; j++) {
+ if (!strcmp(arg, dd_status[j].name)) {
+ dd->status = dd_status[j].value;
+ return 0;
+ }
+ }
+
+ error_report("invalid status level: '%s'", arg);
+ return 1;
+}
+
static int img_dd(int argc, char **argv)
{
int ret = 0;
@@ -4094,13 +4125,16 @@ static int img_dd(int argc, char **argv)
const char *fmt = NULL;
int64_t size = 0, out_size = 0;
int64_t out_pos, in_pos, sparse_count = 0;
+ int64_t in_read = 0, out_wrt = 0; /* Read/write count for status= */
bool writethrough = false;
int flags = 0;
int ibsz = 0, obsz = 0, bsz;
+ struct timeval starttv, endtv;
struct DdInfo dd = {
.flags = 0,
.count = 0,
- .conv = 0
+ .conv = 0,
+ .status = C_STATUS_DEFAULT
};
struct DdIo in = {
.bsz = 512, /* Block size is by default 512 bytes */
@@ -4127,6 +4161,7 @@ static int img_dd(int argc, char **argv)
{ "conv", img_dd_conv, C_CONV },
{ "iflag", img_dd_iflag, C_IFLAG },
{ "oflag", img_dd_oflag, C_OFLAG },
+ { "status", img_dd_status, C_STATUS },
{ NULL, NULL, 0 }
};
const struct option long_options[] = {
@@ -4374,16 +4409,21 @@ static int img_dd(int argc, char **argv)
}
if (in.offset > INT64_MAX / ibsz || size < in.offset * ibsz) {
- /* We give a warning if the skip option is bigger than the input
- * size and create an empty output disk image (i.e. like dd(1)).
- */
- error_report("%s: cannot skip to specified offset", in.filename);
- in_pos = size;
+ if (!(dd.status & C_STATUS_NONE)) {
+ /* We give a warning if the skip option is bigger than the input
+ * size and create an empty output disk image (i.e. like dd(1)).
+ */
+ error_report("%s: cannot skip to specified offset", in.filename);
+ in_pos = size;
+ }
} else {
in_pos = in.offset * ibsz;
}
in.buf = g_new(uint8_t, in.bsz);
+ if (dd.status & C_STATUS_DEFAULT) {
+ gettimeofday(&starttv, NULL);
+ }
for (out_pos = out.offset * obsz; in_pos < size;) {
int in_ret, out_ret;
@@ -4412,10 +4452,12 @@ static int img_dd(int argc, char **argv)
in_ret = bsz;
}
in_pos += in_ret;
+ in_read += in_ret;
if (dd.conv & C_SPARSE) {
if (buffer_is_zero(in.buf, bsz)) {
sparse_count++;
+ out_wrt += bsz;
continue;
}
if (sparse_count > 0) {
@@ -4433,12 +4475,46 @@ static int img_dd(int argc, char **argv)
goto out;
}
out_pos += out_ret;
+ out_wrt += out_ret;
}
if (dd.conv & C_FDATASYNC || dd.conv & C_FSYNC) {
blk_flush(blk2);
}
+ if (dd.status & C_STATUS_NOXFER || dd.status & C_STATUS_DEFAULT) {
+ fprintf(stderr, "%" PRId64 "+%" PRId64 " records in\n",
+ in_read / in.bsz, in_read % in.bsz);
+ fprintf(stderr, "%" PRId64 "+%" PRId64 " records out\n",
+ out_wrt / out.bsz, out_wrt % out.bsz);
+ }
+ if (dd.status & C_STATUS_DEFAULT) {
+ gchar *hsize;
+ double nb_microsec;
+
+ gettimeofday(&endtv, NULL);
+ timersub(&endtv, &starttv, &endtv);
+
+ if (out_wrt >= 1024) {
+ /* human-readable size in IEC format (base 1024) */
+ gchar *iecsize = g_format_size_full(out_wrt,
+ G_FORMAT_SIZE_IEC_UNITS);
+ /* Standard base (e.g. KB = 1000 bytes) */
+ hsize = g_format_size(out_wrt);
+ fprintf(stderr, "%" PRId64 " bytes (%s, %s) copied, ", out_wrt,
+ hsize, iecsize);
+ g_free(hsize);
+ g_free(iecsize);
+ } else {
+ fprintf(stderr, "%" PRId64 " copied, ", out_wrt);
+ }
+ nb_microsec = (double)endtv.tv_sec * 1000000 + endtv.tv_usec;
+ hsize = g_format_size((double)out_wrt * 1000000 / nb_microsec);
+ fprintf(stderr, "%ld.%08ld s, %s/s\n", (long)endtv.tv_sec,
+ (long)endtv.tv_usec, hsize);
+ g_free(hsize);
+ }
+
out:
g_free(arg);
qemu_opts_del(opts);
@@ -202,6 +202,13 @@ interpret 'skip=blocks' as a byte count. Only iflag.
@item seek_bytes
interpret 'seek=blocks' as a byte count. Only oflag.
+@item status=@var{level}
+Define the level of information to print to stderr.
+@item none
+Only error messages are printed.
+@item noxfer
+Do not print the final transfer rate.
+
@end table
Command description:
@@ -375,7 +382,7 @@ skipped. This is useful for formats such as @code{rbd} if the target
volume has already been created with site specific options that cannot
be supplied through qemu-img.
-@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [seek=@var{blocks}] [conv=@var{convs}] [iflag=@var{flags}] [oflag=@var{flags}] if=@var{input} of=@var{output}
+@item dd [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [seek=@var{blocks}] [conv=@var{convs}] [iflag=@var{flags}] [oflag=@var{flags}] [status=@var{level}] if=@var{input} of=@var{output}
Dd copies from @var{input} file to @var{output} file converting it from
@var{fmt} format to @var{output_fmt} format.
@@ -56,7 +56,7 @@ for bs in $TEST_SIZES; do
echo "== Converting the image with dd with a block size of $bs =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" bs=$bs conv=notrunc \
- -O "$IMGFMT"
+ -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
echo
@@ -56,7 +56,7 @@ for skip in $TEST_SKIP_BLOCKS; do
echo "== Converting the image with dd with skip=$skip =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" conv=notrunc \
- -O "$IMGFMT" 2> /dev/null
+ -O "$IMGFMT" 2> /dev/null status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" conv=notrunc \
status=none
@@ -56,7 +56,7 @@ for seek in $TEST_SEEK_BLOCKS; do
echo "== Converting the image with dd with seek=$seek =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" seek="$seek" conv=notrunc \
- -O "$IMGFMT" 2> /dev/null
+ -O "$IMGFMT" 2> /dev/null status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" seek="$seek" conv=notrunc \
status=none
@@ -58,7 +58,7 @@ for skip in $TEST_SKIP_BLOCKS; do
echo "== Converting the image with dd with skip=$skip iflag=skip_bytes =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" skip="$skip" \
- iflag=skip_bytes conv=notrunc -O "$IMGFMT" 2> /dev/null
+ iflag=skip_bytes conv=notrunc -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" skip="$skip" iflag=skip_bytes \
conv=notrunc status=none
@@ -86,7 +86,7 @@ for count in $TEST_COUNT_BLOCKS; do
"iflag=count_bytes =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" count="$skip" \
- iflag=count_bytes conv=notrunc -O "$IMGFMT" 2> /dev/null
+ iflag=count_bytes conv=notrunc -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" count="$skip" iflag=count_bytes \
conv=notrunc status=none
@@ -57,7 +57,7 @@ for seek in $TEST_SEEK_BLOCKS; do
echo "== Converting the image with dd with seek=$seek oflag=seek_bytes =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" seek="$seek" \
- oflag=seek_bytes conv=notrunc -O "$IMGFMT" 2> /dev/null
+ oflag=seek_bytes conv=notrunc -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" seek="$seek" \
oflag=seek_bytes status=none
@@ -83,7 +83,7 @@ echo "== Converting the image with dd with seek=$seek" \
"oflag=seek_bytes,direct =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" seek="$seek" \
- oflag=seek_bytes conv=notrunc -O "$IMGFMT" 2> /dev/null
+ oflag=seek_bytes conv=notrunc -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
dd if="$TEST_IMG" of="$TEST_IMG.out.dd" seek="$seek" \
oflag=seek_bytes,direct conv=notrunc status=none
@@ -53,7 +53,8 @@ $QEMU_IO -c "write -P 0xa 215k 212k" "$TEST_IMG" | _filter_qemu_io
echo
echo "== Converting the image with dd with conv=excl =="
-$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=excl,notrunc -O "$IMGFMT"
+$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=excl,notrunc \
+ -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
@@ -67,7 +68,7 @@ $QEMU_IMG compare "$TEST_IMG.out.dd" "$TEST_IMG.out"
echo
echo "== Converting the image with dd with conv=excl =="
-$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=excl,notrunc \
+$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=excl,notrunc status=none \
-O "$IMGFMT" 2>&1 | sed -e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g"
@@ -83,7 +84,7 @@ echo
echo "== Converting the image with dd with conv=nocreat =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=nocreat,notrunc \
- -O "$IMGFMT"
+ -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
@@ -100,8 +101,8 @@ echo
echo "== Converting the image with dd with conv=nocreat =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=nocreat,notrunc \
- -O "$IMGFMT" 2>&1 | sed -e "s#$TEST_DIR#TEST_DIR#g" \
- -e "s#$IMGFMT#IMGFMT#g"
+ -O "$IMGFMT" 2>&1 status=none | sed -e "s#$TEST_DIR#TEST_DIR#g" \
+ -e "s#$IMGFMT#IMGFMT#g"
echo
echo "*** done"
@@ -56,7 +56,7 @@ echo
echo "== Converting the image with dd with conv=sparse =="
$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=sparse,notrunc \
- -O "$IMGFMT"
+ -O "$IMGFMT" status=none
TEST_IMG="$TEST_IMG.out" _check_test_img
new file mode 100755
@@ -0,0 +1,77 @@
+#! /bin/bash
+#
+# qemu-img dd test for the status option
+#
+# Copyright (C) 2016 Reda Sallahi
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+owner=fullmanet@gmail.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+status=1
+
+_cleanup()
+{
+ _cleanup_test_img
+ rm -f "$TEST_IMG.out" "$TEST_IMG.out.stat" "$TEST_IMG.out.dd" \
+ "$TEST_IMG.out.dd.stat"
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+_supported_fmt raw
+_supported_proto file
+_supported_os Linux
+
+echo
+echo "== Creating image =="
+
+size=1M
+_make_test_img $size
+_check_test_img
+
+$QEMU_IO -c "write -P 0xa 149k 512k" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "== Converting the image with dd status=noxfer =="
+
+$QEMU_IMG dd if="$TEST_IMG" of="$TEST_IMG.out" conv=notrunc -O "$IMGFMT" \
+ status=noxfer 2> "$TEST_IMG.out.stat"
+TEST_IMG="$TEST_IMG.out" _check_test_img
+
+dd if="$TEST_IMG" of="$TEST_IMG.out.dd" conv=notrunc status=noxfer \
+ 2> "$TEST_IMG.out.dd.stat"
+
+echo
+echo "== Compare the images with qemu-img compare =="
+
+$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.out"
+
+echo
+echo "== Compare the stat output =="
+
+diff "$TEST_IMG.out.dd.stat" "$TEST_IMG.out.stat"
+
+echo
+echo "*** done"
+rm -f "$seq.full"
+status=0
new file mode 100644
@@ -0,0 +1,17 @@
+QA output created by 167
+
+== Creating image ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
+No errors were found on the image.
+wrote 524288/524288 bytes at offset 152576
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Converting the image with dd status=noxfer ==
+No errors were found on the image.
+
+== Compare the images with qemu-img compare ==
+Images are identical.
+
+== Compare the stat output ==
+
+*** done
@@ -166,3 +166,4 @@
164 rw auto quick
165 rw auto quick
166 rw auto quick
+167 rw auto quick
This patch adds the status option to the subcommand dd. With this dd will display by default the number of blocks read/written, the transfer rate, etc. like dd(1). The noxfer and none levels will allow the user to surpress the final transfer statistics and everything except error messages respectively. A test case was added to test the status option. Signed-off-by: Reda Sallahi <fullmanet@gmail.com> --- qemu-img-cmds.hx | 4 +-- qemu-img.c | 90 ++++++++++++++++++++++++++++++++++++++++++---- qemu-img.texi | 9 ++++- tests/qemu-iotests/159 | 2 +- tests/qemu-iotests/160 | 2 +- tests/qemu-iotests/161 | 2 +- tests/qemu-iotests/163 | 4 +-- tests/qemu-iotests/164 | 4 +-- tests/qemu-iotests/165 | 11 +++--- tests/qemu-iotests/166 | 2 +- tests/qemu-iotests/167 | 77 +++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/167.out | 17 +++++++++ tests/qemu-iotests/group | 1 + 13 files changed, 202 insertions(+), 23 deletions(-) create mode 100755 tests/qemu-iotests/167 create mode 100644 tests/qemu-iotests/167.out