]> git.proxmox.com Git - pve-qemu.git/blame - debian/patches/pve/0011-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch
pbs-restore: be more verbose if asked to
[pve-qemu.git] / debian / patches / pve / 0011-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>
3c6facff 34---
67af0fa4 35 qemu-img-cmds.hx | 4 +-
b8d43c59
TL
36 qemu-img.c | 192 +++++++++++++++++++++++++++++------------------
37 2 files changed, 122 insertions(+), 74 deletions(-)
3c6facff 38
67af0fa4 39diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
83faa3fe 40index c9c54de1df..0f98033658 100644
67af0fa4
WB
41--- a/qemu-img-cmds.hx
42+++ b/qemu-img-cmds.hx
83faa3fe
TL
43@@ -51,9 +51,9 @@ SRST
44 ERST
67af0fa4
WB
45
46 DEF("dd", img_dd,
6838f038
WB
47- "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
48+ "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
49 SRST
50-.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT
51+.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT
52 ERST
67af0fa4
WB
53
54 DEF("info", img_info,
3c6facff 55diff --git a/qemu-img.c b/qemu-img.c
83faa3fe 56index 667c540a89..6b7d1fcb51 100644
3c6facff
WB
57--- a/qemu-img.c
58+++ b/qemu-img.c
83faa3fe 59@@ -4444,10 +4444,12 @@ out:
3c6facff
WB
60 #define C_IF 04
61 #define C_OF 010
62 #define C_SKIP 020
63+#define C_OSIZE 040
64
65 struct DdInfo {
66 unsigned int flags;
67 int64_t count;
68+ int64_t osize;
69 };
70
71 struct DdIo {
83faa3fe 72@@ -4526,6 +4528,20 @@ static int img_dd_skip(const char *arg,
3c6facff
WB
73 return 0;
74 }
75
76+static int img_dd_osize(const char *arg,
77+ struct DdIo *in, struct DdIo *out,
78+ struct DdInfo *dd)
79+{
80+ dd->osize = cvtnum(arg);
81+
82+ if (dd->osize < 0) {
83+ error_report("invalid number: '%s'", arg);
84+ return 1;
85+ }
86+
87+ return 0;
88+}
89+
90 static int img_dd(int argc, char **argv)
91 {
92 int ret = 0;
83faa3fe 93@@ -4566,6 +4582,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[] = {
83faa3fe 101@@ -4644,8 +4661,13 @@ 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");
6838f038
WB
109+ ret = -1;
110+ goto out;
111+ }
3c6facff
WB
112+ if (!(dd.flags & C_OF) && strcmp(out_fmt, "raw") != 0) {
113+ error_report("Output format must be raw when writing to stdout");
114 ret = -1;
115 goto out;
116 }
83faa3fe 117@@ -4657,85 +4679,101 @@ static int img_dd(int argc, char **argv)
6838f038
WB
118 goto out;
119 }
120
121- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
122- force_share);
3c6facff 123+ if (dd.flags & C_IF) {
6838f038
WB
124+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
125+ force_share);
3c6facff 126
6838f038 127- if (!blk1) {
3c6facff
WB
128- ret = -1;
129- goto out;
130+ if (!blk1) {
131+ ret = -1;
132+ goto out;
133+ }
134 }
3c6facff 135
6838f038
WB
136- drv = bdrv_find_format(out_fmt);
137- if (!drv) {
138- error_report("Unknown file format");
b855dce7
TL
139+ if (dd.flags & C_OSIZE) {
140+ size = dd.osize;
141+ } else if (dd.flags & C_IF) {
142+ size = blk_getlength(blk1);
143+ if (size < 0) {
144+ error_report("Failed to get size for '%s'", in.filename);
145+ ret = -1;
146+ goto out;
147+ }
148+ } else if (dd.flags & C_COUNT) {
149+ size = dd.count * in.bsz;
150+ } else {
151+ error_report("Output size must be known when reading from stdin");
152 ret = -1;
153 goto out;
154 }
b8d43c59 155- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
b855dce7 156
b8d43c59
TL
157- if (!proto_drv) {
158- error_report_err(local_err);
159- ret = -1;
160- goto out;
161- }
162- if (!drv->create_opts) {
163- error_report("Format driver '%s' does not support image creation",
164- drv->format_name);
165- ret = -1;
166- goto out;
167- }
168- if (!proto_drv->create_opts) {
169- error_report("Protocol driver '%s' does not support image creation",
170- proto_drv->format_name);
171- ret = -1;
172- goto out;
b855dce7 173+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
b8d43c59
TL
174+ dd.count * in.bsz < size) {
175+ size = dd.count * in.bsz;
b855dce7 176 }
b8d43c59
TL
177- create_opts = qemu_opts_append(create_opts, drv->create_opts);
178- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
b855dce7 179
b8d43c59 180- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
3c6facff
WB
181+ if (dd.flags & C_OF) {
182+ drv = bdrv_find_format(out_fmt);
183+ if (!drv) {
184+ error_report("Unknown file format");
185+ ret = -1;
186+ goto out;
187+ }
188+ proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
6838f038 189
b8d43c59
TL
190- size = blk_getlength(blk1);
191- if (size < 0) {
192- error_report("Failed to get size for '%s'", in.filename);
6838f038
WB
193- ret = -1;
194- goto out;
195- }
3c6facff
WB
196+ if (!proto_drv) {
197+ error_report_err(local_err);
198+ ret = -1;
199+ goto out;
200+ }
201+ if (!drv->create_opts) {
202+ error_report("Format driver '%s' does not support image creation",
203+ drv->format_name);
204+ ret = -1;
205+ goto out;
206+ }
207+ if (!proto_drv->create_opts) {
208+ error_report("Protocol driver '%s' does not support image creation",
209+ proto_drv->format_name);
210+ ret = -1;
211+ goto out;
212+ }
213+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
214+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
215
b8d43c59
TL
216- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
217- dd.count * in.bsz < size) {
218- size = dd.count * in.bsz;
219- }
3c6facff
WB
220+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
221
b8d43c59
TL
222- /* Overflow means the specified offset is beyond input image's size */
223- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
224- size < in.bsz * in.offset)) {
225- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
226- } else {
227- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
228- size - in.bsz * in.offset, &error_abort);
229- }
3c6facff
WB
230+ /* Overflow means the specified offset is beyond input image's size */
231+ if (dd.flags & C_OSIZE) {
232+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
233+ } else if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
6838f038 234+ size < in.bsz * in.offset)) {
3c6facff
WB
235+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
236+ } else {
237+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
238+ size - in.bsz * in.offset, &error_abort);
239+ }
b8d43c59
TL
240
241- ret = bdrv_create(drv, out.filename, opts, &local_err);
242- if (ret < 0) {
243- error_reportf_err(local_err,
244- "%s: error while creating output image: ",
245- out.filename);
246- ret = -1;
247- goto out;
248- }
3c6facff
WB
249+ ret = bdrv_create(drv, out.filename, opts, &local_err);
250+ if (ret < 0) {
251+ error_reportf_err(local_err,
252+ "%s: error while creating output image: ",
253+ out.filename);
254+ ret = -1;
255+ goto out;
256+ }
b8d43c59
TL
257
258- /* TODO, we can't honour --image-opts for the target,
259- * since it needs to be given in a format compatible
260- * with the bdrv_create() call above which does not
261- * support image-opts style.
262- */
263- blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
264- false, false, false);
6838f038
WB
265+ /* TODO, we can't honour --image-opts for the target,
266+ * since it needs to be given in a format compatible
267+ * with the bdrv_create() call above which does not
268+ * support image-opts style.
269+ */
270+ blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
271+ false, false, false);
b8d43c59
TL
272
273- if (!blk2) {
274- ret = -1;
275- goto out;
3c6facff
WB
276+ if (!blk2) {
277+ ret = -1;
278+ goto out;
279+ }
280 }
281
282 if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
83faa3fe 283@@ -4753,11 +4791,17 @@ static int img_dd(int argc, char **argv)
3c6facff
WB
284
285 for (out_pos = 0; in_pos < size; block_count++) {
286 int in_ret, out_ret;
6838f038 287-
3c6facff
WB
288- if (in_pos + in.bsz > size) {
289- in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos);
6838f038 290+ size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
3c6facff
WB
291+ if (blk1) {
292+ in_ret = blk_pread(blk1, in_pos, in.buf, in_bsz);
293 } else {
294- in_ret = blk_pread(blk1, in_pos, in.buf, in.bsz);
295+ in_ret = read(STDIN_FILENO, in.buf, in_bsz);
296+ if (in_ret == 0) {
297+ /* early EOF is considered an error */
298+ error_report("Input ended unexpectedly");
299+ ret = -1;
300+ goto out;
301+ }
302 }
303 if (in_ret < 0) {
304 error_report("error while reading from input image file: %s",
83faa3fe 305@@ -4767,9 +4811,13 @@ static int img_dd(int argc, char **argv)
3c6facff
WB
306 }
307 in_pos += in_ret;
308
309- out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0);
310+ if (blk2) {
311+ out_ret = blk_pwrite(blk2, out_pos, in.buf, in_ret, 0);
312+ } else {
313+ out_ret = write(STDOUT_FILENO, in.buf, in_ret);
314+ }
315
316- if (out_ret < 0) {
317+ if (out_ret != in_ret) {
318 error_report("error while writing to output image file: %s",
319 strerror(-out_ret));
320 ret = -1;