[Libguestfs] [PATCH nbdkit 1/2] log: Use strict shell quoting for every parameter displayed in the log file.

Richard W.M. Jones rjones at redhat.com
Sun Dec 20 12:23:07 UTC 2020


This is not fully backwards compatible, although the changes are
minor:

 * Lists returned by ListExports and Extents use the array format that
   can be parsed by bash, eg:

   Extents id=1 extents=(0x0 0x8000 "hole,zero" 0x8000 0x8000 "") return=0

 * Errors are returned as separate error= parameters, and simplified, eg:

   ...Read id=1 return=-1 error=EINVAL

 * Strings are quoted properly in all circumstances.

This commit also updates the documentation and adds more tests.
---
 filters/log/nbdkit-log-filter.pod |  8 ++--
 tests/Makefile.am                 | 11 ++++-
 filters/log/log.c                 | 69 +++++++++++++++++++++----------
 filters/log/output.c              | 30 +++++---------
 tests/test-log-error.sh           | 62 +++++++++++++++++++++++++++
 tests/test-log-extents.sh         | 59 ++++++++++++++++++++++++++
 6 files changed, 193 insertions(+), 46 deletions(-)

diff --git a/filters/log/nbdkit-log-filter.pod b/filters/log/nbdkit-log-filter.pod
index c36b3d35..abf52e18 100644
--- a/filters/log/nbdkit-log-filter.pod
+++ b/filters/log/nbdkit-log-filter.pod
@@ -62,10 +62,10 @@ An example logging session of a client that requests an export list
 before performing a single successful read is:
 
  2020-08-06 02:07:23.080415 ListExports id=1 readonly=0 tls=0 ...
- 2020-08-06 02:07:23.080502 ...ListExports id=1 exports=[""] return=0
- 2020-08-06 02:07:23.080712 connection=1 Connect export='' tls=0 size=0x400 write=1 flush=1 rotational=0 trim=1 zero=2 fua=2 extents=1 cache=2 fast_zero=1
+ 2020-08-06 02:07:23.080502 ...ListExports id=1 exports=("") return=0
+ 2020-08-06 02:07:23.080712 connection=1 Connect export="" tls=0 size=0x400 write=1 flush=1 rotational=0 trim=1 zero=2 fua=2 extents=1 cache=2 fast_zero=1
  2020-08-06 02:07:23.080907 connection=1 Read id=1 offset=0x0 count=0x200 ...
- 2020-08-06 02:07:23.080927 connection=1 ...Read id=1 return=0 (Success)
+ 2020-08-06 02:07:23.080927 connection=1 ...Read id=1 return=0
  2020-08-06 02:07:23.081255 connection=1 Disconnect transactions=1
 
 All lines start with a timestamp in C<YYYY-MM-DD HH:MM:ZZ.MS> format.
@@ -82,6 +82,8 @@ value.  Because nbdkit handles requests in parallel different requests
 may be intermingled.  Use the C<id=N> field for correlation, it is
 unique per connection.
 
+Strings and lists are shell-quoted.
+
 =head1 FILES
 
 =over 4
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 562a6209..a6be3938 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1495,8 +1495,15 @@ TESTS += test-limit.sh
 EXTRA_DIST += test-limit.sh
 
 # log filter test.
-TESTS += test-log.sh
-EXTRA_DIST += test-log.sh
+TESTS += \
+	test-log.sh \
+	test-log-error.sh \
+	test-log-extents.sh \
+	$(NULL)
+EXTRA_DIST += \
+	test-log.sh \
+	test-log-extents.sh \
+	$(NULL)
 
 # nofilter test.
 TESTS += test-nofilter.sh
diff --git a/filters/log/log.c b/filters/log/log.c
index 1c67a95e..37b36498 100644
--- a/filters/log/log.c
+++ b/filters/log/log.c
@@ -35,6 +35,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include <stdarg.h>
 #include <errno.h>
@@ -165,24 +166,25 @@ log_list_exports (nbdkit_next_list_exports *next, void *nxdata,
   }
   else {
     FILE *fp;
-    CLEANUP_FREE char *exports_str = NULL;
+    CLEANUP_FREE char *str = NULL;
     size_t i, n, len = 0;
 
-    fp = open_memstream (&exports_str, &len);
+    fp = open_memstream (&str, &len);
     if (fp != NULL) {
+      fprintf (fp, "exports=(");
       n = nbdkit_exports_count (exports);
       for (i = 0; i < n; ++i) {
         struct nbdkit_export e = nbdkit_get_export (exports, i);
         if (i > 0)
-          fprintf (fp, ", ");
+          fprintf (fp, " ");
         shell_quote (e.name, fp);
       }
-
+      fprintf (fp, ") return=0");
       fclose (fp);
+      leave (NULL, id, "ListExports", "%s", str);
     }
-
-    leave (NULL, id, "ListExports", "exports=[%s] return=0",
-           exports_str ? exports_str : "(null)");
+    else
+      leave (NULL, id, "ListExports", "");
   }
   return r;
 }
@@ -246,6 +248,9 @@ static int
 log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle,
              int readonly)
 {
+  FILE *fp;
+  CLEANUP_FREE char *str = NULL;
+  size_t len = 0;
   struct handle *h = handle;
   const char *exportname = h->exportname;
   int64_t size = next_ops->get_size (nxdata);
@@ -263,9 +268,21 @@ log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle,
       e < 0 || c < 0 || Z < 0)
     return -1;
 
-  print (h, "Connect", "export='%s' tls=%d size=0x%" PRIx64 " write=%d "
-         "flush=%d rotational=%d trim=%d zero=%d fua=%d extents=%d cache=%d "
-         "fast_zero=%d", exportname, h->tls, size, w, f, r, t, z, F, e, c, Z);
+  fp = open_memstream (&str, &len);
+  if (fp) {
+    fprintf (fp, "export=");
+    shell_quote (exportname, fp);
+    fprintf (fp,
+             " tls=%d size=0x%" PRIx64 " write=%d "
+             "flush=%d rotational=%d trim=%d zero=%d fua=%d extents=%d "
+             "cache=%d fast_zero=%d",
+             h->tls, size, w, f, r, t, z, F, e, c, Z);
+    fclose (fp);
+    print (h, "Connect", "%s", str);
+  }
+  else
+    print (h, "Connect", "");
+
   return 0;
 }
 
@@ -380,28 +397,36 @@ log_extents (struct nbdkit_next_ops *next_ops, void *nxdata,
     leave_simple (h, id, "Extents", r, err);
   else {
     FILE *fp;
-    CLEANUP_FREE char *extents_str = NULL;
+    CLEANUP_FREE char *str = NULL;
     size_t i, n, len = 0;
 
-    fp = open_memstream (&extents_str, &len);
+    fp = open_memstream (&str, &len);
     if (fp != NULL) {
+      fprintf (fp, "extents=(");
       n = nbdkit_extents_count (extents);
       for (i = 0; i < n; ++i) {
+        bool comma = false;
         struct nbdkit_extent e = nbdkit_get_extent (extents, i);
         if (i > 0)
-          fprintf (fp, ", ");
-        fprintf (fp, "{ offset=0x%" PRIx64 ", length=0x%" PRIx64 ", "
-                 "hole=%d, zero=%d }",
-                 e.offset, e.length,
-                 !!(e.type & NBDKIT_EXTENT_HOLE),
-                 !!(e.type & NBDKIT_EXTENT_ZERO));
+          fprintf (fp, " ");
+        fprintf (fp, "0x%" PRIx64 " 0x%" PRIx64, e.offset, e.length);
+        fprintf (fp, " \"");
+        if ((e.type & NBDKIT_EXTENT_HOLE) != 0) {
+          fprintf (fp, "hole");
+          comma = true;
+        }
+        if ((e.type & NBDKIT_EXTENT_ZERO) != 0) {
+          if (comma) fprintf (fp, ",");
+          fprintf (fp, "zero");
+        }
+        fprintf (fp, "\"");
       }
-
+      fprintf (fp, ") return=0");
       fclose (fp);
+      leave (h, id, "Extents", "%s", str);
     }
-
-    leave (h, id, "Extents", "extents=[%s] return=0",
-           extents_str ? extents_str : "(null)");
+    else
+      leave (h, id, "Extents", "");
   }
   return r;
 }
diff --git a/filters/log/output.c b/filters/log/output.c
index 63c9f70f..0bfcf7c8 100644
--- a/filters/log/output.c
+++ b/filters/log/output.c
@@ -140,57 +140,49 @@ leave_simple (struct handle *h, log_id_t id, const char *act, int r, int *err)
 {
   const char *s;
 
-  /* Only decode what protocol.c:nbd_errno() recognizes */
+  /* Only decode what server/protocol.c:nbd_errno() recognizes */
   if (r == -1) {
     switch (*err) {
     case EROFS:
-      s = "EROFS=>EPERM";
-      break;
     case EPERM:
-      s = "EPERM";
+      s = " error=EPERM";
       break;
     case EIO:
-      s = "EIO";
+      s = " error=EIO";
       break;
     case ENOMEM:
-      s = "ENOMEM";
+      s = " error=ENOMEM";
       break;
 #ifdef EDQUOT
     case EDQUOT:
-      s = "EDQUOT=>ENOSPC";
-      break;
 #endif
     case EFBIG:
-      s = "EFBIG=>ENOSPC";
-      break;
     case ENOSPC:
-      s = "ENOSPC";
+      s = " error=ENOSPC";
       break;
 #ifdef ESHUTDOWN
     case ESHUTDOWN:
-      s = "ESHUTDOWN";
+      s = " error=ESHUTDOWN";
       break;
 #endif
     case ENOTSUP:
 #if ENOTSUP != EOPNOTSUPP
     case EOPNOTSUPP:
 #endif
-      s = "ENOTSUP";
+      s = " error=ENOTSUP";
       break;
     case EOVERFLOW:
-      s = "EOVERFLOW";
+      s = " error=EOVERFLOW";
       break;
     case EINVAL:
-      s = "EINVAL";
-      break;
     default:
-      s = "Other=>EINVAL";
+      s = " error=EINVAL";
     }
   }
   else
-    s = "Success";
+    s = "";
 
-  leave (h, id, act, "return=%d (%s)", r, s);
+  leave (h, id, act, "return=%d%s", r, s);
 }
 
 void
diff --git a/tests/test-log-error.sh b/tests/test-log-error.sh
new file mode 100755
index 00000000..d8f8cc63
--- /dev/null
+++ b/tests/test-log-error.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018 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.
+
+source ./functions.sh
+set -e
+set -x
+
+requires nbdsh
+requires_filter error
+requires_filter log
+
+cleanup_fn rm -f log-error.log
+rm -f log-error.log
+
+nbdsh -c '
+h.connect_command(["nbdkit", "-s",
+                   "--filter=log", "--filter=error",
+                   "null", "size=10M",
+                   "logfile=log-error.log", "error-rate=100%"])
+try:
+    h.pread(512, 0)
+except:
+    pass
+'
+
+# Print the full log to help with debugging.
+cat log-error.log
+
+# The log should show the read request ...
+grep 'connection=1 Read id=1 offset=0x0 count=0x200 \.\.\.' log-error.log
+
+# ... returning an error.
+grep 'connection=1 \.\.\.Read id=1 return=-1 error=EIO' log-error.log
diff --git a/tests/test-log-extents.sh b/tests/test-log-extents.sh
new file mode 100755
index 00000000..13a5638c
--- /dev/null
+++ b/tests/test-log-extents.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright (C) 2018 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.
+
+source ./functions.sh
+set -e
+set -x
+
+requires nbdsh
+requires nbdsh --base-allocation
+requires_filter log
+
+cleanup_fn rm -f log-extents.log
+rm -f log-extents.log
+
+nbdsh --base-allocation -c '
+h.connect_command(["nbdkit", "-s",
+                   "--filter=log",
+                   "data", "@32768 1", "size=64K",
+                   "logfile=log-extents.log"])
+def f(metacontext, offset, e, err):
+    # Throw the data away, we do not care about it here.
+    pass
+h.block_status(65536, 0, f)
+'
+
+# Print the full log to help with debugging.
+cat log-extents.log
+
+# Check the extents.
+grep '\.\.\.Extents .*extents=(0x0 0x8000 "hole,zero" 0x8000 0x8000 "") return=0' log-extents.log
-- 
2.29.0.rc2




More information about the Libguestfs mailing list