]> xenbits.xensource.com Git - libvirt.git/commitdiff
virStorageSourceParseNBDColonString: Rewrite to match what qemu does
authorPeter Krempa <pkrempa@redhat.com>
Fri, 24 Apr 2020 11:59:21 +0000 (13:59 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 27 Apr 2020 06:05:49 +0000 (08:05 +0200)
Our implementation wasn't quite able to parse everything that qemu does.
This patch rewrites the parser to a code that semantically resembles the
combination of 'nbd_parse_filename' and 'inet_parse' methods in qemu to
be able to parse the strings in an equivalent manner.

The only thing that libvirt doesn't do is to check the lengths of
various components in the nbd string in places where qemu uses constant
size buffers.

The test cases validate that some of the corner cases involving colons
are parsed properly.

https://bugzilla.redhat.com/show_bug.cgi?id=1826652

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
src/util/virstoragefile.c
tests/virstoragetest.c

index ffc8bdb3446f0b6ba85ff158568745e0e02d4f9e..a2ecdc39284b1696371308df92280ecdd7be1d3c 100644 (file)
@@ -3072,59 +3072,77 @@ static int
 virStorageSourceParseNBDColonString(const char *nbdstr,
                                     virStorageSourcePtr src)
 {
-    VIR_AUTOSTRINGLIST backing = NULL;
-    const char *exportname;
-
-    if (!(backing = virStringSplit(nbdstr, ":", 0)))
-        return -1;
-
-    /* we know that backing[0] now equals to "nbd" */
-
-    if (VIR_ALLOC_N(src->hosts, 1) < 0)
-        return -1;
+    g_autofree char *nbd = g_strdup(nbdstr);
+    char *export_name;
+    char *host_spec;
+    char *unixpath;
+    char *port;
 
+    src->hosts = g_new0(virStorageNetHostDef, 1);
     src->nhosts = 1;
-    src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
+
+    /* We extract the parameters in a similar way qemu does it */
 
     /* format: [] denotes optional sections, uppercase are variable strings
      * nbd:unix:/PATH/TO/SOCKET[:exportname=EXPORTNAME]
      * nbd:HOSTNAME:PORT[:exportname=EXPORTNAME]
      */
-    if (!backing[1]) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("missing remote information in '%s' for protocol nbd"),
-                       nbdstr);
-        return -1;
-    } else if (STREQ(backing[1], "unix")) {
-        if (!backing[2]) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("missing unix socket path in nbd backing string %s"),
-                           nbdstr);
-            return -1;
-        }
 
-        src->hosts->socket = g_strdup(backing[2]);
+    /* first look for ':exportname=' and cut it off */
+    if ((export_name = strstr(nbd, ":exportname="))) {
+        src->path = g_strdup(export_name + strlen(":exportname="));
+        export_name[0] = '\0';
+    }
+
+    /* Verify the prefix and contents. Note that we require a
+     * "host_spec" part to be present. */
+    if (!(host_spec = STRSKIP(nbd, "nbd:")) || host_spec[0] == '\0')
+        goto malformed;
+
+    if ((unixpath = STRSKIP(host_spec, "unix:"))) {
         src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX;
-   } else {
-        src->hosts->name = g_strdup(backing[1]);
 
-        if (!backing[2]) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("missing port in nbd string '%s'"),
-                           nbdstr);
-            return -1;
+        if (unixpath[0] == '\0')
+            goto malformed;
+
+        src->hosts->socket = g_strdup(unixpath);
+    } else {
+        src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
+
+        if (host_spec[0] == ':') {
+            /* no host given */
+            goto malformed;
+        } else if (host_spec[0] == '[') {
+            host_spec++;
+            /* IPv6 addr */
+            if (!(port = strstr(host_spec, "]:")))
+                goto malformed;
+
+            port[0] = '\0';
+            port += 2;
+
+            if (host_spec[0] == '\0')
+                goto malformed;
+        } else {
+            if (!(port = strchr(host_spec, ':')))
+                goto malformed;
+
+            port[0] = '\0';
+            port++;
         }
 
-        if (virStringParsePort(backing[2], &src->hosts->port) < 0)
+        if (virStringParsePort(port, &src->hosts->port) < 0)
             return -1;
-    }
 
-    if ((exportname = strstr(nbdstr, "exportname="))) {
-        exportname += strlen("exportname=");
-        src->path = g_strdup(exportname);
+        src->hosts->name = g_strdup(host_spec);
     }
 
     return 0;
+
+ malformed:
+    virReportError(VIR_ERR_INTERNAL_ERROR,
+                   _("malformed nbd string '%s'"), nbdstr);
+    return -1;
 }
 
 
index 6d2b21c25f349b217f214c8843df00f6d45032f5..ac1480de4e659e58518384c43f132381565d46f2 100644 (file)
@@ -1261,10 +1261,26 @@ mymain(void)
                        "<source protocol='nbd' name=':test'>\n"
                        "  <host name='example.org' port='6000'/>\n"
                        "</source>\n");
+    TEST_BACKING_PARSE("nbd:[::1]:6000:exportname=:test",
+                       "<source protocol='nbd' name=':test'>\n"
+                       "  <host name='::1' port='6000'/>\n"
+                       "</source>\n");
+    TEST_BACKING_PARSE("nbd:127.0.0.1:6000:exportname=:test",
+                       "<source protocol='nbd' name=':test'>\n"
+                       "  <host name='127.0.0.1' port='6000'/>\n"
+                       "</source>\n");
     TEST_BACKING_PARSE("nbd:unix:/tmp/sock:exportname=/",
                        "<source protocol='nbd' name='/'>\n"
                        "  <host transport='unix' socket='/tmp/sock'/>\n"
                        "</source>\n");
+    TEST_BACKING_PARSE("nbd:unix:/tmp/sock:",
+                       "<source protocol='nbd'>\n"
+                       "  <host transport='unix' socket='/tmp/sock:'/>\n"
+                       "</source>\n");
+    TEST_BACKING_PARSE("nbd:unix:/tmp/sock::exportname=:",
+                       "<source protocol='nbd' name=':'>\n"
+                       "  <host transport='unix' socket='/tmp/sock:'/>\n"
+                       "</source>\n");
     TEST_BACKING_PARSE("nbd://example.org:1234",
                        "<source protocol='nbd'>\n"
                        "  <host name='example.org' port='1234'/>\n"