Richard W.M. Jones
2018-Nov-14  14:27 UTC
[Libguestfs] [PATCH nbdkit v3 0/4] build: Replace ./nbdkit with a C program.
v1 was here: https://www.redhat.com/archives/libguestfs/2018-November/msg00147.html v2 was here: https://www.redhat.com/archives/libguestfs/2018-November/msg00152.html v3: - Use optarg != NULL as a sentinel for has_arg. - Moved some variable decls into the inner loop. - Make nbdkit wrapper depend on config.status, so if srcdir or builddir changes then we rebuild the wrapper. It probably does so anyway because <config.h> will change, but let's be safe. - Document NBDKIT_VALGRIND=1 and NBDKIT_GDB=1. - Add two extra patches which fix existing uses of NBDKIT_VALGRIND. - Retested (make check && make check-valgrind). Rich.
Richard W.M. Jones
2018-Nov-14  14:27 UTC
[Libguestfs] [PATCH nbdkit v3 1/4] src: Move long_options short_options, is_short_name to a header file.
This refactoring is simply so the exact same options can be reused in
another program.
---
 src/Makefile.am |   1 +
 src/main.c      |  70 +------------------------------
 src/options.h   | 109 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+), 69 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index c094ed4..3490c0f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,6 +46,7 @@ nbdkit_SOURCES = \
 	log-stderr.c \
 	log-syslog.c \
 	main.c \
+	options.h \
 	plugins.c \
 	protocol.h \
 	sockets.c \
diff --git a/src/main.c b/src/main.c
index 224955b..0c7dbce 100644
--- a/src/main.c
+++ b/src/main.c
@@ -55,11 +55,11 @@
 #include <dlfcn.h>
 
 #include "internal.h"
+#include "options.h"
 #include "exit-with-parent.h"
 
 #define FIRST_SOCKET_ACTIVATION_FD 3 /* defined by systemd ABI */
 
-static int is_short_name (const char *);
 static char *make_random_fifo (void);
 static struct backend *open_plugin_so (size_t i, const char *filename, int
short_name);
 static struct backend *open_filter_so (struct backend *next, size_t i, const
char *filename, int short_name);
@@ -114,67 +114,6 @@ struct backend *backend;
 static char *random_fifo_dir = NULL;
 static char *random_fifo = NULL;
 
-enum {
-  HELP_OPTION = CHAR_MAX + 1,
-  DUMP_CONFIG_OPTION,
-  DUMP_PLUGIN_OPTION,
-  EXIT_WITH_PARENT_OPTION,
-  FILTER_OPTION,
-  LOG_OPTION,
-  LONG_OPTIONS_OPTION,
-  RUN_OPTION,
-  SELINUX_LABEL_OPTION,
-  SHORT_OPTIONS_OPTION,
-  TLS_OPTION,
-  TLS_CERTIFICATES_OPTION,
-  TLS_PSK_OPTION,
-  TLS_VERIFY_PEER_OPTION,
-};
-
-static const char *short_options = "D:e:fg:i:nop:P:rst:u:U:vV";
-static const struct option long_options[] = {
-  { "debug",            required_argument, NULL, 'D' },
-  { "dump-config",      no_argument,       NULL, DUMP_CONFIG_OPTION
},
-  { "dump-plugin",      no_argument,       NULL, DUMP_PLUGIN_OPTION
},
-  { "exit-with-parent", no_argument,       NULL,
EXIT_WITH_PARENT_OPTION },
-  { "export",           required_argument, NULL, 'e' },
-  { "export-name",      required_argument, NULL, 'e' },
-  { "exportname",       required_argument, NULL, 'e' },
-  { "filter",           required_argument, NULL, FILTER_OPTION },
-  { "foreground",       no_argument,       NULL, 'f' },
-  { "no-fork",          no_argument,       NULL, 'f' },
-  { "group",            required_argument, NULL, 'g' },
-  { "help",             no_argument,       NULL, HELP_OPTION },
-  { "ip-addr",          required_argument, NULL, 'i' },
-  { "ipaddr",           required_argument, NULL, 'i' },
-  { "log",              required_argument, NULL, LOG_OPTION },
-  { "long-options",     no_argument,       NULL, LONG_OPTIONS_OPTION
},
-  { "new-style",        no_argument,       NULL, 'n' },
-  { "newstyle",         no_argument,       NULL, 'n' },
-  { "old-style",        no_argument,       NULL, 'o' },
-  { "oldstyle",         no_argument,       NULL, 'o' },
-  { "pid-file",         required_argument, NULL, 'P' },
-  { "pidfile",          required_argument, NULL, 'P' },
-  { "port",             required_argument, NULL, 'p' },
-  { "read-only",        no_argument,       NULL, 'r' },
-  { "readonly",         no_argument,       NULL, 'r' },
-  { "run",              required_argument, NULL, RUN_OPTION },
-  { "selinux-label",    required_argument, NULL, SELINUX_LABEL_OPTION
},
-  { "short-options",    no_argument,       NULL, SHORT_OPTIONS_OPTION
},
-  { "single",           no_argument,       NULL, 's' },
-  { "stdin",            no_argument,       NULL, 's' },
-  { "threads",          required_argument, NULL, 't' },
-  { "tls",              required_argument, NULL, TLS_OPTION },
-  { "tls-certificates", required_argument, NULL,
TLS_CERTIFICATES_OPTION },
-  { "tls-psk",          required_argument, NULL, TLS_PSK_OPTION },
-  { "tls-verify-peer",  no_argument,       NULL,
TLS_VERIFY_PEER_OPTION },
-  { "unix",             required_argument, NULL, 'U' },
-  { "user",             required_argument, NULL, 'u' },
-  { "verbose",          no_argument,       NULL, 'v' },
-  { "version",          no_argument,       NULL, 'V' },
-  { NULL },
-};
-
 static void
 usage (void)
 {
@@ -748,13 +687,6 @@ main (int argc, char *argv[])
   exit (EXIT_SUCCESS);
 }
 
-/* Is it a plugin or filter name relative to the plugindir/filterdir? */
-static int
-is_short_name (const char *filename)
-{
-  return strchr (filename, '.') == NULL && strchr (filename,
'/') == NULL;
-}
-
 /* Implementation of '-U -' */
 static char *
 make_random_fifo (void)
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 0000000..2bbc96e
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,109 @@
+/* nbdkit
+ * Copyright (C) 2013-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.
+ */
+
+#ifndef NBDKIT_OPTIONS_H
+#define NBDKIT_OPTIONS_H
+
+#include <getopt.h>
+#include <limits.h>
+#include <string.h>
+
+enum {
+  HELP_OPTION = CHAR_MAX + 1,
+  DUMP_CONFIG_OPTION,
+  DUMP_PLUGIN_OPTION,
+  EXIT_WITH_PARENT_OPTION,
+  FILTER_OPTION,
+  LOG_OPTION,
+  LONG_OPTIONS_OPTION,
+  RUN_OPTION,
+  SELINUX_LABEL_OPTION,
+  SHORT_OPTIONS_OPTION,
+  TLS_OPTION,
+  TLS_CERTIFICATES_OPTION,
+  TLS_PSK_OPTION,
+  TLS_VERIFY_PEER_OPTION,
+};
+
+static const char *short_options = "D:e:fg:i:nop:P:rst:u:U:vV";
+static const struct option long_options[] = {
+  { "debug",            required_argument, NULL, 'D' },
+  { "dump-config",      no_argument,       NULL, DUMP_CONFIG_OPTION
},
+  { "dump-plugin",      no_argument,       NULL, DUMP_PLUGIN_OPTION
},
+  { "exit-with-parent", no_argument,       NULL,
EXIT_WITH_PARENT_OPTION },
+  { "export",           required_argument, NULL, 'e' },
+  { "export-name",      required_argument, NULL, 'e' },
+  { "exportname",       required_argument, NULL, 'e' },
+  { "filter",           required_argument, NULL, FILTER_OPTION },
+  { "foreground",       no_argument,       NULL, 'f' },
+  { "no-fork",          no_argument,       NULL, 'f' },
+  { "group",            required_argument, NULL, 'g' },
+  { "help",             no_argument,       NULL, HELP_OPTION },
+  { "ip-addr",          required_argument, NULL, 'i' },
+  { "ipaddr",           required_argument, NULL, 'i' },
+  { "log",              required_argument, NULL, LOG_OPTION },
+  { "long-options",     no_argument,       NULL, LONG_OPTIONS_OPTION
},
+  { "new-style",        no_argument,       NULL, 'n' },
+  { "newstyle",         no_argument,       NULL, 'n' },
+  { "old-style",        no_argument,       NULL, 'o' },
+  { "oldstyle",         no_argument,       NULL, 'o' },
+  { "pid-file",         required_argument, NULL, 'P' },
+  { "pidfile",          required_argument, NULL, 'P' },
+  { "port",             required_argument, NULL, 'p' },
+  { "read-only",        no_argument,       NULL, 'r' },
+  { "readonly",         no_argument,       NULL, 'r' },
+  { "run",              required_argument, NULL, RUN_OPTION },
+  { "selinux-label",    required_argument, NULL, SELINUX_LABEL_OPTION
},
+  { "short-options",    no_argument,       NULL, SHORT_OPTIONS_OPTION
},
+  { "single",           no_argument,       NULL, 's' },
+  { "stdin",            no_argument,       NULL, 's' },
+  { "threads",          required_argument, NULL, 't' },
+  { "tls",              required_argument, NULL, TLS_OPTION },
+  { "tls-certificates", required_argument, NULL,
TLS_CERTIFICATES_OPTION },
+  { "tls-psk",          required_argument, NULL, TLS_PSK_OPTION },
+  { "tls-verify-peer",  no_argument,       NULL,
TLS_VERIFY_PEER_OPTION },
+  { "unix",             required_argument, NULL, 'U' },
+  { "user",             required_argument, NULL, 'u' },
+  { "verbose",          no_argument,       NULL, 'v' },
+  { "version",          no_argument,       NULL, 'V' },
+  { NULL },
+};
+
+/* Is it a plugin or filter name relative to the plugindir/filterdir? */
+static inline int
+is_short_name (const char *filename)
+{
+  return strchr (filename, '.') == NULL && strchr (filename,
'/') == NULL;
+}
+
+#endif /* NBDKIT_OPTIONS_H */
-- 
2.19.0.rc0
Richard W.M. Jones
2018-Nov-14  14:27 UTC
[Libguestfs] [PATCH nbdkit v3 2/4] build: Replace ./nbdkit with a C program.
There are advantages to having the same code parse the options in the
./nbdkit wrapper as in the real nbdkit:
- We can parse options in exactly the same way as the real program.
- Use the more accurate ‘is_short_name’ test for unadorned
  plugin/filter names on the command line.
- Fixes the FreeBSD problem with shebangs caused because FreeBSD
  refuses to use a shell script as a shebang path.
Apart from the above, this is a straightforward translation of the
original shell script into C and preserves all the existing features
such as valgrind and gdb support.
Thanks: Eric Blake.
---
 Makefile.am  |  12 ++-
 README       |   2 +-
 configure.ac |   2 -
 nbdkit.in    | 160 --------------------------------
 wrapper.c    | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 264 insertions(+), 164 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index d5ef59f..5abe18e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -46,7 +46,17 @@ EXTRA_DIST = \
 
 CLEANFILES += html/*.html
 
-noinst_SCRIPTS = nbdkit
+# NB: This is not the real nbdkit binary.  It's a wrapper that allows
+# you to run nbdkit from the build directory before it is installed.
+noinst_PROGRAMS = nbdkit
+nbdkit_SOURCES = wrapper.c src/options.h
+nbdkit_CPPFLAGS = \
+	-I$(top_srcdir)/src \
+	-Dbuilddir=\"$(abs_top_builddir)\" \
+	-Dsrcdir=\"$(abs_top_srcdir)\" \
+	-DVALGRIND=\"$(VALGRIND)\"
+nbdkit_CFLAGS = $(WARNINGS_CFLAGS)
+nbdkit_DEPENDENCIES = config.status
 
 SUBDIRS = \
 	bash \
diff --git a/README b/README
index 0b266f2..57583a3 100644
--- a/README
+++ b/README
@@ -154,7 +154,7 @@ Building
     make check                     make check
 
 To run nbdkit from the source directory, use the top level ./nbdkit
-script.  It will run nbdkit and plugins from the locally compiled
+wrapper.  It will run nbdkit and plugins from the locally compiled
 directory:
 
     $ ./nbdkit example1 -f -v
diff --git a/configure.ac b/configure.ac
index ed07177..5c2e951 100644
--- a/configure.ac
+++ b/configure.ac
@@ -736,8 +736,6 @@ AC_SUBST([filters])
 
 dnl Produce output files.
 AC_CONFIG_HEADERS([config.h])
-AC_CONFIG_FILES([nbdkit],
-                [chmod +x,-w nbdkit])
 AC_CONFIG_FILES([podwrapper.pl],
                 [chmod +x,-w podwrapper.pl])
 AC_CONFIG_FILES([Makefile
diff --git a/nbdkit.in b/nbdkit.in
deleted file mode 100644
index 5efbf75..0000000
--- a/nbdkit.in
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env bash
-# @configure_input@
-
-# Copyright (C) 2017-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.
-
-#------------------------------------------------------------
-# This script lets you run nbdkit from the source directory.
-#
-# You can use either:
-#   ./nbdkit file [arg=value] [arg=value] ...
-# or:
-#   /path/to/nbdkit file [arg=value] [arg=value] ...
-#
-# Or you can set $PATH to include the nbdkit source directory and run
-# the bare "nbdkit" command without supplying the full path.
-#
-# The script modifies the bare plugin name (eg. "file") to be the
full
-# path to the locally compiled plugin.  If you don't use this script
-# and run src/nbdkit directly then it will pick up the installed
-# plugins which is not usually what you want.
-#
-# This script is also used to run the tests (make check).
-#------------------------------------------------------------
-
-# The location of the source and build directories.  Absolute paths
-# are used so this script can be called from any location.
-s="$(cd @abs_srcdir@ && pwd)"
-b="$(cd @abs_builddir@ && pwd)"
-
-# Rewrite the bare module name on the command line.
-declare -a args
-i=0
-done-verbose-
-while [ $# -gt 0 ]; do
-    case "$1" in
-        # Options that we special-case.  Unlike getopt_long with short option
-        # squashing, we only recognize -v in isolation. Oh well.
-        -v | --verbose)
-            verbose=1
-            args[$i]="$1"
-            ((++i))
-            shift
-            ;;
-
-        # Filters can be rewritten if purely alphanumeric.
-        --filter=*)
-            tmp=${1#*=}
-            shift
-            set - --filter "$tmp" "$@"
-            ;& # fallthru
-        --filter)
-            args[$i]="--filter"
-            ((++i))
-            [ $# -gt 1 ] || break
-            if [[ "$2" =~ ^[a-zA-Z0-9]+$ ]]; then
-                if [ -x "$b/filters/$2/.libs/nbdkit-$2-filter.so" ];
then
-                   
args[$i]="$b/filters/$2/.libs/nbdkit-$2-filter.so"
-                else
-                    args[$i]="$2"
-                fi
-            else
-                args[$i]="$2"
-            fi
-            ((++i))
-            shift 2
-            ;;
-
-        # Remaining options that take an argument, which we pass through as is.
-        # Although getopt_long handles abbreviations, we don't. Oh well.
-        --*=*)
-            args[$i]="$1"
-            ((++i))
-            shift
-            ;;
-        -D | --debug | -e | --export* | -g | --group | -i | --ip* | --log | \
-        -P | --pid* | -p | --port | --run | --selinux-label | -t | --threads |
\
-        --tls | --tls-certificates | --tls-psk | -U | --unix | -u | --user)
-            args[$i]="$1"
-            ((++i))
-            [ $# -gt 1 ] || break
-            args[$i]="$2"
-            ((++i))
-            shift 2
-            ;;
-
-        # Anything else can be rewritten if it's purely alphanumeric,
-        # but there is only one module name so only rewrite once.
-        *)
-            if [ ! $done ] && [[ "$1" =~ ^[a-zA-Z0-9]+$ ]];
then
-                # Usual plugins written in C.
-                if [ -x "$b/plugins/$1/.libs/nbdkit-$1-plugin.so" ];
then
-                   
args[$i]="$b/plugins/$1/.libs/nbdkit-$1-plugin.so"
-                    done=1
-                # Special plugins written in Perl.
-                elif [ "$1" = "example4" ] || [
"$1" = "tar" ]; then
-                   
args[$i]="$b/plugins/perl/.libs/nbdkit-perl-plugin.so"
-                    ((++i))
-                    args[$i]="$b/plugins/$1/nbdkit-$1-plugin"
-                    done=1
-                else
-                    args[$i]="$1"
-                fi
-            else
-                args[$i]="$1"
-            fi
-            ((++i))
-            shift
-            ;;
-    esac
-done
-
-# If -v flag was given on the command line, print the command.
-if [ $verbose ]; then
-    echo $b/src/nbdkit "${args[@]}"
-fi
-
-prefix-# If NBDKIT_VALGRIND=1 is set in the environment, then we run
-# the program under valgrind.  This is used by the tests.
-# Similarly, if NBDKIT_GDB=1 is set in the environment, we run
-# the program under gdb, useful during development.
-if [ "$NBDKIT_VALGRIND" ]; then
-    prefix="@VALGRIND@ --vgdb=no --leak-check=full --error-exitcode=119
--suppressions=$s/valgrind-suppressions --trace-children=no
--child-silent-after-fork=yes --run-libc-freeres=no --num-callers=20"
-elif [ "$NBDKIT_GDB" ]; then
-    prefix="gdb --args"
-fi
-
-# Run the final command.
-exec $prefix $b/src/nbdkit "${args[@]}"
diff --git a/wrapper.c b/wrapper.c
new file mode 100644
index 0000000..c253e9f
--- /dev/null
+++ b/wrapper.c
@@ -0,0 +1,252 @@
+/* nbdkit
+ * Copyright (C) 2017-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.
+ */
+
+/*------------------------------------------------------------
+ * This wrapper lets you run nbdkit from the source directory.
+ *
+ * You can use either:
+ * ./nbdkit file [arg=value] [arg=value] ...
+ * or:
+ *   /path/to/nbdkit file [arg=value] [arg=value] ...
+ *
+ * Or you can set $PATH to include the nbdkit source directory and run
+ * the bare "nbdkit" command without supplying the full path.
+ *
+ * The wrapper modifies the bare plugin name (eg. "file") to be the
+ * full path to the locally compiled plugin.  If you don't use this
+ * program and run src/nbdkit directly then it will pick up the
+ * installed plugins which is not usually what you want.
+ *
+ * This program is also used to run the tests (make check).
+ *
+ * You can enable valgrind by setting NBDKIT_VALGRIND=1 (this
+ * is mainly used by the internal tests).
+ *
+ * You can enable debugging by setting NBDKIT_GDB=1
+ *------------------------------------------------------------
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <limits.h>
+
+#include "options.h"
+
+/* Construct an array of parameters passed through to real nbdkit. */
+static const char **cmd;
+static size_t len;
+
+static void
+passthru (const char *s)
+{
+  cmd = realloc (cmd, (len+1) * sizeof (const char *));
+  if (cmd == NULL)
+    abort ();
+  cmd[len] = s;
+  ++len;
+}
+
+static void __attribute__((format (printf, 1, 2)))
+passthru_format (const char *fs, ...)
+{
+  va_list args;
+  char *str;
+
+  va_start (args, fs);
+  if (vasprintf (&str, fs, args) == -1)
+    abort ();
+  va_end (args);
+  passthru (str);
+}
+
+static void
+end_passthru (void)
+{
+  passthru (NULL);
+}
+
+static void
+print_command (void)
+{
+  size_t i;
+
+  if (len > 0)
+    fprintf (stderr, "%s", cmd[0]);
+  for (i = 1; i < len && cmd[i] != NULL; ++i)
+    fprintf (stderr, " %s", cmd[i]);
+  fprintf (stderr, "\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+  bool verbose = false;
+  char *s;
+
+  /* If NBDKIT_VALGRIND=1 is set in the environment, then we run the
+   * program under valgrind.  This is used by the tests.  Similarly if
+   * NBDKIT_GDB=1 is set, we run the program under GDB, useful during
+   * development.
+   */
+  s = getenv ("NBDKIT_VALGRIND");
+  if (s && strcmp (s, "1") == 0) {
+    passthru (VALGRIND);
+    passthru ("--vgdb=no");
+    passthru ("--leak-check=full");
+    passthru ("--error-exitcode=119");
+    passthru_format ("--suppressions=%s/valgrind-suppressions",
srcdir);
+    passthru ("--trace-children=no");
+    passthru ("--child-silent-after-fork=yes");
+    passthru ("--run-libc-freeres=no");
+    passthru ("--num-callers=20");
+  }
+  else {
+    s = getenv ("NBDKIT_GDB");
+    if (s && strcmp (s, "1") == 0) {
+      passthru ("gdb");
+      passthru ("--args");
+    }
+  }
+
+  /* Absolute path of the real nbdkit command. */
+  passthru_format ("%s/src/nbdkit", builddir);
+
+  /* Option parsing.  We don't really parse options here.  We are only
+   * interested in which options have arguments and which need
+   * rewriting.
+   */
+  for (;;) {
+    int c;
+    int long_index = -1;
+    bool is_long_option, has_arg;
+
+    c = getopt_long (argc, argv, short_options, long_options, &long_index);
+    if (c == -1)
+      break;
+
+    if (c == '?')               /* getopt prints an error */
+      exit (EXIT_FAILURE);
+
+    /* long_index is only set if it's an actual long option. */
+    is_long_option = long_index >= 0;
+
+    /* If optarg != NULL then the option has an argument. */
+    has_arg = optarg != NULL;
+
+    /* Verbose is special because we will print the final command. */
+    if (c == 'v') {
+      verbose = true;
+      if (is_long_option)
+        passthru ("--verbose");
+      else
+        passthru ("-v");
+    }
+    /* Filters can be rewritten if they are a short name. */
+    else if (c == FILTER_OPTION) {
+      if (is_short_name (optarg))
+        passthru_format
("--filter=%s/filters/%s/.libs/nbdkit-%s-filter.so",
+                         builddir, optarg, optarg);
+      else
+        passthru_format ("--filter=%s", optarg);
+    }
+    /* Any long option. */
+    else if (is_long_option) {
+      /* Long option which takes an argument. */
+      if (has_arg)
+        passthru_format ("--%s=%s", long_options[long_index].name,
optarg);
+      /* Long option which takes no argument. */
+      else
+        passthru_format ("--%s", long_options[long_index].name);
+    }
+    /* Any short option. */
+    else {
+      /* Short option which takes an argument. */
+      if (has_arg) {
+        passthru_format ("-%c", c);
+        passthru (optarg);
+      }
+      /* Short option which takes no argument. */
+      else
+        passthru_format ("-%c", c);
+    }
+  }
+
+  /* Are there any non-option arguments? */
+  if (optind < argc) {
+    /* Ensure any further parameters can never be parsed as options by
+     * real nbdkit.
+     */
+    passthru ("--");
+
+    /* The first non-option argument is the plugin name.  If it is
+     * a short then rewrite it.
+     */
+    if (is_short_name (argv[optind])) {
+      /* Special plugins written in Perl. */
+      if (strcmp (argv[optind], "example4") == 0 ||
+          strcmp (argv[optind], "tar") == 0) {
+        passthru_format
("%s/plugins/perl/.libs/nbdkit-perl-plugin.so",
+                         builddir);
+        passthru_format ("%s/plugins/%s/nbdkit-%s-plugin",
+                         builddir, argv[optind], argv[optind]);
+      }
+      else {
+        passthru_format ("%s/plugins/%s/.libs/nbdkit-%s-plugin.so",
+                         builddir, argv[optind], argv[optind]);
+      }
+      ++optind;
+    }
+
+    /* Everything else is passed through without rewriting. */
+    while (optind < argc) {
+      passthru (argv[optind]);
+      ++optind;
+    }
+  }
+
+  end_passthru ();
+  if (verbose)
+    print_command ();
+
+  /* Run the final command. */
+  execvp (cmd[0], (char **) cmd);
+  perror (cmd[0]);
+  exit (EXIT_FAILURE);
+}
-- 
2.19.0.rc0
Richard W.M. Jones
2018-Nov-14  14:27 UTC
[Libguestfs] [PATCH nbdkit v3 3/4] tests/test-lang-plugins.c: Free data and reuse variable.
---
 tests/test-lang-plugins.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/test-lang-plugins.c b/tests/test-lang-plugins.c
index 69471c4..46b0563 100644
--- a/tests/test-lang-plugins.c
+++ b/tests/test-lang-plugins.c
@@ -112,6 +112,7 @@ main (int argc, char *argv[])
              program_name, filename, data, content);
     exit (EXIT_FAILURE);
   }
+  free (data);
 
   /* Run sync to test flush path. */
   if (guestfs_sync (g) == -1)
@@ -130,8 +131,8 @@ main (int argc, char *argv[])
   if (guestfs_umount (g, "/") == -1)
     exit (EXIT_FAILURE);
   const char *cmd[] = { "fallocate", "-nzl",
"64k", "/dev/sda", NULL };
-  char *s = guestfs_debug (g, "sh", (char **) cmd);
-  free (s);
+  data = guestfs_debug (g, "sh", (char **) cmd);
+  free (data);
 
   if (guestfs_shutdown (g) == -1)
     exit (EXIT_FAILURE);
-- 
2.19.0.rc0
Richard W.M. Jones
2018-Nov-14  14:27 UTC
[Libguestfs] [PATCH nbdkit v3 4/4] tests: Valgrind is only enabled when NBDKIT_VALGRIND = 1, not any other values.
Fix the tests so they only enable valgrind workarounds or skips when
NBDKIT_VALGRIND is exactly set to "1" and not any other values
(including empty string, or not set).
Thanks: Eric Blake.
---
 tests/test-dump-plugin.sh      | 3 ++-
 tests/test-ext2.c              | 4 +++-
 tests/test-help.sh             | 3 ++-
 tests/test-lang-plugins.c      | 4 +++-
 tests/test-ocaml.c             | 4 +++-
 tests/test-python-exception.sh | 2 +-
 tests/test-version.sh          | 3 ++-
 7 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/tests/test-dump-plugin.sh b/tests/test-dump-plugin.sh
index dc52742..6e0e3d7 100755
--- a/tests/test-dump-plugin.sh
+++ b/tests/test-dump-plugin.sh
@@ -55,7 +55,8 @@ fi
 # However some of these tests are expected to fail.
 test ()
 {
-    case "$1${NBDKIT_VALGRIND:+-valgrind}" in
+    [ "$NBDKIT_VALGRIND" = "1" ] &&
vg="-valgrind"
+    case "$1$vg" in
         vddk | vddk-valgrind)
             # VDDK won't run without special environment variables
             # being set, so ignore it.
diff --git a/tests/test-ext2.c b/tests/test-ext2.c
index 6878028..59e9281 100644
--- a/tests/test-ext2.c
+++ b/tests/test-ext2.c
@@ -49,12 +49,14 @@ main (int argc, char *argv[])
 {
   guestfs_h *g;
   int r;
+  const char *s;
   char *data;
 
   /* The ext2 test fails valgrind.  It seems as if the ext2fs error
    * table cannot be freed.
    */
-  if (getenv ("NBDKIT_VALGRIND") != NULL) {
+  s = getenv ("NBDKIT_VALGRIND");
+  if (s && strcmp (s, "1") == 0) {
     fprintf (stderr, "ext2 test skipped under valgrind.\n");
     exit (77);                  /* Tells automake to skip the test. */
   }
diff --git a/tests/test-help.sh b/tests/test-help.sh
index 68e0bfc..8dc0675 100755
--- a/tests/test-help.sh
+++ b/tests/test-help.sh
@@ -45,7 +45,8 @@ fi
 # However some of these tests are expected to fail.
 test ()
 {
-    case "$1${NBDKIT_VALGRIND:+-valgrind}" in
+    [ "$NBDKIT_VALGRIND" = "1" ] &&
vg="-valgrind"
+    case "$1$vg" in
         vddk | vddk-valgrind)
             # VDDK won't run without special environment variables
             # being set, so ignore it.
diff --git a/tests/test-lang-plugins.c b/tests/test-lang-plugins.c
index 46b0563..f569540 100644
--- a/tests/test-lang-plugins.c
+++ b/tests/test-lang-plugins.c
@@ -49,6 +49,7 @@ main (int argc, char *argv[])
 {
   guestfs_h *g;
   int r;
+  const char *s;
   char *data;
 
   /* These languages currently fail completely when run under
@@ -56,7 +57,8 @@ main (int argc, char *argv[])
    */
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wunused-result"
-  if (getenv ("NBDKIT_VALGRIND") != NULL &&
+  s = getenv ("NBDKIT_VALGRIND");
+  if (s && strcmp (s, "1") == 0 &&
       (strcmp (LANG, "python") == 0 ||
        strcmp (LANG, "ruby") == 0 ||
        strcmp (LANG, "tcl") == 0)) {
diff --git a/tests/test-ocaml.c b/tests/test-ocaml.c
index 4cae8a6..fa61966 100644
--- a/tests/test-ocaml.c
+++ b/tests/test-ocaml.c
@@ -49,13 +49,15 @@ main (int argc, char *argv[])
 {
   guestfs_h *g;
   int r;
+  const char *s;
   char *data;
   size_t i, size;
 
   /* The OCaml tests fail valgrind, so skip them.  We should be able
    * to get this working with a bit of effort.  XXX
    */
-  if (getenv ("NBDKIT_VALGRIND") != NULL) {
+  s = getenv ("NBDKIT_VALGRIND");
+  if (s && strcmp (s, "1") == 0) {
     fprintf (stderr, "ocaml test skipped under valgrind.\n");
     exit (77);                  /* Tells automake to skip the test. */
   }
diff --git a/tests/test-python-exception.sh b/tests/test-python-exception.sh
index 567853a..7813918 100755
--- a/tests/test-python-exception.sh
+++ b/tests/test-python-exception.sh
@@ -36,7 +36,7 @@ set -x
 
 # Python language leaks like a sieve as well as a lot of worrying
 # "Conditional jump or move depends on uninitialised value(s)".
-if test -n "$NBDKIT_VALGRIND"; then
+if [ "$NBDKIT_VALGRIND" = "1" ]; then
     echo "$0: skipping Python test under valgrind."
     exit 77
 fi
diff --git a/tests/test-version.sh b/tests/test-version.sh
index 869d88c..a3b8a18 100755
--- a/tests/test-version.sh
+++ b/tests/test-version.sh
@@ -45,7 +45,8 @@ fi
 # However some of these tests are expected to fail.
 test ()
 {
-    case "$1${NBDKIT_VALGRIND:+-valgrind}" in
+    [ "$NBDKIT_VALGRIND" = "1" ] &&
vg="-valgrind"
+    case "$1$vg" in
         vddk | vddk-valgrind)
             # VDDK won't run without special environment variables
             # being set, so ignore it.
-- 
2.19.0.rc0
Eric Blake
2018-Nov-14  14:43 UTC
Re: [Libguestfs] [PATCH nbdkit v3 4/4] tests: Valgrind is only enabled when NBDKIT_VALGRIND = 1, not any other values.
On 11/14/18 8:27 AM, Richard W.M. Jones wrote:> Fix the tests so they only enable valgrind workarounds or skips when > NBDKIT_VALGRIND is exactly set to "1" and not any other values > (including empty string, or not set). > > Thanks: Eric Blake. > ---> +++ b/tests/test-dump-plugin.sh > @@ -55,7 +55,8 @@ fi > # However some of these tests are expected to fail. > test () > { > - case "$1${NBDKIT_VALGRIND:+-valgrind}" in > + [ "$NBDKIT_VALGRIND" = "1" ] && vg="-valgrind" > + case "$1$vg" inCould misbehave if I have 'export vg=-valgrind' in my environment but not NBDKIT_VALGRIND (cure by prepping with 'vg=' before the [...]). Not sure if that is worth worrying about (someone playing that hard with their environment to try and break the testsuite deserves their problems). Bash has sane rules even if I have NBDKIT_VALGRIND='!' or NBDKIT_VALGRIND='(', but not all other implementations do; the most common ways to ensure that user-supplied input can't cause an unexpected misparse of [ is to use either '[ "x$NBDKIT_VALGRIND" = "x1" ]' or '[ 1 = "$NBDKIT_VALGRIND" ]'. Not sure if that is worth worrying about, since the tests require bash.> +++ b/tests/test-lang-plugins.c > @@ -49,6 +49,7 @@ main (int argc, char *argv[]) > { > guestfs_h *g; > int r; > + const char *s; > char *data; > > /* These languages currently fail completely when run under > @@ -56,7 +57,8 @@ main (int argc, char *argv[]) > */ > #pragma GCC diagnostic push > #pragma GCC diagnostic ignored "-Wunused-result" > - if (getenv ("NBDKIT_VALGRIND") != NULL && > + s = getenv ("NBDKIT_VALGRIND"); > + if (s && strcmp (s, "1") == 0 && > (strcmp (LANG, "python") == 0 || > strcmp (LANG, "ruby") == 0 || > strcmp (LANG, "tcl") == 0)) {Do we still need the #pragma here? Series is looking good now. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
Maybe Matching Threads
- [PATCH nbdkit v2 0/2] build: Replace ./nbdkit with a C program.
- [PATCH 0/2] build: Replace ./nbdkit with a C program.
- Re: [PATCH 2/2] build: Replace ./nbdkit with a C program.
- Re: [PATCH 2/2] build: Replace ./nbdkit with a C program.
- [PATCH nbdkit 0/4] Multiple valgrind improvements and possible security fix.