[Libguestfs] [PATCH nbdkit 5/9 patch split 2/5] lib: Move code for parsing, passwords and paths into libnbdkit.so.

Richard W.M. Jones rjones at redhat.com
Thu Mar 26 20:13:20 UTC 2020


---
 lib/Makefile.am               |  27 ++
 server/Makefile.am            |  24 --
 server/nbdkit.syms            |  28 +--
 server/public.c               | 459 +---------------------------------
 {server => lib}/extents.c     |   4 +-
 lib/parse.c                   | 341 +++++++++++++++++++++++++
 lib/password.c                | 152 +++++++++++
 lib/path.c                    |  97 +++++++
 {server => lib}/test-public.c |   3 +-
 .gitignore                    |   2 +-
 lib/libnbdkit.syms            |  20 ++
 11 files changed, 645 insertions(+), 512 deletions(-)

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4896dc95..268282af 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -40,8 +40,12 @@ EXTRA_DIST = libnbdkit.syms
 
 lib_LTLIBRARIES = libnbdkit.la
 libnbdkit_la_SOURCES = \
+	extents.c \
 	init.c \
 	lib.h \
+	parse.c \
+	password.c \
+	path.c \
 	$(NULL)
 
 libnbdkit_la_CPPFLAGS = \
@@ -69,3 +73,26 @@ if !ENABLE_LIBFUZZER
 libnbdkit_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libnbdkit.syms
 endif
 endif
+
+# Unit testing
+
+TESTS = test-public
+
+check_PROGRAMS = test-public
+
+test_public_SOURCES = \
+	test-public.c \
+	extents.c \
+	parse.c \
+	password.c \
+	$(NULL)
+test_public_CPPFLAGS = \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/common/include \
+	-I$(top_srcdir)/common/protocol \
+	-I$(top_srcdir)/common/utils \
+	$(NULL)
+test_public_CFLAGS = $(WARNINGS_CFLAGS) $(VALGRIND_CFLAGS)
+test_public_LDADD = \
+	$(top_builddir)/common/utils/libutils.la \
+	$(NULL)
diff --git a/server/Makefile.am b/server/Makefile.am
index ad0de9b1..8448bc10 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -43,7 +43,6 @@ nbdkit_SOURCES = \
 	crypto.c \
 	debug.c \
 	debug-flags.c \
-	extents.c \
 	filters.c \
 	internal.h \
 	locks.c \
@@ -131,26 +130,3 @@ synopsis.c: $(top_srcdir)/docs/synopsis.txt
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = nbdkit.pc
-
-# Unit testing
-
-TESTS = test-public
-
-check_PROGRAMS = test-public
-
-test_public_SOURCES = \
-	test-public.c \
-	public.c \
-	extents.c \
-	$(NULL)
-test_public_CPPFLAGS = \
-	-I$(top_srcdir)/lib \
-	-I$(top_srcdir)/include \
-	-I$(top_srcdir)/common/include \
-	-I$(top_srcdir)/common/protocol \
-	-I$(top_srcdir)/common/utils \
-	$(NULL)
-test_public_CFLAGS = $(WARNINGS_CFLAGS) $(VALGRIND_CFLAGS)
-test_public_LDADD = \
-	$(top_builddir)/common/utils/libutils.la \
-	$(NULL)
diff --git a/server/nbdkit.syms b/server/nbdkit.syms
index 111223f2..56e5008e 100644
--- a/server/nbdkit.syms
+++ b/server/nbdkit.syms
@@ -30,44 +30,20 @@
 # SUCH DAMAGE.
 
 # This linker script controls the visibility of symbols in the final
-# nbdkit binary.  We want to export some symbols to plugins, but at
-# the same time we don't want plugins to be able to call arbitrary
-# functions from nbdkit, so this script lists only the symbols we want
-# to export.
+# nbdkit binary.
 
 {
-  # The functions we want plugins and filters to call.
   global:
-    nbdkit_absolute_path;
-    nbdkit_add_extent;
     nbdkit_debug;
     nbdkit_error;
     nbdkit_export_name;
-    nbdkit_extents_count;
-    nbdkit_extents_free;
-    nbdkit_extents_new;
-    nbdkit_get_extent;
     nbdkit_nanosleep;
-    nbdkit_parse_bool;
-    nbdkit_parse_int8_t;
-    nbdkit_parse_int16_t;
-    nbdkit_parse_int32_t;
-    nbdkit_parse_int64_t;
-    nbdkit_parse_int;
-    nbdkit_parse_size;
-    nbdkit_parse_uint8_t;
-    nbdkit_parse_uint16_t;
-    nbdkit_parse_uint32_t;
-    nbdkit_parse_uint64_t;
-    nbdkit_parse_unsigned;
     nbdkit_peer_name;
-    nbdkit_read_password;
-    nbdkit_realpath;
     nbdkit_set_error;
     nbdkit_shutdown;
     nbdkit_vdebug;
     nbdkit_verror;
-
+    # -D server.* flags must be visible to nbdkit itself.
     nbdkit_debug_*;
 
   # Everything else is hidden.
diff --git a/server/public.c b/server/public.c
index 3fd11253..33d40688 100644
--- a/server/public.c
+++ b/server/public.c
@@ -36,7 +36,6 @@
 
 #include <config.h>
 
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -44,6 +43,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <ctype.h>
 #include <termios.h>
@@ -56,463 +56,6 @@
 
 #include "internal.h"
 
-char *
-nbdkit_absolute_path (const char *path)
-{
-  CLEANUP_FREE char *pwd = NULL;
-  char *ret;
-
-  if (path == NULL || *path == '\0') {
-    nbdkit_error ("cannot convert null or empty path to an absolute path");
-    return NULL;
-  }
-
-  if (*path == '/') {
-    ret = strdup (path);
-    if (!ret) {
-      nbdkit_error ("strdup: %m");
-      return NULL;
-    }
-    return ret;
-  }
-
-  pwd = get_current_dir_name ();
-  if (pwd == NULL) {
-    nbdkit_error ("get_current_dir_name: %m");
-    return NULL;
-  }
-
-  if (asprintf (&ret, "%s/%s", pwd, path) == -1) {
-    nbdkit_error ("asprintf: %m");
-    return NULL;
-  }
-
-  return ret;
-}
-
-char *
-nbdkit_realpath (const char *path)
-{
-  char *ret;
-
-  if (path == NULL || *path == '\0') {
-    nbdkit_error ("cannot resolve a null or empty path");
-    return NULL;
-  }
-
-  ret = realpath (path, NULL);
-  if (ret == NULL) {
-    nbdkit_error ("realpath: %s: %m", path);
-    return NULL;
-  }
-
-  return ret;
-}
-
-/* Common code for parsing integers. */
-#define PARSE_COMMON_TAIL                                               \
-  if (errno != 0) {                                                     \
-    nbdkit_error ("%s: could not parse number: \"%s\": %m",             \
-                  what, str);                                           \
-    return -1;                                                          \
-  }                                                                     \
-  if (end == str) {                                                     \
-    nbdkit_error ("%s: empty string where we expected a number",        \
-                  what);                                                \
-    return -1;                                                          \
-  }                                                                     \
-  if (*end) {                                                           \
-    nbdkit_error ("%s: could not parse number: \"%s\": trailing garbage", \
-                  what, str);                                           \
-    return -1;                                                          \
-  }                                                                     \
-                                                                        \
-  if (rp)                                                               \
-    *rp = r;                                                            \
-  return 0
-
-/* Functions for parsing signed integers. */
-int
-nbdkit_parse_int (const char *what, const char *str, int *rp)
-{
-  long r;
-  char *end;
-
-  errno = 0;
-  r = strtol (str, &end, 0);
-#if INT_MAX != LONG_MAX
-  if (r < INT_MIN || r > INT_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_int8_t (const char *what, const char *str, int8_t *rp)
-{
-  long r;
-  char *end;
-
-  errno = 0;
-  r = strtol (str, &end, 0);
-  if (r < INT8_MIN || r > INT8_MAX)
-    errno = ERANGE;
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_int16_t (const char *what, const char *str, int16_t *rp)
-{
-  long r;
-  char *end;
-
-  errno = 0;
-  r = strtol (str, &end, 0);
-  if (r < INT16_MIN || r > INT16_MAX)
-    errno = ERANGE;
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_int32_t (const char *what, const char *str, int32_t *rp)
-{
-  long r;
-  char *end;
-
-  errno = 0;
-  r = strtol (str, &end, 0);
-#if INT32_MAX != LONG_MAX
-  if (r < INT32_MIN || r > INT32_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_int64_t (const char *what, const char *str, int64_t *rp)
-{
-  long long r;
-  char *end;
-
-  errno = 0;
-  r = strtoll (str, &end, 0);
-#if INT64_MAX != LONGLONG_MAX
-  if (r < INT64_MIN || r > INT64_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-/* Functions for parsing unsigned integers. */
-
-/* strtou* functions have surprising behaviour if the first character
- * (after whitespace) is '-', so reject this early.
- */
-#define PARSE_ERROR_IF_NEGATIVE                                         \
-  do {                                                                  \
-    while (isspace (*str))                                              \
-      str++;                                                            \
-    if (*str == '-') {                                                  \
-      nbdkit_error ("%s: negative numbers are not allowed", what);      \
-      return -1;                                                        \
-    }                                                                   \
-  } while (0)
-
-int
-nbdkit_parse_unsigned (const char *what, const char *str, unsigned *rp)
-{
-  unsigned long r;
-  char *end;
-
-  PARSE_ERROR_IF_NEGATIVE;
-  errno = 0;
-  r = strtoul (str, &end, 0);
-#if UINT_MAX != ULONG_MAX
-  if (r > UINT_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_uint8_t (const char *what, const char *str, uint8_t *rp)
-{
-  unsigned long r;
-  char *end;
-
-  PARSE_ERROR_IF_NEGATIVE;
-  errno = 0;
-  r = strtoul (str, &end, 0);
-  if (r > UINT8_MAX)
-    errno = ERANGE;
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_uint16_t (const char *what, const char *str, uint16_t *rp)
-{
-  unsigned long r;
-  char *end;
-
-  PARSE_ERROR_IF_NEGATIVE;
-  errno = 0;
-  r = strtoul (str, &end, 0);
-  if (r > UINT16_MAX)
-    errno = ERANGE;
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_uint32_t (const char *what, const char *str, uint32_t *rp)
-{
-  unsigned long r;
-  char *end;
-
-  PARSE_ERROR_IF_NEGATIVE;
-  errno = 0;
-  r = strtoul (str, &end, 0);
-#if UINT32_MAX != ULONG_MAX
-  if (r > UINT32_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-int
-nbdkit_parse_uint64_t (const char *what, const char *str, uint64_t *rp)
-{
-  unsigned long long r;
-  char *end;
-
-  PARSE_ERROR_IF_NEGATIVE;
-  errno = 0;
-  r = strtoull (str, &end, 0);
-#if UINT64_MAX != ULONGLONG_MAX
-  if (r > UINT64_MAX)
-    errno = ERANGE;
-#endif
-  PARSE_COMMON_TAIL;
-}
-
-/* Parse a string as a size with possible scaling suffix, or return -1
- * after reporting the error.
- */
-int64_t
-nbdkit_parse_size (const char *str)
-{
-  int64_t size;
-  char *end;
-  uint64_t scale = 1;
-
-  /* Disk sizes cannot usefully exceed off_t (which is signed) and
-   * cannot be negative.  */
-  /* XXX Should we also parse things like '1.5M'? */
-  /* XXX Should we allow hex? If so, hex cannot use scaling suffixes,
-   * because some of them are valid hex digits */
-  errno = 0;
-  size = strtoimax (str, &end, 10);
-  if (str == end) {
-    nbdkit_error ("could not parse size string (%s)", str);
-    return -1;
-  }
-  if (size < 0) {
-    nbdkit_error ("size cannot be negative (%s)", str);
-    return -1;
-  }
-  if (errno) {
-    nbdkit_error ("size (%s) exceeds maximum value", str);
-    return -1;
-  }
-
-  switch (*end) {
-    /* No suffix */
-  case '\0':
-    end--; /* Safe, since we already filtered out empty string */
-    break;
-
-    /* Powers of 1024 */
-  case 'e': case 'E':
-    scale *= 1024;
-    /* fallthru */
-  case 'p': case 'P':
-    scale *= 1024;
-    /* fallthru */
-  case 't': case 'T':
-    scale *= 1024;
-    /* fallthru */
-  case 'g': case 'G':
-    scale *= 1024;
-    /* fallthru */
-  case 'm': case 'M':
-    scale *= 1024;
-    /* fallthru */
-  case 'k': case 'K':
-    scale *= 1024;
-    /* fallthru */
-  case 'b': case 'B':
-    break;
-
-    /* "sectors", ie. units of 512 bytes, even if that's not the real
-     * sector size */
-  case 's': case 'S':
-    scale = 512;
-    break;
-
-  default:
-    nbdkit_error ("could not parse size: unknown suffix '%s'", end);
-    return -1;
-  }
-
-  /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB'
-   * for powers of 1000, for similarity to GNU tools. But for now,
-   * anything beyond 'M' is dropped.  */
-  if (end[1]) {
-    nbdkit_error ("could not parse size: unknown suffix '%s'", end);
-    return -1;
-  }
-
-  if (INT64_MAX / scale < size) {
-    nbdkit_error ("overflow computing size (%s)", str);
-    return -1;
-  }
-
-  return size * scale;
-}
-
-/* Parse a string as a boolean, or return -1 after reporting the error.
- */
-int
-nbdkit_parse_bool (const char *str)
-{
-  if (!strcmp (str, "1") ||
-      !strcasecmp (str, "true") ||
-      !strcasecmp (str, "t") ||
-      !strcasecmp (str, "yes") ||
-      !strcasecmp (str, "y") ||
-      !strcasecmp (str, "on"))
-    return 1;
-
-  if (!strcmp (str, "0") ||
-      !strcasecmp (str, "false") ||
-      !strcasecmp (str, "f") ||
-      !strcasecmp (str, "no") ||
-      !strcasecmp (str, "n") ||
-      !strcasecmp (str, "off"))
-    return 0;
-
-  nbdkit_error ("could not decipher boolean (%s)", str);
-  return -1;
-}
-
-/* Read a password from configuration value. */
-static int read_password_from_fd (const char *what, int fd, char **password);
-
-int
-nbdkit_read_password (const char *value, char **password)
-{
-  int tty, err;
-  struct termios orig, temp;
-  ssize_t r;
-  size_t n;
-
-  *password = NULL;
-
-  /* Read from stdin. */
-  if (strcmp (value, "-") == 0) {
-    printf ("password: ");
-
-    /* Set no echo. */
-    tty = isatty (0);
-    if (tty) {
-      tcgetattr (0, &orig);
-      temp = orig;
-      temp.c_lflag &= ~ECHO;
-      tcsetattr (0, TCSAFLUSH, &temp);
-    }
-
-    r = getline (password, &n, stdin);
-    err = errno;
-
-    /* Restore echo. */
-    if (tty)
-      tcsetattr (0, TCSAFLUSH, &orig);
-
-    /* Complete the printf above. */
-    printf ("\n");
-
-    if (r == -1) {
-      errno = err;
-      nbdkit_error ("could not read password from stdin: %m");
-      return -1;
-    }
-    if (*password && r > 0 && (*password)[r-1] == '\n')
-      (*password)[r-1] = '\0';
-  }
-
-  /* Read from numbered file descriptor. */
-  else if (value[0] == '-') {
-    int fd;
-
-    if (nbdkit_parse_int ("password file descriptor", &value[1], &fd) == -1)
-      return -1;
-    if (read_password_from_fd (&value[1], fd, password) == -1)
-      return -1;
-  }
-
-  /* Read password from a file. */
-  else if (value[0] == '+') {
-    int fd;
-
-    fd = open (&value[1], O_CLOEXEC | O_RDONLY);
-    if (fd == -1) {
-      nbdkit_error ("open %s: %m", &value[1]);
-      return -1;
-    }
-    if (read_password_from_fd (&value[1], fd, password) == -1)
-      return -1;
-  }
-
-  /* Parameter is the password. */
-  else {
-    *password = strdup (value);
-    if (*password == NULL) {
-      nbdkit_error ("strdup: %m");
-      return -1;
-    }
-  }
-
-  return 0;
-}
-
-static int
-read_password_from_fd (const char *what, int fd, char **password)
-{
-  FILE *fp;
-  size_t n;
-  ssize_t r;
-  int err;
-
-  fp = fdopen (fd, "r");
-  if (fp == NULL) {
-    nbdkit_error ("fdopen %s: %m", what);
-    close (fd);
-    return -1;
-  }
-  r = getline (password, &n, fp);
-  err = errno;
-  fclose (fp);
-  if (r == -1) {
-    errno = err;
-    nbdkit_error ("could not read password from %s: %m", what);
-    return -1;
-  }
-
-  if (*password && r > 0 && (*password)[r-1] == '\n')
-    (*password)[r-1] = '\0';
-
-  return 0;
-}
-
 int
 nbdkit_nanosleep (unsigned sec, unsigned nsec)
 {
diff --git a/server/extents.c b/lib/extents.c
similarity index 99%
rename from server/extents.c
rename to lib/extents.c
index 2d609652..8e3c8632 100644
--- a/server/extents.c
+++ b/lib/extents.c
@@ -41,10 +41,10 @@
 #include <errno.h>
 #include <assert.h>
 
+#include "nbdkit-filter.h"
+
 #include "minmax.h"
 
-#include "internal.h"
-
 /* Cap nr_extents to avoid sending over-large replies to the client,
  * and to avoid a plugin with frequent alternations consuming too much
  * memory.
diff --git a/lib/parse.c b/lib/parse.c
new file mode 100644
index 00000000..cd3c88ac
--- /dev/null
+++ b/lib/parse.c
@@ -0,0 +1,341 @@
+/* nbdkit
+ * Copyright (C) 2013-2019 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 <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "nbdkit-plugin.h"
+
+#include "cleanup.h"
+
+/* Common code for parsing integers. */
+#define PARSE_COMMON_TAIL                                               \
+  if (errno != 0) {                                                     \
+    nbdkit_error ("%s: could not parse number: \"%s\": %m",             \
+                  what, str);                                           \
+    return -1;                                                          \
+  }                                                                     \
+  if (end == str) {                                                     \
+    nbdkit_error ("%s: empty string where we expected a number",        \
+                  what);                                                \
+    return -1;                                                          \
+  }                                                                     \
+  if (*end) {                                                           \
+    nbdkit_error ("%s: could not parse number: \"%s\": trailing garbage", \
+                  what, str);                                           \
+    return -1;                                                          \
+  }                                                                     \
+                                                                        \
+  if (rp)                                                               \
+    *rp = r;                                                            \
+  return 0
+
+/* Functions for parsing signed integers. */
+int
+nbdkit_parse_int (const char *what, const char *str, int *rp)
+{
+  long r;
+  char *end;
+
+  errno = 0;
+  r = strtol (str, &end, 0);
+#if INT_MAX != LONG_MAX
+  if (r < INT_MIN || r > INT_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_int8_t (const char *what, const char *str, int8_t *rp)
+{
+  long r;
+  char *end;
+
+  errno = 0;
+  r = strtol (str, &end, 0);
+  if (r < INT8_MIN || r > INT8_MAX)
+    errno = ERANGE;
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_int16_t (const char *what, const char *str, int16_t *rp)
+{
+  long r;
+  char *end;
+
+  errno = 0;
+  r = strtol (str, &end, 0);
+  if (r < INT16_MIN || r > INT16_MAX)
+    errno = ERANGE;
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_int32_t (const char *what, const char *str, int32_t *rp)
+{
+  long r;
+  char *end;
+
+  errno = 0;
+  r = strtol (str, &end, 0);
+#if INT32_MAX != LONG_MAX
+  if (r < INT32_MIN || r > INT32_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_int64_t (const char *what, const char *str, int64_t *rp)
+{
+  long long r;
+  char *end;
+
+  errno = 0;
+  r = strtoll (str, &end, 0);
+#if INT64_MAX != LONGLONG_MAX
+  if (r < INT64_MIN || r > INT64_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+/* Functions for parsing unsigned integers. */
+
+/* strtou* functions have surprising behaviour if the first character
+ * (after whitespace) is '-', so reject this early.
+ */
+#define PARSE_ERROR_IF_NEGATIVE                                         \
+  do {                                                                  \
+    while (isspace (*str))                                              \
+      str++;                                                            \
+    if (*str == '-') {                                                  \
+      nbdkit_error ("%s: negative numbers are not allowed", what);      \
+      return -1;                                                        \
+    }                                                                   \
+  } while (0)
+
+int
+nbdkit_parse_unsigned (const char *what, const char *str, unsigned *rp)
+{
+  unsigned long r;
+  char *end;
+
+  PARSE_ERROR_IF_NEGATIVE;
+  errno = 0;
+  r = strtoul (str, &end, 0);
+#if UINT_MAX != ULONG_MAX
+  if (r > UINT_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_uint8_t (const char *what, const char *str, uint8_t *rp)
+{
+  unsigned long r;
+  char *end;
+
+  PARSE_ERROR_IF_NEGATIVE;
+  errno = 0;
+  r = strtoul (str, &end, 0);
+  if (r > UINT8_MAX)
+    errno = ERANGE;
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_uint16_t (const char *what, const char *str, uint16_t *rp)
+{
+  unsigned long r;
+  char *end;
+
+  PARSE_ERROR_IF_NEGATIVE;
+  errno = 0;
+  r = strtoul (str, &end, 0);
+  if (r > UINT16_MAX)
+    errno = ERANGE;
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_uint32_t (const char *what, const char *str, uint32_t *rp)
+{
+  unsigned long r;
+  char *end;
+
+  PARSE_ERROR_IF_NEGATIVE;
+  errno = 0;
+  r = strtoul (str, &end, 0);
+#if UINT32_MAX != ULONG_MAX
+  if (r > UINT32_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+int
+nbdkit_parse_uint64_t (const char *what, const char *str, uint64_t *rp)
+{
+  unsigned long long r;
+  char *end;
+
+  PARSE_ERROR_IF_NEGATIVE;
+  errno = 0;
+  r = strtoull (str, &end, 0);
+#if UINT64_MAX != ULONGLONG_MAX
+  if (r > UINT64_MAX)
+    errno = ERANGE;
+#endif
+  PARSE_COMMON_TAIL;
+}
+
+/* Parse a string as a size with possible scaling suffix, or return -1
+ * after reporting the error.
+ */
+int64_t
+nbdkit_parse_size (const char *str)
+{
+  int64_t size;
+  char *end;
+  uint64_t scale = 1;
+
+  /* Disk sizes cannot usefully exceed off_t (which is signed) and
+   * cannot be negative.  */
+  /* XXX Should we also parse things like '1.5M'? */
+  /* XXX Should we allow hex? If so, hex cannot use scaling suffixes,
+   * because some of them are valid hex digits */
+  errno = 0;
+  size = strtoimax (str, &end, 10);
+  if (str == end) {
+    nbdkit_error ("could not parse size string (%s)", str);
+    return -1;
+  }
+  if (size < 0) {
+    nbdkit_error ("size cannot be negative (%s)", str);
+    return -1;
+  }
+  if (errno) {
+    nbdkit_error ("size (%s) exceeds maximum value", str);
+    return -1;
+  }
+
+  switch (*end) {
+    /* No suffix */
+  case '\0':
+    end--; /* Safe, since we already filtered out empty string */
+    break;
+
+    /* Powers of 1024 */
+  case 'e': case 'E':
+    scale *= 1024;
+    /* fallthru */
+  case 'p': case 'P':
+    scale *= 1024;
+    /* fallthru */
+  case 't': case 'T':
+    scale *= 1024;
+    /* fallthru */
+  case 'g': case 'G':
+    scale *= 1024;
+    /* fallthru */
+  case 'm': case 'M':
+    scale *= 1024;
+    /* fallthru */
+  case 'k': case 'K':
+    scale *= 1024;
+    /* fallthru */
+  case 'b': case 'B':
+    break;
+
+    /* "sectors", ie. units of 512 bytes, even if that's not the real
+     * sector size */
+  case 's': case 'S':
+    scale = 512;
+    break;
+
+  default:
+    nbdkit_error ("could not parse size: unknown suffix '%s'", end);
+    return -1;
+  }
+
+  /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB'
+   * for powers of 1000, for similarity to GNU tools. But for now,
+   * anything beyond 'M' is dropped.  */
+  if (end[1]) {
+    nbdkit_error ("could not parse size: unknown suffix '%s'", end);
+    return -1;
+  }
+
+  if (INT64_MAX / scale < size) {
+    nbdkit_error ("overflow computing size (%s)", str);
+    return -1;
+  }
+
+  return size * scale;
+}
+
+/* Parse a string as a boolean, or return -1 after reporting the error.
+ */
+int
+nbdkit_parse_bool (const char *str)
+{
+  if (!strcmp (str, "1") ||
+      !strcasecmp (str, "true") ||
+      !strcasecmp (str, "t") ||
+      !strcasecmp (str, "yes") ||
+      !strcasecmp (str, "y") ||
+      !strcasecmp (str, "on"))
+    return 1;
+
+  if (!strcmp (str, "0") ||
+      !strcasecmp (str, "false") ||
+      !strcasecmp (str, "f") ||
+      !strcasecmp (str, "no") ||
+      !strcasecmp (str, "n") ||
+      !strcasecmp (str, "off"))
+    return 0;
+
+  nbdkit_error ("could not decipher boolean (%s)", str);
+  return -1;
+}
diff --git a/lib/password.c b/lib/password.c
new file mode 100644
index 00000000..8452c153
--- /dev/null
+++ b/lib/password.c
@@ -0,0 +1,152 @@
+/* nbdkit
+ * Copyright (C) 2013-2019 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 <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include "nbdkit-plugin.h"
+
+/* Read a password from configuration value. */
+
+static int read_password_from_fd (const char *what, int fd, char **password);
+
+int
+nbdkit_read_password (const char *value, char **password)
+{
+  int tty, err;
+  struct termios orig, temp;
+  ssize_t r;
+  size_t n;
+
+  *password = NULL;
+
+  /* Read from stdin. */
+  if (strcmp (value, "-") == 0) {
+    printf ("password: ");
+
+    /* Set no echo. */
+    tty = isatty (0);
+    if (tty) {
+      tcgetattr (0, &orig);
+      temp = orig;
+      temp.c_lflag &= ~ECHO;
+      tcsetattr (0, TCSAFLUSH, &temp);
+    }
+
+    r = getline (password, &n, stdin);
+    err = errno;
+
+    /* Restore echo. */
+    if (tty)
+      tcsetattr (0, TCSAFLUSH, &orig);
+
+    /* Complete the printf above. */
+    printf ("\n");
+
+    if (r == -1) {
+      errno = err;
+      nbdkit_error ("could not read password from stdin: %m");
+      return -1;
+    }
+    if (*password && r > 0 && (*password)[r-1] == '\n')
+      (*password)[r-1] = '\0';
+  }
+
+  /* Read from numbered file descriptor. */
+  else if (value[0] == '-') {
+    int fd;
+
+    if (nbdkit_parse_int ("password file descriptor", &value[1], &fd) == -1)
+      return -1;
+    if (read_password_from_fd (&value[1], fd, password) == -1)
+      return -1;
+  }
+
+  /* Read password from a file. */
+  else if (value[0] == '+') {
+    int fd;
+
+    fd = open (&value[1], O_CLOEXEC | O_RDONLY);
+    if (fd == -1) {
+      nbdkit_error ("open %s: %m", &value[1]);
+      return -1;
+    }
+    if (read_password_from_fd (&value[1], fd, password) == -1)
+      return -1;
+  }
+
+  /* Parameter is the password. */
+  else {
+    *password = strdup (value);
+    if (*password == NULL) {
+      nbdkit_error ("strdup: %m");
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static int
+read_password_from_fd (const char *what, int fd, char **password)
+{
+  FILE *fp;
+  size_t n;
+  ssize_t r;
+  int err;
+
+  fp = fdopen (fd, "r");
+  if (fp == NULL) {
+    nbdkit_error ("fdopen %s: %m", what);
+    close (fd);
+    return -1;
+  }
+  r = getline (password, &n, fp);
+  err = errno;
+  fclose (fp);
+  if (r == -1) {
+    errno = err;
+    nbdkit_error ("could not read password from %s: %m", what);
+    return -1;
+  }
+
+  if (*password && r > 0 && (*password)[r-1] == '\n')
+    (*password)[r-1] = '\0';
+
+  return 0;
+}
diff --git a/lib/path.c b/lib/path.c
new file mode 100644
index 00000000..244c2b0a
--- /dev/null
+++ b/lib/path.c
@@ -0,0 +1,97 @@
+/* nbdkit
+ * Copyright (C) 2013-2019 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 <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "nbdkit-plugin.h"
+
+#include "cleanup.h"
+#include "get-current-dir-name.h"
+
+char *
+nbdkit_absolute_path (const char *path)
+{
+  CLEANUP_FREE char *pwd = NULL;
+  char *ret;
+
+  if (path == NULL || *path == '\0') {
+    nbdkit_error ("cannot convert null or empty path to an absolute path");
+    return NULL;
+  }
+
+  if (*path == '/') {
+    ret = strdup (path);
+    if (!ret) {
+      nbdkit_error ("strdup: %m");
+      return NULL;
+    }
+    return ret;
+  }
+
+  pwd = get_current_dir_name ();
+  if (pwd == NULL) {
+    nbdkit_error ("get_current_dir_name: %m");
+    return NULL;
+  }
+
+  if (asprintf (&ret, "%s/%s", pwd, path) == -1) {
+    nbdkit_error ("asprintf: %m");
+    return NULL;
+  }
+
+  return ret;
+}
+
+char *
+nbdkit_realpath (const char *path)
+{
+  char *ret;
+
+  if (path == NULL || *path == '\0') {
+    nbdkit_error ("cannot resolve a null or empty path");
+    return NULL;
+  }
+
+  ret = realpath (path, NULL);
+  if (ret == NULL) {
+    nbdkit_error ("realpath: %s: %m", path);
+    return NULL;
+  }
+
+  return ret;
+}
diff --git a/server/test-public.c b/lib/test-public.c
similarity index 99%
rename from server/test-public.c
rename to lib/test-public.c
index fe347d44..d680e7ad 100644
--- a/server/test-public.c
+++ b/lib/test-public.c
@@ -41,7 +41,8 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "internal.h"
+#include "nbdkit-plugin.h"
+#include "nbdkit-filter.h"
 
 static bool error_flagged;
 
diff --git a/.gitignore b/.gitignore
index 4bb035e1..2f9d45a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,7 @@ plugins/*/*.3
 /include/nbdkit-version.h
 /INSTALL
 /install-sh
+/lib/test-public
 /libtool
 /ltmain.sh
 /missing
@@ -80,7 +81,6 @@ plugins/*/*.3
 /server/nbdkit
 /server/nbdkit.pc
 /server/synopsis.c
-/server/test-public
 /stamp-h1
 /tests/__pycache__/
 /tests/disk
diff --git a/lib/libnbdkit.syms b/lib/libnbdkit.syms
index a70b35fc..f4e80e42 100644
--- a/lib/libnbdkit.syms
+++ b/lib/libnbdkit.syms
@@ -38,6 +38,26 @@
 {
   # The functions we want plugins and filters to call.
   global:
+    nbdkit_absolute_path;
+    nbdkit_add_extent;
+    nbdkit_extents_count;
+    nbdkit_extents_free;
+    nbdkit_extents_new;
+    nbdkit_get_extent;
+    nbdkit_parse_bool;
+    nbdkit_parse_int16_t;
+    nbdkit_parse_int32_t;
+    nbdkit_parse_int64_t;
+    nbdkit_parse_int8_t;
+    nbdkit_parse_int;
+    nbdkit_parse_size;
+    nbdkit_parse_uint16_t;
+    nbdkit_parse_uint32_t;
+    nbdkit_parse_uint64_t;
+    nbdkit_parse_uint8_t;
+    nbdkit_parse_unsigned;
+    nbdkit_read_password;
+    nbdkit_realpath;
 
     # Private function that must only be called by the server.
     libnbdkit_private_init;
-- 
2.25.0




More information about the Libguestfs mailing list