Commit 4ebbdd67 authored by Paul Eggert's avatar 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.
* 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 <ignore-value.h>.
* 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.
parent 584ee3fc
2013-07-09 Paul Eggert <eggert@cs.ucla.edu>
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 <magnus.henoch@gmail.com> (tiny change)
* configure.ac (HAVE_IMAGEMAGICK): Check on NS also (Bug#14798).
......
2013-07-09 Paul Eggert <eggert@cs.ucla.edu>
Handle error numbers a bit more reliably.
* merge-gnulib (GNULIB_MODULES): Remove ignore-value.
2013-07-07 Paul Eggert <eggert@cs.ucla.edu>
Make file descriptors close-on-exec when possible (Bug#14803).
......
......@@ -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
......
......@@ -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
......
/* 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 <http://www.gnu.org/licenses/>. */
/* 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
......@@ -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
......
2013-07-09 Paul Eggert <eggert@cs.ucla.edu>
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 <ignore-value.h>.
* 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 <magnus.henoch@gmail.com> (tiny change).
* image.c (imagemagick_load_image): Do not use MagickExportImagePixels
......
......@@ -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;
......
......@@ -28,7 +28,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <close-stream.h>
#include <ignore-value.h>
#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));
}
}
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -3603,7 +3603,7 @@ overwriting cursor (usually when cursor on a tab) */
/* 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 @@ overwriting cursor (usually when cursor on a tab) */
if (nr > 0 && readfds)
{
c = 's';
emacs_write (selfds[1], &c, 1);
emacs_write_sig (selfds[1], &c, 1);
}
unblock_input ();
......
......@@ -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
......
......@@ -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);
......
......@@ -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");
}
......
......@@ -31,7 +31,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <c-ctype.h>
#include <ignore-value.h>
#include <utimens.h>
#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.
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment