6c1aee8
diff -up patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.c
6c1aee8
--- patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute	2019-07-29 14:40:53.264464824 +0200
6c1aee8
+++ patch-2.7.6/lib/execute.c	2019-07-29 14:40:53.264464824 +0200
6c1aee8
@@ -0,0 +1,273 @@
6c1aee8
+/* Creation of autonomous subprocesses.
6c1aee8
+   Copyright (C) 2001-2004, 2006-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+
6c1aee8
+#include <config.h>
6c1aee8
+
6c1aee8
+/* Specification.  */
6c1aee8
+#include "execute.h"
6c1aee8
+
6c1aee8
+#include <errno.h>
6c1aee8
+#include <fcntl.h>
6c1aee8
+#include <stdbool.h>
6c1aee8
+#include <stdlib.h>
6c1aee8
+#include <signal.h>
6c1aee8
+#include <unistd.h>
6c1aee8
+
6c1aee8
+#include "error.h"
6c1aee8
+#include "fatal-signal.h"
6c1aee8
+#include "wait-process.h"
6c1aee8
+#include "gettext.h"
6c1aee8
+
6c1aee8
+#define _(str) gettext (str)
6c1aee8
+
6c1aee8
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
6c1aee8
+
6c1aee8
+/* Native Windows API.  */
6c1aee8
+# include <process.h>
6c1aee8
+# include "w32spawn.h"
6c1aee8
+
6c1aee8
+#else
6c1aee8
+
6c1aee8
+/* Unix API.  */
6c1aee8
+# include <spawn.h>
6c1aee8
+
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+#if defined EINTR && ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
6c1aee8
+
6c1aee8
+/* EINTR handling for close(), open().
6c1aee8
+   These functions can return -1/EINTR even though we don't have any
6c1aee8
+   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
6c1aee8
+
6c1aee8
+static int
6c1aee8
+nonintr_close (int fd)
6c1aee8
+{
6c1aee8
+  int retval;
6c1aee8
+
6c1aee8
+  do
6c1aee8
+    retval = close (fd);
6c1aee8
+  while (retval < 0 && errno == EINTR);
6c1aee8
+
6c1aee8
+  return retval;
6c1aee8
+}
6c1aee8
+#define close nonintr_close
6c1aee8
+
6c1aee8
+static int
6c1aee8
+nonintr_open (const char *pathname, int oflag, mode_t mode)
6c1aee8
+{
6c1aee8
+  int retval;
6c1aee8
+
6c1aee8
+  do
6c1aee8
+    retval = open (pathname, oflag, mode);
6c1aee8
+  while (retval < 0 && errno == EINTR);
6c1aee8
+
6c1aee8
+  return retval;
6c1aee8
+}
6c1aee8
+#undef open /* avoid warning on VMS */
6c1aee8
+#define open nonintr_open
6c1aee8
+
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Execute a command, optionally redirecting any of the three standard file
6c1aee8
+   descriptors to /dev/null.  Return its exit code.
6c1aee8
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
6c1aee8
+   return 127.
6c1aee8
+   If slave_process is true, the child process will be terminated when its
6c1aee8
+   creator receives a catchable fatal signal.  */
6c1aee8
+int
6c1aee8
+execute (const char *progname,
6c1aee8
+         const char *prog_path, char **prog_argv,
6c1aee8
+         bool ignore_sigpipe,
6c1aee8
+         bool null_stdin, bool null_stdout, bool null_stderr,
6c1aee8
+         bool slave_process, bool exit_on_error,
6c1aee8
+         int *termsigp)
6c1aee8
+{
6c1aee8
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
6c1aee8
+
6c1aee8
+  /* Native Windows API.  */
6c1aee8
+  int orig_stdin;
6c1aee8
+  int orig_stdout;
6c1aee8
+  int orig_stderr;
6c1aee8
+  int exitcode;
6c1aee8
+  int nullinfd;
6c1aee8
+  int nulloutfd;
6c1aee8
+
6c1aee8
+  /* FIXME: Need to free memory allocated by prepare_spawn.  */
6c1aee8
+  prog_argv = prepare_spawn (prog_argv);
6c1aee8
+
6c1aee8
+  /* Save standard file handles of parent process.  */
6c1aee8
+  if (null_stdin)
6c1aee8
+    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
6c1aee8
+  if (null_stdout)
6c1aee8
+    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
6c1aee8
+  if (null_stderr)
6c1aee8
+    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
6c1aee8
+  exitcode = -1;
6c1aee8
+
6c1aee8
+  /* Create standard file handles of child process.  */
6c1aee8
+  nullinfd = -1;
6c1aee8
+  nulloutfd = -1;
6c1aee8
+  if ((!null_stdin
6c1aee8
+       || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
6c1aee8
+           && (nullinfd == STDIN_FILENO
6c1aee8
+               || (dup2 (nullinfd, STDIN_FILENO) >= 0
6c1aee8
+                   && close (nullinfd) >= 0))))
6c1aee8
+      && (!(null_stdout || null_stderr)
6c1aee8
+          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
6c1aee8
+              && (!null_stdout
6c1aee8
+                  || nulloutfd == STDOUT_FILENO
6c1aee8
+                  || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
6c1aee8
+              && (!null_stderr
6c1aee8
+                  || nulloutfd == STDERR_FILENO
6c1aee8
+                  || dup2 (nulloutfd, STDERR_FILENO) >= 0)
6c1aee8
+              && ((null_stdout && nulloutfd == STDOUT_FILENO)
6c1aee8
+                  || (null_stderr && nulloutfd == STDERR_FILENO)
6c1aee8
+                  || close (nulloutfd) >= 0))))
6c1aee8
+    /* Use spawnvpe and pass the environment explicitly.  This is needed if
6c1aee8
+       the program has modified the environment using putenv() or [un]setenv().
6c1aee8
+       On Windows, programs have two environments, one in the "environment
6c1aee8
+       block" of the process and managed through SetEnvironmentVariable(), and
6c1aee8
+       one inside the process, in the location retrieved by the 'environ'
6c1aee8
+       macro.  When using spawnvp() without 'e', the child process inherits a
6c1aee8
+       copy of the environment block - ignoring the effects of putenv() and
6c1aee8
+       [un]setenv().  */
6c1aee8
+    {
6c1aee8
+      exitcode = spawnvpe (P_WAIT, prog_path, (const char **) prog_argv,
6c1aee8
+                           (const char **) environ);
6c1aee8
+      if (exitcode < 0 && errno == ENOEXEC)
6c1aee8
+        {
6c1aee8
+          /* prog is not a native executable.  Try to execute it as a
6c1aee8
+             shell script.  Note that prepare_spawn() has already prepended
6c1aee8
+             a hidden element "sh.exe" to prog_argv.  */
6c1aee8
+          --prog_argv;
6c1aee8
+          exitcode = spawnvpe (P_WAIT, prog_argv[0], (const char **) prog_argv,
6c1aee8
+                               (const char **) environ);
6c1aee8
+        }
6c1aee8
+    }
6c1aee8
+  if (nulloutfd >= 0)
6c1aee8
+    close (nulloutfd);
6c1aee8
+  if (nullinfd >= 0)
6c1aee8
+    close (nullinfd);
6c1aee8
+
6c1aee8
+  /* Restore standard file handles of parent process.  */
6c1aee8
+  if (null_stderr)
6c1aee8
+    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
6c1aee8
+  if (null_stdout)
6c1aee8
+    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
6c1aee8
+  if (null_stdin)
6c1aee8
+    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
6c1aee8
+
6c1aee8
+  if (termsigp != NULL)
6c1aee8
+    *termsigp = 0;
6c1aee8
+
6c1aee8
+  if (exitcode == -1)
6c1aee8
+    {
6c1aee8
+      if (exit_on_error || !null_stderr)
6c1aee8
+        error (exit_on_error ? EXIT_FAILURE : 0, errno,
6c1aee8
+               _("%s subprocess failed"), progname);
6c1aee8
+      return 127;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  return exitcode;
6c1aee8
+
6c1aee8
+#else
6c1aee8
+
6c1aee8
+  /* Unix API.  */
6c1aee8
+  /* Note about 127: Some errors during posix_spawnp() cause the function
6c1aee8
+     posix_spawnp() to return an error code; some other errors cause the
6c1aee8
+     subprocess to exit with return code 127.  It is implementation
6c1aee8
+     dependent which error is reported which way.  We treat both cases as
6c1aee8
+     equivalent.  */
6c1aee8
+  sigset_t blocked_signals;
6c1aee8
+  posix_spawn_file_actions_t actions;
6c1aee8
+  bool actions_allocated;
6c1aee8
+  posix_spawnattr_t attrs;
6c1aee8
+  bool attrs_allocated;
6c1aee8
+  int err;
6c1aee8
+  pid_t child;
6c1aee8
+
6c1aee8
+  if (slave_process)
6c1aee8
+    {
6c1aee8
+      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
6c1aee8
+      block_fatal_signals ();
6c1aee8
+    }
6c1aee8
+  actions_allocated = false;
6c1aee8
+  attrs_allocated = false;
6c1aee8
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
6c1aee8
+      || (actions_allocated = true,
6c1aee8
+          (null_stdin
6c1aee8
+            && (err = posix_spawn_file_actions_addopen (&actions,
6c1aee8
+                                                        STDIN_FILENO,
6c1aee8
+                                                        "/dev/null", O_RDONLY,
6c1aee8
+                                                        0))
6c1aee8
+               != 0)
6c1aee8
+          || (null_stdout
6c1aee8
+              && (err = posix_spawn_file_actions_addopen (&actions,
6c1aee8
+                                                          STDOUT_FILENO,
6c1aee8
+                                                          "/dev/null", O_RDWR,
6c1aee8
+                                                          0))
6c1aee8
+                 != 0)
6c1aee8
+          || (null_stderr
6c1aee8
+              && (err = posix_spawn_file_actions_addopen (&actions,
6c1aee8
+                                                          STDERR_FILENO,
6c1aee8
+                                                          "/dev/null", O_RDWR,
6c1aee8
+                                                          0))
6c1aee8
+                 != 0)
6c1aee8
+          || (slave_process
6c1aee8
+              && ((err = posix_spawnattr_init (&attrs)) != 0
6c1aee8
+                  || (attrs_allocated = true,
6c1aee8
+                      (err = posix_spawnattr_setsigmask (&attrs,
6c1aee8
+                                                         &blocked_signals))
6c1aee8
+                      != 0
6c1aee8
+                      || (err = posix_spawnattr_setflags (&attrs,
6c1aee8
+                                                        POSIX_SPAWN_SETSIGMASK))
6c1aee8
+                         != 0)))
6c1aee8
+          || (err = posix_spawnp (&child, prog_path, &actions,
6c1aee8
+                                  attrs_allocated ? &attrs : NULL, prog_argv,
6c1aee8
+                                  environ))
6c1aee8
+             != 0))
6c1aee8
+    {
6c1aee8
+      if (actions_allocated)
6c1aee8
+        posix_spawn_file_actions_destroy (&actions);
6c1aee8
+      if (attrs_allocated)
6c1aee8
+        posix_spawnattr_destroy (&attrs);
6c1aee8
+      if (slave_process)
6c1aee8
+        unblock_fatal_signals ();
6c1aee8
+      if (termsigp != NULL)
6c1aee8
+        *termsigp = 0;
6c1aee8
+      if (exit_on_error || !null_stderr)
6c1aee8
+        error (exit_on_error ? EXIT_FAILURE : 0, err,
6c1aee8
+               _("%s subprocess failed"), progname);
6c1aee8
+      return 127;
6c1aee8
+    }
6c1aee8
+  posix_spawn_file_actions_destroy (&actions);
6c1aee8
+  if (attrs_allocated)
6c1aee8
+    posix_spawnattr_destroy (&attrs);
6c1aee8
+  if (slave_process)
6c1aee8
+    {
6c1aee8
+      register_slave_subprocess (child);
6c1aee8
+      unblock_fatal_signals ();
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
6c1aee8
+                          slave_process, exit_on_error, termsigp);
6c1aee8
+
6c1aee8
+#endif
6c1aee8
+}
6c1aee8
diff -up patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.h
6c1aee8
--- patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute	2019-07-29 14:40:53.264464824 +0200
6c1aee8
+++ patch-2.7.6/lib/execute.h	2019-07-29 14:40:53.264464824 +0200
6c1aee8
@@ -0,0 +1,44 @@
6c1aee8
+/* Creation of autonomous subprocesses.
6c1aee8
+   Copyright (C) 2001-2003, 2008-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+#ifndef _EXECUTE_H
6c1aee8
+#define _EXECUTE_H
6c1aee8
+
6c1aee8
+#include <stdbool.h>
6c1aee8
+
6c1aee8
+/* Execute a command, optionally redirecting any of the three standard file
6c1aee8
+   descriptors to /dev/null.  Return its exit code.
6c1aee8
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
6c1aee8
+   return 127.
6c1aee8
+   If ignore_sigpipe is true, consider a subprocess termination due to SIGPIPE
6c1aee8
+   as equivalent to a success.  This is suitable for processes whose only
6c1aee8
+   purpose is to write to standard output.
6c1aee8
+   If slave_process is true, the child process will be terminated when its
6c1aee8
+   creator receives a catchable fatal signal.
6c1aee8
+   If termsigp is not NULL, *termsig will be set to the signal that terminated
6c1aee8
+   the subprocess (if supported by the platform: not on native Windows
6c1aee8
+   platforms), otherwise 0.
6c1aee8
+   It is recommended that no signal is blocked or ignored while execute()
6c1aee8
+   is called.  See pipe.h for the reason.  */
6c1aee8
+extern int execute (const char *progname,
6c1aee8
+                    const char *prog_path, char **prog_argv,
6c1aee8
+                    bool ignore_sigpipe,
6c1aee8
+                    bool null_stdin, bool null_stdout, bool null_stderr,
6c1aee8
+                    bool slave_process, bool exit_on_error,
6c1aee8
+                    int *termsigp);
6c1aee8
+
6c1aee8
+#endif /* _EXECUTE_H */
6c1aee8
diff -up patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.c
6c1aee8
--- patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute	2019-07-29 14:51:00.441882754 +0200
6c1aee8
+++ patch-2.7.6/lib/fatal-signal.c	2019-07-29 14:51:00.441882754 +0200
6c1aee8
@@ -0,0 +1,286 @@
6c1aee8
+/* Emergency actions in case of a fatal signal.
6c1aee8
+   Copyright (C) 2003-2004, 2006-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+
6c1aee8
+#include <config.h>
6c1aee8
+
6c1aee8
+/* Specification.  */
6c1aee8
+#include "fatal-signal.h"
6c1aee8
+
6c1aee8
+#include <stdbool.h>
6c1aee8
+#include <stdlib.h>
6c1aee8
+#include <signal.h>
6c1aee8
+#include <unistd.h>
6c1aee8
+
6c1aee8
+#include "sig-handler.h"
6c1aee8
+#include "xalloc.h"
6c1aee8
+
6c1aee8
+#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
6c1aee8
+
6c1aee8
+/* ========================================================================= */
6c1aee8
+
6c1aee8
+
6c1aee8
+/* The list of fatal signals.
6c1aee8
+   These are those signals whose default action is to terminate the process
6c1aee8
+   without a core dump, except
6c1aee8
+     SIGKILL - because it cannot be caught,
6c1aee8
+     SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
6c1aee8
+       often use them for their own purpose,
6c1aee8
+     SIGPROF SIGVTALRM - because they are used for profiling,
6c1aee8
+     SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
6c1aee8
+     SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
6c1aee8
+     SIGPWR - because it of too special use,
6c1aee8
+     SIGRTMIN...SIGRTMAX - because they are reserved for application use.
6c1aee8
+   plus
6c1aee8
+     SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM.  */
6c1aee8
+
6c1aee8
+static int fatal_signals[] =
6c1aee8
+  {
6c1aee8
+    /* ISO C 99 signals.  */
6c1aee8
+#ifdef SIGINT
6c1aee8
+    SIGINT,
6c1aee8
+#endif
6c1aee8
+#ifdef SIGTERM
6c1aee8
+    SIGTERM,
6c1aee8
+#endif
6c1aee8
+    /* POSIX:2001 signals.  */
6c1aee8
+#ifdef SIGHUP
6c1aee8
+    SIGHUP,
6c1aee8
+#endif
6c1aee8
+#ifdef SIGPIPE
6c1aee8
+    SIGPIPE,
6c1aee8
+#endif
6c1aee8
+    /* BSD signals.  */
6c1aee8
+#ifdef SIGXCPU
6c1aee8
+    SIGXCPU,
6c1aee8
+#endif
6c1aee8
+#ifdef SIGXFSZ
6c1aee8
+    SIGXFSZ,
6c1aee8
+#endif
6c1aee8
+    /* Native Windows signals.  */
6c1aee8
+#ifdef SIGBREAK
6c1aee8
+    SIGBREAK,
6c1aee8
+#endif
6c1aee8
+    0
6c1aee8
+  };
6c1aee8
+
6c1aee8
+#define num_fatal_signals (SIZEOF (fatal_signals) - 1)
6c1aee8
+
6c1aee8
+/* Eliminate signals whose signal handler is SIG_IGN.  */
6c1aee8
+
6c1aee8
+static void
6c1aee8
+init_fatal_signals (void)
6c1aee8
+{
6c1aee8
+  static bool fatal_signals_initialized = false;
6c1aee8
+  if (!fatal_signals_initialized)
6c1aee8
+    {
6c1aee8
+      size_t i;
6c1aee8
+
6c1aee8
+      for (i = 0; i < num_fatal_signals; i++)
6c1aee8
+        {
6c1aee8
+          struct sigaction action;
6c1aee8
+
6c1aee8
+          if (sigaction (fatal_signals[i], NULL, &action) >= 0
6c1aee8
+              && get_handler (&action) == SIG_IGN)
6c1aee8
+            fatal_signals[i] = -1;
6c1aee8
+        }
6c1aee8
+
6c1aee8
+      fatal_signals_initialized = true;
6c1aee8
+    }
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* ========================================================================= */
6c1aee8
+
6c1aee8
+
6c1aee8
+typedef void (*action_t) (void);
6c1aee8
+
6c1aee8
+/* Type of an entry in the actions array.
6c1aee8
+   The 'action' field is accessed from within the fatal_signal_handler(),
6c1aee8
+   therefore we mark it as 'volatile'.  */
6c1aee8
+typedef struct
6c1aee8
+{
6c1aee8
+  volatile action_t action;
6c1aee8
+}
6c1aee8
+actions_entry_t;
6c1aee8
+
6c1aee8
+/* The registered cleanup actions.  */
6c1aee8
+static actions_entry_t static_actions[32];
6c1aee8
+static actions_entry_t * volatile actions = static_actions;
6c1aee8
+static sig_atomic_t volatile actions_count = 0;
6c1aee8
+static size_t actions_allocated = SIZEOF (static_actions);
6c1aee8
+
6c1aee8
+
6c1aee8
+/* The saved signal handlers.
6c1aee8
+   Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34.  */
6c1aee8
+static struct sigaction saved_sigactions[64];
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Uninstall the handlers.  */
6c1aee8
+static void
6c1aee8
+uninstall_handlers (void)
6c1aee8
+{
6c1aee8
+  size_t i;
6c1aee8
+
6c1aee8
+  for (i = 0; i < num_fatal_signals; i++)
6c1aee8
+    if (fatal_signals[i] >= 0)
6c1aee8
+      {
6c1aee8
+        int sig = fatal_signals[i];
6c1aee8
+        if (saved_sigactions[sig].sa_handler == SIG_IGN)
6c1aee8
+          saved_sigactions[sig].sa_handler = SIG_DFL;
6c1aee8
+        sigaction (sig, &saved_sigactions[sig], NULL);
6c1aee8
+      }
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* The signal handler.  It gets called asynchronously.  */
6c1aee8
+static void
6c1aee8
+fatal_signal_handler (int sig)
6c1aee8
+{
6c1aee8
+  for (;;)
6c1aee8
+    {
6c1aee8
+      /* Get the last registered cleanup action, in a reentrant way.  */
6c1aee8
+      action_t action;
6c1aee8
+      size_t n = actions_count;
6c1aee8
+      if (n == 0)
6c1aee8
+        break;
6c1aee8
+      n--;
6c1aee8
+      actions_count = n;
6c1aee8
+      action = actions[n].action;
6c1aee8
+      /* Execute the action.  */
6c1aee8
+      action ();
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  /* Now execute the signal's default action.
6c1aee8
+     If the signal being delivered was blocked, the re-raised signal would be
6c1aee8
+     delivered when this handler returns.  But the way we install this handler,
6c1aee8
+     no signal is blocked, and the re-raised signal is delivered already
6c1aee8
+     during raise().  */
6c1aee8
+  uninstall_handlers ();
6c1aee8
+  raise (sig);
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Install the handlers.  */
6c1aee8
+static void
6c1aee8
+install_handlers (void)
6c1aee8
+{
6c1aee8
+  size_t i;
6c1aee8
+  struct sigaction action;
6c1aee8
+
6c1aee8
+  action.sa_handler = &fatal_signal_handler;
6c1aee8
+  /* If we get a fatal signal while executing fatal_signal_handler, enter
6c1aee8
+     fatal_signal_handler recursively, since it is reentrant.  Hence no
6c1aee8
+     SA_RESETHAND.  */
6c1aee8
+  action.sa_flags = SA_NODEFER;
6c1aee8
+  sigemptyset (&action.sa_mask);
6c1aee8
+  for (i = 0; i < num_fatal_signals; i++)
6c1aee8
+    if (fatal_signals[i] >= 0)
6c1aee8
+      {
6c1aee8
+        int sig = fatal_signals[i];
6c1aee8
+
6c1aee8
+        if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0])))
6c1aee8
+          abort ();
6c1aee8
+        sigaction (sig, &action, &saved_sigactions[sig]);
6c1aee8
+      }
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Register a cleanup function to be executed when a catchable fatal signal
6c1aee8
+   occurs.  */
6c1aee8
+void
6c1aee8
+at_fatal_signal (action_t action)
6c1aee8
+{
6c1aee8
+  static bool cleanup_initialized = false;
6c1aee8
+  if (!cleanup_initialized)
6c1aee8
+    {
6c1aee8
+      init_fatal_signals ();
6c1aee8
+      install_handlers ();
6c1aee8
+      cleanup_initialized = true;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  if (actions_count == actions_allocated)
6c1aee8
+    {
6c1aee8
+      /* Extend the actions array.  Note that we cannot use xrealloc(),
6c1aee8
+         because then the cleanup() function could access an already
6c1aee8
+         deallocated array.  */
6c1aee8
+      actions_entry_t *old_actions = actions;
6c1aee8
+      size_t old_actions_allocated = actions_allocated;
6c1aee8
+      size_t new_actions_allocated = 2 * actions_allocated;
6c1aee8
+      actions_entry_t *new_actions =
6c1aee8
+        XNMALLOC (new_actions_allocated, actions_entry_t);
6c1aee8
+      size_t k;
6c1aee8
+
6c1aee8
+      /* Don't use memcpy() here, because memcpy takes non-volatile arguments
6c1aee8
+         and is therefore not guaranteed to complete all memory stores before
6c1aee8
+         the next statement.  */
6c1aee8
+      for (k = 0; k < old_actions_allocated; k++)
6c1aee8
+        new_actions[k] = old_actions[k];
6c1aee8
+      actions = new_actions;
6c1aee8
+      actions_allocated = new_actions_allocated;
6c1aee8
+      /* Now we can free the old actions array.  */
6c1aee8
+      if (old_actions != static_actions)
6c1aee8
+        free (old_actions);
6c1aee8
+    }
6c1aee8
+  /* The two uses of 'volatile' in the types above (and ISO C 99 section
6c1aee8
+     5.1.2.3.(5)) ensure that we increment the actions_count only after
6c1aee8
+     the new action has been written to the memory location
6c1aee8
+     actions[actions_count].  */
6c1aee8
+  actions[actions_count].action = action;
6c1aee8
+  actions_count++;
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* ========================================================================= */
6c1aee8
+
6c1aee8
+
6c1aee8
+static sigset_t fatal_signal_set;
6c1aee8
+
6c1aee8
+static void
6c1aee8
+init_fatal_signal_set (void)
6c1aee8
+{
6c1aee8
+  static bool fatal_signal_set_initialized = false;
6c1aee8
+  if (!fatal_signal_set_initialized)
6c1aee8
+    {
6c1aee8
+      size_t i;
6c1aee8
+
6c1aee8
+      init_fatal_signals ();
6c1aee8
+
6c1aee8
+      sigemptyset (&fatal_signal_set);
6c1aee8
+      for (i = 0; i < num_fatal_signals; i++)
6c1aee8
+        if (fatal_signals[i] >= 0)
6c1aee8
+          sigaddset (&fatal_signal_set, fatal_signals[i]);
6c1aee8
+
6c1aee8
+      fatal_signal_set_initialized = true;
6c1aee8
+    }
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Temporarily delay the catchable fatal signals.  */
6c1aee8
+void
6c1aee8
+block_fatal_signals (void)
6c1aee8
+{
6c1aee8
+  init_fatal_signal_set ();
6c1aee8
+  sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Stop delaying the catchable fatal signals.  */
6c1aee8
+void
6c1aee8
+unblock_fatal_signals (void)
6c1aee8
+{
6c1aee8
+  init_fatal_signal_set ();
6c1aee8
+  sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
6c1aee8
+}
6c1aee8
diff -up patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.h
6c1aee8
--- patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute	2019-07-29 14:51:09.977920729 +0200
6c1aee8
+++ patch-2.7.6/lib/fatal-signal.h	2019-07-29 14:51:09.977920729 +0200
6c1aee8
@@ -0,0 +1,76 @@
6c1aee8
+/* Emergency actions in case of a fatal signal.
6c1aee8
+   Copyright (C) 2003-2004, 2009-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+
6c1aee8
+#ifdef __cplusplus
6c1aee8
+extern "C" {
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+/* It is often useful to do some cleanup action when a usually fatal signal
6c1aee8
+   terminates the process, like removing a temporary file or killing a
6c1aee8
+   subprocess that may be stuck waiting for a device, pipe or network input.
6c1aee8
+   Such signals are SIGHUP, SIGINT, SIGPIPE, SIGTERM, and possibly others.
6c1aee8
+   The limitation of this facility is that it cannot work for SIGKILL.
6c1aee8
+
6c1aee8
+   Signals with a SIG_IGN handler are considered to be non-fatal.  The
6c1aee8
+   functions in this file assume that when a SIG_IGN handler is installed
6c1aee8
+   for a signal, it was installed before any functions in this file were
6c1aee8
+   called and it stays so for the whole lifetime of the process.  */
6c1aee8
+
6c1aee8
+/* Register a cleanup function to be executed when a catchable fatal signal
6c1aee8
+   occurs.
6c1aee8
+
6c1aee8
+   Restrictions for the cleanup function:
6c1aee8
+     - The cleanup function can do all kinds of system calls.
6c1aee8
+     - It can also access application dependent memory locations and data
6c1aee8
+       structures provided they are in a consistent state. One way to ensure
6c1aee8
+       this is through block_fatal_signals()/unblock_fatal_signals(), see
6c1aee8
+       below.  Another - more tricky - way to ensure this is the careful use
6c1aee8
+       of 'volatile'.
6c1aee8
+   However,
6c1aee8
+     - malloc() and similarly complex facilities are not safe to be called
6c1aee8
+       because they are not guaranteed to be in a consistent state.
6c1aee8
+     - Also, the cleanup function must not block the catchable fatal signals
6c1aee8
+       and leave them blocked upon return.
6c1aee8
+
6c1aee8
+   The cleanup function is executed asynchronously.  It is unspecified
6c1aee8
+   whether during its execution the catchable fatal signals are blocked
6c1aee8
+   or not.  */
6c1aee8
+extern void at_fatal_signal (void (*function) (void));
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Sometimes it is necessary to block the usually fatal signals while the
6c1aee8
+   data structures being accessed by the cleanup action are being built or
6c1aee8
+   reorganized.  This is the case, for example, when a temporary file or
6c1aee8
+   directory is created through mkstemp() or mkdtemp(), because these
6c1aee8
+   functions create the temporary file or directory _before_ returning its
6c1aee8
+   name to the application.  */
6c1aee8
+
6c1aee8
+/* Temporarily delay the catchable fatal signals.
6c1aee8
+   The signals will be blocked (= delayed) until the next call to
6c1aee8
+   unblock_fatal_signals().  If the signals are already blocked, a further
6c1aee8
+   call to block_fatal_signals() has no effect.  */
6c1aee8
+extern void block_fatal_signals (void);
6c1aee8
+
6c1aee8
+/* Stop delaying the catchable fatal signals.  */
6c1aee8
+extern void unblock_fatal_signals (void);
6c1aee8
+
6c1aee8
+
6c1aee8
+#ifdef __cplusplus
6c1aee8
+}
6c1aee8
+#endif
6c1aee8
diff -up patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute patch-2.7.6/lib/gnulib.mk
6c1aee8
--- patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute	2018-02-03 14:31:15.000000000 +0100
6c1aee8
+++ patch-2.7.6/lib/gnulib.mk	2019-07-29 14:49:33.437536285 +0200
6c1aee8
@@ -21,7 +21,7 @@
6c1aee8
 # the same distribution terms as the rest of that program.
6c1aee8
 #
6c1aee8
 # Generated by gnulib-tool.
6c1aee8
-# Reproduce by: gnulib-tool --import --local-dir=gl --lib=libpatch --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl argmatch backupfile clock-time diffseq dirname dup2 errno exitfail extensions faccessat fchmodat fchownat fcntl-h fstatat full-write getdate getopt-gnu gettime git-version-gen gitlog-to-changelog gnupload hash ignore-value intprops largefile linked-list maintainer-makefile malloc manywarnings memchr minmax mkdirat nstrftime openat progname quotearg readlinkat realloc renameat setenv signal size_max ssize_t stat-time stdbool stdlib symlinkat sys_stat tempname time unistd unlinkat update-copyright utimensat verror xalloc xlist xmemdup0
6c1aee8
+# Reproduce by: gnulib-tool --import --local-dir=gl --lib=libpatch --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl argmatch backupfile clock-time diffseq dirname dup2 errno execute exitfail extensions faccessat fchmodat fchownat fcntl-h fstatat full-write getdate getopt-gnu gettime git-version-gen gitlog-to-changelog gnupload hash ignore-value intprops largefile linked-list maintainer-makefile malloc manywarnings memchr minmax mkdirat nstrftime openat progname quotearg readlinkat realloc renameat setenv signal size_max ssize_t stat-time stdbool stdlib symlinkat sys_stat tempname time unistd unlinkat update-copyright utimensat verror xalloc xlist xmemdup0 wait-process fatal-signal
6c1aee8
 
6c1aee8
 
6c1aee8
 MOSTLYCLEANFILES += core *.stackdump
6c1aee8
@@ -378,6 +378,12 @@ EXTRA_libpatch_a_SOURCES += euidaccess.c
6c1aee8
 
6c1aee8
 ## end   gnulib module euidaccess
6c1aee8
 
6c1aee8
+## begin gnulib module execute
6c1aee8
+
6c1aee8
+libpatch_a_SOURCES += execute.h execute.c w32spawn.h
6c1aee8
+
6c1aee8
+## end   gnulib module execute
6c1aee8
+
6c1aee8
 ## begin gnulib module exitfail
6c1aee8
 
6c1aee8
 libpatch_a_SOURCES += exitfail.c
6c1aee8
@@ -2481,6 +2487,28 @@ libpatch_a_SOURCES += verror.h verror.c
6c1aee8
 
6c1aee8
 ## end   gnulib module verror
6c1aee8
 
6c1aee8
+## begin gnulib module wait-process
6c1aee8
+
6c1aee8
+libpatch_a_SOURCES += wait-process.h wait-process.c
6c1aee8
+
6c1aee8
+## end   gnulib module wait-process
6c1aee8
+
6c1aee8
+## begin gnulib module fatal-signal
6c1aee8
+
6c1aee8
+libpatch_a_SOURCES += fatal-signal.h fatal-signal.c
6c1aee8
+
6c1aee8
+## end   gnulib module fatal-signal
6c1aee8
+
6c1aee8
+## begin gnulib module sigaction
6c1aee8
+
6c1aee8
+libpatch_a_SOURCES += sig-handler.c
6c1aee8
+
6c1aee8
+EXTRA_DIST += sig-handler.h sigaction.c
6c1aee8
+
6c1aee8
+EXTRA_libpatch_a_SOURCES += sigaction.c
6c1aee8
+
6c1aee8
+## end   gnulib module sigaction
6c1aee8
+
6c1aee8
 ## begin gnulib module wchar
6c1aee8
 
6c1aee8
 BUILT_SOURCES += wchar.h
6c1aee8
@@ -2694,6 +2722,7 @@ EXTRA_libpatch_a_SOURCES += xmemdup0.c
6c1aee8
 
6c1aee8
 ## end   gnulib module xmemdup0
6c1aee8
 
6c1aee8
+
6c1aee8
 ## begin gnulib module xsize
6c1aee8
 
6c1aee8
 libpatch_a_SOURCES += xsize.h xsize.c
6c1aee8
diff -up patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sigaction.c
6c1aee8
--- patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute	2019-07-29 14:50:31.833768833 +0200
6c1aee8
+++ patch-2.7.6/lib/sigaction.c	2019-07-29 14:50:31.833768833 +0200
6c1aee8
@@ -0,0 +1,204 @@
6c1aee8
+/* POSIX compatible signal blocking.
6c1aee8
+   Copyright (C) 2008-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Eric Blake <ebb9@byu.net>, 2008.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+#include <config.h>
6c1aee8
+
6c1aee8
+/* Specification.  */
6c1aee8
+#include <signal.h>
6c1aee8
+
6c1aee8
+#include <errno.h>
6c1aee8
+#include <stdint.h>
6c1aee8
+#include <stdlib.h>
6c1aee8
+
6c1aee8
+/* This implementation of sigaction is tailored to native Windows behavior:
6c1aee8
+   signal() has SysV semantics (ie. the handler is uninstalled before
6c1aee8
+   it is invoked).  This is an inherent data race if an asynchronous
6c1aee8
+   signal is sent twice in a row before we can reinstall our handler,
6c1aee8
+   but there's nothing we can do about it.  Meanwhile, sigprocmask()
6c1aee8
+   is not present, and while we can use the gnulib replacement to
6c1aee8
+   provide critical sections, it too suffers from potential data races
6c1aee8
+   in the face of an ill-timed asynchronous signal.  And we compound
6c1aee8
+   the situation by reading static storage in a signal handler, which
6c1aee8
+   POSIX warns is not generically async-signal-safe.  Oh well.
6c1aee8
+
6c1aee8
+   Additionally:
6c1aee8
+     - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
6c1aee8
+       is not defined.
6c1aee8
+     - We don't implement SA_ONSTACK, because sigaltstack() is not present.
6c1aee8
+     - We ignore SA_RESTART, because blocking native Windows API calls are
6c1aee8
+       not interrupted anyway when an asynchronous signal occurs, and the
6c1aee8
+       MSVCRT runtime never sets errno to EINTR.
6c1aee8
+     - We don't implement SA_SIGINFO because it is impossible to do so
6c1aee8
+       portably.
6c1aee8
+
6c1aee8
+   POSIX states that an application should not mix signal() and
6c1aee8
+   sigaction().  We support the use of signal() within the gnulib
6c1aee8
+   sigprocmask() substitute, but all other application code linked
6c1aee8
+   with this module should stick with only sigaction().  */
6c1aee8
+
6c1aee8
+/* Check some of our assumptions.  */
6c1aee8
+#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
6c1aee8
+# error "Revisit the assumptions made in the sigaction module"
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* Out-of-range substitutes make a good fallback for uncatchable
6c1aee8
+   signals.  */
6c1aee8
+#ifndef SIGKILL
6c1aee8
+# define SIGKILL (-1)
6c1aee8
+#endif
6c1aee8
+#ifndef SIGSTOP
6c1aee8
+# define SIGSTOP (-1)
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
6c1aee8
+   for the signal SIGABRT.  Only one signal handler is stored for both
6c1aee8
+   SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
6c1aee8
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
6c1aee8
+# undef SIGABRT_COMPAT
6c1aee8
+# define SIGABRT_COMPAT 6
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* A signal handler.  */
6c1aee8
+typedef void (*handler_t) (int signal);
6c1aee8
+
6c1aee8
+/* Set of current actions.  If sa_handler for an entry is NULL, then
6c1aee8
+   that signal is not currently handled by the sigaction handler.  */
6c1aee8
+static struct sigaction volatile action_array[NSIG] /* = 0 */;
6c1aee8
+
6c1aee8
+/* Signal handler that is installed for signals.  */
6c1aee8
+static void
6c1aee8
+sigaction_handler (int sig)
6c1aee8
+{
6c1aee8
+  handler_t handler;
6c1aee8
+  sigset_t mask;
6c1aee8
+  sigset_t oldmask;
6c1aee8
+  int saved_errno = errno;
6c1aee8
+  if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
6c1aee8
+    {
6c1aee8
+      /* Unexpected situation; be careful to avoid recursive abort.  */
6c1aee8
+      if (sig == SIGABRT)
6c1aee8
+        signal (SIGABRT, SIG_DFL);
6c1aee8
+      abort ();
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  /* Reinstall the signal handler when required; otherwise update the
6c1aee8
+     bookkeeping so that the user's handler may call sigaction and get
6c1aee8
+     accurate results.  We know the signal isn't currently blocked, or
6c1aee8
+     we wouldn't be in its handler, therefore we know that we are not
6c1aee8
+     interrupting a sigaction() call.  There is a race where any
6c1aee8
+     asynchronous instance of the same signal occurring before we
6c1aee8
+     reinstall the handler will trigger the default handler; oh
6c1aee8
+     well.  */
6c1aee8
+  handler = action_array[sig].sa_handler;
6c1aee8
+  if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
6c1aee8
+    signal (sig, sigaction_handler);
6c1aee8
+  else
6c1aee8
+    action_array[sig].sa_handler = NULL;
6c1aee8
+
6c1aee8
+  /* Block appropriate signals.  */
6c1aee8
+  mask = action_array[sig].sa_mask;
6c1aee8
+  if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
6c1aee8
+    sigaddset (&mask, sig);
6c1aee8
+  sigprocmask (SIG_BLOCK, &mask, &oldmask);
6c1aee8
+
6c1aee8
+  /* Invoke the user's handler, then restore prior mask.  */
6c1aee8
+  errno = saved_errno;
6c1aee8
+  handler (sig);
6c1aee8
+  saved_errno = errno;
6c1aee8
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
6c1aee8
+  errno = saved_errno;
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Change and/or query the action that will be taken on delivery of
6c1aee8
+   signal SIG.  If not NULL, ACT describes the new behavior.  If not
6c1aee8
+   NULL, OACT is set to the prior behavior.  Return 0 on success, or
6c1aee8
+   set errno and return -1 on failure.  */
6c1aee8
+int
6c1aee8
+sigaction (int sig, const struct sigaction *restrict act,
6c1aee8
+           struct sigaction *restrict oact)
6c1aee8
+{
6c1aee8
+  sigset_t mask;
6c1aee8
+  sigset_t oldmask;
6c1aee8
+  int saved_errno;
6c1aee8
+
6c1aee8
+  if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
6c1aee8
+      || (act && act->sa_handler == SIG_ERR))
6c1aee8
+    {
6c1aee8
+      errno = EINVAL;
6c1aee8
+      return -1;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+#ifdef SIGABRT_COMPAT
6c1aee8
+  if (sig == SIGABRT_COMPAT)
6c1aee8
+    sig = SIGABRT;
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+  /* POSIX requires sigaction() to be async-signal-safe.  In other
6c1aee8
+     words, if an asynchronous signal can occur while we are anywhere
6c1aee8
+     inside this function, the user's handler could then call
6c1aee8
+     sigaction() recursively and expect consistent results.  We meet
6c1aee8
+     this rule by using sigprocmask to block all signals before
6c1aee8
+     modifying any data structure that could be read from a signal
6c1aee8
+     handler; this works since we know that the gnulib sigprocmask
6c1aee8
+     replacement does not try to use sigaction() from its handler.  */
6c1aee8
+  if (!act && !oact)
6c1aee8
+    return 0;
6c1aee8
+  sigfillset (&mask);
6c1aee8
+  sigprocmask (SIG_BLOCK, &mask, &oldmask);
6c1aee8
+  if (oact)
6c1aee8
+    {
6c1aee8
+      if (action_array[sig].sa_handler)
6c1aee8
+        *oact = action_array[sig];
6c1aee8
+      else
6c1aee8
+        {
6c1aee8
+          /* Safe to change the handler at will here, since all
6c1aee8
+             signals are currently blocked.  */
6c1aee8
+          oact->sa_handler = signal (sig, SIG_DFL);
6c1aee8
+          if (oact->sa_handler == SIG_ERR)
6c1aee8
+            goto failure;
6c1aee8
+          signal (sig, oact->sa_handler);
6c1aee8
+          oact->sa_flags = SA_RESETHAND | SA_NODEFER;
6c1aee8
+          sigemptyset (&oact->sa_mask);
6c1aee8
+        }
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  if (act)
6c1aee8
+    {
6c1aee8
+      /* Safe to install the handler before updating action_array,
6c1aee8
+         since all signals are currently blocked.  */
6c1aee8
+      if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
6c1aee8
+        {
6c1aee8
+          if (signal (sig, act->sa_handler) == SIG_ERR)
6c1aee8
+            goto failure;
6c1aee8
+          action_array[sig].sa_handler = NULL;
6c1aee8
+        }
6c1aee8
+      else
6c1aee8
+        {
6c1aee8
+          if (signal (sig, sigaction_handler) == SIG_ERR)
6c1aee8
+            goto failure;
6c1aee8
+          action_array[sig] = *act;
6c1aee8
+        }
6c1aee8
+    }
6c1aee8
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
6c1aee8
+  return 0;
6c1aee8
+
6c1aee8
+ failure:
6c1aee8
+  saved_errno = errno;
6c1aee8
+  sigprocmask (SIG_SETMASK, &oldmask, NULL);
6c1aee8
+  errno = saved_errno;
6c1aee8
+  return -1;
6c1aee8
+}
6c1aee8
diff -up patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.c
6c1aee8
--- patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute	2019-07-29 14:50:17.265710820 +0200
6c1aee8
+++ patch-2.7.6/lib/sig-handler.c	2019-07-29 14:48:19.707242671 +0200
6c1aee8
@@ -0,0 +1,3 @@
6c1aee8
+#include <config.h>
6c1aee8
+#define SIG_HANDLER_INLINE _GL_EXTERN_INLINE
6c1aee8
+#include "sig-handler.h"
6c1aee8
diff -up patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.h
6c1aee8
--- patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute	2019-07-29 14:50:12.249690845 +0200
6c1aee8
+++ patch-2.7.6/lib/sig-handler.h	2019-07-29 14:48:23.099256180 +0200
6c1aee8
@@ -0,0 +1,54 @@
6c1aee8
+/* Convenience declarations when working with <signal.h>.
6c1aee8
+
6c1aee8
+   Copyright (C) 2008-2018 Free Software Foundation, Inc.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+#ifndef _GL_SIG_HANDLER_H
6c1aee8
+#define _GL_SIG_HANDLER_H
6c1aee8
+
6c1aee8
+#include <signal.h>
6c1aee8
+
6c1aee8
+#ifndef _GL_INLINE_HEADER_BEGIN
6c1aee8
+ #error "Please include config.h first."
6c1aee8
+#endif
6c1aee8
+_GL_INLINE_HEADER_BEGIN
6c1aee8
+#ifndef SIG_HANDLER_INLINE
6c1aee8
+# define SIG_HANDLER_INLINE _GL_INLINE
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* Convenience type when working with signal handlers.  */
6c1aee8
+typedef void (*sa_handler_t) (int);
6c1aee8
+
6c1aee8
+/* Return the handler of a signal, as a sa_handler_t value regardless
6c1aee8
+   of its true type.  The resulting function can be compared to
6c1aee8
+   special values like SIG_IGN but it is not portable to call it.  */
6c1aee8
+SIG_HANDLER_INLINE sa_handler_t _GL_ATTRIBUTE_PURE
6c1aee8
+get_handler (struct sigaction const *a)
6c1aee8
+{
6c1aee8
+#ifdef SA_SIGINFO
6c1aee8
+  /* POSIX says that special values like SIG_IGN can only occur when
6c1aee8
+     action.sa_flags does not contain SA_SIGINFO.  But in Linux 2.4,
6c1aee8
+     for example, sa_sigaction and sa_handler are aliases and a signal
6c1aee8
+     is ignored if sa_sigaction (after casting) equals SIG_IGN.  So
6c1aee8
+     use (and cast) sa_sigaction in that case.  */
6c1aee8
+  if (a->sa_flags & SA_SIGINFO)
6c1aee8
+    return (sa_handler_t) a->sa_sigaction;
6c1aee8
+#endif
6c1aee8
+  return a->sa_handler;
6c1aee8
+}
6c1aee8
+
6c1aee8
+_GL_INLINE_HEADER_END
6c1aee8
+
6c1aee8
+#endif /* _GL_SIG_HANDLER_H */
6c1aee8
diff -up patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/w32spawn.h
6c1aee8
--- patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute	2019-07-29 14:40:53.265464828 +0200
6c1aee8
+++ patch-2.7.6/lib/w32spawn.h	2019-07-29 14:40:53.265464828 +0200
6c1aee8
@@ -0,0 +1,233 @@
6c1aee8
+/* Auxiliary functions for the creation of subprocesses.  Native Windows API.
6c1aee8
+   Copyright (C) 2001, 2003-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+#ifndef __KLIBC__
6c1aee8
+/* Get declarations of the native Windows API functions.  */
6c1aee8
+# define WIN32_LEAN_AND_MEAN
6c1aee8
+# include <windows.h>
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* Get _open_osfhandle().  */
6c1aee8
+#include <io.h>
6c1aee8
+
6c1aee8
+#include <stdbool.h>
6c1aee8
+#include <string.h>
6c1aee8
+#include <unistd.h>
6c1aee8
+#include <errno.h>
6c1aee8
+
6c1aee8
+/* Get _get_osfhandle().  */
6c1aee8
+# if GNULIB_MSVC_NOTHROW
6c1aee8
+#  include "msvc-nothrow.h"
6c1aee8
+# else
6c1aee8
+#  include <io.h>
6c1aee8
+# endif
6c1aee8
+
6c1aee8
+#include "cloexec.h"
6c1aee8
+#include "xalloc.h"
6c1aee8
+
6c1aee8
+/* Duplicates a file handle, making the copy uninheritable.
6c1aee8
+   Returns -1 for a file handle that is equivalent to closed.  */
6c1aee8
+static int
6c1aee8
+dup_noinherit (int fd)
6c1aee8
+{
6c1aee8
+  fd = dup_cloexec (fd);
6c1aee8
+  if (fd < 0 && errno == EMFILE)
6c1aee8
+    error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
6c1aee8
+
6c1aee8
+  return fd;
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Returns a file descriptor equivalent to FD, except that the resulting file
6c1aee8
+   descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
6c1aee8
+   FD must be open and non-inheritable.  The result will be non-inheritable as
6c1aee8
+   well.
6c1aee8
+   If FD < 0, FD itself is returned.  */
6c1aee8
+static int
6c1aee8
+fd_safer_noinherit (int fd)
6c1aee8
+{
6c1aee8
+  if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
6c1aee8
+    {
6c1aee8
+      /* The recursion depth is at most 3.  */
6c1aee8
+      int nfd = fd_safer_noinherit (dup_noinherit (fd));
6c1aee8
+      int saved_errno = errno;
6c1aee8
+      close (fd);
6c1aee8
+      errno = saved_errno;
6c1aee8
+      return nfd;
6c1aee8
+    }
6c1aee8
+  return fd;
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Duplicates a file handle, making the copy uninheritable and ensuring the
6c1aee8
+   result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
6c1aee8
+   Returns -1 for a file handle that is equivalent to closed.  */
6c1aee8
+static int
6c1aee8
+dup_safer_noinherit (int fd)
6c1aee8
+{
6c1aee8
+  return fd_safer_noinherit (dup_noinherit (fd));
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD);  */
6c1aee8
+static void
6c1aee8
+undup_safer_noinherit (int tempfd, int origfd)
6c1aee8
+{
6c1aee8
+  if (tempfd >= 0)
6c1aee8
+    {
6c1aee8
+      if (dup2 (tempfd, origfd) < 0)
6c1aee8
+        error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"),
6c1aee8
+               origfd);
6c1aee8
+      close (tempfd);
6c1aee8
+    }
6c1aee8
+  else
6c1aee8
+    {
6c1aee8
+      /* origfd was closed or open to no handle at all.  Set it to a closed
6c1aee8
+         state.  This is (nearly) equivalent to the original state.  */
6c1aee8
+      close (origfd);
6c1aee8
+    }
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Prepares an argument vector before calling spawn().
6c1aee8
+   Note that spawn() does not by itself call the command interpreter
6c1aee8
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
6c1aee8
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
6c1aee8
+         GetVersionEx(&v);
6c1aee8
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
6c1aee8
+      }) ? "cmd.exe" : "command.com").
6c1aee8
+   Instead it simply concatenates the arguments, separated by ' ', and calls
6c1aee8
+   CreateProcess().  We must quote the arguments since Windows CreateProcess()
6c1aee8
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
6c1aee8
+   special way:
6c1aee8
+   - Space and tab are interpreted as delimiters. They are not treated as
6c1aee8
+     delimiters if they are surrounded by double quotes: "...".
6c1aee8
+   - Unescaped double quotes are removed from the input. Their only effect is
6c1aee8
+     that within double quotes, space and tab are treated like normal
6c1aee8
+     characters.
6c1aee8
+   - Backslashes not followed by double quotes are not special.
6c1aee8
+   - But 2*n+1 backslashes followed by a double quote become
6c1aee8
+     n backslashes followed by a double quote (n >= 0):
6c1aee8
+       \" -> "
6c1aee8
+       \\\" -> \"
6c1aee8
+       \\\\\" -> \\"
6c1aee8
+   - '*', '?' characters may get expanded through wildcard expansion in the
6c1aee8
+     callee: By default, in the callee, the initialization code before main()
6c1aee8
+     takes the result of GetCommandLine(), wildcard-expands it, and passes it
6c1aee8
+     to main(). The exceptions to this rule are:
6c1aee8
+       - programs that inspect GetCommandLine() and ignore argv,
6c1aee8
+       - mingw programs that have a global variable 'int _CRT_glob = 0;',
6c1aee8
+       - Cygwin programs, when invoked from a Cygwin program.
6c1aee8
+ */
6c1aee8
+#ifndef __KLIBC__
6c1aee8
+# define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?"
6c1aee8
+# define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
6c1aee8
+#else
6c1aee8
+# define SHELL_SPECIAL_CHARS ""
6c1aee8
+# define SHELL_SPACE_CHARS ""
6c1aee8
+#endif
6c1aee8
+static char **
6c1aee8
+prepare_spawn (char **argv)
6c1aee8
+{
6c1aee8
+  size_t argc;
6c1aee8
+  char **new_argv;
6c1aee8
+  size_t i;
6c1aee8
+
6c1aee8
+  /* Count number of arguments.  */
6c1aee8
+  for (argc = 0; argv[argc] != NULL; argc++)
6c1aee8
+    ;
6c1aee8
+
6c1aee8
+  /* Allocate new argument vector.  */
6c1aee8
+  new_argv = XNMALLOC (1 + argc + 1, char *);
6c1aee8
+
6c1aee8
+  /* Add an element upfront that can be used when argv[0] turns out to be a
6c1aee8
+     script, not a program.
6c1aee8
+     On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
6c1aee8
+     "sh.exe".  We have to omit the directory part and rely on the search in
6c1aee8
+     PATH, because the mingw "mount points" are not visible inside Windows
6c1aee8
+     CreateProcess().  */
6c1aee8
+  *new_argv++ = "sh.exe";
6c1aee8
+
6c1aee8
+  /* Put quoted arguments into the new argument vector.  */
6c1aee8
+  for (i = 0; i < argc; i++)
6c1aee8
+    {
6c1aee8
+      const char *string = argv[i];
6c1aee8
+
6c1aee8
+      if (string[0] == '\0')
6c1aee8
+        new_argv[i] = xstrdup ("\"\"");
6c1aee8
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
6c1aee8
+        {
6c1aee8
+          bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
6c1aee8
+          size_t length;
6c1aee8
+          unsigned int backslashes;
6c1aee8
+          const char *s;
6c1aee8
+          char *quoted_string;
6c1aee8
+          char *p;
6c1aee8
+
6c1aee8
+          length = 0;
6c1aee8
+          backslashes = 0;
6c1aee8
+          if (quote_around)
6c1aee8
+            length++;
6c1aee8
+          for (s = string; *s != '\0'; s++)
6c1aee8
+            {
6c1aee8
+              char c = *s;
6c1aee8
+              if (c == '"')
6c1aee8
+                length += backslashes + 1;
6c1aee8
+              length++;
6c1aee8
+              if (c == '\\')
6c1aee8
+                backslashes++;
6c1aee8
+              else
6c1aee8
+                backslashes = 0;
6c1aee8
+            }
6c1aee8
+          if (quote_around)
6c1aee8
+            length += backslashes + 1;
6c1aee8
+
6c1aee8
+          quoted_string = (char *) xmalloc (length + 1);
6c1aee8
+
6c1aee8
+          p = quoted_string;
6c1aee8
+          backslashes = 0;
6c1aee8
+          if (quote_around)
6c1aee8
+            *p++ = '"';
6c1aee8
+          for (s = string; *s != '\0'; s++)
6c1aee8
+            {
6c1aee8
+              char c = *s;
6c1aee8
+              if (c == '"')
6c1aee8
+                {
6c1aee8
+                  unsigned int j;
6c1aee8
+                  for (j = backslashes + 1; j > 0; j--)
6c1aee8
+                    *p++ = '\\';
6c1aee8
+                }
6c1aee8
+              *p++ = c;
6c1aee8
+              if (c == '\\')
6c1aee8
+                backslashes++;
6c1aee8
+              else
6c1aee8
+                backslashes = 0;
6c1aee8
+            }
6c1aee8
+          if (quote_around)
6c1aee8
+            {
6c1aee8
+              unsigned int j;
6c1aee8
+              for (j = backslashes; j > 0; j--)
6c1aee8
+                *p++ = '\\';
6c1aee8
+              *p++ = '"';
6c1aee8
+            }
6c1aee8
+          *p = '\0';
6c1aee8
+
6c1aee8
+          new_argv[i] = quoted_string;
6c1aee8
+        }
6c1aee8
+      else
6c1aee8
+        new_argv[i] = (char *) string;
6c1aee8
+    }
6c1aee8
+  new_argv[argc] = NULL;
6c1aee8
+
6c1aee8
+  return new_argv;
6c1aee8
+}
6c1aee8
diff -up patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.c
6c1aee8
--- patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute	2019-07-29 14:50:49.937840928 +0200
6c1aee8
+++ patch-2.7.6/lib/wait-process.c	2019-07-29 14:45:17.196515863 +0200
6c1aee8
@@ -0,0 +1,361 @@
6c1aee8
+/* Waiting for a subprocess to finish.
6c1aee8
+   Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+
6c1aee8
+#include <config.h>
6c1aee8
+
6c1aee8
+/* Specification.  */
6c1aee8
+#include "wait-process.h"
6c1aee8
+
6c1aee8
+#include <errno.h>
6c1aee8
+#include <stdlib.h>
6c1aee8
+#include <string.h>
6c1aee8
+#include <signal.h>
6c1aee8
+
6c1aee8
+#include <sys/types.h>
6c1aee8
+#include <sys/wait.h>
6c1aee8
+
6c1aee8
+#include "error.h"
6c1aee8
+#include "fatal-signal.h"
6c1aee8
+#include "xalloc.h"
6c1aee8
+#include "gettext.h"
6c1aee8
+
6c1aee8
+#define _(str) gettext (str)
6c1aee8
+
6c1aee8
+#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
6c1aee8
+
6c1aee8
+
6c1aee8
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
6c1aee8
+
6c1aee8
+# define WIN32_LEAN_AND_MEAN
6c1aee8
+# include <windows.h>
6c1aee8
+
6c1aee8
+/* The return value of spawnvp() is really a process handle as returned
6c1aee8
+   by CreateProcess().  Therefore we can kill it using TerminateProcess.  */
6c1aee8
+# define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig)
6c1aee8
+
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Type of an entry in the slaves array.
6c1aee8
+   The 'used' bit determines whether this entry is currently in use.
6c1aee8
+   (If pid_t was an atomic type like sig_atomic_t, we could just set the
6c1aee8
+   'child' field to 0 when unregistering a slave process, and wouldn't need
6c1aee8
+   the 'used' field.)
6c1aee8
+   The 'used' and 'child' fields are accessed from within the cleanup_slaves()
6c1aee8
+   action, therefore we mark them as 'volatile'.  */
6c1aee8
+typedef struct
6c1aee8
+{
6c1aee8
+  volatile sig_atomic_t used;
6c1aee8
+  volatile pid_t child;
6c1aee8
+}
6c1aee8
+slaves_entry_t;
6c1aee8
+
6c1aee8
+/* The registered slave subprocesses.  */
6c1aee8
+static slaves_entry_t static_slaves[32];
6c1aee8
+static slaves_entry_t * volatile slaves = static_slaves;
6c1aee8
+static sig_atomic_t volatile slaves_count = 0;
6c1aee8
+static size_t slaves_allocated = SIZEOF (static_slaves);
6c1aee8
+
6c1aee8
+/* The termination signal for slave subprocesses.
6c1aee8
+   2003-10-07:  Terminator becomes Governator.  */
6c1aee8
+#ifdef SIGHUP
6c1aee8
+# define TERMINATOR SIGHUP
6c1aee8
+#else
6c1aee8
+# define TERMINATOR SIGTERM
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+/* The cleanup action.  It gets called asynchronously.  */
6c1aee8
+static void
6c1aee8
+cleanup_slaves (void)
6c1aee8
+{
6c1aee8
+  for (;;)
6c1aee8
+    {
6c1aee8
+      /* Get the last registered slave.  */
6c1aee8
+      size_t n = slaves_count;
6c1aee8
+      if (n == 0)
6c1aee8
+        break;
6c1aee8
+      n--;
6c1aee8
+      slaves_count = n;
6c1aee8
+      /* Skip unused entries in the slaves array.  */
6c1aee8
+      if (slaves[n].used)
6c1aee8
+        {
6c1aee8
+          pid_t slave = slaves[n].child;
6c1aee8
+
6c1aee8
+          /* Kill the slave.  */
6c1aee8
+          kill (slave, TERMINATOR);
6c1aee8
+        }
6c1aee8
+    }
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Register a subprocess as being a slave process.  This means that the
6c1aee8
+   subprocess will be terminated when its creator receives a catchable fatal
6c1aee8
+   signal or exits normally.  Registration ends when wait_subprocess()
6c1aee8
+   notices that the subprocess has exited.  */
6c1aee8
+void
6c1aee8
+register_slave_subprocess (pid_t child)
6c1aee8
+{
6c1aee8
+  static bool cleanup_slaves_registered = false;
6c1aee8
+  if (!cleanup_slaves_registered)
6c1aee8
+    {
6c1aee8
+      atexit (cleanup_slaves);
6c1aee8
+      at_fatal_signal (cleanup_slaves);
6c1aee8
+      cleanup_slaves_registered = true;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  /* Try to store the new slave in an unused entry of the slaves array.  */
6c1aee8
+  {
6c1aee8
+    slaves_entry_t *s = slaves;
6c1aee8
+    slaves_entry_t *s_end = s + slaves_count;
6c1aee8
+
6c1aee8
+    for (; s < s_end; s++)
6c1aee8
+      if (!s->used)
6c1aee8
+        {
6c1aee8
+          /* The two uses of 'volatile' in the slaves_entry_t type above
6c1aee8
+             (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
6c1aee8
+             entry as used only after the child pid has been written to the
6c1aee8
+             memory location s->child.  */
6c1aee8
+          s->child = child;
6c1aee8
+          s->used = 1;
6c1aee8
+          return;
6c1aee8
+        }
6c1aee8
+  }
6c1aee8
+
6c1aee8
+  if (slaves_count == slaves_allocated)
6c1aee8
+    {
6c1aee8
+      /* Extend the slaves array.  Note that we cannot use xrealloc(),
6c1aee8
+         because then the cleanup_slaves() function could access an already
6c1aee8
+         deallocated array.  */
6c1aee8
+      slaves_entry_t *old_slaves = slaves;
6c1aee8
+      size_t new_slaves_allocated = 2 * slaves_allocated;
6c1aee8
+      slaves_entry_t *new_slaves =
6c1aee8
+        (slaves_entry_t *)
6c1aee8
+        malloc (new_slaves_allocated * sizeof (slaves_entry_t));
6c1aee8
+      if (new_slaves == NULL)
6c1aee8
+        {
6c1aee8
+          /* xalloc_die() will call exit() which will invoke cleanup_slaves().
6c1aee8
+             Additionally we need to kill child, because it's not yet among
6c1aee8
+             the slaves list.  */
6c1aee8
+          kill (child, TERMINATOR);
6c1aee8
+          xalloc_die ();
6c1aee8
+        }
6c1aee8
+      memcpy (new_slaves, old_slaves,
6c1aee8
+              slaves_allocated * sizeof (slaves_entry_t));
6c1aee8
+      slaves = new_slaves;
6c1aee8
+      slaves_allocated = new_slaves_allocated;
6c1aee8
+      /* Now we can free the old slaves array.  */
6c1aee8
+      if (old_slaves != static_slaves)
6c1aee8
+        free (old_slaves);
6c1aee8
+    }
6c1aee8
+  /* The three uses of 'volatile' in the types above (and ISO C 99 section
6c1aee8
+     5.1.2.3.(5)) ensure that we increment the slaves_count only after the
6c1aee8
+     new slave and its 'used' bit have been written to the memory locations
6c1aee8
+     that make up slaves[slaves_count].  */
6c1aee8
+  slaves[slaves_count].child = child;
6c1aee8
+  slaves[slaves_count].used = 1;
6c1aee8
+  slaves_count++;
6c1aee8
+}
6c1aee8
+
6c1aee8
+/* Unregister a child from the list of slave subprocesses.  */
6c1aee8
+static void
6c1aee8
+unregister_slave_subprocess (pid_t child)
6c1aee8
+{
6c1aee8
+  /* The easiest way to remove an entry from a list that can be used by
6c1aee8
+     an asynchronous signal handler is just to mark it as unused.  For this,
6c1aee8
+     we rely on sig_atomic_t.  */
6c1aee8
+  slaves_entry_t *s = slaves;
6c1aee8
+  slaves_entry_t *s_end = s + slaves_count;
6c1aee8
+
6c1aee8
+  for (; s < s_end; s++)
6c1aee8
+    if (s->used && s->child == child)
6c1aee8
+      s->used = 0;
6c1aee8
+}
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Wait for a subprocess to finish.  Return its exit code.
6c1aee8
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
6c1aee8
+   return 127.  */
6c1aee8
+int
6c1aee8
+wait_subprocess (pid_t child, const char *progname,
6c1aee8
+                 bool ignore_sigpipe, bool null_stderr,
6c1aee8
+                 bool slave_process, bool exit_on_error,
6c1aee8
+                 int *termsigp)
6c1aee8
+{
6c1aee8
+#if HAVE_WAITID && defined WNOWAIT && 0
6c1aee8
+  /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
6c1aee8
+     work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
6c1aee8
+     and on HP-UX 10.20 it just hangs.  */
6c1aee8
+  /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
6c1aee8
+     true, and this process sleeps a very long time between the return from
6c1aee8
+     waitpid() and the execution of unregister_slave_subprocess(), and
6c1aee8
+     meanwhile another process acquires the same PID as child, and then - still
6c1aee8
+     before unregister_slave_subprocess() - this process gets a fatal signal,
6c1aee8
+     it would kill the other totally unrelated process.  */
6c1aee8
+  siginfo_t info;
6c1aee8
+
6c1aee8
+  if (termsigp != NULL)
6c1aee8
+    *termsigp = 0;
6c1aee8
+  for (;;)
6c1aee8
+    {
6c1aee8
+      if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
6c1aee8
+          < 0)
6c1aee8
+        {
6c1aee8
+# ifdef EINTR
6c1aee8
+          if (errno == EINTR)
6c1aee8
+            continue;
6c1aee8
+# endif
6c1aee8
+          if (exit_on_error || !null_stderr)
6c1aee8
+            error (exit_on_error ? EXIT_FAILURE : 0, errno,
6c1aee8
+                   _("%s subprocess"), progname);
6c1aee8
+          return 127;
6c1aee8
+        }
6c1aee8
+
6c1aee8
+      /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
6c1aee8
+         CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED.  Loop until the program
6c1aee8
+         terminates.  */
6c1aee8
+      if (info.si_code == CLD_EXITED
6c1aee8
+          || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
6c1aee8
+        break;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  /* The child process has exited or was signalled.  */
6c1aee8
+
6c1aee8
+  if (slave_process)
6c1aee8
+    {
6c1aee8
+      /* Unregister the child from the list of slave subprocesses, so that
6c1aee8
+         later, when we exit, we don't kill a totally unrelated process which
6c1aee8
+         may have acquired the same pid.  */
6c1aee8
+      unregister_slave_subprocess (child);
6c1aee8
+
6c1aee8
+      /* Now remove the zombie from the process list.  */
6c1aee8
+      for (;;)
6c1aee8
+        {
6c1aee8
+          if (waitid (P_PID, child, &info, WEXITED) < 0)
6c1aee8
+            {
6c1aee8
+# ifdef EINTR
6c1aee8
+              if (errno == EINTR)
6c1aee8
+                continue;
6c1aee8
+# endif
6c1aee8
+              if (exit_on_error || !null_stderr)
6c1aee8
+                error (exit_on_error ? EXIT_FAILURE : 0, errno,
6c1aee8
+                       _("%s subprocess"), progname);
6c1aee8
+              return 127;
6c1aee8
+            }
6c1aee8
+          break;
6c1aee8
+        }
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  switch (info.si_code)
6c1aee8
+    {
6c1aee8
+    case CLD_KILLED:
6c1aee8
+    case CLD_DUMPED:
6c1aee8
+      if (termsigp != NULL)
6c1aee8
+        *termsigp = info.si_status; /* TODO: or info.si_signo? */
6c1aee8
+# ifdef SIGPIPE
6c1aee8
+      if (info.si_status == SIGPIPE && ignore_sigpipe)
6c1aee8
+        return 0;
6c1aee8
+# endif
6c1aee8
+      if (exit_on_error || (!null_stderr && termsigp == NULL))
6c1aee8
+        error (exit_on_error ? EXIT_FAILURE : 0, 0,
6c1aee8
+               _("%s subprocess got fatal signal %d"),
6c1aee8
+               progname, info.si_status);
6c1aee8
+      return 127;
6c1aee8
+    case CLD_EXITED:
6c1aee8
+      if (info.si_status == 127)
6c1aee8
+        {
6c1aee8
+          if (exit_on_error || !null_stderr)
6c1aee8
+            error (exit_on_error ? EXIT_FAILURE : 0, 0,
6c1aee8
+                   _("%s subprocess failed"), progname);
6c1aee8
+          return 127;
6c1aee8
+        }
6c1aee8
+      return info.si_status;
6c1aee8
+    default:
6c1aee8
+      abort ();
6c1aee8
+    }
6c1aee8
+#else
6c1aee8
+  /* waitpid() is just as portable as wait() nowadays.  */
6c1aee8
+  int status;
6c1aee8
+
6c1aee8
+  if (termsigp != NULL)
6c1aee8
+    *termsigp = 0;
6c1aee8
+  status = 0;
6c1aee8
+  for (;;)
6c1aee8
+    {
6c1aee8
+      int result = waitpid (child, &status, 0);
6c1aee8
+
6c1aee8
+      if (result != child)
6c1aee8
+        {
6c1aee8
+# ifdef EINTR
6c1aee8
+          if (errno == EINTR)
6c1aee8
+            continue;
6c1aee8
+# endif
6c1aee8
+# if 0 /* defined ECHILD */
6c1aee8
+          if (errno == ECHILD)
6c1aee8
+            {
6c1aee8
+              /* Child process nonexistent?! Assume it terminated
6c1aee8
+                 successfully.  */
6c1aee8
+              status = 0;
6c1aee8
+              break;
6c1aee8
+            }
6c1aee8
+# endif
6c1aee8
+          if (exit_on_error || !null_stderr)
6c1aee8
+            error (exit_on_error ? EXIT_FAILURE : 0, errno,
6c1aee8
+                   _("%s subprocess"), progname);
6c1aee8
+          return 127;
6c1aee8
+        }
6c1aee8
+
6c1aee8
+      /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
6c1aee8
+         must always be true, since we did not specify WCONTINUED in the
6c1aee8
+         waitpid() call.  Loop until the program terminates.  */
6c1aee8
+      if (!WIFSTOPPED (status))
6c1aee8
+        break;
6c1aee8
+    }
6c1aee8
+
6c1aee8
+  /* The child process has exited or was signalled.  */
6c1aee8
+
6c1aee8
+  if (slave_process)
6c1aee8
+    /* Unregister the child from the list of slave subprocesses, so that
6c1aee8
+       later, when we exit, we don't kill a totally unrelated process which
6c1aee8
+       may have acquired the same pid.  */
6c1aee8
+    unregister_slave_subprocess (child);
6c1aee8
+
6c1aee8
+  if (WIFSIGNALED (status))
6c1aee8
+    {
6c1aee8
+      if (termsigp != NULL)
6c1aee8
+        *termsigp = WTERMSIG (status);
6c1aee8
+# ifdef SIGPIPE
6c1aee8
+      if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
6c1aee8
+        return 0;
6c1aee8
+# endif
6c1aee8
+      if (exit_on_error || (!null_stderr && termsigp == NULL))
6c1aee8
+        error (exit_on_error ? EXIT_FAILURE : 0, 0,
6c1aee8
+               _("%s subprocess got fatal signal %d"),
6c1aee8
+               progname, (int) WTERMSIG (status));
6c1aee8
+      return 127;
6c1aee8
+    }
6c1aee8
+  if (!WIFEXITED (status))
6c1aee8
+    abort ();
6c1aee8
+  if (WEXITSTATUS (status) == 127)
6c1aee8
+    {
6c1aee8
+      if (exit_on_error || !null_stderr)
6c1aee8
+        error (exit_on_error ? EXIT_FAILURE : 0, 0,
6c1aee8
+               _("%s subprocess failed"), progname);
6c1aee8
+      return 127;
6c1aee8
+    }
6c1aee8
+  return WEXITSTATUS (status);
6c1aee8
+#endif
6c1aee8
+}
6c1aee8
diff -up patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.h
6c1aee8
--- patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute	2019-07-29 14:50:46.505827261 +0200
6c1aee8
+++ patch-2.7.6/lib/wait-process.h	2019-07-29 14:45:20.715529876 +0200
6c1aee8
@@ -0,0 +1,74 @@
6c1aee8
+/* Waiting for a subprocess to finish.
6c1aee8
+   Copyright (C) 2001-2003, 2006, 2008-2018 Free Software Foundation, Inc.
6c1aee8
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
6c1aee8
+
6c1aee8
+   This program is free software: you can redistribute it and/or modify
6c1aee8
+   it under the terms of the GNU General Public License as published by
6c1aee8
+   the Free Software Foundation; either version 3 of the License, or
6c1aee8
+   (at your option) any later version.
6c1aee8
+
6c1aee8
+   This program is distributed in the hope that it will be useful,
6c1aee8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6c1aee8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6c1aee8
+   GNU General Public License for more details.
6c1aee8
+
6c1aee8
+   You should have received a copy of the GNU General Public License
6c1aee8
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
6c1aee8
+
6c1aee8
+#ifndef _WAIT_PROCESS_H
6c1aee8
+#define _WAIT_PROCESS_H
6c1aee8
+
6c1aee8
+/* Get pid_t.  */
6c1aee8
+#include <stdlib.h>
6c1aee8
+#include <unistd.h>
6c1aee8
+#include <sys/types.h>
6c1aee8
+
6c1aee8
+#include <stdbool.h>
6c1aee8
+
6c1aee8
+
6c1aee8
+#ifdef __cplusplus
6c1aee8
+extern "C" {
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+/* Wait for a subprocess to finish.  Return its exit code.
6c1aee8
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
6c1aee8
+   return 127.
6c1aee8
+   Arguments:
6c1aee8
+   - child is the pid of the subprocess.
6c1aee8
+   - progname is the name of the program executed by the subprocess, used for
6c1aee8
+     error messages.
6c1aee8
+   - If ignore_sigpipe is true, consider a subprocess termination due to
6c1aee8
+     SIGPIPE as equivalent to a success.  This is suitable for processes whose
6c1aee8
+     only purpose is to write to standard output.  This flag can be safely set
6c1aee8
+     to false when the process' standard output is known to go to DEV_NULL.
6c1aee8
+   - If null_stderr is true, the usual error message to stderr will be omitted.
6c1aee8
+     This is suitable when the subprocess does not fulfill an important task.
6c1aee8
+   - slave_process should be set to true if the process has been launched as a
6c1aee8
+     slave process.
6c1aee8
+   - If exit_on_error is true, any error will cause the main process to exit
6c1aee8
+     with an error status.
6c1aee8
+   - If termsigp is not NULL: *termsig will be set to the signal that
6c1aee8
+     terminated the subprocess (if supported by the platform: not on native
6c1aee8
+     Windows platforms), otherwise 0, and the error message about the signal
6c1aee8
+     that terminated the subprocess will be omitted.
6c1aee8
+   Prerequisites: The signal handler for SIGCHLD should not be set to SIG_IGN,
6c1aee8
+   otherwise this function will not work.  */
6c1aee8
+extern int wait_subprocess (pid_t child, const char *progname,
6c1aee8
+                            bool ignore_sigpipe, bool null_stderr,
6c1aee8
+                            bool slave_process, bool exit_on_error,
6c1aee8
+                            int *termsigp);
6c1aee8
+
6c1aee8
+/* Register a subprocess as being a slave process.  This means that the
6c1aee8
+   subprocess will be terminated when its creator receives a catchable fatal
6c1aee8
+   signal or exits normally.  Registration ends when wait_subprocess()
6c1aee8
+   notices that the subprocess has exited.  */
6c1aee8
+extern void register_slave_subprocess (pid_t child);
6c1aee8
+
6c1aee8
+
6c1aee8
+#ifdef __cplusplus
6c1aee8
+}
6c1aee8
+#endif
6c1aee8
+
6c1aee8
+
6c1aee8
+#endif /* _WAIT_PROCESS_H */
6c1aee8
diff -up patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute patch-2.7.6/src/pch.c
6c1aee8
--- patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute	2019-07-29 14:40:53.262464816 +0200
6c1aee8
+++ patch-2.7.6/src/pch.c	2019-07-29 15:01:10.338312098 +0200
6c1aee8
@@ -33,7 +33,8 @@
6c1aee8
 # include <io.h>
6c1aee8
 #endif
6c1aee8
 #include <safe.h>
6c1aee8
-#include <sys/wait.h>
6c1aee8
+#include <alloca.h>
6c1aee8
+#include "execute.h"
6c1aee8
 
6c1aee8
 #define INITHUNKMAX 125			/* initial dynamic allocation size */
6c1aee8
 
6c1aee8
@@ -2453,6 +2463,9 @@ do_ed_script (char const *inname, char c
6c1aee8
 
6c1aee8
     if (! dry_run && ! skip_rest_of_patch) {
6c1aee8
 	int exclusive = *outname_needs_removal ? 0 : O_EXCL;
6c1aee8
+	char const **ed_argv;
6c1aee8
+	int stdin_dup, status;
6c1aee8
+
6c1aee8
 	*outname_needs_removal = true;
6c1aee8
 	if (inerrno != ENOENT)
6c1aee8
 	  {
6c1aee8
@@ -2461,24 +2474,22 @@ do_ed_script (char const *inname, char c
6c1aee8
 	  }
6c1aee8
 	fflush (stdout);
6c1aee8
 
6c1aee8
-	pid = fork();
6c1aee8
-	if (pid == -1)
6c1aee8
-	  pfatal ("Can't fork");
6c1aee8
-	else if (pid == 0)
6c1aee8
-	  {
6c1aee8
-	    dup2 (tmpfd, 0);
6c1aee8
-	    assert (outname[0] != '!' && outname[0] != '-');
6c1aee8
-	    execlp (editor_program, editor_program, "-", outname, (char  *) NULL);
6c1aee8
-	    _exit (2);
6c1aee8
-	  }
6c1aee8
-	else
6c1aee8
-	  {
6c1aee8
-	    int wstatus;
6c1aee8
-	    if (waitpid (pid, &wstatus, 0) == -1
6c1aee8
-	        || ! WIFEXITED (wstatus)
6c1aee8
-		|| WEXITSTATUS (wstatus) != 0)
6c1aee8
-	      fatal ("%s FAILED", editor_program);
6c1aee8
-	  }
6c1aee8
+	if ((stdin_dup = dup (0)) == -1
6c1aee8
+	    || dup2 (tmpfd, 0) == -1)
6c1aee8
+	  pfatal ("Failed to duplicate standard input");
6c1aee8
+	assert (outname[0] != '!' && outname[0] != '-');
6c1aee8
+	ed_argv = alloca (4 * sizeof * ed_argv);
6c1aee8
+	ed_argv[0] = editor_program;
6c1aee8
+	ed_argv[1] = "-";
6c1aee8
+	ed_argv[2] = outname;
6c1aee8
+	ed_argv[3] = (char  *) NULL;
6c1aee8
+	status = execute (editor_program, editor_program, (char **)ed_argv,
6c1aee8
+			  false, false, false, false, true, false, NULL);
6c1aee8
+	if (status)
6c1aee8
+	  fatal ("%s FAILED", editor_program);
6c1aee8
+	if (dup2 (stdin_dup, 0) == -1
6c1aee8
+	    || close (stdin_dup) == -1)
6c1aee8
+	  pfatal ("Failed to duplicate standard input");
6c1aee8
     }
6c1aee8
 
6c1aee8
     fclose (tmpfp);