]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
readlink: quote problematic names on tty
authorPádraig Brady <P@draigBrady.com>
Thu, 30 Jul 2026 20:49:12 +0000 (21:49 +0100)
committerPádraig Brady <P@draigBrady.com>
Sat, 1 Aug 2026 11:38:28 +0000 (12:38 +0100)
* doc/coreutils.texi (readlink invocation): Mention $QUOTING_STYLE
is significant.
* src/readlink.c (main): Quote output when appropriate.
* tests/readlink/rl-1.sh: Add a test case.
* NEWS: Mention the improvement.

NEWS
doc/coreutils.texi
src/readlink.c
tests/readlink/rl-1.sh

diff --git a/NEWS b/NEWS
index 0667f4fddc5e08e5926393c14b3e91da427689e3..2db6c99ae0e067cdafb1e51e1e1269cb9fd1b95a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -84,8 +84,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   'install -C' will now avoid updating file metadata when the destination
   already has the appropriate ownership and permissions.
 
-  'basename' and 'realpath' now quote output in shell-escape style when
-  standard output is a terminal.  The QUOTING_STYLE environment variable
+  'basename', 'readlink', and 'realpath' now quote output in shell-escape style
+  when standard output is a terminal.  The QUOTING_STYLE environment variable
   can be used to adjust or disable the quoting.
 
   'ls -m' now quotes files names containing commas when appropriate,
index d9b6a8761f666196df90b32ec8fcd334aaa0878f..b675b6345abb329e5b3339e80069c7eeca9a3936 100644 (file)
@@ -11100,6 +11100,11 @@ variable is set.
 
 @end table
 
+When standard output is a terminal, output is quoted using the
+@samp{shell-escape} style.  The environment variable
+@env{QUOTING_STYLE} can select the quoting style. Valid quoting styles are:
+@quotingStyles
+
 The @command{readlink} utility first appeared in OpenBSD 2.1.
 
 The @command{realpath} command without options, operates like
index 3a2d6aaed10706e14e6896df886518956e40f232..f25aced2c18b11a410b3412acfa27fb88fdc8e31 100644 (file)
@@ -21,6 +21,7 @@
 #include <getopt.h>
 #include <sys/types.h>
 
+#include "argmatch.h"  /* argmatch($QUOTING_STYLE).  */
 #include "system.h"
 #include "canonicalize.h"
 #include "areadlink.h"
@@ -36,6 +37,9 @@ static bool no_newline;
 /* If true, report error messages.  */
 static bool verbose;
 
+/* If true, quote output according to the selected quoting style.  */
+static bool quote_output;
+
 static struct option const longopts[] =
 {
   {"canonicalize", no_argument, NULL, 'f'},
@@ -170,6 +174,18 @@ main (int argc, char **argv)
       no_newline = false;
     }
 
+  if (!use_nuls && isatty (STDOUT_FILENO))
+    {
+      int qs = getenv_quoting_style ();
+      if (qs < 0)
+        qs = shell_escape_quoting_style;
+      if (qs != literal_quoting_style)
+        {
+          set_quoting_style (NULL, qs);
+          quote_output = true;
+        }
+    }
+
   /* POSIX requires a diagnostic message written to standard error and a
      non-zero exit status when given a file that is not a symbolic link.  */
   if (getenv ("POSIXLY_CORRECT") != NULL)
@@ -183,7 +199,7 @@ main (int argc, char **argv)
                      : areadlink_with_size (fname, 63));
       if (value)
         {
-          fputs (value, stdout);
+          fputs (quote_output ? quoteN (value) : value, stdout);
           if (! no_newline)
             putchar (use_nuls ? '\0' : '\n');
           free (value);
index b3f6a20495af72308197650c6e4941f1eb7cce80..4beffad967087a0ee6dc8fda34d325308247a7a5 100755 (executable)
@@ -23,6 +23,7 @@ mkdir subdir || framework_failure_
 touch regfile || framework_failure_
 ln -s regfile link1 || framework_failure_
 ln -s missing link2 || framework_failure_
+ln -s 'q name' qlink || framework_failure_
 
 
 v=$(readlink link1) || fail=1
@@ -31,6 +32,20 @@ test "$v" = regfile || fail=1
 v=$(readlink link2) || fail=1
 test "$v" = missing || fail=1
 
+# QUOTING_STYLE does not affect redirected output.
+printf 'q name\n' > exp || framework_failure_
+for style in literal shell-always invalid; do
+  QUOTING_STYLE="$style" readlink qlink > out 2> err || fail=1
+  compare exp out || fail=1
+  compare /dev/null err || fail=1
+done
+
+# --zero disables quoting, and does not inspect QUOTING_STYLE.
+QUOTING_STYLE=invalid readlink -z qlink > out 2> err || fail=1
+printf 'q name\0' > exp || framework_failure_
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
 v=$(returns_ 1 readlink subdir) || fail=1
 test -z "$v" || fail=1