OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [binutils-2.18.50/] [libiberty/] [pex-win32.c] - Blame information for rev 868

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, 2006
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 pid_t 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 *, pid_t, 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 = 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
/* We'll try the passed filename with all the known standard
386
   extensions, and then without extension.  We try no extension
387
   last so that we don't try to run some random extension-less
388
   file that might be hanging around.  We try both extension
389
   and no extension so that we don't need any fancy logic
390
   to determine if a file has extension.  */
391
static const char *const
392
std_suffixes[] = {
393
  ".com",
394
  ".exe",
395
  ".bat",
396
  ".cmd",
397
  "",
398
 
399
};
400
 
401
/* Returns the full path to PROGRAM.  If SEARCH is true, look for
402
   PROGRAM in each directory in PATH.  */
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 /* space for extension */;
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
      /* At this point, e points to the terminating NUL character for
461
         full_executable.  */
462
      for (ext = std_suffixes; *ext; ext++)
463
        {
464
          /* Remove any current extension.  */
465
          *e = '\0';
466
          /* Add the new one.  */
467
          strcat (full_executable, *ext);
468
 
469
          /* Attempt to open this file.  */
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
/* Low-level process creation function and helper.  */
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
  /* a and b will be of the form: VAR=VALUE
501
     We compare only the variable name part here using a case-insensitive
502
     comparison algorithm.  It might appear that in fact strcasecmp () can
503
     take the place of this whole function, and indeed it could, save for
504
     the fact that it would fail in cases such as comparing A1=foo and
505
     A=bar (because 1 is less than = in the ASCII character set).
506
     (Environment variables containing no numbers would work in such a
507
     scenario.)  */
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 pid_t
526
win32_spawn (const char *executable,
527
             BOOL search,
528
             char *const *argv,
529
             char *const *env, /* array of strings of the form: VAR=VALUE */
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
      /* Count the number of environment bindings supplied.  */
547
      for (env_size = 0; env[env_size]; env_size++)
548
        continue;
549
 
550
      /* Assemble an environment block, if required.  This consists of
551
         VAR=VALUE strings juxtaposed (with one null character between each
552
         pair) and an additional null at the end.  */
553
      if (env_size > 0)
554
        {
555
          int var;
556
          int total_size = 1; /* 1 is for the final null.  */
557
          char *bufptr;
558
 
559
          /* Windows needs the members of the block to be sorted by variable
560
             name.  */
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; var++)
566
            total_size += strlen (env[var]) + 1;
567
 
568
          env_block = XNEWVEC (char, total_size);
569
          bufptr = env_block;
570
          for (var = 0; var < env_size; var++)
571
            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
572
 
573
          *bufptr = '\0';
574
        }
575
    }
576
 
577
  full_executable = find_executable (executable, search);
578
  if (!full_executable)
579
    goto error;
580
  cmdline = argv_to_cmdline (argv);
581
  if (!cmdline)
582
    goto error;
583
 
584
  /* Create the child process.  */
585
  if (!CreateProcess (full_executable, cmdline,
586
                      /*lpProcessAttributes=*/NULL,
587
                      /*lpThreadAttributes=*/NULL,
588
                      /*bInheritHandles=*/TRUE,
589
                      dwCreationFlags,
590
                      (LPVOID) env_block,
591
                      /*lpCurrentDirectory=*/NULL,
592
                      si,
593
                      pi))
594
    {
595
      if (env_block)
596
        free (env_block);
597
 
598
      free (full_executable);
599
 
600
      return (pid_t) -1;
601
    }
602
 
603
  /* Clean up.  */
604
  CloseHandle (pi->hThread);
605
  free (full_executable);
606
  if (env_block)
607
    free (env_block);
608
 
609
  return (pid_t) pi->hProcess;
610
 
611
 error:
612
  if (env_block)
613
    free (env_block);
614
  if (cmdline)
615
    free (cmdline);
616
  if (full_executable)
617
    free (full_executable);
618
 
619
  return (pid_t) -1;
620
}
621
 
622
static pid_t
623
spawn_script (const char *executable, char *const *argv,
624
              char* const *env,
625
              DWORD dwCreationFlags,
626
              LPSTARTUPINFO si,
627
              LPPROCESS_INFORMATION pi)
628
{
629
  pid_t pid = (pid_t) -1;
630
  int save_errno = errno;
631
  int fd = _open (executable, _O_RDONLY);
632
 
633
  if (fd >= 0)
634
    {
635
      char buf[MAX_PATH + 5];
636
      int len = _read (fd, buf, sizeof (buf) - 1);
637
      _close (fd);
638
      if (len > 3)
639
        {
640
          char *eol;
641
          buf[len] = '\0';
642
          eol = strchr (buf, '\n');
643
          if (eol && strncmp (buf, "#!", 2) == 0)
644
            {
645
              char *executable1;
646
              const char ** avhere = (const char **) --argv;
647
              do
648
                *eol = '\0';
649
              while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
650
              for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
651
                continue;
652
 
653
              backslashify (executable1);
654
              *avhere = executable1;
655
#ifndef USE_MINGW_MSYS
656
              executable = strrchr (executable1, '\\') + 1;
657
              if (!executable)
658
                executable = executable1;
659
              pid = win32_spawn (executable, TRUE, argv, env,
660
                                 dwCreationFlags, si, pi);
661
#else
662
              if (strchr (executable1, '\\') == NULL)
663
                pid = win32_spawn (executable1, TRUE, argv, env,
664
                                   dwCreationFlags, si, pi);
665
              else if (executable1[0] != '\\')
666
                pid = win32_spawn (executable1, FALSE, argv, env,
667
                                   dwCreationFlags, si, pi);
668
              else
669
                {
670
                  const char *newex = mingw_rootify (executable1);
671
                  *avhere = newex;
672
                  pid = win32_spawn (newex, FALSE, argv, env,
673
                                     dwCreationFlags, si, pi);
674
                  if (executable1 != newex)
675
                    free ((char *) newex);
676
                  if ((long) pid < 0)
677
                    {
678
                      newex = msys_rootify (executable1);
679
                      if (newex != executable1)
680
                        {
681
                          *avhere = newex;
682
                          pid = win32_spawn (newex, FALSE, argv, env,
683
                                             dwCreationFlags, si, pi);
684
                          free ((char *) newex);
685
                        }
686
                    }
687
                }
688
#endif
689
            }
690
        }
691
    }
692
  if ((long) pid < 0)
693
    errno = save_errno;
694
  return pid;
695
}
696
 
697
/* Execute a child.  */
698
 
699
static pid_t
700
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
701
                      const char *executable, char * const * argv,
702
                      char* const* env,
703
                      int in, int out, int errdes,
704
                      int toclose ATTRIBUTE_UNUSED,
705
                      const char **errmsg,
706
                      int *err)
707
{
708
  pid_t pid;
709
  HANDLE stdin_handle;
710
  HANDLE stdout_handle;
711
  HANDLE stderr_handle;
712
  DWORD dwCreationFlags;
713
  OSVERSIONINFO version_info;
714
  STARTUPINFO si;
715
  PROCESS_INFORMATION pi;
716
 
717
  stdin_handle = INVALID_HANDLE_VALUE;
718
  stdout_handle = INVALID_HANDLE_VALUE;
719
  stderr_handle = INVALID_HANDLE_VALUE;
720
 
721
  stdin_handle = (HANDLE) _get_osfhandle (in);
722
  stdout_handle = (HANDLE) _get_osfhandle (out);
723
  if (!(flags & PEX_STDERR_TO_STDOUT))
724
    stderr_handle = (HANDLE) _get_osfhandle (errdes);
725
  else
726
    stderr_handle = stdout_handle;
727
 
728
  /* Determine the version of Windows we are running on.  */
729
  version_info.dwOSVersionInfoSize = sizeof (version_info);
730
  GetVersionEx (&version_info);
731
  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
732
    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
733
       supported, so we cannot avoid creating a console window.  */
734
    dwCreationFlags = 0;
735
  else
736
    {
737
      HANDLE conout_handle;
738
 
739
      /* Determine whether or not we have an associated console.  */
740
      conout_handle = CreateFile("CONOUT$",
741
                                 GENERIC_WRITE,
742
                                 FILE_SHARE_WRITE,
743
                                 /*lpSecurityAttributes=*/NULL,
744
                                 OPEN_EXISTING,
745
                                 FILE_ATTRIBUTE_NORMAL,
746
                                 /*hTemplateFile=*/NULL);
747
      if (conout_handle == INVALID_HANDLE_VALUE)
748
        /* There is no console associated with this process.  Since
749
           the child is a console process, the OS would normally
750
           create a new console Window for the child.  Since we'll be
751
           redirecting the child's standard streams, we do not need
752
           the console window.  */
753
        dwCreationFlags = CREATE_NO_WINDOW;
754
      else
755
        {
756
          /* There is a console associated with the process, so the OS
757
             will not create a new console.  And, if we use
758
             CREATE_NO_WINDOW in this situation, the child will have
759
             no associated console.  Therefore, if the child's
760
             standard streams are connected to the console, the output
761
             will be discarded.  */
762
          CloseHandle(conout_handle);
763
          dwCreationFlags = 0;
764
        }
765
    }
766
 
767
  /* Since the child will be a console process, it will, by default,
768
     connect standard input/output to its console.  However, we want
769
     the child to use the handles specifically designated above.  In
770
     addition, if there is no console (such as when we are running in
771
     a Cygwin X window), then we must redirect the child's
772
     input/output, as there is no console for the child to use.  */
773
  memset (&si, 0, sizeof (si));
774
  si.cb = sizeof (si);
775
  si.dwFlags = STARTF_USESTDHANDLES;
776
  si.hStdInput = stdin_handle;
777
  si.hStdOutput = stdout_handle;
778
  si.hStdError = stderr_handle;
779
 
780
  /* Create the child process.  */
781
  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
782
                     argv, env, dwCreationFlags, &si, &pi);
783
  if (pid == (pid_t) -1)
784
    pid = spawn_script (executable, argv, env, dwCreationFlags,
785
                        &si, &pi);
786
  if (pid == (pid_t) -1)
787
    {
788
      *err = ENOENT;
789
      *errmsg = "CreateProcess";
790
    }
791
 
792
  /* Close the standard output and standard error handles in the
793
     parent.  */
794
  if (out != STDOUT_FILENO)
795
    obj->funcs->close (obj, out);
796
  if (errdes != STDERR_FILENO)
797
    obj->funcs->close (obj, errdes);
798
 
799
  return pid;
800
}
801
 
802
/* Wait for a child process to complete.  MS CRTDLL doesn't return
803
   enough information in status to decide if the child exited due to a
804
   signal or not, rather it simply returns an integer with the exit
805
   code of the child; eg., if the child exited with an abort() call
806
   and didn't have a handler for SIGABRT, it simply returns with
807
   status == 3.  We fix the status code to conform to the usual WIF*
808
   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
809
 
810
static int
811
pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
812
                int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
813
                const char **errmsg, int *err)
814
{
815
  DWORD termstat;
816
  HANDLE h;
817
 
818
  if (time != NULL)
819
    memset (time, 0, sizeof *time);
820
 
821
  h = (HANDLE) pid;
822
 
823
  /* FIXME: If done is non-zero, we should probably try to kill the
824
     process.  */
825
  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
826
    {
827
      CloseHandle (h);
828
      *err = ECHILD;
829
      *errmsg = "WaitForSingleObject";
830
      return -1;
831
    }
832
 
833
  GetExitCodeProcess (h, &termstat);
834
  CloseHandle (h);
835
 
836
  /* A value of 3 indicates that the child caught a signal, but not
837
     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
838
     report SIGABRT.  */
839
  if (termstat == 3)
840
    *status = SIGABRT;
841
  else
842
    *status = (termstat & 0xff) << 8;
843
 
844
  return 0;
845
}
846
 
847
/* Create a pipe.  */
848
 
849
static int
850
pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
851
                int binary)
852
{
853
  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
854
}
855
 
856
/* Get a FILE pointer to read from a file descriptor.  */
857
 
858
static FILE *
859
pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
860
                   int binary)
861
{
862
  return fdopen (fd, binary ? "rb" : "r");
863
}
864
 
865
static FILE *
866
pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
867
                   int binary)
868
{
869
  HANDLE h = (HANDLE) _get_osfhandle (fd);
870
  if (h == INVALID_HANDLE_VALUE)
871
    return NULL;
872
  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
873
    return NULL;
874
  return fdopen (fd, binary ? "wb" : "w");
875
}
876
 
877
#ifdef MAIN
878
#include <stdio.h>
879
 
880
int
881
main (int argc ATTRIBUTE_UNUSED, char **argv)
882
{
883
  char const *errmsg;
884
  int err;
885
  argv++;
886
  printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
887
  exit (0);
888
}
889
#endif

powered by: WebSVN 2.1.0

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