diff --git a/src/launch-direct.c b/src/launch-direct.c index aa6094d6f..26693e611 100644 --- a/src/launch-direct.c +++ b/src/launch-direct.c @@ -76,6 +76,7 @@ free_regexps (void) } static int is_openable (guestfs_h *g, const char *path, int flags); +static char *make_appliance_dev (guestfs_h *g, int virtio_scsi); static void print_qemu_command_line (guestfs_h *g, char **argv); static int qemu_supports (guestfs_h *g, const char *option); static int qemu_supports_device (guestfs_h *g, const char *device_name); @@ -175,6 +176,7 @@ launch_direct (guestfs_h *g, const char *arg) struct sockaddr_un addr; CLEANUP_FREE char *kernel = NULL, *initrd = NULL, *appliance = NULL; int has_appliance_drive; + CLEANUP_FREE char *appliance_dev = NULL; uint32_t size; CLEANUP_FREE void *buf = NULL; @@ -313,8 +315,6 @@ launch_direct (guestfs_h *g, const char *arg) } } - char appliance_dev[64] = "/dev/Xd"; - /* Add the ext2 appliance drive (after all the drives). */ if (has_appliance_drive) { const char *cachemode = ""; @@ -337,8 +337,7 @@ launch_direct (guestfs_h *g, const char *arg) add_cmdline (g, "scsi-hd,drive=appliance"); } - appliance_dev[5] = virtio_scsi ? 's' : 'v'; - guestfs___drive_name (g->nr_drives, &appliance_dev[7]); + appliance_dev = make_appliance_dev (g, virtio_scsi); } /* The qemu -machine option (added 2010-12) is a bit more sane @@ -696,6 +695,40 @@ launch_direct (guestfs_h *g, const char *arg) return -1; } +/* Calculate the appliance device name. + * + * The easy thing would be to use g->nr_drives (indeed, that's what we + * used to do). However this breaks if some of the drives being added + * use the deprecated 'iface' parameter. To further add confusion, + * the format of the 'iface' parameter has never been defined, but + * given existing usage we can assume it has one of only three values: + * NULL, "ide" or "virtio" (which means virtio-blk). See RHBZ#975797. + */ +static char * +make_appliance_dev (guestfs_h *g, int virtio_scsi) +{ + size_t i, index = 0; + struct drive *drv; + char dev[64] = "/dev/Xd"; + + /* Calculate the index of the drive. */ + ITER_DRIVES (g, i, drv) { + if (virtio_scsi) { + if (drv->iface == NULL || STREQ (drv->iface, "ide")) + index++; + } + else /* virtio-blk */ { + if (drv->iface == NULL || STRNEQ (drv->iface, "virtio")) + index++; + } + } + + dev[5] = virtio_scsi ? 's' : 'v'; + guestfs___drive_name (index, &dev[7]); + + return safe_strdup (g, dev); /* Caller frees. */ +} + /* This is called from the forked subprocess just before qemu runs, so * it can just print the message straight to stderr, where it will be * picked up and funnelled through the usual appliance event API. diff --git a/src/launch.c b/src/launch.c index 368c8e8ea..894ca15db 100644 --- a/src/launch.c +++ b/src/launch.c @@ -302,11 +302,15 @@ char * guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev, int flags) { + char root[64] = ""; char *term = getenv ("TERM"); char *ret; bool tcg = flags & APPLIANCE_COMMAND_LINE_IS_TCG; char lpj_s[64] = ""; + if (appliance_dev) + snprintf (root, sizeof root, " root=%s", appliance_dev); + if (tcg) { int lpj = guestfs___get_lpj (g); if (lpj > 0) @@ -326,13 +330,13 @@ guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev, " acpi=off" /* we don't need ACPI, turn it off */ " printk.time=1" /* display timestamp before kernel messages */ " cgroup_disable=memory" /* saves us about 5 MB of RAM */ - " root=%s" /* root (appliance_dev) */ + "%s" /* root=appliance_dev */ " %s" /* selinux */ "%s" /* verbose */ " TERM=%s" /* TERM environment variable */ "%s%s", /* append */ lpj_s, - appliance_dev, + root, g->selinux ? "selinux=1 enforcing=0" : "selinux=0", g->verbose ? " guestfs_verbose=1" : "", term ? term : "linux",