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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libiberty/] [pex-win32.c] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 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
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 <process.h>
40
#include <io.h>
41
#include <fcntl.h>
42
#include <signal.h>
43
#include <sys/stat.h>
44
 
45
/* mingw32 headers may not define the following.  */
46
 
47
#ifndef _P_WAIT
48
#  define _P_WAIT       0
49
#  define _P_NOWAIT     1
50
#  define _P_OVERLAY    2
51
#  define _P_NOWAITO    3
52
#  define _P_DETACH     4
53
 
54
#  define WAIT_CHILD            0
55
#  define WAIT_GRANDCHILD       1
56
#endif
57
 
58
#define MINGW_NAME "Minimalist GNU for Windows"
59
#define MINGW_NAME_LEN (sizeof(MINGW_NAME) - 1)
60
 
61
/* Ensure that the executable pathname uses Win32 backslashes. This
62
   is not necessary on NT, but on W9x, forward slashes causes
63
   failure of spawn* and exec* functions (and probably any function
64
   that calls CreateProcess) *iff* the executable pathname (argv[0])
65
   is a quoted string.  And quoting is necessary in case a pathname
66
   contains embedded white space.  You can't win.  */
67
static void
68
backslashify (char *s)
69
{
70
  while ((s = strchr (s, '/')) != NULL)
71
    *s = '\\';
72
  return;
73
}
74
 
75
/* This is a kludge to get around the Microsoft C spawn functions' propensity
76
   to remove the outermost set of double quotes from all arguments.  */
77
 
78
static const char * const *
79
fix_argv (char * const *argvec)
80
{
81
  char **argv;
82
  int i;
83
  char *command0;
84
 
85
  /* See whether we need to change anything.  */
86
  for (command0 = argvec[0]; *command0 != '\0'; command0++)
87
    if (*command0 == '/')
88
      break;
89
  if (*command0 == '\0')
90
    {
91
      for (i = 1; argvec[i] != NULL; i++)
92
        if (strpbrk (argvec[i], "\" \t") != NULL)
93
          break;
94
 
95
      if (argvec[i] == NULL)
96
        return (const char * const *) argvec;
97
    }
98
 
99
  for (i = 0; argvec[i] != NULL; i++)
100
    ;
101
  argv = XNEWVEC (char *, i + 2);
102
 
103
  argv++;       /* Leave space at the beginning of argv
104
                   for potential #! handling */
105
 
106
  for (i = 0; argvec[i] != NULL; i++)
107
    argv[i] = xstrdup (argvec[i]);
108
  argv[i] = NULL;
109
 
110
  backslashify (argv[0]);
111
 
112
  for (i = 1; argv[i] != 0; i++)
113
    {
114
      int len, j;
115
      char *temp, *newtemp;
116
 
117
      temp = argv[i];
118
      len = strlen (temp);
119
      for (j = 0; j < len; j++)
120
        {
121
          if (temp[j] == '"')
122
            {
123
              newtemp = XNEWVEC (char, len + 2);
124
              strncpy (newtemp, temp, j);
125
              newtemp [j] = '\\';
126
              strncpy (&newtemp [j+1], &temp [j], len-j);
127
              newtemp [len+1] = 0;
128
              temp = newtemp;
129
              len++;
130
              j++;
131
            }
132
        }
133
 
134
      if (argv[i] != temp)
135
        {
136
          free (argv[i]);
137
          argv[i] = temp;
138
        }
139
    }
140
 
141
  for (i = 0; argv[i] != 0; i++)
142
    {
143
      if (strpbrk (argv[i], " \t"))
144
        {
145
          int len, trailing_backslash;
146
          char *temp;
147
 
148
          len = strlen (argv[i]);
149
          trailing_backslash = 0;
150
 
151
          /* There is an added complication when an arg with embedded white
152
             space ends in a backslash (such as in the case of -iprefix arg
153
             passed to cpp). The resulting quoted strings gets misinterpreted
154
             by the command interpreter -- it thinks that the ending quote
155
             is escaped by the trailing backslash and things get confused.
156
             We handle this case by escaping the trailing backslash, provided
157
             it was not escaped in the first place.  */
158
          if (len > 1
159
              && argv[i][len-1] == '\\'
160
              && argv[i][len-2] != '\\')
161
            {
162
              trailing_backslash = 1;
163
              ++len;                    /* to escape the final backslash. */
164
            }
165
 
166
          len += 2;                     /* and for the enclosing quotes. */
167
 
168
          temp = XNEWVEC (char, len + 1);
169
          temp[0] = '"';
170
          strcpy (temp + 1, argv[i]);
171
          if (trailing_backslash)
172
            temp[len - 2] = '\\';
173
          temp[len - 1] = '"';
174
          temp[len] = '\0';
175
 
176
          free (argv[i]);
177
          argv[i] = temp;
178
        }
179
    }
180
 
181
  return (const char * const *) argv;
182
}
183
 
184
static int pex_win32_open_read (struct pex_obj *, const char *, int);
185
static int pex_win32_open_write (struct pex_obj *, const char *, int);
186
static long pex_win32_exec_child (struct pex_obj *, int, const char *,
187
                                  char * const *, int, int, int,
188
                                  const char **, int *);
189
static int pex_win32_close (struct pex_obj *, int);
190
static int pex_win32_wait (struct pex_obj *, long, int *,
191
                           struct pex_time *, int, const char **, int *);
192
static int pex_win32_pipe (struct pex_obj *, int *, int);
193
static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
194
 
195
/* The list of functions we pass to the common routines.  */
196
 
197
const struct pex_funcs funcs =
198
{
199
  pex_win32_open_read,
200
  pex_win32_open_write,
201
  pex_win32_exec_child,
202
  pex_win32_close,
203
  pex_win32_wait,
204
  pex_win32_pipe,
205
  pex_win32_fdopenr,
206
  NULL /* cleanup */
207
};
208
 
209
/* Return a newly initialized pex_obj structure.  */
210
 
211
struct pex_obj *
212
pex_init (int flags, const char *pname, const char *tempbase)
213
{
214
  return pex_init_common (flags, pname, tempbase, &funcs);
215
}
216
 
217
/* Open a file for reading.  */
218
 
219
static int
220
pex_win32_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
221
                     int binary)
222
{
223
  return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
224
}
225
 
226
/* Open a file for writing.  */
227
 
228
static int
229
pex_win32_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
230
                      int binary)
231
{
232
  /* Note that we can't use O_EXCL here because gcc may have already
233
     created the temporary file via make_temp_file.  */
234
  return _open (name,
235
                (_O_WRONLY | _O_CREAT | _O_TRUNC
236
                 | (binary ? _O_BINARY : _O_TEXT)),
237
                _S_IREAD | _S_IWRITE);
238
}
239
 
240
/* Close a file.  */
241
 
242
static int
243
pex_win32_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
244
{
245
  return _close (fd);
246
}
247
 
248
#ifdef USE_MINGW_MSYS
249
static const char *mingw_keys[] = {"SOFTWARE", "Microsoft", "Windows", "CurrentVersion", "Uninstall", NULL};
250
 
251
/* Tack the executable on the end of a (possibly slash terminated) buffer
252
   and convert everything to \. */
253
static const char *
254
tack_on_executable (char *buf, const char *executable)
255
{
256
  char *p = strchr (buf, '\0');
257
  if (p > buf && (p[-1] == '\\' || p[-1] == '/'))
258
    p[-1] = '\0';
259
  backslashify (strcat (buf, executable));
260
  return buf;
261
}
262
 
263
/* Walk down a registry hierarchy until the end.  Return the key. */
264
static HKEY
265
openkey (HKEY hStart, const char *keys[])
266
{
267
  HKEY hKey, hTmp;
268
  for (hKey = hStart; *keys; keys++)
269
    {
270
      LONG res;
271
      hTmp = hKey;
272
      res = RegOpenKey (hTmp, *keys, &hKey);
273
 
274
      if (hTmp != HKEY_LOCAL_MACHINE)
275
        RegCloseKey (hTmp);
276
 
277
      if (res != ERROR_SUCCESS)
278
        return NULL;
279
    }
280
  return hKey;
281
}
282
 
283
/* Return the "mingw root" as derived from the mingw uninstall information. */
284
static const char *
285
mingw_rootify (const char *executable)
286
{
287
  HKEY hKey, hTmp;
288
  DWORD maxlen;
289
  char *namebuf, *foundbuf;
290
  DWORD i;
291
  LONG res;
292
 
293
  /* Open the uninstall "directory". */
294
  hKey = openkey (HKEY_LOCAL_MACHINE, mingw_keys);
295
 
296
  /* Not found. */
297
  if (!hKey)
298
    return executable;
299
 
300
  /* Need to enumerate all of the keys here looking for one the most recent
301
     one for MinGW. */
302
  if (RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, &maxlen, NULL, NULL,
303
                       NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
304
    {
305
      RegCloseKey (hKey);
306
      return executable;
307
    }
308
  namebuf = XNEWVEC (char, ++maxlen);
309
  foundbuf = XNEWVEC (char, maxlen);
310
  foundbuf[0] = '\0';
311
  if (!namebuf || !foundbuf)
312
    {
313
      RegCloseKey (hKey);
314
      if (namebuf)
315
        free (namebuf);
316
      if (foundbuf)
317
        free (foundbuf);
318
      return executable;
319
    }
320
 
321
  /* Look through all of the keys for one that begins with Minimal GNU...
322
     Try to get the latest version by doing a string compare although that
323
     string never really works with version number sorting. */
324
  for (i = 0; RegEnumKey (hKey, i, namebuf, maxlen) == ERROR_SUCCESS; i++)
325
    {
326
      int match = strcasecmp (namebuf, MINGW_NAME);
327
      if (match < 0)
328
        continue;
329
      if (match > 0 && strncasecmp (namebuf, MINGW_NAME, MINGW_NAME_LEN) > 0)
330
        continue;
331
      if (strcasecmp (namebuf, foundbuf) > 0)
332
        strcpy (foundbuf, namebuf);
333
    }
334
  free (namebuf);
335
 
336
  /* If foundbuf is empty, we didn't find anything.  Punt. */
337
  if (!foundbuf[0])
338
    {
339
      free (foundbuf);
340
      RegCloseKey (hKey);
341
      return executable;
342
    }
343
 
344
  /* Open the key that we wanted */
345
  res = RegOpenKey (hKey, foundbuf, &hTmp);
346
  RegCloseKey (hKey);
347
  free (foundbuf);
348
 
349
  /* Don't know why this would fail, but you gotta check */
350
  if (res != ERROR_SUCCESS)
351
    return executable;
352
 
353
  maxlen = 0;
354
  /* Get the length of the value pointed to by InstallLocation */
355
  if (RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, NULL,
356
                       &maxlen) != ERROR_SUCCESS || maxlen == 0)
357
    {
358
      RegCloseKey (hTmp);
359
      return executable;
360
    }
361
 
362
  /* Allocate space for the install location */
363
  foundbuf = XNEWVEC (char, maxlen + strlen (executable));
364
  if (!foundbuf)
365
    {
366
      free (foundbuf);
367
      RegCloseKey (hTmp);
368
    }
369
 
370
  /* Read the install location into the buffer */
371
  res = RegQueryValueEx (hTmp, "InstallLocation", 0, NULL, (LPBYTE) foundbuf,
372
                         &maxlen);
373
  RegCloseKey (hTmp);
374
  if (res != ERROR_SUCCESS)
375
    {
376
      free (foundbuf);
377
      return executable;
378
    }
379
 
380
  /* Concatenate the install location and the executable, turn all slashes
381
     to backslashes, and return that. */
382
  return tack_on_executable (foundbuf, executable);
383
}
384
 
385
/* Read the install location of msys from it's installation file and
386
   rootify the executable based on that. */
387
static const char *
388
msys_rootify (const char *executable)
389
{
390
  size_t bufsize = 64;
391
  size_t execlen = strlen (executable) + 1;
392
  char *buf;
393
  DWORD res = 0;
394
  for (;;)
395
    {
396
      buf = XNEWVEC (char, bufsize + execlen);
397
      if (!buf)
398
        break;
399
      res = GetPrivateProfileString ("InstallSettings", "InstallPath", NULL,
400
                                     buf, bufsize, "msys.ini");
401
      if (!res)
402
        break;
403
      if (strlen (buf) < bufsize)
404
        break;
405
      res = 0;
406
      free (buf);
407
      bufsize *= 2;
408
      if (bufsize > 65536)
409
        {
410
          buf = NULL;
411
          break;
412
        }
413
    }
414
 
415
  if (res)
416
    return tack_on_executable (buf, executable);
417
 
418
  /* failed */
419
  if (buf)
420
    free (buf);
421
  return executable;
422
}
423
#endif
424
 
425
static long
426
spawn_script (const char *executable, const char * const * argv)
427
{
428
  int pid = -1;
429
  int save_errno = errno;
430
  int fd = _open (executable, _O_RDONLY);
431
 
432
  if (fd >= 0)
433
    {
434
      char buf[MAX_PATH + 5];
435
      int len = _read (fd, buf, sizeof (buf) - 1);
436
      _close (fd);
437
      if (len > 3)
438
        {
439
          char *eol;
440
          buf[len] = '\0';
441
          eol = strchr (buf, '\n');
442
          if (eol && strncmp (buf, "#!", 2) == 0)
443
            {
444
              char *executable1;
445
              const char ** avhere = (const char **) --argv;
446
              do
447
                *eol = '\0';
448
              while (*--eol == '\r' || *eol == ' ' || *eol == '\t');
449
              for (executable1 = buf + 2; *executable1 == ' ' || *executable1 == '\t'; executable1++)
450
                continue;
451
 
452
              backslashify (executable1);
453
              *avhere = executable1;
454
#ifndef USE_MINGW_MSYS
455
              executable = strrchr (executable1, '\\') + 1;
456
              if (!executable)
457
                executable = executable1;
458
              pid = _spawnvp (_P_NOWAIT, executable, argv);
459
#else
460
              if (strchr (executable1, '\\') == NULL)
461
                pid = _spawnvp (_P_NOWAIT, executable1, argv);
462
              else if (executable1[0] != '\\')
463
                pid = _spawnv (_P_NOWAIT, executable1, argv);
464
              else
465
                {
466
                  const char *newex = mingw_rootify (executable1);
467
                  *avhere = newex;
468
                  pid = _spawnv (_P_NOWAIT, newex, argv);
469
                  if (executable1 != newex)
470
                    free ((char *) newex);
471
                  if (pid < 0)
472
                    {
473
                      newex = msys_rootify (executable1);
474
                      if (newex != executable1)
475
                        {
476
                          *avhere = newex;
477
                          pid = _spawnv (_P_NOWAIT, newex, argv);
478
                          free ((char *) newex);
479
                        }
480
                    }
481
                }
482
#endif
483
            }
484
        }
485
    }
486
  if (pid < 0)
487
    errno = save_errno;
488
  return pid;
489
}
490
 
491
/* Execute a child.  */
492
 
493
static long
494
pex_win32_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED, int flags,
495
                      const char *executable, char * const * argv,
496
                      int in, int out, int errdes, const char **errmsg,
497
                      int *err)
498
{
499
  int org_in, org_out, org_errdes;
500
  long pid;
501
  const char * const * newargv;
502
 
503
  org_in = -1;
504
  org_out = -1;
505
  org_errdes = -1;
506
 
507
  if (in != STDIN_FILE_NO)
508
    {
509
      org_in = _dup (STDIN_FILE_NO);
510
      if (org_in < 0)
511
        {
512
          *err = errno;
513
          *errmsg = "_dup";
514
          return -1;
515
        }
516
      if (_dup2 (in, STDIN_FILE_NO) < 0)
517
        {
518
          *err = errno;
519
          *errmsg = "_dup2";
520
          return -1;
521
        }
522
      if (_close (in) < 0)
523
        {
524
          *err = errno;
525
          *errmsg = "_close";
526
          return -1;
527
        }
528
    }
529
 
530
  if (out != STDOUT_FILE_NO)
531
    {
532
      org_out = _dup (STDOUT_FILE_NO);
533
      if (org_out < 0)
534
        {
535
          *err = errno;
536
          *errmsg = "_dup";
537
          return -1;
538
        }
539
      if (_dup2 (out, STDOUT_FILE_NO) < 0)
540
        {
541
          *err = errno;
542
          *errmsg = "_dup2";
543
          return -1;
544
        }
545
      if (_close (out) < 0)
546
        {
547
          *err = errno;
548
          *errmsg = "_close";
549
          return -1;
550
        }
551
    }
552
 
553
  if (errdes != STDERR_FILE_NO
554
      || (flags & PEX_STDERR_TO_STDOUT) != 0)
555
    {
556
      org_errdes = _dup (STDERR_FILE_NO);
557
      if (org_errdes < 0)
558
        {
559
          *err = errno;
560
          *errmsg = "_dup";
561
          return -1;
562
        }
563
      if (_dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
564
                 STDERR_FILE_NO) < 0)
565
        {
566
          *err = errno;
567
          *errmsg = "_dup2";
568
          return -1;
569
        }
570
      if (errdes != STDERR_FILE_NO)
571
        {
572
          if (_close (errdes) < 0)
573
            {
574
              *err = errno;
575
              *errmsg = "_close";
576
              return -1;
577
            }
578
        }
579
    }
580
 
581
  newargv = fix_argv (argv);
582
  pid = (((flags & PEX_SEARCH) != 0 ? _spawnvp : _spawnv)
583
         (_P_NOWAIT, executable, newargv));
584
 
585
  if (pid == -1)
586
    pid = spawn_script (executable, newargv);
587
 
588
  if (pid == -1)
589
    {
590
      *err = errno;
591
      *errmsg = ((flags & PEX_SEARCH) != 0) ? "_spawnvp" : "_spawnv";
592
    }
593
 
594
  if (in != STDIN_FILE_NO)
595
    {
596
      if (_dup2 (org_in, STDIN_FILE_NO) < 0)
597
        {
598
          *err = errno;
599
          *errmsg = "_dup2";
600
          return -1;
601
        }
602
      if (_close (org_in) < 0)
603
        {
604
          *err = errno;
605
          *errmsg = "_close";
606
          return -1;
607
        }
608
    }
609
 
610
  if (out != STDOUT_FILE_NO)
611
    {
612
      if (_dup2 (org_out, STDOUT_FILE_NO) < 0)
613
        {
614
          *err = errno;
615
          *errmsg = "_dup2";
616
          return -1;
617
        }
618
      if (_close (org_out) < 0)
619
        {
620
          *err = errno;
621
          *errmsg = "_close";
622
          return -1;
623
        }
624
    }
625
 
626
  if (errdes != STDERR_FILE_NO
627
      || (flags & PEX_STDERR_TO_STDOUT) != 0)
628
    {
629
      if (_dup2 (org_errdes, STDERR_FILE_NO) < 0)
630
        {
631
          *err = errno;
632
          *errmsg = "_dup2";
633
          return -1;
634
        }
635
      if (_close (org_errdes) < 0)
636
        {
637
          *err = errno;
638
          *errmsg = "_close";
639
          return -1;
640
        }
641
    }
642
 
643
  return pid;
644
}
645
 
646
/* Wait for a child process to complete.  MS CRTDLL doesn't return
647
   enough information in status to decide if the child exited due to a
648
   signal or not, rather it simply returns an integer with the exit
649
   code of the child; eg., if the child exited with an abort() call
650
   and didn't have a handler for SIGABRT, it simply returns with
651
   status == 3.  We fix the status code to conform to the usual WIF*
652
   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
653
 
654
static int
655
pex_win32_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, long pid,
656
                int *status, struct pex_time *time, int done ATTRIBUTE_UNUSED,
657
                const char **errmsg, int *err)
658
{
659
  int termstat;
660
 
661
  if (time != NULL)
662
    memset (time, 0, sizeof *time);
663
 
664
  /* FIXME: If done is non-zero, we should probably try to kill the
665
     process.  */
666
 
667
  if (_cwait (&termstat, pid, WAIT_CHILD) < 0)
668
    {
669
      *err = errno;
670
      *errmsg = "_cwait";
671
      return -1;
672
    }
673
 
674
  /* cwait returns the child process exit code in termstat.  A value
675
     of 3 indicates that the child caught a signal, but not which one.
676
     Since only SIGABRT, SIGFPE and SIGINT do anything, we report
677
     SIGABRT.  */
678
 
679
  if (termstat == 3)
680
    *status = SIGABRT;
681
  else
682
    *status = ((termstat & 0xff) << 8);
683
 
684
  return 0;
685
}
686
 
687
/* Create a pipe.  */
688
 
689
static int
690
pex_win32_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
691
                int binary)
692
{
693
  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
694
}
695
 
696
/* Get a FILE pointer to read from a file descriptor.  */
697
 
698
static FILE *
699
pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
700
                   int binary)
701
{
702
  return fdopen (fd, binary ? "rb" : "r");
703
}
704
 
705
#ifdef MAIN
706
#include <stdio.h>
707
 
708
int
709
main (int argc ATTRIBUTE_UNUSED, char **argv)
710
{
711
  char const *errmsg;
712
  int err;
713
  argv++;
714
  printf ("%ld\n", pex_win32_exec_child (NULL, PEX_SEARCH, argv[0], argv, 0, 1, 2, &errmsg, &err));
715
  exit (0);
716
}
717
#endif

powered by: WebSVN 2.1.0

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