The child process handling is delegated to start_command() and finish_command(). Signed-off-by: Johannes Sixt <johannes.sixt@xxxxxxxxxx> --- connect.c | 108 ++++++++++++++++++++++++++++-------------------------------- 1 files changed, 50 insertions(+), 58 deletions(-) diff --git a/connect.c b/connect.c index b156f92..21597bf 100644 --- a/connect.c +++ b/connect.c @@ -484,11 +484,15 @@ struct child_process *git_connect(int fd[2], char *url, char *host, *path = url; char *end; int c; - int pipefd[2][2]; struct child_process *conn; enum protocol protocol = PROTO_LOCAL; int free_path = 0; char *port = NULL; + const char **arg; + char command[MAX_CMD_LEN]; + char *posn = command; + int size = MAX_CMD_LEN; + int of = 0; /* Without this we cannot rely on waitpid() to tell * what happened to our children. @@ -574,62 +578,51 @@ struct child_process *git_connect(int fd[2], char *url, return NULL; } - if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) - die("unable to create pipe pair for communication"); conn = xcalloc(1, sizeof(*conn)); - conn->pid = fork(); - if (conn->pid < 0) - die("unable to fork"); - if (!conn->pid) { - char command[MAX_CMD_LEN]; - char *posn = command; - int size = MAX_CMD_LEN; - int of = 0; - - of |= add_to_string(&posn, &size, prog, 0); - of |= add_to_string(&posn, &size, " ", 0); - of |= add_to_string(&posn, &size, path, 1); - - if (of) - die("command line too long"); - - dup2(pipefd[1][0], 0); - dup2(pipefd[0][1], 1); - close(pipefd[0][0]); - close(pipefd[0][1]); - close(pipefd[1][0]); - close(pipefd[1][1]); - if (protocol == PROTO_SSH) { - const char *ssh, *ssh_basename; - ssh = getenv("GIT_SSH"); - if (!ssh) ssh = "ssh"; - ssh_basename = strrchr(ssh, '/'); - if (!ssh_basename) - ssh_basename = ssh; - else - ssh_basename++; - if (!port) - execlp(ssh, ssh_basename, host, command, NULL); - else - execlp(ssh, ssh_basename, "-p", port, host, - command, NULL); - } - else { - unsetenv(ALTERNATE_DB_ENVIRONMENT); - unsetenv(DB_ENVIRONMENT); - unsetenv(GIT_DIR_ENVIRONMENT); - unsetenv(GIT_WORK_TREE_ENVIRONMENT); - unsetenv(GRAFT_ENVIRONMENT); - unsetenv(INDEX_ENVIRONMENT); - execlp("sh", "sh", "-c", command, NULL); + of |= add_to_string(&posn, &size, prog, 0); + of |= add_to_string(&posn, &size, " ", 0); + of |= add_to_string(&posn, &size, path, 1); + + if (of) + die("command line too long"); + + conn->in = conn->out = -1; + conn->argv = arg = xcalloc(6, sizeof(*arg)); + if (protocol == PROTO_SSH) { + const char *ssh = getenv("GIT_SSH"); + if (!ssh) ssh = "ssh"; + + *arg++ = ssh; + if (port) { + *arg++ = "-p"; + *arg++ = port; } - die("exec failed"); + *arg++ = host; + } + else { + /* remove these from the environment */ + const char *env[] = { + ALTERNATE_DB_ENVIRONMENT, + DB_ENVIRONMENT, + GIT_DIR_ENVIRONMENT, + GIT_WORK_TREE_ENVIRONMENT, + GRAFT_ENVIRONMENT, + INDEX_ENVIRONMENT, + NULL + }; + conn->env = env; + *arg++ = "sh"; + *arg++ = "-c"; } - fd[0] = pipefd[0][0]; - fd[1] = pipefd[1][1]; - close(pipefd[0][1]); - close(pipefd[1][0]); + *arg++ = command; + *arg = NULL; + + if (start_command(conn)) + die("unable to fork"); + + fd[0] = conn->out; /* read from child's stdout */ + fd[1] = conn->in; /* write to child's stdin */ if (free_path) free(path); return conn; @@ -637,13 +630,12 @@ struct child_process *git_connect(int fd[2], char *url, int finish_connect(struct child_process *conn) { + int code; if (conn == NULL) return 0; - while (waitpid(conn->pid, NULL, 0) < 0) { - if (errno != EINTR) - return -1; - } + code = finish_command(conn); + free(conn->argv); free(conn); - return 0; + return code; } -- 1.5.3.3.1134.gee562 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html