* doc/c-avr.texi: New file.
[deliverable/binutils-gdb.git] / libiberty / pex-win32.c
CommitLineData
5a17353c
DD
1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2 with other subprocesses), and wait for it. Generic Win32 specialization.
1e45deed 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
5a17353c
DD
4 Free Software Foundation, Inc.
5
6This file is part of the libiberty library.
7Libiberty is free software; you can redistribute it and/or
8modify it under the terms of the GNU Library General Public
9License as published by the Free Software Foundation; either
10version 2 of the License, or (at your option) any later version.
11
12Libiberty is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15Library General Public License for more details.
16
17You should have received a copy of the GNU Library General Public
18License along with libiberty; see the file COPYING.LIB. If not,
979c05d3
NC
19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20Boston, MA 02110-1301, USA. */
5a17353c
DD
21
22#include "pex-common.h"
23
f59e96e0
DD
24#include <windows.h>
25
b109e79a
ILT
26#ifdef HAVE_STDLIB_H
27#include <stdlib.h>
28#endif
5a17353c
DD
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 <process.h>
40#include <io.h>
41#include <fcntl.h>
42#include <signal.h>
b109e79a 43#include <sys/stat.h>
8e1e9959 44#include <errno.h>
5a17353c
DD
45
46/* mingw32 headers may not define the following. */
47
48#ifndef _P_WAIT
49# define _P_WAIT 0
50# define _P_NOWAIT 1
51# define _P_OVERLAY 2
52# define _P_NOWAITO 3
53# define _P_DETACH 4
54
55# define WAIT_CHILD 0
56# define WAIT_GRANDCHILD 1
57#endif
58
f59e96e0
DD
59#define MINGW_NAME "Minimalist GNU for Windows"
60#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
61
62/* Ensure that the executable pathname uses Win32 backslashes. This
63 is not necessary on NT, but on W9x, forward slashes causes
64 failure of spawn* and exec* functions (and probably any function
65 that calls CreateProcess) *iff* the executable pathname (argv[0])
66 is a quoted string. And quoting is necessary in case a pathname
67 contains embedded white space. You can't win. */
68static void
69backslashify (char *s)
70{
71 while ((s = strchr (s, '/')) != NULL)
72 *s = '\\';
73 return;
74}
75
b109e79a
ILT
76static int pex_win32_open_read (struct pex_obj *, const char *, int);
77static int pex_win32_open_write (struct pex_obj *, const char *, int);
78static long pex_win32_exec_child (struct pex_obj *, int, const char *,
79 char * const *, int, int, int,
80 const char **, int *);
81static int pex_win32_close (struct pex_obj *, int);
82static int pex_win32_wait (struct pex_obj *, long, int *,
83 struct pex_time *, int, const char **, int *);
84static int pex_win32_pipe (struct pex_obj *, int *, int);
85static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
3db2e6dd 86static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
b109e79a
ILT
87
88/* The list of functions we pass to the common routines. */
89
90const struct pex_funcs funcs =
5a17353c 91{
b109e79a
ILT
92 pex_win32_open_read,
93 pex_win32_open_write,
94 pex_win32_exec_child,
95 pex_win32_close,
96 pex_win32_wait,
97 pex_win32_pipe,
98 pex_win32_fdopenr,
3db2e6dd 99 pex_win32_fdopenw,
b109e79a
ILT
100 NULL /* cleanup */
101};
102
103/* Return a newly initialized pex_obj structure. */
104
105struct pex_obj *
106pex_init (int flags, const char *pname, const char *tempbase)
107{
108 return pex_init_common (flags, pname, tempbase, &funcs);
109}
110
111/* Open a file for reading. */
112
113static int
114pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
115 int binary)
116{
117 return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
118}
119
120/* Open a file for writing. */
121
122static int
123pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
124 int binary)
125{
126 /* Note that we can't use O_EXCL here because gcc may have already
127 created the temporary file via make_temp_file. */
128 return _open (name,
129 (_O_WRONLY | _O_CREAT | _O_TRUNC
130 | (binary ? _O_BINARY : _O_TEXT)),
131 _S_IREAD | _S_IWRITE);
132}
133
134/* Close a file. */
135
136static int
137pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
138{
139 return _close (fd);
140}
141
f59e96e0
DD
142#ifdef USE_MINGW_MSYS
143static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
144
145/* Tack the executable on the end of a (possibly slash terminated) buffer
146 and convert everything to \. */
147static const char *
148tack_on_executable (char *buf, const char *executable)
149{
150 char *p = strchr (buf, '\0');
151 if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
152 p[-1] = '\0';
153 backslashify (strcat (buf, executable));
154 return buf;
155}
156
157/* Walk down a registry hierarchy until the end. Return the key. */
158static HKEY
159openkey (HKEY hStart, const char *keys[])
160{
161 HKEY hKey, hTmp;
162 for (hKey = hStart; *keys; keys++)
163 {
164 LONG res;
165 hTmp = hKey;
166 res = RegOpenKey (hTmp, *keys, &hKey);
167
168 if (hTmp != HKEY_LOCAL_MACHINE)
169 RegCloseKey (hTmp);
170
171 if (res != ERROR_SUCCESS)
172 return NULL;
173 }
174 return hKey;
175}
176
177/* Return the "mingw root" as derived from the mingw uninstall information. */
178static const char *
179mingw_rootify (const char *executable)
180{
181 HKEY hKey, hTmp;
182 DWORD maxlen;
183 char *namebuf, *foundbuf;
184 DWORD i;
185 LONG res;
186
187 /* Open the uninstall "directory". */
188 hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
189
190 /* Not found. */
191 if (!hKey)
192 return executable;
193
194 /* Need to enumerate all of the keys here looking for one the most recent
195 one for MinGW. */
196 if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
197 NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
198 {
199 RegCloseKey (hKey);
200 return executable;
201 }
202 namebuf = XNEWVEC (char, ++maxlen);
203 foundbuf = XNEWVEC (char, maxlen);
204 foundbuf[0] = '\0';
205 if (!namebuf || !foundbuf)
206 {
207 RegCloseKey (hKey);
208 if (namebuf)
209 free (namebuf);
210 if (foundbuf)
211 free (foundbuf);
212 return executable;
213 }
214
215 /* Look through all of the keys for one that begins with Minimal GNU...
216 Try to get the latest version by doing a string compare although that
217 string never really works with version number sorting. */
218 for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
219 {
220 int match = strcasecmp (namebuf, MINGW_NAME);
221 if (match < 0)
222 continue;
223 if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
224 continue;
225 if (strcasecmp (namebuf, foundbuf) > 0)
226 strcpy (foundbuf, namebuf);
227 }
228 free (namebuf);
229
230 /* If foundbuf is empty, we didn't find anything. Punt. */
231 if (!foundbuf[0])
232 {
233 free (foundbuf);
234 RegCloseKey (hKey);
235 return executable;
236 }
237
238 /* Open the key that we wanted */
239 res = RegOpenKey (hKey, foundbuf, &hTmp);
240 RegCloseKey (hKey);
241 free (foundbuf);
242
243 /* Don't know why this would fail, but you gotta check */
244 if (res != ERROR_SUCCESS)
245 return executable;
246
247 maxlen = 0;
248 /* Get the length of the value pointed to by InstallLocation */
249 if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
250 &maxlen) != ERROR_SUCCESS || maxlen == 0)
251 {
252 RegCloseKey (hTmp);
253 return executable;
254 }
255
256 /* Allocate space for the install location */
257 foundbuf = XNEWVEC (char, maxlen + strlen (executable));
258 if (!foundbuf)
259 {
260 free (foundbuf);
261 RegCloseKey (hTmp);
262 }
263
264 /* Read the install location into the buffer */
265 res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
266 &maxlen);
267 RegCloseKey (hTmp);
268 if (res != ERROR_SUCCESS)
269 {
270 free (foundbuf);
271 return executable;
272 }
273
274 /* Concatenate the install location and the executable, turn all slashes
275 to backslashes, and return that. */
276 return tack_on_executable (foundbuf, executable);
277}
278
279/* Read the install location of msys from it's installation file and
280 rootify the executable based on that. */
281static const char *
282msys_rootify (const char *executable)
283{
284 size_t bufsize = 64;
285 size_t execlen = strlen (executable) + 1;
286 char *buf;
287 DWORD res = 0;
288 for (;;)
289 {
290 buf = XNEWVEC (char, bufsize + execlen);
291 if (!buf)
292 break;
293 res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
294 buf, bufsize, "msys.ini");
295 if (!res)
296 break;
297 if (strlen (buf) < bufsize)
298 break;
299 res = 0;
300 free (buf);
301 bufsize *= 2;
302 if (bufsize > 65536)
303 {
304 buf = NULL;
305 break;
306 }
307 }
308
309 if (res)
310 return tack_on_executable (buf, executable);
311
312 /* failed */
313 if (buf)
314 free (buf);
315 return executable;
316}
317#endif
318
8e1e9959
DD
319/* Return a Windows command-line from ARGV. It is the caller's
320 responsibility to free the string returned. */
321
322static char *
323argv_to_cmdline (char *const *argv)
324{
325 char *cmdline;
326 char *p;
327 size_t cmdline_len;
328 int i, j, k;
329
330 cmdline_len = 0;
331 for (i = 0; argv[i]; i++)
332 {
333 /* We quote every last argument. This simplifies the problem;
334 we need only escape embedded double-quotes and immediately
335 preceeding backslash characters. A sequence of backslach characters
336 that is not follwed by a double quote character will not be
337 escaped. */
338 for (j = 0; argv[i][j]; j++)
339 {
340 if (argv[i][j] == '"')
341 {
342 /* Escape preceeding backslashes. */
343 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
344 cmdline_len++;
345 /* Escape the qote character. */
346 cmdline_len++;
347 }
348 }
349 /* Trailing backslashes also need to be escaped because they will be
350 followed by the terminating quote. */
351 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
352 cmdline_len++;
353 cmdline_len += j;
354 cmdline_len += 3; /* for leading and trailing quotes and space */
355 }
356 cmdline = xmalloc (cmdline_len);
357 p = cmdline;
358 for (i = 0; argv[i]; i++)
359 {
360 *p++ = '"';
361 for (j = 0; argv[i][j]; j++)
362 {
363 if (argv[i][j] == '"')
364 {
365 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
366 *p++ = '\\';
367 *p++ = '\\';
368 }
369 *p++ = argv[i][j];
370 }
371 for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
372 *p++ = '\\';
373 *p++ = '"';
374 *p++ = ' ';
375 }
376 p[-1] = '\0';
377 return cmdline;
378}
379
380static const char *const
381std_suffixes[] = {
382 ".com",
383 ".exe",
384 ".bat",
385 ".cmd",
386 0
387};
388static const char *const
389no_suffixes[] = {
390 "",
391 0
392};
393
394/* Returns the full path to PROGRAM. If SEARCH is true, look for
395 PROGRAM in each directory in PATH. */
396
397static char *
398find_executable (const char *program, BOOL search)
399{
400 char *full_executable;
401 char *e;
402 size_t fe_len;
403 const char *path = 0;
404 const char *const *ext;
405 const char *p, *q;
406 size_t proglen = strlen (program);
407 int has_extension = !!strchr (program, '.');
408 int has_slash = (strchr (program, '/') || strchr (program, '\\'));
409 HANDLE h;
410
411 if (has_slash)
412 search = FALSE;
413
414 if (search)
415 path = getenv ("PATH");
416 if (!path)
417 path = "";
418
419 fe_len = 0;
420 for (p = path; *p; p = q)
421 {
422 q = p;
423 while (*q != ';' && *q != '\0')
424 q++;
425 if ((size_t)(q - p) > fe_len)
426 fe_len = q - p;
427 if (*q == ';')
428 q++;
429 }
430 fe_len = fe_len + 1 + proglen + (has_extension ? 1 : 5);
431 full_executable = xmalloc (fe_len);
432
433 p = path;
434 do
435 {
436 q = p;
437 while (*q != ';' && *q != '\0')
438 q++;
439
440 e = full_executable;
441 memcpy (e, p, q - p);
442 e += (q - p);
443 if (q - p)
444 *e++ = '\\';
445 strcpy (e, program);
446
447 if (*q == ';')
448 q++;
449
450 for (e = full_executable; *e; e++)
451 if (*e == '/')
452 *e = '\\';
453
454 /* At this point, e points to the terminating NUL character for
455 full_executable. */
456 for (ext = has_extension ? no_suffixes : std_suffixes; *ext; ext++)
457 {
458 /* Remove any current extension. */
459 *e = '\0';
460 /* Add the new one. */
461 strcat (full_executable, *ext);
462
463 /* Attempt to open this file. */
464 h = CreateFile (full_executable, GENERIC_READ,
465 FILE_SHARE_READ | FILE_SHARE_WRITE,
466 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
467 if (h != INVALID_HANDLE_VALUE)
468 goto found;
469 }
470 p = q;
471 }
472 while (*p);
473 free (full_executable);
474 return 0;
475
476 found:
477 CloseHandle (h);
478 return full_executable;
479}
480
481/* Low-level process creation function. */
482
483static long
484win32_spawn (const char *executable,
485 BOOL search,
486 char *const *argv,
487 DWORD dwCreationFlags,
488 LPSTARTUPINFO si,
489 LPPROCESS_INFORMATION pi)
490{
491 char *full_executable;
492 char *cmdline;
493
494 full_executable = NULL;
495 cmdline = NULL;
496
497 full_executable = find_executable (executable, search);
498 if (!full_executable)
499 goto error;
500 cmdline = argv_to_cmdline (argv);
501 if (!cmdline)
502 goto error;
503
504 /* Create the child process. */
505 if (!CreateProcess (full_executable, cmdline,
506 /*lpProcessAttributes=*/NULL,
507 /*lpThreadAttributes=*/NULL,
508 /*bInheritHandles=*/TRUE,
509 dwCreationFlags,
510 /*lpEnvironment=*/NULL,
511 /*lpCurrentDirectory=*/NULL,
512 si,
513 pi))
514 {
515 free (full_executable);
516 return -1;
517 }
518
519 /* Clean up. */
520 CloseHandle (pi->hThread);
521 free (full_executable);
522
523 return (long) pi->hProcess;
524
525 error:
526 if (cmdline)
527 free (cmdline);
528 if (full_executable)
529 free (full_executable);
530 return -1;
531}
532
f59e96e0 533static long
8e1e9959
DD
534spawn_script (const char *executable, char *const *argv,
535 DWORD dwCreationFlags,
536 LPSTARTUPINFO si,
537 LPPROCESS_INFORMATION pi)
f59e96e0
DD
538{
539 int pid = -1;
540 int save_errno = errno;
541 int fd = _open (executable, _O_RDONLY);
542
543 if (fd >= 0)
544 {
545 char buf[MAX_PATH + 5];
546 int len = _read (fd, buf, sizeof (buf) - 1);
547 _close (fd);
548 if (len > 3)
549 {
550 char *eol;
551 buf[len] = '\0';
552 eol = strchr (buf, '\n');
553 if (eol && strncmp (buf, "#!", 2) == 0)
554 {
555 char *executable1;
556 const char ** avhere = (const char **) --argv;
557 do
558 *eol = '\0';
559 while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
560 for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
561 continue;
562
563 backslashify (executable1);
564 *avhere = executable1;
565#ifndef USE_MINGW_MSYS
566 executable = strrchr (executable1, '\\') + 1;
567 if (!executable)
568 executable = executable1;
8e1e9959
DD
569 pid = win32_spawn (executable, TRUE, argv,
570 dwCreationFlags, si, pi);
f59e96e0
DD
571#else
572 if (strchr (executable1, '\\') == NULL)
8e1e9959
DD
573 pid = win32_spawn (executable1, TRUE, argv,
574 dwCreationFlags, si, pi);
f59e96e0 575 else if (executable1[0] != '\\')
8e1e9959
DD
576 pid = win32_spawn (executable1, FALSE, argv,
577 dwCreationFlags, si, pi);
f59e96e0
DD
578 else
579 {
580 const char *newex = mingw_rootify (executable1);
581 *avhere = newex;
8e1e9959
DD
582 pid = win32_spawn (newex, FALSE, argv,
583 dwCreationFlags, si, pi);
f59e96e0
DD
584 if (executable1 != newex)
585 free ((char *) newex);
586 if (pid < 0)
587 {
588 newex = msys_rootify (executable1);
589 if (newex != executable1)
590 {
591 *avhere = newex;
8e1e9959
DD
592 pid = win32_spawn (newex, FALSE, argv,
593 dwCreationFlags, si, pi);
f59e96e0
DD
594 free ((char *) newex);
595 }
596 }
597 }
598#endif
599 }
600 }
601 }
602 if (pid < 0)
603 errno = save_errno;
604 return pid;
605}
606
b109e79a
ILT
607/* Execute a child. */
608
609static long
610pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
611 const char *executable, char * const * argv,
612 int in, int out, int errdes, const char **errmsg,
613 int *err)
614{
b109e79a 615 long pid;
8e1e9959
DD
616 HANDLE stdin_handle;
617 HANDLE stdout_handle;
618 HANDLE stderr_handle;
619 DWORD dwCreationFlags;
620 OSVERSIONINFO version_info;
621 STARTUPINFO si;
622 PROCESS_INFORMATION pi;
623
624 stdin_handle = INVALID_HANDLE_VALUE;
625 stdout_handle = INVALID_HANDLE_VALUE;
626 stderr_handle = INVALID_HANDLE_VALUE;
627
628 stdin_handle = (HANDLE) _get_osfhandle (in);
629 stdout_handle = (HANDLE) _get_osfhandle (out);
630 if (!(flags & PEX_STDERR_TO_STDOUT))
631 stderr_handle = (HANDLE) _get_osfhandle (errdes);
632 else
633 stderr_handle = stdout_handle;
634
635 /* Determine the version of Windows we are running on. */
636 version_info.dwOSVersionInfoSize = sizeof (version_info);
637 GetVersionEx (&version_info);
638 if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
639 /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
640 supported, so we cannot avoid creating a console window. */
641 dwCreationFlags = 0;
642 else
5a17353c 643 {
8e1e9959
DD
644 HANDLE conout_handle;
645
646 /* Determine whether or not we have an associated console. */
647 conout_handle = CreateFile("CONOUT$",
648 GENERIC_WRITE,
649 FILE_SHARE_WRITE,
650 /*lpSecurityAttributes=*/NULL,
651 OPEN_EXISTING,
652 FILE_ATTRIBUTE_NORMAL,
653 /*hTemplateFile=*/NULL);
654 if (conout_handle == INVALID_HANDLE_VALUE)
655 /* There is no console associated with this process. Since
656 the child is a console process, the OS would normally
657 create a new console Window for the child. Since we'll be
658 redirecting the child's standard streams, we do not need
659 the console window. */
660 dwCreationFlags = CREATE_NO_WINDOW;
661 else
b109e79a 662 {
8e1e9959
DD
663 /* There is a console associated with the process, so the OS
664 will not create a new console. And, if we use
665 CREATE_NO_WINDOW in this situation, the child will have
666 no associated console. Therefore, if the child's
667 standard streams are connected to the console, the output
668 will be discarded. */
669 CloseHandle(conout_handle);
670 dwCreationFlags = 0;
b109e79a 671 }
5a17353c
DD
672 }
673
8e1e9959
DD
674 /* Since the child will be a console process, it will, by default,
675 connect standard input/output to its console. However, we want
676 the child to use the handles specifically designated above. In
677 addition, if there is no console (such as when we are running in
678 a Cygwin X window), then we must redirect the child's
679 input/output, as there is no console for the child to use. */
680 memset (&si, 0, sizeof (si));
681 si.cb = sizeof (si);
682 si.dwFlags = STARTF_USESTDHANDLES;
683 si.hStdInput = stdin_handle;
684 si.hStdOutput = stdout_handle;
685 si.hStdError = stderr_handle;
686
687 /* Create the child process. */
688 pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
689 argv, dwCreationFlags, &si, &pi);
f59e96e0 690 if (pid == -1)
8e1e9959 691 pid = spawn_script (executable, argv, dwCreationFlags, &si, &pi);
b109e79a 692 if (pid == -1)
5a17353c 693 {
8e1e9959
DD
694 *err = ENOENT;
695 *errmsg = "CreateProcess";
5a17353c
DD
696 }
697
8e1e9959
DD
698 /* Close the standard output and standard error handles in the
699 parent. */
700 if (out != STDOUT_FILENO)
701 obj->funcs->close (obj, out);
702 if (errdes != STDERR_FILENO)
703 obj->funcs->close (obj, errdes);
5a17353c
DD
704
705 return pid;
706}
707
b109e79a
ILT
708/* Wait for a child process to complete. MS CRTDLL doesn't return
709 enough information in status to decide if the child exited due to a
710 signal or not, rather it simply returns an integer with the exit
711 code of the child; eg., if the child exited with an abort() call
712 and didn't have a handler for SIGABRT, it simply returns with
713 status == 3. We fix the status code to conform to the usual WIF*
714 macros. Note that WIFSIGNALED will never be true under CRTDLL. */
715
716static int
717pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
718 int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
719 const char **errmsg, int *err)
5a17353c 720{
8e1e9959
DD
721 DWORD termstat;
722 HANDLE h;
5a17353c 723
b109e79a
ILT
724 if (time != NULL)
725 memset (time, 0, sizeof *time);
726
8e1e9959
DD
727 h = (HANDLE) pid;
728
b109e79a
ILT
729 /* FIXME: If done is non-zero, we should probably try to kill the
730 process. */
8e1e9959 731 if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
b109e79a 732 {
8e1e9959
DD
733 CloseHandle (h);
734 *err = ECHILD;
735 *errmsg = "WaitForSingleObject";
b109e79a
ILT
736 return -1;
737 }
5a17353c 738
8e1e9959
DD
739 GetExitCodeProcess (h, &termstat);
740 CloseHandle (h);
741
742 /* A value of 3 indicates that the child caught a signal, but not
743 which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we
744 report SIGABRT. */
5a17353c
DD
745 if (termstat == 3)
746 *status = SIGABRT;
747 else
8e1e9959 748 *status = (termstat & 0xff) << 8;
5a17353c 749
b109e79a
ILT
750 return 0;
751}
752
753/* Create a pipe. */
754
755static int
756pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
757 int binary)
758{
759 return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
760}
761
762/* Get a FILE pointer to read from a file descriptor. */
763
764static FILE *
765pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
766 int binary)
767{
768 return fdopen (fd, binary ? "rb" : "r");
5a17353c 769}
f59e96e0 770
3db2e6dd
DD
771static FILE *
772pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
773 int binary)
774{
775 HANDLE h = (HANDLE) _get_osfhandle (fd);
776 if (h == INVALID_HANDLE_VALUE)
777 return NULL;
778 if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
779 return NULL;
780 return fdopen (fd, binary ? "wb" : "w");
781}
782
f59e96e0
DD
783#ifdef MAIN
784#include <stdio.h>
785
786int
787main (int argc ATTRIBUTE_UNUSED, char **argv)
788{
789 char const *errmsg;
790 int err;
791 argv++;
792 printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, 0, 1, 2, &errmsg, &err));
793 exit (0);
794}
795#endif
This page took 0.193154 seconds and 4 git commands to generate.