[packages/patch] - rel 3; fixes from FC
arekm
arekm at pld-linux.org
Tue Feb 25 22:39:36 CET 2020
commit 93925d0d9d75587c27ed526835c8572c1b38a780
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Tue Feb 25 22:39:27 2020 +0100
- rel 3; fixes from FC
CVE-2018-1000156.patch | 211 +++
patch-2.7.6-CVE-2018-17942.patch | 14 +
...-6952-fix-swapping-fake-lines-in-pch_swap.patch | 25 +
patch-2.7.6-CVE-2019-13636-symlinks.patch | 102 ++
...ed-ed-directly-instead-of-using-the-shell.patch | 33 +
patch-2.7.6-abort_when_cleaning_up_fails.patch | 46 +
...-files-to-be-missing-for-ed-style-patches.patch | 28 +
...lid-memory-access-in-context-format-diffs.patch | 21 +
..._file_attributes-sign-conversion-warnings.patch | 24 +
patch-2.7.6-avoid-warnings-gcc8.patch | 85 +
patch-2.7.6-avoid_invalid_memory_access.patch | 21 +
patch-2.7.6-check-of-return-value-of-fwrite.patch | 75 +
patch-2.7.6-cleanups-in-do_ed_script.patch | 91 +
patch-2.7.6-crash-RLIMIT_NOFILE.patch | 84 +
...k-temporary-file-on-failed-ed-style-patch.patch | 95 ++
...-file-on-failed-multi-file-ed-style-patch.patch | 71 +
patch-2.7.6-failed_assertion.patch | 29 +
patch-2.7.6-fix-ed-style-test-failure.patch | 22 +
patch-2.7.6-fix-korn-shell-incompatibility.patch | 21 +
....6-fix-segfault-with-mangled-rename-patch.patch | 24 +
...improve_support_for_memory_leak_detection.patch | 48 +
patch-2.7.6-make-debug-output-more-useful.patch | 40 +
...test-when-the-ed-utility-is-not-installed.patch | 20 +
...-2.7.6-switch-from-fork-execlp-to-execute.patch | 1774 ++++++++++++++++++++
patch-2.7.6-test-suite-compatibility-fixes.patch | 124 ++
patch-CVE-2018-1000156.patch | 179 +-
patch-selinux.patch | 326 ++++
patch.spec | 52 +-
28 files changed, 3589 insertions(+), 96 deletions(-)
---
diff --git a/patch.spec b/patch.spec
index dad52cb..5af8c8e 100644
--- a/patch.spec
+++ b/patch.spec
@@ -11,13 +11,36 @@ Summary(tr.UTF-8): GNU yama yardımcı programları
Summary(uk.UTF-8): Утиліта GNU patch, для модифікації/апгрейду файлів
Name: patch
Version: 2.7.6
-Release: 2
+Release: 3
License: GPL v3+
Group: Applications/Text
Source0: http://ftp.gnu.org/gnu/patch/%{name}-%{version}.tar.xz
# Source0-md5: 78ad9937e4caadcba1526ef1853730d5
Source1: %{name}.1.pl
-Patch0: patch-CVE-2018-1000156.patch
+Patch0: patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch
+Patch1: patch-2.7.6-test-suite-compatibility-fixes.patch
+Patch2: patch-2.7.6-fix-korn-shell-incompatibility.patch
+Patch3: patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch
+Patch4: patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch
+Patch5: patch-CVE-2018-1000156.patch
+Patch6: patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch
+Patch7: patch-2.7.6-switch-from-fork-execlp-to-execute.patch
+Patch8: patch-2.7.6-cleanups-in-do_ed_script.patch
+Patch9: patch-2.7.6-avoid-warnings-gcc8.patch
+Patch10: patch-2.7.6-check-of-return-value-of-fwrite.patch
+Patch11: patch-2.7.6-fix-ed-style-test-failure.patch
+Patch12: patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch
+Patch13: patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch
+Patch14: patch-2.7.6-make-debug-output-more-useful.patch
+Patch15: patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch
+Patch16: patch-2.7.6-improve_support_for_memory_leak_detection.patch
+Patch17: patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch
+Patch18: patch-2.7.6-abort_when_cleaning_up_fails.patch
+Patch19: patch-2.7.6-crash-RLIMIT_NOFILE.patch
+Patch20: patch-2.7.6-CVE-2019-13636-symlinks.patch
+Patch21: patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch
+Patch22: patch-2.7.6-CVE-2018-17942.patch
+Patch23: patch-2.7.6-failed_assertion.patch
URL: http://www.gnu.org/software/patch/
BuildRequires: autoconf >= 2.65
BuildRequires: automake >= 1:1.11.2
@@ -77,7 +100,30 @@ Patch - це програма, яка допомогає в модифікаці
%prep
%setup -q
-%patch0 -p1
+%patch0 -p1 -b .avoid-set_file_attributes-sign-conversion-warnings
+%patch1 -p1 -b .test-suite-compatibility-fixes
+%patch2 -p1 -b .fix-korn-shell-incompatibility
+%patch3 -p1 -b .fix-segfault-with-mangled-rename-patch
+%patch4 -p1 -b .allow-input-files-to-be-missing-for-ed-style-patches
+%patch5 -p1 -b .CVE-2018-1000156
+%patch6 -p1 -b .CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell
+%patch7 -p1 -b .switch-from-fork-execlp-to-execute
+%patch8 -p1 -b .cleanups-in-do_ed_script
+%patch9 -p1 -b .avoid-warnings-gcc8
+%patch10 -p1 -b .check-of-return-value-of-fwrite
+%patch11 -p1 -b .fix-ed-style-test-failure
+%patch12 -p1 -b .dont-leak-temporary-file-on-failed-ed-style-patch
+%patch13 -p1 -b .dont-leak-temporary-file-on-failed-multi-file-ed-style-patch
+%patch14 -p1 -b .make-debug-output-more-useful
+%patch15 -p1 -b .CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap
+%patch16 -p1 -b .improve_support_for_memory_leak_detection
+%patch17 -p1 -b .skip-ed-test-when-the-ed-utility-is-not-installed
+%patch18 -p1 -b .abort_when_cleaning_up_fails
+%patch19 -p1 -b .crash-RLIMIT_NOFILE
+%patch20 -p1 -b .CVE-2019-13636-symlinks
+%patch21 -p1 -b .avoid-invalid-memory-access-in-context-format-diffs
+%patch22 -p1 -b .CVE-2018-17942-gnulib_buffer_overflow
+%patch23 -p1 -b .failed_assertion
%build
%{__aclocal} -I m4
diff --git a/CVE-2018-1000156.patch b/CVE-2018-1000156.patch
new file mode 100644
index 0000000..36f33de
--- /dev/null
+++ b/CVE-2018-1000156.patch
@@ -0,0 +1,211 @@
+From 123eaff0d5d1aebe128295959435b9ca5909c26d Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri, 6 Apr 2018 12:14:49 +0200
+Subject: Fix arbitrary command execution in ed-style patches
+ (CVE-2018-1000156)
+
+* src/pch.c (do_ed_script): Write ed script to a temporary file instead
+of piping it to ed: this will cause ed to abort on invalid commands
+instead of rejecting them and carrying on.
+* tests/ed-style: New test case.
+* tests/Makefile.am (TESTS): Add test case.
+---
+ src/pch.c | 91 ++++++++++++++++++++++++++++++++++++++++---------------
+ tests/Makefile.am | 1 +
+ tests/ed-style | 41 +++++++++++++++++++++++++
+ 3 files changed, 108 insertions(+), 25 deletions(-)
+ create mode 100644 tests/ed-style
+
+diff --git a/src/pch.c b/src/pch.c
+index 0c5cc26..4fd5a05 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -33,6 +33,7 @@
+ # include <io.h>
+ #endif
+ #include <safe.h>
++#include <sys/wait.h>
+
+ #define INITHUNKMAX 125 /* initial dynamic allocation size */
+
+@@ -2389,24 +2390,28 @@ do_ed_script (char const *inname, char const *outname,
+ static char const editor_program[] = EDITOR_PROGRAM;
+
+ file_offset beginning_of_this_line;
+- FILE *pipefp = 0;
+ size_t chars_read;
++ FILE *tmpfp = 0;
++ char const *tmpname;
++ int tmpfd;
++ pid_t pid;
++
++ if (! dry_run && ! skip_rest_of_patch)
++ {
++ /* Write ed script to a temporary file. This causes ed to abort on
++ invalid commands such as when line numbers or ranges exceed the
++ number of available lines. When ed reads from a pipe, it rejects
++ invalid commands and treats the next line as a new command, which
++ can lead to arbitrary command execution. */
++
++ tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
++ if (tmpfd == -1)
++ pfatal ("Can't create temporary file %s", quotearg (tmpname));
++ tmpfp = fdopen (tmpfd, "w+b");
++ if (! tmpfp)
++ pfatal ("Can't open stream for file %s", quotearg (tmpname));
++ }
+
+- if (! dry_run && ! skip_rest_of_patch) {
+- int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+- if (inerrno != ENOENT)
+- {
+- *outname_needs_removal = true;
+- copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+- }
+- sprintf (buf, "%s %s%s", editor_program,
+- verbosity == VERBOSE ? "" : "- ",
+- outname);
+- fflush (stdout);
+- pipefp = popen(buf, binary_transput ? "wb" : "w");
+- if (!pipefp)
+- pfatal ("Can't open pipe to %s", quotearg (buf));
+- }
+ for (;;) {
+ char ed_command_letter;
+ beginning_of_this_line = file_tell (pfp);
+@@ -2417,14 +2422,14 @@ do_ed_script (char const *inname, char const *outname,
+ }
+ ed_command_letter = get_ed_command_letter (buf);
+ if (ed_command_letter) {
+- if (pipefp)
+- if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
++ if (tmpfp)
++ if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
+ write_fatal ();
+ if (ed_command_letter != 'd' && ed_command_letter != 's') {
+ p_pass_comments_through = true;
+ while ((chars_read = get_line ()) != 0) {
+- if (pipefp)
+- if (! fwrite (buf, sizeof *buf, chars_read, pipefp))
++ if (tmpfp)
++ if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
+ write_fatal ();
+ if (chars_read == 2 && strEQ (buf, ".\n"))
+ break;
+@@ -2437,13 +2442,49 @@ do_ed_script (char const *inname, char const *outname,
+ break;
+ }
+ }
+- if (!pipefp)
++ if (!tmpfp)
+ return;
+- if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0
+- || fflush (pipefp) != 0)
++ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0
++ || fflush (tmpfp) != 0)
+ write_fatal ();
+- if (pclose (pipefp) != 0)
+- fatal ("%s FAILED", editor_program);
++
++ if (lseek (tmpfd, 0, SEEK_SET) == -1)
++ pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));
++
++ if (! dry_run && ! skip_rest_of_patch) {
++ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
++ *outname_needs_removal = true;
++ if (inerrno != ENOENT)
++ {
++ *outname_needs_removal = true;
++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++ }
++ sprintf (buf, "%s %s%s", editor_program,
++ verbosity == VERBOSE ? "" : "- ",
++ outname);
++ fflush (stdout);
++
++ pid = fork();
++ if (pid == -1)
++ pfatal ("Can't fork");
++ else if (pid == 0)
++ {
++ dup2 (tmpfd, 0);
++ execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
++ _exit (2);
++ }
++ else
++ {
++ int wstatus;
++ if (waitpid (pid, &wstatus, 0) == -1
++ || ! WIFEXITED (wstatus)
++ || WEXITSTATUS (wstatus) != 0)
++ fatal ("%s FAILED", editor_program);
++ }
++ }
++
++ fclose (tmpfp);
++ safe_unlink (tmpname);
+
+ if (ofp)
+ {
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 6b6df63..16f8693 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -32,6 +32,7 @@ TESTS = \
+ crlf-handling \
+ dash-o-append \
+ deep-directories \
++ ed-style \
+ empty-files \
+ false-match \
+ fifo \
+diff --git a/tests/ed-style b/tests/ed-style
+new file mode 100644
+index 0000000..d8c0689
+--- /dev/null
++++ b/tests/ed-style
+@@ -0,0 +1,41 @@
++# Copyright (C) 2018 Free Software Foundation, Inc.
++#
++# Copying and distribution of this file, with or without modification,
++# in any medium, are permitted without royalty provided the copyright
++# notice and this notice are preserved.
++
++. $srcdir/test-lib.sh
++
++require cat
++use_local_patch
++use_tmpdir
++
++# ==============================================================
++
++cat > ed1.diff <<EOF
++0a
++foo
++.
++EOF
++
++check 'patch -e foo -i ed1.diff' <<EOF
++EOF
++
++check 'cat foo' <<EOF
++foo
++EOF
++
++cat > ed2.diff <<EOF
++1337a
++r !echo bar
++,p
++EOF
++
++check 'patch -e foo -i ed2.diff 2> /dev/null || echo "Status: $?"' <<EOF
++?
++Status: 2
++EOF
++
++check 'cat foo' <<EOF
++foo
++EOF
+--
+cgit v1.0-41-gc330
+
diff --git a/patch-2.7.6-CVE-2018-17942.patch b/patch-2.7.6-CVE-2018-17942.patch
new file mode 100644
index 0000000..5eb224e
--- /dev/null
+++ b/patch-2.7.6-CVE-2018-17942.patch
@@ -0,0 +1,14 @@
+diff -up patch-2.7.6/lib/vasnprintf.c.me patch-2.7.6/lib/vasnprintf.c
+--- patch-2.7.6/lib/vasnprintf.c.me 2018-11-26 14:02:03.401718842 +0100
++++ patch-2.7.6/lib/vasnprintf.c 2018-11-26 14:03:02.923913446 +0100
+@@ -860,7 +860,9 @@ convert_to_decimal (mpn_t a, size_t extr
+ size_t a_len = a.nlimbs;
+ /* 0.03345 is slightly larger than log(2)/(9*log(10)). */
+ size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1);
+- char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes));
++ /* We need extra_zeroes bytes for zeroes, followed by c_len bytes for the
++ digits of a, followed by 1 byte for the terminating NUL. */
++ char *c_ptr = (char *) malloc (xsum (xsum (extra_zeroes, c_len), 1));
+ if (c_ptr != NULL)
+ {
+ char *d_ptr = c_ptr;
diff --git a/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch b/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch
new file mode 100644
index 0000000..257a300
--- /dev/null
+++ b/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch
@@ -0,0 +1,25 @@
+commit 9c986353e420ead6e706262bf204d6e03322c300
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Aug 17 13:35:40 2018 +0200
+
+ Fix swapping fake lines in pch_swap
+
+ * src/pch.c (pch_swap): Fix swapping p_bfake and p_efake when there is a
+ blank line in the middle of a context-diff hunk: that empty line stays
+ in the middle of the hunk and isn't swapped.
+
+ Fixes: https://savannah.gnu.org/bugs/index.php?53133
+
+diff --git a/src/pch.c b/src/pch.c
+index e92bc64..a500ad9 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2122,7 +2122,7 @@ pch_swap (void)
+ }
+ if (p_efake >= 0) { /* fix non-freeable ptr range */
+ if (p_efake <= i)
+- n = p_end - i + 1;
++ n = p_end - p_ptrn_lines;
+ else
+ n = -i;
+ p_efake += n;
diff --git a/patch-2.7.6-CVE-2019-13636-symlinks.patch b/patch-2.7.6-CVE-2019-13636-symlinks.patch
new file mode 100644
index 0000000..bf3e603
--- /dev/null
+++ b/patch-2.7.6-CVE-2019-13636-symlinks.patch
@@ -0,0 +1,102 @@
+commit dce4683cbbe107a95f1f0d45fabc304acfb5d71a
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Mon Jul 15 16:21:48 2019 +0200
+
+ Don't follow symlinks unless --follow-symlinks is given
+
+ * src/inp.c (plan_a, plan_b), src/util.c (copy_to_fd, copy_file,
+ append_to_file): Unless the --follow-symlinks option is given, open files with
+ the O_NOFOLLOW flag to avoid following symlinks. So far, we were only doing
+ that consistently for input files.
+ * src/util.c (create_backup): When creating empty backup files, (re)create them
+ with O_CREAT | O_EXCL to avoid following symlinks in that case as well.
+
+diff --git a/src/inp.c b/src/inp.c
+index 32d0919..22d7473 100644
+--- a/src/inp.c
++++ b/src/inp.c
+@@ -238,8 +238,13 @@ plan_a (char const *filename)
+ {
+ if (S_ISREG (instat.st_mode))
+ {
+- int ifd = safe_open (filename, O_RDONLY|binary_transput, 0);
++ int flags = O_RDONLY | binary_transput;
+ size_t buffered = 0, n;
++ int ifd;
++
++ if (! follow_symlinks)
++ flags |= O_NOFOLLOW;
++ ifd = safe_open (filename, flags, 0);
+ if (ifd < 0)
+ pfatal ("can't open file %s", quotearg (filename));
+
+@@ -340,6 +345,7 @@ plan_a (char const *filename)
+ static void
+ plan_b (char const *filename)
+ {
++ int flags = O_RDONLY | binary_transput;
+ int ifd;
+ FILE *ifp;
+ int c;
+@@ -353,7 +359,9 @@ plan_b (char const *filename)
+
+ if (instat.st_size == 0)
+ filename = NULL_DEVICE;
+- if ((ifd = safe_open (filename, O_RDONLY | binary_transput, 0)) < 0
++ if (! follow_symlinks)
++ flags |= O_NOFOLLOW;
++ if ((ifd = safe_open (filename, flags, 0)) < 0
+ || ! (ifp = fdopen (ifd, binary_transput ? "rb" : "r")))
+ pfatal ("Can't open file %s", quotearg (filename));
+ if (TMPINNAME_needs_removal)
+diff --git a/src/util.c b/src/util.c
+index 1cc08ba..fb38307 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -388,7 +388,7 @@ create_backup (char const *to, const struct stat *to_st, bool leave_original)
+
+ try_makedirs_errno = ENOENT;
+ safe_unlink (bakname);
+- while ((fd = safe_open (bakname, O_CREAT | O_WRONLY | O_TRUNC, 0666)) < 0)
++ while ((fd = safe_open (bakname, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, 0666)) < 0)
+ {
+ if (errno != try_makedirs_errno)
+ pfatal ("Can't create file %s", quotearg (bakname));
+@@ -579,10 +579,13 @@ create_file (char const *file, int open_flags, mode_t mode,
+ static void
+ copy_to_fd (const char *from, int tofd)
+ {
++ int from_flags = O_RDONLY | O_BINARY;
+ int fromfd;
+ ssize_t i;
+
+- if ((fromfd = safe_open (from, O_RDONLY | O_BINARY, 0)) < 0)
++ if (! follow_symlinks)
++ from_flags |= O_NOFOLLOW;
++ if ((fromfd = safe_open (from, from_flags, 0)) < 0)
+ pfatal ("Can't reopen file %s", quotearg (from));
+ while ((i = read (fromfd, buf, bufsize)) != 0)
+ {
+@@ -625,6 +628,8 @@ copy_file (char const *from, char const *to, struct stat *tost,
+ else
+ {
+ assert (S_ISREG (mode));
++ if (! follow_symlinks)
++ to_flags |= O_NOFOLLOW;
+ tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode,
+ to_dir_known_to_exist);
+ copy_to_fd (from, tofd);
+@@ -640,9 +645,12 @@ copy_file (char const *from, char const *to, struct stat *tost,
+ void
+ append_to_file (char const *from, char const *to)
+ {
++ int to_flags = O_WRONLY | O_APPEND | O_BINARY;
+ int tofd;
+
+- if ((tofd = safe_open (to, O_WRONLY | O_BINARY | O_APPEND, 0)) < 0)
++ if (! follow_symlinks)
++ to_flags |= O_NOFOLLOW;
++ if ((tofd = safe_open (to, to_flags, 0)) < 0)
+ pfatal ("Can't reopen file %s", quotearg (to));
+ copy_to_fd (from, tofd);
+ if (close (tofd) != 0)
diff --git a/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch b/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch
new file mode 100644
index 0000000..4a9f2d6
--- /dev/null
+++ b/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch
@@ -0,0 +1,33 @@
+commit 3fcd042d26d70856e826a42b5f93dc4854d80bf0
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Apr 6 19:36:15 2018 +0200
+
+ Invoke ed directly instead of using the shell
+
+ * src/pch.c (do_ed_script): Invoke ed directly instead of using a shell
+ command to avoid quoting vulnerabilities.
+
+diff --git a/src/pch.c b/src/pch.c
+index 4fd5a05..16e001a 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2459,9 +2459,6 @@ do_ed_script (char const *inname, char const *outname,
+ *outname_needs_removal = true;
+ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+ }
+- sprintf (buf, "%s %s%s", editor_program,
+- verbosity == VERBOSE ? "" : "- ",
+- outname);
+ fflush (stdout);
+
+ pid = fork();
+@@ -2470,7 +2467,8 @@ do_ed_script (char const *inname, char const *outname,
+ else if (pid == 0)
+ {
+ dup2 (tmpfd, 0);
+- execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
++ assert (outname[0] != '!' && outname[0] != '-');
++ execlp (editor_program, editor_program, "-", outname, (char *) NULL);
+ _exit (2);
+ }
+ else
diff --git a/patch-2.7.6-abort_when_cleaning_up_fails.patch b/patch-2.7.6-abort_when_cleaning_up_fails.patch
new file mode 100644
index 0000000..56dbda8
--- /dev/null
+++ b/patch-2.7.6-abort_when_cleaning_up_fails.patch
@@ -0,0 +1,46 @@
+commit b7b028a77bd855f6f56b17c8837fc1cca77b469d
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Jun 28 00:30:25 2019 +0200
+
+ Abort when cleaning up fails
+
+ When a fatal error triggers during cleanup, another attempt will be made to
+ clean up, which will likely lead to the same fatal error. So instead, bail out
+ when that happens.
+ src/patch.c (cleanup): Bail out when called recursively.
+ (main): There is no need to call output_files() before cleanup() as cleanup()
+ already does that.
+
+diff --git a/src/patch.c b/src/patch.c
+index 4616a48..02fd982 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -685,7 +685,6 @@ main (int argc, char **argv)
+ }
+ if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0))
+ write_fatal ();
+- output_files (NULL);
+ cleanup ();
+ delete_files ();
+ if (somefailed)
+@@ -1991,7 +1990,6 @@ void
+ fatal_exit (int sig)
+ {
+ cleanup ();
+-
+ if (sig)
+ exit_with_signal (sig);
+
+@@ -2011,6 +2009,12 @@ remove_if_needed (char const *name, bool *needs_removal)
+ static void
+ cleanup (void)
+ {
++ static bool already_cleaning_up;
++
++ if (already_cleaning_up)
++ return;
++ already_cleaning_up = true;
++
+ remove_if_needed (TMPINNAME, &TMPINNAME_needs_removal);
+ remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal);
+ remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal);
diff --git a/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch b/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch
new file mode 100644
index 0000000..34b8fb4
--- /dev/null
+++ b/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch
@@ -0,0 +1,28 @@
+commit b5a91a01e5d0897facdd0f49d64b76b0f02b43e1
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Apr 6 11:34:51 2018 +0200
+
+ Allow input files to be missing for ed-style patches
+
+ * src/pch.c (do_ed_script): Allow input files to be missing so that new
+ files will be created as with non-ed-style patches.
+
+diff --git a/src/pch.c b/src/pch.c
+index bc6278c..0c5cc26 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2394,9 +2394,11 @@ do_ed_script (char const *inname, char const *outname,
+
+ if (! dry_run && ! skip_rest_of_patch) {
+ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+- assert (! inerrno);
+- *outname_needs_removal = true;
+- copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++ if (inerrno != ENOENT)
++ {
++ *outname_needs_removal = true;
++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++ }
+ sprintf (buf, "%s %s%s", editor_program,
+ verbosity == VERBOSE ? "" : "- ",
+ outname);
diff --git a/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch b/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch
new file mode 100644
index 0000000..39b59d1
--- /dev/null
+++ b/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch
@@ -0,0 +1,21 @@
+commit 15b158db3ae11cb835f2eb8d2eb48e09d1a4af48
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Mon Jul 15 19:10:02 2019 +0200
+
+ Avoid invalid memory access in context format diffs
+
+ * src/pch.c (another_hunk): Avoid invalid memory access in context format
+ diffs.
+
+diff --git a/src/pch.c b/src/pch.c
+index a500ad9..cb54e03 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -1328,6 +1328,7 @@ another_hunk (enum diff difftype, bool rev)
+ ptrn_prefix_context = context;
+ ptrn_suffix_context = context;
+ if (repl_beginning
++ || p_end <= 0
+ || (p_end
+ != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n')))
+ {
diff --git a/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch b/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch
new file mode 100644
index 0000000..dd57034
--- /dev/null
+++ b/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch
@@ -0,0 +1,24 @@
+commit 3bbebbb29f6fbbf2988b9f2e75695b7c0b1f1c9b
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Wed Feb 7 12:01:22 2018 +0100
+
+ Avoid set_file_attributes sign conversion warnings
+
+ * src/util.c (set_file_attributes): Avoid sign conversion warnings when
+ assigning -1 to uid_t / gid_t.
+
+diff --git a/src/util.c b/src/util.c
+index b1c7266..1cc08ba 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -256,8 +256,8 @@ set_file_attributes (char const *to, enum file_attributes attr,
+ }
+ if (attr & FA_IDS)
+ {
+- static uid_t euid = -1;
+- static gid_t egid = -1;
++ static uid_t euid = (uid_t)-1;
++ static gid_t egid = (gid_t)-1;
+ uid_t uid;
+ uid_t gid;
+
diff --git a/patch-2.7.6-avoid-warnings-gcc8.patch b/patch-2.7.6-avoid-warnings-gcc8.patch
new file mode 100644
index 0000000..5cc3366
--- /dev/null
+++ b/patch-2.7.6-avoid-warnings-gcc8.patch
@@ -0,0 +1,85 @@
+commit ae81be0024ea4eaf139b7ba57e9a8ce9e4a163ec
+Author: Jim Meyering <jim at meyering.net>
+Date: Fri Apr 6 17:17:11 2018 -0700
+
+ maint: avoid warnings from GCC8
+
+ Hi Andreas,
+
+ I configured with --enable-gcc-warnings and bleeding-edge gcc
+ (version 8.0.1 20180406) and hit some warning-escalated-to-errors.
+ This fixes them:
+
+ >From a71ddb200dbe7ac0f9258796b5a51979b2740e88 Mon Sep 17 00:00:00 2001
+ From: Jim Meyering <meyering at fb.com>
+ Date: Fri, 6 Apr 2018 16:47:00 -0700
+ Subject: [PATCH] maint: avoid warnings from GCC8
+
+ * src/common.h (FALLTHROUGH): Define.
+ * src/patch.c (abort_hunk_context): Use FALLTHROUGH macro in place of
+ a comment. This avoids a warning from -Wimplicit-fallthrough=.
+ * src/pch.c (do_ed_script): Add otherwise unnecessary initialization
+ to avoid warning from -Wmaybe-uninitialized.
+ (another_hunk): Use FALLTHROUGH macro here, too, twice.
+
+diff --git a/src/common.h b/src/common.h
+index ec50b40..904a3f8 100644
+--- a/src/common.h
++++ b/src/common.h
+@@ -218,3 +218,11 @@ bool merge_hunk (int hunk, struct outstate *, lin where, bool *);
+ #else
+ # define merge_hunk(hunk, outstate, where, somefailed) false
+ #endif
++
++#ifndef FALLTHROUGH
++# if __GNUC__ < 7
++# define FALLTHROUGH ((void) 0)
++# else
++# define FALLTHROUGH __attribute__ ((__fallthrough__))
++# endif
++#endif
+diff --git a/src/patch.c b/src/patch.c
+index 0fe6d72..1ae91d9 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -1381,7 +1381,7 @@ abort_hunk_context (bool header, bool reverse)
+ break;
+ case ' ': case '-': case '+': case '!':
+ fprintf (rejfp, "%c ", pch_char (i));
+- /* fall into */
++ FALLTHROUGH;
+ case '\n':
+ pch_write_line (i, rejfp);
+ break;
+diff --git a/src/pch.c b/src/pch.c
+index 1055542..cda3dfa 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -1735,7 +1735,7 @@ another_hunk (enum diff difftype, bool rev)
+ break;
+ case '=':
+ ch = ' ';
+- /* FALL THROUGH */
++ FALLTHROUGH;
+ case ' ':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+@@ -1756,7 +1756,7 @@ another_hunk (enum diff difftype, bool rev)
+ p_end = fillsrc-1;
+ return -1;
+ }
+- /* FALL THROUGH */
++ FALLTHROUGH;
+ case '+':
+ if (filldst > p_end) {
+ free(s);
+@@ -2394,8 +2394,7 @@ do_ed_script (char const *inname, char const *outname,
+ size_t chars_read;
+ FILE *tmpfp = 0;
+ char const *tmpname;
+- int tmpfd;
+- pid_t pid;
++ int tmpfd = -1; /* placate gcc's -Wmaybe-uninitialized */
+ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+ char const **ed_argv;
+ int stdin_dup, status;
diff --git a/patch-2.7.6-avoid_invalid_memory_access.patch b/patch-2.7.6-avoid_invalid_memory_access.patch
new file mode 100644
index 0000000..39b59d1
--- /dev/null
+++ b/patch-2.7.6-avoid_invalid_memory_access.patch
@@ -0,0 +1,21 @@
+commit 15b158db3ae11cb835f2eb8d2eb48e09d1a4af48
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Mon Jul 15 19:10:02 2019 +0200
+
+ Avoid invalid memory access in context format diffs
+
+ * src/pch.c (another_hunk): Avoid invalid memory access in context format
+ diffs.
+
+diff --git a/src/pch.c b/src/pch.c
+index a500ad9..cb54e03 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -1328,6 +1328,7 @@ another_hunk (enum diff difftype, bool rev)
+ ptrn_prefix_context = context;
+ ptrn_suffix_context = context;
+ if (repl_beginning
++ || p_end <= 0
+ || (p_end
+ != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n')))
+ {
diff --git a/patch-2.7.6-check-of-return-value-of-fwrite.patch b/patch-2.7.6-check-of-return-value-of-fwrite.patch
new file mode 100644
index 0000000..01242c0
--- /dev/null
+++ b/patch-2.7.6-check-of-return-value-of-fwrite.patch
@@ -0,0 +1,75 @@
+commit 1e9104c18019e7dc6b5590aea4b1d4f9d8ecfd56
+Author: Bruno Haible <bruno at clisp.org>
+Date: Sat Apr 7 12:21:04 2018 +0200
+
+ Fix check of return value of fwrite().
+
+ * src/patch.c (copy_till): Consider incomplete fwrite() write as an error.
+ * src/pch.c (pch_write_line, do_ed_script): Likewise.
+
+diff --git a/src/patch.c b/src/patch.c
+index 1ae91d9..3fcaec5 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -2,7 +2,7 @@
+
+ /* Copyright (C) 1984, 1985, 1986, 1987, 1988 Larry Wall
+
+- Copyright (C) 1989-1993, 1997-1999, 2002-2003, 2006, 2009-2012 Free Software
++ Copyright (C) 1989-1993, 1997-1999, 2002-2003, 2006, 2009-2018 Free Software
+ Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+@@ -1641,7 +1641,7 @@ copy_till (struct outstate *outstate, lin lastline)
+ if (size)
+ {
+ if ((! outstate->after_newline && putc ('\n', fp) == EOF)
+- || ! fwrite (s, sizeof *s, size, fp))
++ || fwrite (s, sizeof *s, size, fp) < size)
+ write_fatal ();
+ outstate->after_newline = s[size - 1] == '\n';
+ outstate->zero_output = false;
+diff --git a/src/pch.c b/src/pch.c
+index cda3dfa..79a3c99 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2279,8 +2279,11 @@ pfetch (lin line)
+ bool
+ pch_write_line (lin line, FILE *file)
+ {
+- bool after_newline = (p_len[line] > 0) && (p_line[line][p_len[line] - 1] == '\n');
+- if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file))
++ bool after_newline =
++ (p_len[line] > 0) && (p_line[line][p_len[line] - 1] == '\n');
++
++ if (fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file)
++ < p_len[line])
+ write_fatal ();
+ return after_newline;
+ }
+@@ -2427,13 +2430,14 @@ do_ed_script (char const *inname, char const *outname,
+ ed_command_letter = get_ed_command_letter (buf);
+ if (ed_command_letter) {
+ if (tmpfp)
+- if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
++ if (fwrite (buf, sizeof *buf, chars_read, tmpfp) < chars_read)
+ write_fatal ();
+ if (ed_command_letter != 'd' && ed_command_letter != 's') {
+ p_pass_comments_through = true;
+ while ((chars_read = get_line ()) != 0) {
+ if (tmpfp)
+- if (! fwrite (buf, sizeof *buf, chars_read, tmpfp))
++ if (fwrite (buf, sizeof *buf, chars_read, tmpfp)
++ < chars_read)
+ write_fatal ();
+ if (chars_read == 2 && strEQ (buf, ".\n"))
+ break;
+@@ -2448,7 +2452,7 @@ do_ed_script (char const *inname, char const *outname,
+ }
+ if (dry_run || skip_rest_of_patch)
+ return;
+- if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0
++ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) < (size_t) 4
+ || fflush (tmpfp) != 0)
+ write_fatal ();
+
diff --git a/patch-2.7.6-cleanups-in-do_ed_script.patch b/patch-2.7.6-cleanups-in-do_ed_script.patch
new file mode 100644
index 0000000..1fab381
--- /dev/null
+++ b/patch-2.7.6-cleanups-in-do_ed_script.patch
@@ -0,0 +1,91 @@
+commit 2a32bf09f5e9572da4be183bb0dbde8164351474
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Apr 6 20:32:46 2018 +0200
+
+ Minor cleanups in do_ed_script
+
+ * src/pch.c (do_ed_script): Minor cleanups.
+
+diff --git a/src/pch.c b/src/pch.c
+index 1f14624..1055542 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2396,6 +2396,10 @@ do_ed_script (char const *inname, char const *outname,
+ char const *tmpname;
+ int tmpfd;
+ pid_t pid;
++ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
++ char const **ed_argv;
++ int stdin_dup, status;
++
+
+ if (! dry_run && ! skip_rest_of_patch)
+ {
+@@ -2443,7 +2447,7 @@ do_ed_script (char const *inname, char const *outname,
+ break;
+ }
+ }
+- if (!tmpfp)
++ if (dry_run || skip_rest_of_patch)
+ return;
+ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0
+ || fflush (tmpfp) != 0)
+@@ -2452,36 +2456,29 @@ do_ed_script (char const *inname, char const *outname,
+ if (lseek (tmpfd, 0, SEEK_SET) == -1)
+ pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));
+
+- if (! dry_run && ! skip_rest_of_patch) {
+- int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+- char const **ed_argv;
+- int stdin_dup, status;
+-
++ if (inerrno != ENOENT)
++ {
+ *outname_needs_removal = true;
+- if (inerrno != ENOENT)
+- {
+- *outname_needs_removal = true;
+- copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+- }
+- fflush (stdout);
+-
+- if ((stdin_dup = dup (0)) == -1
+- || dup2 (tmpfd, 0) == -1)
+- pfatal ("Failed to duplicate standard input");
+- assert (outname[0] != '!' && outname[0] != '-');
+- ed_argv = alloca (4 * sizeof * ed_argv);
+- ed_argv[0] = editor_program;
+- ed_argv[1] = "-";
+- ed_argv[2] = outname;
+- ed_argv[3] = (char *) NULL;
+- status = execute (editor_program, editor_program, (char **)ed_argv,
+- false, false, false, false, true, false, NULL);
+- if (status)
+- fatal ("%s FAILED", editor_program);
+- if (dup2 (stdin_dup, 0) == -1
+- || close (stdin_dup) == -1)
+- pfatal ("Failed to duplicate standard input");
+- }
++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++ }
++ fflush (stdout);
++
++ if ((stdin_dup = dup (0)) == -1
++ || dup2 (tmpfd, 0) == -1)
++ pfatal ("Failed to duplicate standard input");
++ assert (outname[0] != '!' && outname[0] != '-');
++ ed_argv = alloca (4 * sizeof * ed_argv);
++ ed_argv[0] = editor_program;
++ ed_argv[1] = "-";
++ ed_argv[2] = outname;
++ ed_argv[3] = (char *) NULL;
++ status = execute (editor_program, editor_program, (char **)ed_argv,
++ false, false, false, false, true, false, NULL);
++ if (status)
++ fatal ("%s FAILED", editor_program);
++ if (dup2 (stdin_dup, 0) == -1
++ || close (stdin_dup) == -1)
++ pfatal ("Failed to duplicate standard input");
+
+ fclose (tmpfp);
+ safe_unlink (tmpname);
diff --git a/patch-2.7.6-crash-RLIMIT_NOFILE.patch b/patch-2.7.6-crash-RLIMIT_NOFILE.patch
new file mode 100644
index 0000000..c0f4fe1
--- /dev/null
+++ b/patch-2.7.6-crash-RLIMIT_NOFILE.patch
@@ -0,0 +1,84 @@
+commit 61d7788b83b302207a67b82786f4fd79e3538f30
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Thu Jun 27 11:10:43 2019 +0200
+
+ Don't crash when RLIMIT_NOFILE is set to RLIM_INFINITY
+
+ * src/safe.c (min_cached_fds): Define minimum number of cached dir file
+ descriptors.
+ (max_cached_fds): Change type to rlim_t to allow storing RLIM_INFINITY.
+ (init_dirfd_cache): Set max_cached_fds to RLIM_INFINITY when RLIMIT_NOFILE is
+ RLIM_INFINITY. Set the initial hash table size to min_cached_fds, independent
+ of RLIMIT_NOFILE: patches commonly only affect one or a few files, so a small
+ hash table will usually suffice; if needed, the hash table will grow.
+ (insert_cached_dirfd): Don't shrink the cache when max_cached_fds is
+ RLIM_INFINITY.
+
+diff --git a/src/safe.c b/src/safe.c
+index 5a7202f..f147b0e 100644
+--- a/src/safe.c
++++ b/src/safe.c
+@@ -67,7 +67,8 @@ struct cached_dirfd {
+ };
+
+ static Hash_table *cached_dirfds = NULL;
+-static size_t max_cached_fds;
++static rlim_t min_cached_fds = 8;
++static rlim_t max_cached_fds;
+ LIST_HEAD (lru_list);
+
+ static size_t hash_cached_dirfd (const void *entry, size_t table_size)
+@@ -98,11 +99,17 @@ static void init_dirfd_cache (void)
+ {
+ struct rlimit nofile;
+
+- max_cached_fds = 8;
+ if (getrlimit (RLIMIT_NOFILE, &nofile) == 0)
+- max_cached_fds = MAX (nofile.rlim_cur / 4, max_cached_fds);
++ {
++ if (nofile.rlim_cur == RLIM_INFINITY)
++ max_cached_fds = RLIM_INFINITY;
++ else
++ max_cached_fds = MAX (nofile.rlim_cur / 4, min_cached_fds);
++ }
++ else
++ max_cached_fds = min_cached_fds;
+
+- cached_dirfds = hash_initialize (max_cached_fds,
++ cached_dirfds = hash_initialize (min_cached_fds,
+ NULL,
+ hash_cached_dirfd,
+ compare_cached_dirfds,
+@@ -148,20 +155,23 @@ static void insert_cached_dirfd (struct cached_dirfd *entry, int keepfd)
+ if (cached_dirfds == NULL)
+ init_dirfd_cache ();
+
+- /* Trim off the least recently used entries */
+- while (hash_get_n_entries (cached_dirfds) >= max_cached_fds)
++ if (max_cached_fds != RLIM_INFINITY)
+ {
+- struct cached_dirfd *last =
+- list_entry (lru_list.prev, struct cached_dirfd, lru_link);
+- if (&last->lru_link == &lru_list)
+- break;
+- if (last->fd == keepfd)
++ /* Trim off the least recently used entries */
++ while (hash_get_n_entries (cached_dirfds) >= max_cached_fds)
+ {
+- last = list_entry (last->lru_link.prev, struct cached_dirfd, lru_link);
++ struct cached_dirfd *last =
++ list_entry (lru_list.prev, struct cached_dirfd, lru_link);
+ if (&last->lru_link == &lru_list)
+ break;
++ if (last->fd == keepfd)
++ {
++ last = list_entry (last->lru_link.prev, struct cached_dirfd, lru_link);
++ if (&last->lru_link == &lru_list)
++ break;
++ }
++ remove_cached_dirfd (last);
+ }
+- remove_cached_dirfd (last);
+ }
+
+ /* Only insert if the parent still exists. */
diff --git a/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch b/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch
new file mode 100644
index 0000000..d0c7869
--- /dev/null
+++ b/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch
@@ -0,0 +1,95 @@
+commit 19599883ffb6a450d2884f081f8ecf68edbed7ee
+Author: Jean Delvare <jdelvare at suse.de>
+Date: Thu May 3 14:31:55 2018 +0200
+
+ Don't leak temporary file on failed ed-style patch
+
+ Now that we write ed-style patches to a temporary file before we
+ apply them, we need to ensure that the temporary file is removed
+ before we leave, even on fatal error.
+
+ * src/pch.c (do_ed_script): Use global TMPEDNAME instead of local
+ tmpname. Don't unlink the file directly, instead tag it for removal
+ at exit time.
+ * src/patch.c (cleanup): Unlink TMPEDNAME at exit.
+
+ This closes bug #53820:
+ https://savannah.gnu.org/bugs/index.php?53820
+
+ Fixes: 123eaff0d5d1 ("Fix arbitrary command execution in ed-style patches (CVE-2018-1000156)")
+
+diff --git a/src/common.h b/src/common.h
+index 904a3f8..53c5e32 100644
+--- a/src/common.h
++++ b/src/common.h
+@@ -94,10 +94,12 @@ XTERN char const *origsuff;
+ XTERN char const * TMPINNAME;
+ XTERN char const * TMPOUTNAME;
+ XTERN char const * TMPPATNAME;
++XTERN char const * TMPEDNAME;
+
+ XTERN bool TMPINNAME_needs_removal;
+ XTERN bool TMPOUTNAME_needs_removal;
+ XTERN bool TMPPATNAME_needs_removal;
++XTERN bool TMPEDNAME_needs_removal;
+
+ #ifdef DEBUGGING
+ XTERN int debug;
+diff --git a/src/patch.c b/src/patch.c
+index 3fcaec5..9146597 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -1999,6 +1999,7 @@ cleanup (void)
+ remove_if_needed (TMPINNAME, &TMPINNAME_needs_removal);
+ remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal);
+ remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal);
++ remove_if_needed (TMPEDNAME, &TMPEDNAME_needs_removal);
+ remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal);
+ output_files (NULL);
+ }
+diff --git a/src/pch.c b/src/pch.c
+index 79a3c99..1bb3153 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -2396,7 +2396,6 @@ do_ed_script (char const *inname, char const *outname,
+ file_offset beginning_of_this_line;
+ size_t chars_read;
+ FILE *tmpfp = 0;
+- char const *tmpname;
+ int tmpfd = -1; /* placate gcc's -Wmaybe-uninitialized */
+ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
+ char const **ed_argv;
+@@ -2411,12 +2410,13 @@ do_ed_script (char const *inname, char const *outname,
+ invalid commands and treats the next line as a new command, which
+ can lead to arbitrary command execution. */
+
+- tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
++ tmpfd = make_tempfile (&TMPEDNAME, 'e', NULL, O_RDWR | O_BINARY, 0);
+ if (tmpfd == -1)
+- pfatal ("Can't create temporary file %s", quotearg (tmpname));
++ pfatal ("Can't create temporary file %s", quotearg (TMPEDNAME));
++ TMPEDNAME_needs_removal = true;
+ tmpfp = fdopen (tmpfd, "w+b");
+ if (! tmpfp)
+- pfatal ("Can't open stream for file %s", quotearg (tmpname));
++ pfatal ("Can't open stream for file %s", quotearg (TMPEDNAME));
+ }
+
+ for (;;) {
+@@ -2457,7 +2457,7 @@ do_ed_script (char const *inname, char const *outname,
+ write_fatal ();
+
+ if (lseek (tmpfd, 0, SEEK_SET) == -1)
+- pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));
++ pfatal ("Can't rewind to the beginning of file %s", quotearg (TMPEDNAME));
+
+ if (inerrno != ENOENT)
+ {
+@@ -2484,7 +2484,6 @@ do_ed_script (char const *inname, char const *outname,
+ pfatal ("Failed to duplicate standard input");
+
+ fclose (tmpfp);
+- safe_unlink (tmpname);
+
+ if (ofp)
+ {
diff --git a/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch b/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch
new file mode 100644
index 0000000..959a59c
--- /dev/null
+++ b/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch
@@ -0,0 +1,71 @@
+commit 369dcccdfa6336e5a873d6d63705cfbe04c55727
+Author: Jean Delvare <jdelvare at suse.de>
+Date: Mon May 7 15:14:45 2018 +0200
+
+ Don't leak temporary file on failed multi-file ed-style patch
+
+ The previous fix worked fine with single-file ed-style patches, but
+ would still leak temporary files in the case of multi-file ed-style
+ patch. Fix that case as well, and extend the test case to check for
+ it.
+
+ * src/patch.c (main): Unlink TMPEDNAME if needed before moving to
+ the next file in a patch.
+
+ This closes bug #53820:
+ https://savannah.gnu.org/bugs/index.php?53820
+
+ Fixes: 123eaff0d5d1 ("Fix arbitrary command execution in ed-style patches (CVE-2018-1000156)")
+ Fixes: 19599883ffb6 ("Don't leak temporary file on failed ed-style patch")
+
+diff --git a/src/patch.c b/src/patch.c
+index 9146597..81c7a02 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -236,6 +236,7 @@ main (int argc, char **argv)
+ }
+ remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal);
+ }
++ remove_if_needed (TMPEDNAME, &TMPEDNAME_needs_removal);
+
+ if (! skip_rest_of_patch && ! file_type)
+ {
+diff --git a/tests/ed-style b/tests/ed-style
+index 6b6ef9d..504e6e5 100644
+--- a/tests/ed-style
++++ b/tests/ed-style
+@@ -38,3 +38,34 @@ EOF
+ check 'cat foo' <<EOF
+ foo
+ EOF
++
++# Test the case where one ed-style patch modifies several files
++
++cat > ed3.diff <<EOF
++--- foo
+++++ foo
++1c
++bar
++.
++--- baz
+++++ baz
++0a
++baz
++.
++EOF
++
++# Apparently we can't create a file with such a patch, while it works fine
++# when the file name is provided on the command line
++cat > baz <<EOF
++EOF
++
++check 'patch -e -i ed3.diff' <<EOF
++EOF
++
++check 'cat foo' <<EOF
++bar
++EOF
++
++check 'cat baz' <<EOF
++baz
++EOF
diff --git a/patch-2.7.6-failed_assertion.patch b/patch-2.7.6-failed_assertion.patch
new file mode 100644
index 0000000..f3d9022
--- /dev/null
+++ b/patch-2.7.6-failed_assertion.patch
@@ -0,0 +1,29 @@
+commit 76e775847f4954b63dc72afe34d9d921c6688b31
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Tue Jul 16 01:16:28 2019 +0200
+
+ Fix failed assertion 'outstate->after_newline'
+
+ The assertion triggers when the -o FILE option is used, more than one output
+ file is written into FILE, and one of those files (except the last one) ends in
+ the middle of a line.
+ * src/patch.c (main): Fix the case described above.
+
+diff --git a/src/patch.c b/src/patch.c
+index 02fd982..3794319 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -369,6 +369,13 @@ main (int argc, char **argv)
+ /* outstate.ofp now owns the file descriptor */
+ outfd = -1;
+ }
++ else
++ {
++ /* When writing to a single output file (-o FILE), always pretend
++ that the output file ends in a newline. Otherwise, when another
++ file is written to the same output file, apply_hunk will fail. */
++ outstate.after_newline = true;
++ }
+
+ /* find out where all the lines are */
+ if (!skip_rest_of_patch) {
diff --git a/patch-2.7.6-fix-ed-style-test-failure.patch b/patch-2.7.6-fix-ed-style-test-failure.patch
new file mode 100644
index 0000000..609516d
--- /dev/null
+++ b/patch-2.7.6-fix-ed-style-test-failure.patch
@@ -0,0 +1,22 @@
+commit 458ac51a05426c1af9aa6bf1342ecf60728c19b4
+Author: Bruno Haible <bruno at clisp.org>
+Date: Sat Apr 7 12:34:03 2018 +0200
+
+ Fix 'ed-style' test failure.
+
+ * tests/ed-style: Remove '?' line from expected output.
+
+diff --git a/tests/ed-style b/tests/ed-style
+index d8c0689..6b6ef9d 100644
+--- a/tests/ed-style
++++ b/tests/ed-style
+@@ -31,8 +31,7 @@ r !echo bar
+ ,p
+ EOF
+
+-check 'patch -e foo -i ed2.diff 2> /dev/null || echo "Status: $?"' <<EOF
+-?
++check 'patch -e foo -i ed2.diff > /dev/null 2> /dev/null || echo "Status: $?"' <<EOF
+ Status: 2
+ EOF
+
diff --git a/patch-2.7.6-fix-korn-shell-incompatibility.patch b/patch-2.7.6-fix-korn-shell-incompatibility.patch
new file mode 100644
index 0000000..ec2c23f
--- /dev/null
+++ b/patch-2.7.6-fix-korn-shell-incompatibility.patch
@@ -0,0 +1,21 @@
+commit 074e2395f81d0ecaa66b71a6c228c70b49db72e5
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Wed Feb 7 17:05:00 2018 +0100
+
+ Test suite: fix Korn shell incompatibility
+
+ tests/merge: In a Korn shell, shift apparently fails when $# is 0.
+
+diff --git a/tests/merge b/tests/merge
+index b628891..e950b92 100644
+--- a/tests/merge
++++ b/tests/merge
+@@ -32,7 +32,7 @@ x2() {
+ shift
+ done > b.sed
+ echo "$body" | sed -f b.sed > b
+- shift
++ test $# -eq 0 || shift
+ while test $# -gt 0 ; do
+ echo "$1"
+ shift
diff --git a/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch b/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch
new file mode 100644
index 0000000..c5bcba5
--- /dev/null
+++ b/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch
@@ -0,0 +1,24 @@
+commit f290f48a621867084884bfff87f8093c15195e6a
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Mon Feb 12 16:48:24 2018 +0100
+
+ Fix segfault with mangled rename patch
+
+ http://savannah.gnu.org/bugs/?53132
+ * src/pch.c (intuit_diff_type): Ensure that two filenames are specified
+ for renames and copies (fix the existing check).
+
+diff --git a/src/pch.c b/src/pch.c
+index ff9ed2c..bc6278c 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -974,7 +974,8 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
+ if ((pch_rename () || pch_copy ())
+ && ! inname
+ && ! ((i == OLD || i == NEW) &&
+- p_name[! reverse] &&
++ p_name[reverse] && p_name[! reverse] &&
++ name_is_valid (p_name[reverse]) &&
+ name_is_valid (p_name[! reverse])))
+ {
+ say ("Cannot %s file without two valid file names\n", pch_rename () ? "rename" : "copy");
diff --git a/patch-2.7.6-improve_support_for_memory_leak_detection.patch b/patch-2.7.6-improve_support_for_memory_leak_detection.patch
new file mode 100644
index 0000000..fc92ff0
--- /dev/null
+++ b/patch-2.7.6-improve_support_for_memory_leak_detection.patch
@@ -0,0 +1,48 @@
+commit 2b584aec9e5f2806b1eccadcabe7e901fcfa0b0a
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Thu Jun 27 11:02:02 2019 +0200
+
+ Improve support for memory leak detection
+
+ When building with the address sanitizer on, free some more resources before
+ exiting. (This is unnecessary when not looking for memory leaks.)
+ * src/patch.c (init_files_to_delete): Add dispose function for freeing
+ filenames.
+
+diff --git a/src/patch.c b/src/patch.c
+index 81c7a02..4616a48 100644
+--- a/src/patch.c
++++ b/src/patch.c
+@@ -36,6 +36,10 @@
+ #include <minmax.h>
+ #include <safe.h>
+
++#ifdef __SANITIZE_ADDRESS__
++# define FREE_BEFORE_EXIT
++#endif
++
+ /* procedures */
+
+ static FILE *create_output_file (char const *, int);
+@@ -1777,10 +1781,20 @@ struct file_to_delete {
+
+ static gl_list_t files_to_delete;
+
++#ifdef FREE_BEFORE_EXIT
++void dispose_file_to_delete (const void *elt)
++{
++ free ((void *) elt);
++}
++#else
++#define dispose_file_to_delete NULL
++#endif
++
+ static void
+ init_files_to_delete (void)
+ {
+- files_to_delete = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, true);
++ files_to_delete = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL,
++ dispose_file_to_delete, true);
+ }
+
+ static void
diff --git a/patch-2.7.6-make-debug-output-more-useful.patch b/patch-2.7.6-make-debug-output-more-useful.patch
new file mode 100644
index 0000000..69e79c2
--- /dev/null
+++ b/patch-2.7.6-make-debug-output-more-useful.patch
@@ -0,0 +1,40 @@
+commit ff81775f4eb6ab9a91b75e4031e8216654c0c76a
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Aug 17 10:31:22 2018 +0200
+
+ Make the (debug & 2) output more useful
+
+ * src/pch.c (another_hunk): In the (debug & 2) output, fix how empty
+ lines that are not part of the patch context are printed. Also, add
+ newlines to lines that are missing them to keep the output readable.
+
+diff --git a/src/pch.c b/src/pch.c
+index 1bb3153..e92bc64 100644
+--- a/src/pch.c
++++ b/src/pch.c
+@@ -1916,8 +1916,13 @@ another_hunk (enum diff difftype, bool rev)
+ lin i;
+
+ for (i = 0; i <= p_end + 1; i++) {
+- fprintf (stderr, "%s %c",
+- format_linenum (numbuf0, i),
++ fputs (format_linenum (numbuf0, i), stderr);
++ if (p_Char[i] == '\n')
++ {
++ fputc('\n', stderr);
++ continue;
++ }
++ fprintf (stderr, " %c",
+ p_Char[i]);
+ if (p_Char[i] == '*')
+ fprintf (stderr, " %s,%s\n",
+@@ -1930,7 +1935,8 @@ another_hunk (enum diff difftype, bool rev)
+ else if (p_Char[i] != '^')
+ {
+ fputs(" |", stderr);
+- pch_write_line (i, stderr);
++ if (! pch_write_line (i, stderr))
++ fputc('\n', stderr);
+ }
+ else
+ fputc('\n', stderr);
diff --git a/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch b/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch
new file mode 100644
index 0000000..e9738ad
--- /dev/null
+++ b/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch
@@ -0,0 +1,20 @@
+commit a5b442ce01b80a758606ede316f739426a12bc33
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Thu Jun 27 11:09:31 2019 +0200
+
+ Skip "ed" test when the ed utility is not installed
+
+ * tests/ed-style: Require ed.
+
+diff --git a/tests/ed-style b/tests/ed-style
+index 504e6e5..9907cb6 100644
+--- a/tests/ed-style
++++ b/tests/ed-style
+@@ -7,6 +7,7 @@
+ . $srcdir/test-lib.sh
+
+ require cat
++require ed
+ use_local_patch
+ use_tmpdir
+
diff --git a/patch-2.7.6-switch-from-fork-execlp-to-execute.patch b/patch-2.7.6-switch-from-fork-execlp-to-execute.patch
new file mode 100644
index 0000000..4212552
--- /dev/null
+++ b/patch-2.7.6-switch-from-fork-execlp-to-execute.patch
@@ -0,0 +1,1774 @@
+diff -up patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.c
+--- patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.264464824 +0200
++++ patch-2.7.6/lib/execute.c 2019-07-29 14:40:53.264464824 +0200
+@@ -0,0 +1,273 @@
++/* Creation of autonomous subprocesses.
++ Copyright (C) 2001-2004, 2006-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <haible at clisp.cons.org>, 2001.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++
++#include <config.h>
++
++/* Specification. */
++#include "execute.h"
++
++#include <errno.h>
++#include <fcntl.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <unistd.h>
++
++#include "error.h"
++#include "fatal-signal.h"
++#include "wait-process.h"
++#include "gettext.h"
++
++#define _(str) gettext (str)
++
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++
++/* Native Windows API. */
++# include <process.h>
++# include "w32spawn.h"
++
++#else
++
++/* Unix API. */
++# include <spawn.h>
++
++#endif
++
++
++#if defined EINTR && ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
++
++/* EINTR handling for close(), open().
++ These functions can return -1/EINTR even though we don't have any
++ signal handlers set up, namely when we get interrupted via SIGSTOP. */
++
++static int
++nonintr_close (int fd)
++{
++ int retval;
++
++ do
++ retval = close (fd);
++ while (retval < 0 && errno == EINTR);
++
++ return retval;
++}
++#define close nonintr_close
++
++static int
++nonintr_open (const char *pathname, int oflag, mode_t mode)
++{
++ int retval;
++
++ do
++ retval = open (pathname, oflag, mode);
++ while (retval < 0 && errno == EINTR);
++
++ return retval;
++}
++#undef open /* avoid warning on VMS */
++#define open nonintr_open
++
++#endif
++
++
++/* Execute a command, optionally redirecting any of the three standard file
++ descriptors to /dev/null. Return its exit code.
++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise
++ return 127.
++ If slave_process is true, the child process will be terminated when its
++ creator receives a catchable fatal signal. */
++int
++execute (const char *progname,
++ const char *prog_path, char **prog_argv,
++ bool ignore_sigpipe,
++ bool null_stdin, bool null_stdout, bool null_stderr,
++ bool slave_process, bool exit_on_error,
++ int *termsigp)
++{
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++
++ /* Native Windows API. */
++ int orig_stdin;
++ int orig_stdout;
++ int orig_stderr;
++ int exitcode;
++ int nullinfd;
++ int nulloutfd;
++
++ /* FIXME: Need to free memory allocated by prepare_spawn. */
++ prog_argv = prepare_spawn (prog_argv);
++
++ /* Save standard file handles of parent process. */
++ if (null_stdin)
++ orig_stdin = dup_safer_noinherit (STDIN_FILENO);
++ if (null_stdout)
++ orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
++ if (null_stderr)
++ orig_stderr = dup_safer_noinherit (STDERR_FILENO);
++ exitcode = -1;
++
++ /* Create standard file handles of child process. */
++ nullinfd = -1;
++ nulloutfd = -1;
++ if ((!null_stdin
++ || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
++ && (nullinfd == STDIN_FILENO
++ || (dup2 (nullinfd, STDIN_FILENO) >= 0
++ && close (nullinfd) >= 0))))
++ && (!(null_stdout || null_stderr)
++ || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
++ && (!null_stdout
++ || nulloutfd == STDOUT_FILENO
++ || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
++ && (!null_stderr
++ || nulloutfd == STDERR_FILENO
++ || dup2 (nulloutfd, STDERR_FILENO) >= 0)
++ && ((null_stdout && nulloutfd == STDOUT_FILENO)
++ || (null_stderr && nulloutfd == STDERR_FILENO)
++ || close (nulloutfd) >= 0))))
++ /* Use spawnvpe and pass the environment explicitly. This is needed if
++ the program has modified the environment using putenv() or [un]setenv().
++ On Windows, programs have two environments, one in the "environment
++ block" of the process and managed through SetEnvironmentVariable(), and
++ one inside the process, in the location retrieved by the 'environ'
++ macro. When using spawnvp() without 'e', the child process inherits a
++ copy of the environment block - ignoring the effects of putenv() and
++ [un]setenv(). */
++ {
++ exitcode = spawnvpe (P_WAIT, prog_path, (const char **) prog_argv,
++ (const char **) environ);
++ if (exitcode < 0 && errno == ENOEXEC)
++ {
++ /* prog is not a native executable. Try to execute it as a
++ shell script. Note that prepare_spawn() has already prepended
++ a hidden element "sh.exe" to prog_argv. */
++ --prog_argv;
++ exitcode = spawnvpe (P_WAIT, prog_argv[0], (const char **) prog_argv,
++ (const char **) environ);
++ }
++ }
++ if (nulloutfd >= 0)
++ close (nulloutfd);
++ if (nullinfd >= 0)
++ close (nullinfd);
++
++ /* Restore standard file handles of parent process. */
++ if (null_stderr)
++ undup_safer_noinherit (orig_stderr, STDERR_FILENO);
++ if (null_stdout)
++ undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
++ if (null_stdin)
++ undup_safer_noinherit (orig_stdin, STDIN_FILENO);
++
++ if (termsigp != NULL)
++ *termsigp = 0;
++
++ if (exitcode == -1)
++ {
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, errno,
++ _("%s subprocess failed"), progname);
++ return 127;
++ }
++
++ return exitcode;
++
++#else
++
++ /* Unix API. */
++ /* Note about 127: Some errors during posix_spawnp() cause the function
++ posix_spawnp() to return an error code; some other errors cause the
++ subprocess to exit with return code 127. It is implementation
++ dependent which error is reported which way. We treat both cases as
++ equivalent. */
++ sigset_t blocked_signals;
++ posix_spawn_file_actions_t actions;
++ bool actions_allocated;
++ posix_spawnattr_t attrs;
++ bool attrs_allocated;
++ int err;
++ pid_t child;
++
++ if (slave_process)
++ {
++ sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
++ block_fatal_signals ();
++ }
++ actions_allocated = false;
++ attrs_allocated = false;
++ if ((err = posix_spawn_file_actions_init (&actions)) != 0
++ || (actions_allocated = true,
++ (null_stdin
++ && (err = posix_spawn_file_actions_addopen (&actions,
++ STDIN_FILENO,
++ "/dev/null", O_RDONLY,
++ 0))
++ != 0)
++ || (null_stdout
++ && (err = posix_spawn_file_actions_addopen (&actions,
++ STDOUT_FILENO,
++ "/dev/null", O_RDWR,
++ 0))
++ != 0)
++ || (null_stderr
++ && (err = posix_spawn_file_actions_addopen (&actions,
++ STDERR_FILENO,
++ "/dev/null", O_RDWR,
++ 0))
++ != 0)
++ || (slave_process
++ && ((err = posix_spawnattr_init (&attrs)) != 0
++ || (attrs_allocated = true,
++ (err = posix_spawnattr_setsigmask (&attrs,
++ &blocked_signals))
++ != 0
++ || (err = posix_spawnattr_setflags (&attrs,
++ POSIX_SPAWN_SETSIGMASK))
++ != 0)))
++ || (err = posix_spawnp (&child, prog_path, &actions,
++ attrs_allocated ? &attrs : NULL, prog_argv,
++ environ))
++ != 0))
++ {
++ if (actions_allocated)
++ posix_spawn_file_actions_destroy (&actions);
++ if (attrs_allocated)
++ posix_spawnattr_destroy (&attrs);
++ if (slave_process)
++ unblock_fatal_signals ();
++ if (termsigp != NULL)
++ *termsigp = 0;
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, err,
++ _("%s subprocess failed"), progname);
++ return 127;
++ }
++ posix_spawn_file_actions_destroy (&actions);
++ if (attrs_allocated)
++ posix_spawnattr_destroy (&attrs);
++ if (slave_process)
++ {
++ register_slave_subprocess (child);
++ unblock_fatal_signals ();
++ }
++
++ return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
++ slave_process, exit_on_error, termsigp);
++
++#endif
++}
+diff -up patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.h
+--- patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.264464824 +0200
++++ patch-2.7.6/lib/execute.h 2019-07-29 14:40:53.264464824 +0200
+@@ -0,0 +1,44 @@
++/* Creation of autonomous subprocesses.
++ Copyright (C) 2001-2003, 2008-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <haible at clisp.cons.org>, 2001.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _EXECUTE_H
++#define _EXECUTE_H
++
++#include <stdbool.h>
++
++/* Execute a command, optionally redirecting any of the three standard file
++ descriptors to /dev/null. Return its exit code.
++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise
++ return 127.
++ If ignore_sigpipe is true, consider a subprocess termination due to SIGPIPE
++ as equivalent to a success. This is suitable for processes whose only
++ purpose is to write to standard output.
++ If slave_process is true, the child process will be terminated when its
++ creator receives a catchable fatal signal.
++ If termsigp is not NULL, *termsig will be set to the signal that terminated
++ the subprocess (if supported by the platform: not on native Windows
++ platforms), otherwise 0.
++ It is recommended that no signal is blocked or ignored while execute()
++ is called. See pipe.h for the reason. */
++extern int execute (const char *progname,
++ const char *prog_path, char **prog_argv,
++ bool ignore_sigpipe,
++ bool null_stdin, bool null_stdout, bool null_stderr,
++ bool slave_process, bool exit_on_error,
++ int *termsigp);
++
++#endif /* _EXECUTE_H */
+diff -up patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.c
+--- patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute 2019-07-29 14:51:00.441882754 +0200
++++ patch-2.7.6/lib/fatal-signal.c 2019-07-29 14:51:00.441882754 +0200
+@@ -0,0 +1,286 @@
++/* Emergency actions in case of a fatal signal.
++ Copyright (C) 2003-2004, 2006-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <bruno at clisp.org>, 2003.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++
++#include <config.h>
++
++/* Specification. */
++#include "fatal-signal.h"
++
++#include <stdbool.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <unistd.h>
++
++#include "sig-handler.h"
++#include "xalloc.h"
++
++#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
++
++/* ========================================================================= */
++
++
++/* The list of fatal signals.
++ These are those signals whose default action is to terminate the process
++ without a core dump, except
++ SIGKILL - because it cannot be caught,
++ SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications
++ often use them for their own purpose,
++ SIGPROF SIGVTALRM - because they are used for profiling,
++ SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS,
++ SIGSYS - because it is more similar to SIGABRT, SIGSEGV,
++ SIGPWR - because it of too special use,
++ SIGRTMIN...SIGRTMAX - because they are reserved for application use.
++ plus
++ SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */
++
++static int fatal_signals[] =
++ {
++ /* ISO C 99 signals. */
++#ifdef SIGINT
++ SIGINT,
++#endif
++#ifdef SIGTERM
++ SIGTERM,
++#endif
++ /* POSIX:2001 signals. */
++#ifdef SIGHUP
++ SIGHUP,
++#endif
++#ifdef SIGPIPE
++ SIGPIPE,
++#endif
++ /* BSD signals. */
++#ifdef SIGXCPU
++ SIGXCPU,
++#endif
++#ifdef SIGXFSZ
++ SIGXFSZ,
++#endif
++ /* Native Windows signals. */
++#ifdef SIGBREAK
++ SIGBREAK,
++#endif
++ 0
++ };
++
++#define num_fatal_signals (SIZEOF (fatal_signals) - 1)
++
++/* Eliminate signals whose signal handler is SIG_IGN. */
++
++static void
++init_fatal_signals (void)
++{
++ static bool fatal_signals_initialized = false;
++ if (!fatal_signals_initialized)
++ {
++ size_t i;
++
++ for (i = 0; i < num_fatal_signals; i++)
++ {
++ struct sigaction action;
++
++ if (sigaction (fatal_signals[i], NULL, &action) >= 0
++ && get_handler (&action) == SIG_IGN)
++ fatal_signals[i] = -1;
++ }
++
++ fatal_signals_initialized = true;
++ }
++}
++
++
++/* ========================================================================= */
++
++
++typedef void (*action_t) (void);
++
++/* Type of an entry in the actions array.
++ The 'action' field is accessed from within the fatal_signal_handler(),
++ therefore we mark it as 'volatile'. */
++typedef struct
++{
++ volatile action_t action;
++}
++actions_entry_t;
++
++/* The registered cleanup actions. */
++static actions_entry_t static_actions[32];
++static actions_entry_t * volatile actions = static_actions;
++static sig_atomic_t volatile actions_count = 0;
++static size_t actions_allocated = SIZEOF (static_actions);
++
++
++/* The saved signal handlers.
++ Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */
++static struct sigaction saved_sigactions[64];
++
++
++/* Uninstall the handlers. */
++static void
++uninstall_handlers (void)
++{
++ size_t i;
++
++ for (i = 0; i < num_fatal_signals; i++)
++ if (fatal_signals[i] >= 0)
++ {
++ int sig = fatal_signals[i];
++ if (saved_sigactions[sig].sa_handler == SIG_IGN)
++ saved_sigactions[sig].sa_handler = SIG_DFL;
++ sigaction (sig, &saved_sigactions[sig], NULL);
++ }
++}
++
++
++/* The signal handler. It gets called asynchronously. */
++static void
++fatal_signal_handler (int sig)
++{
++ for (;;)
++ {
++ /* Get the last registered cleanup action, in a reentrant way. */
++ action_t action;
++ size_t n = actions_count;
++ if (n == 0)
++ break;
++ n--;
++ actions_count = n;
++ action = actions[n].action;
++ /* Execute the action. */
++ action ();
++ }
++
++ /* Now execute the signal's default action.
++ If the signal being delivered was blocked, the re-raised signal would be
++ delivered when this handler returns. But the way we install this handler,
++ no signal is blocked, and the re-raised signal is delivered already
++ during raise(). */
++ uninstall_handlers ();
++ raise (sig);
++}
++
++
++/* Install the handlers. */
++static void
++install_handlers (void)
++{
++ size_t i;
++ struct sigaction action;
++
++ action.sa_handler = &fatal_signal_handler;
++ /* If we get a fatal signal while executing fatal_signal_handler, enter
++ fatal_signal_handler recursively, since it is reentrant. Hence no
++ SA_RESETHAND. */
++ action.sa_flags = SA_NODEFER;
++ sigemptyset (&action.sa_mask);
++ for (i = 0; i < num_fatal_signals; i++)
++ if (fatal_signals[i] >= 0)
++ {
++ int sig = fatal_signals[i];
++
++ if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0])))
++ abort ();
++ sigaction (sig, &action, &saved_sigactions[sig]);
++ }
++}
++
++
++/* Register a cleanup function to be executed when a catchable fatal signal
++ occurs. */
++void
++at_fatal_signal (action_t action)
++{
++ static bool cleanup_initialized = false;
++ if (!cleanup_initialized)
++ {
++ init_fatal_signals ();
++ install_handlers ();
++ cleanup_initialized = true;
++ }
++
++ if (actions_count == actions_allocated)
++ {
++ /* Extend the actions array. Note that we cannot use xrealloc(),
++ because then the cleanup() function could access an already
++ deallocated array. */
++ actions_entry_t *old_actions = actions;
++ size_t old_actions_allocated = actions_allocated;
++ size_t new_actions_allocated = 2 * actions_allocated;
++ actions_entry_t *new_actions =
++ XNMALLOC (new_actions_allocated, actions_entry_t);
++ size_t k;
++
++ /* Don't use memcpy() here, because memcpy takes non-volatile arguments
++ and is therefore not guaranteed to complete all memory stores before
++ the next statement. */
++ for (k = 0; k < old_actions_allocated; k++)
++ new_actions[k] = old_actions[k];
++ actions = new_actions;
++ actions_allocated = new_actions_allocated;
++ /* Now we can free the old actions array. */
++ if (old_actions != static_actions)
++ free (old_actions);
++ }
++ /* The two uses of 'volatile' in the types above (and ISO C 99 section
++ 5.1.2.3.(5)) ensure that we increment the actions_count only after
++ the new action has been written to the memory location
++ actions[actions_count]. */
++ actions[actions_count].action = action;
++ actions_count++;
++}
++
++
++/* ========================================================================= */
++
++
++static sigset_t fatal_signal_set;
++
++static void
++init_fatal_signal_set (void)
++{
++ static bool fatal_signal_set_initialized = false;
++ if (!fatal_signal_set_initialized)
++ {
++ size_t i;
++
++ init_fatal_signals ();
++
++ sigemptyset (&fatal_signal_set);
++ for (i = 0; i < num_fatal_signals; i++)
++ if (fatal_signals[i] >= 0)
++ sigaddset (&fatal_signal_set, fatal_signals[i]);
++
++ fatal_signal_set_initialized = true;
++ }
++}
++
++/* Temporarily delay the catchable fatal signals. */
++void
++block_fatal_signals (void)
++{
++ init_fatal_signal_set ();
++ sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
++}
++
++/* Stop delaying the catchable fatal signals. */
++void
++unblock_fatal_signals (void)
++{
++ init_fatal_signal_set ();
++ sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
++}
+diff -up patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.h
+--- patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute 2019-07-29 14:51:09.977920729 +0200
++++ patch-2.7.6/lib/fatal-signal.h 2019-07-29 14:51:09.977920729 +0200
+@@ -0,0 +1,76 @@
++/* Emergency actions in case of a fatal signal.
++ Copyright (C) 2003-2004, 2009-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <bruno at clisp.org>, 2003.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/* It is often useful to do some cleanup action when a usually fatal signal
++ terminates the process, like removing a temporary file or killing a
++ subprocess that may be stuck waiting for a device, pipe or network input.
++ Such signals are SIGHUP, SIGINT, SIGPIPE, SIGTERM, and possibly others.
++ The limitation of this facility is that it cannot work for SIGKILL.
++
++ Signals with a SIG_IGN handler are considered to be non-fatal. The
++ functions in this file assume that when a SIG_IGN handler is installed
++ for a signal, it was installed before any functions in this file were
++ called and it stays so for the whole lifetime of the process. */
++
++/* Register a cleanup function to be executed when a catchable fatal signal
++ occurs.
++
++ Restrictions for the cleanup function:
++ - The cleanup function can do all kinds of system calls.
++ - It can also access application dependent memory locations and data
++ structures provided they are in a consistent state. One way to ensure
++ this is through block_fatal_signals()/unblock_fatal_signals(), see
++ below. Another - more tricky - way to ensure this is the careful use
++ of 'volatile'.
++ However,
++ - malloc() and similarly complex facilities are not safe to be called
++ because they are not guaranteed to be in a consistent state.
++ - Also, the cleanup function must not block the catchable fatal signals
++ and leave them blocked upon return.
++
++ The cleanup function is executed asynchronously. It is unspecified
++ whether during its execution the catchable fatal signals are blocked
++ or not. */
++extern void at_fatal_signal (void (*function) (void));
++
++
++/* Sometimes it is necessary to block the usually fatal signals while the
++ data structures being accessed by the cleanup action are being built or
++ reorganized. This is the case, for example, when a temporary file or
++ directory is created through mkstemp() or mkdtemp(), because these
++ functions create the temporary file or directory _before_ returning its
++ name to the application. */
++
++/* Temporarily delay the catchable fatal signals.
++ The signals will be blocked (= delayed) until the next call to
++ unblock_fatal_signals(). If the signals are already blocked, a further
++ call to block_fatal_signals() has no effect. */
++extern void block_fatal_signals (void);
++
++/* Stop delaying the catchable fatal signals. */
++extern void unblock_fatal_signals (void);
++
++
++#ifdef __cplusplus
++}
++#endif
+diff -up patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute patch-2.7.6/lib/gnulib.mk
+--- patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute 2018-02-03 14:31:15.000000000 +0100
++++ patch-2.7.6/lib/gnulib.mk 2019-07-29 14:49:33.437536285 +0200
+@@ -21,7 +21,7 @@
+ # the same distribution terms as the rest of that program.
+ #
+ # Generated by gnulib-tool.
+-# 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
++# 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
+
+
+ MOSTLYCLEANFILES += core *.stackdump
+@@ -378,6 +378,12 @@ EXTRA_libpatch_a_SOURCES += euidaccess.c
+
+ ## end gnulib module euidaccess
+
++## begin gnulib module execute
++
++libpatch_a_SOURCES += execute.h execute.c w32spawn.h
++
++## end gnulib module execute
++
+ ## begin gnulib module exitfail
+
+ libpatch_a_SOURCES += exitfail.c
+@@ -2481,6 +2487,28 @@ libpatch_a_SOURCES += verror.h verror.c
+
+ ## end gnulib module verror
+
++## begin gnulib module wait-process
++
++libpatch_a_SOURCES += wait-process.h wait-process.c
++
++## end gnulib module wait-process
++
++## begin gnulib module fatal-signal
++
++libpatch_a_SOURCES += fatal-signal.h fatal-signal.c
++
++## end gnulib module fatal-signal
++
++## begin gnulib module sigaction
++
++libpatch_a_SOURCES += sig-handler.c
++
++EXTRA_DIST += sig-handler.h sigaction.c
++
++EXTRA_libpatch_a_SOURCES += sigaction.c
++
++## end gnulib module sigaction
++
+ ## begin gnulib module wchar
+
+ BUILT_SOURCES += wchar.h
+@@ -2694,6 +2722,7 @@ EXTRA_libpatch_a_SOURCES += xmemdup0.c
+
+ ## end gnulib module xmemdup0
+
++
+ ## begin gnulib module xsize
+
+ libpatch_a_SOURCES += xsize.h xsize.c
+diff -up patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sigaction.c
+--- patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:31.833768833 +0200
++++ patch-2.7.6/lib/sigaction.c 2019-07-29 14:50:31.833768833 +0200
+@@ -0,0 +1,204 @@
++/* POSIX compatible signal blocking.
++ Copyright (C) 2008-2018 Free Software Foundation, Inc.
++ Written by Eric Blake <ebb9 at byu.net>, 2008.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#include <config.h>
++
++/* Specification. */
++#include <signal.h>
++
++#include <errno.h>
++#include <stdint.h>
++#include <stdlib.h>
++
++/* This implementation of sigaction is tailored to native Windows behavior:
++ signal() has SysV semantics (ie. the handler is uninstalled before
++ it is invoked). This is an inherent data race if an asynchronous
++ signal is sent twice in a row before we can reinstall our handler,
++ but there's nothing we can do about it. Meanwhile, sigprocmask()
++ is not present, and while we can use the gnulib replacement to
++ provide critical sections, it too suffers from potential data races
++ in the face of an ill-timed asynchronous signal. And we compound
++ the situation by reading static storage in a signal handler, which
++ POSIX warns is not generically async-signal-safe. Oh well.
++
++ Additionally:
++ - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
++ is not defined.
++ - We don't implement SA_ONSTACK, because sigaltstack() is not present.
++ - We ignore SA_RESTART, because blocking native Windows API calls are
++ not interrupted anyway when an asynchronous signal occurs, and the
++ MSVCRT runtime never sets errno to EINTR.
++ - We don't implement SA_SIGINFO because it is impossible to do so
++ portably.
++
++ POSIX states that an application should not mix signal() and
++ sigaction(). We support the use of signal() within the gnulib
++ sigprocmask() substitute, but all other application code linked
++ with this module should stick with only sigaction(). */
++
++/* Check some of our assumptions. */
++#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
++# error "Revisit the assumptions made in the sigaction module"
++#endif
++
++/* Out-of-range substitutes make a good fallback for uncatchable
++ signals. */
++#ifndef SIGKILL
++# define SIGKILL (-1)
++#endif
++#ifndef SIGSTOP
++# define SIGSTOP (-1)
++#endif
++
++/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
++ for the signal SIGABRT. Only one signal handler is stored for both
++ SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++# undef SIGABRT_COMPAT
++# define SIGABRT_COMPAT 6
++#endif
++
++/* A signal handler. */
++typedef void (*handler_t) (int signal);
++
++/* Set of current actions. If sa_handler for an entry is NULL, then
++ that signal is not currently handled by the sigaction handler. */
++static struct sigaction volatile action_array[NSIG] /* = 0 */;
++
++/* Signal handler that is installed for signals. */
++static void
++sigaction_handler (int sig)
++{
++ handler_t handler;
++ sigset_t mask;
++ sigset_t oldmask;
++ int saved_errno = errno;
++ if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
++ {
++ /* Unexpected situation; be careful to avoid recursive abort. */
++ if (sig == SIGABRT)
++ signal (SIGABRT, SIG_DFL);
++ abort ();
++ }
++
++ /* Reinstall the signal handler when required; otherwise update the
++ bookkeeping so that the user's handler may call sigaction and get
++ accurate results. We know the signal isn't currently blocked, or
++ we wouldn't be in its handler, therefore we know that we are not
++ interrupting a sigaction() call. There is a race where any
++ asynchronous instance of the same signal occurring before we
++ reinstall the handler will trigger the default handler; oh
++ well. */
++ handler = action_array[sig].sa_handler;
++ if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
++ signal (sig, sigaction_handler);
++ else
++ action_array[sig].sa_handler = NULL;
++
++ /* Block appropriate signals. */
++ mask = action_array[sig].sa_mask;
++ if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
++ sigaddset (&mask, sig);
++ sigprocmask (SIG_BLOCK, &mask, &oldmask);
++
++ /* Invoke the user's handler, then restore prior mask. */
++ errno = saved_errno;
++ handler (sig);
++ saved_errno = errno;
++ sigprocmask (SIG_SETMASK, &oldmask, NULL);
++ errno = saved_errno;
++}
++
++/* Change and/or query the action that will be taken on delivery of
++ signal SIG. If not NULL, ACT describes the new behavior. If not
++ NULL, OACT is set to the prior behavior. Return 0 on success, or
++ set errno and return -1 on failure. */
++int
++sigaction (int sig, const struct sigaction *restrict act,
++ struct sigaction *restrict oact)
++{
++ sigset_t mask;
++ sigset_t oldmask;
++ int saved_errno;
++
++ if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
++ || (act && act->sa_handler == SIG_ERR))
++ {
++ errno = EINVAL;
++ return -1;
++ }
++
++#ifdef SIGABRT_COMPAT
++ if (sig == SIGABRT_COMPAT)
++ sig = SIGABRT;
++#endif
++
++ /* POSIX requires sigaction() to be async-signal-safe. In other
++ words, if an asynchronous signal can occur while we are anywhere
++ inside this function, the user's handler could then call
++ sigaction() recursively and expect consistent results. We meet
++ this rule by using sigprocmask to block all signals before
++ modifying any data structure that could be read from a signal
++ handler; this works since we know that the gnulib sigprocmask
++ replacement does not try to use sigaction() from its handler. */
++ if (!act && !oact)
++ return 0;
++ sigfillset (&mask);
++ sigprocmask (SIG_BLOCK, &mask, &oldmask);
++ if (oact)
++ {
++ if (action_array[sig].sa_handler)
++ *oact = action_array[sig];
++ else
++ {
++ /* Safe to change the handler at will here, since all
++ signals are currently blocked. */
++ oact->sa_handler = signal (sig, SIG_DFL);
++ if (oact->sa_handler == SIG_ERR)
++ goto failure;
++ signal (sig, oact->sa_handler);
++ oact->sa_flags = SA_RESETHAND | SA_NODEFER;
++ sigemptyset (&oact->sa_mask);
++ }
++ }
++
++ if (act)
++ {
++ /* Safe to install the handler before updating action_array,
++ since all signals are currently blocked. */
++ if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
++ {
++ if (signal (sig, act->sa_handler) == SIG_ERR)
++ goto failure;
++ action_array[sig].sa_handler = NULL;
++ }
++ else
++ {
++ if (signal (sig, sigaction_handler) == SIG_ERR)
++ goto failure;
++ action_array[sig] = *act;
++ }
++ }
++ sigprocmask (SIG_SETMASK, &oldmask, NULL);
++ return 0;
++
++ failure:
++ saved_errno = errno;
++ sigprocmask (SIG_SETMASK, &oldmask, NULL);
++ errno = saved_errno;
++ return -1;
++}
+diff -up patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.c
+--- patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:17.265710820 +0200
++++ patch-2.7.6/lib/sig-handler.c 2019-07-29 14:48:19.707242671 +0200
+@@ -0,0 +1,3 @@
++#include <config.h>
++#define SIG_HANDLER_INLINE _GL_EXTERN_INLINE
++#include "sig-handler.h"
+diff -up patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.h
+--- patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute 2019-07-29 14:50:12.249690845 +0200
++++ patch-2.7.6/lib/sig-handler.h 2019-07-29 14:48:23.099256180 +0200
+@@ -0,0 +1,54 @@
++/* Convenience declarations when working with <signal.h>.
++
++ Copyright (C) 2008-2018 Free Software Foundation, Inc.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _GL_SIG_HANDLER_H
++#define _GL_SIG_HANDLER_H
++
++#include <signal.h>
++
++#ifndef _GL_INLINE_HEADER_BEGIN
++ #error "Please include config.h first."
++#endif
++_GL_INLINE_HEADER_BEGIN
++#ifndef SIG_HANDLER_INLINE
++# define SIG_HANDLER_INLINE _GL_INLINE
++#endif
++
++/* Convenience type when working with signal handlers. */
++typedef void (*sa_handler_t) (int);
++
++/* Return the handler of a signal, as a sa_handler_t value regardless
++ of its true type. The resulting function can be compared to
++ special values like SIG_IGN but it is not portable to call it. */
++SIG_HANDLER_INLINE sa_handler_t _GL_ATTRIBUTE_PURE
++get_handler (struct sigaction const *a)
++{
++#ifdef SA_SIGINFO
++ /* POSIX says that special values like SIG_IGN can only occur when
++ action.sa_flags does not contain SA_SIGINFO. But in Linux 2.4,
++ for example, sa_sigaction and sa_handler are aliases and a signal
++ is ignored if sa_sigaction (after casting) equals SIG_IGN. So
++ use (and cast) sa_sigaction in that case. */
++ if (a->sa_flags & SA_SIGINFO)
++ return (sa_handler_t) a->sa_sigaction;
++#endif
++ return a->sa_handler;
++}
++
++_GL_INLINE_HEADER_END
++
++#endif /* _GL_SIG_HANDLER_H */
+diff -up patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/w32spawn.h
+--- patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.265464828 +0200
++++ patch-2.7.6/lib/w32spawn.h 2019-07-29 14:40:53.265464828 +0200
+@@ -0,0 +1,233 @@
++/* Auxiliary functions for the creation of subprocesses. Native Windows API.
++ Copyright (C) 2001, 2003-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <bruno at clisp.org>, 2003.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef __KLIBC__
++/* Get declarations of the native Windows API functions. */
++# define WIN32_LEAN_AND_MEAN
++# include <windows.h>
++#endif
++
++/* Get _open_osfhandle(). */
++#include <io.h>
++
++#include <stdbool.h>
++#include <string.h>
++#include <unistd.h>
++#include <errno.h>
++
++/* Get _get_osfhandle(). */
++# if GNULIB_MSVC_NOTHROW
++# include "msvc-nothrow.h"
++# else
++# include <io.h>
++# endif
++
++#include "cloexec.h"
++#include "xalloc.h"
++
++/* Duplicates a file handle, making the copy uninheritable.
++ Returns -1 for a file handle that is equivalent to closed. */
++static int
++dup_noinherit (int fd)
++{
++ fd = dup_cloexec (fd);
++ if (fd < 0 && errno == EMFILE)
++ error (EXIT_FAILURE, errno, _("_open_osfhandle failed"));
++
++ return fd;
++}
++
++/* Returns a file descriptor equivalent to FD, except that the resulting file
++ descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
++ FD must be open and non-inheritable. The result will be non-inheritable as
++ well.
++ If FD < 0, FD itself is returned. */
++static int
++fd_safer_noinherit (int fd)
++{
++ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
++ {
++ /* The recursion depth is at most 3. */
++ int nfd = fd_safer_noinherit (dup_noinherit (fd));
++ int saved_errno = errno;
++ close (fd);
++ errno = saved_errno;
++ return nfd;
++ }
++ return fd;
++}
++
++/* Duplicates a file handle, making the copy uninheritable and ensuring the
++ result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
++ Returns -1 for a file handle that is equivalent to closed. */
++static int
++dup_safer_noinherit (int fd)
++{
++ return fd_safer_noinherit (dup_noinherit (fd));
++}
++
++/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD); */
++static void
++undup_safer_noinherit (int tempfd, int origfd)
++{
++ if (tempfd >= 0)
++ {
++ if (dup2 (tempfd, origfd) < 0)
++ error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"),
++ origfd);
++ close (tempfd);
++ }
++ else
++ {
++ /* origfd was closed or open to no handle at all. Set it to a closed
++ state. This is (nearly) equivalent to the original state. */
++ close (origfd);
++ }
++}
++
++/* Prepares an argument vector before calling spawn().
++ Note that spawn() does not by itself call the command interpreter
++ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
++ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
++ GetVersionEx(&v);
++ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
++ }) ? "cmd.exe" : "command.com").
++ Instead it simply concatenates the arguments, separated by ' ', and calls
++ CreateProcess(). We must quote the arguments since Windows CreateProcess()
++ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
++ special way:
++ - Space and tab are interpreted as delimiters. They are not treated as
++ delimiters if they are surrounded by double quotes: "...".
++ - Unescaped double quotes are removed from the input. Their only effect is
++ that within double quotes, space and tab are treated like normal
++ characters.
++ - Backslashes not followed by double quotes are not special.
++ - But 2*n+1 backslashes followed by a double quote become
++ n backslashes followed by a double quote (n >= 0):
++ \" -> "
++ \\\" -> \"
++ \\\\\" -> \\"
++ - '*', '?' characters may get expanded through wildcard expansion in the
++ callee: By default, in the callee, the initialization code before main()
++ takes the result of GetCommandLine(), wildcard-expands it, and passes it
++ to main(). The exceptions to this rule are:
++ - programs that inspect GetCommandLine() and ignore argv,
++ - mingw programs that have a global variable 'int _CRT_glob = 0;',
++ - Cygwin programs, when invoked from a Cygwin program.
++ */
++#ifndef __KLIBC__
++# 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*?"
++# 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"
++#else
++# define SHELL_SPECIAL_CHARS ""
++# define SHELL_SPACE_CHARS ""
++#endif
++static char **
++prepare_spawn (char **argv)
++{
++ size_t argc;
++ char **new_argv;
++ size_t i;
++
++ /* Count number of arguments. */
++ for (argc = 0; argv[argc] != NULL; argc++)
++ ;
++
++ /* Allocate new argument vector. */
++ new_argv = XNMALLOC (1 + argc + 1, char *);
++
++ /* Add an element upfront that can be used when argv[0] turns out to be a
++ script, not a program.
++ On Unix, this would be "/bin/sh". On native Windows, "sh" is actually
++ "sh.exe". We have to omit the directory part and rely on the search in
++ PATH, because the mingw "mount points" are not visible inside Windows
++ CreateProcess(). */
++ *new_argv++ = "sh.exe";
++
++ /* Put quoted arguments into the new argument vector. */
++ for (i = 0; i < argc; i++)
++ {
++ const char *string = argv[i];
++
++ if (string[0] == '\0')
++ new_argv[i] = xstrdup ("\"\"");
++ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
++ {
++ bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
++ size_t length;
++ unsigned int backslashes;
++ const char *s;
++ char *quoted_string;
++ char *p;
++
++ length = 0;
++ backslashes = 0;
++ if (quote_around)
++ length++;
++ for (s = string; *s != '\0'; s++)
++ {
++ char c = *s;
++ if (c == '"')
++ length += backslashes + 1;
++ length++;
++ if (c == '\\')
++ backslashes++;
++ else
++ backslashes = 0;
++ }
++ if (quote_around)
++ length += backslashes + 1;
++
++ quoted_string = (char *) xmalloc (length + 1);
++
++ p = quoted_string;
++ backslashes = 0;
++ if (quote_around)
++ *p++ = '"';
++ for (s = string; *s != '\0'; s++)
++ {
++ char c = *s;
++ if (c == '"')
++ {
++ unsigned int j;
++ for (j = backslashes + 1; j > 0; j--)
++ *p++ = '\\';
++ }
++ *p++ = c;
++ if (c == '\\')
++ backslashes++;
++ else
++ backslashes = 0;
++ }
++ if (quote_around)
++ {
++ unsigned int j;
++ for (j = backslashes; j > 0; j--)
++ *p++ = '\\';
++ *p++ = '"';
++ }
++ *p = '\0';
++
++ new_argv[i] = quoted_string;
++ }
++ else
++ new_argv[i] = (char *) string;
++ }
++ new_argv[argc] = NULL;
++
++ return new_argv;
++}
+diff -up patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.c
+--- patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:49.937840928 +0200
++++ patch-2.7.6/lib/wait-process.c 2019-07-29 14:45:17.196515863 +0200
+@@ -0,0 +1,361 @@
++/* Waiting for a subprocess to finish.
++ Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <haible at clisp.cons.org>, 2001.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++
++#include <config.h>
++
++/* Specification. */
++#include "wait-process.h"
++
++#include <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include <signal.h>
++
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#include "error.h"
++#include "fatal-signal.h"
++#include "xalloc.h"
++#include "gettext.h"
++
++#define _(str) gettext (str)
++
++#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
++
++
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++
++# define WIN32_LEAN_AND_MEAN
++# include <windows.h>
++
++/* The return value of spawnvp() is really a process handle as returned
++ by CreateProcess(). Therefore we can kill it using TerminateProcess. */
++# define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig)
++
++#endif
++
++
++/* Type of an entry in the slaves array.
++ The 'used' bit determines whether this entry is currently in use.
++ (If pid_t was an atomic type like sig_atomic_t, we could just set the
++ 'child' field to 0 when unregistering a slave process, and wouldn't need
++ the 'used' field.)
++ The 'used' and 'child' fields are accessed from within the cleanup_slaves()
++ action, therefore we mark them as 'volatile'. */
++typedef struct
++{
++ volatile sig_atomic_t used;
++ volatile pid_t child;
++}
++slaves_entry_t;
++
++/* The registered slave subprocesses. */
++static slaves_entry_t static_slaves[32];
++static slaves_entry_t * volatile slaves = static_slaves;
++static sig_atomic_t volatile slaves_count = 0;
++static size_t slaves_allocated = SIZEOF (static_slaves);
++
++/* The termination signal for slave subprocesses.
++ 2003-10-07: Terminator becomes Governator. */
++#ifdef SIGHUP
++# define TERMINATOR SIGHUP
++#else
++# define TERMINATOR SIGTERM
++#endif
++
++/* The cleanup action. It gets called asynchronously. */
++static void
++cleanup_slaves (void)
++{
++ for (;;)
++ {
++ /* Get the last registered slave. */
++ size_t n = slaves_count;
++ if (n == 0)
++ break;
++ n--;
++ slaves_count = n;
++ /* Skip unused entries in the slaves array. */
++ if (slaves[n].used)
++ {
++ pid_t slave = slaves[n].child;
++
++ /* Kill the slave. */
++ kill (slave, TERMINATOR);
++ }
++ }
++}
++
++/* Register a subprocess as being a slave process. This means that the
++ subprocess will be terminated when its creator receives a catchable fatal
++ signal or exits normally. Registration ends when wait_subprocess()
++ notices that the subprocess has exited. */
++void
++register_slave_subprocess (pid_t child)
++{
++ static bool cleanup_slaves_registered = false;
++ if (!cleanup_slaves_registered)
++ {
++ atexit (cleanup_slaves);
++ at_fatal_signal (cleanup_slaves);
++ cleanup_slaves_registered = true;
++ }
++
++ /* Try to store the new slave in an unused entry of the slaves array. */
++ {
++ slaves_entry_t *s = slaves;
++ slaves_entry_t *s_end = s + slaves_count;
++
++ for (; s < s_end; s++)
++ if (!s->used)
++ {
++ /* The two uses of 'volatile' in the slaves_entry_t type above
++ (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
++ entry as used only after the child pid has been written to the
++ memory location s->child. */
++ s->child = child;
++ s->used = 1;
++ return;
++ }
++ }
++
++ if (slaves_count == slaves_allocated)
++ {
++ /* Extend the slaves array. Note that we cannot use xrealloc(),
++ because then the cleanup_slaves() function could access an already
++ deallocated array. */
++ slaves_entry_t *old_slaves = slaves;
++ size_t new_slaves_allocated = 2 * slaves_allocated;
++ slaves_entry_t *new_slaves =
++ (slaves_entry_t *)
++ malloc (new_slaves_allocated * sizeof (slaves_entry_t));
++ if (new_slaves == NULL)
++ {
++ /* xalloc_die() will call exit() which will invoke cleanup_slaves().
++ Additionally we need to kill child, because it's not yet among
++ the slaves list. */
++ kill (child, TERMINATOR);
++ xalloc_die ();
++ }
++ memcpy (new_slaves, old_slaves,
++ slaves_allocated * sizeof (slaves_entry_t));
++ slaves = new_slaves;
++ slaves_allocated = new_slaves_allocated;
++ /* Now we can free the old slaves array. */
++ if (old_slaves != static_slaves)
++ free (old_slaves);
++ }
++ /* The three uses of 'volatile' in the types above (and ISO C 99 section
++ 5.1.2.3.(5)) ensure that we increment the slaves_count only after the
++ new slave and its 'used' bit have been written to the memory locations
++ that make up slaves[slaves_count]. */
++ slaves[slaves_count].child = child;
++ slaves[slaves_count].used = 1;
++ slaves_count++;
++}
++
++/* Unregister a child from the list of slave subprocesses. */
++static void
++unregister_slave_subprocess (pid_t child)
++{
++ /* The easiest way to remove an entry from a list that can be used by
++ an asynchronous signal handler is just to mark it as unused. For this,
++ we rely on sig_atomic_t. */
++ slaves_entry_t *s = slaves;
++ slaves_entry_t *s_end = s + slaves_count;
++
++ for (; s < s_end; s++)
++ if (s->used && s->child == child)
++ s->used = 0;
++}
++
++
++/* Wait for a subprocess to finish. Return its exit code.
++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise
++ return 127. */
++int
++wait_subprocess (pid_t child, const char *progname,
++ bool ignore_sigpipe, bool null_stderr,
++ bool slave_process, bool exit_on_error,
++ int *termsigp)
++{
++#if HAVE_WAITID && defined WNOWAIT && 0
++ /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
++ work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
++ and on HP-UX 10.20 it just hangs. */
++ /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
++ true, and this process sleeps a very long time between the return from
++ waitpid() and the execution of unregister_slave_subprocess(), and
++ meanwhile another process acquires the same PID as child, and then - still
++ before unregister_slave_subprocess() - this process gets a fatal signal,
++ it would kill the other totally unrelated process. */
++ siginfo_t info;
++
++ if (termsigp != NULL)
++ *termsigp = 0;
++ for (;;)
++ {
++ if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
++ < 0)
++ {
++# ifdef EINTR
++ if (errno == EINTR)
++ continue;
++# endif
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, errno,
++ _("%s subprocess"), progname);
++ return 127;
++ }
++
++ /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
++ CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED. Loop until the program
++ terminates. */
++ if (info.si_code == CLD_EXITED
++ || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
++ break;
++ }
++
++ /* The child process has exited or was signalled. */
++
++ if (slave_process)
++ {
++ /* Unregister the child from the list of slave subprocesses, so that
++ later, when we exit, we don't kill a totally unrelated process which
++ may have acquired the same pid. */
++ unregister_slave_subprocess (child);
++
++ /* Now remove the zombie from the process list. */
++ for (;;)
++ {
++ if (waitid (P_PID, child, &info, WEXITED) < 0)
++ {
++# ifdef EINTR
++ if (errno == EINTR)
++ continue;
++# endif
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, errno,
++ _("%s subprocess"), progname);
++ return 127;
++ }
++ break;
++ }
++ }
++
++ switch (info.si_code)
++ {
++ case CLD_KILLED:
++ case CLD_DUMPED:
++ if (termsigp != NULL)
++ *termsigp = info.si_status; /* TODO: or info.si_signo? */
++# ifdef SIGPIPE
++ if (info.si_status == SIGPIPE && ignore_sigpipe)
++ return 0;
++# endif
++ if (exit_on_error || (!null_stderr && termsigp == NULL))
++ error (exit_on_error ? EXIT_FAILURE : 0, 0,
++ _("%s subprocess got fatal signal %d"),
++ progname, info.si_status);
++ return 127;
++ case CLD_EXITED:
++ if (info.si_status == 127)
++ {
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, 0,
++ _("%s subprocess failed"), progname);
++ return 127;
++ }
++ return info.si_status;
++ default:
++ abort ();
++ }
++#else
++ /* waitpid() is just as portable as wait() nowadays. */
++ int status;
++
++ if (termsigp != NULL)
++ *termsigp = 0;
++ status = 0;
++ for (;;)
++ {
++ int result = waitpid (child, &status, 0);
++
++ if (result != child)
++ {
++# ifdef EINTR
++ if (errno == EINTR)
++ continue;
++# endif
++# if 0 /* defined ECHILD */
++ if (errno == ECHILD)
++ {
++ /* Child process nonexistent?! Assume it terminated
++ successfully. */
++ status = 0;
++ break;
++ }
++# endif
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, errno,
++ _("%s subprocess"), progname);
++ return 127;
++ }
++
++ /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
++ must always be true, since we did not specify WCONTINUED in the
++ waitpid() call. Loop until the program terminates. */
++ if (!WIFSTOPPED (status))
++ break;
++ }
++
++ /* The child process has exited or was signalled. */
++
++ if (slave_process)
++ /* Unregister the child from the list of slave subprocesses, so that
++ later, when we exit, we don't kill a totally unrelated process which
++ may have acquired the same pid. */
++ unregister_slave_subprocess (child);
++
++ if (WIFSIGNALED (status))
++ {
++ if (termsigp != NULL)
++ *termsigp = WTERMSIG (status);
++# ifdef SIGPIPE
++ if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
++ return 0;
++# endif
++ if (exit_on_error || (!null_stderr && termsigp == NULL))
++ error (exit_on_error ? EXIT_FAILURE : 0, 0,
++ _("%s subprocess got fatal signal %d"),
++ progname, (int) WTERMSIG (status));
++ return 127;
++ }
++ if (!WIFEXITED (status))
++ abort ();
++ if (WEXITSTATUS (status) == 127)
++ {
++ if (exit_on_error || !null_stderr)
++ error (exit_on_error ? EXIT_FAILURE : 0, 0,
++ _("%s subprocess failed"), progname);
++ return 127;
++ }
++ return WEXITSTATUS (status);
++#endif
++}
+diff -up patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.h
+--- patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute 2019-07-29 14:50:46.505827261 +0200
++++ patch-2.7.6/lib/wait-process.h 2019-07-29 14:45:20.715529876 +0200
+@@ -0,0 +1,74 @@
++/* Waiting for a subprocess to finish.
++ Copyright (C) 2001-2003, 2006, 2008-2018 Free Software Foundation, Inc.
++ Written by Bruno Haible <haible at clisp.cons.org>, 2001.
++
++ This program is free software: you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <https://www.gnu.org/licenses/>. */
++
++#ifndef _WAIT_PROCESS_H
++#define _WAIT_PROCESS_H
++
++/* Get pid_t. */
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/types.h>
++
++#include <stdbool.h>
++
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/* Wait for a subprocess to finish. Return its exit code.
++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise
++ return 127.
++ Arguments:
++ - child is the pid of the subprocess.
++ - progname is the name of the program executed by the subprocess, used for
++ error messages.
++ - If ignore_sigpipe is true, consider a subprocess termination due to
++ SIGPIPE as equivalent to a success. This is suitable for processes whose
++ only purpose is to write to standard output. This flag can be safely set
++ to false when the process' standard output is known to go to DEV_NULL.
++ - If null_stderr is true, the usual error message to stderr will be omitted.
++ This is suitable when the subprocess does not fulfill an important task.
++ - slave_process should be set to true if the process has been launched as a
++ slave process.
++ - If exit_on_error is true, any error will cause the main process to exit
++ with an error status.
++ - If termsigp is not NULL: *termsig will be set to the signal that
++ terminated the subprocess (if supported by the platform: not on native
++ Windows platforms), otherwise 0, and the error message about the signal
++ that terminated the subprocess will be omitted.
++ Prerequisites: The signal handler for SIGCHLD should not be set to SIG_IGN,
++ otherwise this function will not work. */
++extern int wait_subprocess (pid_t child, const char *progname,
++ bool ignore_sigpipe, bool null_stderr,
++ bool slave_process, bool exit_on_error,
++ int *termsigp);
++
++/* Register a subprocess as being a slave process. This means that the
++ subprocess will be terminated when its creator receives a catchable fatal
++ signal or exits normally. Registration ends when wait_subprocess()
++ notices that the subprocess has exited. */
++extern void register_slave_subprocess (pid_t child);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++
++#endif /* _WAIT_PROCESS_H */
+diff -up patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute patch-2.7.6/src/pch.c
+--- patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.262464816 +0200
++++ patch-2.7.6/src/pch.c 2019-07-29 15:01:10.338312098 +0200
+@@ -33,7 +33,8 @@
+ # include <io.h>
+ #endif
+ #include <safe.h>
+-#include <sys/wait.h>
++#include <alloca.h>
++#include "execute.h"
+
+ #define INITHUNKMAX 125 /* initial dynamic allocation size */
+
+@@ -2453,6 +2463,9 @@ do_ed_script (char const *inname, char c
+
+ if (! dry_run && ! skip_rest_of_patch) {
+ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
++ char const **ed_argv;
++ int stdin_dup, status;
++
+ *outname_needs_removal = true;
+ if (inerrno != ENOENT)
+ {
+@@ -2461,24 +2474,22 @@ do_ed_script (char const *inname, char c
+ }
+ fflush (stdout);
+
+- pid = fork();
+- if (pid == -1)
+- pfatal ("Can't fork");
+- else if (pid == 0)
+- {
+- dup2 (tmpfd, 0);
+- assert (outname[0] != '!' && outname[0] != '-');
+- execlp (editor_program, editor_program, "-", outname, (char *) NULL);
+- _exit (2);
+- }
+- else
+- {
+- int wstatus;
+- if (waitpid (pid, &wstatus, 0) == -1
+- || ! WIFEXITED (wstatus)
+- || WEXITSTATUS (wstatus) != 0)
+- fatal ("%s FAILED", editor_program);
+- }
++ if ((stdin_dup = dup (0)) == -1
++ || dup2 (tmpfd, 0) == -1)
++ pfatal ("Failed to duplicate standard input");
++ assert (outname[0] != '!' && outname[0] != '-');
++ ed_argv = alloca (4 * sizeof * ed_argv);
++ ed_argv[0] = editor_program;
++ ed_argv[1] = "-";
++ ed_argv[2] = outname;
++ ed_argv[3] = (char *) NULL;
++ status = execute (editor_program, editor_program, (char **)ed_argv,
++ false, false, false, false, true, false, NULL);
++ if (status)
++ fatal ("%s FAILED", editor_program);
++ if (dup2 (stdin_dup, 0) == -1
++ || close (stdin_dup) == -1)
++ pfatal ("Failed to duplicate standard input");
+ }
+
+ fclose (tmpfp);
diff --git a/patch-2.7.6-test-suite-compatibility-fixes.patch b/patch-2.7.6-test-suite-compatibility-fixes.patch
new file mode 100644
index 0000000..ce3e36f
--- /dev/null
+++ b/patch-2.7.6-test-suite-compatibility-fixes.patch
@@ -0,0 +1,124 @@
+commit f6bc5b14bd193859851d15a049bafb1007acd288
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Wed Feb 7 12:10:41 2018 +0100
+
+ Test suite compatibility fixes
+
+ * tests/crlf-handling, tests/git-cleanup, tests/test-lib.sh: Use printf
+ instead of echo -e / echo -n for compatibility with systems that don't
+ support these echo options.
+ * tests/merge: Minor other cleanups.
+
+diff --git a/tests/crlf-handling b/tests/crlf-handling
+index 239149c..c192cac 100644
+--- a/tests/crlf-handling
++++ b/tests/crlf-handling
+@@ -14,7 +14,7 @@ use_local_patch
+ use_tmpdir
+
+ lf2crlf() {
+- while read l; do echo -e "$l\r"; done
++ while read l; do printf "%s\r\n" "$l"; done
+ }
+
+ echo 1 > a
+diff --git a/tests/git-cleanup b/tests/git-cleanup
+index 2e3e4c6..ca527a1 100644
+--- a/tests/git-cleanup
++++ b/tests/git-cleanup
+@@ -36,8 +36,8 @@ BAD PATCH
+ EOF
+
+ echo 1 > f
+-echo -n '' > g
+-echo -n '' > h
++printf '' > g
++printf '' > h
+
+ check 'patch -f -i 1.diff || echo status: $?' <<EOF
+ patching file f
+diff --git a/tests/merge b/tests/merge
+index 22d787b..b628891 100644
+--- a/tests/merge
++++ b/tests/merge
+@@ -30,30 +30,28 @@ x2() {
+ while test $# -gt 0 && test "$1" != -- ; do
+ echo "$1"
+ shift
+- done > a.sed
+- echo "$body" | sed -f a.sed > b
++ done > b.sed
++ echo "$body" | sed -f b.sed > b
+ shift
+ while test $# -gt 0 ; do
+ echo "$1"
+ shift
+- done > b.sed
+- echo "$body" | sed -f b.sed > c
+- rm -f a.sed b.sed
++ done > c.sed
++ echo "$body" | sed -f c.sed > c
++ rm -f b.sed c.sed
+ output=`diff -u a b | patch $ARGS -f c`
+ status=$?
+ echo "$output" | sed -e '/^$/d' -e '/^patching file c$/d'
+ cat c
+- test $status == 0 || echo "Status: $status"
++ test $status = 0 || echo "Status: $status"
+ }
+
+ x() {
+- ARGS="$ARGS --merge" x2 "$@"
++ ARGS="--merge" x2 "$@"
+ echo
+- ARGS="$ARGS --merge=diff3" x2 "$@"
++ ARGS="--merge=diff3" x2 "$@"
+ }
+
+-unset ARGS
+-
+ # ==============================================================
+
+ check 'x 3' <<EOF
+diff --git a/tests/test-lib.sh b/tests/test-lib.sh
+index be0d7e3..661da52 100644
+--- a/tests/test-lib.sh
++++ b/tests/test-lib.sh
+@@ -41,7 +41,7 @@ use_local_patch() {
+
+ eval 'patch() {
+ if test -n "$GDB" ; then
+- echo -e "\n" >&3
++ printf "\n\n" >&3
+ gdbserver localhost:53153 $PATCH "$@" 2>&3
+ else
+ $PATCH "$@"
+@@ -113,22 +113,15 @@ cleanup() {
+ exit $status
+ }
+
+-if test -z "`echo -n`"; then
+- if eval 'test -n "${BASH_LINENO[0]}" 2>/dev/null'; then
+- eval '
+- _start_test() {
+- echo -n "[${BASH_LINENO[2]}] $* -- "
+- }'
+- else
+- eval '
+- _start_test() {
+- echo -n "* $* -- "
+- }'
+- fi
++if eval 'test -n "${BASH_LINENO[0]}" 2>/dev/null'; then
++ eval '
++ _start_test() {
++ printf "[${BASH_LINENO[2]}] %s -- " "$*"
++ }'
+ else
+ eval '
+ _start_test() {
+- echo "* $*"
++ printf "* %s -- " "$*"
+ }'
+ fi
+
diff --git a/patch-CVE-2018-1000156.patch b/patch-CVE-2018-1000156.patch
index fc3b0c2..988964f 100644
--- a/patch-CVE-2018-1000156.patch
+++ b/patch-CVE-2018-1000156.patch
@@ -1,6 +1,19 @@
-diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
---- patch-2.7.6/src/pch.c.CVE-2018-1000156 2018-02-03 12:41:49.000000000 +0000
-+++ patch-2.7.6/src/pch.c 2018-05-03 12:50:43.374036905 +0100
+commit 123eaff0d5d1aebe128295959435b9ca5909c26d
+Author: Andreas Gruenbacher <agruen at gnu.org>
+Date: Fri Apr 6 12:14:49 2018 +0200
+
+ Fix arbitrary command execution in ed-style patches (CVE-2018-1000156)
+
+ * src/pch.c (do_ed_script): Write ed script to a temporary file instead
+ of piping it to ed: this will cause ed to abort on invalid commands
+ instead of rejecting them and carrying on.
+ * tests/ed-style: New test case.
+ * tests/Makefile.am (TESTS): Add test case.
+
+diff --git a/src/pch.c b/src/pch.c
+index 0c5cc26..4fd5a05 100644
+--- a/src/pch.c
++++ b/src/pch.c
@@ -33,6 +33,7 @@
# include <io.h>
#endif
@@ -9,7 +22,7 @@ diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
#define INITHUNKMAX 125 /* initial dynamic allocation size */
-@@ -2388,22 +2389,28 @@ do_ed_script (char const *inname, char c
+@@ -2389,24 +2390,28 @@ do_ed_script (char const *inname, char const *outname,
static char const editor_program[] = EDITOR_PROGRAM;
file_offset beginning_of_this_line;
@@ -17,30 +30,32 @@ diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
size_t chars_read;
+ FILE *tmpfp = 0;
+ char const *tmpname;
-+ int tmpfd = -1;
++ int tmpfd;
+ pid_t pid;
+
+ if (! dry_run && ! skip_rest_of_patch)
+ {
-+ /* Write ed script to a temporary file. This causes ed to abort on
-+ invalid commands such as when line numbers or ranges exceed the
-+ number of available lines. When ed reads from a pipe, it rejects
-+ invalid commands and treats the next line as a new command, which
-+ can lead to arbitrary command execution. */
++ /* Write ed script to a temporary file. This causes ed to abort on
++ invalid commands such as when line numbers or ranges exceed the
++ number of available lines. When ed reads from a pipe, it rejects
++ invalid commands and treats the next line as a new command, which
++ can lead to arbitrary command execution. */
+
-+ tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
-+ if (tmpfd == -1)
-+ pfatal ("Can't create temporary file %s", quotearg (tmpname));
-+ tmpfp = fdopen (tmpfd, "w+b");
-+ if (! tmpfp)
-+ pfatal ("Can't open stream for file %s", quotearg (tmpname));
++ tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0);
++ if (tmpfd == -1)
++ pfatal ("Can't create temporary file %s", quotearg (tmpname));
++ tmpfp = fdopen (tmpfd, "w+b");
++ if (! tmpfp)
++ pfatal ("Can't open stream for file %s", quotearg (tmpname));
+ }
- if (! dry_run && ! skip_rest_of_patch) {
- int exclusive = *outname_needs_removal ? 0 : O_EXCL;
-- assert (! inerrno);
-- *outname_needs_removal = true;
-- copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+- if (inerrno != ENOENT)
+- {
+- *outname_needs_removal = true;
+- copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
+- }
- sprintf (buf, "%s %s%s", editor_program,
- verbosity == VERBOSE ? "" : "- ",
- outname);
@@ -52,7 +67,7 @@ diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
for (;;) {
char ed_command_letter;
beginning_of_this_line = file_tell (pfp);
-@@ -2414,14 +2421,14 @@ do_ed_script (char const *inname, char c
+@@ -2417,14 +2422,14 @@ do_ed_script (char const *inname, char const *outname,
}
ed_command_letter = get_ed_command_letter (buf);
if (ed_command_letter) {
@@ -71,7 +86,7 @@ diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
write_fatal ();
if (chars_read == 2 && strEQ (buf, ".\n"))
break;
-@@ -2434,13 +2441,50 @@ do_ed_script (char const *inname, char c
+@@ -2437,13 +2442,49 @@ do_ed_script (char const *inname, char const *outname,
break;
}
}
@@ -90,47 +105,60 @@ diff -up patch-2.7.6/src/pch.c.CVE-2018-1000156 patch-2.7.6/src/pch.c
+ pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname));
+
+ if (! dry_run && ! skip_rest_of_patch) {
-+ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
-+ *outname_needs_removal = true;
-+ if (inerrno != ENOENT)
-+ {
-+ *outname_needs_removal = true;
-+ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
-+ }
-+ sprintf (buf, "%s %s%s", editor_program,
-+ verbosity == VERBOSE ? "" : "- ",
-+ outname);
-+ fflush (stdout);
++ int exclusive = *outname_needs_removal ? 0 : O_EXCL;
++ *outname_needs_removal = true;
++ if (inerrno != ENOENT)
++ {
++ *outname_needs_removal = true;
++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true);
++ }
++ sprintf (buf, "%s %s%s", editor_program,
++ verbosity == VERBOSE ? "" : "- ",
++ outname);
++ fflush (stdout);
+
-+ pid = fork();
-+ if (pid == -1)
-+ pfatal ("Can't fork");
-+ else if (pid == 0)
-+ {
-+ dup2 (tmpfd, 0);
-+ execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
-+ _exit (2);
-+ }
-+ else
-+ {
-+ int wstatus;
-+ if (waitpid (pid, &wstatus, 0) == -1
-+ || ! WIFEXITED (wstatus)
-+ || WEXITSTATUS (wstatus) != 0)
-+ fatal ("%s FAILED", editor_program);
-+ }
++ pid = fork();
++ if (pid == -1)
++ pfatal ("Can't fork");
++ else if (pid == 0)
++ {
++ dup2 (tmpfd, 0);
++ execl ("/bin/sh", "sh", "-c", buf, (char *) 0);
++ _exit (2);
++ }
++ else
++ {
++ int wstatus;
++ if (waitpid (pid, &wstatus, 0) == -1
++ || ! WIFEXITED (wstatus)
++ || WEXITSTATUS (wstatus) != 0)
++ fatal ("%s FAILED", editor_program);
++ }
+ }
+
+ fclose (tmpfp);
-+ unlink (tmpname);
-+ free((char*) tmpname);
++ safe_unlink (tmpname);
if (ofp)
{
-diff -up patch-2.7.6/tests/ed-style.CVE-2018-1000156 patch-2.7.6/tests/ed-style
---- patch-2.7.6/tests/ed-style.CVE-2018-1000156 2018-05-03 12:50:28.988937938 +0100
-+++ patch-2.7.6/tests/ed-style 2018-05-03 12:51:35.841397873 +0100
-@@ -0,0 +1,40 @@
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 6b6df63..16f8693 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -32,6 +32,7 @@ TESTS = \
+ crlf-handling \
+ dash-o-append \
+ deep-directories \
++ ed-style \
+ empty-files \
+ false-match \
+ fifo \
+diff --git a/tests/ed-style b/tests/ed-style
+new file mode 100644
+index 0000000..d8c0689
+--- /dev/null
++++ b/tests/ed-style
+@@ -0,0 +1,41 @@
+# Copyright (C) 2018 Free Software Foundation, Inc.
+#
+# Copying and distribution of this file, with or without modification,
@@ -139,7 +167,7 @@ diff -up patch-2.7.6/tests/ed-style.CVE-2018-1000156 patch-2.7.6/tests/ed-style
+
+. $srcdir/test-lib.sh
+
-+require_cat
++require cat
+use_local_patch
+use_tmpdir
+
@@ -164,46 +192,11 @@ diff -up patch-2.7.6/tests/ed-style.CVE-2018-1000156 patch-2.7.6/tests/ed-style
+,p
+EOF
+
-+check 'patch -e foo -i ed2.diff > /dev/null 2> /dev/null || echo "Status: $?"' <<EOF
++check 'patch -e foo -i ed2.diff 2> /dev/null || echo "Status: $?"' <<EOF
++?
+Status: 2
+EOF
+
+check 'cat foo' <<EOF
+foo
+EOF
-diff -up patch-2.7.6/tests/Makefile.am.CVE-2018-1000156 patch-2.7.6/tests/Makefile.am
---- patch-2.7.6/tests/Makefile.am.CVE-2018-1000156 2018-05-03 12:50:28.988937938 +0100
-+++ patch-2.7.6/tests/Makefile.am 2018-05-03 12:50:57.340132989 +0100
-@@ -32,6 +32,7 @@ TESTS = \
- crlf-handling \
- dash-o-append \
- deep-directories \
-+ ed-style \
- empty-files \
- false-match \
- fifo \
-diff -up patch-2.7.6/tests/Makefile.in.CVE-2018-1000156 patch-2.7.6/tests/Makefile.in
---- patch-2.7.6/tests/Makefile.in.CVE-2018-1000156 2018-05-03 12:50:28.989937944 +0100
-+++ patch-2.7.6/tests/Makefile.in 2018-05-03 12:51:25.974329992 +0100
-@@ -1308,6 +1308,7 @@ TESTS = \
- crlf-handling \
- dash-o-append \
- deep-directories \
-+ ed-style \
- empty-files \
- false-match \
- fifo \
-@@ -1645,6 +1646,13 @@ empty-files.log: empty-files
- $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
- --log-file $$b.log --trs-file $$b.trs \
- $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
-+ "$$tst" $(AM_TESTS_FD_REDIRECT)
-+ed-style.log: empty-files
-+ @p='ed-style'; \
-+ b='ed-style'; \
-+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
-+ --log-file $$b.log --trs-file $$b.trs \
-+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
- "$$tst" $(AM_TESTS_FD_REDIRECT)
- false-match.log: false-match
- @p='false-match'; \
diff --git a/patch-selinux.patch b/patch-selinux.patch
new file mode 100644
index 0000000..7c16a1a
--- /dev/null
+++ b/patch-selinux.patch
@@ -0,0 +1,326 @@
+diff -up patch-2.7.6/src/common.h.selinux patch-2.7.6/src/common.h
+--- patch-2.7.6/src/common.h.selinux 2018-02-03 12:41:49.000000000 +0000
++++ patch-2.7.6/src/common.h 2018-02-12 12:29:44.415225377 +0000
+@@ -30,6 +30,8 @@
+ #include <sys/types.h>
+ #include <time.h>
+
++#include <selinux/selinux.h>
++
+ #include <sys/stat.h>
+
+ #include <limits.h>
+@@ -84,6 +86,7 @@ XTERN char *outfile;
+ XTERN int inerrno;
+ XTERN int invc;
+ XTERN struct stat instat;
++XTERN security_context_t incontext;
+ XTERN bool dry_run;
+ XTERN bool posixly_correct;
+
+diff -up patch-2.7.6/src/inp.c.selinux patch-2.7.6/src/inp.c
+--- patch-2.7.6/src/inp.c.selinux 2017-09-04 12:34:16.000000000 +0100
++++ patch-2.7.6/src/inp.c 2018-02-12 12:29:44.415225377 +0000
+@@ -145,7 +145,7 @@ get_input_file (char const *filename, ch
+ char *getbuf;
+
+ if (inerrno == -1)
+- inerrno = stat_file (filename, &instat);
++ inerrno = stat_file (filename, &instat, &incontext);
+
+ /* Perhaps look for RCS or SCCS versions. */
+ if (S_ISREG (file_type)
+@@ -190,7 +190,7 @@ get_input_file (char const *filename, ch
+ }
+
+ if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
+- &instat))
++ &instat, &incontext))
+ inerrno = 0;
+
+ free (getbuf);
+@@ -201,6 +201,7 @@ get_input_file (char const *filename, ch
+ {
+ instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ instat.st_size = 0;
++ incontext = NULL;
+ }
+ else if (! ((S_ISREG (file_type) || S_ISLNK (file_type))
+ && (file_type & S_IFMT) == (instat.st_mode & S_IFMT)))
+diff -up patch-2.7.6/src/Makefile.am.selinux patch-2.7.6/src/Makefile.am
+--- patch-2.7.6/src/Makefile.am.selinux 2017-09-04 12:34:16.000000000 +0100
++++ patch-2.7.6/src/Makefile.am 2018-02-12 12:29:44.415225377 +0000
+@@ -37,7 +37,7 @@ patch_SOURCES = \
+
+ AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
+ patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME) \
+- $(LIB_XATTR) $(LIB_EACCESS)
++ $(LIB_XATTR) $(LIB_EACCESS) -lselinux
+
+ if ENABLE_MERGE
+ patch_SOURCES += merge.c
+diff -up patch-2.7.6/src/Makefile.in.selinux patch-2.7.6/src/Makefile.in
+--- patch-2.7.6/src/Makefile.in.selinux 2018-02-03 13:33:56.000000000 +0000
++++ patch-2.7.6/src/Makefile.in 2018-02-12 12:29:44.415225377 +0000
+@@ -1147,7 +1147,7 @@ patch_SOURCES = bestmatch.h common.h inp
+ AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \
+ $(am__append_2)
+ patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME) \
+- $(LIB_XATTR) $(LIB_EACCESS)
++ $(LIB_XATTR) $(LIB_EACCESS) -lselinux
+
+ all: all-am
+
+diff -up patch-2.7.6/src/patch.c.selinux patch-2.7.6/src/patch.c
+--- patch-2.7.6/src/patch.c.selinux 2018-02-03 12:41:49.000000000 +0000
++++ patch-2.7.6/src/patch.c 2018-02-12 12:30:27.315164138 +0000
+@@ -269,19 +269,19 @@ main (int argc, char **argv)
+ if (! strcmp (inname, outname))
+ {
+ if (inerrno == -1)
+- inerrno = stat_file (inname, &instat);
++ inerrno = stat_file (inname, &instat, NULL);
+ outstat = instat;
+ outerrno = inerrno;
+ }
+ else
+- outerrno = stat_file (outname, &outstat);
++ outerrno = stat_file (outname, &outstat, NULL);
+
+ if (! outerrno)
+ {
+ if (has_queued_output (&outstat))
+ {
+ output_files (&outstat);
+- outerrno = stat_file (outname, &outstat);
++ outerrno = stat_file (outname, &outstat, NULL);
+ inerrno = -1;
+ }
+ if (! outerrno)
+@@ -598,7 +598,7 @@ main (int argc, char **argv)
+ }
+ else
+ {
+- attr |= FA_IDS | FA_MODE | FA_XATTRS;
++ attr |= FA_IDS | FA_MODE | FA_XATTRS | FA_SECCONTEXT;
+ set_file_attributes (TMPOUTNAME, attr, inname, &instat,
+ mode, &new_time);
+ }
+@@ -658,7 +658,7 @@ main (int argc, char **argv)
+ struct stat oldst;
+ int olderrno;
+
+- olderrno = stat_file (rej, &oldst);
++ olderrno = stat_file (rej, &oldst, NULL);
+ if (olderrno && olderrno != ENOENT)
+ write_fatal ();
+ if (! olderrno && lookup_file_id (&oldst) == CREATED)
+@@ -1790,7 +1790,7 @@ delete_file_later (const char *name, con
+
+ if (! st)
+ {
+- if (stat_file (name, &st_tmp) != 0)
++ if (stat_file (name, &st_tmp, NULL) != 0)
+ pfatal ("Can't get file attributes of %s %s", "file", name);
+ st = &st_tmp;
+ }
+diff -up patch-2.7.6/src/pch.c.selinux patch-2.7.6/src/pch.c
+--- patch-2.7.6/src/pch.c.selinux 2018-02-03 12:41:49.000000000 +0000
++++ patch-2.7.6/src/pch.c 2018-02-12 12:29:44.416225375 +0000
+@@ -1,6 +1,6 @@
+ /* reading patches */
+
+-/* Copyright (C) 1986, 1987, 1988 Larry Wall
++/* Copyright (C) 1986, 1987, 1988, 2012 Larry Wall
+
+ Copyright (C) 1990-1993, 1997-2003, 2006, 2009-2012 Free Software
+ Foundation, Inc.
+@@ -296,7 +296,7 @@ there_is_another_patch (bool need_header
+ if (t > buf + 1 && *(t - 1) == '\n')
+ {
+ inname = xmemdup0 (buf, t - buf - 1);
+- inerrno = stat_file (inname, &instat);
++ inerrno = stat_file (inname, &instat, &incontext);
+ if (inerrno)
+ {
+ perror (inname);
+@@ -433,6 +433,7 @@ intuit_diff_type (bool need_header, mode
+ bool extended_headers = false;
+ enum nametype i;
+ struct stat st[3];
++ security_context_t con[3];
+ int stat_errno[3];
+ int version_controlled[3];
+ enum diff retval;
+@@ -473,6 +474,7 @@ intuit_diff_type (bool need_header, mode
+ version_controlled[OLD] = -1;
+ version_controlled[NEW] = -1;
+ version_controlled[INDEX] = -1;
++ con[OLD] = con[NEW] = con[INDEX] = NULL;
+ p_rfc934_nesting = 0;
+ p_timestamp[OLD].tv_sec = p_timestamp[NEW].tv_sec = -1;
+ p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
+@@ -883,7 +885,7 @@ intuit_diff_type (bool need_header, mode
+ }
+ else
+ {
+- stat_errno[i] = stat_file (p_name[i], &st[i]);
++ stat_errno[i] = stat_file (p_name[i], &st[i], &con[i]);
+ if (! stat_errno[i])
+ {
+ if (lookup_file_id (&st[i]) == DELETE_LATER)
+@@ -922,7 +924,7 @@ intuit_diff_type (bool need_header, mode
+ if (cs)
+ {
+ if (version_get (p_name[i], cs, false, readonly,
+- getbuf, &st[i]))
++ getbuf, &st[i], &con[i]))
+ stat_errno[i] = 0;
+ else
+ version_controlled[i] = 0;
+@@ -985,7 +987,7 @@ intuit_diff_type (bool need_header, mode
+ {
+ if (inname)
+ {
+- inerrno = stat_file (inname, &instat);
++ inerrno = stat_file (inname, &instat, &incontext);
+ if (inerrno || (instat.st_mode & S_IFMT) == file_type)
+ maybe_reverse (inname, inerrno, inerrno || instat.st_size == 0);
+ }
+@@ -998,8 +1000,14 @@ intuit_diff_type (bool need_header, mode
+ inerrno = stat_errno[i];
+ invc = version_controlled[i];
+ instat = st[i];
++ incontext = con[i];
++ con[i] = NULL;
+ }
+
++ for (i = OLD; i <= INDEX; i++)
++ if (con[i])
++ freecon (con[i]);
++
+ return retval;
+ }
+
+diff -up patch-2.7.6/src/util.c.selinux patch-2.7.6/src/util.c
+--- patch-2.7.6/src/util.c.selinux 2018-02-03 12:41:49.000000000 +0000
++++ patch-2.7.6/src/util.c 2018-02-12 12:29:44.417225374 +0000
+@@ -300,6 +300,23 @@ set_file_attributes (char const *to, enu
+ S_ISLNK (mode) ? "symbolic link" : "file",
+ quotearg (to));
+ }
++ if (attr & FA_SECCONTEXT)
++ {
++ security_context_t outcontext;
++ if (incontext && getfilecon (to, &outcontext) != -1 && outcontext)
++ {
++ if (strcmp (outcontext, incontext) &&
++ setfilecon (to, incontext) != 0)
++ {
++ freecon (outcontext);
++ if (errno != ENOTSUP && errno != EPERM)
++ pfatal ("Can't set security context on file %s",
++ quotearg (to));
++ }
++ else
++ freecon (outcontext);
++ }
++ }
+ }
+
+ static void
+@@ -446,7 +463,7 @@ move_file (char const *from, bool *from_
+ struct stat to_st;
+ int to_errno;
+
+- to_errno = stat_file (to, &to_st);
++ to_errno = stat_file (to, &to_st, NULL);
+ if (backup)
+ create_backup (to, to_errno ? NULL : &to_st, false);
+ if (! to_errno)
+@@ -818,7 +835,8 @@ version_controller (char const *filename
+ Return true if successful. */
+ bool
+ version_get (char const *filename, char const *cs, bool exists, bool readonly,
+- char const *getbuf, struct stat *filestat)
++ char const *getbuf, struct stat *filestat,
++ security_context_t *filecontext)
+ {
+ if (patch_get < 0)
+ {
+@@ -843,6 +861,13 @@ version_get (char const *filename, char
+ fatal ("Can't get file %s from %s", quotearg (filename), cs);
+ if (safe_stat (filename, filestat) != 0)
+ pfatal ("%s", quotearg (filename));
++ if (filecontext && getfilecon (filename, filecontext) == -1)
++ {
++ if (errno == ENODATA || errno == ENOTSUP)
++ *filecontext = NULL;
++ else
++ pfatal ("%s", quotearg (filename));
++ }
+ }
+
+ return 1;
+@@ -1670,12 +1695,28 @@ make_tempfile (char const **name, char l
+ return fd;
+ }
+
+-int stat_file (char const *filename, struct stat *st)
++int stat_file (char const *filename, struct stat *st, security_context_t *con)
+ {
+ int (*xstat)(char const *, struct stat *) =
+ follow_symlinks ? safe_stat : safe_lstat;
++ int (*xgetfilecon)(char const *, security_context_t *) =
++ follow_symlinks ? getfilecon : lgetfilecon;
++
++ if (xstat (filename, st) == 0)
++ {
++ if (con)
++ {
++ if (xgetfilecon (filename, con) != -1 ||
++ errno == ENODATA || errno == ENOTSUP)
++ return 0;
+
+- return xstat (filename, st) == 0 ? 0 : errno;
++ *con = NULL;
++ }
++ else
++ return 0;
++ }
++
++ return errno;
+ }
+
+ /* Check if a filename is relative and free of ".." components.
+diff -up patch-2.7.6/src/util.h.selinux patch-2.7.6/src/util.h
+--- patch-2.7.6/src/util.h.selinux 2018-02-03 12:41:49.000000000 +0000
++++ patch-2.7.6/src/util.h 2018-02-12 12:30:08.533190949 +0000
+@@ -44,7 +44,7 @@ char *parse_name (char const *, int, cha
+ char *savebuf (char const *, size_t);
+ char *savestr (char const *);
+ char const *version_controller (char const *, bool, struct stat const *, char **, char **);
+-bool version_get (char const *, char const *, bool, bool, char const *, struct stat *);
++bool version_get (char const *, char const *, bool, bool, char const *, struct stat *, security_context_t *);
+ int create_file (char const *, int, mode_t, bool);
+ int systemic (char const *);
+ char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], lin);
+@@ -67,7 +67,7 @@ void insert_file_id (struct stat const *
+ enum file_id_type lookup_file_id (struct stat const *);
+ void set_queued_output (struct stat const *, bool);
+ bool has_queued_output (struct stat const *);
+-int stat_file (char const *, struct stat *);
++int stat_file (char const *, struct stat *, security_context_t *);
+ bool filename_is_safe (char const *) _GL_ATTRIBUTE_PURE;
+ bool cwd_is_root (char const *);
+
+@@ -75,7 +75,8 @@ enum file_attributes {
+ FA_TIMES = 1,
+ FA_IDS = 2,
+ FA_MODE = 4,
+- FA_XATTRS = 8
++ FA_XATTRS = 8,
++ FA_SECCONTEXT = 16
+ };
+
+ void set_file_attributes (char const *, enum file_attributes, char const *,
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/patch.git/commitdiff/93925d0d9d75587c27ed526835c8572c1b38a780
More information about the pld-cvs-commit
mailing list