1169695Skan/* Utilities to execute a program in a subprocess (possibly linked by pipes
2169695Skan   with other subprocesses), and wait for it.  Generic MSDOS specialization.
3169695Skan   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
4169695Skan   Free Software Foundation, Inc.
5169695Skan
6169695SkanThis file is part of the libiberty library.
7169695SkanLibiberty is free software; you can redistribute it and/or
8169695Skanmodify it under the terms of the GNU Library General Public
9169695SkanLicense as published by the Free Software Foundation; either
10169695Skanversion 2 of the License, or (at your option) any later version.
11169695Skan
12169695SkanLibiberty is distributed in the hope that it will be useful,
13169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
14169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15169695SkanLibrary General Public License for more details.
16169695Skan
17169695SkanYou should have received a copy of the GNU Library General Public
18169695SkanLicense along with libiberty; see the file COPYING.LIB.  If not,
19169695Skanwrite to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20169695SkanBoston, MA 02110-1301, USA.  */
21169695Skan
22169695Skan#include "pex-common.h"
23169695Skan
24169695Skan#include <stdio.h>
25169695Skan#include <errno.h>
26169695Skan#ifdef NEED_DECLARATION_ERRNO
27169695Skanextern int errno;
28169695Skan#endif
29169695Skan#ifdef HAVE_STRING_H
30169695Skan#include <string.h>
31169695Skan#endif
32169695Skan#ifdef HAVE_STDLIB_H
33169695Skan#include <stdlib.h>
34169695Skan#endif
35169695Skan
36169695Skan#include "safe-ctype.h"
37169695Skan#include <process.h>
38169695Skan
39169695Skan/* The structure we keep in obj->sysdep.  */
40169695Skan
41169695Skan#define PEX_MSDOS_FILE_COUNT 3
42169695Skan
43169695Skan#define PEX_MSDOS_FD_OFFSET 10
44169695Skan
45169695Skanstruct pex_msdos
46169695Skan{
47169695Skan  /* An array of file names.  We refer to these using file descriptors
48169695Skan     of 10 + array index.  */
49169695Skan  const char *files[PEX_MSDOS_FILE_COUNT];
50169695Skan  /* Exit statuses of programs which have been run.  */
51169695Skan  int *statuses;
52169695Skan};
53169695Skan
54169695Skanstatic int pex_msdos_open (struct pex_obj *, const char *, int);
55169695Skanstatic int pex_msdos_open (struct pex_obj *, const char *, int);
56169695Skanstatic int pex_msdos_fdindex (struct pex_msdos *, int);
57169695Skanstatic long pex_msdos_exec_child (struct pex_obj *, int, const char *,
58169695Skan				  char * const *, char * const *,
59169695Skan				  int, int, int, int,
60169695Skan				  int, const char **, int *);
61169695Skanstatic int pex_msdos_close (struct pex_obj *, int);
62169695Skanstatic int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *,
63169695Skan			   int, const char **, int *);
64169695Skanstatic void pex_msdos_cleanup (struct pex_obj *);
65169695Skan
66169695Skan/* The list of functions we pass to the common routines.  */
67169695Skan
68169695Skanconst struct pex_funcs funcs =
69169695Skan{
70169695Skan  pex_msdos_open,
71169695Skan  pex_msdos_open,
72169695Skan  pex_msdos_exec_child,
73169695Skan  pex_msdos_close,
74169695Skan  pex_msdos_wait,
75169695Skan  NULL, /* pipe */
76169695Skan  NULL, /* fdopenr */
77169695Skan  NULL, /* fdopenw */
78169695Skan  pex_msdos_cleanup
79169695Skan};
80169695Skan
81169695Skan/* Return a newly initialized pex_obj structure.  */
82169695Skan
83169695Skanstruct pex_obj *
84169695Skanpex_init (int flags, const char *pname, const char *tempbase)
85169695Skan{
86169695Skan  struct pex_obj *ret;
87169695Skan  int i;
88169695Skan
89169695Skan  /* MSDOS does not support pipes.  */
90169695Skan  flags &= ~ PEX_USE_PIPES;
91169695Skan
92169695Skan  ret = pex_init_common (flags, pname, tempbase, funcs);
93169695Skan
94169695Skan  ret->sysdep = XNEW (struct pex_msdos);
95169695Skan  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
96169695Skan    ret->files[i] = NULL;
97169695Skan  ret->statuses = NULL;
98169695Skan
99169695Skan  return ret;
100169695Skan}
101169695Skan
102169695Skan/* Open a file.  FIXME: We ignore the binary argument, since we have
103169695Skan   no way to handle it.  */
104169695Skan
105169695Skanstatic int
106169695Skanpex_msdos_open (struct pex_obj *obj, const char *name,
107169695Skan		int binary ATTRIBUTE_UNUSED)
108169695Skan{
109169695Skan  struct pex_msdos *ms;
110169695Skan  int i;
111169695Skan
112169695Skan  ms = (struct pex_msdos *) obj->sysdep;
113169695Skan
114169695Skan  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
115169695Skan    {
116169695Skan      if (ms->files[i] == NULL)
117169695Skan	{
118169695Skan	  ms->files[i] = xstrdup (name);
119169695Skan	  return i + PEX_MSDOS_FD_OFFSET;
120169695Skan	}
121169695Skan    }
122169695Skan
123169695Skan  abort ();
124169695Skan}
125169695Skan
126169695Skan/* Get the index into msdos->files associated with an open file
127169695Skan   descriptor.  */
128169695Skan
129169695Skanstatic int
130169695Skanpex_msdos_fdindex (struct pex_msdos *ms, int fd)
131169695Skan{
132169695Skan  fd -= PEX_MSDOS_FD_OFFSET;
133169695Skan  if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
134169695Skan    abort ();
135169695Skan  return fd;
136169695Skan}
137169695Skan
138169695Skan
139169695Skan/* Close a file.  */
140169695Skan
141169695Skanstatic int
142169695Skanpex_msdos_close (struct pex_obj *obj, int fd)
143169695Skan{
144169695Skan  struct pex_msdos *ms;
145169695Skan  int fdinex;
146169695Skan
147169695Skan  ms = (struct pex_msdos *) obj->sysdep;
148169695Skan  fdindex = pe_msdos_fdindex (ms, fd);
149169695Skan  free (ms->files[fdindex]);
150169695Skan  ms->files[fdindex] = NULL;
151169695Skan}
152169695Skan
153169695Skan/* Execute a child.  */
154169695Skan
155169695Skanstatic long
156169695Skanpex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
157169695Skan		      char * const * argv, char * const * env, int in, int out,
158169695Skan		      int toclose ATTRIBUTE_UNUSED,
159169695Skan		      int errdes ATTRIBUTE_UNUSED, const char **errmsg,
160169695Skan		      int *err)
161169695Skan{
162169695Skan  struct pex_msdos *ms;
163169695Skan  char *temp_base;
164169695Skan  int temp_base_allocated;
165169695Skan  char *rf;
166169695Skan  int inindex;
167169695Skan  char *infile;
168169695Skan  int outindex;
169169695Skan  char *outfile;
170169695Skan  char *scmd;
171169695Skan  FILE *argfile;
172169695Skan  int i;
173169695Skan  int status;
174169695Skan
175169695Skan  ms = (struct pex_msdos *) obj->sysdep;
176169695Skan
177169695Skan  /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
178169695Skan     and PEX_STDERR_TO_STDOUT.  */
179169695Skan
180169695Skan  temp_base = obj->temp_base;
181169695Skan  if (temp_base != NULL)
182169695Skan    temp_base_allocated = 0;
183169695Skan  else
184169695Skan    {
185169695Skan      temp_base = choose_temp_base ();
186169695Skan      temp_base_allocated = 1;
187169695Skan    }
188169695Skan
189169695Skan  rf = concat (temp_base, ".gp", NULL);
190169695Skan
191169695Skan  if (temp_base_allocated)
192169695Skan    free (temp_base);
193169695Skan
194169695Skan  if (in == STDIN_FILE_NO)
195169695Skan    {
196169695Skan      inindex = -1;
197169695Skan      infile = "";
198169695Skan    }
199169695Skan  else
200169695Skan    {
201169695Skan      inindex = pex_msdos_fdindex (ms, in);
202169695Skan      infile = ms->files[inindex];
203169695Skan    }
204169695Skan
205169695Skan  if (out == STDOUT_FILE_NO)
206169695Skan    {
207169695Skan      outindex = -1;
208169695Skan      outfile = "";
209169695Skan    }
210169695Skan  else
211169695Skan    {
212169695Skan      outindex = pex_msdos_fdindex (ms, out);
213169695Skan      outfile = ms->files[outindex];
214169695Skan    }
215169695Skan
216169695Skan  scmd = XNEWVEC (char, strlen (program)
217169695Skan		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
218169695Skan		  + strlen (rf)
219169695Skan		  + strlen (infile)
220169695Skan		  + strlen (outfile)
221169695Skan		  + 10);
222169695Skan  sprintf (scmd, "%s%s @%s%s%s%s%s",
223169695Skan	   program,
224169695Skan	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
225169695Skan	   rf,
226169695Skan	   inindex != -1 ? " <" : "",
227169695Skan	   infile,
228169695Skan	   outindex != -1 ? " >" : "",
229169695Skan	   outfile);
230169695Skan
231169695Skan  argfile = fopen (rf, "w");
232169695Skan  if (argfile == NULL)
233169695Skan    {
234169695Skan      *err = errno;
235169695Skan      free (scmd);
236169695Skan      free (rf);
237169695Skan      *errmsg = "cannot open temporary command file";
238169695Skan      return -1;
239169695Skan    }
240169695Skan
241169695Skan  for (i = 1; argv[i] != NULL; ++i)
242169695Skan    {
243169695Skan      char *p;
244169695Skan
245169695Skan      for (p = argv[i]; *p != '\0'; ++p)
246169695Skan	{
247169695Skan	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
248169695Skan	    putc ('\\', argfile);
249169695Skan	  putc (*p, argfile);
250169695Skan	}
251169695Skan      putc ('\n', argfile);
252169695Skan    }
253169695Skan
254169695Skan  fclose (argfile);
255169695Skan
256169695Skan  status = system (scmd);
257169695Skan
258169695Skan  if (status == -1)
259169695Skan    {
260169695Skan      *err = errno;
261169695Skan      remove (rf);
262169695Skan      free (scmd);
263169695Skan      free (rf);
264169695Skan      *errmsg = "system";
265169695Skan      return -1;
266169695Skan    }
267169695Skan
268169695Skan  remove (rf);
269169695Skan  free (scmd);
270169695Skan  free (rf);
271169695Skan
272169695Skan  /* Save the exit status for later.  When we are called, obj->count
273169695Skan     is the number of children which have executed before this
274169695Skan     one.  */
275169695Skan  ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
276169695Skan  ms->statuses[obj->count] = status;
277169695Skan
278169695Skan  return obj->count;
279169695Skan}
280169695Skan
281169695Skan/* Wait for a child process to complete.  Actually the child process
282169695Skan   has already completed, and we just need to return the exit
283169695Skan   status.  */
284169695Skan
285169695Skanstatic int
286169695Skanpex_msdos_wait (struct pex_obj *obj, long pid, int *status,
287169695Skan		struct pex_time *time, int done ATTRIBUTE_UNUSED,
288169695Skan		const char **errmsg ATTRIBUTE_UNUSED,
289169695Skan		int *err ATTRIBUTE_UNUSED)
290169695Skan{
291169695Skan  struct pex_msdos *ms;
292169695Skan
293169695Skan  ms = (struct pex_msdos *) obj->sysdep;
294169695Skan
295169695Skan  if (time != NULL)
296169695Skan    memset (time, 0, sizeof *time);
297169695Skan
298169695Skan  *status = ms->statuses[pid];
299169695Skan
300169695Skan  return 0;
301169695Skan}
302169695Skan
303169695Skan/* Clean up the pex_msdos structure.  */
304169695Skan
305169695Skanstatic void
306169695Skanpex_msdos_cleanup (struct pex_obj  *obj)
307169695Skan{
308169695Skan  struct pex_msdos *ms;
309169695Skan  int i;
310169695Skan
311169695Skan  ms = (struct pex_msdos *) obj->sysdep;
312169695Skan  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
313169695Skan    if (msdos->files[i] != NULL)
314169695Skan      free (msdos->files[i]);
315169695Skan  if (msdos->statuses != NULL)
316169695Skan    free (msdos->statuses);
317169695Skan  free (msdos);
318169695Skan  obj->sysdep = NULL;
319169695Skan}
320