OSDN Git Service

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