source: rtems-tools/rtemstoolkit/libiberty/pex-win32.c @ 87e0e76

4.104.11
Last change on this file since 87e0e76 was 87e0e76, checked in by Chris Johns <chrisj@…>, on Sep 13, 2014 at 2:09:16 AM

Refactor code into the RTEMS Toolkit.

  • Property mode set to 100644
File size: 24.6 KB
Line 
1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2   with other subprocesses), and wait for it.  Generic Win32 specialization.
3   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
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,
19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20Boston, MA 02110-1301, USA.  */
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#include <malloc.h>
48
49/* mingw32 headers may not define the following.  */
50
51#ifndef _P_WAIT
52#  define _P_WAIT       0
53#  define _P_NOWAIT     1
54#  define _P_OVERLAY    2
55#  define _P_NOWAITO    3
56#  define _P_DETACH     4
57
58#  define WAIT_CHILD            0
59#  define WAIT_GRANDCHILD       1
60#endif
61
62#define MINGW_NAME "Minimalist GNU for Windows"
63#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
64
65extern char *stpcpy (char *dst, const char *src);
66
67/* Ensure that the executable pathname uses Win32 backslashes. This
68   is not necessary on NT, but on W9x, forward slashes causes
69   failure of spawn* and exec* functions (and probably any function
70   that calls CreateProcess) *iff* the executable pathname (argv[0])
71   is a quoted string.  And quoting is necessary in case a pathname
72   contains embedded white space.  You can't win.  */
73static void
74backslashify (char *s)
75{
76  while ((s = strchr (s, '/')) != NULL)
77    *s = '\\';
78  return;
79}
80
81static int pex_win32_open_read (struct pex_obj *, const char *, int);
82static int pex_win32_open_write (struct pex_obj *, const char *, int);
83static pid_t pex_win32_exec_child (struct pex_obj *, int, const char *,
84                                  char * const *, char * const *,
85                                  int, int, int, int,
86                                  const char **, int *);
87static int pex_win32_close (struct pex_obj *, int);
88static pid_t pex_win32_wait (struct pex_obj *, pid_t, int *,
89                           struct pex_time *, int, const char **, int *);
90static int pex_win32_pipe (struct pex_obj *, int *, int);
91static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
92static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
93
94/* The list of functions we pass to the common routines.  */
95
96const struct pex_funcs funcs =
97{
98  pex_win32_open_read,
99  pex_win32_open_write,
100  pex_win32_exec_child,
101  pex_win32_close,
102  pex_win32_wait,
103  pex_win32_pipe,
104  pex_win32_fdopenr,
105  pex_win32_fdopenw,
106  NULL /* cleanup */
107};
108
109/* Return a newly initialized pex_obj structure.  */
110
111struct pex_obj *
112pex_init (int flags, const char *pname, const char *tempbase)
113{
114  return pex_init_common (flags, pname, tempbase, &funcs);
115}
116
117/* Open a file for reading.  */
118
119static int
120pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
121                     int binary)
122{
123  return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
124}
125
126/* Open a file for writing.  */
127
128static int
129pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
130                      int binary)
131{
132  /* Note that we can't use O_EXCL here because gcc may have already
133     created the temporary file via make_temp_file.  */
134  return _open (name,
135                (_O_WRONLY | _O_CREAT | _O_TRUNC
136                 | (binary ? _O_BINARY : _O_TEXT)),
137                _S_IREAD | _S_IWRITE);
138}
139
140/* Close a file.  */
141
142static int
143pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
144{
145  return _close (fd);
146}
147
148#ifdef USE_MINGW_MSYS
149static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
150
151/* Tack the executable on the end of a (possibly slash terminated) buffer
152   and convert everything to \. */
153static const char *
154tack_on_executable (char *buf, const char *executable)
155{
156  char *p = strchr (buf, '\0');
157  if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
158    p[-1] = '\0';
159  backslashify (strcat (buf, executable));
160  return buf;
161}
162
163/* Walk down a registry hierarchy until the end.  Return the key. */
164static HKEY
165openkey (HKEY hStart, const char *keys[])
166{
167  HKEY hKey, hTmp;
168  for (hKey = hStart; *keys; keys++)
169    {
170      LONG res;
171      hTmp = hKey;
172      res = RegOpenKey (hTmp, *keys, &hKey);
173
174      if (hTmp != HKEY_LOCAL_MACHINE)
175        RegCloseKey (hTmp);
176
177      if (res != ERROR_SUCCESS)
178        return NULL;
179    }
180  return hKey;
181}
182
183/* Return the "mingw root" as derived from the mingw uninstall information. */
184static const char *
185mingw_rootify (const char *executable)
186{
187  HKEY hKey, hTmp;
188  DWORD maxlen;
189  char *namebuf, *foundbuf;
190  DWORD i;
191  LONG res;
192
193  /* Open the uninstall "directory". */
194  hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
195
196  /* Not found. */
197  if (!hKey)
198    return executable;
199
200  /* Need to enumerate all of the keys here looking for one the most recent
201     one for MinGW. */
202  if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
203                       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
204    {
205      RegCloseKey (hKey);
206      return executable;
207    }
208  namebuf = XNEWVEC (char, ++maxlen);
209  foundbuf = XNEWVEC (char, maxlen);
210  foundbuf[0] = '\0';
211  if (!namebuf || !foundbuf)
212    {
213      RegCloseKey (hKey);
214      free (namebuf);
215      free (foundbuf);
216      return executable;
217    }
218
219  /* Look through all of the keys for one that begins with Minimal GNU...
220     Try to get the latest version by doing a string compare although that
221     string never really works with version number sorting. */
222  for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
223    {
224      int match = strcasecmp (namebuf, MINGW_NAME);
225      if (match < 0)
226        continue;
227      if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
228        continue;
229      if (strcasecmp (namebuf, foundbuf) > 0)
230        strcpy (foundbuf, namebuf);
231    }
232  free (namebuf);
233
234  /* If foundbuf is empty, we didn't find anything.  Punt. */
235  if (!foundbuf[0])
236    {
237      free (foundbuf);
238      RegCloseKey (hKey);
239      return executable;
240    }
241
242  /* Open the key that we wanted */
243  res = RegOpenKey (hKey, foundbuf, &hTmp);
244  RegCloseKey (hKey);
245  free (foundbuf);
246
247  /* Don't know why this would fail, but you gotta check */
248  if (res != ERROR_SUCCESS)
249    return executable;
250
251  maxlen = 0;
252  /* Get the length of the value pointed to by InstallLocation */
253  if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
254                       &maxlen) != ERROR_SUCCESS || maxlen == 0)
255    {
256      RegCloseKey (hTmp);
257      return executable;
258    }
259
260  /* Allocate space for the install location */
261  foundbuf = XNEWVEC (char, maxlen + strlen (executable));
262  if (!foundbuf)
263    {
264      free (foundbuf);
265      RegCloseKey (hTmp);
266    }
267
268  /* Read the install location into the buffer */
269  res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
270                         &maxlen);
271  RegCloseKey (hTmp);
272  if (res != ERROR_SUCCESS)
273    {
274      free (foundbuf);
275      return executable;
276    }
277
278  /* Concatenate the install location and the executable, turn all slashes
279     to backslashes, and return that. */
280  return tack_on_executable (foundbuf, executable);
281}
282
283/* Read the install location of msys from it's installation file and
284   rootify the executable based on that. */
285static const char *
286msys_rootify (const char *executable)
287{
288  size_t bufsize = 64;
289  size_t execlen = strlen (executable) + 1;
290  char *buf;
291  DWORD res = 0;
292  for (;;)
293    {
294      buf = XNEWVEC (char, bufsize + execlen);
295      if (!buf)
296        break;
297      res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
298                                     buf, bufsize, "msys.ini");
299      if (!res)
300        break;
301      if (strlen (buf) < bufsize)
302        break;
303      res = 0;
304      free (buf);
305      bufsize *= 2;
306      if (bufsize > 65536)
307        {
308          buf = NULL;
309          break;
310        }
311    }
312
313  if (res)
314    return tack_on_executable (buf, executable);
315
316  /* failed */
317  free (buf);
318  return executable;
319}
320#endif
321
322/* Return the number of arguments in an argv array, not including the null
323   terminating argument. */
324
325static int
326argv_to_argc (char *const *argv)
327{
328  char *const *i = argv;
329  while (*i)
330    i++;
331  return i - argv;
332}
333
334/* Return a Windows command-line from ARGV.  It is the caller's
335   responsibility to free the string returned.  */
336
337static char *
338argv_to_cmdline (char *const *argv)
339{
340  char *cmdline;
341  char *p;
342  size_t cmdline_len;
343  int i, j, k;
344
345  cmdline_len = 0;
346  for (i = 0; argv[i]; i++)
347    {
348      /* We quote every last argument.  This simplifies the problem;
349         we need only escape embedded double-quotes and immediately
350         preceeding backslash characters.  A sequence of backslach characters
351         that is not follwed by a double quote character will not be
352         escaped.  */
353      for (j = 0; argv[i][j]; j++)
354        {
355          if (argv[i][j] == '"')
356            {
357              /* Escape preceeding backslashes.  */
358              for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
359                cmdline_len++;
360              /* Escape the qote character.  */
361              cmdline_len++;
362            }
363        }
364      /* Trailing backslashes also need to be escaped because they will be
365         followed by the terminating quote.  */
366      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
367        cmdline_len++;
368      cmdline_len += j;
369      cmdline_len += 3;  /* for leading and trailing quotes and space */
370    }
371  cmdline = XNEWVEC (char, cmdline_len);
372  p = cmdline;
373  for (i = 0; argv[i]; i++)
374    {
375      *p++ = '"';
376      for (j = 0; argv[i][j]; j++)
377        {
378          if (argv[i][j] == '"')
379            {
380              for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
381                *p++ = '\\';
382              *p++ = '\\';
383            }
384          *p++ = argv[i][j];
385        }
386      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
387        *p++ = '\\';
388      *p++ = '"';
389      *p++ = ' ';
390    }
391  p[-1] = '\0';
392  return cmdline;
393}
394
395/* We'll try the passed filename with all the known standard
396   extensions, and then without extension.  We try no extension
397   last so that we don't try to run some random extension-less
398   file that might be hanging around.  We try both extension
399   and no extension so that we don't need any fancy logic
400   to determine if a file has extension.  */
401static const char *const
402std_suffixes[] = {
403  ".com",
404  ".exe",
405  ".bat",
406  ".cmd",
407  "",
408  0
409};
410
411/* Returns the full path to PROGRAM.  If SEARCH is true, look for
412   PROGRAM in each directory in PATH.  */
413
414static char *
415find_executable (const char *program, BOOL search)
416{
417  char *full_executable;
418  char *e;
419  size_t fe_len;
420  const char *path = 0;
421  const char *const *ext;
422  const char *p, *q;
423  size_t proglen = strlen (program);
424  int has_slash = (strchr (program, '/') || strchr (program, '\\'));
425  HANDLE h;
426
427  if (has_slash)
428    search = FALSE;
429
430  if (search)
431    path = getenv ("PATH");
432  if (!path)
433    path = "";
434
435  fe_len = 0;
436  for (p = path; *p; p = q)
437    {
438      q = p;
439      while (*q != ';' && *q != '\0')
440        q++;
441      if ((size_t)(q - p) > fe_len)
442        fe_len = q - p;
443      if (*q == ';')
444        q++;
445    }
446  fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
447  full_executable = XNEWVEC (char, fe_len);
448
449  p = path;
450  do
451    {
452      q = p;
453      while (*q != ';' && *q != '\0')
454        q++;
455
456      e = full_executable;
457      memcpy (e, p, q - p);
458      e += (q - p);
459      if (q - p)
460        *e++ = '\\';
461      strcpy (e, program);
462
463      if (*q == ';')
464        q++;
465
466      for (e = full_executable; *e; e++)
467        if (*e == '/')
468          *e = '\\';
469
470      /* At this point, e points to the terminating NUL character for
471         full_executable.  */
472      for (ext = std_suffixes; *ext; ext++)
473        {
474          /* Remove any current extension.  */
475          *e = '\0';
476          /* Add the new one.  */
477          strcat (full_executable, *ext);
478
479          /* Attempt to open this file.  */
480          h = CreateFile (full_executable, GENERIC_READ,
481                          FILE_SHARE_READ | FILE_SHARE_WRITE,
482                          0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
483          if (h != INVALID_HANDLE_VALUE)
484            goto found;
485        }
486      p = q;
487    }
488  while (*p);
489  free (full_executable);
490  return 0;
491
492 found:
493  CloseHandle (h);
494  return full_executable;
495}
496
497/* Low-level process creation function and helper.  */
498
499static int
500env_compare (const void *a_ptr, const void *b_ptr)
501{
502  const char *a;
503  const char *b;
504  unsigned char c1;
505  unsigned char c2;
506
507  a = *(const char **) a_ptr;
508  b = *(const char **) b_ptr;
509
510  /* a and b will be of the form: VAR=VALUE
511     We compare only the variable name part here using a case-insensitive
512     comparison algorithm.  It might appear that in fact strcasecmp () can
513     take the place of this whole function, and indeed it could, save for
514     the fact that it would fail in cases such as comparing A1=foo and
515     A=bar (because 1 is less than = in the ASCII character set).
516     (Environment variables containing no numbers would work in such a
517     scenario.)  */
518
519  do
520    {
521      c1 = (unsigned char) tolower (*a++);
522      c2 = (unsigned char) tolower (*b++);
523
524      if (c1 == '=')
525        c1 = '\0';
526
527      if (c2 == '=')
528        c2 = '\0';
529    }
530  while (c1 == c2 && c1 != '\0');
531
532  return c1 - c2;
533}
534
535/* Execute a Windows executable as a child process.  This will fail if the
536 * target is not actually an executable, such as if it is a shell script. */
537
538static pid_t
539win32_spawn (const char *executable,
540             BOOL search,
541             char *const *argv,
542             char *const *env, /* array of strings of the form: VAR=VALUE */
543             DWORD dwCreationFlags,
544             LPSTARTUPINFO si,
545             LPPROCESS_INFORMATION pi)
546{
547  char *full_executable;
548  char *cmdline;
549  char **env_copy;
550  char *env_block = NULL;
551
552  full_executable = NULL;
553  cmdline = NULL;
554
555  if (env)
556    {
557      int env_size;
558
559      /* Count the number of environment bindings supplied.  */
560      for (env_size = 0; env[env_size]; env_size++)
561        continue;
562   
563      /* Assemble an environment block, if required.  This consists of
564         VAR=VALUE strings juxtaposed (with one null character between each
565         pair) and an additional null at the end.  */
566      if (env_size > 0)
567        {
568          int var;
569          int total_size = 1; /* 1 is for the final null.  */
570          char *bufptr;
571   
572          /* Windows needs the members of the block to be sorted by variable
573             name.  */
574          env_copy = (char **) alloca (sizeof (char *) * env_size);
575          memcpy (env_copy, env, sizeof (char *) * env_size);
576          qsort (env_copy, env_size, sizeof (char *), env_compare);
577   
578          for (var = 0; var < env_size; var++)
579            total_size += strlen (env[var]) + 1;
580   
581          env_block = XNEWVEC (char, total_size);
582          bufptr = env_block;
583          for (var = 0; var < env_size; var++)
584            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
585   
586          *bufptr = '\0';
587        }
588    }
589
590  full_executable = find_executable (executable, search);
591  if (!full_executable)
592    goto error;
593  cmdline = argv_to_cmdline (argv);
594  if (!cmdline)
595    goto error;
596   
597  /* Create the child process.  */ 
598  if (!CreateProcess (full_executable, cmdline, 
599                      /*lpProcessAttributes=*/NULL,
600                      /*lpThreadAttributes=*/NULL,
601                      /*bInheritHandles=*/TRUE,
602                      dwCreationFlags,
603                      (LPVOID) env_block,
604                      /*lpCurrentDirectory=*/NULL,
605                      si,
606                      pi))
607    {
608      free (env_block);
609
610      free (full_executable);
611
612      return (pid_t) -1;
613    }
614
615  /* Clean up.  */
616  CloseHandle (pi->hThread);
617  free (full_executable);
618  free (env_block);
619
620  return (pid_t) pi->hProcess;
621
622 error:
623  free (env_block);
624  free (cmdline);
625  free (full_executable);
626
627  return (pid_t) -1;
628}
629
630/* Spawn a script.  This simulates the Unix script execution mechanism.
631   This function is called as a fallback if win32_spawn fails. */
632
633static pid_t
634spawn_script (const char *executable, char *const *argv,
635              char* const *env,
636              DWORD dwCreationFlags,
637              LPSTARTUPINFO si,
638              LPPROCESS_INFORMATION pi)
639{
640  pid_t pid = (pid_t) -1;
641  int save_errno = errno;
642  int fd = _open (executable, _O_RDONLY);
643
644  /* Try to open script, check header format, extract interpreter path,
645     and spawn script using that interpretter. */
646  if (fd >= 0)
647    {
648      char buf[MAX_PATH + 5];
649      int len = _read (fd, buf, sizeof (buf) - 1);
650      _close (fd);
651      if (len > 3)
652        {
653          char *eol;
654          buf[len] = '\0';
655          eol = strchr (buf, '\n');
656          if (eol && strncmp (buf, "#!", 2) == 0)
657            {
658           
659              /* Header format is OK. */
660              char *executable1;
661              int new_argc;
662              const char **avhere;
663
664              /* Extract interpreter path. */
665              do
666                *eol = '\0';
667              while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
668              for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
669                continue;
670              backslashify (executable1);
671
672              /* Duplicate argv, prepending the interpreter path. */
673              new_argc = argv_to_argc (argv) + 1;
674              avhere = XNEWVEC (const char *, new_argc + 1);
675              *avhere = executable1;
676              memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
677              argv = (char *const *)avhere;
678
679              /* Spawn the child. */
680#ifndef USE_MINGW_MSYS
681              executable = strrchr (executable1, '\\') + 1;
682              if (!executable)
683                executable = executable1;
684              pid = win32_spawn (executable, TRUE, argv, env,
685                                 dwCreationFlags, si, pi);
686#else
687              if (strchr (executable1, '\\') == NULL)
688                pid = win32_spawn (executable1, TRUE, argv, env,
689                                   dwCreationFlags, si, pi);
690              else if (executable1[0] != '\\')
691                pid = win32_spawn (executable1, FALSE, argv, env,
692                                   dwCreationFlags, si, pi);
693              else
694                {
695                  const char *newex = mingw_rootify (executable1);
696                  *avhere = newex;
697                  pid = win32_spawn (newex, FALSE, argv, env,
698                                     dwCreationFlags, si, pi);
699                  if (executable1 != newex)
700                    free ((char *) newex);
701                  if (pid == (pid_t) -1)
702                    {
703                      newex = msys_rootify (executable1);
704                      if (newex != executable1)
705                        {
706                          *avhere = newex;
707                          pid = win32_spawn (newex, FALSE, argv, env,
708                                             dwCreationFlags, si, pi);
709                          free ((char *) newex);
710                        }
711                    }
712                }
713#endif
714              free (avhere);
715            }
716        }
717    }
718  if (pid == (pid_t) -1)
719    errno = save_errno;
720  return pid;
721}
722
723/* Execute a child.  */
724
725static pid_t
726pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
727                      const char *executable, char * const * argv,
728                      char* const* env,
729                      int in, int out, int errdes,
730                      int toclose ATTRIBUTE_UNUSED,
731                      const char **errmsg,
732                      int *err)
733{
734  pid_t pid;
735  HANDLE stdin_handle;
736  HANDLE stdout_handle;
737  HANDLE stderr_handle;
738  DWORD dwCreationFlags;
739  OSVERSIONINFO version_info;
740  STARTUPINFO si;
741  PROCESS_INFORMATION pi;
742  int orig_out, orig_in, orig_err;
743  BOOL separate_stderr = !(flags & PEX_STDERR_TO_STDOUT);
744
745  /* Ensure we have inheritable descriptors to pass to the child, and close the
746     original descriptors.  */
747  orig_in = in;
748  in = _dup (orig_in);
749  if (orig_in != STDIN_FILENO)
750    _close (orig_in);
751 
752  orig_out = out;
753  out = _dup (orig_out);
754  if (orig_out != STDOUT_FILENO)
755    _close (orig_out);
756 
757  if (separate_stderr)
758    {
759      orig_err = errdes;
760      errdes = _dup (orig_err);
761      if (orig_err != STDERR_FILENO)
762        _close (orig_err);
763    }
764
765  stdin_handle = INVALID_HANDLE_VALUE;
766  stdout_handle = INVALID_HANDLE_VALUE;
767  stderr_handle = INVALID_HANDLE_VALUE;
768
769  stdin_handle = (HANDLE) _get_osfhandle (in);
770  stdout_handle = (HANDLE) _get_osfhandle (out);
771  if (separate_stderr)
772    stderr_handle = (HANDLE) _get_osfhandle (errdes);
773  else
774    stderr_handle = stdout_handle;
775
776  /* Determine the version of Windows we are running on.  */
777  version_info.dwOSVersionInfoSize = sizeof (version_info); 
778  GetVersionEx (&version_info);
779  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
780    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
781       supported, so we cannot avoid creating a console window.  */
782    dwCreationFlags = 0;
783  else
784    {
785      HANDLE conout_handle;
786
787      /* Determine whether or not we have an associated console.  */
788      conout_handle = CreateFile("CONOUT$", 
789                                 GENERIC_WRITE,
790                                 FILE_SHARE_WRITE,
791                                 /*lpSecurityAttributes=*/NULL,
792                                 OPEN_EXISTING,
793                                 FILE_ATTRIBUTE_NORMAL,
794                                 /*hTemplateFile=*/NULL);
795      if (conout_handle == INVALID_HANDLE_VALUE)
796        /* There is no console associated with this process.  Since
797           the child is a console process, the OS would normally
798           create a new console Window for the child.  Since we'll be
799           redirecting the child's standard streams, we do not need
800           the console window.  */ 
801        dwCreationFlags = CREATE_NO_WINDOW;
802      else 
803        {
804          /* There is a console associated with the process, so the OS
805             will not create a new console.  And, if we use
806             CREATE_NO_WINDOW in this situation, the child will have
807             no associated console.  Therefore, if the child's
808             standard streams are connected to the console, the output
809             will be discarded.  */
810          CloseHandle(conout_handle);
811          dwCreationFlags = 0;
812        }
813    }
814
815  /* Since the child will be a console process, it will, by default,
816     connect standard input/output to its console.  However, we want
817     the child to use the handles specifically designated above.  In
818     addition, if there is no console (such as when we are running in
819     a Cygwin X window), then we must redirect the child's
820     input/output, as there is no console for the child to use.  */
821  memset (&si, 0, sizeof (si));
822  si.cb = sizeof (si);
823  si.dwFlags = STARTF_USESTDHANDLES;
824  si.hStdInput = stdin_handle;
825  si.hStdOutput = stdout_handle;
826  si.hStdError = stderr_handle;
827
828  /* Create the child process.  */ 
829  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
830                     argv, env, dwCreationFlags, &si, &pi);
831  if (pid == (pid_t) -1)
832    pid = spawn_script (executable, argv, env, dwCreationFlags,
833                        &si, &pi);
834  if (pid == (pid_t) -1)
835    {
836      *err = ENOENT;
837      *errmsg = "CreateProcess";
838    }
839
840  /* Close the standard input, standard output and standard error handles
841     in the parent.  */ 
842
843  _close (in);
844  _close (out);
845  if (separate_stderr)
846    _close (errdes);
847
848  return pid;
849}
850
851/* Wait for a child process to complete.  MS CRTDLL doesn't return
852   enough information in status to decide if the child exited due to a
853   signal or not, rather it simply returns an integer with the exit
854   code of the child; eg., if the child exited with an abort() call
855   and didn't have a handler for SIGABRT, it simply returns with
856   status == 3.  We fix the status code to conform to the usual WIF*
857   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
858
859static pid_t
860pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
861                int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
862                const char **errmsg, int *err)
863{
864  DWORD termstat;
865  HANDLE h;
866
867  if (time != NULL)
868    memset (time, 0, sizeof *time);
869
870  h = (HANDLE) pid;
871
872  /* FIXME: If done is non-zero, we should probably try to kill the
873     process.  */
874  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
875    {
876      CloseHandle (h);
877      *err = ECHILD;
878      *errmsg = "WaitForSingleObject";
879      return -1;
880    }
881
882  GetExitCodeProcess (h, &termstat);
883  CloseHandle (h);
884 
885  /* A value of 3 indicates that the child caught a signal, but not
886     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
887     report SIGABRT.  */
888  if (termstat == 3)
889    *status = SIGABRT;
890  else
891    *status = (termstat & 0xff) << 8;
892
893  return 0;
894}
895
896/* Create a pipe.  */
897
898static int
899pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
900                int binary)
901{
902  return _pipe (p, 256, (binary ? _O_BINARY : _O_TEXT) | _O_NOINHERIT);
903}
904
905/* Get a FILE pointer to read from a file descriptor.  */
906
907static FILE *
908pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
909                   int binary)
910{
911  HANDLE h = (HANDLE) _get_osfhandle (fd);
912  if (h == INVALID_HANDLE_VALUE)
913    return NULL;
914  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
915    return NULL;
916  return fdopen (fd, binary ? "rb" : "r");
917}
918
919static FILE *
920pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
921                   int binary)
922{
923  HANDLE h = (HANDLE) _get_osfhandle (fd);
924  if (h == INVALID_HANDLE_VALUE)
925    return NULL;
926  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
927    return NULL;
928  return fdopen (fd, binary ? "wb" : "w");
929}
930
931#ifdef MAIN
932#include <stdio.h>
933
934int
935main (int argc ATTRIBUTE_UNUSED, char **argv)
936{
937  char const *errmsg;
938  int err;
939  argv++;
940  printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
941  exit (0);
942}
943#endif
Note: See TracBrowser for help on using the repository browser.