From 5a4dd174e893aec775c3f93c5c94c0a633437245 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" 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 + +#include +#include +#include + +#include + +#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) if +true, or failure (S) 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) if true, or +failure (S) if false. (Other exit codes indicate an +error querying the flag). + +For further information see the L +and the following libnbd functions: L, +L, L, L, +L, L, L, +L, L. + =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) if true, or failure (S) if false. +(Other exit codes indicate an error querying the flag). + +For further information see the L +and the following libnbd functions: L, +L. + =item B<--json> The output is displayed in JSON format. -- 2.31.1