diff options
| author | Junio C Hamano <gitster@pobox.com> | 2011-11-10 09:05:31 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2011-11-10 09:05:31 -0800 |
| commit | 77f143bf3e218857ec8e5244d7e862e8e0c1a041 (patch) | |
| tree | 9f720e61941241b53a4f258d0dc62e5a9a360aa8 /exec_cmd.c | |
| parent | cd9519bd2c5c666cfb3ec219ee0b47c83f26f3fe (diff) | |
| parent | 633e3556ccbcc7e443f5e9194c4a830181696ef0 (diff) | |
| download | git-77f143bf3e218857ec8e5244d7e862e8e0c1a041.tar.xz | |
Merge 'build-in git-mktree'
* commit '633e3556ccbc': (5835 commits)
build-in git-mktree
allow -t abbreviation for --track in git branch
gitweb: Remove function prototypes (cleanup)
Documentation: cloning to empty directory is allowed
Clarify kind of conflict in merge-one-file helper
git config: clarify --add and --get-color
archive-tar.c: squelch a type mismatch warning
Start 1.6.4 development
Start 1.6.3.1 maintenance series.
GIT 1.6.3
t4029: use sh instead of bash
t4200: convert sed expression which operates on non-text file to perl
t4200: remove two unnecessary lines
t/annotate-tests.sh: avoid passing a non-newline terminated file to sed
t4118: avoid sed invocation on file without terminating newline
t4118: add missing '&&'
t8005: use egrep when extended regular expressions are required
git-clean doc: the command only affects paths under $(cwd)
improve error message in config.c
t4018-diff-funcname: add cpp xfuncname pattern to syntax test
...
Diffstat (limited to 'exec_cmd.c')
| -rw-r--r-- | exec_cmd.c | 177 |
1 files changed, 105 insertions, 72 deletions
diff --git a/exec_cmd.c b/exec_cmd.c index 9b74ed2f42..408e4e55e1 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -4,12 +4,67 @@ #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; +static const char *argv0_path; -void git_set_exec_path(const char *exec_path) +const char *system_path(const char *path) { - current_exec_path = exec_path; +#ifdef RUNTIME_PREFIX + static const char *prefix; +#else + static const char *prefix = PREFIX; +#endif + struct strbuf d = STRBUF_INIT; + + if (is_absolute_path(path)) + return path; + +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix && + !(prefix = strip_path_suffix(argv0_path, GIT_EXEC_PATH)) && + !(prefix = strip_path_suffix(argv0_path, BINDIR)) && + !(prefix = strip_path_suffix(argv0_path, "git"))) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#endif + + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); + return path; +} + +const char *git_extract_argv0_path(const char *argv0) +{ + const char *slash; + + if (!argv0 || !*argv0) + return NULL; + slash = argv0 + strlen(argv0); + + while (argv0 <= slash && !is_dir_sep(*slash)) + slash--; + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; +} + +void git_set_argv_exec_path(const char *exec_path) +{ + argv_exec_path = exec_path; + /* + * Propagate this setting to external programs. + */ + setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); } @@ -18,96 +73,74 @@ const char *git_exec_path(void) { 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 system_path(GIT_EXEC_PATH); } - -int execv_git_cmd(const char **argv) +static void add_path(struct strbuf *out, const char *path) { - char git_command[PATH_MAX + 1]; - int i; - const char *paths[] = { current_exec_path, - getenv(EXEC_PATH_ENVIRONMENT), - builtin_exec_path }; + if (path && *path) { + if (is_absolute_path(path)) + strbuf_addstr(out, path); + else + strbuf_addstr(out, make_nonrelative_path(path)); - for (i = 0; i < ARRAY_SIZE(paths); ++i) { - size_t len; - int rc; - const char *exec_dir = paths[i]; - const char *tmp; + strbuf_addch(out, PATH_SEP); + } +} - if (!exec_dir || !*exec_dir) continue; +void setup_path(void) +{ + const char *old_path = getenv("PATH"); + struct strbuf new_path = STRBUF_INIT; - 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); + add_path(&new_path, git_exec_path()); + add_path(&new_path, argv0_path); - /* Trivial cleanup */ - while (!prefixcmp(exec_dir, "./")) { - exec_dir += 2; - while (*exec_dir == '/') - exec_dir++; - } + if (old_path) + strbuf_addstr(&new_path, old_path); + else + strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin"); - 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); - } + setenv("PATH", new_path.buf, 1); - 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_release(&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. - */ +const char **prepare_git_cmd(const char **argv) +{ + int argc; + const char **nargv; - tmp = argv[0]; - argv[0] = git_command; + for (argc = 0; argv[argc]; argc++) + ; /* just counting */ + nargv = xmalloc(sizeof(*nargv) * (argc + 2)); - trace_argv_printf(argv, -1, "trace: exec:"); + nargv[0] = "git"; + for (argc = 0; argv[argc]; argc++) + nargv[argc + 1] = argv[argc]; + nargv[argc + 1] = NULL; + return nargv; +} - /* execve() can only ever return if it fails */ - execve(git_command, (char **)argv, environ); +int execv_git_cmd(const char **argv) { + const char **nargv = prepare_git_cmd(argv); + trace_argv_printf(nargv, "trace: exec:"); - trace_printf("trace: exec failed: %s\n", strerror(errno)); + /* execvp() can only ever return if it fails */ + execvp("git", (char **)nargv); - argv[0] = tmp; - } - return -1; + trace_printf("trace: exec failed: %s\n", strerror(errno)); + free(nargv); + return -1; } |
