OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.2.2/] [libiberty/] [pex-win32.c] - Blame information for rev 277

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* 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
4
   Free Software Foundation, Inc.
5
 
6
This file is part of the libiberty library.
7
Libiberty is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Library General Public
9
License as published by the Free Software Foundation; either
10
version 2 of the License, or (at your option) any later version.
11
 
12
Libiberty is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
Library General Public License for more details.
16
 
17
You should have received a copy of the GNU Library General Public
18
License along with libiberty; see the file COPYING.LIB.  If not,
19
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20
Boston, 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
 
48
/* mingw32 headers may not define the following.  */
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
/* Ensure that the executable pathname uses Win32 backslashes. This
67
   is not necessary on NT, but on W9x, forward slashes causes
68
   failure of spawn* and exec* functions (and probably any function
69
   that calls CreateProcess) *iff* the executable pathname (argv[0])
70
   is a quoted string.  And quoting is necessary in case a pathname
71
   contains embedded white space.  You can't win.  */
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
/* The list of functions we pass to the common routines.  */
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 /* cleanup */
106
};
107
 
108
/* Return a newly initialized pex_obj structure.  */
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
/* Open a file for reading.  */
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
/* Open a file for writing.  */
126
 
127
static int
128
pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
129
                      int binary)
130
{
131
  /* Note that we can't use O_EXCL here because gcc may have already
132
     created the temporary file via make_temp_file.  */
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
/* Close a file.  */
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
/* Tack the executable on the end of a (possibly slash terminated) buffer
151
   and convert everything to \. */
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
/* Walk down a registry hierarchy until the end.  Return the key. */
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
/* Return the "mingw root" as derived from the mingw uninstall information. */
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
  /* Open the uninstall "directory". */
193
  hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
194
 
195
  /* Not found. */
196
  if (!hKey)
197
    return executable;
198
 
199
  /* Need to enumerate all of the keys here looking for one the most recent
200
     one for MinGW. */
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
  /* Look through all of the keys for one that begins with Minimal GNU...
221
     Try to get the latest version by doing a string compare although that
222
     string never really works with version number sorting. */
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
  /* If foundbuf is empty, we didn't find anything.  Punt. */
236
  if (!foundbuf[0])
237
    {
238
      free (foundbuf);
239
      RegCloseKey (hKey);
240
      return executable;
241
    }
242
 
243
  /* Open the key that we wanted */
244
  res = RegOpenKey (hKey, foundbuf, &hTmp);
245
  RegCloseKey (hKey);
246
  free (foundbuf);
247
 
248
  /* Don't know why this would fail, but you gotta check */
249
  if (res != ERROR_SUCCESS)
250
    return executable;
251
 
252
  maxlen = 0;
253
  /* Get the length of the value pointed to by InstallLocation */
254
  if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
255
                       &maxlen) != ERROR_SUCCESS || maxlen == 0)
256
    {
257
      RegCloseKey (hTmp);
258
      return executable;
259
    }
260
 
261
  /* Allocate space for the install location */
262
  foundbuf = XNEWVEC (char, maxlen + strlen (executable));
263
  if (!foundbuf)
264
    {
265
      free (foundbuf);
266
      RegCloseKey (hTmp);
267
    }
268
 
269
  /* Read the install location into the buffer */
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
  /* Concatenate the install location and the executable, turn all slashes
280
     to backslashes, and return that. */
281
  return tack_on_executable (foundbuf, executable);
282
}
283
 
284
/* Read the install location of msys from it's installation file and
285
   rootify the executable based on that. */
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
  /* failed */
318
  if (buf)
319
    free (buf);
320
  return executable;
321
}
322
#endif
323
 
324
/* Return a Windows command-line from ARGV.  It is the caller's
325
   responsibility to free the string returned.  */
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
      /* We quote every last argument.  This simplifies the problem;
339
         we need only escape embedded double-quotes and immediately
340
         preceeding backslash characters.  A sequence of backslach characters
341
         that is not follwed by a double quote character will not be
342
         escaped.  */
343
      for (j = 0; argv[i][j]; j++)
344
        {
345
          if (argv[i][j] == '"')
346
            {
347
              /* Escape preceeding backslashes.  */
348
              for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
349
                cmdline_len++;
350
              /* Escape the qote character.  */
351
              cmdline_len++;
352
            }
353
        }
354
      /* Trailing backslashes also need to be escaped because they will be
355
         followed by the terminating quote.  */
356
      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
357
        cmdline_len++;
358
      cmdline_len += j;
359
      cmdline_len += 3;  /* for leading and trailing quotes and space */
360
    }
361
  cmdline = xmalloc (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
static const char *const
386
std_suffixes[] = {
387
  ".com",
388
  ".exe",
389
  ".bat",
390
  ".cmd",
391
 
392
};
393
static const char *const
394
no_suffixes[] = {
395
  "",
396
 
397
};
398
 
399
/* Returns the full path to PROGRAM.  If SEARCH is true, look for
400
   PROGRAM in each directory in PATH.  */
401
 
402
static char *
403
find_executable (const char *program, BOOL search)
404
{
405
  char *full_executable;
406
  char *e;
407
  size_t fe_len;
408
  const char *path = 0;
409
  const char *const *ext;
410
  const char *p, *q;
411
  size_t proglen = strlen (program);
412
  int has_extension = !!strchr (program, '.');
413
  int has_slash = (strchr (program, '/') || strchr (program, '\\'));
414
  HANDLE h;
415
 
416
  if (has_slash)
417
    search = FALSE;
418
 
419
  if (search)
420
    path = getenv ("PATH");
421
  if (!path)
422
    path = "";
423
 
424
  fe_len = 0;
425
  for (p = path; *p; p = q)
426
    {
427
      q = p;
428
      while (*q != ';' && *q != '\0')
429
        q++;
430
      if ((size_t)(q - p) > fe_len)
431
        fe_len = q - p;
432
      if (*q == ';')
433
        q++;
434
    }
435
  fe_len = fe_len + 1 + proglen + (has_extension ? 1 : 5);
436
  full_executable = xmalloc (fe_len);
437
 
438
  p = path;
439
  do
440
    {
441
      q = p;
442
      while (*q != ';' && *q != '\0')
443
        q++;
444
 
445
      e = full_executable;
446
      memcpy (e, p, q - p);
447
      e += (q - p);
448
      if (q - p)
449
        *e++ = '\\';
450
      strcpy (e, program);
451
 
452
      if (*q == ';')
453
        q++;
454
 
455
      for (e = full_executable; *e; e++)
456
        if (*e == '/')
457
          *e = '\\';
458
 
459
      /* At this point, e points to the terminating NUL character for
460
         full_executable.  */
461
      for (ext = has_extension ? no_suffixes : std_suffixes; *ext; ext++)
462
        {
463
          /* Remove any current extension.  */
464
          *e = '\0';
465
          /* Add the new one.  */
466
          strcat (full_executable, *ext);
467
 
468
          /* Attempt to open this file.  */
469
          h = CreateFile (full_executable, GENERIC_READ,
470
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
471
                          0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
472
          if (h != INVALID_HANDLE_VALUE)
473
            goto found;
474
        }
475
      p = q;
476
    }
477
  while (*p);
478
  free (full_executable);
479
  return 0;
480
 
481
 found:
482
  CloseHandle (h);
483
  return full_executable;
484
}
485
 
486
/* Low-level process creation function and helper.  */
487
 
488
static int
489
env_compare (const void *a_ptr, const void *b_ptr)
490
{
491
  const char *a;
492
  const char *b;
493
  unsigned char c1;
494
  unsigned char c2;
495
 
496
  a = *(const char **) a_ptr;
497
  b = *(const char **) b_ptr;
498
 
499
  /* a and b will be of the form: VAR=VALUE
500
     We compare only the variable name part here using a case-insensitive
501
     comparison algorithm.  It might appear that in fact strcasecmp () can
502
     take the place of this whole function, and indeed it could, save for
503
     the fact that it would fail in cases such as comparing A1=foo and
504
     A=bar (because 1 is less than = in the ASCII character set).
505
     (Environment variables containing no numbers would work in such a
506
     scenario.)  */
507
 
508
  do
509
    {
510
      c1 = (unsigned char) tolower (*a++);
511
      c2 = (unsigned char) tolower (*b++);
512
 
513
      if (c1 == '=')
514
        c1 = '\0';
515
 
516
      if (c2 == '=')
517
        c2 = '\0';
518
    }
519
  while (c1 == c2 && c1 != '\0');
520
 
521
  return c1 - c2;
522
}
523
 
524
static long
525
win32_spawn (const char *executable,
526
             BOOL search,
527
             char *const *argv,
528
             char *const *env, /* array of strings of the form: VAR=VALUE */
529
             DWORD dwCreationFlags,
530
             LPSTARTUPINFO si,
531
             LPPROCESS_INFORMATION pi)
532
{
533
  char *full_executable;
534
  char *cmdline;
535
  char **env_copy;
536
  char *env_block = NULL;
537
 
538
  full_executable = NULL;
539
  cmdline = NULL;
540
 
541
  if (env)
542
    {
543
      int env_size;
544
 
545
      /* Count the number of environment bindings supplied.  */
546
      for (env_size = 0; env[env_size]; env_size++)
547
        continue;
548
 
549
      /* Assemble an environment block, if required.  This consists of
550
         VAR=VALUE strings juxtaposed (with one null character between each
551
         pair) and an additional null at the end.  */
552
      if (env_size > 0)
553
        {
554
          int var;
555
          int total_size = 1; /* 1 is for the final null.  */
556
          char *bufptr;
557
 
558
          /* Windows needs the members of the block to be sorted by variable
559
             name.  */
560
          env_copy = alloca (sizeof (char *) * env_size);
561
          memcpy (env_copy, env, sizeof (char *) * env_size);
562
          qsort (env_copy, env_size, sizeof (char *), env_compare);
563
 
564
          for (var = 0; var < env_size; var++)
565
            total_size += strlen (env[var]) + 1;
566
 
567
          env_block = malloc (total_size);
568
          bufptr = env_block;
569
          for (var = 0; var < env_size; var++)
570
            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
571
 
572
          *bufptr = '\0';
573
        }
574
    }
575
 
576
  full_executable = find_executable (executable, search);
577
  if (!full_executable)
578
    goto error;
579
  cmdline = argv_to_cmdline (argv);
580
  if (!cmdline)
581
    goto error;
582
 
583
  /* Create the child process.  */
584
  if (!CreateProcess (full_executable, cmdline,
585
                      /*lpProcessAttributes=*/NULL,
586
                      /*lpThreadAttributes=*/NULL,
587
                      /*bInheritHandles=*/TRUE,
588
                      dwCreationFlags,
589
                      (LPVOID) env_block,
590
                      /*lpCurrentDirectory=*/NULL,
591
                      si,
592
                      pi))
593
    {
594
      if (env_block)
595
        free (env_block);
596
 
597
      free (full_executable);
598
 
599
      return -1;
600
    }
601
 
602
  /* Clean up.  */
603
  CloseHandle (pi->hThread);
604
  free (full_executable);
605
  if (env_block)
606
    free (env_block);
607
 
608
  return (long) pi->hProcess;
609
 
610
 error:
611
  if (env_block)
612
    free (env_block);
613
  if (cmdline)
614
    free (cmdline);
615
  if (full_executable)
616
    free (full_executable);
617
 
618
  return -1;
619
}
620
 
621
static long
622
spawn_script (const char *executable, char *const *argv,
623
              char* const *env,
624
              DWORD dwCreationFlags,
625
              LPSTARTUPINFO si,
626
              LPPROCESS_INFORMATION pi)
627
{
628
  int pid = -1;
629
  int save_errno = errno;
630
  int fd = _open (executable, _O_RDONLY);
631
 
632
  if (fd >= 0)
633
    {
634
      char buf[MAX_PATH + 5];
635
      int len = _read (fd, buf, sizeof (buf) - 1);
636
      _close (fd);
637
      if (len > 3)
638
        {
639
          char *eol;
640
          buf[len] = '\0';
641
          eol = strchr (buf, '\n');
642
          if (eol && strncmp (buf, "#!", 2) == 0)
643
            {
644
              char *executable1;
645
              const char ** avhere = (const char **) --argv;
646
              do
647
                *eol = '\0';
648
              while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
649
              for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
650
                continue;
651
 
652
              backslashify (executable1);
653
              *avhere = executable1;
654
#ifndef USE_MINGW_MSYS
655
              executable = strrchr (executable1, '\\') + 1;
656
              if (!executable)
657
                executable = executable1;
658
              pid = win32_spawn (executable, TRUE, argv, env,
659
                                 dwCreationFlags, si, pi);
660
#else
661
              if (strchr (executable1, '\\') == NULL)
662
                pid = win32_spawn (executable1, TRUE, argv, env,
663
                                   dwCreationFlags, si, pi);
664
              else if (executable1[0] != '\\')
665
                pid = win32_spawn (executable1, FALSE, argv, env,
666
                                   dwCreationFlags, si, pi);
667
              else
668
                {
669
                  const char *newex = mingw_rootify (executable1);
670
                  *avhere = newex;
671
                  pid = win32_spawn (newex, FALSE, argv, env,
672
                                     dwCreationFlags, si, pi);
673
                  if (executable1 != newex)
674
                    free ((char *) newex);
675
                  if (pid < 0)
676
                    {
677
                      newex = msys_rootify (executable1);
678
                      if (newex != executable1)
679
                        {
680
                          *avhere = newex;
681
                          pid = win32_spawn (newex, FALSE, argv, env,
682
                                             dwCreationFlags, si, pi);
683
                          free ((char *) newex);
684
                        }
685
                    }
686
                }
687
#endif
688
            }
689
        }
690
    }
691
  if (pid < 0)
692
    errno = save_errno;
693
  return pid;
694
}
695
 
696
/* Execute a child.  */
697
 
698
static long
699
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
700
                      const char *executable, char * const * argv,
701
                      char* const* env,
702
                      int in, int out, int errdes,
703
                      int toclose ATTRIBUTE_UNUSED,
704
                      const char **errmsg,
705
                      int *err)
706
{
707
  long pid;
708
  HANDLE stdin_handle;
709
  HANDLE stdout_handle;
710
  HANDLE stderr_handle;
711
  DWORD dwCreationFlags;
712
  OSVERSIONINFO version_info;
713
  STARTUPINFO si;
714
  PROCESS_INFORMATION pi;
715
 
716
  stdin_handle = INVALID_HANDLE_VALUE;
717
  stdout_handle = INVALID_HANDLE_VALUE;
718
  stderr_handle = INVALID_HANDLE_VALUE;
719
 
720
  stdin_handle = (HANDLE) _get_osfhandle (in);
721
  stdout_handle = (HANDLE) _get_osfhandle (out);
722
  if (!(flags & PEX_STDERR_TO_STDOUT))
723
    stderr_handle = (HANDLE) _get_osfhandle (errdes);
724
  else
725
    stderr_handle = stdout_handle;
726
 
727
  /* Determine the version of Windows we are running on.  */
728
  version_info.dwOSVersionInfoSize = sizeof (version_info);
729
  GetVersionEx (&version_info);
730
  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
731
    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
732
       supported, so we cannot avoid creating a console window.  */
733
    dwCreationFlags = 0;
734
  else
735
    {
736
      HANDLE conout_handle;
737
 
738
      /* Determine whether or not we have an associated console.  */
739
      conout_handle = CreateFile("CONOUT$",
740
                                 GENERIC_WRITE,
741
                                 FILE_SHARE_WRITE,
742
                                 /*lpSecurityAttributes=*/NULL,
743
                                 OPEN_EXISTING,
744
                                 FILE_ATTRIBUTE_NORMAL,
745
                                 /*hTemplateFile=*/NULL);
746
      if (conout_handle == INVALID_HANDLE_VALUE)
747
        /* There is no console associated with this process.  Since
748
           the child is a console process, the OS would normally
749
           create a new console Window for the child.  Since we'll be
750
           redirecting the child's standard streams, we do not need
751
           the console window.  */
752
        dwCreationFlags = CREATE_NO_WINDOW;
753
      else
754
        {
755
          /* There is a console associated with the process, so the OS
756
             will not create a new console.  And, if we use
757
             CREATE_NO_WINDOW in this situation, the child will have
758
             no associated console.  Therefore, if the child's
759
             standard streams are connected to the console, the output
760
             will be discarded.  */
761
          CloseHandle(conout_handle);
762
          dwCreationFlags = 0;
763
        }
764
    }
765
 
766
  /* Since the child will be a console process, it will, by default,
767
     connect standard input/output to its console.  However, we want
768
     the child to use the handles specifically designated above.  In
769
     addition, if there is no console (such as when we are running in
770
     a Cygwin X window), then we must redirect the child's
771
     input/output, as there is no console for the child to use.  */
772
  memset (&si, 0, sizeof (si));
773
  si.cb = sizeof (si);
774
  si.dwFlags = STARTF_USESTDHANDLES;
775
  si.hStdInput = stdin_handle;
776
  si.hStdOutput = stdout_handle;
777
  si.hStdError = stderr_handle;
778
 
779
  /* Create the child process.  */
780
  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
781
                     argv, env, dwCreationFlags, &si, &pi);
782
  if (pid == -1)
783
    pid = spawn_script (executable, argv, env, dwCreationFlags,
784
                        &si, &pi);
785
  if (pid == -1)
786
    {
787
      *err = ENOENT;
788
      *errmsg = "CreateProcess";
789
    }
790
 
791
  /* Close the standard output and standard error handles in the
792
     parent.  */
793
  if (out != STDOUT_FILENO)
794
    obj->funcs->close (obj, out);
795
  if (errdes != STDERR_FILENO)
796
    obj->funcs->close (obj, errdes);
797
 
798
  return pid;
799
}
800
 
801
/* Wait for a child process to complete.  MS CRTDLL doesn't return
802
   enough information in status to decide if the child exited due to a
803
   signal or not, rather it simply returns an integer with the exit
804
   code of the child; eg., if the child exited with an abort() call
805
   and didn't have a handler for SIGABRT, it simply returns with
806
   status == 3.  We fix the status code to conform to the usual WIF*
807
   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
808
 
809
static int
810
pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
811
                int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
812
                const char **errmsg, int *err)
813
{
814
  DWORD termstat;
815
  HANDLE h;
816
 
817
  if (time != NULL)
818
    memset (time, 0, sizeof *time);
819
 
820
  h = (HANDLE) pid;
821
 
822
  /* FIXME: If done is non-zero, we should probably try to kill the
823
     process.  */
824
  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
825
    {
826
      CloseHandle (h);
827
      *err = ECHILD;
828
      *errmsg = "WaitForSingleObject";
829
      return -1;
830
    }
831
 
832
  GetExitCodeProcess (h, &termstat);
833
  CloseHandle (h);
834
 
835
  /* A value of 3 indicates that the child caught a signal, but not
836
     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
837
     report SIGABRT.  */
838
  if (termstat == 3)
839
    *status = SIGABRT;
840
  else
841
    *status = (termstat & 0xff) << 8;
842
 
843
  return 0;
844
}
845
 
846
/* Create a pipe.  */
847
 
848
static int
849
pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
850
                int binary)
851
{
852
  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
853
}
854
 
855
/* Get a FILE pointer to read from a file descriptor.  */
856
 
857
static FILE *
858
pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
859
                   int binary)
860
{
861
  return fdopen (fd, binary ? "rb" : "r");
862
}
863
 
864
static FILE *
865
pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
866
                   int binary)
867
{
868
  HANDLE h = (HANDLE) _get_osfhandle (fd);
869
  if (h == INVALID_HANDLE_VALUE)
870
    return NULL;
871
  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
872
    return NULL;
873
  return fdopen (fd, binary ? "wb" : "w");
874
}
875
 
876
#ifdef MAIN
877
#include <stdio.h>
878
 
879
int
880
main (int argc ATTRIBUTE_UNUSED, char **argv)
881
{
882
  char const *errmsg;
883
  int err;
884
  argv++;
885
  printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
886
  exit (0);
887
}
888
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.