]>
Commit | Line | Data |
---|---|---|
77cb17e9 MO |
1 | #include "cache.h" |
2 | #include "exec_cmd.h" | |
575ba9d6 | 3 | #include "quote.h" |
77cb17e9 MO |
4 | #define MAX_ARGS 32 |
5 | ||
6 | extern char **environ; | |
384df833 | 7 | static const char *argv_exec_path; |
e1464ca7 | 8 | static const char *argv0_path; |
77cb17e9 | 9 | |
2de9de5e SP |
10 | const char *system_path(const char *path) |
11 | { | |
35fb0e86 SP |
12 | #ifdef RUNTIME_PREFIX |
13 | static const char *prefix; | |
14 | #else | |
026fa0d5 | 15 | static const char *prefix = PREFIX; |
35fb0e86 | 16 | #endif |
026fa0d5 SP |
17 | struct strbuf d = STRBUF_INIT; |
18 | ||
19 | if (is_absolute_path(path)) | |
20 | return path; | |
21 | ||
35fb0e86 SP |
22 | #ifdef RUNTIME_PREFIX |
23 | assert(argv0_path); | |
24 | assert(is_absolute_path(argv0_path)); | |
25 | ||
26 | if (!prefix) { | |
27 | const char *strip[] = { | |
28 | GIT_EXEC_PATH, | |
29 | BINDIR, | |
30 | 0 | |
31 | }; | |
32 | const char **s; | |
33 | ||
34 | for (s = strip; *s; s++) { | |
35 | const char *sargv = argv0_path + strlen(argv0_path); | |
36 | const char *ss = *s + strlen(*s); | |
37 | while (argv0_path < sargv && *s < ss | |
38 | && (*sargv == *ss || | |
39 | (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { | |
40 | sargv--; | |
41 | ss--; | |
42 | } | |
43 | if (*s == ss) { | |
44 | struct strbuf d = STRBUF_INIT; | |
45 | /* We also skip the trailing directory separator. */ | |
46 | assert(sargv - argv0_path - 1 >= 0); | |
47 | strbuf_add(&d, argv0_path, sargv - argv0_path - 1); | |
48 | prefix = strbuf_detach(&d, NULL); | |
49 | break; | |
50 | } | |
51 | } | |
52 | } | |
53 | ||
54 | if (!prefix) { | |
55 | prefix = PREFIX; | |
56 | fprintf(stderr, "RUNTIME_PREFIX requested, " | |
57 | "but prefix computation failed. " | |
58 | "Using static fallback '%s'.\n", prefix); | |
59 | } | |
60 | #endif | |
61 | ||
026fa0d5 SP |
62 | strbuf_addf(&d, "%s/%s", prefix, path); |
63 | path = strbuf_detach(&d, NULL); | |
2de9de5e SP |
64 | return path; |
65 | } | |
66 | ||
4dd47c3b | 67 | const char *git_extract_argv0_path(const char *argv0) |
e1464ca7 | 68 | { |
2cd72b0b SP |
69 | const char *slash; |
70 | ||
71 | if (!argv0 || !*argv0) | |
72 | return NULL; | |
73 | slash = argv0 + strlen(argv0); | |
4dd47c3b SH |
74 | |
75 | while (argv0 <= slash && !is_dir_sep(*slash)) | |
76 | slash--; | |
77 | ||
78 | if (slash >= argv0) { | |
79 | argv0_path = xstrndup(argv0, slash - argv0); | |
80 | return slash + 1; | |
81 | } | |
82 | ||
83 | return argv0; | |
e1464ca7 JS |
84 | } |
85 | ||
384df833 | 86 | void git_set_argv_exec_path(const char *exec_path) |
77cb17e9 | 87 | { |
384df833 | 88 | argv_exec_path = exec_path; |
77cb17e9 MO |
89 | } |
90 | ||
91 | ||
92 | /* Returns the highest-priority, location to look for git programs. */ | |
962554c6 | 93 | const char *git_exec_path(void) |
77cb17e9 MO |
94 | { |
95 | const char *env; | |
96 | ||
384df833 SP |
97 | if (argv_exec_path) |
98 | return argv_exec_path; | |
77cb17e9 | 99 | |
d4ebc36c | 100 | env = getenv(EXEC_PATH_ENVIRONMENT); |
2b601626 | 101 | if (env && *env) { |
77cb17e9 MO |
102 | return env; |
103 | } | |
104 | ||
49fa65a7 | 105 | return system_path(GIT_EXEC_PATH); |
77cb17e9 MO |
106 | } |
107 | ||
511707d4 SP |
108 | static void add_path(struct strbuf *out, const char *path) |
109 | { | |
110 | if (path && *path) { | |
111 | if (is_absolute_path(path)) | |
112 | strbuf_addstr(out, path); | |
113 | else | |
10c4c881 | 114 | strbuf_addstr(out, make_nonrelative_path(path)); |
511707d4 | 115 | |
80ba074f | 116 | strbuf_addch(out, PATH_SEP); |
511707d4 SP |
117 | } |
118 | } | |
119 | ||
e1464ca7 | 120 | void setup_path(void) |
511707d4 SP |
121 | { |
122 | const char *old_path = getenv("PATH"); | |
f285a2d7 | 123 | struct strbuf new_path = STRBUF_INIT; |
511707d4 | 124 | |
8e346283 | 125 | add_path(&new_path, git_exec_path()); |
e1464ca7 | 126 | add_path(&new_path, argv0_path); |
511707d4 SP |
127 | |
128 | if (old_path) | |
129 | strbuf_addstr(&new_path, old_path); | |
130 | else | |
131 | strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin"); | |
132 | ||
133 | setenv("PATH", new_path.buf, 1); | |
134 | ||
135 | strbuf_release(&new_path); | |
136 | } | |
77cb17e9 | 137 | |
4933e5eb | 138 | const char **prepare_git_cmd(const char **argv) |
77cb17e9 | 139 | { |
7550be0a JH |
140 | int argc; |
141 | const char **nargv; | |
77cb17e9 | 142 | |
7550be0a JH |
143 | for (argc = 0; argv[argc]; argc++) |
144 | ; /* just counting */ | |
145 | nargv = xmalloc(sizeof(*nargv) * (argc + 2)); | |
77cb17e9 | 146 | |
7550be0a JH |
147 | nargv[0] = "git"; |
148 | for (argc = 0; argv[argc]; argc++) | |
149 | nargv[argc + 1] = argv[argc]; | |
150 | nargv[argc + 1] = NULL; | |
4933e5eb SP |
151 | return nargv; |
152 | } | |
153 | ||
154 | int execv_git_cmd(const char **argv) { | |
155 | const char **nargv = prepare_git_cmd(argv); | |
7550be0a | 156 | trace_argv_printf(nargv, "trace: exec:"); |
575ba9d6 | 157 | |
511707d4 | 158 | /* execvp() can only ever return if it fails */ |
7550be0a | 159 | execvp("git", (char **)nargv); |
77cb17e9 | 160 | |
511707d4 | 161 | trace_printf("trace: exec failed: %s\n", strerror(errno)); |
575ba9d6 | 162 | |
7550be0a | 163 | free(nargv); |
511707d4 | 164 | return -1; |
77cb17e9 MO |
165 | } |
166 | ||
167 | ||
9201c707 | 168 | int execl_git_cmd(const char *cmd,...) |
77cb17e9 MO |
169 | { |
170 | int argc; | |
9201c707 JH |
171 | const char *argv[MAX_ARGS + 1]; |
172 | const char *arg; | |
77cb17e9 MO |
173 | va_list param; |
174 | ||
175 | va_start(param, cmd); | |
176 | argv[0] = cmd; | |
177 | argc = 1; | |
178 | while (argc < MAX_ARGS) { | |
179 | arg = argv[argc++] = va_arg(param, char *); | |
180 | if (!arg) | |
181 | break; | |
182 | } | |
183 | va_end(param); | |
184 | if (MAX_ARGS <= argc) | |
185 | return error("too many args to run %s", cmd); | |
186 | ||
187 | argv[argc] = NULL; | |
188 | return execv_git_cmd(argv); | |
189 | } |