GNU bug report logs - #76197
[PROPOSED] gzip: drop support for the GZIP env var

Previous Next

Package: gzip;

Reported by: Paul Eggert <eggert <at> cs.ucla.edu>

Date: Tue, 11 Feb 2025 07:24:02 UTC

Severity: normal

Tags: patch

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Bug is archived. No further changes may be made.

Full log


View this message in rfc822 format

From: help-debbugs <at> gnu.org (GNU bug Tracking System)
To: Paul Eggert <eggert <at> cs.ucla.edu>
Subject: bug#76197: closed (Re: bug#76197: [PROPOSED] gzip: drop support
 for the GZIP env var)
Date: Thu, 20 Feb 2025 06:51:02 +0000
[Message part 1 (text/plain, inline)]
Your bug report

#76197: [PROPOSED] gzip: drop support for the GZIP env var

which was filed against the gzip package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to 76197 <at> debbugs.gnu.org.

-- 
76197: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=76197
GNU Bug Tracking System
Contact help-debbugs <at> gnu.org with problems
[Message part 2 (message/rfc822, inline)]
From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Lasse Collin <lasse.collin <at> tukaani.org>
Cc: 76197-done <at> debbugs.gnu.org
Subject: Re: bug#76197: [PROPOSED] gzip: drop support for the GZIP env var
Date: Wed, 19 Feb 2025 22:50:14 -0800
[Message part 3 (text/plain, inline)]
On 2025-02-12 05:58, Lasse Collin wrote:

> the removal makes gzip one
> of the few compression tools that don't support setting even the
> compression level via an environment variable.

Thanks for the review. On further thought I agree that, for backward 
compatibility reasons at least, the gzip command should continue to 
examine the GZIP environment variable for options like -9 that affect 
only performance (including compression performance). These options 
shouldn't cause the bigger glitches (and perhaps even security hazards) 
that behavior-oriented options can cause. This would be more in line 
with zstd, which takes this relatively-cautious approach to environment 
variables.

You mentioned --synchronous as being innocuous even though gzip 
currently doesn't allow it in GZIP, and that also is a good suggestion.

So I installed the attached patch instead into Savannah master gzip. It 
means gzip will pay attention to -1..-9, --rsyncable, and --synchronous 
but will silently ignore everything else in GZIP. The idea is that a 
garbage GZIP value shouldn't disrupt normal operations.


[0001-Ignore-GZIP-envvar-except-for-innocuous-flags.patch (text/x-patch, attachment)]
[Message part 5 (message/rfc822, inline)]
From: Paul Eggert <eggert <at> cs.ucla.edu>
To: bug-gzip <at> gnu.org
Cc: Paul Eggert <eggert <at> cs.ucla.edu>
Subject: [PROPOSED] gzip: drop support for the GZIP env var
Date: Mon, 10 Feb 2025 23:22:34 -0800
The GZIP environment variable is too hazardous.
* gzip.c (env, ENV_OPTION):
* tailor.h (OPTIONS_VAR):
* util.c (SEPARATOR, add_envopt):
Remove.  All uses removed.
* gzip.c (main): Ignore GZIP.
* tests/gzip-env: Test that GZIP is ignored.
---
 NEWS           |  6 ++++
 doc/gzip.texi  | 11 ++-----
 gzip.1         | 18 ++++--------
 gzip.c         | 79 +-------------------------------------------------
 gzip.h         |  1 -
 tailor.h       |  4 ---
 tests/gzip-env | 19 +++++-------
 util.c         | 60 --------------------------------------
 znew.in        |  2 +-
 9 files changed, 24 insertions(+), 176 deletions(-)

diff --git a/NEWS b/NEWS
index e348355..0c4a2fc 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ GNU gzip NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Changes in behavior
+
+  The GZIP environment variable, which was marked as obsolescent in
+  gzip 1.7 (2016) due to its hazards, has been removed.  You can use
+  an alias or script instead.
+
 ** Bug fixes
 
   'gzip -d' no longer omits the last partial output buffer when the
diff --git a/doc/gzip.texi b/doc/gzip.texi
index cc05b60..1bfca98 100644
--- a/doc/gzip.texi
+++ b/doc/gzip.texi
@@ -487,14 +487,9 @@ complement to @command{tar}, not as a replacement.
 @chapter Environment
 @cindex Environment
 
-The obsolescent environment variable @env{GZIP} can hold a set of
-default options for @command{gzip}.  These options are interpreted
-first and can be overwritten by explicit command line parameters.  As
-this can cause problems when using scripts, this feature is supported
-only for options that are reasonably likely to not cause too much
-harm, and @command{gzip} warns if it is used.  This feature will be
-removed in a future release of @command{gzip}.
-
+Although previous verions of @command{gzip} examined the environment
+variable @env{GZIP} for a set of default options,
+this feature has been removed because it caused problems when using scripts.
 You can use an alias or script instead.  For example, if
 @command{gzip} is in the directory @samp{/usr/bin} you can prepend
 @file{$HOME/bin} to your @env{PATH} and create an executable script
diff --git a/gzip.1 b/gzip.1
index 0efe399..4afa243 100644
--- a/gzip.1
+++ b/gzip.1
@@ -416,20 +416,12 @@ such as tar or zip.
 GNU tar supports the \-z option to invoke gzip transparently.
 gzip is designed as a complement to tar, not as a replacement.
 .SH "ENVIRONMENT"
-The obsolescent environment variable
-.B GZIP
-can hold a set of default options for
-.BR gzip .
-These options are interpreted first and can be overwritten by explicit
-command line parameters.
-As this can cause problems when using scripts,
-this feature is supported only for options that are
-reasonably likely to not cause too much harm, and
+Although previous versions of
 .B gzip
-warns if it is used.
-This feature will be removed in a future release of
-.BR gzip .
-.PP
+examined the environment variable
+.B GZIP
+for a set of default options, this feature has been removed
+because it caused problems when using scripts.
 You can use an alias or script instead.
 For example, if
 .B gzip
diff --git a/gzip.c b/gzip.c
index a33841a..1fe589b 100644
--- a/gzip.c
+++ b/gzip.c
@@ -182,7 +182,6 @@ static int foreground = 0;   /* set if program run in foreground */
 static int last_member;      /* set for .zip and .Z files */
 static int part_nb;          /* number of parts in .gz file */
        off_t ifile_size;      /* input file size, -1 for devices (debug only) */
-static char *env;            /* contents of GZIP env variable */
 static char const *z_suffix; /* default suffix (can be set with --suffix) */
 static size_t z_len;         /* strlen(z_suffix) */
 
@@ -249,10 +248,6 @@ enum
   PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1,
   RSYNCABLE_OPTION,
   SYNCHRONOUS_OPTION,
-
-  /* A value greater than all valid long options, used as a flag to
-     distinguish options derived from the GZIP environment variable.  */
-  ENV_OPTION
 };
 
 static char const shortopts[] = "ab:cdfhH?klLmMnNqrS:tvVZ123456789";
@@ -413,9 +408,6 @@ int main (int argc, char **argv)
 {
     int file_count;     /* number of files to process */
     size_t proglen;     /* length of program_name */
-    char **argv_copy;
-    int env_argc;
-    char **env_argv;
 
     EXPAND(argc, argv); /* wild card expansion if necessary */
 
@@ -426,11 +418,6 @@ int main (int argc, char **argv)
     if (4 < proglen && strequ (program_name + proglen - 4, ".exe"))
       program_name[proglen - 4] = '\0';
 
-    /* Add options in GZIP environment variable if there is one */
-    argv_copy = argv;
-    env = add_envopt (&env_argc, &argv_copy, OPTIONS_VAR);
-    env_argv = env ? argv_copy : NULL;
-
 #ifndef GNU_STANDARD
 # define GNU_STANDARD 1
 #endif
@@ -454,49 +441,8 @@ int main (int argc, char **argv)
     z_len = strlen(z_suffix);
 
     while (true) {
-        int optc;
         int longind = -1;
-
-        if (env_argv)
-          {
-            if (env_argv[optind] && strequ (env_argv[optind], "--"))
-              optc = ENV_OPTION + '-';
-            else
-              {
-                optc = getopt_long (env_argc, env_argv, shortopts, longopts,
-                                    &longind);
-                if (0 <= optc)
-                  optc += ENV_OPTION;
-                else
-                  {
-                    if (optind != env_argc)
-                      {
-                        fprintf (stderr,
-                                 ("%s: %s: non-option in "OPTIONS_VAR
-                                  " environment variable\n"),
-                                 program_name, env_argv[optind]);
-                        try_help ();
-                      }
-
-                    /* Wait until here before warning, so that GZIP='-q'
-                       doesn't warn.  */
-                    if (env_argc != 1 && !quiet)
-                      fprintf (stderr,
-                               ("%s: warning: "OPTIONS_VAR" environment variable"
-                                " is deprecated; use an alias or script\n"),
-                               program_name);
-
-                    /* Start processing ARGC and ARGV instead.  */
-                    free (env_argv);
-                    env_argv = NULL;
-                    optind = 1;
-                    longind = -1;
-                  }
-              }
-          }
-
-        if (!env_argv)
-          optc = getopt_long (argc, argv, shortopts, longopts, &longind);
+        int optc = getopt_long (argc, argv, shortopts, longopts, &longind);
         if (optc < 0)
           break;
 
@@ -532,15 +478,12 @@ int main (int argc, char **argv)
         case 'M': /* undocumented, may change later */
             no_time = 0; break;
         case 'n':
-        case 'n' + ENV_OPTION:
             no_name = no_time = 1; break;
         case 'N':
-        case 'N' + ENV_OPTION:
             no_name = no_time = 0; break;
         case PRESUME_INPUT_TTY_OPTION:
             presume_input_tty = true; break;
         case 'q':
-        case 'q' + ENV_OPTION:
             quiet = 1; verbose = 0; break;
         case 'r':
 #if NO_DIR
@@ -553,7 +496,6 @@ int main (int argc, char **argv)
             break;
 
         case RSYNCABLE_OPTION:
-        case RSYNCABLE_OPTION + ENV_OPTION:
             rsync = 1;
             break;
         case 'S':
@@ -575,7 +517,6 @@ int main (int argc, char **argv)
             test = decompress = to_stdout = 1;
             break;
         case 'v':
-        case 'v' + ENV_OPTION:
             verbose++; quiet = 0; break;
         case 'V':
             version (); finish_out (); break;
@@ -584,28 +525,12 @@ int main (int argc, char **argv)
                     program_name);
             try_help ();
             break;
-        case '1' + ENV_OPTION:  case '2' + ENV_OPTION:  case '3' + ENV_OPTION:
-        case '4' + ENV_OPTION:  case '5' + ENV_OPTION:  case '6' + ENV_OPTION:
-        case '7' + ENV_OPTION:  case '8' + ENV_OPTION:  case '9' + ENV_OPTION:
-            optc -= ENV_OPTION;
-            FALLTHROUGH;
         case '1':  case '2':  case '3':  case '4':
         case '5':  case '6':  case '7':  case '8':  case '9':
             level = optc - '0';
             break;
 
         default:
-            if (ENV_OPTION <= optc && optc != ENV_OPTION + '?')
-              {
-                /* Output a diagnostic, since getopt_long didn't.  */
-                fprintf (stderr, "%s: ", program_name);
-                if (longind < 0)
-                  fprintf (stderr, "-%c: ", optc - ENV_OPTION);
-                else
-                  fprintf (stderr, "--%s: ", longopts[longind].name);
-                fprintf (stderr, ("option not valid in "OPTIONS_VAR
-                                  " environment variable\n"));
-              }
             try_help ();
         }
     } /* loop on all arguments */
@@ -2042,8 +1967,6 @@ do_exit (int exitcode)
 
     if (in_exit) exit(exitcode);
     in_exit = 1;
-    free(env);
-    env  = NULL;
     FREE(inbuf);
     FREE(outbuf);
     FREE(d_buf);
diff --git a/gzip.h b/gzip.h
index 855a88b..66b504b 100644
--- a/gzip.h
+++ b/gzip.h
@@ -314,7 +314,6 @@ extern char *strlwr       (char *s);
 extern char *gzip_base_name (char *fname) _GL_ATTRIBUTE_PURE;
 extern int xunlink        (char *fname);
 extern void make_simple_name (char *name);
-extern char *add_envopt   (int *argcp, char ***argvp, char const *env);
 _Noreturn extern void gzip_error (char const *m);
 _Noreturn extern void xalloc_die (void);
 extern void warning       (char const *m);
diff --git a/tailor.h b/tailor.h
index c9147b1..095d7ce 100644
--- a/tailor.h
+++ b/tailor.h
@@ -163,10 +163,6 @@
 #  define casemap(c) (c)
 #endif
 
-#ifndef OPTIONS_VAR
-#  define OPTIONS_VAR "GZIP"
-#endif
-
 #ifndef Z_SUFFIX
 #  define Z_SUFFIX ".gz"
 #endif
diff --git a/tests/gzip-env b/tests/gzip-env
index b7382d9..2da5915 100755
--- a/tests/gzip-env
+++ b/tests/gzip-env
@@ -1,5 +1,5 @@
 #!/bin/sh
-# Test the obsolescent GZIP environment variable.
+# Test that gzip is unaffected by the GZIP environment variable.
 
 # Copyright 2015-2025 Free Software Foundation, Inc.
 
@@ -23,20 +23,17 @@ echo a >exp || framework_failure_
 gzip <exp >in || framework_failure_
 
 fail=0
-GZIP=-qv gzip -d <in >out 2>err || fail=1
-compare exp out || fail=1
 
-for badopt in -- -c --stdout -d --decompress -f --force -h --help -k --keep \
+for opt in -qv \
+  -- -c --stdout -d --decompress -f --force -h --help -k --keep \
   -l --list -L --license -r --recursive -Sxxx --suffix=xxx '--suffix xxx' \
-  -t --test -V --version
-do
-  GZIP=$badopt gzip -d <in >out 2>err && fail=1
-done
-
-for goodopt in -n --no-name -N --name -q --quiet -v --verbose \
+  -t --test -V --version \
+  -n --no-name -N --name -q --quiet -v --verbose \
   -1 --fast -2 -3 -4 -5 -6 -7 -8 -9 --best
 do
-  GZIP=$goodopt gzip -d <in >out 2>err || fail=1
+  GZIP=$opt gzip <exp >inopt 2>err || fail=1
+  compare in inopt || fail=1
+  GZIP=$opt gzip -d <in >out 2>err || fail=1
   compare exp out || fail=1
 done
 
diff --git a/util.c b/util.c
index e3eb739..c799ac1 100644
--- a/util.c
+++ b/util.c
@@ -291,66 +291,6 @@ make_simple_name (char *name)
 }
 #endif
 
-/* Convert the value of the environment variable ENVVAR_NAME
-   to a newly allocated argument vector, and set *ARGCP and *ARGVP
-   to the number of arguments and to the vector, respectively.
-   Make the new vector's zeroth element equal to the old **ARGVP.
-   Return a pointer to the newly allocated string storage.
-
-   If the vector would be empty, do not allocate storage,
-   do not set *ARGCP and *ARGVP, and return NULL.  */
-
-#define SEPARATOR	" \t"	/* separators in env variable */
-
-char *add_envopt(
-    int *argcp,          /* pointer to argc */
-    char ***argvp,       /* pointer to argv */
-    char const *envvar_name) /* name of environment variable */
-{
-    char *p;             /* running pointer through env variable */
-    char **oargv;        /* runs through old argv array */
-    char **nargv;        /* runs through new argv array */
-    int  nargc = 0;      /* number of arguments in env variable */
-    char *env_val;
-
-    env_val = getenv(envvar_name);
-    if (env_val == NULL) return NULL;
-
-    env_val = xstrdup (env_val);
-
-    for (p = env_val; *p; nargc++ ) {        /* move through env_val */
-        p += strspn(p, SEPARATOR);	     /* skip leading separators */
-        if (*p == '\0') break;
-
-        p += strcspn(p, SEPARATOR);	     /* find end of word */
-        if (*p) *p++ = '\0';		     /* mark it */
-    }
-    if (nargc == 0) {
-        free(env_val);
-        return NULL;
-    }
-    *argcp = nargc + 1;
-    /* Allocate the new argv array, with an extra element just in case
-     * the original arg list did not end with a NULL.
-     */
-    nargv = xcalloc (*argcp + 1, sizeof (char *));
-    oargv  = *argvp;
-    *argvp = nargv;
-
-    /* Copy the program name first */
-    *nargv++ = *oargv;
-
-    /* Then copy the environment args */
-    for (p = env_val; nargc > 0; nargc--) {
-        p += strspn(p, SEPARATOR);	     /* skip separators */
-        *(nargv++) = p;			     /* store start */
-        while (*p++) ;			     /* skip over word */
-    }
-
-    *nargv = NULL;
-    return env_val;
-}
-
 /* ========================================================================
  * Error handlers.
  */
diff --git a/znew.in b/znew.in
index b09d967..e9d87f3 100644
--- a/znew.in
+++ b/znew.in
@@ -55,7 +55,7 @@ new=0
 block=1024
 # block is the disk block size (best guess, need not be exact)
 
-# Beware -s or --suffix in $GZIP.
+# Beware -s or --suffix in $GZIP, used by gzip 1.13 and earlier.
 unset GZIP
 ext=.gz
 
-- 
2.45.2




This bug report was last modified 132 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.