X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=exec_cmd.c;h=38d52d90a232471e65c433fe7d6fb6a3abadf511;hb=226c0ddd0d63dd6c8dde497c755af2ad1f02e0c1;hp=ce192a2d64c846e9d7ccffe10c9476f9c5abb8b8;hpb=07d90eadb50ee687a7313186b654975b0944a74e;p=thirdparty%2Fgit.git diff --git a/exec_cmd.c b/exec_cmd.c index ce192a2d64..38d52d90a2 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -2,24 +2,52 @@ #include "exec_cmd.h" #include "quote.h" #include "argv-array.h" -#define MAX_ARGS 32 -static const char *argv_exec_path; +#if defined(RUNTIME_PREFIX) + +#if defined(HAVE_NS_GET_EXECUTABLE_PATH) +#include +#endif + +#if defined(HAVE_BSD_KERN_PROC_SYSCTL) +#include +#include +#include +#endif + +#endif /* RUNTIME_PREFIX */ + +#define MAX_ARGS 32 + +static const char *system_prefix(void); #ifdef RUNTIME_PREFIX -static const char *argv0_path; + +/** + * When using a runtime prefix, Git dynamically resolves paths relative to its + * executable. + * + * The method for determining the path of the executable is highly + * platform-specific. + */ + +/** + * Path to the current Git executable. Resolved on startup by + * 'git_resolve_executable_dir'. + */ +static const char *executable_dirname; static const char *system_prefix(void) { static const char *prefix; - assert(argv0_path); - assert(is_absolute_path(argv0_path)); + assert(executable_dirname); + assert(is_absolute_path(executable_dirname)); 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 = strip_path_suffix(executable_dirname, GIT_EXEC_PATH)) && + !(prefix = strip_path_suffix(executable_dirname, BINDIR)) && + !(prefix = strip_path_suffix(executable_dirname, "git"))) { prefix = PREFIX; trace_printf("RUNTIME_PREFIX requested, " "but prefix computation failed. " @@ -28,27 +56,179 @@ static const char *system_prefix(void) return prefix; } -void git_extract_argv0_path(const char *argv0) +/* + * Resolves the executable path from argv[0], only if it is absolute. + * + * Returns 0 on success, -1 on failure. + */ +static int git_get_exec_path_from_argv0(struct strbuf *buf, const char *argv0) { const char *slash; if (!argv0 || !*argv0) - return; + return -1; slash = find_last_dir_sep(argv0); + if (slash) { + trace_printf("trace: resolved executable path from argv0: %s\n", + argv0); + strbuf_add_absolute_path(buf, argv0); + return 0; + } + return -1; +} +#ifdef PROCFS_EXECUTABLE_PATH +/* + * Resolves the executable path by examining a procfs symlink. + * + * Returns 0 on success, -1 on failure. + */ +static int git_get_exec_path_procfs(struct strbuf *buf) +{ + if (strbuf_realpath(buf, PROCFS_EXECUTABLE_PATH, 0)) { + trace_printf( + "trace: resolved executable path from procfs: %s\n", + buf->buf); + return 0; + } + return -1; +} +#endif /* PROCFS_EXECUTABLE_PATH */ + +#ifdef HAVE_BSD_KERN_PROC_SYSCTL +/* + * Resolves the executable path using KERN_PROC_PATHNAME BSD sysctl. + * + * Returns 0 on success, -1 on failure. + */ +static int git_get_exec_path_bsd_sysctl(struct strbuf *buf) +{ + int mib[4]; + char path[MAXPATHLEN]; + size_t cb = sizeof(path); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + if (!sysctl(mib, 4, path, &cb, NULL, 0)) { + trace_printf( + "trace: resolved executable path from sysctl: %s\n", + path); + strbuf_addstr(buf, path); + return 0; + } + return -1; +} +#endif /* HAVE_BSD_KERN_PROC_SYSCTL */ + +#ifdef HAVE_NS_GET_EXECUTABLE_PATH +/* + * Resolves the executable path by querying Darwin application stack. + * + * Returns 0 on success, -1 on failure. + */ +static int git_get_exec_path_darwin(struct strbuf *buf) +{ + char path[PATH_MAX]; + uint32_t size = sizeof(path); + if (!_NSGetExecutablePath(path, &size)) { + trace_printf( + "trace: resolved executable path from Darwin stack: %s\n", + path); + strbuf_addstr(buf, path); + return 0; + } + return -1; +} +#endif /* HAVE_NS_GET_EXECUTABLE_PATH */ + +/* + * Resolves the absolute path of the current executable. + * + * Returns 0 on success, -1 on failure. + */ +static int git_get_exec_path(struct strbuf *buf, const char *argv0) +{ + /* + * Identifying the executable path is operating system specific. + * Selectively employ all available methods in order of preference, + * preferring highly-available authoritative methods over + * selectively-available or non-authoritative methods. + * + * All cases fall back on resolving against argv[0] if there isn't a + * better functional method. However, note that argv[0] can be + * used-supplied on many operating systems, and is not authoritative + * in those cases. + * + * Each of these functions returns 0 on success, so evaluation will stop + * after the first successful method. + */ + if ( +#ifdef HAVE_BSD_KERN_PROC_SYSCTL + git_get_exec_path_bsd_sysctl(buf) && +#endif /* HAVE_BSD_KERN_PROC_SYSCTL */ + +#ifdef HAVE_NS_GET_EXECUTABLE_PATH + git_get_exec_path_darwin(buf) && +#endif /* HAVE_NS_GET_EXECUTABLE_PATH */ + +#ifdef PROCFS_EXECUTABLE_PATH + git_get_exec_path_procfs(buf) && +#endif /* PROCFS_EXECUTABLE_PATH */ + + git_get_exec_path_from_argv0(buf, argv0)) { + return -1; + } + + if (strbuf_normalize_path(buf)) { + trace_printf("trace: could not normalize path: %s\n", buf->buf); + return -1; + } + + return 0; +} + +void git_resolve_executable_dir(const char *argv0) +{ + struct strbuf buf = STRBUF_INIT; + char *resolved; + const char *slash; + + if (git_get_exec_path(&buf, argv0)) { + trace_printf( + "trace: could not determine executable path from: %s\n", + argv0); + strbuf_release(&buf); + return; + } + + resolved = strbuf_detach(&buf, NULL); + slash = find_last_dir_sep(resolved); if (slash) - argv0_path = xstrndup(argv0, slash - argv0); + resolved[slash - resolved] = '\0'; + + executable_dirname = resolved; + trace_printf("trace: resolved executable dir: %s\n", + executable_dirname); } #else +/* + * When not using a runtime prefix, Git uses a hard-coded path. + */ static const char *system_prefix(void) { return PREFIX; } -void git_extract_argv0_path(const char *argv0) +/* + * This is called during initialization, but No work needs to be done here when + * runtime prefix is not being used. + */ +void git_resolve_executable_dir(const char *argv0) { } @@ -65,32 +245,28 @@ char *system_path(const char *path) return strbuf_detach(&d, NULL); } -void git_set_argv_exec_path(const char *exec_path) +static const char *exec_path_value; + +void git_set_exec_path(const char *exec_path) { - argv_exec_path = exec_path; + exec_path_value = exec_path; /* * Propagate this setting to external programs. */ setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); } - -/* Returns the highest-priority, location to look for git programs. */ +/* Returns the highest-priority location to look for git programs. */ const char *git_exec_path(void) { - static char *cached_exec_path; - - if (argv_exec_path) - return argv_exec_path; - - if (!cached_exec_path) { + if (!exec_path_value) { const char *env = getenv(EXEC_PATH_ENVIRONMENT); if (env && *env) - cached_exec_path = xstrdup(env); + exec_path_value = xstrdup(env); else - cached_exec_path = system_path(GIT_EXEC_PATH); + exec_path_value = system_path(GIT_EXEC_PATH); } - return cached_exec_path; + return exec_path_value; } static void add_path(struct strbuf *out, const char *path) @@ -103,10 +279,12 @@ static void add_path(struct strbuf *out, const char *path) void setup_path(void) { + const char *exec_path = git_exec_path(); const char *old_path = getenv("PATH"); struct strbuf new_path = STRBUF_INIT; - add_path(&new_path, git_exec_path()); + git_set_exec_path(exec_path); + add_path(&new_path, exec_path); if (old_path) strbuf_addstr(&new_path, old_path); @@ -125,7 +303,8 @@ const char **prepare_git_cmd(struct argv_array *out, const char **argv) return out->argv; } -int execv_git_cmd(const char **argv) { +int execv_git_cmd(const char **argv) +{ struct argv_array nargv = ARGV_ARRAY_INIT; prepare_git_cmd(&nargv, argv); @@ -140,8 +319,7 @@ int execv_git_cmd(const char **argv) { return -1; } - -int execl_git_cmd(const char *cmd,...) +int execl_git_cmd(const char *cmd, ...) { int argc; const char *argv[MAX_ARGS + 1];