source: trunk/third/gcc/pexecute.c @ 11288

Revision 11288, 16.2 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11287, which included commits to RCS files with non-trunk default branches.
Line 
1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2   with other subprocesses), and wait for it.
3   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
4
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11Libiberty is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14Library General Public License for more details.
15
16You should have received a copy of the GNU Library General Public
17License along with libiberty; see the file COPYING.LIB.  If not,
18write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.  */
20
21/* This file exports two functions: pexecute and pwait.  */
22
23/* This file lives in at least two places: libiberty and gcc.
24   Don't change one without the other.  */
25
26#ifdef IN_GCC
27#include "config.h"
28#endif
29
30#include <stdio.h>
31#include <errno.h>
32
33#ifdef IN_GCC
34#include "gansidecl.h"
35/* ??? Need to find a suitable header file.  */
36#define PEXECUTE_FIRST   1
37#define PEXECUTE_LAST    2
38#define PEXECUTE_ONE     (PEXECUTE_FIRST + PEXECUTE_LAST)
39#define PEXECUTE_SEARCH  4
40#define PEXECUTE_VERBOSE 8
41#else
42#include "libiberty.h"
43#endif
44
45/* stdin file number.  */
46#define STDIN_FILE_NO 0
47
48/* stdout file number.  */
49#define STDOUT_FILE_NO 1
50
51/* value of `pipe': port index for reading.  */
52#define READ_PORT 0
53
54/* value of `pipe': port index for writing.  */
55#define WRITE_PORT 1
56
57static char *install_error_msg = "installation problem, cannot exec `%s'";
58
59/* pexecute: execute a program.
60
61   PROGRAM and ARGV are the arguments to execv/execvp.
62
63   THIS_PNAME is name of the calling program (i.e. argv[0]).
64
65   TEMP_BASE is the path name, sans suffix, of a temporary file to use
66   if needed.  This is currently only needed for MSDOS ports that don't use
67   GO32 (do any still exist?).  Ports that don't need it can pass NULL.
68
69   (FLAGS & PEXECUTE_SEARCH) is non-zero if $PATH should be searched
70   (??? It's not clear that GCC passes this flag correctly).
71   (FLAGS & PEXECUTE_FIRST) is nonzero for the first process in chain.
72   (FLAGS & PEXECUTE_FIRST) is nonzero for the last process in chain.
73   FIRST_LAST could be simplified to only mark the last of a chain of processes
74   but that requires the caller to always mark the last one (and not give up
75   early if some error occurs).  It's more robust to require the caller to
76   mark both ends of the chain.
77
78   The result is the pid on systems like Unix where we fork/exec and on systems
79   like WIN32 and OS2 where we use spawn.  It is up to the caller to wait for
80   the child.
81
82   The result is the WEXITSTATUS on systems like MSDOS where we spawn and wait
83   for the child here.
84
85   Upon failure, ERRMSG_FMT and ERRMSG_ARG are set to the text of the error
86   message with an optional argument (if not needed, ERRMSG_ARG is set to
87   NULL), and -1 is returned.  `errno' is available to the caller to use.
88
89   pwait: cover function for wait.
90
91   PID is the process id of the task to wait for.
92   STATUS is the `status' argument to wait.
93   FLAGS is currently unused (allows future enhancement without breaking
94   upward compatibility).  Pass 0 for now.
95
96   The result is the pid of the child reaped,
97   or -1 for failure (errno says why).
98
99   On systems that don't support waiting for a particular child, PID is
100   ignored.  On systems like MSDOS that don't really multitask pwait
101   is just a mechanism to provide a consistent interface for the caller.
102
103   pfinish: finish generation of script
104
105   pfinish is necessary for systems like MPW where a script is generated that
106   runs the requested programs.
107*/
108
109#ifdef __MSDOS__
110
111/* MSDOS doesn't multitask, but for the sake of a consistent interface
112   the code behaves like it does.  pexecute runs the program, tucks the
113   exit code away, and returns a "pid".  pwait must be called to fetch the
114   exit code.  */
115
116#include <process.h>
117
118/* For communicating information from pexecute to pwait.  */
119static int last_pid = 0;
120static int last_status = 0;
121static int last_reaped = 0;
122
123int
124pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
125     const char *program;
126     char * const *argv;
127     const char *this_pname;
128     const char *temp_base;
129     char **errmsg_fmt, **errmsg_arg;
130     int flags;
131{
132  int rc;
133
134  last_pid++;
135  if (last_pid < 0)
136    last_pid = 1;
137
138  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
139    abort ();
140
141#ifdef __GO32__
142  /* ??? What are the possible return values from spawnv?  */
143  rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
144#else
145  char *scmd, *rf;
146  FILE *argfile;
147  int i, el = flags & PEXECUTE_SEARCH ? 4 : 0;
148
149  scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el);
150  rf = scmd + strlen(program) + 2 + el;
151  sprintf (scmd, "%s%s @%s.gp", program,
152           (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base);
153  argfile = fopen (rf, "w");
154  if (argfile == 0)
155    {
156      int errno_save = errno;
157      free (scmd);
158      errno = errno_save;
159      *errmsg_fmt = "cannot open `%s.gp'";
160      *errmsg_arg = temp_base;
161      return -1;
162    }
163
164  for (i=1; argv[i]; i++)
165    {
166      char *cp;
167      for (cp = argv[i]; *cp; cp++)
168        {
169          if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
170            fputc ('\\', argfile);
171          fputc (*cp, argfile);
172        }
173      fputc ('\n', argfile);
174    }
175  fclose (argfile);
176
177  rc = system (scmd);
178
179  {
180    int errno_save = errno;
181    remove (rf);
182    free (scmd);
183    errno = errno_save;
184  }
185#endif
186
187  if (rc == -1)
188    {
189      *errmsg_fmt = install_error_msg;
190      *errmsg_arg = program;
191      return -1;
192    }
193
194  /* Tuck the status away for pwait, and return a "pid".  */
195  last_status = rc << 8;
196  return last_pid;
197}
198
199int
200pwait (pid, status, flags)
201     int pid;
202     int *status;
203     int flags;
204{
205  /* On MSDOS each pexecute must be followed by it's associated pwait.  */
206  if (pid != last_pid
207      /* Called twice for the same child?  */
208      || pid == last_reaped)
209    {
210      /* ??? ECHILD would be a better choice.  Can we use it here?  */
211      errno = EINVAL;
212      return -1;
213    }
214  /* ??? Here's an opportunity to canonicalize the values in STATUS.
215     Needed?  */
216  *status = last_status;
217  last_reaped = last_pid;
218  return last_pid;
219}
220
221#endif /* MSDOS */
222
223#if defined (_WIN32)
224
225#include <process.h>
226#include <signal.h>
227extern int _spawnv ();
228extern int _spawnvp ();
229
230#ifdef __CYGWIN32__
231
232#define fix_argv(argvec) (argvec)
233
234#else
235
236/* This is a kludge to get around the Microsoft C spawn functions' propensity
237   to remove the outermost set of double quotes from all arguments.  */
238
239char * const *
240fix_argv (argvec)
241     char **argvec;
242{
243  int i;
244
245  for (i = 1; argvec[i] != 0; i++)
246    {
247      int len, j;
248      char *temp, *newtemp;
249
250      temp = argvec[i];
251      len = strlen (temp);
252      for (j = 0; j < len; j++)
253        {
254          if (temp[j] == '"')
255            {
256              newtemp = (char *) xmalloc (len + 2);
257              strncpy (newtemp, temp, j);
258              newtemp [j] = '\\';
259              strncpy (&newtemp [j+1], &temp [j], len-j);
260              newtemp [len+1] = 0;
261              temp = newtemp;
262              len++;
263              j++;
264            }
265        }
266
267        argvec[i] = temp;
268      }
269
270  return (char * const *) argvec;
271}
272
273#endif /* ! defined (__CYGWIN32__) */
274
275int
276pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
277     const char *program;
278     char * const *argv;
279     const char *this_pname;
280     const char *temp_base;
281     char **errmsg_fmt;
282     const char **errmsg_arg;
283     int flags;
284{
285  int pid;
286
287  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
288    abort ();
289  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
290    (_P_NOWAIT, program, fix_argv (argv));
291  if (pid == -1)
292    {
293      *errmsg_fmt = install_error_msg;
294      *errmsg_arg = program;
295      return -1;
296    }
297  return pid;
298}
299
300int
301pwait (pid, status, flags)
302     int pid;
303     int *status;
304     int flags;
305{
306  int termstat;
307
308  pid = cwait (&termstat, pid, WAIT_CHILD);
309
310  /* ??? Here's an opportunity to canonicalize the values in STATUS.
311     Needed?  */
312
313  /* cwait returns the child process exit code in termstat.
314     A value of 3 indicates that the child caught a signal, but not
315     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
316     report SIGABRT.  */
317  if (termstat == 3)
318    *status = SIGABRT;
319  else
320    *status = (((termstat) & 0xff) << 8);
321
322  return pid;
323}
324
325#endif /* _WIN32 */
326
327#ifdef OS2
328
329/* ??? Does OS2 have process.h?  */
330extern int spawnv ();
331extern int spawnvp ();
332
333int
334pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
335     const char *program;
336     char * const *argv;
337     const char *this_pname;
338     const char *temp_base;
339     char **errmsg_fmt, **errmsg_arg;
340     int flags;
341{
342  int pid;
343
344  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
345    abort ();
346  /* ??? Presumably 1 == _P_NOWAIT.  */
347  pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
348  if (pid == -1)
349    {
350      *errmsg_fmt = install_error_msg;
351      *errmsg_arg = program;
352      return -1;
353    }
354  return pid;
355}
356
357int
358pwait (pid, status, flags)
359     int pid;
360     int *status;
361     int flags;
362{
363  /* ??? Here's an opportunity to canonicalize the values in STATUS.
364     Needed?  */
365  int pid = wait (status);
366  return pid;
367}
368
369#endif /* OS2 */
370
371#ifdef MPW
372
373/* MPW pexecute doesn't actually run anything; instead, it writes out
374   script commands that, when run, will do the actual executing.
375
376   For example, in GCC's case, GCC will write out several script commands:
377
378   cpp ...
379   cc1 ...
380   as ...
381   ld ...
382
383   and then exit.  None of the above programs will have run yet.  The task
384   that called GCC will then execute the script and cause cpp,etc. to run.
385   The caller must invoke pfinish before calling exit.  This adds
386   the finishing touches to the generated script.  */
387
388static int first_time = 1;
389
390int
391pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
392     const char *program;
393     char * const *argv;
394     const char *this_pname;
395     const char *temp_base;
396     char **errmsg_fmt, **errmsg_arg;
397     int flags;
398{
399  char tmpprogram[255];
400  char *cp, *tmpname;
401  int i;
402
403  mpwify_filename (program, tmpprogram);
404  if (first_time)
405    {
406      printf ("Set Failed 0\n");
407      first_time = 0;
408    }
409
410  fputs ("If {Failed} == 0\n", stdout);
411  /* If being verbose, output a copy of the command.  It should be
412     accurate enough and escaped enough to be "clickable".  */
413  if (flags & PEXECUTE_VERBOSE)
414    {
415      fputs ("\tEcho ", stdout);
416      fputc ('\'', stdout);
417      fputs (tmpprogram, stdout);
418      fputc ('\'', stdout);
419      fputc (' ', stdout);
420      for (i=1; argv[i]; i++)
421        {
422          fputc ('\'', stdout);
423          /* See if we have an argument that needs fixing.  */
424          if (strchr(argv[i], '/'))
425            {
426              tmpname = (char *) xmalloc (256);
427              mpwify_filename (argv[i], tmpname);
428              argv[i] = tmpname;
429            }
430          for (cp = argv[i]; *cp; cp++)
431            {
432              /* Write an Option-d escape char in front of special chars.  */
433              if (strchr("'+", *cp))
434                fputc ('\266', stdout);
435              fputc (*cp, stdout);
436            }
437          fputc ('\'', stdout);
438          fputc (' ', stdout);
439        }
440      fputs ("\n", stdout);
441    }
442  fputs ("\t", stdout);
443  fputs (tmpprogram, stdout);
444  fputc (' ', stdout);
445
446  for (i=1; argv[i]; i++)
447    {
448      /* See if we have an argument that needs fixing.  */
449      if (strchr(argv[i], '/'))
450        {
451          tmpname = (char *) xmalloc (256);
452          mpwify_filename (argv[i], tmpname);
453          argv[i] = tmpname;
454        }
455      if (strchr (argv[i], ' '))
456        fputc ('\'', stdout);
457      for (cp = argv[i]; *cp; cp++)
458        {
459          /* Write an Option-d escape char in front of special chars.  */
460          if (strchr("'+", *cp))
461            fputc ('\266', stdout);
462          fputc (*cp, stdout);
463        }
464      if (strchr (argv[i], ' '))
465        fputc ('\'', stdout);
466      fputc (' ', stdout);
467    }
468
469  fputs ("\n", stdout);
470
471  /* Output commands that arrange to clean up and exit if a failure occurs.
472     We have to be careful to collect the status from the program that was
473     run, rather than some other script command.  Also, we don't exit
474     immediately, since necessary cleanups are at the end of the script.  */
475  fputs ("\tSet TmpStatus {Status}\n", stdout);
476  fputs ("\tIf {TmpStatus} != 0\n", stdout);
477  fputs ("\t\tSet Failed {TmpStatus}\n", stdout);
478  fputs ("\tEnd\n", stdout);
479  fputs ("End\n", stdout);
480
481  /* We're just composing a script, can't fail here.  */
482  return 0;
483}
484
485int
486pwait (pid, status, flags)
487     int pid;
488     int *status;
489     int flags;
490{
491  *status = 0;
492  return 0;
493}
494
495/* Write out commands that will exit with the correct error code
496   if something in the script failed.  */
497
498void
499pfinish ()
500{
501  printf ("\tExit \"{Failed}\"\n");
502}
503
504#endif /* MPW */
505
506/* include for Unix-like environments but not for Dos-like environments */
507#if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \
508    && ! defined (_WIN32)
509
510#ifdef VMS
511#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
512               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
513#else
514#ifdef USG
515#define vfork fork
516#endif
517#endif
518
519extern int execv ();
520extern int execvp ();
521
522int
523pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
524     const char *program;
525     char * const *argv;
526     const char *this_pname;
527     const char *temp_base;
528     char **errmsg_fmt, **errmsg_arg;
529     int flags;
530{
531  int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
532  int pid;
533  int pdes[2];
534  int input_desc, output_desc;
535  int retries, sleep_interval;
536  /* Pipe waiting from last process, to be used as input for the next one.
537     Value is STDIN_FILE_NO if no pipe is waiting
538     (i.e. the next command is the first of a group).  */
539  static int last_pipe_input;
540
541  /* If this is the first process, initialize.  */
542  if (flags & PEXECUTE_FIRST)
543    last_pipe_input = STDIN_FILE_NO;
544
545  input_desc = last_pipe_input;
546
547  /* If this isn't the last process, make a pipe for its output,
548     and record it as waiting to be the input to the next process.  */
549  if (! (flags & PEXECUTE_LAST))
550    {
551      if (pipe (pdes) < 0)
552        {
553          *errmsg_fmt = "pipe";
554          *errmsg_arg = NULL;
555          return -1;
556        }
557      output_desc = pdes[WRITE_PORT];
558      last_pipe_input = pdes[READ_PORT];
559    }
560  else
561    {
562      /* Last process.  */
563      output_desc = STDOUT_FILE_NO;
564      last_pipe_input = STDIN_FILE_NO;
565    }
566
567  /* Fork a subprocess; wait and retry if it fails.  */
568  sleep_interval = 1;
569  for (retries = 0; retries < 4; retries++)
570    {
571      pid = vfork ();
572      if (pid >= 0)
573        break;
574      sleep (sleep_interval);
575      sleep_interval *= 2;
576    }
577
578  switch (pid)
579    {
580    case -1:
581      {
582#ifdef vfork
583        *errmsg_fmt = "fork";
584#else
585        *errmsg_fmt = "vfork";
586#endif
587        *errmsg_arg = NULL;
588        return -1;
589      }
590
591    case 0: /* child */
592      /* Move the input and output pipes into place, if necessary.  */
593      if (input_desc != STDIN_FILE_NO)
594        {
595          close (STDIN_FILE_NO);
596          dup (input_desc);
597          close (input_desc);
598        }
599      if (output_desc != STDOUT_FILE_NO)
600        {
601          close (STDOUT_FILE_NO);
602          dup (output_desc);
603          close (output_desc);
604        }
605
606      /* Close the parent's descs that aren't wanted here.  */
607      if (last_pipe_input != STDIN_FILE_NO)
608        close (last_pipe_input);
609
610      /* Exec the program.  */
611      (*func) (program, argv);
612
613      /* Note: Calling fprintf and exit here doesn't seem right for vfork.  */
614      fprintf (stderr, "%s: ", this_pname);
615      fprintf (stderr, install_error_msg, program);
616#ifdef IN_GCC
617      fprintf (stderr, ": %s\n", my_strerror (errno));
618#else
619      fprintf (stderr, ": %s\n", xstrerror (errno));
620#endif
621      exit (-1);
622      /* NOTREACHED */
623      return 0;
624
625    default:
626      /* In the parent, after forking.
627         Close the descriptors that we made for this child.  */
628      if (input_desc != STDIN_FILE_NO)
629        close (input_desc);
630      if (output_desc != STDOUT_FILE_NO)
631        close (output_desc);
632
633      /* Return child's process number.  */
634      return pid;
635    }
636}
637
638int
639pwait (pid, status, flags)
640     int pid;
641     int *status;
642     int flags;
643{
644  /* ??? Here's an opportunity to canonicalize the values in STATUS.
645     Needed?  */
646#ifdef VMS
647  pid = waitpid (-1, status, 0);
648#else
649  pid = wait (status);
650#endif
651  return pid;
652}
653
654#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! _WIN32 */
Note: See TracBrowser for help on using the repository browser.