1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22: #include "pex-common.h"
23:
24: #include <windows.h>
25:
26: #ifdef HAVE_STDLIB_H
27: #include <stdlib.h>
28: #endif
29: #ifdef HAVE_STRING_H
30: #include <string.h>
31: #endif
32: #ifdef HAVE_UNISTD_H
33: #include <unistd.h>
34: #endif
35: #ifdef HAVE_SYS_WAIT_H
36: #include <sys/wait.h>
37: #endif
38:
39: #include <assert.h>
40: #include <process.h>
41: #include <io.h>
42: #include <fcntl.h>
43: #include <signal.h>
44: #include <sys/stat.h>
45: #include <errno.h>
46: #include <ctype.h>
47:
48:
49:
50: #ifndef _P_WAIT
51: # define _P_WAIT 0
52: # define _P_NOWAIT 1
53: # define _P_OVERLAY 2
54: # define _P_NOWAITO 3
55: # define _P_DETACH 4
56:
57: # define WAIT_CHILD 0
58: # define WAIT_GRANDCHILD 1
59: #endif
60:
61: #define MINGW_NAME "Minimalist GNU for Windows"
62: #define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
63:
64: extern char *stpcpy (char *dst, const char *src);
65:
66:
67:
68:
69:
70:
71:
72: static void
73: backslashify (char *s)
74: {
75: while ((s = strchr (s, '/')) != NULL)
76: *s = '\\';
77: return;
78: }
79:
80: static int pex_win32_open_read (struct pex_obj *, const char *, int);
81: static int pex_win32_open_write (struct pex_obj *, const char *, int);
82: static long pex_win32_exec_child (struct pex_obj *, int, const char *,
83: char * const *, char * const *,
84: int, int, int, int,
85: const char **, int *);
86: static int pex_win32_close (struct pex_obj *, int);
87: static int pex_win32_wait (struct pex_obj *, long, int *,
88: struct pex_time *, int, const char **, int *);
89: static int pex_win32_pipe (struct pex_obj *, int *, int);
90: static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
91: static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
92:
93:
94:
95: const struct pex_funcs funcs =
96: {
97: pex_win32_open_read,
98: pex_win32_open_write,
99: pex_win32_exec_child,
100: pex_win32_close,
101: pex_win32_wait,
102: pex_win32_pipe,
103: pex_win32_fdopenr,
104: pex_win32_fdopenw,
105: NULL
106: };
107:
108:
109:
110: struct pex_obj *
111: pex_init (int flags, const char *pname, const char *tempbase)
112: {
113: return pex_init_common (flags, pname, tempbase, &funcs);
114: }
115:
116:
117:
118: static int
119: pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
120: int binary)
121: {
122: return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
123: }
124:
125:
126:
127: static int
128: pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
129: int binary)
130: {
131:
132:
133: return _open (name,
134: (_O_WRONLY | _O_CREAT | _O_TRUNC
135: | (binary ? _O_BINARY : _O_TEXT)),
136: _S_IREAD | _S_IWRITE);
137: }
138:
139:
140:
141: static int
142: pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
143: {
144: return _close (fd);
145: }
146:
147: #ifdef USE_MINGW_MSYS
148: static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
149:
150:
151:
152: static const char *
153: tack_on_executable (char *buf, const char *executable)
154: {
155: char *p = strchr (buf, '\0');
156: if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
157: p[-1] = '\0';
158: backslashify (strcat (buf, executable));
159: return buf;
160: }
161:
162:
163: static HKEY
164: openkey (HKEY hStart, const char *keys[])
165: {
166: HKEY hKey, hTmp;
167: for (hKey = hStart; *keys; keys++)
168: {
169: LONG res;
170: hTmp = hKey;
171: res = RegOpenKey (hTmp, *keys, &hKey);
172:
173: if (hTmp != HKEY_LOCAL_MACHINE)
174: RegCloseKey (hTmp);
175:
176: if (res != ERROR_SUCCESS)
177: return NULL;
178: }
179: return hKey;
180: }
181:
182:
183: static const char *
184: mingw_rootify (const char *executable)
185: {
186: HKEY hKey, hTmp;
187: DWORD maxlen;
188: char *namebuf, *foundbuf;
189: DWORD i;
190: LONG res;
191:
192:
193: hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
194:
195:
196: if (!hKey)
197: return executable;
198:
199:
200:
201: if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
202: NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
203: {
204: RegCloseKey (hKey);
205: return executable;
206: }
207: namebuf = XNEWVEC (char, ++maxlen);
208: foundbuf = XNEWVEC (char, maxlen);
209: foundbuf[0] = '\0';
210: if (!namebuf || !foundbuf)
211: {
212: RegCloseKey (hKey);
213: if (namebuf)
214: free (namebuf);
215: if (foundbuf)
216: free (foundbuf);
217: return executable;
218: }
219:
220:
221:
222:
223: for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
224: {
225: int match = strcasecmp (namebuf, MINGW_NAME);
226: if (match < 0)
227: continue;
228: if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
229: continue;
230: if (strcasecmp (namebuf, foundbuf) > 0)
231: strcpy (foundbuf, namebuf);
232: }
233: free (namebuf);
234:
235:
236: if (!foundbuf[0])
237: {
238: free (foundbuf);
239: RegCloseKey (hKey);
240: return executable;
241: }
242:
243:
244: res = RegOpenKey (hKey, foundbuf, &hTmp);
245: RegCloseKey (hKey);
246: free (foundbuf);
247:
248:
249: if (res != ERROR_SUCCESS)
250: return executable;
251:
252: maxlen = 0;
253:
254: if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
255: &maxlen) != ERROR_SUCCESS || maxlen == 0)
256: {
257: RegCloseKey (hTmp);
258: return executable;
259: }
260:
261:
262: foundbuf = XNEWVEC (char, maxlen + strlen (executable));
263: if (!foundbuf)
264: {
265: free (foundbuf);
266: RegCloseKey (hTmp);
267: }
268:
269:
270: res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
271: &maxlen);
272: RegCloseKey (hTmp);
273: if (res != ERROR_SUCCESS)
274: {
275: free (foundbuf);
276: return executable;
277: }
278:
279:
280:
281: return tack_on_executable (foundbuf, executable);
282: }
283:
284:
285:
286: static const char *
287: msys_rootify (const char *executable)
288: {
289: size_t bufsize = 64;
290: size_t execlen = strlen (executable) + 1;
291: char *buf;
292: DWORD res = 0;
293: for (;;)
294: {
295: buf = XNEWVEC (char, bufsize + execlen);
296: if (!buf)
297: break;
298: res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
299: buf, bufsize, "msys.ini");
300: if (!res)
301: break;
302: if (strlen (buf) < bufsize)
303: break;
304: res = 0;
305: free (buf);
306: bufsize *= 2;
307: if (bufsize > 65536)
308: {
309: buf = NULL;
310: break;
311: }
312: }
313:
314: if (res)
315: return tack_on_executable (buf, executable);
316:
317:
318: if (buf)
319: free (buf);
320: return executable;
321: }
322: #endif
323:
324:
325:
326:
327: static char *
328: argv_to_cmdline (char *const *argv)
329: {
330: char *cmdline;
331: char *p;
332: size_t cmdline_len;
333: int i, j, k;
334:
335: cmdline_len = 0;
336: for (i = 0; argv[i]; i++)
337: {
338:
339:
340:
341:
342:
343: for (j = 0; argv[i][j]; j++)
344: {
345: if (argv[i][j] == '"')
346: {
347:
348: for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
349: cmdline_len++;
350:
351: cmdline_len++;
352: }
353: }
354:
355:
356: for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
357: cmdline_len++;
358: cmdline_len += j;
359: cmdline_len += 3;
360: }
361: cmdline = XNEWVEC (char, cmdline_len);
362: p = cmdline;
363: for (i = 0; argv[i]; i++)
364: {
365: *p++ = '"';
366: for (j = 0; argv[i][j]; j++)
367: {
368: if (argv[i][j] == '"')
369: {
370: for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
371: *p++ = '\\';
372: *p++ = '\\';
373: }
374: *p++ = argv[i][j];
375: }
376: for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
377: *p++ = '\\';
378: *p++ = '"';
379: *p++ = ' ';
380: }
381: p[-1] = '\0';
382: return cmdline;
383: }
384:
385:
386:
387:
388:
389:
390:
391: static const char *const
392: std_suffixes[] = {
393: ".com",
394: ".exe",
395: ".bat",
396: ".cmd",
397: "",
398: 0
399: };
400:
401:
402:
403:
404: static char *
405: find_executable (const char *program, BOOL search)
406: {
407: char *full_executable;
408: char *e;
409: size_t fe_len;
410: const char *path = 0;
411: const char *const *ext;
412: const char *p, *q;
413: size_t proglen = strlen (program);
414: int has_slash = (strchr (program, '/') || strchr (program, '\\'));
415: HANDLE h;
416:
417: if (has_slash)
418: search = FALSE;
419:
420: if (search)
421: path = getenv ("PATH");
422: if (!path)
423: path = "";
424:
425: fe_len = 0;
426: for (p = path; *p; p = q)
427: {
428: q = p;
429: while (*q != ';' && *q != '\0')
430: q++;
431: if ((size_t)(q - p) > fe_len)
432: fe_len = q - p;
433: if (*q == ';')
434: q++;
435: }
436: fe_len = fe_len + 1 + proglen + 5 ;
437: full_executable = XNEWVEC (char, fe_len);
438:
439: p = path;
440: do
441: {
442: q = p;
443: while (*q != ';' && *q != '\0')
444: q++;
445:
446: e = full_executable;
447: memcpy (e, p, q - p);
448: e += (q - p);
449: if (q - p)
450: *e++ = '\\';
451: strcpy (e, program);
452:
453: if (*q == ';')
454: q++;
455:
456: for (e = full_executable; *e; e++)
457: if (*e == '/')
458: *e = '\\';
459:
460:
461:
462: for (ext = std_suffixes; *ext; ext++)
463: {
464:
465: *e = '\0';
466:
467: strcat (full_executable, *ext);
468:
469:
470: h = CreateFile (full_executable, GENERIC_READ,
471: FILE_SHARE_READ | FILE_SHARE_WRITE,
472: 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
473: if (h != INVALID_HANDLE_VALUE)
474: goto found;
475: }
476: p = q;
477: }
478: while (*p);
479: free (full_executable);
480: return 0;
481:
482: found:
483: CloseHandle (h);
484: return full_executable;
485: }
486:
487:
488:
489: static int
490: env_compare (const void *a_ptr, const void *b_ptr)
491: {
492: const char *a;
493: const char *b;
494: unsigned char c1;
495: unsigned char c2;
496:
497: a = *(const char **) a_ptr;
498: b = *(const char **) b_ptr;
499:
500:
501:
502:
503:
504:
505:
506:
507:
508:
509: do
510: {
511: c1 = (unsigned char) tolower (*a++);
512: c2 = (unsigned char) tolower (*b++);
513:
514: if (c1 == '=')
515: c1 = '\0';
516:
517: if (c2 == '=')
518: c2 = '\0';
519: }
520: while (c1 == c2 && c1 != '\0');
521:
522: return c1 - c2;
523: }
524:
525: static long
526: win32_spawn (const char *executable,
527: BOOL search,
528: char *const *argv,
529: char *const *env,
530: DWORD dwCreationFlags,
531: LPSTARTUPINFO si,
532: LPPROCESS_INFORMATION pi)
533: {
534: char *full_executable;
535: char *cmdline;
536: char **env_copy;
537: char *env_block = NULL;
538:
539: full_executable = NULL;
540: cmdline = NULL;
541:
542: if (env)
543: {
544: int env_size;
545:
546:
547: for (env_size = 0; env[env_size]; env_size++)
548: continue;
549:
550:
551:
552:
553: if (env_size > 0)
554: {
555: int var;
556: int total_size = 1;
557: char *bufptr;
558:
559:
560:
561: env_copy = (char **) alloca (sizeof (char *) * env_size);
562: memcpy (env_copy, env, sizeof (char *) * env_size);
563: qsort (env_copy, env_size, sizeof (char *), env_compare);
564:
565: for (var = 0; var < env_size;