Reimplement rename()
[git/pclouds.git] / spawn-pipe.c
blobc3223f3ce479788f8e32981ced50b612d163e14a
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 const char *argv0 = argv[0];
127 pid_t pid;
129 #ifdef __MINGW32__
130 int s0 = -1, s1 = -1, argc;
131 char *prog;
132 const char **qargv, *interpr;
134 if (!cmd_basename)
135 cmd_basename = strrchr(cmd, '\\');
136 #endif
138 if (!cmd_basename)
139 cmd_basename = cmd;
140 else
141 cmd_basename++;
142 argv[0] = cmd_basename;
144 #ifndef __MINGW32__
145 pid = fork();
146 if (pid < 0)
147 die("unable to fork");
148 if (!pid) {
149 if (pin) {
150 if (pin[0] >= 0) {
151 dup2(pin[0], 0);
152 close(pin[0]);
154 if (pin[1] >= 0)
155 close(pin[1]);
157 if (pout) {
158 if (pout[1] >= 0) {
159 dup2(pout[1], 1);
160 close(pout[1]);
162 if (pout[0] >= 0)
163 close(pout[0]);
165 environ = env;
166 execvp(cmd, argv);
167 die("exec failed");
170 if (pin && pin[0] >= 0)
171 close(pin[0]);
172 if (pout && pout[1] >= 1)
173 close(pout[1]);
174 #else
175 if (pin) {
176 if (pin[0] >= 0) {
177 s0 = dup(0);
178 dup2(pin[0], 0);
179 close(pin[0]);
182 if (pout) {
183 if (pout[1] >= 0) {
184 s1 = dup(1);
185 dup2(pout[1], 1);
186 close(pout[1]);
190 prog = path_lookup(cmd, path);
191 interpr = parse_interpreter(prog);
193 for (argc = 0; argv[argc];) argc++;
194 qargv = xmalloc((argc+3)*sizeof(char*));
195 if (!interpr) {
196 quote_argv(qargv, argv);
197 pid = spawnve(_P_NOWAIT, prog, qargv, env);
198 } else {
199 if (!strcmp(interpr, "sh")) {
200 qargv[0] = "box";
201 qargv[1] = "sh";
202 argv[0] = prog;
203 memcpy(&qargv[2], argv, (argc+1)*sizeof(char*));
204 pid = spawnve_git_cmd(qargv, NULL, NULL, env);
205 } else {
206 qargv[0] = interpr;
207 argv[0] = prog;
208 quote_argv(&qargv[1], argv);
209 pid = spawnvpe(_P_NOWAIT, interpr, qargv, env);
213 free(qargv); /* TODO: quoted args should be freed, too */
214 free(prog);
216 if (s0 >= 0) {
217 dup2(s0, 0);
218 close(s0);
220 if (s1 >= 0) {
221 dup2(s1, 1);
222 close(s1);
224 #endif
226 argv[0] = argv0;
228 return pid;
231 const char **copy_environ()
233 return copy_env(environ);
236 const char **copy_env(const char **env)
238 const char **s;
239 int n = 1;
240 for (s = env; *s; s++)
241 n++;
242 s = xmalloc(n*sizeof(const char *));
243 memcpy(s, env, n*sizeof(const char *));
244 return s;
247 void env_unsetenv(const char **env, const char *name)
249 int src, dst;
250 size_t nmln;
252 nmln = strlen(name);
254 for (src = dst = 0; env[src]; ++src) {
255 size_t enln;
256 enln = strlen(env[src]);
257 if (enln > nmln) {
258 /* might match, and can test for '=' safely */
259 if (0 == strncmp (env[src], name, nmln)
260 && '=' == env[src][nmln])
261 /* matches, so skip */
262 continue;
264 env[dst] = env[src];
265 ++dst;
267 env[dst] = NULL;