Update Red Hat Copyright Notices
[nbdkit.git] / plugins / sh / methods.c
blob736cd8ef07135aa4b96d3f97ca12f93f63605b6e
1 /* nbdkit
2 * Copyright Red Hat
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 <stdlib.h>
37 #include <stdbool.h>
38 #include <inttypes.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <errno.h>
43 #define NBDKIT_API_VERSION 2
45 #include <nbdkit-plugin.h>
47 #include "cleanup.h"
48 #include "ascii-string.h"
50 #include "call.h"
51 #include "methods.h"
53 void
54 sh_dump_plugin (void)
56 const char *method = "dump_plugin";
57 const char *script = get_script (method);
58 const char *args[] = { script, method, NULL };
59 CLEANUP_FREE_STRING string o = empty_vector;
61 /* Dump information about the sh/eval features */
62 printf ("max_known_status=%d\n", DISC_SOFT_ERR);
64 /* Dump any additional information from the script */
65 if (script) {
66 /* Call dump_plugin method. */
67 switch (call_read (&o, args)) {
68 case OK:
69 printf ("%s", o.ptr);
70 break;
72 case MISSING:
73 /* Ignore if the method was missing. */
74 break;
76 case ERROR:
77 break;
79 case RET_FALSE:
80 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
81 script, method);
82 errno = EIO;
83 return;
85 default: abort ();
90 int
91 sh_thread_model (void)
93 const char *method = "thread_model";
94 const char *script = get_script (method);
95 const char *args[] = { script, method, NULL };
96 CLEANUP_FREE_STRING string s = empty_vector;
97 int r;
99 /* For historical compatibility: the lack of a script is assumed to
100 * be parallel, but an existing script with missing or unparseable
101 * thread_model remains at the older (but safe)
102 * serialize_all_requests.
104 if (!script)
105 return NBDKIT_THREAD_MODEL_PARALLEL;
107 switch (call_read (&s, args)) {
108 case OK:
109 if (s.len > 0 && s.ptr[s.len-1] == '\n')
110 s.ptr[s.len-1] = '\0';
111 if (ascii_strcasecmp (s.ptr, "parallel") == 0)
112 r = NBDKIT_THREAD_MODEL_PARALLEL;
113 else if (ascii_strcasecmp (s.ptr, "serialize_requests") == 0 ||
114 ascii_strcasecmp (s.ptr, "serialize-requests") == 0)
115 r = NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS;
116 else if (ascii_strcasecmp (s.ptr, "serialize_all_requests") == 0 ||
117 ascii_strcasecmp (s.ptr, "serialize-all-requests") == 0)
118 r = NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS;
119 else if (ascii_strcasecmp (s.ptr, "serialize_connections") == 0 ||
120 ascii_strcasecmp (s.ptr, "serialize-connections") == 0)
121 r = NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS;
122 else {
123 nbdkit_debug ("%s: ignoring unrecognized thread model: %s",
124 script, s.ptr);
125 r = NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS;
127 return r;
129 case MISSING:
130 return NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS;
132 case ERROR:
133 return -1;
135 case RET_FALSE:
136 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
137 script, method);
138 errno = EIO;
139 return -1;
141 default: abort ();
146 sh_get_ready (void)
148 const char *method = "get_ready";
149 const char *script = get_script (method);
150 const char *args[] = { script, method, NULL };
152 switch (call (args)) {
153 case OK:
154 case MISSING:
155 return 0;
157 case ERROR:
158 return -1;
160 case RET_FALSE:
161 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
162 script, method);
163 errno = EIO;
164 return -1;
166 default: abort ();
171 sh_after_fork (void)
173 const char *method = "after_fork";
174 const char *script = get_script (method);
175 const char *args[] = { script, method, NULL };
177 switch (call (args)) {
178 case OK:
179 case MISSING:
180 return 0;
182 case ERROR:
183 return -1;
185 case RET_FALSE:
186 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
187 script, method);
188 errno = EIO;
189 return -1;
191 default: abort ();
196 sh_preconnect (int readonly)
198 const char *method = "preconnect";
199 const char *script = get_script (method);
200 const char *args[] =
201 { script, method,
202 readonly ? "true" : "false",
203 NULL };
205 switch (call (args)) {
206 case OK:
207 case MISSING:
208 return 0;
210 case ERROR:
211 return -1;
213 case RET_FALSE:
214 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
215 script, method);
216 errno = EIO;
217 return -1;
219 default: abort ();
223 struct sh_handle {
224 string h;
225 int can_flush;
226 int can_zero;
229 /* If @s begins with @prefix, return the next offset, else NULL */
230 static const char *
231 skip_prefix (const char *s, const char *prefix)
233 size_t len = strlen (prefix);
234 if (strncmp (s, prefix, len) == 0)
235 return s + len;
236 return NULL;
239 static int
240 parse_exports (const char *script,
241 const char *s, size_t slen, struct nbdkit_exports *exports)
243 const char *n, *d, *p, *q;
245 /* The first line determines how to parse the rest of s. Keep
246 * sh_default_export in sync with this.
248 if ((p = skip_prefix (s, "INTERLEAVED\n")) != NULL) {
249 n = p;
250 while ((d = strchr (n, '\n')) != NULL) {
251 p = strchr (d + 1, '\n') ?: d + 1;
252 CLEANUP_FREE char *name = strndup (n, d - n);
253 CLEANUP_FREE char *desc = strndup (d + 1, p - d - 1);
254 if (!name || !desc) {
255 nbdkit_error ("%s: strndup: %m", script);
256 return -1;
258 if (nbdkit_add_export (exports, name, desc) == -1)
259 return -1;
260 n = p + !!*p;
263 else if ((p = skip_prefix (s, "NAMES+DESCRIPTIONS\n")) != NULL) {
264 n = d = p;
265 /* Searching from both ends, using memrchr, would be less work, but
266 * memrchr is not widely portable. Multiple passes isn't too bad.
268 while (p && (p = strchr (p, '\n')) != NULL) {
269 p = strchr (p + 1, '\n');
270 if (p)
271 p++;
272 d = strchr (d, '\n') + 1;
274 s = d;
275 while (n < s) {
276 p = strchr (n, '\n');
277 q = strchr (d, '\n') ?: d;
278 CLEANUP_FREE char *name = strndup (n, p - n);
279 CLEANUP_FREE char *desc = strndup (d, q - d);
280 if (!name || !desc) {
281 nbdkit_error ("%s: strndup: %m", script);
282 return -1;
284 if (nbdkit_add_export (exports, name, desc) == -1)
285 return -1;
286 n = p + 1;
287 d = q + 1;
290 else {
291 n = skip_prefix (s, "NAMES\n") ?: s;
292 while ((p = strchr (n, '\n')) != NULL) {
293 CLEANUP_FREE char *name = strndup (n, p - n);
294 if (!name) {
295 nbdkit_error ("%s: strndup: %m", script);
296 return -1;
298 if (nbdkit_add_export (exports, name, NULL) == -1)
299 return -1;
300 n = p + 1;
303 return 0;
307 sh_list_exports (int readonly, int is_tls, struct nbdkit_exports *exports)
309 const char *method = "list_exports";
310 const char *script = get_script (method);
311 const char *args[] = { script, method, readonly ? "true" : "false",
312 is_tls ? "true" : "false", NULL };
313 CLEANUP_FREE_STRING string s = empty_vector;
315 switch (call_read (&s, args)) {
316 case OK:
317 return parse_exports (script, s.ptr, s.len, exports);
319 case MISSING:
320 return nbdkit_use_default_export (exports);
322 case ERROR:
323 return -1;
325 case RET_FALSE:
326 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
327 script, method);
328 errno = EIO;
329 return -1;
331 default: abort ();
335 const char *
336 sh_default_export (int readonly, int is_tls)
338 const char *method = "default_export";
339 const char *script = get_script (method);
340 const char *args[] = { script, method, readonly ? "true" : "false",
341 is_tls ? "true" : "false", NULL };
342 CLEANUP_FREE_STRING string s = empty_vector;
343 const char *p, *n;
345 switch (call_read (&s, args)) {
346 case OK:
347 /* The first line determines how to parse the rest of s. For now,
348 * all export modes treat the next line as the first export.
350 if ((p = skip_prefix (s.ptr, "INTERLEAVED\n")) != NULL ||
351 (p = skip_prefix (s.ptr, "NAMES+DESCRIPTIONS\n")) != NULL ||
352 (p = skip_prefix (s.ptr, "NAMES\n")) != NULL)
354 else
355 p = s.ptr;
356 n = strchr (p, '\n') ?: s.ptr + s.len;
357 return nbdkit_strndup_intern (p, n - p);
359 case MISSING:
360 return "";
362 case ERROR:
363 return NULL;
365 case RET_FALSE:
366 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
367 script, method);
368 errno = EIO;
369 return NULL;
371 default: abort ();
375 void *
376 sh_open (int readonly)
378 const char *method = "open";
379 const char *script = get_script (method);
380 const char *args[] =
381 { script, method,
382 readonly ? "true" : "false",
383 nbdkit_export_name () ? : "",
384 nbdkit_is_tls () > 0 ? "true" : "false",
385 NULL };
386 struct sh_handle *h = calloc (1, sizeof *h);
388 if (!h) {
389 nbdkit_error ("malloc: %m");
390 return NULL;
392 h->can_flush = -1;
393 h->can_zero = -1;
395 /* We store the string returned by open in the handle. */
396 switch (call_read (&h->h, args)) {
397 case OK:
398 /* Remove final newline if present. */
399 if (h->h.len > 0 && h->h.ptr[h->h.len-1] == '\n')
400 h->h.ptr[--h->h.len] = '\0';
401 if (h->h.len > 0)
402 nbdkit_debug ("sh: handle: %s", h->h.ptr);
403 return h;
405 case MISSING:
406 /* Unlike regular C plugins, open is not required. If it is
407 * missing then we return "" as the handle. Allocate a new string
408 * for it because we don't know what call_read returned here.
410 string_reset (&h->h);
411 if (string_reserve (&h->h, 1) == -1) {
412 nbdkit_error ("realloc: %m");
413 free (h);
414 return NULL;
416 h->h.ptr[0] = '\0';
417 return h;
419 case ERROR:
420 string_reset (&h->h);
421 free (h);
422 return NULL;
424 case RET_FALSE:
425 string_reset (&h->h);
426 free (h);
427 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
428 script, method);
429 errno = EIO;
430 return NULL;
432 default: abort ();
436 void
437 sh_close (void *handle)
439 const char *method = "close";
440 const char *script = get_script (method);
441 struct sh_handle *h = handle;
442 const char *args[] = { script, method, h->h.ptr, NULL };
444 switch (call (args)) {
445 case OK:
446 case MISSING:
447 case ERROR:
448 case RET_FALSE:
449 string_reset (&h->h);
450 free (h);
451 return;
452 default: abort ();
456 const char *
457 sh_export_description (void *handle)
459 const char *method = "export_description";
460 const char *script = get_script (method);
461 struct sh_handle *h = handle;
462 const char *args[] = { script, method, h->h.ptr, NULL };
463 CLEANUP_FREE_STRING string s = empty_vector;
465 switch (call_read (&s, args)) {
466 case OK:
467 if (s.len > 0 && s.ptr[s.len-1] == '\n')
468 s.ptr[s.len-1] = '\0';
469 return nbdkit_strdup_intern (s.ptr);
471 case MISSING:
472 return NULL;
474 case ERROR:
475 return NULL;
477 case RET_FALSE:
478 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
479 script, method);
480 errno = EIO;
481 return NULL;
483 default: abort ();
487 int64_t
488 sh_get_size (void *handle)
490 const char *method = "get_size";
491 const char *script = get_script (method);
492 struct sh_handle *h = handle;
493 const char *args[] = { script, method, h->h.ptr, NULL };
494 CLEANUP_FREE_STRING string s = empty_vector;
495 int64_t r;
497 switch (call_read (&s, args)) {
498 case OK:
499 if (s.len > 0 && s.ptr[s.len-1] == '\n')
500 s.ptr[s.len-1] = '\0';
501 r = nbdkit_parse_size (s.ptr);
502 if (r == -1)
503 nbdkit_error ("%s: could not parse output from get_size method: %s",
504 script, s.ptr);
505 return r;
507 case MISSING:
508 nbdkit_error ("%s: the get_size method is required", script);
509 return -1;
511 case ERROR:
512 return -1;
514 case RET_FALSE:
515 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
516 script, method);
517 errno = EIO;
518 return -1;
520 default: abort ();
525 sh_block_size (void *handle,
526 uint32_t *minimum, uint32_t *preferred, uint32_t *maximum)
528 const char *method = "block_size";
529 const char *script = get_script (method);
530 struct sh_handle *h = handle;
531 const char *args[] = { script, method, h->h.ptr, NULL };
532 CLEANUP_FREE_STRING string s = empty_vector;
533 const char *delim = " \t\n";
534 char *sp, *p;
535 int64_t r;
537 switch (call_read (&s, args)) {
538 case OK:
539 if ((p = strtok_r (s.ptr, delim, &sp)) == NULL) {
540 parse_error:
541 nbdkit_error ("%s: %s method cannot be parsed", script, method);
542 return -1;
544 r = nbdkit_parse_size (p);
545 if (r == -1 || r > UINT32_MAX)
546 goto parse_error;
547 *minimum = r;
549 if ((p = strtok_r (NULL, delim, &sp)) == NULL)
550 goto parse_error;
551 r = nbdkit_parse_size (p);
552 if (r == -1 || r > UINT32_MAX)
553 goto parse_error;
554 *preferred = r;
556 if ((p = strtok_r (NULL, delim, &sp)) == NULL)
557 goto parse_error;
558 r = nbdkit_parse_size (p);
559 if (r == -1 || r > UINT32_MAX)
560 goto parse_error;
561 *maximum = r;
563 #if 0
564 nbdkit_debug ("setting block_size: "
565 "minimum=%" PRIu32 " "
566 "preferred=%" PRIu32 " "
567 "maximum=%" PRIu32,
568 *minimum, *preferred, *maximum);
569 #endif
570 return 0;
572 case MISSING:
573 *minimum = *preferred = *maximum = 0;
574 return 0;
576 case ERROR:
577 return -1;
579 case RET_FALSE:
580 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
581 script, method);
582 errno = EIO;
583 return -1;
585 default: abort ();
590 sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
591 uint32_t flags)
593 const char *method = "pread";
594 const char *script = get_script (method);
595 struct sh_handle *h = handle;
596 char cbuf[32], obuf[32];
597 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, NULL };
598 CLEANUP_FREE_STRING string data = empty_vector;
600 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
601 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
603 switch (call_read (&data, args)) {
604 case OK:
605 if (count != data.len) {
606 nbdkit_error ("%s: incorrect amount of data read: "
607 "expecting %" PRIu32 " bytes but "
608 "received %zu bytes from the script",
609 script, count, data.len);
610 return -1;
612 memcpy (buf, data.ptr, count);
613 return 0;
615 case MISSING:
616 nbdkit_error ("%s: the pread method is required", script);
617 return -1;
619 case ERROR:
620 return -1;
622 case RET_FALSE:
623 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
624 script, method);
625 errno = EIO;
626 return -1;
628 default: abort ();
632 /* Convert NBDKIT_FLAG_* to flags string. */
633 static void flag_append (const char *str, bool *comma, char **buf, size_t *len);
635 static void
636 flags_string (uint32_t flags, char *buf, size_t len)
638 bool comma = false;
640 buf[0] = '\0';
642 if (flags & NBDKIT_FLAG_FUA)
643 flag_append ("fua", &comma, &buf, &len);
645 if (flags & NBDKIT_FLAG_MAY_TRIM)
646 flag_append ("may_trim", &comma, &buf, &len);
648 if (flags & NBDKIT_FLAG_REQ_ONE)
649 flag_append ("req_one", &comma, &buf, &len);
651 if (flags & NBDKIT_FLAG_FAST_ZERO)
652 flag_append ("fast", &comma, &buf, &len);
655 static void
656 flag_append (const char *str, bool *comma, char **buf, size_t *len)
658 size_t slen = strlen (str);
660 if (*comma) {
661 /* Too short flags buffer is an internal error so abort. */
662 if (*len <= 1) abort ();
663 strcpy (*buf, ",");
664 (*buf)++;
665 (*len)--;
668 if (*len <= slen) abort ();
669 strcpy (*buf, str);
670 (*buf) += slen;
671 (*len) -= slen;
673 *comma = true;
677 sh_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
678 uint32_t flags)
680 const char *method = "pwrite";
681 const char *script = get_script (method);
682 struct sh_handle *h = handle;
683 char cbuf[32], obuf[32], fbuf[32];
684 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, fbuf, NULL };
686 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
687 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
688 flags_string (flags, fbuf, sizeof fbuf);
690 switch (call_write (buf, count, args)) {
691 case OK:
692 return 0;
694 case MISSING:
695 nbdkit_error ("pwrite not implemented");
696 return -1;
698 case ERROR:
699 return -1;
701 case RET_FALSE:
702 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
703 script, method);
704 errno = EIO;
705 return -1;
707 default: abort ();
711 /* Common code for handling all boolean methods like can_write etc. */
712 static int
713 boolean_method (const char *script, const char *method,
714 void *handle, int def)
716 struct sh_handle *h = handle;
717 const char *args[] = { script, method, h->h.ptr, NULL };
719 switch (call (args)) {
720 case OK: /* true */
721 return 1;
722 case RET_FALSE: /* false */
723 return 0;
724 case MISSING: /* missing => caller chooses default */
725 return def;
726 case ERROR: /* error cases */
727 return -1;
728 default: abort ();
733 sh_can_write (void *handle)
735 const char *method = "can_write";
736 const char *script = get_script (method);
737 return boolean_method (script, method, handle, 0);
741 sh_can_flush (void *handle)
743 const char *method = "can_flush";
744 const char *script;
745 struct sh_handle *h = handle;
747 if (h->can_flush >= 0)
748 return h->can_flush;
750 script = get_script (method);
751 return h->can_flush = boolean_method (script, method, handle, 0);
755 sh_is_rotational (void *handle)
757 const char *method = "is_rotational";
758 const char *script = get_script (method);
759 return boolean_method (script, method, handle, 0);
763 sh_can_trim (void *handle)
765 const char *method = "can_trim";
766 const char *script = get_script (method);
767 return boolean_method (script, method, handle, 0);
771 sh_can_zero (void *handle)
773 const char *method = "can_zero";
774 const char *script;
775 struct sh_handle *h = handle;
777 if (h->can_zero >= 0)
778 return h->can_zero;
780 script = get_script (method);
781 return h->can_zero = boolean_method (script, method, handle, 0);
785 sh_can_extents (void *handle)
787 const char *method = "can_extents";
788 const char *script = get_script (method);
789 return boolean_method (script, method, handle, 0);
793 sh_can_multi_conn (void *handle)
795 const char *method = "can_multi_conn";
796 const char *script = get_script (method);
797 return boolean_method (script, method, handle, 0);
800 /* Not a boolean method, the method prints "none", "emulate" or "native". */
802 sh_can_fua (void *handle)
804 const char *method = "can_fua";
805 const char *script = get_script (method);
806 struct sh_handle *h = handle;
807 const char *args[] = { script, method, h->h.ptr, NULL };
808 CLEANUP_FREE_STRING string s = empty_vector;
809 int r;
811 switch (call_read (&s, args)) {
812 case OK:
813 if (s.len > 0 && s.ptr[s.len-1] == '\n')
814 s.ptr[s.len-1] = '\0';
815 if (ascii_strcasecmp (s.ptr, "none") == 0)
816 r = NBDKIT_FUA_NONE;
817 else if (ascii_strcasecmp (s.ptr, "emulate") == 0)
818 r = NBDKIT_FUA_EMULATE;
819 else if (ascii_strcasecmp (s.ptr, "native") == 0)
820 r = NBDKIT_FUA_NATIVE;
821 else {
822 nbdkit_error ("%s: could not parse output from %s method: %s",
823 script, method, s.ptr);
824 r = -1;
826 return r;
828 case MISSING:
829 /* Check if the plugin claims to support flush. */
830 switch (sh_can_flush (handle)) {
831 case -1:
832 return -1;
833 case 0:
834 return NBDKIT_FUA_NONE;
835 case 1:
836 return NBDKIT_FUA_EMULATE;
837 default:
838 abort ();
841 case ERROR:
842 return -1;
844 case RET_FALSE:
845 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
846 script, method);
847 errno = EIO;
848 return -1;
850 default: abort ();
854 /* Not a boolean method, the method prints "none", "emulate" or "native". */
856 sh_can_cache (void *handle)
858 const char *method = "can_cache";
859 const char *script = get_script (method);
860 struct sh_handle *h = handle;
861 const char *args[] = { script, method, h->h.ptr, NULL };
862 CLEANUP_FREE_STRING string s = empty_vector;
863 int r;
865 switch (call_read (&s, args)) {
866 case OK:
867 if (s.len > 0 && s.ptr[s.len-1] == '\n')
868 s.ptr[s.len-1] = '\0';
869 if (ascii_strcasecmp (s.ptr, "none") == 0)
870 r = NBDKIT_CACHE_NONE;
871 else if (ascii_strcasecmp (s.ptr, "emulate") == 0)
872 r = NBDKIT_CACHE_EMULATE;
873 else if (ascii_strcasecmp (s.ptr, "native") == 0)
874 r = NBDKIT_CACHE_NATIVE;
875 else {
876 nbdkit_error ("%s: could not parse output from %s method: %s",
877 script, method, s.ptr);
878 r = -1;
880 return r;
882 case MISSING:
883 /* NBDKIT_CACHE_EMULATE means that nbdkit will call .pread. However
884 * we cannot know if that fallback would be efficient, so the safest
885 * default is to return NBDKIT_CACHE_NONE.
887 return NBDKIT_CACHE_NONE;
889 case ERROR:
890 return -1;
892 case RET_FALSE:
893 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
894 script, method);
895 errno = EIO;
896 return -1;
898 default: abort ();
903 sh_can_fast_zero (void *handle)
905 const char *method = "can_fast_zero";
906 const char *script = get_script (method);
907 int r = boolean_method (script, method, handle, 2);
908 if (r < 2)
909 return r;
910 /* We need to duplicate the logic of plugins.c: if can_fast_zero is
911 * missing, we advertise fast fail support when can_zero is false.
913 r = sh_can_zero (handle);
914 if (r == -1)
915 return -1;
916 return !r;
920 sh_flush (void *handle, uint32_t flags)
922 const char *method = "flush";
923 const char *script = get_script (method);
924 struct sh_handle *h = handle;
925 const char *args[] = { script, method, h->h.ptr, NULL };
927 switch (call (args)) {
928 case OK:
929 return 0;
931 case MISSING:
932 /* Ignore lack of flush callback. */
933 return 0;
935 case ERROR: /* error cases */
936 return -1;
938 case RET_FALSE:
939 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
940 script, method);
941 errno = EIO;
942 return -1;
944 default: abort ();
949 sh_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
951 const char *method = "trim";
952 const char *script = get_script (method);
953 struct sh_handle *h = handle;
954 char cbuf[32], obuf[32], fbuf[32];
955 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, fbuf, NULL };
957 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
958 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
959 flags_string (flags, fbuf, sizeof fbuf);
961 switch (call (args)) {
962 case OK:
963 return 0;
965 case MISSING:
966 /* Ignore lack of trim callback. */
967 return 0;
969 case ERROR:
970 return -1;
972 case RET_FALSE:
973 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
974 script, method);
975 errno = EIO;
976 return -1;
978 default: abort ();
983 sh_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
985 const char *method = "zero";
986 const char *script = get_script (method);
987 struct sh_handle *h = handle;
988 char cbuf[32], obuf[32], fbuf[32];
989 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, fbuf, NULL };
991 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
992 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
993 flags_string (flags, fbuf, sizeof fbuf);
995 switch (call (args)) {
996 case OK:
997 return 0;
999 case MISSING:
1000 nbdkit_debug ("zero falling back to pwrite");
1001 errno = EOPNOTSUPP;
1002 return -1;
1004 case ERROR:
1005 return -1;
1007 case RET_FALSE:
1008 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
1009 script, method);
1010 errno = EIO;
1011 return -1;
1013 default: abort ();
1017 static int
1018 parse_extents (const char *script,
1019 const char *s, size_t slen, struct nbdkit_extents *extents)
1021 FILE *fp = NULL;
1022 CLEANUP_FREE char *line = NULL;
1023 size_t linelen = 0;
1024 ssize_t len;
1025 int ret = -1;
1027 fp = fmemopen ((void *) s, slen, "r");
1028 if (!fp) {
1029 nbdkit_error ("%s: extents: fmemopen: %m", script);
1030 goto out;
1033 while ((len = getline (&line, &linelen, fp)) != -1) {
1034 const char *delim = " \t";
1035 char *sp, *p;
1036 int64_t offset, length;
1037 uint32_t type;
1039 if (len > 0 && line[len-1] == '\n') {
1040 line[len-1] = '\0';
1041 len--;
1044 if ((p = strtok_r (line, delim, &sp)) == NULL) {
1045 parse_error:
1046 nbdkit_error ("%s: extents: cannot parse %s", script, line);
1047 goto out;
1049 offset = nbdkit_parse_size (p);
1050 if (offset == -1)
1051 goto out;
1053 if ((p = strtok_r (NULL, delim, &sp)) == NULL)
1054 goto parse_error;
1055 length = nbdkit_parse_size (p);
1056 if (length == -1)
1057 goto out;
1059 if ((p = strtok_r (NULL, delim, &sp)) == NULL)
1060 /* empty type field means allocated data (0) */
1061 type = 0;
1062 else if (sscanf (p, "%" SCNu32, &type) == 1)
1064 else {
1065 type = 0;
1066 if (strstr (p, "hole") != NULL)
1067 type |= NBDKIT_EXTENT_HOLE;
1068 if (strstr (p, "zero") != NULL)
1069 type |= NBDKIT_EXTENT_ZERO;
1072 nbdkit_debug ("%s: adding extent %" PRIi64 " %" PRIi64 " %" PRIu32,
1073 script, offset, length, type);
1074 if (nbdkit_add_extent (extents, offset, length, type) == -1)
1075 goto out;
1078 ret = 0;
1080 out:
1081 if (fp)
1082 fclose (fp);
1083 return ret;
1087 sh_extents (void *handle, uint32_t count, uint64_t offset, uint32_t flags,
1088 struct nbdkit_extents *extents)
1090 const char *method = "extents";
1091 const char *script = get_script (method);
1092 struct sh_handle *h = handle;
1093 char cbuf[32], obuf[32], fbuf[32];
1094 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, fbuf, NULL };
1095 CLEANUP_FREE_STRING string s = empty_vector;
1096 int r;
1098 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
1099 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
1100 flags_string (flags, fbuf, sizeof fbuf);
1102 switch (call_read (&s, args)) {
1103 case OK:
1104 r = parse_extents (script, s.ptr, s.len, extents);
1105 return r;
1107 case MISSING:
1108 /* extents method should not have been called unless the script
1109 * defined a can_extents method which returns true, so if this
1110 * happens it's a script error.
1112 nbdkit_error ("%s: can_extents returned true, "
1113 "but extents method is not defined",
1114 script);
1115 errno = EIO;
1116 return -1;
1118 case ERROR:
1119 return -1;
1121 case RET_FALSE:
1122 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
1123 script, method);
1124 errno = EIO;
1125 return -1;
1127 default: abort ();
1132 sh_cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
1134 const char *method = "cache";
1135 const char *script = get_script (method);
1136 struct sh_handle *h = handle;
1137 char cbuf[32], obuf[32];
1138 const char *args[] = { script, method, h->h.ptr, cbuf, obuf, NULL };
1140 snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
1141 snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
1142 assert (!flags);
1144 switch (call (args)) {
1145 case OK:
1146 return 0;
1148 case MISSING:
1149 /* Ignore lack of cache callback. */
1150 return 0;
1152 case ERROR:
1153 return -1;
1155 case RET_FALSE:
1156 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
1157 script, method);
1158 errno = EIO;
1159 return -1;
1161 default: abort ();