Enable the spawn workhorse function to spawn shell scripts.
[git/mingw.git] / spawn-pipe.c
blob53a1487d32cc1f8b8f001984b00ab8ac8fd5ef26
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 * Determines the absolute path of cmd based on the PATH environment variable.
22 * If cmd contains a slash or backslash, no lookup is performed.
24 static char *path_lookup(const char *cmd)
26 char *p, *envpath = getenv("PATH");
27 char *prog = NULL;
28 int len = strlen(cmd);
29 int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe");
31 if (strchr(cmd, '/') || strchr(cmd, '\\') ||
32 !envpath || !*envpath)
33 envpath = "";
34 envpath = xstrdup(envpath);
35 p = envpath;
36 while (p && !prog) {
37 const char *dir = p;
38 p = strchr(p, ';');
39 if (p) *p++ = '\0';
40 if (*dir)
41 prog = lookup_prog(dir, cmd, tryexe);
43 free(envpath);
44 if (!prog) {
45 prog = lookup_prog(".", cmd, tryexe);
46 if (!prog)
47 prog = xstrdup(cmd);
49 return prog;
51 #endif
53 /* cmd specifies the command to invoke.
54 * argv specifies its arguments; argv[0] will be replaced by the basename of cmd.
55 * env specifies the environment.
56 * pin and pout specify pipes; the read end of pin is made the standard input
57 * of the spawned process, and the write end of pout is mad the standard output.
58 * The respective unused ends of the pipes are closed both in the parent
59 * process as well as in the child process.
60 * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to
61 * indicate that no processing shall occur.
63 int spawnvpe_pipe(const char *cmd, const char **argv, const char **env,
64 int pin[], int pout[])
66 const char *cmd_basename = strrchr(cmd, '/');
67 pid_t pid;
69 #ifdef __MINGW32__
70 int s0 = -1, s1 = -1, argc;
71 char *prog;
72 const char **qargv, *interpr;
74 if (!cmd_basename)
75 cmd_basename = strrchr(cmd, '\\');
76 #endif
78 if (!cmd_basename)
79 cmd_basename = cmd;
80 else
81 cmd_basename++;
82 argv[0] = cmd_basename;
84 #ifndef __MINGW32__
85 pid = fork();
86 if (pid < 0)
87 die("unable to fork");
88 if (!pid) {
89 if (pin) {
90 if (pin[0] >= 0) {
91 dup2(pin[0], 0);
92 close(pin[0]);
94 if (pin[1] >= 0)
95 close(pin[1]);
97 if (pout) {
98 if (pout[1] >= 0) {
99 dup2(pout[1], 1);
100 close(pout[1]);
102 if (pout[0] >= 0)
103 close(pout[0]);
105 environ = env;
106 execvp(cmd, argv);
107 die("exec failed");
110 if (pin && pin[0] >= 0)
111 close(pin[0]);
112 if (pout && pout[1] >= 1)
113 close(pout[1]);
114 #else
115 if (pin) {
116 if (pin[0] >= 0) {
117 s0 = dup(0);
118 dup2(pin[0], 0);
119 close(pin[0]);
122 if (pout) {
123 if (pout[1] >= 0) {
124 s1 = dup(1);
125 dup2(pout[1], 1);
126 close(pout[1]);
130 prog = path_lookup(cmd);
131 interpr = parse_interpreter(prog);
133 for (argc = 0; argv[argc];) argc++;
134 qargv = xmalloc((argc+2)*sizeof(char*));
135 if (!interpr) {
136 quote_argv(qargv, argv);
137 pid = spawnve(_P_NOWAIT, prog, qargv, env);
138 } else {
139 qargv[0] = interpr;
140 argv[0] = prog;
141 quote_argv(&qargv[1], argv);
142 pid = spawnvpe(_P_NOWAIT, interpr, qargv, env);
145 if (pid < 0)
146 die("unable to run %s", cmd);
148 free(qargv); /* TODO: quoted args should be freed, too */
149 free(prog);
151 if (s0 >= 0) {
152 dup2(s0, 0);
153 close(s0);
155 if (s1 >= 0) {
156 dup2(s1, 1);
157 close(s1);
159 #endif
161 return pid;
164 const char **copy_environ()
166 return copy_env(environ);
169 const char **copy_env(const char **env)
171 const char **s;
172 int n = 1;
173 for (s = env; *s; s++)
174 n++;
175 s = xmalloc(n*sizeof(const char *));
176 memcpy(s, env, n*sizeof(const char *));
177 return s;
180 void env_unsetenv(const char **env, const char *name)
182 int src, dst;
183 size_t nmln;
185 nmln = strlen(name);
187 for (src = dst = 0; env[src]; ++src) {
188 size_t enln;
189 enln = strlen(env[src]);
190 if (enln > nmln) {
191 /* might match, and can test for '=' safely */
192 if (0 == strncmp (env[src], name, nmln)
193 && '=' == env[src][nmln])
194 /* matches, so skip */
195 continue;
197 env[dst] = env[src];
198 ++dst;
200 env[dst] = NULL;