Richard W.M. Jones
2021-Nov-17 17:58 UTC
[Libguestfs] [PATCH nbdkit v2 0/2] ocaml: Simplify NBDKit.set_error
v1 was here: https://listman.redhat.com/archives/libguestfs/2021-November/msg00176.html This version addresses all or very nearly all of the feedback. I already posted v2 1/2, but including it again here since it is necessary for the 2/2 to make sense. Rich.
Richard W.M. Jones
2021-Nov-17 17:58 UTC
[Libguestfs] [PATCH nbdkit v2 1/2] tests: Use compound literal array for nbd_connect_command parameter
Instead of having a separate char *args[] local variable, we can use a
compound literal array (C99 feature). This change is just
refactoring.
---
tests/README.tests | 7 ++++---
tests/test-connect.c | 8 ++++----
tests/test-curl-cookie-script.c | 21 ++++++++++-----------
tests/test-curl-header-script.c | 21 ++++++++++-----------
tests/test-delay.c | 13 ++++++-------
tests/test-layers.c | 27 ++++++++++++++-------------
tests/test-newstyle.c | 10 +++++-----
tests/test-null.c | 8 +++++---
tests/test-oldstyle.c | 10 +++++-----
tests/test-pause.c | 11 ++++++-----
tests/test-random.c | 9 +++++----
tests/test-split.c | 12 ++++++------
12 files changed, 80 insertions(+), 77 deletions(-)
diff --git a/tests/README.tests b/tests/README.tests
index 595c3c19..a55e6958 100644
--- a/tests/README.tests
+++ b/tests/README.tests
@@ -65,9 +65,10 @@ To test a plugin using libnbd
Open a libnbd handle, and configure it using:
- char *args[] = { "nbdkit", "-s",
"--exit-with-parent",
- "plugin", <plugin args ...>, NULL };
- nbd_connect_command (nbd, args);
+ nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "plugin", <plugin args ...>, NULL });
Perform tests via libnbd functions.
diff --git a/tests/test-connect.c b/tests/test-connect.c
index f6b494ac..13143f46 100644
--- a/tests/test-connect.c
+++ b/tests/test-connect.c
@@ -53,10 +53,10 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
"example1", NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "example1", NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-curl-cookie-script.c b/tests/test-curl-cookie-script.c
index 481207b5..45e3d136 100644
--- a/tests/test-curl-cookie-script.c
+++ b/tests/test-curl-cookie-script.c
@@ -104,17 +104,16 @@ main (int argc, char *argv[])
perror ("asprintf");
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
"-v",
- "curl",
- "-D", "curl.verbose=1",
- "http://localhost/disk",
- "cookie-script=" SCRIPT,
- "cookie-script-renew=1",
- usp_param, /* unix-socket-path=... */
- NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent", "-v",
+ "curl",
+ "-D", "curl.verbose=1",
+ "http://localhost/disk",
+ "cookie-script=" SCRIPT,
+ "cookie-script-renew=1",
+ usp_param, /* unix-socket-path=... */
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-curl-header-script.c b/tests/test-curl-header-script.c
index a151af05..afe16591 100644
--- a/tests/test-curl-header-script.c
+++ b/tests/test-curl-header-script.c
@@ -126,17 +126,16 @@ main (int argc, char *argv[])
perror ("asprintf");
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
"-v",
- "curl",
- "-D", "curl.verbose=1",
- "http://localhost/disk",
- "header-script=" SCRIPT,
- "header-script-renew=1",
- usp_param, /* unix-socket-path=... */
- NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent", "-v",
+ "curl",
+ "-D", "curl.verbose=1",
+ "http://localhost/disk",
+ "header-script=" SCRIPT,
+ "header-script-renew=1",
+ usp_param, /* unix-socket-path=... */
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-delay.c b/tests/test-delay.c
index 736de529..b0e6f8de 100644
--- a/tests/test-delay.c
+++ b/tests/test-delay.c
@@ -56,13 +56,12 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
- "--filter", "delay",
- "memory", "1M",
- "wdelay=10", NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "--filter", "delay",
+ "memory", "1M",
+ "wdelay=10", NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-layers.c b/tests/test-layers.c
index 13c82289..0083b733 100644
--- a/tests/test-layers.c
+++ b/tests/test-layers.c
@@ -157,19 +157,20 @@ main (int argc, char *argv[])
}
/* Start nbdkit. */
- char *args[] = {
- "nbdkit", "--exit-with-parent", "-fvns",
- /* Because of asynchronous shutdown with threads, finalize
- * isn't reliably called unless we disable parallel.
- */
- "-t", "1",
- "--filter", ".libs/test-layers-filter3." SOEXT,
- "--filter", ".libs/test-layers-filter2." SOEXT,
- "--filter", ".libs/test-layers-filter1." SOEXT,
- ".libs/test-layers-plugin." SOEXT,
- "foo=bar",
- NULL};
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit",
"--exit-with-parent", "-fvns",
+ /* Because of asynchronous shutdown with
+ * threads, finalize isn't reliably
+ * called unless we disable parallel.
+ */
+ "-t", "1",
+ "--filter",
".libs/test-layers-filter3." SOEXT,
+ "--filter",
".libs/test-layers-filter2." SOEXT,
+ "--filter",
".libs/test-layers-filter1." SOEXT,
+ ".libs/test-layers-plugin." SOEXT,
+ "foo=bar",
+ NULL }) == -1) {
dprintf (orig_stderr, "nbd_connect_command: %s\n", nbd_get_error
());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-newstyle.c b/tests/test-newstyle.c
index d96c7e44..1f5d1ca3 100644
--- a/tests/test-newstyle.c
+++ b/tests/test-newstyle.c
@@ -49,11 +49,11 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
- "--newstyle", "file", "file-data", NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "--newstyle", "file",
"file-data",
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-null.c b/tests/test-null.c
index 2205934f..d220999a 100644
--- a/tests/test-null.c
+++ b/tests/test-null.c
@@ -52,9 +52,11 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] - { "nbdkit", "-s",
"--exit-with-parent", "null", "100M", NULL };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "null", "100M",
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-oldstyle.c b/tests/test-oldstyle.c
index 5147768a..0afe868f 100644
--- a/tests/test-oldstyle.c
+++ b/tests/test-oldstyle.c
@@ -49,11 +49,11 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
- "--oldstyle", "file", "file-data", NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "--oldstyle", "file",
"file-data",
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-pause.c b/tests/test-pause.c
index 3c8ee520..e5a970d6 100644
--- a/tests/test-pause.c
+++ b/tests/test-pause.c
@@ -78,11 +78,12 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
"--filter", "pause",
- "example1", "pause-control=" SOCKET, NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "--filter", "pause",
+ "example1", "pause-control="
SOCKET,
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-random.c b/tests/test-random.c
index 4316d2b3..b7716efa 100644
--- a/tests/test-random.c
+++ b/tests/test-random.c
@@ -72,10 +72,11 @@ main (int argc, char *argv[])
}
snprintf (sizearg, sizeof sizearg, "%d", SIZE);
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
"random", sizearg, NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "random", sizearg,
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
diff --git a/tests/test-split.c b/tests/test-split.c
index be53590d..657e5b5a 100644
--- a/tests/test-split.c
+++ b/tests/test-split.c
@@ -51,12 +51,12 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
- char *args[] = {
- "nbdkit", "-s", "--exit-with-parent",
- "split", "split1", "split2",
"file=split3" /* leave file= to test */,
- NULL
- };
- if (nbd_connect_command (nbd, args) == -1) {
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "split", "split1",
"split2",
+ "file=split3" /* leave file= to test */,
+ NULL }) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
}
--
2.32.0
Richard W.M. Jones
2021-Nov-17 17:58 UTC
[Libguestfs] [PATCH nbdkit v2 2/2] ocaml: Simplify NBDKit.set_error
Using the function code_of_unix_error from <caml/unixsupport.h> we can
greatly simplify this function. code_of_unix_error was added in OCaml
4.01 which is ? 4.03 that we currently require.
See also: https://github.com/ocaml/ocaml/issues/4812
This does require a small change ot how OCaml plugins are linked -- we
now need to link them with the standard OCaml Unix library (unix.cmxa).
This commit also adds a comprehensive end-to-end test of error codes.
---
plugins/cc/nbdkit-cc-plugin.pod | 4 +-
plugins/ocaml/nbdkit-ocaml-plugin.pod | 2 +-
plugins/ocaml/Makefile.am | 2 +-
tests/Makefile.am | 20 +++++-
plugins/ocaml/NBDKit.ml | 25 +------
plugins/ocaml/bindings.c | 22 +------
tests/test-cc-ocaml.sh | 2 +-
tests/cc_shebang.ml | 2 +-
tests/test-ocaml-errorcodes.c | 95 +++++++++++++++++++++++++++
tests/test_ocaml_errorcodes_plugin.ml | 32 +++++++++
.gitignore | 1 +
11 files changed, 155 insertions(+), 52 deletions(-)
diff --git a/plugins/cc/nbdkit-cc-plugin.pod b/plugins/cc/nbdkit-cc-plugin.pod
index 0fe0d9ea..be4019f9 100644
--- a/plugins/cc/nbdkit-cc-plugin.pod
+++ b/plugins/cc/nbdkit-cc-plugin.pod
@@ -89,7 +89,7 @@ C<CC=g++> as a parameter to exec nbdkit.
=head2 Using this plugin with OCaml
nbdkit cc CC=ocamlopt \
- CFLAGS="-output-obj -runtime-variant _pic NBDKit.cmx -cclib
-lnbdkitocaml" \
+ CFLAGS="-output-obj -runtime-variant _pic unix.cmxa NBDKit.cmx
-cclib -lnbdkitocaml" \
source.ml
OCaml plugin scripts can be created using this trick:
@@ -97,7 +97,7 @@ OCaml plugin scripts can be created using this trick:
(*/.)>/dev/null 2>&1
exec nbdkit cc "$0" \
CC=ocamlopt \
- CFLAGS="-output-obj -runtime-variant _pic NBDKit.cmx -cclib
-lnbdkitocaml" \
+ CFLAGS="-output-obj -runtime-variant _pic unix.cmxa NBDKit.cmx
-cclib -lnbdkitocaml" \
"$@"
*)
(* followed by OCaml code for the plugin here *)
diff --git a/plugins/ocaml/nbdkit-ocaml-plugin.pod
b/plugins/ocaml/nbdkit-ocaml-plugin.pod
index 293f8143..efeb2240 100644
--- a/plugins/ocaml/nbdkit-ocaml-plugin.pod
+++ b/plugins/ocaml/nbdkit-ocaml-plugin.pod
@@ -53,7 +53,7 @@ using this command:
ocamlopt.opt -output-obj -runtime-variant _pic \
-o nbdkit-myplugin-plugin.so \
- NBDKit.cmx myplugin.ml \
+ unix.cmxa NBDKit.cmx myplugin.ml \
-cclib -lnbdkitocaml
You can then use C<nbdkit-myplugin-plugin.so> as an nbdkit plugin (see
diff --git a/plugins/ocaml/Makefile.am b/plugins/ocaml/Makefile.am
index 1082fc0a..fcf3396d 100644
--- a/plugins/ocaml/Makefile.am
+++ b/plugins/ocaml/Makefile.am
@@ -81,7 +81,7 @@ noinst_SCRIPTS = nbdkit-ocamlexample-plugin.so
nbdkit-ocamlexample-plugin.so: example.cmx libnbdkitocaml.la NBDKit.cmi
NBDKit.cmx
$(OCAMLOPT) $(OCAMLOPTFLAGS) \
-output-obj -runtime-variant _pic -o $@ \
- NBDKit.cmx $< \
+ unix.cmxa NBDKit.cmx $< \
-cclib -L.libs -cclib -lnbdkitocaml
example.cmx: example.ml NBDKit.cmi NBDKit.cmx
$(OCAMLOPT) $(OCAMLOPTFLAGS) -c $< -o $@
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 07b09207..912e8b3f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1067,6 +1067,7 @@ EXTRA_DIST += test-zero.sh
if HAVE_OCAML
LIBGUESTFS_TESTS += test-ocaml
+LIBNBD_TESTS += test-ocaml-errorcodes
test_ocaml_SOURCES = test-ocaml.c test.h
test_ocaml_CFLAGS = \
@@ -1075,15 +1076,30 @@ test_ocaml_CFLAGS = \
$(NULL)
test_ocaml_LDADD = libtest.la $(LIBGUESTFS_LIBS)
-check_SCRIPTS += test-ocaml-plugin.so
+test_ocaml_errorcodes_SOURCES = test-ocaml-errorcodes.c
+test_ocaml_errorcodes_CFLAGS = $(WARNINGS_CFLAGS) $(LIBNBD_CFLAGS)
+test_ocaml_errorcodes_LDADD = $(LIBNBD_LIBS)
+
+check_SCRIPTS += \
+ test-ocaml-plugin.so \
+ test-ocaml-errorcodes-plugin.so
+
test-ocaml-plugin.so: test_ocaml_plugin.cmx ../plugins/ocaml/libnbdkitocaml.la
../plugins/ocaml/NBDKit.cmi ../plugins/ocaml/NBDKit.cmx
$(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../plugins/ocaml \
-output-obj -runtime-variant _pic -o $@ \
- NBDKit.cmx $< \
+ unix.cmxa NBDKit.cmx $< \
-cclib -L../plugins/ocaml/.libs -cclib -lnbdkitocaml
test_ocaml_plugin.cmx: test_ocaml_plugin.ml ../plugins/ocaml/NBDKit.cmi
../plugins/ocaml/NBDKit.cmx
$(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../plugins/ocaml -c $< -o $@
+test-ocaml-errorcodes-plugin.so: test_ocaml_errorcodes_plugin.cmx
../plugins/ocaml/libnbdkitocaml.la ../plugins/ocaml/NBDKit.cmi
../plugins/ocaml/NBDKit.cmx
+ $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../plugins/ocaml \
+ -output-obj -runtime-variant _pic -o $@ \
+ unix.cmxa NBDKit.cmx $< \
+ -cclib -L../plugins/ocaml/.libs -cclib -lnbdkitocaml
+test_ocaml_errorcodes_plugin.cmx: test_ocaml_errorcodes_plugin.ml
../plugins/ocaml/NBDKit.cmi ../plugins/ocaml/NBDKit.cmx
+ $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../plugins/ocaml -c $< -o $@
+
endif HAVE_OCAML
EXTRA_DIST += \
diff --git a/plugins/ocaml/NBDKit.ml b/plugins/ocaml/NBDKit.ml
index c9ce31b5..d28992c8 100644
--- a/plugins/ocaml/NBDKit.ml
+++ b/plugins/ocaml/NBDKit.ml
@@ -220,30 +220,7 @@ let register_plugin plugin
(* Bindings to nbdkit server functions. *)
-external _set_error : int -> unit = "ocaml_nbdkit_set_error"
[@@noalloc]
-
-let set_error unix_error - (* There's an awkward triple translation going
on here, because
- * OCaml Unix.error codes, errno on the host system, and NBD_*
- * errnos are not all the same integer value. Plus we cannot
- * read the host system errno values from OCaml.
- *)
- let nbd_error - match unix_error with
- | Unix.EPERM -> 1
- | Unix.EIO -> 2
- | Unix.ENOMEM -> 3
- | Unix.EINVAL -> 4
- | Unix.ENOSPC -> 5
- | Unix.ESHUTDOWN -> 6
- | Unix.EOVERFLOW -> 7
- | Unix.EOPNOTSUPP -> 8
- | Unix.EROFS -> 9
- | Unix.EFBIG -> 10
- | _ -> 4 (* EINVAL *) in
-
- _set_error nbd_error
-
+external set_error : Unix.error -> unit = "ocaml_nbdkit_set_error"
[@@noalloc]
external parse_size : string -> int64 = "ocaml_nbdkit_parse_size"
external parse_bool : string -> bool = "ocaml_nbdkit_parse_bool"
external read_password : string -> string =
"ocaml_nbdkit_read_password"
diff --git a/plugins/ocaml/bindings.c b/plugins/ocaml/bindings.c
index a6d57084..ba95fb4a 100644
--- a/plugins/ocaml/bindings.c
+++ b/plugins/ocaml/bindings.c
@@ -42,6 +42,7 @@
#include <caml/memory.h>
#include <caml/mlvalues.h>
#include <caml/threads.h>
+#include <caml/unixsupport.h>
#define NBDKIT_API_VERSION 2
#include <nbdkit-plugin.h>
@@ -54,26 +55,7 @@
NBDKIT_DLL_PUBLIC value
ocaml_nbdkit_set_error (value nv)
{
- int err;
-
- switch (Int_val (nv)) {
- /* Host errno values that will map to NBD protocol values */
- case 1: err = EPERM; break;
- case 2: err = EIO; break;
- case 3: err = ENOMEM; break;
- case 4: err = EINVAL; break;
- case 5: err = ENOSPC; break;
- case 6: err = ESHUTDOWN; break;
- case 7: err = EOVERFLOW; break;
- case 8: err = EOPNOTSUPP; break;
- /* Other errno values that server/protocol.c treats specially */
- case 9: err = EROFS; break;
- case 10: err = EFBIG; break;
- default: abort ();
- }
-
- nbdkit_set_error (err);
-
+ nbdkit_set_error (code_of_unix_error (nv));
return Val_unit;
}
diff --git a/tests/test-cc-ocaml.sh b/tests/test-cc-ocaml.sh
index e47bf26f..9ba7ee98 100755
--- a/tests/test-cc-ocaml.sh
+++ b/tests/test-cc-ocaml.sh
@@ -58,6 +58,6 @@ cleanup_fn rm -f $out
rm -f $out
nbdkit -U - cc $script a=1 b=2 c=3 \
- CC="$OCAMLOPT" CFLAGS="-output-obj -runtime-variant _pic
-I $SRCDIR/../plugins/ocaml NBDKit.cmx -cclib -lnbdkitocaml" \
+ CC="$OCAMLOPT" CFLAGS="-output-obj -runtime-variant _pic
-I $SRCDIR/../plugins/ocaml unix.cmxa NBDKit.cmx -cclib -lnbdkitocaml" \
--run 'nbdinfo --size $uri' > $out
test "$(cat $out)" -eq $((512 * 2048))
diff --git a/tests/cc_shebang.ml b/tests/cc_shebang.ml
index 05036284..a6c79039 100755
--- a/tests/cc_shebang.ml
+++ b/tests/cc_shebang.ml
@@ -4,7 +4,7 @@
# shell as an impossible command which is ignored. The line below is
# run by the shell and ignored by OCaml.
-exec nbdkit cc "$0" CC=ocamlopt CFLAGS="-output-obj
-runtime-variant _pic NBDKit.cmx -cclib -lnbdkitocaml" "$@"
+exec nbdkit cc "$0" CC=ocamlopt CFLAGS="-output-obj
-runtime-variant _pic unix.cmxa NBDKit.cmx -cclib -lnbdkitocaml"
"$@"
*)
open Printf
diff --git a/tests/test-ocaml-errorcodes.c b/tests/test-ocaml-errorcodes.c
new file mode 100644
index 00000000..a7a3f125
--- /dev/null
+++ b/tests/test-ocaml-errorcodes.c
@@ -0,0 +1,95 @@
+/* nbdkit
+ * Copyright (C) 2013-2021 Red Hat Inc.
+ *
+ * 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.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <libnbd.h>
+
+/* This test checks the conversion from OCaml Unix.error to errno (in
+ * the plugin) to NBD_E* (over the wire) and back to errno (in
+ * libnbd).
+ *
+ * Reading at various sector offsets in the associated plugin
+ * (test_ocaml_errorcodes_plugin.ml) produces predictable error codes.
+ */
+static struct { uint64_t offset; int expected_errno; } tests[] = {
+ { 1*512, EPERM },
+ { 2*512, EIO },
+ { 3*512, ENOMEM },
+ { 4*512, ESHUTDOWN },
+ { 5*512, EINVAL },
+ { 0 }
+};
+
+int
+main (int argc, char *argv[])
+{
+ struct nbd_handle *nbd;
+ char buf[512];
+ size_t i;
+ int actual_errno;
+
+ nbd = nbd_create ();
+ if (nbd == NULL) {
+ fprintf (stderr, "%s\n", nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+
+ if (nbd_connect_command (nbd,
+ (char *[]) {
+ "nbdkit", "-s",
"--exit-with-parent",
+ "./test-ocaml-errorcodes-plugin.so",
+ NULL }) == -1) {
+ fprintf (stderr, "%s\n", nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+
+ assert (nbd_pread (nbd, buf, 512, 0, 0) == 0);
+
+ for (i = 0; tests[i].offset != 0; ++i) {
+ assert (nbd_pread (nbd, buf, 512, tests[i].offset, 0) == -1);
+ actual_errno = nbd_get_errno ();
+ if (actual_errno != tests[i].expected_errno) {
+ fprintf (stderr, "%s: FAIL: actual errno = %d expected errno =
%d\n",
+ argv[0], actual_errno, tests[i].expected_errno);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ nbd_close (nbd);
+ exit (EXIT_SUCCESS);
+}
diff --git a/tests/test_ocaml_errorcodes_plugin.ml
b/tests/test_ocaml_errorcodes_plugin.ml
new file mode 100644
index 00000000..4b128846
--- /dev/null
+++ b/tests/test_ocaml_errorcodes_plugin.ml
@@ -0,0 +1,32 @@
+open Unix
+
+let sector_size = 512
+
+let open_connection _ = ()
+
+let get_size () = Int64.of_int (6 * sector_size)
+
+let pread () count offset _ + (* Depending on the sector requested (offset),
return a different
+ * error code.
+ *)
+ match (Int64.to_int offset) / sector_size with
+ | 0 -> (* good, return data *) String.make (Int32.to_int count)
'\000'
+ | 1 -> NBDKit.set_error EPERM; failwith "EPERM"
+ | 2 -> NBDKit.set_error EIO; failwith "EIO"
+ | 3 -> NBDKit.set_error ENOMEM; failwith "ENOMEM"
+ | 4 -> NBDKit.set_error ESHUTDOWN; failwith "ESHUTDOWN"
+ | 5 -> NBDKit.set_error EINVAL; failwith "EINVAL"
+ | _ -> assert false
+
+let plugin = {
+ NBDKit.default_callbacks with
+ NBDKit.name = "test-ocaml-errorcodes";
+ version = NBDKit.version ();
+
+ open_connection = Some open_connection;
+ get_size = Some get_size;
+ pread = Some pread;
+}
+
+let () = NBDKit.register_plugin plugin
diff --git a/.gitignore b/.gitignore
index 91cbc810..4e2ae75d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -146,6 +146,7 @@ plugins/*/*.3
/tests/test-nbd
/tests/test-null
/tests/test-ocaml
+/tests/test-ocaml-errorcodes
/tests/test-offset
/tests/test-oldstyle
/tests/test-old-plugins-*.sh
--
2.32.0