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);
1702static const cmdinfo_t truncate_cmd = {
1703 .name = "truncate",
1704 .altname = "t",
1705 .cfunc = truncate_f,
1706 .perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
1707 .argmin = 1,
1708 .argmax = 3,
1709 .args = "[-m prealloc_mode] off",
1710 .oneline = "truncates the current file at the given offset",
1711};
1712
1713static int truncate_f(BlockBackend *blk, int argc, char **argv)
1714{
1715 Error *local_err = NULL;
1716 int64_t offset;
1717 int c, ret;
1718 PreallocMode prealloc = PREALLOC_MODE_OFF;
1719
1720 while ((c = getopt(argc, argv, "m:")) != -1) {
1721 switch (c) {
1722 case 'm':
1723 prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
1724 PREALLOC_MODE__MAX, NULL);
1725 if (prealloc == PREALLOC_MODE__MAX) {
1726 error_report("Invalid preallocation mode '%s'", optarg);
1727 return -EINVAL;
1728 }
1729 break;
1730 default:
1731 qemuio_command_usage(&truncate_cmd);
1732 return -EINVAL;
1733 }
1734 }
1735
1736 offset = cvtnum(argv[optind]);
1737 if (offset < 0) {
1738 print_cvtnum_err(offset, argv[1]);
1739 return offset;
1740 }
1741
1742
1743
1744
1745
1746
1747 ret = blk_truncate(blk, offset, false, prealloc, 0, &local_err);
1748 if (ret < 0) {
1749 error_report_err(local_err);
1750 return ret;
1751 }
1752
1753 return 0;
1754}
1755
1756static int length_f(BlockBackend *blk, int argc, char **argv)
1757{
1758 int64_t size;
1759 char s1[64];
1760
1761 size = blk_getlength(blk);
1762 if (size < 0) {
1763 printf("getlength: %s\n", strerror(-size));
1764 return size;
1765 }
1766
1767 cvtstr(size, s1, sizeof(s1));
1768 printf("%s\n", s1);
1769 return 0;
1770}
1771
1772
1773static const cmdinfo_t length_cmd = {
1774 .name = "length",
1775 .altname = "l",
1776 .cfunc = length_f,
1777 .oneline = "gets the length of the current file",
1778};
1779
1780
1781static int info_f(BlockBackend *blk, int argc, char **argv)
1782{
1783 BlockDriverState *bs = blk_bs(blk);
1784 BlockDriverInfo bdi;
1785 ImageInfoSpecific *spec_info;
1786 Error *local_err = NULL;
1787 char s1[64], s2[64];
1788 int ret;
1789
1790 if (bs->drv && bs->drv->format_name) {
1791 printf("format name: %s\n", bs->drv->format_name);
1792 }
1793 if (bs->drv && bs->drv->protocol_name) {
1794 printf("format name: %s\n", bs->drv->protocol_name);
1795 }
1796
1797 ret = bdrv_get_info(bs, &bdi);
1798 if (ret) {
1799 return ret;
1800 }
1801
1802 cvtstr(bdi.cluster_size, s1, sizeof(s1));
1803 cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
1804
1805 printf("cluster size: %s\n", s1);
1806 printf("vm state offset: %s\n", s2);
1807
1808 spec_info = bdrv_get_specific_info(bs, &local_err);
1809 if (local_err) {
1810 error_report_err(local_err);
1811 return -EIO;
1812 }
1813 if (spec_info) {
1814 printf("Format specific information:\n");
1815 bdrv_image_info_specific_dump(spec_info);
1816 qapi_free_ImageInfoSpecific(spec_info);
1817 }
1818
1819 return 0;
1820}
1821
1822
1823
1824static const cmdinfo_t info_cmd = {
1825 .name = "info",
1826 .altname = "i",
1827 .cfunc = info_f,
1828 .oneline = "prints information about the current file",
1829};
1830
1831static void discard_help(void)
1832{
1833 printf(
1834"\n"
1835" discards a range of bytes from the given offset\n"
1836"\n"
1837" Example:\n"
1838" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
1839"\n"
1840" Discards a segment of the currently open file.\n"
1841" -C, -- report statistics in a machine parsable format\n"
1842" -q, -- quiet mode, do not show I/O statistics\n"
1843"\n");
1844}
1845
1846static int discard_f(BlockBackend *blk, int argc, char **argv);
1847
1848static const cmdinfo_t discard_cmd = {
1849 .name = "discard",
1850 .altname = "d",
1851 .cfunc = discard_f,
1852 .perm = BLK_PERM_WRITE,
1853 .argmin = 2,
1854 .argmax = -1,
1855 .args = "[-Cq] off len",
1856 .oneline = "discards a number of bytes at a specified offset",
1857 .help = discard_help,
1858};
1859
1860static int discard_f(BlockBackend *blk, int argc, char **argv)
1861{
1862 struct timespec t1, t2;
1863 bool Cflag = false, qflag = false;
1864 int c, ret;
1865 int64_t offset, bytes;
1866
1867 while ((c = getopt(argc, argv, "Cq")) != -1) {
1868 switch (c) {
1869 case 'C':
1870 Cflag = true;
1871 break;
1872 case 'q':
1873 qflag = true;
1874 break;
1875 default:
1876 qemuio_command_usage(&discard_cmd);
1877 return -EINVAL;
1878 }
1879 }
1880
1881 if (optind != argc - 2) {
1882 qemuio_command_usage(&discard_cmd);
1883 return -EINVAL;
1884 }
1885
1886 offset = cvtnum(argv[optind]);
1887 if (offset < 0) {
1888 print_cvtnum_err(offset, argv[optind]);
1889 return offset;
1890 }
1891
1892 optind++;
1893 bytes = cvtnum(argv[optind]);
1894 if (bytes < 0) {
1895 print_cvtnum_err(bytes, argv[optind]);
1896 return bytes;
1897 } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
1898 printf("length cannot exceed %"PRIu64", given %s\n",
1899 (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
1900 return -EINVAL;
1901 }
1902
1903 clock_gettime(CLOCK_MONOTONIC, &t1);
1904 ret = blk_pdiscard(blk, offset, bytes);
1905 clock_gettime(CLOCK_MONOTONIC, &t2);
1906
1907 if (ret < 0) {
1908 printf("discard failed: %s\n", strerror(-ret));
1909 return ret;
1910 }
1911
1912
1913 if (!qflag) {
1914 t2 = tsub(t2, t1);
1915 print_report("discard", &t2, offset, bytes, bytes, 1, Cflag);
1916 }
1917
1918 return 0;
1919}
1920
1921static int alloc_f(BlockBackend *blk, int argc, char **argv)
1922{
1923 BlockDriverState *bs = blk_bs(blk);
1924 int64_t offset, start, remaining, count;
1925 char s1[64];
1926 int ret;
1927 int64_t num, sum_alloc;
1928
1929 start = offset = cvtnum(argv[1]);
1930 if (offset < 0) {
1931 print_cvtnum_err(offset, argv[1]);
1932 return offset;
1933 }
1934
1935 if (argc == 3) {
1936 count = cvtnum(argv[2]);
1937 if (count < 0) {
1938 print_cvtnum_err(count, argv[2]);
1939 return count;
1940 }
1941 } else {
1942 count = BDRV_SECTOR_SIZE;
1943 }
1944
1945 remaining = count;
1946 sum_alloc = 0;
1947 while (remaining) {
1948 ret = bdrv_is_allocated(bs, offset, remaining, &num);
1949 if (ret < 0) {
1950 printf("is_allocated failed: %s\n", strerror(-ret));
1951 return ret;
1952 }
1953 offset += num;
1954 remaining -= num;
1955 if (ret) {
1956 sum_alloc += num;
1957 }
1958 if (num == 0) {
1959 count -= remaining;
1960 remaining = 0;
1961 }
1962 }
1963
1964 cvtstr(start, s1, sizeof(s1));
1965
1966 printf("%"PRId64"/%"PRId64" bytes allocated at offset %s\n",
1967 sum_alloc, count, s1);
1968 return 0;
1969}
1970
1971static const cmdinfo_t alloc_cmd = {
1972 .name = "alloc",
1973 .altname = "a",
1974 .argmin = 1,
1975 .argmax = 2,
1976 .cfunc = alloc_f,
1977 .args = "offset [count]",
1978 .oneline = "checks if offset is allocated in the file",
1979};
1980
1981
1982static int map_is_allocated(BlockDriverState *bs, int64_t offset,
1983 int64_t bytes, int64_t *pnum)
1984{
1985 int64_t num;
1986 int num_checked;
1987 int ret, firstret;
1988
1989 num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
1990 ret = bdrv_is_allocated(bs, offset, num_checked, &num);
1991 if (ret < 0) {
1992 return ret;
1993 }
1994
1995 firstret = ret;
1996 *pnum = num;
1997
1998 while (bytes > 0 && ret == firstret) {
1999 offset += num;
2000 bytes -= num;
2001
2002 num_checked = MIN(bytes, BDRV_REQUEST_MAX_BYTES);
2003 ret = bdrv_is_allocated(bs, offset, num_checked, &num);
2004 if (ret == firstret && num) {
2005 *pnum += num;
2006 } else {
2007 break;
2008 }
2009 }
2010
2011 return firstret;
2012}
2013
2014static int map_f(BlockBackend *blk, int argc, char **argv)
2015{
2016 int64_t offset, bytes;
2017 char s1[64], s2[64];
2018 int64_t num;
2019 int ret;
2020 const char *retstr;
2021
2022 offset = 0;
2023 bytes = blk_getlength(blk);
2024 if (bytes < 0) {
2025 error_report("Failed to query image length: %s", strerror(-bytes));
2026 return bytes;
2027 }
2028
2029 while (bytes) {
2030 ret = map_is_allocated(blk_bs(blk), offset, bytes, &num);
2031 if (ret < 0) {
2032 error_report("Failed to get allocation status: %s", strerror(-ret));
2033 return ret;
2034 } else if (!num) {
2035 error_report("Unexpected end of image");
2036 return -EIO;
2037 }
2038
2039 retstr = ret ? " allocated" : "not allocated";
2040 cvtstr(num, s1, sizeof(s1));
2041 cvtstr(offset, s2, sizeof(s2));
2042 printf("%s (0x%" PRIx64 ") bytes %s at offset %s (0x%" PRIx64 ")\n",
2043 s1, num, retstr, s2, offset);
2044
2045 offset += num;
2046 bytes -= num;
2047 }
2048
2049 return 0;
2050}
2051
2052static const cmdinfo_t map_cmd = {
2053 .name = "map",
2054 .argmin = 0,
2055 .argmax = 0,
2056 .cfunc = map_f,
2057 .args = "",
2058 .oneline = "prints the allocated areas of a file",
2059};
2060
2061static void reopen_help(void)
2062{
2063 printf(
2064"\n"
2065" Changes the open options of an already opened image\n"
2066"\n"
2067" Example:\n"
2068" 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
2069"\n"
2070" -r, -- Reopen the image read-only\n"
2071" -w, -- Reopen the image read-write\n"
2072" -c, -- Change the cache mode to the given value\n"
2073" -o, -- Changes block driver options (cf. 'open' command)\n"
2074"\n");
2075}
2076
2077static int reopen_f(BlockBackend *blk, int argc, char **argv);
2078
2079static QemuOptsList reopen_opts = {
2080 .name = "reopen",
2081 .merge_lists = true,
2082 .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
2083 .desc = {
2084
2085 { }
2086 },
2087};
2088
2089static const cmdinfo_t reopen_cmd = {
2090 .name = "reopen",
2091 .argmin = 0,
2092 .argmax = -1,
2093 .cfunc = reopen_f,
2094 .args = "[(-r|-w)] [-c cache] [-o options]",
2095 .oneline = "reopens an image with new options",
2096 .help = reopen_help,
2097};
2098
2099static int reopen_f(BlockBackend *blk, int argc, char **argv)
2100{
2101 BlockDriverState *bs = blk_bs(blk);
2102 QemuOpts *qopts;
2103 QDict *opts;
2104 int c;
2105 int flags = bs->open_flags;
2106 bool writethrough = !blk_enable_write_cache(blk);
2107 bool has_rw_option = false;
2108 bool has_cache_option = false;
2109
2110 BlockReopenQueue *brq;
2111 Error *local_err = NULL;
2112
2113 while ((c = getopt(argc, argv, "c:o:rw")) != -1) {
2114 switch (c) {
2115 case 'c':
2116 if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
2117 error_report("Invalid cache option: %s", optarg);
2118 return -EINVAL;
2119 }
2120 has_cache_option = true;
2121 break;
2122 case 'o':
2123 if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
2124 qemu_opts_reset(&reopen_opts);
2125 return -EINVAL;
2126 }
2127 break;
2128 case 'r':
2129 if (has_rw_option) {
2130 error_report("Only one -r/-w option may be given");
2131 return -EINVAL;
2132 }
2133 flags &= ~BDRV_O_RDWR;
2134 has_rw_option = true;
2135 break;
2136 case 'w':
2137 if (has_rw_option) {
2138 error_report("Only one -r/-w option may be given");
2139 return -EINVAL;
2140 }
2141 flags |= BDRV_O_RDWR;
2142 has_rw_option = true;
2143 break;
2144 default:
2145 qemu_opts_reset(&reopen_opts);
2146 qemuio_command_usage(&reopen_cmd);
2147 return -EINVAL;
2148 }
2149 }
2150
2151 if (optind != argc) {
2152 qemu_opts_reset(&reopen_opts);
2153 qemuio_command_usage(&reopen_cmd);
2154 return -EINVAL;
2155 }
2156
2157 if (!writethrough != blk_enable_write_cache(blk) &&
2158 blk_get_attached_dev(blk))
2159 {
2160 error_report("Cannot change cache.writeback: Device attached");
2161 qemu_opts_reset(&reopen_opts);
2162 return -EBUSY;
2163 }
2164
2165 if (!(flags & BDRV_O_RDWR)) {
2166 uint64_t orig_perm, orig_shared_perm;
2167
2168 bdrv_drain(bs);
2169
2170 blk_get_perm(blk, &orig_perm, &orig_shared_perm);
2171 blk_set_perm(blk,
2172 orig_perm & ~(BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED),
2173 orig_shared_perm,
2174 &error_abort);
2175 }
2176
2177 qopts = qemu_opts_find(&reopen_opts, NULL);
2178 opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new();
2179 qemu_opts_reset(&reopen_opts);
2180
2181 if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) {
2182 if (has_rw_option) {
2183 error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'");
2184 qobject_unref(opts);
2185 return -EINVAL;
2186 }
2187 } else {
2188 qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
2189 }
2190
2191 if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) ||
2192 qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) {
2193 if (has_cache_option) {
2194 error_report("Cannot set both -c and the cache options");
2195 qobject_unref(opts);
2196 return -EINVAL;
2197 }
2198 } else {
2199 qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
2200 qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
2201 }
2202
2203 bdrv_subtree_drained_begin(bs);
2204 brq = bdrv_reopen_queue(NULL, bs, opts, true);
2205 bdrv_reopen_multiple(brq, &local_err);
2206 bdrv_subtree_drained_end(bs);
2207
2208 if (local_err) {
2209 error_report_err(local_err);
2210 return -EINVAL;
2211 }
2212
2213 blk_set_enable_write_cache(blk, !writethrough);
2214 return 0;
2215}
2216
2217static int break_f(BlockBackend *blk, int argc, char **argv)
2218{
2219 int ret;
2220
2221 ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
2222 if (ret < 0) {
2223 printf("Could not set breakpoint: %s\n", strerror(-ret));
2224 return ret;
2225 }
2226
2227 return 0;
2228}
2229
2230static int remove_break_f(BlockBackend *blk, int argc, char **argv)
2231{
2232 int ret;
2233
2234 ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
2235 if (ret < 0) {
2236 printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
2237 return ret;
2238 }
2239
2240 return 0;
2241}
2242
2243static const cmdinfo_t break_cmd = {
2244 .name = "break",
2245 .argmin = 2,
2246 .argmax = 2,
2247 .cfunc = break_f,
2248 .args = "event tag",
2249 .oneline = "sets a breakpoint on event and tags the stopped "
2250 "request as tag",
2251};
2252
2253static const cmdinfo_t remove_break_cmd = {
2254 .name = "remove_break",
2255 .argmin = 1,
2256 .argmax = 1,
2257 .cfunc = remove_break_f,
2258 .args = "tag",
2259 .oneline = "remove a breakpoint by tag",
2260};
2261
2262static int resume_f(BlockBackend *blk, int argc, char **argv)
2263{
2264 int ret;
2265
2266 ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
2267 if (ret < 0) {
2268 printf("Could not resume request: %s\n", strerror(-ret));
2269 return ret;
2270 }
2271
2272 return 0;
2273}
2274
2275static const cmdinfo_t resume_cmd = {
2276 .name = "resume",
2277 .argmin = 1,
2278 .argmax = 1,
2279 .cfunc = resume_f,
2280 .args = "tag",
2281 .oneline = "resumes the request tagged as tag",
2282};
2283
2284static int wait_break_f(BlockBackend *blk, int argc, char **argv)
2285{
2286 while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
2287 aio_poll(blk_get_aio_context(blk), true);
2288 }
2289 return 0;
2290}
2291
2292static const cmdinfo_t wait_break_cmd = {
2293 .name = "wait_break",
2294 .argmin = 1,
2295 .argmax = 1,
2296 .cfunc = wait_break_f,
2297 .args = "tag",
2298 .oneline = "waits for the suspension of a request",
2299};
2300
2301static int abort_f(BlockBackend *blk, int argc, char **argv)
2302{
2303 abort();
2304}
2305
2306static const cmdinfo_t abort_cmd = {
2307 .name = "abort",
2308 .cfunc = abort_f,
2309 .flags = CMD_NOFILE_OK,
2310 .oneline = "simulate a program crash using abort(3)",
2311};
2312
2313static void sigraise_help(void)
2314{
2315 printf(
2316"\n"
2317" raises the given signal\n"
2318"\n"
2319" Example:\n"
2320" 'sigraise %i' - raises SIGTERM\n"
2321"\n"
2322" Invokes raise(signal), where \"signal\" is the mandatory integer argument\n"
2323" given to sigraise.\n"
2324"\n", SIGTERM);
2325}
2326
2327static int sigraise_f(BlockBackend *blk, int argc, char **argv);
2328
2329static const cmdinfo_t sigraise_cmd = {
2330 .name = "sigraise",
2331 .cfunc = sigraise_f,
2332 .argmin = 1,
2333 .argmax = 1,
2334 .flags = CMD_NOFILE_OK,
2335 .args = "signal",
2336 .oneline = "raises a signal",
2337 .help = sigraise_help,
2338};
2339
2340static int sigraise_f(BlockBackend *blk, int argc, char **argv)
2341{
2342 int64_t sig = cvtnum(argv[1]);
2343 if (sig < 0) {
2344 print_cvtnum_err(sig, argv[1]);
2345 return sig;
2346 } else if (sig > NSIG) {
2347 printf("signal argument '%s' is too large to be a valid signal\n",
2348 argv[1]);
2349 return -EINVAL;
2350 }
2351
2352
2353
2354
2355 fflush(stdout);
2356 fflush(stderr);
2357
2358 raise(sig);
2359
2360 return 0;
2361}
2362
2363static void sleep_cb(void *opaque)
2364{
2365 bool *expired = opaque;
2366 *expired = true;
2367}
2368
2369static int sleep_f(BlockBackend *blk, int argc, char **argv)
2370{
2371 char *endptr;
2372 long ms;
2373 struct QEMUTimer *timer;
2374 bool expired = false;
2375
2376 ms = strtol(argv[1], &endptr, 0);
2377 if (ms < 0 || *endptr != '\0') {
2378 printf("%s is not a valid number\n", argv[1]);
2379 return -EINVAL;
2380 }
2381
2382 timer = timer_new_ns(QEMU_CLOCK_HOST, sleep_cb, &expired);
2383 timer_mod(timer, qemu_clock_get_ns(QEMU_CLOCK_HOST) + SCALE_MS * ms);
2384
2385 while (!expired) {
2386 main_loop_wait(false);
2387 }
2388
2389 timer_free(timer);
2390 return 0;
2391}
2392
2393static const cmdinfo_t sleep_cmd = {
2394 .name = "sleep",
2395 .argmin = 1,
2396 .argmax = 1,
2397 .cfunc = sleep_f,
2398 .flags = CMD_NOFILE_OK,
2399 .oneline = "waits for the given value in milliseconds",
2400};
2401
2402static void help_oneline(const char *cmd, const cmdinfo_t *ct)
2403{
2404 printf("%s ", cmd);
2405
2406 if (ct->args) {
2407 printf("%s ", ct->args);
2408 }
2409 printf("-- %s\n", ct->oneline);
2410}
2411
2412static void help_onecmd(const char *cmd, const cmdinfo_t *ct)
2413{
2414 help_oneline(cmd, ct);
2415 if (ct->help) {
2416 ct->help();
2417 }
2418}
2419
2420static void help_all(void)
2421{
2422 const cmdinfo_t *ct;
2423
2424 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
2425 help_oneline(ct->name, ct);
2426 }
2427 printf("\nUse 'help commandname' for extended help.\n");
2428}
2429
2430static int help_f(BlockBackend *blk, int argc, char **argv)
2431{
2432 const cmdinfo_t *ct;
2433
2434 if (argc < 2) {
2435 help_all();
2436 return 0;
2437 }
2438
2439 ct = find_command(argv[1]);
2440 if (ct == NULL) {
2441 printf("command %s not found\n", argv[1]);
2442 return -EINVAL;
2443 }
2444
2445 help_onecmd(argv[1], ct);
2446 return 0;
2447}
2448
2449static const cmdinfo_t help_cmd = {
2450 .name = "help",
2451 .altname = "?",
2452 .cfunc = help_f,
2453 .argmin = 0,
2454 .argmax = 1,
2455 .flags = CMD_FLAG_GLOBAL,
2456 .args = "[command]",
2457 .oneline = "help for one or all commands",
2458};
2459
2460int qemuio_command(BlockBackend *blk, const char *cmd)
2461{
2462 AioContext *ctx;
2463 char *input;
2464 const cmdinfo_t *ct;
2465 char **v;
2466 int c;
2467 int ret = 0;
2468
2469 input = g_strdup(cmd);
2470 v = breakline(input, &c);
2471 if (c) {
2472 ct = find_command(v[0]);
2473 if (ct) {
2474 ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context();
2475 aio_context_acquire(ctx);
2476 ret = command(blk, ct, c, v);
2477 aio_context_release(ctx);
2478 } else {
2479 fprintf(stderr, "command \"%s\" not found\n", v[0]);
2480 ret = -EINVAL;
2481 }
2482 }
2483 g_free(input);
2484 g_free(v);
2485
2486 return ret;
2487}
2488
2489static void __attribute((constructor)) init_qemuio_commands(void)
2490{
2491
2492 qemuio_add_command(&help_cmd);
2493 qemuio_add_command(&read_cmd);
2494 qemuio_add_command(&readv_cmd);
2495 qemuio_add_command(&write_cmd);
2496 qemuio_add_command(&writev_cmd);
2497 qemuio_add_command(&aio_read_cmd);
2498 qemuio_add_command(&aio_write_cmd);
2499 qemuio_add_command(&aio_flush_cmd);
2500 qemuio_add_command(&flush_cmd);
2501 qemuio_add_command(&truncate_cmd);
2502 qemuio_add_command(&length_cmd);
2503 qemuio_add_command(&info_cmd);
2504 qemuio_add_command(&discard_cmd);
2505 qemuio_add_command(&alloc_cmd);
2506 qemuio_add_command(&map_cmd);
2507 qemuio_add_command(&reopen_cmd);
2508 qemuio_add_command(&break_cmd);
2509 qemuio_add_command(&remove_break_cmd);
2510 qemuio_add_command(&resume_cmd);
2511 qemuio_add_command(&wait_break_cmd);
2512 qemuio_add_command(&abort_cmd);
2513 qemuio_add_command(&sleep_cmd);
2514 qemuio_add_command(&sigraise_cmd);
2515}
2516