From 4ebbdd6712c1966406b40d2673464949775cbd7a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 9 Jul 2013 00:04:48 -0700 Subject: [PATCH] Handle errno and exit status a bit more carefully. * lib/ignore-value.h: Remove this gnulib-imported file. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Remove ignore-value. * src/callproc.c (child_setup) [!DOS_NT]: Don't try to stuff an error number into an exit status. Instead, use EXIT_CANCELED. (child_setup) [!MSDOS]: Avoid possible deadlock with vfork. * src/callproc.c (relocate_fd): * src/emacs.c (close_output_streams, main): * src/process.c (create_process): * src/sysdep.c (sys_subshell) [!DOS_NT || !WINDOWSNT]: Use emacs_perror for simplicity. * src/callproc.c (relocate_fd, main): * src/sysdep.c (sys_subshell): Exit with EXIT_CANCELED etc., not 1, when exec setup fails. (shut_down_emacs): Use emacs_write, not write. * src/emacs.c, src/sysdep.c: Don't include . * src/fileio.c (Fcopy_file, e_write): * src/nsterm.m (ns_select): * src/process.c (send_process): * src/sound.c (vox_write): Use emacs_write_sig, not emacs_write. * src/lisp.h (emacs_write_sig, emacs_perror): New decls. * src/process.h (EXIT_CANCELED), EXIT_CANNOT_INVOKE, EXIT_ENOENT): New constants. * src/sysdep.c (emacs_backtrace): Use emacs_write, not ignore_value of write. (emacs_full_write): New function. (emacs_write): Rewrite to use it. (emacswrite_sig, emacs_perror): New functions. * src/xrdb.c (fatal): Don't invoke perror, since errno might be garbage. --- ChangeLog | 6 ++++ admin/ChangeLog | 5 +++ admin/merge-gnulib | 2 +- lib/gnulib.mk | 9 +---- lib/ignore-value.h | 48 -------------------------- m4/gnulib-comp.m4 | 2 -- src/ChangeLog | 31 +++++++++++++++++ src/callproc.c | 21 +++++------- src/emacs.c | 23 ++++++------- src/fileio.c | 12 +++---- src/lisp.h | 3 ++ src/nsterm.m | 4 +-- src/process.c | 10 +++--- src/process.h | 8 +++++ src/sound.c | 2 +- src/sysdep.c | 85 ++++++++++++++++++++++++++++++++++------------ src/xrdb.c | 5 +-- 17 files changed, 151 insertions(+), 125 deletions(-) delete mode 100644 lib/ignore-value.h diff --git a/ChangeLog b/ChangeLog index 05f87cf273..c9571aec61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-07-09 Paul Eggert + + Handle errno and exit status a bit more carefully. + * lib/ignore-value.h: Remove this gnulib-imported file. + * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. + 2013-07-08 Magnus Henoch (tiny change) * configure.ac (HAVE_IMAGEMAGICK): Check on NS also (Bug#14798). diff --git a/admin/ChangeLog b/admin/ChangeLog index f7d7cbb55d..deb3059f8d 100644 --- a/admin/ChangeLog +++ b/admin/ChangeLog @@ -1,3 +1,8 @@ +2013-07-09 Paul Eggert + + Handle error numbers a bit more reliably. + * merge-gnulib (GNULIB_MODULES): Remove ignore-value. + 2013-07-07 Paul Eggert Make file descriptors close-on-exec when possible (Bug#14803). diff --git a/admin/merge-gnulib b/admin/merge-gnulib index f89fe7959f..be4dfdd409 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -31,7 +31,7 @@ GNULIB_MODULES=' dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday - ignore-value intprops largefile lstat + intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio diff --git a/lib/gnulib.mk b/lib/gnulib.mk index 9f9ac6c058..1bb1bea5f9 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk @@ -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=binary-io --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --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 faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv 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=binary-io --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --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 faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings MOSTLYCLEANFILES += core *.stackdump @@ -485,13 +485,6 @@ EXTRA_libgnu_a_SOURCES += group-member.c ## end gnulib module group-member -## begin gnulib module ignore-value - - -EXTRA_DIST += ignore-value.h - -## end gnulib module ignore-value - ## begin gnulib module intprops diff --git a/lib/ignore-value.h b/lib/ignore-value.h deleted file mode 100644 index ebd6bf42f5..0000000000 --- a/lib/ignore-value.h +++ /dev/null @@ -1,48 +0,0 @@ -/* ignore a function return without a compiler warning - - Copyright (C) 2008-2013 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 . */ - -/* Written by Jim Meyering, Eric Blake and Pádraig Brady. */ - -/* Use "ignore_value" to avoid a warning when using a function declared with - gcc's warn_unused_result attribute, but for which you really do want to - ignore the result. Traditionally, people have used a "(void)" cast to - indicate that a function's return value is deliberately unused. However, - if the function is declared with __attribute__((warn_unused_result)), - gcc issues a warning even with the cast. - - Caution: most of the time, you really should heed gcc's warning, and - check the return value. However, in those exceptional cases in which - you're sure you know what you're doing, use this function. - - For the record, here's one of the ignorable warnings: - "copy.c:233: warning: ignoring return value of 'fchown', - declared with attribute warn_unused_result". */ - -#ifndef _GL_IGNORE_VALUE_H -#define _GL_IGNORE_VALUE_H - -/* The __attribute__((__warn_unused_result__)) feature - is available in gcc versions 3.4 and newer, - while the typeof feature has been available since 2.7 at least. */ -#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) -# define ignore_value(x) \ - (__extension__ ({ __typeof__ (x) __x = (x); (void) __x; })) -#else -# define ignore_value(x) ((void) (x)) -#endif - -#endif diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index e813692aea..a909927f31 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -80,7 +80,6 @@ AC_DEFUN([gl_EARLY], # Code from module gettime: # Code from module gettimeofday: # Code from module group-member: - # Code from module ignore-value: # Code from module include_next: # Code from module intprops: # Code from module inttypes-incomplete: @@ -798,7 +797,6 @@ AC_DEFUN([gl_FILE_LIST], [ lib/gettime.c lib/gettimeofday.c lib/group-member.c - lib/ignore-value.h lib/intprops.h lib/inttypes.in.h lib/lstat.c diff --git a/src/ChangeLog b/src/ChangeLog index 9be0b59ee0..8b152f4a17 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,34 @@ +2013-07-09 Paul Eggert + + Handle errno and exit status a bit more carefully. + * callproc.c (child_setup) [!DOS_NT]: Don't try to stuff an error + number into an exit status. Instead, use EXIT_CANCELED. + (child_setup) [!MSDOS]: Avoid possible deadlock with vfork. + * callproc.c (relocate_fd): + * emacs.c (close_output_streams, main): + * process.c (create_process): + * sysdep.c (sys_subshell) [!DOS_NT || !WINDOWSNT]: + Use emacs_perror for simplicity. + * callproc.c (relocate_fd, main): + * sysdep.c (sys_subshell): + Exit with EXIT_CANCELED etc., not 1, when exec setup fails. + (shut_down_emacs): Use emacs_write, not write. + * emacs.c, sysdep.c: Don't include . + * fileio.c (Fcopy_file, e_write): + * nsterm.m (ns_select): + * process.c (send_process): + * sound.c (vox_write): + Use emacs_write_sig, not emacs_write. + * lisp.h (emacs_write_sig, emacs_perror): New decls. + * process.h (EXIT_CANCELED), EXIT_CANNOT_INVOKE, EXIT_ENOENT): + New constants. + * sysdep.c (emacs_backtrace): Use emacs_write, not ignore_value + of write. + (emacs_full_write): New function. + (emacs_write): Rewrite to use it. + (emacswrite_sig, emacs_perror): New functions. + * xrdb.c (fatal): Don't invoke perror, since errno might be garbage. + 2013-07-08 Magnus Henoch (tiny change). * image.c (imagemagick_load_image): Do not use MagickExportImagePixels diff --git a/src/callproc.c b/src/callproc.c index 369d6eda90..fc274f3d9c 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -1221,7 +1221,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, are changed between the check and this chdir, but we should at least check. */ if (chdir (temp) < 0) - _exit (errno); + _exit (EXIT_CANCELED); #else /* DOS_NT */ /* Get past the drive letter, so that d:/ is left alone. */ if (i > 2 && IS_DEVICE_SEP (temp[1]) && IS_DIRECTORY_SEP (temp[2])) @@ -1366,10 +1366,12 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, execve (new_argv[0], new_argv, env); - emacs_write (1, "Can't exec program: ", 20); - emacs_write (1, new_argv[0], strlen (new_argv[0])); - emacs_write (1, "\n", 1); - _exit (1); + /* Don't output the program name here, as it can be arbitrarily long, + and a long write from a vforked child to its parent can cause a + deadlock. */ + emacs_perror ("child process"); + + _exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); #else /* MSDOS */ pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env); @@ -1395,13 +1397,8 @@ relocate_fd (int fd, int minfd) int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd); if (new == -1) { - const char *message_1 = "Error while setting up child: "; - const char *errmessage = strerror (errno); - const char *message_2 = "\n"; - emacs_write (2, message_1, strlen (message_1)); - emacs_write (2, errmessage, strlen (errmessage)); - emacs_write (2, message_2, strlen (message_2)); - _exit (1); + emacs_perror ("while setting up child"); + _exit (EXIT_CANCELED); } emacs_close (fd); return new; diff --git a/src/emacs.c b/src/emacs.c index edf98d8cdb..ee72095f70 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -28,7 +28,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include "lisp.h" @@ -646,9 +645,7 @@ close_output_streams (void) { if (close_stream (stdout) != 0) { - fprintf (stderr, "Write error to standard output: %s\n", - strerror (errno)); - fflush (stderr); + emacs_perror ("Write error to standard output"); _exit (EXIT_FAILURE); } @@ -789,7 +786,7 @@ main (int argc, char **argv) execvp (argv[0], argv); /* If the exec fails, try to dump anyway. */ - perror ("execvp"); + emacs_perror (argv[0]); } #endif /* HAVE_PERSONALITY_LINUX32 */ @@ -1020,8 +1017,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem } if (f < 0) { - fprintf (stderr, "Cannot fork!\n"); - exit (1); + emacs_perror ("fork"); + exit (EXIT_CANCELED); } #ifdef DAEMON_MUST_EXEC @@ -1038,14 +1035,14 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem if (! (0 <= fdStrlen && fdStrlen < sizeof fdStr)) { fprintf (stderr, "daemon: child name too long\n"); - exit (1); + exit (EXIT_CANNOT_INVOKE); } argv[skip_args] = fdStr; execvp (argv[0], argv); - fprintf (stderr, "emacs daemon: exec failed: %d\n", errno); - exit (1); + emacs_perror (argv[0]); + exit (errno == ENOENT : EXIT_ENOENT : EXIT_CANNOT_INVOKE); } /* In exec'd: parse special dname into pipe and name info. */ @@ -1053,7 +1050,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem || strlen (dname_arg) < 1 || strlen (dname_arg) > 70) { fprintf (stderr, "emacs daemon: daemon name absent or too long\n"); - exit (1); + exit (EXIT_CANNOT_INVOKE); } dname_arg2[0] = '\0'; sscanf (dname_arg, "\n%d,%d\n%s", &(daemon_pipe[0]), &(daemon_pipe[1]), @@ -1916,8 +1913,8 @@ shut_down_emacs (int sig, Lisp_Object stuff) char buf[sizeof format - 2 + INT_STRLEN_BOUND (int)]; int buflen = sprintf (buf, format, sig); char const *sig_desc = safe_strsignal (sig); - ignore_value (write (STDERR_FILENO, buf, buflen)); - ignore_value (write (STDERR_FILENO, sig_desc, strlen (sig_desc))); + emacs_write (STDERR_FILENO, buf, buflen); + emacs_write (STDERR_FILENO, sig_desc, strlen (sig_desc)); } } } diff --git a/src/fileio.c b/src/fileio.c index 89ae89e161..d030c78c42 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -2122,7 +2122,7 @@ entries (depending on how Emacs was built). */) immediate_quit = 1; QUIT; while ((n = emacs_read (ifd, buf, sizeof buf)) > 0) - if (emacs_write (ofd, buf, n) != n) + if (emacs_write_sig (ofd, buf, n) != n) report_file_error ("I/O error", Fcons (newname, Qnil)); immediate_quit = 0; @@ -5317,12 +5317,10 @@ e_write (int desc, Lisp_Object string, ptrdiff_t start, ptrdiff_t end, if (coding->produced > 0) { - coding->produced - -= emacs_write (desc, - STRINGP (coding->dst_object) - ? SSDATA (coding->dst_object) - : (char *) BYTE_POS_ADDR (coding->dst_pos_byte), - coding->produced); + char *buf = (STRINGP (coding->dst_object) + ? SSDATA (coding->dst_object) + : (char *) BYTE_POS_ADDR (coding->dst_pos_byte)); + coding->produced -= emacs_write_sig (desc, buf, coding->produced); if (coding->produced) return 0; diff --git a/src/lisp.h b/src/lisp.h index c7e36fbf9d..33e9309de3 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3998,6 +3998,7 @@ extern void init_process_emacs (void); extern void syms_of_process (void); extern void setup_process_coding_systems (Lisp_Object); +/* Defined in callproc.c. */ #ifndef DOS_NT _Noreturn #endif @@ -4090,6 +4091,8 @@ extern int emacs_open (const char *, int, int); extern int emacs_close (int); extern ptrdiff_t emacs_read (int, char *, ptrdiff_t); extern ptrdiff_t emacs_write (int, const char *, ptrdiff_t); +extern ptrdiff_t emacs_write_sig (int, char const *, ptrdiff_t); +extern void emacs_perror (char const *); extern void unlock_all_files (void); extern void lock_file (Lisp_Object); diff --git a/src/nsterm.m b/src/nsterm.m index 074a5adf78..d7cea5c189 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3603,7 +3603,7 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, /* Inform fd_handler that select should be called */ c = 'g'; - emacs_write (selfds[1], &c, 1); + emacs_write_sig (selfds[1], &c, 1); } else if (nr == 0 && timeout) { @@ -3636,7 +3636,7 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, if (nr > 0 && readfds) { c = 's'; - emacs_write (selfds[1], &c, 1); + emacs_write_sig (selfds[1], &c, 1); } unblock_input (); diff --git a/src/process.c b/src/process.c index 1c21064902..36ca1cf678 100644 --- a/src/process.c +++ b/src/process.c @@ -1752,7 +1752,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) tcgetattr (xforkin, &t); t.c_lflag = LDISC1; if (tcsetattr (xforkin, TCSANOW, &t) < 0) - emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39); + emacs_perror ("create_process/tcsetattr LDISC1"); } #else #if defined (NTTYDISC) && defined (TIOCSETD) @@ -1799,10 +1799,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) if (xforkin < 0) { - emacs_write (1, "Couldn't open the pty terminal ", 31); - emacs_write (1, pty_name, strlen (pty_name)); - emacs_write (1, "\n", 1); - _exit (1); + emacs_perror (pty_name); + _exit (EXIT_CANCELED); } } @@ -5503,7 +5501,7 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len, written = emacs_gnutls_write (p, cur_buf, cur_len); else #endif - written = emacs_write (outfd, cur_buf, cur_len); + written = emacs_write_sig (outfd, cur_buf, cur_len); rv = (written ? 0 : -1); #ifdef ADAPTIVE_READ_BUFFERING if (p->read_output_delay > 0 diff --git a/src/process.h b/src/process.h index e7ee5f9add..8ae33aebf3 100644 --- a/src/process.h +++ b/src/process.h @@ -198,6 +198,14 @@ extern Lisp_Object QCspeed; extern Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven; extern Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary; +/* Exit statuses for GNU programs that exec other programs. */ +enum +{ + EXIT_CANCELED = 125, /* Internal error prior to exec attempt. */ + EXIT_CANNOT_INVOKE = 126, /* Program located, but not usable. */ + EXIT_ENOENT = 127 /* Could not find program to exec. */ +}; + /* Defined in callproc.c. */ extern void block_child_signal (void); diff --git a/src/sound.c b/src/sound.c index 7f0ede5b39..5ce185ea60 100644 --- a/src/sound.c +++ b/src/sound.c @@ -879,7 +879,7 @@ vox_init (struct sound_device *sd) static void vox_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes) { - if (emacs_write (sd->fd, buffer, nbytes) != nbytes) + if (emacs_write_sig (sd->fd, buffer, nbytes) != nbytes) sound_perror ("Error writing to sound device"); } diff --git a/src/sysdep.c b/src/sysdep.c index faca7fae46..6346b0bbfc 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -31,7 +31,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include "lisp.h" @@ -538,8 +537,8 @@ sys_subshell (void) if (str && chdir ((char *) str) != 0) { #ifndef DOS_NT - ignore_value (write (1, "Can't chdir\n", 12)); - _exit (1); + emacs_perror ((char *) str); + _exit (EXIT_CANCELED); #endif } @@ -570,8 +569,8 @@ sys_subshell (void) write (1, "Can't execute subshell", 22); #else /* not WINDOWSNT */ execlp (sh, sh, (char *) 0); - ignore_value (write (1, "Can't execute subshell", 22)); - _exit (1); + emacs_perror (sh); + _exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE); #endif /* not WINDOWSNT */ #endif /* not MSDOS */ } @@ -2134,10 +2133,10 @@ emacs_backtrace (int backtrace_limit) if (npointers) { - ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12)); + emacs_write (STDERR_FILENO, "\nBacktrace:\n", 12); backtrace_symbols_fd (buffer, npointers, STDERR_FILENO); if (bounded_limit < npointers) - ignore_value (write (STDERR_FILENO, "...\n", 4)); + emacs_write (STDERR_FILENO, "...\n", 4); } } @@ -2246,27 +2245,26 @@ emacs_read (int fildes, char *buf, ptrdiff_t nbyte) } /* Write to FILEDES from a buffer BUF with size NBYTE, retrying if interrupted - or if a partial write occurs. Return the number of bytes written, setting + or if a partial write occurs. If interrupted, process pending + signals if PROCESS SIGNALS. Return the number of bytes written, setting errno if this is less than NBYTE. */ -ptrdiff_t -emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) +static ptrdiff_t +emacs_full_write (int fildes, char const *buf, ptrdiff_t nbyte, + bool process_signals) { - ssize_t rtnval; - ptrdiff_t bytes_written; - - bytes_written = 0; + ptrdiff_t bytes_written = 0; while (nbyte > 0) { - rtnval = write (fildes, buf, min (nbyte, MAX_RW_COUNT)); + ssize_t n = write (fildes, buf, min (nbyte, MAX_RW_COUNT)); - if (rtnval < 0) + if (n < 0) { if (errno == EINTR) { /* I originally used `QUIT' but that might causes files to be truncated if you hit C-g in the middle of it. --Stef */ - if (pending_signals) + if (process_signals && pending_signals) process_pending_signals (); continue; } @@ -2274,12 +2272,57 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte) break; } - buf += rtnval; - nbyte -= rtnval; - bytes_written += rtnval; + buf += n; + nbyte -= n; + bytes_written += n; } - return (bytes_written); + return bytes_written; +} + +/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if + interrupted or if a partial write occurs. Return the number of + bytes written, setting errno if this is less than NBYTE. */ +ptrdiff_t +emacs_write (int fildes, char const *buf, ptrdiff_t nbyte) +{ + return emacs_full_write (fildes, buf, nbyte, 0); +} + +/* Like emacs_write, but also process pending signals if interrupted. */ +ptrdiff_t +emacs_write_sig (int fildes, char const *buf, ptrdiff_t nbyte) +{ + return emacs_full_write (fildes, buf, nbyte, 1); +} + +/* Write a diagnostic to standard error that contains MESSAGE and a + string derived from errno. Preserve errno. Do not buffer stderr. + Do not process pending signals if interrupted. */ +void +emacs_perror (char const *message) +{ + int err = errno; + char const *error_string = strerror (err); + char const *command = (initial_argv && initial_argv[0] + ? initial_argv[0] : "emacs"); + /* Write it out all at once, if it's short; this is less likely to + be interleaved with other output. */ + char buf[BUFSIZ]; + int nbytes = snprintf (buf, sizeof buf, "%s: %s: %s\n", + command, message, error_string); + if (0 <= nbytes && nbytes < BUFSIZ) + emacs_write (STDERR_FILENO, buf, nbytes); + else + { + emacs_write (STDERR_FILENO, command, strlen (command)); + emacs_write (STDERR_FILENO, ": ", 2); + emacs_write (STDERR_FILENO, message, strlen (message)); + emacs_write (STDERR_FILENO, ": ", 2); + emacs_write (STDERR_FILENO, error_string, strlen (error_string)); + emacs_write (STDERR_FILENO, "\n", 1); + } + errno = err; } /* Return a struct timeval that is roughly equivalent to T. diff --git a/src/xrdb.c b/src/xrdb.c index c25c25d6f3..7c9cd53fa8 100644 --- a/src/xrdb.c +++ b/src/xrdb.c @@ -634,10 +634,7 @@ member (char *elt, List list) static void fatal (char *msg, char *prog) { - if (errno) - perror (prog); - - (void) fprintf (stderr, msg, prog); + fprintf (stderr, msg, prog); exit (1); } -- 2.20.1