From 67a1a0eac50404799328448ae7540696cc3f6c79 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 5 Aug 2009 13:52:38 +0300 Subject: [PATCH] Implement the --warning option. * src/warning.c: New file. * src/Makefile.am: Add warning.c * src/common.h: Provide definitions for warning classes. (warning_option): New global. (WARNOPT): New define. (set_warning_option): New prototype. * src/tar.c: New option `--warning'. * src/compare.c: When applicable WARNOPT instead of WARN. * src/create.c: Likewise. * src/extract.c: Likewise. * src/incremen.c: Likewise. * src/list.c: Likewise. * NEWS, doc/tar.texi: Update. --- NEWS | 13 +++++ doc/tar.texi | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 3 +- src/common.h | 35 ++++++++++++ src/compare.c | 5 +- src/create.c | 62 +++++++++++--------- src/extract.c | 29 ++++++---- src/incremen.c | 28 +++++---- src/list.c | 5 +- src/tar.c | 12 +++- src/xheader.c | 5 +- 11 files changed, 289 insertions(+), 57 deletions(-) diff --git a/NEWS b/NEWS index 9c15ad7..4dba114 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,19 @@ When listing or extracting archives, the actual record size is reported only if the archive is read from a device (as opposed to regular files and pipes). +* New command line option `--warning' + +The `--warning' command line option allows to suppress or enable +particular warning messages during `tar' run. It takes a single +argument (a `keyword'), identifying the class of warning messages +to affect. If the argument is prefixed with `no-', such warning +messages are suppressed. For example, + + tar --warning=no-alone-zero-block -x -f archive + +suppresses the output of `A lone zero block' diagnostics, which is +normally issued if `archive' ends with a single block of zeros. + * Bugfixes ** Fix handling of hard link targets by -c --transform. ** Fix hard links recognition with -c --remove-files. diff --git a/doc/tar.texi b/doc/tar.texi index fe09c12..a613d6b 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -21,12 +21,14 @@ @include value.texi @defcodeindex op +@defcodeindex kw @c Put everything in one index (arbitrarily chosen to be the concept index). @syncodeindex fn cp @syncodeindex ky cp @syncodeindex pg cp @syncodeindex vr cp +@syncodeindex kw cp @copying @@ -177,6 +179,7 @@ Invoking @GNUTAR{} * defaults:: * verbose:: * checkpoints:: +* warnings:: * interactive:: The Three Option Styles @@ -1801,6 +1804,7 @@ and @option{--interactive} options (@pxref{interactive}). * defaults:: * verbose:: * checkpoints:: +* warnings:: * interactive:: @end menu @@ -3348,6 +3352,13 @@ Used in conjunction with @option{--multi-volume}. @command{tar} will keep track of which volume of a multi-volume archive it is working in @var{file}. @xref{volno-file}. +@opsummary{warning} +@item --warning=@var{keyword} + +Enable or disable warning messages identified by @var{keyword}. The +messages are suppressed if @var{keyword} is prefixed with @samp{no-}. +@xref{warnings}. + @opsummary{wildcards} @item --wildcards Use wildcards when matching member names with patterns. @@ -3951,6 +3962,144 @@ This example also illustrates the fact that @option{--checkpoint}. In this case, the default checkpoint frequency (at each 10th record) is assumed. +@node warnings +@section Controlling Warning Messages + +Sometimes, while performing the requested task, @GNUTAR{} notices +some conditions that are not exactly erros, but which the user +should be aware of. When this happens, @command{tar} issues a +@dfn{warning message} describing the condition. Warning messages +are output to the standard error and they do not affect the exit +code of @command{tar} command. + +@xopindex{warning, explained} +@GNUTAR{} allows the user to suppress some or all of its warning +messages: + +@table @option +@item --warning=@var{keyword} +Control display of the warning messages identified by @var{keyword}. +If @var{keyword} starts with the prefix @samp{no-}, such messages are +suppressed. Otherwise, they are enabled. + +Multiple @option{--warning} messages accumulate. + +The tables below list allowed values for @var{keyword} along with the +warning messages they control. +@end table + +@subheading Keywords controlling @command{tar} operation +@table @asis +@kwindex all +@item all +Enable all warning messages. This is the default. +@kwindex none +@item none +Disable all warning messages. +@kwindex filename-with-nuls +@cindex @samp{file name read contains nul character}, warning message +@item filename-with-nuls +@samp{%s: file name read contains nul character} +@kwindex alone-zero-block +@cindex @samp{A lone zero block at}, warning message +@item alone-zero-block +@samp{A lone zero block at %s} +@end table + +@subheading Keywords applicable for @command{tar --create} +@table @asis +@kwindex cachedir +@cindex @samp{contains a cache directory tag}, warning message +@item cachedir +@samp{%s: contains a cache directory tag %s; %s} +@kwindex file-shrank +@cindex @samp{File shrank by %s bytes}, warning message +@item file-shrank +@samp{%s: File shrank by %s bytes; padding with zeros} +@kwindex xdev +@cindex @samp{file is on a different filesystem}, warning message +@item xdev +@samp{%s: file is on a different filesystem; not dumped} +@kwindex file-ignored +@cindex @samp{Unknown file type; file ignored}, warning message +@cindex @samp{socket ignored}, warning message +@cindex @samp{door ignored}, warning message +@item file-ignored +@samp{%s: Unknown file type; file ignored} +@samp{%s: socket ignored} +@*@samp{%s: door ignored} +@kwindex file-unchanged +@cindex @samp{file is unchanged; not dumped}, warning message +@item file-unchanged +@samp{%s: file is unchanged; not dumped} +@kwindex ignore-archive +@cindex @samp{file is the archive; not dumped}, warning message +@kwindex ignore-archive +@cindex @samp{file is the archive; not dumped}, warning message +@item ignore-archive +@samp{%s: file is the archive; not dumped} +@kwindex file-removed +@cindex @samp{File removed before we read it}, warning message +@item file-removed +@samp{%s: File removed before we read it} +@kwindex file-changed +@cindex @samp{file changed as we read it}, warning message +@item file-changed +@samp{%s: file changed as we read it} +@end table + +@subheading Keywords applicable for @command{tar --extract} +@table @asis +@kwindex timestamp +@cindex @samp{implausibly old time stamp %s}, warning message +@cindex @samp{time stamp %s is %s s in the future}, warning message +@item timestamp +@samp{%s: implausibly old time stamp %s} +@*@samp{%s: time stamp %s is %s s in the future} +@kwindex contiguous-cast +@cindex @samp{Extracting contiguous files as regular files}, warning message +@item contiguous-cast +@samp{Extracting contiguous files as regular files} +@kwindex symlink-cast +@cindex @samp{Attempting extraction of symbolic links as hard links}, warning message +@item symlink-cast +@samp{Attempting extraction of symbolic links as hard links} +@kwindex unknown-cast +@cindex @samp{Unknown file type `%c', extracted as normal file}, warning message +@item unknown-cast +@samp{%s: Unknown file type `%c', extracted as normal file} +@kwindex ignore-newer +@cindex @samp{Current %s is newer or same age}, warning message +@item ignore-newer +@samp{Current %s is newer or same age} +@kwindex unknown-keyword +@cindex @samp{Ignoring unknown extended header keyword `%s'}, warning message +@item unknown-keyword +@samp{Ignoring unknown extended header keyword `%s'} +@end table + +@subheading Keywords controlling incremental extraction: +@table @asis +@kwindex rename-directory +@cindex @samp{%s: Directory has been renamed from %s}, warning message +@cindex @samp{%s: Directory has been renamed}, warning message +@item rename-directory +@samp{%s: Directory has been renamed from %s} +@*@samp{%s: Directory has been renamed} +@kwindex new-directory +@cindex @samp{%s: Directory is new}, warning message +@item new-directory +@samp{%s: Directory is new} +@kwindex xdev +@cindex @samp{%s: directory is on a different device: not purging}, warning message +@item xdev +@samp{%s: directory is on a different device: not purging} +@kwindex bad-dumpdir +@cindex @samp{Malformed dumpdir: 'X' never used}, warning message +@item bad-dumpdir +@samp{Malformed dumpdir: 'X' never used} +@end table + @node interactive @section Asking for Confirmation During Operations @cindex Interactive operation diff --git a/src/Makefile.am b/src/Makefile.am index fdb7d68..9f268c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,7 +39,8 @@ tar_SOURCES = \ tar.c\ transform.c\ update.c\ - utf8.c + utf8.c\ + warning.c INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu -I$(top_srcdir)/lib -I../lib diff --git a/src/common.h b/src/common.h index 9897b46..2e048a3 100644 --- a/src/common.h +++ b/src/common.h @@ -752,3 +752,38 @@ void set_comression_program_by_suffix (const char *name, const char *defprog); void checkpoint_compile_action (const char *str); void checkpoint_finish_compile (void); void checkpoint_run (bool do_write); + +/* Module warning.c */ +#define WARN_ALONE_ZERO_BLOCK 0x00000001 +#define WARN_BAD_DUMPDIR 0x00000002 +#define WARN_CACHEDIR 0x00000004 +#define WARN_CONTIGUOUS_CAST 0x00000008 +#define WARN_FILE_CHANGED 0x00000010 +#define WARN_FILE_IGNORED 0x00000020 +#define WARN_FILE_REMOVED 0x00000040 +#define WARN_FILE_SHRANK 0x00000080 +#define WARN_FILE_UNCHANGED 0x00000100 +#define WARN_FILENAME_WITH_NULS 0x00000200 +#define WARN_IGNORE_ARCHIVE 0x00000400 +#define WARN_IGNORE_NEWER 0x00000800 +#define WARN_NEW_DIRECTORY 0x00001000 +#define WARN_RENAME_DIRECTORY 0x00002000 +#define WARN_SYMLINK_CAST 0x00004000 +#define WARN_TIMESTAMP 0x00008000 +#define WARN_UNKNOWN_CAST 0x00010000 +#define WARN_UNKNOWN_KEYWORD 0x00020000 +#define WARN_XDEV 0x00040000 + +#define WARN_ALL 0xffffffff + +void set_warning_option (const char *arg); + +extern int warning_option; + +#define WARNOPT(opt,args) \ + do \ + { \ + if (warning_option & opt) WARN (args); \ + } \ + while (0) + diff --git a/src/compare.c b/src/compare.c index 66205cb..da03d86 100644 --- a/src/compare.c +++ b/src/compare.c @@ -609,8 +609,9 @@ verify_volume (void) status = read_header (false); if (status == HEADER_ZERO_BLOCK) break; - WARN ((0, 0, _("A lone zero block at %s"), - STRINGIFY_BIGINT (current_block_ordinal (), buf))); + WARNOPT (WARN_ALONE_ZERO_BLOCK, + (0, 0, _("A lone zero block at %s"), + STRINGIFY_BIGINT (current_block_ordinal (), buf))); } } diff --git a/src/create.c b/src/create.c index 1031cc2..2724fc4 100644 --- a/src/create.c +++ b/src/create.c @@ -63,11 +63,12 @@ exclusion_tag_warning (const char *dirname, const char *tagname, const char *message) { if (verbose_option) - WARN ((0, 0, - _("%s: contains a cache directory tag %s; %s"), - quotearg_colon (dirname), - quotearg_n (1, tagname), - message)); + WARNOPT (WARN_CACHEDIR, + (0, 0, + _("%s: contains a cache directory tag %s; %s"), + quotearg_colon (dirname), + quotearg_n (1, tagname), + message)); } enum exclusion_tag_type @@ -1072,12 +1073,13 @@ dump_regular_file (int fd, struct tar_stat_info *st) { char buf[UINTMAX_STRSIZE_BOUND]; memset (blk->buffer + count, 0, bufsize - count); - WARN ((0, 0, - ngettext ("%s: File shrank by %s byte; padding with zeros", - "%s: File shrank by %s bytes; padding with zeros", - size_left), - quotearg_colon (st->orig_file_name), - STRINGIFY_BIGINT (size_left, buf))); + WARNOPT (WARN_FILE_SHRANK, + (0, 0, + ngettext ("%s: File shrank by %s byte; padding with zeros", + "%s: File shrank by %s bytes; padding with zeros", + size_left), + quotearg_colon (st->orig_file_name), + STRINGIFY_BIGINT (size_left, buf))); if (! ignore_failed_read_option) exit_status = TAREXIT_DIFFERS; pad_archive (size_left - (bufsize - count)); @@ -1173,9 +1175,10 @@ dump_dir0 (char *directory, && parent_device != st->stat.st_dev) { if (verbose_option) - WARN ((0, 0, - _("%s: file is on a different filesystem; not dumped"), - quotearg_colon (st->orig_file_name))); + WARNOPT (WARN_XDEV, + (0, 0, + _("%s: file is on a different filesystem; not dumped"), + quotearg_colon (st->orig_file_name))); } else { @@ -1358,8 +1361,9 @@ compare_links (void const *entry1, void const *entry2) static void unknown_file_error (char const *p) { - WARN ((0, 0, _("%s: Unknown file type; file ignored"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: Unknown file type; file ignored"), + quotearg_colon (p))); if (!ignore_failed_read_option) exit_status = TAREXIT_FAILURE; } @@ -1539,16 +1543,18 @@ dump_file0 (struct tar_stat_info *st, const char *p, && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c))) { if (!incremental_option && verbose_option) - WARN ((0, 0, _("%s: file is unchanged; not dumped"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_UNCHANGED, + (0, 0, _("%s: file is unchanged; not dumped"), + quotearg_colon (p))); return; } /* See if we are trying to dump the archive. */ if (sys_file_is_archive (st)) { - WARN ((0, 0, _("%s: file is the archive; not dumped"), - quotearg_colon (p))); + WARNOPT (WARN_IGNORE_ARCHIVE, + (0, 0, _("%s: file is the archive; not dumped"), + quotearg_colon (p))); return; } @@ -1577,8 +1583,9 @@ dump_file0 (struct tar_stat_info *st, const char *p, if (fd < 0) { if (!top_level && errno == ENOENT) - WARN ((0, 0, _("%s: File removed before we read it"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_REMOVED, + (0, 0, _("%s: File removed before we read it"), + quotearg_colon (p))); else open_diag (p); return; @@ -1663,8 +1670,9 @@ dump_file0 (struct tar_stat_info *st, const char *p, && !(remove_files_option && is_dir)) || original_size < final_stat.st_size) { - WARN ((0, 0, _("%s: file changed as we read it"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_CHANGED, + (0, 0, _("%s: file changed as we read it"), + quotearg_colon (p))); if (exit_status == TAREXIT_SUCCESS) exit_status = TAREXIT_DIFFERS; } @@ -1743,12 +1751,14 @@ dump_file0 (struct tar_stat_info *st, const char *p, type = FIFOTYPE; else if (S_ISSOCK (st->stat.st_mode)) { - WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: socket ignored"), quotearg_colon (p))); return; } else if (S_ISDOOR (st->stat.st_mode)) { - WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: door ignored"), quotearg_colon (p))); return; } else diff --git a/src/extract.c b/src/extract.c index 5361506..3c92e53 100644 --- a/src/extract.c +++ b/src/extract.c @@ -207,8 +207,9 @@ static void check_time (char const *file_name, struct timespec t) { if (t.tv_sec <= 0) - WARN ((0, 0, _("%s: implausibly old time stamp %s"), - file_name, tartime (t, true))); + WARNOPT (WARN_TIMESTAMP, + (0, 0, _("%s: implausibly old time stamp %s"), + file_name, tartime (t, true))); else if (timespec_cmp (volume_start_time, t) < 0) { struct timespec now; @@ -224,8 +225,9 @@ check_time (char const *file_name, struct timespec t) diff.tv_nsec += BILLION; diff.tv_sec--; } - WARN ((0, 0, _("%s: time stamp %s is %s s in the future"), - file_name, tartime (t, true), code_timespec (diff, buf))); + WARNOPT (WARN_TIMESTAMP, + (0, 0, _("%s: time stamp %s is %s s in the future"), + file_name, tartime (t, true), code_timespec (diff, buf))); } } } @@ -753,7 +755,8 @@ open_output_file (char *file_name, int typeflag, mode_t mode) if (!conttype_diagnosed) { conttype_diagnosed = 1; - WARN ((0, 0, _("Extracting contiguous files as regular files"))); + WARNOPT (WARN_CONTIGUOUS_CAST, + (0, 0, _("Extracting contiguous files as regular files"))); } } fd = open (file_name, openflag, mode); @@ -1031,7 +1034,9 @@ extract_symlink (char *file_name, int typeflag) if (!warned_once) { warned_once = 1; - WARN ((0, 0, _("Attempting extraction of symbolic links as hard links"))); + WARNOPT (WARN_SYMBOLIC_CAST, + (0, 0, + _("Attempting extraction of symbolic links as hard links"))); } return extract_link (file_name, typeflag); #endif @@ -1189,9 +1194,10 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) break; default: - WARN ((0, 0, - _("%s: Unknown file type `%c', extracted as normal file"), - quotearg_colon (file_name), typeflag)); + WARNOPT (WARN_UNKNOWN_CAST, + (0, 0, + _("%s: Unknown file type `%c', extracted as normal file"), + quotearg_colon (file_name), typeflag)); *fun = extract_file; } @@ -1215,8 +1221,9 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) case KEEP_NEWER_FILES: if (file_newer_p (file_name, ¤t_stat_info)) { - WARN ((0, 0, _("Current %s is newer or same age"), - quote (file_name))); + WARNOPT (WARN_IGNORE_NEWER, + (0, 0, _("Current %s is newer or same age"), + quote (file_name))); return 0; } break; diff --git a/src/incremen.c b/src/incremen.c index cd32e19..025701b 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -445,9 +445,11 @@ procdir (char *name_buffer, struct stat *stat_data, if (strcmp (d->name, name_buffer)) { if (verbose_option) - WARN ((0, 0, _("%s: Directory has been renamed from %s"), - quotearg_colon (name_buffer), - quote_n (1, d->name))); + WARNOPT (WARN_RENAME_DIRECTORY, + (0, 0, + _("%s: Directory has been renamed from %s"), + quotearg_colon (name_buffer), + quote_n (1, d->name))); directory->orig = d; DIR_SET_FLAG (directory, DIRF_RENAMED); dirlist_replace_prefix (d->name, name_buffer); @@ -457,8 +459,9 @@ procdir (char *name_buffer, struct stat *stat_data, else { if (verbose_option) - WARN ((0, 0, _("%s: Directory has been renamed"), - quotearg_colon (name_buffer))); + WARNOPT (WARN_RENAME_DIRECTORY, + (0, 0, _("%s: Directory has been renamed"), + quotearg_colon (name_buffer))); directory->children = ALL_CHILDREN; directory->device_number = stat_data->st_dev; directory->inode_number = stat_data->st_ino; @@ -489,9 +492,10 @@ procdir (char *name_buffer, struct stat *stat_data, if (strcmp (d->name, name_buffer)) { if (flag & PD_VERBOSE) - WARN ((0, 0, _("%s: Directory has been renamed from %s"), - quotearg_colon (name_buffer), - quote_n (1, d->name))); + WARNOPT (WARN_RENAME_DIRECTORY, + (0, 0, _("%s: Directory has been renamed from %s"), + quotearg_colon (name_buffer), + quote_n (1, d->name))); directory->orig = d; DIR_SET_FLAG (directory, DIRF_RENAMED); dirlist_replace_prefix (d->name, name_buffer); @@ -502,8 +506,9 @@ procdir (char *name_buffer, struct stat *stat_data, { DIR_SET_FLAG (directory, DIRF_NEW); if (flag & PD_VERBOSE) - WARN ((0, 0, _("%s: Directory is new"), - quotearg_colon (name_buffer))); + WARNOPT (WARN_NEW_DIRECTORY, + (0, 0, _("%s: Directory is new"), + quotearg_colon (name_buffer))); directory->children = (listed_incremental_option || (OLDER_STAT_TIME (*stat_data, m) @@ -1504,7 +1509,8 @@ dumpdir_ok (char *dumpdir) } if (has_tempdir) - WARN ((0, 0, _("Malformed dumpdir: 'X' never used"))); + WARNOPT (WARN_BAD_DUMPDIR, + (0, 0, _("Malformed dumpdir: 'X' never used"))); return true; } diff --git a/src/list.c b/src/list.c index 98c1e39..2436901 100644 --- a/src/list.c +++ b/src/list.c @@ -141,8 +141,9 @@ read_and (void (*do_something) (void)) status = read_header (false); if (status == HEADER_ZERO_BLOCK) break; - WARN ((0, 0, _("A lone zero block at %s"), - STRINGIFY_BIGINT (current_block_ordinal (), buf))); + WARNOPT (WARN_ALONE_ZERO_BLOCK, + (0, 0, _("A lone zero block at %s"), + STRINGIFY_BIGINT (current_block_ordinal (), buf))); break; } status = prev_status; diff --git a/src/tar.c b/src/tar.c index 0abd88b..b11edad 100644 --- a/src/tar.c +++ b/src/tar.c @@ -328,6 +328,7 @@ enum UTC_OPTION, VERSION_OPTION, VOLNO_FILE_OPTION, + WARNING_OPTION, WILDCARDS_MATCH_SLASH_OPTION, WILDCARDS_OPTION }; @@ -719,6 +720,8 @@ static struct argp_option options[] = { {"verbose", 'v', 0, 0, N_("verbosely list files processed"), GRID+1 }, + {"warning", WARNING_OPTION, N_("KEYWORD"), 0, + N_("warning control"), GRID+1 }, {"checkpoint", CHECKPOINT_OPTION, N_("NUMBER"), OPTION_ARG_OPTIONAL, N_("display progress messages every NUMBERth record (default 10)"), GRID+1 }, @@ -1183,8 +1186,9 @@ update_argv (const char *filename, struct argp_state *state) { size_t size; - WARN ((0, 0, N_("%s: file name read contains nul character"), - quotearg_colon (filename))); + WARNOPT (WARN_FILENAME_WITH_NULS, + (0, 0, N_("%s: file name read contains nul character"), + quotearg_colon (filename))); /* Prepare new stack contents */ size = obstack_object_size (&argv_stk); @@ -1949,6 +1953,10 @@ parse_opt (int key, char *arg, struct argp_state *state) unquote_option = false; break; + case WARNING_OPTION: + set_warning_option (arg); + break; + case '0': case '1': case '2': diff --git a/src/xheader.c b/src/xheader.c index 84ae08b..c779c0a 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -571,8 +571,9 @@ decx (void *data, char const *keyword, char const *value, size_t size) if (t) t->decoder (st, keyword, value, size); else - WARN((0, 0, _("Ignoring unknown extended header keyword `%s'"), - keyword)); + WARNOPT (WARN_UNKNOWN_KEYWORD, + (0, 0, _("Ignoring unknown extended header keyword `%s'"), + keyword)); } void -- 2.44.0