]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch
update submodule and patches to QEMU 8.1.5
[pve-qemu.git] / debian / patches / pve / 0009-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch
CommitLineData
23102ed6 1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
3c6facff 2From: Wolfgang Bumiller <w.bumiller@proxmox.com>
83faa3fe
TL
3Date: Mon, 6 Apr 2020 12:16:40 +0200
4Subject: [PATCH] PVE: [Up] qemu-img dd: add osize and read from/to
53e83913 5 stdin/stdout
3c6facff
WB
6
7Neither convert nor dd were previously able to write to or
8read from a pipe. Particularly serializing an image file
9into a raw stream or vice versa can be useful, but using
10`qemu-img convert -f qcow2 -O raw foo.qcow2 /dev/stdout` in
11a pipe will fail trying to seek.
12
13While dd and convert have overlapping use cases, `dd` is a
14simple read/write loop while convert is much more
15sophisticated and has ways to dealing with holes and blocks
16of zeroes.
17Since these typically can't be detected in pipes via
18SEEK_DATA/HOLE or skipped while writing, dd seems to be the
19better choice for implementing stdin/stdout streams.
20
21This patch causes "if" and "of" to default to stdin and
22stdout respectively, allowing only the "raw" format to be
23used in these cases.
24Since the input can now be a pipe we have no way of
25detecting the size of the output image to create. Since we
26also want to support images with a size not matching the
27dd command's "bs" parameter (which, together with "count"
28could be used to calculate the desired size, and is already
29used to limit it), the "osize" option is added to explicitly
30override the output file's size.
31
32Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
b855dce7 33Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
5b15e2ec 34Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
3c6facff 35---
67af0fa4 36 qemu-img-cmds.hx | 4 +-
5b15e2ec
FE
37 qemu-img.c | 202 ++++++++++++++++++++++++++++++-----------------
38 2 files changed, 133 insertions(+), 73 deletions(-)
3c6facff 39
67af0fa4 40diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
dc9827a6 41index 1b1dab5b17..d1616c045a 100644
67af0fa4
WB
42--- a/qemu-img-cmds.hx
43+++ b/qemu-img-cmds.hx
60ae3775 44@@ -58,9 +58,9 @@ SRST
83faa3fe 45 ERST
67af0fa4
WB
46
47 DEF("dd", img_dd,
6838f038
WB
48- "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
49+ "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output")
83faa3fe
TL
50 SRST
51-.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT
52+.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT
53 ERST
67af0fa4
WB
54
55 DEF("info", img_info,
3c6facff 56diff --git a/qemu-img.c b/qemu-img.c
4b7975e7 57index 25d427edd1..220e6ec577 100644
3c6facff
WB
58--- a/qemu-img.c
59+++ b/qemu-img.c
4b7975e7 60@@ -4899,10 +4899,12 @@ static int img_bitmap(int argc, char **argv)
3c6facff
WB
61 #define C_IF 04
62 #define C_OF 010
63 #define C_SKIP 020
64+#define C_OSIZE 040
65
66 struct DdInfo {
67 unsigned int flags;
68 int64_t count;
69+ int64_t osize;
70 };
71
72 struct DdIo {
4b7975e7 73@@ -4978,6 +4980,19 @@ static int img_dd_skip(const char *arg,
3c6facff
WB
74 return 0;
75 }
76
77+static int img_dd_osize(const char *arg,
78+ struct DdIo *in, struct DdIo *out,
79+ struct DdInfo *dd)
80+{
60ae3775 81+ dd->osize = cvtnum("size", arg);
3c6facff
WB
82+
83+ if (dd->osize < 0) {
3c6facff
WB
84+ return 1;
85+ }
86+
87+ return 0;
88+}
89+
90 static int img_dd(int argc, char **argv)
91 {
92 int ret = 0;
4b7975e7 93@@ -5018,6 +5033,7 @@ static int img_dd(int argc, char **argv)
3c6facff
WB
94 { "if", img_dd_if, C_IF },
95 { "of", img_dd_of, C_OF },
96 { "skip", img_dd_skip, C_SKIP },
97+ { "osize", img_dd_osize, C_OSIZE },
98 { NULL, NULL, 0 }
99 };
100 const struct option long_options[] = {
4b7975e7 101@@ -5093,91 +5109,112 @@ static int img_dd(int argc, char **argv)
3c6facff
WB
102 arg = NULL;
103 }
104
105- if (!(dd.flags & C_IF && dd.flags & C_OF)) {
106- error_report("Must specify both input and output files");
107+ if (!(dd.flags & C_IF) && (!fmt || strcmp(fmt, "raw") != 0)) {
108+ error_report("Input format must be raw when readin from stdin");
3c6facff
WB
109 ret = -1;
110 goto out;
111 }
8dca018b
SR
112-
113- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
114- force_share);
115-
116- if (!blk1) {
117+ if (!(dd.flags & C_OF) && strcmp(out_fmt, "raw") != 0) {
118+ error_report("Output format must be raw when writing to stdout");
119 ret = -1;
6838f038
WB
120 goto out;
121 }
122
8dca018b
SR
123- drv = bdrv_find_format(out_fmt);
124- if (!drv) {
125- error_report("Unknown file format");
126- ret = -1;
127- goto out;
128- }
129- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
3c6facff 130+ if (dd.flags & C_IF) {
6838f038
WB
131+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
132+ force_share);
3c6facff 133
8dca018b
SR
134- if (!proto_drv) {
135- error_report_err(local_err);
136- ret = -1;
137- goto out;
4fd0fa7f 138- }
8dca018b
SR
139- if (!drv->create_opts) {
140- error_report("Format driver '%s' does not support image creation",
141- drv->format_name);
142- ret = -1;
143- goto out;
144- }
145- if (!proto_drv->create_opts) {
146- error_report("Protocol driver '%s' does not support image creation",
147- proto_drv->format_name);
3c6facff
WB
148- ret = -1;
149- goto out;
4fd0fa7f
TL
150+ if (!blk1) {
151+ ret = -1;
152+ goto out;
153+ }
154 }
8dca018b
SR
155- create_opts = qemu_opts_append(create_opts, drv->create_opts);
156- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
4fd0fa7f 157-
5b15e2ec
FE
158- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
159
8dca018b
SR
160- size = blk_getlength(blk1);
161- if (size < 0) {
162- error_report("Failed to get size for '%s'", in.filename);
b855dce7
TL
163+ if (dd.flags & C_OSIZE) {
164+ size = dd.osize;
165+ } else if (dd.flags & C_IF) {
166+ size = blk_getlength(blk1);
167+ if (size < 0) {
168+ error_report("Failed to get size for '%s'", in.filename);
169+ ret = -1;
170+ goto out;
171+ }
172+ } else if (dd.flags & C_COUNT) {
173+ size = dd.count * in.bsz;
174+ } else {
175+ error_report("Output size must be known when reading from stdin");
176 ret = -1;
177 goto out;
178 }
179
8dca018b 180- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
b855dce7 181+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
8dca018b
SR
182 dd.count * in.bsz < size) {
183 size = dd.count * in.bsz;
b855dce7
TL
184 }
185
8dca018b
SR
186- /* Overflow means the specified offset is beyond input image's size */
187- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
188- size < in.bsz * in.offset)) {
189- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
190- } else {
191- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
192- size - in.bsz * in.offset, &error_abort);
193- }
3c6facff
WB
194+ if (dd.flags & C_OF) {
195+ drv = bdrv_find_format(out_fmt);
196+ if (!drv) {
197+ error_report("Unknown file format");
198+ ret = -1;
199+ goto out;
200+ }
201+ proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
6838f038 202
8dca018b
SR
203- ret = bdrv_create(drv, out.filename, opts, &local_err);
204- if (ret < 0) {
205- error_reportf_err(local_err,
206- "%s: error while creating output image: ",
207- out.filename);
6838f038
WB
208- ret = -1;
209- goto out;
210- }
3c6facff
WB
211+ if (!proto_drv) {
212+ error_report_err(local_err);
213+ ret = -1;
214+ goto out;
215+ }
216+ if (!drv->create_opts) {
217+ error_report("Format driver '%s' does not support image creation",
218+ drv->format_name);
219+ ret = -1;
220+ goto out;
221+ }
222+ if (!proto_drv->create_opts) {
223+ error_report("Protocol driver '%s' does not support image creation",
224+ proto_drv->format_name);
225+ ret = -1;
226+ goto out;
227+ }
228+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
229+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
230
8dca018b
SR
231- /* TODO, we can't honour --image-opts for the target,
232- * since it needs to be given in a format compatible
233- * with the bdrv_create() call above which does not
234- * support image-opts style.
235- */
236- blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
237- false, false, false);
3c6facff
WB
238+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
239
8dca018b
SR
240- if (!blk2) {
241- ret = -1;
242- goto out;
3c6facff
WB
243+ /* Overflow means the specified offset is beyond input image's size */
244+ if (dd.flags & C_OSIZE) {
245+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
246+ } else if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
6838f038 247+ size < in.bsz * in.offset)) {
3c6facff
WB
248+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
249+ } else {
250+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
251+ size - in.bsz * in.offset, &error_abort);
252+ }
8dca018b 253+
3c6facff
WB
254+ ret = bdrv_create(drv, out.filename, opts, &local_err);
255+ if (ret < 0) {
256+ error_reportf_err(local_err,
257+ "%s: error while creating output image: ",
258+ out.filename);
259+ ret = -1;
260+ goto out;
261+ }
8dca018b 262+
6838f038
WB
263+ /* TODO, we can't honour --image-opts for the target,
264+ * since it needs to be given in a format compatible
265+ * with the bdrv_create() call above which does not
266+ * support image-opts style.
267+ */
268+ blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
269+ false, false, false);
8dca018b 270+
3c6facff
WB
271+ if (!blk2) {
272+ ret = -1;
273+ goto out;
274+ }
275 }
276
277 if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
4b7975e7 278@@ -5194,20 +5231,43 @@ static int img_dd(int argc, char **argv)
5b15e2ec 279 in.buf = g_new(uint8_t, in.bsz);
3c6facff 280
d03e1b3c 281 for (out_pos = 0; in_pos < size; ) {
5b15e2ec
FE
282+ int in_ret, out_ret;
283 int bytes = (in_pos + in.bsz > size) ? size - in_pos : in.bsz;
6838f038 284-
5b15e2ec
FE
285- ret = blk_pread(blk1, in_pos, bytes, in.buf, 0);
286- if (ret < 0) {
3c6facff 287+ if (blk1) {
5b15e2ec
FE
288+ in_ret = blk_pread(blk1, in_pos, bytes, in.buf, 0);
289+ if (in_ret == 0) {
290+ in_ret = bytes;
291+ }
292+ } else {
293+ in_ret = read(STDIN_FILENO, in.buf, bytes);
3c6facff
WB
294+ if (in_ret == 0) {
295+ /* early EOF is considered an error */
296+ error_report("Input ended unexpectedly");
297+ ret = -1;
298+ goto out;
299+ }
5b15e2ec
FE
300+ }
301+ if (in_ret < 0) {
3c6facff 302 error_report("error while reading from input image file: %s",
5b15e2ec
FE
303- strerror(-ret));
304+ strerror(-in_ret));
305+ ret = -1;
306 goto out;
3c6facff 307 }
5b15e2ec 308 in_pos += bytes;
3c6facff 309
5b15e2ec
FE
310- ret = blk_pwrite(blk2, out_pos, bytes, in.buf, 0);
311- if (ret < 0) {
3c6facff 312+ if (blk2) {
5b15e2ec
FE
313+ out_ret = blk_pwrite(blk2, out_pos, in_ret, in.buf, 0);
314+ if (out_ret == 0) {
315+ out_ret = in_ret;
316+ }
3c6facff
WB
317+ } else {
318+ out_ret = write(STDOUT_FILENO, in.buf, in_ret);
319+ }
5b15e2ec 320+
3c6facff
WB
321+ if (out_ret != in_ret) {
322 error_report("error while writing to output image file: %s",
5b15e2ec
FE
323- strerror(-ret));
324+ strerror(-out_ret));
325+ ret = -1;
326 goto out;
327 }
328 out_pos += bytes;