diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | doc/make.texi | 2 | ||||
-rw-r--r-- | main.c | 5 | ||||
-rw-r--r-- | make.h | 5 | ||||
-rw-r--r-- | misc.c | 47 | ||||
-rw-r--r-- | tests/ChangeLog | 5 | ||||
-rw-r--r-- | tests/scripts/misc/close_stdout | 9 |
8 files changed, 84 insertions, 6 deletions
@@ -1,7 +1,18 @@ +2005-06-12 Paul D. Smith <psmith@gnu.org> + + 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 <psmith@gnu.org> - + VMS build updates from Hartmut Becker <Hartmut.Becker@hp.com>: - + * 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. @@ -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; } @@ -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 @@ -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 <psmith@gnu.org> + + * 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 <psmith@gnu.org> * 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; |