Hi Eric, You said:
> Among other things, I can see the following changes that coreutils > will need to make to become compliant, or else we need to push back on > the POSIX folks if we have strong reasons to complain that their > specification will break things: > > POSIX wants 'readlink non-symlink' to output a diagnostic; that is, it > looks like POSIX wants us to behave like '-v' is enabled by default > (our current behavior of -q by default will be non-compliant). I have attached a patch that I think is correct for readlink. It is a bit more complex than just behaving the same as 'readlink -v' previously would. This is because the behavior of non-POSIX options. Here are some commands: $ touch file $ ln -s symlink file # Example 1 $ readlink -v file readlink: file: Invalid argument # Example 2 $ readlink -v -f file /home/collin/file If 'readlink -v' where 'POSIXLY_CORRECT=1 readlink' then example 1 would conform. I think that example 2 would violate POSIX. So, when POSIXLY_CORRECT is enabled we can call 'readlink', check for errors, and then canonicalize if it is successful. Collin
>From 49d32775db13eb3f272853eb1c7124fff17b93f8 Mon Sep 17 00:00:00 2001 Message-ID: <49d32775db13eb3f272853eb1c7124fff17b93f8.1754194901.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Sat, 2 Aug 2025 20:51:30 -0700 Subject: [PATCH] readlink: emit errors when POSIXLY_CORRECT is set * src/readlink.c (main): Set verbose if the POSIXLY_CORRECT environment variable is set. Check if the file is a symbolic link if POSIXLY_CORRECT is set. * tests/readlink/readlink-posix.sh: New file. * tests/local.mk (all_tests): Add it. * NEWS: Mention the change. * doc/coreutils.texi (readlink invocation): Document the behavior of POSIXLY_CORRECT. --- NEWS | 6 ++++ doc/coreutils.texi | 5 ++++ src/readlink.c | 24 ++++++++++++++-- tests/local.mk | 1 + tests/readlink/readlink-posix.sh | 48 ++++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 3 deletions(-) create mode 100755 tests/readlink/readlink-posix.sh diff --git a/NEWS b/NEWS index 110e688b1..e79067bb4 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,12 @@ GNU coreutils NEWS -*- outline -*- 'factor' is now much faster at identifying large prime numbers, and significantly faster on composite numbers greater than 2^128. +** New Features + + readlink will print a diagnostic message to standard error and exit + with a non-zero status when given a file that is not a symbolic link + if the POSIXLY_CORRECT environment variable is defined. + ** Bug fixes cksum was not compilable by Apple LLVM 10.0.0 x86-64, which diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 40ecf3126..15a231bc3 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -11474,6 +11474,11 @@ @node readlink invocation @end table +@vindex POSIXLY_CORRECT +If the @env{POSIXLY_CORRECT} environment variable is set and +@var{file} is not a symbolic link, @command{readlink} will emit a +diagnostic message to standard error and exit with a nonzero status. + The @command{readlink} utility first appeared in OpenBSD 2.1. The @command{realpath} command without options, operates like diff --git a/src/readlink.c b/src/readlink.c index 44def1dbb..4586e5820 100644 --- a/src/readlink.c +++ b/src/readlink.c @@ -97,6 +97,7 @@ main (int argc, char **argv) int status = EXIT_SUCCESS; int optc; bool use_nuls = false; + bool posixly_correct = (getenv ("POSIXLY_CORRECT") != nullptr); initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -152,12 +153,29 @@ main (int argc, char **argv) no_newline = false; } + /* 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 (posixly_correct) + verbose = true; + for (; optind < argc; ++optind) { char const *fname = argv[optind]; - char *value = (can_mode != -1 - ? canonicalize_filename_mode (fname, can_mode) - : areadlink_with_size (fname, 63)); + char *value; + + if (! posixly_correct) + value = (can_mode != -1 + ? canonicalize_filename_mode (fname, can_mode) + : areadlink_with_size (fname, 63)); + else + { + /* We have to check if the file is a symbolic link before + canonicalizing. */ + value = areadlink_with_size (fname, 63); + if (value && can_mode != -1) + value = canonicalize_filename_mode (value, can_mode); + } + if (value) { fputs (value, stdout); diff --git a/tests/local.mk b/tests/local.mk index 6b527f108..7364ec89f 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -365,6 +365,7 @@ all_tests = \ tests/printf/printf-quote.sh \ tests/pwd/pwd-long.sh \ tests/readlink/readlink-fp-loop.sh \ + tests/readlink/readlink-posix.sh \ tests/readlink/readlink-root.sh \ tests/misc/realpath.sh \ tests/runcon/runcon-compute.sh \ diff --git a/tests/readlink/readlink-posix.sh b/tests/readlink/readlink-posix.sh new file mode 100755 index 000000000..a301545cf --- /dev/null +++ b/tests/readlink/readlink-posix.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# Test readlink with POSIXLY_CORRECT defined. + +# Copyright (C) 2025 Free Software Foundation, Inc. + +# This program 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. + +# This program 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 <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ readlink + +touch file || framework_failure_ +ln -s file link1 || framework_failure_ + +# POSIX requires a diagnostic error and non-zero exit status if the file is not +# a symbolic link. +cat <<\EOF > exp || framework_failure_ +readlink: file: Invalid argument +EOF +returns_ 1 env POSIXLY_CORRECT=1 readlink file 2>err || fail=1 +compare exp err || fail=1 +returns_ 1 env POSIXLY_CORRECT=1 readlink -f file 2>err || fail=1 +compare exp err || fail=1 +returns_ 1 env POSIXLY_CORRECT=1 readlink -e file 2>err || fail=1 +compare exp err || fail=1 +returns_ 1 env POSIXLY_CORRECT=1 readlink -m file 2>err || fail=1 + +# Check on a symbolic link. +cat <<\EOF > exp || framework_failure_ +file +EOF +POSIXLY_CORRECT=1 readlink link1 >out || fail=1 +compare exp out || fail=1 +POSIXLY_CORRECT=1 readlink -f link1 || fail=1 +POSIXLY_CORRECT=1 readlink -e link1 || fail=1 +POSIXLY_CORRECT=1 readlink -m link1 || fail=1 + +Exit $fail -- 2.50.1