1 /* 2 * Command line utility to exercise the QEMU I/O path. 3 * 4 * Copyright (C) 2009 Red Hat, Inc. 5 * Copyright (c) 2003-2005 Silicon Graphics, Inc. 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or later. 8 * See the COPYING file in the top-level directory. 9 */ 10 #include <sys/types.h> 11 #include <stdarg.h> 12 #include <stdio.h> 13 #include <getopt.h> 14 15 #include "qemu-common.h" 16 #include "block_int.h" 17 #include "cmd.h" 18 19 #define VERSION "0.0.1" 20 21 #define CMD_NOFILE_OK 0x01 22 23 char *progname; 24 static BlockDriverState *bs; 25 26 static int misalign; 27 28 /* 29 * Memory allocation helpers. 30 * 31 * Make sure memory is aligned by default, or purposefully misaligned if 32 * that is specified on the command line. 33 */ 34 35 #define MISALIGN_OFFSET 16 36 static void *qemu_io_alloc(size_t len, int pattern) 37 { 38 void *buf; 39 40 if (misalign) 41 len += MISALIGN_OFFSET; 42 buf = qemu_memalign(512, len); 43 memset(buf, pattern, len); 44 if (misalign) 45 buf += MISALIGN_OFFSET; 46 return buf; 47 } 48 49 static void qemu_io_free(void *p) 50 { 51 if (misalign) 52 p -= MISALIGN_OFFSET; 53 qemu_vfree(p); 54 } 55 56 static void 57 dump_buffer(char *buffer, int64_t offset, int len) 58 { 59 int i, j; 60 char *p; 61 62 for (i = 0, p = buffer; i < len; i += 16) { 63 char *s = p; 64 65 printf("%08llx: ", (unsigned long long)offset + i); 66 for (j = 0; j < 16 && i + j < len; j++, p++) 67 printf("%02x ", *p); 68 printf(" "); 69 for (j = 0; j < 16 && i + j < len; j++, s++) { 70 if (isalnum((int)*s)) 71 printf("%c", *s); 72 else 73 printf("."); 74 } 75 printf("\n"); 76 } 77 } 78 79 static void 80 print_report(const char *op, struct timeval *t, int64_t offset, 81 int count, int total, int cnt, int Cflag) 82 { 83 char s1[64], s2[64], ts[64]; 84 85 timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); 86 if (!Cflag) { 87 cvtstr((double)total, s1, sizeof(s1)); 88 cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); 89 printf("%s %d/%d bytes at offset %lld\n", 90 op, total, count, (long long)offset); 91 printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", 92 s1, cnt, ts, s2, tdiv((double)cnt, *t)); 93 } else {/* bytes,ops,time,bytes/sec,ops/sec */ 94 printf("%d,%d,%s,%.3f,%.3f\n", 95 total, cnt, ts, 96 tdiv((double)total, *t), 97 tdiv((double)cnt, *t)); 98 } 99 } 100 101 static int do_read(char *buf, int64_t offset, int count, int *total) 102 { 103 int ret; 104 105 ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); 106 if (ret < 0) 107 return ret; 108 *total = count; 109 return 1; 110 } 111 112 static int do_write(char *buf, int64_t offset, int count, int *total) 113 { 114 int ret; 115 116 ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); 117 if (ret < 0) 118 return ret; 119 *total = count; 120 return 1; 121 } 122 123 static int do_pread(char *buf, int64_t offset, int count, int *total) 124 { 125 *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); 126 if (*total < 0) 127 return *total; 128 return 1; 129 } 130 131 static int do_pwrite(char *buf, int64_t offset, int count, int *total) 132 { 133 *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); 134 if (*total < 0) 135 return *total; 136 return 1; 137 } 138 139 #define NOT_DONE 0x7fffffff 140 static void aio_rw_done(void *opaque, int ret) 141 { 142 *(int *)opaque = ret; 143 } 144 145 static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) 146 { 147 BlockDriverAIOCB *acb; 148 int async_ret = NOT_DONE; 149 150 acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, 151 aio_rw_done, &async_ret); 152 if (!acb) 153 return -EIO; 154 155 while (async_ret == NOT_DONE) 156 qemu_aio_wait(); 157 158 *total = qiov->size; 159 return async_ret < 0 ? async_ret : 1; 160 } 161 162 static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) 163 { 164 BlockDriverAIOCB *acb; 165 int async_ret = NOT_DONE; 166 167 acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, 168 aio_rw_done, &async_ret); 169 if (!acb) 170 return -EIO; 171 172 while (async_ret == NOT_DONE) 173 qemu_aio_wait(); 174 175 *total = qiov->size; 176 return async_ret < 0 ? async_ret : 1; 177 } 178 179 180 static const cmdinfo_t read_cmd; 181 182 static void 183 read_help(void) 184 { 185 printf( 186 "\n" 187 " reads a range of bytes from the given offset\n" 188 "\n" 189 " Example:\n" 190 " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" 191 "\n" 192 " Reads a segment of the currently open file, optionally dumping it to the\n" 193 " standard output stream (with -v option) for subsequent inspection.\n" 194 " -C, -- report statistics in a machine parsable format\n" 195 " -l, -- length for pattern verification (only with -P)\n" 196 " -p, -- use bdrv_pread to read the file\n" 197 " -P, -- use a pattern to verify read data\n" 198 " -q, -- quite mode, do not show I/O statistics\n" 199 " -s, -- start offset for pattern verification (only with -P)\n" 200 " -v, -- dump buffer to standard output\n" 201 "\n"); 202 } 203 204 static int 205 read_f(int argc, char **argv) 206 { 207 struct timeval t1, t2; 208 int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; 209 int Pflag = 0, sflag = 0, lflag = 0; 210 int c, cnt; 211 char *buf; 212 int64_t offset; 213 int count; 214 /* Some compilers get confused and warn if this is not initialized. */ 215 int total = 0; 216 int pattern = 0, pattern_offset = 0, pattern_count = 0; 217 218 while ((c = getopt(argc, argv, "Cl:pP:qs:v")) != EOF) { 219 switch (c) { 220 case 'C': 221 Cflag = 1; 222 break; 223 case 'l': 224 lflag = 1; 225 pattern_count = cvtnum(optarg); 226 if (pattern_count < 0) { 227 printf("non-numeric length argument -- %s\n", optarg); 228 return 0; 229 } 230 break; 231 case 'p': 232 pflag = 1; 233 break; 234 case 'P': 235 Pflag = 1; 236 pattern = atoi(optarg); 237 break; 238 case 'q': 239 qflag = 1; 240 break; 241 case 's': 242 sflag = 1; 243 pattern_offset = cvtnum(optarg); 244 if (pattern_offset < 0) { 245 printf("non-numeric length argument -- %s\n", optarg); 246 return 0; 247 } 248 break; 249 case 'v': 250 vflag = 1; 251 break; 252 default: 253 return command_usage(&read_cmd); 254 } 255 } 256 257 if (optind != argc - 2) 258 return command_usage(&read_cmd); 259 260 offset = cvtnum(argv[optind]); 261 if (offset < 0) { 262 printf("non-numeric length argument -- %s\n", argv[optind]); 263 return 0; 264 } 265 266 optind++; 267 count = cvtnum(argv[optind]); 268 if (count < 0) { 269 printf("non-numeric length argument -- %s\n", argv[optind]); 270 return 0; 271 } 272 273 if (!Pflag && (lflag || sflag)) { 274 return command_usage(&read_cmd); 275 } 276 277 if (!lflag) { 278 pattern_count = count - pattern_offset; 279 } 280 281 if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { 282 printf("pattern verfication range exceeds end of read data\n"); 283 return 0; 284 } 285 286 if (!pflag) 287 if (offset & 0x1ff) { 288 printf("offset %lld is not sector aligned\n", 289 (long long)offset); 290 return 0; 291 292 if (count & 0x1ff) { 293 printf("count %d is not sector aligned\n", 294 count); 295 return 0; 296 } 297 } 298 299 buf = qemu_io_alloc(count, 0xab); 300 301 gettimeofday(&t1, NULL); 302 if (pflag) 303 cnt = do_pread(buf, offset, count, &total); 304 else 305 cnt = do_read(buf, offset, count, &total); 306 gettimeofday(&t2, NULL); 307 308 if (cnt < 0) { 309 printf("read failed: %s\n", strerror(-cnt)); 310 return 0; 311 } 312 313 if (Pflag) { 314 void* cmp_buf = malloc(pattern_count); 315 memset(cmp_buf, pattern, pattern_count); 316 if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { 317 printf("Pattern verification failed at offset %lld, " 318 "%d bytes\n", 319 (long long) offset + pattern_offset, pattern_count); 320 } 321 free(cmp_buf); 322 } 323 324 if (qflag) 325 return 0; 326 327 if (vflag) 328 dump_buffer(buf, offset, count); 329 330 /* Finally, report back -- -C gives a parsable format */ 331 t2 = tsub(t2, t1); 332 print_report("read", &t2, offset, count, total, cnt, Cflag); 333 334 qemu_io_free(buf); 335 336 return 0; 337 } 338 339 static const cmdinfo_t read_cmd = { 340 .name = "read", 341 .altname = "r", 342 .cfunc = read_f, 343 .argmin = 2, 344 .argmax = -1, 345 .args = "[-aCpqv] [-P pattern [-s off] [-l len]] off len", 346 .oneline = "reads a number of bytes at a specified offset", 347 .help = read_help, 348 }; 349 350 static const cmdinfo_t readv_cmd; 351 352 static void 353 readv_help(void) 354 { 355 printf( 356 "\n" 357 " reads a range of bytes from the given offset into multiple buffers\n" 358 "\n" 359 " Example:\n" 360 " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" 361 "\n" 362 " Reads a segment of the currently open file, optionally dumping it to the\n" 363 " standard output stream (with -v option) for subsequent inspection.\n" 364 " Uses multiple iovec buffers if more than one byte range is specified.\n" 365 " -C, -- report statistics in a machine parsable format\n" 366 " -P, -- use a pattern to verify read data\n" 367 " -v, -- dump buffer to standard output\n" 368 " -q, -- quite mode, do not show I/O statistics\n" 369 "\n"); 370 } 371 372 static int 373 readv_f(int argc, char **argv) 374 { 375 struct timeval t1, t2; 376 int Cflag = 0, qflag = 0, vflag = 0; 377 int c, cnt; 378 char *buf, *p; 379 int64_t offset; 380 int count = 0, total; 381 int nr_iov, i; 382 QEMUIOVector qiov; 383 int pattern = 0; 384 int Pflag = 0; 385 386 while ((c = getopt(argc, argv, "CP:qv")) != EOF) { 387 switch (c) { 388 case 'C': 389 Cflag = 1; 390 break; 391 case 'P': 392 Pflag = 1; 393 pattern = atoi(optarg); 394 break; 395 case 'q': 396 qflag = 1; 397 break; 398 case 'v': 399 vflag = 1; 400 break; 401 default: 402 return command_usage(&readv_cmd); 403 } 404 } 405 406 if (optind > argc - 2) 407 return command_usage(&readv_cmd); 408 409 410 offset = cvtnum(argv[optind]); 411 if (offset < 0) { 412 printf("non-numeric length argument -- %s\n", argv[optind]); 413 return 0; 414 } 415 optind++; 416 417 if (offset & 0x1ff) { 418 printf("offset %lld is not sector aligned\n", 419 (long long)offset); 420 return 0; 421 } 422 423 if (count & 0x1ff) { 424 printf("count %d is not sector aligned\n", 425 count); 426 return 0; 427 } 428 429 for (i = optind; i < argc; i++) { 430 size_t len; 431 432 len = cvtnum(argv[i]); 433 if (len < 0) { 434 printf("non-numeric length argument -- %s\n", argv[i]); 435 return 0; 436 } 437 count += len; 438 } 439 440 nr_iov = argc - optind; 441 qemu_iovec_init(&qiov, nr_iov); 442 buf = p = qemu_io_alloc(count, 0xab); 443 for (i = 0; i < nr_iov; i++) { 444 size_t len; 445 446 len = cvtnum(argv[optind]); 447 if (len < 0) { 448 printf("non-numeric length argument -- %s\n", 449 argv[optind]); 450 return 0; 451 } 452 453 qemu_iovec_add(&qiov, p, len); 454 p += len; 455 optind++; 456 } 457 458 gettimeofday(&t1, NULL); 459 cnt = do_aio_readv(&qiov, offset, &total); 460 gettimeofday(&t2, NULL); 461 462 if (cnt < 0) { 463 printf("readv failed: %s\n", strerror(-cnt)); 464 return 0; 465 } 466 467 if (Pflag) { 468 void* cmp_buf = malloc(count); 469 memset(cmp_buf, pattern, count); 470 if (memcmp(buf, cmp_buf, count)) { 471 printf("Pattern verification failed at offset %lld, " 472 "%d bytes\n", 473 (long long) offset, count); 474 } 475 free(cmp_buf); 476 } 477 478 if (qflag) 479 return 0; 480 481 if (vflag) 482 dump_buffer(buf, offset, qiov.size); 483 484 /* Finally, report back -- -C gives a parsable format */ 485 t2 = tsub(t2, t1); 486 print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); 487 488 qemu_io_free(buf); 489 490 return 0; 491 } 492 493 static const cmdinfo_t readv_cmd = { 494 .name = "readv", 495 .cfunc = readv_f, 496 .argmin = 2, 497 .argmax = -1, 498 .args = "[-Cqv] [-P pattern ] off len [len..]", 499 .oneline = "reads a number of bytes at a specified offset", 500 .help = readv_help, 501 }; 502 503 static const cmdinfo_t write_cmd; 504 505 static void 506 write_help(void) 507 { 508 printf( 509 "\n" 510 " writes a range of bytes from the given offset\n" 511 "\n" 512 " Example:\n" 513 " 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" 514 "\n" 515 " Writes into a segment of the currently open file, using a buffer\n" 516 " filled with a set pattern (0xcdcdcdcd).\n" 517 " -p, -- use bdrv_pwrite to write the file\n" 518 " -P, -- use different pattern to fill file\n" 519 " -C, -- report statistics in a machine parsable format\n" 520 " -q, -- quite mode, do not show I/O statistics\n" 521 "\n"); 522 } 523 524 static int 525 write_f(int argc, char **argv) 526 { 527 struct timeval t1, t2; 528 int Cflag = 0, pflag = 0, qflag = 0; 529 int c, cnt; 530 char *buf; 531 int64_t offset; 532 int count; 533 /* Some compilers get confused and warn if this is not initialized. */ 534 int total = 0; 535 int pattern = 0xcd; 536 537 while ((c = getopt(argc, argv, "CpP:q")) != EOF) { 538 switch (c) { 539 case 'C': 540 Cflag = 1; 541 break; 542 case 'p': 543 pflag = 1; 544 break; 545 case 'P': 546 pattern = atoi(optarg); 547 break; 548 case 'q': 549 qflag = 1; 550 break; 551 default: 552 return command_usage(&write_cmd); 553 } 554 } 555 556 if (optind != argc - 2) 557 return command_usage(&write_cmd); 558 559 offset = cvtnum(argv[optind]); 560 if (offset < 0) { 561 printf("non-numeric length argument -- %s\n", argv[optind]); 562 return 0; 563 } 564 565 optind++; 566 count = cvtnum(argv[optind]); 567 if (count < 0) { 568 printf("non-numeric length argument -- %s\n", argv[optind]); 569 return 0; 570 } 571 572 if (!pflag) { 573 if (offset & 0x1ff) { 574 printf("offset %lld is not sector aligned\n", 575 (long long)offset); 576 return 0; 577 } 578 579 if (count & 0x1ff) { 580 printf("count %d is not sector aligned\n", 581 count); 582 return 0; 583 } 584 } 585 586 buf = qemu_io_alloc(count, pattern); 587 588 gettimeofday(&t1, NULL); 589 if (pflag) 590 cnt = do_pwrite(buf, offset, count, &total); 591 else 592 cnt = do_write(buf, offset, count, &total); 593 gettimeofday(&t2, NULL); 594 595 if (cnt < 0) { 596 printf("write failed: %s\n", strerror(-cnt)); 597 return 0; 598 } 599 600 if (qflag) 601 return 0; 602 603 /* Finally, report back -- -C gives a parsable format */ 604 t2 = tsub(t2, t1); 605 print_report("wrote", &t2, offset, count, total, cnt, Cflag); 606 607 qemu_io_free(buf); 608 609 return 0; 610 } 611 612 static const cmdinfo_t write_cmd = { 613 .name = "write", 614 .altname = "w", 615 .cfunc = write_f, 616 .argmin = 2, 617 .argmax = -1, 618 .args = "[-aCpq] [-P pattern ] off len", 619 .oneline = "writes a number of bytes at a specified offset", 620 .help = write_help, 621 }; 622 623 static const cmdinfo_t writev_cmd; 624 625 static void 626 writev_help(void) 627 { 628 printf( 629 "\n" 630 " writes a range of bytes from the given offset source from multiple buffers\n" 631 "\n" 632 " Example:\n" 633 " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" 634 "\n" 635 " Writes into a segment of the currently open file, using a buffer\n" 636 " filled with a set pattern (0xcdcdcdcd).\n" 637 " -P, -- use different pattern to fill file\n" 638 " -C, -- report statistics in a machine parsable format\n" 639 " -q, -- quite mode, do not show I/O statistics\n" 640 "\n"); 641 } 642 643 static int 644 writev_f(int argc, char **argv) 645 { 646 struct timeval t1, t2; 647 int Cflag = 0, qflag = 0; 648 int c, cnt; 649 char *buf, *p; 650 int64_t offset; 651 int count = 0, total; 652 int nr_iov, i; 653 int pattern = 0xcd; 654 QEMUIOVector qiov; 655 656 while ((c = getopt(argc, argv, "CqP:")) != EOF) { 657 switch (c) { 658 case 'C': 659 Cflag = 1; 660 break; 661 case 'q': 662 qflag = 1; 663 break; 664 case 'P': 665 pattern = atoi(optarg); 666 break; 667 default: 668 return command_usage(&writev_cmd); 669 } 670 } 671 672 if (optind > argc - 2) 673 return command_usage(&writev_cmd); 674 675 offset = cvtnum(argv[optind]); 676 if (offset < 0) { 677 printf("non-numeric length argument -- %s\n", argv[optind]); 678 return 0; 679 } 680 optind++; 681 682 if (offset & 0x1ff) { 683 printf("offset %lld is not sector aligned\n", 684 (long long)offset); 685 return 0; 686 } 687 688 if (count & 0x1ff) { 689 printf("count %d is not sector aligned\n", 690 count); 691 return 0; 692 } 693 694 695 for (i = optind; i < argc; i++) { 696 size_t len; 697 698 len = cvtnum(argv[optind]); 699 if (len < 0) { 700 printf("non-numeric length argument -- %s\n", argv[i]); 701 return 0; 702 } 703 count += len; 704 } 705 706 nr_iov = argc - optind; 707 qemu_iovec_init(&qiov, nr_iov); 708 buf = p = qemu_io_alloc(count, pattern); 709 for (i = 0; i < nr_iov; i++) { 710 size_t len; 711 712 len = cvtnum(argv[optind]); 713 if (len < 0) { 714 printf("non-numeric length argument -- %s\n", 715 argv[optind]); 716 return 0; 717 } 718 719 qemu_iovec_add(&qiov, p, len); 720 p += len; 721 optind++; 722 } 723 724 gettimeofday(&t1, NULL); 725 cnt = do_aio_writev(&qiov, offset, &total); 726 gettimeofday(&t2, NULL); 727 728 if (cnt < 0) { 729 printf("writev failed: %s\n", strerror(-cnt)); 730 return 0; 731 } 732 733 if (qflag) 734 return 0; 735 736 /* Finally, report back -- -C gives a parsable format */ 737 t2 = tsub(t2, t1); 738 print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); 739 740 qemu_io_free(buf); 741 742 return 0; 743 } 744 745 static const cmdinfo_t writev_cmd = { 746 .name = "writev", 747 .cfunc = writev_f, 748 .argmin = 2, 749 .argmax = -1, 750 .args = "[-Cq] [-P pattern ] off len [len..]", 751 .oneline = "writes a number of bytes at a specified offset", 752 .help = writev_help, 753 }; 754 755 static int 756 flush_f(int argc, char **argv) 757 { 758 bdrv_flush(bs); 759 return 0; 760 } 761 762 static const cmdinfo_t flush_cmd = { 763 .name = "flush", 764 .altname = "f", 765 .cfunc = flush_f, 766 .oneline = "flush all in-core file state to disk", 767 }; 768 769 static int 770 truncate_f(int argc, char **argv) 771 { 772 int64_t offset; 773 int ret; 774 775 offset = cvtnum(argv[1]); 776 if (offset < 0) { 777 printf("non-numeric truncate argument -- %s\n", argv[1]); 778 return 0; 779 } 780 781 ret = bdrv_truncate(bs, offset); 782 if (ret < 0) { 783 printf("truncate: %s", strerror(ret)); 784 return 0; 785 } 786 787 return 0; 788 } 789 790 static const cmdinfo_t truncate_cmd = { 791 .name = "truncate", 792 .altname = "t", 793 .cfunc = truncate_f, 794 .argmin = 1, 795 .argmax = 1, 796 .args = "off", 797 .oneline = "truncates the current file at the given offset", 798 }; 799 800 static int 801 length_f(int argc, char **argv) 802 { 803 int64_t size; 804 char s1[64]; 805 806 size = bdrv_getlength(bs); 807 if (size < 0) { 808 printf("getlength: %s", strerror(size)); 809 return 0; 810 } 811 812 cvtstr(size, s1, sizeof(s1)); 813 printf("%s\n", s1); 814 return 0; 815 } 816 817 818 static const cmdinfo_t length_cmd = { 819 .name = "length", 820 .altname = "l", 821 .cfunc = length_f, 822 .oneline = "gets the length of the current file", 823 }; 824 825 826 static int 827 info_f(int argc, char **argv) 828 { 829 BlockDriverInfo bdi; 830 char s1[64], s2[64]; 831 int ret; 832 833 if (bs->drv && bs->drv->format_name) 834 printf("format name: %s\n", bs->drv->format_name); 835 if (bs->drv && bs->drv->protocol_name) 836 printf("format name: %s\n", bs->drv->protocol_name); 837 838 ret = bdrv_get_info(bs, &bdi); 839 if (ret) 840 return 0; 841 842 cvtstr(bdi.cluster_size, s1, sizeof(s1)); 843 cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); 844 845 printf("cluster size: %s\n", s1); 846 printf("vm state offset: %s\n", s2); 847 848 return 0; 849 } 850 851 852 853 static const cmdinfo_t info_cmd = { 854 .name = "info", 855 .altname = "i", 856 .cfunc = info_f, 857 .oneline = "prints information about the current file", 858 }; 859 860 static int 861 alloc_f(int argc, char **argv) 862 { 863 int64_t offset; 864 int nb_sectors; 865 char s1[64]; 866 int num; 867 int ret; 868 const char *retstr; 869 870 offset = cvtnum(argv[1]); 871 if (offset & 0x1ff) { 872 printf("offset %lld is not sector aligned\n", 873 (long long)offset); 874 return 0; 875 } 876 877 if (argc == 3) 878 nb_sectors = cvtnum(argv[2]); 879 else 880 nb_sectors = 1; 881 882 ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num); 883 884 cvtstr(offset, s1, sizeof(s1)); 885 886 retstr = ret ? "allocated" : "not allocated"; 887 if (nb_sectors == 1) 888 printf("sector %s at offset %s\n", retstr, s1); 889 else 890 printf("%d/%d sectors %s at offset %s\n", 891 num, nb_sectors, retstr, s1); 892 return 0; 893 } 894 895 static const cmdinfo_t alloc_cmd = { 896 .name = "alloc", 897 .altname = "a", 898 .argmin = 1, 899 .argmax = 2, 900 .cfunc = alloc_f, 901 .args = "off [sectors]", 902 .oneline = "checks if a sector is present in the file", 903 }; 904 905 static int 906 close_f(int argc, char **argv) 907 { 908 bdrv_close(bs); 909 bs = NULL; 910 return 0; 911 } 912 913 static const cmdinfo_t close_cmd = { 914 .name = "close", 915 .altname = "c", 916 .cfunc = close_f, 917 .oneline = "close the current open file", 918 }; 919 920 static int openfile(char *name, int flags) 921 { 922 if (bs) { 923 fprintf(stderr, "file open already, try 'help close'\n"); 924 return 1; 925 } 926 927 bs = bdrv_new("hda"); 928 if (!bs) 929 return 1; 930 931 if (bdrv_open(bs, name, flags) == -1) { 932 fprintf(stderr, "%s: can't open device %s\n", progname, name); 933 bs = NULL; 934 return 1; 935 } 936 937 return 0; 938 } 939 940 static void 941 open_help(void) 942 { 943 printf( 944 "\n" 945 " opens a new file in the requested mode\n" 946 "\n" 947 " Example:\n" 948 " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" 949 "\n" 950 " Opens a file for subsequent use by all of the other qemu-io commands.\n" 951 " -C, -- create new file if it doesn't exist\n" 952 " -r, -- open file read-only\n" 953 " -s, -- use snapshot file\n" 954 " -n, -- disable host cache\n" 955 "\n"); 956 } 957 958 static const cmdinfo_t open_cmd; 959 960 static int 961 open_f(int argc, char **argv) 962 { 963 int flags = 0; 964 int readonly = 0; 965 int c; 966 967 while ((c = getopt(argc, argv, "snCr")) != EOF) { 968 switch (c) { 969 case 's': 970 flags |= BDRV_O_SNAPSHOT; 971 break; 972 case 'n': 973 flags |= BDRV_O_NOCACHE; 974 break; 975 case 'C': 976 flags |= BDRV_O_CREAT; 977 break; 978 case 'r': 979 readonly = 1; 980 break; 981 default: 982 return command_usage(&open_cmd); 983 } 984 } 985 986 if (readonly) 987 flags |= BDRV_O_RDONLY; 988 else 989 flags |= BDRV_O_RDWR; 990 991 if (optind != argc - 1) 992 return command_usage(&open_cmd); 993 994 return openfile(argv[optind], flags); 995 } 996 997 static const cmdinfo_t open_cmd = { 998 .name = "open", 999 .altname = "o", 1000 .cfunc = open_f, 1001 .argmin = 1, 1002 .argmax = -1, 1003 .flags = CMD_NOFILE_OK, 1004 .args = "[-Crsn] [path]", 1005 .oneline = "open the file specified by path", 1006 .help = open_help, 1007 }; 1008 1009 static int 1010 init_args_command( 1011 int index) 1012 { 1013 /* only one device allowed so far */ 1014 if (index >= 1) 1015 return 0; 1016 return ++index; 1017 } 1018 1019 static int 1020 init_check_command( 1021 const cmdinfo_t *ct) 1022 { 1023 if (ct->flags & CMD_FLAG_GLOBAL) 1024 return 1; 1025 if (!(ct->flags & CMD_NOFILE_OK) && !bs) { 1026 fprintf(stderr, "no file open, try 'help open'\n"); 1027 return 0; 1028 } 1029 return 1; 1030 } 1031 1032 static void usage(const char *name) 1033 { 1034 printf( 1035 "Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n" 1036 "QEMU Disk excerciser\n" 1037 "\n" 1038 " -C, --create create new file if it doesn't exist\n" 1039 " -c, --cmd command to execute\n" 1040 " -r, --read-only export read-only\n" 1041 " -s, --snapshot use snapshot file\n" 1042 " -n, --nocache disable host cache\n" 1043 " -m, --misalign misalign allocations for O_DIRECT\n" 1044 " -h, --help display this help and exit\n" 1045 " -V, --version output version information and exit\n" 1046 "\n", 1047 name); 1048 } 1049 1050 1051 int main(int argc, char **argv) 1052 { 1053 int readonly = 0; 1054 const char *sopt = "hVc:Crsnm"; 1055 struct option lopt[] = { 1056 { "help", 0, 0, 'h' }, 1057 { "version", 0, 0, 'V' }, 1058 { "offset", 1, 0, 'o' }, 1059 { "cmd", 1, 0, 'c' }, 1060 { "create", 0, 0, 'C' }, 1061 { "read-only", 0, 0, 'r' }, 1062 { "snapshot", 0, 0, 's' }, 1063 { "nocache", 0, 0, 'n' }, 1064 { "misalign", 0, 0, 'm' }, 1065 { NULL, 0, 0, 0 } 1066 }; 1067 int c; 1068 int opt_index = 0; 1069 int flags = 0; 1070 1071 progname = basename(argv[0]); 1072 1073 while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { 1074 switch (c) { 1075 case 's': 1076 flags |= BDRV_O_SNAPSHOT; 1077 break; 1078 case 'n': 1079 flags |= BDRV_O_NOCACHE; 1080 break; 1081 case 'c': 1082 add_user_command(optarg); 1083 break; 1084 case 'C': 1085 flags |= BDRV_O_CREAT; 1086 break; 1087 case 'r': 1088 readonly = 1; 1089 break; 1090 case 'm': 1091 misalign = 1; 1092 break; 1093 case 'V': 1094 printf("%s version %s\n", progname, VERSION); 1095 exit(0); 1096 case 'h': 1097 usage(progname); 1098 exit(0); 1099 default: 1100 usage(progname); 1101 exit(1); 1102 } 1103 } 1104 1105 if ((argc - optind) > 1) { 1106 usage(progname); 1107 exit(1); 1108 } 1109 1110 bdrv_init(); 1111 1112 /* initialize commands */ 1113 quit_init(); 1114 help_init(); 1115 add_command(&open_cmd); 1116 add_command(&close_cmd); 1117 add_command(&read_cmd); 1118 add_command(&readv_cmd); 1119 add_command(&write_cmd); 1120 add_command(&writev_cmd); 1121 add_command(&flush_cmd); 1122 add_command(&truncate_cmd); 1123 add_command(&length_cmd); 1124 add_command(&info_cmd); 1125 add_command(&alloc_cmd); 1126 1127 add_args_command(init_args_command); 1128 add_check_command(init_check_command); 1129 1130 /* open the device */ 1131 if (readonly) 1132 flags |= BDRV_O_RDONLY; 1133 else 1134 flags |= BDRV_O_RDWR; 1135 1136 if ((argc - optind) == 1) 1137 openfile(argv[optind], flags); 1138 command_loop(); 1139 1140 if (bs) 1141 bdrv_close(bs); 1142 return 0; 1143 } 1144