* src/dircolors.c (syntax): New global variable.
(append_quoted): Escape '!' if we are using 'csh' syntax to prevent
history substitution.
(main): Remove the syntax variable that was made global.
* tests/misc/dircolors.pl (@Tests): Add a test case.
* NEWS: Mention the bug fix.
Discovered by Anthropic's OSS Scanner, as bug ANT-2026-SFBDLZ6V.
---
NEWS | 6 ++++++
src/dircolors.c | 11 ++++++++++-
tests/misc/dircolors.pl | 5 +++++
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index b1d8f09ec..a856efff8 100644
--- a/NEWS
+++ b/NEWS
@@ -71,6 +71,12 @@ GNU coreutils NEWS -*-
outline -*-
oflag=seek_bytes, and when N is smaller than the output block size.
[bug introduced with oflag=seek_bytes in coreutils-8.16]
+ 'dircolors --csh' now escapes '!' characters in its output. Previously, csh
+ would perform history substitution on the output when evaluated, which would
+ fail or execute arbitrary commands depending on the contents of the database
+ file.
+ [This bug was present in "the beginning".]
+
'factor' no longer treats inputs requiring the use of arbitrary-precision
integers followed by a non-numeric suffix as zero if the suffix includes
non-space characters, or the number itself when followed by spaces.
diff --git a/src/dircolors.c b/src/dircolors.c
index 72f62820c..b7b1c72da 100644
--- a/src/dircolors.c
+++ b/src/dircolors.c
@@ -44,6 +44,9 @@ enum Shell_syntax
SHELL_SYNTAX_UNKNOWN
};
+/* The shell syntax being used. */
+static enum Shell_syntax syntax = SHELL_SYNTAX_UNKNOWN;
+
#define APPEND_CHAR(C) obstack_1grow (&lsc_obstack, C)
/* Accumulate in this obstack the value for the LS_COLORS environment
@@ -235,6 +238,13 @@ append_quoted (char const *str)
need_backslash = !need_backslash;
break;
+ case '!':
+ /* Prevent 'csh' from doing history substitution. */
+ if (syntax == SHELL_SYNTAX_C)
+ APPEND_CHAR ('\\');
+ need_backslash = true;
+ break;
+
case ':':
case '=':
if (need_backslash)
@@ -436,7 +446,6 @@ main (int argc, char **argv)
{
bool ok = true;
int optc;
- enum Shell_syntax syntax = SHELL_SYNTAX_UNKNOWN;
bool print_database = false;
initialize_main (&argc, &argv);
diff --git a/tests/misc/dircolors.pl b/tests/misc/dircolors.pl
index 404fbb075..6c0575c43 100755
--- a/tests/misc/dircolors.pl
+++ b/tests/misc/dircolors.pl
@@ -66,6 +66,11 @@ my @Tests =
['print-ls-colors', '--print-ls-colors', {IN => "OWT 40;33\n"},
{OUT => "\x1B[40;33mtw\t40;33\x1B[0m\n"}],
+ ['csh-history-sub', '-c',
+ {IN => "*.a!#^:s\\LS_COLORS\\' ; touch ./a; echo '\n"},
+ {OUT => ("setenv LS_COLORS '*.a\\!#^:s\\LS_COLORS\\'\\''=; "
+ . "touch ./a; echo '\\'':'\n")}],
+
# CAREFUL: always specify the -b option, unless explicitly testing
# for csh syntax output, or --print-ls-color output.
);
--
2.56.0