From 2ff35b618a2ff6520e26266e3298cc48bba80339 Mon Sep 17 00:00:00 2001 From: wangziliang Date: Wed, 10 Jul 2024 09:00:53 +0000 Subject: [PATCH] fix exit status on broken pipe (cherry picked from commit 38260d0a17081adebd2572479275e3f5a392d637) --- fix-exit-status-on-broken-pipe.patch | 244 +++++++++++++++++++++++++++ gzip.spec | 6 +- 2 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 fix-exit-status-on-broken-pipe.patch diff --git a/fix-exit-status-on-broken-pipe.patch b/fix-exit-status-on-broken-pipe.patch new file mode 100644 index 0000000..fba89c9 --- /dev/null +++ b/fix-exit-status-on-broken-pipe.patch @@ -0,0 +1,244 @@ +From 75dac03adcdf79b8d38a87bf29f50bcde9fa46a5 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Fri, 3 Feb 2023 01:19:44 -0800 +Subject: [PATCH] gzip: fix exit status on broken pipe + +Fix gzip to behave like cat etc. when outputting to a broken pipe: +i.e., exit with nonzero status if SIGPIPE is ignored, and be +terminated by SIGPIPE otherwise. +* NEWS: Mention this. +* gzip.c: Do not install signal handlers unless creating an output +file, for which signal handlers are needed. This avoids gzip +having to deal with signal handlers when outputting to stdout. +(exiting_signal): Remove. All uses removed. +(main): Do not install signal handlers at first. +(create_outfile): Instead, install them only when needed. +(finish_up_gzip): New function, which generalizes abort_gzip. +(abort_gzip): Use it. +* tests/pipe-output: New test. +* tests/Makefile.am (TESTS): Add it. +* util.c (EPIPE): Default to 0. +(write_error): Just warn if it is a pipe error, and suppress that +warning if quiet. In any event exit with status 2 (warning), +not status 1 (error). +* zgrep.in: Treat gzip status 141 like status 2; +it is a broken pipe either way. + +Conflict: write_error() in util.c and NEWS file +Reference: https://git.savannah.gnu.org/cgit/gzip.git/commit/?id=75dac03adcdf79b8d38a87bf29f50bcde9fa46a5 + +--- + gzip.c | 30 +++++++++++++++--------------- + gzip.h | 1 + + tests/Makefile.am | 1 + + tests/pipe-output | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + util.c | 8 +++++++- + zgrep.in | 4 ++-- + 6 files changed, 72 insertions(+), 18 deletions(-) + create mode 100755 tests/pipe-output + +diff --git a/gzip.c b/gzip.c +index 7547e19..7865a65 100644 +--- a/gzip.c ++++ b/gzip.c +@@ -202,11 +202,6 @@ struct timespec time_stamp; + /* The set of signals that are caught. */ + static sigset_t caught_signals; + +-/* If nonzero then exit with status WARNING, rather than with the usual +- signal status, on receipt of a signal with this value. This +- suppresses a "Broken Pipe" message with some shells. */ +-static int volatile exiting_signal; +- + /* If nonnegative, close this file descriptor and unlink remove_ofname + on error. */ + static int volatile remove_ofname_fd = -1; +@@ -647,11 +642,6 @@ int main (int argc, char **argv) + ALLOC(ush, tab_prefix1, 1L<<(BITS-1)); + #endif + +-#if SIGPIPE +- exiting_signal = quiet ? SIGPIPE : 0; +-#endif +- install_signal_handlers (); +- + /* And get to work */ + if (file_count != 0) { + if (to_stdout && !test && (!decompress || !ascii)) { +@@ -1088,6 +1078,7 @@ volatile_strcpy (char volatile *dst, char const volatile *src) + */ + local int create_outfile() + { ++ static bool signal_handlers_installed; + int name_shortened = 0; + int flags = (O_WRONLY | O_CREAT | O_EXCL + | (ascii && decompress ? 0 : O_BINARY)); +@@ -1105,6 +1096,12 @@ create_outfile () + } + } + ++ if (!signal_handlers_installed) ++ { ++ signal_handlers_installed = true; ++ install_signal_handlers (); ++ } ++ + for (;;) + { + int open_errno; +@@ -2103,12 +2100,17 @@ remove_output_file (bool signals_already_blocked) + * Error handler. + */ + void ++finish_up_gzip (int exitcode) ++{ ++ if (0 <= remove_ofname_fd) ++ remove_output_file (false); ++ do_exit (exitcode); ++} ++void + abort_gzip (void) + { +- remove_output_file (false); +- do_exit(ERROR); ++ finish_up_gzip (ERROR); + } +- + /* ======================================================================== + * Signal handler. + */ +@@ -2116,8 +2118,6 @@ static void + abort_gzip_signal (int sig) + { + remove_output_file (true); +- if (sig == exiting_signal) +- _exit (WARNING); + signal (sig, SIG_DFL); + raise (sig); + } +diff --git a/gzip.h b/gzip.h +index fad2b3f..b26bc4f 100644 +--- a/gzip.h ++++ b/gzip.h +@@ -277,6 +277,7 @@ extern int unpack (int in, int out); + extern int unlzh (int in, int out); + + /* in gzip.c */ ++extern noreturn void finish_up_gzip (int); + extern noreturn void abort_gzip (void); + + /* in deflate.c */ +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 077b25c..80249b1 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -25,6 +25,7 @@ TESTS = \ + memcpy-abuse \ + mixed \ + null-suffix-clobber \ ++ pipe-output \ + reproducible \ + stdin \ + timestamp \ +diff --git a/tests/pipe-output b/tests/pipe-output +new file mode 100755 +index 0000000..5419963 +--- /dev/null ++++ b/tests/pipe-output +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# Check behavior of output to pipes ++ ++# Copyright 2023 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 . ++# limit so don't run it by default. ++ ++. "${srcdir=.}/init.sh"; path_prepend_ .. ++ ++sleep 0.01 && sleep_amount=0.01 || sleep_amount=1 ++ ++echo a >a && echo b >b || framework_failure_ ++gzip a && gzip b || fail=1 ++ ++# Check that gzip etc. behave like cat if the output is a broken pipe. ++for trap_pipe in trap :; do ++ cat_status=$( (($trap_pipe '' PIPE ++ sleep $sleep_amount ++ cat &3) | : ) 3>&1) ++ test 1 -lt $cat_status && test $cat_status -lt 128 && cat_status=1 ++ ++ for cmd in 'gunzip' 'gunzip -q' 'gzip -d' 'gzip -dq' \ ++ 'zcat' 'zcmp - b.gz' 'zdiff - b.gz' 'zgrep a'; do ++ cmd_status=$( (($trap_pipe '' PIPE ++ sleep $sleep_amount ++ $cmd &3) | : ) 3>&1) ++ test 1 -lt $cmd_status && test $cmd_status -lt 128 && cmd_status=1 ++ test $cat_status -eq $cmd_status || fail=1 ++ done ++done ++ ++Exit $fail +diff --git a/util.c b/util.c +index 642e620..71a937f 100644 +--- a/util.c ++++ b/util.c +@@ -36,6 +36,10 @@ + # define CHAR_BIT 8 + #endif + ++#ifndef EPIPE ++# define EPIPE 0 ++#endif ++ + static int write_buffer (int, voidp, unsigned int); + + /* ======================================================================== +@@ -500,11 +504,10 @@ void read_error() + + void write_error() + { +- int e = errno; +- fprintf (stderr, "\n%s: ", program_name); +- errno = e; +- perror(ofname); +- abort_gzip(); ++ int exitcode = errno == EPIPE ? WARNING : ERROR; ++ if (! (exitcode == WARNING && quiet)) ++ fprintf (stderr, "\n%s: %s: %s\n", program_name, ofname, strerror (errno)); ++ finish_up_gzip (exitcode); + } + + /* ======================================================================== +diff --git a/zgrep.in b/zgrep.in +index 7aeee6c..504cca1 100644 +--- a/zgrep.in ++++ b/zgrep.in +@@ -253,9 +253,9 @@ do + ) + r=$? + +- # Ignore gzip status 2, as it is just a warning. ++ # Ignore gzip status 2 or 141, as it is just a warning or broken pipe. + # gzip status 1 is an error, like grep status 2. +- test $gzip_status -eq 2 && gzip_status=0 ++ { test $gzip_status -eq 2 || test $gzip_status -eq 141; } && gzip_status=0 + test $gzip_status -eq 1 && gzip_status=2 + + # Use the more serious of the grep and gzip statuses. +-- +2.33.0 + diff --git a/gzip.spec b/gzip.spec index 7057c80..8470ee8 100644 --- a/gzip.spec +++ b/gzip.spec @@ -1,6 +1,6 @@ Name: gzip Version: 1.12 -Release: 4 +Release: 5 Summary: A data compression utility License: GPLv3 @@ -14,6 +14,7 @@ Patch6001: backport-gzip-test-invalid-input-bug.patch Patch9000: fix-verbose-disable.patch Patch9001: performance-neoncrc32-and-prfm.patch +Patch9002: fix-exit-status-on-broken-pipe.patch BuildRequires: gcc texinfo less autoconf automake Requires: coreutils @@ -70,6 +71,9 @@ make check %{_mandir}/man1/* %changelog +* Wed Jul 10 2024 wangziliang - 1.12-5 +- fix exit status on broken pipe + * Thu Jun 01 2023 renhognxun - 1.12-4 - fix typo error in csh -- Gitee