static BlockDriverState *bdrv_new_open(const char *filename,
                                       const char *fmt)
{
    BlockDriverState *bs;
    BlockDriver *drv;

    bs = bdrv_new("");
    if (!bs)
        FDBG("Not enough memory");
    if (fmt) {
        drv = bdrv_find_format(fmt);
        if (!drv)
            FDBG("Unknown file format '%s'", fmt);
    } else {
        drv = NULL;
    }
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
        FDBG("Could not open '%s'", filename);
    }
    return bs;
}
Beispiel #2
0
/**
 * Return the file descriptor for Linux AIO
 *
 * This function is a layering violation and should be removed when it becomes
 * possible to call the block layer outside the global mutex.  It allows the
 * caller to hijack the file descriptor so I/O can be performed outside the
 * block layer.
 */
int raw_get_aio_fd(BlockDriverState *bs)
{
    BDRVRawState *s;

    if (!bs->drv) {
        return -ENOMEDIUM;
    }

    if (bs->drv == bdrv_find_format("raw")) {
        bs = bs->file;
    }

    /* raw-posix has several protocols so just check for raw_aio_readv */
    if (bs->drv->bdrv_aio_readv != raw_aio_readv) {
        return -ENOTSUP;
    }

    s = bs->opaque;
    if (!s->use_aio) {
        return -ENOTSUP;
    }
    return s->fd;
}
Beispiel #3
0
void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options,
                         Error **errp)
{
    BlockdevCreateJob *s;
    const char *fmt = BlockdevDriver_str(options->driver);
    BlockDriver *drv = bdrv_find_format(fmt);

    /* If the driver is in the schema, we know that it exists. But it may not
     * be whitelisted. */
    assert(drv);
    if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
        error_setg(errp, "Driver is not whitelisted");
        return;
    }

    /* Error out if the driver doesn't support .bdrv_co_create */
    if (!drv->bdrv_co_create) {
        error_setg(errp, "Driver does not support blockdev-create");
        return;
    }

    /* Create the block job */
    /* TODO Running in the main context. Block drivers need to error out or add
     * locking when they use a BDS in a different AioContext. */
    s = job_create(job_id, &blockdev_create_job_driver, NULL,
                   qemu_get_aio_context(), JOB_DEFAULT | JOB_MANUAL_DISMISS,
                   NULL, NULL, errp);
    if (!s) {
        return;
    }

    s->drv = drv,
    s->opts = QAPI_CLONE(BlockdevCreateOptions, options),

    job_start(&s->common);
}
Beispiel #4
0
static int img_convert(int argc, char **argv)
{
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
    BlockDriver *drv;
    BlockDriverState **bs, *out_bs;
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
    uint64_t bs_sectors;
    uint8_t * buf;
    const uint8_t *buf1;
    BlockDriverInfo bdi;
    QEMUOptionParameter *param = NULL;
    char *options = NULL;

    fmt = NULL;
    out_fmt = "raw";
    out_baseimg = NULL;
    flags = 0;
    for(;;) {
        c = getopt(argc, argv, "f:O:B:hce6o:");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
            help();
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'O':
            out_fmt = optarg;
            break;
        case 'B':
            out_baseimg = optarg;
            break;
        case 'c':
            flags |= BLOCK_FLAG_COMPRESS;
            break;
        case 'e':
            flags |= BLOCK_FLAG_ENCRYPT;
            break;
        case '6':
            flags |= BLOCK_FLAG_COMPAT6;
            break;
        case 'o':
            options = optarg;
            break;
        }
    }

    bs_n = argc - optind - 1;
    if (bs_n < 1) help();

    out_filename = argv[argc - 1];

    if (bs_n > 1 && out_baseimg)
        error("-B makes no sense when concatenating multiple input images");
        
    bs = calloc(bs_n, sizeof(BlockDriverState *));
    if (!bs)
        error("Out of memory");

    total_sectors = 0;
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
        if (!bs[bs_i])
            error("Could not open '%s'", argv[optind + bs_i]);
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
        total_sectors += bs_sectors;
    }

    /* Find driver and parse its options */
    drv = bdrv_find_format(out_fmt);
    if (!drv)
        error("Unknown file format '%s'", out_fmt);

    if (options && !strcmp(options, "?")) {
        print_option_help(drv->create_options);
        free(bs);
        return 0;
    }

    if (options) {
        param = parse_option_parameters(options, drv->create_options, param);
        if (param == NULL) {
            error("Invalid options for file format '%s'.", out_fmt);
        }
    } else {
        param = parse_option_parameters("", drv->create_options, param);
    }

    set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
    add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);

    /* Check if compression is supported */
    if (flags & BLOCK_FLAG_COMPRESS) {
        QEMUOptionParameter *encryption =
            get_option_parameter(param, BLOCK_OPT_ENCRYPT);

        if (!drv->bdrv_write_compressed) {
            error("Compression not supported for this file format");
        }

        if (encryption && encryption->value.n) {
            error("Compression and encryption not supported at the same time");
        }
    }

    /* Create the new image */
    ret = bdrv_create(drv, out_filename, param);
    free_option_parameters(param);

    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error("Formatting not supported for file format '%s'", out_fmt);
        } else if (ret == -EFBIG) {
            error("The image size is too large for file format '%s'", out_fmt);
        } else {
            error("%s: error while converting %s: %s", out_filename, out_fmt, strerror(-ret));
        }
    }

    out_bs = bdrv_new_open(out_filename, out_fmt, BDRV_O_FLAGS | BDRV_O_RDWR);

    bs_i = 0;
    bs_offset = 0;
    bdrv_get_geometry(bs[0], &bs_sectors);
    buf = qemu_malloc(IO_BUF_SIZE);

    if (flags & BLOCK_FLAG_COMPRESS) {
        if (bdrv_get_info(out_bs, &bdi) < 0)
            error("could not get block driver info");
        cluster_size = bdi.cluster_size;
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
            error("invalid cluster size");
        cluster_sectors = cluster_size >> 9;
        sector_num = 0;
        for(;;) {
            int64_t bs_num;
            int remainder;
            uint8_t *buf2;

            nb_sectors = total_sectors - sector_num;
            if (nb_sectors <= 0)
                break;
            if (nb_sectors >= cluster_sectors)
                n = cluster_sectors;
            else
                n = nb_sectors;

            bs_num = sector_num - bs_offset;
            assert (bs_num >= 0);
            remainder = n;
            buf2 = buf;
            while (remainder > 0) {
                int nlow;
                while (bs_num == bs_sectors) {
                    bs_i++;
                    assert (bs_i < bs_n);
                    bs_offset += bs_sectors;
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
                    bs_num = 0;
                    /* printf("changing part: sector_num=%lld, "
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
                       sector_num, bs_i, bs_offset, bs_sectors); */
                }
                assert (bs_num < bs_sectors);

                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;

                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
                    error("error while reading");

                buf2 += nlow * 512;
                bs_num += nlow;

                remainder -= nlow;
            }
            assert (remainder == 0);

            if (n < cluster_sectors)
                memset(buf + n * 512, 0, cluster_size - n * 512);
            if (is_not_zero(buf, cluster_size)) {
                if (bdrv_write_compressed(out_bs, sector_num, buf,
                                          cluster_sectors) != 0)
                    error("error while compressing sector %" PRId64,
                          sector_num);
            }
            sector_num += n;
        }
        /* signal EOF to align */
        bdrv_write_compressed(out_bs, 0, NULL, 0);
    } else {
Beispiel #5
0
static int img_create(int argc, char **argv)
{
    int c, ret, flags;
    const char *fmt = "raw";
    const char *base_fmt = NULL;
    const char *filename;
    const char *base_filename = NULL;
    BlockDriver *drv;
    QEMUOptionParameter *param = NULL;
    char *options = NULL;

    flags = 0;
    for(;;) {
        c = getopt(argc, argv, "F:b:f:he6o:");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
            help();
            break;
        case 'F':
            base_fmt = optarg;
            break;
        case 'b':
            base_filename = optarg;
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'e':
            flags |= BLOCK_FLAG_ENCRYPT;
            break;
        case '6':
            flags |= BLOCK_FLAG_COMPAT6;
            break;
        case 'o':
            options = optarg;
            break;
        }
    }

    /* Find driver and parse its options */
    drv = bdrv_find_format(fmt);
    if (!drv)
        error("Unknown file format '%s'", fmt);

    if (options && !strcmp(options, "?")) {
        print_option_help(drv->create_options);
        return 0;
    }

    /* Create parameter list with default values */
    param = parse_option_parameters("", drv->create_options, param);
    set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);

    /* Parse -o options */
    if (options) {
        param = parse_option_parameters(options, drv->create_options, param);
        if (param == NULL) {
            error("Invalid options for file format '%s'.", fmt);
        }
    }

    /* Get the filename */
    if (optind >= argc)
        help();
    filename = argv[optind++];

    /* Add size to parameters */
    if (optind < argc) {
        set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
    }

    /* Add old-style options to parameters */
    add_old_style_options(fmt, param, flags, base_filename, base_fmt);

    // The size for the image must always be specified, with one exception:
    // If we are using a backing file, we can obtain the size from there
    if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {

        QEMUOptionParameter *backing_file =
            get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
        QEMUOptionParameter *backing_fmt =
            get_option_parameter(param, BLOCK_OPT_BACKING_FMT);

        if (backing_file && backing_file->value.s) {
            BlockDriverState *bs;
            uint64_t size;
            const char *fmt = NULL;
            char buf[32];

            if (backing_fmt && backing_fmt->value.s) {
                 if (bdrv_find_format(backing_fmt->value.s)) {
                     fmt = backing_fmt->value.s;
                } else {
                     error("Unknown backing file format '%s'",
                        backing_fmt->value.s);
                }
            }

            bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);
            bdrv_get_geometry(bs, &size);
            size *= 512;
            bdrv_delete(bs);

            snprintf(buf, sizeof(buf), "%" PRId64, size);
            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
        } else {
            error("Image creation needs a size parameter");
        }
    }

    printf("Formatting '%s', fmt=%s ", filename, fmt);
    print_option_parameters(param);
    puts("");

    ret = bdrv_create(drv, filename, param);
    free_option_parameters(param);

    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error("Formatting or formatting option not supported for file format '%s'", fmt);
        } else if (ret == -EFBIG) {
            error("The image size is too large for file format '%s'", fmt);
        } else {
            error("%s: error while creating %s: %s", filename, fmt, strerror(-ret));
        }
    }
    return 0;
}
Beispiel #6
0
static int img_convert(int argc, char **argv)
{
    int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
    int progress = 0;
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
    BlockDriver *drv, *proto_drv;
    BlockDriverState **bs = NULL, *out_bs = NULL;
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
    uint64_t bs_sectors;
    uint8_t * buf = NULL;
    const uint8_t *buf1;
    BlockDriverInfo bdi;
    QEMUOptionParameter *param = NULL, *create_options = NULL;
    QEMUOptionParameter *out_baseimg_param;
    char *options = NULL;
    const char *snapshot_name = NULL;
    float local_progress;

    fmt = NULL;
    out_fmt = "raw";
    out_baseimg = NULL;
    compress = 0;
    for(;;) {
        c = getopt(argc, argv, "f:O:B:s:hce6o:p");
        if (c == -1) {
            break;
        }
        switch(c) {
        case '?':
        case 'h':
            help();
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'O':
            out_fmt = optarg;
            break;
        case 'B':
            out_baseimg = optarg;
            break;
        case 'c':
            compress = 1;
            break;
        case 'e':
            error_report("qemu-img: option -e is deprecated, please use \'-o "
                  "encryption\' instead!");
            return 1;
        case '6':
            error_report("qemu-img: option -6 is deprecated, please use \'-o "
                  "compat6\' instead!");
            return 1;
        case 'o':
            options = optarg;
            break;
        case 's':
            snapshot_name = optarg;
            break;
        case 'p':
            progress = 1;
            break;
        }
    }

    bs_n = argc - optind - 1;
    if (bs_n < 1) {
        help();
    }

    out_filename = argv[argc - 1];

    if (options && !strcmp(options, "?")) {
        ret = print_block_option_help(out_filename, out_fmt);
        goto out;
    }

    if (bs_n > 1 && out_baseimg) {
        error_report("-B makes no sense when concatenating multiple input "
                     "images");
        ret = -1;
        goto out;
    }
        
    qemu_progress_init(progress, 2.0);
    qemu_progress_print(0, 100);

    bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));

    total_sectors = 0;
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
        if (!bs[bs_i]) {
            error_report("Could not open '%s'", argv[optind + bs_i]);
            ret = -1;
            goto out;
        }
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
        total_sectors += bs_sectors;
    }

    if (snapshot_name != NULL) {
        if (bs_n > 1) {
            error_report("No support for concatenating multiple snapshot\n");
            ret = -1;
            goto out;
        }
        if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
            error_report("Failed to load snapshot\n");
            ret = -1;
            goto out;
        }
    }

    /* Find driver and parse its options */
    drv = bdrv_find_format(out_fmt);
    if (!drv) {
        error_report("Unknown file format '%s'", out_fmt);
        ret = -1;
        goto out;
    }

    proto_drv = bdrv_find_protocol(out_filename);
    if (!proto_drv) {
        error_report("Unknown protocol '%s'", out_filename);
        ret = -1;
        goto out;
    }

    create_options = append_option_parameters(create_options,
                                              drv->create_options);
    create_options = append_option_parameters(create_options,
                                              proto_drv->create_options);

    if (options) {
        param = parse_option_parameters(options, create_options, param);
        if (param == NULL) {
            error_report("Invalid options for file format '%s'.", out_fmt);
            ret = -1;
            goto out;
        }
    } else {
        param = parse_option_parameters("", create_options, param);
    }

    set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
    ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
    if (ret < 0) {
        goto out;
    }

    /* Get backing file name if -o backing_file was used */
    out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
    if (out_baseimg_param) {
        out_baseimg = out_baseimg_param->value.s;
    }

    /* Check if compression is supported */
    if (compress) {
        QEMUOptionParameter *encryption =
            get_option_parameter(param, BLOCK_OPT_ENCRYPT);

        if (!drv->bdrv_write_compressed) {
            error_report("Compression not supported for this file format");
            ret = -1;
            goto out;
        }

        if (encryption && encryption->value.n) {
            error_report("Compression and encryption not supported at "
                         "the same time");
            ret = -1;
            goto out;
        }
    }

    /* Create the new image */
    ret = bdrv_create(drv, out_filename, param);
    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error_report("Formatting not supported for file format '%s'",
                         out_fmt);
        } else if (ret == -EFBIG) {
            error_report("The image size is too large for file format '%s'",
                         out_fmt);
        } else {
            error_report("%s: error while converting %s: %s",
                         out_filename, out_fmt, strerror(-ret));
        }
        goto out;
    }

    out_bs = bdrv_new_open(out_filename, out_fmt,
        BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH);
    if (!out_bs) {
        ret = -1;
        goto out;
    }

    bs_i = 0;
    bs_offset = 0;
    bdrv_get_geometry(bs[0], &bs_sectors);
    buf = qemu_malloc(IO_BUF_SIZE);

    if (compress) {
        ret = bdrv_get_info(out_bs, &bdi);
        if (ret < 0) {
            error_report("could not get block driver info");
            goto out;
        }
        cluster_size = bdi.cluster_size;
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
            error_report("invalid cluster size");
            ret = -1;
            goto out;
        }
        cluster_sectors = cluster_size >> 9;
        sector_num = 0;

        nb_sectors = total_sectors;
        local_progress = (float)100 /
            (nb_sectors / MIN(nb_sectors, (cluster_sectors)));

        for(;;) {
            int64_t bs_num;
            int remainder;
            uint8_t *buf2;

            nb_sectors = total_sectors - sector_num;
            if (nb_sectors <= 0)
                break;
            if (nb_sectors >= cluster_sectors)
                n = cluster_sectors;
            else
                n = nb_sectors;

            bs_num = sector_num - bs_offset;
            assert (bs_num >= 0);
            remainder = n;
            buf2 = buf;
            while (remainder > 0) {
                int nlow;
                while (bs_num == bs_sectors) {
                    bs_i++;
                    assert (bs_i < bs_n);
                    bs_offset += bs_sectors;
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
                    bs_num = 0;
                    /* printf("changing part: sector_num=%" PRId64 ", "
                       "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
                       "\n", sector_num, bs_i, bs_offset, bs_sectors); */
                }
                assert (bs_num < bs_sectors);

                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;

                ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
                if (ret < 0) {
                    error_report("error while reading");
                    goto out;
                }

                buf2 += nlow * 512;
                bs_num += nlow;

                remainder -= nlow;
            }
            assert (remainder == 0);

            if (n < cluster_sectors) {
                memset(buf + n * 512, 0, cluster_size - n * 512);
            }
            if (is_not_zero(buf, cluster_size)) {
                ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                            cluster_sectors);
                if (ret != 0) {
                    error_report("error while compressing sector %" PRId64,
                          sector_num);
                    goto out;
                }
            }
            sector_num += n;
            qemu_progress_print(local_progress, 100);
        }
        /* signal EOF to align */
        bdrv_write_compressed(out_bs, 0, NULL, 0);
    } else {
Beispiel #7
0
int main(int argc, char **argv)
{
    BlockBackend *blk;
    BlockDriverState *bs;
    BlockDriver *drv;
    off_t dev_offset = 0;
    uint32_t nbdflags = 0;
    bool disconnect = false;
    const char *bindto = "0.0.0.0";
    char *device = NULL;
    int port = NBD_DEFAULT_PORT;
    off_t fd_size;
    QemuOpts *sn_opts = NULL;
    const char *sn_id_or_name = NULL;
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:";
    struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "bind", 1, NULL, 'b' },
        { "port", 1, NULL, 'p' },
        { "socket", 1, NULL, 'k' },
        { "offset", 1, NULL, 'o' },
        { "read-only", 0, NULL, 'r' },
        { "partition", 1, NULL, 'P' },
        { "connect", 1, NULL, 'c' },
        { "disconnect", 0, NULL, 'd' },
        { "snapshot", 0, NULL, 's' },
        { "load-snapshot", 1, NULL, 'l' },
        { "nocache", 0, NULL, 'n' },
        { "cache", 1, NULL, QEMU_NBD_OPT_CACHE },
#ifdef CONFIG_LINUX_AIO
        { "aio", 1, NULL, QEMU_NBD_OPT_AIO },
#endif
        { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD },
        { "detect-zeroes", 1, NULL, QEMU_NBD_OPT_DETECT_ZEROES },
        { "shared", 1, NULL, 'e' },
        { "format", 1, NULL, 'f' },
        { "persistent", 0, NULL, 't' },
        { "verbose", 0, NULL, 'v' },
        { NULL, 0, NULL, 0 }
    };
    int ch;
    int opt_ind = 0;
    int li;
    char *end;
    int flags = BDRV_O_RDWR;
    int partition = -1;
    int ret;
    int fd;
    bool seen_cache = false;
    bool seen_discard = false;
#ifdef CONFIG_LINUX_AIO
    bool seen_aio = false;
#endif
    pthread_t client_thread;
    const char *fmt = NULL;
    Error *local_err = NULL;
    BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;

    /* The client thread uses SIGTERM to interrupt the server.  A signal
     * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
     */
    struct sigaction sa_sigterm;
    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
    sa_sigterm.sa_handler = termsig_handler;
    sigaction(SIGTERM, &sa_sigterm, NULL);
    qemu_init_exec_dir(argv[0]);

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            optarg = (char *) "none";
            /* fallthrough */
        case QEMU_NBD_OPT_CACHE:
            if (seen_cache) {
                errx(EXIT_FAILURE, "-n and --cache can only be specified once");
            }
            seen_cache = true;
            if (bdrv_parse_cache_flags(optarg, &flags) == -1) {
                errx(EXIT_FAILURE, "Invalid cache mode `%s'", optarg);
            }
            break;
#ifdef CONFIG_LINUX_AIO
        case QEMU_NBD_OPT_AIO:
            if (seen_aio) {
                errx(EXIT_FAILURE, "--aio can only be specified once");
            }
            seen_aio = true;
            if (!strcmp(optarg, "native")) {
                flags |= BDRV_O_NATIVE_AIO;
            } else if (!strcmp(optarg, "threads")) {
                /* this is the default */
            } else {
               errx(EXIT_FAILURE, "invalid aio mode `%s'", optarg);
            }
            break;
#endif
        case QEMU_NBD_OPT_DISCARD:
            if (seen_discard) {
                errx(EXIT_FAILURE, "--discard can only be specified once");
            }
            seen_discard = true;
            if (bdrv_parse_discard_flags(optarg, &flags) == -1) {
                errx(EXIT_FAILURE, "Invalid discard mode `%s'", optarg);
            }
            break;
        case QEMU_NBD_OPT_DETECT_ZEROES:
            detect_zeroes =
                qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
                                optarg,
                                BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
                                BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                                &local_err);
            if (local_err) {
                errx(EXIT_FAILURE, "Failed to parse detect_zeroes mode: %s", 
                     error_get_pretty(local_err));
            }
            if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
                !(flags & BDRV_O_UNMAP)) {
                errx(EXIT_FAILURE, "setting detect-zeroes to unmap is not allowed "
                                   "without setting discard operation to unmap"); 
            }
            break;
        case 'b':
            bindto = optarg;
            break;
        case 'p':
            li = strtol(optarg, &end, 0);
            if (*end) {
                errx(EXIT_FAILURE, "Invalid port `%s'", optarg);
            }
            if (li < 1 || li > 65535) {
                errx(EXIT_FAILURE, "Port out of range `%s'", optarg);
            }
            port = (uint16_t)li;
            break;
        case 'o':
                dev_offset = strtoll (optarg, &end, 0);
            if (*end) {
                errx(EXIT_FAILURE, "Invalid offset `%s'", optarg);
            }
            if (dev_offset < 0) {
                errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg);
            }
            break;
        case 'l':
            if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
                sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);
                if (!sn_opts) {
                    errx(EXIT_FAILURE, "Failed in parsing snapshot param `%s'",
                         optarg);
                }
            } else {
                sn_id_or_name = optarg;
            }
            /* fall through */
        case 'r':
            nbdflags |= NBD_FLAG_READ_ONLY;
            flags &= ~BDRV_O_RDWR;
            break;
        case 'P':
            partition = strtol(optarg, &end, 0);
            if (*end) {
                errx(EXIT_FAILURE, "Invalid partition `%s'", optarg);
            }
            if (partition < 1 || partition > 8) {
                errx(EXIT_FAILURE, "Invalid partition %d", partition);
            }
            break;
        case 'k':
            sockpath = optarg;
            if (sockpath[0] != '/') {
                errx(EXIT_FAILURE, "socket path must be absolute\n");
            }
            break;
        case 'd':
            disconnect = true;
            break;
        case 'c':
            device = optarg;
            break;
        case 'e':
            shared = strtol(optarg, &end, 0);
            if (*end) {
                errx(EXIT_FAILURE, "Invalid shared device number '%s'", optarg);
            }
            if (shared < 1) {
                errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
            }
            break;
        case 'f':
            fmt = optarg;
            break;
        case 't':
            persistent = 1;
            break;
        case 'v':
            verbose = 1;
            break;
        case 'V':
            version(argv[0]);
            exit(0);
            break;
        case 'h':
            usage(argv[0]);
            exit(0);
            break;
        case '?':
            errx(EXIT_FAILURE, "Try `%s --help' for more information.",
                 argv[0]);
        }
    }

    if ((argc - optind) != 1) {
        errx(EXIT_FAILURE, "Invalid number of argument.\n"
             "Try `%s --help' for more information.",
             argv[0]);
    }

    if (disconnect) {
        fd = open(argv[optind], O_RDWR);
        if (fd < 0) {
            err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
        }
        nbd_disconnect(fd);

        close(fd);

        printf("%s disconnected\n", argv[optind]);

        return 0;
    }

    if (device && !verbose) {
        int stderr_fd[2];
        pid_t pid;
        int ret;

        if (qemu_pipe(stderr_fd) < 0) {
            err(EXIT_FAILURE, "Error setting up communication pipe");
        }

        /* Now daemonize, but keep a communication channel open to
         * print errors and exit with the proper status code.
         */
        pid = fork();
        if (pid == 0) {
            close(stderr_fd[0]);
            ret = qemu_daemon(1, 0);

            /* Temporarily redirect stderr to the parent's pipe...  */
            dup2(stderr_fd[1], STDERR_FILENO);
            if (ret < 0) {
                err(EXIT_FAILURE, "Failed to daemonize");
            }

            /* ... close the descriptor we inherited and go on.  */
            close(stderr_fd[1]);
        } else {
            bool errors = false;
            char *buf;

            /* In the parent.  Print error messages from the child until
             * it closes the pipe.
             */
            close(stderr_fd[1]);
            buf = g_malloc(1024);
            while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
                errors = true;
                ret = qemu_write_full(STDERR_FILENO, buf, ret);
                if (ret < 0) {
                    exit(EXIT_FAILURE);
                }
            }
            if (ret < 0) {
                err(EXIT_FAILURE, "Cannot read from daemon");
            }

            /* Usually the daemon should not print any message.
             * Exit with zero status in that case.
             */
            exit(errors);
        }
    }

    if (device != NULL && sockpath == NULL) {
        sockpath = g_malloc(128);
        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
    }

    if (qemu_init_main_loop(&local_err)) {
        error_report("%s", error_get_pretty(local_err));
        error_free(local_err);
        exit(EXIT_FAILURE);
    }
    bdrv_init();
    atexit(bdrv_close_all);

    if (fmt) {
        drv = bdrv_find_format(fmt);
        if (!drv) {
            errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
        }
    } else {
        drv = NULL;
    }

    blk = blk_new_with_bs("hda", &error_abort);
    bs = blk_bs(blk);

    srcpath = argv[optind];
    ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err);
    if (ret < 0) {
        errno = -ret;
        err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind],
            error_get_pretty(local_err));
    }

    if (sn_opts) {
        ret = bdrv_snapshot_load_tmp(bs,
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
                                     &local_err);
    } else if (sn_id_or_name) {
        ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name,
                                                   &local_err);
    }
    if (ret < 0) {
        errno = -ret;
        err(EXIT_FAILURE,
            "Failed to load snapshot: %s",
            error_get_pretty(local_err));
    }

    bs->detect_zeroes = detect_zeroes;
    fd_size = blk_getlength(blk);

    if (partition != -1) {
        ret = find_partition(blk, partition, &dev_offset, &fd_size);
        if (ret < 0) {
            errno = -ret;
            err(EXIT_FAILURE, "Could not find partition %d", partition);
        }
    }

    exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed);

    if (sockpath) {
        fd = unix_socket_incoming(sockpath);
    } else {
        fd = tcp_socket_incoming(bindto, port);
    }

    if (fd < 0) {
        return 1;
    }

    if (device) {
        int ret;

        ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
        if (ret != 0) {
            errx(EXIT_FAILURE, "Failed to create client thread: %s",
                 strerror(ret));
        }
    } else {
        /* Shut up GCC warnings.  */
        memset(&client_thread, 0, sizeof(client_thread));
    }

    qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL,
                         (void *)(uintptr_t)fd);

    /* now when the initialization is (almost) complete, chdir("/")
     * to free any busy filesystems */
    if (chdir("/") < 0) {
        err(EXIT_FAILURE, "Could not chdir to root directory");
    }

    state = RUNNING;
    do {
        main_loop_wait(false);
        if (state == TERMINATE) {
            state = TERMINATING;
            nbd_export_close(exp);
            nbd_export_put(exp);
            exp = NULL;
        }
    } while (state != TERMINATED);

    blk_unref(blk);
    if (sockpath) {
        unlink(sockpath);
    }

    qemu_opts_del(sn_opts);

    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
}
Beispiel #8
0
static void perform_test(const char *truth_file, const char *test_file,
                         const char *format, int compare_before,
                         int compare_after)
{
    int flags, i;

    bs = bdrv_new ("hda");
    if (!bs) {
        die ("bdrv_new failed\n");
    }

    BlockDriver *drv = NULL;
    if (format) {
        drv = bdrv_find_format (format);
        if (!drv) {
            die ("Found no driver for format '%s'.\n", format);
        }
    }

    flags = BDRV_O_RDWR | BDRV_O_CACHE_WB;

    if (bdrv_open (bs, test_file, flags, drv) < 0) {
        die ("Failed to open '%s'\n", test_file);
    }

    fd = open (truth_file, O_RDWR | O_LARGEFILE, 0);
    if (fd < 0) {
        perror ("open");
        die ("Failed to open '%s'\n", truth_file);
    }

    int64_t l0 = lseek (fd, 0, SEEK_END);
    int64_t l1 = bdrv_getlength (bs);
    if (l0 < 0 || l1 < 0 || l0 < l1) {
        die ("Mismatch: truth image %s length %" PRId64 ", test image %s "
             "length %" PRId64 "\n", truth_file, l0, test_file, l1);
    }

    total_sectors = l1 / 512;
    if (total_sectors <= 1) {
        die ("Total sectors: %" PRId64 "\n", total_sectors);
    }

    io_size /= 512;
    if (io_size <= 0) {
        io_size = 1;
    } else if (io_size > total_sectors / 2) {
        io_size = total_sectors / 2;
    }

    if (compare_before) {
        if (compare_full_images ()) {
            die ("The original two files do not match.\n");
        }
    }

    if (round > 0) {
        /* Create testers. */
        testers = g_malloc(sizeof(RandomIO) * parallel);
        for (i = 0; i < parallel; i++) {
            RandomIO *r = &testers[i];
            r->test_buf = qemu_blockalign (bs, io_size * 512);
            if (posix_memalign ((void **) &r->truth_buf, 512, io_size * 512)) {
                die ("posix_memalign");
            }
            r->qiov.iov = g_malloc(sizeof(struct iovec) * max_iov);
            r->sector_num = 0;
            r->nb_sectors = 0;
            r->type = OP_READ;
            r->tester = i;
        }
        for (i = 0; i < parallel; i++) {
            perform_next_io (&testers[i]);
        }
    }

    sim_all_tasks ();        /* Run tests. */

    if (round > 0) {
        /* Create testers. */
        if (compare_after) {
            if (compare_full_images ()) {
                die ("The two files do not match after I/O operations.\n");
            }
        }

        for (i = 0; i < parallel; i++) {
            RandomIO *r = &testers[i];
            qemu_vfree (r->test_buf);
            free (r->truth_buf);
            g_free(r->qiov.iov);
        }
        g_free(testers);
    }

    printf ("Test process %d finished successfully\n", getpid ());

    int fvd = (strncmp (bs->drv->format_name, "fvd", 3) == 0);
    bdrv_delete (bs);
    if (fvd) {
        fvd_check_memory_usage ();
    }
    close (fd);
}
Beispiel #9
0
static int blk_init(struct XenDevice *xendev)
{
    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
    int mode, qflags, have_barriers, info = 0;
    char *h = NULL;

    /* read xenstore entries */
    if (blkdev->params == NULL) {
	blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
        if (blkdev->params != NULL)
            h = strchr(blkdev->params, ':');
	if (h != NULL) {
	    blkdev->fileproto = blkdev->params;
	    blkdev->filename  = h+1;
	    *h = 0;
	} else {
	    blkdev->fileproto = "<unset>";
	    blkdev->filename  = blkdev->params;
	}
    }
    if (!strcmp("aio", blkdev->fileproto))
        blkdev->fileproto = "raw";
    if (blkdev->mode == NULL)
	blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
    if (blkdev->type == NULL)
	blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
    if (blkdev->dev == NULL)
	blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
    if (blkdev->devtype == NULL)
	blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");

    /* do we have all we need? */
    if (blkdev->params == NULL ||
	blkdev->mode == NULL   ||
	blkdev->type == NULL   ||
	blkdev->dev == NULL)
	return -1;

    /* read-only ? */
    qflags = BDRV_O_NOCACHE;
    if (strcmp(blkdev->mode, "w") == 0) {
	mode   = O_RDWR;
	qflags |= BDRV_O_RDWR;
    } else {
	mode   = O_RDONLY;
	qflags |= BDRV_O_RDONLY;
	info  |= VDISK_READONLY;
    }

    /* cdrom ? */
    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom"))
	info  |= VDISK_CDROM;

    /* init qemu block driver */
    blkdev->index = (blkdev->xendev.dev - 202 * 256) / 16;
    blkdev->index = drive_get_index(IF_XEN, 0, blkdev->index);
    if (blkdev->index == -1) {
        /* setup via xenbus -> create new block driver instance */
        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
	blkdev->bs = bdrv_new(blkdev->dev);
	if (blkdev->bs) {
	    if (bdrv_open2(blkdev->bs, blkdev->filename, qflags,
                           bdrv_find_format(blkdev->fileproto)) != 0) {
		bdrv_delete(blkdev->bs);
		blkdev->bs = NULL;
	    }
	}
	if (!blkdev->bs)
	    return -1;
    } else {
        /* setup via qemu cmdline -> already setup for us */
        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
	blkdev->bs = drives_table[blkdev->index].bdrv;
    }
    blkdev->file_blk  = BLOCK_SIZE;
    blkdev->file_size = bdrv_getlength(blkdev->bs);
    if (blkdev->file_size < 0) {
        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
                      (int)blkdev->file_size, strerror(-blkdev->file_size),
                      blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
	blkdev->file_size = 0;
    }
    have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;

    xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
		  " size %" PRId64 " (%" PRId64 " MB)\n",
		  blkdev->type, blkdev->fileproto, blkdev->filename,
		  blkdev->file_size, blkdev->file_size >> 20);

    /* fill info */
    xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
    xenstore_write_be_int(&blkdev->xendev, "info",            info);
    xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
    xenstore_write_be_int(&blkdev->xendev, "sectors",
			  blkdev->file_size / blkdev->file_blk);
    return 0;
}
Beispiel #10
0
static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
{
    BDRVDMGState *s = bs->opaque;
    off_t info_begin,info_end,last_in_offset,last_out_offset;
    uint32_t count;
    uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;

    s->fd = open(filename, O_RDONLY | O_BINARY);
    if (s->fd < 0)
        return -errno;
    bs->read_only = 1;
    s->n_chunks = 0;
    s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;

    /* read offset of info blocks */
    if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
dmg_close:
	close(s->fd);
	/* open raw instead */
	bs->drv=bdrv_find_format("raw");
	return bs->drv->bdrv_open(bs, filename, flags);
    }
    info_begin=read_off(s->fd);
    if(info_begin==0)
	goto dmg_close;
    if(lseek(s->fd,info_begin,SEEK_SET)<0)
	goto dmg_close;
    if(read_uint32(s->fd)!=0x100)
	goto dmg_close;
    if((count = read_uint32(s->fd))==0)
	goto dmg_close;
    info_end = info_begin+count;
    if(lseek(s->fd,0xf8,SEEK_CUR)<0)
	goto dmg_close;

    /* read offsets */
    last_in_offset = last_out_offset = 0;
    while(lseek(s->fd,0,SEEK_CUR)<info_end) {
        uint32_t type;

	count = read_uint32(s->fd);
	if(count==0)
	    goto dmg_close;
	type = read_uint32(s->fd);
	if(type!=0x6d697368 || count<244)
	    lseek(s->fd,count-4,SEEK_CUR);
	else {
	    int new_size, chunk_count;
	    if(lseek(s->fd,200,SEEK_CUR)<0)
	        goto dmg_close;
	    chunk_count = (count-204)/40;
	    new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
	    s->types = qemu_realloc(s->types, new_size/2);
	    s->offsets = qemu_realloc(s->offsets, new_size);
	    s->lengths = qemu_realloc(s->lengths, new_size);
	    s->sectors = qemu_realloc(s->sectors, new_size);
	    s->sectorcounts = qemu_realloc(s->sectorcounts, new_size);

	    for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
		s->types[i] = read_uint32(s->fd);
		if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
		    if(s->types[i]==0xffffffff) {
			last_in_offset = s->offsets[i-1]+s->lengths[i-1];
			last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
		    }
		    chunk_count--;
		    i--;
		    if(lseek(s->fd,36,SEEK_CUR)<0)
			goto dmg_close;
		    continue;
		}
		read_uint32(s->fd);
		s->sectors[i] = last_out_offset+read_off(s->fd);
		s->sectorcounts[i] = read_off(s->fd);
		s->offsets[i] = last_in_offset+read_off(s->fd);
		s->lengths[i] = read_off(s->fd);
		if(s->lengths[i]>max_compressed_size)
		    max_compressed_size = s->lengths[i];
		if(s->sectorcounts[i]>max_sectors_per_chunk)
		    max_sectors_per_chunk = s->sectorcounts[i];
	    }
	    s->n_chunks+=chunk_count;
	}
    }

    /* initialize zlib engine */
    s->compressed_chunk = qemu_malloc(max_compressed_size+1);
    s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk);
    if(inflateInit(&s->zstream) != Z_OK)
	goto dmg_close;

    s->current_chunk = s->n_chunks;

    return 0;
}
Beispiel #11
0
int 
main(int argc, char *argv[])
{
    int c;
    const char *filename, *fmt;
    BlockDriver *drv;
    BlockDriverState *bs;
    char fmt_name[128], size_buf[128], dsize_buf[128];
    uint64_t total_sectors;
    int64_t allocated_size;
    char backing_filename[1024];
    char backing_filename2[1024];
    BlockDriverInfo bdi;

    bdrv_init();

    fmt = NULL;
    for(;;) {
        c = getopt(argc, argv, "f:h");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
           // help();
            break;
        case 'f':
            fmt = optarg;
            break;
        }
    }
    if (optind >= argc)
        help();
    filename = argv[optind++];

    bs = bdrv_new("");
    if (!bs)
        error("Not enough memory");
    if (fmt) {
        drv = bdrv_find_format(fmt);
        if (!drv)
            error("Unknown file format '%s'", fmt);
    } else {
        drv = NULL;
    }
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
        error("Could not open '%s'", filename);
    }
    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
    bdrv_get_geometry(bs, &total_sectors);
    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
    allocated_size = get_allocated_file_size(filename);
    if (allocated_size < 0)
        sprintf(dsize_buf, "unavailable");
    else
        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
                                allocated_size);
    /*
    if (bdrv_is_encrypted(bs))
        fprintf(stderr, "encrypted: yes\n");
    if (bdrv_get_info(bs, &bdi) >= 0) {
        if (bdi.cluster_size != 0)
            fprintf(stderr, "cluster_size: %d\n", bdi.cluster_size);
    }
    */
    bdrv_get_info(bs, &bdi);
    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
    if (backing_filename[0] != '\0') {
        path_combine(backing_filename2, sizeof(backing_filename2),
                     filename, backing_filename);
        /*
        fprintf(stderr, "backing file: %s (actual path: %s)\n",
               backing_filename,
               backing_filename2);
        */
    }
    fprintf(stdout, "{'filename' : '%s',"
            " 'format' : '%s',"
            " 'image_disk_size' : '%s',"
            " 'allocated_size' : '%s',"
            " 'total_sectors' : '%"PRId64"',"
            " 'backing_file' : '%s',}",
           filename, fmt_name, size_buf, dsize_buf, total_sectors, 
           backing_filename);
    dump_snapshots(bs);
    bdrv_delete(bs);
    return 0;
}
Beispiel #12
0
static int img_convert(int argc, char **argv)
{
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
    BlockDriver *drv;
    BlockDriverState **bs, *out_bs;
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
    uint64_t bs_sectors;
    uint8_t buf[IO_BUF_SIZE];
    const uint8_t *buf1;
    BlockDriverInfo bdi;

    fmt = NULL;
    out_fmt = "raw";
    out_baseimg = NULL;
    flags = 0;
    for(;;) {
        c = getopt(argc, argv, "f:O:B:hce6");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
            help();
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'O':
            out_fmt = optarg;
            break;
        case 'B':
            out_baseimg = optarg;
            break;
        case 'c':
            flags |= BLOCK_FLAG_COMPRESS;
            break;
        case 'e':
            flags |= BLOCK_FLAG_ENCRYPT;
            break;
        case '6':
            flags |= BLOCK_FLAG_COMPAT6;
            break;
        }
    }

    bs_n = argc - optind - 1;
    if (bs_n < 1) help();

    out_filename = argv[argc - 1];

    if (bs_n > 1 && out_baseimg)
        error("-B makes no sense when concatenating multiple input images");
        
    bs = calloc(bs_n, sizeof(BlockDriverState *));
    if (!bs)
        error("Out of memory");

    total_sectors = 0;
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt,
					BDRV_O_CACHE_WB|BDRV_O_RDONLY);
        if (!bs[bs_i])
            error("Could not open '%s'", argv[optind + bs_i]);
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
        total_sectors += bs_sectors;
    }

    drv = bdrv_find_format(out_fmt);
    if (!drv)
        error("Unknown file format '%s'", out_fmt);
    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
        error("Compression not supported for this file format");
    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
        error("Encryption not supported for this file format");
    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
        error("Alternative compatibility level not supported for this file format");
    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
        error("Compression and encryption not supported at the same time");

    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error("Formatting not supported for file format '%s'", fmt);
        } else {
            error("Error while formatting '%s'", out_filename);
        }
    }

    out_bs = bdrv_new_open(out_filename, out_fmt, BDRV_O_CACHE_WB|BDRV_O_RDWR);

    bs_i = 0;
    bs_offset = 0;
    bdrv_get_geometry(bs[0], &bs_sectors);

    if (flags & BLOCK_FLAG_COMPRESS) {
        if (bdrv_get_info(out_bs, &bdi) < 0)
            error("could not get block driver info");
        cluster_size = bdi.cluster_size;
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
            error("invalid cluster size");
        cluster_sectors = cluster_size >> 9;
        sector_num = 0;
        for(;;) {
            int64_t bs_num;
            int remainder;
            uint8_t *buf2;

            nb_sectors = total_sectors - sector_num;
            if (nb_sectors <= 0)
                break;
            if (nb_sectors >= cluster_sectors)
                n = cluster_sectors;
            else
                n = nb_sectors;

            bs_num = sector_num - bs_offset;
            assert (bs_num >= 0);
            remainder = n;
            buf2 = buf;
            while (remainder > 0) {
                int nlow;
                while (bs_num == bs_sectors) {
                    bs_i++;
                    assert (bs_i < bs_n);
                    bs_offset += bs_sectors;
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
                    bs_num = 0;
                    /* printf("changing part: sector_num=%lld, "
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
                       sector_num, bs_i, bs_offset, bs_sectors); */
                }
                assert (bs_num < bs_sectors);

                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;

                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
                    error("error while reading");

                buf2 += nlow * 512;
                bs_num += nlow;

                remainder -= nlow;
            }
            assert (remainder == 0);

            if (n < cluster_sectors)
                memset(buf + n * 512, 0, cluster_size - n * 512);
            if (is_not_zero(buf, cluster_size)) {
                if (bdrv_write_compressed(out_bs, sector_num, buf,
                                          cluster_sectors) != 0)
                    error("error while compressing sector %" PRId64,
                          sector_num);
            }
            sector_num += n;
        }
        /* signal EOF to align */
        bdrv_write_compressed(out_bs, 0, NULL, 0);
    } else {
Beispiel #13
0
static int img_create(int argc, char **argv)
{
    int c, ret, flags;
    const char *fmt = "raw";
    const char *filename;
    const char *base_filename = NULL;
    uint64_t size;
    const char *p;
    BlockDriver *drv;

    flags = 0;
    for(;;) {
        c = getopt(argc, argv, "b:f:he6");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
            help();
            break;
        case 'b':
            base_filename = optarg;
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'e':
            flags |= BLOCK_FLAG_ENCRYPT;
            break;
        case '6':
            flags |= BLOCK_FLAG_COMPAT6;
            break;
        }
    }
    if (optind >= argc)
        help();
    filename = argv[optind++];
    size = 0;
    if (base_filename) {
        BlockDriverState *bs;
        bs = bdrv_new_open(base_filename, NULL, BDRV_O_RDWR);
        bdrv_get_geometry(bs, &size);
        size *= 512;
        bdrv_delete(bs);
    } else {
        if (optind >= argc)
            help();
        p = argv[optind];
        size = strtoul(p, (char **)&p, 0);
        if (*p == 'M') {
            size *= 1024 * 1024;
        } else if (*p == 'G') {
            size *= 1024 * 1024 * 1024;
        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
            size *= 1024;
        } else {
            help();
        }
    }
    drv = bdrv_find_format(fmt);
    if (!drv)
        error("Unknown file format '%s'", fmt);
    printf("Formatting '%s', fmt=%s",
           filename, fmt);
    if (flags & BLOCK_FLAG_ENCRYPT)
        printf(", encrypted");
    if (flags & BLOCK_FLAG_COMPAT6)
        printf(", compatibility level=6");
    if (base_filename) {
        printf(", backing_file=%s",
               base_filename);
    }
    printf(", size=%" PRIu64 " kB\n", size / 1024);
    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error("Formatting or formatting option not supported for file format '%s'", fmt);
        } else {
            error("Error while formatting");
        }
    }
    return 0;
}
Beispiel #14
0
static int img_convert(int argc, char **argv)
{
    int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt;
    const char *filename, *fmt, *out_fmt, *out_filename;
    BlockDriver *drv;
    BlockDriverState *bs, *out_bs;
    int64_t total_sectors, nb_sectors, sector_num;
    uint8_t buf[IO_BUF_SIZE];
    const uint8_t *buf1;
    BlockDriverInfo bdi;

    fmt = NULL;
    out_fmt = "raw";
    compress = 0;
    encrypt = 0;
    for(;;) {
        c = getopt(argc, argv, "f:O:hce");
        if (c == -1)
            break;
        switch(c) {
        case 'h':
            help();
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'O':
            out_fmt = optarg;
            break;
        case 'c':
            compress = 1;
            break;
        case 'e':
            encrypt = 1;
            break;
        }
    }
    if (optind >= argc) 
        help();
    filename = argv[optind++];
    if (optind >= argc) 
        help();
    out_filename = argv[optind++];
    
    bs = bdrv_new_open(filename, fmt);

    drv = bdrv_find_format(out_fmt);
    if (!drv)
        error("Unknown file format '%s'", fmt);
    if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2)
        error("Compression not supported for this file format");
    if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2)
        error("Encryption not supported for this file format");
    if (compress && encrypt)
        error("Compression and encryption not supported at the same time");
    bdrv_get_geometry(bs, &total_sectors);
    ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt);
    if (ret < 0) {
        if (ret == -ENOTSUP) {
            error("Formatting not supported for file format '%s'", fmt);
        } else {
            error("Error while formatting '%s'", out_filename);
        }
    }
    
    out_bs = bdrv_new_open(out_filename, out_fmt);

    if (compress) {
        if (bdrv_get_info(out_bs, &bdi) < 0)
            error("could not get block driver info");
        cluster_size = bdi.cluster_size;
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
            error("invalid cluster size");
        cluster_sectors = cluster_size >> 9;
        sector_num = 0;
        for(;;) {
            nb_sectors = total_sectors - sector_num;
            if (nb_sectors <= 0)
                break;
            if (nb_sectors >= cluster_sectors)
                n = cluster_sectors;
            else
                n = nb_sectors;
            if (bdrv_read(bs, sector_num, buf, n) < 0) 
                error("error while reading");
            if (n < cluster_sectors)
                memset(buf + n * 512, 0, cluster_size - n * 512);
            if (is_not_zero(buf, cluster_size)) {
                if (bdrv_write_compressed(out_bs, sector_num, buf, 
                                          cluster_sectors) != 0)
                    error("error while compressing sector %" PRId64,
                          sector_num);
            }
            sector_num += n;
        }
        /* signal EOF to align */
        bdrv_write_compressed(out_bs, 0, NULL, 0);
    } else {