1214082Sdim/* Utilities to execute a program in a subprocess (possibly linked by pipes
2214082Sdim   with other subprocesses), and wait for it.
3214082Sdim   Copyright (C) 2004 Free Software Foundation, Inc.
4214082Sdim
5214082SdimThis file is part of the libiberty library.
6214082SdimLibiberty is free software; you can redistribute it and/or
7214082Sdimmodify it under the terms of the GNU Library General Public
8214082SdimLicense as published by the Free Software Foundation; either
9214082Sdimversion 2 of the License, or (at your option) any later version.
10214082Sdim
11214082SdimLibiberty is distributed in the hope that it will be useful,
12214082Sdimbut WITHOUT ANY WARRANTY; without even the implied warranty of
13214082SdimMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14214082SdimLibrary General Public License for more details.
15214082Sdim
16214082SdimYou should have received a copy of the GNU Library General Public
17214082SdimLicense along with libiberty; see the file COPYING.LIB.  If not,
18214082Sdimwrite to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19214082SdimBoston, MA 02110-1301, USA.  */
20214082Sdim
21214082Sdim/* pexecute is an old routine.  This implementation uses the newer
22214082Sdim   pex_init/pex_run/pex_get_status/pex_free routines.  Don't use
23214082Sdim   pexecute in new code.  Use the newer routines instead.  */
24214082Sdim
25214082Sdim#include "config.h"
26214082Sdim#include "libiberty.h"
27214082Sdim
28214082Sdim#ifdef HAVE_STDLIB_H
29214082Sdim#include <stdlib.h>
30214082Sdim#endif
31214082Sdim
32214082Sdim/* We only permit a single pexecute chain to execute at a time.  This
33214082Sdim   was always true anyhow, though it wasn't documented.  */
34214082Sdim
35214082Sdimstatic struct pex_obj *pex;
36214082Sdimstatic int idx;
37214082Sdim
38214082Sdimint
39214082Sdimpexecute (const char *program, char * const *argv, const char *pname,
40214082Sdim	  const char *temp_base, char **errmsg_fmt, char **errmsg_arg,
41214082Sdim	  int flags)
42214082Sdim{
43214082Sdim  const char *errmsg;
44214082Sdim  int err;
45214082Sdim
46214082Sdim  if ((flags & PEXECUTE_FIRST) != 0)
47214082Sdim    {
48214082Sdim      if (pex != NULL)
49214082Sdim	{
50214082Sdim	  *errmsg_fmt = (char *) "pexecute already in progress";
51214082Sdim	  *errmsg_arg = NULL;
52214082Sdim	  return -1;
53214082Sdim	}
54214082Sdim      pex = pex_init (PEX_USE_PIPES, pname, temp_base);
55214082Sdim      idx = 0;
56214082Sdim    }
57214082Sdim  else
58214082Sdim    {
59214082Sdim      if (pex == NULL)
60214082Sdim	{
61214082Sdim	  *errmsg_fmt = (char *) "pexecute not in progress";
62214082Sdim	  *errmsg_arg = NULL;
63214082Sdim	  return -1;
64214082Sdim	}
65214082Sdim    }
66214082Sdim
67214082Sdim  errmsg = pex_run (pex,
68214082Sdim		    (((flags & PEXECUTE_LAST) != 0 ? PEX_LAST : 0)
69214082Sdim		     | ((flags & PEXECUTE_SEARCH) != 0 ? PEX_SEARCH : 0)),
70214082Sdim		    program, argv, NULL, NULL, &err);
71214082Sdim  if (errmsg != NULL)
72214082Sdim    {
73214082Sdim      *errmsg_fmt = (char *) errmsg;
74214082Sdim      *errmsg_arg = NULL;
75214082Sdim      return -1;
76214082Sdim    }
77214082Sdim
78214082Sdim  /* Instead of a PID, we just return a one-based index into the
79214082Sdim     status values.  We avoid zero just because the old pexecute would
80214082Sdim     never return it.  */
81214082Sdim  return ++idx;
82214082Sdim}
83214082Sdim
84214082Sdimint
85214082Sdimpwait (int pid, int *status, int flags ATTRIBUTE_UNUSED)
86214082Sdim{
87214082Sdim  /* The PID returned by pexecute is one-based.  */
88214082Sdim  --pid;
89214082Sdim
90214082Sdim  if (pex == NULL || pid < 0 || pid >= idx)
91214082Sdim    return -1;
92214082Sdim
93214082Sdim  if (pid == 0 && idx == 1)
94214082Sdim    {
95214082Sdim      if (!pex_get_status (pex, 1, status))
96214082Sdim	return -1;
97214082Sdim    }
98214082Sdim  else
99214082Sdim    {
100214082Sdim      int *vector;
101214082Sdim
102214082Sdim      vector = XNEWVEC (int, idx);
103214082Sdim      if (!pex_get_status (pex, idx, vector))
104214082Sdim	{
105214082Sdim	  free (vector);
106214082Sdim	  return -1;
107214082Sdim	}
108214082Sdim      *status = vector[pid];
109214082Sdim      free (vector);
110214082Sdim    }
111214082Sdim
112214082Sdim  /* Assume that we are done after the caller has retrieved the last
113214082Sdim     exit status.  The original implementation did not require that
114214082Sdim     the exit statuses be retrieved in order, but this implementation
115214082Sdim     does.  */
116214082Sdim  if (pid + 1 == idx)
117214082Sdim    {
118214082Sdim      pex_free (pex);
119214082Sdim      pex = NULL;
120214082Sdim      idx = 0;
121214082Sdim    }
122214082Sdim
123214082Sdim  return pid + 1;
124214082Sdim}
125