See comment for explanation and
https://listman.redhat.com/archives/libguestfs/2023-August/032468.html
---
 tests/Makefile.am                    |  2 +
 plugins/sh/call.c                    | 33 +++++++-----
 tests/test-sh-pwrite-ignore-stdin.sh | 77 ++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 12 deletions(-)

diff --git a/tests/Makefile.am b/tests/Makefile.am
index d57eb01b8..e69893e0d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1325,11 +1325,13 @@ test-shell.img:
 TESTS += \
        test-sh-errors.sh \
        test-sh-extents.sh \
+       test-sh-pwrite-ignore-stdin.sh \
        test-sh-tmpdir-leak.sh \
        $(NULL)
 EXTRA_DIST += \
        test-sh-errors.sh \
        test-sh-extents.sh \
+       test-sh-pwrite-ignore-stdin.sh \
        test-sh-tmpdir-leak.sh \
        $(NULL)
 
diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index 888c6459a..621465252 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -275,22 +275,31 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin 
(can be NULL) */
       r = write (pfds[0].fd, wbuf, wbuflen);
       if (r == -1) {
         if (errno == EPIPE) {
-          /* We tried to write to the script but it didn't consume
-           * the data.  Probably the script exited without reading
-           * from stdin.  This is an error in the script.
+          /* In nbdkit <= 1.35.11 we gave an error here, arguing that
+           * scripts must always consume or discard their full input
+           * when 'pwrite' is called.  Previously we had many cases
+           * where scripts forgot to discard the data on a path out of
+           * pwrite (such as an error or where the script is not
+           * interested in the data being written), resulting in
+           * intermittent test failures.
+           *
+           * It is valid for a script to ignore the written data
+           * (plenty of non-sh plugins do this), or for a script to be
+           * gradually processing the data, encounter an error and
+           * wish to exit immediately.  Therefore ignore this error.
            */
-          nbdkit_error ("%s: write to script failed because of a broken pipe: "
-                        "this can happen if the script exits without "
-                        "consuming stdin, which usually indicates a bug "
-                        "in the script",
-                        argv0);
+          nbdkit_debug ("%s: write: %m (ignored)", argv0);
+          wbuflen = 0;          /* discard the rest */
         }
-        else
+        else {
           nbdkit_error ("%s: write: %m", argv0);
-        goto error;
+          goto error;
+        }
+      }
+      else {
+        wbuf += r;
+        wbuflen -= r;
       }
-      wbuf += r;
-      wbuflen -= r;
       /* After writing all the data we close the pipe so that
        * the reader on the other end doesn't wait for more.
        */
diff --git a/tests/test-sh-pwrite-ignore-stdin.sh 
b/tests/test-sh-pwrite-ignore-stdin.sh
new file mode 100755
index 000000000..3448eca17
--- /dev/null
+++ b/tests/test-sh-pwrite-ignore-stdin.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+# nbdkit
+# Copyright Red Hat
+#
+# 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.
+
+# Test that pwrite is allowed to ignore stdin (in nbdkit >= 1.36).
+
+source ./functions.sh
+set -e
+set -x
+
+requires_plugin sh
+requires_nbdsh_uri
+
+sock=$(mktemp -u /tmp/nbdkit-test-sock.XXXXXX)
+pid=sh-pwrite-ignore-stdin.pid
+files="$sock $pid"
+rm -f $files
+cleanup_fn rm -f $files
+
+start_nbdkit -P $pid -U $sock sh - <<'EOF'
+case "$1" in
+    can_write) echo 0 ;;
+    pwrite)
+        # Always ignore the input.  If the offset >= 32M return an error.
+        if [ $4 -ge 33554432 ]; then
+            echo 'ENOSPC Out of space' >&2
+            exit 1
+        fi
+        ;;
+    get_size)
+        echo 64M
+        ;;
+    pread)
+        ;;
+    *) exit 2 ;;
+esac
+EOF
+
+nbdsh -u "nbd+unix://?socket=$sock" -c '
+buf = bytearray(16*1024*1024)
+h.pwrite(buf, 0)
+
+try:
+    h.pwrite(buf, 32*1024*1024)
+    assert False
+except nbd.Error:
+    # Expect an error here.
+    pass
+'
-- 
2.41.0

_______________________________________________
Libguestfs mailing list
Libguestfs@redhat.com
https://listman.redhat.com/mailman/listinfo/libguestfs

Reply via email to