Revert "ci: skip "lib/test-fork-safe-execvpe.sh" on Alpine Linux"
[libnbd.git] / examples / list-exports.c
blobc7780ffd5bb7dbe711bb62e3161f3dc86df82272
1 /* This example shows how to list NBD exports.
3 * To test this with qemu-nbd:
4 * $ qemu-nbd -x "hello" -t -k /tmp/sock disk.img
5 * $ ./run examples/list-exports /tmp/sock
6 * [0] hello
7 * Which export to connect to (-1 to quit)? 0
8 * Connecting to hello ...
9 * /tmp/sock: hello: size = 2048 bytes
11 * To test this with nbdkit (requires 1.22):
12 * $ nbdkit -U /tmp/sock sh - <<\EOF
13 * case $1 in
14 * list_exports) echo NAMES; echo foo; echo foobar ;;
15 * open) echo "$3" ;;
16 * get_size) echo "$2" | wc -c ;;
17 * pread) echo "$2" | dd bs=1 skip=$4 count=$3 ;;
18 * *) exit 2 ;;
19 * esac
20 * EOF
21 * $ ./run examples/list-exports /tmp/sock
22 * [0] foo
23 * [1] foobar
24 * Which export to connect to (-1 to quit)? 1
25 * Connecting to foobar ...
26 * /tmp/sock: foobar: size = 7 bytes
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <inttypes.h>
34 #include <errno.h>
36 #include <libnbd.h>
38 struct export_list {
39 int i;
40 char **names;
43 /* Callback function for nbd_opt_list */
44 static int
45 list_one (void *opaque, const char *name,
46 const char *description)
48 struct export_list *l = opaque;
49 char **names;
51 printf ("[%d] %s\n", l->i, name);
52 if (*description)
53 printf (" (%s)\n", description);
54 names = realloc (l->names,
55 (l->i + 1) * sizeof *names);
56 if (!names) {
57 perror ("realloc");
58 exit (EXIT_FAILURE);
60 names[l->i] = strdup (name);
61 if (!names[l->i]) {
62 perror ("strdup");
63 exit (EXIT_FAILURE);
65 l->names = names;
66 l->i++;
67 return 0;
70 int
71 main (int argc, char *argv[])
73 struct nbd_handle *nbd;
74 int i;
75 const char *name;
76 int64_t size;
77 struct export_list list = { 0 };
79 if (argc != 2) {
80 fprintf (stderr, "%s socket\n", argv[0]);
81 exit (EXIT_FAILURE);
84 /* Create the libnbd handle. */
85 nbd = nbd_create ();
86 if (nbd == NULL) {
87 fprintf (stderr, "%s\n", nbd_get_error ());
88 exit (EXIT_FAILURE);
91 /* Set opt mode. */
92 nbd_set_opt_mode (nbd, true);
94 /* Connect to the NBD server over a
95 * Unix domain socket. If we did not
96 * end up in option mode, then a
97 * listing is not possible.
99 if (nbd_connect_unix (nbd, argv[1]) == -1) {
100 fprintf (stderr, "%s\n", nbd_get_error ());
101 exit (EXIT_FAILURE);
103 if (!nbd_aio_is_negotiating (nbd)) {
104 fprintf (stderr, "Server does not support "
105 "listing exports.\n");
106 exit (EXIT_FAILURE);
109 /* Print the export list. */
110 if (nbd_opt_list (nbd,
111 (nbd_list_callback) {
112 .callback = list_one,
113 .user_data = &list, }) == -1) {
114 fprintf (stderr, "%s\n", nbd_get_error ());
115 exit (EXIT_FAILURE);
118 /* Display the list of exports. */
119 printf ("Which export to connect to? ");
120 if (scanf ("%d", &i) != 1) exit (EXIT_FAILURE);
121 if (i == -1) {
122 if (nbd_opt_abort (nbd) == -1) {
123 fprintf (stderr, "%s\n", nbd_get_error ());
124 exit (EXIT_FAILURE);
126 nbd_close (nbd);
127 exit (EXIT_SUCCESS);
129 if (i < 0 || i >= list.i) {
130 fprintf (stderr, "index %d out of range", i);
131 exit (EXIT_FAILURE);
133 name = list.names[i];
134 printf ("Connecting to %s ...\n", name);
136 /* Resume connecting to the chosen export. */
137 if (nbd_set_export_name (nbd, name) == -1 ||
138 nbd_opt_go (nbd) == -1) {
139 fprintf (stderr, "%s\n", nbd_get_error ());
140 exit (EXIT_FAILURE);
142 if (!nbd_aio_is_ready (nbd)) {
143 fprintf (stderr, "server closed early\n");
144 exit (EXIT_FAILURE);
147 /* Read the size in bytes and print it. */
148 size = nbd_get_size (nbd);
149 if (size == -1) {
150 fprintf (stderr, "%s\n", nbd_get_error ());
151 exit (EXIT_FAILURE);
153 printf ("%s: %s: size = %" PRIi64 " bytes\n",
154 argv[1], name, size);
156 /* Close the libnbd handle. */
157 nbd_close (nbd);
159 for (i = 0; i < list.i; i++)
160 free (list.names[i]);
161 free (list.names);
163 exit (EXIT_SUCCESS);