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