[Libguestfs] [PATCH nbdkit] server: Add nbdkit_export_name() to allow export name to be read.

Richard W.M. Jones rjones at redhat.com
Tue Sep 10 11:20:27 UTC 2019


This allows plugins (or filters) to read the export name which was
passed to the server from the client.

UNFINISHED:

 - Needs tests
---
 TODO                                 |  8 ++++++
 docs/nbdkit-plugin.pod               | 39 ++++++++++++++++++++++++++++
 server/connections.c                 |  1 +
 server/internal.h                    |  1 +
 server/protocol-handshake-newstyle.c | 30 ++++++++++++---------
 server/public.c                      | 10 +++++++
 6 files changed, 77 insertions(+), 12 deletions(-)

diff --git a/TODO b/TODO
index 49b60b1..2468d74 100644
--- a/TODO
+++ b/TODO
@@ -62,6 +62,12 @@ General ideas for improvements
   and also look at the implementation of the -swap option in
   nbd-client.
 
+* Clients should be able to list export names supported by plugins.
+  Current behaviour is not really correct: We only list the -e
+  parameter from the command line, which is different from the export
+  name(s) that a plugin might want to support.  Probably we should
+  deprecate the -e option entirely since it does nothing useful.
+
 Suggestions for plugins
 -----------------------
 
@@ -190,3 +196,5 @@ using ‘#define NBDKIT_API_VERSION <version>’.
   value) strings.  nbdkit should know the possible keys for the plugin
   and filters, and the type of the values, and both check and parse
   them for the plugin.
+
+* Modify open() API so it takes an export name parameter.
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index bb162e4..53687ad 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -362,6 +362,45 @@ requested, or -1 after calling C<nbdkit_error> if there is no point in
 continuing the current command.  Attempts to sleep more than
 C<INT_MAX> seconds are treated as an error.
 
+=head1 EXPORT NAME
+
+If the client negotiated an NBD export name with nbdkit then plugins
+may read this from any connected callbacks.  Nbdkit's normal behaviour
+is to accept any export name passed by the client, log it in debug
+output, but otherwise ignore it.  By using C<nbdkit_export_name>
+plugins may choose to filter by export name or serve different
+content.
+
+=head2 C<nbdkit_export_name>
+
+ const char *nbdkit_export_name (void);
+
+Return the optional NBD export name if one was negotiated with the
+current client (this uses thread-local magic so no parameter is
+required).  The returned string is only valid while the client is
+connected, so if you need to store it in the plugin you must copy it.
+
+The export name is a free-form text string, it is not necessarily a
+path or filename and it does not need to begin with a C<'/'>
+character.  The NBD protocol describes the empty string (C<"">) as a
+representing a "default export" or to be used in cases where the
+export name does not make sense.
+
+This may return C<NULL> which does I<not> indicate an error:
+
+=over 4
+
+=item *
+
+It only returns the export name when there is a connected client.
+
+=item *
+
+If the server is using the oldstyle protocol the client does not send
+an export name.
+
+=back
+
 =head1 CALLBACKS
 
 =head2 C<.name>
diff --git a/server/connections.c b/server/connections.c
index b582764..a1fea54 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -385,6 +385,7 @@ free_connection (struct connection *conn)
   pthread_mutex_destroy (&conn->status_lock);
 
   free (conn->handles);
+  free (conn->exportname);
   free (conn);
 }
 
diff --git a/server/internal.h b/server/internal.h
index 9314e8f..3bfc1a7 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -180,6 +180,7 @@ struct connection {
   struct b_conn_handle *handles;
   size_t nr_handles;
 
+  char *exportname;
   uint32_t cflags;
   uint16_t eflags;
   bool using_tls;
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index 9ddc319..e1301a0 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -274,11 +274,17 @@ negotiate_handshake_newstyle_options (struct connection *conn)
       if (conn_recv_full (conn, data, optlen,
                           "read: %s: %m", name_of_nbd_opt (option)) == -1)
         return -1;
-      /* Apart from printing it, ignore the export name. */
+      /* Print the export name and save it in the connection. */
       data[optlen] = '\0';
-      debug ("newstyle negotiation: %s: "
-             "client requested export '%s' (ignored)",
+      debug ("newstyle negotiation: %s: client requested export '%s'",
              name_of_nbd_opt (option), data);
+      free (conn->exportname);
+      conn->exportname = malloc (optlen+1);
+      if (conn->exportname == NULL) {
+        nbdkit_error ("malloc: %m");
+        return -1;
+      }
+      memcpy (conn->exportname, data, optlen+1);
 
       /* We have to finish the handshake by sending handshake_finish. */
       if (finish_newstyle_options (conn, &exportsize) == -1)
@@ -413,19 +419,19 @@ negotiate_handshake_newstyle_options (struct connection *conn)
           continue;
         }
 
-        /* As with NBD_OPT_EXPORT_NAME we print the export name and then
-         * ignore it.
+        /* As with NBD_OPT_EXPORT_NAME we print the export name and
+         * save it in the connection.
          */
-        requested_exportname = malloc (exportnamelen+1);
-        if (requested_exportname == NULL) {
+        free (conn->exportname);
+        conn->exportname = malloc (exportnamelen+1);
+        if (conn->exportname == NULL) {
           nbdkit_error ("malloc: %m");
           return -1;
         }
-        memcpy (requested_exportname, &data[4], exportnamelen);
-        requested_exportname[exportnamelen] = '\0';
-        debug ("newstyle negotiation: %s: "
-               "client requested export '%s' (ignored)",
-               optname, requested_exportname);
+        memcpy (conn->exportname, &data[4], exportnamelen);
+        conn->exportname[exportnamelen] = '\0';
+        debug ("newstyle negotiation: %s: client requested export '%s'",
+               optname, conn->exportname);
 
         /* The spec is confusing, but it is required that we send back
          * NBD_INFO_EXPORT, even if the client did not request it!
diff --git a/server/public.c b/server/public.c
index 630de9b..eb7f996 100644
--- a/server/public.c
+++ b/server/public.c
@@ -379,3 +379,13 @@ nbdkit_nanosleep (unsigned sec, unsigned nsec)
   return 0;
 #endif
 }
+
+const char *
+nbdkit_export_name (void)
+{
+  struct connection *conn = threadlocal_get_conn ();
+
+  if (!conn)
+    return NULL;
+  return conn->exportname;
+}
-- 
2.23.0




More information about the Libguestfs mailing list