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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-binutils/] [binutils-2.19.1/] [libiberty/] [pex-win32.c] - Blame information for rev 13

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

Line No. Rev Author Line
1 6 jlechner
/* 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 the number of arguments in an argv array, not including the null
325
   terminating argument. */
326
 
327
static int
328
argv_to_argc (char *const *argv)
329
{
330
  char *const *i = argv;
331
  while (*i)
332
    i++;
333
  return i - argv;
334
}
335
 
336
/* Return a Windows command-line from ARGV.  It is the caller's
337
   responsibility to free the string returned.  */
338
 
339
static char *
340
argv_to_cmdline (char *const *argv)
341
{
342
  char *cmdline;
343
  char *p;
344
  size_t cmdline_len;
345
  int i, j, k;
346
 
347
  cmdline_len = 0;
348
  for (i = 0; argv[i]; i++)
349
    {
350
      /* We quote every last argument.  This simplifies the problem;
351
         we need only escape embedded double-quotes and immediately
352
         preceeding backslash characters.  A sequence of backslach characters
353
         that is not follwed by a double quote character will not be
354
         escaped.  */
355
      for (j = 0; argv[i][j]; j++)
356
        {
357
          if (argv[i][j] == '"')
358
            {
359
              /* Escape preceeding backslashes.  */
360
              for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
361
                cmdline_len++;
362
              /* Escape the qote character.  */
363
              cmdline_len++;
364
            }
365
        }
366
      /* Trailing backslashes also need to be escaped because they will be
367
         followed by the terminating quote.  */
368
      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
369
        cmdline_len++;
370
      cmdline_len += j;
371
      cmdline_len += 3;  /* for leading and trailing quotes and space */
372
    }
373
  cmdline = XNEWVEC (char, cmdline_len);
374
  p = cmdline;
375
  for (i = 0; argv[i]; i++)
376
    {
377
      *p++ = '"';
378
      for (j = 0; argv[i][j]; j++)
379
        {
380
          if (argv[i][j] == '"')
381
            {
382
              for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
383
                *p++ = '\\';
384
              *p++ = '\\';
385
            }
386
          *p++ = argv[i][j];
387
        }
388
      for (k = j - 1; k >= 0 && argv[i][k] == '\\'; k--)
389
        *p++ = '\\';
390
      *p++ = '"';
391
      *p++ = ' ';
392
    }
393
  p[-1] = '\0';
394
  return cmdline;
395
}
396
 
397
/* We'll try the passed filename with all the known standard
398
   extensions, and then without extension.  We try no extension
399
   last so that we don't try to run some random extension-less
400
   file that might be hanging around.  We try both extension
401
   and no extension so that we don't need any fancy logic
402
   to determine if a file has extension.  */
403
static const char *const
404
std_suffixes[] = {
405
  ".com",
406
  ".exe",
407
  ".bat",
408
  ".cmd",
409
  "",
410
 
411
};
412
 
413
/* Returns the full path to PROGRAM.  If SEARCH is true, look for
414
   PROGRAM in each directory in PATH.  */
415
 
416
static char *
417
find_executable (const char *program, BOOL search)
418
{
419
  char *full_executable;
420
  char *e;
421
  size_t fe_len;
422
  const char *path = 0;
423
  const char *const *ext;
424
  const char *p, *q;
425
  size_t proglen = strlen (program);
426
  int has_slash = (strchr (program, '/') || strchr (program, '\\'));
427
  HANDLE h;
428
 
429
  if (has_slash)
430
    search = FALSE;
431
 
432
  if (search)
433
    path = getenv ("PATH");
434
  if (!path)
435
    path = "";
436
 
437
  fe_len = 0;
438
  for (p = path; *p; p = q)
439
    {
440
      q = p;
441
      while (*q != ';' && *q != '\0')
442
        q++;
443
      if ((size_t)(q - p) > fe_len)
444
        fe_len = q - p;
445
      if (*q == ';')
446
        q++;
447
    }
448
  fe_len = fe_len + 1 + proglen + 5 /* space for extension */;
449
  full_executable = XNEWVEC (char, fe_len);
450
 
451
  p = path;
452
  do
453
    {
454
      q = p;
455
      while (*q != ';' && *q != '\0')
456
        q++;
457
 
458
      e = full_executable;
459
      memcpy (e, p, q - p);
460
      e += (q - p);
461
      if (q - p)
462
        *e++ = '\\';
463
      strcpy (e, program);
464
 
465
      if (*q == ';')
466
        q++;
467
 
468
      for (e = full_executable; *e; e++)
469
        if (*e == '/')
470
          *e = '\\';
471
 
472
      /* At this point, e points to the terminating NUL character for
473
         full_executable.  */
474
      for (ext = std_suffixes; *ext; ext++)
475
        {
476
          /* Remove any current extension.  */
477
          *e = '\0';
478
          /* Add the new one.  */
479
          strcat (full_executable, *ext);
480
 
481
          /* Attempt to open this file.  */
482
          h = CreateFile (full_executable, GENERIC_READ,
483
                          FILE_SHARE_READ | FILE_SHARE_WRITE,
484
                          0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
485
          if (h != INVALID_HANDLE_VALUE)
486
            goto found;
487
        }
488
      p = q;
489
    }
490
  while (*p);
491
  free (full_executable);
492
  return 0;
493
 
494
 found:
495
  CloseHandle (h);
496
  return full_executable;
497
}
498
 
499
/* Low-level process creation function and helper.  */
500
 
501
static int
502
env_compare (const void *a_ptr, const void *b_ptr)
503
{
504
  const char *a;
505
  const char *b;
506
  unsigned char c1;
507
  unsigned char c2;
508
 
509
  a = *(const char **) a_ptr;
510
  b = *(const char **) b_ptr;
511
 
512
  /* a and b will be of the form: VAR=VALUE
513
     We compare only the variable name part here using a case-insensitive
514
     comparison algorithm.  It might appear that in fact strcasecmp () can
515
     take the place of this whole function, and indeed it could, save for
516
     the fact that it would fail in cases such as comparing A1=foo and
517
     A=bar (because 1 is less than = in the ASCII character set).
518
     (Environment variables containing no numbers would work in such a
519
     scenario.)  */
520
 
521
  do
522
    {
523
      c1 = (unsigned char) tolower (*a++);
524
      c2 = (unsigned char) tolower (*b++);
525
 
526
      if (c1 == '=')
527
        c1 = '\0';
528
 
529
      if (c2 == '=')
530
        c2 = '\0';
531
    }
532
  while (c1 == c2 && c1 != '\0');
533
 
534
  return c1 - c2;
535
}
536
 
537
/* Execute a Windows executable as a child process.  This will fail if the
538
 * target is not actually an executable, such as if it is a shell script. */
539
 
540
static pid_t
541
win32_spawn (const char *executable,
542
             BOOL search,
543
             char *const *argv,
544
             char *const *env, /* array of strings of the form: VAR=VALUE */
545
             DWORD dwCreationFlags,
546
             LPSTARTUPINFO si,
547
             LPPROCESS_INFORMATION pi)
548
{
549
  char *full_executable;
550
  char *cmdline;
551
  char **env_copy;
552
  char *env_block = NULL;
553
 
554
  full_executable = NULL;
555
  cmdline = NULL;
556
 
557
  if (env)
558
    {
559
      int env_size;
560
 
561
      /* Count the number of environment bindings supplied.  */
562
      for (env_size = 0; env[env_size]; env_size++)
563
        continue;
564
 
565
      /* Assemble an environment block, if required.  This consists of
566
         VAR=VALUE strings juxtaposed (with one null character between each
567
         pair) and an additional null at the end.  */
568
      if (env_size > 0)
569
        {
570
          int var;
571
          int total_size = 1; /* 1 is for the final null.  */
572
          char *bufptr;
573
 
574
          /* Windows needs the members of the block to be sorted by variable
575
             name.  */
576
          env_copy = (char **) alloca (sizeof (char *) * env_size);
577
          memcpy (env_copy, env, sizeof (char *) * env_size);
578
          qsort (env_copy, env_size, sizeof (char *), env_compare);
579
 
580
          for (var = 0; var < env_size; var++)
581
            total_size += strlen (env[var]) + 1;
582
 
583
          env_block = XNEWVEC (char, total_size);
584
          bufptr = env_block;
585
          for (var = 0; var < env_size; var++)
586
            bufptr = stpcpy (bufptr, env_copy[var]) + 1;
587
 
588
          *bufptr = '\0';
589
        }
590
    }
591
 
592
  full_executable = find_executable (executable, search);
593
  if (!full_executable)
594
    goto error;
595
  cmdline = argv_to_cmdline (argv);
596
  if (!cmdline)
597
    goto error;
598
 
599
  /* Create the child process.  */
600
  if (!CreateProcess (full_executable, cmdline,
601
                      /*lpProcessAttributes=*/NULL,
602
                      /*lpThreadAttributes=*/NULL,
603
                      /*bInheritHandles=*/TRUE,
604
                      dwCreationFlags,
605
                      (LPVOID) env_block,
606
                      /*lpCurrentDirectory=*/NULL,
607
                      si,
608
                      pi))
609
    {
610
      if (env_block)
611
        free (env_block);
612
 
613
      free (full_executable);
614
 
615
      return (pid_t) -1;
616
    }
617
 
618
  /* Clean up.  */
619
  CloseHandle (pi->hThread);
620
  free (full_executable);
621
  if (env_block)
622
    free (env_block);
623
 
624
  return (pid_t) pi->hProcess;
625
 
626
 error:
627
  if (env_block)
628
    free (env_block);
629
  if (cmdline)
630
    free (cmdline);
631
  if (full_executable)
632
    free (full_executable);
633
 
634
  return (pid_t) -1;
635
}
636
 
637
/* Spawn a script.  This simulates the Unix script execution mechanism.
638
   This function is called as a fallback if win32_spawn fails. */
639
 
640
static pid_t
641
spawn_script (const char *executable, char *const *argv,
642
              char* const *env,
643
              DWORD dwCreationFlags,
644
              LPSTARTUPINFO si,
645
              LPPROCESS_INFORMATION pi)
646
{
647
  pid_t pid = (pid_t) -1;
648
  int save_errno = errno;
649
  int fd = _open (executable, _O_RDONLY);
650
 
651
  /* Try to open script, check header format, extract interpreter path,
652
     and spawn script using that interpretter. */
653
  if (fd >= 0)
654
    {
655
      char buf[MAX_PATH + 5];
656
      int len = _read (fd, buf, sizeof (buf) - 1);
657
      _close (fd);
658
      if (len > 3)
659
        {
660
          char *eol;
661
          buf[len] = '\0';
662
          eol = strchr (buf, '\n');
663
          if (eol && strncmp (buf, "#!", 2) == 0)
664
            {
665
 
666
              /* Header format is OK. */
667
              char *executable1;
668
              int new_argc;
669
              const char **avhere;
670
 
671
              /* Extract interpreter path. */
672
              do
673
                *eol = '\0';
674
              while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
675
              for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
676
                continue;
677
              backslashify (executable1);
678
 
679
              /* Duplicate argv, prepending the interpreter path. */
680
              new_argc = argv_to_argc (argv) + 1;
681
              avhere = XNEWVEC (const char *, new_argc + 1);
682
              *avhere = executable1;
683
              memcpy (avhere + 1, argv, new_argc * sizeof(*argv));
684
              argv = (char *const *)avhere;
685
 
686
              /* Spawn the child. */
687
#ifndef USE_MINGW_MSYS
688
              executable = strrchr (executable1, '\\') + 1;
689
              if (!executable)
690
                executable = executable1;
691
              pid = win32_spawn (executable, TRUE, argv, env,
692
                                 dwCreationFlags, si, pi);
693
#else
694
              if (strchr (executable1, '\\') == NULL)
695
                pid = win32_spawn (executable1, TRUE, argv, env,
696
                                   dwCreationFlags, si, pi);
697
              else if (executable1[0] != '\\')
698
                pid = win32_spawn (executable1, FALSE, argv, env,
699
                                   dwCreationFlags, si, pi);
700
              else
701
                {
702
                  const char *newex = mingw_rootify (executable1);
703
                  *avhere = newex;
704
                  pid = win32_spawn (newex, FALSE, argv, env,
705
                                     dwCreationFlags, si, pi);
706
                  if (executable1 != newex)
707
                    free ((char *) newex);
708
                  if ((long) pid < 0)
709
                    {
710
                      newex = msys_rootify (executable1);
711
                      if (newex != executable1)
712
                        {
713
                          *avhere = newex;
714
                          pid = win32_spawn (newex, FALSE, argv, env,
715
                                             dwCreationFlags, si, pi);
716
                          free ((char *) newex);
717
                        }
718
                    }
719
                }
720
#endif
721
              free (avhere);
722
            }
723
        }
724
    }
725
  if ((long) pid < 0)
726
    errno = save_errno;
727
  return pid;
728
}
729
 
730
/* Execute a child.  */
731
 
732
static pid_t
733
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
734
                      const char *executable, char * const * argv,
735
                      char* const* env,
736
                      int in, int out, int errdes,
737
                      int toclose ATTRIBUTE_UNUSED,
738
                      const char **errmsg,
739
                      int *err)
740
{
741
  pid_t pid;
742
  HANDLE stdin_handle;
743
  HANDLE stdout_handle;
744
  HANDLE stderr_handle;
745
  DWORD dwCreationFlags;
746
  OSVERSIONINFO version_info;
747
  STARTUPINFO si;
748
  PROCESS_INFORMATION pi;
749
 
750
  stdin_handle = INVALID_HANDLE_VALUE;
751
  stdout_handle = INVALID_HANDLE_VALUE;
752
  stderr_handle = INVALID_HANDLE_VALUE;
753
 
754
  stdin_handle = (HANDLE) _get_osfhandle (in);
755
  stdout_handle = (HANDLE) _get_osfhandle (out);
756
  if (!(flags & PEX_STDERR_TO_STDOUT))
757
    stderr_handle = (HANDLE) _get_osfhandle (errdes);
758
  else
759
    stderr_handle = stdout_handle;
760
 
761
  /* Determine the version of Windows we are running on.  */
762
  version_info.dwOSVersionInfoSize = sizeof (version_info);
763
  GetVersionEx (&version_info);
764
  if (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
765
    /* On Windows 95/98/ME the CREATE_NO_WINDOW flag is not
766
       supported, so we cannot avoid creating a console window.  */
767
    dwCreationFlags = 0;
768
  else
769
    {
770
      HANDLE conout_handle;
771
 
772
      /* Determine whether or not we have an associated console.  */
773
      conout_handle = CreateFile("CONOUT$",
774
                                 GENERIC_WRITE,
775
                                 FILE_SHARE_WRITE,
776
                                 /*lpSecurityAttributes=*/NULL,
777
                                 OPEN_EXISTING,
778
                                 FILE_ATTRIBUTE_NORMAL,
779
                                 /*hTemplateFile=*/NULL);
780
      if (conout_handle == INVALID_HANDLE_VALUE)
781
        /* There is no console associated with this process.  Since
782
           the child is a console process, the OS would normally
783
           create a new console Window for the child.  Since we'll be
784
           redirecting the child's standard streams, we do not need
785
           the console window.  */
786
        dwCreationFlags = CREATE_NO_WINDOW;
787
      else
788
        {
789
          /* There is a console associated with the process, so the OS
790
             will not create a new console.  And, if we use
791
             CREATE_NO_WINDOW in this situation, the child will have
792
             no associated console.  Therefore, if the child's
793
             standard streams are connected to the console, the output
794
             will be discarded.  */
795
          CloseHandle(conout_handle);
796
          dwCreationFlags = 0;
797
        }
798
    }
799
 
800
  /* Since the child will be a console process, it will, by default,
801
     connect standard input/output to its console.  However, we want
802
     the child to use the handles specifically designated above.  In
803
     addition, if there is no console (such as when we are running in
804
     a Cygwin X window), then we must redirect the child's
805
     input/output, as there is no console for the child to use.  */
806
  memset (&si, 0, sizeof (si));
807
  si.cb = sizeof (si);
808
  si.dwFlags = STARTF_USESTDHANDLES;
809
  si.hStdInput = stdin_handle;
810
  si.hStdOutput = stdout_handle;
811
  si.hStdError = stderr_handle;
812
 
813
  /* Create the child process.  */
814
  pid = win32_spawn (executable, (flags & PEX_SEARCH) != 0,
815
                     argv, env, dwCreationFlags, &si, &pi);
816
  if (pid == (pid_t) -1)
817
    pid = spawn_script (executable, argv, env, dwCreationFlags,
818
                        &si, &pi);
819
  if (pid == (pid_t) -1)
820
    {
821
      *err = ENOENT;
822
      *errmsg = "CreateProcess";
823
    }
824
 
825
  /* Close the standard output and standard error handles in the
826
     parent.  */
827
  if (out != STDOUT_FILENO)
828
    obj->funcs->close (obj, out);
829
  if (errdes != STDERR_FILENO)
830
    obj->funcs->close (obj, errdes);
831
 
832
  return pid;
833
}
834
 
835
/* Wait for a child process to complete.  MS CRTDLL doesn't return
836
   enough information in status to decide if the child exited due to a
837
   signal or not, rather it simply returns an integer with the exit
838
   code of the child; eg., if the child exited with an abort() call
839
   and didn't have a handler for SIGABRT, it simply returns with
840
   status == 3.  We fix the status code to conform to the usual WIF*
841
   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
842
 
843
static int
844
pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid,
845
                int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
846
                const char **errmsg, int *err)
847
{
848
  DWORD termstat;
849
  HANDLE h;
850
 
851
  if (time != NULL)
852
    memset (time, 0, sizeof *time);
853
 
854
  h = (HANDLE) pid;
855
 
856
  /* FIXME: If done is non-zero, we should probably try to kill the
857
     process.  */
858
  if (WaitForSingleObject (h, INFINITE) != WAIT_OBJECT_0)
859
    {
860
      CloseHandle (h);
861
      *err = ECHILD;
862
      *errmsg = "WaitForSingleObject";
863
      return -1;
864
    }
865
 
866
  GetExitCodeProcess (h, &termstat);
867
  CloseHandle (h);
868
 
869
  /* A value of 3 indicates that the child caught a signal, but not
870
     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
871
     report SIGABRT.  */
872
  if (termstat == 3)
873
    *status = SIGABRT;
874
  else
875
    *status = (termstat & 0xff) << 8;
876
 
877
  return 0;
878
}
879
 
880
/* Create a pipe.  */
881
 
882
static int
883
pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
884
                int binary)
885
{
886
  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
887
}
888
 
889
/* Get a FILE pointer to read from a file descriptor.  */
890
 
891
static FILE *
892
pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
893
                   int binary)
894
{
895
  return fdopen (fd, binary ? "rb" : "r");
896
}
897
 
898
static FILE *
899
pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
900
                   int binary)
901
{
902
  HANDLE h = (HANDLE) _get_osfhandle (fd);
903
  if (h == INVALID_HANDLE_VALUE)
904
    return NULL;
905
  if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
906
    return NULL;
907
  return fdopen (fd, binary ? "wb" : "w");
908
}
909
 
910
#ifdef MAIN
911
#include <stdio.h>
912
 
913
int
914
main (int argc ATTRIBUTE_UNUSED, char **argv)
915
{
916
  char const *errmsg;
917
  int err;
918
  argv++;
919
  printf ("%ld\n", (long) pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, NULL, 0, 0, 1, 2, &errmsg, &err));
920
  exit (0);
921
}
922
#endif

powered by: WebSVN 2.1.0

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