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
43 #define NBDKIT_API_VERSION 2
45 #include <nbdkit-plugin.h>
48 #include "ascii-string.h"
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 */
66 /* Call dump_plugin method. */
67 switch (call_read (&o
, args
)) {
73 /* Ignore if the method was missing. */
80 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
;
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.
105 return NBDKIT_THREAD_MODEL_PARALLEL
;
107 switch (call_read (&s
, args
)) {
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
;
123 nbdkit_debug ("%s: ignoring unrecognized thread model: %s",
125 r
= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
;
130 return NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
;
136 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
148 const char *method
= "get_ready";
149 const char *script
= get_script (method
);
150 const char *args
[] = { script
, method
, NULL
};
152 switch (call (args
)) {
161 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
173 const char *method
= "after_fork";
174 const char *script
= get_script (method
);
175 const char *args
[] = { script
, method
, NULL
};
177 switch (call (args
)) {
186 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
196 sh_preconnect (int readonly
)
198 const char *method
= "preconnect";
199 const char *script
= get_script (method
);
202 readonly
? "true" : "false",
205 switch (call (args
)) {
214 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
229 /* If @s begins with @prefix, return the next offset, else NULL */
231 skip_prefix (const char *s
, const char *prefix
)
233 size_t len
= strlen (prefix
);
234 if (strncmp (s
, prefix
, len
) == 0)
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
) {
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
);
258 if (nbdkit_add_export (exports
, name
, desc
) == -1)
263 else if ((p
= skip_prefix (s
, "NAMES+DESCRIPTIONS\n")) != NULL
) {
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');
272 d
= strchr (d
, '\n') + 1;
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
);
284 if (nbdkit_add_export (exports
, name
, desc
) == -1)
291 n
= skip_prefix (s
, "NAMES\n") ?: s
;
292 while ((p
= strchr (n
, '\n')) != NULL
) {
293 CLEANUP_FREE
char *name
= strndup (n
, p
- n
);
295 nbdkit_error ("%s: strndup: %m", script
);
298 if (nbdkit_add_export (exports
, name
, NULL
) == -1)
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
)) {
317 return parse_exports (script
, s
.ptr
, s
.len
, exports
);
320 return nbdkit_use_default_export (exports
);
326 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
;
345 switch (call_read (&s
, args
)) {
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
)
356 n
= strchr (p
, '\n') ?: s
.ptr
+ s
.len
;
357 return nbdkit_strndup_intern (p
, n
- p
);
366 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
376 sh_open (int readonly
)
378 const char *method
= "open";
379 const char *script
= get_script (method
);
382 readonly
? "true" : "false",
383 nbdkit_export_name () ? : "",
384 nbdkit_is_tls () > 0 ? "true" : "false",
386 struct sh_handle
*h
= calloc (1, sizeof *h
);
389 nbdkit_error ("malloc: %m");
395 /* We store the string returned by open in the handle. */
396 switch (call_read (&h
->h
, args
)) {
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';
402 nbdkit_debug ("sh: handle: %s", h
->h
.ptr
);
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");
420 string_reset (&h
->h
);
425 string_reset (&h
->h
);
427 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
)) {
449 string_reset (&h
->h
);
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
)) {
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
);
478 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
;
497 switch (call_read (&s
, args
)) {
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
);
503 nbdkit_error ("%s: could not parse output from get_size method: %s",
508 nbdkit_error ("%s: the get_size method is required", script
);
515 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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";
537 switch (call_read (&s
, args
)) {
539 if ((p
= strtok_r (s
.ptr
, delim
, &sp
)) == NULL
) {
541 nbdkit_error ("%s: %s method cannot be parsed", script
, method
);
544 r
= nbdkit_parse_size (p
);
545 if (r
== -1 || r
> UINT32_MAX
)
549 if ((p
= strtok_r (NULL
, delim
, &sp
)) == NULL
)
551 r
= nbdkit_parse_size (p
);
552 if (r
== -1 || r
> UINT32_MAX
)
556 if ((p
= strtok_r (NULL
, delim
, &sp
)) == NULL
)
558 r
= nbdkit_parse_size (p
);
559 if (r
== -1 || r
> UINT32_MAX
)
564 nbdkit_debug ("setting block_size: "
565 "minimum=%" PRIu32
" "
566 "preferred=%" PRIu32
" "
568 *minimum
, *preferred
, *maximum
);
573 *minimum
= *preferred
= *maximum
= 0;
580 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
590 sh_pread (void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
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
)) {
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
);
612 memcpy (buf
, data
.ptr
, count
);
616 nbdkit_error ("%s: the pread method is required", script
);
623 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
632 /* Convert NBDKIT_FLAG_* to flags string. */
633 static void flag_append (const char *str
, bool *comma
, char **buf
, size_t *len
);
636 flags_string (uint32_t flags
, char *buf
, size_t len
)
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
);
656 flag_append (const char *str
, bool *comma
, char **buf
, size_t *len
)
658 size_t slen
= strlen (str
);
661 /* Too short flags buffer is an internal error so abort. */
662 if (*len
<= 1) abort ();
668 if (*len
<= slen
) abort ();
677 sh_pwrite (void *handle
, const void *buf
, uint32_t count
, uint64_t offset
,
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
)) {
695 nbdkit_error ("pwrite not implemented");
702 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
711 /* Common code for handling all boolean methods like can_write etc. */
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
)) {
722 case RET_FALSE
: /* false */
724 case MISSING
: /* missing => caller chooses default */
726 case ERROR
: /* error cases */
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";
745 struct sh_handle
*h
= handle
;
747 if (h
->can_flush
>= 0)
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";
775 struct sh_handle
*h
= handle
;
777 if (h
->can_zero
>= 0)
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
;
811 switch (call_read (&s
, args
)) {
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)
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
;
822 nbdkit_error ("%s: could not parse output from %s method: %s",
823 script
, method
, s
.ptr
);
829 /* Check if the plugin claims to support flush. */
830 switch (sh_can_flush (handle
)) {
834 return NBDKIT_FUA_NONE
;
836 return NBDKIT_FUA_EMULATE
;
845 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
;
865 switch (call_read (&s
, args
)) {
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
;
876 nbdkit_error ("%s: could not parse output from %s method: %s",
877 script
, method
, s
.ptr
);
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
;
893 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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);
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
);
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
)) {
932 /* Ignore lack of flush callback. */
935 case ERROR
: /* error cases */
939 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
)) {
966 /* Ignore lack of trim callback. */
973 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
)) {
1000 nbdkit_debug ("zero falling back to pwrite");
1008 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
1018 parse_extents (const char *script
,
1019 const char *s
, size_t slen
, struct nbdkit_extents
*extents
)
1022 CLEANUP_FREE
char *line
= NULL
;
1027 fp
= fmemopen ((void *) s
, slen
, "r");
1029 nbdkit_error ("%s: extents: fmemopen: %m", script
);
1033 while ((len
= getline (&line
, &linelen
, fp
)) != -1) {
1034 const char *delim
= " \t";
1036 int64_t offset
, length
;
1039 if (len
> 0 && line
[len
-1] == '\n') {
1044 if ((p
= strtok_r (line
, delim
, &sp
)) == NULL
) {
1046 nbdkit_error ("%s: extents: cannot parse %s", script
, line
);
1049 offset
= nbdkit_parse_size (p
);
1053 if ((p
= strtok_r (NULL
, delim
, &sp
)) == NULL
)
1055 length
= nbdkit_parse_size (p
);
1059 if ((p
= strtok_r (NULL
, delim
, &sp
)) == NULL
)
1060 /* empty type field means allocated data (0) */
1062 else if (sscanf (p
, "%" SCNu32
, &type
) == 1)
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)
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
;
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
)) {
1104 r
= parse_extents (script
, s
.ptr
, s
.len
, extents
);
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",
1122 nbdkit_error ("%s: %s method returned unexpected code (3/false)",
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
);
1144 switch (call (args
)) {
1149 /* Ignore lack of cache callback. */
1156 nbdkit_error ("%s: %s method returned unexpected code (3/false)",