Richard W.M. Jones
2018-Dec-15 11:01 UTC
[Libguestfs] [PATCH nbdkit v2 0/4] tests: Test export flags (eflags).
v1 was here: https://www.redhat.com/archives/libguestfs/2018-December/thread.html#00123 v2: - Document "-" instead of "script=-" and use it in the test; and verify this also works on FreeBSD; and verify that it doesn't depend on the particular behaviour of our wrapper script and should work with installed nbdkit too. - Fix handling of zero flags parameter. - Add "to stdout" for can_fua. - "In future" -> "In the future," in various places. - Make the test work on FreeBSD by avoiding use of endian swaps. - Use socat "cool-write" to avoid occasional EPIPE error seen in tests. - Retest on Linux & FreeBSD. - Extra commit for a small documentation change in nbdkit-sh-plugin. Rich.
Richard W.M. Jones
2018-Dec-15 11:01 UTC
[Libguestfs] [PATCH nbdkit v2 1/4] sh: Implement inline scripts.
This implements a readonly disk reading as zeroes:
nbdkit sh - <<'EOF'
case "$1" in
get_size) echo 1M ;;
pread) dd if=/dev/zero count=$3 iflag=count_bytes ;;
*) exit 2 ;;
esac
EOF
Use of "-" is analogous to reading passwords from stdin.
---
plugins/sh/nbdkit-sh-plugin.pod | 20 ++++++++++++
plugins/sh/sh.c | 55 ++++++++++++++++++++++++++++++++-
2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index 371de5f..2765841 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -6,6 +6,10 @@ nbdkit-sh-plugin - nbdkit shell, script or executable plugin
nbdkit sh /path/to/script [arguments...]
+ nbdkit sh - <<'EOF'
+ ... shell script ...
+ EOF
+
=head1 DESCRIPTION
C<nbdkit-sh-plugin> allows you to write plugins for L<nbdkit(1)>
using
@@ -26,6 +30,22 @@ like this:
You may have to add further C<key=value> arguments to the command
line.
+=head2 Inline shell scripts
+
+It is also possible to write a shell script plugin "inline" using
C<->
+as the name of the script, like this:
+
+ nbdkit sh - <<'EOF'
+ case "$1" in
+ get_size) echo 1M ;;
+ pread) dd if=/dev/zero count=$3 iflag=count_bytes ;;
+ *) exit 2 ;;
+ esac
+ EOF
+
+By default the inline script runs under F</bin/sh>. You can add a
+shebang (C<#!>) to use other scripting languages.
+
=head1 WRITING AN NBDKIT SH PLUGIN
For an example plugin written in Bash, see:
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index 368f1eb..4ca394f 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -39,6 +39,7 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/stat.h>
#include <nbdkit-plugin.h>
@@ -115,6 +116,50 @@ sh_dump_plugin (void)
}
}
+/* This implements the "inline script" feature. Read stdin into a
+ * temporary file and return the name of the file which the caller
+ * must free. For convenience we put the temporary file into tmpdir
+ * but that's an implementation detail.
+ */
+static char *
+inline_script (void)
+{
+ const char scriptname[] = "inline-script.sh";
+ char *filename = NULL;
+ char *cmd = NULL;
+
+ if (asprintf (&filename, "%s/%s", tmpdir, scriptname) == -1) {
+ nbdkit_error ("asprintf: %m");
+ goto err;
+ }
+
+ /* Safe because both the tmpdir and script name are controlled by us
+ * and don't contain characters that need quoting.
+ */
+ if (asprintf (&cmd, "cat > %s", filename) == -1) {
+ nbdkit_error ("asprintf: %m");
+ goto err;
+ }
+
+ if (system (cmd) != 0) {
+ nbdkit_error ("sh: failed to copy inline script to temporary
file");
+ goto err;
+ }
+
+ if (chmod (filename, 0500) == -1) {
+ nbdkit_error ("chmod: %s: %m", filename);
+ goto err;
+ }
+
+ free (cmd);
+ return filename;
+
+ err:
+ free (filename);
+ free (cmd);
+ return NULL;
+}
+
static int
sh_config (const char *key, const char *value)
{
@@ -124,7 +169,15 @@ sh_config (const char *key, const char *value)
nbdkit_error ("the first parameter must be
script=/path/to/script");
return -1;
}
- script = nbdkit_realpath (value);
+
+ /* If the script name is not "-" then it's expected to be a
+ * filename, otherwise it's an inline script which must be read
+ * into a temporary file. Either way we want an absolute path.
+ */
+ if (strcmp (value, "-") != 0)
+ script = nbdkit_realpath (value);
+ else
+ script = inline_script ();
if (script == NULL)
return -1;
--
2.19.2
Richard W.M. Jones
2018-Dec-15 11:01 UTC
[Libguestfs] [PATCH nbdkit v2 2/4] sh: docs: Add note that the script must be executable.
--- plugins/sh/nbdkit-sh-plugin.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod index 2765841..14fe7b8 100644 --- a/plugins/sh/nbdkit-sh-plugin.pod +++ b/plugins/sh/nbdkit-sh-plugin.pod @@ -28,7 +28,7 @@ like this: nbdkit sh /path/to/script You may have to add further C<key=value> arguments to the command -line. +line. The script must be executable (C<chmod +x>). =head2 Inline shell scripts -- 2.19.2
Richard W.M. Jones
2018-Dec-15 11:01 UTC
[Libguestfs] [PATCH nbdkit v2 3/4] sh: Switch nbdkit-sh-plugin to use API version 2.
This allows us to add the following callbacks:
- can_zero returns boolean
- can_fua should print "none", "emulate" or
"native"
Furthermore the following callbacks are modified in a backwards
compatible manner:
- pwrite adding flags parameter
- trim adding flags parameter
This change is not backwards compatible:
- zero may_trim parameter replaced by flags parameter
---
plugins/sh/nbdkit-sh-plugin.pod | 43 +++++++---
plugins/sh/sh.c | 139 +++++++++++++++++++++++++++-----
2 files changed, 154 insertions(+), 28 deletions(-)
diff --git a/plugins/sh/nbdkit-sh-plugin.pod b/plugins/sh/nbdkit-sh-plugin.pod
index 14fe7b8..4cea076 100644
--- a/plugins/sh/nbdkit-sh-plugin.pod
+++ b/plugins/sh/nbdkit-sh-plugin.pod
@@ -199,17 +199,21 @@ This method is required.
=item C<can_trim>
+=item C<can_zero>
+
Unlike in other languages, you B<must> provide the C<can_*> methods
otherwise they are assumed to all return false and your C<pwrite>,
-C<flush> and C<trim> methods will never be called. The reason for
-this is obscure: In other languages we can detect if (eg) a C<pwrite>
-method is defined and synthesize an appropriate response if no actual
-C<can_write> method is defined. However detecting if methods are
-present without running them is not possible with this plugin.
+C<flush>, C<trim> and C<zero> methods will never be called.
The
+reason for this is obscure: In other languages we can detect if (eg) a
+C<pwrite> method is defined and synthesize an appropriate response if
+no actual C<can_write> method is defined. However detecting if
+methods are present without running them is not possible with this
+plugin.
/path/to/script can_write <handle>
/path/to/script can_flush <handle>
/path/to/script can_trim <handle>
+ /path/to/script can_zero <handle>
The script should exit with code C<0> for true or code C<3> for
false.
@@ -219,6 +223,16 @@ The script should exit with code C<0> for true or
code C<3> for false.
The script should exit with code C<0> for true or code C<3> for
false.
+=item C<can_fua>
+
+ /path/to/script can_fua <handle>
+
+This controls Forced Unit Access (FUA) behaviour of the core server.
+
+Unlike the other C<can_*> callbacks, this one is I<not> a boolean.
It
+must print either "none", "emulate" or "native"
to stdout. The
+meaning of these is described in L<nbdkit-plugin(3)>.
+
=item C<pread>
/path/to/script pread <handle> <count> <offset>
@@ -230,10 +244,13 @@ This method is required.
=item C<pwrite>
- /path/to/script pwrite <handle> <count> <offset>
+ /path/to/script pwrite <handle> <count> <offset>
<flags>
The script should read the binary data to be written from stdin.
+The C<flags> parameter can be an empty string or
C<"fua">. In the
+future, a comma-separated list of flags may be present.
+
Unlike in other languages, if you provide a C<pwrite> method you
B<must> also provide a C<can_write> method which exits with code
C<0>
(true).
@@ -248,16 +265,24 @@ B<must> also provide a C<can_flush> method
which exits with code C<0>
=item C<trim>
- /path/to/script trim <handle> <count> <offset>
+ /path/to/script trim <handle> <count> <offset> <flags>
+
+The C<flags> parameter can be an empty string or
C<"fua">. In the
+future, a comma-separated list of flags may be present.
Unlike in other languages, if you provide a C<trim> method you
B<must>
also provide a C<can_trim> method which exits with code C<0>
(true).
=item C<zero>
- /path/to/script zero <handle> <count> <offset>
<may_trim>
+ /path/to/script zero <handle> <count> <offset> <flags>
-C<may_trim> will be either C<true> or C<false>.
+The C<flags> parameter can be an empty string or a comma-separated
+list of the flags: C<"fua"> and C<"may_trim">
(eg. C<"">, C<"fua">,
+C<"fua,may_trim"> are all possible values).
+
+Unlike in other languages, if you provide a C<zero> method you
B<must>
+also provide a C<can_zero> method which exits with code C<0>
(true).
=back
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index 4ca394f..159052e 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -35,12 +35,15 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
+#define NBDKIT_API_VERSION 2
+
#include <nbdkit-plugin.h>
#include "call.h"
@@ -360,7 +363,8 @@ sh_get_size (void *handle)
}
static int
-sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
+sh_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
{
char *h = handle;
char cbuf[32], obuf[32];
@@ -403,16 +407,53 @@ sh_pread (void *handle, void *buf, uint32_t count,
uint64_t offset)
}
}
+/* Convert NBDKIT_FLAG_* to flags string. */
+static void flag_append (const char *str, bool *comma, char **buf, size_t
*len);
+
+static void
+flags_string (uint32_t flags, char *buf, size_t len)
+{
+ bool comma = false;
+
+ if (flags & NBDKIT_FLAG_FUA)
+ flag_append ("fua", &comma, &buf, &len);
+
+ if (flags & NBDKIT_FLAG_MAY_TRIM)
+ flag_append ("may_trim", &comma, &buf, &len);
+}
+
+static void
+flag_append (const char *str, bool *comma, char **buf, size_t *len)
+{
+ size_t slen = strlen (str);
+
+ if (*comma) {
+ /* Too short flags buffer is an internal error so abort. */
+ if (*len <= 1) abort ();
+ strcpy (*buf, ",");
+ (*buf)++;
+ (*len)--;
+ }
+
+ if (*len <= slen) abort ();
+ strcpy (*buf, str);
+ (*buf) += slen;
+ (*len) -= slen;
+
+ *comma = true;
+}
+
static int
-sh_pwrite (void *handle, const void *buf,
- uint32_t count, uint64_t offset)
+sh_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
{
char *h = handle;
- char cbuf[32], obuf[32];
- const char *args[] = { script, "pwrite", h, cbuf, obuf, NULL };
+ char cbuf[32], obuf[32], fbuf[32];
+ const char *args[] = { script, "pwrite", h, cbuf, obuf, fbuf, NULL
};
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
+ flags_string (flags, fbuf, sizeof fbuf);
switch (call_write (buf, count, args)) {
case OK:
@@ -467,12 +508,6 @@ sh_can_flush (void *handle)
return boolean_method (handle, "can_flush");
}
-static int
-sh_can_trim (void *handle)
-{
- return boolean_method (handle, "can_trim");
-}
-
static int
sh_is_rotational (void *handle)
{
@@ -480,7 +515,70 @@ sh_is_rotational (void *handle)
}
static int
-sh_flush (void *handle)
+sh_can_trim (void *handle)
+{
+ return boolean_method (handle, "can_trim");
+}
+
+static int
+sh_can_zero (void *handle)
+{
+ return boolean_method (handle, "can_zero");
+}
+
+static int
+sh_can_fua (void *handle)
+{
+ char *h = handle;
+ const char *args[] = { script, "can_fua", h, NULL };
+ char *s = NULL;
+ size_t slen;
+ int r;
+
+ switch (call_read (&s, &slen, args)) {
+ case OK:
+ if (slen > 0 && s[slen-1] == '\n')
+ s[slen-1] = '\0';
+ if (strcmp (s, "none") == 0)
+ r = NBDKIT_FUA_NONE;
+ else if (strcmp (s, "emulate") == 0)
+ r = NBDKIT_FUA_EMULATE;
+ else if (strcmp (s, "native") == 0)
+ r = NBDKIT_FUA_NATIVE;
+ else {
+ nbdkit_error ("%s: could not parse output from can_fua method:
%s",
+ script, s);
+ free (s);
+ return -1;
+ }
+ free (s);
+ return r;
+
+ case MISSING:
+ free (s);
+ /* NBDKIT_FUA_EMULATE means that nbdkit will call .flush. However
+ * we cannot know if that callback exists, so the safest default
+ * is to return NBDKIT_FUA_NONE.
+ */
+ return NBDKIT_FUA_NONE;
+
+ case ERROR:
+ free (s);
+ return -1;
+
+ case RET_FALSE:
+ free (s);
+ nbdkit_error ("%s: %s method returned unexpected code (3/false)",
+ script, "can_fua");
+ errno = EIO;
+ return -1;
+
+ default: abort ();
+ }
+}
+
+static int
+sh_flush (void *handle, uint32_t flags)
{
char *h = handle;
const char *args[] = { script, "flush", h, NULL };
@@ -507,14 +605,15 @@ sh_flush (void *handle)
}
static int
-sh_trim (void *handle, uint32_t count, uint64_t offset)
+sh_trim (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
char *h = handle;
- char cbuf[32], obuf[32];
- const char *args[] = { script, "trim", h, cbuf, obuf, NULL };
+ char cbuf[32], obuf[32], fbuf[32];
+ const char *args[] = { script, "trim", h, cbuf, obuf, fbuf, NULL };
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
+ flags_string (flags, fbuf, sizeof fbuf);
switch (call (args)) {
case OK:
@@ -538,15 +637,15 @@ sh_trim (void *handle, uint32_t count, uint64_t offset)
}
static int
-sh_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
+sh_zero (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
{
char *h = handle;
- char cbuf[32], obuf[32];
- const char *args[] = { script, "zero", h, cbuf, obuf,
- may_trim ? "true" : "false", NULL
};
+ char cbuf[32], obuf[32], fbuf[32];
+ const char *args[] = { script, "zero", h, cbuf, obuf, fbuf, NULL };
snprintf (cbuf, sizeof cbuf, "%" PRIu32, count);
snprintf (obuf, sizeof obuf, "%" PRIu64, offset);
+ flags_string (flags, fbuf, sizeof fbuf);
switch (call (args)) {
case OK:
@@ -596,6 +695,8 @@ static struct nbdkit_plugin plugin = {
.can_flush = sh_can_flush,
.is_rotational = sh_is_rotational,
.can_trim = sh_can_trim,
+ .can_zero = sh_can_zero,
+ .can_fua = sh_can_fua,
.pread = sh_pread,
.pwrite = sh_pwrite,
--
2.19.2
Richard W.M. Jones
2018-Dec-15 11:01 UTC
[Libguestfs] [PATCH nbdkit v2 4/4] tests: Test export flags (eflags).
---
tests/Makefile.am | 3 +
tests/test-eflags.sh | 221 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 224 insertions(+)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d463d6b..4e3e179 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -282,6 +282,9 @@ test_oldstyle_LDADD = libtest.la $(LIBGUESTFS_LIBS)
endif HAVE_LIBGUESTFS
+# Test export flags.
+TESTS += test-eflags.sh
+
# common disk image shared with several tests
if HAVE_GUESTFISH
check_DATA += disk
diff --git a/tests/test-eflags.sh b/tests/test-eflags.sh
new file mode 100755
index 0000000..e3f2813
--- /dev/null
+++ b/tests/test-eflags.sh
@@ -0,0 +1,221 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018 Red Hat Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS
IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+# Test export flags.
+#
+# Run nbdkit with various can_* callbacks defined and with or without
+# the -r flag, and check that nbdkit constructs the export flags
+# controlling READ_ONLY, ROTATIONAL, SEND_TRIM, etc. as expected.
+#
+# We use the oldstyle (-o) protocol here because it's simpler to read
+# out the eflags. We use the shell plugin because it gives maximum
+# control over the can_* callbacks (at least, max without having to
+# write a C plugin).
+
+source ./functions.sh
+set -e
+
+if ! socat -h >/dev/null; then
+ echo "$0: 'socat' command not available"
+ exit 77
+fi
+
+# Check 'od' command exists.
+if ! od </dev/null >/dev/null; then
+ echo "$0: 'od' command not available"
+ exit 77
+fi
+
+files="eflags.out"
+rm -f $files
+cleanup_fn rm -f $files
+
+# The export flags.
+# See also src/protocol.h
+HAS_FLAGS=$(( 1 << 0 ))
+READ_ONLY=$(( 1 << 1 ))
+SEND_FLUSH=$(( 1 << 2 ))
+SEND_FUA=$(( 1 << 3 ))
+ROTATIONAL=$(( 1 << 4 ))
+SEND_TRIM=$(( 1 << 5 ))
+SEND_WRITE_ZEROES=$(( 1 << 6 ))
+
+all_flags="HAS_FLAGS READ_ONLY SEND_FLUSH SEND_FUA ROTATIONAL SEND_TRIM
SEND_WRITE_ZEROES"
+
+do_nbdkit ()
+{
+ nbdkit -v -U - -o "$@" sh - --run '
+ socat -b 28 unix-connect:$unixsocket \
+ exec:"dd bs=1 skip=26 count=2 of=eflags.out",cool-write
+ '
+
+ # Protocol is big endian, we want native endian.
+ eflags=$(( $(od -An -N1 -tu1 eflags.out) << 8 |
+ $(od -An -N1 -j1 -tu1 eflags.out) ))
+ printf "eflags 0x%04x" $eflags
+ for f in $all_flags; do
+ [ $(( eflags & ${!f} )) -ne 0 ] && echo -n " $f"
+ done
+ echo
+}
+
+fail ()
+{
+ echo "$@"
+ exit 1
+}
+
+# no -r
+# can_write=false
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "expected HAS_FLAGS|READ_ONLY"
+
+# -r
+# can_write=false
+
+do_nbdkit -r <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "expected HAS_FLAGS|READ_ONLY"
+
+# no -r
+# can_write=true
+#
+# NBD_FLAG_SEND_WRITE_ZEROES is always set on writable connections
+# even if can_zero returns false, because nbdkit reckons it can
+# emulate zeroing using pwrite.
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|SEND_WRITE_ZEROES )) ] ||
+ fail "expected HAS_FLAGS|SEND_WRITE_ZEROES"
+
+# -r
+# can_write=true
+#
+# The -r flag overrides the plugin so this behaves as if can_write is
+# false.
+
+do_nbdkit -r <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "expected HAS_FLAGS|READ_ONLY"
+
+# can_write=false
+# can_trim=true
+# can_zero=true
+#
+# If writing is not possible then trim and zero are always disabled.
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 3 ;;
+ can_trim) exit 0 ;;
+ can_zero) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|READ_ONLY )) ] ||
+ fail "expected HAS_FLAGS|READ_ONLY"
+
+# can_write=true
+# can_trim=true
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ can_trim) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|SEND_TRIM|SEND_WRITE_ZEROES )) ] ||
+ fail "expected HAS_FLAGS|SEND_TRIM|SEND_WRITE_ZEROES"
+
+# can_write=true
+# is_rotational=true
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ is_rotational) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|ROTATIONAL|SEND_WRITE_ZEROES )) ] ||
+ fail "expected HAS_FLAGS|ROTATIONAL|SEND_WRITE_ZEROES"
+
+# can_write=true
+# can_fua=native
+
+do_nbdkit <<'EOF'
+case "$1" in
+ get_size) echo 1M ;;
+ can_write) exit 0 ;;
+ can_fua) echo "native" ;;
+ *) exit 2 ;;
+esac
+EOF
+
+[ $eflags -eq $(( HAS_FLAGS|SEND_FUA|SEND_WRITE_ZEROES )) ] ||
+ fail "expected HAS_FLAGS|SEND_FUA|SEND_WRITE_ZEROES"
--
2.19.2
Eric Blake
2018-Dec-15 13:43 UTC
Re: [Libguestfs] [PATCH nbdkit v2 3/4] sh: Switch nbdkit-sh-plugin to use API version 2.
On 12/15/18 5:01 AM, Richard W.M. Jones wrote:> This allows us to add the following callbacks: > > - can_zero returns boolean > - can_fua should print "none", "emulate" or "native" > > Furthermore the following callbacks are modified in a backwards > compatible manner: > > - pwrite adding flags parameter > - trim adding flags parameter > > This change is not backwards compatible: > > - zero may_trim parameter replaced by flags parameter > ---> +=item C<can_fua> > + > + /path/to/script can_fua <handle> > + > +This controls Forced Unit Access (FUA) behaviour of the core server. > + > +Unlike the other C<can_*> callbacks, this one is I<not> a boolean. It > +must print either "none", "emulate" or "native" to stdout. The > +meaning of these is described in L<nbdkit-plugin(3)>.Presumably we don't care if the user includes or omits a trailing newline on their output?> +static int > +sh_can_fua (void *handle) > +{ > + char *h = handle; > + const char *args[] = { script, "can_fua", h, NULL }; > + char *s = NULL; > + size_t slen; > + int r; > + > + switch (call_read (&s, &slen, args)) { > + case OK: > + if (slen > 0 && s[slen-1] == '\n') > + s[slen-1] = '\0';Good - you do ignore trailing newline. Makes it easier for the author to not worry about it either way.> + > + case RET_FALSE: > + free (s); > + nbdkit_error ("%s: %s method returned unexpected code (3/false)", > + script, "can_fua"); > + errno = EIO; > + return -1; > +So you decided not to take the suggestion of a false return being equivalent to a successful output of "none". I can live with that. Series is looking good on my quick glance through. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Maybe Matching Threads
- [PATCH nbdkit 2/3] sh: Switch nbdkit-sh-plugin to use API version 2.
- [nbdkit PATCH 1/2] sh, eval: Cache .can_zero and .can_flush
- [nbdkit PATCH 6/9] sh: Implement .cache script callback
- [nbdkit PATCH v2 07/24] sh: Implement .cache script callback
- [nbdkit PATCH v3 06/14] api: Add .export_description