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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libiberty/] [pex-win32.c] - Blame information for rev 749

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

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

powered by: WebSVN 2.1.0

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