Add always-available Git Bash menu item
[git-cheetah/kirill.git] / exec.c
blobd484453bab3e9cd8252ee4259f23ab1cd8a5233a
1 #include "cache.h"
3 #include "debug.h"
4 #include "systeminfo.h"
5 #include "exec.h"
7 #define MAX_PROCESSING_TIME (60 * 1000)
8 #define MAX_ARGS 32
11 * builds an array of environment variables,
12 * as expected by mingw_spawnvpe
14 static char **env_for_git()
16 static char **environment;
19 * if we can't find path to msys in the registry, return NULL and
20 * the CreateProcess will copy the environment for us
22 if (!environment && msys_path()) {
23 char *old = GetEnvironmentStrings();
24 size_t space = 0, path_index = -1, name_len = 0;
25 int total = 0, i;
27 while (old[space]) {
28 /* if it's PATH variable (could be Path= too!) */
29 if (!strnicmp(old + space, "PATH=", 5)) {
30 path_index = space;
31 name_len = 5;
34 while (old[space])
35 space++;
36 space++; /* skip var-terminating NULL */
38 total++;
41 if (path_index == -1)
42 path_index = space;
44 environment = malloc(sizeof(*environment) * (total + 1));
45 space = 0;
46 for (i = 0; i < total; i++) {
47 if (path_index == space) {
48 char *path = old + space + name_len;
49 size_t len;
50 environment[i] = malloc(strlen(path) + 1 +
51 2 * strlen(msys_path()) + 32);
52 len = sprintf(environment[i],
53 "PATH=%s\\bin;%s\\mingw\\bin%s%s",
54 msys_path(), msys_path(),
55 *path ? ";" : "", path);
56 } else
57 environment[i] = strdup(old + space);
59 while (old[space])
60 space++;
61 space++; /* skip var-terminating NULL */
64 /* mark the end of the array */
65 environment[i] = 0;
67 FreeEnvironmentStrings(old);
70 return environment;
73 /* copy from run-command.c */
74 static inline void close_pair(int fd[2])
76 close(fd[0]);
77 close(fd[1]);
80 int exec_program(const char *working_directory,
81 struct strbuf *output, struct strbuf *error_output,
82 int flags, ...)
84 int fdout[2], fderr[2];
85 int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
87 va_list params;
88 const char *argv[MAX_ARGS];
89 char *arg;
90 int argc = 0;
92 pid_t pid;
93 DWORD status = 0;
95 reporter *debug = QUIETMODE & flags ? debug_git : debug_git_mbox;
97 if (!msys_path()) {
98 debug("[ERROR] Could not find msysPath");
99 return -1;
102 if (output) {
103 if (pipe(fdout) < 0) {
104 return -ERR_RUN_COMMAND_PIPE;
106 s1 = dup(1);
107 dup2(fdout[1], 1);
109 flags |= WAITMODE;
112 if (error_output) {
113 if (pipe(fderr) < 0) {
114 if (output)
115 close_pair(fdout);
116 return -ERR_RUN_COMMAND_PIPE;
118 s2 = dup(2);
119 dup2(fderr[1], 2);
121 flags |= WAITMODE;
124 va_start(params, flags);
125 do {
126 arg = va_arg(params, char*);
127 argv[argc++] = arg;
128 } while (argc < MAX_ARGS && arg);
129 va_end(params);
131 pid = mingw_spawnvpe_cwd(argv[0], argv, env_for_git(),
132 working_directory);
134 if (s1 >= 0)
135 dup2(s1, 1), close(s1);
136 if (s2 >= 0)
137 dup2(s2, 2), close(s2);
139 if (pid < 0) {
140 if (output)
141 close_pair(fdout);
142 if (error_output)
143 close_pair(fderr);
144 return -ERR_RUN_COMMAND_FORK;
147 if (output)
148 close(fdout[1]);
149 if (error_output)
150 close(fderr[1]);
152 if (WAITMODE & flags) {
153 if (WAIT_OBJECT_0 == WaitForSingleObject((HANDLE)pid,
154 MAX_PROCESSING_TIME)) {
155 if (GetExitCodeProcess((HANDLE)pid, &status))
156 debug_git("Exit code: %d", status);
157 else {
158 /* play safe, and return total failure */
159 status = -1;
160 debug_git("[ERROR] GetExitCode failed (%d); "
161 "wd: %s; cmd: %s",
162 GetLastError(),
163 working_directory,
164 argv[0]);
167 if (output) {
168 strbuf_read(output, fdout[0], 0);
169 debug_git("STDOUT:\r\n%s\r\n*** end of STDOUT ***\r\n", output->buf);
172 if (error_output) {
173 strbuf_read(error_output, fderr[0], 0);
174 debug_git("STDERR:\r\n%s\r\n*** end of STDERR ***\r\n", error_output->buf);
176 } else {
177 status = -ERR_RUN_COMMAND_WAITPID_NOEXIT;
178 debug_git("[ERROR] process timed out; "
179 "wd: %s; cmd: %s",
180 working_directory, argv[0]);
184 if (output)
185 close(fdout[0]);
186 if (error_output)
187 close(fderr[0]);
189 return status;