libnbd/SOURCES/0010-info-Add-can-is-option...

680 lines
21 KiB
Diff

From 5a4dd174e893aec775c3f93c5c94c0a633437245 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Sat, 26 Jun 2021 20:15:01 +0100
Subject: [PATCH] info: Add --can|--is options to test for NBD flags
You can use them to test export properties from shell scripts, eg:
if nbdinfo --is read-only nbd://localhost ; then
error "this NBD server does not support writing"
fi
Note in this implementation --can and --is are really synonyms.
(cherry picked from commit b39ab287a94f5743775dc13a33b814653d11bdd1)
---
info/Makefile.am | 6 ++
info/can.c | 94 ++++++++++++++++++++++++++++++++
info/info-can-connect.sh | 29 ++++++++++
info/info-can-read.sh | 29 ++++++++++
info/info-can-zero.sh | 35 ++++++++++++
info/info-can.sh | 93 +++++++++++++++++++++++++++++++
info/info-is-read-only.sh | 36 ++++++++++++
info/main.c | 21 ++++++-
info/nbdinfo.h | 5 ++
info/nbdinfo.pod | 112 ++++++++++++++++++++++++++++++++++++++
10 files changed, 458 insertions(+), 2 deletions(-)
create mode 100644 info/can.c
create mode 100755 info/info-can-connect.sh
create mode 100755 info/info-can-read.sh
create mode 100755 info/info-can-zero.sh
create mode 100755 info/info-can.sh
create mode 100755 info/info-is-read-only.sh
diff --git a/info/Makefile.am b/info/Makefile.am
index 75c6a75..a5708ec 100644
--- a/info/Makefile.am
+++ b/info/Makefile.am
@@ -18,6 +18,11 @@
include $(top_srcdir)/subdir-rules.mk
info_sh_files = \
+ info-can.sh \
+ info-can-connect.sh \
+ info-can-read.sh \
+ info-can-zero.sh \
+ info-is-read-only.sh \
info-list.sh \
info-list-json.sh \
info-list-qemu.sh \
@@ -63,6 +68,7 @@ TESTS =
nbdinfo_SOURCES = \
nbdinfo.h \
+ can.c \
list.c \
main.c \
map.c \
diff --git a/info/can.c b/info/can.c
new file mode 100644
index 0000000..ee8bbb7
--- /dev/null
+++ b/info/can.c
@@ -0,0 +1,94 @@
+/* NBD client library in userspace
+ * Copyright (C) 2020-2021 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libnbd.h>
+
+#include "nbdinfo.h"
+
+int can_exit_code;
+
+void
+do_can (void)
+{
+ int feature;
+
+ if (strcasecmp (can, "connect") == 0 ||
+ strcasecmp (can, "read") == 0)
+ feature = 1;
+
+ else if (strcasecmp (can, "readonly") == 0 ||
+ strcasecmp (can, "read-only") == 0 ||
+ strcasecmp (can, "read_only") == 0)
+ feature = nbd_is_read_only (nbd);
+
+ else if (strcasecmp (can, "write") == 0) {
+ feature = nbd_is_read_only (nbd);
+ if (feature >= 0) feature = !feature;
+ }
+
+ else if (strcasecmp (can, "rotational") == 0)
+ feature = nbd_is_rotational (nbd);
+
+ else if (strcasecmp (can, "cache") == 0)
+ feature = nbd_can_cache (nbd);
+
+ else if (strcasecmp (can, "df") == 0)
+ feature = nbd_can_df (nbd);
+
+ else if (strcasecmp (can, "fastzero") == 0 ||
+ strcasecmp (can, "fast-zero") == 0 ||
+ strcasecmp (can, "fast_zero") == 0)
+ feature = nbd_can_fast_zero (nbd);
+
+ else if (strcasecmp (can, "flush") == 0)
+ feature = nbd_can_flush (nbd);
+
+ else if (strcasecmp (can, "fua") == 0)
+ feature = nbd_can_fua (nbd);
+
+ else if (strcasecmp (can, "multiconn") == 0 ||
+ strcasecmp (can, "multi-conn") == 0 ||
+ strcasecmp (can, "multi_conn") == 0)
+ feature = nbd_can_multi_conn (nbd);
+
+ else if (strcasecmp (can, "trim") == 0)
+ feature = nbd_can_trim (nbd);
+
+ else if (strcasecmp (can, "zero") == 0)
+ feature = nbd_can_zero (nbd);
+
+ else {
+ fprintf (stderr, "%s: unknown --can or --is option: %s\n",
+ progname, can);
+ exit (EXIT_FAILURE);
+ }
+
+ if (feature == -1) {
+ fprintf (stderr, "%s: %s\n", progname, nbd_get_error ());
+ exit (EXIT_FAILURE);
+ }
+
+ /* Translate the feature bool into an exit code. This is used in main(). */
+ can_exit_code = feature ? EXIT_SUCCESS : 2;
+}
diff --git a/info/info-can-connect.sh b/info/info-can-connect.sh
new file mode 100755
index 0000000..eecc290
--- /dev/null
+++ b/info/info-can-connect.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020-2021 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+# --can connect always returns true.
+
+requires nbdkit null --version
+
+nbdkit -v -U - null \
+ --run '$VG nbdinfo --can connect "nbd+unix:///?socket=$unixsocket"'
diff --git a/info/info-can-read.sh b/info/info-can-read.sh
new file mode 100755
index 0000000..b1edeab
--- /dev/null
+++ b/info/info-can-read.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020-2021 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+# --can read always returns true.
+
+requires nbdkit null --version
+
+nbdkit -v -U - null \
+ --run '$VG nbdinfo --can read "nbd+unix:///?socket=$unixsocket"'
diff --git a/info/info-can-zero.sh b/info/info-can-zero.sh
new file mode 100755
index 0000000..e388243
--- /dev/null
+++ b/info/info-can-zero.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020-2021 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+# nbdkit emulates zeroing so we have to use the nozero filter to test
+# the negative case below.
+
+requires nbdkit null --version
+requires nbdkit null --filter=nozero --version
+
+nbdkit -v -U - null \
+ --run '$VG nbdinfo --can zero "nbd+unix:///?socket=$unixsocket"'
+
+nbdkit -v -U - null \
+ --filter=nozero \
+ --run '! $VG nbdinfo --can zero "nbd+unix:///?socket=$unixsocket"'
diff --git a/info/info-can.sh b/info/info-can.sh
new file mode 100755
index 0000000..4154e38
--- /dev/null
+++ b/info/info-can.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020-2021 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+requires nbdkit --version
+requires nbdkit sh --version
+
+# --is read-only and --can write are tested in info-is-read-only.sh
+
+# --can connect is tested in info-can-connect.sh
+
+# --can read is tested in info-can-read.sh
+
+# --can zero is tested in info-can-zero.sh
+
+# --can df is hard to test. nbdkit newstyle probably always sets this
+# and oldstyle never, but that feels like depending a bit too much on
+# the implementation.
+
+# --can cache and --can fua require special handling because in
+# nbdkit-sh-plugin we must print "native" or "none". Also the can_fua
+# flag is only sent if the export is writable (hence can_write below).
+
+for flag in cache fua; do
+ export flag
+ nbdkit -v -U - sh - \
+ --run '$VG nbdinfo --can $flag "nbd+unix:///?socket=$unixsocket"' <<'EOF'
+case "$1" in
+ get_size) echo 1024 ;;
+ pread) ;;
+ can_write) ;;
+ can_$flag) echo native ;;
+ *) exit 2 ;;
+esac
+EOF
+
+ nbdkit -v -U - sh - \
+ --run '! $VG nbdinfo --can $flag "nbd+unix:///?socket=$unixsocket"' <<'EOF'
+case "$1" in
+ get_size) echo 1024 ;;
+ pread) ;;
+ can_write) ;;
+ can_$flag) echo none ;;
+ *) exit 2 ;;
+esac
+EOF
+done
+
+# These ones are normal booleans.
+
+for flag in fast_zero flush multi_conn trim ; do
+ export flag
+ nbdkit -v -U - sh - \
+ --run '$VG nbdinfo --can $flag "nbd+unix:///?socket=$unixsocket"' <<'EOF'
+case "$1" in
+ get_size) echo 1024 ;;
+ pread) ;;
+ can_write) ;;
+ can_$flag) exit 0 ;;
+ *) exit 2 ;;
+esac
+EOF
+
+ nbdkit -v -U - sh - \
+ --run '! $VG nbdinfo --can $flag "nbd+unix:///?socket=$unixsocket"' <<'EOF'
+case "$1" in
+ get_size) echo 1024 ;;
+ pread) ;;
+ can_write) ;;
+ can_$flag) exit 3 ;;
+ *) exit 2 ;;
+esac
+EOF
+done
diff --git a/info/info-is-read-only.sh b/info/info-is-read-only.sh
new file mode 100755
index 0000000..db024b4
--- /dev/null
+++ b/info/info-is-read-only.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# nbd client library in userspace
+# Copyright (C) 2020-2021 Red Hat Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. ../tests/functions.sh
+
+set -e
+set -x
+
+# Test --is read-only and --can write.
+
+requires nbdkit --version
+requires nbdkit null --version
+
+nbdkit -U - -r null \
+ --run '$VG nbdinfo --is read-only "nbd+unix:///?socket=$unixsocket"'
+nbdkit -U - -r null \
+ --run '! $VG nbdinfo --can write "nbd+unix:///?socket=$unixsocket"'
+nbdkit -U - null \
+ --run '$VG nbdinfo --can write "nbd+unix:///?socket=$unixsocket"'
+nbdkit -U - null \
+ --run '! $VG nbdinfo --is read-only "nbd+unix:///?socket=$unixsocket"'
diff --git a/info/main.c b/info/main.c
index fcda25c..82946ee 100644
--- a/info/main.c
+++ b/info/main.c
@@ -40,6 +40,7 @@ FILE *fp; /* output file descriptor */
bool list_all = false; /* --list option */
bool probe_content = false; /* --content / --no-content option */
bool json_output = false; /* --json option */
+const char *can = NULL; /* --is/--can option */
const char *map = NULL; /* --map option */
bool size_only = false; /* --size option */
bool totals = false; /* --totals option */
@@ -53,6 +54,8 @@ usage (FILE *fp, int exitcode)
"\n"
" nbdinfo [--json] NBD-URI\n"
" nbdinfo --size [--json] NBD-URI\n"
+" nbdinfo --is read-only|rotational NBD-URI\n"
+" nbdinfo --can cache|connect|... NBD-URI\n"
" nbdinfo --map [--totals] [--json] NBD-URI\n"
" nbdinfo -L|--list [--json] NBD-URI\n"
"\n"
@@ -66,6 +69,8 @@ usage (FILE *fp, int exitcode)
" nbdinfo nbd://localhost\n"
" nbdinfo \"nbd+unix:///?socket=/tmp/unixsock\"\n"
" nbdinfo --size nbd://example.com\n"
+" nbdinfo --can connect nbd://example.com\n"
+" nbdinfo --is read-only nbd://example.com\n"
" nbdinfo --map nbd://example.com\n"
" nbdinfo --json nbd://example.com\n"
" nbdinfo --list nbd://example.com\n"
@@ -86,6 +91,7 @@ main (int argc, char *argv[])
CONTENT_OPTION,
NO_CONTENT_OPTION,
JSON_OPTION,
+ CAN_OPTION,
MAP_OPTION,
SIZE_OPTION,
TOTALS_OPTION,
@@ -93,8 +99,10 @@ main (int argc, char *argv[])
const char *short_options = "LV";
const struct option long_options[] = {
{ "help", no_argument, NULL, HELP_OPTION },
+ { "can", required_argument, NULL, CAN_OPTION },
{ "content", no_argument, NULL, CONTENT_OPTION },
{ "no-content", no_argument, NULL, NO_CONTENT_OPTION },
+ { "is", required_argument, NULL, CAN_OPTION },
{ "json", no_argument, NULL, JSON_OPTION },
{ "list", no_argument, NULL, 'L' },
{ "long-options", no_argument, NULL, LONG_OPTIONS },
@@ -151,6 +159,10 @@ main (int argc, char *argv[])
no_content_flag = true;
break;
+ case CAN_OPTION:
+ can = optarg;
+ break;
+
case MAP_OPTION:
map = optarg ? optarg : "base:allocation";
break;
@@ -181,7 +193,7 @@ main (int argc, char *argv[])
usage (stderr, EXIT_FAILURE);
/* You cannot combine certain options. */
- if (!!list_all + !!map + !!size_only > 1) {
+ if (!!list_all + !!can + !!map + !!size_only > 1) {
fprintf (stderr,
"%s: you cannot use --list, --map and --size together.\n",
progname);
@@ -204,6 +216,8 @@ main (int argc, char *argv[])
probe_content = true;
if (no_content_flag)
probe_content = false;
+ if (can)
+ probe_content = false;
if (map)
probe_content = false;
@@ -227,7 +241,7 @@ main (int argc, char *argv[])
nbd_set_uri_allow_local_file (nbd, true); /* Allow ?tls-psk-file. */
/* Set optional modes in the handle. */
- if (!map && !size_only) {
+ if (!can && !map && !size_only) {
nbd_set_opt_mode (nbd, true);
nbd_set_full_info (nbd, true);
}
@@ -246,6 +260,8 @@ main (int argc, char *argv[])
if (size_only) /* --size (!list_all) */
do_size ();
+ else if (can) /* --is/--can (!list_all) */
+ do_can ();
else if (map) /* --map (!list_all) */
do_map ();
else { /* not --size or --map */
@@ -304,5 +320,6 @@ main (int argc, char *argv[])
free (output);
+ if (can) exit (can_exit_code);
exit (list_okay ? EXIT_SUCCESS : EXIT_FAILURE);
}
diff --git a/info/nbdinfo.h b/info/nbdinfo.h
index 6ff73af..566a2cb 100644
--- a/info/nbdinfo.h
+++ b/info/nbdinfo.h
@@ -30,10 +30,15 @@ extern FILE *fp;
extern bool list_all;
extern bool probe_content;
extern bool json_output;
+extern const char *can;
extern const char *map;
extern bool size_only;
extern bool totals;
+/* can.c */
+extern int can_exit_code;
+extern void do_can (void);
+
/* list.c */
extern void collect_exports (void);
extern bool list_all_exports (const char *uri);
diff --git a/info/nbdinfo.pod b/info/nbdinfo.pod
index 0c03bcd..fb20f0e 100644
--- a/info/nbdinfo.pod
+++ b/info/nbdinfo.pod
@@ -8,6 +8,10 @@ nbdinfo - display information and metadata about NBD servers and exports
nbdinfo --size [--json] NBD-URI
+ nbdinfo --is read-only|rotational NBD-URI
+
+ nbdinfo --can cache|connect|... NBD-URI
+
nbdinfo --map [--totals] [--json] NBD-URI
nbdinfo -L|--list [--json] NBD-URI
@@ -87,6 +91,66 @@ scripting) use the I<--size> parameter:
$ nbdinfo --size nbd://localhost
1048576
+=head2 Test for flags
+
+Use one of the options below to test NBD flags. The command does not
+print anything. Instead it exits with success (S<exit code 0>) if
+true, or failure (S<exit code 2>) if false. (Other exit codes
+indicate an error querying the flag). You can use it in shell scripts
+like this:
+
+ if nbdinfo --is read-only nbd://localhost ||
+ ! nbdinfo --can trim nbd://localhost
+ then
+ error "the device must support writing and trimming"
+ fi
+
+=over 4
+
+=item nbdinfo --is read-only URI
+
+Test if the server export is read-only.
+
+=item nbdinfo --can write URI
+
+For convenience this is the opposite of I<--is read-only>.
+
+=item nbdinfo --can read URI
+
+All NBD servers must support read, so this always exits with success
+(unless there is a failure connecting to the URI).
+
+=item nbdinfo --can connect URI
+
+Test if we can connect to the NBD URI.
+
+=item nbdinfo --is rotational URI
+
+Test if the server export is backed by something which behaves like a
+rotating disk: accessing nearby blocks may be faster than random
+access and requests should be sorted to improve performance. Many
+servers do not or cannot report this accurately.
+
+=item nbdinfo --can cache URI
+
+=item nbdinfo --can df URI
+
+=item nbdinfo --can fast-zero URI
+
+=item nbdinfo --can flush URI
+
+=item nbdinfo --can fua URI
+
+=item nbdinfo --can multi-conn URI
+
+=item nbdinfo --can trim URI
+
+=item nbdinfo --can zero URI
+
+Test other properties of the NBD server export.
+
+=back
+
=head2 Map
To show a map of which areas of the disk are allocated and sparse, use
@@ -181,6 +245,40 @@ API can be used for more complex queries.
Display brief command line help and exit.
+=item B<--can cache>
+
+=item B<--can connect>
+
+=item B<--can df>
+
+=item B<--can fast-zero>
+
+=item B<--can flush>
+
+=item B<--can fua>
+
+=item B<--can multi-conn>
+
+=item B<--can read>
+
+=item B<--can trim>
+
+=item B<--can write>
+
+=item B<--can zero>
+
+Test properties of the NBD server export. The command does not print
+anything. Instead it exits with success (S<exit code 0>) if true, or
+failure (S<exit code 2>) if false. (Other exit codes indicate an
+error querying the flag).
+
+For further information see the L<NBD
+protocol|https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md>
+and the following libnbd functions: L<nbd_can_cache(3)>,
+L<nbd_can_df(3)>, L<nbd_can_fast_zero(3)>, L<nbd_can_flush(3)>,
+L<nbd_can_fua(3)>, L<nbd_can_multi_conn(3)>, L<nbd_can_trim(3)>,
+L<nbd_can_zero(3)>, L<nbd_is_read_only(3)>.
+
=item B<--content>
=item B<--no-content>
@@ -197,6 +295,20 @@ When using I<--list>, the default is I<--no-content> (since
downloading from each export is expensive). To enable content probing
use I<--list --content>.
+=item B<--is read-only>
+
+=item B<--is rotational>
+
+Test if the NBD server export is read-only and rotational. The
+command does not print anything. Instead it exits with success
+(S<exit code 0>) if true, or failure (S<exit code 2>) if false.
+(Other exit codes indicate an error querying the flag).
+
+For further information see the L<NBD
+protocol|https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md>
+and the following libnbd functions: L<nbd_is_read_only(3)>,
+L<nbd_is_rotational(3)>.
+
=item B<--json>
The output is displayed in JSON format.
--
2.31.1