Add expat
[git/pclouds.git] / exec_cmd.c
blob098f8632742046d5aeba4739b9ea23196f1ce3a9
1 #include "cache.h"
2 #include "exec_cmd.h"
3 #include "quote.h"
4 #include "spawn-pipe.h"
5 #define MAX_ARGS 32
7 extern char **environ;
8 static const char *current_exec_path;
10 static const char *builtin_exec_path(void)
12 #ifndef __MINGW32__
13 return GIT_EXEC_PATH;
14 #else
15 int len;
16 char *p, *q, *sl;
17 static char *ep;
18 if (ep)
19 return ep;
21 len = strlen(_pgmptr);
22 if (len < 2)
23 return ep = ".";
25 p = ep = xmalloc(len+1);
26 q = _pgmptr;
27 sl = NULL;
28 /* copy program name, turn '\\' into '/', skip last part */
29 while ((*p = *q)) {
30 if (*q == '\\' || *q == '/') {
31 *p = '/';
32 sl = p;
34 p++, q++;
36 if (sl)
37 *sl = '\0';
38 else
39 ep[0] = '.', ep[1] = '\0';
40 return ep;
41 #endif
44 void git_set_exec_path(const char *exec_path)
46 current_exec_path = exec_path;
50 /* Returns the highest-priority, location to look for git programs. */
51 const char *git_exec_path(void)
53 const char *env;
55 if (current_exec_path)
56 return current_exec_path;
58 env = getenv(EXEC_PATH_ENVIRONMENT);
59 if (env && *env) {
60 return env;
63 return builtin_exec_path();
67 int execv_git_cmd(const char **argv)
69 char git_command[PATH_MAX + 1];
70 int i;
71 const char *paths[] = { current_exec_path,
72 getenv(EXEC_PATH_ENVIRONMENT),
73 builtin_exec_path() };
75 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
76 size_t len;
77 int rc;
78 const char *exec_dir = paths[i];
79 const char *tmp;
81 if (!exec_dir || !*exec_dir) continue;
83 #ifdef __MINGW32__
84 if (*exec_dir != '/' && exec_dir[1] != ':') {
85 #else
86 if (*exec_dir != '/') {
87 #endif
88 if (!getcwd(git_command, sizeof(git_command))) {
89 fprintf(stderr, "git: cannot determine "
90 "current directory: %s\n",
91 strerror(errno));
92 break;
94 len = strlen(git_command);
96 /* Trivial cleanup */
97 while (!prefixcmp(exec_dir, "./")) {
98 exec_dir += 2;
99 while (*exec_dir == '/')
100 exec_dir++;
103 rc = snprintf(git_command + len,
104 sizeof(git_command) - len, "/%s",
105 exec_dir);
106 if (rc < 0 || rc >= sizeof(git_command) - len) {
107 fprintf(stderr, "git: command name given "
108 "is too long.\n");
109 break;
111 } else {
112 if (strlen(exec_dir) + 1 > sizeof(git_command)) {
113 fprintf(stderr, "git: command name given "
114 "is too long.\n");
115 break;
117 strcpy(git_command, exec_dir);
120 len = strlen(git_command);
121 rc = snprintf(git_command + len, sizeof(git_command) - len,
122 "/git-%s", argv[0]);
123 if (rc < 0 || rc >= sizeof(git_command) - len) {
124 fprintf(stderr,
125 "git: command name given is too long.\n");
126 break;
129 /* argv[0] must be the git command, but the argv array
130 * belongs to the caller, and my be reused in
131 * subsequent loop iterations. Save argv[0] and
132 * restore it on error.
135 tmp = argv[0];
136 argv[0] = git_command;
138 trace_argv_printf(argv, -1, "trace: exec:");
140 /* execve() can only ever return if it fails */
141 execve(git_command, (char **)argv, environ);
143 trace_printf("trace: exec failed: %s\n", strerror(errno));
145 argv[0] = tmp;
147 return -1;
152 int execl_git_cmd(const char *cmd,...)
154 int argc;
155 const char *argv[MAX_ARGS + 1];
156 const char *arg;
157 va_list param;
159 va_start(param, cmd);
160 argv[0] = cmd;
161 argc = 1;
162 while (argc < MAX_ARGS) {
163 arg = argv[argc++] = va_arg(param, char *);
164 if (!arg)
165 break;
167 va_end(param);
168 if (MAX_ARGS <= argc)
169 return error("too many args to run %s", cmd);
171 argv[argc] = NULL;
172 return execv_git_cmd(argv);
175 int spawnve_git_cmd(const char **argv, int pin[2], int pout[2], char **envp)
177 int i, rc;
178 pid_t pid;
179 const char *paths[] = { current_exec_path,
180 getenv(EXEC_PATH_ENVIRONMENT),
181 builtin_exec_path() };
182 char p[3][PATH_MAX + 1];
183 char *usedpaths[4], **up = usedpaths;
184 const char **new_argv;
186 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
187 size_t len;
188 const char *exec_dir = paths[i];
190 if (!exec_dir || !*exec_dir) continue;
192 #ifdef __MINGW32__
193 if (*exec_dir != '/' && exec_dir[1] != ':') {
194 #else
195 if (*exec_dir != '/') {
196 #endif
197 if (!getcwd(p[i], sizeof(p[i]))) {
198 fprintf(stderr, "git: cannot determine "
199 "current directory: %s\n",
200 strerror(errno));
201 return -1;
203 len = strlen(p[i]);
205 /* Trivial cleanup */
206 while (!strncmp(exec_dir, "./", 2)) {
207 exec_dir += 2;
208 while (*exec_dir == '/')
209 exec_dir++;
212 rc = snprintf(p[i] + len,
213 sizeof(p[i]) - len, "/%s",
214 exec_dir);
215 if (rc < 0 || rc >= sizeof(p[i]) - len) {
216 fprintf(stderr, "git: command name given "
217 "is too long.\n");
218 return -1;
220 } else {
221 if (strlen(exec_dir) + 1 > sizeof(p[i])) {
222 fprintf(stderr, "git: command name given "
223 "is too long.\n");
224 return -1;
226 strcpy(p[i], exec_dir);
228 *up++ = p[i];
230 *up = NULL;
232 for (rc = 0;argv[rc];rc++);
234 new_argv = malloc(sizeof(char*)*(rc+2)); /* git command plus null */
235 new_argv[0] = "git";
236 new_argv[1] = argv[0];
237 memcpy(&new_argv[2], &argv[1], sizeof(char*)*rc);
239 trace_argv_printf(new_argv, -1, "trace: exec:");
241 pid = spawnvppe_pipe(new_argv[0], new_argv, envp, usedpaths,
242 pin, pout);
244 free(new_argv);
246 return pid;
250 int spawnv_git_cmd(const char **argv, int pin[2], int pout[2])
252 return spawnve_git_cmd(argv, pin, pout, environ);