pex-djgpp.c revision 169696
1234852Sbapt/* Utilities to execute a program in a subprocess (possibly linked by pipes
2234852Sbapt   with other subprocesses), and wait for it.  DJGPP specialization.
3234852Sbapt   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
4234852Sbapt   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 *, char * const *,
49				  int, int, int, int,
50				  const char **, int *);
51static int pex_djgpp_close (struct pex_obj *, int);
52static int pex_djgpp_wait (struct pex_obj *, long, int *, struct pex_time *,
53			   int, const char **, int *);
54
55/* The list of functions we pass to the common routines.  */
56
57const struct pex_funcs funcs =
58{
59  pex_djgpp_open_read,
60  pex_djgpp_open_write,
61  pex_djgpp_exec_child,
62  pex_djgpp_close,
63  pex_djgpp_wait,
64  NULL, /* pipe */
65  NULL, /* fdopenr */
66  NULL, /* fdopenw */
67  NULL  /* cleanup */
68};
69
70/* Return a newly initialized pex_obj structure.  */
71
72struct pex_obj *
73pex_init (int flags, const char *pname, const char *tempbase)
74{
75  /* DJGPP does not support pipes.  */
76  flags &= ~ PEX_USE_PIPES;
77  return pex_init_common (flags, pname, tempbase, &funcs);
78}
79
80/* Open a file for reading.  */
81
82static int
83pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
84		     const char *name, int binary)
85{
86  return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT));
87}
88
89/* Open a file for writing.  */
90
91static int
92pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
93		      const char *name, int binary)
94{
95  /* Note that we can't use O_EXCL here because gcc may have already
96     created the temporary file via make_temp_file.  */
97  return open (name,
98	       (O_WRONLY | O_CREAT | O_TRUNC
99		| (binary ? O_BINARY : O_TEXT)),
100	       S_IRUSR | S_IWUSR);
101}
102
103/* Close a file.  */
104
105static int
106pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
107{
108  return close (fd);
109}
110
111/* Execute a child.  */
112
113static long
114pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
115		      char * const * argv, char * const * env,
116                      int in, int out, int errdes,
117		      int toclose ATTRIBUTE_UNUSED, const char **errmsg,
118		      int *err)
119{
120  int org_in, org_out, org_errdes;
121  int status;
122  int *statuses;
123
124  org_in = -1;
125  org_out = -1;
126  org_errdes = -1;
127
128  if (in != STDIN_FILE_NO)
129    {
130      org_in = dup (STDIN_FILE_NO);
131      if (org_in < 0)
132	{
133	  *err = errno;
134	  *errmsg = "dup";
135	  return -1;
136	}
137      if (dup2 (in, STDIN_FILE_NO) < 0)
138	{
139	  *err = errno;
140	  *errmsg = "dup2";
141	  return -1;
142	}
143      if (close (in) < 0)
144	{
145	  *err = errno;
146	  *errmsg = "close";
147	  return -1;
148	}
149    }
150
151  if (out != STDOUT_FILE_NO)
152    {
153      org_out = dup (STDOUT_FILE_NO);
154      if (org_out < 0)
155	{
156	  *err = errno;
157	  *errmsg = "dup";
158	  return -1;
159	}
160      if (dup2 (out, STDOUT_FILE_NO) < 0)
161	{
162	  *err = errno;
163	  *errmsg = "dup2";
164	  return -1;
165	}
166      if (close (out) < 0)
167	{
168	  *err = errno;
169	  *errmsg = "close";
170	  return -1;
171	}
172    }
173
174  if (errdes != STDERR_FILE_NO
175      || (flags & PEX_STDERR_TO_STDOUT) != 0)
176    {
177      org_errdes = dup (STDERR_FILE_NO);
178      if (org_errdes < 0)
179	{
180	  *err = errno;
181	  *errmsg = "dup";
182	  return -1;
183	}
184      if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
185		 STDERR_FILE_NO) < 0)
186	{
187	  *err = errno;
188	  *errmsg = "dup2";
189	  return -1;
190	}
191      if (errdes != STDERR_FILE_NO)
192	{
193	  if (close (errdes) < 0)
194	    {
195	      *err = errno;
196	      *errmsg = "close";
197	      return -1;
198	    }
199	}
200    }
201
202  if (env)
203    status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve)
204	      (P_WAIT, executable, argv, env));
205  else
206    status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
207  	      (P_WAIT, executable, argv));
208
209  if (status == -1)
210    {
211      *err = errno;
212      *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv";
213    }
214
215  if (in != STDIN_FILE_NO)
216    {
217      if (dup2 (org_in, STDIN_FILE_NO) < 0)
218	{
219	  *err = errno;
220	  *errmsg = "dup2";
221	  return -1;
222	}
223      if (close (org_in) < 0)
224	{
225	  *err = errno;
226	  *errmsg = "close";
227	  return -1;
228	}
229    }
230
231  if (out != STDOUT_FILE_NO)
232    {
233      if (dup2 (org_out, STDOUT_FILE_NO) < 0)
234	{
235	  *err = errno;
236	  *errmsg = "dup2";
237	  return -1;
238	}
239      if (close (org_out) < 0)
240	{
241	  *err = errno;
242	  *errmsg = "close";
243	  return -1;
244	}
245    }
246
247  if (errdes != STDERR_FILE_NO
248      || (flags & PEX_STDERR_TO_STDOUT) != 0)
249    {
250      if (dup2 (org_errdes, STDERR_FILE_NO) < 0)
251	{
252	  *err = errno;
253	  *errmsg = "dup2";
254	  return -1;
255	}
256      if (close (org_errdes) < 0)
257	{
258	  *err = errno;
259	  *errmsg = "close";
260	  return -1;
261	}
262    }
263
264  /* Save the exit status for later.  When we are called, obj->count
265     is the number of children which have executed before this
266     one.  */
267  statuses = (int *) obj->sysdep;
268  statuses = XRESIZEVEC (int, statuses, obj->count + 1);
269  statuses[obj->count] = status;
270  obj->sysdep = (void *) statuses;
271
272  return obj->count;
273}
274
275/* Wait for a child process to complete.  Actually the child process
276   has already completed, and we just need to return the exit
277   status.  */
278
279static int
280pex_djgpp_wait (struct pex_obj *obj, long pid, int *status,
281		struct pex_time *time, int done ATTRIBUTE_UNUSED,
282		const char **errmsg ATTRIBUTE_UNUSED,
283		int *err ATTRIBUTE_UNUSED)
284{
285  int *statuses;
286
287  if (time != NULL)
288    memset (time, 0, sizeof *time);
289
290  statuses = (int *) obj->sysdep;
291  *status = statuses[pid];
292
293  return 0;
294}
295