Split PATH into parts in advance, and pass the result to the new spawnvppe_pipe.
[git/mingw.git] / spawn-pipe.c
blobb82880982001174c6fdefd290562d18b0ccf4347
1 #include "git-compat-util.h"
2 #include "spawn-pipe.h"
4 extern char **environ;
6 #ifdef __MINGW32__
7 static char *lookup_prog(const char *dir, const char *cmd, int tryexe)
9 char path[MAX_PATH];
10 snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
12 if (tryexe && access(path, 0) == 0)
13 return xstrdup(path);
14 path[strlen(path)-4] = '\0';
15 if (access(path, 0) == 0)
16 return xstrdup(path);
17 return NULL;
21 * Splits the PATH into parts.
23 char **get_path_split()
25 char *p, **path, *envpath = getenv("PATH");
26 int i, n = 0;
28 if (!envpath || !*envpath)
29 return NULL;
31 envpath = xstrdup(envpath);
32 p = envpath;
33 while (p) {
34 char *dir = p;
35 p = strchr(p, ';');
36 if (p) *p++ = '\0';
37 if (*dir) { /* not earlier, catches series of ; */
38 ++n;
41 if (!n)
42 return NULL;
44 path = xmalloc((n+1)*sizeof(char*));
45 p = envpath;
46 i = 0;
47 do {
48 if (*p)
49 path[i++] = xstrdup(p);
50 p = p+strlen(p)+1;
51 } while (i < n);
52 path[i] = NULL;
54 free(envpath);
56 return path;
59 void free_path_split(char **path)
61 if (!path)
62 return;
64 char **p = path;
65 while (*p)
66 free(*p++);
67 free(path);
71 * Determines the absolute path of cmd using the the split path in path.
72 * If cmd contains a slash or backslash, no lookup is performed.
74 static char *path_lookup(const char *cmd, char **path)
76 char **p = path;
77 char *prog = NULL;
78 int len = strlen(cmd);
79 int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe");
81 if (strchr(cmd, '/') || strchr(cmd, '\\'))
82 p = NULL;
84 while (*p && !prog) {
85 prog = lookup_prog(*p++, cmd, tryexe);
87 if (!prog) {
88 prog = lookup_prog(".", cmd, tryexe);
89 if (!prog)
90 prog = xstrdup(cmd);
92 return prog;
94 #endif
96 /* cmd specifies the command to invoke.
97 * argv specifies its arguments; argv[0] will be replaced by the basename of cmd.
98 * env specifies the environment.
99 * pin and pout specify pipes; the read end of pin is made the standard input
100 * of the spawned process, and the write end of pout is mad the standard output.
101 * The respective unused ends of the pipes are closed both in the parent
102 * process as well as in the child process.
103 * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to
104 * indicate that no processing shall occur.
106 int spawnvpe_pipe(const char *cmd, const char **argv, const char **env,
107 int pin[], int pout[])
109 char **path = get_path_split();
111 pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout);
113 free_path_split(path);
115 return pid;
118 int spawnvppe_pipe(const char *cmd, const char **argv, const char **env,
119 char **path,
120 int pin[], int pout[])
122 const char *cmd_basename = strrchr(cmd, '/');
123 pid_t pid;
125 #ifdef __MINGW32__
126 int s0 = -1, s1 = -1, argc;
127 char *prog;
128 const char **qargv, *interpr;
130 if (!cmd_basename)
131 cmd_basename = strrchr(cmd, '\\');
132 #endif
134 if (!cmd_basename)
135 cmd_basename = cmd;
136 else
137 cmd_basename++;
138 argv[0] = cmd_basename;
140 #ifndef __MINGW32__
141 pid = fork();
142 if (pid < 0)
143 die("unable to fork");
144 if (!pid) {
145 if (pin) {
146 if (pin[0] >= 0) {
147 dup2(pin[0], 0);
148 close(pin[0]);
150 if (pin[1] >= 0)
151 close(pin[1]);
153 if (pout) {
154 if (pout[1] >= 0) {
155 dup2(pout[1], 1);
156 close(pout[1]);
158 if (pout[0] >= 0)
159 close(pout[0]);
161 environ = env;
162 execvp(cmd, argv);
163 die("exec failed");
166 if (pin && pin[0] >= 0)
167 close(pin[0]);
168 if (pout && pout[1] >= 1)
169 close(pout[1]);
170 #else
171 if (pin) {
172 if (pin[0] >= 0) {
173 s0 = dup(0);
174 dup2(pin[0], 0);
175 close(pin[0]);
178 if (pout) {
179 if (pout[1] >= 0) {
180 s1 = dup(1);
181 dup2(pout[1], 1);
182 close(pout[1]);
186 prog = path_lookup(cmd, path);
187 interpr = parse_interpreter(prog);
189 for (argc = 0; argv[argc];) argc++;
190 qargv = xmalloc((argc+2)*sizeof(char*));
191 if (!interpr) {
192 quote_argv(qargv, argv);
193 pid = spawnve(_P_NOWAIT, prog, qargv, env);
194 } else {
195 qargv[0] = interpr;
196 argv[0] = prog;
197 quote_argv(&qargv[1], argv);
198 pid = spawnvpe(_P_NOWAIT, interpr, qargv, env);
201 if (pid < 0)
202 die("unable to run %s", cmd);
204 free(qargv); /* TODO: quoted args should be freed, too */
205 free(prog);
207 if (s0 >= 0) {
208 dup2(s0, 0);
209 close(s0);
211 if (s1 >= 0) {
212 dup2(s1, 1);
213 close(s1);
215 #endif
217 return pid;
220 const char **copy_environ()
222 return copy_env(environ);
225 const char **copy_env(const char **env)
227 const char **s;
228 int n = 1;
229 for (s = env; *s; s++)
230 n++;
231 s = xmalloc(n*sizeof(const char *));
232 memcpy(s, env, n*sizeof(const char *));
233 return s;
236 void env_unsetenv(const char **env, const char *name)
238 int src, dst;
239 size_t nmln;
241 nmln = strlen(name);
243 for (src = dst = 0; env[src]; ++src) {
244 size_t enln;
245 enln = strlen(env[src]);
246 if (enln > nmln) {
247 /* might match, and can test for '=' safely */
248 if (0 == strncmp (env[src], name, nmln)
249 && '=' == env[src][nmln])
250 /* matches, so skip */
251 continue;
253 env[dst] = env[src];
254 ++dst;
256 env[dst] = NULL;