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]);