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