I ran into what I think is a bug:
sh$ git fetch 0<&-(i.e. run git-fetch with stdin closed.)
It aborts with:
fatal: read error (Bad file descriptor)I think the problem arises from the use of dup2+close in
start_command(). It wants to rename a pipe file descriptor to 0,
so it does
dup2(from, to);
close(from);... but in this case from == to == 0, so
dup2(0, 0);
close(0);
just ends up closing the pipe.The patch below fixes the problem for me.
>From 78446c82131a5ca7f22f92bc32d7f3036bba9629 Mon Sep 17 00:00:00 2001
From: Karl Chen <quarl@quarl.org> Date: Mon, 25 Aug 2008 01:09:08 -0700 Subject: [PATCH] Fix start_command() pipe bug when stdin is closed.
When intending to rename a fd to 0, if the fd is already 0, then do nothing, instead of dup2(0,0); close(0);
The problematic behavior could be seen thus: git-fetch 0<&-
Signed-off-by: Karl Chen <quarl@quarl.org>
--- run-command.c | 29 +++++++++++++++++------------ 1 files changed, 17 insertions(+), 12 deletions(-)
Show changes to run-command.c +17 −12
diff --git a/run-command.c b/run-command.c index caab374..b4bd80f 100644 --- a/run-command.c +++ b/run-command.c @@ -8,11 +8,18 @@ static inline void close_pair(int fd[2]) close(fd[1]); } +static inline void rename_fd(int from, int to) +{ + if (from != to) { + dup2(from, to); + close(from); + } +} + static inline void dup_devnull(int to) { int fd = open("/dev/null", O_RDWR); - dup2(fd, to); - close(fd); + rename_fd(fd, to); } int start_command(struct child_process *cmd) @@ -74,18 +81,17 @@ int start_command(struct child_process *cmd) if (cmd->no_stdin) dup_devnull(0); else if (need_in) { - dup2(fdin[0], 0); - close_pair(fdin); + rename_fd(fdin[0], 0); + close(fdin[1]); } else if (cmd->in) { - dup2(cmd->in, 0); - close(cmd->in); + rename_fd(cmd->in, 0); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { - dup2(fderr[1], 2); - close_pair(fderr); + rename_fd(fderr[1], 2); + close(fderr[0]); } if (cmd->no_stdout) @@ -93,11 +99,10 @@ int start_command(struct child_process *cmd) else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { - dup2(fdout[1], 1); - close_pair(fdout); + rename_fd(fdout[1], 1); + close(fdout[0]); } else if (cmd->out > 1) { - dup2(cmd->out, 1); - close(cmd->out); + rename_fd(cmd->out, 1); } if (cmd->dir && chdir(cmd->dir))
-- 1.5.6.2