From c7cf98b0e03780f78abe5275c6fb282f71a2369f Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Fri, 23 Mar 2012 11:10:04 +0100 Subject: [PATCH] lib: add fileutils file with stream error checking facility The close_stream() is copied from GNU lib. Inspiration to do this is talk by Jim Meyering - Goodbye World! The perils of relying on output streams in C. Reference: http://www.irill.org/events/ghm-gnu-hackers-meeting/videos/jim-meyering-goodbye-world-the-perils-of-relying-on-output-streams-in-c Signed-off-by: Sami Kerola --- include/fileutils.h | 7 +++++ lib/.gitignore | 1 + lib/Makefile.am | 3 +- lib/fileutils.c | 43 +++++++++++++++++++++++++++ testsuite/Makefile.am | 1 + testsuite/lib.test/fileutils.exp | 19 ++++++++++++ testsuite/lib.test/fileutils_badfd.sh | 4 +++ testsuite/lib.test/fileutils_full.sh | 4 +++ 8 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 include/fileutils.h create mode 100644 lib/fileutils.c create mode 100644 testsuite/lib.test/fileutils.exp create mode 100755 testsuite/lib.test/fileutils_badfd.sh create mode 100755 testsuite/lib.test/fileutils_full.sh diff --git a/include/fileutils.h b/include/fileutils.h new file mode 100644 index 00000000..cfab570c --- /dev/null +++ b/include/fileutils.h @@ -0,0 +1,7 @@ +#ifndef PROCPS_NG_FILEUTILS +#define PROCPS_NG_FILEUTILS + +int close_stream(FILE * stream); +void close_stdout(void); + +#endif diff --git a/lib/.gitignore b/lib/.gitignore index f4208e7a..6b7ce835 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,2 +1,3 @@ .dirstamp +test_fileutils test_strutils diff --git a/lib/Makefile.am b/lib/Makefile.am index 4216a252..9430de2e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,6 +2,7 @@ AM_CPPFLAGS = -include $(top_builddir)/config.h -I$(top_srcdir)/include AM_CPPFLAGS += -DTEST_PROGRAM -noinst_PROGRAMS = test_strutils +noinst_PROGRAMS = test_strutils test_fileutils test_strutils_SOURCES = strutils.c +test_fileutils_SOURCES = fileutils.c diff --git a/lib/fileutils.c b/lib/fileutils.c new file mode 100644 index 00000000..b47a9cf7 --- /dev/null +++ b/lib/fileutils.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +#include "nls.h" + +int close_stream(FILE * stream) +{ + const int some_pending = (__fpending(stream) != 0); + const int prev_fail = (ferror(stream) != 0); + const int fclose_fail = (fclose(stream) != 0); + if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) { + if (!fclose_fail) + errno = 0; + return EOF; + } + return 0; +} + +/* Use atexit(); */ +void close_stdout(void) +{ + if (close_stream(stdout) != 0 && !(errno == EPIPE)) { + char const *write_error = _("write error"); + error(0, errno, "%s", write_error); + _exit(EXIT_FAILURE); + } + + if (close_stream(stderr) != 0) + _exit(EXIT_FAILURE); +} + +#ifdef TEST_PROGRAM +#include +int main(int argc, char *argv[]) +{ + atexit(close_stdout); + printf("Hello, World!\n"); + return EXIT_SUCCESS; +} +#endif /* TEST_PROGRAM */ diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 62acfa64..0bb7fb9f 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -34,6 +34,7 @@ EXTRA_DIST = \ global-conf.exp \ free.test/free.exp \ kill.test/kill.exp \ + lib.test/fileutils.exp \ lib.test/strutils.exp \ pgrep.test/pgrep.exp \ pkill.test/pkill.exp \ diff --git a/testsuite/lib.test/fileutils.exp b/testsuite/lib.test/fileutils.exp new file mode 100644 index 00000000..3fab11e2 --- /dev/null +++ b/testsuite/lib.test/fileutils.exp @@ -0,0 +1,19 @@ +# +# Testsuite for lib/fileutils program +# + +set noarg "${topdir}lib/test_fileutils" + +set test "without argument" +spawn $noarg +expect_pass "$test" "Hello, World!" + +set badfd "${topdir}testsuite/lib.test/fileutils_badfd.sh" +set test "test bad file descriptor" +spawn $badfd +expect_pass "$test" "test_fileutils: write error: Bad file descriptor" + +set full "${topdir}testsuite/lib.test/fileutils_full.sh" +set test "test no space left on device" +spawn $full +expect_pass "$test" "test_fileutils: write error: No space left on device" diff --git a/testsuite/lib.test/fileutils_badfd.sh b/testsuite/lib.test/fileutils_badfd.sh new file mode 100755 index 00000000..4a0d5c67 --- /dev/null +++ b/testsuite/lib.test/fileutils_badfd.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +BASEDIR=$(dirname ${0}) +${BASEDIR}/../../lib/test_fileutils >&- diff --git a/testsuite/lib.test/fileutils_full.sh b/testsuite/lib.test/fileutils_full.sh new file mode 100755 index 00000000..0d96a0dd --- /dev/null +++ b/testsuite/lib.test/fileutils_full.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +BASEDIR=$(dirname ${0}) +${BASEDIR}/../../lib/test_fileutils > /dev/full