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