All of lore.kernel.org
 help / color / mirror / Atom feed
From: Reda Sallahi <fullmanet@gmail.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, mreitz@redhat.com, qemu-block@nongnu.org,
	stefanha@redhat.com, famz@redhat.com
Subject: [Qemu-devel] [PATCH RFC 1/1] qemu-img: add the 'dd' subcommand
Date: Wed, 22 Jun 2016 19:21:30 +0200	[thread overview]
Message-ID: <20160622172119.GA4709@localhost> (raw)

This patch adds a basic dd subcommand analogous to dd(1) to qemu-img.

For the start, this implements the bs, if, of and count options and requires
both if and of to be specified (no stdin/stdout if not specified) and doesn't
support tty, pipes, etc.

The image format must be specified with -O for the output if the raw format
is not the intended one.

get_size() and get_offset() were needed for the size syntax dd(1) supports
which is different from qemu_strtosz_suffix.

Signed-off-by: Reda Sallahi <fullmanet@gmail.com>
---
 qemu-img-cmds.hx |   6 +
 qemu-img.c       | 833 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 838 insertions(+), 1 deletion(-)

diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 7e95b2d..68f81b0 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -45,6 +45,12 @@ STEXI
 @item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
 
+DEF("dd", img_dd,
+    "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [ibs=in_block_size] [count=blocks] if=input of=output")
+STEXI
+@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [ibs=@var{in_block_size}] [count=@var{blocks}] if=@var{input} of=@var{output}
+ETEXI
+
 DEF("info", img_info,
     "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename")
 STEXI
diff --git a/qemu-img.c b/qemu-img.c
index 14e2661..dace76b 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -159,7 +159,25 @@ static void QEMU_NORETURN help(void)
            "Parameters to compare subcommand:\n"
            "  '-f' first image format\n"
            "  '-F' second image format\n"
-           "  '-s' run in Strict mode - fail on different image size or sector allocation\n";
+           "  '-s' run in Strict mode - fail on different image size or sector allocation\n"
+           "\n"
+           "Parameters to dd subcommand:\n"
+           "  'bs=BYTES' read and write up to BYTES bytes at a time\n"
+/*         "  'cbs=BYTES' convert BYTES bytes at a time\n"
+           "  'conv=CONVS' convert the file as per the comma separated "
+           "symbol list\n" */
+           "  'count=N' copy only N input blocks\n"
+           "  'ibs=BYTES' read up to BYTES bytes at a time (default: 512)\n"
+           "  'if=FILE' read from FILE instead of stdin\n"
+           "  'obs=BYTES' write BYTES bytes at a time (default: 512)\n"
+           "  'of=FILE' write to FILE instead of stdout\n";
+/*         "  'seek=N' skip N obs-sized blocks at start of output\n"
+           "  'skip=N' skip N ibs-sized blocks at start of input\n"
+           "  'status=LEVEL' The LEVEL of information to print to stderr; "
+           "'none' suppresses everything but error messages, 'noxfer' "
+           "suppresses the final transfer statistics, 'progress' shows "
+           "periodic transfer statistics\n" */
+
 
     printf("%s\nSupported formats:", help_msg);
     bdrv_iterate_format(format_print, NULL);
@@ -3788,6 +3806,819 @@ out:
     return 0;
 }
 
+#define C_BS      01
+#define C_CBS     02
+#define C_CONV    04
+#define C_COUNT   010
+#define C_IBS     020
+#define C_IF      040
+#define C_IFLAG   0100
+#define C_OBS     0200
+#define C_OF      0400
+#define C_OFLAG   01000
+#define C_SEEK    02000
+#define C_SKIP    04000
+#define C_STATUS  010000
+
+struct DdEss {
+    unsigned int flags;
+    unsigned int status;
+    unsigned int conv;
+    size_t count;
+    size_t cbsz; /* Conversion block size */
+};
+
+struct DdIo {
+    size_t bsz;    /* Block size */
+    off_t offset;
+    const char *filename;
+    unsigned int flags;
+    uint8_t *buf;
+};
+
+struct DdOpts {
+    const char *name;
+    int (*f)(const char *, struct DdIo *, struct DdIo *, struct DdEss *);
+    unsigned int flag;
+};
+
+static size_t get_size(const char *str)
+{
+    /* XXX: handle {k,m,g}B notations */
+    unsigned long num;
+    size_t res = 0;
+    const char *buf;
+
+    errno = 0;
+    qemu_strtoul(str, &buf, 0, &num);
+
+    if (num == ULONG_MAX && errno == ERANGE) {
+        error_report("invalid number: %s", str);
+        return res;
+    }
+
+    switch (*buf) {
+    case '\0':
+    case 'c':
+        res = num;
+        break;
+    case 'w':
+        res = num * 2;
+        break;
+    case 'b':
+        res = num * 512;
+        break;
+    case 'K':
+        res = num * 1024;
+        break;
+    case 'M':
+        res = num * 1024 * 1024;
+        break;
+    case 'G':
+        res = num * 1024 * 1024 * 1024;
+        break;
+    case 'T':
+        res = num * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'P':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'E':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'Z':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'Y':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    default:
+        error_report("invalid number: '%s'", str);
+        errno = EINVAL;
+    }
+
+    return res;
+
+}
+
+static off_t get_offset(const char *str)
+{
+    /* XXX handle {k,m,g}B notations */
+    off_t res = 0;
+    long num;
+    const char *buf;
+
+    errno = 0;
+    qemu_strtol(str, &buf, 0, &num);
+
+    if (errno == ERANGE) {
+        error_report("invalid number: '%s'", str);
+        return res;
+    }
+
+    switch (*buf) {
+    case '\0':
+    case 'c':
+        res = num;
+        break;
+    case 'w':
+        res = num * 2;
+        break;
+    case 'b':
+        res = num * 512;
+        break;
+    case 'K':
+        res = num * 1024;
+        break;
+    case 'M':
+        res = num * 1024 * 1024;
+        break;
+    case 'G':
+        res = num * 1024 * 1024 * 1024;
+        break;
+    case 'T':
+        res = num * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'P':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'E':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'Z':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    case 'Y':
+        res = num * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+        break;
+    default:
+        error_report("invalid number: '%s'", str);
+        errno = EINVAL;
+    }
+
+    return res;
+}
+
+static int img_dd_bs(const char *arg,
+                     struct DdIo *in, struct DdIo *out,
+                     struct DdEss *dd)
+{
+    if (strchr(arg, '-')) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    in->bsz = out->bsz = get_size(arg);
+
+    if (in->bsz == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+    if (in->bsz == 0) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+
+    return 0;
+}
+
+static int img_dd_cbs(const char *arg,
+                      struct DdIo *in, struct DdIo *out,
+                      struct DdEss *dd)
+{
+    if (strchr(arg, '-')) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    dd->cbsz = get_size(arg);
+
+    if (dd->cbsz == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+    if (dd->cbsz == 0) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+
+    return 0;
+}
+
+struct DdSymbols {
+    const char *name;
+    unsigned int value;
+};
+
+#define C_ASCII    01
+#define C_EBCDIC   02
+#define C_IBM      04
+#define C_BLOCK    010
+#define C_UNBLOCK  020
+#define C_LCASE    040
+#define C_UCASE    0100
+#define C_SPARSE   0200
+#define C_SWAB     0400
+#define C_SYNC     01000
+#define C_EXCL     02000
+#define C_NOCREAT  04000
+#define C_NOTRUNC  010000
+#define C_NOERROR  020000
+#define C_FDATASYNC 040000
+#define C_FSYNC     0100000
+
+static int img_dd_conv(const char *arg,
+                       struct DdIo *in, struct DdIo *out,
+                       struct DdEss *dd)
+{
+    const char *tok;
+    char *str, *tmp;
+    int ret = 0;
+    const struct DdSymbols conv[] = {
+        { "ascii", C_ASCII },
+        { "ebcdic", C_EBCDIC },
+        { "ibm", C_IBM },
+        { "block", C_BLOCK },
+        { "unblock", C_UNBLOCK },
+        { "lcase", C_LCASE },
+        { "ucase", C_UCASE },
+        { "sparse", C_SPARSE },
+        { "sync", C_SYNC },
+        { "excl", C_EXCL },
+        { "nocreat", C_NOCREAT },
+        { "notrunc", C_NOTRUNC },
+        { "noerror", C_NOERROR },
+        { "fdatasync", C_FDATASYNC },
+        { "fsync", C_FSYNC },
+        { NULL, 0 }
+    };
+
+    tmp = str = g_strdup(arg);
+
+    while (tmp != NULL && !ret) {
+        tok = qemu_strsep(&tmp, ",");
+        int j;
+        for (j = 0; conv[j].name != NULL; j++) {
+            if (!strcmp(tok, conv[j].name)) {
+                dd->conv |= conv[j].value;
+                break;
+            }
+        }
+        if (conv[j].name == NULL) {
+            error_report("invalid conversion: '%s'", tok);
+            ret = 1;
+        }
+    }
+
+    g_free(str);
+    return ret;
+}
+
+static int img_dd_count(const char *arg,
+                        struct DdIo *in, struct DdIo *out,
+                        struct DdEss *dd)
+{
+    if (strchr(arg, '-')) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    dd->count = get_size(arg);
+
+    if (dd->count == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int img_dd_ibs(const char *arg,
+                      struct DdIo *in, struct DdIo *out,
+                      struct DdEss *dd)
+{
+    if (strchr(arg, '-')) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    in->bsz = get_size(arg);
+
+    if (in->bsz == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+    if (in->bsz == 0) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    return 0;
+}
+
+static int img_dd_if(const char *arg,
+                     struct DdIo *in, struct DdIo *out,
+                     struct DdEss *dd)
+{
+    in->filename = arg;
+
+    return 0;
+}
+
+#define C_APPEND      01
+#define C_DIRECT      02
+#define C_DIRECTORY   04
+#define C_DSYNC       010
+#define C_SYNC_FLAG   020
+#define C_FULLBLOCK   040
+#define C_NONBLOCK    0100
+#define C_NOATIME     0200
+#define C_NOCACHE     0400
+#define C_NOCTTY      01000
+#define C_NOFOLLOW    02000
+#define C_COUNT_BYTES 04000
+#define C_SKIP_BYTES  010000
+#define C_SEEK_BYTES  020000
+
+static int img_dd_iflag(const char *arg,
+                        struct DdIo *in, struct DdIo *out,
+                        struct DdEss *dd)
+{
+    const struct DdSymbols flags[] = {
+        { "direct", C_DIRECT },
+        { "directory", C_DIRECTORY },
+        { "dsync", C_DSYNC },
+        { "sync", C_SYNC_FLAG },
+        { "fullblock", C_FULLBLOCK },
+        { "nonblock", C_NONBLOCK },
+        { "noatime", C_NOATIME },
+        { "nocache", C_NOCACHE },
+        { "noctty", C_NOCTTY },
+        { "nofollow", C_NOFOLLOW },
+        { "count_bytes", C_COUNT_BYTES },
+        { "skip_bytes", C_SKIP_BYTES },
+        { NULL, 0}
+    };
+
+    for (int j = 0; flags[j].name != NULL; j++) {
+        if (!strcmp(arg, flags[j].name)) {
+            in->flags = flags[j].value;
+            return 0;
+        }
+    }
+
+    error_report("invalid input flag: '%s'", arg);
+    return 1;
+}
+
+static int img_dd_obs(const char *arg,
+                      struct DdIo *in, struct DdIo *out,
+                      struct DdEss *dd)
+{
+    if (strchr(arg, '-')) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+    out->bsz = get_size(arg);
+
+    if (out->bsz == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+    if (out->bsz == 0) {
+        error_report("invalid number: '%s'", arg);
+        return 1;
+    }
+
+
+    return 0;
+}
+
+static int img_dd_of(const char *arg,
+                     struct DdIo *in, struct DdIo *out,
+                     struct DdEss *dd)
+{
+    out->filename = arg;
+
+    return 0;
+}
+
+static int img_dd_oflag(const char *arg,
+                        struct DdIo *in, struct DdIo *out,
+                        struct DdEss *dd)
+{
+    const struct DdSymbols flags[] = {
+        { "append", C_APPEND },
+        { "direct", C_DIRECT },
+        { "directory", C_DIRECTORY },
+        { "dsync", C_DSYNC },
+        { "sync", C_SYNC_FLAG },
+        { "nonblock", C_NONBLOCK },
+        { "noatime", C_NOATIME },
+        { "nocache", C_NOCACHE },
+        { "noctty", C_NOCTTY },
+        { "nofollow", C_NOFOLLOW },
+        { "seek_bytes", C_SEEK_BYTES },
+        { NULL, 0 }
+    };
+
+    for (int j = 0; flags[j].name != NULL; j++) {
+        if (!strcmp(arg, flags[j].name)) {
+            out->flags = flags[j].value;
+            return 0;
+        }
+    }
+
+    error_report("invalid output flag: '%s'", arg);
+    return 1;
+}
+
+static int img_dd_seek(const char *arg,
+                       struct DdIo *in, struct DdIo *out,
+                       struct DdEss *dd)
+{
+    out->offset = get_offset(arg);
+
+    if (out->offset == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int img_dd_skip(const char *arg,
+                       struct DdIo *in, struct DdIo *out,
+                       struct DdEss *dd)
+{
+    in->offset = get_offset(arg);
+
+    if (in->offset == 0 && (errno == EINVAL || errno == ERANGE)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#define C_STATUS_DEFAULT  00
+#define C_STATUS_NONE     01
+#define C_STATUS_NOXFER   02
+#define C_STATUS_PROGRESS 04
+
+static int img_dd_status(const char *arg,
+                         struct DdIo *in, struct DdIo *out,
+                         struct DdEss *dd)
+{
+    const struct DdSymbols dd_status[] = {
+        { "none", C_STATUS_NONE },
+        { "noxfer", C_STATUS_NOXFER },
+        { "progress", C_STATUS_PROGRESS },
+        { "default", C_STATUS_DEFAULT },
+        { 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;
+}
+
+/* Conversion table for later user for the conv option.
+
+static char const ascii_to_ebcdic[] =
+{
+  '\000', '\001', '\002', '\003', '\067', '\055', '\056', '\057',
+  '\026', '\005', '\045', '\013', '\014', '\015', '\016', '\017',
+  '\020', '\021', '\022', '\023', '\074', '\075', '\062', '\046',
+  '\030', '\031', '\077', '\047', '\034', '\035', '\036', '\037',
+  '\100', '\132', '\177', '\173', '\133', '\154', '\120', '\175',
+  '\115', '\135', '\134', '\116', '\153', '\140', '\113', '\141',
+  '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+  '\370', '\371', '\172', '\136', '\114', '\176', '\156', '\157',
+  '\174', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+  '\310', '\311', '\321', '\322', '\323', '\324', '\325', '\326',
+  '\327', '\330', '\331', '\342', '\343', '\344', '\345', '\346',
+  '\347', '\350', '\351', '\255', '\340', '\275', '\232', '\155',
+  '\171', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+  '\210', '\211', '\221', '\222', '\223', '\224', '\225', '\226',
+  '\227', '\230', '\231', '\242', '\243', '\244', '\245', '\246',
+  '\247', '\250', '\251', '\300', '\117', '\320', '\137', '\007',
+  '\040', '\041', '\042', '\043', '\044', '\025', '\006', '\027',
+  '\050', '\051', '\052', '\053', '\054', '\011', '\012', '\033',
+  '\060', '\061', '\032', '\063', '\064', '\065', '\066', '\010',
+  '\070', '\071', '\072', '\073', '\004', '\024', '\076', '\341',
+  '\101', '\102', '\103', '\104', '\105', '\106', '\107', '\110',
+  '\111', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+  '\130', '\131', '\142', '\143', '\144', '\145', '\146', '\147',
+  '\150', '\151', '\160', '\161', '\162', '\163', '\164', '\165',
+  '\166', '\167', '\170', '\200', '\212', '\213', '\214', '\215',
+  '\216', '\217', '\220', '\152', '\233', '\234', '\235', '\236',
+  '\237', '\240', '\252', '\253', '\254', '\112', '\256', '\257',
+  '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+  '\270', '\271', '\272', '\273', '\274', '\241', '\276', '\277',
+  '\312', '\313', '\314', '\315', '\316', '\317', '\332', '\333',
+  '\334', '\335', '\336', '\337', '\352', '\353', '\354', '\355',
+  '\356', '\357', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static char const ascii_to_ibm[] =
+{
+  '\000', '\001', '\002', '\003', '\067', '\055', '\056', '\057',
+  '\026', '\005', '\045', '\013', '\014', '\015', '\016', '\017',
+  '\020', '\021', '\022', '\023', '\074', '\075', '\062', '\046',
+  '\030', '\031', '\077', '\047', '\034', '\035', '\036', '\037',
+  '\100', '\132', '\177', '\173', '\133', '\154', '\120', '\175',
+  '\115', '\135', '\134', '\116', '\153', '\140', '\113', '\141',
+  '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+  '\370', '\371', '\172', '\136', '\114', '\176', '\156', '\157',
+  '\174', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
+  '\310', '\311', '\321', '\322', '\323', '\324', '\325', '\326',
+  '\327', '\330', '\331', '\342', '\343', '\344', '\345', '\346',
+  '\347', '\350', '\351', '\255', '\340', '\275', '\137', '\155',
+  '\171', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+  '\210', '\211', '\221', '\222', '\223', '\224', '\225', '\226',
+  '\227', '\230', '\231', '\242', '\243', '\244', '\245', '\246',
+  '\247', '\250', '\251', '\300', '\117', '\320', '\241', '\007',
+  '\040', '\041', '\042', '\043', '\044', '\025', '\006', '\027',
+  '\050', '\051', '\052', '\053', '\054', '\011', '\012', '\033',
+  '\060', '\061', '\032', '\063', '\064', '\065', '\066', '\010',
+  '\070', '\071', '\072', '\073', '\004', '\024', '\076', '\341',
+  '\101', '\102', '\103', '\104', '\105', '\106', '\107', '\110',
+  '\111', '\121', '\122', '\123', '\124', '\125', '\126', '\127',
+  '\130', '\131', '\142', '\143', '\144', '\145', '\146', '\147',
+  '\150', '\151', '\160', '\161', '\162', '\163', '\164', '\165',
+  '\166', '\167', '\170', '\200', '\212', '\213', '\214', '\215',
+  '\216', '\217', '\220', '\232', '\233', '\234', '\235', '\236',
+  '\237', '\240', '\252', '\253', '\254', '\255', '\256', '\257',
+  '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+  '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+  '\312', '\313', '\314', '\315', '\316', '\317', '\332', '\333',
+  '\334', '\335', '\336', '\337', '\352', '\353', '\354', '\355',
+  '\356', '\357', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+
+static char const ebcdic_to_ascii[] =
+{
+  '\000', '\001', '\002', '\003', '\234', '\011', '\206', '\177',
+  '\227', '\215', '\216', '\013', '\014', '\015', '\016', '\017',
+  '\020', '\021', '\022', '\023', '\235', '\205', '\010', '\207',
+  '\030', '\031', '\222', '\217', '\034', '\035', '\036', '\037',
+  '\200', '\201', '\202', '\203', '\204', '\012', '\027', '\033',
+  '\210', '\211', '\212', '\213', '\214', '\005', '\006', '\007',
+  '\220', '\221', '\026', '\223', '\224', '\225', '\226', '\004',
+  '\230', '\231', '\232', '\233', '\024', '\025', '\236', '\032',
+  '\040', '\240', '\241', '\242', '\243', '\244', '\245', '\246',
+  '\247', '\250', '\325', '\056', '\074', '\050', '\053', '\174',
+  '\046', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+  '\260', '\261', '\041', '\044', '\052', '\051', '\073', '\176',
+  '\055', '\057', '\262', '\263', '\264', '\265', '\266', '\267',
+  '\270', '\271', '\313', '\054', '\045', '\137', '\076', '\077',
+  '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301',
+  '\302', '\140', '\072', '\043', '\100', '\047', '\075', '\042',
+  '\303', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+  '\150', '\151', '\304', '\305', '\306', '\307', '\310', '\311',
+  '\312', '\152', '\153', '\154', '\155', '\156', '\157', '\160',
+  '\161', '\162', '\136', '\314', '\315', '\316', '\317', '\320',
+  '\321', '\345', '\163', '\164', '\165', '\166', '\167', '\170',
+  '\171', '\172', '\322', '\323', '\324', '\133', '\326', '\327',
+  '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
+  '\340', '\341', '\342', '\343', '\344', '\135', '\346', '\347',
+  '\173', '\101', '\102', '\103', '\104', '\105', '\106', '\107',
+  '\110', '\111', '\350', '\351', '\352', '\353', '\354', '\355',
+  '\175', '\112', '\113', '\114', '\115', '\116', '\117', '\120',
+  '\121', '\122', '\356', '\357', '\360', '\361', '\362', '\363',
+  '\134', '\237', '\123', '\124', '\125', '\126', '\127', '\130',
+  '\131', '\132', '\364', '\365', '\366', '\367', '\370', '\371',
+  '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+  '\070', '\071', '\372', '\373', '\374', '\375', '\376', '\377'
+};
+*/
+
+
+static int img_dd(int argc, char **argv)
+{
+    int ret = 0;
+    char *arg = NULL;
+    char *tmp;
+    struct DdEss dd;
+    struct DdIo in, out;
+    BlockDriver *drv = NULL, *proto_drv = NULL;
+    BlockBackend *blk1 = NULL, *blk2 = NULL;
+    QemuOpts *opts = NULL;
+    QemuOptsList *create_opts = NULL;
+    Error *local_err = NULL;
+    bool image_opts = false;
+    int c;
+    const char *out_fmt = "raw";
+    const char *fmt = NULL;
+    int64_t size = 0;
+
+    dd.flags = 0;
+    dd.status = C_STATUS_DEFAULT;
+    dd.conv = 0;
+    dd.count = 0;
+    in.buf = out.buf = NULL;
+    dd.cbsz = in.bsz = out.bsz = 512; /* Block size is by default 512 bytes */
+
+    const struct DdOpts options[] = {
+        { "bs", img_dd_bs, C_BS },
+        { "cbs", img_dd_cbs, C_CBS },
+        { "conv", img_dd_conv, C_CONV },
+        { "count", img_dd_count, C_COUNT },
+        { "ibs", img_dd_ibs, C_IBS },
+        { "if", img_dd_if, C_IF },
+        { "iflag", img_dd_iflag, C_IFLAG },
+        { "obs", img_dd_obs, C_OBS },
+        { "of", img_dd_of, C_OF },
+        { "oflag", img_dd_oflag, C_OFLAG },
+        { "seek", img_dd_seek, C_SEEK },
+        { "skip", img_dd_skip, C_SKIP },
+        { "status", img_dd_status, C_STATUS },
+        { NULL, NULL, 0 }
+    };
+    const struct option long_options[] = {
+        { "help", no_argument, 0, 'h'},
+        { "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+        { 0, 0, 0, 0 }
+    };
+
+    while ((c = getopt_long(argc, argv, "hf:O:", long_options, NULL))) {
+        if (c == EOF) {
+            break;
+        }
+        switch (c) {
+        case 'O':
+            out_fmt = optarg;
+            break;
+        case 'f':
+            fmt = optarg;
+            break;
+        case '?':
+            error_report("Try 'qemu-img --help' for more information.");
+            ret = -1;
+            goto out;
+            break;
+        case 'h':
+            help();
+            break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
+        }
+    }
+
+    for (int i = optind; i < argc; i++) {
+        arg = g_strdup(argv[i]);
+
+        tmp = strchr(arg, '=');
+        if (tmp == NULL) {
+            error_report("unrecognized operand %s", arg);
+            ret = -1;
+            goto out;
+        }
+
+        *tmp++ = '\0';
+        int j;
+        for (j = 0; options[j].name != NULL; j++) {
+            if (!strcmp(arg, options[j].name)) {
+                break;
+            }
+        }
+        if (options[j].name == NULL) {
+            error_report("unrecognized operand %s", arg);
+            ret = -1;
+            goto out;
+        }
+
+        if (options[j].f(tmp, &in, &out, &dd) != 0) {
+            ret = -1;
+            goto out;
+        }
+        dd.flags |= options[j].flag;
+    }
+
+    if (dd.flags & C_IF && dd.flags & C_OF) {
+        blk1 = img_open(image_opts, in.filename, fmt, 0, false, true);
+
+        if (!blk1) {
+            error_report("failed to open '%s'", in.filename);
+            ret = -1;
+            goto out;
+        }
+
+        drv = bdrv_find_format(out_fmt);
+        if (!drv) {
+            error_report("Unknown file format");
+            ret = -1;
+            goto out;
+        }
+        proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
+
+        if (!proto_drv) {
+            error_report_err(local_err);
+            ret = -1;
+            goto out;
+        }
+        if (!drv->create_opts) {
+            error_report("Format driver '%s' does not support image creation",
+                       drv->format_name);
+            ret = -1;
+            goto out;
+        }
+        if (!proto_drv->create_opts) {
+            error_report("Protocol driver '%s' does not support image creation",
+                       proto_drv->format_name);
+            ret = -1;
+            goto out;
+        }
+        create_opts = qemu_opts_append(create_opts, drv->create_opts);
+        create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+
+        opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+
+        size =  blk_getlength(blk1);
+
+        if (dd.flags & C_COUNT && dd.count * in.bsz < size) {
+            qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
+                                dd.count * in.bsz, &error_abort);
+        } else {
+            qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
+        }
+
+        ret = bdrv_create(drv, out.filename, opts, &local_err);
+        if (ret < 0) {
+            error_reportf_err(local_err,
+                              "%s: error while copying and converting raw: ",
+                              out.filename);
+            ret = -1;
+            goto out;
+        }
+
+        blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
+                        false, true);
+
+        if (!blk2) {
+            error_report("failed to open '%s'", out.filename);
+            ret = -1;
+            goto out;
+        }
+
+        in.buf = g_new(uint8_t, in.bsz);
+        out.buf = g_new(uint8_t, out.bsz);
+
+        int64_t count, block_count;
+
+        for (count = 0, block_count = 0; count < size;
+             count += ret, block_count++) {
+            /* If the count option is specified. */
+            if (dd.flags & C_COUNT && block_count >= dd.count) {
+                break;
+            }
+
+            if (in.bsz + count > size) {
+                ret = blk_pread(blk1, count, in.buf, size - count);
+            } else {
+                ret = blk_pread(blk1, count, in.buf, in.bsz);
+            }
+
+            if (ret < 0) {
+                error_report("error while reading from input image file: %s",
+                             strerror(-ret));
+                ret = -1;
+                goto out;
+            }
+            int out_ret = blk_pwrite(blk2, count, in.buf, ret, 0);
+
+            if (out_ret < 0) {
+                error_report("error while writing to output image file: %s",
+                             strerror(-out_ret));
+                ret = -1;
+                goto out;
+            }
+        }
+
+    } else {
+        error_report("Must specify both input and output files");
+        ret = -1;
+        goto out;
+    }
+out:
+    g_free(arg);
+    qemu_opts_del(opts);
+    qemu_opts_free(create_opts);
+    blk_unref(blk1);
+    blk_unref(blk2);
+    g_free(in.buf);
+    g_free(out.buf);
+
+    if (ret) {
+        return 1;
+    }
+    return 0;
+}
+
 
 static const img_cmd_t img_cmds[] = {
 #define DEF(option, callback, arg_string)        \
-- 
2.9.0

             reply	other threads:[~2016-06-22 17:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-22 17:21 Reda Sallahi [this message]
2016-06-23  3:32 ` [Qemu-devel] [PATCH RFC 1/1] qemu-img: add the 'dd' subcommand Fam Zheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160622172119.GA4709@localhost \
    --to=fullmanet@gmail.com \
    --cc=famz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.