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