#include "cache.h"
#include "exec_cmd.h"
+#include "quote.h"
#define MAX_ARGS 32
extern char **environ;
static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path = NULL;
+static const char *argv_exec_path;
-void git_set_exec_path(const char *exec_path)
+void git_set_argv_exec_path(const char *exec_path)
{
- current_exec_path = exec_path;
+ argv_exec_path = exec_path;
}
{
const char *env;
- if (current_exec_path)
- return current_exec_path;
+ if (argv_exec_path)
+ return argv_exec_path;
- env = getenv("GIT_EXEC_PATH");
- if (env) {
+ env = getenv(EXEC_PATH_ENVIRONMENT);
+ if (env && *env) {
return env;
}
return builtin_exec_path;
}
+static void add_path(struct strbuf *out, const char *path)
+{
+ if (path && *path) {
+ if (is_absolute_path(path))
+ strbuf_addstr(out, path);
+ else
+ strbuf_addstr(out, make_absolute_path(path));
-int execv_git_cmd(char **argv)
+ strbuf_addch(out, ':');
+ }
+}
+
+void setup_path(const char *cmd_path)
{
- char git_command[PATH_MAX + 1];
- char *tmp;
- int len, err, i;
- const char *paths[] = { current_exec_path,
- getenv("GIT_EXEC_PATH"),
- builtin_exec_path };
-
- for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
- const char *exec_dir = paths[i];
- if (!exec_dir) continue;
-
- if (*exec_dir != '/') {
- if (!getcwd(git_command, sizeof(git_command))) {
- fprintf(stderr, "git: cannot determine "
- "current directory\n");
- exit(1);
- }
- len = strlen(git_command);
-
- /* Trivial cleanup */
- while (!strncmp(exec_dir, "./", 2)) {
- exec_dir += 2;
- while (*exec_dir == '/')
- exec_dir++;
- }
- snprintf(git_command + len, sizeof(git_command) - len,
- "/%s", exec_dir);
- } else {
- strcpy(git_command, exec_dir);
- }
-
- len = strlen(git_command);
- len += snprintf(git_command + len, sizeof(git_command) - len,
- "/git-%s", argv[0]);
-
- if (sizeof(git_command) <= len) {
- fprintf(stderr,
- "git: command name given is too long.\n");
- break;
- }
+ const char *old_path = getenv("PATH");
+ struct strbuf new_path;
- /* argv[0] must be the git command, but the argv array
- * belongs to the caller, and my be reused in
- * subsequent loop iterations. Save argv[0] and
- * restore it on error.
- */
+ strbuf_init(&new_path, 0);
- tmp = argv[0];
- argv[0] = git_command;
+ add_path(&new_path, argv_exec_path);
+ add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
+ add_path(&new_path, builtin_exec_path);
+ add_path(&new_path, cmd_path);
- /* execve() can only ever return if it fails */
- execve(git_command, argv, environ);
+ if (old_path)
+ strbuf_addstr(&new_path, old_path);
+ else
+ strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
- err = errno;
+ setenv("PATH", new_path.buf, 1);
- argv[0] = tmp;
- }
- return -1;
+ strbuf_release(&new_path);
+}
+
+int execv_git_cmd(const char **argv)
+{
+ struct strbuf cmd;
+ const char *tmp;
+
+ strbuf_init(&cmd, 0);
+ strbuf_addf(&cmd, "git-%s", argv[0]);
+
+ /*
+ * argv[0] must be the git command, but the argv array
+ * belongs to the caller, and may be reused in
+ * subsequent loop iterations. Save argv[0] and
+ * restore it on error.
+ */
+ tmp = argv[0];
+ argv[0] = cmd.buf;
+
+ trace_argv_printf(argv, "trace: exec:");
+
+ /* execvp() can only ever return if it fails */
+ execvp(cmd.buf, (char **)argv);
+ trace_printf("trace: exec failed: %s\n", strerror(errno));
+
+ argv[0] = tmp;
+
+ strbuf_release(&cmd);
+
+ return -1;
}
-int execl_git_cmd(char *cmd,...)
+int execl_git_cmd(const char *cmd,...)
{
int argc;
- char *argv[MAX_ARGS + 1];
- char *arg;
+ const char *argv[MAX_ARGS + 1];
+ const char *arg;
va_list param;
va_start(param, cmd);