Merge commit '7c851733e4bc2b36bd9df63cab2fe11180242670'
[git/dscho.git] / spawn-pipe.c
blobc8f04528237e4e940ef4cd57d3235c3c33448977
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 prog = xstrdup(cmd);
84 while (!prog && *p) {
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 #ifdef __MINGW32__
110 char **path = get_path_split();
112 pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout);
114 free_path_split(path);
115 #else
116 pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout);
117 #endif
118 return pid;
121 int spawnvppe_pipe(const char *cmd, const char **argv, const char **env,
122 char **path,
123 int pin[], int pout[])
125 const char *cmd_basename = strrchr(cmd, '/');
126 pid_t pid;
128 #ifdef __MINGW32__
129 int s0 = -1, s1 = -1, argc;
130 char *prog;
131 const char **qargv, *interpr;
133 if (!cmd_basename)
134 cmd_basename = strrchr(cmd, '\\');
135 #endif
137 if (!cmd_basename)
138 cmd_basename = cmd;
139 else
140 cmd_basename++;
141 argv[0] = cmd_basename;
143 #ifndef __MINGW32__
144 pid = fork();
145 if (pid < 0)
146 die("unable to fork");
147 if (!pid) {
148 if (pin) {
149 if (pin[0] >= 0) {
150 dup2(pin[0], 0);
151 close(pin[0]);
153 if (pin[1] >= 0)
154 close(pin[1]);
156 if (pout) {
157 if (pout[1] >= 0) {
158 dup2(pout[1], 1);
159 close(pout[1]);
161 if (pout[0] >= 0)
162 close(pout[0]);
164 environ = env;
165 execvp(cmd, argv);
166 die("exec failed");
169 if (pin && pin[0] >= 0)
170 close(pin[0]);
171 if (pout && pout[1] >= 1)
172 close(pout[1]);
173 #else
174 if (pin) {
175 if (pin[0] >= 0) {
176 s0 = dup(0);
177 dup2(pin[0], 0);
178 close(pin[0]);
181 if (pout) {
182 if (pout[1] >= 0) {
183 s1 = dup(1);
184 dup2(pout[1], 1);
185 close(pout[1]);
189 prog = path_lookup(cmd, path);
190 interpr = parse_interpreter(prog);
192 for (argc = 0; argv[argc];) argc++;
193 qargv = xmalloc((argc+2)*sizeof(char*));
194 if (!interpr) {
195 quote_argv(qargv, argv);
196 pid = spawnve(_P_NOWAIT, prog, qargv, env);
197 } else {
198 qargv[0] = interpr;
199 argv[0] = prog;
200 quote_argv(&qargv[1], argv);
201 pid = spawnvpe(_P_NOWAIT, interpr, qargv, env);
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;