Make file descriptors close-on-exec when possible.
[bpt/emacs.git] / src / sysdep.c
index 9c90485..faca7fa 100644 (file)
@@ -1,6 +1,6 @@
 /* Interfaces to system-dependent kernel and library entries.
-   Copyright (C) 1985-1988, 1993-1995, 1999-2012
-                 Free Software Foundation, Inc.
+   Copyright (C) 1985-1988, 1993-1995, 1999-2013 Free Software
+   Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -22,7 +22,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define SYSTIME_INLINE EXTERN_INLINE
 
 #include <execinfo.h>
-#include <stdio.h>
+#include "sysstdio.h"
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #include <grp.h>
@@ -30,9 +30,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <limits.h>
 #include <unistd.h>
 
-#include <allocator.h>
 #include <c-ctype.h>
-#include <careadlinkat.h>
 #include <ignore-value.h>
 #include <utimens.h>
 
@@ -40,9 +38,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "sysselect.h"
 #include "blockinput.h"
 
-#ifdef BSD_SYSTEM
-#include <sys/param.h>
-#include <sys/sysctl.h>
+#if defined DARWIN_OS || defined __FreeBSD__
+# include <sys/sysctl.h>
 #endif
 
 #ifdef __FreeBSD__
@@ -71,9 +68,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef MSDOS   /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
 #include "msdos.h"
-#include <sys/param.h>
 #endif
 
+#include <sys/param.h>
 #include <sys/file.h>
 #include <fcntl.h>
 
@@ -285,7 +282,7 @@ get_child_status (pid_t child, int *status, int options, bool interruptible)
      reap an unwanted process by mistake.  For example, invoking
      waitpid (-1, ...) can mess up glib by reaping glib's subprocesses,
      so that another thread running glib won't find them.  */
-  eassert (0 < child);
+  eassert (child > 0);
 
   while ((pid = waitpid (child, status, options)) < 0)
     {
@@ -457,20 +454,15 @@ static void restore_signal_handlers (struct save_signal *);
 void
 sys_suspend (void)
 {
-#if defined (SIGTSTP) && !defined (MSDOS)
-
-  {
-    pid_t pgrp = getpgrp ();
-    EMACS_KILLPG (pgrp, SIGTSTP);
-  }
-
-#else /* No SIGTSTP */
+#ifndef DOS_NT
+  kill (0, SIGTSTP);
+#else
 /* On a system where suspending is not implemented,
    instead fork a subshell and let it talk directly to the terminal
    while we wait.  */
   sys_subshell ();
 
-#endif /* no SIGTSTP */
+#endif
 }
 
 /* Fork a subshell.  */
@@ -534,10 +526,10 @@ sys_subshell (void)
 #ifdef DOS_NT    /* MW, Aug 1993 */
       getcwd (oldwd, sizeof oldwd);
       if (sh == 0)
-       sh = (char *) egetenv ("SUSPEND");      /* KFS, 1994-12-14 */
+       sh = egetenv ("SUSPEND");       /* KFS, 1994-12-14 */
 #endif
       if (sh == 0)
-       sh = (char *) egetenv ("SHELL");
+       sh = egetenv ("SHELL");
       if (sh == 0)
        sh = "sh";
 
@@ -551,8 +543,6 @@ sys_subshell (void)
 #endif
        }
 
-      close_process_descs ();  /* Close Emacs's pipes/ptys */
-
 #ifdef MSDOS    /* Demacs 1.1.2 91/10/20 Manabu Higashida */
       {
        char *epwd = getenv ("PWD");
@@ -719,6 +709,27 @@ init_foreground_group (void)
   inherited_pgroup = getpid () == pgrp ? 0 : pgrp;
 }
 
+/* Block and unblock SIGTTOU.  */
+
+void
+block_tty_out_signal (void)
+{
+#ifdef SIGTTOU
+  sigset_t blocked;
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGTTOU);
+  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+#endif
+}
+
+void
+unblock_tty_out_signal (void)
+{
+#ifdef SIGTTOU
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
+}
+
 /* Safely set a controlling terminal FD's process group to PGID.
    If we are not in the foreground already, POSIX requires tcsetpgrp
    to deliver a SIGTTOU signal, which would stop us.  This is an
@@ -730,11 +741,10 @@ static void
 tcsetpgrp_without_stopping (int fd, pid_t pgid)
 {
 #ifdef SIGTTOU
-  signal_handler_t handler;
   block_input ();
-  handler = signal (SIGTTOU, SIG_IGN);
+  block_tty_out_signal ();
   tcsetpgrp (fd, pgid);
-  signal (SIGTTOU, handler);
+  unblock_tty_out_signal ();
   unblock_input ();
 #endif
 }
@@ -1277,10 +1287,9 @@ reset_sys_modes (struct tty_display_info *tty_out)
   if (tty_out->terminal->reset_terminal_modes_hook)
     tty_out->terminal->reset_terminal_modes_hook (tty_out->terminal);
 
-#ifdef BSD_SYSTEM
   /* Avoid possible loss of output when changing terminal modes.  */
-  fsync (fileno (tty_out->output));
-#endif
+  while (fdatasync (fileno (tty_out->output)) != 0 && errno == EINTR)
+    continue;
 
 #ifndef DOS_NT
 #ifdef F_SETOWN
@@ -1518,9 +1527,7 @@ emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
   /* When handling a signal, block nonfatal system signals that are caught
      by Emacs.  This makes race conditions less likely.  */
   sigaddset (&action->sa_mask, SIGALRM);
-#ifdef SIGCHLD
   sigaddset (&action->sa_mask, SIGCHLD);
-#endif
 #ifdef SIGDANGER
   sigaddset (&action->sa_mask, SIGDANGER);
 #endif
@@ -1621,6 +1628,8 @@ deliver_thread_signal (int sig, signal_handler_t handler)
 # undef sys_siglist
 # ifdef _sys_siglist
 #  define sys_siglist _sys_siglist
+# elif HAVE_DECL___SYS_SIGLIST
+#  define sys_siglist __sys_siglist
 # else
 #  define sys_siglist my_sys_siglist
 static char const *sys_siglist[NSIG];
@@ -1665,6 +1674,25 @@ deliver_arith_signal (int sig)
   deliver_thread_signal (sig, handle_arith_signal);
 }
 
+#ifdef SIGDANGER
+
+/* Handler for SIGDANGER.  */
+static void
+handle_danger_signal (int sig)
+{
+  malloc_warning ("Operating system warns that virtual memory is running low.\n");
+
+  /* It might be unsafe to call do_auto_save now.  */
+  force_auto_save_soon ();
+}
+
+static void
+deliver_danger_signal (int sig)
+{
+  deliver_process_signal (sig, handle_danger_signal);
+}
+#endif
+
 /* Treat SIG as a terminating signal, unless it is already ignored and
    we are in --batch mode.  Among other things, this makes nohup work.  */
 static void
@@ -1700,18 +1728,11 @@ init_signals (bool dumping)
 # ifdef SIGAIO
       sys_siglist[SIGAIO] = "LAN I/O interrupt";
 # endif
-# ifdef SIGALRM
       sys_siglist[SIGALRM] = "Alarm clock";
-# endif
 # ifdef SIGBUS
       sys_siglist[SIGBUS] = "Bus error";
 # endif
-# ifdef SIGCLD
-      sys_siglist[SIGCLD] = "Child status changed";
-# endif
-# ifdef SIGCHLD
       sys_siglist[SIGCHLD] = "Child status changed";
-# endif
 # ifdef SIGCONT
       sys_siglist[SIGCONT] = "Continued";
 # endif
@@ -1731,9 +1752,7 @@ init_signals (bool dumping)
 # ifdef SIGGRANT
       sys_siglist[SIGGRANT] = "Monitor mode granted";
 # endif
-# ifdef SIGHUP
       sys_siglist[SIGHUP] = "Hangup";
-# endif
       sys_siglist[SIGILL] = "Illegal instruction";
       sys_siglist[SIGINT] = "Interrupt";
 # ifdef SIGIO
@@ -1745,9 +1764,7 @@ init_signals (bool dumping)
 # ifdef SIGIOT
       sys_siglist[SIGIOT] = "IOT trap";
 # endif
-# ifdef SIGKILL
       sys_siglist[SIGKILL] = "Killed";
-# endif
 # ifdef SIGLOST
       sys_siglist[SIGLOST] = "Resource lost";
 # endif
@@ -1760,9 +1777,7 @@ init_signals (bool dumping)
 # ifdef SIGPHONE
       sys_siglist[SIGWIND] = "SIGPHONE";
 # endif
-# ifdef SIGPIPE
       sys_siglist[SIGPIPE] = "Broken pipe";
-# endif
 # ifdef SIGPOLL
       sys_siglist[SIGPOLL] = "Pollable event occurred";
 # endif
@@ -1775,9 +1790,7 @@ init_signals (bool dumping)
 # ifdef SIGPWR
       sys_siglist[SIGPWR] = "Power-fail restart";
 # endif
-# ifdef SIGQUIT
       sys_siglist[SIGQUIT] = "Quit";
-# endif
 # ifdef SIGRETRACT
       sys_siglist[SIGRETRACT] = "Need to relinquish monitor mode";
 # endif
@@ -2132,19 +2145,57 @@ emacs_backtrace (int backtrace_limit)
 void
 emacs_abort (void)
 {
-  terminate_due_to_signal (SIGABRT, 10);
+  terminate_due_to_signal (SIGABRT, 40);
 }
 #endif
 
+/* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
+   Arrange for subprograms to not inherit the file descriptor.
+   Prefer a method that is multithread-safe, if available.
+   Do not fail merely because the open was interrupted by a signal.
+   Allow the user to quit.  */
+
 int
-emacs_open (const char *path, int oflag, int mode)
+emacs_open (const char *file, int oflags, int mode)
 {
-  register int rtnval;
-
-  while ((rtnval = open (path, oflag, mode)) == -1
-        && (errno == EINTR))
+  int fd;
+  oflags |= O_CLOEXEC;
+  while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
     QUIT;
-  return (rtnval);
+  if (! O_CLOEXEC && 0 <= fd)
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
+  return fd;
+}
+
+/* Open FILE as a stream for Emacs use, with mode MODE.
+   Act like emacs_open with respect to threads, signals, and quits.  */
+
+FILE *
+emacs_fopen (char const *file, char const *mode)
+{
+  int fd, omode, oflags;
+  int bflag = 0;
+  char const *m = mode;
+
+  switch (*m++)
+    {
+    case 'r': omode = O_RDONLY; oflags = 0; break;
+    case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
+    case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
+    default: emacs_abort ();
+    }
+
+  while (*m)
+    switch (*m++)
+      {
+      case '+': omode = O_RDWR; break;
+      case 'b': bflag = O_BINARY; break;
+      case 't': bflag = O_TEXT; break;
+      default: /* Ignore.  */ break;
+      }
+
+  fd = emacs_open (file, omode | oflags | bflag, 0666);
+  return fd < 0 ? 0 : fdopen (fd, mode);
 }
 
 int
@@ -2230,22 +2281,6 @@ emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
 
   return (bytes_written);
 }
-
-static struct allocator const emacs_norealloc_allocator =
-  { xmalloc, NULL, xfree, memory_full };
-
-/* Get the symbolic link value of FILENAME.  Return a pointer to a
-   NUL-terminated string.  If readlink fails, return NULL and set
-   errno.  If the value fits in INITIAL_BUF, return INITIAL_BUF.
-   Otherwise, allocate memory and return a pointer to that memory.  If
-   memory allocation fails, diagnose and fail without returning.  If
-   successful, store the length of the symbolic link into *LINKLEN.  */
-char *
-emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
-{
-  return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
-                      &emacs_norealloc_allocator, careadlinkatcwd);
-}
 \f
 /* Return a struct timeval that is roughly equivalent to T.
    Use the least timeval not less than T.
@@ -2542,12 +2577,12 @@ list_system_processes (void)
   return proclist;
 }
 
-#elif defined BSD_SYSTEM
+#elif defined DARWIN_OS || defined __FreeBSD__
 
 Lisp_Object
 list_system_processes (void)
 {
-#if defined DARWIN_OS || defined __NetBSD__ || defined __OpenBSD__
+#ifdef DARWIN_OS
   int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
 #else
   int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC};
@@ -2573,10 +2608,8 @@ list_system_processes (void)
   len /= sizeof (struct kinfo_proc);
   for (i = 0; i < len; i++)
     {
-#if defined DARWIN_OS || defined __NetBSD__
+#ifdef DARWIN_OS
       proclist = Fcons (make_fixnum_or_float (procs[i].kp_proc.p_pid), proclist);
-#elif defined __OpenBSD__
-      proclist = Fcons (make_fixnum_or_float (procs[i].p_pid), proclist);
 #else
       proclist = Fcons (make_fixnum_or_float (procs[i].ki_pid), proclist);
 #endif
@@ -2640,7 +2673,7 @@ get_up_time (void)
   EMACS_TIME up = make_emacs_time (0, 0);
 
   block_input ();
-  fup = fopen ("/proc/uptime", "r");
+  fup = emacs_fopen ("/proc/uptime", "r");
 
   if (fup)
     {
@@ -2685,7 +2718,7 @@ procfs_ttyname (int rdev)
   char name[PATH_MAX];
 
   block_input ();
-  fdev = fopen ("/proc/tty/drivers", "r");
+  fdev = emacs_fopen ("/proc/tty/drivers", "r");
 
   if (fdev)
     {
@@ -2696,7 +2729,7 @@ procfs_ttyname (int rdev)
 
       while (!feof (fdev) && !ferror (fdev))
        {
-         if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor)
+         if (fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) >= 3
              && major == MAJOR (rdev))
            {
              minor_beg = strtoul (minor, &endp, 0);
@@ -2727,7 +2760,7 @@ procfs_get_total_memory (void)
   unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
 
   block_input ();
-  fmem = fopen ("/proc/meminfo", "r");
+  fmem = emacs_fopen ("/proc/meminfo", "r");
 
   if (fmem)
     {
@@ -2736,7 +2769,7 @@ procfs_get_total_memory (void)
 
       while (!feof (fmem) && !ferror (fmem))
        {
-         if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value)
+         if (fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) >= 2
              && strcmp (entry_name, "MemTotal:") == 0)
            {
              retval = entry_value;