#define MAX_ARGS 32
extern char **environ;
-static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path;
+static const char *argv_exec_path;
-void git_set_exec_path(const char *exec_path)
+static const char *builtin_exec_path(void)
{
- current_exec_path = exec_path;
+#ifndef __MINGW32__
+ return GIT_EXEC_PATH;
+#else
+ int len;
+ char *p, *q, *sl;
+ static char *ep;
+ if (ep)
+ return ep;
+
+ len = strlen(_pgmptr);
+ if (len < 2)
+ return ep = ".";
+
+ p = ep = xmalloc(len+1);
+ q = _pgmptr;
+ sl = NULL;
+ /* copy program name, turn '\\' into '/', skip last part */
+ while ((*p = *q)) {
+ if (*q == '\\' || *q == '/') {
+ *p = '/';
+ sl = p;
+ }
+ p++, q++;
+ }
+ if (sl)
+ *sl = '\0';
+ else
+ ep[0] = '.', ep[1] = '\0';
+ return ep;
+#endif
+}
+
+void git_set_argv_exec_path(const char *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(EXEC_PATH_ENVIRONMENT);
if (env && *env) {
return env;
}
- return builtin_exec_path;
+ 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));
+
+ strbuf_addch(out, PATH_SEP);
+ }
+}
-int execv_git_cmd(const char **argv)
+void setup_path(const char *cmd_path)
{
- char git_command[PATH_MAX + 1];
- int i;
- const char *paths[] = { current_exec_path,
- getenv(EXEC_PATH_ENVIRONMENT),
- builtin_exec_path };
-
- for (i = 0; i < ARRAY_SIZE(paths); ++i) {
- size_t len;
- int rc;
- const char *exec_dir = paths[i];
- const char *tmp;
-
- if (!exec_dir || !*exec_dir) continue;
-
- if (*exec_dir != '/') {
- if (!getcwd(git_command, sizeof(git_command))) {
- fprintf(stderr, "git: cannot determine "
- "current directory: %s\n",
- strerror(errno));
- break;
- }
- len = strlen(git_command);
-
- /* Trivial cleanup */
- while (!prefixcmp(exec_dir, "./")) {
- exec_dir += 2;
- while (*exec_dir == '/')
- exec_dir++;
- }
-
- rc = snprintf(git_command + len,
- sizeof(git_command) - len, "/%s",
- exec_dir);
- if (rc < 0 || rc >= sizeof(git_command) - len) {
- fprintf(stderr, "git: command name given "
- "is too long.\n");
- break;
- }
- } else {
- if (strlen(exec_dir) + 1 > sizeof(git_command)) {
- fprintf(stderr, "git: command name given "
- "is too long.\n");
- break;
- }
- strcpy(git_command, exec_dir);
- }
+ const char *old_path = getenv("PATH");
+ struct strbuf new_path;
- len = strlen(git_command);
- rc = snprintf(git_command + len, sizeof(git_command) - len,
- "/git-%s", argv[0]);
- if (rc < 0 || rc >= sizeof(git_command) - len) {
- fprintf(stderr,
- "git: command name given is too long.\n");
- break;
- }
+ strbuf_init(&new_path, 0);
- /* 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.
- */
+ 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);
- tmp = argv[0];
- argv[0] = git_command;
+ if (old_path)
+ strbuf_addstr(&new_path, old_path);
+ else
+ strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
- trace_argv_printf(argv, -1, "trace: exec:");
+ setenv("PATH", new_path.buf, 1);
- /* execve() can only ever return if it fails */
- execve(git_command, (char **)argv, environ);
+ strbuf_release(&new_path);
+}
- trace_printf("trace: exec failed: %s\n", strerror(errno));
+int execv_git_cmd(const char **argv)
+{
+ int argc;
+ const char **nargv;
- argv[0] = tmp;
- }
- return -1;
+ for (argc = 0; argv[argc]; argc++)
+ ; /* just counting */
+ nargv = xmalloc(sizeof(*nargv) * (argc + 2));
+
+ nargv[0] = "git";
+ for (argc = 0; argv[argc]; argc++)
+ nargv[argc + 1] = argv[argc];
+ nargv[argc + 1] = NULL;
+ trace_argv_printf(nargv, "trace: exec:");
+
+ /* execvp() can only ever return if it fails */
+ execvp("git", (char **)nargv);
+ trace_printf("trace: exec failed: %s\n", strerror(errno));
+
+ free(nargv);
+ return -1;
}