]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
csplit: check and report fwrite errors with errno
authorAssaf Gordon <assafgordon@gmail.com>
Thu, 12 Nov 2015 10:20:29 +0000 (05:20 -0500)
committerAssaf Gordon <assafgordon@gmail.com>
Thu, 12 Nov 2015 20:17:55 +0000 (15:17 -0500)
discussed in:
http://lists.gnu.org/archive/html/coreutils/2015-10/msg00091.html

* src/csplit.c: (save_line_to_file): check fwrite failures, report
  and exit immediately instead of deferring to 'close_output'.
* tests/misc/csplit-io-err.sh: test fwrite failure using LD_PRELOAD.
* tests/local.mk: add new test.

src/csplit.c
tests/local.mk
tests/misc/csplit-io-err.sh [new file with mode: 0755]

index c97acb86219160df90f73f567f0d4cc488a2f246..a2034bf77b28714beffccea5d3ae0e521da87215 100644 (file)
@@ -1051,7 +1051,13 @@ close_output_file (void)
 static void
 save_line_to_file (const struct cstring *line)
 {
-  fwrite (line->str, sizeof (char), line->len, output_stream);
+  size_t l = fwrite (line->str, sizeof (char), line->len, output_stream);
+  if (l != line->len)
+    {
+      error (0, errno, _("write error for %s"), quoteaf (output_filename));
+      output_stream = NULL;
+      cleanup_fatal ();
+    }
   bytes_written += line->len;
 }
 
index 675607e7ac582237477e0f81fcb4bf7535ee8a88..adf96f01572e8263a407310085bb2e22e8cb9503 100644 (file)
@@ -274,6 +274,7 @@ all_tests =                                 \
   tests/misc/csplit.sh                         \
   tests/misc/csplit-1000.sh                    \
   tests/misc/csplit-heap.sh                    \
+  tests/misc/csplit-io-err.sh                  \
   tests/misc/csplit-suppress-matched.pl                \
   tests/misc/date-sec.sh                       \
   tests/misc/dircolors.pl                      \
diff --git a/tests/misc/csplit-io-err.sh b/tests/misc/csplit-io-err.sh
new file mode 100755 (executable)
index 0000000..6bdd5f1
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+# Ensure we handle i/o errors correctly in csplit
+
+# Copyright (C) 2015 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ csplit
+require_gcc_shared_
+
+if ! test -w /dev/full || ! test -c /dev/full; then
+  skip_ '/dev/full is required'
+fi
+
+# Ensure error messages are in English
+LC_ALL=C
+export LC_ALL
+
+# Replace fwrite and ferror, always returning an error
+cat > k.c <<'EOF' || framework_failure_
+#include <stdio.h>
+#include <errno.h>
+
+#undef fwrite
+#undef fwrite_unlocked
+
+size_t
+fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+  fclose (fopen ("preloaded","w")); /* marker for preloaded interception */
+  errno = ENOSPC;
+  return 0;
+}
+
+size_t
+fwrite_unlocked (const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+  return fwrite (ptr, size, nitems, stream);
+}
+EOF
+
+# Get the wording of the OS-dependent ENOSPC message
+returns_ 1 seq 1 >/dev/full 2>msgt || framework_failure_
+sed 's/seq: write error: //' msgt > msg || framework_failure_
+
+# Create the expected error message
+{ printf "%s" "csplit: write error for 'xx01': " ; cat msg ; } > exp \
+  || framework_failure_
+
+# compile/link the interception shared library:
+gcc_shared_ k.c k.so \
+  || skip_ 'failed to build forced-fwrite-failure shared library'
+
+# Split the input, and force fwrite() failure -
+# the 'csplit' command should fail with exit code 1
+# (checked with 'returns_ 1 ... || fail=1')
+seq 10 \
+  | LD_PRELOAD=$LD_PRELOAD:./k.so returns_ 1 csplit - 1 4 2>out \
+  || fail=1
+
+test -e preloaded || skip_ 'LD_PRELOAD interception failed'
+
+# Ensure we got the expected error message
+compare exp out || fail=1
+
+Exit $fail