GNU bug report logs - #9574
data-loss with --batch: ignored write failure

Previous Next

Package: emacs;

Reported by: Jim Meyering <jim <at> meyering.net>

Date: Thu, 22 Sep 2011 14:40:02 UTC

Severity: minor

Tags: patch

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 9574 in the body.
You can then email your comments to 9574 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Thu, 22 Sep 2011 14:40:03 GMT) Full text and rfc822 format available.

Acknowledgement sent to Jim Meyering <jim <at> meyering.net>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Thu, 22 Sep 2011 14:40:04 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Jim Meyering <jim <at> meyering.net>
To: bug-emacs <at> gnu.org
Subject: data-loss with --batch: ignored write failure
Date: Thu, 22 Sep 2011 16:39:04 +0200
This should diagnose the write failure and exit nonzero:

    emacs --version > /dev/full

Currently (latest from bzr trunk as of yesterday),
emacs exits 0 (successfully) and gives no diagnostic.
Obviously that doesn't matter too much, but this next one
can easily cause real trouble:

    $ emacs --batch --eval '(print "important")' > /dev/full && echo FAIL
    FAIL

I.e., the write fails and emacs fails to report that failure.

That means anything written via --batch to standard output may
be corrupted or incomplete, and emacs will still exit successfully.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Thu, 22 Sep 2011 17:30:03 GMT) Full text and rfc822 format available.

Message #8 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Glenn Morris <rgm <at> gnu.org>
To: Jim Meyering <jim <at> meyering.net>
Cc: 9574 <at> debbugs.gnu.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Thu, 22 Sep 2011 13:29:04 -0400
Publicly shamed. :(

http://www.gnu.org/ghm/2011/paris/slides/jim-meyering-goodbye-world.pdf

;)

(All the way back to at least Emacs 21.1.)




Reply sent to Andreas Schwab <schwab <at> linux-m68k.org>:
You have taken responsibility. (Fri, 23 Sep 2011 10:00:02 GMT) Full text and rfc822 format available.

Notification sent to Jim Meyering <jim <at> meyering.net>:
bug acknowledged by developer. (Fri, 23 Sep 2011 10:00:02 GMT) Full text and rfc822 format available.

Message #13 received at 9574-done <at> debbugs.gnu.org (full text, mbox):

From: Andreas Schwab <schwab <at> linux-m68k.org>
To: Jim Meyering <jim <at> meyering.net>
Cc: 9574-done <at> debbugs.gnu.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Fri, 23 Sep 2011 11:58:44 +0200
Fixed.

Andreas.

-- 
Andreas Schwab, schwab <at> linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Fri, 23 Sep 2011 18:31:01 GMT) Full text and rfc822 format available.

Message #16 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Glenn Morris <rgm <at> gnu.org>
To: 9574 <at> debbugs.gnu.org
Cc: schwab <at> linux-m68k.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Fri, 23 Sep 2011 14:30:06 -0400
Andreas Schwab wrote:

> Fixed.

Not the --version part, FWIW.

./src/emacs -Q --version > /dev/full ; echo $?
0

./src/emacs -Q --help > /dev/full ; echo $?
0

cf

ls --version > /dev/full ; echo $?
ls: write error: No space left on device
2


Also:
./src/emacs -Q --batch --eval '(print "important")' > /dev/full

does indeed now return status 1, but no error message.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Sat, 24 Sep 2011 09:24:02 GMT) Full text and rfc822 format available.

Message #19 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Jim Meyering <jim <at> meyering.net>
To: 9574 <at> debbugs.gnu.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Sat, 24 Sep 2011 11:23:26 +0200
> Subject: Re: bug#9574: data-loss with --batch: ignored write failure
>
> Fixed.

Thanks, but even with your fix, emacs --batch would
still ignore some write errors.

I've just committed a change to fix that part properly.
Included below.

A clean fix for the entire problem (including --help and --version and
anything else that may write to stdout) would be to ensure that no other
code path explicitly closes stdout and to add this line in main:

    atexit (close_stdout);

However, that would require gnulib's closeout module and would probably
end up being too invasive a change to make during a code freeze.

2011-09-24  Jim Meyering  <meyering <at> redhat.com>

	do not ignore write error for any output size
	The previous change was incomplete.
	While it makes emacs --batch detect the vast majority of stdout
	write failures, errors were still ignored whenever the output size is
	k * (BUFSIZ+1) - 4.  E.g., on a system with BUFSIZ of 4096,
	  $ emacs --batch --eval '(print (format "%4093d" 0))' > /dev/full \
	      && echo FAIL: ignored write error
	  FAIL: ignored write error
	  $ emacs --batch --eval '(print (format "%20481d" 0))' > /dev/full \
	      && echo FAIL: ignored write error
	  FAIL: ignored write error
	* emacs.c (Fkill_emacs): Also test ferror.  (Bug#9574)


=== modified file 'src/emacs.c'
--- src/emacs.c	2011-09-23 09:56:55 +0000
+++ src/emacs.c	2011-09-24 08:28:32 +0000
@@ -2019,7 +2019,7 @@
     unlink (SSDATA (Vauto_save_list_file_name));

   exit_code = EXIT_SUCCESS;
-  if (noninteractive && fflush (stdout))
+  if (noninteractive && (fflush (stdout) || ferror (stdout)))
     exit_code = EXIT_FAILURE;
   exit (INTEGERP (arg) ? XINT (arg) : exit_code);
 }




Did not alter fixed versions and reopened. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 10 Oct 2011 00:22:02 GMT) Full text and rfc822 format available.

Severity set to 'minor' from 'normal' Request was from Glenn Morris <rgm <at> gnu.org> to control <at> debbugs.gnu.org. (Mon, 10 Oct 2011 00:22:02 GMT) Full text and rfc822 format available.

Added tag(s) pending. Request was from Glenn Morris <rgm <at> gnu.org> to control <at> debbugs.gnu.org. (Mon, 10 Oct 2011 00:22:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Tue, 17 Apr 2012 01:59:02 GMT) Full text and rfc822 format available.

Message #28 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Glenn Morris <rgm <at> gnu.org>
To: Jim Meyering <jim <at> meyering.net>
Cc: Paul Eggert <eggert <at> cs.ucla.edu>, 9574 <at> debbugs.gnu.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Mon, 16 Apr 2012 21:58:03 -0400
Jim Meyering wrote:

> A clean fix for the entire problem (including --help and --version and
> anything else that may write to stdout) would be to ensure that no other
> code path explicitly closes stdout and to add this line in main:
>
>     atexit (close_stdout);
>
> However, that would require gnulib's closeout module and would probably
> end up being too invasive a change to make during a code freeze.


Such a change could probably be applied to the Emacs trunk now...
(Cc'ing Paul since he has done most/all of the gnulib additions in Emacs.)




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Tue, 17 Apr 2012 04:55:02 GMT) Full text and rfc822 format available.

Message #31 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Glenn Morris <rgm <at> gnu.org>
Cc: Jim Meyering <jim <at> meyering.net>, 9574 <at> debbugs.gnu.org
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Mon, 16 Apr 2012 21:53:52 -0700
On 04/16/2012 06:58 PM, Glenn Morris wrote:
> Such a change could probably be applied to the Emacs trunk now...

I wouldn't do that without syncing from gnulib (because I'd rather
not debug cherry-picking changes from gnulib).  That would be an
automatic but pervasive change.  Stefan has indicated
that he doesn't want pervasive changes until after Emacs 24.1 is out,
because it might make it harder to merge changes from the emacs-24
branch back into the trunk.

> (Cc'ing Paul since he has done most/all of the gnulib additions in Emacs.)





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Mon, 29 Oct 2012 09:31:02 GMT) Full text and rfc822 format available.

Message #34 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Chong Yidong <cyd <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: Glenn Morris <rgm <at> gnu.org>, 9574 <at> debbugs.gnu.org,
	Jim Meyering <jim <at> meyering.net>
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Mon, 29 Oct 2012 17:27:46 +0800
Paul Eggert <eggert <at> cs.ucla.edu> writes:

> On 04/16/2012 06:58 PM, Glenn Morris wrote:
>> Such a change could probably be applied to the Emacs trunk now...
>
> I wouldn't do that without syncing from gnulib (because I'd rather not
> debug cherry-picking changes from gnulib).  That would be an automatic
> but pervasive change.

Has this bug been fixed since the above was written 6 months ago?
If so, please close it, thanks.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#9574; Package emacs. (Thu, 01 Nov 2012 20:12:02 GMT) Full text and rfc822 format available.

Message #37 received at 9574 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Chong Yidong <cyd <at> gnu.org>
Cc: Glenn Morris <rgm <at> gnu.org>, 9574 <at> debbugs.gnu.org,
	Jim Meyering <jim <at> meyering.net>
Subject: Re: bug#9574: data-loss with --batch: ignored write failure
Date: Thu, 01 Nov 2012 13:09:03 -0700
On 10/29/2012 02:27 AM, Chong Yidong wrote:

> Has this bug been fixed since the above was written 6 months ago?

Sorry, no.  Here's a patch, relative to trunk bzr 110763.
I won't install it right now, since we're so close
to creating a branch.


=== modified file 'ChangeLog'
--- ChangeLog	2012-10-26 18:35:36 +0000
+++ ChangeLog	2012-11-01 20:07:42 +0000
@@ -1,3 +1,11 @@
+2012-11-01  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix data-loss with --batch (Bug#9574).
+	* lib/close-stream.c, lib/close-stream.h, lib/fpending.c
+	* lib/fpending.h, m4/close-stream.m4, m4/fpending.m4:
+	New files, from gnulib.
+	* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 2012-10-26  Glenn Morris  <rgm <at> gnu.org>
 
 	* Makefile.in (EMACS_NAME): New variable.

=== modified file 'admin/ChangeLog'
--- admin/ChangeLog	2012-10-19 19:25:18 +0000
+++ admin/ChangeLog	2012-11-01 20:07:42 +0000
@@ -1,3 +1,8 @@
+2012-11-01  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix data-loss with --batch (Bug#9574).
+	* merge-gnulib (GNULIB_MODULES): Add close-stream.
+
 2012-10-12  Kenichi Handa  <handa <at> gnu.org>
 
 	* charsets/Makefile (JISC6226.map): Add missing mappings.

=== modified file 'admin/merge-gnulib'
--- admin/merge-gnulib	2012-10-19 19:25:18 +0000
+++ admin/merge-gnulib	2012-11-01 20:07:42 +0000
@@ -27,7 +27,7 @@
 
 GNULIB_MODULES='
   alloca-opt c-ctype c-strcase
-  careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
+  careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
   dtoastr dtotimespec dup2 environ execinfo
   filemode getloadavg getopt-gnu gettime gettimeofday
   ignore-value intprops largefile lstat

=== added file 'lib/close-stream.c'
--- lib/close-stream.c	1970-01-01 00:00:00 +0000
+++ lib/close-stream.c	2012-11-01 20:07:42 +0000
@@ -0,0 +1,78 @@
+/* Close a stream, with nicer error checking than fclose's.
+
+   Copyright (C) 1998-2002, 2004, 2006-2012 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/>.  */
+
+#include <config.h>
+
+#include "close-stream.h"
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "fpending.h"
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+/* Close STREAM.  Return 0 if successful, EOF (setting errno)
+   otherwise.  A failure might set errno to 0 if the error number
+   cannot be determined.
+
+   A failure with errno set to EPIPE may or may not indicate an error
+   situation worth signaling to the user.  See the documentation of the
+   close_stdout_set_ignore_EPIPE function for details.
+
+   If a program writes *anything* to STREAM, that program should close
+   STREAM 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 STREAM.  The last
+   printf can succeed in writing to the internal stream buffer, and yet
+   the fclose(STREAM) 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 STREAM -- just let the internal stream state record
+   the failure.  That's what the ferror test is checking below.  */
+
+int
+close_stream (FILE *stream)
+{
+  const bool some_pending = (__fpending (stream) != 0);
+  const bool prev_fail = (ferror (stream) != 0);
+  const bool fclose_fail = (fclose (stream) != 0);
+
+  /* Return an error indication if there was a previous failure or if
+     fclose failed, with one exception: ignore an fclose failure if
+     there was no previous error, no data remains to be flushed, and
+     fclose failed with EBADF.  That can happen when a program like cp
+     is invoked like this 'cp a b >&-' (i.e., with standard output
+     closed) and doesn't generate any output (hence no previous error
+     and nothing to be flushed).  */
+
+  if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
+    {
+      if (! fclose_fail)
+        errno = 0;
+      return EOF;
+    }
+
+  return 0;
+}

=== added file 'lib/close-stream.h'
--- lib/close-stream.h	1970-01-01 00:00:00 +0000
+++ lib/close-stream.h	2012-11-01 20:07:42 +0000
@@ -0,0 +1,2 @@
+#include <stdio.h>
+int close_stream (FILE *stream);

=== added file 'lib/fpending.c'
--- lib/fpending.c	1970-01-01 00:00:00 +0000
+++ lib/fpending.c	2012-11-01 20:07:42 +0000
@@ -0,0 +1,30 @@
+/* fpending.c -- return the number of pending output bytes on a stream
+   Copyright (C) 2000, 2004, 2006-2007, 2009-2012 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/>.  */
+
+/* Written by Jim Meyering. */
+
+#include <config.h>
+
+#include "fpending.h"
+
+/* Return the number of pending (aka buffered, unflushed)
+   bytes on the stream, FP, that is open for writing.  */
+size_t
+__fpending (FILE *fp)
+{
+  return PENDING_OUTPUT_N_BYTES;
+}

=== added file 'lib/fpending.h'
--- lib/fpending.h	1970-01-01 00:00:00 +0000
+++ lib/fpending.h	2012-11-01 20:07:42 +0000
@@ -0,0 +1,30 @@
+/* Declare __fpending.
+
+   Copyright (C) 2000, 2003, 2005-2006, 2009-2012 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/>.
+
+   Written by Jim Meyering.  */
+
+#include <stddef.h>
+#include <stdio.h>
+
+#if HAVE_DECL___FPENDING
+# if HAVE_STDIO_EXT_H
+#  include <stdio_ext.h>
+# endif
+#else
+size_t __fpending (FILE *);
+#endif

=== modified file 'lib/gnulib.mk'
--- lib/gnulib.mk	2012-10-19 19:25:18 +0000
+++ lib/gnulib.mk	2012-11-01 20:07:42 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=errno --avoid=fcntl --avoid=fcntl-h --avoid=fstat --avoid=msvc-inval --avoid=msvc-nothrow --avoid=raise --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo filemode getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings mktime pselect pthread_sigmask readlink socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub utimens warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -84,6 +84,14 @@
 
 ## end   gnulib module careadlinkat
 
+## begin gnulib module close-stream
+
+libgnu_a_SOURCES += close-stream.c
+
+EXTRA_DIST += close-stream.h
+
+## end   gnulib module close-stream
+
 ## begin gnulib module crypto/md5
 
 libgnu_a_SOURCES += md5.c
@@ -183,6 +191,15 @@
 
 ## end   gnulib module filemode
 
+## begin gnulib module fpending
+
+
+EXTRA_DIST += fpending.c fpending.h
+
+EXTRA_libgnu_a_SOURCES += fpending.c
+
+## end   gnulib module fpending
+
 ## begin gnulib module getloadavg
 
 

=== added file 'm4/close-stream.m4'
--- m4/close-stream.m4	1970-01-01 00:00:00 +0000
+++ m4/close-stream.m4	2012-11-01 20:07:42 +0000
@@ -0,0 +1,11 @@
+#serial 4
+dnl Copyright (C) 2006-2007, 2009-2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Prerequisites of lib/close-stream.c.
+AC_DEFUN([gl_CLOSE_STREAM],
+[
+  :
+])

=== added file 'm4/fpending.m4'
--- m4/fpending.m4	1970-01-01 00:00:00 +0000
+++ m4/fpending.m4	2012-11-01 20:07:42 +0000
@@ -0,0 +1,90 @@
+# serial 19
+
+# Copyright (C) 2000-2001, 2004-2012 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+dnl From Jim Meyering
+dnl Using code from emacs, based on suggestions from Paul Eggert
+dnl and Ulrich Drepper.
+
+dnl Find out how to determine the number of pending output bytes on a stream.
+dnl glibc (2.1.93 and newer) and Solaris provide __fpending.  On other systems,
+dnl we have to grub around in the FILE struct.
+
+AC_DEFUN([gl_FUNC_FPENDING],
+[
+  AC_CHECK_HEADERS_ONCE([stdio_ext.h])
+  AC_CHECK_FUNCS_ONCE([__fpending])
+  fp_headers='
+#     include <stdio.h>
+#     if HAVE_STDIO_EXT_H
+#      include <stdio_ext.h>
+#     endif
+'
+  AC_CHECK_DECLS([__fpending], , , $fp_headers)
+])
+
+AC_DEFUN([gl_PREREQ_FPENDING],
+[
+  AC_CACHE_CHECK(
+              [how to determine the number of pending output bytes on a stream],
+                 ac_cv_sys_pending_output_n_bytes,
+    [
+      for ac_expr in                                                    \
+                                                                        \
+          '# glibc2'                                                    \
+          'fp->_IO_write_ptr - fp->_IO_write_base'                      \
+                                                                        \
+          '# traditional Unix'                                          \
+          'fp->_ptr - fp->_base'                                        \
+                                                                        \
+          '# BSD'                                                       \
+          'fp->_p - fp->_bf._base'                                      \
+                                                                        \
+          '# SCO, Unixware'                                             \
+          '(fp->__ptr ? fp->__ptr - fp->__base : 0)'                    \
+                                                                        \
+          '# QNX'                                                       \
+          '(fp->_Mode & 0x2000 /*_MWRITE*/ ? fp->_Next - fp->_Buf : 0)' \
+                                                                        \
+          '# old glibc?'                                                \
+          'fp->__bufp - fp->__buffer'                                   \
+                                                                        \
+          '# old glibc iostream?'                                       \
+          'fp->_pptr - fp->_pbase'                                      \
+                                                                        \
+          '# emx+gcc'                                                   \
+          'fp->_ptr - fp->_buffer'                                      \
+                                                                        \
+          '# Minix'                                                     \
+          'fp->_ptr - fp->_buf'                                         \
+                                                                        \
+          '# Plan9'                                                     \
+          'fp->wp - fp->buf'                                            \
+                                                                        \
+          '# VMS'                                                       \
+          '(*fp)->_ptr - (*fp)->_base'                                  \
+                                                                        \
+          '# e.g., DGUX R4.11; the info is not available'               \
+          1                                                             \
+          ; do
+
+        # Skip each embedded comment.
+        case "$ac_expr" in '#'*) continue;; esac
+
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]],
+          [[FILE *fp = stdin; (void) ($ac_expr);]])],
+          [fp_done=yes]
+        )
+        test "$fp_done" = yes && break
+      done
+
+      ac_cv_sys_pending_output_n_bytes=$ac_expr
+    ]
+  )
+  AC_DEFINE_UNQUOTED([PENDING_OUTPUT_N_BYTES],
+    $ac_cv_sys_pending_output_n_bytes,
+    [the number of pending output bytes on stream 'fp'])
+])

=== modified file 'm4/gnulib-comp.m4'
--- m4/gnulib-comp.m4	2012-10-19 19:25:18 +0000
+++ m4/gnulib-comp.m4	2012-11-01 20:07:42 +0000
@@ -44,6 +44,7 @@
   # Code from module c-strcase:
   # Code from module careadlinkat:
   # Code from module clock-time:
+  # Code from module close-stream:
   # Code from module crypto/md5:
   # Code from module crypto/sha1:
   # Code from module crypto/sha256:
@@ -58,6 +59,7 @@
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   # Code from module extern-inline:
   # Code from module filemode:
+  # Code from module fpending:
   # Code from module getloadavg:
   # Code from module getopt-gnu:
   # Code from module getopt-posix:
@@ -141,6 +143,8 @@
   gl_FUNC_ALLOCA
   AC_CHECK_FUNCS_ONCE([readlinkat])
   gl_CLOCK_TIME
+  gl_CLOSE_STREAM
+  gl_MODULE_INDICATOR([close-stream])
   gl_MD5
   gl_SHA1
   gl_SHA256
@@ -157,6 +161,11 @@
   gl_EXECINFO_H
   AC_REQUIRE([gl_EXTERN_INLINE])
   gl_FILEMODE
+  gl_FUNC_FPENDING
+  if test $ac_cv_func___fpending = no; then
+    AC_LIBOBJ([fpending])
+    gl_PREREQ_FPENDING
+  fi
   gl_GETLOADAVG
   if test $HAVE_GETLOADAVG = 0; then
     AC_LIBOBJ([getloadavg])
@@ -534,6 +543,8 @@
   lib/c-strncasecmp.c
   lib/careadlinkat.c
   lib/careadlinkat.h
+  lib/close-stream.c
+  lib/close-stream.h
   lib/dosname.h
   lib/dtoastr.c
   lib/dtotimespec.c
@@ -542,6 +553,8 @@
   lib/execinfo.in.h
   lib/filemode.c
   lib/filemode.h
+  lib/fpending.c
+  lib/fpending.h
   lib/ftoastr.c
   lib/ftoastr.h
   lib/getloadavg.c
@@ -609,12 +622,14 @@
   m4/alloca.m4
   m4/c-strtod.m4
   m4/clock_time.m4
+  m4/close-stream.m4
   m4/dup2.m4
   m4/environ.m4
   m4/execinfo.m4
   m4/extensions.m4
   m4/extern-inline.m4
   m4/filemode.m4
+  m4/fpending.m4
   m4/getloadavg.m4
   m4/getopt.m4
   m4/gettime.m4

=== modified file 'src/ChangeLog'
--- src/ChangeLog	2012-11-01 14:21:45 +0000
+++ src/ChangeLog	2012-11-01 20:07:42 +0000
@@ -1,3 +1,13 @@
+2012-11-01  Paul Eggert  <eggert <at> cs.ucla.edu>
+
+	Fix data-loss with --batch (Bug#9574).
+	* emacs.c: Include <close-stream.h>.
+	(close_output_streams): New function.
+	(main): Pass it to atexit, so that Emacs closes stdout and stderr
+	and handles errors appropriately.
+	(Fkill_emacs): Don't worry about flushing, as close_output_stream
+	does that now.
+
 2012-11-01  Eli Zaretskii  <eliz <at> gnu.org>
 
 	* w32proc.c (getpgrp, setpgid): New functions.  (Bug#12776)

=== modified file 'src/emacs.c'
--- src/emacs.c	2012-10-31 17:27:29 +0000
+++ src/emacs.c	2012-11-01 20:07:42 +0000
@@ -27,6 +27,7 @@
 #include <sys/file.h>
 #include <unistd.h>
 
+#include <close-stream.h>
 #include <ignore-value.h>
 
 #include "lisp.h"
@@ -675,6 +676,22 @@
 
 #endif /* DOUG_LEA_MALLOC */
 
+/* Close standard output and standard error, reporting any write
+   errors as best we can.  This is intended for use with atexit.  */
+static void
+close_output_streams (void)
+{
+  if (close_stream (stdout) != 0)
+    {
+      fprintf (stderr, "Write error to standard output: %s\n",
+	       emacs_strerror (errno));
+      fflush (stderr);
+      _exit (EXIT_FAILURE);
+    }
+
+   if (close_stream (stderr) != 0)
+     _exit (EXIT_FAILURE);
+}
 
 /* ARGSUSED */
 int
@@ -890,6 +907,8 @@
   if (do_initial_setlocale)
     setlocale (LC_ALL, "");
 
+  atexit (close_output_streams);
+
   inhibit_window_system = 0;
 
   /* Handle the -t switch, which specifies filename to use as terminal.  */
@@ -1867,8 +1886,6 @@
     exit_code = (XINT (arg) < 0
 		 ? XINT (arg) | INT_MIN
 		 : XINT (arg) & INT_MAX);
-  else if (noninteractive && (fflush (stdout) || ferror (stdout)))
-    exit_code = EXIT_FAILURE;
   else
     exit_code = EXIT_SUCCESS;
   exit (exit_code);






Added tag(s) patch. Request was from Paul Eggert <eggert <at> cs.ucla.edu> to control <at> debbugs.gnu.org. (Thu, 01 Nov 2012 20:13:02 GMT) Full text and rfc822 format available.

Reply sent to Paul Eggert <eggert <at> cs.ucla.edu>:
You have taken responsibility. (Sun, 04 Nov 2012 17:23:02 GMT) Full text and rfc822 format available.

Notification sent to Jim Meyering <jim <at> meyering.net>:
bug acknowledged by developer. (Sun, 04 Nov 2012 17:23:03 GMT) Full text and rfc822 format available.

Message #44 received at 9574-done <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: 9574-done <at> debbugs.gnu.org
Subject: patch installed
Date: Sun, 04 Nov 2012 09:19:07 -0800
I installed the patch for this into the Emacs trunk as bzr 110786
and am marking it as done.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 03 Dec 2012 12:24:03 GMT) Full text and rfc822 format available.

This bug report was last modified 11 years and 153 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.