From 467115baae38eba41b3800b4e0e84afb7f3ec99b Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 12 Jun 2005 22:22:07 +0000 Subject: Fix Savannah bug # 1328: if stdout is redirected to a full filesystem, we check for this and exit with an error. The closeout.c version from gnulib pulls in too much other stuff, and gnulib requires an ANSI C 89 compliant compiler, while GNU make (so far) still wants to work on K&R. --- ChangeLog | 15 +++++++++++-- configure.in | 2 +- doc/make.texi | 2 +- main.c | 5 +++++ make.h | 5 +++-- misc.c | 47 +++++++++++++++++++++++++++++++++++++++++ tests/ChangeLog | 5 +++++ tests/scripts/misc/close_stdout | 9 ++++++++ 8 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 tests/scripts/misc/close_stdout diff --git a/ChangeLog b/ChangeLog index 86966eb..227c0b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,18 @@ +2005-06-12 Paul D. Smith + + Fix Savannah bug # 1328. + + * configure.in: Check for atexit(). + * misc.c (close_stdout): Test stdout to see if writes to it have + failed. If so, be sure to exit with a non-0 error code. Based on + code found in gnulib. + * make.h: Prototype. + * main.c (main): Install close_stdout() with atexit(). + 2005-06-10 Paul D. Smith - + VMS build updates from Hartmut Becker : - + * vmsjobs.c [VMS]: Updates to compile on VMS: add some missing headers; make vmsWaitForChildren() static; extern vmsify(). * job.c [VMS]: Move vmsWaitForChildren() prototype to be global. diff --git a/configure.in b/configure.in index 783d180..2c981c9 100644 --- a/configure.in +++ b/configure.in @@ -137,7 +137,7 @@ AC_CHECK_FUNCS( memcpy memmove strchr strdup mkstemp mktemp fdopen \ bsd_signal dup2 getcwd realpath sigsetmask sigaction \ getgroups seteuid setegid setlinebuf setreuid setregid \ getrlimit setrlimit setvbuf pipe strerror strsignal \ - lstat readlink) + lstat readlink atexit) AC_FUNC_SETVBUF_REVERSED diff --git a/doc/make.texi b/doc/make.texi index 4ffefb9..f17a5d4 100644 --- a/doc/make.texi +++ b/doc/make.texi @@ -9385,7 +9385,7 @@ foolib(hack.o) : hack.o @end example In fact, nearly all archive member targets are updated in just this way -and there is an implicit rule to do it for you. @strong{Note:} The +and there is an implicit rule to do it for you. @strong{Please note:} The @samp{c} flag to @code{ar} is required if the archive file does not already exist. diff --git a/main.c b/main.c index 5536190..60d11ab 100644 --- a/main.c +++ b/main.c @@ -914,6 +914,10 @@ main (int argc, char **argv, char **envp) } #endif +#ifdef HAVE_ATEXIT + atexit (close_stdout); +#endif + /* Needed for OS/2 */ initialize_main(&argc, &argv); @@ -2176,6 +2180,7 @@ main (int argc, char **argv, char **envp) die (status); } + /* NOTREACHED */ return 0; } diff --git a/make.h b/make.h index 5696965..699a6e4 100644 --- a/make.h +++ b/make.h @@ -459,8 +459,9 @@ extern void user_access PARAMS ((void)); extern void make_access PARAMS ((void)); extern void child_access PARAMS ((void)); -extern char * -strip_whitespace PARAMS ((const char **begpp, const char **endpp)); +extern void close_stdout PARAMS ((void)); + +extern char *strip_whitespace PARAMS ((const char **begpp, const char **endpp)); #ifdef HAVE_VFORK_H diff --git a/misc.c b/misc.c index 63936f7..995fd20 100644 --- a/misc.c +++ b/misc.c @@ -823,3 +823,50 @@ get_path_max (void) return value; } #endif + + +/* This code is stolen from gnulib. + If/when we abandon the requirement to work with K&R compilers, we can + remove this (and perhaps other parts of GNU make!) and migrate to using + gnulib directly. + + This is called only through atexit(), which means die() has already been + invoked. So, call exit() here directly. Apparently that works...? +*/ + +/* Close standard output, exiting with status 'exit_failure' on failure. + If a program writes *anything* to stdout, that program should close + stdout and make sure that it succeeds before exiting. Otherwise, + suppose that you go to the extreme of checking the return status + of every function that does an explicit write to stdout. The last + printf can succeed in writing to the internal stream buffer, and yet + the fclose(stdout) could still fail (due e.g., to a disk full error) + when it tries to write out that buffered data. Thus, you would be + left with an incomplete output file and the offending program would + exit successfully. Even calling fflush is not always sufficient, + since some file systems (NFS and CODA) buffer written/flushed data + until an actual close call. + + Besides, it's wasteful to check the return value from every call + that writes to stdout -- just let the internal stream state record + the failure. That's what the ferror test is checking below. + + It's important to detect such failures and exit nonzero because many + tools (most notably `make' and other build-management systems) depend + on being able to detect failure in other tools via their exit status. */ + +void +close_stdout (void) +{ + int prev_fail = ferror (stdout); + int fclose_fail = fclose (stdout); + + if (prev_fail || fclose_fail) + { + if (fclose_fail) + error (NILF, _("write error: %s"), strerror (errno)); + else + error (NILF, _("write error")); + exit (EXIT_FAILURE); + } +} diff --git a/tests/ChangeLog b/tests/ChangeLog index ffb3fe0..2e22195 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,8 @@ +2005-06-12 Paul D. Smith + + * scripts/misc/close_stdout: Add a test for Savannah bug #1328. + This test only works on systems that have /dev/full (e.g., Linux). + 2005-06-09 Paul D. Smith * scripts/functions/foreach: Add a test for Savannah bug #11913. diff --git a/tests/scripts/misc/close_stdout b/tests/scripts/misc/close_stdout new file mode 100644 index 0000000..688942e --- /dev/null +++ b/tests/scripts/misc/close_stdout @@ -0,0 +1,9 @@ +# -*-perl-*- + +$description = "Make sure make exits with an error if stdout is full."; + +if (-e '/dev/full') { + run_make_test('', '-v > /dev/full', '#MAKE#: write error', 256); +} + +1; -- cgit v1.2.3