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