Git fork
at 2cdb7a38c7bb157adc6ef632b08cefd130ce02e7 396 lines 8.8 kB view raw
1#include "git-compat-util.h" 2#include "abspath.h" 3#include "environment.h" 4#include "exec-cmd.h" 5#include "gettext.h" 6#include "path.h" 7#include "run-command.h" 8#include "strvec.h" 9#include "trace.h" 10#include "trace2.h" 11 12#if defined(RUNTIME_PREFIX) 13 14#if defined(HAVE_NS_GET_EXECUTABLE_PATH) 15#include <mach-o/dyld.h> 16#endif 17 18#if defined(HAVE_BSD_KERN_PROC_SYSCTL) 19#include <sys/param.h> 20#include <sys/types.h> 21#include <sys/sysctl.h> 22#endif 23 24#endif /* RUNTIME_PREFIX */ 25 26#define MAX_ARGS 32 27 28static const char *system_prefix(void); 29 30#ifdef RUNTIME_PREFIX 31 32/** 33 * When using a runtime prefix, Git dynamically resolves paths relative to its 34 * executable. 35 * 36 * The method for determining the path of the executable is highly 37 * platform-specific. 38 */ 39 40/** 41 * Path to the current Git executable. Resolved on startup by 42 * 'git_resolve_executable_dir'. 43 */ 44static const char *executable_dirname; 45 46static const char *system_prefix(void) 47{ 48 static const char *prefix; 49 50 assert(executable_dirname); 51 assert(is_absolute_path(executable_dirname)); 52 53 if (!prefix && 54 !(prefix = strip_path_suffix(executable_dirname, GIT_EXEC_PATH)) && 55 !(prefix = strip_path_suffix(executable_dirname, BINDIR)) && 56 !(prefix = strip_path_suffix(executable_dirname, "git"))) { 57 prefix = FALLBACK_RUNTIME_PREFIX; 58 trace_printf("RUNTIME_PREFIX requested, " 59 "but prefix computation failed. " 60 "Using static fallback '%s'.\n", prefix); 61 } 62 return prefix; 63} 64 65/* 66 * Resolves the executable path from argv[0], only if it is absolute. 67 * 68 * Returns 0 on success, -1 on failure. 69 */ 70static int git_get_exec_path_from_argv0(struct strbuf *buf, const char *argv0) 71{ 72 const char *slash; 73 74 if (!argv0 || !*argv0) 75 return -1; 76 77 slash = find_last_dir_sep(argv0); 78 if (slash) { 79 trace_printf("trace: resolved executable path from argv0: %s\n", 80 argv0); 81 strbuf_add_absolute_path(buf, argv0); 82 return 0; 83 } 84 return -1; 85} 86 87#ifdef PROCFS_EXECUTABLE_PATH 88/* 89 * Resolves the executable path by examining a procfs symlink. 90 * 91 * Returns 0 on success, -1 on failure. 92 */ 93static int git_get_exec_path_procfs(struct strbuf *buf) 94{ 95 if (strbuf_realpath(buf, PROCFS_EXECUTABLE_PATH, 0)) { 96 trace_printf( 97 "trace: resolved executable path from procfs: %s\n", 98 buf->buf); 99 return 0; 100 } 101 return -1; 102} 103#endif /* PROCFS_EXECUTABLE_PATH */ 104 105#ifdef HAVE_BSD_KERN_PROC_SYSCTL 106/* 107 * Resolves the executable path using KERN_PROC_PATHNAME BSD sysctl. 108 * 109 * Returns 0 on success, -1 on failure. 110 */ 111static int git_get_exec_path_bsd_sysctl(struct strbuf *buf) 112{ 113 int mib[4]; 114 char path[MAXPATHLEN]; 115 size_t cb = sizeof(path); 116 117 mib[0] = CTL_KERN; 118 mib[1] = KERN_PROC; 119 mib[2] = KERN_PROC_PATHNAME; 120 mib[3] = -1; 121 if (!sysctl(mib, 4, path, &cb, NULL, 0)) { 122 trace_printf( 123 "trace: resolved executable path from sysctl: %s\n", 124 path); 125 strbuf_addstr(buf, path); 126 return 0; 127 } 128 return -1; 129} 130#endif /* HAVE_BSD_KERN_PROC_SYSCTL */ 131 132#ifdef HAVE_NS_GET_EXECUTABLE_PATH 133/* 134 * Resolves the executable path by querying Darwin application stack. 135 * 136 * Returns 0 on success, -1 on failure. 137 */ 138static int git_get_exec_path_darwin(struct strbuf *buf) 139{ 140 char path[PATH_MAX]; 141 uint32_t size = sizeof(path); 142 if (!_NSGetExecutablePath(path, &size)) { 143 trace_printf( 144 "trace: resolved executable path from Darwin stack: %s\n", 145 path); 146 strbuf_addstr(buf, path); 147 return 0; 148 } 149 return -1; 150} 151#endif /* HAVE_NS_GET_EXECUTABLE_PATH */ 152 153#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH 154/* 155 * Resolves the executable path from current program's directory and name. 156 * 157 * Returns 0 on success, -1 on failure. 158 */ 159static int git_get_exec_path_zos(struct strbuf *buf) 160{ 161 char *dir = __getprogramdir(); 162 char *exe = getprogname(); 163 if (dir && exe) { 164 strbuf_addf(buf, "%s/%s", dir, exe); 165 return 0; 166 } 167 return -1; 168} 169 170#endif /* HAVE_ZOS_GET_EXECUTABLE_PATH */ 171 172#ifdef HAVE_WPGMPTR 173/* 174 * Resolves the executable path by using the global variable _wpgmptr. 175 * 176 * Returns 0 on success, -1 on failure. 177 */ 178static int git_get_exec_path_wpgmptr(struct strbuf *buf) 179{ 180 int len = wcslen(_wpgmptr) * 3 + 1; 181 strbuf_grow(buf, len); 182 len = xwcstoutf(buf->buf, _wpgmptr, len); 183 if (len < 0) 184 return -1; 185 buf->len += len; 186 return 0; 187} 188#endif /* HAVE_WPGMPTR */ 189 190/* 191 * Resolves the absolute path of the current executable. 192 * 193 * Returns 0 on success, -1 on failure. 194 */ 195static int git_get_exec_path(struct strbuf *buf, const char *argv0) 196{ 197 /* 198 * Identifying the executable path is operating system specific. 199 * Selectively employ all available methods in order of preference, 200 * preferring highly-available authoritative methods over 201 * selectively-available or non-authoritative methods. 202 * 203 * All cases fall back on resolving against argv[0] if there isn't a 204 * better functional method. However, note that argv[0] can be 205 * used-supplied on many operating systems, and is not authoritative 206 * in those cases. 207 * 208 * Each of these functions returns 0 on success, so evaluation will stop 209 * after the first successful method. 210 */ 211 if ( 212#ifdef HAVE_BSD_KERN_PROC_SYSCTL 213 git_get_exec_path_bsd_sysctl(buf) && 214#endif /* HAVE_BSD_KERN_PROC_SYSCTL */ 215 216#ifdef HAVE_NS_GET_EXECUTABLE_PATH 217 git_get_exec_path_darwin(buf) && 218#endif /* HAVE_NS_GET_EXECUTABLE_PATH */ 219 220#ifdef PROCFS_EXECUTABLE_PATH 221 git_get_exec_path_procfs(buf) && 222#endif /* PROCFS_EXECUTABLE_PATH */ 223 224#ifdef HAVE_WPGMPTR 225 git_get_exec_path_wpgmptr(buf) && 226#endif /* HAVE_WPGMPTR */ 227 228#ifdef HAVE_ZOS_GET_EXECUTABLE_PATH 229 git_get_exec_path_zos(buf) && 230#endif /*HAVE_ZOS_GET_EXECUTABLE_PATH */ 231 232 git_get_exec_path_from_argv0(buf, argv0)) { 233 return -1; 234 } 235 236 if (strbuf_normalize_path(buf)) { 237 trace_printf("trace: could not normalize path: %s\n", buf->buf); 238 return -1; 239 } 240 241 trace2_cmd_path(buf->buf); 242 243 return 0; 244} 245 246void git_resolve_executable_dir(const char *argv0) 247{ 248 struct strbuf buf = STRBUF_INIT; 249 char *resolved; 250 const char *slash; 251 252 if (git_get_exec_path(&buf, argv0)) { 253 trace_printf( 254 "trace: could not determine executable path from: %s\n", 255 argv0); 256 strbuf_release(&buf); 257 return; 258 } 259 260 resolved = strbuf_detach(&buf, NULL); 261 slash = find_last_dir_sep(resolved); 262 if (slash) 263 resolved[slash - resolved] = '\0'; 264 265 executable_dirname = resolved; 266 trace_printf("trace: resolved executable dir: %s\n", 267 executable_dirname); 268} 269 270#else 271 272/* 273 * When not using a runtime prefix, Git uses a hard-coded path. 274 */ 275static const char *system_prefix(void) 276{ 277 return FALLBACK_RUNTIME_PREFIX; 278} 279 280/* 281 * This is called during initialization, but No work needs to be done here when 282 * runtime prefix is not being used. 283 */ 284void git_resolve_executable_dir(const char *argv0 UNUSED) 285{ 286} 287 288#endif /* RUNTIME_PREFIX */ 289 290char *system_path(const char *path) 291{ 292 struct strbuf d = STRBUF_INIT; 293 294 if (is_absolute_path(path)) 295 return xstrdup(path); 296 297 strbuf_addf(&d, "%s/%s", system_prefix(), path); 298 return strbuf_detach(&d, NULL); 299} 300 301static const char *exec_path_value; 302 303void git_set_exec_path(const char *exec_path) 304{ 305 exec_path_value = exec_path; 306 /* 307 * Propagate this setting to external programs. 308 */ 309 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); 310} 311 312/* Returns the highest-priority location to look for git programs. */ 313const char *git_exec_path(void) 314{ 315 if (!exec_path_value) { 316 const char *env = getenv(EXEC_PATH_ENVIRONMENT); 317 if (env && *env) 318 exec_path_value = xstrdup(env); 319 else 320 exec_path_value = system_path(GIT_EXEC_PATH); 321 } 322 return exec_path_value; 323} 324 325static void add_path(struct strbuf *out, const char *path) 326{ 327 if (path && *path) { 328 strbuf_add_absolute_path(out, path); 329 strbuf_addch(out, PATH_SEP); 330 } 331} 332 333void setup_path(void) 334{ 335 const char *exec_path = git_exec_path(); 336 const char *old_path = getenv("PATH"); 337 struct strbuf new_path = STRBUF_INIT; 338 339 git_set_exec_path(exec_path); 340 add_path(&new_path, exec_path); 341 342 if (old_path) 343 strbuf_addstr(&new_path, old_path); 344 else 345 strbuf_addstr(&new_path, _PATH_DEFPATH); 346 347 setenv("PATH", new_path.buf, 1); 348 349 strbuf_release(&new_path); 350} 351 352const char **prepare_git_cmd(struct strvec *out, const char **argv) 353{ 354 strvec_push(out, "git"); 355 strvec_pushv(out, argv); 356 return out->v; 357} 358 359int execv_git_cmd(const char **argv) 360{ 361 struct strvec nargv = STRVEC_INIT; 362 363 prepare_git_cmd(&nargv, argv); 364 trace_argv_printf(nargv.v, "trace: exec:"); 365 366 /* execvp() can only ever return if it fails */ 367 sane_execvp("git", (char **)nargv.v); 368 369 trace_printf("trace: exec failed: %s\n", strerror(errno)); 370 371 strvec_clear(&nargv); 372 return -1; 373} 374 375int execl_git_cmd(const char *cmd, ...) 376{ 377 int argc; 378 const char *argv[MAX_ARGS + 1]; 379 const char *arg; 380 va_list param; 381 382 va_start(param, cmd); 383 argv[0] = cmd; 384 argc = 1; 385 while (argc < MAX_ARGS) { 386 arg = argv[argc++] = va_arg(param, char *); 387 if (!arg) 388 break; 389 } 390 va_end(param); 391 if (MAX_ARGS <= argc) 392 return error(_("too many args to run %s"), cmd); 393 394 argv[argc] = NULL; 395 return execv_git_cmd(argv); 396}