[Libguestfs] guestfish Remote Images IPv6 Support

Richard W.M. Jones rjones at redhat.com
Mon Apr 1 15:45:10 UTC 2019


On Mon, Apr 01, 2019 at 09:45:56AM -0500, Jonathan Wright wrote:
> I believe the bug lies in libguestfs.
> 
> Taking out the commands being sent to QEMU and using qemu-img info I
> can recreate the error:
> 
> # qemu-img info "rbd:images/CentOS-7-x86_64-GenericCloud-1901:mon_host=[fd00::cefc:1]\:6789:auth_supported=none"
> qemu-img: Could not open 'rbd:images/CentOS-7-x86_64-GenericCloud-1901:mon_host=[fd00::cefc:1]\:6789:auth_supported=none':
> invalid conf option :cefc:1]:6789:auth_supported: No such file or
> directory
> 
> When escaping the : in the v6 address (just like is done with the
> port's : ) the command works as expected.

Ah I see.  Can you try the small patch attached?

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org
-------------- next part --------------
>From a23969a4505a7cfb8d741b81e70ab23a868862c7 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Mon, 1 Apr 2019 16:36:15 +0100
Subject: [PATCH] lib: qemu: rbd: Properly escape IPv6 addresses.

Each ':' character in the address must be escaped from qemu.

Thanks: Jonathan Wright
---
 common/utils/guestfs-utils.h |  1 +
 common/utils/utils.c         | 47 ++++++++++++++++++++++++++++++++++++
 lib/qemu.c                   | 37 +++++++++-------------------
 3 files changed, 60 insertions(+), 25 deletions(-)

diff --git a/common/utils/guestfs-utils.h b/common/utils/guestfs-utils.h
index 1459a4c3c..52aeca012 100644
--- a/common/utils/guestfs-utils.h
+++ b/common/utils/guestfs-utils.h
@@ -47,6 +47,7 @@ extern char *guestfs_int_concat_strings (char *const *);
 extern char **guestfs_int_copy_string_list (char *const *);
 extern char *guestfs_int_join_strings (const char *sep, char *const *);
 extern char **guestfs_int_split_string (char sep, const char *);
+extern char *guestfs_int_replace_string (const char *str, const char *s1, const char *s2);
 extern char *guestfs_int_exit_status_to_string (int status, const char *cmd_name, char *buffer, size_t buflen);
 extern int guestfs_int_random_string (char *ret, size_t len);
 extern char *guestfs_int_drive_name (size_t index, char *ret);
diff --git a/common/utils/utils.c b/common/utils/utils.c
index 48e7ed4d1..18725f693 100644
--- a/common/utils/utils.c
+++ b/common/utils/utils.c
@@ -214,6 +214,53 @@ guestfs_int_split_string (char sep, const char *str)
   return ret;
 }
 
+/**
+ * Replace every instance of C<s1> appearing in C<str> with C<s2>.  A
+ * newly allocated string is returned which must be freed by the
+ * caller.  If allocation fails this can return C<NULL>.
+ *
+ * For example:
+ *
+ *  replace_string ("abcabb", "ab", "a");
+ *
+ * would return C<"acab">.
+ */
+char *
+guestfs_int_replace_string (const char *str, const char *s1, const char *s2)
+{
+  const size_t len = strlen (str), s1len = strlen (s1), s2len = strlen (s2);
+  size_t i, n;
+  char *ret;
+
+  /* Count the size of the final string. */
+  n = 0;
+  for (i = 0; i < len; ++i) {
+    if (strncmp (&str[i], s1, s1len) == 0)
+      n += s2len;
+    else
+      n++;
+  }
+
+  ret = malloc (n+1);
+  if (ret == NULL)
+    return NULL;
+
+  n = 0;
+  for (i = 0; i < len; ++i) {
+    if (strncmp (&str[i], s1, s1len) == 0) {
+      strcpy (&ret[n], s2);
+      n += s2len;
+    }
+    else {
+      ret[n] = str[i];
+      n++;
+    }
+  }
+  ret[n] = '\0';
+
+  return ret;
+}
+
 /**
  * Translate a wait/system exit status into a printable string.
  */
diff --git a/lib/qemu.c b/lib/qemu.c
index 2f3493217..21450f996 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -903,37 +903,24 @@ guestfs_int_drive_source_qemu_param (guestfs_h *g,
   }
 
   case drive_protocol_rbd: {
+    CLEANUP_FREE_STRING_LIST char **hosts = NULL;
     CLEANUP_FREE char *mon_host = NULL, *username = NULL, *secret = NULL;
     const char *auth;
-    size_t n = 0;
-    size_t i, j;
+    size_t i;
 
-    /* build the list of all the mon hosts */
-    for (i = 0; i < src->nr_servers; i++) {
-      n += strlen (src->servers[i].u.hostname);
-      n += 8; /* for slashes, colons, & port numbers */
-    }
-    n++; /* for \0 */
-    mon_host = safe_malloc (g, n);
-    n = 0;
-    for (i = 0; i < src->nr_servers; i++) {
-      CLEANUP_FREE char *port = NULL;
+    /* Build the list of all the mon hosts. */
+    hosts = safe_calloc (g, src->nr_servers + 1, sizeof (char *));
 
-      for (j = 0; j < strlen (src->servers[i].u.hostname); j++)
-        mon_host[n++] = src->servers[i].u.hostname[j];
-      mon_host[n++] = '\\';
-      mon_host[n++] = ':';
-      port = safe_asprintf (g, "%d", src->servers[i].port);
-      for (j = 0; j < strlen (port); j++)
-        mon_host[n++] = port[j];
+    for (i = 0; i < src->nr_servers; i++) {
+      CLEANUP_FREE char *escaped_host;
 
-      /* join each host with \; */
-      if (i != src->nr_servers - 1) {
-        mon_host[n++] = '\\';
-        mon_host[n++] = ';';
-      }
+      escaped_host =
+        guestfs_int_replace_string (src->servers[i].u.hostname, ":", "\\:");
+      if (escaped_host == NULL) g->abort_cb ();
+      hosts[i] =
+        safe_asprintf (g, "%s\\:%d", escaped_host, src->servers[i].port);
     }
-    mon_host[n] = '\0';
+    mon_host = guestfs_int_join_strings ("\\;", hosts);
 
     if (src->username)
       username = safe_asprintf (g, ":id=%s", src->username);
-- 
2.20.1



More information about the Libguestfs mailing list