|  | #include "cache.h" | 
|  | #include "exec-cmd.h" | 
|  | #include "quote.h" | 
|  | #include "strvec.h" | 
|  |  | 
|  | #if defined(RUNTIME_PREFIX) | 
|  |  | 
|  | #if defined(HAVE_NS_GET_EXECUTABLE_PATH) | 
|  | #include <mach-o/dyld.h> | 
|  | #endif | 
|  |  | 
|  | #if defined(HAVE_BSD_KERN_PROC_SYSCTL) | 
|  | #include <sys/param.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/sysctl.h> | 
|  | #endif | 
|  |  | 
|  | #endif /* RUNTIME_PREFIX */ | 
|  |  | 
|  | #define MAX_ARGS 32 | 
|  |  | 
|  | static const char *system_prefix(void); | 
|  |  | 
|  | #ifdef RUNTIME_PREFIX | 
|  |  | 
|  | /** | 
|  | * 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(executable_dirname); | 
|  | assert(is_absolute_path(executable_dirname)); | 
|  |  | 
|  | if (!prefix && | 
|  | !(prefix = strip_path_suffix(executable_dirname, GIT_EXEC_PATH)) && | 
|  | !(prefix = strip_path_suffix(executable_dirname, BINDIR)) && | 
|  | !(prefix = strip_path_suffix(executable_dirname, "git"))) { | 
|  | prefix = FALLBACK_RUNTIME_PREFIX; | 
|  | trace_printf("RUNTIME_PREFIX requested, " | 
|  | "but prefix computation failed.  " | 
|  | "Using static fallback '%s'.\n", prefix); | 
|  | } | 
|  | return prefix; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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 -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 */ | 
|  |  | 
|  | #ifdef HAVE_WPGMPTR | 
|  | /* | 
|  | * Resolves the executable path by using the global variable _wpgmptr. | 
|  | * | 
|  | * Returns 0 on success, -1 on failure. | 
|  | */ | 
|  | static int git_get_exec_path_wpgmptr(struct strbuf *buf) | 
|  | { | 
|  | int len = wcslen(_wpgmptr) * 3 + 1; | 
|  | strbuf_grow(buf, len); | 
|  | len = xwcstoutf(buf->buf, _wpgmptr, len); | 
|  | if (len < 0) | 
|  | return -1; | 
|  | buf->len += len; | 
|  | return 0; | 
|  | } | 
|  | #endif /* HAVE_WPGMPTR */ | 
|  |  | 
|  | /* | 
|  | * 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 */ | 
|  |  | 
|  | #ifdef HAVE_WPGMPTR | 
|  | git_get_exec_path_wpgmptr(buf) && | 
|  | #endif /* HAVE_WPGMPTR */ | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | trace2_cmd_path(buf->buf); | 
|  |  | 
|  | 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) | 
|  | 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 FALLBACK_RUNTIME_PREFIX; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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) | 
|  | { | 
|  | } | 
|  |  | 
|  | #endif /* RUNTIME_PREFIX */ | 
|  |  | 
|  | char *system_path(const char *path) | 
|  | { | 
|  | struct strbuf d = STRBUF_INIT; | 
|  |  | 
|  | if (is_absolute_path(path)) | 
|  | return xstrdup(path); | 
|  |  | 
|  | strbuf_addf(&d, "%s/%s", system_prefix(), path); | 
|  | return strbuf_detach(&d, NULL); | 
|  | } | 
|  |  | 
|  | static const char *exec_path_value; | 
|  |  | 
|  | void git_set_exec_path(const char *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. */ | 
|  | const char *git_exec_path(void) | 
|  | { | 
|  | if (!exec_path_value) { | 
|  | const char *env = getenv(EXEC_PATH_ENVIRONMENT); | 
|  | if (env && *env) | 
|  | exec_path_value = xstrdup(env); | 
|  | else | 
|  | exec_path_value = system_path(GIT_EXEC_PATH); | 
|  | } | 
|  | return exec_path_value; | 
|  | } | 
|  |  | 
|  | static void add_path(struct strbuf *out, const char *path) | 
|  | { | 
|  | if (path && *path) { | 
|  | strbuf_add_absolute_path(out, path); | 
|  | strbuf_addch(out, PATH_SEP); | 
|  | } | 
|  | } | 
|  |  | 
|  | void setup_path(void) | 
|  | { | 
|  | const char *exec_path = git_exec_path(); | 
|  | const char *old_path = getenv("PATH"); | 
|  | struct strbuf new_path = STRBUF_INIT; | 
|  |  | 
|  | git_set_exec_path(exec_path); | 
|  | add_path(&new_path, exec_path); | 
|  |  | 
|  | if (old_path) | 
|  | strbuf_addstr(&new_path, old_path); | 
|  | else | 
|  | strbuf_addstr(&new_path, _PATH_DEFPATH); | 
|  |  | 
|  | setenv("PATH", new_path.buf, 1); | 
|  |  | 
|  | strbuf_release(&new_path); | 
|  | } | 
|  |  | 
|  | const char **prepare_git_cmd(struct strvec *out, const char **argv) | 
|  | { | 
|  | strvec_push(out, "git"); | 
|  | strvec_pushv(out, argv); | 
|  | return out->v; | 
|  | } | 
|  |  | 
|  | int execv_git_cmd(const char **argv) | 
|  | { | 
|  | struct strvec nargv = STRVEC_INIT; | 
|  |  | 
|  | prepare_git_cmd(&nargv, argv); | 
|  | trace_argv_printf(nargv.v, "trace: exec:"); | 
|  |  | 
|  | /* execvp() can only ever return if it fails */ | 
|  | sane_execvp("git", (char **)nargv.v); | 
|  |  | 
|  | trace_printf("trace: exec failed: %s\n", strerror(errno)); | 
|  |  | 
|  | strvec_clear(&nargv); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int execl_git_cmd(const char *cmd, ...) | 
|  | { | 
|  | int argc; | 
|  | const char *argv[MAX_ARGS + 1]; | 
|  | const char *arg; | 
|  | va_list param; | 
|  |  | 
|  | va_start(param, cmd); | 
|  | argv[0] = cmd; | 
|  | argc = 1; | 
|  | while (argc < MAX_ARGS) { | 
|  | arg = argv[argc++] = va_arg(param, char *); | 
|  | if (!arg) | 
|  | break; | 
|  | } | 
|  | va_end(param); | 
|  | if (MAX_ARGS <= argc) | 
|  | return error(_("too many args to run %s"), cmd); | 
|  |  | 
|  | argv[argc] = NULL; | 
|  | return execv_git_cmd(argv); | 
|  | } |