Subject: bug#20795: [PATCH][TRY2] Fix behavior of --follow-symlinks on stdin

From: Stanislav Brabec <[email-masked]>
Date: Mon, 13 Jul 2015 22:59:17 +0200

When reading from stdin, --follow-symlinks causes failure since
v4.2.1-13-g84066bf:
echo abc | sed --follow-symlinks s/a/d/
sed: cannot stat -: No such file or directory

Never call follow_symlink("-") to prevent this problem.
http://bugs.gnu.org/20795
---
 NEWS                               |  3 +++
 sed/execute.c                      | 24 +++++++++++++-----------
 testsuite/Makefile.am              |  1 +
 testsuite/follow-symlinks-stdin.sh | 29 +++++++++++++++++++++++++++++
 4 files changed, 46 insertions(+), 11 deletions(-)
 create mode 100644 testsuite/follow-symlinks-stdin.sh

diff --git a/NEWS b/NEWS
index 61b8aa2..6367dea 100644
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,9 @@ GNU sed NEWS                                    -*- outline -*-
   leaves behind a temporary file.  Before, that command would create a file
   alongside F with a name matching /^sed......$/ and fail to remove it.
 
+  sed --follow-symlinks now works again for stdin.
+  [bug introduced in sed-4.2.2]
+
 ** Feature removal
 
   The "L" command (format a paragraph like the fmt(1) command would)
diff --git a/sed/execute.c b/sed/execute.c
index 49cfb45..de2dc4e 100644
--- a/sed/execute.c
+++ b/sed/execute.c
@@ -549,6 +549,7 @@ open_next_file(const char *name, struct input *input)
 {
   buffer.length = 0;
 
+  input->in_file_name = name;
   if (name[0] == '-' && name[1] == '\0')
     {
       if (in_place_extension)
@@ -562,22 +563,23 @@ open_next_file(const char *name, struct input *input)
       input->fp = stdin;
 #endif
     }
-  else if ( ! (input->fp = ck_fopen(name, read_mode, false)) )
+  else
     {
-      const char *ptr = strerror(errno);
-      fprintf(stderr, _("%s: can't read %s: %s\n"), myname, name, ptr);
-      input->read_fn = read_always_fail; /* a redundancy */
-      ++input->bad_count;
-      return;
+      if (follow_symlinks)
+        input->in_file_name = follow_symlink (name);
+
+      if ( ! (input->fp = ck_fopen(name, read_mode, false)) )
+        {
+          const char *ptr = strerror(errno);
+          fprintf(stderr, _("%s: can't read %s: %s\n"), myname, name, ptr);
+          input->read_fn = read_always_fail; /* a redundancy */
+          ++input->bad_count;
+          return;
+        }
     }
 
   input->read_fn = read_file_line;
 
-  if (follow_symlinks)
-    input->in_file_name = follow_symlink (name);
-  else
-    input->in_file_name = name;
-
   if (in_place_extension)
     {
       int input_fd;
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index bfffda0..9bd7465 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -6,6 +6,7 @@ SH_LOG_COMPILER = $(SHELL)
 # Put new, init.sh-using tests here, so that each name
 # is listed in only one place.
 T =			\
+  follow-symlinks-stdin.sh \
   help-version.sh	\
   in-place-hyphen.sh	\
   invalid-mb-seq-UMR.sh	\
diff --git a/testsuite/follow-symlinks-stdin.sh b/testsuite/follow-symlinks-stdin.sh
new file mode 100644
index 0000000..e7cd3b2
--- /dev/null
+++ b/testsuite/follow-symlinks-stdin.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Verify that --follow-symlinks does not break reading from stdin.
+
+# Copyright (C) 2015 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 <http://www.gnu.org/licenses/>.
+. "${srcdir=.}/init.sh"; path_prepend_ ../sed
+print_ver_ sed
+
+echo "dbc" > exp-out || framework_failure_
+
+fail=0
+echo "abc" | sed --follow-symlinks 's/a/d/' > out 2> err || fail=1
+
+compare exp-out out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
-- 
2.4.5

-- 
Best Regards / S pozdravem,

Stanislav Brabec
software developer
---------------------------------------------------------------------
SUSE LINUX, s. r. o.                         e-mail: [email-masked]
Lihovarská 1060/12                            tel: +49 911 7405384547
190 00 Praha 9                                 fax:  +420 284 084 001
Czech Republic                                    http://www.suse.cz/
PGP: 830B 40D5 9E05 35D8 5E27 6FA3 717C 209F A04F CD76