Projects
Mega:24.03:SP1:Everything
gzip
_service:tar_scm:fix-exit-status-on-broken-pipe...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:fix-exit-status-on-broken-pipe.patch of Package gzip
From 75dac03adcdf79b8d38a87bf29f50bcde9fa46a5 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> 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 <https://www.gnu.org/licenses/>. +# 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 <a.gz + echo $? >&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 <a.gz + echo $? >&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
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2