docs: Fix typo in nbdkit-protocol(1)
[nbdkit.git] / filters / exportname / exportname.c
blob277b8125b1f12748524af5aedfd2f20a681b32ba
1 /* nbdkit
2 * Copyright (C) 2020 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdbool.h>
37 #include <string.h>
39 #include <nbdkit-filter.h>
41 #include "cleanup.h"
42 #include "open_memstream.h"
43 #include "utils.h"
45 static const char *default_export;
46 static enum {
47 LIST_KEEP,
48 LIST_ERROR,
49 LIST_EMPTY,
50 LIST_DEFAULT,
51 LIST_EXPLICIT,
52 } list;
53 static bool strict;
54 static enum {
55 DESC_KEEP,
56 DESC_NONE,
57 DESC_FIXED,
58 DESC_SCRIPT,
59 } desc_mode;
60 static const char *desc;
61 struct nbdkit_exports *exports;
63 static void
64 exportname_load (void)
66 exports = nbdkit_exports_new ();
67 if (!exports) {
68 nbdkit_error ("malloc: %m");
69 exit (EXIT_FAILURE);
73 static void
74 exportname_unload (void)
76 nbdkit_exports_free (exports);
79 /* Called for each key=value passed on the command line. */
80 static int
81 exportname_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
82 const char *key, const char *value)
84 int r;
86 if (strcmp (key, "default-export") == 0 ||
87 strcmp (key, "default_export") == 0) {
88 default_export = value;
89 return 0;
91 if (strcmp (key, "exportname-list") == 0 ||
92 strcmp (key, "exportname_list") == 0) {
93 if (strcmp (value, "keep") == 0)
94 list = LIST_KEEP;
95 else if (strcmp (value, "error") == 0)
96 list = LIST_ERROR;
97 else if (strcmp (value, "empty") == 0)
98 list = LIST_EMPTY;
99 else if (strcmp (value, "defaultonly") == 0 ||
100 strcmp (value, "default-only") == 0)
101 list = LIST_DEFAULT;
102 else if (strcmp (value, "explicit") == 0)
103 list = LIST_EXPLICIT;
104 else {
105 nbdkit_error ("unrecognized exportname-list mode: %s", value);
106 return -1;
108 return 0;
110 if (strcmp (key, "exportname-strict") == 0 ||
111 strcmp (key, "exportname_strict") == 0) {
112 r = nbdkit_parse_bool (value);
113 if (r == -1)
114 return -1;
115 strict = r;
116 return 0;
118 if (strcmp (key, "exportname") == 0)
119 return nbdkit_add_export (exports, value, NULL);
120 if (strcmp (key, "exportdesc") == 0) {
121 if (strcmp (value, "keep") == 0)
122 desc_mode = DESC_KEEP;
123 else if (strcmp (value, "none") == 0) {
124 desc_mode = DESC_NONE;
125 desc = NULL;
127 else if (strncmp (value, "fixed:", 6) == 0) {
128 desc_mode = DESC_FIXED;
129 desc = value + 6;
131 else if (strncmp (value, "script:", 7) == 0) {
132 desc_mode = DESC_SCRIPT;
133 desc = value + 7;
135 else {
136 nbdkit_error ("unrecognized exportdesc mode: %s", value);
137 return -1;
139 return 0;
141 return next (nxdata, key, value);
144 #define exportname_config_help \
145 "default-export=<NAME> Canonical name for the \"\" default export.\n" \
146 "exportname-list=<MODE> Which exports to advertise: keep (default), error,\n" \
147 " empty, defaultonly, explicit.\n" \
148 "exportname-strict=<BOOL> Limit clients to explicit exports (default false).\n" \
149 "exportname=<NAME> Add an explicit export name, may be repeated.\n" \
150 "exportdesc=<MODE> Set descriptions according to mode: keep (default),\n" \
151 " none, fixed:STRING, script:SCRIPT.\n" \
153 static const char *
154 get_desc (const char *name, const char *def)
156 FILE *fp;
157 CLEANUP_FREE char *cmd = NULL;
158 size_t cmdlen = 0;
159 char buf[4096]; /* Maximum NBD string; we truncate any longer response */
160 size_t r;
162 switch (desc_mode) {
163 case DESC_KEEP:
164 return def;
165 case DESC_NONE:
166 case DESC_FIXED:
167 return desc;
168 case DESC_SCRIPT:
169 break;
170 default:
171 abort ();
174 /* Construct the command. */
175 fp = open_memstream (&cmd, &cmdlen);
176 if (fp == NULL) {
177 nbdkit_debug ("open_memstream: %m");
178 return NULL;
180 fprintf (fp, "export name; name=");
181 shell_quote (name, fp);
182 fprintf (fp, "\n%s\n", desc);
183 if (close_memstream (fp) == -1) {
184 nbdkit_debug ("memstream failed: %m");
185 return NULL;
187 nbdkit_debug ("%s", cmd);
188 fp = popen (cmd, "r");
189 if (fp == NULL) {
190 nbdkit_debug ("popen: %m");
191 return NULL;
194 /* Now read the description */
195 r = fread (buf, 1, sizeof buf, fp);
196 if (r == 0 && ferror (fp)) {
197 nbdkit_debug ("fread: %m");
198 pclose (fp);
199 return NULL;
201 pclose (fp);
202 if (r && buf[r-1] == '\n')
203 r--;
204 return nbdkit_strndup_intern (buf, r);
207 static int
208 exportname_list_exports (nbdkit_next_list_exports *next,
209 nbdkit_backend *nxdata,
210 int readonly, int is_tls,
211 struct nbdkit_exports *exps)
213 size_t i;
214 struct nbdkit_exports *source;
215 CLEANUP_EXPORTS_FREE struct nbdkit_exports *exps2 = NULL;
217 switch (list) {
218 case LIST_KEEP:
219 source = exps2 = nbdkit_exports_new ();
220 if (exps2 == NULL)
221 return -1;
222 if (next (nxdata, readonly, exps2) == -1)
223 return -1;
224 break;
225 case LIST_ERROR:
226 nbdkit_error ("export list restricted by policy");
227 return -1;
228 case LIST_EMPTY:
229 return 0;
230 case LIST_DEFAULT:
231 return nbdkit_use_default_export (exps);
232 case LIST_EXPLICIT:
233 source = exports;
234 break;
235 default:
236 abort ();
239 for (i = 0; i < nbdkit_exports_count (source); i++) {
240 struct nbdkit_export e = nbdkit_get_export (source, i);
242 if (nbdkit_add_export (exps, e.name,
243 get_desc (e.name, e.description)) == -1)
244 return -1;
246 return 0;
249 static const char *
250 exportname_default_export (nbdkit_next_default_export *next,
251 nbdkit_backend *nxdata,
252 int readonly, int is_tls)
254 size_t i;
256 /* If we are strict, do not allow connection unless "" was advertised. */
257 if (strict) {
258 for (i = 0; i < nbdkit_exports_count (exports); i++) {
259 if (nbdkit_get_export (exports, i).name[0] == '\0')
260 return default_export ?: "";
262 return NULL;
265 if (default_export)
266 return default_export;
267 return next (nxdata, readonly);
270 struct handle {
271 const char *name;
274 static void *
275 exportname_open (nbdkit_next_open *next, nbdkit_context *nxdata,
276 int readonly, const char *exportname, int is_tls)
278 size_t i;
279 struct handle *h;
281 if (strict) {
282 for (i = 0; i < nbdkit_exports_count (exports); i++) {
283 if (strcmp (nbdkit_get_export (exports, i).name, exportname) == 0)
284 break;
286 if (i == nbdkit_exports_count (exports)) {
287 nbdkit_error ("export '%s not found", exportname);
288 errno = ENOENT;
289 return NULL;
293 h = malloc (sizeof *h);
294 if (h == NULL) {
295 nbdkit_error ("malloc: %m");
296 return NULL;
299 h->name = nbdkit_strdup_intern (exportname);
300 if (h->name == NULL) {
301 free (h);
302 return NULL;
304 if (next (nxdata, readonly, exportname) == -1) {
305 free (h);
306 return NULL;
309 return h;
312 static void
313 exportname_close (void *handle)
315 free (handle);
318 static const char *
319 exportname_export_description (nbdkit_next *next,
320 void *handle)
322 struct handle *h = handle;
323 const char *def = NULL;
325 if (desc_mode == DESC_KEEP)
326 def = next->export_description (next);
328 return get_desc (h->name, def);
331 static struct nbdkit_filter filter = {
332 .name = "exportname",
333 .longname = "nbdkit exportname filter",
334 .load = exportname_load,
335 .unload = exportname_unload,
336 .config = exportname_config,
337 .config_help = exportname_config_help,
338 .list_exports = exportname_list_exports,
339 .default_export = exportname_default_export,
340 .open = exportname_open,
341 .close = exportname_close,
342 .export_description = exportname_export_description,
345 NBDKIT_REGISTER_FILTER(filter)