Really run scripts under the interpreter specified in the first line.
[git/mingw.git] / exec_cmd.c
blob4e8125aab8e7e3f2814098f433d5cc316ff81ca1
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 *builtin_exec_path = GIT_EXEC_PATH;
9 static const char *current_exec_path;
11 void git_set_exec_path(const char *exec_path)
13 current_exec_path = exec_path;
17 /* Returns the highest-priority, location to look for git programs. */
18 const char *git_exec_path(void)
20 const char *env;
22 if (current_exec_path)
23 return current_exec_path;
25 env = getenv(EXEC_PATH_ENVIRONMENT);
26 if (env && *env) {
27 return env;
30 return builtin_exec_path;
34 int execv_git_cmd(const char **argv)
36 char git_command[PATH_MAX + 1];
37 int i;
38 const char *paths[] = { current_exec_path,
39 getenv(EXEC_PATH_ENVIRONMENT),
40 builtin_exec_path };
42 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
43 size_t len;
44 int rc;
45 const char *exec_dir = paths[i];
46 const char *tmp;
48 if (!exec_dir || !*exec_dir) continue;
50 #ifdef __MINGW32__
51 if (*exec_dir != '/' && exec_dir[1] != ':') {
52 #else
53 if (*exec_dir != '/') {
54 #endif
55 if (!getcwd(git_command, sizeof(git_command))) {
56 fprintf(stderr, "git: cannot determine "
57 "current directory: %s\n",
58 strerror(errno));
59 break;
61 len = strlen(git_command);
63 /* Trivial cleanup */
64 while (!prefixcmp(exec_dir, "./")) {
65 exec_dir += 2;
66 while (*exec_dir == '/')
67 exec_dir++;
70 rc = snprintf(git_command + len,
71 sizeof(git_command) - len, "/%s",
72 exec_dir);
73 if (rc < 0 || rc >= sizeof(git_command) - len) {
74 fprintf(stderr, "git: command name given "
75 "is too long.\n");
76 break;
78 } else {
79 if (strlen(exec_dir) + 1 > sizeof(git_command)) {
80 fprintf(stderr, "git: command name given "
81 "is too long.\n");
82 break;
84 strcpy(git_command, exec_dir);
87 len = strlen(git_command);
88 rc = snprintf(git_command + len, sizeof(git_command) - len,
89 "/git-%s", argv[0]);
90 if (rc < 0 || rc >= sizeof(git_command) - len) {
91 fprintf(stderr,
92 "git: command name given is too long.\n");
93 break;
96 /* argv[0] must be the git command, but the argv array
97 * belongs to the caller, and my be reused in
98 * subsequent loop iterations. Save argv[0] and
99 * restore it on error.
102 tmp = argv[0];
103 argv[0] = git_command;
105 trace_argv_printf(argv, -1, "trace: exec:");
107 /* execve() can only ever return if it fails */
108 execve(git_command, (char **)argv, environ);
110 trace_printf("trace: exec failed: %s\n", strerror(errno));
112 argv[0] = tmp;
114 return -1;
119 int execl_git_cmd(const char *cmd,...)
121 int argc;
122 const char *argv[MAX_ARGS + 1];
123 const char *arg;
124 va_list param;
126 va_start(param, cmd);
127 argv[0] = cmd;
128 argc = 1;
129 while (argc < MAX_ARGS) {
130 arg = argv[argc++] = va_arg(param, char *);
131 if (!arg)
132 break;
134 va_end(param);
135 if (MAX_ARGS <= argc)
136 return error("too many args to run %s", cmd);
138 argv[argc] = NULL;
139 return execv_git_cmd(argv);
142 int spawnv_git_cmd(const char **argv, int pin[2], int pout[2])
144 char cmd[100];
145 int i, rc;
146 pid_t pid;
147 const char *paths[] = { current_exec_path,
148 getenv(EXEC_PATH_ENVIRONMENT),
149 builtin_exec_path };
150 char p[3][PATH_MAX + 1];
151 char *usedpaths[4], **up = usedpaths;
152 const char *tmp;
154 for (i = 0; i < ARRAY_SIZE(paths); ++i) {
155 size_t len;
156 const char *exec_dir = paths[i];
158 if (!exec_dir || !*exec_dir) continue;
160 #ifdef __MINGW32__
161 if (*exec_dir != '/' && exec_dir[1] != ':') {
162 #else
163 if (*exec_dir != '/') {
164 #endif
165 if (!getcwd(p[i], sizeof(p[i]))) {
166 fprintf(stderr, "git: cannot determine "
167 "current directory: %s\n",
168 strerror(errno));
169 return -1;
171 len = strlen(p[i]);
173 /* Trivial cleanup */
174 while (!strncmp(exec_dir, "./", 2)) {
175 exec_dir += 2;
176 while (*exec_dir == '/')
177 exec_dir++;
180 rc = snprintf(p[i] + len,
181 sizeof(p[i]) - len, "/%s",
182 exec_dir);
183 if (rc < 0 || rc >= sizeof(p[i]) - len) {
184 fprintf(stderr, "git: command name given "
185 "is too long.\n");
186 return -1;
188 } else {
189 if (strlen(exec_dir) + 1 > sizeof(p[i])) {
190 fprintf(stderr, "git: command name given "
191 "is too long.\n");
192 return -1;
194 strcpy(p[i], exec_dir);
196 *up++ = p[i];
198 *up = NULL;
200 rc = snprintf(cmd, sizeof(cmd), "git-%s", argv[0]);
201 if (rc < 0 || rc >= sizeof(cmd)) {
202 fprintf(stderr,
203 "git: command name given is too long.\n");
204 return -1;
207 /* argv[0] must be the git command, but the argv array
208 * belongs to the caller. Save argv[0] and
209 * restore it later.
212 tmp = argv[0];
213 argv[0] = cmd;
215 trace_argv_printf(argv, -1, "trace: exec:");
217 pid = spawnvppe_pipe(cmd, argv, environ, usedpaths,
218 pin, pout);
220 argv[0] = tmp;
221 return pid;