[Libguestfs] [libnbd PATCH 3/4] info: Fix --json output when list size != 1

Eric Blake eblake at redhat.com
Mon Aug 3 18:45:56 UTC 2020


We were producing invalid JSON for a server advertising zero exports
(we left a dangling trailing comma after the "TLS" line), or for
multiple exports (we omitted commas between array elements of
"exports").  We were also failing to check for failure in
nbd_get_nr_list_exports (which was fixed a couple patches ago, but
previously possible when querying with a URI matching an export known
by the server which resulted in a handle in Connected state).

Tested by using qemu-kvm in a second terminal (although the setup is
involved enough that I did not add it to the testsuite; instead, I
will add things when nbdkit is also taught to expose list size != 1):

t1$ touch a b
t1$ qemu-kvm -nodefaults -nographic -qmp stdio
{'execute':'qmp_capabilities'}
{'execute':'nbd-server-start','arguments':{'addr':{'type':'inet',
 'data':{'host':'localhost','port':'10809'}}}}
{'execute':'blockdev-add','arguments':{'driver':'file','node-name':'a',
 'filename':'a'}}
{'execute':'blockdev-add','arguments':{'driver':'file','node-name':'b',
 'filename':'b'}}

# now qemu is advertising zero exports
t2$ nbdinfo --list --json nbd://localhost:10809 | jq .

# back to t1
{'execute':'nbd-server-add','arguments':{'device':'a'}}
{'execute':'nbd-server-add','arguments':{'device':'b'}}

# now qemu is advertising two exports
t2$ nbdinfo --list --json nbd://localhost:10809 | jq .

# back to t1
{'execute':'quit'}
---
 info/nbdinfo.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/info/nbdinfo.c b/info/nbdinfo.c
index b18cebc..f37ffea 100644
--- a/info/nbdinfo.c
+++ b/info/nbdinfo.c
@@ -37,7 +37,8 @@ static bool probe_content, content_flag, no_content_flag;
 static bool json_output = false;
 static bool size_only = false;

-static void list_one_export (struct nbd_handle *nbd, const char *desc);
+static void list_one_export (struct nbd_handle *nbd, const char *desc,
+                             bool first, bool last);
 static void list_all_exports (struct nbd_handle *nbd1, const char *uri);
 static void print_json_string (const char *);
 static char *get_content (struct nbd_handle *, int64_t size);
@@ -250,7 +251,7 @@ main (int argc, char *argv[])

     if (!list_all)
       /* XXX We would need libnbd to request NBD_INFO_DESCRIPTION */
-      list_one_export (nbd, NULL);
+      list_one_export (nbd, NULL, true, true);
     else
       list_all_exports (nbd, argv[optind]);

@@ -263,7 +264,8 @@ main (int argc, char *argv[])
 }

 static void
-list_one_export (struct nbd_handle *nbd, const char *desc)
+list_one_export (struct nbd_handle *nbd, const char *desc,
+                 bool first, bool last)
 {
   int64_t size;
   char *export_name = NULL;
@@ -338,7 +340,8 @@ list_one_export (struct nbd_handle *nbd, const char *desc)
       printf ("\t%s: %" PRId64 "\n", "block_size_maximum", block_maximum);
   }
   else {
-    printf ("\"exports\": [\n");
+    if (first)
+      printf ("\"exports\": [\n");
     printf ("\t{\n");

     printf ("\t\"export-name\": ");
@@ -399,8 +402,10 @@ list_one_export (struct nbd_handle *nbd, const char *desc)
     /* Put this one at the end because of the stupid comma thing in JSON. */
     printf ("\t\"export-size\": %" PRIi64 "\n", size);

-    printf ("\t}\n");
-    printf ("]\n");
+    if (last)
+      printf ("\t} ]\n");
+    else
+      printf ("\t},\n");
   }

   free (content);
@@ -415,8 +420,17 @@ list_all_exports (struct nbd_handle *nbd1, const char *uri)
 {
   int i;
   xmlURIPtr xmluri = NULL;
+  int count = nbd_get_nr_list_exports (nbd1);

-  for (i = 0; i < nbd_get_nr_list_exports (nbd1); ++i) {
+  if (count == -1) {
+    fprintf (stderr, "unable to obtain list of exports: %s\n",
+             nbd_get_error ());
+    exit (EXIT_FAILURE);
+  }
+  if (count == 0 && json_output)
+    printf ("\t\"exports\": []\n");
+
+  for (i = 0; i < count; ++i) {
     char *name, *desc, *new_path, *new_uri;
     struct nbd_handle *nbd2;

@@ -453,7 +467,7 @@ list_all_exports (struct nbd_handle *nbd1, const char *uri)

       /* List the metadata of this export. */
       desc = nbd_get_list_export_description (nbd1, i);
-      list_one_export (nbd2, desc);
+      list_one_export (nbd2, desc, i == 0, i + 1 == count);

       nbd_close (nbd2);
       free (new_uri);
-- 
2.28.0




More information about the Libguestfs mailing list