Use start_command() in git_connect() instead of explicit fork/exec.

The child process handling is delegated to start_command() and
finish_command().

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
maint
Johannes Sixt 2007-10-19 21:47:54 +02:00 committed by Shawn O. Pearce
parent 98158e9cfd
commit f364cb8823
1 changed files with 46 additions and 53 deletions

View File

@ -482,11 +482,12 @@ struct child_process *git_connect(int fd[2], char *url,
char *host, *path = url; char *host, *path = url;
char *end; char *end;
int c; int c;
int pipefd[2][2];
struct child_process *conn; struct child_process *conn;
enum protocol protocol = PROTO_LOCAL; enum protocol protocol = PROTO_LOCAL;
int free_path = 0; int free_path = 0;
char *port = NULL; char *port = NULL;
const char **arg;
struct strbuf cmd;


/* Without this we cannot rely on waitpid() to tell /* Without this we cannot rely on waitpid() to tell
* what happened to our children. * what happened to our children.
@ -572,59 +573,52 @@ struct child_process *git_connect(int fd[2], char *url,
return NULL; 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 = xcalloc(1, sizeof(*conn));
conn->pid = fork();
if (conn->pid < 0)
die("unable to fork");
if (!conn->pid) {
struct strbuf cmd;


strbuf_init(&cmd, MAX_CMD_LEN); strbuf_init(&cmd, MAX_CMD_LEN);
strbuf_addstr(&cmd, prog); strbuf_addstr(&cmd, prog);
strbuf_addch(&cmd, ' '); strbuf_addch(&cmd, ' ');
sq_quote_buf(&cmd, path); sq_quote_buf(&cmd, path);
if (cmd.len >= MAX_CMD_LEN) if (cmd.len >= MAX_CMD_LEN)
die("command line too long"); die("command line too long");


dup2(pipefd[1][0], 0); conn->in = conn->out = -1;
dup2(pipefd[0][1], 1); conn->argv = arg = xcalloc(6, sizeof(*arg));
close(pipefd[0][0]); if (protocol == PROTO_SSH) {
close(pipefd[0][1]); const char *ssh = getenv("GIT_SSH");
close(pipefd[1][0]); if (!ssh) ssh = "ssh";
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) *arg++ = ssh;
execlp(ssh, ssh_basename, host, cmd.buf, NULL); if (port) {
else *arg++ = "-p";
execlp(ssh, ssh_basename, "-p", port, host, *arg++ = port;
cmd.buf, NULL);
} }
else { *arg++ = host;
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", cmd.buf, NULL);
}
die("exec failed");
} }
fd[0] = pipefd[0][0]; else {
fd[1] = pipefd[1][1]; /* remove these from the environment */
close(pipefd[0][1]); const char *env[] = {
close(pipefd[1][0]); ALTERNATE_DB_ENVIRONMENT,
DB_ENVIRONMENT,
GIT_DIR_ENVIRONMENT,
GIT_WORK_TREE_ENVIRONMENT,
GRAFT_ENVIRONMENT,
INDEX_ENVIRONMENT,
NULL
};
conn->env = env;
*arg++ = "sh";
*arg++ = "-c";
}
*arg++ = cmd.buf;
*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 */
strbuf_release(&cmd);
if (free_path) if (free_path)
free(path); free(path);
return conn; return conn;
@ -632,13 +626,12 @@ struct child_process *git_connect(int fd[2], char *url,


int finish_connect(struct child_process *conn) int finish_connect(struct child_process *conn)
{ {
int code;
if (!conn) if (!conn)
return 0; return 0;


while (waitpid(conn->pid, NULL, 0) < 0) { code = finish_command(conn);
if (errno != EINTR) free(conn->argv);
return -1;
}
free(conn); free(conn);
return 0; return code;
} }