X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Flaunch.c;h=7b3372c2bc85d43d596ff351eaf62cb15c9ace25;hb=edd502543adbdc2fa5dda0c015ea7c390bb39f64;hp=d6e99f72ff36b73ea460f8ccc4858ac453133b6a;hpb=f1041e912b72116d66274d2f15e50ce34a9531fd;p=libguestfs.git diff --git a/src/launch.c b/src/launch.c index d6e99f7..7b3372c 100644 --- a/src/launch.c +++ b/src/launch.c @@ -76,6 +76,7 @@ static int64_t timeval_diff (const struct timeval *x, const struct timeval *y); static void print_qemu_command_line (guestfs_h *g, char **argv); static int connect_unix_socket (guestfs_h *g, const char *sock); static int qemu_supports (guestfs_h *g, const char *option); +static char *qemu_drive_param (guestfs_h *g, const struct drive *drv); #if 0 static int qemu_supports_re (guestfs_h *g, const pcre *option_regex); @@ -186,20 +187,8 @@ guestfs__debug_drives (guestfs_h *g) ret = safe_malloc (g, sizeof (char *) * (count + 1)); - for (i = 0, drv = g->drives; drv; i++, drv = drv->next) { - size_t len = 64 + strlen (drv->path) + strlen (drv->iface); - if (drv->format) len += strlen (drv->format); - - ret[i] = safe_malloc (g, len); - - snprintf (ret[i], len, "file=%s%s%s%s%s,if=%s", - drv->path, - drv->readonly ? ",snapshot=on" : "", - drv->use_cache_off ? ",cache=off" : "", - drv->format ? ",format=" : "", - drv->format ? drv->format : "", - drv->iface); - } + for (i = 0, drv = g->drives; drv; i++, drv = drv->next) + ret[i] = qemu_drive_param (g, drv); ret[count] = NULL; @@ -244,17 +233,21 @@ guestfs__config (guestfs_h *g, * O_DIRECT. This fails on some filesystem types (notably tmpfs). * So we check if we can open the file with or without O_DIRECT, * and use cache=off (or not) accordingly. + * + * NB: This function is only called on the !readonly path. We must + * try to open with O_RDWR to test that the file is readable and + * writable here. */ static int test_cache_off (guestfs_h *g, const char *filename) { - int fd = open (filename, O_RDONLY|O_DIRECT); + int fd = open (filename, O_RDWR|O_DIRECT); if (fd >= 0) { close (fd); return 1; } - fd = open (filename, O_RDONLY); + fd = open (filename, O_RDWR); if (fd >= 0) { close (fd); return 0; @@ -289,6 +282,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, int readonly; char *format; char *iface; + char *name; int use_cache_off; if (strchr (filename, ',') != NULL) { @@ -302,12 +296,15 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, ? safe_strdup (g, optargs->format) : NULL; iface = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK ? safe_strdup (g, optargs->iface) : safe_strdup (g, DRIVE_IF); + name = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_NAME_BITMASK + ? safe_strdup (g, optargs->name) : NULL; if (format && !valid_format_iface (format)) { error (g, _("%s parameter is empty or contains disallowed characters"), "format"); free (format); free (iface); + free (name); return -1; } if (!valid_format_iface (iface)) { @@ -315,6 +312,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, "iface"); free (format); free (iface); + free (name); return -1; } @@ -326,14 +324,16 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, if (use_cache_off == -1) { free (format); free (iface); + free (name); return -1; } if (readonly) { - if (access (filename, F_OK) == -1) { + if (access (filename, R_OK) == -1) { perrorf (g, "%s", filename); free (format); free (iface); + free (name); return -1; } } @@ -347,6 +347,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, (*i)->readonly = readonly; (*i)->format = format; (*i)->iface = iface; + (*i)->name = name; (*i)->use_cache_off = use_cache_off; return 0; @@ -564,25 +565,16 @@ launch_appliance (guestfs_h *g) g->cmdline[0] = g->qemu; /* Add drives */ - struct drive *i = g->drives; - while (i != NULL) { + struct drive *drv = g->drives; + while (drv != NULL) { /* Construct the final -drive parameter. */ - size_t len = 64 + strlen (i->path) + strlen (i->iface); - if (i->format) len += strlen (i->format); - char buf[len]; - - snprintf (buf, len, "file=%s%s%s%s%s,if=%s", - i->path, - i->readonly ? ",snapshot=on" : "", - i->use_cache_off ? ",cache=off" : "", - i->format ? ",format=" : "", - i->format ? i->format : "", - i->iface); + char *buf = qemu_drive_param (g, drv); add_cmdline (g, "-drive"); add_cmdline (g, buf); + free (buf); - i = i->next; + drv = drv->next; } if (qemu_supports (g, "-nodefconfig")) @@ -594,7 +586,19 @@ launch_appliance (guestfs_h *g) */ if (qemu_supports (g, "-machine")) { add_cmdline (g, "-machine"); +#if QEMU_MACHINE_TYPE_IS_BROKEN + /* Workaround for qemu 0.15: We have to add the '[type=]pc' + * since there is no default. This is not a permanent solution + * because this only works on PC-like hardware. Other platforms + * like ppc would need a different machine type. + * + * This bug is fixed in qemu commit 2645c6dcaf6ea2a51a, and was + * not a problem in qemu < 0.15. + */ + add_cmdline (g, "pc,accel=kvm:tcg"); +#else add_cmdline (g, "accel=kvm:tcg"); +#endif } else { /* qemu sometimes needs this option to enable hardware * virtualization, but some versions of 'qemu-kvm' will use KVM @@ -865,6 +869,13 @@ launch_appliance (guestfs_h *g) if (r == -1) goto cleanup1; + /* NB: We reach here just because qemu has opened the socket. It + * does not mean the daemon is up until we read the + * GUESTFS_LAUNCH_FLAG below. Failures in qemu startup can still + * happen even if we reach here, even early failures like not being + * able to open a drive. + */ + close (g->sock); /* Close the listening socket. */ g->sock = r; /* This is the accepted data socket. */ @@ -1273,6 +1284,30 @@ is_openable (guestfs_h *g, const char *path, int flags) return 1; } +static char * +qemu_drive_param (guestfs_h *g, const struct drive *drv) +{ + size_t len = 64; + char *r; + + len += strlen (drv->path); + len += strlen (drv->iface); + if (drv->format) + len += strlen (drv->format); + + r = safe_malloc (g, len); + + snprintf (r, len, "file=%s%s%s%s%s,if=%s", + drv->path, + drv->readonly ? ",snapshot=on" : "", + drv->use_cache_off ? ",cache=off" : "", + drv->format ? ",format=" : "", + drv->format ? drv->format : "", + drv->iface); + + return r; /* caller frees */ +} + /* You had to call this function after launch in versions <= 1.0.70, * but it is now a no-op. */