Пример #1
0
int main(int argc, char **argv)
{
    int readonly = 0;
    int growable = 0;
    const char *sopt = "hVc:d:rsnmgkt:T:";
    const struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "offset", 1, NULL, 'o' },
        { "cmd", 1, NULL, 'c' },
        { "read-only", 0, NULL, 'r' },
        { "snapshot", 0, NULL, 's' },
        { "nocache", 0, NULL, 'n' },
        { "misalign", 0, NULL, 'm' },
        { "growable", 0, NULL, 'g' },
        { "native-aio", 0, NULL, 'k' },
        { "discard", 1, NULL, 'd' },
        { "cache", 1, NULL, 't' },
        { "trace", 1, NULL, 'T' },
        { NULL, 0, NULL, 0 }
    };
    int c;
    int opt_index = 0;
    int flags = BDRV_O_UNMAP;

    progname = basename(argv[0]);

    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
        switch (c) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
            break;
        case 'd':
            if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
                error_report("Invalid discard option: %s", optarg);
                exit(1);
            }
            break;
        case 'c':
            add_user_command(optarg);
            break;
        case 'r':
            readonly = 1;
            break;
        case 'm':
            misalign = 1;
            break;
        case 'g':
            growable = 1;
            break;
        case 'k':
            flags |= BDRV_O_NATIVE_AIO;
            break;
        case 't':
            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
                error_report("Invalid cache option: %s", optarg);
                exit(1);
            }
            break;
        case 'T':
            if (!trace_backend_init(optarg, NULL)) {
                exit(1); /* error message will have been printed */
            }
            break;
        case 'V':
            printf("%s version %s\n", progname, VERSION);
            exit(0);
        case 'h':
            usage(progname);
            exit(0);
        default:
            usage(progname);
            exit(1);
        }
    }

    if ((argc - optind) > 1) {
        usage(progname);
        exit(1);
    }

    qemu_init_main_loop();
    bdrv_init();

    /* initialize commands */
    quit_init();
    help_init();
    add_command(&open_cmd);
    add_command(&close_cmd);
    add_command(&read_cmd);
    add_command(&readv_cmd);
    add_command(&write_cmd);
    add_command(&writev_cmd);
    add_command(&multiwrite_cmd);
    add_command(&aio_read_cmd);
    add_command(&aio_write_cmd);
    add_command(&aio_flush_cmd);
    add_command(&flush_cmd);
    add_command(&truncate_cmd);
    add_command(&length_cmd);
    add_command(&info_cmd);
    add_command(&discard_cmd);
    add_command(&alloc_cmd);
    add_command(&map_cmd);
    add_command(&break_cmd);
    add_command(&resume_cmd);
    add_command(&wait_break_cmd);
    add_command(&abort_cmd);

    add_args_command(init_args_command);
    add_check_command(init_check_command);

    /* open the device */
    if (!readonly) {
        flags |= BDRV_O_RDWR;
    }

    if ((argc - optind) == 1) {
        openfile(argv[optind], flags, growable);
    }
    command_loop();

    /*
     * Make sure all outstanding requests complete before the program exits.
     */
    bdrv_drain_all();

    if (bs) {
        bdrv_delete(bs);
    }
    return 0;
}
Пример #2
0
int main(int argc, char **argv)
{
    BlockBackend *blk;
    BlockDriverState *bs;
    off_t dev_offset = 0;
    uint32_t nbdflags = 0;
    bool disconnect = false;
    const char *bindto = "0.0.0.0";
    const char *port = NULL;
    char *sockpath = NULL;
    char *device = NULL;
    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 },
        { "aio", 1, NULL, QEMU_NBD_OPT_AIO },
        { "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;
    char *end;
    int flags = BDRV_O_RDWR;
    int partition = -1;
    int ret = 0;
    int fd;
    bool seen_cache = false;
    bool seen_discard = false;
    bool seen_aio = false;
    pthread_t client_thread;
    const char *fmt = NULL;
    Error *local_err = NULL;
    BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
    QDict *options = NULL;

    /* 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;
        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;
        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':
            port = optarg;
            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_noisily(&internal_snapshot_opts,
                                                  optarg, false);
                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) {
            err(EXIT_FAILURE, "Failed to fork");
        } else 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));
    }

    saddr = nbd_build_socket_address(sockpath, bindto, port);

    if (qemu_init_main_loop(&local_err)) {
        error_report_err(local_err);
        exit(EXIT_FAILURE);
    }
    bdrv_init();
    atexit(bdrv_close_all);

    if (fmt) {
        options = qdict_new();
        qdict_put(options, "driver", qstring_from_str(fmt));
    }

    srcpath = argv[optind];
    blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
    if (!blk) {
        errx(EXIT_FAILURE, "Failed to blk_new_open '%s': %s", argv[optind],
             error_get_pretty(local_err));
    }
    bs = blk_bs(blk);

    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 (fd_size < 0) {
        errx(EXIT_FAILURE, "Failed to determine the image length: %s",
             strerror(-fd_size));
    }

    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,
                         &local_err);
    if (!exp) {
        errx(EXIT_FAILURE, "%s", error_get_pretty(local_err));
    }

    fd = socket_listen(saddr, &local_err);
    if (fd < 0) {
        error_report_err(local_err);
        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));
    }

    server_fd = fd;
    nbd_update_server_fd_handler(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);
    }
}
Пример #3
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, flags;
    const char *fmt, *out_fmt, *cache, *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;
    int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */

    fmt = NULL;
    out_fmt = "raw";
    cache = "unsafe";
    out_baseimg = NULL;
    compress = 0;
    for(;;) {
        c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
        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("option -e is deprecated, please use \'-o "
                  "encryption\' instead!");
            return 1;
        case '6':
            error_report("option -6 is deprecated, please use \'-o "
                  "compat6\' instead!");
            return 1;
        case 'o':
            options = optarg;
            break;
        case 's':
            snapshot_name = optarg;
            break;
        case 'S':
        {
            int64_t sval;
            char *end;
            sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
            if (sval < 0 || *end) {
                error_report("Invalid minimum zero buffer size for sparse output specified");
                return 1;
            }

            min_sparse = sval / BDRV_SECTOR_SIZE;
            break;
        }
        case 'p':
            progress = 1;
            break;
        case 't':
            cache = optarg;
            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 = g_malloc0(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");
            ret = -1;
            goto out;
        }
        if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
            error_report("Failed to load snapshot");
            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);
        QEMUOptionParameter *preallocation =
            get_option_parameter(param, BLOCK_OPT_PREALLOC);

        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;
        }

        if (preallocation && preallocation->value.s
            && strcmp(preallocation->value.s, "off"))
        {
            error_report("Compression and preallocation 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;
    }

    flags = BDRV_O_RDWR;
    ret = bdrv_parse_cache_flags(cache, &flags);
    if (ret < 0) {
        error_report("Invalid cache option: %s", cache);
        return -1;
    }

    out_bs = bdrv_new_open(out_filename, out_fmt, flags);
    if (!out_bs) {
        ret = -1;
        goto out;
    }

    bs_i = 0;
    bs_offset = 0;
    bdrv_get_geometry(bs[0], &bs_sectors);
    buf = qemu_blockalign(out_bs, 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 sector %" PRId64 ": %s",
                                 bs_num, strerror(-ret));
                    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 (!buffer_is_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
                                 ": %s", sector_num, strerror(-ret));
                    goto out;
                }
            }
            sector_num += n;
            qemu_progress_print(local_progress, 100);
        }
        /* signal EOF to align */
        bdrv_write_compressed(out_bs, 0, NULL, 0);
    } else {
Пример #4
0
int main(int argc, char **argv)
{
    int readonly = 0;
    int growable = 0;
    const char *sopt = "hVc:d:rsnmgkt:T:";
    const struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "offset", 1, NULL, 'o' },
        { "cmd", 1, NULL, 'c' },
        { "read-only", 0, NULL, 'r' },
        { "snapshot", 0, NULL, 's' },
        { "nocache", 0, NULL, 'n' },
        { "misalign", 0, NULL, 'm' },
        { "growable", 0, NULL, 'g' },
        { "native-aio", 0, NULL, 'k' },
        { "discard", 1, NULL, 'd' },
        { "cache", 1, NULL, 't' },
        { "trace", 1, NULL, 'T' },
        { NULL, 0, NULL, 0 }
    };
    int c;
    int opt_index = 0;
    int flags = BDRV_O_UNMAP;

#ifdef CONFIG_POSIX
    signal(SIGPIPE, SIG_IGN);
#endif

    progname = basename(argv[0]);

    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
        switch (c) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
            break;
        case 'd':
            if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
                error_report("Invalid discard option: %s", optarg);
                exit(1);
            }
            break;
        case 'c':
            add_user_command(optarg);
            break;
        case 'r':
            readonly = 1;
            break;
        case 'm':
            qemuio_misalign = 1;
            break;
        case 'g':
            growable = 1;
            break;
        case 'k':
            flags |= BDRV_O_NATIVE_AIO;
            break;
        case 't':
            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
                error_report("Invalid cache option: %s", optarg);
                exit(1);
            }
            break;
        case 'T':
            if (!trace_backend_init(optarg, NULL)) {
                exit(1); /* error message will have been printed */
            }
            break;
        case 'V':
            printf("%s version %s\n", progname, QEMU_VERSION);
            exit(0);
        case 'h':
            usage(progname);
            exit(0);
        default:
            usage(progname);
            exit(1);
        }
    }

    if ((argc - optind) > 1) {
        usage(progname);
        exit(1);
    }

    qemu_init_main_loop();
    bdrv_init();

    /* initialize commands */
    qemuio_add_command(&quit_cmd);
    qemuio_add_command(&open_cmd);
    qemuio_add_command(&close_cmd);

    if (isatty(STDIN_FILENO)) {
        readline_state = readline_init(readline_printf_func,
                                       readline_flush_func,
                                       NULL,
                                       readline_completion_func);
        qemu_set_tty_echo(STDIN_FILENO, false);
        atexit(reenable_tty_echo);
    }

    /* open the device */
    if (!readonly) {
        flags |= BDRV_O_RDWR;
    }

    if ((argc - optind) == 1) {
        openfile(argv[optind], flags, growable, NULL);
    }
    command_loop();

    /*
     * Make sure all outstanding requests complete before the program exits.
     */
    bdrv_drain_all();

    if (qemuio_bs) {
        bdrv_unref(qemuio_bs);
    }
    g_free(readline_state);
    return 0;
}
Пример #5
0
static int img_commit(int argc, char **argv)
{
    int c, ret, flags;
    const char *filename, *fmt, *cache;
    BlockDriverState *bs;

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

    flags = BDRV_O_RDWR;
    ret = bdrv_parse_cache_flags(cache, &flags);
    if (ret < 0) {
        error_report("Invalid cache option: %s", cache);
        return -1;
    }

    bs = bdrv_new_open(filename, fmt, flags);
    if (!bs) {
        return 1;
    }
    ret = bdrv_commit(bs);
    switch(ret) {
    case 0:
        printf("Image committed.\n");
        break;
    case -ENOENT:
        error_report("No disk inserted");
        break;
    case -EACCES:
        error_report("Image is read-only");
        break;
    case -ENOTSUP:
        error_report("Image is already committed");
        break;
    default:
        error_report("Error while committing image");
        break;
    }

    bdrv_delete(bs);
    if (ret) {
        return 1;
    }
    return 0;
}