Annotation of qemu/qemu-io.c, revision 1.1

1.1     ! root        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/time.h>
        !            11: #include <sys/types.h>
        !            12: #include <stdarg.h>
        !            13: #include <stdio.h>
        !            14: #include <getopt.h>
        !            15: #include <libgen.h>
        !            16: 
        !            17: #include "qemu-common.h"
        !            18: #include "block_int.h"
        !            19: #include "cmd.h"
        !            20: 
        !            21: #define VERSION        "0.0.1"
        !            22: 
        !            23: #define CMD_NOFILE_OK  0x01
        !            24: 
        !            25: char *progname;
        !            26: static BlockDriverState *bs;
        !            27: 
        !            28: static int misalign;
        !            29: 
        !            30: /*
        !            31:  * Memory allocation helpers.
        !            32:  *
        !            33:  * Make sure memory is aligned by default, or purposefully misaligned if
        !            34:  * that is specified on the command line.
        !            35:  */
        !            36: 
        !            37: #define MISALIGN_OFFSET                16
        !            38: static void *qemu_io_alloc(size_t len, int pattern)
        !            39: {
        !            40:        void *buf;
        !            41: 
        !            42:        if (misalign)
        !            43:                len += MISALIGN_OFFSET;
        !            44:        buf = qemu_memalign(512, len);
        !            45:        memset(buf, pattern, len);
        !            46:        if (misalign)
        !            47:                buf += MISALIGN_OFFSET;
        !            48:        return buf;
        !            49: }
        !            50: 
        !            51: static void qemu_io_free(void *p)
        !            52: {
        !            53:        if (misalign)
        !            54:                p -= MISALIGN_OFFSET;
        !            55:        qemu_vfree(p);
        !            56: }
        !            57: 
        !            58: static void
        !            59: dump_buffer(const void *buffer, int64_t offset, int len)
        !            60: {
        !            61:        int i, j;
        !            62:        const uint8_t *p;
        !            63: 
        !            64:        for (i = 0, p = buffer; i < len; i += 16) {
        !            65:                const uint8_t *s = p;
        !            66: 
        !            67:                printf("%08llx:  ", (unsigned long long)offset + i);
        !            68:                for (j = 0; j < 16 && i + j < len; j++, p++)
        !            69:                        printf("%02x ", *p);
        !            70:                printf(" ");
        !            71:                for (j = 0; j < 16 && i + j < len; j++, s++) {
        !            72:                        if (isalnum(*s))
        !            73:                                printf("%c", *s);
        !            74:                        else
        !            75:                                printf(".");
        !            76:                }
        !            77:                printf("\n");
        !            78:        }
        !            79: }
        !            80: 
        !            81: static void
        !            82: print_report(const char *op, struct timeval *t, int64_t offset,
        !            83:                int count, int total, int cnt, int Cflag)
        !            84: {
        !            85:        char s1[64], s2[64], ts[64];
        !            86: 
        !            87:        timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0);
        !            88:        if (!Cflag) {
        !            89:                cvtstr((double)total, s1, sizeof(s1));
        !            90:                cvtstr(tdiv((double)total, *t), s2, sizeof(s2));
        !            91:                printf("%s %d/%d bytes at offset %lld\n",
        !            92:                        op, total, count, (long long)offset);
        !            93:                printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n",
        !            94:                        s1, cnt, ts, s2, tdiv((double)cnt, *t));
        !            95:        } else {/* bytes,ops,time,bytes/sec,ops/sec */
        !            96:                printf("%d,%d,%s,%.3f,%.3f\n",
        !            97:                        total, cnt, ts,
        !            98:                        tdiv((double)total, *t),
        !            99:                        tdiv((double)cnt, *t));
        !           100:        }
        !           101: }
        !           102: 
        !           103: /*
        !           104:  * Parse multiple length statements for vectored I/O, and construct an I/O
        !           105:  * vector matching it.
        !           106:  */
        !           107: static void *
        !           108: create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
        !           109: {
        !           110:        size_t *sizes = calloc(nr_iov, sizeof(size_t));
        !           111:        size_t count = 0;
        !           112:        void *buf, *p;
        !           113:        int i;
        !           114: 
        !           115:        for (i = 0; i < nr_iov; i++) {
        !           116:                char *arg = argv[i];
        !           117:                long long len;
        !           118: 
        !           119:                len = cvtnum(arg);
        !           120:                if (len < 0) {
        !           121:                        printf("non-numeric length argument -- %s\n", arg);
        !           122:                        return NULL;
        !           123:                }
        !           124: 
        !           125:                /* should be SIZE_T_MAX, but that doesn't exist */
        !           126:                if (len > UINT_MAX) {
        !           127:                        printf("too large length argument -- %s\n", arg);
        !           128:                        return NULL;
        !           129:                }
        !           130: 
        !           131:                if (len & 0x1ff) {
        !           132:                        printf("length argument %lld is not sector aligned\n",
        !           133:                                len);
        !           134:                        return NULL;
        !           135:                }
        !           136: 
        !           137:                sizes[i] = len;
        !           138:                count += len;
        !           139:        }
        !           140: 
        !           141:        qemu_iovec_init(qiov, nr_iov);
        !           142: 
        !           143:        buf = p = qemu_io_alloc(count, pattern);
        !           144: 
        !           145:        for (i = 0; i < nr_iov; i++) {
        !           146:                qemu_iovec_add(qiov, p, sizes[i]);
        !           147:                p += sizes[i];
        !           148:        }
        !           149: 
        !           150:        free(sizes);
        !           151:        return buf;
        !           152: }
        !           153: 
        !           154: static int do_read(char *buf, int64_t offset, int count, int *total)
        !           155: {
        !           156:        int ret;
        !           157: 
        !           158:        ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
        !           159:        if (ret < 0)
        !           160:                return ret;
        !           161:        *total = count;
        !           162:        return 1;
        !           163: }
        !           164: 
        !           165: static int do_write(char *buf, int64_t offset, int count, int *total)
        !           166: {
        !           167:        int ret;
        !           168: 
        !           169:        ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
        !           170:        if (ret < 0)
        !           171:                return ret;
        !           172:        *total = count;
        !           173:        return 1;
        !           174: }
        !           175: 
        !           176: static int do_pread(char *buf, int64_t offset, int count, int *total)
        !           177: {
        !           178:        *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
        !           179:        if (*total < 0)
        !           180:                return *total;
        !           181:        return 1;
        !           182: }
        !           183: 
        !           184: static int do_pwrite(char *buf, int64_t offset, int count, int *total)
        !           185: {
        !           186:        *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
        !           187:        if (*total < 0)
        !           188:                return *total;
        !           189:        return 1;
        !           190: }
        !           191: 
        !           192: static int do_load_vmstate(char *buf, int64_t offset, int count, int *total)
        !           193: {
        !           194:        *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
        !           195:        if (*total < 0)
        !           196:                return *total;
        !           197:        return 1;
        !           198: }
        !           199: 
        !           200: static int do_save_vmstate(char *buf, int64_t offset, int count, int *total)
        !           201: {
        !           202:        *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
        !           203:        if (*total < 0)
        !           204:                return *total;
        !           205:        return 1;
        !           206: }
        !           207: 
        !           208: #define NOT_DONE 0x7fffffff
        !           209: static void aio_rw_done(void *opaque, int ret)
        !           210: {
        !           211:        *(int *)opaque = ret;
        !           212: }
        !           213: 
        !           214: static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total)
        !           215: {
        !           216:        BlockDriverAIOCB *acb;
        !           217:        int async_ret = NOT_DONE;
        !           218: 
        !           219:        acb = bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
        !           220:                             aio_rw_done, &async_ret);
        !           221:        if (!acb)
        !           222:                return -EIO;
        !           223: 
        !           224:        while (async_ret == NOT_DONE)
        !           225:                qemu_aio_wait();
        !           226: 
        !           227:        *total = qiov->size;
        !           228:        return async_ret < 0 ? async_ret : 1;
        !           229: }
        !           230: 
        !           231: static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total)
        !           232: {
        !           233:        BlockDriverAIOCB *acb;
        !           234:        int async_ret = NOT_DONE;
        !           235: 
        !           236:        acb = bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
        !           237:                              aio_rw_done, &async_ret);
        !           238:        if (!acb)
        !           239:                return -EIO;
        !           240: 
        !           241:        while (async_ret == NOT_DONE)
        !           242:                qemu_aio_wait();
        !           243: 
        !           244:        *total = qiov->size;
        !           245:        return async_ret < 0 ? async_ret : 1;
        !           246: }
        !           247: 
        !           248: 
        !           249: static const cmdinfo_t read_cmd;
        !           250: 
        !           251: static void
        !           252: read_help(void)
        !           253: {
        !           254:        printf(
        !           255: "\n"
        !           256: " reads a range of bytes from the given offset\n"
        !           257: "\n"
        !           258: " Example:\n"
        !           259: " 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n"
        !           260: "\n"
        !           261: " Reads a segment of the currently open file, optionally dumping it to the\n"
        !           262: " standard output stream (with -v option) for subsequent inspection.\n"
        !           263: " -b, -- read from the VM state rather than the virtual disk\n"
        !           264: " -C, -- report statistics in a machine parsable format\n"
        !           265: " -l, -- length for pattern verification (only with -P)\n"
        !           266: " -p, -- use bdrv_pread to read the file\n"
        !           267: " -P, -- use a pattern to verify read data\n"
        !           268: " -q, -- quite mode, do not show I/O statistics\n"
        !           269: " -s, -- start offset for pattern verification (only with -P)\n"
        !           270: " -v, -- dump buffer to standard output\n"
        !           271: "\n");
        !           272: }
        !           273: 
        !           274: static int
        !           275: read_f(int argc, char **argv)
        !           276: {
        !           277:        struct timeval t1, t2;
        !           278:        int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
        !           279:        int Pflag = 0, sflag = 0, lflag = 0, bflag = 0;
        !           280:        int c, cnt;
        !           281:        char *buf;
        !           282:        int64_t offset;
        !           283:        int count;
        !           284:         /* Some compilers get confused and warn if this is not initialized.  */
        !           285:         int total = 0;
        !           286:        int pattern = 0, pattern_offset = 0, pattern_count = 0;
        !           287: 
        !           288:        while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) {
        !           289:                switch (c) {
        !           290:                case 'b':
        !           291:                        bflag = 1;
        !           292:                        break;
        !           293:                case 'C':
        !           294:                        Cflag = 1;
        !           295:                        break;
        !           296:                case 'l':
        !           297:                        lflag = 1;
        !           298:                        pattern_count = cvtnum(optarg);
        !           299:                        if (pattern_count < 0) {
        !           300:                                printf("non-numeric length argument -- %s\n", optarg);
        !           301:                                return 0;
        !           302:                        }
        !           303:                        break;
        !           304:                case 'p':
        !           305:                        pflag = 1;
        !           306:                        break;
        !           307:                case 'P':
        !           308:                        Pflag = 1;
        !           309:                        pattern = atoi(optarg);
        !           310:                        break;
        !           311:                case 'q':
        !           312:                        qflag = 1;
        !           313:                        break;
        !           314:                case 's':
        !           315:                        sflag = 1;
        !           316:                        pattern_offset = cvtnum(optarg);
        !           317:                        if (pattern_offset < 0) {
        !           318:                                printf("non-numeric length argument -- %s\n", optarg);
        !           319:                                return 0;
        !           320:                        }
        !           321:                        break;
        !           322:                case 'v':
        !           323:                        vflag = 1;
        !           324:                        break;
        !           325:                default:
        !           326:                        return command_usage(&read_cmd);
        !           327:                }
        !           328:        }
        !           329: 
        !           330:        if (optind != argc - 2)
        !           331:                return command_usage(&read_cmd);
        !           332: 
        !           333:        if (bflag && pflag) {
        !           334:                printf("-b and -p cannot be specified at the same time\n");
        !           335:                return 0;
        !           336:        }
        !           337: 
        !           338:        offset = cvtnum(argv[optind]);
        !           339:        if (offset < 0) {
        !           340:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           341:                return 0;
        !           342:        }
        !           343: 
        !           344:        optind++;
        !           345:        count = cvtnum(argv[optind]);
        !           346:        if (count < 0) {
        !           347:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           348:                return 0;
        !           349:        }
        !           350: 
        !           351:     if (!Pflag && (lflag || sflag)) {
        !           352:         return command_usage(&read_cmd);
        !           353:     }
        !           354: 
        !           355:     if (!lflag) {
        !           356:         pattern_count = count - pattern_offset;
        !           357:     }
        !           358: 
        !           359:     if ((pattern_count < 0) || (pattern_count + pattern_offset > count))  {
        !           360:         printf("pattern verfication range exceeds end of read data\n");
        !           361:         return 0;
        !           362:     }
        !           363: 
        !           364:        if (!pflag)
        !           365:                if (offset & 0x1ff) {
        !           366:                        printf("offset %lld is not sector aligned\n",
        !           367:                                (long long)offset);
        !           368:                        return 0;
        !           369: 
        !           370:                if (count & 0x1ff) {
        !           371:                        printf("count %d is not sector aligned\n",
        !           372:                                count);
        !           373:                        return 0;
        !           374:                }
        !           375:        }
        !           376: 
        !           377:        buf = qemu_io_alloc(count, 0xab);
        !           378: 
        !           379:        gettimeofday(&t1, NULL);
        !           380:        if (pflag)
        !           381:                cnt = do_pread(buf, offset, count, &total);
        !           382:        else if (bflag)
        !           383:                cnt = do_load_vmstate(buf, offset, count, &total);
        !           384:        else
        !           385:                cnt = do_read(buf, offset, count, &total);
        !           386:        gettimeofday(&t2, NULL);
        !           387: 
        !           388:        if (cnt < 0) {
        !           389:                printf("read failed: %s\n", strerror(-cnt));
        !           390:                goto out;
        !           391:        }
        !           392: 
        !           393:        if (Pflag) {
        !           394:                void* cmp_buf = malloc(pattern_count);
        !           395:                memset(cmp_buf, pattern, pattern_count);
        !           396:                if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
        !           397:                        printf("Pattern verification failed at offset %lld, "
        !           398:                                "%d bytes\n",
        !           399:                                (long long) offset + pattern_offset, pattern_count);
        !           400:                }
        !           401:                free(cmp_buf);
        !           402:        }
        !           403: 
        !           404:        if (qflag)
        !           405:                goto out;
        !           406: 
        !           407:         if (vflag)
        !           408:                dump_buffer(buf, offset, count);
        !           409: 
        !           410:        /* Finally, report back -- -C gives a parsable format */
        !           411:        t2 = tsub(t2, t1);
        !           412:        print_report("read", &t2, offset, count, total, cnt, Cflag);
        !           413: 
        !           414: out:
        !           415:        qemu_io_free(buf);
        !           416: 
        !           417:        return 0;
        !           418: }
        !           419: 
        !           420: static const cmdinfo_t read_cmd = {
        !           421:        .name           = "read",
        !           422:        .altname        = "r",
        !           423:        .cfunc          = read_f,
        !           424:        .argmin         = 2,
        !           425:        .argmax         = -1,
        !           426:        .args           = "[-abCpqv] [-P pattern [-s off] [-l len]] off len",
        !           427:        .oneline        = "reads a number of bytes at a specified offset",
        !           428:        .help           = read_help,
        !           429: };
        !           430: 
        !           431: static const cmdinfo_t readv_cmd;
        !           432: 
        !           433: static void
        !           434: readv_help(void)
        !           435: {
        !           436:        printf(
        !           437: "\n"
        !           438: " reads a range of bytes from the given offset into multiple buffers\n"
        !           439: "\n"
        !           440: " Example:\n"
        !           441: " 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
        !           442: "\n"
        !           443: " Reads a segment of the currently open file, optionally dumping it to the\n"
        !           444: " standard output stream (with -v option) for subsequent inspection.\n"
        !           445: " Uses multiple iovec buffers if more than one byte range is specified.\n"
        !           446: " -C, -- report statistics in a machine parsable format\n"
        !           447: " -P, -- use a pattern to verify read data\n"
        !           448: " -v, -- dump buffer to standard output\n"
        !           449: " -q, -- quite mode, do not show I/O statistics\n"
        !           450: "\n");
        !           451: }
        !           452: 
        !           453: static int
        !           454: readv_f(int argc, char **argv)
        !           455: {
        !           456:        struct timeval t1, t2;
        !           457:        int Cflag = 0, qflag = 0, vflag = 0;
        !           458:        int c, cnt;
        !           459:        char *buf;
        !           460:        int64_t offset;
        !           461:        int total;
        !           462:        int nr_iov;
        !           463:        QEMUIOVector qiov;
        !           464:        int pattern = 0;
        !           465:        int Pflag = 0;
        !           466: 
        !           467:        while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
        !           468:                switch (c) {
        !           469:                case 'C':
        !           470:                        Cflag = 1;
        !           471:                        break;
        !           472:                case 'P':
        !           473:                        Pflag = 1;
        !           474:                        pattern = atoi(optarg);
        !           475:                        break;
        !           476:                case 'q':
        !           477:                        qflag = 1;
        !           478:                        break;
        !           479:                case 'v':
        !           480:                        vflag = 1;
        !           481:                        break;
        !           482:                default:
        !           483:                        return command_usage(&readv_cmd);
        !           484:                }
        !           485:        }
        !           486: 
        !           487:        if (optind > argc - 2)
        !           488:                return command_usage(&readv_cmd);
        !           489: 
        !           490: 
        !           491:        offset = cvtnum(argv[optind]);
        !           492:        if (offset < 0) {
        !           493:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           494:                return 0;
        !           495:        }
        !           496:        optind++;
        !           497: 
        !           498:        if (offset & 0x1ff) {
        !           499:                printf("offset %lld is not sector aligned\n",
        !           500:                        (long long)offset);
        !           501:                return 0;
        !           502:        }
        !           503: 
        !           504:        nr_iov = argc - optind;
        !           505:        buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
        !           506: 
        !           507:        gettimeofday(&t1, NULL);
        !           508:        cnt = do_aio_readv(&qiov, offset, &total);
        !           509:        gettimeofday(&t2, NULL);
        !           510: 
        !           511:        if (cnt < 0) {
        !           512:                printf("readv failed: %s\n", strerror(-cnt));
        !           513:                goto out;
        !           514:        }
        !           515: 
        !           516:        if (Pflag) {
        !           517:                void* cmp_buf = malloc(qiov.size);
        !           518:                memset(cmp_buf, pattern, qiov.size);
        !           519:                if (memcmp(buf, cmp_buf, qiov.size)) {
        !           520:                        printf("Pattern verification failed at offset %lld, "
        !           521:                                "%zd bytes\n",
        !           522:                                (long long) offset, qiov.size);
        !           523:                }
        !           524:                free(cmp_buf);
        !           525:        }
        !           526: 
        !           527:        if (qflag)
        !           528:                goto out;
        !           529: 
        !           530:         if (vflag)
        !           531:                dump_buffer(buf, offset, qiov.size);
        !           532: 
        !           533:        /* Finally, report back -- -C gives a parsable format */
        !           534:        t2 = tsub(t2, t1);
        !           535:        print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
        !           536: 
        !           537: out:
        !           538:        qemu_io_free(buf);
        !           539:        return 0;
        !           540: }
        !           541: 
        !           542: static const cmdinfo_t readv_cmd = {
        !           543:        .name           = "readv",
        !           544:        .cfunc          = readv_f,
        !           545:        .argmin         = 2,
        !           546:        .argmax         = -1,
        !           547:        .args           = "[-Cqv] [-P pattern ] off len [len..]",
        !           548:        .oneline        = "reads a number of bytes at a specified offset",
        !           549:        .help           = readv_help,
        !           550: };
        !           551: 
        !           552: static const cmdinfo_t write_cmd;
        !           553: 
        !           554: static void
        !           555: write_help(void)
        !           556: {
        !           557:        printf(
        !           558: "\n"
        !           559: " writes a range of bytes from the given offset\n"
        !           560: "\n"
        !           561: " Example:\n"
        !           562: " 'write 512 1k' - writes 1 kilobyte 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: " -b, -- write to the VM state rather than the virtual disk\n"
        !           567: " -p, -- use bdrv_pwrite to write the file\n"
        !           568: " -P, -- use different pattern to fill file\n"
        !           569: " -C, -- report statistics in a machine parsable format\n"
        !           570: " -q, -- quite mode, do not show I/O statistics\n"
        !           571: "\n");
        !           572: }
        !           573: 
        !           574: static int
        !           575: write_f(int argc, char **argv)
        !           576: {
        !           577:        struct timeval t1, t2;
        !           578:        int Cflag = 0, pflag = 0, qflag = 0, bflag = 0;
        !           579:        int c, cnt;
        !           580:        char *buf;
        !           581:        int64_t offset;
        !           582:        int count;
        !           583:         /* Some compilers get confused and warn if this is not initialized.  */
        !           584:         int total = 0;
        !           585:        int pattern = 0xcd;
        !           586: 
        !           587:        while ((c = getopt(argc, argv, "bCpP:q")) != EOF) {
        !           588:                switch (c) {
        !           589:                case 'b':
        !           590:                        bflag = 1;
        !           591:                        break;
        !           592:                case 'C':
        !           593:                        Cflag = 1;
        !           594:                        break;
        !           595:                case 'p':
        !           596:                        pflag = 1;
        !           597:                        break;
        !           598:                case 'P':
        !           599:                        pattern = atoi(optarg);
        !           600:                        break;
        !           601:                case 'q':
        !           602:                        qflag = 1;
        !           603:                        break;
        !           604:                default:
        !           605:                        return command_usage(&write_cmd);
        !           606:                }
        !           607:        }
        !           608: 
        !           609:        if (optind != argc - 2)
        !           610:                return command_usage(&write_cmd);
        !           611: 
        !           612:        if (bflag && pflag) {
        !           613:                printf("-b and -p cannot be specified at the same time\n");
        !           614:                return 0;
        !           615:        }
        !           616: 
        !           617:        offset = cvtnum(argv[optind]);
        !           618:        if (offset < 0) {
        !           619:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           620:                return 0;
        !           621:        }
        !           622: 
        !           623:        optind++;
        !           624:        count = cvtnum(argv[optind]);
        !           625:        if (count < 0) {
        !           626:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           627:                return 0;
        !           628:        }
        !           629: 
        !           630:        if (!pflag) {
        !           631:                if (offset & 0x1ff) {
        !           632:                        printf("offset %lld is not sector aligned\n",
        !           633:                                (long long)offset);
        !           634:                        return 0;
        !           635:                }
        !           636: 
        !           637:                if (count & 0x1ff) {
        !           638:                        printf("count %d is not sector aligned\n",
        !           639:                                count);
        !           640:                        return 0;
        !           641:                }
        !           642:        }
        !           643: 
        !           644:        buf = qemu_io_alloc(count, pattern);
        !           645: 
        !           646:        gettimeofday(&t1, NULL);
        !           647:        if (pflag)
        !           648:                cnt = do_pwrite(buf, offset, count, &total);
        !           649:        else if (bflag)
        !           650:                cnt = do_save_vmstate(buf, offset, count, &total);
        !           651:        else
        !           652:                cnt = do_write(buf, offset, count, &total);
        !           653:        gettimeofday(&t2, NULL);
        !           654: 
        !           655:        if (cnt < 0) {
        !           656:                printf("write failed: %s\n", strerror(-cnt));
        !           657:                goto out;
        !           658:        }
        !           659: 
        !           660:        if (qflag)
        !           661:                goto out;
        !           662: 
        !           663:        /* Finally, report back -- -C gives a parsable format */
        !           664:        t2 = tsub(t2, t1);
        !           665:        print_report("wrote", &t2, offset, count, total, cnt, Cflag);
        !           666: 
        !           667: out:
        !           668:        qemu_io_free(buf);
        !           669: 
        !           670:        return 0;
        !           671: }
        !           672: 
        !           673: static const cmdinfo_t write_cmd = {
        !           674:        .name           = "write",
        !           675:        .altname        = "w",
        !           676:        .cfunc          = write_f,
        !           677:        .argmin         = 2,
        !           678:        .argmax         = -1,
        !           679:        .args           = "[-abCpq] [-P pattern ] off len",
        !           680:        .oneline        = "writes a number of bytes at a specified offset",
        !           681:        .help           = write_help,
        !           682: };
        !           683: 
        !           684: static const cmdinfo_t writev_cmd;
        !           685: 
        !           686: static void
        !           687: writev_help(void)
        !           688: {
        !           689:        printf(
        !           690: "\n"
        !           691: " writes a range of bytes from the given offset source from multiple buffers\n"
        !           692: "\n"
        !           693: " Example:\n"
        !           694: " 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
        !           695: "\n"
        !           696: " Writes into a segment of the currently open file, using a buffer\n"
        !           697: " filled with a set pattern (0xcdcdcdcd).\n"
        !           698: " -P, -- use different pattern to fill file\n"
        !           699: " -C, -- report statistics in a machine parsable format\n"
        !           700: " -q, -- quite mode, do not show I/O statistics\n"
        !           701: "\n");
        !           702: }
        !           703: 
        !           704: static int
        !           705: writev_f(int argc, char **argv)
        !           706: {
        !           707:        struct timeval t1, t2;
        !           708:        int Cflag = 0, qflag = 0;
        !           709:        int c, cnt;
        !           710:        char *buf;
        !           711:        int64_t offset;
        !           712:        int total;
        !           713:        int nr_iov;
        !           714:        int pattern = 0xcd;
        !           715:        QEMUIOVector qiov;
        !           716: 
        !           717:        while ((c = getopt(argc, argv, "CqP:")) != EOF) {
        !           718:                switch (c) {
        !           719:                case 'C':
        !           720:                        Cflag = 1;
        !           721:                        break;
        !           722:                case 'q':
        !           723:                        qflag = 1;
        !           724:                        break;
        !           725:                case 'P':
        !           726:                        pattern = atoi(optarg);
        !           727:                        break;
        !           728:                default:
        !           729:                        return command_usage(&writev_cmd);
        !           730:                }
        !           731:        }
        !           732: 
        !           733:        if (optind > argc - 2)
        !           734:                return command_usage(&writev_cmd);
        !           735: 
        !           736:        offset = cvtnum(argv[optind]);
        !           737:        if (offset < 0) {
        !           738:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           739:                return 0;
        !           740:        }
        !           741:        optind++;
        !           742: 
        !           743:        if (offset & 0x1ff) {
        !           744:                printf("offset %lld is not sector aligned\n",
        !           745:                        (long long)offset);
        !           746:                return 0;
        !           747:        }
        !           748: 
        !           749:        nr_iov = argc - optind;
        !           750:        buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
        !           751: 
        !           752:        gettimeofday(&t1, NULL);
        !           753:        cnt = do_aio_writev(&qiov, offset, &total);
        !           754:        gettimeofday(&t2, NULL);
        !           755: 
        !           756:        if (cnt < 0) {
        !           757:                printf("writev failed: %s\n", strerror(-cnt));
        !           758:                goto out;
        !           759:        }
        !           760: 
        !           761:        if (qflag)
        !           762:                goto out;
        !           763: 
        !           764:        /* Finally, report back -- -C gives a parsable format */
        !           765:        t2 = tsub(t2, t1);
        !           766:        print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
        !           767: out:
        !           768:        qemu_io_free(buf);
        !           769:        return 0;
        !           770: }
        !           771: 
        !           772: static const cmdinfo_t writev_cmd = {
        !           773:        .name           = "writev",
        !           774:        .cfunc          = writev_f,
        !           775:        .argmin         = 2,
        !           776:        .argmax         = -1,
        !           777:        .args           = "[-Cq] [-P pattern ] off len [len..]",
        !           778:        .oneline        = "writes a number of bytes at a specified offset",
        !           779:        .help           = writev_help,
        !           780: };
        !           781: 
        !           782: struct aio_ctx {
        !           783:        QEMUIOVector qiov;
        !           784:        int64_t offset;
        !           785:        char *buf;
        !           786:        int qflag;
        !           787:        int vflag;
        !           788:        int Cflag;
        !           789:        int Pflag;
        !           790:        int pattern;
        !           791:        struct timeval t1;
        !           792: };
        !           793: 
        !           794: static void
        !           795: aio_write_done(void *opaque, int ret)
        !           796: {
        !           797:        struct aio_ctx *ctx = opaque;
        !           798:        struct timeval t2;
        !           799: 
        !           800:        gettimeofday(&t2, NULL);
        !           801: 
        !           802: 
        !           803:        if (ret < 0) {
        !           804:                printf("aio_write failed: %s\n", strerror(-ret));
        !           805:                goto out;
        !           806:        }
        !           807: 
        !           808:        if (ctx->qflag) {
        !           809:                goto out;
        !           810:        }
        !           811: 
        !           812:        /* Finally, report back -- -C gives a parsable format */
        !           813:        t2 = tsub(t2, ctx->t1);
        !           814:        print_report("wrote", &t2, ctx->offset, ctx->qiov.size,
        !           815:                     ctx->qiov.size, 1, ctx->Cflag);
        !           816: out:
        !           817:        qemu_io_free(ctx->buf);
        !           818:        free(ctx);
        !           819: }
        !           820: 
        !           821: static const cmdinfo_t aio_read_cmd;
        !           822: 
        !           823: static void
        !           824: aio_read_done(void *opaque, int ret)
        !           825: {
        !           826:        struct aio_ctx *ctx = opaque;
        !           827:        struct timeval t2;
        !           828: 
        !           829:        gettimeofday(&t2, NULL);
        !           830: 
        !           831:        if (ret < 0) {
        !           832:                printf("readv failed: %s\n", strerror(-ret));
        !           833:                goto out;
        !           834:        }
        !           835: 
        !           836:        if (ctx->Pflag) {
        !           837:                void *cmp_buf = malloc(ctx->qiov.size);
        !           838: 
        !           839:                memset(cmp_buf, ctx->pattern, ctx->qiov.size);
        !           840:                if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
        !           841:                        printf("Pattern verification failed at offset %lld, "
        !           842:                                "%zd bytes\n",
        !           843:                                (long long) ctx->offset, ctx->qiov.size);
        !           844:                }
        !           845:                free(cmp_buf);
        !           846:        }
        !           847: 
        !           848:        if (ctx->qflag) {
        !           849:                goto out;
        !           850:        }
        !           851: 
        !           852:        if (ctx->vflag) {
        !           853:                dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size);
        !           854:        }
        !           855: 
        !           856:        /* Finally, report back -- -C gives a parsable format */
        !           857:        t2 = tsub(t2, ctx->t1);
        !           858:        print_report("read", &t2, ctx->offset, ctx->qiov.size,
        !           859:                     ctx->qiov.size, 1, ctx->Cflag);
        !           860: out:
        !           861:        qemu_io_free(ctx->buf);
        !           862:        free(ctx);
        !           863: }
        !           864: 
        !           865: static void
        !           866: aio_read_help(void)
        !           867: {
        !           868:        printf(
        !           869: "\n"
        !           870: " asynchronously reads a range of bytes from the given offset\n"
        !           871: "\n"
        !           872: " Example:\n"
        !           873: " 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n"
        !           874: "\n"
        !           875: " Reads a segment of the currently open file, optionally dumping it to the\n"
        !           876: " standard output stream (with -v option) for subsequent inspection.\n"
        !           877: " The read is performed asynchronously and should the aio_flush command \n"
        !           878: " should be used to ensure all outstanding aio requests have been completed\n"
        !           879: " -C, -- report statistics in a machine parsable format\n"
        !           880: " -P, -- use a pattern to verify read data\n"
        !           881: " -v, -- dump buffer to standard output\n"
        !           882: " -q, -- quite mode, do not show I/O statistics\n"
        !           883: "\n");
        !           884: }
        !           885: 
        !           886: static int
        !           887: aio_read_f(int argc, char **argv)
        !           888: {
        !           889:        int nr_iov, c;
        !           890:        struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
        !           891:        BlockDriverAIOCB *acb;
        !           892: 
        !           893:        while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
        !           894:                switch (c) {
        !           895:                case 'C':
        !           896:                        ctx->Cflag = 1;
        !           897:                        break;
        !           898:                case 'P':
        !           899:                        ctx->Pflag = 1;
        !           900:                        ctx->pattern = atoi(optarg);
        !           901:                        break;
        !           902:                case 'q':
        !           903:                        ctx->qflag = 1;
        !           904:                        break;
        !           905:                case 'v':
        !           906:                        ctx->vflag = 1;
        !           907:                        break;
        !           908:                default:
        !           909:                        free(ctx);
        !           910:                        return command_usage(&aio_read_cmd);
        !           911:                }
        !           912:        }
        !           913: 
        !           914:        if (optind > argc - 2) {
        !           915:                free(ctx);
        !           916:                return command_usage(&aio_read_cmd);
        !           917:        }
        !           918: 
        !           919:        ctx->offset = cvtnum(argv[optind]);
        !           920:        if (ctx->offset < 0) {
        !           921:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !           922:                free(ctx);
        !           923:                return 0;
        !           924:        }
        !           925:        optind++;
        !           926: 
        !           927:        if (ctx->offset & 0x1ff) {
        !           928:                printf("offset %lld is not sector aligned\n",
        !           929:                        (long long)ctx->offset);
        !           930:                free(ctx);
        !           931:                return 0;
        !           932:        }
        !           933: 
        !           934:        nr_iov = argc - optind;
        !           935:        ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
        !           936: 
        !           937:        gettimeofday(&ctx->t1, NULL);
        !           938:        acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
        !           939:                              ctx->qiov.size >> 9, aio_read_done, ctx);
        !           940:        if (!acb) {
        !           941:                free(ctx->buf);
        !           942:                free(ctx);
        !           943:                return -EIO;
        !           944:        }
        !           945: 
        !           946:        return 0;
        !           947: }
        !           948: 
        !           949: static const cmdinfo_t aio_read_cmd = {
        !           950:        .name           = "aio_read",
        !           951:        .cfunc          = aio_read_f,
        !           952:        .argmin         = 2,
        !           953:        .argmax         = -1,
        !           954:        .args           = "[-Cqv] [-P pattern ] off len [len..]",
        !           955:        .oneline        = "asynchronously reads a number of bytes",
        !           956:        .help           = aio_read_help,
        !           957: };
        !           958: 
        !           959: static const cmdinfo_t aio_write_cmd;
        !           960: 
        !           961: static void
        !           962: aio_write_help(void)
        !           963: {
        !           964:        printf(
        !           965: "\n"
        !           966: " asynchronously writes a range of bytes from the given offset source \n"
        !           967: " from multiple buffers\n"
        !           968: "\n"
        !           969: " Example:\n"
        !           970: " 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n"
        !           971: "\n"
        !           972: " Writes into a segment of the currently open file, using a buffer\n"
        !           973: " filled with a set pattern (0xcdcdcdcd).\n"
        !           974: " The write is performed asynchronously and should the aio_flush command \n"
        !           975: " should be used to ensure all outstanding aio requests have been completed\n"
        !           976: " -P, -- use different pattern to fill file\n"
        !           977: " -C, -- report statistics in a machine parsable format\n"
        !           978: " -q, -- quite mode, do not show I/O statistics\n"
        !           979: "\n");
        !           980: }
        !           981: 
        !           982: 
        !           983: static int
        !           984: aio_write_f(int argc, char **argv)
        !           985: {
        !           986:        int nr_iov, c;
        !           987:        int pattern = 0xcd;
        !           988:        struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
        !           989:        BlockDriverAIOCB *acb;
        !           990: 
        !           991:        while ((c = getopt(argc, argv, "CqP:")) != EOF) {
        !           992:                switch (c) {
        !           993:                case 'C':
        !           994:                        ctx->Cflag = 1;
        !           995:                        break;
        !           996:                case 'q':
        !           997:                        ctx->qflag = 1;
        !           998:                        break;
        !           999:                case 'P':
        !          1000:                        pattern = atoi(optarg);
        !          1001:                        break;
        !          1002:                default:
        !          1003:                        free(ctx);
        !          1004:                        return command_usage(&aio_write_cmd);
        !          1005:                }
        !          1006:        }
        !          1007: 
        !          1008:        if (optind > argc - 2) {
        !          1009:                free(ctx);
        !          1010:                return command_usage(&aio_write_cmd);
        !          1011:        }
        !          1012: 
        !          1013:        ctx->offset = cvtnum(argv[optind]);
        !          1014:        if (ctx->offset < 0) {
        !          1015:                printf("non-numeric length argument -- %s\n", argv[optind]);
        !          1016:                free(ctx);
        !          1017:                return 0;
        !          1018:        }
        !          1019:        optind++;
        !          1020: 
        !          1021:        if (ctx->offset & 0x1ff) {
        !          1022:                printf("offset %lld is not sector aligned\n",
        !          1023:                        (long long)ctx->offset);
        !          1024:                free(ctx);
        !          1025:                return 0;
        !          1026:        }
        !          1027: 
        !          1028:        nr_iov = argc - optind;
        !          1029:        ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
        !          1030: 
        !          1031:        gettimeofday(&ctx->t1, NULL);
        !          1032:        acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
        !          1033:                              ctx->qiov.size >> 9, aio_write_done, ctx);
        !          1034:        if (!acb) {
        !          1035:                free(ctx->buf);
        !          1036:                free(ctx);
        !          1037:                return -EIO;
        !          1038:        }
        !          1039: 
        !          1040:        return 0;
        !          1041: }
        !          1042: 
        !          1043: static const cmdinfo_t aio_write_cmd = {
        !          1044:        .name           = "aio_write",
        !          1045:        .cfunc          = aio_write_f,
        !          1046:        .argmin         = 2,
        !          1047:        .argmax         = -1,
        !          1048:        .args           = "[-Cq] [-P pattern ] off len [len..]",
        !          1049:        .oneline        = "asynchronously writes a number of bytes",
        !          1050:        .help           = aio_write_help,
        !          1051: };
        !          1052: 
        !          1053: static int
        !          1054: aio_flush_f(int argc, char **argv)
        !          1055: {
        !          1056:        qemu_aio_flush();
        !          1057:        return 0;
        !          1058: }
        !          1059: 
        !          1060: static const cmdinfo_t aio_flush_cmd = {
        !          1061:        .name           = "aio_flush",
        !          1062:        .cfunc          = aio_flush_f,
        !          1063:        .oneline        = "completes all outstanding aio requets"
        !          1064: };
        !          1065: 
        !          1066: static int
        !          1067: flush_f(int argc, char **argv)
        !          1068: {
        !          1069:        bdrv_flush(bs);
        !          1070:        return 0;
        !          1071: }
        !          1072: 
        !          1073: static const cmdinfo_t flush_cmd = {
        !          1074:        .name           = "flush",
        !          1075:        .altname        = "f",
        !          1076:        .cfunc          = flush_f,
        !          1077:        .oneline        = "flush all in-core file state to disk",
        !          1078: };
        !          1079: 
        !          1080: static int
        !          1081: truncate_f(int argc, char **argv)
        !          1082: {
        !          1083:        int64_t offset;
        !          1084:        int ret;
        !          1085: 
        !          1086:        offset = cvtnum(argv[1]);
        !          1087:        if (offset < 0) {
        !          1088:                printf("non-numeric truncate argument -- %s\n", argv[1]);
        !          1089:                return 0;
        !          1090:        }
        !          1091: 
        !          1092:        ret = bdrv_truncate(bs, offset);
        !          1093:        if (ret < 0) {
        !          1094:                printf("truncate: %s", strerror(ret));
        !          1095:                return 0;
        !          1096:        }
        !          1097: 
        !          1098:        return 0;
        !          1099: }
        !          1100: 
        !          1101: static const cmdinfo_t truncate_cmd = {
        !          1102:        .name           = "truncate",
        !          1103:        .altname        = "t",
        !          1104:        .cfunc          = truncate_f,
        !          1105:        .argmin         = 1,
        !          1106:        .argmax         = 1,
        !          1107:        .args           = "off",
        !          1108:        .oneline        = "truncates the current file at the given offset",
        !          1109: };
        !          1110: 
        !          1111: static int
        !          1112: length_f(int argc, char **argv)
        !          1113: {
        !          1114:         int64_t size;
        !          1115:        char s1[64];
        !          1116: 
        !          1117:        size = bdrv_getlength(bs);
        !          1118:        if (size < 0) {
        !          1119:                printf("getlength: %s", strerror(size));
        !          1120:                return 0;
        !          1121:        }
        !          1122: 
        !          1123:        cvtstr(size, s1, sizeof(s1));
        !          1124:        printf("%s\n", s1);
        !          1125:        return 0;
        !          1126: }
        !          1127: 
        !          1128: 
        !          1129: static const cmdinfo_t length_cmd = {
        !          1130:        .name           = "length",
        !          1131:        .altname        = "l",
        !          1132:        .cfunc          = length_f,
        !          1133:        .oneline        = "gets the length of the current file",
        !          1134: };
        !          1135: 
        !          1136: 
        !          1137: static int
        !          1138: info_f(int argc, char **argv)
        !          1139: {
        !          1140:        BlockDriverInfo bdi;
        !          1141:        char s1[64], s2[64];
        !          1142:        int ret;
        !          1143: 
        !          1144:        if (bs->drv && bs->drv->format_name)
        !          1145:                printf("format name: %s\n", bs->drv->format_name);
        !          1146:        if (bs->drv && bs->drv->protocol_name)
        !          1147:                printf("format name: %s\n", bs->drv->protocol_name);
        !          1148: 
        !          1149:        ret = bdrv_get_info(bs, &bdi);
        !          1150:        if (ret)
        !          1151:                return 0;
        !          1152: 
        !          1153:        cvtstr(bdi.cluster_size, s1, sizeof(s1));
        !          1154:        cvtstr(bdi.vm_state_offset, s2, sizeof(s2));
        !          1155: 
        !          1156:        printf("cluster size: %s\n", s1);
        !          1157:        printf("vm state offset: %s\n", s2);
        !          1158: 
        !          1159:        return 0;
        !          1160: }
        !          1161: 
        !          1162: 
        !          1163: 
        !          1164: static const cmdinfo_t info_cmd = {
        !          1165:        .name           = "info",
        !          1166:        .altname        = "i",
        !          1167:        .cfunc          = info_f,
        !          1168:        .oneline        = "prints information about the current file",
        !          1169: };
        !          1170: 
        !          1171: static int
        !          1172: alloc_f(int argc, char **argv)
        !          1173: {
        !          1174:        int64_t offset;
        !          1175:        int nb_sectors;
        !          1176:        char s1[64];
        !          1177:        int num;
        !          1178:        int ret;
        !          1179:        const char *retstr;
        !          1180: 
        !          1181:        offset = cvtnum(argv[1]);
        !          1182:        if (offset & 0x1ff) {
        !          1183:                printf("offset %lld is not sector aligned\n",
        !          1184:                        (long long)offset);
        !          1185:                return 0;
        !          1186:        }
        !          1187: 
        !          1188:        if (argc == 3)
        !          1189:                nb_sectors = cvtnum(argv[2]);
        !          1190:        else
        !          1191:                nb_sectors = 1;
        !          1192: 
        !          1193:        ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
        !          1194: 
        !          1195:        cvtstr(offset, s1, sizeof(s1));
        !          1196: 
        !          1197:        retstr = ret ? "allocated" : "not allocated";
        !          1198:        if (nb_sectors == 1)
        !          1199:                printf("sector %s at offset %s\n", retstr, s1);
        !          1200:        else
        !          1201:                printf("%d/%d sectors %s at offset %s\n",
        !          1202:                        num, nb_sectors, retstr, s1);
        !          1203:        return 0;
        !          1204: }
        !          1205: 
        !          1206: static const cmdinfo_t alloc_cmd = {
        !          1207:        .name           = "alloc",
        !          1208:        .altname        = "a",
        !          1209:        .argmin         = 1,
        !          1210:        .argmax         = 2,
        !          1211:        .cfunc          = alloc_f,
        !          1212:        .args           = "off [sectors]",
        !          1213:        .oneline        = "checks if a sector is present in the file",
        !          1214: };
        !          1215: 
        !          1216: static int
        !          1217: close_f(int argc, char **argv)
        !          1218: {
        !          1219:        bdrv_close(bs);
        !          1220:        bs = NULL;
        !          1221:        return 0;
        !          1222: }
        !          1223: 
        !          1224: static const cmdinfo_t close_cmd = {
        !          1225:        .name           = "close",
        !          1226:        .altname        = "c",
        !          1227:        .cfunc          = close_f,
        !          1228:        .oneline        = "close the current open file",
        !          1229: };
        !          1230: 
        !          1231: static int openfile(char *name, int flags, int growable)
        !          1232: {
        !          1233:        if (bs) {
        !          1234:                fprintf(stderr, "file open already, try 'help close'\n");
        !          1235:                return 1;
        !          1236:        }
        !          1237: 
        !          1238:        bs = bdrv_new("hda");
        !          1239:        if (!bs)
        !          1240:                return 1;
        !          1241: 
        !          1242:        if (growable) {
        !          1243:                flags |= BDRV_O_FILE;
        !          1244:        }
        !          1245: 
        !          1246:        if (bdrv_open(bs, name, flags) == -1) {
        !          1247:                fprintf(stderr, "%s: can't open device %s\n", progname, name);
        !          1248:                bs = NULL;
        !          1249:                return 1;
        !          1250:        }
        !          1251: 
        !          1252:        if (growable) {
        !          1253:                bs->growable = 1;
        !          1254:        }
        !          1255:        return 0;
        !          1256: }
        !          1257: 
        !          1258: static void
        !          1259: open_help(void)
        !          1260: {
        !          1261:        printf(
        !          1262: "\n"
        !          1263: " opens a new file in the requested mode\n"
        !          1264: "\n"
        !          1265: " Example:\n"
        !          1266: " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
        !          1267: "\n"
        !          1268: " Opens a file for subsequent use by all of the other qemu-io commands.\n"
        !          1269: " -C, -- create new file if it doesn't exist\n"
        !          1270: " -r, -- open file read-only\n"
        !          1271: " -s, -- use snapshot file\n"
        !          1272: " -n, -- disable host cache\n"
        !          1273: " -g, -- allow file to grow (only applies to protocols)"
        !          1274: "\n");
        !          1275: }
        !          1276: 
        !          1277: static const cmdinfo_t open_cmd;
        !          1278: 
        !          1279: static int
        !          1280: open_f(int argc, char **argv)
        !          1281: {
        !          1282:        int flags = 0;
        !          1283:        int readonly = 0;
        !          1284:        int growable = 0;
        !          1285:        int c;
        !          1286: 
        !          1287:        while ((c = getopt(argc, argv, "snCrg")) != EOF) {
        !          1288:                switch (c) {
        !          1289:                case 's':
        !          1290:                        flags |= BDRV_O_SNAPSHOT;
        !          1291:                        break;
        !          1292:                case 'n':
        !          1293:                        flags |= BDRV_O_NOCACHE;
        !          1294:                        break;
        !          1295:                case 'C':
        !          1296:                        flags |= BDRV_O_CREAT;
        !          1297:                        break;
        !          1298:                case 'r':
        !          1299:                        readonly = 1;
        !          1300:                        break;
        !          1301:                case 'g':
        !          1302:                        growable = 1;
        !          1303:                        break;
        !          1304:                default:
        !          1305:                        return command_usage(&open_cmd);
        !          1306:                }
        !          1307:        }
        !          1308: 
        !          1309:        if (readonly)
        !          1310:                flags |= BDRV_O_RDONLY;
        !          1311:        else
        !          1312:                flags |= BDRV_O_RDWR;
        !          1313: 
        !          1314:        if (optind != argc - 1)
        !          1315:                return command_usage(&open_cmd);
        !          1316: 
        !          1317:        return openfile(argv[optind], flags, growable);
        !          1318: }
        !          1319: 
        !          1320: static const cmdinfo_t open_cmd = {
        !          1321:        .name           = "open",
        !          1322:        .altname        = "o",
        !          1323:        .cfunc          = open_f,
        !          1324:        .argmin         = 1,
        !          1325:        .argmax         = -1,
        !          1326:        .flags          = CMD_NOFILE_OK,
        !          1327:        .args           = "[-Crsn] [path]",
        !          1328:        .oneline        = "open the file specified by path",
        !          1329:        .help           = open_help,
        !          1330: };
        !          1331: 
        !          1332: static int
        !          1333: init_args_command(
        !          1334:         int     index)
        !          1335: {
        !          1336:        /* only one device allowed so far */
        !          1337:        if (index >= 1)
        !          1338:                return 0;
        !          1339:        return ++index;
        !          1340: }
        !          1341: 
        !          1342: static int
        !          1343: init_check_command(
        !          1344:        const cmdinfo_t *ct)
        !          1345: {
        !          1346:        if (ct->flags & CMD_FLAG_GLOBAL)
        !          1347:                return 1;
        !          1348:        if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
        !          1349:                fprintf(stderr, "no file open, try 'help open'\n");
        !          1350:                return 0;
        !          1351:        }
        !          1352:        return 1;
        !          1353: }
        !          1354: 
        !          1355: static void usage(const char *name)
        !          1356: {
        !          1357:        printf(
        !          1358: "Usage: %s [-h] [-V] [-Crsnm] [-c cmd] ... [file]\n"
        !          1359: "QEMU Disk exerciser\n"
        !          1360: "\n"
        !          1361: "  -C, --create         create new file if it doesn't exist\n"
        !          1362: "  -c, --cmd            command to execute\n"
        !          1363: "  -r, --read-only      export read-only\n"
        !          1364: "  -s, --snapshot       use snapshot file\n"
        !          1365: "  -n, --nocache        disable host cache\n"
        !          1366: "  -g, --growable       allow file to grow (only applies to protocols)\n"
        !          1367: "  -m, --misalign       misalign allocations for O_DIRECT\n"
        !          1368: "  -h, --help           display this help and exit\n"
        !          1369: "  -V, --version        output version information and exit\n"
        !          1370: "\n",
        !          1371:        name);
        !          1372: }
        !          1373: 
        !          1374: 
        !          1375: int main(int argc, char **argv)
        !          1376: {
        !          1377:        int readonly = 0;
        !          1378:        int growable = 0;
        !          1379:        const char *sopt = "hVc:Crsnmg";
        !          1380:        struct option lopt[] = {
        !          1381:                { "help", 0, NULL, 'h' },
        !          1382:                { "version", 0, NULL, 'V' },
        !          1383:                { "offset", 1, NULL, 'o' },
        !          1384:                { "cmd", 1, NULL, 'c' },
        !          1385:                { "create", 0, NULL, 'C' },
        !          1386:                { "read-only", 0, NULL, 'r' },
        !          1387:                { "snapshot", 0, NULL, 's' },
        !          1388:                { "nocache", 0, NULL, 'n' },
        !          1389:                { "misalign", 0, NULL, 'm' },
        !          1390:                { "growable", 0, NULL, 'g' },
        !          1391:                { NULL, 0, NULL, 0 }
        !          1392:        };
        !          1393:        int c;
        !          1394:        int opt_index = 0;
        !          1395:        int flags = 0;
        !          1396: 
        !          1397:        progname = basename(argv[0]);
        !          1398: 
        !          1399:        while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
        !          1400:                switch (c) {
        !          1401:                case 's':
        !          1402:                        flags |= BDRV_O_SNAPSHOT;
        !          1403:                        break;
        !          1404:                case 'n':
        !          1405:                        flags |= BDRV_O_NOCACHE;
        !          1406:                        break;
        !          1407:                case 'c':
        !          1408:                        add_user_command(optarg);
        !          1409:                        break;
        !          1410:                case 'C':
        !          1411:                        flags |= BDRV_O_CREAT;
        !          1412:                        break;
        !          1413:                case 'r':
        !          1414:                        readonly = 1;
        !          1415:                        break;
        !          1416:                case 'm':
        !          1417:                        misalign = 1;
        !          1418:                        break;
        !          1419:                case 'g':
        !          1420:                        growable = 1;
        !          1421:                        break;
        !          1422:                case 'V':
        !          1423:                        printf("%s version %s\n", progname, VERSION);
        !          1424:                        exit(0);
        !          1425:                case 'h':
        !          1426:                        usage(progname);
        !          1427:                        exit(0);
        !          1428:                default:
        !          1429:                        usage(progname);
        !          1430:                        exit(1);
        !          1431:                }
        !          1432:        }
        !          1433: 
        !          1434:        if ((argc - optind) > 1) {
        !          1435:                usage(progname);
        !          1436:                exit(1);
        !          1437:        }
        !          1438: 
        !          1439:        bdrv_init();
        !          1440: 
        !          1441:        /* initialize commands */
        !          1442:        quit_init();
        !          1443:        help_init();
        !          1444:        add_command(&open_cmd);
        !          1445:        add_command(&close_cmd);
        !          1446:        add_command(&read_cmd);
        !          1447:        add_command(&readv_cmd);
        !          1448:        add_command(&write_cmd);
        !          1449:        add_command(&writev_cmd);
        !          1450:        add_command(&aio_read_cmd);
        !          1451:        add_command(&aio_write_cmd);
        !          1452:        add_command(&aio_flush_cmd);
        !          1453:        add_command(&flush_cmd);
        !          1454:        add_command(&truncate_cmd);
        !          1455:        add_command(&length_cmd);
        !          1456:        add_command(&info_cmd);
        !          1457:        add_command(&alloc_cmd);
        !          1458: 
        !          1459:        add_args_command(init_args_command);
        !          1460:        add_check_command(init_check_command);
        !          1461: 
        !          1462:        /* open the device */
        !          1463:        if (readonly)
        !          1464:                flags |= BDRV_O_RDONLY;
        !          1465:        else
        !          1466:                flags |= BDRV_O_RDWR;
        !          1467: 
        !          1468:        if ((argc - optind) == 1)
        !          1469:                openfile(argv[optind], flags, growable);
        !          1470:        command_loop();
        !          1471: 
        !          1472:        /*
        !          1473:         * Make sure all outstanding requests get flushed the program exits.
        !          1474:         */
        !          1475:        qemu_aio_flush();
        !          1476: 
        !          1477:        if (bs)
        !          1478:                bdrv_close(bs);
        !          1479:        return 0;
        !          1480: }

unix.superglobalmegacorp.com