1nbd_opt_list(3) LIBNBD nbd_opt_list(3)
2
3
4
6 nbd_opt_list - request the server to list all exports during
7 negotiation
8
10 #include <libnbd.h>
11
12 typedef struct {
13 int (*callback) (void *user_data, const char *name,
14 const char *description);
15 void *user_data;
16 void (*free) (void *user_data);
17 } nbd_list_callback;
18
19 int nbd_opt_list (struct nbd_handle *h,
20 nbd_list_callback list_callback);
21
23 Request that the server list all exports that it supports. This can
24 only be used if nbd_set_opt_mode(3) enabled option mode.
25
26 The "list" function is called once per advertised export, with any
27 "user_data" passed to this function, and with "name" and "description"
28 supplied by the server. Many servers omit descriptions, in which case
29 "description" will be an empty string. Remember that it is not safe to
30 call nbd_set_export_name(3) from within the context of the callback
31 function; rather, your code must copy any "name" needed for later use
32 after this function completes. At present, the return value of the
33 callback is ignored, although a return of -1 should be avoided.
34
35 For convenience, when this function succeeds, it returns the number of
36 exports that were advertised by the server.
37
38 Not all servers understand this request, and even when it is
39 understood, the server might intentionally send an empty list to avoid
40 being an information leak, may encounter a failure after delivering
41 partial results, or may refuse to answer more than one query per
42 connection in the interest of avoiding negotiation that does not
43 resolve. Thus, this function may succeed even when no exports are
44 reported, or may fail but have a non-empty list. Likewise, the NBD
45 protocol does not specify an upper bound for the number of exports that
46 might be advertised, so client code should be aware that a server may
47 send a lengthy list.
48
49 For nbd-server(1) you will need to allow clients to make list requests
50 by adding "allowlist=true" to the "[generic]" section of
51 /etc/nbd-server/config. For qemu-nbd(8), a description is set with -D.
52
54 This call returns an integer ≥ 0.
55
57 On error "-1" is returned.
58
59 Refer to "ERROR HANDLING" in libnbd(3) for how to get further details
60 of the error.
61
63 The handle must be negotiating, otherwise this call will return an
64 error.
65
67 This function first appeared in libnbd 1.4.
68
69 If you need to test if this function is available at compile time check
70 if the following macro is defined:
71
72 #define LIBNBD_HAVE_NBD_OPT_LIST 1
73
75 This example is also available as examples/list-exports.c in the libnbd
76 source code.
77
78 /* This example shows how to list NBD exports.
79 *
80 * To test this with qemu-nbd:
81 * $ qemu-nbd -x "hello" -t -k /tmp/sock disk.img
82 * $ ./run examples/list-exports /tmp/sock
83 * [0] hello
84 * Which export to connect to (-1 to quit)? 0
85 * Connecting to hello ...
86 * /tmp/sock: hello: size = 2048 bytes
87 *
88 * To test this with nbdkit (requires 1.22):
89 * $ nbdkit -U /tmp/sock sh - <<\EOF
90 * case $1 in
91 * list_exports) echo NAMES; echo foo; echo foobar ;;
92 * open) echo "$3" ;;
93 * get_size) echo "$2" | wc -c ;;
94 * pread) echo "$2" | dd bs=1 skip=$4 count=$3 ;;
95 * *) exit 2 ;;
96 * esac
97 * EOF
98 * $ ./run examples/list-exports /tmp/sock
99 * [0] foo
100 * [1] foobar
101 * Which export to connect to (-1 to quit)? 1
102 * Connecting to foobar ...
103 * /tmp/sock: foobar: size = 7 bytes
104 */
105
106 #include <stdio.h>
107 #include <stdlib.h>
108 #include <stdint.h>
109 #include <string.h>
110 #include <inttypes.h>
111 #include <errno.h>
112
113 #include <libnbd.h>
114
115 struct export_list {
116 int i;
117 char **names;
118 };
119
120 /* Callback function for nbd_opt_list */
121 static int
122 list_one (void *opaque, const char *name,
123 const char *description)
124 {
125 struct export_list *l = opaque;
126 char **names;
127
128 printf ("[%d] %s\n", l->i, name);
129 if (*description)
130 printf(" (%s)\n", description);
131 names = realloc (l->names,
132 (l->i + 1) * sizeof *names);
133 if (!names) {
134 perror ("realloc");
135 exit (EXIT_FAILURE);
136 }
137 names[l->i] = strdup (name);
138 if (!names[l->i]) {
139 perror ("strdup");
140 exit (EXIT_FAILURE);
141 }
142 l->names = names;
143 l->i++;
144 return 0;
145 }
146
147 int
148 main (int argc, char *argv[])
149 {
150 struct nbd_handle *nbd;
151 int i;
152 const char *name;
153 int64_t size;
154 struct export_list list = { 0 };
155
156 if (argc != 2) {
157 fprintf (stderr, "%s socket\n", argv[0]);
158 exit (EXIT_FAILURE);
159 }
160
161 /* Create the libnbd handle. */
162 nbd = nbd_create ();
163 if (nbd == NULL) {
164 fprintf (stderr, "%s\n", nbd_get_error ());
165 exit (EXIT_FAILURE);
166 }
167
168 /* Set opt mode. */
169 nbd_set_opt_mode (nbd, true);
170
171 /* Connect to the NBD server over a
172 * Unix domain socket. If we did not
173 * end up in option mode, then a
174 * listing is not possible.
175 */
176 if (nbd_connect_unix (nbd, argv[1]) == -1) {
177 fprintf (stderr, "%s\n", nbd_get_error ());
178 exit (EXIT_FAILURE);
179 }
180 if (!nbd_aio_is_negotiating (nbd)) {
181 fprintf (stderr, "Server does not support "
182 "listing exports.\n");
183 exit (EXIT_FAILURE);
184 }
185
186 /* Print the export list. */
187 if (nbd_opt_list (nbd,
188 (nbd_list_callback) {
189 .callback = list_one,
190 .user_data = &list, }) == -1) {
191 fprintf (stderr, "%s\n", nbd_get_error ());
192 exit (EXIT_FAILURE);
193 }
194
195 /* Display the list of exports. */
196 printf ("Which export to connect to? ");
197 if (scanf ("%d", &i) != 1) exit (EXIT_FAILURE);
198 if (i == -1) {
199 if (nbd_opt_abort (nbd) == -1) {
200 fprintf (stderr, "%s\n", nbd_get_error ());
201 exit (EXIT_FAILURE);
202 }
203 nbd_close (nbd);
204 exit (EXIT_SUCCESS);
205 }
206 if (i < 0 || i >= list.i) {
207 fprintf (stderr, "index %d out of range", i);
208 exit (EXIT_FAILURE);
209 }
210 name = list.names[i];
211 printf ("Connecting to %s ...\n", name);
212
213 /* Resume connecting to the chosen export. */
214 if (nbd_set_export_name (nbd, name) == -1 ||
215 nbd_opt_go (nbd) == -1) {
216 fprintf (stderr, "%s\n", nbd_get_error ());
217 exit (EXIT_FAILURE);
218 }
219 if (!nbd_aio_is_ready (nbd)) {
220 fprintf (stderr, "server closed early\n");
221 exit (EXIT_FAILURE);
222 }
223
224 /* Read the size in bytes and print it. */
225 size = nbd_get_size (nbd);
226 if (size == -1) {
227 fprintf (stderr, "%s\n", nbd_get_error ());
228 exit (EXIT_FAILURE);
229 }
230 printf ("%s: %s: size = %" PRIi64 " bytes\n",
231 argv[1], name, size);
232
233 /* Close the libnbd handle. */
234 nbd_close (nbd);
235
236 for (i = 0; i < list.i; i++)
237 free (list.names[i]);
238 free (list.names);
239
240 exit (EXIT_SUCCESS);
241 }
242
244 nbd_aio_opt_list(3), nbd_create(3), nbd_opt_go(3),
245 nbd_set_export_name(3), nbd_set_opt_mode(3), libnbd(3).
246
248 Eric Blake
249
250 Richard W.M. Jones
251
253 Copyright (C) 2019-2021 Red Hat Inc.
254
256 This library is free software; you can redistribute it and/or modify it
257 under the terms of the GNU Lesser General Public License as published
258 by the Free Software Foundation; either version 2 of the License, or
259 (at your option) any later version.
260
261 This library is distributed in the hope that it will be useful, but
262 WITHOUT ANY WARRANTY; without even the implied warranty of
263 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
264 Lesser General Public License for more details.
265
266 You should have received a copy of the GNU Lesser General Public
267 License along with this library; if not, write to the Free Software
268 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
269 02110-1301 USA
270
271
272
273libnbd-1.12.5 2022-07-10 nbd_opt_list(3)