From c84f02153b70b80a7463c3bea255e773d8f5cb8f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 18 Jan 2007 18:07:44 +0100 Subject: [PATCH] Add a spawnv_git_cmd() function and use it in fetch-pack.c. This function is intended to be used in place of exec[vl]_git_cmd() that follows a fork. It constructs the (at most) 3 paths that execv_git_cmd() searches manually for the git command and hands them over to spawnvppe_pipe(). The use case in get_pack() is one of the simplest possible. --- exec_cmd.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ exec_cmd.h | 1 + fetch-pack.c | 10 +------- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 68c39e348c..9f31b040de 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,6 +1,7 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" +#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -137,3 +138,86 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } + +int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) +{ + char cmd[100]; + int i, rc; + pid_t pid; + const char *paths[] = { current_exec_path, + getenv(EXEC_PATH_ENVIRONMENT), + builtin_exec_path }; + char p[3][PATH_MAX + 1]; + char *usedpaths[4], **up = usedpaths; + const char *tmp; + + for (i = 0; i < ARRAY_SIZE(paths); ++i) { + size_t len; + const char *exec_dir = paths[i]; + + if (!exec_dir || !*exec_dir) continue; + +#ifdef __MINGW32__ + if (*exec_dir != '/' && exec_dir[1] != ':') { +#else + if (*exec_dir != '/') { +#endif + if (!getcwd(p[i], sizeof(p[i]))) { + fprintf(stderr, "git: cannot determine " + "current directory: %s\n", + strerror(errno)); + return -1; + } + len = strlen(p[i]); + + /* Trivial cleanup */ + while (!strncmp(exec_dir, "./", 2)) { + exec_dir += 2; + while (*exec_dir == '/') + exec_dir++; + } + + rc = snprintf(p[i] + len, + sizeof(p[i]) - len, "/%s", + exec_dir); + if (rc < 0 || rc >= sizeof(p[i]) - len) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + } else { + if (strlen(exec_dir) + 1 > sizeof(p[i])) { + fprintf(stderr, "git: command name given " + "is too long.\n"); + return -1; + } + strcpy(p[i], exec_dir); + } + *up++ = p[i]; + } + *up = NULL; + + rc = snprintf(cmd, sizeof(cmd), "git-%s", argv[0]); + if (rc < 0 || rc >= sizeof(cmd)) { + fprintf(stderr, + "git: command name given is too long.\n"); + return -1; + } + + /* argv[0] must be the git command, but the argv array + * belongs to the caller. Save argv[0] and + * restore it later. + */ + + tmp = argv[0]; + argv[0] = cmd; + + trace_argv_printf(argv, -1, "trace: exec:"); + + pid = spawnvppe_pipe(cmd, argv, environ, usedpaths, + pin, pout); + + argv[0] = tmp; + return pid; + +} diff --git a/exec_cmd.h b/exec_cmd.h index 989621ff4e..eefb4afe40 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -5,6 +5,7 @@ extern void git_set_exec_path(const char *exec_path); extern const char* git_exec_path(void); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); +extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* __GIT_EXEC_CMD_H_ */ diff --git a/fetch-pack.c b/fetch-pack.c index 48670f9c62..10683bee9a 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -493,17 +493,9 @@ static int get_pack(int xd[2], const char **argv) int fd[2]; side_pid = setup_sideband(fd, xd); - pid = fork(); + pid = spawnv_git_cmd(argv, fd, NULL); if (pid < 0) die("fetch-pack: unable to fork off %s", argv[0]); - if (!pid) { - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - execv_git_cmd(argv); - die("%s exec failed", argv[0]); - } - close(fd[0]); close(fd[1]); while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) -- 2.11.4.GIT