]> git.proxmox.com Git - mirror_qemu.git/blame - qemu-io-cmds.c
qemu-io: Check for trailing chars
[mirror_qemu.git] / qemu-io-cmds.c
CommitLineData
797ac58c
KW
1/*
2 * Command line utility to exercise the QEMU I/O path.
3 *
4 * Copyright (C) 2009 Red Hat, Inc.
5 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
3d21994f 11#include "qemu-io.h"
4c7b7e9b
HR
12#include "sysemu/block-backend.h"
13#include "block/block.h"
14#include "block/block_int.h" /* for info_f() */
a8d8ecb7 15#include "block/qapi.h"
d49b6836 16#include "qemu/error-report.h"
6a1751b7 17#include "qemu/main-loop.h"
cd33d02a 18#include "qemu/timer.h"
a91f9584 19#include "sysemu/block-backend.h"
797ac58c
KW
20
21#define CMD_NOFILE_OK 0x01
22
f9883880 23bool qemuio_misalign;
797ac58c 24
c2cdf5c5
KW
25static cmdinfo_t *cmdtab;
26static int ncmds;
27
28static int compare_cmdname(const void *a, const void *b)
29{
30 return strcmp(((const cmdinfo_t *)a)->name,
31 ((const cmdinfo_t *)b)->name);
32}
33
34void qemuio_add_command(const cmdinfo_t *ci)
35{
02c4f26b 36 cmdtab = g_renew(cmdinfo_t, cmdtab, ++ncmds);
c2cdf5c5
KW
37 cmdtab[ncmds - 1] = *ci;
38 qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname);
39}
40
41int qemuio_command_usage(const cmdinfo_t *ci)
42{
43 printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
44 return 0;
45}
46
4c7b7e9b 47static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
c2cdf5c5
KW
48{
49 if (ct->flags & CMD_FLAG_GLOBAL) {
50 return 1;
51 }
4c7b7e9b 52 if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
c2cdf5c5
KW
53 fprintf(stderr, "no file open, try 'help open'\n");
54 return 0;
55 }
56 return 1;
57}
58
4c7b7e9b 59static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
3d21994f 60 char **argv)
c2cdf5c5
KW
61{
62 char *cmd = argv[0];
63
4c7b7e9b 64 if (!init_check_command(blk, ct)) {
c2cdf5c5
KW
65 return 0;
66 }
67
68 if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) {
69 if (ct->argmax == -1) {
70 fprintf(stderr,
71 "bad argument count %d to %s, expected at least %d arguments\n",
72 argc-1, cmd, ct->argmin);
73 } else if (ct->argmin == ct->argmax) {
74 fprintf(stderr,
75 "bad argument count %d to %s, expected %d arguments\n",
76 argc-1, cmd, ct->argmin);
77 } else {
78 fprintf(stderr,
79 "bad argument count %d to %s, expected between %d and %d arguments\n",
80 argc-1, cmd, ct->argmin, ct->argmax);
81 }
82 return 0;
83 }
84 optind = 0;
4c7b7e9b 85 return ct->cfunc(blk, argc, argv);
c2cdf5c5
KW
86}
87
88static const cmdinfo_t *find_command(const char *cmd)
89{
90 cmdinfo_t *ct;
91
92 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
93 if (strcmp(ct->name, cmd) == 0 ||
94 (ct->altname && strcmp(ct->altname, cmd) == 0))
95 {
96 return (const cmdinfo_t *)ct;
97 }
98 }
99 return NULL;
100}
101
4694020d
SH
102/* Invoke fn() for commands with a matching prefix */
103void qemuio_complete_command(const char *input,
104 void (*fn)(const char *cmd, void *opaque),
105 void *opaque)
106{
107 cmdinfo_t *ct;
108 size_t input_len = strlen(input);
109
110 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
111 if (strncmp(input, ct->name, input_len) == 0) {
112 fn(ct->name, opaque);
113 }
114 }
115}
116
c2cdf5c5
KW
117static char **breakline(char *input, int *count)
118{
119 int c = 0;
120 char *p;
5839e53b 121 char **rval = g_new0(char *, 1);
c2cdf5c5
KW
122
123 while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
124 if (!*p) {
125 continue;
126 }
127 c++;
08193dd5 128 rval = g_renew(char *, rval, (c + 1));
c2cdf5c5
KW
129 rval[c - 1] = p;
130 rval[c] = NULL;
131 }
132 *count = c;
133 return rval;
134}
135
797ac58c
KW
136static int64_t cvtnum(const char *s)
137{
138 char *end;
ef5a7885
JS
139 int64_t ret;
140
141 ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
142 if (*end != '\0') {
143 /* Detritus at the end of the string */
144 return -EINVAL;
145 }
146 return ret;
797ac58c
KW
147}
148
0b613881
KW
149#define EXABYTES(x) ((long long)(x) << 60)
150#define PETABYTES(x) ((long long)(x) << 50)
151#define TERABYTES(x) ((long long)(x) << 40)
152#define GIGABYTES(x) ((long long)(x) << 30)
153#define MEGABYTES(x) ((long long)(x) << 20)
154#define KILOBYTES(x) ((long long)(x) << 10)
155
156#define TO_EXABYTES(x) ((x) / EXABYTES(1))
157#define TO_PETABYTES(x) ((x) / PETABYTES(1))
158#define TO_TERABYTES(x) ((x) / TERABYTES(1))
159#define TO_GIGABYTES(x) ((x) / GIGABYTES(1))
160#define TO_MEGABYTES(x) ((x) / MEGABYTES(1))
161#define TO_KILOBYTES(x) ((x) / KILOBYTES(1))
162
163static void cvtstr(double value, char *str, size_t size)
164{
165 char *trim;
166 const char *suffix;
167
168 if (value >= EXABYTES(1)) {
169 suffix = " EiB";
170 snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
171 } else if (value >= PETABYTES(1)) {
172 suffix = " PiB";
173 snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
174 } else if (value >= TERABYTES(1)) {
175 suffix = " TiB";
176 snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
177 } else if (value >= GIGABYTES(1)) {
178 suffix = " GiB";
179 snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
180 } else if (value >= MEGABYTES(1)) {
181 suffix = " MiB";
182 snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
183 } else if (value >= KILOBYTES(1)) {
184 suffix = " KiB";
185 snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
186 } else {
187 suffix = " bytes";
188 snprintf(str, size - 6, "%f", value);
189 }
190
191 trim = strstr(str, ".000");
192 if (trim) {
193 strcpy(trim, suffix);
194 } else {
195 strcat(str, suffix);
196 }
197}
198
199
200
201static struct timeval tsub(struct timeval t1, struct timeval t2)
202{
203 t1.tv_usec -= t2.tv_usec;
204 if (t1.tv_usec < 0) {
205 t1.tv_usec += 1000000;
206 t1.tv_sec--;
207 }
208 t1.tv_sec -= t2.tv_sec;
209 return t1;
210}
211
212static double tdiv(double value, struct timeval tv)
213{
214 return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
215}
216
217#define HOURS(sec) ((sec) / (60 * 60))
218#define MINUTES(sec) (((sec) % (60 * 60)) / 60)
219#define SECONDS(sec) ((sec) % 60)
220
221enum {
222 DEFAULT_TIME = 0x0,
223 TERSE_FIXED_TIME = 0x1,
224 VERBOSE_FIXED_TIME = 0x2,
225};
226
227static void timestr(struct timeval *tv, char *ts, size_t size, int format)
228{
229 double usec = (double)tv->tv_usec / 1000000.0;
230
231 if (format & TERSE_FIXED_TIME) {
232 if (!HOURS(tv->tv_sec)) {
233 snprintf(ts, size, "%u:%02u.%02u",
234 (unsigned int) MINUTES(tv->tv_sec),
235 (unsigned int) SECONDS(tv->tv_sec),
236 (unsigned int) (usec * 100));
237 return;
238 }
239 format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */
240 }
241
242 if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
243 snprintf(ts, size, "%u:%02u:%02u.%02u",
244 (unsigned int) HOURS(tv->tv_sec),
245 (unsigned int) MINUTES(tv->tv_sec),
246 (unsigned int) SECONDS(tv->tv_sec),
247 (unsigned int) (usec * 100));
248 } else {
249 snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000));
250 }
251}
252
797ac58c
KW
253/*
254 * Parse the pattern argument to various sub-commands.
255 *
256 * Because the pattern is used as an argument to memset it must evaluate
257 * to an unsigned integer that fits into a single byte.
258 */
259static int parse_pattern(const char *arg)
260{
261 char *endptr = NULL;
262 long pattern;
263
264 pattern = strtol(arg, &endptr, 0);
265 if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') {
266 printf("%s is not a valid pattern byte\n", arg);
267 return -1;
268 }
269
270 return pattern;
271}
272
273/*
274 * Memory allocation helpers.
275 *
276 * Make sure memory is aligned by default, or purposefully misaligned if
277 * that is specified on the command line.
278 */
279
280#define MISALIGN_OFFSET 16
4c7b7e9b 281static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
797ac58c
KW
282{
283 void *buf;
284
285 if (qemuio_misalign) {
286 len += MISALIGN_OFFSET;
287 }
4c7b7e9b 288 buf = blk_blockalign(blk, len);
797ac58c
KW
289 memset(buf, pattern, len);
290 if (qemuio_misalign) {
291 buf += MISALIGN_OFFSET;
292 }
293 return buf;
294}
295
296static void qemu_io_free(void *p)
297{
298 if (qemuio_misalign) {
299 p -= MISALIGN_OFFSET;
300 }
301 qemu_vfree(p);
302}
303
9b0beaf3 304static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
797ac58c 305{
9b0beaf3
JS
306 uint64_t i;
307 int j;
797ac58c
KW
308 const uint8_t *p;
309
310 for (i = 0, p = buffer; i < len; i += 16) {
311 const uint8_t *s = p;
312
313 printf("%08" PRIx64 ": ", offset + i);
314 for (j = 0; j < 16 && i + j < len; j++, p++) {
315 printf("%02x ", *p);
316 }
317 printf(" ");
318 for (j = 0; j < 16 && i + j < len; j++, s++) {
319 if (isalnum(*s)) {
320 printf("%c", *s);
321 } else {
322 printf(".");
323 }
324 }
325 printf("\n");
326 }
327}
328
329static void print_report(const char *op, struct timeval *t, int64_t offset,
9b0beaf3 330 int64_t count, int64_t total, int cnt, int Cflag)
797ac58c
KW
331{
332 char s1[64], s2[64], ts[64];
333
334 timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
335 if (!Cflag) {
336 cvtstr((double)total, s1, sizeof(s1));
337 cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
9b0beaf3 338 printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n",
797ac58c
KW
339 op, total, count, offset);
340 printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
341 s1, cnt, ts, s2, tdiv((double)cnt, *t));
342 } else {/* bytes,ops,time,bytes/sec,ops/sec */
9b0beaf3 343 printf("%"PRId64",%d,%s,%.3f,%.3f\n",
797ac58c
KW
344 total, cnt, ts,
345 tdiv((double)total, *t),
346 tdiv((double)cnt, *t));
347 }
348}
349
350/*
351 * Parse multiple length statements for vectored I/O, and construct an I/O
352 * vector matching it.
353 */
354static void *
4c7b7e9b 355create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
797ac58c
KW
356 int pattern)
357{
358 size_t *sizes = g_new0(size_t, nr_iov);
359 size_t count = 0;
360 void *buf = NULL;
361 void *p;
362 int i;
363
364 for (i = 0; i < nr_iov; i++) {
365 char *arg = argv[i];
366 int64_t len;
367
368 len = cvtnum(arg);
369 if (len < 0) {
370 printf("non-numeric length argument -- %s\n", arg);
371 goto fail;
372 }
373
374 /* should be SIZE_T_MAX, but that doesn't exist */
375 if (len > INT_MAX) {
376 printf("too large length argument -- %s\n", arg);
377 goto fail;
378 }
379
380 if (len & 0x1ff) {
381 printf("length argument %" PRId64
382 " is not sector aligned\n", len);
383 goto fail;
384 }
385
386 sizes[i] = len;
387 count += len;
388 }
389
390 qemu_iovec_init(qiov, nr_iov);
391
4c7b7e9b 392 buf = p = qemu_io_alloc(blk, count, pattern);
797ac58c
KW
393
394 for (i = 0; i < nr_iov; i++) {
395 qemu_iovec_add(qiov, p, sizes[i]);
396 p += sizes[i];
397 }
398
399fail:
400 g_free(sizes);
401 return buf;
402}
403
9b0beaf3
JS
404static int do_read(BlockBackend *blk, char *buf, int64_t offset, int64_t count,
405 int64_t *total)
797ac58c
KW
406{
407 int ret;
408
9b0beaf3
JS
409 if (count >> 9 > INT_MAX) {
410 return -ERANGE;
411 }
412
4c7b7e9b 413 ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9);
797ac58c
KW
414 if (ret < 0) {
415 return ret;
416 }
417 *total = count;
418 return 1;
419}
420
9b0beaf3
JS
421static int do_write(BlockBackend *blk, char *buf, int64_t offset, int64_t count,
422 int64_t *total)
797ac58c
KW
423{
424 int ret;
425
9b0beaf3
JS
426 if (count >> 9 > INT_MAX) {
427 return -ERANGE;
428 }
429
4c7b7e9b 430 ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9);
797ac58c
KW
431 if (ret < 0) {
432 return ret;
433 }
434 *total = count;
435 return 1;
436}
437
9b0beaf3
JS
438static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
439 int64_t count, int64_t *total)
797ac58c 440{
9b0beaf3
JS
441 if (count > INT_MAX) {
442 return -ERANGE;
443 }
444
4c7b7e9b 445 *total = blk_pread(blk, offset, (uint8_t *)buf, count);
797ac58c
KW
446 if (*total < 0) {
447 return *total;
448 }
449 return 1;
450}
451
9b0beaf3
JS
452static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
453 int64_t count, int64_t *total)
797ac58c 454{
9b0beaf3
JS
455 if (count > INT_MAX) {
456 return -ERANGE;
457 }
458
4c7b7e9b 459 *total = blk_pwrite(blk, offset, (uint8_t *)buf, count);
797ac58c
KW
460 if (*total < 0) {
461 return *total;
462 }
463 return 1;
464}
465
466typedef struct {
4c7b7e9b 467 BlockBackend *blk;
797ac58c 468 int64_t offset;
9b0beaf3
JS
469 int64_t count;
470 int64_t *total;
797ac58c
KW
471 int ret;
472 bool done;
473} CoWriteZeroes;
474
475static void coroutine_fn co_write_zeroes_entry(void *opaque)
476{
477 CoWriteZeroes *data = opaque;
478
4c7b7e9b
HR
479 data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE,
480 data->count / BDRV_SECTOR_SIZE, 0);
797ac58c
KW
481 data->done = true;
482 if (data->ret < 0) {
483 *data->total = data->ret;
484 return;
485 }
486
487 *data->total = data->count;
488}
489
9b0beaf3
JS
490static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
491 int64_t *total)
797ac58c
KW
492{
493 Coroutine *co;
494 CoWriteZeroes data = {
4c7b7e9b 495 .blk = blk,
797ac58c
KW
496 .offset = offset,
497 .count = count,
498 .total = total,
499 .done = false,
500 };
501
9b0beaf3
JS
502 if (count >> BDRV_SECTOR_BITS > INT_MAX) {
503 return -ERANGE;
504 }
505
797ac58c
KW
506 co = qemu_coroutine_create(co_write_zeroes_entry);
507 qemu_coroutine_enter(co, &data);
508 while (!data.done) {
4c7b7e9b 509 aio_poll(blk_get_aio_context(blk), true);
797ac58c
KW
510 }
511 if (data.ret < 0) {
512 return data.ret;
513 } else {
514 return 1;
515 }
516}
517
4c7b7e9b 518static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
9b0beaf3 519 int64_t count, int64_t *total)
797ac58c
KW
520{
521 int ret;
522
9b0beaf3
JS
523 if (count >> 9 > INT_MAX) {
524 return -ERANGE;
525 }
526
4c7b7e9b 527 ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9);
797ac58c
KW
528 if (ret < 0) {
529 return ret;
530 }
531 *total = count;
532 return 1;
533}
534
4c7b7e9b 535static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
9b0beaf3 536 int64_t count, int64_t *total)
797ac58c 537{
9b0beaf3
JS
538 if (count > INT_MAX) {
539 return -ERANGE;
540 }
541
4c7b7e9b 542 *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
797ac58c
KW
543 if (*total < 0) {
544 return *total;
545 }
546 return 1;
547}
548
4c7b7e9b 549static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
9b0beaf3 550 int64_t count, int64_t *total)
797ac58c 551{
9b0beaf3
JS
552 if (count > INT_MAX) {
553 return -ERANGE;
554 }
555
4c7b7e9b 556 *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
797ac58c
KW
557 if (*total < 0) {
558 return *total;
559 }
560 return 1;
561}
562
563#define NOT_DONE 0x7fffffff
564static void aio_rw_done(void *opaque, int ret)
565{
566 *(int *)opaque = ret;
567}
568
4c7b7e9b 569static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
797ac58c
KW
570 int64_t offset, int *total)
571{
572 int async_ret = NOT_DONE;
573
4c7b7e9b
HR
574 blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9,
575 aio_rw_done, &async_ret);
797ac58c
KW
576 while (async_ret == NOT_DONE) {
577 main_loop_wait(false);
578 }
579
580 *total = qiov->size;
581 return async_ret < 0 ? async_ret : 1;
582}
583
4c7b7e9b 584static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
797ac58c
KW
585 int64_t offset, int *total)
586{
587 int async_ret = NOT_DONE;
588
4c7b7e9b
HR
589 blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9,
590 aio_rw_done, &async_ret);
797ac58c
KW
591 while (async_ret == NOT_DONE) {
592 main_loop_wait(false);
593 }
594
595 *total = qiov->size;
596 return async_ret < 0 ? async_ret : 1;
597}
598
599struct multiwrite_async_ret {
600 int num_done;
601 int error;
602};
603
604static void multiwrite_cb(void *opaque, int ret)
605{
606 struct multiwrite_async_ret *async_ret = opaque;
607
608 async_ret->num_done++;
609 if (ret < 0) {
610 async_ret->error = ret;
611 }
612}
613
4c7b7e9b 614static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs,
797ac58c
KW
615 int num_reqs, int *total)
616{
617 int i, ret;
618 struct multiwrite_async_ret async_ret = {
619 .num_done = 0,
620 .error = 0,
621 };
622
623 *total = 0;
624 for (i = 0; i < num_reqs; i++) {
625 reqs[i].cb = multiwrite_cb;
626 reqs[i].opaque = &async_ret;
627 *total += reqs[i].qiov->size;
628 }
629
4c7b7e9b 630 ret = blk_aio_multiwrite(blk, reqs, num_reqs);
797ac58c
KW
631 if (ret < 0) {
632 return ret;
633 }
634
635 while (async_ret.num_done < num_reqs) {
636 main_loop_wait(false);
637 }
638
639 return async_ret.error < 0 ? async_ret.error : 1;
640}
641
642static void read_help(void)
643{
644 printf(
645"\n"
646" reads a range of bytes from the given offset\n"
647"\n"
648" Example:\n"
649" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
650"\n"
651" Reads a segment of the currently open file, optionally dumping it to the\n"
652" standard output stream (with -v option) for subsequent inspection.\n"
653" -b, -- read from the VM state rather than the virtual disk\n"
654" -C, -- report statistics in a machine parsable format\n"
655" -l, -- length for pattern verification (only with -P)\n"
4c7b7e9b 656" -p, -- use blk_pread to read the file\n"
797ac58c
KW
657" -P, -- use a pattern to verify read data\n"
658" -q, -- quiet mode, do not show I/O statistics\n"
659" -s, -- start offset for pattern verification (only with -P)\n"
660" -v, -- dump buffer to standard output\n"
661"\n");
662}
663
4c7b7e9b 664static int read_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
665
666static const cmdinfo_t read_cmd = {
667 .name = "read",
668 .altname = "r",
669 .cfunc = read_f,
670 .argmin = 2,
671 .argmax = -1,
672 .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
673 .oneline = "reads a number of bytes at a specified offset",
674 .help = read_help,
675};
676
4c7b7e9b 677static int read_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
678{
679 struct timeval t1, t2;
680 int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
681 int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
682 int c, cnt;
683 char *buf;
684 int64_t offset;
9b0beaf3 685 int64_t count;
797ac58c 686 /* Some compilers get confused and warn if this is not initialized. */
9b0beaf3
JS
687 int64_t total = 0;
688 int pattern = 0;
689 int64_t pattern_offset = 0, pattern_count = 0;
797ac58c 690
b062ad86 691 while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
797ac58c
KW
692 switch (c) {
693 case 'b':
694 bflag = 1;
695 break;
696 case 'C':
697 Cflag = 1;
698 break;
699 case 'l':
700 lflag = 1;
701 pattern_count = cvtnum(optarg);
702 if (pattern_count < 0) {
703 printf("non-numeric length argument -- %s\n", optarg);
704 return 0;
705 }
706 break;
707 case 'p':
708 pflag = 1;
709 break;
710 case 'P':
711 Pflag = 1;
712 pattern = parse_pattern(optarg);
713 if (pattern < 0) {
714 return 0;
715 }
716 break;
717 case 'q':
718 qflag = 1;
719 break;
720 case 's':
721 sflag = 1;
722 pattern_offset = cvtnum(optarg);
723 if (pattern_offset < 0) {
724 printf("non-numeric length argument -- %s\n", optarg);
725 return 0;
726 }
727 break;
728 case 'v':
729 vflag = 1;
730 break;
731 default:
c2cdf5c5 732 return qemuio_command_usage(&read_cmd);
797ac58c
KW
733 }
734 }
735
736 if (optind != argc - 2) {
c2cdf5c5 737 return qemuio_command_usage(&read_cmd);
797ac58c
KW
738 }
739
740 if (bflag && pflag) {
741 printf("-b and -p cannot be specified at the same time\n");
742 return 0;
743 }
744
745 offset = cvtnum(argv[optind]);
746 if (offset < 0) {
747 printf("non-numeric length argument -- %s\n", argv[optind]);
748 return 0;
749 }
750
751 optind++;
752 count = cvtnum(argv[optind]);
753 if (count < 0) {
754 printf("non-numeric length argument -- %s\n", argv[optind]);
755 return 0;
9b0beaf3
JS
756 } else if (count > SIZE_MAX) {
757 printf("length cannot exceed %" PRIu64 ", given %s\n",
758 (uint64_t) SIZE_MAX, argv[optind]);
759 return 0;
797ac58c
KW
760 }
761
762 if (!Pflag && (lflag || sflag)) {
c2cdf5c5 763 return qemuio_command_usage(&read_cmd);
797ac58c
KW
764 }
765
766 if (!lflag) {
767 pattern_count = count - pattern_offset;
768 }
769
770 if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) {
771 printf("pattern verification range exceeds end of read data\n");
772 return 0;
773 }
774
775 if (!pflag) {
776 if (offset & 0x1ff) {
777 printf("offset %" PRId64 " is not sector aligned\n",
778 offset);
779 return 0;
780 }
781 if (count & 0x1ff) {
9b0beaf3 782 printf("count %"PRId64" is not sector aligned\n",
797ac58c
KW
783 count);
784 return 0;
785 }
786 }
787
4c7b7e9b 788 buf = qemu_io_alloc(blk, count, 0xab);
797ac58c
KW
789
790 gettimeofday(&t1, NULL);
791 if (pflag) {
4c7b7e9b 792 cnt = do_pread(blk, buf, offset, count, &total);
797ac58c 793 } else if (bflag) {
4c7b7e9b 794 cnt = do_load_vmstate(blk, buf, offset, count, &total);
797ac58c 795 } else {
4c7b7e9b 796 cnt = do_read(blk, buf, offset, count, &total);
797ac58c
KW
797 }
798 gettimeofday(&t2, NULL);
799
800 if (cnt < 0) {
801 printf("read failed: %s\n", strerror(-cnt));
802 goto out;
803 }
804
805 if (Pflag) {
806 void *cmp_buf = g_malloc(pattern_count);
807 memset(cmp_buf, pattern, pattern_count);
808 if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
809 printf("Pattern verification failed at offset %"
9b0beaf3 810 PRId64 ", %"PRId64" bytes\n",
797ac58c
KW
811 offset + pattern_offset, pattern_count);
812 }
813 g_free(cmp_buf);
814 }
815
816 if (qflag) {
817 goto out;
818 }
819
820 if (vflag) {
821 dump_buffer(buf, offset, count);
822 }
823
824 /* Finally, report back -- -C gives a parsable format */
825 t2 = tsub(t2, t1);
826 print_report("read", &t2, offset, count, total, cnt, Cflag);
827
828out:
829 qemu_io_free(buf);
830
831 return 0;
832}
833
834static void readv_help(void)
835{
836 printf(
837"\n"
838" reads a range of bytes from the given offset into multiple buffers\n"
839"\n"
840" Example:\n"
841" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
842"\n"
843" Reads a segment of the currently open file, optionally dumping it to the\n"
844" standard output stream (with -v option) for subsequent inspection.\n"
845" Uses multiple iovec buffers if more than one byte range is specified.\n"
846" -C, -- report statistics in a machine parsable format\n"
847" -P, -- use a pattern to verify read data\n"
848" -v, -- dump buffer to standard output\n"
849" -q, -- quiet mode, do not show I/O statistics\n"
850"\n");
851}
852
4c7b7e9b 853static int readv_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
854
855static const cmdinfo_t readv_cmd = {
856 .name = "readv",
857 .cfunc = readv_f,
858 .argmin = 2,
859 .argmax = -1,
860 .args = "[-Cqv] [-P pattern ] off len [len..]",
861 .oneline = "reads a number of bytes at a specified offset",
862 .help = readv_help,
863};
864
4c7b7e9b 865static int readv_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
866{
867 struct timeval t1, t2;
868 int Cflag = 0, qflag = 0, vflag = 0;
869 int c, cnt;
870 char *buf;
871 int64_t offset;
872 /* Some compilers get confused and warn if this is not initialized. */
873 int total = 0;
874 int nr_iov;
875 QEMUIOVector qiov;
876 int pattern = 0;
877 int Pflag = 0;
878
b062ad86 879 while ((c = getopt(argc, argv, "CP:qv")) != -1) {
797ac58c
KW
880 switch (c) {
881 case 'C':
882 Cflag = 1;
883 break;
884 case 'P':
885 Pflag = 1;
886 pattern = parse_pattern(optarg);
887 if (pattern < 0) {
888 return 0;
889 }
890 break;
891 case 'q':
892 qflag = 1;
893 break;
894 case 'v':
895 vflag = 1;
896 break;
897 default:
c2cdf5c5 898 return qemuio_command_usage(&readv_cmd);
797ac58c
KW
899 }
900 }
901
902 if (optind > argc - 2) {
c2cdf5c5 903 return qemuio_command_usage(&readv_cmd);
797ac58c
KW
904 }
905
906
907 offset = cvtnum(argv[optind]);
908 if (offset < 0) {
909 printf("non-numeric length argument -- %s\n", argv[optind]);
910 return 0;
911 }
912 optind++;
913
914 if (offset & 0x1ff) {
915 printf("offset %" PRId64 " is not sector aligned\n",
916 offset);
917 return 0;
918 }
919
920 nr_iov = argc - optind;
4c7b7e9b 921 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
797ac58c
KW
922 if (buf == NULL) {
923 return 0;
924 }
925
926 gettimeofday(&t1, NULL);
4c7b7e9b 927 cnt = do_aio_readv(blk, &qiov, offset, &total);
797ac58c
KW
928 gettimeofday(&t2, NULL);
929
930 if (cnt < 0) {
931 printf("readv failed: %s\n", strerror(-cnt));
932 goto out;
933 }
934
935 if (Pflag) {
936 void *cmp_buf = g_malloc(qiov.size);
937 memset(cmp_buf, pattern, qiov.size);
938 if (memcmp(buf, cmp_buf, qiov.size)) {
939 printf("Pattern verification failed at offset %"
940 PRId64 ", %zd bytes\n", offset, qiov.size);
941 }
942 g_free(cmp_buf);
943 }
944
945 if (qflag) {
946 goto out;
947 }
948
949 if (vflag) {
950 dump_buffer(buf, offset, qiov.size);
951 }
952
953 /* Finally, report back -- -C gives a parsable format */
954 t2 = tsub(t2, t1);
955 print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
956
957out:
958 qemu_iovec_destroy(&qiov);
959 qemu_io_free(buf);
960 return 0;
961}
962
963static void write_help(void)
964{
965 printf(
966"\n"
967" writes a range of bytes from the given offset\n"
968"\n"
969" Example:\n"
970" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
971"\n"
972" Writes into a segment of the currently open file, using a buffer\n"
973" filled with a set pattern (0xcdcdcdcd).\n"
974" -b, -- write to the VM state rather than the virtual disk\n"
4c7b7e9b
HR
975" -c, -- write compressed data with blk_write_compressed\n"
976" -p, -- use blk_pwrite to write the file\n"
797ac58c
KW
977" -P, -- use different pattern to fill file\n"
978" -C, -- report statistics in a machine parsable format\n"
979" -q, -- quiet mode, do not show I/O statistics\n"
4c7b7e9b 980" -z, -- write zeroes using blk_co_write_zeroes\n"
797ac58c
KW
981"\n");
982}
983
4c7b7e9b 984static int write_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
985
986static const cmdinfo_t write_cmd = {
987 .name = "write",
988 .altname = "w",
989 .cfunc = write_f,
990 .argmin = 2,
991 .argmax = -1,
992 .args = "[-bcCpqz] [-P pattern ] off len",
993 .oneline = "writes a number of bytes at a specified offset",
994 .help = write_help,
995};
996
4c7b7e9b 997static int write_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
998{
999 struct timeval t1, t2;
1000 int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
1001 int cflag = 0;
1002 int c, cnt;
1003 char *buf = NULL;
1004 int64_t offset;
9b0beaf3 1005 int64_t count;
797ac58c 1006 /* Some compilers get confused and warn if this is not initialized. */
9b0beaf3 1007 int64_t total = 0;
797ac58c
KW
1008 int pattern = 0xcd;
1009
b062ad86 1010 while ((c = getopt(argc, argv, "bcCpP:qz")) != -1) {
797ac58c
KW
1011 switch (c) {
1012 case 'b':
1013 bflag = 1;
1014 break;
1015 case 'c':
1016 cflag = 1;
1017 break;
1018 case 'C':
1019 Cflag = 1;
1020 break;
1021 case 'p':
1022 pflag = 1;
1023 break;
1024 case 'P':
1025 Pflag = 1;
1026 pattern = parse_pattern(optarg);
1027 if (pattern < 0) {
1028 return 0;
1029 }
1030 break;
1031 case 'q':
1032 qflag = 1;
1033 break;
1034 case 'z':
1035 zflag = 1;
1036 break;
1037 default:
c2cdf5c5 1038 return qemuio_command_usage(&write_cmd);
797ac58c
KW
1039 }
1040 }
1041
1042 if (optind != argc - 2) {
c2cdf5c5 1043 return qemuio_command_usage(&write_cmd);
797ac58c
KW
1044 }
1045
1046 if (bflag + pflag + zflag > 1) {
1047 printf("-b, -p, or -z cannot be specified at the same time\n");
1048 return 0;
1049 }
1050
1051 if (zflag && Pflag) {
1052 printf("-z and -P cannot be specified at the same time\n");
1053 return 0;
1054 }
1055
1056 offset = cvtnum(argv[optind]);
1057 if (offset < 0) {
1058 printf("non-numeric length argument -- %s\n", argv[optind]);
1059 return 0;
1060 }
1061
1062 optind++;
1063 count = cvtnum(argv[optind]);
1064 if (count < 0) {
1065 printf("non-numeric length argument -- %s\n", argv[optind]);
1066 return 0;
9b0beaf3
JS
1067 } else if (count > SIZE_MAX) {
1068 printf("length cannot exceed %" PRIu64 ", given %s\n",
1069 (uint64_t) SIZE_MAX, argv[optind]);
1070 return 0;
797ac58c
KW
1071 }
1072
1073 if (!pflag) {
1074 if (offset & 0x1ff) {
1075 printf("offset %" PRId64 " is not sector aligned\n",
1076 offset);
1077 return 0;
1078 }
1079
1080 if (count & 0x1ff) {
9b0beaf3 1081 printf("count %"PRId64" is not sector aligned\n",
797ac58c
KW
1082 count);
1083 return 0;
1084 }
1085 }
1086
1087 if (!zflag) {
4c7b7e9b 1088 buf = qemu_io_alloc(blk, count, pattern);
797ac58c
KW
1089 }
1090
1091 gettimeofday(&t1, NULL);
1092 if (pflag) {
4c7b7e9b 1093 cnt = do_pwrite(blk, buf, offset, count, &total);
797ac58c 1094 } else if (bflag) {
4c7b7e9b 1095 cnt = do_save_vmstate(blk, buf, offset, count, &total);
797ac58c 1096 } else if (zflag) {
4c7b7e9b 1097 cnt = do_co_write_zeroes(blk, offset, count, &total);
797ac58c 1098 } else if (cflag) {
4c7b7e9b 1099 cnt = do_write_compressed(blk, buf, offset, count, &total);
797ac58c 1100 } else {
4c7b7e9b 1101 cnt = do_write(blk, buf, offset, count, &total);
797ac58c
KW
1102 }
1103 gettimeofday(&t2, NULL);
1104
1105 if (cnt < 0) {
1106 printf("write failed: %s\n", strerror(-cnt));
1107 goto out;
1108 }
1109
1110 if (qflag) {
1111 goto out;
1112 }
1113
1114 /* Finally, report back -- -C gives a parsable format */
1115 t2 = tsub(t2, t1);
1116 print_report("wrote", &t2, offset, count, total, cnt, Cflag);
1117
1118out:
1119 if (!zflag) {
1120 qemu_io_free(buf);
1121 }
1122
1123 return 0;
1124}
1125
1126static void
1127writev_help(void)
1128{
1129 printf(
1130"\n"
1131" writes a range of bytes from the given offset source from multiple buffers\n"
1132"\n"
1133" Example:\n"
6e6507c0 1134" 'writev 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
797ac58c
KW
1135"\n"
1136" Writes into a segment of the currently open file, using a buffer\n"
1137" filled with a set pattern (0xcdcdcdcd).\n"
1138" -P, -- use different pattern to fill file\n"
1139" -C, -- report statistics in a machine parsable format\n"
1140" -q, -- quiet mode, do not show I/O statistics\n"
1141"\n");
1142}
1143
4c7b7e9b 1144static int writev_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
1145
1146static const cmdinfo_t writev_cmd = {
1147 .name = "writev",
1148 .cfunc = writev_f,
1149 .argmin = 2,
1150 .argmax = -1,
1151 .args = "[-Cq] [-P pattern ] off len [len..]",
1152 .oneline = "writes a number of bytes at a specified offset",
1153 .help = writev_help,
1154};
1155
4c7b7e9b 1156static int writev_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1157{
1158 struct timeval t1, t2;
1159 int Cflag = 0, qflag = 0;
1160 int c, cnt;
1161 char *buf;
1162 int64_t offset;
1163 /* Some compilers get confused and warn if this is not initialized. */
1164 int total = 0;
1165 int nr_iov;
1166 int pattern = 0xcd;
1167 QEMUIOVector qiov;
1168
b062ad86 1169 while ((c = getopt(argc, argv, "CqP:")) != -1) {
797ac58c
KW
1170 switch (c) {
1171 case 'C':
1172 Cflag = 1;
1173 break;
1174 case 'q':
1175 qflag = 1;
1176 break;
1177 case 'P':
1178 pattern = parse_pattern(optarg);
1179 if (pattern < 0) {
1180 return 0;
1181 }
1182 break;
1183 default:
c2cdf5c5 1184 return qemuio_command_usage(&writev_cmd);
797ac58c
KW
1185 }
1186 }
1187
1188 if (optind > argc - 2) {
c2cdf5c5 1189 return qemuio_command_usage(&writev_cmd);
797ac58c
KW
1190 }
1191
1192 offset = cvtnum(argv[optind]);
1193 if (offset < 0) {
1194 printf("non-numeric length argument -- %s\n", argv[optind]);
1195 return 0;
1196 }
1197 optind++;
1198
1199 if (offset & 0x1ff) {
1200 printf("offset %" PRId64 " is not sector aligned\n",
1201 offset);
1202 return 0;
1203 }
1204
1205 nr_iov = argc - optind;
4c7b7e9b 1206 buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
797ac58c
KW
1207 if (buf == NULL) {
1208 return 0;
1209 }
1210
1211 gettimeofday(&t1, NULL);
4c7b7e9b 1212 cnt = do_aio_writev(blk, &qiov, offset, &total);
797ac58c
KW
1213 gettimeofday(&t2, NULL);
1214
1215 if (cnt < 0) {
1216 printf("writev failed: %s\n", strerror(-cnt));
1217 goto out;
1218 }
1219
1220 if (qflag) {
1221 goto out;
1222 }
1223
1224 /* Finally, report back -- -C gives a parsable format */
1225 t2 = tsub(t2, t1);
1226 print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
1227out:
1228 qemu_iovec_destroy(&qiov);
1229 qemu_io_free(buf);
1230 return 0;
1231}
1232
1233static void multiwrite_help(void)
1234{
1235 printf(
1236"\n"
1237" writes a range of bytes from the given offset source from multiple buffers,\n"
1238" in a batch of requests that may be merged by qemu\n"
1239"\n"
1240" Example:\n"
1241" 'multiwrite 512 1k 1k ; 4k 1k'\n"
1242" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
1243"\n"
1244" Writes into a segment of the currently open file, using a buffer\n"
1245" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
1246" by one for each request contained in the multiwrite command.\n"
1247" -P, -- use different pattern to fill file\n"
1248" -C, -- report statistics in a machine parsable format\n"
1249" -q, -- quiet mode, do not show I/O statistics\n"
1250"\n");
1251}
1252
4c7b7e9b 1253static int multiwrite_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
1254
1255static const cmdinfo_t multiwrite_cmd = {
1256 .name = "multiwrite",
1257 .cfunc = multiwrite_f,
1258 .argmin = 2,
1259 .argmax = -1,
1260 .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
1261 .oneline = "issues multiple write requests at once",
1262 .help = multiwrite_help,
1263};
1264
4c7b7e9b 1265static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1266{
1267 struct timeval t1, t2;
1268 int Cflag = 0, qflag = 0;
1269 int c, cnt;
1270 char **buf;
1271 int64_t offset, first_offset = 0;
1272 /* Some compilers get confused and warn if this is not initialized. */
1273 int total = 0;
1274 int nr_iov;
1275 int nr_reqs;
1276 int pattern = 0xcd;
1277 QEMUIOVector *qiovs;
1278 int i;
1279 BlockRequest *reqs;
1280
b062ad86 1281 while ((c = getopt(argc, argv, "CqP:")) != -1) {
797ac58c
KW
1282 switch (c) {
1283 case 'C':
1284 Cflag = 1;
1285 break;
1286 case 'q':
1287 qflag = 1;
1288 break;
1289 case 'P':
1290 pattern = parse_pattern(optarg);
1291 if (pattern < 0) {
1292 return 0;
1293 }
1294 break;
1295 default:
c2cdf5c5 1296 return qemuio_command_usage(&writev_cmd);
797ac58c
KW
1297 }
1298 }
1299
1300 if (optind > argc - 2) {
c2cdf5c5 1301 return qemuio_command_usage(&writev_cmd);
797ac58c
KW
1302 }
1303
1304 nr_reqs = 1;
1305 for (i = optind; i < argc; i++) {
1306 if (!strcmp(argv[i], ";")) {
1307 nr_reqs++;
1308 }
1309 }
1310
02c4f26b
MA
1311 reqs = g_new0(BlockRequest, nr_reqs);
1312 buf = g_new0(char *, nr_reqs);
1313 qiovs = g_new(QEMUIOVector, nr_reqs);
797ac58c
KW
1314
1315 for (i = 0; i < nr_reqs && optind < argc; i++) {
1316 int j;
1317
1318 /* Read the offset of the request */
1319 offset = cvtnum(argv[optind]);
1320 if (offset < 0) {
1321 printf("non-numeric offset argument -- %s\n", argv[optind]);
1322 goto out;
1323 }
1324 optind++;
1325
1326 if (offset & 0x1ff) {
1327 printf("offset %lld is not sector aligned\n",
1328 (long long)offset);
1329 goto out;
1330 }
1331
1332 if (i == 0) {
1333 first_offset = offset;
1334 }
1335
1336 /* Read lengths for qiov entries */
1337 for (j = optind; j < argc; j++) {
1338 if (!strcmp(argv[j], ";")) {
1339 break;
1340 }
1341 }
1342
1343 nr_iov = j - optind;
1344
1345 /* Build request */
4c7b7e9b 1346 buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern);
797ac58c
KW
1347 if (buf[i] == NULL) {
1348 goto out;
1349 }
1350
1351 reqs[i].qiov = &qiovs[i];
1352 reqs[i].sector = offset >> 9;
1353 reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
1354
1355 optind = j + 1;
1356
1357 pattern++;
1358 }
1359
1360 /* If there were empty requests at the end, ignore them */
1361 nr_reqs = i;
1362
1363 gettimeofday(&t1, NULL);
4c7b7e9b 1364 cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total);
797ac58c
KW
1365 gettimeofday(&t2, NULL);
1366
1367 if (cnt < 0) {
1368 printf("aio_multiwrite failed: %s\n", strerror(-cnt));
1369 goto out;
1370 }
1371
1372 if (qflag) {
1373 goto out;
1374 }
1375
1376 /* Finally, report back -- -C gives a parsable format */
1377 t2 = tsub(t2, t1);
1378 print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
1379out:
1380 for (i = 0; i < nr_reqs; i++) {
1381 qemu_io_free(buf[i]);
1382 if (reqs[i].qiov != NULL) {
1383 qemu_iovec_destroy(&qiovs[i]);
1384 }
1385 }
1386 g_free(buf);
1387 g_free(reqs);
1388 g_free(qiovs);
1389 return 0;
1390}
1391
1392struct aio_ctx {
4c7b7e9b 1393 BlockBackend *blk;
797ac58c
KW
1394 QEMUIOVector qiov;
1395 int64_t offset;
1396 char *buf;
1397 int qflag;
1398 int vflag;
1399 int Cflag;
1400 int Pflag;
a91f9584 1401 BlockAcctCookie acct;
797ac58c
KW
1402 int pattern;
1403 struct timeval t1;
1404};
1405
1406static void aio_write_done(void *opaque, int ret)
1407{
1408 struct aio_ctx *ctx = opaque;
1409 struct timeval t2;
1410
1411 gettimeofday(&t2, NULL);
1412
1413
1414 if (ret < 0) {
1415 printf("aio_write failed: %s\n", strerror(-ret));
1416 goto out;
1417 }
1418
4c7b7e9b 1419 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
a91f9584 1420
797ac58c
KW
1421 if (ctx->qflag) {
1422 goto out;
1423 }
1424
1425 /* Finally, report back -- -C gives a parsable format */
1426 t2 = tsub(t2, ctx->t1);
1427 print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
1428 ctx->qiov.size, 1, ctx->Cflag);
1429out:
1430 qemu_io_free(ctx->buf);
1431 qemu_iovec_destroy(&ctx->qiov);
1432 g_free(ctx);
1433}
1434
1435static void aio_read_done(void *opaque, int ret)
1436{
1437 struct aio_ctx *ctx = opaque;
1438 struct timeval t2;
1439
1440 gettimeofday(&t2, NULL);
1441
1442 if (ret < 0) {
1443 printf("readv failed: %s\n", strerror(-ret));
1444 goto out;
1445 }
1446
1447 if (ctx->Pflag) {
1448 void *cmp_buf = g_malloc(ctx->qiov.size);
1449
1450 memset(cmp_buf, ctx->pattern, ctx->qiov.size);
1451 if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
1452 printf("Pattern verification failed at offset %"
1453 PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
1454 }
1455 g_free(cmp_buf);
1456 }
1457
4c7b7e9b 1458 block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
a91f9584 1459
797ac58c
KW
1460 if (ctx->qflag) {
1461 goto out;
1462 }
1463
1464 if (ctx->vflag) {
1465 dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
1466 }
1467
1468 /* Finally, report back -- -C gives a parsable format */
1469 t2 = tsub(t2, ctx->t1);
1470 print_report("read", &t2, ctx->offset, ctx->qiov.size,
1471 ctx->qiov.size, 1, ctx->Cflag);
1472out:
1473 qemu_io_free(ctx->buf);
1474 qemu_iovec_destroy(&ctx->qiov);
1475 g_free(ctx);
1476}
1477
1478static void aio_read_help(void)
1479{
1480 printf(
1481"\n"
1482" asynchronously reads a range of bytes from the given offset\n"
1483"\n"
1484" Example:\n"
1485" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
1486"\n"
1487" Reads a segment of the currently open file, optionally dumping it to the\n"
1488" standard output stream (with -v option) for subsequent inspection.\n"
1489" The read is performed asynchronously and the aio_flush command must be\n"
1490" used to ensure all outstanding aio requests have been completed.\n"
1491" -C, -- report statistics in a machine parsable format\n"
1492" -P, -- use a pattern to verify read data\n"
1493" -v, -- dump buffer to standard output\n"
1494" -q, -- quiet mode, do not show I/O statistics\n"
1495"\n");
1496}
1497
4c7b7e9b 1498static int aio_read_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
1499
1500static const cmdinfo_t aio_read_cmd = {
1501 .name = "aio_read",
1502 .cfunc = aio_read_f,
1503 .argmin = 2,
1504 .argmax = -1,
1505 .args = "[-Cqv] [-P pattern ] off len [len..]",
1506 .oneline = "asynchronously reads a number of bytes",
1507 .help = aio_read_help,
1508};
1509
4c7b7e9b 1510static int aio_read_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1511{
1512 int nr_iov, c;
1513 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1514
4c7b7e9b 1515 ctx->blk = blk;
b062ad86 1516 while ((c = getopt(argc, argv, "CP:qv")) != -1) {
797ac58c
KW
1517 switch (c) {
1518 case 'C':
1519 ctx->Cflag = 1;
1520 break;
1521 case 'P':
1522 ctx->Pflag = 1;
1523 ctx->pattern = parse_pattern(optarg);
1524 if (ctx->pattern < 0) {
1525 g_free(ctx);
1526 return 0;
1527 }
1528 break;
1529 case 'q':
1530 ctx->qflag = 1;
1531 break;
1532 case 'v':
1533 ctx->vflag = 1;
1534 break;
1535 default:
1536 g_free(ctx);
c2cdf5c5 1537 return qemuio_command_usage(&aio_read_cmd);
797ac58c
KW
1538 }
1539 }
1540
1541 if (optind > argc - 2) {
1542 g_free(ctx);
c2cdf5c5 1543 return qemuio_command_usage(&aio_read_cmd);
797ac58c
KW
1544 }
1545
1546 ctx->offset = cvtnum(argv[optind]);
1547 if (ctx->offset < 0) {
1548 printf("non-numeric length argument -- %s\n", argv[optind]);
1549 g_free(ctx);
1550 return 0;
1551 }
1552 optind++;
1553
1554 if (ctx->offset & 0x1ff) {
1555 printf("offset %" PRId64 " is not sector aligned\n",
1556 ctx->offset);
1557 g_free(ctx);
1558 return 0;
1559 }
1560
1561 nr_iov = argc - optind;
4c7b7e9b 1562 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
797ac58c
KW
1563 if (ctx->buf == NULL) {
1564 g_free(ctx);
1565 return 0;
1566 }
1567
1568 gettimeofday(&ctx->t1, NULL);
4c7b7e9b
HR
1569 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
1570 BLOCK_ACCT_READ);
1571 blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov,
1572 ctx->qiov.size >> 9, aio_read_done, ctx);
797ac58c
KW
1573 return 0;
1574}
1575
1576static void aio_write_help(void)
1577{
1578 printf(
1579"\n"
1580" asynchronously writes a range of bytes from the given offset source\n"
1581" from multiple buffers\n"
1582"\n"
1583" Example:\n"
1584" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
1585"\n"
1586" Writes into a segment of the currently open file, using a buffer\n"
1587" filled with a set pattern (0xcdcdcdcd).\n"
1588" The write is performed asynchronously and the aio_flush command must be\n"
1589" used to ensure all outstanding aio requests have been completed.\n"
1590" -P, -- use different pattern to fill file\n"
1591" -C, -- report statistics in a machine parsable format\n"
1592" -q, -- quiet mode, do not show I/O statistics\n"
1593"\n");
1594}
1595
4c7b7e9b 1596static int aio_write_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
1597
1598static const cmdinfo_t aio_write_cmd = {
1599 .name = "aio_write",
1600 .cfunc = aio_write_f,
1601 .argmin = 2,
1602 .argmax = -1,
1603 .args = "[-Cq] [-P pattern ] off len [len..]",
1604 .oneline = "asynchronously writes a number of bytes",
1605 .help = aio_write_help,
1606};
1607
4c7b7e9b 1608static int aio_write_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1609{
1610 int nr_iov, c;
1611 int pattern = 0xcd;
1612 struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
1613
4c7b7e9b 1614 ctx->blk = blk;
b062ad86 1615 while ((c = getopt(argc, argv, "CqP:")) != -1) {
797ac58c
KW
1616 switch (c) {
1617 case 'C':
1618 ctx->Cflag = 1;
1619 break;
1620 case 'q':
1621 ctx->qflag = 1;
1622 break;
1623 case 'P':
1624 pattern = parse_pattern(optarg);
1625 if (pattern < 0) {
1626 g_free(ctx);
1627 return 0;
1628 }
1629 break;
1630 default:
1631 g_free(ctx);
c2cdf5c5 1632 return qemuio_command_usage(&aio_write_cmd);
797ac58c
KW
1633 }
1634 }
1635
1636 if (optind > argc - 2) {
1637 g_free(ctx);
c2cdf5c5 1638 return qemuio_command_usage(&aio_write_cmd);
797ac58c
KW
1639 }
1640
1641 ctx->offset = cvtnum(argv[optind]);
1642 if (ctx->offset < 0) {
1643 printf("non-numeric length argument -- %s\n", argv[optind]);
1644 g_free(ctx);
1645 return 0;
1646 }
1647 optind++;
1648
1649 if (ctx->offset & 0x1ff) {
1650 printf("offset %" PRId64 " is not sector aligned\n",
1651 ctx->offset);
1652 g_free(ctx);
1653 return 0;
1654 }
1655
1656 nr_iov = argc - optind;
4c7b7e9b 1657 ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, pattern);
797ac58c
KW
1658 if (ctx->buf == NULL) {
1659 g_free(ctx);
1660 return 0;
1661 }
1662
1663 gettimeofday(&ctx->t1, NULL);
4c7b7e9b
HR
1664 block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
1665 BLOCK_ACCT_WRITE);
1666 blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov,
1667 ctx->qiov.size >> 9, aio_write_done, ctx);
797ac58c
KW
1668 return 0;
1669}
1670
4c7b7e9b 1671static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
797ac58c 1672{
4c7b7e9b 1673 blk_drain_all();
797ac58c
KW
1674 return 0;
1675}
1676
1677static const cmdinfo_t aio_flush_cmd = {
1678 .name = "aio_flush",
1679 .cfunc = aio_flush_f,
1680 .oneline = "completes all outstanding aio requests"
1681};
1682
4c7b7e9b 1683static int flush_f(BlockBackend *blk, int argc, char **argv)
797ac58c 1684{
4c7b7e9b 1685 blk_flush(blk);
797ac58c
KW
1686 return 0;
1687}
1688
1689static const cmdinfo_t flush_cmd = {
1690 .name = "flush",
1691 .altname = "f",
1692 .cfunc = flush_f,
1693 .oneline = "flush all in-core file state to disk",
1694};
1695
4c7b7e9b 1696static int truncate_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1697{
1698 int64_t offset;
1699 int ret;
1700
1701 offset = cvtnum(argv[1]);
1702 if (offset < 0) {
1703 printf("non-numeric truncate argument -- %s\n", argv[1]);
1704 return 0;
1705 }
1706
4c7b7e9b 1707 ret = blk_truncate(blk, offset);
797ac58c
KW
1708 if (ret < 0) {
1709 printf("truncate: %s\n", strerror(-ret));
1710 return 0;
1711 }
1712
1713 return 0;
1714}
1715
1716static const cmdinfo_t truncate_cmd = {
1717 .name = "truncate",
1718 .altname = "t",
1719 .cfunc = truncate_f,
1720 .argmin = 1,
1721 .argmax = 1,
1722 .args = "off",
1723 .oneline = "truncates the current file at the given offset",
1724};
1725
4c7b7e9b 1726static int length_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1727{
1728 int64_t size;
1729 char s1[64];
1730
4c7b7e9b 1731 size = blk_getlength(blk);
797ac58c
KW
1732 if (size < 0) {
1733 printf("getlength: %s\n", strerror(-size));
1734 return 0;
1735 }
1736
1737 cvtstr(size, s1, sizeof(s1));
1738 printf("%s\n", s1);
1739 return 0;
1740}
1741
1742
1743static const cmdinfo_t length_cmd = {
1744 .name = "length",
1745 .altname = "l",
1746 .cfunc = length_f,
1747 .oneline = "gets the length of the current file",
1748};
1749
1750
4c7b7e9b 1751static int info_f(BlockBackend *blk, int argc, char **argv)
797ac58c 1752{
4c7b7e9b 1753 BlockDriverState *bs = blk_bs(blk);
797ac58c 1754 BlockDriverInfo bdi;
a8d8ecb7 1755 ImageInfoSpecific *spec_info;
797ac58c
KW
1756 char s1[64], s2[64];
1757 int ret;
1758
1759 if (bs->drv && bs->drv->format_name) {
1760 printf("format name: %s\n", bs->drv->format_name);
1761 }
1762 if (bs->drv && bs->drv->protocol_name) {
1763 printf("format name: %s\n", bs->drv->protocol_name);
1764 }
1765
1766 ret = bdrv_get_info(bs, &bdi);
1767 if (ret) {
1768 return 0;
1769 }
1770
1771 cvtstr(bdi.cluster_size, s1, sizeof(s1));
1772 cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1773
1774 printf("cluster size: %s\n", s1);
1775 printf("vm state offset: %s\n", s2);
1776
a8d8ecb7
HR
1777 spec_info = bdrv_get_specific_info(bs);
1778 if (spec_info) {
1779 printf("Format specific information:\n");
1780 bdrv_image_info_specific_dump(fprintf, stdout, spec_info);
1781 qapi_free_ImageInfoSpecific(spec_info);
1782 }
1783
797ac58c
KW
1784 return 0;
1785}
1786
1787
1788
1789static const cmdinfo_t info_cmd = {
1790 .name = "info",
1791 .altname = "i",
1792 .cfunc = info_f,
1793 .oneline = "prints information about the current file",
1794};
1795
1796static void discard_help(void)
1797{
1798 printf(
1799"\n"
1800" discards a range of bytes from the given offset\n"
1801"\n"
1802" Example:\n"
1803" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1804"\n"
1805" Discards a segment of the currently open file.\n"
1806" -C, -- report statistics in a machine parsable format\n"
1807" -q, -- quiet mode, do not show I/O statistics\n"
1808"\n");
1809}
1810
4c7b7e9b 1811static int discard_f(BlockBackend *blk, int argc, char **argv);
797ac58c
KW
1812
1813static const cmdinfo_t discard_cmd = {
1814 .name = "discard",
1815 .altname = "d",
1816 .cfunc = discard_f,
1817 .argmin = 2,
1818 .argmax = -1,
1819 .args = "[-Cq] off len",
1820 .oneline = "discards a number of bytes at a specified offset",
1821 .help = discard_help,
1822};
1823
4c7b7e9b 1824static int discard_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1825{
1826 struct timeval t1, t2;
1827 int Cflag = 0, qflag = 0;
1828 int c, ret;
9b0beaf3 1829 int64_t offset, count;
797ac58c 1830
b062ad86 1831 while ((c = getopt(argc, argv, "Cq")) != -1) {
797ac58c
KW
1832 switch (c) {
1833 case 'C':
1834 Cflag = 1;
1835 break;
1836 case 'q':
1837 qflag = 1;
1838 break;
1839 default:
c2cdf5c5 1840 return qemuio_command_usage(&discard_cmd);
797ac58c
KW
1841 }
1842 }
1843
1844 if (optind != argc - 2) {
c2cdf5c5 1845 return qemuio_command_usage(&discard_cmd);
797ac58c
KW
1846 }
1847
1848 offset = cvtnum(argv[optind]);
1849 if (offset < 0) {
1850 printf("non-numeric length argument -- %s\n", argv[optind]);
1851 return 0;
1852 }
1853
1854 optind++;
1855 count = cvtnum(argv[optind]);
1856 if (count < 0) {
1857 printf("non-numeric length argument -- %s\n", argv[optind]);
1858 return 0;
9b0beaf3
JS
1859 } else if (count >> BDRV_SECTOR_BITS > INT_MAX) {
1860 printf("length cannot exceed %"PRIu64", given %s\n",
1861 (uint64_t)INT_MAX << BDRV_SECTOR_BITS,
1862 argv[optind]);
1863 return 0;
797ac58c
KW
1864 }
1865
1866 gettimeofday(&t1, NULL);
4c7b7e9b
HR
1867 ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS,
1868 count >> BDRV_SECTOR_BITS);
797ac58c
KW
1869 gettimeofday(&t2, NULL);
1870
1871 if (ret < 0) {
1872 printf("discard failed: %s\n", strerror(-ret));
1873 goto out;
1874 }
1875
1876 /* Finally, report back -- -C gives a parsable format */
1877 if (!qflag) {
1878 t2 = tsub(t2, t1);
1879 print_report("discard", &t2, offset, count, count, 1, Cflag);
1880 }
1881
1882out:
1883 return 0;
1884}
1885
4c7b7e9b 1886static int alloc_f(BlockBackend *blk, int argc, char **argv)
797ac58c 1887{
4c7b7e9b 1888 BlockDriverState *bs = blk_bs(blk);
9b0beaf3 1889 int64_t offset, sector_num, nb_sectors, remaining;
797ac58c 1890 char s1[64];
9b0beaf3
JS
1891 int num, ret;
1892 int64_t sum_alloc;
797ac58c
KW
1893
1894 offset = cvtnum(argv[1]);
1895 if (offset < 0) {
1896 printf("non-numeric offset argument -- %s\n", argv[1]);
1897 return 0;
1898 } else if (offset & 0x1ff) {
1899 printf("offset %" PRId64 " is not sector aligned\n",
1900 offset);
1901 return 0;
1902 }
1903
1904 if (argc == 3) {
1905 nb_sectors = cvtnum(argv[2]);
1906 if (nb_sectors < 0) {
1907 printf("non-numeric length argument -- %s\n", argv[2]);
1908 return 0;
9b0beaf3
JS
1909 } else if (nb_sectors > INT_MAX) {
1910 printf("length argument cannot exceed %d, given %s\n",
1911 INT_MAX, argv[2]);
1912 return 0;
797ac58c
KW
1913 }
1914 } else {
1915 nb_sectors = 1;
1916 }
1917
1918 remaining = nb_sectors;
1919 sum_alloc = 0;
1920 sector_num = offset >> 9;
1921 while (remaining) {
1922 ret = bdrv_is_allocated(bs, sector_num, remaining, &num);
d663640c
PB
1923 if (ret < 0) {
1924 printf("is_allocated failed: %s\n", strerror(-ret));
1925 return 0;
1926 }
797ac58c
KW
1927 sector_num += num;
1928 remaining -= num;
1929 if (ret) {
1930 sum_alloc += num;
1931 }
1932 if (num == 0) {
1933 nb_sectors -= remaining;
1934 remaining = 0;
1935 }
1936 }
1937
1938 cvtstr(offset, s1, sizeof(s1));
1939
9b0beaf3 1940 printf("%"PRId64"/%"PRId64" sectors allocated at offset %s\n",
797ac58c
KW
1941 sum_alloc, nb_sectors, s1);
1942 return 0;
1943}
1944
1945static const cmdinfo_t alloc_cmd = {
1946 .name = "alloc",
1947 .altname = "a",
1948 .argmin = 1,
1949 .argmax = 2,
1950 .cfunc = alloc_f,
1951 .args = "off [sectors]",
1952 .oneline = "checks if a sector is present in the file",
1953};
1954
1955
1956static int map_is_allocated(BlockDriverState *bs, int64_t sector_num,
1957 int64_t nb_sectors, int64_t *pnum)
1958{
1959 int num, num_checked;
1960 int ret, firstret;
1961
1962 num_checked = MIN(nb_sectors, INT_MAX);
1963 ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
1964 if (ret < 0) {
1965 return ret;
1966 }
1967
1968 firstret = ret;
1969 *pnum = num;
1970
1971 while (nb_sectors > 0 && ret == firstret) {
1972 sector_num += num;
1973 nb_sectors -= num;
1974
1975 num_checked = MIN(nb_sectors, INT_MAX);
1976 ret = bdrv_is_allocated(bs, sector_num, num_checked, &num);
4b25bbc4 1977 if (ret == firstret && num) {
797ac58c
KW
1978 *pnum += num;
1979 } else {
1980 break;
1981 }
1982 }
1983
1984 return firstret;
1985}
1986
4c7b7e9b 1987static int map_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
1988{
1989 int64_t offset;
4c7b7e9b 1990 int64_t nb_sectors, total_sectors;
797ac58c
KW
1991 char s1[64];
1992 int64_t num;
1993 int ret;
1994 const char *retstr;
1995
1996 offset = 0;
4c7b7e9b
HR
1997 total_sectors = blk_nb_sectors(blk);
1998 if (total_sectors < 0) {
1999 error_report("Failed to query image length: %s",
2000 strerror(-total_sectors));
2001 return 0;
2002 }
2003
2004 nb_sectors = total_sectors;
797ac58c
KW
2005
2006 do {
4c7b7e9b 2007 ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num);
797ac58c
KW
2008 if (ret < 0) {
2009 error_report("Failed to get allocation status: %s", strerror(-ret));
2010 return 0;
4b25bbc4
HR
2011 } else if (!num) {
2012 error_report("Unexpected end of image");
2013 return 0;
797ac58c
KW
2014 }
2015
2016 retstr = ret ? " allocated" : "not allocated";
2017 cvtstr(offset << 9ULL, s1, sizeof(s1));
2018 printf("[% 24" PRId64 "] % 8" PRId64 "/% 8" PRId64 " sectors %s "
2019 "at offset %s (%d)\n",
2020 offset << 9ULL, num, nb_sectors, retstr, s1, ret);
2021
2022 offset += num;
2023 nb_sectors -= num;
4c7b7e9b 2024 } while (offset < total_sectors);
797ac58c
KW
2025
2026 return 0;
2027}
2028
2029static const cmdinfo_t map_cmd = {
2030 .name = "map",
2031 .argmin = 0,
2032 .argmax = 0,
2033 .cfunc = map_f,
2034 .args = "",
2035 .oneline = "prints the allocated areas of a file",
2036};
2037
5bbd2e59
KW
2038static void reopen_help(void)
2039{
2040 printf(
2041"\n"
2042" Changes the open options of an already opened image\n"
2043"\n"
2044" Example:\n"
2045" 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
2046"\n"
2047" -r, -- Reopen the image read-only\n"
2048" -c, -- Change the cache mode to the given value\n"
2049" -o, -- Changes block driver options (cf. 'open' command)\n"
2050"\n");
2051}
2052
2053static int reopen_f(BlockBackend *blk, int argc, char **argv);
2054
2055static QemuOptsList reopen_opts = {
2056 .name = "reopen",
2057 .merge_lists = true,
2058 .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
2059 .desc = {
2060 /* no elements => accept any params */
2061 { /* end of list */ }
2062 },
2063};
2064
2065static const cmdinfo_t reopen_cmd = {
2066 .name = "reopen",
2067 .argmin = 0,
2068 .argmax = -1,
2069 .cfunc = reopen_f,
2070 .args = "[-r] [-c cache] [-o options]",
2071 .oneline = "reopens an image with new options",
2072 .help = reopen_help,
2073};
2074
2075static int reopen_f(BlockBackend *blk, int argc, char **argv)
2076{
2077 BlockDriverState *bs = blk_bs(blk);
2078 QemuOpts *qopts;
2079 QDict *opts;
2080 int c;
2081 int flags = bs->open_flags;
2082
2083 BlockReopenQueue *brq;
2084 Error *local_err = NULL;
2085
2086 while ((c = getopt(argc, argv, "c:o:r")) != -1) {
2087 switch (c) {
2088 case 'c':
2089 if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
2090 error_report("Invalid cache option: %s", optarg);
2091 return 0;
2092 }
2093 break;
2094 case 'o':
2095 if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
2096 qemu_opts_reset(&reopen_opts);
2097 return 0;
2098 }
2099 break;
2100 case 'r':
2101 flags &= ~BDRV_O_RDWR;
2102 break;
2103 default:
2104 qemu_opts_reset(&reopen_opts);
2105 return qemuio_command_usage(&reopen_cmd);
2106 }
2107 }
2108
2109 if (optind != argc) {
2110 qemu_opts_reset(&reopen_opts);
2111 return qemuio_command_usage(&reopen_cmd);
2112 }
2113
2114 qopts = qemu_opts_find(&reopen_opts, NULL);
2115 opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
2116 qemu_opts_reset(&reopen_opts);
2117
2118 brq = bdrv_reopen_queue(NULL, bs, opts, flags);
2119 bdrv_reopen_multiple(brq, &local_err);
2120 if (local_err) {
2121 error_report_err(local_err);
2122 }
2123
2124 return 0;
2125}
2126
4c7b7e9b 2127static int break_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
2128{
2129 int ret;
2130
4c7b7e9b 2131 ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
797ac58c
KW
2132 if (ret < 0) {
2133 printf("Could not set breakpoint: %s\n", strerror(-ret));
2134 }
2135
2136 return 0;
2137}
2138
4c7b7e9b 2139static int remove_break_f(BlockBackend *blk, int argc, char **argv)
4cc70e93
FZ
2140{
2141 int ret;
2142
4c7b7e9b 2143 ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
4cc70e93
FZ
2144 if (ret < 0) {
2145 printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
2146 }
2147
2148 return 0;
2149}
2150
797ac58c
KW
2151static const cmdinfo_t break_cmd = {
2152 .name = "break",
2153 .argmin = 2,
2154 .argmax = 2,
2155 .cfunc = break_f,
2156 .args = "event tag",
2157 .oneline = "sets a breakpoint on event and tags the stopped "
2158 "request as tag",
2159};
2160
4cc70e93
FZ
2161static const cmdinfo_t remove_break_cmd = {
2162 .name = "remove_break",
2163 .argmin = 1,
2164 .argmax = 1,
2165 .cfunc = remove_break_f,
2166 .args = "tag",
2167 .oneline = "remove a breakpoint by tag",
2168};
2169
4c7b7e9b 2170static int resume_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
2171{
2172 int ret;
2173
4c7b7e9b 2174 ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
797ac58c
KW
2175 if (ret < 0) {
2176 printf("Could not resume request: %s\n", strerror(-ret));
2177 }
2178
2179 return 0;
2180}
2181
2182static const cmdinfo_t resume_cmd = {
2183 .name = "resume",
2184 .argmin = 1,
2185 .argmax = 1,
2186 .cfunc = resume_f,
2187 .args = "tag",
2188 .oneline = "resumes the request tagged as tag",
2189};
2190
4c7b7e9b 2191static int wait_break_f(BlockBackend *blk, int argc, char **argv)
797ac58c 2192{
4c7b7e9b
HR
2193 while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
2194 aio_poll(blk_get_aio_context(blk), true);
797ac58c
KW
2195 }
2196
2197 return 0;
2198}
2199
2200static const cmdinfo_t wait_break_cmd = {
2201 .name = "wait_break",
2202 .argmin = 1,
2203 .argmax = 1,
2204 .cfunc = wait_break_f,
2205 .args = "tag",
2206 .oneline = "waits for the suspension of a request",
2207};
2208
4c7b7e9b 2209static int abort_f(BlockBackend *blk, int argc, char **argv)
797ac58c
KW
2210{
2211 abort();
2212}
2213
2214static const cmdinfo_t abort_cmd = {
2215 .name = "abort",
2216 .cfunc = abort_f,
2217 .flags = CMD_NOFILE_OK,
2218 .oneline = "simulate a program crash using abort(3)",
2219};
2220
0e82dc7b
HR
2221static void sigraise_help(void)
2222{
2223 printf(
2224"\n"
2225" raises the given signal\n"
2226"\n"
2227" Example:\n"
2228" 'sigraise %i' - raises SIGTERM\n"
2229"\n"
2230" Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
2231" given to sigraise.\n"
2232"\n", SIGTERM);
2233}
2234
4c7b7e9b 2235static int sigraise_f(BlockBackend *blk, int argc, char **argv);
0e82dc7b
HR
2236
2237static const cmdinfo_t sigraise_cmd = {
2238 .name = "sigraise",
2239 .cfunc = sigraise_f,
2240 .argmin = 1,
2241 .argmax = 1,
2242 .flags = CMD_NOFILE_OK,
2243 .args = "signal",
2244 .oneline = "raises a signal",
2245 .help = sigraise_help,
2246};
2247
4c7b7e9b 2248static int sigraise_f(BlockBackend *blk, int argc, char **argv)
0e82dc7b 2249{
9b0beaf3 2250 int64_t sig = cvtnum(argv[1]);
0e82dc7b
HR
2251 if (sig < 0) {
2252 printf("non-numeric signal number argument -- %s\n", argv[1]);
2253 return 0;
9b0beaf3
JS
2254 } else if (sig > NSIG) {
2255 printf("signal argument '%s' is too large to be a valid signal\n",
2256 argv[1]);
2257 return 0;
0e82dc7b
HR
2258 }
2259
2260 /* Using raise() to kill this process does not necessarily flush all open
2261 * streams. At least stdout and stderr (although the latter should be
2262 * non-buffered anyway) should be flushed, though. */
2263 fflush(stdout);
2264 fflush(stderr);
2265
2266 raise(sig);
2267 return 0;
2268}
2269
cd33d02a
KW
2270static void sleep_cb(void *opaque)
2271{
2272 bool *expired = opaque;
2273 *expired = true;
2274}
2275
4c7b7e9b 2276static int sleep_f(BlockBackend *blk, int argc, char **argv)
cd33d02a
KW
2277{
2278 char *endptr;
2279 long ms;
2280 struct QEMUTimer *timer;
2281 bool expired = false;
2282
2283 ms = strtol(argv[1], &endptr, 0);
2284 if (ms < 0 || *endptr != '\0') {
2285 printf("%s is not a valid number\n", argv[1]);
2286 return 0;
2287 }
2288
2289 timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2290 timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2291
2292 while (!expired) {
2293 main_loop_wait(false);
2294 }
2295
2296 timer_free(timer);
2297
2298 return 0;
2299}
2300
2301static const cmdinfo_t sleep_cmd = {
2302 .name = "sleep",
2303 .argmin = 1,
2304 .argmax = 1,
2305 .cfunc = sleep_f,
2306 .flags = CMD_NOFILE_OK,
2307 .oneline = "waits for the given value in milliseconds",
2308};
2309
f18a834a
KW
2310static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2311{
2312 if (cmd) {
2313 printf("%s ", cmd);
2314 } else {
2315 printf("%s ", ct->name);
2316 if (ct->altname) {
2317 printf("(or %s) ", ct->altname);
2318 }
2319 }
2320
2321 if (ct->args) {
2322 printf("%s ", ct->args);
2323 }
2324 printf("-- %s\n", ct->oneline);
2325}
2326
2327static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2328{
2329 help_oneline(cmd, ct);
2330 if (ct->help) {
2331 ct->help();
2332 }
2333}
2334
2335static void help_all(void)
2336{
2337 const cmdinfo_t *ct;
2338
2339 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2340 help_oneline(ct->name, ct);
2341 }
2342 printf("\nUse 'help commandname' for extended help.\n");
2343}
2344
4c7b7e9b 2345static int help_f(BlockBackend *blk, int argc, char **argv)
f18a834a
KW
2346{
2347 const cmdinfo_t *ct;
2348
2349 if (argc == 1) {
2350 help_all();
2351 return 0;
2352 }
2353
2354 ct = find_command(argv[1]);
2355 if (ct == NULL) {
2356 printf("command %s not found\n", argv[1]);
2357 return 0;
2358 }
2359
2360 help_onecmd(argv[1], ct);
2361 return 0;
2362}
2363
2364static const cmdinfo_t help_cmd = {
2365 .name = "help",
2366 .altname = "?",
2367 .cfunc = help_f,
2368 .argmin = 0,
2369 .argmax = 1,
2370 .flags = CMD_FLAG_GLOBAL,
2371 .args = "[command]",
2372 .oneline = "help for one or all commands",
2373};
2374
4c7b7e9b 2375bool qemuio_command(BlockBackend *blk, const char *cmd)
dd583296
KW
2376{
2377 char *input;
2378 const cmdinfo_t *ct;
2379 char **v;
2380 int c;
2381 bool done = false;
2382
2383 input = g_strdup(cmd);
2384 v = breakline(input, &c);
2385 if (c) {
2386 ct = find_command(v[0]);
2387 if (ct) {
4c7b7e9b 2388 done = command(blk, ct, c, v);
dd583296
KW
2389 } else {
2390 fprintf(stderr, "command \"%s\" not found\n", v[0]);
2391 }
2392 }
2393 g_free(input);
2394 g_free(v);
2395
2396 return done;
2397}
2398
797ac58c
KW
2399static void __attribute((constructor)) init_qemuio_commands(void)
2400{
2401 /* initialize commands */
c2cdf5c5
KW
2402 qemuio_add_command(&help_cmd);
2403 qemuio_add_command(&read_cmd);
2404 qemuio_add_command(&readv_cmd);
2405 qemuio_add_command(&write_cmd);
2406 qemuio_add_command(&writev_cmd);
2407 qemuio_add_command(&multiwrite_cmd);
2408 qemuio_add_command(&aio_read_cmd);
2409 qemuio_add_command(&aio_write_cmd);
2410 qemuio_add_command(&aio_flush_cmd);
2411 qemuio_add_command(&flush_cmd);
2412 qemuio_add_command(&truncate_cmd);
2413 qemuio_add_command(&length_cmd);
2414 qemuio_add_command(&info_cmd);
2415 qemuio_add_command(&discard_cmd);
2416 qemuio_add_command(&alloc_cmd);
2417 qemuio_add_command(&map_cmd);
5bbd2e59 2418 qemuio_add_command(&reopen_cmd);
c2cdf5c5 2419 qemuio_add_command(&break_cmd);
4cc70e93 2420 qemuio_add_command(&remove_break_cmd);
c2cdf5c5
KW
2421 qemuio_add_command(&resume_cmd);
2422 qemuio_add_command(&wait_break_cmd);
2423 qemuio_add_command(&abort_cmd);
cd33d02a 2424 qemuio_add_command(&sleep_cmd);
0e82dc7b 2425 qemuio_add_command(&sigraise_cmd);
797ac58c 2426}