>From 9876b9c6694ffaf12cad355484fa1f5fe482f0ce Mon Sep 17 00:00:00 2001 From: Paul Eggert
Date: Mon, 16 Mar 2015 14:25:17 -0700 Subject: [PATCH] gzip: make the GZIP env var obsolescent * NEWS, gzip.1: * doc/gzip.texi (Environment, Tapes): Document this. * gzip.c (args): Remove static var; no longer needed now that 'main' frees it. All uses removed. (ENV_OPTION, shortopts): New constants. (main): Warn about nontrivial uses of GZIP. Reject dangerous uses. * tests/gzip-env: New test case. * tests/Makefile.am (TESTS): Add it. * util.c (add_envopt): Create new vector instead of adding to old one. Only use changed. --- NEWS | 6 ++++ doc/gzip.texi | 43 ++++++++++++-------------- gzip.1 | 46 +++++++++++++++++----------- gzip.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++------ tests/Makefile.am | 1 + tests/gzip-env | 43 ++++++++++++++++++++++++++ util.c | 23 +++++++------- 7 files changed, 190 insertions(+), 63 deletions(-) create mode 100755 tests/gzip-env diff --git a/NEWS b/NEWS index 4203f56..120fb93 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ GNU gzip NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** Changes in behavior + + The GZIP environment variable is now obsolescent; gzip now warns if + it is used, and rejects attempts to use dangerous options or operands. + You can use an alias or script instead. + ** Bug fixes gzip -k -v no longer reports that files are replaced. diff --git a/doc/gzip.texi b/doc/gzip.texi index 2f4f1ab..5754aae 100644 --- a/doc/gzip.texi +++ b/doc/gzip.texi @@ -469,18 +469,28 @@ complement to @command{tar}, not as a replacement. @chapter Environment @cindex Environment -The environment variable @env{GZIP} can hold a set of default options for address@hidden These options are interpreted first and can be overwritten by -explicit command line parameters. For example: +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}. + +You can use an alias or script instead. For example, if address@hidden is in the directory @samp{/usr/bin} you can prepend address@hidden/bin} to your @env{PATH} and create an executable script address@hidden/bin/gzip} containing the following: @example -for sh: GZIP="-8v --name"; export GZIP -for csh: setenv GZIP "-8v --name" -for MSDOS: set GZIP=-8v --name +#! /bin/sh +export PATH=/usr/bin +exec gzip -9 "$@@" @end example -On @abbr{VMS}, the name of the environment variable is @env{GZIP_OPT}, to -avoid a conflict with the symbol set for invocation of the program. +On @abbr{VMS}, the name of the obsolescent environment variable is address@hidden, to avoid a conflict with the symbol set for invocation +of the program. @node Tapes @chapter Using @command{gzip} on tapes @@ -491,21 +501,8 @@ the output with zeroes up to a block boundary. When the data is read and the whole block is passed to @command{gunzip} for decompression, @command{gunzip} detects that there is extra trailing garbage after the compressed data and emits a warning by default if the garbage contains -nonzero bytes. You have to use the address@hidden option to suppress the warning. This option can be set in the address@hidden environment variable, as in: - address@hidden -for sh: GZIP="-q" tar -xfz --block-compress /dev/rst0 -for csh: (setenv GZIP "-q"; tar -xfz --block-compress /dev/rst0) address@hidden example - -In the above example, @command{gzip} is invoked implicitly by the @option{-z} -option of @acronym{GNU} @command{tar}. Make sure that the same block -size (@option{-b} -option of @command{tar}) is used for reading and writing compressed data on -tapes. (This example assumes you are using the @acronym{GNU} version of address@hidden) +nonzero bytes. You can use the @option{--quiet} option to suppress +the warning. @node Problems @chapter Reporting Bugs diff --git a/gzip.1 b/gzip.1 index d81c45a..23987e2 100644 --- a/gzip.1 +++ b/gzip.1 @@ -364,17 +364,36 @@ 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 environment variable +The obsolescent environment variable .B GZIP can hold a set of default options for .IR gzip . -These options are interpreted first and can be overwritten by -explicit command line parameters. For example: - for sh: GZIP="-8v --name"; export GZIP - for csh: setenv GZIP "-8v --name" - for MSDOS: set GZIP=-8v --name +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 +.I gzip +warns if it is used. +This feature will be removed in a future release of +.IR gzip . +.PP +You can use an alias or script instead. For example, if +.I gzip +is in the directory +.B /usr/bin +you can prepend +.B $HOME/bin +to your +.B PATH +and create an executable script +.B $HOME/bin/gzip +containing the following: -On Vax/VMS, the name of the environment variable is GZIP_OPT, to + #! /bin/sh + export PATH=/usr/bin + exec gzip \-9 "$@" + +On VMS, the name of the obsolescent environment variable is GZIP_OPT, to avoid a conflict with the symbol set for invocation of the program. .SH "SEE ALSO" znew(1), zcmp(1), zmore(1), zforce(1), gzexe(1), zip(1), unzip(1), compress(1) @@ -454,17 +473,8 @@ read and the whole block is passed to for decompression, .I gunzip detects that there is extra trailing garbage after the compressed data -and emits a warning by default. You have to use the --quiet option to -suppress the warning. This option can be set in the -.B GZIP -environment variable as in: - for sh: GZIP="-q" tar -xfz --block-compress /dev/rst0 - for csh: (setenv GZIP -q; tar -xfz --block-compr /dev/rst0 - -In the above example, gzip is invoked implicitly by the -z option of -GNU tar. Make sure that the same block size (-b option of tar) is used -for reading and writing compressed data on tapes. (This example -assumes you are using the GNU version of tar.) +and emits a warning by default. You can use the --quiet option to +suppress the warning. .SH BUGS The gzip format represents the input size modulo 2^32, so the --list option reports incorrect uncompressed sizes and compression diff --git a/gzip.c b/gzip.c index e69c3e0..19ea909 100644 --- a/gzip.c +++ b/gzip.c @@ -188,7 +188,6 @@ static int part_nb; /* number of parts in .gz file */ struct timespec time_stamp; /* original time stamp (modification time) */ off_t ifile_size; /* input file size, -1 for devices (debug only) */ static char *env; /* contents of GZIP env variable */ -static char **args = NULL; /* argv pointer if GZIP env variable defined */ static char const *z_suffix; /* default suffix (can be set with --suffix) */ static size_t z_len; /* strlen(z_suffix) */ @@ -242,9 +241,15 @@ static int handled_sig[] = non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1 + PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1, + + /* 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"; + static const struct option longopts[] = { /* { name has_arg *flag val } */ @@ -401,7 +406,9 @@ int main (int argc, char **argv) { int file_count; /* number of files to process */ size_t proglen; /* length of program_name */ - int optc; /* current option */ + char **argv_copy; + int env_argc; + char **env_argv; EXPAND(argc, argv); /* wild card expansion if necessary */ @@ -415,8 +422,9 @@ int main (int argc, char **argv) program_name[proglen - 4] = '\0'; /* Add options in GZIP environment variable if there is one */ - env = add_envopt(&argc, &argv, OPTIONS_VAR); - if (env != NULL) args = argv; + 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 @@ -440,8 +448,53 @@ int main (int argc, char **argv) z_suffix = Z_SUFFIX; z_len = strlen(z_suffix); - while ((optc = getopt_long (argc, argv, "ab:cdfhH?klLmMnNqrS:tvVZ123456789", - longopts, (int *)0)) != -1) { + 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); + if (optc < 0) + break; + switch (optc) { case 'a': ascii = 1; break; @@ -474,12 +527,15 @@ 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 @@ -501,6 +557,7 @@ 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(); do_exit(OK); break; @@ -513,12 +570,28 @@ int main (int argc, char **argv) try_help (); break; #endif + 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; + /* Fall through. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': level = optc - '0'; break; + default: - /* Error message already emitted by getopt_long. */ + if (ENV_OPTION <= optc && optc != ENV_OPTION + '?') + { + /* Output a diagnostic, since getopt_long didn't. */ + fprintf (stderr, "%s: ", program_name); + if (0 <= longind) + fprintf (stderr, "--%s: ", longopts[longind].name); + else + fprintf (stderr, "-%c: ", optc - ENV_OPTION); + fprintf (stderr, ("option not valid in "OPTIONS_VAR + " environment variable\n")); + } try_help (); } } /* loop on all arguments */ @@ -1902,8 +1975,6 @@ local void do_exit(exitcode) in_exit = 1; free(env); env = NULL; - free(args); - args = NULL; FREE(inbuf); FREE(outbuf); FREE(d_buf); diff --git a/tests/Makefile.am b/tests/Makefile.am index 8dd6436..8252670 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,7 @@ # along with this program. If not, see