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
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
39 #include <nbdkit-filter.h>
42 #include "open_memstream.h"
45 static const char *default_export
;
60 static const char *desc
;
61 struct nbdkit_exports
*exports
;
64 exportname_load (void)
66 exports
= nbdkit_exports_new ();
68 nbdkit_error ("malloc: %m");
74 exportname_unload (void)
76 nbdkit_exports_free (exports
);
79 /* Called for each key=value passed on the command line. */
81 exportname_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
82 const char *key
, const char *value
)
86 if (strcmp (key
, "default-export") == 0 ||
87 strcmp (key
, "default_export") == 0) {
88 default_export
= value
;
91 if (strcmp (key
, "exportname-list") == 0 ||
92 strcmp (key
, "exportname_list") == 0) {
93 if (strcmp (value
, "keep") == 0)
95 else if (strcmp (value
, "error") == 0)
97 else if (strcmp (value
, "empty") == 0)
99 else if (strcmp (value
, "defaultonly") == 0 ||
100 strcmp (value
, "default-only") == 0)
102 else if (strcmp (value
, "explicit") == 0)
103 list
= LIST_EXPLICIT
;
105 nbdkit_error ("unrecognized exportname-list mode: %s", value
);
110 if (strcmp (key
, "exportname-strict") == 0 ||
111 strcmp (key
, "exportname_strict") == 0) {
112 r
= nbdkit_parse_bool (value
);
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
;
127 else if (strncmp (value
, "fixed:", 6) == 0) {
128 desc_mode
= DESC_FIXED
;
131 else if (strncmp (value
, "script:", 7) == 0) {
132 desc_mode
= DESC_SCRIPT
;
136 nbdkit_error ("unrecognized exportdesc mode: %s", value
);
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" \
154 get_desc (const char *name
, const char *def
)
157 CLEANUP_FREE
char *cmd
= NULL
;
159 char buf
[4096]; /* Maximum NBD string; we truncate any longer response */
174 /* Construct the command. */
175 fp
= open_memstream (&cmd
, &cmdlen
);
177 nbdkit_debug ("open_memstream: %m");
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");
187 nbdkit_debug ("%s", cmd
);
188 fp
= popen (cmd
, "r");
190 nbdkit_debug ("popen: %m");
194 /* Now read the description */
195 r
= fread (buf
, 1, sizeof buf
, fp
);
196 if (r
== 0 && ferror (fp
)) {
197 nbdkit_debug ("fread: %m");
202 if (r
&& buf
[r
-1] == '\n')
204 return nbdkit_strndup_intern (buf
, r
);
208 exportname_list_exports (nbdkit_next_list_exports
*next
,
209 nbdkit_backend
*nxdata
,
210 int readonly
, int is_tls
,
211 struct nbdkit_exports
*exps
)
214 struct nbdkit_exports
*source
;
215 CLEANUP_EXPORTS_FREE
struct nbdkit_exports
*exps2
= NULL
;
219 source
= exps2
= nbdkit_exports_new ();
222 if (next (nxdata
, readonly
, exps2
) == -1)
226 nbdkit_error ("export list restricted by policy");
231 return nbdkit_use_default_export (exps
);
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)
250 exportname_default_export (nbdkit_next_default_export
*next
,
251 nbdkit_backend
*nxdata
,
252 int readonly
, int is_tls
)
256 /* If we are strict, do not allow connection unless "" was advertised. */
258 for (i
= 0; i
< nbdkit_exports_count (exports
); i
++) {
259 if (nbdkit_get_export (exports
, i
).name
[0] == '\0')
260 return default_export
?: "";
266 return default_export
;
267 return next (nxdata
, readonly
);
275 exportname_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
276 int readonly
, const char *exportname
, int is_tls
)
282 for (i
= 0; i
< nbdkit_exports_count (exports
); i
++) {
283 if (strcmp (nbdkit_get_export (exports
, i
).name
, exportname
) == 0)
286 if (i
== nbdkit_exports_count (exports
)) {
287 nbdkit_error ("export '%s not found", exportname
);
293 h
= malloc (sizeof *h
);
295 nbdkit_error ("malloc: %m");
299 h
->name
= nbdkit_strdup_intern (exportname
);
300 if (h
->name
== NULL
) {
304 if (next (nxdata
, readonly
, exportname
) == -1) {
313 exportname_close (void *handle
)
319 exportname_export_description (nbdkit_next
*next
,
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
)