X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Flaunch.c;h=ce26e253c0ca300100ea1b61b42ae447553310ed;hp=8e171f7b28ab464839b46ab29379ebf905c1348c;hb=527079aa0db9b608ee4c25e7b3eccc4058685608;hpb=c155330f04f933d13298d5cddab6b7f3dc9d218f diff --git a/src/launch.c b/src/launch.c index 8e171f7..ce26e25 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); @@ -105,9 +106,9 @@ free_regexps (void) } #endif -/* Add a string to the current command line. */ +/* Functions to add a string to the current command line. */ static void -incr_cmdline_size (guestfs_h *g) +alloc_cmdline (guestfs_h *g) { if (g->cmdline == NULL) { /* g->cmdline[0] is reserved for argv[0], set in guestfs_launch. */ @@ -115,7 +116,12 @@ incr_cmdline_size (guestfs_h *g) g->cmdline = safe_malloc (g, sizeof (char *)); g->cmdline[0] = NULL; } +} +static void +incr_cmdline_size (guestfs_h *g) +{ + alloc_cmdline (g); g->cmdline_size++; g->cmdline = safe_realloc (g, g->cmdline, sizeof (char *) * g->cmdline_size); } @@ -134,23 +140,18 @@ add_cmdline (guestfs_h *g, const char *str) return 0; } -size_t -guestfs___checkpoint_cmdline (guestfs_h *g) +struct drive ** +guestfs___checkpoint_drives (guestfs_h *g) { - return g->cmdline_size; + struct drive **i = &g->drives; + while (*i != NULL) i = &((*i)->next); + return i; } void -guestfs___rollback_cmdline (guestfs_h *g, size_t pos) +guestfs___rollback_drives (guestfs_h *g, struct drive **i) { - size_t i; - - assert (g->cmdline_size >= pos); - - for (i = pos; i < g->cmdline_size; ++i) - free (g->cmdline[i]); - - g->cmdline_size = pos; + guestfs___free_drives(i); } /* Internal command to return the command line. */ @@ -160,11 +161,7 @@ guestfs__debug_cmdline (guestfs_h *g) size_t i; char **r; - if (g->cmdline == NULL) { - r = safe_malloc (g, sizeof (char *) * 1); - r[0] = NULL; - return r; - } + alloc_cmdline (g); r = safe_malloc (g, sizeof (char *) * (g->cmdline_size + 1)); r[0] = safe_strdup (g, g->qemu); /* g->cmdline[0] is always NULL */ @@ -177,6 +174,27 @@ guestfs__debug_cmdline (guestfs_h *g) return r; /* caller frees */ } +/* Internal command to return the list of drives. */ +char ** +guestfs__debug_drives (guestfs_h *g) +{ + size_t i, count; + char **ret; + struct drive *drv; + + for (count = 0, drv = g->drives; drv; count++, drv = drv->next) + ; + + ret = safe_malloc (g, sizeof (char *) * (count + 1)); + + for (i = 0, drv = g->drives; drv; i++, drv = drv->next) + ret[i] = qemu_drive_param (g, drv); + + ret[count] = NULL; + + return ret; /* caller frees */ +} + int guestfs__config (guestfs_h *g, const char *qemu_param, const char *qemu_value) @@ -258,8 +276,10 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, const struct guestfs_add_drive_opts_argv *optargs) { int readonly; - const char *format; - const char *iface; + char *format; + char *iface; + char *name; + int use_cache_off; if (strchr (filename, ',') != NULL) { error (g, _("filename cannot contain ',' (comma) character")); @@ -269,18 +289,26 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, readonly = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK ? optargs->readonly : 0; format = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK - ? optargs->format : NULL; + ? safe_strdup (g, optargs->format) : NULL; iface = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK - ? optargs->iface : DRIVE_IF; + ? 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)) { error (g, _("%s parameter is empty or contains disallowed characters"), "iface"); + free (format); + free (iface); + free (name); return -1; } @@ -288,31 +316,37 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, * checks for the existence of the file. For readonly we have * to do the check explicitly. */ - int use_cache_off = readonly ? 0 : test_cache_off (g, filename); - if (use_cache_off == -1) + use_cache_off = readonly ? 0 : test_cache_off (g, filename); + if (use_cache_off == -1) { + free (format); + free (iface); + free (name); return -1; + } if (readonly) { if (access (filename, F_OK) == -1) { perrorf (g, "%s", filename); + free (format); + free (iface); + free (name); return -1; } } - /* Construct the final -drive parameter. */ - size_t len = 64 + strlen (filename) + strlen (iface); - if (format) len += strlen (format); - char buf[len]; + struct drive **i = &(g->drives); + while (*i != NULL) i = &((*i)->next); - snprintf (buf, len, "file=%s%s%s%s%s,if=%s", - filename, - readonly ? ",snapshot=on" : "", - use_cache_off ? ",cache=off" : "", - format ? ",format=" : "", - format ? format : "", - iface); + *i = safe_malloc (g, sizeof (struct drive)); + (*i)->next = NULL; + (*i)->path = safe_strdup (g, filename); + (*i)->readonly = readonly; + (*i)->format = format; + (*i)->iface = iface; + (*i)->name = name; + (*i)->use_cache_off = use_cache_off; - return guestfs__config (g, "-drive", buf); + return 0; } int @@ -432,7 +466,7 @@ launch_appliance (guestfs_h *g) /* At present you must add drives before starting the appliance. In * future when we enable hotplugging you won't need to do this. */ - if (!g->cmdline) { + if (!g->drives) { error (g, _("you must call guestfs_add_drive before guestfs_launch")); return -1; } @@ -518,8 +552,27 @@ launch_appliance (guestfs_h *g) /* Set up the full command line. Do this in the subprocess so we * don't need to worry about cleaning up. */ + + /* Set g->cmdline[0] to the name of the qemu process. However + * it is possible that no g->cmdline has been allocated yet so + * we must do that first. + */ + alloc_cmdline (g); g->cmdline[0] = g->qemu; + /* Add drives */ + struct drive *drv = g->drives; + while (drv != NULL) { + /* Construct the final -drive parameter. */ + char *buf = qemu_drive_param (g, drv); + + add_cmdline (g, "-drive"); + add_cmdline (g, buf); + free (buf); + + drv = drv->next; + } + if (qemu_supports (g, "-nodefconfig")) add_cmdline (g, "-nodefconfig"); @@ -1208,6 +1261,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. */