[Libguestfs] [PATCH nbdkit] sh: In pwrite, allow scripts to ignore stdin
Laszlo Ersek
lersek at redhat.com
Thu Aug 31 10:19:41 UTC 2023
On 8/31/23 10:50, Richard W.M. Jones wrote:
> 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.
> */
I'm not reviewing the code changes in detail, just asking for a comment extension here:
Can you highlight that, "if a script fails to consume all input due to a crash, we're going to catch that with waitpid() / WIFSIGNALED() below"?
Basically I'd like us to show that we *know* that we cover for the case when an EPIPE might not be a conscious decision from the child script.
... Hmmm, let me check something:
#!/bin/bash
ulimit -f 1
cat >f
$ ./script </dev/zero
./script: line 3: 18032 File size limit exceeded(core dumped) cat > f
$ echo $?
153
$ kill -l 153
XFSZ
Good!
(This example simulates a subprocess of the pwrite script crashing with SIGXFSZ, due to exceeding the permitted file size limit, *and* the shell propagating that crashing exit status up to nbdkit's sh plugin.)
Acked-by: Laszlo Ersek <lersek at redhat.com>
Laszlo
> - 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
> +'
More information about the Libguestfs
mailing list