@matheusbsbs / matheus-bagliano / commits / ba26f296f9
Fork 0

Windows: Implement start_command().

On Windows, we have spawnv() variants to run a child process instead of fork()/exec(). In order to attach pipe ends to stdin, stdout, and stderr, we have to use this idiom: save1 = dup(1); dup2(pipe[1], 1); spawnv(); dup2(save1, 1); close(pipe[1]); assuming that the descriptors created by pipe() are not inheritable. Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

Johannes Sixt committed Dec 7, 2007 at 22:08 UTC ba26f296f9ddc694fc42683132bc328dffd777ec
3 files changed +153 -14
compat/mingw.c
+62
@@ -315,6 +315,68 @@ void mingw_execvp(const char *cmd, char *const *argv)
315 free_path_split(path);
316 }
317
318 +char **copy_environ()
319 +{
320 + char **env;
321 + int i = 0;
322 + while (environ[i])
323 + i++;
324 + env = xmalloc((i+1)*sizeof(*env));
325 + for (i = 0; environ[i]; i++)
326 + env[i] = xstrdup(environ[i]);
327 + env[i] = NULL;
328 + return env;
329 +}
330 +
331 +void free_environ(char **env)
332 +{
333 + int i;
334 + for (i = 0; env[i]; i++)
335 + free(env[i]);
336 + free(env);
337 +}
338 +
339 +static int lookup_env(char **env, const char *name, size_t nmln)
340 +{
341 + int i;
342 +
343 + for (i = 0; env[i]; i++) {
344 + if (0 == strncmp(env[i], name, nmln)
345 + && '=' == env[i][nmln])
346 + /* matches */
347 + return i;
348 + }
349 + return -1;
350 +}
351 +
352 +/*
353 + * If name contains '=', then sets the variable, otherwise it unsets it
354 + */
355 +char **env_setenv(char **env, const char *name)
356 +{
357 + char *eq = strchrnul(name, '=');
358 + int i = lookup_env(env, name, eq-name);
359 +
360 + if (i < 0) {
361 + if (*eq) {
362 + for (i = 0; env[i]; i++)
363 + ;
364 + env = xrealloc(env, (i+2)*sizeof(*env));
365 + env[i] = xstrdup(name);
366 + env[i+1] = NULL;
367 + }
368 + }
369 + else {
370 + free(env[i]);
371 + if (*eq)
372 + env[i] = xstrdup(name);
373 + else
374 + for (; env[i]; i++)
375 + env[i] = env[i+1];
376 + }
377 + return env;
378 +}
379 +
380 #undef rename
381 int mingw_rename(const char *pold, const char *pnew)
382 {
compat/mingw.h
+8
@@ -165,3 +165,11 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler);
165 #define is_dir_sep(c) ((c) == '/' || (c) == '\\')
166 #define PATH_SEP ';'
167 #define PRIuMAX "I64u"
168 +
169 +/*
170 + * helpers
171 + */
172 +
173 +char **copy_environ(void);
174 +void free_environ(char **env);
175 +char **env_setenv(char **env, const char *name);
run-command.c
+83 -14
@@ -65,21 +65,8 @@ int start_command(struct child_process *cmd)
65 cmd->err = fderr[0];
66 }
67
68 +#ifndef __MINGW32__
69 cmd->pid = fork();
69 - if (cmd->pid < 0) {
70 - if (need_in)
71 - close_pair(fdin);
72 - else if (cmd->in)
73 - close(cmd->in);
74 - if (need_out)
75 - close_pair(fdout);
76 - else if (cmd->out)
77 - close(cmd->out);
78 - if (need_err)
79 - close_pair(fderr);
80 - return -ERR_RUN_COMMAND_FORK;
81 - }
82 -
70 if (!cmd->pid) {
71 if (cmd->no_stdin)
72 dup_devnull(0);
@@ -128,6 +115,88 @@ int start_command(struct child_process *cmd)
115 }
116 die("exec %s failed.", cmd->argv[0]);
117 }
118 +#else
119 + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
120 + const char *sargv0 = cmd->argv[0];
121 + char **env = environ;
122 + struct strbuf git_cmd;
123 +
124 + if (cmd->no_stdin) {
125 + s0 = dup(0);
126 + dup_devnull(0);
127 + } else if (need_in) {
128 + s0 = dup(0);
129 + dup2(fdin[0], 0);
130 + } else if (cmd->in) {
131 + s0 = dup(0);
132 + dup2(cmd->in, 0);
133 + }
134 +
135 + if (cmd->no_stderr) {
136 + s2 = dup(2);
137 + dup_devnull(2);
138 + } else if (need_err) {
139 + s2 = dup(2);
140 + dup2(fderr[1], 2);
141 + }
142 +
143 + if (cmd->no_stdout) {
144 + s1 = dup(1);
145 + dup_devnull(1);
146 + } else if (cmd->stdout_to_stderr) {
147 + s1 = dup(1);
148 + dup2(2, 1);
149 + } else if (need_out) {
150 + s1 = dup(1);
151 + dup2(fdout[1], 1);
152 + } else if (cmd->out > 1) {
153 + s1 = dup(1);
154 + dup2(cmd->out, 1);
155 + }
156 +
157 + if (cmd->dir)
158 + die("chdir in start_command() not implemented");
159 + if (cmd->env) {
160 + env = copy_environ();
161 + for (; *cmd->env; cmd->env++)
162 + env = env_setenv(env, *cmd->env);
163 + }
164 +
165 + if (cmd->git_cmd) {
166 + strbuf_init(&git_cmd, 0);
167 + strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]);
168 + cmd->argv[0] = git_cmd.buf;
169 + }
170 +
171 + cmd->pid = spawnvpe(_P_NOWAIT, cmd->argv[0], cmd->argv, (const char **)env);
172 +
173 + if (cmd->env)
174 + free_environ(env);
175 + if (cmd->git_cmd)
176 + strbuf_release(&git_cmd);
177 +
178 + cmd->argv[0] = sargv0;
179 + if (s0 >= 0)
180 + dup2(s0, 0), close(s0);
181 + if (s1 >= 0)
182 + dup2(s1, 1), close(s1);
183 + if (s2 >= 0)
184 + dup2(s2, 2), close(s2);
185 +#endif
186 +
187 + if (cmd->pid < 0) {
188 + if (need_in)
189 + close_pair(fdin);
190 + else if (cmd->in)
191 + close(cmd->in);
192 + if (need_out)
193 + close_pair(fdout);
194 + else if (cmd->out)
195 + close(cmd->out);
196 + if (need_err)
197 + close_pair(fderr);
198 + return -ERR_RUN_COMMAND_FORK;
199 + }
200
201 if (need_in)
202 close(fdin[0]);