Statistics
| Branch: | Revision:

root / qemu-io.c @ e3aff4f6

History | View | Annotate | Download (20.4 kB)

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 >> 9;
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
" -C, -- report statistics in a machine parsable format\n"
196
" -v, -- dump buffer to standard output\n"
197
" -q, -- quite mode, do not show I/O statistics\n"
198
"\n");
199
}
200

    
201
static int
202
read_f(int argc, char **argv)
203
{
204
        struct timeval t1, t2;
205
        int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
206
        int c, cnt;
207
        char *buf;
208
        int64_t offset;
209
        int count, total;
210

    
211
        while ((c = getopt(argc, argv, "Cpqv")) != EOF) {
212
                switch (c) {
213
                case 'C':
214
                        Cflag = 1;
215
                        break;
216
                case 'p':
217
                        pflag = 1;
218
                        break;
219
                case 'q':
220
                        qflag = 1;
221
                        break;
222
                case 'v':
223
                        vflag = 1;
224
                        break;
225
                default:
226
                        return command_usage(&read_cmd);
227
                }
228
        }
229

    
230
        if (optind != argc - 2)
231
                return command_usage(&read_cmd);
232

    
233
        offset = cvtnum(argv[optind]);
234
        if (offset < 0) {
235
                printf("non-numeric length argument -- %s\n", argv[optind]);
236
                return 0;
237
        }
238

    
239
        optind++;
240
        count = cvtnum(argv[optind]);
241
        if (count < 0) {
242
                printf("non-numeric length argument -- %s\n", argv[optind]);
243
                return 0;
244
        }
245

    
246
        if (!pflag)
247
                if (offset & 0x1ff) {
248
                        printf("offset %lld is not sector aligned\n",
249
                                (long long)offset);
250
                        return 0;
251

    
252
                if (count & 0x1ff) {
253
                        printf("count %d is not sector aligned\n",
254
                                count);
255
                        return 0;
256
                }
257
        }
258

    
259
        buf = qemu_io_alloc(count, 0xab);
260

    
261
        gettimeofday(&t1, NULL);
262
        if (pflag)
263
                cnt = do_pread(buf, offset, count, &total);
264
        else
265
                cnt = do_read(buf, offset, count, &total);
266
        gettimeofday(&t2, NULL);
267

    
268
        if (cnt < 0) {
269
                printf("read failed: %s\n", strerror(-cnt));
270
                return 0;
271
        }
272

    
273
        if (qflag)
274
                return 0;
275

    
276
        if (vflag)
277
                dump_buffer(buf, offset, count);
278

    
279
        /* Finally, report back -- -C gives a parsable format */
280
        t2 = tsub(t2, t1);
281
        print_report("read", &t2, offset, count, total, cnt, Cflag);
282

    
283
        qemu_io_free(buf);
284

    
285
        return 0;
286
}
287

    
288
static const cmdinfo_t read_cmd = {
289
        .name                = "read",
290
        .altname        = "r",
291
        .cfunc                = read_f,
292
        .argmin                = 2,
293
        .argmax                = -1,
294
        .args                = "[-aCpqv] off len",
295
        .oneline        = "reads a number of bytes at a specified offset",
296
        .help                = read_help,
297
};
298

    
299
static const cmdinfo_t readv_cmd;
300

    
301
static void
302
readv_help(void)
303
{
304
        printf(
305
"\n"
306
" reads a range of bytes from the given offset into multiple buffers\n"
307
"\n"
308
" Example:\n"
309
" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
310
"\n"
311
" Reads a segment of the currently open file, optionally dumping it to the\n"
312
" standard output stream (with -v option) for subsequent inspection.\n"
313
" Uses multiple iovec buffers if more than one byte range is specified.\n"
314
" -C, -- report statistics in a machine parsable format\n"
315
" -v, -- dump buffer to standard output\n"
316
" -q, -- quite mode, do not show I/O statistics\n"
317
"\n");
318
}
319

    
320
static int
321
readv_f(int argc, char **argv)
322
{
323
        struct timeval t1, t2;
324
        int Cflag = 0, qflag = 0, vflag = 0;
325
        int c, cnt;
326
        char *buf, *p;
327
        int64_t offset;
328
        int count = 0, total;
329
        int nr_iov, i;
330
        QEMUIOVector qiov;
331

    
332
        while ((c = getopt(argc, argv, "Cqv")) != EOF) {
333
                switch (c) {
334
                case 'C':
335
                        Cflag = 1;
336
                        break;
337
                case 'q':
338
                        qflag = 1;
339
                        break;
340
                case 'v':
341
                        vflag = 1;
342
                        break;
343
                default:
344
                        return command_usage(&readv_cmd);
345
                }
346
        }
347

    
348
        if (optind > argc - 2)
349
                return command_usage(&readv_cmd);
350

    
351

    
352
        offset = cvtnum(argv[optind]);
353
        if (offset < 0) {
354
                printf("non-numeric length argument -- %s\n", argv[optind]);
355
                return 0;
356
        }
357
        optind++;
358

    
359
        if (offset & 0x1ff) {
360
                printf("offset %lld is not sector aligned\n",
361
                        (long long)offset);
362
                return 0;
363
        }
364

    
365
        if (count & 0x1ff) {
366
                printf("count %d is not sector aligned\n",
367
                        count);
368
                return 0;
369
        }
370

    
371
        for (i = optind; i < argc; i++) {
372
                size_t len;
373

    
374
                len = cvtnum(argv[i]);
375
                if (len < 0) {
376
                        printf("non-numeric length argument -- %s\n", argv[i]);
377
                        return 0;
378
                }
379
                count += len;
380
        }
381

    
382
        nr_iov = argc - optind;
383
        qemu_iovec_init(&qiov, nr_iov);
384
        buf = p = qemu_io_alloc(count, 0xab);
385
        for (i = 0; i < nr_iov; i++) {
386
                size_t len;
387

    
388
                len = cvtnum(argv[optind]);
389
                if (len < 0) {
390
                        printf("non-numeric length argument -- %s\n",
391
                                argv[optind]);
392
                        return 0;
393
                }
394

    
395
                qemu_iovec_add(&qiov, p, len);
396
                p += len;
397
                optind++;
398
        }
399

    
400
        gettimeofday(&t1, NULL);
401
        cnt = do_aio_readv(&qiov, offset, &total);
402
        gettimeofday(&t2, NULL);
403

    
404
        if (cnt < 0) {
405
                printf("readv failed: %s\n", strerror(-cnt));
406
                return 0;
407
        }
408

    
409
        if (qflag)
410
                return 0;
411

    
412
        if (vflag)
413
                dump_buffer(buf, offset, qiov.size);
414

    
415
        /* Finally, report back -- -C gives a parsable format */
416
        t2 = tsub(t2, t1);
417
        print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
418

    
419
        qemu_io_free(buf);
420

    
421
        return 0;
422
}
423

    
424
static const cmdinfo_t readv_cmd = {
425
        .name                = "readv",
426
        .cfunc                = readv_f,
427
        .argmin                = 2,
428
        .argmax                = -1,
429
        .args                = "[-Cqv] off len [len..]",
430
        .oneline        = "reads a number of bytes at a specified offset",
431
        .help                = readv_help,
432
};
433

    
434
static const cmdinfo_t write_cmd;
435

    
436
static void
437
write_help(void)
438
{
439
        printf(
440
"\n"
441
" writes a range of bytes from the given offset\n"
442
"\n"
443
" Example:\n"
444
" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n"
445
"\n"
446
" Writes into a segment of the currently open file, using a buffer\n"
447
" filled with a set pattern (0xcdcdcdcd).\n"
448
" -p, -- use bdrv_pwrite to write the file\n"
449
" -P, -- use different pattern to fill file\n"
450
" -C, -- report statistics in a machine parsable format\n"
451
" -q, -- quite mode, do not show I/O statistics\n"
452
"\n");
453
}
454

    
455
static int
456
write_f(int argc, char **argv)
457
{
458
        struct timeval t1, t2;
459
        int Cflag = 0, pflag = 0, qflag = 0;
460
        int c, cnt;
461
        char *buf;
462
        int64_t offset;
463
        int count, total;
464
        int pattern = 0xcd;
465

    
466
        while ((c = getopt(argc, argv, "CpP:q")) != EOF) {
467
                switch (c) {
468
                case 'C':
469
                        Cflag = 1;
470
                        break;
471
                case 'p':
472
                        pflag = 1;
473
                        break;
474
                case 'P':
475
                        pattern = atoi(optarg);
476
                        break;
477
                case 'q':
478
                        qflag = 1;
479
                        break;
480
                default:
481
                        return command_usage(&write_cmd);
482
                }
483
        }
484

    
485
        if (optind != argc - 2)
486
                return command_usage(&write_cmd);
487

    
488
        offset = cvtnum(argv[optind]);
489
        if (offset < 0) {
490
                printf("non-numeric length argument -- %s\n", argv[optind]);
491
                return 0;
492
        }
493

    
494
        optind++;
495
        count = cvtnum(argv[optind]);
496
        if (count < 0) {
497
                printf("non-numeric length argument -- %s\n", argv[optind]);
498
                return 0;
499
        }
500

    
501
        if (!pflag) {
502
                if (offset & 0x1ff) {
503
                        printf("offset %lld is not sector aligned\n",
504
                                (long long)offset);
505
                        return 0;
506
                }
507

    
508
                if (count & 0x1ff) {
509
                        printf("count %d is not sector aligned\n",
510
                                count);
511
                        return 0;
512
                }
513
        }
514

    
515
        buf = qemu_io_alloc(count, pattern);
516

    
517
        gettimeofday(&t1, NULL);
518
        if (pflag)
519
                cnt = do_pwrite(buf, offset, count, &total);
520
        else
521
                cnt = do_write(buf, offset, count, &total);
522
        gettimeofday(&t2, NULL);
523

    
524
        if (cnt < 0) {
525
                printf("write failed: %s\n", strerror(-cnt));
526
                return 0;
527
        }
528

    
529
        if (qflag)
530
                return 0;
531

    
532
        /* Finally, report back -- -C gives a parsable format */
533
        t2 = tsub(t2, t1);
534
        print_report("wrote", &t2, offset, count, total, cnt, Cflag);
535

    
536
        qemu_io_free(buf);
537

    
538
        return 0;
539
}
540

    
541
static const cmdinfo_t write_cmd = {
542
        .name                = "write",
543
        .altname        = "w",
544
        .cfunc                = write_f,
545
        .argmin                = 2,
546
        .argmax                = -1,
547
        .args                = "[-aCpq] [-P pattern ] off len",
548
        .oneline        = "writes a number of bytes at a specified offset",
549
        .help                = write_help,
550
};
551

    
552
static const cmdinfo_t writev_cmd;
553

    
554
static void
555
writev_help(void)
556
{
557
        printf(
558
"\n"
559
" writes a range of bytes from the given offset source from multiple buffers\n"
560
"\n"
561
" Example:\n"
562
" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
563
"\n"
564
" Writes into a segment of the currently open file, using a buffer\n"
565
" filled with a set pattern (0xcdcdcdcd).\n"
566
" -P, -- use different pattern to fill file\n"
567
" -C, -- report statistics in a machine parsable format\n"
568
" -q, -- quite mode, do not show I/O statistics\n"
569
"\n");
570
}
571

    
572
static int
573
writev_f(int argc, char **argv)
574
{
575
        struct timeval t1, t2;
576
        int Cflag = 0, qflag = 0;
577
        int c, cnt;
578
        char *buf, *p;
579
        int64_t offset;
580
        int count = 0, total;
581
        int nr_iov, i;
582
        int pattern = 0xcd;
583
        QEMUIOVector qiov;
584

    
585
        while ((c = getopt(argc, argv, "CqP:")) != EOF) {
586
                switch (c) {
587
                case 'C':
588
                        Cflag = 1;
589
                        break;
590
                case 'q':
591
                        qflag = 1;
592
                        break;
593
                case 'P':
594
                        pattern = atoi(optarg);
595
                        break;
596
                default:
597
                        return command_usage(&writev_cmd);
598
                }
599
        }
600

    
601
        if (optind > argc - 2)
602
                return command_usage(&writev_cmd);
603

    
604
        offset = cvtnum(argv[optind]);
605
        if (offset < 0) {
606
                printf("non-numeric length argument -- %s\n", argv[optind]);
607
                return 0;
608
        }
609
        optind++;
610

    
611
        if (offset & 0x1ff) {
612
                printf("offset %lld is not sector aligned\n",
613
                        (long long)offset);
614
                return 0;
615
        }
616

    
617
        if (count & 0x1ff) {
618
                printf("count %d is not sector aligned\n",
619
                        count);
620
                return 0;
621
        }
622

    
623

    
624
        for (i = optind; i < argc; i++) {
625
                size_t len;
626

    
627
                len = cvtnum(argv[optind]);
628
                if (len < 0) {
629
                        printf("non-numeric length argument -- %s\n", argv[i]);
630
                        return 0;
631
                }
632
                count += len;
633
        }
634

    
635
        nr_iov = argc - optind;
636
        qemu_iovec_init(&qiov, nr_iov);
637
        buf = p = qemu_io_alloc(count, 0xab);
638
        for (i = 0; i < nr_iov; i++) {
639
                size_t len;
640

    
641
                len = cvtnum(argv[optind]);
642
                if (len < 0) {
643
                        printf("non-numeric length argument -- %s\n",
644
                                argv[optind]);
645
                        return 0;
646
                }
647

    
648
                qemu_iovec_add(&qiov, p, len);
649
                p += len;
650
                optind++;
651
        }
652

    
653
        gettimeofday(&t1, NULL);
654
        cnt = do_aio_writev(&qiov, offset, &total);
655
        gettimeofday(&t2, NULL);
656

    
657
        if (cnt < 0) {
658
                printf("writev failed: %s\n", strerror(-cnt));
659
                return 0;
660
        }
661

    
662
        if (qflag)
663
                return 0;
664

    
665
        /* Finally, report back -- -C gives a parsable format */
666
        t2 = tsub(t2, t1);
667
        print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
668

    
669
        qemu_io_free(buf);
670

    
671
        return 0;
672
}
673

    
674
static const cmdinfo_t writev_cmd = {
675
        .name                = "writev",
676
        .cfunc                = writev_f,
677
        .argmin                = 2,
678
        .argmax                = -1,
679
        .args                = "[-Cq] [-P pattern ] off len [len..]",
680
        .oneline        = "writes a number of bytes at a specified offset",
681
        .help                = writev_help,
682
};
683

    
684
static int
685
flush_f(int argc, char **argv)
686
{
687
        bdrv_flush(bs);
688
        return 0;
689
}
690

    
691
static const cmdinfo_t flush_cmd = {
692
        .name                = "flush",
693
        .altname        = "f",
694
        .cfunc                = flush_f,
695
        .oneline        = "flush all in-core file state to disk",
696
};
697

    
698
static int
699
truncate_f(int argc, char **argv)
700
{
701
        int64_t offset;
702
        int ret;
703

    
704
        offset = cvtnum(argv[1]);
705
        if (offset < 0) {
706
                printf("non-numeric truncate argument -- %s\n", argv[1]);
707
                return 0;
708
        }
709

    
710
        ret = bdrv_truncate(bs, offset);
711
        if (ret < 0) {
712
                printf("truncate: %s", strerror(ret));
713
                return 0;
714
        }
715

    
716
        return 0;
717
}
718

    
719
static const cmdinfo_t truncate_cmd = {
720
        .name                = "truncate",
721
        .altname        = "t",
722
        .cfunc                = truncate_f,
723
        .argmin                = 1,
724
        .argmax                = 1,
725
        .args                = "off",
726
        .oneline        = "truncates the current file at the given offset",
727
};
728

    
729
static int
730
length_f(int argc, char **argv)
731
{
732
        int64_t size;
733
        char s1[64];
734

    
735
        size = bdrv_getlength(bs);
736
        if (size < 0) {
737
                printf("getlength: %s", strerror(size));
738
                return 0;
739
        }
740

    
741
        cvtstr(size, s1, sizeof(s1));
742
        printf("%s\n", s1);
743
        return 0;
744
}
745

    
746

    
747
static const cmdinfo_t length_cmd = {
748
        .name                = "length",
749
        .altname        = "l",
750
        .cfunc                = length_f,
751
        .oneline        = "gets the length of the current file",
752
};
753

    
754

    
755
static int
756
info_f(int argc, char **argv)
757
{
758
        BlockDriverInfo bdi;
759
        char s1[64], s2[64];
760
        int ret;
761

    
762
        if (bs->drv && bs->drv->format_name)
763
                printf("format name: %s\n", bs->drv->format_name);
764
        if (bs->drv && bs->drv->protocol_name)
765
                printf("format name: %s\n", bs->drv->protocol_name);
766

    
767
        ret = bdrv_get_info(bs, &bdi);
768
        if (ret)
769
                return 0;
770

    
771
        cvtstr(bdi.cluster_size, s1, sizeof(s1));
772
        cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
773

    
774
        printf("cluster size: %s\n", s1);
775
        printf("vm state offset: %s\n", s2);
776

    
777
        return 0;
778
}
779

    
780

    
781

    
782
static const cmdinfo_t info_cmd = {
783
        .name                = "info",
784
        .altname        = "i",
785
        .cfunc                = info_f,
786
        .oneline        = "prints information about the current file",
787
};
788

    
789
static int
790
alloc_f(int argc, char **argv)
791
{
792
        int64_t offset;
793
        int nb_sectors;
794
        char s1[64];
795
        int num;
796
        int ret;
797

    
798
        offset = cvtnum(argv[1]);
799
        if (offset & 0x1ff) {
800
                printf("offset %lld is not sector aligned\n",
801
                        (long long)offset);
802
                return 0;
803
        }
804

    
805
        if (argc == 3)
806
                nb_sectors = cvtnum(argv[2]);
807
        else
808
                nb_sectors = 1;
809

    
810
        ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
811
        if (ret) {
812
                printf("is_allocated: %s", strerror(ret));
813
                return 0;
814
        }
815

    
816
        cvtstr(offset, s1, sizeof(s1));
817

    
818
        if (nb_sectors == 1)
819
                printf("sector allocated at offset %s\n", s1);
820
        else
821
                printf("%d/%d sectors allocated at offset %s\n",
822
                        num, nb_sectors, s1);
823
        return 0;
824
}
825

    
826
static const cmdinfo_t alloc_cmd = {
827
        .name                = "alloc",
828
        .altname        = "a",
829
        .argmin                = 1,
830
        .argmax                = 2,
831
        .cfunc                = alloc_f,
832
        .args                = "off [sectors]",
833
        .oneline        = "checks if a sector is present in the file",
834
};
835

    
836
static int
837
close_f(int argc, char **argv)
838
{
839
        bdrv_close(bs);
840
        bs = NULL;
841
        return 0;
842
}
843

    
844
static const cmdinfo_t close_cmd = {
845
        .name                = "close",
846
        .altname        = "c",
847
        .cfunc                = close_f,
848
        .oneline        = "close the current open file",
849
};
850

    
851
static int openfile(char *name, int flags)
852
{
853
        if (bs) {
854
                fprintf(stderr, "file open already, try 'help close'\n");
855
                return 1;
856
        }
857

    
858
        bs = bdrv_new("hda");
859
        if (!bs)
860
                return 1;
861

    
862
        if (bdrv_open(bs, name, flags) == -1) {
863
                fprintf(stderr, "%s: can't open device %s\n", progname, name);
864
                bs = NULL;
865
                return 1;
866
        }
867

    
868
        return 0;
869
}
870

    
871
static void
872
open_help(void)
873
{
874
        printf(
875
"\n"
876
" opens a new file in the requested mode\n"
877
"\n"
878
" Example:\n"
879
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
880
"\n"
881
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
882
" -C, -- create new file if it doesn't exist\n"
883
" -r, -- open file read-only\n"
884
" -s, -- use snapshot file\n"
885
" -n, -- disable host cache\n"
886
"\n");
887
}
888

    
889
static const cmdinfo_t open_cmd;
890

    
891
static int
892
open_f(int argc, char **argv)
893
{
894
        int flags = 0;
895
        int readonly = 0;
896
        int c;
897

    
898
        while ((c = getopt(argc, argv, "snCr")) != EOF) {
899
                switch (c) {
900
                case 's':
901
                        flags |= BDRV_O_SNAPSHOT;
902
                        break;
903
                case 'n':
904
                        flags |= BDRV_O_NOCACHE;
905
                        break;
906
                case 'C':
907
                        flags |= BDRV_O_CREAT;
908
                        break;
909
                case 'r':
910
                        readonly = 1;
911
                        break;
912
                default:
913
                        return command_usage(&open_cmd);
914
                }
915
        }
916

    
917
        if (readonly)
918
                flags |= BDRV_O_RDONLY;
919
        else
920
                flags |= BDRV_O_RDWR;
921

    
922
        if (optind != argc - 1)
923
                return command_usage(&open_cmd);
924

    
925
        return openfile(argv[optind], flags);
926
}
927

    
928
static const cmdinfo_t open_cmd = {
929
        .name                = "open",
930
        .altname        = "o",
931
        .cfunc                = open_f,
932
        .argmin                = 1,
933
        .argmax                = -1,
934
        .flags                = CMD_NOFILE_OK,
935
        .args                = "[-Crsn] [path]",
936
        .oneline        = "open the file specified by path",
937
        .help                = open_help,
938
};
939

    
940
static int
941
init_args_command(
942
        int     index)
943
{
944
        /* only one device allowed so far */
945
        if (index >= 1)
946
                return 0;
947
        return ++index;
948
}
949

    
950
static int
951
init_check_command(
952
        const cmdinfo_t *ct)
953
{
954
        if (ct->flags & CMD_FLAG_GLOBAL)
955
                return 1;
956
        if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
957
                fprintf(stderr, "no file open, try 'help open'\n");
958
                return 0;
959
        }
960
        return 1;
961
}
962

    
963
static void usage(const char *name)
964
{
965
        printf(
966
"Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
967
"QEMU Disk excerciser\n"
968
"\n"
969
"  -C, --create         create new file if it doesn't exist\n"
970
"  -c, --cmd            command to execute\n"
971
"  -r, --read-only      export read-only\n"
972
"  -s, --snapshot       use snapshot file\n"
973
"  -n, --nocache        disable host cache\n"
974
"  -m, --misalign       misalign allocations for O_DIRECT\n"
975
"  -h, --help           display this help and exit\n"
976
"  -V, --version        output version information and exit\n"
977
"\n",
978
        name);
979
}
980

    
981

    
982
int main(int argc, char **argv)
983
{
984
        int readonly = 0;
985
        const char *sopt = "hVc:Crsnm";
986
        struct option lopt[] = {
987
                { "help", 0, 0, 'h' },
988
                { "version", 0, 0, 'V' },
989
                { "offset", 1, 0, 'o' },
990
                { "cmd", 1, 0, 'c' },
991
                { "create", 0, 0, 'C' },
992
                { "read-only", 0, 0, 'r' },
993
                { "snapshot", 0, 0, 's' },
994
                { "nocache", 0, 0, 'n' },
995
                { "misalign", 0, 0, 'm' },
996
                { NULL, 0, 0, 0 }
997
        };
998
        int c;
999
        int opt_index = 0;
1000
        int flags = 0;
1001

    
1002
        progname = basename(argv[0]);
1003

    
1004
        while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
1005
                switch (c) {
1006
                case 's':
1007
                        flags |= BDRV_O_SNAPSHOT;
1008
                        break;
1009
                case 'n':
1010
                        flags |= BDRV_O_NOCACHE;
1011
                        break;
1012
                case 'c':
1013
                        add_user_command(optarg);
1014
                        break;
1015
                case 'C':
1016
                        flags |= BDRV_O_CREAT;
1017
                        break;
1018
                case 'r':
1019
                        readonly = 1;
1020
                        break;
1021
                case 'm':
1022
                        misalign = 1;
1023
                        break;
1024
                case 'V':
1025
                        printf("%s version %s\n", progname, VERSION);
1026
                        exit(0);
1027
                case 'h':
1028
                        usage(progname);
1029
                        exit(0);
1030
                default:
1031
                        usage(progname);
1032
                        exit(1);
1033
                }
1034
        }
1035

    
1036
        if ((argc - optind) > 1) {
1037
                usage(progname);
1038
                exit(1);
1039
        }
1040

    
1041
        bdrv_init();
1042

    
1043
        /* initialize commands */
1044
        quit_init();
1045
        help_init();
1046
        add_command(&open_cmd);
1047
        add_command(&close_cmd);
1048
        add_command(&read_cmd);
1049
        add_command(&readv_cmd);
1050
        add_command(&write_cmd);
1051
        add_command(&writev_cmd);
1052
        add_command(&flush_cmd);
1053
        add_command(&truncate_cmd);
1054
        add_command(&length_cmd);
1055
        add_command(&info_cmd);
1056
        add_command(&alloc_cmd);
1057

    
1058
        add_args_command(init_args_command);
1059
        add_check_command(init_check_command);
1060

    
1061
        /* open the device */
1062
        if (readonly)
1063
                flags |= BDRV_O_RDONLY;
1064
        else
1065
                flags |= BDRV_O_RDWR;
1066

    
1067
        if ((argc - optind) == 1)
1068
                openfile(argv[optind], flags);
1069
        command_loop();
1070

    
1071
        if (bs)
1072
                bdrv_close(bs);
1073
        return 0;
1074
}