summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-05-27 10:39:49 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2016-05-27 11:50:19 +0300
commit9a33077a7b7ad7d32815a21dee54eba63b38a81c (patch)
tree3b9336b1b23725ab9814eaf2ec8a6629843c8b02
parent20b55f0679d314568ec21ae6db1ea635494e292b (diff)
downloadtar-9a33077a7b7ad7d32815a21dee54eba63b38a81c.tar.gz
Report positional options that were used but had no effect during archive creation
* src/names.c (file_selection_option) (file_selection_option_name): New functions. (unconsumed_option_push, unconsumed_option_free) (unconsumed_option_report): New functions. (name_list_advance): Maintain a list of eventually unconsumed options during archive creation. Report unconsumed options, if any. * tests/positional01.at: New test case. * tests/positional02.at: New test case. * tests/positional03.at: New test case. * tests/Makefile.am: Add new test cases. * tests/testsuite.at: Likewise. * NEWS: Document the changes. * configure.ac: Version 1.29.90 * doc/tar.texi: Document the changes.
-rw-r--r--NEWS24
-rw-r--r--configure.ac2
-rw-r--r--doc/tar.texi17
-rw-r--r--src/names.c114
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/positional01.at54
-rw-r--r--tests/positional02.at49
-rw-r--r--tests/positional03.at47
-rw-r--r--tests/testsuite.at5
9 files changed, 308 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 501164ab..caa77bc1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,29 @@
-GNU tar NEWS - User visible changes. 2016-05-16
+GNU tar NEWS - User visible changes. 2016-05-27
Please send GNU tar bug reports to <bug-tar@gnu.org>
+version 1.29.90 (Git)
+
+* Report erroneous use of positional options.
+
+During archive creation or update, tar keeps track of positional
+options (see the manual, subsection 3.4.4 "Position-Sensitive
+Options"), and reports those that had no effect. For example, when
+invoked as
+
+ tar -cf a.tar . --exclude '*.o'
+
+tar will create the archive, but will exit with status 2, having
+issued the following error message
+
+ tar: The following options were used after any non-optional
+ arguments in archive create or update mode. These options are
+ positional and affect only arguments that follow them. Please,
+ rearrange them properly.
+ tar: --exclude '*.o' has no effect
+ tar: Exiting with failure status due to previous errors
+
+
version 1.29 - Sergey Poznyakoff, 2016-05-16
* New options: --verbatim-files-from, --no-verbatim-files-from
diff --git a/configure.ac b/configure.ac
index 50fbae51..715a3661 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-AC_INIT([GNU tar], [1.29], [bug-tar@gnu.org])
+AC_INIT([GNU tar], [1.29.90], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
diff --git a/doc/tar.texi b/doc/tar.texi
index a8969e08..51ed159b 100644
--- a/doc/tar.texi
+++ b/doc/tar.texi
@@ -3879,6 +3879,23 @@ tar -cf a.tar /usr --no-recursion /var/*
tar -cf a.tar --recursion /usr --no-recursion /var/*
@end example
+During archive creation, @GNUTAR{} keeps track of positional options
+used and arguments affected by them. If it finds out that any such
+options are used in an obviously erroneous way, the fact is reported
+and exit code is set to 2. E.g.:
+
+@example
+@group
+$ @kbd{tar -cf a.tar . --exclude '*.o'}
+tar: The following options were used after any non-optional
+arguments in archive create or update mode. These options are
+positional and affect only arguments that follow them. Please,
+rearrange them properly.
+tar: --exclude '*.o' has no effect
+tar: Exiting with failure status due to previous errors
+@end group
+@end example
+
The following table summarizes all position-sensitive options.
@table @option
diff --git a/src/names.c b/src/names.c
index 037b869d..e3be7569 100644
--- a/src/names.c
+++ b/src/names.c
@@ -149,16 +149,29 @@ static struct argp_option names_options[] = {
{NULL}
};
-static bool
-is_file_selection_option (int key)
+static struct argp_option const *
+file_selection_option (int key)
{
struct argp_option *p;
for (p = names_options;
!(p->name == NULL && p->key == 0 && p->doc == NULL); p++)
if (p->key == key)
- return true;
- return false;
+ return p;
+ return NULL;
+}
+
+static char const *
+file_selection_option_name (int key)
+{
+ struct argp_option const *opt = file_selection_option (key);
+ return opt ? opt->name : NULL;
+}
+
+static bool
+is_file_selection_option (int key)
+{
+ return file_selection_option (key) != NULL;
}
/* Either NL or NUL, as decided by the --null option. */
@@ -670,7 +683,85 @@ name_list_adjust (void)
while (name_head->prev)
name_head = name_head->prev;
}
+
+/* For error-reporting purposes, keep a doubly-linked list of unconsumed file
+ selection options. The option is deemed unconsumed unless followed by one
+ or more file/member name arguments. When archive creation is requested,
+ each file selection option encountered is pushed into the list. The list
+ is cleared upon encountering a file name argument.
+
+ If the list is not empty when all arguments have been processed, an error
+ message is issued reporting the options that had no effect.
+
+ For simplicity, only a tail pointer of the list is maintained.
+*/
+
+struct name_elt *unconsumed_option_tail;
+
+/* Push an option to the list */
+static void
+unconsumed_option_push (struct name_elt *elt)
+{
+ elt->prev = unconsumed_option_tail;
+ if (unconsumed_option_tail)
+ unconsumed_option_tail->next = elt;
+ unconsumed_option_tail = elt;
+}
+
+/* Clear the unconsumed option list */
+static void
+unconsumed_option_free (void)
+{
+ while (unconsumed_option_tail)
+ {
+ struct name_elt *elt = unconsumed_option_tail;
+ unconsumed_option_tail = unconsumed_option_tail->prev;
+ free (elt);
+ }
+}
+
+/* Report any options that have not been consumed */
+static void
+unconsumed_option_report (void)
+{
+ if (unconsumed_option_tail)
+ {
+ struct name_elt *elt;
+
+ ERROR ((0, 0, _("The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.")));
+
+ elt = unconsumed_option_tail;
+ while (elt->prev)
+ elt = elt->prev;
+ while (elt)
+ {
+ switch (elt->type)
+ {
+ case NELT_CHDIR:
+ ERROR ((0, 0, _("-C %s has no effect"), quote (elt->v.name)));
+ break;
+
+ case NELT_OPTION:
+ if (elt->v.opt.arg)
+ ERROR ((0, 0, _("--%s %s has no effect"),
+ file_selection_option_name (elt->v.opt.option),
+ quote (elt->v.opt.arg)));
+ else
+ ERROR ((0, 0, _("--%s has no effect"),
+ file_selection_option_name (elt->v.opt.option)));
+ break;
+
+ default:
+ break;
+ }
+ elt = elt->next;
+ }
+
+ unconsumed_option_free ();
+ }
+}
+
static void
name_list_advance (void)
{
@@ -678,7 +769,18 @@ name_list_advance (void)
name_head = elt->next;
if (name_head)
name_head->prev = NULL;
- free (elt);
+ if (elt->type == NELT_OPTION || elt->type == NELT_CHDIR)
+ {
+ if (subcommand_option == CREATE_SUBCOMMAND
+ || subcommand_option == UPDATE_SUBCOMMAND)
+ unconsumed_option_push (elt);
+ }
+ else
+ {
+ if (elt->type != NELT_NOOP)
+ unconsumed_option_free ();
+ free (elt);
+ }
}
@@ -1013,6 +1115,8 @@ name_next_elt (int change_dirs)
}
}
+ unconsumed_option_report ();
+
return NULL;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3e942769..0ea6d172 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -166,6 +166,9 @@ TESTSUITE_AT = \
opcomp04.at\
opcomp05.at\
opcomp06.at\
+ positional01.at\
+ positional02.at\
+ positional03.at\
options.at\
options02.at\
owner.at\
diff --git a/tests/positional01.at b/tests/positional01.at
new file mode 100644
index 00000000..37b14db6
--- /dev/null
+++ b/tests/positional01.at
@@ -0,0 +1,54 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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.
+
+# GNU tar 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 <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Exclude])
+AT_KEYWORDS([options positional positional01 exclude])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -cf a.tar --exclude '*.b' dir
+echo $?
+tar -tf a.tar | sort
+tar -cf a.tar dir --exclude '*.b'
+echo $?
+tar -tf a.tar | sort
+],
+[0],
+[0
+dir/
+dir/A.a
+dir/B.a
+2
+dir/
+dir/A.a
+dir/A.b
+dir/B.a
+],
+[tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: --exclude '*.b' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
diff --git a/tests/positional02.at b/tests/positional02.at
new file mode 100644
index 00000000..352b62cf
--- /dev/null
+++ b/tests/positional02.at
@@ -0,0 +1,49 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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.
+
+# GNU tar 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 <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Directory])
+AT_KEYWORDS([options positional positional02 directory chdir])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -cf a.tar -C dir .
+echo $?
+tar -tf a.tar | sort
+tar -cf a.tar . -C dir
+],
+[2],
+[0
+./
+./A.a
+./A.b
+./B.a
+],
+[tar: ./a.tar: file is the archive; not dumped
+tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: -C 'dir' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
diff --git a/tests/positional03.at b/tests/positional03.at
new file mode 100644
index 00000000..9a03671d
--- /dev/null
+++ b/tests/positional03.at
@@ -0,0 +1,47 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This file is part of GNU tar.
+
+# GNU tar 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.
+
+# GNU tar 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 <http://www.gnu.org/licenses/>.
+
+AT_SETUP([Several options])
+AT_KEYWORDS([options positional positional03])
+
+AT_CHECK([
+AT_SORT_PREREQ
+mkdir t
+cd t
+mkdir dir
+> dir/A.a
+> dir/B.a
+> dir/A.b
+tar -vcf ../a.tar --exclude '*.b' . -C dir --exclude '*.c' | sort
+],
+[0],
+[./
+./dir/
+./dir/A.a
+./dir/B.a
+],
+[tar: The following options were used after any non-optional arguments in archive create or update mode. These options are positional and affect only arguments that follow them. Please, rearrange them properly.
+tar: -C 'dir' has no effect
+tar: --exclude '*.c' has no effect
+tar: Exiting with failure status due to previous errors
+])
+
+AT_CLEANUP
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index cf4b2fd5..11c39c9f 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -213,6 +213,11 @@ m4_include([opcomp04.at])
m4_include([opcomp05.at])
m4_include([opcomp06.at])
+AT_BANNER([Positional options])
+m4_include([positional01.at])
+m4_include([positional02.at])
+m4_include([positional03.at])
+
AT_BANNER([The -T option])
m4_include([T-mult.at])
m4_include([T-nest.at])