]> code.delx.au - gnu-emacs/blobdiff - src/callproc.c
Merge from emacs-24; up to 2012-11-24T16:58:43Z!cyd@gnu.org
[gnu-emacs] / src / callproc.c
index 5eabd689188495496e856ee8d9cbca2ef8d97e6d..6153bc1b6c6cb6b87fc9eba3820bdd18b424527e 100644 (file)
@@ -19,10 +19,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
 #include <config.h>
-#include <signal.h>
 #include <errno.h>
 #include <stdio.h>
-#include <setjmp.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -53,6 +51,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "process.h"
 #include "syssignal.h"
 #include "systty.h"
+#include "syswait.h"
 #include "blockinput.h"
 #include "frame.h"
 #include "termhooks.h"
@@ -65,102 +64,113 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "nsterm.h"
 #endif
 
-#ifndef USE_CRT_DLL
-extern char **environ;
-#endif
-
-#ifdef HAVE_SETPGID
-#if !defined (USG)
-#undef setpgrp
-#define setpgrp setpgid
-#endif
-#endif
-
 /* Pattern used by call-process-region to make temp files.  */
 static Lisp_Object Vtemp_file_name_pattern;
 
-/* True if we are about to fork off a synchronous process or if we
-   are waiting for it.  */
-int synch_process_alive;
+/* The next two variables are valid only while record-unwind-protect
+   is in place during call-process for a synchronous subprocess.  At
+   other times, their contents are irrelevant.  Doing this via static
+   C variables is more convenient than putting them into the arguments
+   of record-unwind-protect, as they need to be updated at randomish
+   times in the code, and Lisp cannot always store these values as
+   Emacs integers.  It's safe to use static variables here, as the
+   code is never invoked reentrantly.  */
+
+/* If nonzero, a process-ID that has not been reaped.  */
+static pid_t synch_process_pid;
 
-/* Nonzero => this is a string explaining death of synchronous subprocess.  */
-const char *synch_process_death;
+/* If nonnegative, a file descriptor that has not been closed.  */
+static int synch_process_fd;
+\f
+/* Block SIGCHLD.  */
 
-/* Nonzero => this is the signal number that terminated the subprocess.  */
-int synch_process_termsig;
+static void
+block_child_signal (void)
+{
+#ifdef SIGCHLD
+  sigset_t blocked;
+  sigemptyset (&blocked);
+  sigaddset (&blocked, SIGCHLD);
+  pthread_sigmask (SIG_BLOCK, &blocked, 0);
+#endif
+}
 
-/* If synch_process_death is zero,
-   this is exit code of synchronous subprocess.  */
-int synch_process_retcode;
+/* Unblock SIGCHLD.  */
 
-\f
-/* Clean up when exiting Fcall_process.
-   On MSDOS, delete the temporary file on any kind of termination.
-   On Unix, kill the process and any children on termination by signal.  */
+static void
+unblock_child_signal (void)
+{
+#ifdef SIGCHLD
+  pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+#endif
+}
 
-/* Nonzero if this is termination due to exit.  */
-static int call_process_exited;
+/* Clean up when exiting call_process_cleanup.  */
 
 static Lisp_Object
-call_process_kill (Lisp_Object fdpid)
+call_process_kill (Lisp_Object ignored)
 {
-  int fd;
-  pid_t pid;
-  CONS_TO_INTEGER (Fcar (fdpid), int, fd);
-  CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid);
-  emacs_close (fd);
-  EMACS_KILLPG (pid, SIGKILL);
-  synch_process_alive = 0;
+  if (0 <= synch_process_fd)
+    emacs_close (synch_process_fd);
+
+  /* If PID is reapable, kill it and record it as a deleted process.
+     Do this in a critical section.  Unless PID is wedged it will be
+     reaped on receipt of the first SIGCHLD after the critical section.  */
+  if (synch_process_pid)
+    {
+      block_child_signal ();
+      record_deleted_pid (synch_process_pid);
+      EMACS_KILLPG (synch_process_pid, SIGKILL);
+      unblock_child_signal ();
+    }
+
   return Qnil;
 }
 
+/* Clean up when exiting Fcall_process.
+   On MSDOS, delete the temporary file on any kind of termination.
+   On Unix, kill the process and any children on termination by signal.  */
+
 static Lisp_Object
 call_process_cleanup (Lisp_Object arg)
 {
-  Lisp_Object fdpid = Fcdr (arg);
-  int fd;
-#if defined (MSDOS)
-  Lisp_Object file;
+#ifdef MSDOS
+  Lisp_Object buffer = Fcar (arg);
+  Lisp_Object file = Fcdr (arg);
 #else
-  pid_t pid;
+  Lisp_Object buffer = arg;
 #endif
 
-  Fset_buffer (Fcar (arg));
-  CONS_TO_INTEGER (Fcar (fdpid), int, fd);
+  Fset_buffer (buffer);
 
-#if defined (MSDOS)
-  /* for MSDOS fdpid is really (fd . tempfile)  */
-  file = Fcdr (fdpid);
-  /* FD is -1 and FILE is "" when we didn't actually create a
-     temporary file in call-process.  */
-  if (fd >= 0)
-    emacs_close (fd);
-  if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0'))
-    unlink (SDATA (file));
-#else /* not MSDOS */
-  CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid);
-
-  if (call_process_exited)
-    {
-      emacs_close (fd);
-      return Qnil;
-    }
-
-  if (EMACS_KILLPG (pid, SIGINT) == 0)
+#ifndef MSDOS
+  /* If the process still exists, kill its process group.  */
+  if (synch_process_pid)
     {
       ptrdiff_t count = SPECPDL_INDEX ();
-      record_unwind_protect (call_process_kill, fdpid);
+      EMACS_KILLPG (synch_process_pid, SIGINT);
+      record_unwind_protect (call_process_kill, make_number (0));
       message1 ("Waiting for process to die...(type C-g again to kill it instantly)");
       immediate_quit = 1;
       QUIT;
-      wait_for_termination (pid);
+      wait_for_termination (synch_process_pid, 0, 1);
+      synch_process_pid = 0;
       immediate_quit = 0;
       specpdl_ptr = specpdl + count; /* Discard the unwind protect.  */
       message1 ("Waiting for process to die...done");
     }
-  synch_process_alive = 0;
-  emacs_close (fd);
-#endif /* not MSDOS */
+#endif
+
+  if (0 <= synch_process_fd)
+    emacs_close (synch_process_fd);
+
+#ifdef MSDOS
+  /* FILE is "" when we didn't actually create a temporary file in
+     call-process.  */
+  if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0'))
+    unlink (SDATA (file));
+#endif
+
   return Qnil;
 }
 
@@ -193,18 +203,14 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again.
 usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail;
-  int display_p;
-  int fd[2];
-  int filefd;
-#define CALLPROC_BUFFER_SIZE_MIN (16 * 1024)
-#define CALLPROC_BUFFER_SIZE_MAX (4 * CALLPROC_BUFFER_SIZE_MIN)
-  char buf[CALLPROC_BUFFER_SIZE_MAX];
-  int bufsize = CALLPROC_BUFFER_SIZE_MIN;
+  Lisp_Object infile, buffer, current_dir, path;
+  bool display_p;
+  int fd0, fd1, filefd;
+  int status;
   ptrdiff_t count = SPECPDL_INDEX ();
   USE_SAFE_ALLOCA;
 
-  register const unsigned char **new_argv;
+  char **new_argv;
   /* File to use for stderr in the child.
      t means use same as standard output.  */
   Lisp_Object error_file;
@@ -216,12 +222,13 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 #else
   pid_t pid;
 #endif
+  int child_errno;
   int fd_output = -1;
   struct coding_system process_coding; /* coding-system of process output */
   struct coding_system argument_coding;        /* coding-system of arguments */
   /* Set to the return value of Ffind_operation_coding_system.  */
   Lisp_Object coding_systems;
-  int output_to_buffer = 1;
+  bool output_to_buffer = 1;
 
   /* Qt denotes that Ffind_operation_coding_system is not yet called.  */
   coding_systems = Qt;
@@ -245,7 +252,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     /* If arguments are supplied, we may have to encode them.  */
     if (nargs >= 5)
       {
-       int must_encode = 0;
+       bool must_encode = 0;
        Lisp_Object coding_attrs;
 
        for (i = 4; i < nargs; i++)
@@ -444,12 +451,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
        }
       UNGCPRO;
       for (i = 4; i < nargs; i++)
-       new_argv[i - 3] = SDATA (args[i]);
+       new_argv[i - 3] = SSDATA (args[i]);
       new_argv[i - 3] = 0;
     }
   else
     new_argv[1] = 0;
-  new_argv[0] = SDATA (path);
+  new_argv[0] = SSDATA (path);
 
 #ifdef MSDOS /* MW, July 1993 */
 
@@ -478,51 +485,36 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     }
   else
     outfilefd = fd_output;
-  fd[0] = filefd;
-  fd[1] = outfilefd;
+  fd0 = filefd;
+  fd1 = outfilefd;
 #endif /* MSDOS */
 
   if (INTEGERP (buffer))
-    fd[1] = emacs_open (NULL_DEVICE, O_WRONLY, 0), fd[0] = -1;
+    {
+      fd0 = -1;
+      fd1 = emacs_open (NULL_DEVICE, O_WRONLY, 0);
+    }
   else
     {
 #ifndef MSDOS
-      errno = 0;
+      int fd[2];
       if (pipe (fd) == -1)
        {
+         int pipe_errno = errno;
          emacs_close (filefd);
+         errno = pipe_errno;
          report_file_error ("Creating process pipe", Qnil);
        }
+      fd0 = fd[0];
+      fd1 = fd[1];
 #endif
     }
 
   {
-    /* child_setup must clobber environ in systems with true vfork.
-       Protect it from permanent change.  */
-    register char **save_environ = environ;
-    register int fd1 = fd[1];
     int fd_error = fd1;
-#ifdef HAVE_WORKING_VFORK
-    sigset_t procmask;
-    sigset_t blocked;
-    struct sigaction sigpipe_action;
-#endif
 
     if (fd_output >= 0)
       fd1 = fd_output;
-#if 0  /* Some systems don't have sigblock.  */
-    mask = sigblock (sigmask (SIGCHLD));
-#endif
-
-    /* Record that we're about to create a synchronous process.  */
-    synch_process_alive = 1;
-
-    /* These vars record information from process termination.
-       Clear them now before process can possibly terminate,
-       to avoid timing error if process terminates soon.  */
-    synch_process_death = 0;
-    synch_process_retcode = 0;
-    synch_process_termsig = 0;
 
     if (NILP (error_file))
       fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0);
@@ -540,8 +532,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
     if (fd_error < 0)
       {
        emacs_close (filefd);
-       if (fd[0] != filefd)
-         emacs_close (fd[0]);
+       if (fd0 != filefd)
+         emacs_close (fd0);
        if (fd1 >= 0)
          emacs_close (fd1);
 #ifdef MSDOS
@@ -556,31 +548,28 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
 #ifdef MSDOS /* MW, July 1993 */
     /* Note that on MSDOS `child_setup' actually returns the child process
-       exit status, not its PID, so we assign it to `synch_process_retcode'
-       below.  */
-    pid = child_setup (filefd, outfilefd, fd_error, (char **) new_argv,
-                      0, current_dir);
-
-    /* Record that the synchronous process exited and note its
-       termination status.  */
-    synch_process_alive = 0;
-    synch_process_retcode = pid;
-    if (synch_process_retcode < 0)  /* means it couldn't be exec'ed */
-      {
-       synchronize_system_messages_locale ();
-       synch_process_death = strerror (errno);
-      }
+       exit status, not its PID, so assign it to status below.  */
+    pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir);
+    child_errno = errno;
 
     emacs_close (outfilefd);
     if (fd_error != outfilefd)
       emacs_close (fd_error);
+    if (pid < 0)
+      {
+       synchronize_system_messages_locale ();
+       return
+         code_convert_string_norecord (build_string (strerror (child_errno)),
+                                       Vlocale_coding_system, 0);
+      }
+    status = pid;
     fd1 = -1; /* No harm in closing that one!  */
     if (tempfile)
       {
        /* Since CRLF is converted to LF within `decode_coding', we
           can always open a file with binary mode.  */
-       fd[0] = emacs_open (tempfile, O_RDONLY | O_BINARY, 0);
-       if (fd[0] < 0)
+       fd0 = emacs_open (tempfile, O_RDONLY | O_BINARY, 0);
+       if (fd0 < 0)
          {
            unlink (tempfile);
            emacs_close (filefd);
@@ -589,97 +578,102 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          }
       }
     else
-      fd[0] = -1; /* We are not going to read from tempfile.   */
-#else /* not MSDOS */
-#ifdef WINDOWSNT
-    pid = child_setup (filefd, fd1, fd_error, (char **) new_argv,
-                      0, current_dir);
-#else  /* not WINDOWSNT */
+      fd0 = -1; /* We are not going to read from tempfile.   */
+#endif /* MSDOS */
 
-#ifdef HAVE_WORKING_VFORK
-    /* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal',
-       this sets the parent's signal handlers as well as the child's.
-       So delay all interrupts whose handlers the child might munge,
-       and record the current handlers so they can be restored later.  */
-    sigemptyset (&blocked);
-    sigaddset (&blocked, SIGPIPE);
-    sigaction (SIGPIPE, 0, &sigpipe_action);
-    pthread_sigmask (SIG_BLOCK, &blocked, &procmask);
-#endif
+    /* Do the unwind-protect now, even though the pid is not known, so
+       that no storage allocation is done in the critical section.
+       The actual PID will be filled in during the critical section.  */
+    synch_process_pid = 0;
+    synch_process_fd = fd0;
+
+#ifdef MSDOS
+    /* MSDOS needs different cleanup information.  */
+    record_unwind_protect (call_process_cleanup,
+                          Fcons (Fcurrent_buffer (),
+                                 build_string (tempfile ? tempfile : "")));
+#else
+    record_unwind_protect (call_process_cleanup, Fcurrent_buffer ());
 
-    BLOCK_INPUT;
+    block_input ();
+    block_child_signal ();
+
+#ifdef WINDOWSNT
+    pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir);
+#else  /* not WINDOWSNT */
 
     /* vfork, and prevent local vars from being clobbered by the vfork.  */
     {
       Lisp_Object volatile buffer_volatile = buffer;
       Lisp_Object volatile coding_systems_volatile = coding_systems;
       Lisp_Object volatile current_dir_volatile = current_dir;
-      int volatile display_p_volatile = display_p;
+      bool volatile display_p_volatile = display_p;
+      bool volatile output_to_buffer_volatile = output_to_buffer;
+      bool volatile sa_must_free_volatile = sa_must_free;
       int volatile fd1_volatile = fd1;
       int volatile fd_error_volatile = fd_error;
       int volatile fd_output_volatile = fd_output;
-      int volatile output_to_buffer_volatile = output_to_buffer;
-      int volatile sa_must_free_volatile = sa_must_free;
+      int volatile filefd_volatile = filefd;
+      ptrdiff_t volatile count_volatile = count;
       ptrdiff_t volatile sa_count_volatile = sa_count;
-      unsigned char const **volatile new_argv_volatile = new_argv;
+      char **volatile new_argv_volatile = new_argv;
 
       pid = vfork ();
+      child_errno = errno;
 
       buffer = buffer_volatile;
       coding_systems = coding_systems_volatile;
       current_dir = current_dir_volatile;
       display_p = display_p_volatile;
+      output_to_buffer = output_to_buffer_volatile;
+      sa_must_free = sa_must_free_volatile;
       fd1 = fd1_volatile;
       fd_error = fd_error_volatile;
       fd_output = fd_output_volatile;
-      output_to_buffer = output_to_buffer_volatile;
-      sa_must_free = sa_must_free_volatile;
+      filefd = filefd_volatile;
+      count = count_volatile;
       sa_count = sa_count_volatile;
       new_argv = new_argv_volatile;
+
+      fd0 = synch_process_fd;
     }
 
     if (pid == 0)
       {
-       if (fd[0] >= 0)
-         emacs_close (fd[0]);
-#ifdef HAVE_SETSID
+       unblock_child_signal ();
+
+       if (fd0 >= 0)
+         emacs_close (fd0);
+
        setsid ();
-#endif
-#if defined (USG)
-       setpgrp ();
-#else
-       setpgrp (pid, pid);
-#endif /* USG */
 
-       /* GConf causes us to ignore SIGPIPE, make sure it is restored
-          in the child.  */
+       /* Emacs ignores SIGPIPE, but the child should not.  */
        signal (SIGPIPE, SIG_DFL);
-#ifdef HAVE_WORKING_VFORK
-       pthread_sigmask (SIG_SETMASK, &procmask, 0);
-#endif
 
-       child_setup (filefd, fd1, fd_error, (char **) new_argv,
-                    0, current_dir);
+       child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir);
       }
 
-    UNBLOCK_INPUT;
+#endif /* not WINDOWSNT */
 
-#ifdef HAVE_WORKING_VFORK
-    /* Restore the signal state.  */
-    sigaction (SIGPIPE, &sigpipe_action, 0);
-    pthread_sigmask (SIG_SETMASK, &procmask, 0);
-#endif
+    child_errno = errno;
 
-#endif /* not WINDOWSNT */
+    if (0 < pid)
+      {
+       if (INTEGERP (buffer))
+         record_deleted_pid (pid);
+       else
+         synch_process_pid = pid;
+      }
+
+    unblock_child_signal ();
+    unblock_input ();
 
     /* The MSDOS case did this already.  */
     if (fd_error >= 0)
       emacs_close (fd_error);
 #endif /* not MSDOS */
 
-    environ = save_environ;
-
-    /* Close most of our fd's, but not fd[0]
+    /* Close most of our file descriptors, but not fd0
        since we will use that to read input from.  */
     emacs_close (filefd);
     if (fd_output >= 0)
@@ -690,31 +684,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
   if (pid < 0)
     {
-      if (fd[0] >= 0)
-       emacs_close (fd[0]);
+      errno = child_errno;
       report_file_error ("Doing vfork", Qnil);
     }
 
   if (INTEGERP (buffer))
-    {
-      if (fd[0] >= 0)
-       emacs_close (fd[0]);
-      return Qnil;
-    }
-
-  /* Enable sending signal if user quits below.  */
-  call_process_exited = 0;
-
-#if defined (MSDOS)
-  /* MSDOS needs different cleanup information.  */
-  cleanup_info_tail = build_string (tempfile ? tempfile : "");
-#else
-  cleanup_info_tail = INTEGER_TO_CONS (pid);
-#endif /* not MSDOS */
-  record_unwind_protect (call_process_cleanup,
-                        Fcons (Fcurrent_buffer (),
-                               Fcons (INTEGER_TO_CONS (fd[0]),
-                                      cleanup_info_tail)));
+    return unbind_to (count, Qnil);
 
   if (BUFFERP (buffer))
     Fset_buffer (buffer);
@@ -770,11 +745,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
   if (output_to_buffer)
     {
-      register int nread;
-      int first = 1;
+      enum { CALLPROC_BUFFER_SIZE_MIN = 16 * 1024 };
+      enum { CALLPROC_BUFFER_SIZE_MAX = 4 * CALLPROC_BUFFER_SIZE_MIN };
+      char buf[CALLPROC_BUFFER_SIZE_MAX];
+      int bufsize = CALLPROC_BUFFER_SIZE_MIN;
+      int nread;
+      bool first = 1;
       EMACS_INT total_read = 0;
       int carryover = 0;
-      int display_on_the_fly = display_p;
+      bool display_on_the_fly = display_p;
       struct coding_system saved_coding;
 
       saved_coding = process_coding;
@@ -786,7 +765,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
          nread = carryover;
          while (nread < bufsize - 1024)
            {
-             int this_read = emacs_read (fd[0], buf + nread,
+             int this_read = emacs_read (fd0, buf + nread,
                                          bufsize - nread);
 
              if (this_read < 0)
@@ -897,38 +876,34 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS)  */)
 
 #ifndef MSDOS
   /* Wait for it to terminate, unless it already has.  */
-  if (output_to_buffer)
-    wait_for_termination (pid);
-  else
-    interruptible_wait_for_termination (pid);
+  wait_for_termination (pid, &status, !output_to_buffer);
 #endif
 
   immediate_quit = 0;
 
   /* Don't kill any children that the subprocess may have left behind
      when exiting.  */
-  call_process_exited = 1;
+  synch_process_pid = 0;
 
   SAFE_FREE ();
   unbind_to (count, Qnil);
 
-  if (synch_process_termsig)
+  if (WIFSIGNALED (status))
     {
       const char *signame;
 
       synchronize_system_messages_locale ();
-      signame = strsignal (synch_process_termsig);
+      signame = strsignal (WTERMSIG (status));
 
       if (signame == 0)
        signame = "unknown";
 
-      synch_process_death = signame;
+      return code_convert_string_norecord (build_string (signame),
+                                          Vlocale_coding_system, 0);
     }
 
-  if (synch_process_death)
-    return code_convert_string_norecord (build_string (synch_process_death),
-                                        Vlocale_coding_system, 0);
-  return make_number (synch_process_retcode);
+  eassert (WIFEXITED (status));
+  return make_number (WEXITSTATUS (status));
 }
 \f
 static Lisp_Object
@@ -1002,17 +977,18 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
   {
     USE_SAFE_ALLOCA;
     Lisp_Object pattern = Fexpand_file_name (Vtemp_file_name_pattern, tmpdir);
-    char *tempfile = SAFE_ALLOCA (SBYTES (pattern) + 1);
-    memcpy (tempfile, SDATA (pattern), SBYTES (pattern) + 1);
+    Lisp_Object encoded_tem = ENCODE_FILE (pattern);
+    char *tempfile = SAFE_ALLOCA (SBYTES (encoded_tem) + 1);
+    memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1);
     coding_systems = Qt;
 
 #ifdef HAVE_MKSTEMP
     {
       int fd;
 
-      BLOCK_INPUT;
+      block_input ();
       fd = mkstemp (tempfile);
-      UNBLOCK_INPUT;
+      unblock_input ();
       if (fd == -1)
        report_file_error ("Failed to open temporary file",
                           Fcons (build_string (tempfile), Qnil));
@@ -1020,7 +996,15 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
        close (fd);
     }
 #else
+    errno = 0;
     mktemp (tempfile);
+    if (!*tempfile)
+      {
+       if (!errno)
+         errno = EEXIST;
+       report_file_error ("Failed to open temporary file using pattern",
+                          Fcons (pattern, Qnil));
+      }
 #endif
 
     filename_string = build_string (tempfile);
@@ -1090,7 +1074,7 @@ static char **
 add_env (char **env, char **new_env, char *string)
 {
   char **ep;
-  int ok = 1;
+  bool ok = 1;
   if (string == NULL)
     return new_env;
 
@@ -1126,12 +1110,7 @@ add_env (char **env, char **new_env, char *string)
    Initialize inferior's priority, pgrp, connected dir and environment.
    then exec another program based on new_argv.
 
-   This function may change environ for the superior process.
-   Therefore, the superior process must save and restore the value
-   of environ around the vfork and the call to this function.
-
-   SET_PGRP is nonzero if we should put the subprocess into a separate
-   process group.
+   If SET_PGRP, put the subprocess into a separate process group.
 
    CURRENT_DIR is an elisp string giving the path of the current
    directory the subprocess should have.  Since we can't really signal
@@ -1139,7 +1118,8 @@ add_env (char **env, char **new_env, char *string)
    executable directory by the parent.  */
 
 int
-child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, Lisp_Object current_dir)
+child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
+            Lisp_Object current_dir)
 {
   char **env;
   char *pwd_var;
@@ -1329,22 +1309,10 @@ child_setup (int in, int out, int err, register char **new_argv, int set_pgrp, L
   if (err != in && err != out)
     emacs_close (err);
 
-#if defined (USG)
-#ifndef SETPGRP_RELEASES_CTTY
-  setpgrp ();                  /* No arguments but equivalent in this case */
-#endif
-#else /* not USG */
-  setpgrp (pid, pid);
-#endif /* not USG */
-
-  /* setpgrp_of_tty is incorrect here; it uses input_fd.  */
+  setpgid (0, 0);
   tcsetpgrp (0, pid);
 
-  /* execvp does not accept an environment arg so the only way
-     to pass this environment is to set environ.  Our caller
-     is responsible for restoring the ambient value of environ.  */
-  environ = env;
-  execvp (new_argv[0], new_argv);
+  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]));
@@ -1372,16 +1340,7 @@ relocate_fd (int fd, int minfd)
     return fd;
   else
     {
-      int new;
-#ifdef F_DUPFD
-      new = fcntl (fd, F_DUPFD, minfd);
-#else
-      new = dup (fd);
-      if (new != -1)
-       /* Note that we hold the original FD open while we recurse,
-          to guarantee we'll get a new FD if we need it.  */
-       new = relocate_fd (new, minfd);
-#endif
+      int new = fcntl (fd, F_DUPFD, minfd);
       if (new == -1)
        {
          const char *message_1 = "Error while setting up child: ";
@@ -1398,7 +1357,7 @@ relocate_fd (int fd, int minfd)
 }
 #endif /* not WINDOWSNT */
 
-static int
+static bool
 getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value,
                   ptrdiff_t *valuelen, Lisp_Object env)
 {
@@ -1433,7 +1392,7 @@ getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value,
   return 0;
 }
 
-static int
+static bool
 getenv_internal (const char *var, ptrdiff_t varlen, char **value,
                 ptrdiff_t *valuelen, Lisp_Object frame)
 {
@@ -1513,29 +1472,24 @@ egetenv (const char *var)
 void
 init_callproc_1 (void)
 {
-  char *data_dir = egetenv ("EMACSDATA");
-  char *doc_dir = egetenv ("EMACSDOC");
 #ifdef HAVE_NS
   const char *etc_dir = ns_etc_directory ();
   const char *path_exec = ns_exec_path ();
 #endif
 
-  Vdata_directory
-    = Ffile_name_as_directory (build_string (data_dir ? data_dir
+  Vdata_directory = decode_env_path ("EMACSDATA",
 #ifdef HAVE_NS
-                                             : (etc_dir ? etc_dir : PATH_DATA)
-#else
-                                             : PATH_DATA
+                                             etc_dir ? etc_dir :
 #endif
-                                             ));
-  Vdoc_directory
-    = Ffile_name_as_directory (build_string (doc_dir ? doc_dir
+                                             PATH_DATA);
+  Vdata_directory = Ffile_name_as_directory (Fcar (Vdata_directory));
+
+  Vdoc_directory = decode_env_path ("EMACSDOC",
 #ifdef HAVE_NS
-                                             : (etc_dir ? etc_dir : PATH_DOC)
-#else
-                                             : PATH_DOC
+                                             etc_dir ? etc_dir :
 #endif
-                                             ));
+                                             PATH_DOC);
+  Vdoc_directory = Ffile_name_as_directory (Fcar (Vdoc_directory));
 
   /* Check the EMACSPATH environment variable, defaulting to the
      PATH_EXEC path from epaths.h.  */
@@ -1576,7 +1530,7 @@ init_callproc (void)
       Lisp_Object tem;
       tem = Fexpand_file_name (build_string ("lib-src"),
                               Vinstallation_directory);
-#ifndef DOS_NT
+#ifndef MSDOS
          /* MSDOS uses wrapped binaries, so don't do this.  */
       if (NILP (Fmember (tem, Vexec_path)))
        {
@@ -1593,7 +1547,7 @@ init_callproc (void)
        }
 
       Vexec_directory = Ffile_name_as_directory (tem);
-#endif /* not DOS_NT */
+#endif /* not MSDOS */
 
       /* Maybe use ../etc as well as ../lib-src.  */
       if (data_dir == 0)
@@ -1636,15 +1590,13 @@ init_callproc (void)
 #endif
     {
       tempdir = Fdirectory_file_name (Vexec_directory);
-      if (access (SSDATA (tempdir), 0) < 0)
-       dir_warning ("Warning: arch-dependent data dir (%s) does not exist.\n",
-                    Vexec_directory);
+      if (! file_accessible_directory_p (SSDATA (tempdir)))
+       dir_warning ("arch-dependent data dir", Vexec_directory);
     }
 
   tempdir = Fdirectory_file_name (Vdata_directory);
-  if (access (SSDATA (tempdir), 0) < 0)
-    dir_warning ("Warning: arch-independent data dir (%s) does not exist.\n",
-                Vdata_directory);
+  if (! file_accessible_directory_p (SSDATA (tempdir)))
+    dir_warning ("arch-independent data dir", Vdata_directory);
 
   sh = (char *) getenv ("SHELL");
   Vshell_file_name = build_string (sh ? sh : "/bin/sh");
@@ -1653,7 +1605,7 @@ init_callproc (void)
   Vshared_game_score_directory = Qnil;
 #else
   Vshared_game_score_directory = build_string (PATH_GAME);
-  if (NILP (Ffile_directory_p (Vshared_game_score_directory)))
+  if (NILP (Ffile_accessible_directory_p (Vshared_game_score_directory)))
     Vshared_game_score_directory = Qnil;
 #endif
 }