Beispiel #1
0
static void test_groups(void)
{
    ThrottleConfig cfg1, cfg2;
    BlockDriverState *bdrv1, *bdrv2, *bdrv3;

    bdrv1 = bdrv_new();
    bdrv2 = bdrv_new();
    bdrv3 = bdrv_new();

    g_assert(bdrv1->throttle_state == NULL);
    g_assert(bdrv2->throttle_state == NULL);
    g_assert(bdrv3->throttle_state == NULL);

    throttle_group_register_bs(bdrv1, "bar");
    throttle_group_register_bs(bdrv2, "foo");
    throttle_group_register_bs(bdrv3, "bar");

    g_assert(bdrv1->throttle_state != NULL);
    g_assert(bdrv2->throttle_state != NULL);
    g_assert(bdrv3->throttle_state != NULL);

    g_assert(!strcmp(throttle_group_get_name(bdrv1), "bar"));
    g_assert(!strcmp(throttle_group_get_name(bdrv2), "foo"));
    g_assert(bdrv1->throttle_state == bdrv3->throttle_state);

    /* Setting the config of a group member affects the whole group */
    memset(&cfg1, 0, sizeof(cfg1));
    cfg1.buckets[THROTTLE_BPS_READ].avg  = 500000;
    cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
    cfg1.buckets[THROTTLE_OPS_READ].avg  = 20000;
    cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
    throttle_group_config(bdrv1, &cfg1);

    throttle_group_get_config(bdrv1, &cfg1);
    throttle_group_get_config(bdrv3, &cfg2);
    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));

    cfg2.buckets[THROTTLE_BPS_READ].avg  = 4547;
    cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
    cfg2.buckets[THROTTLE_OPS_READ].avg  = 123;
    cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
    throttle_group_config(bdrv3, &cfg1);

    throttle_group_get_config(bdrv1, &cfg1);
    throttle_group_get_config(bdrv3, &cfg2);
    g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));

    throttle_group_unregister_bs(bdrv1);
    throttle_group_unregister_bs(bdrv2);
    throttle_group_unregister_bs(bdrv3);

    g_assert(bdrv1->throttle_state == NULL);
    g_assert(bdrv2->throttle_state == NULL);
    g_assert(bdrv3->throttle_state == NULL);
}
Beispiel #2
0
static int img_commit(int argc, char **argv)
{
    int c, ret;
    const char *filename, *fmt;
    BlockDriver *drv;
    BlockDriverState *bs;

    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, BRDV_O_FLAGS, drv) < 0) {
        error("Could not open '%s'", filename);
    }
    ret = bdrv_commit(bs);
    switch(ret) {
    case 0:
        printf("Image committed.\n");
        break;
    case -ENOENT:
        error("No disk inserted");
        break;
    case -EACCES:
        error("Image is read-only");
        break;
    case -ENOTSUP:
        error("Image is already committed");
        break;
    default:
        error("Error while committing image");
        break;
    }

    bdrv_delete(bs);
    return 0;
}
Beispiel #3
0
static int openfile(char *name, int flags, int growable, QDict *opts)
{
    Error *local_err = NULL;

    if (qemuio_bs) {
        fprintf(stderr, "file open already, try 'help close'\n");
        return 1;
    }

    if (growable) {
        if (bdrv_file_open(&qemuio_bs, name, NULL, opts, flags, &local_err)) {
            fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
                    error_get_pretty(local_err));
            error_free(local_err);
            return 1;
        }
    } else {
        qemuio_bs = bdrv_new("hda");

        if (bdrv_open(qemuio_bs, name, opts, flags, NULL, &local_err) < 0) {
            fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
                    error_get_pretty(local_err));
            error_free(local_err);
            bdrv_unref(qemuio_bs);
            qemuio_bs = NULL;
            return 1;
        }
    }

    return 0;
}
Beispiel #4
0
USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs)
{
    MSDState *s;
    BlockDriverState *bdrv;
    BlockDriver *drv = NULL;
    const char *p1;
    char fmt[32];

    p1 = strchr(filename, ':');
    if (p1++) {
        const char *p2;

        if (strstart(filename, "format=", &p2)) {
            int len = MIN(p1 - p2, sizeof(fmt));
            pstrcpy(fmt, len, p2);

            drv = bdrv_find_format(fmt);
            if (!drv) {
                printf("invalid format %s\n", fmt);
                return NULL;
            }
        } else if (*filename != ':') {
            printf("unrecognized USB mass-storage option %s\n", filename);
            return NULL;
        }

        filename = p1;
    }

    if (!*filename) {
        printf("block device specification needed\n");
        return NULL;
    }

    s = qemu_mallocz(sizeof(MSDState));

    bdrv = bdrv_new("usb");
    if (bdrv_open2(bdrv, filename, 0, drv) < 0)
        goto fail;
    s->bs = bdrv;
    *pbs = bdrv;

    s->dev.speed = USB_SPEED_FULL;
    s->dev.handle_packet = usb_generic_handle_packet;

    s->dev.handle_reset = usb_msd_handle_reset;
    s->dev.handle_control = usb_msd_handle_control;
    s->dev.handle_data = usb_msd_handle_data;
    s->dev.handle_destroy = usb_msd_handle_destroy;

    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
             filename);

    s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
    usb_msd_handle_reset((USBDevice *)s);
    return (USBDevice *)s;
 fail:
    qemu_free(s);
    return NULL;
}
static int openfile(char *name, int flags, int growable)
{
	if (bs) {
		fprintf(stderr, "file open already, try 'help close'\n");
		return 1;
	}

	bs = bdrv_new("hda");
	if (!bs)
		return 1;

	if (growable) {
		flags |= BDRV_O_FILE;
	}

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

	if (growable) {
		bs->growable = 1;
	}
	return 0;
}
Beispiel #6
0
USBDevice *usb_msd_init(const char *filename)
{
    MSDState *s;
    BlockDriverState *bdrv;

    s = qemu_mallocz(sizeof(MSDState));
    if (!s)
        return NULL;

    bdrv = bdrv_new("usb");
    if (bdrv_open(bdrv, filename, 0) < 0)
        goto fail;
    if (qemu_key_check(bdrv, filename))
        goto fail;
    s->bs = bdrv;

    s->dev.speed = USB_SPEED_FULL;
    s->dev.handle_packet = usb_generic_handle_packet;

    s->dev.handle_reset = usb_msd_handle_reset;
    s->dev.handle_control = usb_msd_handle_control;
    s->dev.handle_data = usb_msd_handle_data;
    s->dev.handle_destroy = usb_msd_handle_destroy;

    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
             filename);

    s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
    usb_msd_handle_reset((USBDevice *)s);
    return (USBDevice *)s;
 fail:
    qemu_free(s);
    return NULL;
}
Beispiel #7
0
/* Create a block job that completes with a given return code after a given
 * number of event loop iterations.  The return code is stored in the given
 * result pointer.
 *
 * The event loop iterations can either be handled automatically with a 0 delay
 * timer, or they can be stepped manually by entering the coroutine.
 */
static BlockJob *test_block_job_start(unsigned int iterations,
                                      bool use_timer,
                                      int rc, int *result)
{
    BlockDriverState *bs;
    TestBlockJob *s;
    TestBlockJobCBData *data;
    static unsigned counter;
    char job_id[24];

    data = g_new0(TestBlockJobCBData, 1);
    bs = bdrv_new();
    snprintf(job_id, sizeof(job_id), "job%u", counter++);
    s = block_job_create(job_id, &test_block_job_driver, bs, 0,
                         BLOCK_JOB_DEFAULT, test_block_job_cb,
                         data, &error_abort);
    s->iterations = iterations;
    s->use_timer = use_timer;
    s->rc = rc;
    s->result = result;
    s->common.co = qemu_coroutine_create(test_block_job_run, s);
    data->job = s;
    data->result = result;
    qemu_coroutine_enter(s->common.co);
    return &s->common;
}
Beispiel #8
0
static BlockDriverState *bdrv_new_open(const char *filename,
                                       const char *fmt,
                                       int flags)
{
    BlockDriverState *bs;
    BlockDriver *drv;
    char password[256];

    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_open(bs, filename, flags, drv) < 0) {
        error("Could not open '%s'", filename);
    }
    if (bdrv_is_encrypted(bs)) {
        printf("Disk image '%s' is encrypted.\n", filename);
        if (read_password(password, sizeof(password)) < 0)
            error("No password given");
        if (bdrv_set_key(bs, password) < 0)
            error("invalid password");
    }
    return bs;
}
Beispiel #9
0
static int openfile(char *name, int flags, int growable)
{
    if (bs) {
        fprintf(stderr, "file open already, try 'help close'\n");
        return 1;
    }

    if (growable) {
        if (bdrv_file_open(&bs, name, NULL, flags)) {
            fprintf(stderr, "%s: can't open device %s\n", progname, name);
            return 1;
        }
    } else {
        bs = bdrv_new("hda");

        if (bdrv_open(bs, name, NULL, flags, NULL) < 0) {
            fprintf(stderr, "%s: can't open device %s\n", progname, name);
            bdrv_delete(bs);
            bs = NULL;
            return 1;
        }
    }

    return 0;
}
Beispiel #10
0
static int img_check(int argc, char **argv)
{
    int c, ret;
    const char *filename, *fmt;
    BlockDriver *drv;
    BlockDriverState *bs;

    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, BRDV_O_FLAGS, drv) < 0) {
        error("Could not open '%s'", filename);
    }
    ret = bdrv_check(bs);
    switch(ret) {
    case 0:
        printf("No errors were found on the image.\n");
        break;
    case -ENOTSUP:
        error("This image format does not support checks");
        break;
    default:
        if (ret < 0) {
            error("An error occurred during the check");
        } else {
            printf("%d errors were found on the image.\n", ret);
        }
        break;
    }

    bdrv_delete(bs);
    return 0;
}
Beispiel #11
0
static int blkverify_open(BlockDriverState *bs, QDict *options, int flags)
{
    BDRVBlkverifyState *s = bs->opaque;
    QemuOpts *opts;
    Error *local_err = NULL;
    const char *filename, *raw;
    int ret;

    opts = qemu_opts_create_nofail(&runtime_opts);
    qemu_opts_absorb_qdict(opts, options, &local_err);
    if (error_is_set(&local_err)) {
        qerror_report_err(local_err);
        error_free(local_err);
        ret = -EINVAL;
        goto fail;
    }

    /* Parse the raw image filename */
    raw = qemu_opt_get(opts, "x-raw");
    if (raw == NULL) {
        ret = -EINVAL;
        goto fail;
    }

    ret = bdrv_file_open(&bs->file, raw, NULL, flags);
    if (ret < 0) {
        goto fail;
    }

    /* Open the test file */
    filename = qemu_opt_get(opts, "x-image");
    if (filename == NULL) {
        ret = -EINVAL;
        goto fail;
    }

    s->test_file = bdrv_new("");
    ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
    if (ret < 0) {
        bdrv_unref(s->test_file);
        s->test_file = NULL;
        goto fail;
    }

    ret = 0;
fail:
    return ret;
}
Beispiel #12
0
static int disk_img_info(const char *filename)
{
    BlockDriver *drv;
    BlockDriverState *bs;

    bs = bdrv_new("");
    if (!bs)
        FDBG("Not enough memory");
    drv = NULL;
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
        FDBG("Could not open '%s'", filename);
    }
    bdrv_get_format(bs, disk_img_data.img_format, (sizeof(char) * 128));
    bdrv_delete(bs);
    return 0;
}
Beispiel #13
0
static BlockDriverState *bdrv_new_open(const char *filename,
                                       const char *fmt,
                                       int flags)
{
    BlockDriverState *bs;
    BlockDriver *drv;
    char password[256];
    int ret;

    bs = bdrv_new("image");

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

    ret = bdrv_open(bs, filename, flags, drv);
    if (ret < 0) {
        error_report("Could not open '%s': %s", filename, strerror(-ret));
        goto fail;
    }

    if (bdrv_is_encrypted(bs)) {
        printf("Disk image '%s' is encrypted.\n", filename);
        if (read_password(password, sizeof(password)) < 0) {
            error_report("No password given");
            goto fail;
        }
        if (bdrv_set_key(bs, password) < 0) {
            error_report("invalid password");
            goto fail;
        }
    }
    return bs;
fail:
    if (bs) {
        bdrv_delete(bs);
    }
    return NULL;
}
Beispiel #14
0
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;
}
/* Create a block job that completes with a given return code after a given
 * number of event loop iterations.  The return code is stored in the given
 * result pointer.
 *
 * The event loop iterations can either be handled automatically with a 0 delay
 * timer, or they can be stepped manually by entering the coroutine.
 */
static BlockJob *test_block_job_start(unsigned int iterations,
                                      bool use_timer,
                                      int rc, int *result)
{
    BlockDriverState *bs;
    TestBlockJob *s;
    TestBlockJobCBData *data;

    data = g_new0(TestBlockJobCBData, 1);
    bs = bdrv_new();
    s = block_job_create(&test_block_job_driver, bs, 0, test_block_job_cb,
                         data, &error_abort);
    s->iterations = iterations;
    s->use_timer = use_timer;
    s->rc = rc;
    s->result = result;
    s->common.co = qemu_coroutine_create(test_block_job_run);
    data->job = s;
    data->result = result;
    qemu_coroutine_enter(s->common.co, s);
    return &s->common;
}
Beispiel #16
0
/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
{
    BDRVBlkverifyState *s = bs->opaque;
    int ret;
    char *raw, *c;

    /* Parse the blkverify: prefix */
    if (strncmp(filename, "blkverify:", strlen("blkverify:"))) {
        return -EINVAL;
    }
    filename += strlen("blkverify:");

    /* Parse the raw image filename */
    c = strchr(filename, ':');
    if (c == NULL) {
        return -EINVAL;
    }

    raw = g_strdup(filename);
    raw[c - filename] = '\0';
    ret = bdrv_file_open(&bs->file, raw, flags);
    g_free(raw);
    if (ret < 0) {
        return ret;
    }
    filename = c + 1;

    /* Open the test file */
    s->test_file = bdrv_new("");
    ret = bdrv_open(s->test_file, filename, flags, NULL);
    if (ret < 0) {
        bdrv_delete(s->test_file);
        s->test_file = NULL;
        return ret;
    }

    return 0;
}
Beispiel #17
0
static int open_disk(struct td_state *s, char *path, int readonly)
{
	BlockDriverState* bs;
	char* devname;
	static int devnumber = 0;
	int i;

	DPRINTF("Opening %s as blktap%d\n", path, devnumber);
	asprintf(&devname, "blktap%d", devnumber++);
	bs = bdrv_new(devname);
	free(devname);

	if (bdrv_open(bs, path, 0) != 0) {
		fprintf(stderr, "Could not open image file %s\n", path);
		return -ENOMEM;
	}

	s->bs = bs;
	s->flags = readonly ? TD_RDONLY : 0;
	s->size = bs->total_sectors;
	s->sector_size = 512;

	s->info = ((s->flags & TD_RDONLY) ? VDISK_READONLY : 0);

#ifndef QEMU_TOOL
	for (i = 0; i < MAX_DRIVES + 1; i++) {
		if (drives_table[i].bdrv == NULL) {
			drives_table[i].bdrv = bs;
			drives_table[i].type = IF_BLKTAP;
			drives_table[i].bus = 0;
			drives_table[i].unit = 0;
			break;
		}
	}
#endif

	return 0;
}
Beispiel #18
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 #19
0
int main(int argc, char **argv)
{
    BlockDriverState *bs;
    off_t dev_offset = 0;
    off_t offset = 0;
    uint32_t nbdflags = 0;
    bool disconnect = false;
    const char *bindto = "0.0.0.0";
    int port = NBD_DEFAULT_PORT;
    struct sockaddr_in addr;
    socklen_t addr_len = sizeof(addr);
    off_t fd_size;
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
    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' },
        { "nocache", 0, NULL, 'n' },
        { "shared", 1, NULL, 'e' },
        { "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 shared = 1;
    uint8_t *data;
    fd_set fds;
    int *sharing_fds;
    int fd;
    int i;
    int nb_fds = 0;
    int max_fd;
    int persistent = 0;
    pthread_t client_thread;

    /* 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;
    int sigterm_fd[2];
    if (qemu_pipe(sigterm_fd) == -1) {
        err(EXIT_FAILURE, "Error setting up communication pipe");
    }

    sigterm_wfd = sigterm_fd[1];
    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
    sa_sigterm.sa_handler = termsig_handler;
    sigaction(SIGTERM, &sa_sigterm, NULL);

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
            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 '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 '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 == -1)
            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) == -1) {
            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(0, 0);

            /* Temporarily redirect stderr to the parent's pipe...  */
            dup2(stderr_fd[1], STDERR_FILENO);
            if (ret == -1) {
                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 == -1) {
                    exit(EXIT_FAILURE);
                }
            }
            if (ret == -1) {
                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) {
        /* Open before spawning new threads.  In the future, we may
         * drop privileges after opening.
         */
        fd = open(device, O_RDWR);
        if (fd == -1) {
            err(EXIT_FAILURE, "Failed to open %s", device);
        }

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

    bdrv_init();
    atexit(bdrv_close_all);

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

    fd_size = bs->total_sectors * 512;

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

    sharing_fds = g_malloc((shared + 1) * sizeof(int));

    if (sockpath) {
        sharing_fds[0] = unix_socket_incoming(sockpath);
    } else {
        sharing_fds[0] = tcp_socket_incoming(bindto, port);
    }

    if (sharing_fds[0] == -1)
        return 1;

    if (device) {
        int ret;

        ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
        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));
    }

    max_fd = sharing_fds[0];
    nb_fds++;

    data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
    if (data == NULL) {
        errx(EXIT_FAILURE, "Cannot allocate data buffer");
    }

    do {
        FD_ZERO(&fds);
        FD_SET(sigterm_fd[0], &fds);
        for (i = 0; i < nb_fds; i++)
            FD_SET(sharing_fds[i], &fds);

        do {
            ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
        } while (ret == -1 && errno == EINTR);
        if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) {
            break;
        }

        if (FD_ISSET(sharing_fds[0], &fds))
            ret--;
        for (i = 1; i < nb_fds && ret; i++) {
            if (FD_ISSET(sharing_fds[i], &fds)) {
                if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
                    &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) {
                    close(sharing_fds[i]);
                    nb_fds--;
                    sharing_fds[i] = sharing_fds[nb_fds];
                    i--;
                }
                ret--;
            }
        }
        /* new connection ? */
        if (FD_ISSET(sharing_fds[0], &fds)) {
            if (nb_fds < shared + 1) {
                sharing_fds[nb_fds] = accept(sharing_fds[0],
                                             (struct sockaddr *)&addr,
                                             &addr_len);
                if (sharing_fds[nb_fds] != -1 &&
                    nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) {
                        if (sharing_fds[nb_fds] > max_fd)
                            max_fd = sharing_fds[nb_fds];
                        nb_fds++;
                }
            }
        }
    } while (persistent || nb_fds > 1);
    qemu_vfree(data);

    close(sharing_fds[0]);
    g_free(sharing_fds);
    if (sockpath) {
        unlink(sockpath);
    }

    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
}
Beispiel #20
0
static int blk_init(struct XenDevice *xendev)
{
    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
    int index, qflags, have_barriers, info = 0;
    char *h;

    /* read xenstore entries */
    if (blkdev->params == NULL) {
	blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
        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 (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 ? */
    if (strcmp(blkdev->mode, "w") == 0) {
	qflags = BDRV_O_RDWR;
    } else {
	qflags = 0;
	info  |= VDISK_READONLY;
    }

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

    /* init qemu block driver */
    index = (blkdev->xendev.dev - 202 * 256) / 16;
    blkdev->dinfo = drive_get(IF_XEN, 0, index);
    if (!blkdev->dinfo) {
        /* 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 (bdrv_open(blkdev->bs, blkdev->filename, qflags,
                      bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
            bdrv_delete(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 = blkdev->dinfo->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 #21
0
int main(int argc, char **argv)
{
    BlockDriverState *bs;
    off_t dev_offset = 0;
    off_t offset = 0;
    bool readonly = false;
    bool disconnect = false;
    const char *bindto = "0.0.0.0";
    int port = NBD_DEFAULT_PORT;
    struct sockaddr_in addr;
    socklen_t addr_len = sizeof(addr);
    off_t fd_size;
    char *device = NULL;
    char *socket = NULL;
    char sockpath[128];
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
    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' },
        { "nocache", 0, NULL, 'n' },
        { "shared", 1, NULL, 'e' },
        { "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 shared = 1;
    uint8_t *data;
    fd_set fds;
    int *sharing_fds;
    int fd;
    int i;
    int nb_fds = 0;
    int max_fd;
    int persistent = 0;
    uint32_t nbdflags;

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE;
            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 'r':
            readonly = true;
            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':
            socket = optarg;
            if (socket[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 '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 == -1)
            err(EXIT_FAILURE, "Cannot open %s", argv[optind]);

        nbd_disconnect(fd);

        close(fd);

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

	return 0;
    }

    bdrv_init();

    bs = bdrv_new("hda");
    if (bs == NULL)
        return 1;

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

    fd_size = bs->total_sectors * 512;

    if (partition != -1 &&
        find_partition(bs, partition, &dev_offset, &fd_size))
        err(EXIT_FAILURE, "Could not find partition %d", partition);

    if (device) {
        pid_t pid;
        int sock;

        /* want to fail before daemonizing */
        if (access(device, R_OK|W_OK) == -1) {
            err(EXIT_FAILURE, "Could not access '%s'", device);
        }

        if (!verbose) {
            /* detach client and server */
            if (daemon(0, 0) == -1) {
                err(EXIT_FAILURE, "Failed to daemonize");
            }
        }

        if (socket == NULL) {
            snprintf(sockpath, sizeof(sockpath), SOCKET_PATH,
                     basename(device));
            socket = sockpath;
        }

        pid = fork();
        if (pid < 0)
            return 1;
        if (pid != 0) {
            off_t size;
            size_t blocksize;

            ret = 0;
            bdrv_close(bs);

            do {
                sock = unix_socket_outgoing(socket);
                if (sock == -1) {
                    if (errno != ENOENT && errno != ECONNREFUSED) {
                        ret = 1;
                        goto out;
                    }
                    sleep(1);	/* wait children */
                }
            } while (sock == -1);

            fd = open(device, O_RDWR);
            if (fd == -1) {
                ret = 1;
                goto out;
            }

            ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
					&size, &blocksize);
            if (ret == -1) {
                ret = 1;
                goto out;
            }

            ret = nbd_init(fd, sock, size, blocksize);
            if (ret == -1) {
                ret = 1;
                goto out;
            }

            printf("NBD device %s is now connected to file %s\n",
                    device, argv[optind]);

	    /* update partition table */

            show_parts(device);

            ret = nbd_client(fd);
            if (ret) {
                ret = 1;
            }
            close(fd);
 out:
            kill(pid, SIGTERM);
            unlink(socket);

            return ret;
        }
        /* children */
    }

    sharing_fds = qemu_malloc((shared + 1) * sizeof(int));

    if (socket) {
        sharing_fds[0] = unix_socket_incoming(socket);
    } else {
        sharing_fds[0] = tcp_socket_incoming(bindto, port);
    }

    if (sharing_fds[0] == -1)
        return 1;
    max_fd = sharing_fds[0];
    nb_fds++;

    data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
    if (data == NULL)
        errx(EXIT_FAILURE, "Cannot allocate data buffer");

    do {

        FD_ZERO(&fds);
        for (i = 0; i < nb_fds; i++)
            FD_SET(sharing_fds[i], &fds);

        ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
        if (ret == -1)
            break;

        if (FD_ISSET(sharing_fds[0], &fds))
            ret--;
        for (i = 1; i < nb_fds && ret; i++) {
            if (FD_ISSET(sharing_fds[i], &fds)) {
                if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset,
                    &offset, readonly, data, NBD_BUFFER_SIZE) != 0) {
                    close(sharing_fds[i]);
                    nb_fds--;
                    sharing_fds[i] = sharing_fds[nb_fds];
                    i--;
                }
                ret--;
            }
        }
        /* new connection ? */
        if (FD_ISSET(sharing_fds[0], &fds)) {
            if (nb_fds < shared + 1) {
                sharing_fds[nb_fds] = accept(sharing_fds[0],
                                             (struct sockaddr *)&addr,
                                             &addr_len);
                if (sharing_fds[nb_fds] != -1 &&
                    nbd_negotiate(sharing_fds[nb_fds], fd_size) != -1) {
                        if (sharing_fds[nb_fds] > max_fd)
                            max_fd = sharing_fds[nb_fds];
                        nb_fds++;
                }
            }
        }
    } while (persistent || nb_fds > 1);
    qemu_vfree(data);

    close(sharing_fds[0]);
    bdrv_close(bs);
    qemu_free(sharing_fds);
    if (socket)
        unlink(socket);

    return 0;
}
Beispiel #22
0
void xenstore_parse_domain_config(int domid)
{
    char **e = NULL;
    char *buf = NULL, *path;
    char *fpath = NULL, *bpath = NULL,
        *dev = NULL, *params = NULL, *type = NULL, *drv = NULL;
    int i, is_scsi, is_hdN = 0;
    unsigned int len, num, hd_index;
    BlockDriverState *bs;

    for(i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++)
        media_filename[i] = NULL;

    xsh = xs_daemon_open();
    if (xsh == NULL) {
        fprintf(logfile, "Could not contact xenstore for domain config\n");
        return;
    }

    path = xs_get_domain_path(xsh, domid);
    if (path == NULL) {
        fprintf(logfile, "xs_get_domain_path() error\n");
        goto out;
    }

    if (pasprintf(&buf, "%s/device/vbd", path) == -1)
        goto out;

    e = xs_directory(xsh, XBT_NULL, buf, &num);
    if (e == NULL)
        goto out;

    for (i = 0; i < num; i++) {
        /* read the backend path */
        if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
            continue;
        free(bpath);
        bpath = xs_read(xsh, XBT_NULL, buf, &len);
        if (bpath == NULL)
            continue;
        /* read the name of the device */
        if (pasprintf(&buf, "%s/dev", bpath) == -1)
            continue;
        free(dev);
        dev = xs_read(xsh, XBT_NULL, buf, &len);
        if (dev == NULL)
            continue;
        if (!strncmp(dev, "hd", 2)) {
            is_hdN = 1;
            break;
        }
    }
        
    for (i = 0; i < num; i++) {
        /* read the backend path */
        if (pasprintf(&buf, "%s/device/vbd/%s/backend", path, e[i]) == -1)
            continue;
        free(bpath);
        bpath = xs_read(xsh, XBT_NULL, buf, &len);
        if (bpath == NULL)
            continue;
        /* read the name of the device */
        if (pasprintf(&buf, "%s/dev", bpath) == -1)
            continue;
        free(dev);
        dev = xs_read(xsh, XBT_NULL, buf, &len);
        if (dev == NULL)
            continue;
        /* Change xvdN to look like hdN */
        if (!is_hdN && !strncmp(dev, "xvd", 3)) {
            fprintf(logfile, "Change xvd%c to look like hd%c\n",
                    dev[3], dev[3]);
            memmove(dev, dev+1, strlen(dev));
            dev[0] = 'h';
            dev[1] = 'd';
        }
        is_scsi = !strncmp(dev, "sd", 2);
        if ((strncmp(dev, "hd", 2) && !is_scsi) || strlen(dev) != 3 )
            continue;
        hd_index = dev[2] - 'a';
        if (hd_index >= (is_scsi ? MAX_SCSI_DISKS : MAX_DISKS))
            continue;
        /* read the type of the device */
        if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1)
            continue;
        free(type);
        type = xs_read(xsh, XBT_NULL, buf, &len);
        if (pasprintf(&buf, "%s/params", bpath) == -1)
            continue;
        free(params);
        params = xs_read(xsh, XBT_NULL, buf, &len);
        if (params == NULL)
            continue;
        /* read the name of the device */
        if (pasprintf(&buf, "%s/type", bpath) == -1)
            continue;
        free(drv);
        drv = xs_read(xsh, XBT_NULL, buf, &len);
        if (drv == NULL)
            continue;
        /* Strip off blktap sub-type prefix aio: - QEMU can autodetect this */
        if (!strcmp(drv, "tap") && params[0]) {
            char *offset = strchr(params, ':'); 
            if (!offset)
                continue ;
            memmove(params, offset+1, strlen(offset+1)+1 );
            fprintf(logfile, "Strip off blktap sub-type prefix to %s\n", params); 
        }
        /* Prefix with /dev/ if needed */
        if (!strcmp(drv, "phy") && params[0] != '/') {
            char *newparams = malloc(5 + strlen(params) + 1);
            sprintf(newparams, "/dev/%s", params);
            free(params);
            params = newparams;
        }

        /* 
         * check if device has a phantom vbd; the phantom is hooked
         * to the frontend device (for ease of cleanup), so lookup 
         * the frontend device, and see if there is a phantom_vbd
         * if there is, we will use resolution as the filename
         */
        if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
            continue;
        free(fpath);
        fpath = xs_read(xsh, XBT_NULL, buf, &len);
        if (fpath) {
            if (pasprintf(&buf, "%s/dev", fpath) == -1)
                continue;
            free(params);
            params = xs_read(xsh, XBT_NULL, buf , &len);
            if (params) {
                /* 
                 * wait for device, on timeout silently fail because we will 
                 * fail to open below
                 */
                waitForDevice(params);
            }
        }

        bs = bs_table[hd_index + (is_scsi ? MAX_DISKS : 0)] = bdrv_new(dev);
        /* check if it is a cdrom */
        if (type && !strcmp(type, "cdrom")) {
            bdrv_set_type_hint(bs, BDRV_TYPE_CDROM);
            if (pasprintf(&buf, "%s/params", bpath) != -1)
                xs_watch(xsh, buf, dev);
        }

        /* open device now if media present */
        if (params[0]) {
            if (bdrv_open(bs, params, 0 /* snapshot */) < 0)
                fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
                        params);
        }
    }

    /* Set a watch for log-dirty requests from the migration tools */
    if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
                  domid) != -1) {
        xs_watch(xsh, buf, "logdirty");
        fprintf(logfile, "Watching %s\n", buf);
    }

    /* Set a watch for suspend requests from the migration tools */
    if (pasprintf(&buf, 
                  "/local/domain/0/device-model/%u/command", domid) != -1) {
        xs_watch(xsh, buf, "dm-command");
        fprintf(logfile, "Watching %s\n", buf);
    }

 out:
    free(type);
    free(params);
    free(dev);
    free(bpath);
    free(buf);
    free(path);
    free(e);
    free(drv);
    return;
}
Beispiel #23
0
void nand_add_dev(const char *arg)
{
    uint64_t dev_size = 0;
    const char *next_arg;
    const char *value;
    size_t arg_len, value_len;
    nand_dev *new_devs, *dev;
    char *devname = NULL;
    size_t devname_len = 0;
    char *initfilename = NULL;
    char *rwfilename = NULL;
    int initfd = -1;
    int rwfd = -1;
    int read_only = 0;
    int pad;
    ssize_t read_size;
    uint32_t page_size = 2048;
    uint32_t extra_size = 64;
    uint32_t erase_pages = 64;

    //VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg);

    while(arg) {
        next_arg = strchr(arg, ',');
        value = strchr(arg, '=');
        if(next_arg != NULL) {
            arg_len = next_arg - arg;
            next_arg++;
            if(value >= next_arg)
                value = NULL;
        }
        else
            arg_len = strlen(arg);
        if(value != NULL) {
            size_t new_arg_len = value - arg;
            value_len = arg_len - new_arg_len - 1;
            arg_len = new_arg_len;
            value++;
        }
        else
            value_len = 0;

        if(devname == NULL) {
            if(value != NULL)
                goto bad_arg_and_value;
            devname_len = arg_len;
            devname = malloc(arg_len+1);
            if(devname == NULL)
                goto out_of_memory;
            memcpy(devname, arg, arg_len);
            devname[arg_len] = 0;
        }
        else if(value == NULL) {
            if(arg_match("readonly", arg, arg_len)) {
                read_only = 1;
            }
            else {
                XLOG("bad arg: %.*s\n", arg_len, arg);
                exit(1);
            }
        }
        else {
            if(arg_match("size", arg, arg_len)) {
                char *ep;
                dev_size = strtoull(value, &ep, 0);
                D("Dev size 0x%X came from argument\n", dev_size);
                if(ep != value + value_len)
                    goto bad_arg_and_value;
            }
            else if(arg_match("pagesize", arg, arg_len)) {
                char *ep;
                page_size = strtoul(value, &ep, 0);
                if(ep != value + value_len)
                    goto bad_arg_and_value;
            }
            else if(arg_match("extrasize", arg, arg_len)) {
                char *ep;
                extra_size = strtoul(value, &ep, 0);
                if(ep != value + value_len)
                    goto bad_arg_and_value;
            }
            else if(arg_match("erasepages", arg, arg_len)) {
                char *ep;
                erase_pages = strtoul(value, &ep, 0);
                if(ep != value + value_len)
                    goto bad_arg_and_value;
            }
            else if(arg_match("initfile", arg, arg_len)) {
                initfilename = malloc(value_len + 1);
                if(initfilename == NULL)
                    goto out_of_memory;
                memcpy(initfilename, value, value_len);
                initfilename[value_len] = '\0';
            }
            else if(arg_match("file", arg, arg_len)) {
                rwfilename = malloc(value_len + 1);
                if(rwfilename == NULL)
                    goto out_of_memory;
                memcpy(rwfilename, value, value_len);
                rwfilename[value_len] = '\0';
            }
            else {
                goto bad_arg_and_value;
            }
        }

        arg = next_arg;
    }

    if (rwfilename == NULL) {
        /* we create a temporary file to store everything */
        TempFile*    tmp = tempfile_create();

        if (tmp == NULL) {
            XLOG("could not create temp file for %.*s NAND disk image: %s\n",
                 devname_len, devname, strerror(errno));
            exit(1);
        }
        rwfilename = (char*) tempfile_path(tmp);
        // if (VERBOSE_CHECK(init))
        //     dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
    }

    if(rwfilename) {
        rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
        if(rwfd < 0) {
            XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
            exit(1);
        }
        /* this could be a writable temporary file. use atexit_close_fd to ensure
         * that it is properly cleaned up at exit on Win32
         */
        if (!read_only)
            atexit_close_fd(rwfd);
    }

    if(initfilename) {
        uint64_t dev_bigger;
        initfd = open(initfilename, O_BINARY | O_RDONLY);
        if(initfd < 0) {
            XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
            exit(1);
        }
        //if(dev_size == 0) {
        D("calculating dev_size from lseek of %s\n", initfilename);
        dev_bigger = do_lseek(initfd, 0, SEEK_END);
        do_lseek(initfd, 0, SEEK_SET);
        if (dev_bigger > dev_size) {
            dev_size = dev_bigger;
        }
    }

    new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
    if(new_devs == NULL)
        goto out_of_memory;
    nand_devs = new_devs;
    dev = &new_devs[nand_dev_count];

    dev->page_size = page_size;
    dev->extra_size = extra_size;
    dev->erase_size = erase_pages * (page_size + extra_size);

    dev->data = malloc(dev->erase_size);
    if(dev->data == NULL)
        goto out_of_memory;
    dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
#ifdef TARGET_I386
    dev->flags |= NAND_DEV_FLAG_BATCH_CAP;
#endif

    if (initfd >= 0) {
        do {
            read_size = do_read(initfd, dev->data, dev->erase_size);
            if(read_size < 0) {
                XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
                exit(1);
            }
            if(do_write(rwfd, dev->data, read_size) != read_size) {
                XLOG("could not write file %s, %s\n", rwfilename, strerror(errno));
                exit(1);
            }
        } while(read_size == dev->erase_size);
        close(initfd);
    }
#if defined ANDROID_QCOW
    close(rwfd);

    dev->bdrv = bdrv_new(rwfilename);
    if (0 > bdrv_open(dev->bdrv, rwfilename, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, NULL)) {
        //if (0 > bdrv_file_open(&dev->bdrv,rwfilename, BDRV_O_RDWR)) {
        XLOG("failed to open block driver %s\n", rwfilename);
        exit(1);
    }
    dev_size = 0;
    //dev_size = bdrv_getlength(dev->bdrv->file); // gets allocated file size
    // This is how qemu-img gets the virtual disk size:
    bdrv_get_geometry(dev->bdrv, &dev_size);
    dev_size *= 512;
#else
    dev->fd = rwfd;
#endif
    pad = dev_size % dev->erase_size;
    if (pad != 0) {
        //dev_size += (dev->erase_size - pad);
        dev_size -= pad;
        D("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
    }
    dev->devname = devname;
    dev->devname_len = devname_len;
    dev->max_size = dev_size;
    D("Dev size of %s is %llx\n", rwfilename, dev_size);


    nand_dev_count++;

    return;

out_of_memory:
    XLOG("out of memory\n");
    exit(1);

bad_arg_and_value:
    XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
    exit(1);
}
Beispiel #24
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 #25
0
int initNbd(char* filename)
{
    BlockDriverState *bs;
    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;
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
    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' },
        { "nocache", 0, NULL, 'n' },
        { "shared", 1, NULL, 'e' },
        { "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;
    int persistent = 0;
    pthread_t client_thread;

    /* 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);

//    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
//        switch (ch) {
//        case 's':
//            flags |= BDRV_O_SNAPSHOT;
//            break;
//        case 'n':
//            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
//            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 '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 '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]);
//    }


    /*
       Start a daemon!
       Use client thread to start daemon and write errors;
       Use parent thread to wait for and write error messages.
    */


//    if (device && !verbose) {
//        int stderr_fd[2];
//        pid_t pid;
//        int ret;
//
//        //Setting up Pipe, close after succeeded.
//        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.
//         */
//        //Fork returns 0 for child process and the pid of child process for the parent process
//        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);
//        }
//    }
//
//    //Set sock path... But what is sock path???
//    if (device != NULL && sockpath == NULL) {
//        sockpath = g_malloc(128);
//        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
//    }

    //Init a block device!
    bdrv_init();
    atexit(bdrv_close_all);

    //Malloc a new block device state
    bs = bdrv_new("hda");
    srcpath = filename;
    if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
        errno = -ret;
        err(EXIT_FAILURE, "Failed to bdrv_open '%s'", srcpath);
    }

    fd_size = bdrv_getlength(bs);

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

    exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags);


    if (sockpath) {
        fd = unix_socket_incoming(sockpath);
        fprintf(stderr, "NBD device running on sock path :%s\n", sockpath);
    } else {
        fd = tcp_socket_incoming(bindto, port);
        fprintf(stderr, "NBD device running on port :%i\n", 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_init_main_loop();
    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");
    }


    do {
        main_loop_wait(false);
    } while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0));

    nbd_export_close(exp);
    if (sockpath) {
        unlink(sockpath);
    }


    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
}
Beispiel #26
0
int main(int argc, char **argv)
{
    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 },
        { "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;

    /* 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 '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));
    }

    qemu_init_main_loop();
    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;
    }

    bs = bdrv_new("hda");
    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));
    }

    fd_size = bdrv_getlength(bs);

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

    exp = nbd_export_new(bs, 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);

    bdrv_close(bs);
    if (sockpath) {
        unlink(sockpath);
    }

    if (sn_opts) {
        qemu_opts_del(sn_opts);
    }

    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
}