diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index ffc8bdb344..a2ecdc3928 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -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]);
- 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 (virStringParsePort(backing[2], &src->hosts->port) < 0)
- return -1;
+ /* 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';
}
- if ((exportname = strstr(nbdstr, "exportname="))) {
- exportname += strlen("exportname=");
- src->path = g_strdup(exportname);
+ /* 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;
+
+ 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(port, &src->hosts->port) < 0)
+ return -1;
+
+ src->hosts->name = g_strdup(host_spec);
}
return 0;
+
+ malformed:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("malformed nbd string '%s'"), nbdstr);
+ return -1;
}
diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c
index 6d2b21c25f..ac1480de4e 100644
--- a/tests/virstoragetest.c
+++ b/tests/virstoragetest.c
@@ -1261,10 +1261,26 @@ mymain(void)
"\n"
" \n"
"\n");
+ TEST_BACKING_PARSE("nbd:[::1]:6000:exportname=:test",
+ "\n"
+ " \n"
+ "\n");
+ TEST_BACKING_PARSE("nbd:127.0.0.1:6000:exportname=:test",
+ "\n"
+ " \n"
+ "\n");
TEST_BACKING_PARSE("nbd:unix:/tmp/sock:exportname=/",
"\n"
" \n"
"\n");
+ TEST_BACKING_PARSE("nbd:unix:/tmp/sock:",
+ "\n"
+ " \n"
+ "\n");
+ TEST_BACKING_PARSE("nbd:unix:/tmp/sock::exportname=:",
+ "\n"
+ " \n"
+ "\n");
TEST_BACKING_PARSE("nbd://example.org:1234",
"\n"
" \n"