virtio-blk: add SGI_IO passthru support
[qemu] / qemu-io.c
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 }