2
#include "exec_cmd.h"
3
#include "quote.h"
4
#include "argv-array.h"
5
-#define MAX_ARGS 32
5
7
-static const char *argv_exec_path;
6
+#if defined(RUNTIME_PREFIX)
7
+
8
+#if defined(HAVE_NS_GET_EXECUTABLE_PATH)
9
+#include <mach-o/dyld.h>
10
+#endif
11
+
12
+#if defined(HAVE_BSD_KERN_PROC_SYSCTL)
13
+#include <sys/param.h>
14
+#include <sys/types.h>
15
+#include <sys/sysctl.h>
16
+#endif
17
+
18
+#endif /* RUNTIME_PREFIX */
19
+
20
+#define MAX_ARGS 32
21
+
22
+static const char *system_prefix(void);
23
24
#ifdef RUNTIME_PREFIX
10
-static const char *argv0_path;
25
+
26
+/**
27
+ * When using a runtime prefix, Git dynamically resolves paths relative to its
28
+ * executable.
29
+ *
30
+ * The method for determining the path of the executable is highly
31
+ * platform-specific.
32
+ */
33
+
34
+/**
35
+ * Path to the current Git executable. Resolved on startup by
36
+ * 'git_resolve_executable_dir'.
37
+ */
38
+static const char *executable_dirname;
39
40
static const char *system_prefix(void)
41
{
42
static const char *prefix;
43
16
- assert(argv0_path);
17
- assert(is_absolute_path(argv0_path));
44
+ assert(executable_dirname);
45
+ assert(is_absolute_path(executable_dirname));
46
47
if (!prefix &&
20
- !(prefix = strip_path_suffix(argv0_path, GIT_EXEC_PATH)) &&
21
- !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
22
- !(prefix = strip_path_suffix(argv0_path, "git"))) {
48
+ !(prefix = strip_path_suffix(executable_dirname, GIT_EXEC_PATH)) &&
49
+ !(prefix = strip_path_suffix(executable_dirname, BINDIR)) &&
50
+ !(prefix = strip_path_suffix(executable_dirname, "git"))) {
51
prefix = PREFIX;
52
trace_printf("RUNTIME_PREFIX requested, "
53
"but prefix computation failed. "
56
return prefix;
57
}
58
31
-void git_extract_argv0_path(const char *argv0)
59
+/*
60
+ * Resolves the executable path from argv[0], only if it is absolute.
61
+ *
62
+ * Returns 0 on success, -1 on failure.
63
+ */
64
+static int git_get_exec_path_from_argv0(struct strbuf *buf, const char *argv0)
65
{
66
const char *slash;
67
68
if (!argv0 || !*argv0)
36
- return;
69
+ return -1;
70
71
slash = find_last_dir_sep(argv0);
72
+ if (slash) {
73
+ trace_printf("trace: resolved executable path from argv0: %s\n",
74
+ argv0);
75
+ strbuf_add_absolute_path(buf, argv0);
76
+ return 0;
77
+ }
78
+ return -1;
79
+}
80
81
+#ifdef PROCFS_EXECUTABLE_PATH
82
+/*
83
+ * Resolves the executable path by examining a procfs symlink.
84
+ *
85
+ * Returns 0 on success, -1 on failure.
86
+ */
87
+static int git_get_exec_path_procfs(struct strbuf *buf)
88
+{
89
+ if (strbuf_realpath(buf, PROCFS_EXECUTABLE_PATH, 0)) {
90
+ trace_printf(
91
+ "trace: resolved executable path from procfs: %s\n",
92
+ buf->buf);
93
+ return 0;
94
+ }
95
+ return -1;
96
+}
97
+#endif /* PROCFS_EXECUTABLE_PATH */
98
+
99
+#ifdef HAVE_BSD_KERN_PROC_SYSCTL
100
+/*
101
+ * Resolves the executable path using KERN_PROC_PATHNAME BSD sysctl.
102
+ *
103
+ * Returns 0 on success, -1 on failure.
104
+ */
105
+static int git_get_exec_path_bsd_sysctl(struct strbuf *buf)
106
+{
107
+ int mib[4];
108
+ char path[MAXPATHLEN];
109
+ size_t cb = sizeof(path);
110
+
111
+ mib[0] = CTL_KERN;
112
+ mib[1] = KERN_PROC;
113
+ mib[2] = KERN_PROC_PATHNAME;
114
+ mib[3] = -1;
115
+ if (!sysctl(mib, 4, path, &cb, NULL, 0)) {
116
+ trace_printf(
117
+ "trace: resolved executable path from sysctl: %s\n",
118
+ path);
119
+ strbuf_addstr(buf, path);
120
+ return 0;
121
+ }
122
+ return -1;
123
+}
124
+#endif /* HAVE_BSD_KERN_PROC_SYSCTL */
125
+
126
+#ifdef HAVE_NS_GET_EXECUTABLE_PATH
127
+/*
128
+ * Resolves the executable path by querying Darwin application stack.
129
+ *
130
+ * Returns 0 on success, -1 on failure.
131
+ */
132
+static int git_get_exec_path_darwin(struct strbuf *buf)
133
+{
134
+ char path[PATH_MAX];
135
+ uint32_t size = sizeof(path);
136
+ if (!_NSGetExecutablePath(path, &size)) {
137
+ trace_printf(
138
+ "trace: resolved executable path from Darwin stack: %s\n",
139
+ path);
140
+ strbuf_addstr(buf, path);
141
+ return 0;
142
+ }
143
+ return -1;
144
+}
145
+#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
146
+
147
+/*
148
+ * Resolves the absolute path of the current executable.
149
+ *
150
+ * Returns 0 on success, -1 on failure.
151
+ */
152
+static int git_get_exec_path(struct strbuf *buf, const char *argv0)
153
+{
154
+ /*
155
+ * Identifying the executable path is operating system specific.
156
+ * Selectively employ all available methods in order of preference,
157
+ * preferring highly-available authoritative methods over
158
+ * selectively-available or non-authoritative methods.
159
+ *
160
+ * All cases fall back on resolving against argv[0] if there isn't a
161
+ * better functional method. However, note that argv[0] can be
162
+ * used-supplied on many operating systems, and is not authoritative
163
+ * in those cases.
164
+ *
165
+ * Each of these functions returns 0 on success, so evaluation will stop
166
+ * after the first successful method.
167
+ */
168
+ if (
169
+#ifdef HAVE_BSD_KERN_PROC_SYSCTL
170
+ git_get_exec_path_bsd_sysctl(buf) &&
171
+#endif /* HAVE_BSD_KERN_PROC_SYSCTL */
172
+
173
+#ifdef HAVE_NS_GET_EXECUTABLE_PATH
174
+ git_get_exec_path_darwin(buf) &&
175
+#endif /* HAVE_NS_GET_EXECUTABLE_PATH */
176
+
177
+#ifdef PROCFS_EXECUTABLE_PATH
178
+ git_get_exec_path_procfs(buf) &&
179
+#endif /* PROCFS_EXECUTABLE_PATH */
180
+
181
+ git_get_exec_path_from_argv0(buf, argv0)) {
182
+ return -1;
183
+ }
184
+
185
+ if (strbuf_normalize_path(buf)) {
186
+ trace_printf("trace: could not normalize path: %s\n", buf->buf);
187
+ return -1;
188
+ }
189
+
190
+ return 0;
191
+}
192
+
193
+void git_resolve_executable_dir(const char *argv0)
194
+{
195
+ struct strbuf buf = STRBUF_INIT;
196
+ char *resolved;
197
+ const char *slash;
198
+
199
+ if (git_get_exec_path(&buf, argv0)) {
200
+ trace_printf(
201
+ "trace: could not determine executable path from: %s\n",
202
+ argv0);
203
+ strbuf_release(&buf);
204
+ return;
205
+ }
206
+
207
+ resolved = strbuf_detach(&buf, NULL);
208
+ slash = find_last_dir_sep(resolved);
209
if (slash)
41
- argv0_path = xstrndup(argv0, slash - argv0);
210
+ resolved[slash - resolved] = '\0';
211
+
212
+ executable_dirname = resolved;
213
+ trace_printf("trace: resolved executable dir: %s\n",
214
+ executable_dirname);
215
}
216
217
#else
218
219
+/*
220
+ * When not using a runtime prefix, Git uses a hard-coded path.
221
+ */
222
static const char *system_prefix(void)
223
{
224
return PREFIX;
225
}
226
51
-void git_extract_argv0_path(const char *argv0)
227
+/*
228
+ * This is called during initialization, but No work needs to be done here when
229
+ * runtime prefix is not being used.
230
+ */
231
+void git_resolve_executable_dir(const char *argv0)
232
{
233
}
234
245
return strbuf_detach(&d, NULL);
246
}
247
68
-void git_set_argv_exec_path(const char *exec_path)
248
+static const char *exec_path_value;
249
+
250
+void git_set_exec_path(const char *exec_path)
251
{
70
- argv_exec_path = exec_path;
252
+ exec_path_value = exec_path;
253
/*
254
* Propagate this setting to external programs.
255
*/
256
setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
257
}
258
77
-
78
-/* Returns the highest-priority, location to look for git programs. */
259
+/* Returns the highest-priority location to look for git programs. */
260
const char *git_exec_path(void)
261
{
81
- static char *cached_exec_path;
82
-
83
- if (argv_exec_path)
84
- return argv_exec_path;
85
-
86
- if (!cached_exec_path) {
262
+ if (!exec_path_value) {
263
const char *env = getenv(EXEC_PATH_ENVIRONMENT);
264
if (env && *env)
89
- cached_exec_path = xstrdup(env);
265
+ exec_path_value = xstrdup(env);
266
else
91
- cached_exec_path = system_path(GIT_EXEC_PATH);
267
+ exec_path_value = system_path(GIT_EXEC_PATH);
268
}
93
- return cached_exec_path;
269
+ return exec_path_value;
270
}
271
272
static void add_path(struct strbuf *out, const char *path)
279
280
void setup_path(void)
281
{
282
+ const char *exec_path = git_exec_path();
283
const char *old_path = getenv("PATH");
284
struct strbuf new_path = STRBUF_INIT;
285
109
- add_path(&new_path, git_exec_path());
286
+ git_set_exec_path(exec_path);
287
+ add_path(&new_path, exec_path);
288
289
if (old_path)
290
strbuf_addstr(&new_path, old_path);
303
return out->argv;
304
}
305
128
-int execv_git_cmd(const char **argv) {
306
+int execv_git_cmd(const char **argv)
307
+{
308
struct argv_array nargv = ARGV_ARRAY_INIT;
309
310
prepare_git_cmd(&nargv, argv);
319
return -1;
320
}
321
143
-
144
-int execl_git_cmd(const char *cmd,...)
322
+int execl_git_cmd(const char *cmd, ...)
323
{
324
int argc;
325
const char *argv[MAX_ARGS + 1];