1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2   with other subprocesses), and wait for it.  DJGPP specialization.
3   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
4   Free Software Foundation, Inc.
5
6This file is part of the libiberty library.
7Libiberty is free software; you can redistribute it and/or
8modify it under the terms of the GNU Library General Public
9License as published by the Free Software Foundation; either
10version 2 of the License, or (at your option) any later version.
11
12Libiberty is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15Library General Public License for more details.
16
17You should have received a copy of the GNU Library General Public
18License along with libiberty; see the file COPYING.LIB.  If not,
19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22#include "pex-common.h"
23
24#include <stdio.h>
25#include <errno.h>
26#ifdef NEED_DECLARATION_ERRNO
27extern int errno;
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#include <string.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <sys/stat.h>
36#include <process.h>
37
38/* Use ECHILD if available, otherwise use EINVAL.  */
39#ifdef ECHILD
40#define PWAIT_ERROR ECHILD
41#else
42#define PWAIT_ERROR EINVAL
43#endif
44
45static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
46static int pex_djgpp_open_write (struct pex_obj *, const char *, int);
47static long pex_djgpp_exec_child (struct pex_obj *, int, const char *,
48				  char * const *, int, int, int,
49				  const char **, int *);
50static int pex_djgpp_close (struct pex_obj *, int);
51static int pex_djgpp_wait (struct pex_obj *, long, int *, struct pex_time *,
52			   int, const char **, int *);
53
54/* The list of functions we pass to the common routines.  */
55
56const struct pex_funcs funcs =
57{
58  pex_djgpp_open_read,
59  pex_djgpp_open_write,
60  pex_djgpp_exec_child,
61  pex_djgpp_close,
62  pex_djgpp_wait,
63  NULL, /* pipe */
64  NULL, /* fdopenr */
65  NULL, /* fdopenw */
66  NULL  /* cleanup */
67};
68
69/* Return a newly initialized pex_obj structure.  */
70
71struct pex_obj *
72pex_init (int flags, const char *pname, const char *tempbase)
73{
74  /* DJGPP does not support pipes.  */
75  flags &= ~ PEX_USE_PIPES;
76  return pex_init_common (flags, pname, tempbase, &funcs);
77}
78
79/* Open a file for reading.  */
80
81static int
82pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
83		     const char *name, int binary)
84{
85  return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT));
86}
87
88/* Open a file for writing.  */
89
90static int
91pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
92		      const char *name, int binary)
93{
94  /* Note that we can't use O_EXCL here because gcc may have already
95     created the temporary file via make_temp_file.  */
96  return open (name,
97	       (O_WRONLY | O_CREAT | O_TRUNC
98		| (binary ? O_BINARY : O_TEXT)),
99	       S_IRUSR | S_IWUSR);
100}
101
102/* Close a file.  */
103
104static int
105pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
106{
107  return close (fd);
108}
109
110/* Execute a child.  */
111
112static long
113pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
114		      char * const * argv, int in, int out, int errdes,
115		      const char **errmsg, int *err)
116{
117  int org_in, org_out, org_errdes;
118  int status;
119  int *statuses;
120
121  org_in = -1;
122  org_out = -1;
123  org_errdes = -1;
124
125  if (in != STDIN_FILE_NO)
126    {
127      org_in = dup (STDIN_FILE_NO);
128      if (org_in < 0)
129	{
130	  *err = errno;
131	  *errmsg = "dup";
132	  return -1;
133	}
134      if (dup2 (in, STDIN_FILE_NO) < 0)
135	{
136	  *err = errno;
137	  *errmsg = "dup2";
138	  return -1;
139	}
140      if (close (in) < 0)
141	{
142	  *err = errno;
143	  *errmsg = "close";
144	  return -1;
145	}
146    }
147
148  if (out != STDOUT_FILE_NO)
149    {
150      org_out = dup (STDOUT_FILE_NO);
151      if (org_out < 0)
152	{
153	  *err = errno;
154	  *errmsg = "dup";
155	  return -1;
156	}
157      if (dup2 (out, STDOUT_FILE_NO) < 0)
158	{
159	  *err = errno;
160	  *errmsg = "dup2";
161	  return -1;
162	}
163      if (close (out) < 0)
164	{
165	  *err = errno;
166	  *errmsg = "close";
167	  return -1;
168	}
169    }
170
171  if (errdes != STDERR_FILE_NO
172      || (flags & PEX_STDERR_TO_STDOUT) != 0)
173    {
174      org_errdes = dup (STDERR_FILE_NO);
175      if (org_errdes < 0)
176	{
177	  *err = errno;
178	  *errmsg = "dup";
179	  return -1;
180	}
181      if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
182		 STDERR_FILE_NO) < 0)
183	{
184	  *err = errno;
185	  *errmsg = "dup2";
186	  return -1;
187	}
188      if (errdes != STDERR_FILE_NO)
189	{
190	  if (close (errdes) < 0)
191	    {
192	      *err = errno;
193	      *errmsg = "close";
194	      return -1;
195	    }
196	}
197    }
198
199  status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
200	    (P_WAIT, executable, (char * const *) argv));
201
202  if (status == -1)
203    {
204      *err = errno;
205      *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv";
206    }
207
208  if (in != STDIN_FILE_NO)
209    {
210      if (dup2 (org_in, STDIN_FILE_NO) < 0)
211	{
212	  *err = errno;
213	  *errmsg = "dup2";
214	  return -1;
215	}
216      if (close (org_in) < 0)
217	{
218	  *err = errno;
219	  *errmsg = "close";
220	  return -1;
221	}
222    }
223
224  if (out != STDOUT_FILE_NO)
225    {
226      if (dup2 (org_out, STDOUT_FILE_NO) < 0)
227	{
228	  *err = errno;
229	  *errmsg = "dup2";
230	  return -1;
231	}
232      if (close (org_out) < 0)
233	{
234	  *err = errno;
235	  *errmsg = "close";
236	  return -1;
237	}
238    }
239
240  if (errdes != STDERR_FILE_NO
241      || (flags & PEX_STDERR_TO_STDOUT) != 0)
242    {
243      if (dup2 (org_errdes, STDERR_FILE_NO) < 0)
244	{
245	  *err = errno;
246	  *errmsg = "dup2";
247	  return -1;
248	}
249      if (close (org_errdes) < 0)
250	{
251	  *err = errno;
252	  *errmsg = "close";
253	  return -1;
254	}
255    }
256
257  /* Save the exit status for later.  When we are called, obj->count
258     is the number of children which have executed before this
259     one.  */
260  statuses = (int *) obj->sysdep;
261  statuses = XRESIZEVEC (int, statuses, obj->count + 1);
262  statuses[obj->count] = status;
263  obj->sysdep = (void *) statuses;
264
265  return obj->count;
266}
267
268/* Wait for a child process to complete.  Actually the child process
269   has already completed, and we just need to return the exit
270   status.  */
271
272static int
273pex_djgpp_wait (struct pex_obj *obj, long pid, int *status,
274		struct pex_time *time, int done ATTRIBUTE_UNUSED,
275		const char **errmsg ATTRIBUTE_UNUSED,
276		int *err ATTRIBUTE_UNUSED)
277{
278  int *statuses;
279
280  if (time != NULL)
281    memset (time, 0, sizeof *time);
282
283  statuses = (int *) obj->sysdep;
284  *status = statuses[pid];
285
286  return 0;
287}
288