t5701: skip hardlink test
[git/mingw/4msysgit/wingit-dll.git] / spawn-pipe.c
blobe8872dc0ff9ce9aeb3c933caced9c67d9143e5d1
1 #include "git-compat-util.h"
2 #include "spawn-pipe.h"
4 #ifdef __MINGW32__
5 static char *lookup_prog(const char *dir, const char *cmd, int tryexe)
7 char path[MAX_PATH];
8 snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
10 if (tryexe && access(path, 0) == 0)
11 return xstrdup(path);
12 path[strlen(path)-4] = '\0';
13 if (access(path, 0) == 0)
14 return xstrdup(path);
15 return NULL;
19 * Splits the PATH into parts.
21 char **get_path_split()
23 char *p, **path, *envpath = getenv("PATH");
24 int i, n = 0;
26 if (!envpath || !*envpath)
27 return NULL;
29 envpath = xstrdup(envpath);
30 p = envpath;
31 while (p) {
32 char *dir = p;
33 p = strchr(p, ';');
34 if (p) *p++ = '\0';
35 if (*dir) { /* not earlier, catches series of ; */
36 ++n;
39 if (!n)
40 return NULL;
42 path = xmalloc((n+1)*sizeof(char*));
43 p = envpath;
44 i = 0;
45 do {
46 if (*p)
47 path[i++] = xstrdup(p);
48 p = p+strlen(p)+1;
49 } while (i < n);
50 path[i] = NULL;
52 free(envpath);
54 return path;
57 void free_path_split(char **path)
59 if (!path)
60 return;
62 char **p = path;
63 while (*p)
64 free(*p++);
65 free(path);
69 * Determines the absolute path of cmd using the the split path in path.
70 * If cmd contains a slash or backslash, no lookup is performed.
72 static char *path_lookup(const char *cmd, char **path)
74 char **p = path;
75 char *prog = NULL;
76 int len = strlen(cmd);
77 int tryexe = len < 4 || strcasecmp(cmd+len-4, ".exe");
79 if (strchr(cmd, '/') || strchr(cmd, '\\'))
80 prog = xstrdup(cmd);
82 while (!prog && *p) {
83 prog = lookup_prog(*p++, cmd, tryexe);
85 if (!prog) {
86 prog = lookup_prog(".", cmd, tryexe);
87 if (!prog)
88 prog = xstrdup(cmd);
90 return prog;
92 #endif
94 /* cmd specifies the command to invoke.
95 * argv specifies its arguments; argv[0] will be replaced by the basename of cmd.
96 * env specifies the environment.
97 * pin and pout specify pipes; the read end of pin is made the standard input
98 * of the spawned process, and the write end of pout is mad the standard output.
99 * The respective unused ends of the pipes are closed both in the parent
100 * process as well as in the child process.
101 * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to
102 * indicate that no processing shall occur.
104 int spawnvpe_pipe(const char *cmd, const char **argv, const char **env,
105 int pin[], int pout[])
107 #ifdef __MINGW32__
108 char **path = get_path_split();
110 pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout);
112 free_path_split(path);
113 #else
114 pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout);
115 #endif
116 return pid;
119 int spawnvppe_pipe(const char *cmd, const char **argv, const char **env,
120 char **path,
121 int pin[], int pout[])
123 const char *cmd_basename = strrchr(cmd, '/');
124 pid_t pid;
126 #ifdef __MINGW32__
127 int s0 = -1, s1 = -1, argc;
128 char *prog;
129 const char **qargv, *interpr;
131 if (!cmd_basename)
132 cmd_basename = strrchr(cmd, '\\');
133 #endif
135 if (!cmd_basename)
136 cmd_basename = cmd;
137 else
138 cmd_basename++;
139 argv[0] = cmd_basename;
141 #ifndef __MINGW32__
142 pid = fork();
143 if (pid < 0)
144 die("unable to fork");
145 if (!pid) {
146 if (pin) {
147 if (pin[0] >= 0) {
148 dup2(pin[0], 0);
149 close(pin[0]);
151 if (pin[1] >= 0)
152 close(pin[1]);
154 if (pout) {
155 if (pout[1] >= 0) {
156 dup2(pout[1], 1);
157 close(pout[1]);
159 if (pout[0] >= 0)
160 close(pout[0]);
162 environ = env;
163 execvp(cmd, argv);
164 die("exec failed");
167 if (pin && pin[0] >= 0)
168 close(pin[0]);
169 if (pout && pout[1] >= 1)
170 close(pout[1]);
171 #else
172 if (pin) {
173 if (pin[0] >= 0) {
174 s0 = dup(0);
175 dup2(pin[0], 0);
176 close(pin[0]);
179 if (pout) {
180 if (pout[1] >= 0) {
181 s1 = dup(1);
182 dup2(pout[1], 1);
183 close(pout[1]);
187 prog = path_lookup(cmd, path);
188 interpr = parse_interpreter(prog);
190 for (argc = 0; argv[argc];) argc++;
191 qargv = xmalloc((argc+2)*sizeof(char*));
192 if (!interpr) {
193 quote_argv(qargv, argv);
194 pid = spawnve(_P_NOWAIT, prog, qargv, (const char**) env);
195 } else {
196 qargv[0] = interpr;
197 argv[0] = prog;
198 quote_argv(&qargv[1], argv);
199 pid = spawnvpe(_P_NOWAIT, interpr, qargv, env);
202 free(qargv); /* TODO: quoted args should be freed, too */
203 free(prog);
205 if (s0 >= 0) {
206 dup2(s0, 0);
207 close(s0);
209 if (s1 >= 0) {
210 dup2(s1, 1);
211 close(s1);
213 #endif
215 return pid;
218 const char **copy_environ()
220 return copy_env( (const char**)environ);
223 const char **copy_env(const char **env)
225 const char **s;
226 int n = 1;
227 for (s = env; *s; s++)
228 n++;
229 s = xmalloc(n*sizeof(const char *));
230 memcpy(s, env, n*sizeof(const char *));
231 return s;
234 void env_unsetenv(const char **env, const char *name)
236 int src, dst;
237 size_t nmln;
239 nmln = strlen(name);
241 for (src = dst = 0; env[src]; ++src) {
242 size_t enln;
243 enln = strlen(env[src]);
244 if (enln > nmln) {
245 /* might match, and can test for '=' safely */
246 if (0 == strncmp (env[src], name, nmln)
247 && '=' == env[src][nmln])
248 /* matches, so skip */
249 continue;
251 env[dst] = env[src];
252 ++dst;
254 env[dst] = NULL;