Subject: Re: bin/25395: sh(1) closes FD 0 for some pipe members
To: None <netbsd-bugs@netbsd.org>
From: David Laight <david@l8s.co.uk>
List: netbsd-bugs
Date: 04/29/2004 21:49:25
> >Number: 25395
> >Category: bin
> >Synopsis: sh(1) closes FD 0 for some pipe members
> I do not know if this bug is still present in newer releases
Still fails in current.
> >How-To-Repeat:
> $ sh -c 'cat /etc/motd | tr a-z A-Z | grep foo | sed s/zip/zap/g' <&-
> grep: fstat: Bad file descriptor
The problem arises because the shell isn't careful enough to use fd numbers
above 2 for the ends of pipes it is keeping internally as it builds the
command pipeline.
This diff fixes it, but is (maybe) a bit OTT since at least one end of
every pipe is closed very shortly after.
David
Index: eval.c
===================================================================
RCS file: /cvsroot/src/bin/sh/eval.c,v
retrieving revision 1.75
diff -u -p -r1.75 eval.c
--- eval.c 14 Nov 2003 10:27:10 -0000 1.75
+++ eval.c 29 Apr 2004 20:36:57 -0000
@@ -45,6 +45,7 @@ __RCSID("$NetBSD: eval.c,v 1.75 2003/11/
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
+#include <sys/fcntl.h>
#include <sys/times.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -125,6 +126,31 @@ SHELLPROC {
}
#endif
+static int
+sh_pipe(int fds[2])
+{
+ int nfd;
+
+ if (pipe(fds))
+ return -1;
+
+ if (fds[0] < 10) {
+ nfd = fcntl(fds[0], F_DUPFD, 10);
+ if (nfd != -1) {
+ close(fds[0]);
+ fds[0] = nfd;
+ }
+ }
+
+ if (fds[1] < 10) {
+ nfd = fcntl(fds[1], F_DUPFD, 10);
+ if (nfd != -1) {
+ close(fds[1]);
+ fds[1] = nfd;
+ }
+ }
+ return 0;
+}
/*
@@ -476,7 +502,7 @@ evalpipe(union node *n)
prehash(lp->n);
pip[1] = -1;
if (lp->next) {
- if (pipe(pip) < 0) {
+ if (sh_pipe(pip) < 0) {
close(prevfd);
error("Pipe call failed");
}
@@ -548,7 +574,7 @@ evalbackcmd(union node *n, struct backcm
#endif
{
INTOFF;
- if (pipe(pip) < 0)
+ if (sh_pipe(pip) < 0)
error("Pipe call failed");
jp = makejob(n, 1);
if (forkshell(jp, n, FORK_NOJOB) == 0) {
@@ -800,7 +826,7 @@ evalcommand(union node *cmd, int flags,
mode = cmd->ncmd.backgnd;
if (flags & EV_BACKCMD) {
mode = FORK_NOJOB;
- if (pipe(pip) < 0)
+ if (sh_pipe(pip) < 0)
error("Pipe call failed");
}
#ifdef DO_SHAREDVFORK
--
David Laight: david@l8s.co.uk