OSDN Git Service

2006-04-10 Jim Blandy <jimb@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / libiberty / pex-common.c
1 /* Common code for executing a program in a sub-process.
2    Copyright (C) 2005 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor <ian@airs.com>.
4
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB.  If not,
18 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA.  */
20
21 #include "config.h"
22 #include "libiberty.h"
23 #include "pex-common.h"
24
25 #include <stdio.h>
26 #include <errno.h>
27 #ifdef NEED_DECLARATION_ERRNO
28 extern int errno;
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 extern int mkstemps (char *, int);
41
42 /* This file contains subroutines for the program execution routines
43    (pex_init, pex_run, etc.).  This file is compiled on all
44    systems.  */
45
46 static void pex_add_remove (struct pex_obj *, const char *, int);
47 static int pex_get_status_and_time (struct pex_obj *, int, const char **,
48                                     int *);
49
50 /* Initialize a pex_obj structure.  */
51
52 struct pex_obj *
53 pex_init_common (int flags, const char *pname, const char *tempbase,
54                  const struct pex_funcs *funcs)
55 {
56   struct pex_obj *obj;
57
58   obj = XNEW (struct pex_obj);
59   obj->flags = flags;
60   obj->pname = pname;
61   obj->tempbase = tempbase;
62   obj->next_input = STDIN_FILE_NO;
63   obj->next_input_name = NULL;
64   obj->next_input_name_allocated = 0;
65   obj->count = 0;
66   obj->children = NULL;
67   obj->status = NULL;
68   obj->time = NULL;
69   obj->number_waited = 0;
70   obj->read_output = NULL;
71   obj->remove_count = 0;
72   obj->remove = NULL;
73   obj->funcs = funcs;
74   obj->sysdep = NULL;
75   return obj;
76 }
77
78 /* Add a file to be removed when we are done.  */
79
80 static void
81 pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
82 {
83   char *add;
84
85   ++obj->remove_count;
86   obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
87   if (allocated)
88     add = (char *) name;
89   else
90     add = xstrdup (name);
91   obj->remove[obj->remove_count - 1] = add;
92 }
93
94 /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
95    Return NULL if we were unable to reserve a temporary filename.
96
97    If non-NULL, the result is either allocated with malloc, or the
98    same pointer as NAME.  */
99 static char *
100 temp_file (struct pex_obj *obj, int flags, char *name)
101 {
102   if (name == NULL)
103     {
104       if (obj->tempbase == NULL)
105         {
106           name = make_temp_file (NULL);
107         }
108       else
109         {
110           int len = strlen (obj->tempbase);
111           int out;
112
113           if (len >= 6
114               && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
115             name = xstrdup (obj->tempbase);
116           else
117             name = concat (obj->tempbase, "XXXXXX", NULL);
118
119           out = mkstemps (name, 0);
120           if (out < 0)
121             {
122               free (name);
123               return NULL;
124             }
125
126           /* This isn't obj->funcs->close because we got the
127              descriptor from mkstemps, not from a function in
128              obj->funcs.  Calling close here is just like what
129              make_temp_file does.  */
130           close (out);
131         }
132     }
133   else if ((flags & PEX_SUFFIX) != 0)
134     {
135       if (obj->tempbase == NULL)
136         name = make_temp_file (name);
137       else
138         name = concat (obj->tempbase, name, NULL);
139     }
140
141   return name;
142 }
143
144 /* Run a program.  */
145
146 const char *
147 pex_run (struct pex_obj *obj, int flags, const char *executable,
148          char * const * argv, const char *orig_outname, const char *errname,
149          int *err)
150 {
151   const char *errmsg;
152   int in, out, errdes;
153   char *outname;
154   int outname_allocated;
155   int p[2];
156   long pid;
157
158   in = -1;
159   out = -1;
160   errdes = -1;
161   outname = (char *) orig_outname;
162   outname_allocated = 0;
163
164   /* Set IN.  */
165
166   if (obj->next_input_name != NULL)
167     {
168       /* We have to make sure that the previous process has completed
169          before we try to read the file.  */
170       if (!pex_get_status_and_time (obj, 0, &errmsg, err))
171         goto error_exit;
172
173       in = obj->funcs->open_read (obj, obj->next_input_name,
174                                   (flags & PEX_BINARY_INPUT) != 0);
175       if (in < 0)
176         {
177           *err = errno;
178           errmsg = "open temporary file";
179           goto error_exit;
180         }
181       if (obj->next_input_name_allocated)
182         {
183           free (obj->next_input_name);
184           obj->next_input_name_allocated = 0;
185         }
186       obj->next_input_name = NULL;
187     }
188   else
189     {
190       in = obj->next_input;
191       if (in < 0)
192         {
193           *err = 0;
194           errmsg = "pipeline already complete";
195           goto error_exit;
196         }
197     }
198
199   /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
200
201   if ((flags & PEX_LAST) != 0)
202     {
203       if (outname == NULL)
204         out = STDOUT_FILE_NO;
205       else if ((flags & PEX_SUFFIX) != 0)
206         {
207           outname = concat (obj->tempbase, outname, NULL);
208           outname_allocated = 1;
209         }
210       obj->next_input = -1;
211     }
212   else if ((obj->flags & PEX_USE_PIPES) == 0)
213     {
214       outname = temp_file (obj, flags, outname);
215       if (! outname)
216         {
217           *err = 0;
218           errmsg = "could not create temporary file";
219           goto error_exit;
220         }
221
222       if (outname != orig_outname)
223         outname_allocated = 1;
224
225       if ((obj->flags & PEX_SAVE_TEMPS) == 0)
226         {
227           pex_add_remove (obj, outname, outname_allocated);
228           outname_allocated = 0;
229         }
230
231       /* Hand off ownership of outname to the next stage.  */
232       obj->next_input_name = outname;
233       obj->next_input_name_allocated = outname_allocated;
234       outname_allocated = 0;
235     }
236   else
237     {
238       if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
239         {
240           *err = errno;
241           errmsg = "pipe";
242           goto error_exit;
243         }
244
245       out = p[WRITE_PORT];
246       obj->next_input = p[READ_PORT];
247     }
248
249   if (out < 0)
250     {
251       out = obj->funcs->open_write (obj, outname,
252                                     (flags & PEX_BINARY_OUTPUT) != 0);
253       if (out < 0)
254         {
255           *err = errno;
256           errmsg = "open temporary output file";
257           goto error_exit;
258         }
259     }
260
261   if (outname_allocated)
262     {
263       free (outname);
264       outname_allocated = 0;
265     }
266
267   /* Set ERRDES.  */
268
269   if (errname == NULL)
270     errdes = STDERR_FILE_NO;
271   else
272     {
273       /* We assume that stderr is in text mode--it certainly shouldn't
274          be controlled by PEX_BINARY_OUTPUT.  If necessary, we can add
275          a PEX_BINARY_STDERR flag.  */
276       errdes = obj->funcs->open_write (obj, errname, 0);
277       if (errdes < 0)
278         {
279           *err = errno;
280           errmsg = "open error file";
281           goto error_exit;
282         }
283     }
284
285   /* Run the program.  */
286
287   pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
288                                 &errmsg, err);
289   if (pid < 0)
290     goto error_exit;
291
292   ++obj->count;
293   obj->children = XRESIZEVEC (long, obj->children, obj->count);
294   obj->children[obj->count - 1] = pid;
295
296   return NULL;
297
298  error_exit:
299   if (in >= 0 && in != STDIN_FILE_NO)
300     obj->funcs->close (obj, in);
301   if (out >= 0 && out != STDOUT_FILE_NO)
302     obj->funcs->close (obj, out);
303   if (errdes >= 0 && errdes != STDERR_FILE_NO)
304     obj->funcs->close (obj, errdes);
305   if (outname_allocated)
306     free (outname);
307   return errmsg;
308 }
309
310 /* Return a FILE pointer for the output of the last program
311    executed.  */
312
313 FILE *
314 pex_read_output (struct pex_obj *obj, int binary)
315 {
316   if (obj->next_input_name != NULL)
317     {
318       const char *errmsg;
319       int err;
320
321       /* We have to make sure that the process has completed before we
322          try to read the file.  */
323       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
324         {
325           errno = err;
326           return NULL;
327         }
328
329       obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
330
331       if (obj->next_input_name_allocated)
332         {
333           free (obj->next_input_name);
334           obj->next_input_name_allocated = 0;
335         }
336       obj->next_input_name = NULL;
337     }
338   else
339     {
340       int o;
341
342       o = obj->next_input;
343       if (o < 0 || o == STDIN_FILE_NO)
344         return NULL;
345       obj->read_output = obj->funcs->fdopenr (obj, o, binary);
346       obj->next_input = -1;
347     }
348
349   return obj->read_output;
350 }
351
352 /* Get the exit status and, if requested, the resource time for all
353    the child processes.  Return 0 on failure, 1 on success.  */
354
355 static int
356 pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
357                          int *err)
358 {
359   int ret;
360   int i;
361
362   if (obj->number_waited == obj->count)
363     return 1;
364
365   obj->status = XRESIZEVEC (int, obj->status, obj->count);
366   if ((obj->flags & PEX_RECORD_TIMES) != 0)
367     obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
368
369   ret = 1;
370   for (i = obj->number_waited; i < obj->count; ++i)
371     {
372       if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
373                             obj->time == NULL ? NULL : &obj->time[i],
374                             done, errmsg, err) < 0)
375         ret = 0;
376     }
377   obj->number_waited = i;
378
379   return ret;
380 }
381
382 /* Get exit status of executed programs.  */
383
384 int
385 pex_get_status (struct pex_obj *obj, int count, int *vector)
386 {
387   if (obj->status == NULL)
388     {
389       const char *errmsg;
390       int err;
391
392       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
393         return 0;
394     }
395
396   if (count > obj->count)
397     {
398       memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
399       count = obj->count;
400     }
401
402   memcpy (vector, obj->status, count * sizeof (int));
403
404   return 1;
405 }
406
407 /* Get process times of executed programs.  */
408
409 int
410 pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
411 {
412   if (obj->status == NULL)
413     {
414       const char *errmsg;
415       int err;
416
417       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
418         return 0;
419     }
420
421   if (obj->time == NULL)
422     return 0;
423
424   if (count > obj->count)
425     {
426       memset (vector + obj->count, 0,
427               (count - obj->count) * sizeof (struct pex_time));
428       count = obj->count;
429     }
430
431   memcpy (vector, obj->time, count * sizeof (struct pex_time));
432
433   return 1;
434 }
435
436 /* Free a pex_obj structure.  */
437
438 void
439 pex_free (struct pex_obj *obj)
440 {
441   if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
442     obj->funcs->close (obj, obj->next_input);
443
444   /* If the caller forgot to wait for the children, we do it here, to
445      avoid zombies.  */
446   if (obj->status == NULL)
447     {
448       const char *errmsg;
449       int err;
450
451       obj->flags &= ~ PEX_RECORD_TIMES;
452       pex_get_status_and_time (obj, 1, &errmsg, &err);
453     }
454
455   if (obj->next_input_name_allocated)
456     free (obj->next_input_name);
457   if (obj->children != NULL)
458     free (obj->children);
459   if (obj->status != NULL)
460     free (obj->status);
461   if (obj->time != NULL)
462     free (obj->time);
463   if (obj->read_output != NULL)
464     fclose (obj->read_output);
465
466   if (obj->remove_count > 0)
467     {
468       int i;
469
470       for (i = 0; i < obj->remove_count; ++i)
471         {
472           remove (obj->remove[i]);
473           free (obj->remove[i]);
474         }
475       free (obj->remove);
476     }
477
478   if (obj->funcs->cleanup != NULL)
479     obj->funcs->cleanup (obj);
480
481   free (obj);
482 }