[Libguestfs] [PATCH 2/5] p2v: Clean up ugly implementation of --nbd option.

Richard W.M. Jones rjones at redhat.com
Fri Feb 3 14:21:15 UTC 2017


The previous implementation was pretty ugly.  This reimplements things
a bit more cleanly.
---
 p2v/nbd.c | 129 ++++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 71 insertions(+), 58 deletions(-)

diff --git a/p2v/nbd.c b/p2v/nbd.c
index 519774f..ce90361 100644
--- a/p2v/nbd.c
+++ b/p2v/nbd.c
@@ -36,6 +36,7 @@
 #include <libintl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <assert.h>
 
 #include "getprogname.h"
 
@@ -44,14 +45,24 @@
 /* How long to wait for the NBD server to start (seconds). */
 #define WAIT_NBD_TIMEOUT 10
 
-/* virt-p2v --nbd option. */
+/* List of servers specified by the --nbd option. */
 enum nbd_server {
-  NO_SERVER = 0,
+  /* 0 is reserved for "end of list" */
   QEMU_NBD = 1,
   NBDKIT = 2,
-#define NR_NBD_SERVERS 2
 };
-static enum nbd_server nbd_servers[NR_NBD_SERVERS] = { QEMU_NBD, NBDKIT };
+static enum nbd_server *cmdline_servers = NULL;
+
+/* If no --nbd option is passed, we use this standard list instead.
+ * Must match the documentation in virt-p2v(1).
+ */
+static const enum nbd_server standard_servers[] =
+  { QEMU_NBD, NBDKIT, 0 };
+
+/* After testing the list of servers passed by the user, this is
+ * server we decide to use.
+ */
+static enum nbd_server use_server;
 
 static pid_t start_qemu_nbd (int nbd_local_port, const char *device);
 static pid_t start_nbdkit (int nbd_local_port, const char *device);
@@ -94,59 +105,70 @@ get_nbd_error (void)
 void
 set_nbd_option (const char *opt)
 {
-  size_t i;
-  CLEANUP_FREE_STRING_LIST char **strs
-    = guestfs_int_split_string (',', opt);
+  size_t i, len;
+  CLEANUP_FREE_STRING_LIST char **strs = NULL;
+
+  if (cmdline_servers != NULL)
+    error (EXIT_FAILURE, 0, _("--nbd option appears multiple times"));
+
+  strs = guestfs_int_split_string (',', opt);
 
   if (strs == NULL)
     error (EXIT_FAILURE, errno, _("malloc"));
 
-  if (strs[0] == NULL)
+  len = guestfs_int_count_strings (strs);
+  if (len == 0)
     error (EXIT_FAILURE, 0, _("--nbd option cannot be empty"));
 
-  for (i = 0; strs[i] != NULL; ++i) {
-    if (i >= NR_NBD_SERVERS)
-      error (EXIT_FAILURE, 0, _("too many --nbd servers"));
+  cmdline_servers = malloc (sizeof (enum nbd_server) * (len + 1));
+  if (cmdline_servers == NULL)
+    error (EXIT_FAILURE, errno, _("malloc"));
 
+  for (i = 0; strs[i] != NULL; ++i) {
     if (STREQ (strs[i], "qemu-nbd") || STREQ (strs[i], "qemu"))
-      nbd_servers[i] = QEMU_NBD;
+      cmdline_servers[i] = QEMU_NBD;
     else if (STREQ (strs[i], "nbdkit"))
-      nbd_servers[i] = NBDKIT;
+      cmdline_servers[i] = NBDKIT;
     else
       error (EXIT_FAILURE, 0, _("--nbd: unknown server: %s"), strs[i]);
   }
 
-  for (; i < NR_NBD_SERVERS; ++i)
-    nbd_servers[i] = NO_SERVER;
+  assert (i == len);
+  cmdline_servers[i] = 0;       /* marks the end of the list */
 }
 
 /**
  * Test the I<--nbd> option (or built-in default list) to see which
  * servers are actually installed and appear to be working.
  *
- * If a server is not installed we set the corresponding
- * C<nbd_servers[i] = NO_SERVER>.
+ * Set the C<use_server> global accordingly.
  */
 void
 test_nbd_servers (void)
 {
   size_t i;
   int r;
+  const enum nbd_server *servers;
 
-  for (i = 0; i < NR_NBD_SERVERS; ++i) {
-    switch (nbd_servers[i]) {
-    case NO_SERVER:
-      /* ignore entry */
-      break;
+  if (cmdline_servers != NULL)
+    servers = cmdline_servers;
+  else
+    servers = standard_servers;
+
+  use_server = 0;
 
+  for (i = 0; servers[i] != 0; ++i) {
+    switch (servers[i]) {
     case QEMU_NBD:
       r = system ("qemu-nbd --version"
 #ifndef DEBUG_STDERR
                   " >/dev/null 2>&1"
 #endif
                   );
-      if (r != 0)
-        nbd_servers[i] = NO_SERVER;
+      if (r == 0) {
+        use_server = servers[i];
+        goto finish;
+      }
       break;
 
     case NBDKIT:
@@ -155,8 +177,10 @@ test_nbd_servers (void)
                   " >/dev/null 2>&1"
 #endif
                   );
-      if (r != 0)
-        nbd_servers[i] = NO_SERVER;
+      if (r == 0) {
+        use_server = servers[i];
+        goto finish;
+      }
       break;
 
     default:
@@ -164,52 +188,41 @@ test_nbd_servers (void)
     }
   }
 
-  for (i = 0; i < NR_NBD_SERVERS; ++i)
-    if (nbd_servers[i] != NO_SERVER)
-      return;
+ finish:
+  if (use_server == 0) {
+    fprintf (stderr,
+             _("%s: no working NBD server was found, cannot continue.\n"
+               "Please check the --nbd option in the virt-p2v(1) man page.\n"),
+             getprogname ());
+    exit (EXIT_FAILURE);
+  }
 
-  /* If we reach here, there are no servers left, so we have to exit. */
-  fprintf (stderr,
-           _("%s: no working NBD server was found, cannot continue.\n"
-             "Please check the --nbd option in the virt-p2v(1) man page.\n"),
-           getprogname ());
-  exit (EXIT_FAILURE);
+  /* Release memory used by the --nbd option. */
+  free (cmdline_servers);
+  cmdline_servers = NULL;
 }
 
 /**
- * Start the first server found in the C<nbd_servers> list.
+ * Start the NBD server.
  *
- * We previously tested all NBD servers (see C<test_nbd_servers>) so
- * we only need to run the first server in the list.
+ * We previously tested all NBD servers (see C<test_nbd_servers>) and
+ * hopefully found one which will work.
  *
  * Returns the process ID (E<gt> 0) or C<0> if there is an error.
  */
 pid_t
 start_nbd_server (int port, const char *device)
 {
-  size_t i;
-
-  for (i = 0; i < NR_NBD_SERVERS; ++i) {
-    switch (nbd_servers[i]) {
-    case NO_SERVER:
-      /* ignore */
-      break;
+  switch (use_server) {
+  case QEMU_NBD:
+    return start_qemu_nbd (port, device);
 
-    case QEMU_NBD:
-      return start_qemu_nbd (port, device);
+  case NBDKIT:
+    return start_nbdkit (port, device);
 
-    case NBDKIT:
-      return start_nbdkit (port, device);
-
-    default:
-      abort ();
-    }
+  default:
+    abort ();
   }
-
-  /* This should never happen because of the checks in
-   * test_nbd_servers.
-   */
-  abort ();
 }
 
 /**
-- 
2.9.3




More information about the Libguestfs mailing list