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; }
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; }
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; }
/* 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, BlockJobTxn *txn) { BlockDriverState *bs; TestBlockJob *s; TestBlockJobCBData *data; static unsigned counter; char job_id[24]; data = g_new0(TestBlockJobCBData, 1); bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort); g_assert_nonnull(bs); snprintf(job_id, sizeof(job_id), "job%u", counter++); s = block_job_create(job_id, &test_block_job_driver, txn, bs, 0, BLK_PERM_ALL, 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; data->job = s; data->result = result; return &s->common; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
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); }
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; }
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); }
static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) { uint8_t buf[1024]; VHDFooter *footer = (VHDFooter *) buf; char *disk_type_param; int i; uint16_t cyls = 0; uint8_t heads = 0; uint8_t secs_per_cyl = 0; int64_t total_sectors; int64_t total_size; int disk_type; int ret = -EIO; Error *local_err = NULL; BlockDriverState *bs = NULL; /* Read out options */ total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), BDRV_SECTOR_SIZE); disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); if (disk_type_param) { if (!strcmp(disk_type_param, "dynamic")) { disk_type = VHD_DYNAMIC; } else if (!strcmp(disk_type_param, "fixed")) { disk_type = VHD_FIXED; } else { ret = -EINVAL; goto out; } } else { disk_type = VHD_DYNAMIC; } ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; } ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; } /* * Calculate matching total_size and geometry. Increase the number of * sectors requested until we get enough (or fail). This ensures that * qemu-img convert doesn't truncate images, but rather rounds up. * * If the image size can't be represented by a spec conform CHS geometry, * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use * the image size from the VHD footer to calculate total_sectors. */ total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE); for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl); } if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) { total_sectors = total_size / BDRV_SECTOR_SIZE; /* Allow a maximum disk size of approximately 2 TB */ if (total_sectors > VHD_MAX_SECTORS) { ret = -EFBIG; goto out; } } else { total_sectors = (int64_t)cyls * heads * secs_per_cyl; total_size = total_sectors * BDRV_SECTOR_SIZE; } /* Prepare the Hard Disk Footer */ memset(buf, 0, 1024); memcpy(footer->creator, "conectix", 8); /* TODO Check if "qemu" creator_app is ok for VPC */ memcpy(footer->creator_app, "qemu", 4); memcpy(footer->creator_os, "Wi2k", 4); footer->features = cpu_to_be32(0x02); footer->version = cpu_to_be32(0x00010000); if (disk_type == VHD_DYNAMIC) { footer->data_offset = cpu_to_be64(HEADER_SIZE); } else { footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL); } footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE); /* Version of Virtual PC 2007 */ footer->major = cpu_to_be16(0x0005); footer->minor = cpu_to_be16(0x0003); footer->orig_size = cpu_to_be64(total_size); footer->current_size = cpu_to_be64(total_size); footer->cyls = cpu_to_be16(cyls); footer->heads = heads; footer->secs_per_cyl = secs_per_cyl; footer->type = cpu_to_be32(disk_type); #if defined(CONFIG_UUID) uuid_generate(footer->uuid); #endif footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE)); if (disk_type == VHD_DYNAMIC) { ret = create_dynamic_disk(bs, buf, total_sectors); } else { ret = create_fixed_disk(bs, buf, total_size); } out: bdrv_unref(bs); g_free(disk_type_param); return ret; }
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; }
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; }
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); } }
int main(int argc, char **argv) { BlockBackend *blk; BlockDriverState *bs; BlockDriver *drv; off_t dev_offset = 0; uint32_t nbdflags = 0; bool disconnect = false; const char *bindto = "0.0.0.0"; char *device = NULL; int port = NBD_DEFAULT_PORT; off_t fd_size; QemuOpts *sn_opts = NULL; const char *sn_id_or_name = NULL; const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:"; struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "bind", 1, NULL, 'b' }, { "port", 1, NULL, 'p' }, { "socket", 1, NULL, 'k' }, { "offset", 1, NULL, 'o' }, { "read-only", 0, NULL, 'r' }, { "partition", 1, NULL, 'P' }, { "connect", 1, NULL, 'c' }, { "disconnect", 0, NULL, 'd' }, { "snapshot", 0, NULL, 's' }, { "load-snapshot", 1, NULL, 'l' }, { "nocache", 0, NULL, 'n' }, { "cache", 1, NULL, QEMU_NBD_OPT_CACHE }, #ifdef CONFIG_LINUX_AIO { "aio", 1, NULL, QEMU_NBD_OPT_AIO }, #endif { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD }, { "detect-zeroes", 1, NULL, QEMU_NBD_OPT_DETECT_ZEROES }, { "shared", 1, NULL, 'e' }, { "format", 1, NULL, 'f' }, { "persistent", 0, NULL, 't' }, { "verbose", 0, NULL, 'v' }, { NULL, 0, NULL, 0 } }; int ch; int opt_ind = 0; int li; char *end; int flags = BDRV_O_RDWR; int partition = -1; int ret; int fd; bool seen_cache = false; bool seen_discard = false; #ifdef CONFIG_LINUX_AIO bool seen_aio = false; #endif pthread_t client_thread; const char *fmt = NULL; Error *local_err = NULL; BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; /* The client thread uses SIGTERM to interrupt the server. A signal * handler ensures that "qemu-nbd -v -c" exits with a nice status code. */ struct sigaction sa_sigterm; memset(&sa_sigterm, 0, sizeof(sa_sigterm)); sa_sigterm.sa_handler = termsig_handler; sigaction(SIGTERM, &sa_sigterm, NULL); qemu_init_exec_dir(argv[0]); while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch (ch) { case 's': flags |= BDRV_O_SNAPSHOT; break; case 'n': optarg = (char *) "none"; /* fallthrough */ case QEMU_NBD_OPT_CACHE: if (seen_cache) { errx(EXIT_FAILURE, "-n and --cache can only be specified once"); } seen_cache = true; if (bdrv_parse_cache_flags(optarg, &flags) == -1) { errx(EXIT_FAILURE, "Invalid cache mode `%s'", optarg); } break; #ifdef CONFIG_LINUX_AIO case QEMU_NBD_OPT_AIO: if (seen_aio) { errx(EXIT_FAILURE, "--aio can only be specified once"); } seen_aio = true; if (!strcmp(optarg, "native")) { flags |= BDRV_O_NATIVE_AIO; } else if (!strcmp(optarg, "threads")) { /* this is the default */ } else { errx(EXIT_FAILURE, "invalid aio mode `%s'", optarg); } break; #endif case QEMU_NBD_OPT_DISCARD: if (seen_discard) { errx(EXIT_FAILURE, "--discard can only be specified once"); } seen_discard = true; if (bdrv_parse_discard_flags(optarg, &flags) == -1) { errx(EXIT_FAILURE, "Invalid discard mode `%s'", optarg); } break; case QEMU_NBD_OPT_DETECT_ZEROES: detect_zeroes = qapi_enum_parse(BlockdevDetectZeroesOptions_lookup, optarg, BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX, BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF, &local_err); if (local_err) { errx(EXIT_FAILURE, "Failed to parse detect_zeroes mode: %s", error_get_pretty(local_err)); } if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && !(flags & BDRV_O_UNMAP)) { errx(EXIT_FAILURE, "setting detect-zeroes to unmap is not allowed " "without setting discard operation to unmap"); } break; case 'b': bindto = optarg; break; case 'p': li = strtol(optarg, &end, 0); if (*end) { errx(EXIT_FAILURE, "Invalid port `%s'", optarg); } if (li < 1 || li > 65535) { errx(EXIT_FAILURE, "Port out of range `%s'", optarg); } port = (uint16_t)li; break; case 'o': dev_offset = strtoll (optarg, &end, 0); if (*end) { errx(EXIT_FAILURE, "Invalid offset `%s'", optarg); } if (dev_offset < 0) { errx(EXIT_FAILURE, "Offset must be positive `%s'", optarg); } break; case 'l': if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0); if (!sn_opts) { errx(EXIT_FAILURE, "Failed in parsing snapshot param `%s'", optarg); } } else { sn_id_or_name = optarg; } /* fall through */ case 'r': nbdflags |= NBD_FLAG_READ_ONLY; flags &= ~BDRV_O_RDWR; break; case 'P': partition = strtol(optarg, &end, 0); if (*end) { errx(EXIT_FAILURE, "Invalid partition `%s'", optarg); } if (partition < 1 || partition > 8) { errx(EXIT_FAILURE, "Invalid partition %d", partition); } break; case 'k': sockpath = optarg; if (sockpath[0] != '/') { errx(EXIT_FAILURE, "socket path must be absolute\n"); } break; case 'd': disconnect = true; break; case 'c': device = optarg; break; case 'e': shared = strtol(optarg, &end, 0); if (*end) { errx(EXIT_FAILURE, "Invalid shared device number '%s'", optarg); } if (shared < 1) { errx(EXIT_FAILURE, "Shared device number must be greater than 0\n"); } break; case 'f': fmt = optarg; break; case 't': persistent = 1; break; case 'v': verbose = 1; break; case 'V': version(argv[0]); exit(0); break; case 'h': usage(argv[0]); exit(0); break; case '?': errx(EXIT_FAILURE, "Try `%s --help' for more information.", argv[0]); } } if ((argc - optind) != 1) { errx(EXIT_FAILURE, "Invalid number of argument.\n" "Try `%s --help' for more information.", argv[0]); } if (disconnect) { fd = open(argv[optind], O_RDWR); if (fd < 0) { err(EXIT_FAILURE, "Cannot open %s", argv[optind]); } nbd_disconnect(fd); close(fd); printf("%s disconnected\n", argv[optind]); return 0; } if (device && !verbose) { int stderr_fd[2]; pid_t pid; int ret; if (qemu_pipe(stderr_fd) < 0) { err(EXIT_FAILURE, "Error setting up communication pipe"); } /* Now daemonize, but keep a communication channel open to * print errors and exit with the proper status code. */ pid = fork(); if (pid == 0) { close(stderr_fd[0]); ret = qemu_daemon(1, 0); /* Temporarily redirect stderr to the parent's pipe... */ dup2(stderr_fd[1], STDERR_FILENO); if (ret < 0) { err(EXIT_FAILURE, "Failed to daemonize"); } /* ... close the descriptor we inherited and go on. */ close(stderr_fd[1]); } else { bool errors = false; char *buf; /* In the parent. Print error messages from the child until * it closes the pipe. */ close(stderr_fd[1]); buf = g_malloc(1024); while ((ret = read(stderr_fd[0], buf, 1024)) > 0) { errors = true; ret = qemu_write_full(STDERR_FILENO, buf, ret); if (ret < 0) { exit(EXIT_FAILURE); } } if (ret < 0) { err(EXIT_FAILURE, "Cannot read from daemon"); } /* Usually the daemon should not print any message. * Exit with zero status in that case. */ exit(errors); } } if (device != NULL && sockpath == NULL) { sockpath = g_malloc(128); snprintf(sockpath, 128, SOCKET_PATH, basename(device)); } if (qemu_init_main_loop(&local_err)) { error_report("%s", error_get_pretty(local_err)); error_free(local_err); exit(EXIT_FAILURE); } bdrv_init(); atexit(bdrv_close_all); if (fmt) { drv = bdrv_find_format(fmt); if (!drv) { errx(EXIT_FAILURE, "Unknown file format '%s'", fmt); } } else { drv = NULL; } blk = blk_new_with_bs("hda", &error_abort); bs = blk_bs(blk); srcpath = argv[optind]; ret = bdrv_open(&bs, srcpath, NULL, NULL, flags, drv, &local_err); if (ret < 0) { errno = -ret; err(EXIT_FAILURE, "Failed to bdrv_open '%s': %s", argv[optind], error_get_pretty(local_err)); } if (sn_opts) { ret = bdrv_snapshot_load_tmp(bs, qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), &local_err); } else if (sn_id_or_name) { ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name, &local_err); } if (ret < 0) { errno = -ret; err(EXIT_FAILURE, "Failed to load snapshot: %s", error_get_pretty(local_err)); } bs->detect_zeroes = detect_zeroes; fd_size = blk_getlength(blk); if (partition != -1) { ret = find_partition(blk, partition, &dev_offset, &fd_size); if (ret < 0) { errno = -ret; err(EXIT_FAILURE, "Could not find partition %d", partition); } } exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed); if (sockpath) { fd = unix_socket_incoming(sockpath); } else { fd = tcp_socket_incoming(bindto, port); } if (fd < 0) { return 1; } if (device) { int ret; ret = pthread_create(&client_thread, NULL, nbd_client_thread, device); if (ret != 0) { errx(EXIT_FAILURE, "Failed to create client thread: %s", strerror(ret)); } } else { /* Shut up GCC warnings. */ memset(&client_thread, 0, sizeof(client_thread)); } qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, (void *)(uintptr_t)fd); /* now when the initialization is (almost) complete, chdir("/") * to free any busy filesystems */ if (chdir("/") < 0) { err(EXIT_FAILURE, "Could not chdir to root directory"); } state = RUNNING; do { main_loop_wait(false); if (state == TERMINATE) { state = TERMINATING; nbd_export_close(exp); nbd_export_put(exp); exp = NULL; } } while (state != TERMINATED); blk_unref(blk); if (sockpath) { unlink(sockpath); } qemu_opts_del(sn_opts); if (device) { void *ret; pthread_join(client_thread, &ret); exit(ret != NULL); } else { exit(EXIT_SUCCESS); } }
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); } }