At least 'qemu-nbd -D' can send a description when listing an export;
it's not that much harder to expose things via a new
nbd_get_list_export_description. We may still want to rethink our
list mode API (perhaps adding a callback that informs the client of
name/description pairs as they come in, instead of malloc'ing a copy
for browsing later), but for this patch, it is a straightforward
expansion building on top of commit c2851cf5.
---
lib/internal.h | 7 +++++-
generator/API.ml | 21 ++++++++++++++++--
generator/states-newstyle-opt-list.c | 29 +++++++++++++++++--------
lib/handle.c | 32 ++++++++++++++++++++++++----
examples/list-exports.c | 6 +++++-
interop/Makefile.am | 6 ++++--
interop/list-exports.c | 12 +++++++++--
7 files changed, 92 insertions(+), 21 deletions(-)
diff --git a/lib/internal.h b/lib/internal.h
index 90bc94e..4d0c4e1 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -66,6 +66,11 @@ struct meta_context;
struct socket;
struct command;
+struct export {
+ char *name;
+ char *description;
+};
+
struct nbd_handle {
/* Unique name assigned to this handle for debug messages
* (to avoid having to print actual pointers).
@@ -96,7 +101,7 @@ struct nbd_handle {
/* List exports mode. */
bool list_exports;
size_t nr_exports;
- char **exports;
+ struct export *exports;
/* Global flags from the server. */
uint16_t gflags;
diff --git a/generator/API.ml b/generator/API.ml
index 985d715..3b4cbb1 100644
--- a/generator/API.ml
+++ b/generator/API.ml
@@ -656,7 +656,8 @@ If list exports mode was enabled on the handle and you connected
to the server, this returns the number of exports returned by the
server. This may be 0 or incomplete for reasons given in
C<nbd_set_list_exports>.";
- see_also = [Link "set_list_exports"];
+ see_also = [Link "set_list_exports"; Link
"get_list_export_name";
+ Link "get_list_export_description"];
};
"get_list_export_name", {
@@ -668,7 +669,22 @@ C<nbd_set_list_exports>.";
If list exports mode was enabled on the handle and you connected
to the server, this can be used to return the i'th export name
from the list returned by the server.";
- see_also = [Link "set_list_exports"];
+ see_also = [Link "set_list_exports"; Link
"get_list_export_description"];
+ };
+
+ "get_list_export_description", {
+ default_call with
+ args = [ Int "i" ]; ret = RString;
+ permitted_states = [ Closed; Dead ];
+ shortdesc = "return the i'th export description";
+ longdesc = "\
+If list exports mode was enabled on the handle and you connected
+to the server, this can be used to return the i'th export description
+from the list returned by the server, which may be an empty string.
+
+Many servers omit a description. For L<qemu-nbd(8)>, a description
+is set with I<-D>.";
+ see_also = [Link "set_list_exports"; Link
"get_list_export_name"];
};
"add_meta_context", {
@@ -2336,6 +2352,7 @@ let first_version = [
"get_list_exports", (1, 4);
"get_nr_list_exports", (1, 4);
"get_list_export_name", (1, 4);
+ "get_list_export_description", (1, 4);
"get_block_size", (1, 4);
(* These calls are proposed for a future version of libnbd, but
diff --git a/generator/states-newstyle-opt-list.c b/generator/states-newstyle-opt-list.c
index 49b6f75..f7ea4dc 100644
--- a/generator/states-newstyle-opt-list.c
+++ b/generator/states-newstyle-opt-list.c
@@ -70,8 +70,8 @@ STATE_MACHINE {
uint32_t reply;
uint32_t len;
uint32_t elen;
- char *name;
- char **new_exports;
+ struct export exp;
+ struct export *new_exports;
reply = be32toh (h->sbuf.or.option_reply.reply);
len = be32toh (h->sbuf.or.option_reply.replylen);
@@ -82,27 +82,38 @@ STATE_MACHINE {
debug (h, "skipping too large export name reply");
else {
elen = be32toh (h->sbuf.or.payload.server.server.export_name_len);
- if (elen > len - 4 || elen > NBD_MAX_STRING) {
+ if (elen > len - 4 || elen > NBD_MAX_STRING ||
+ len - 4 - elen > NBD_MAX_STRING) {
set_error (0, "invalid export length");
SET_NEXT_STATE (%.DEAD);
return 0;
}
- /* Copy the export name to the handle list. */
- name = strndup (h->sbuf.or.payload.server.str, elen);
- if (name == NULL) {
+ /* Copy the export name and description to the handle list. */
+ exp.name = strndup (h->sbuf.or.payload.server.str, elen);
+ if (exp.name == NULL) {
set_error (errno, "strdup");
SET_NEXT_STATE (%.DEAD);
return 0;
}
- new_exports = realloc (h->exports, sizeof (char *) * (h->nr_exports+1));
+ exp.description = strndup (h->sbuf.or.payload.server.str + elen,
+ len - 4 - elen);
+ if (exp.name == NULL) {
+ set_error (errno, "strdup");
+ free (exp.name);
+ SET_NEXT_STATE (%.DEAD);
+ return 0;
+ }
+ new_exports = realloc (h->exports,
+ sizeof (*new_exports) * (h->nr_exports+1));
if (new_exports == NULL) {
set_error (errno, "strdup");
SET_NEXT_STATE (%.DEAD);
- free (name);
+ free (exp.name);
+ free (exp.description);
return 0;
}
h->exports = new_exports;
- h->exports[h->nr_exports++] = name;
+ h->exports[h->nr_exports++] = exp;
}
/* Just limit this so we don't receive unlimited amounts
diff --git a/lib/handle.c b/lib/handle.c
index 5ac052a..210ac7d 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -1,5 +1,5 @@
/* NBD client library in userspace
- * Copyright (C) 2013-2019 Red Hat Inc.
+ * Copyright (C) 2013-2020 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -131,8 +131,10 @@ nbd_close (struct nbd_handle *h)
free (m->name);
free (m);
}
- for (i = 0; i < h->nr_exports; ++i)
- free (h->exports[i]);
+ for (i = 0; i < h->nr_exports; ++i) {
+ free (h->exports[i].name);
+ free (h->exports[i].description);
+ }
free (h->exports);
free_cmd_list (h->cmds_to_issue);
free_cmd_list (h->cmds_in_flight);
@@ -268,7 +270,7 @@ nbd_unlocked_get_list_export_name (struct nbd_handle *h,
set_error (EINVAL, "invalid index");
return NULL;
}
- name = strdup (h->exports[i]);
+ name = strdup (h->exports[i].name);
if (!name) {
set_error (errno, "strdup");
return NULL;
@@ -276,6 +278,28 @@ nbd_unlocked_get_list_export_name (struct nbd_handle *h,
return name;
}
+char *
+nbd_unlocked_get_list_export_description (struct nbd_handle *h,
+ int i)
+{
+ char *desc;
+
+ if (!h->list_exports) {
+ set_error (EINVAL, "list exports mode not selected on this handle");
+ return NULL;
+ }
+ if (i < 0 || i >= (int) h->nr_exports) {
+ set_error (EINVAL, "invalid index");
+ return NULL;
+ }
+ desc = strdup (h->exports[i].description);
+ if (!desc) {
+ set_error (errno, "strdup");
+ return NULL;
+ }
+ return desc;
+}
+
int
nbd_unlocked_add_meta_context (struct nbd_handle *h, const char *name)
{
diff --git a/examples/list-exports.c b/examples/list-exports.c
index f654f39..643e611 100644
--- a/examples/list-exports.c
+++ b/examples/list-exports.c
@@ -22,7 +22,7 @@ main (int argc, char *argv[])
{
struct nbd_handle *nbd, *nbd2;
int r, i;
- char *name;
+ char *name, *desc;
int64_t size;
if (argc != 2) {
@@ -65,7 +65,11 @@ main (int argc, char *argv[])
i++) {
name = nbd_get_list_export_name (nbd, i);
printf ("[%d] %s\n", i, name);
+ desc = nbd_get_list_export_description (nbd, i);
+ if (desc && *desc)
+ printf(" (%s)\n", desc);
free (name);
+ free (desc);
}
printf ("Which export to connect to? ");
if (scanf ("%d", &i) != 1) exit (EXIT_FAILURE);
diff --git a/interop/Makefile.am b/interop/Makefile.am
index 08a4336..8b5b03c 100644
--- a/interop/Makefile.am
+++ b/interop/Makefile.am
@@ -1,5 +1,5 @@
# nbd client library in userspace
-# Copyright (C) 2013-2019 Red Hat Inc.
+# Copyright (C) 2013-2020 Red Hat Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -137,6 +137,7 @@ list_exports_nbd_server_CPPFLAGS = \
-DSERVER=\"$(NBD_SERVER)\" \
-DSERVER_PARAMS='"-C", "list-exports-nbd-config",
"-d", "0"' \
-DEXPORTS='"disk1", "disk2"' \
+ -DDESCRIPTIONS='"", ""' \
$(NULL)
list_exports_nbd_server_CFLAGS = $(WARNINGS_CFLAGS)
list_exports_nbd_server_LDADD = $(top_builddir)/lib/libnbd.la
@@ -146,8 +147,9 @@ list_exports_qemu_nbd_CPPFLAGS = \
-I$(top_srcdir)/include \
-DSOCKET_ACTIVATION=1 \
-DSERVER=\"$(QEMU_NBD)\" \
- -DSERVER_PARAMS='"-f", "raw", "-x",
"testing", tmpfile' \
+ -DSERVER_PARAMS='"-f", "raw", "-x",
"testing", "-D", "data", tmpfile' \
-DEXPORTS='"testing"' \
+ -DDESCRIPTIONS='"data"' \
$(NULL)
list_exports_qemu_nbd_CFLAGS = $(WARNINGS_CFLAGS)
list_exports_qemu_nbd_LDADD = $(top_builddir)/lib/libnbd.la
diff --git a/interop/list-exports.c b/interop/list-exports.c
index e9ee0c5..d003ce9 100644
--- a/interop/list-exports.c
+++ b/interop/list-exports.c
@@ -34,7 +34,7 @@ main (int argc, char *argv[])
char tmpfile[] = "/tmp/nbdXXXXXX";
int fd, r;
size_t i;
- char *name;
+ char *name, *desc;
/* Create a sparse temporary file. */
fd = mkstemp (tmpfile);
@@ -71,6 +71,7 @@ main (int argc, char *argv[])
/* Check for expected number of exports. */
const char *exports[] = { EXPORTS };
+ const char *descriptions[] = { DESCRIPTIONS };
const size_t nr_exports = sizeof exports / sizeof exports[0];
r = nbd_get_nr_list_exports (nbd);
if (r != nr_exports) {
@@ -79,7 +80,7 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- /* Check the export names. */
+ /* Check the export names and descriptions. */
for (i = 0; i < nr_exports; ++i) {
name = nbd_get_list_export_name (nbd, (int) i);
if (strcmp (name, exports[i]) != 0) {
@@ -88,6 +89,13 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
free (name);
+ desc = nbd_get_list_export_description (nbd, (int) i);
+ if (strcmp (desc, descriptions[i]) != 0) {
+ fprintf (stderr, "%s: expected description \"%s\", but got
\"%s\"\n",
+ argv[0], descriptions[i], desc);
+ exit (EXIT_FAILURE);
+ }
+ free (desc);
}
nbd_close (nbd);
--
2.27.0