gcc41 removal: Part 1 of 2: makefiles
[dragonfly.git] / contrib / gcc-4.1 / 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 /* Run a program.  */
95
96 const char *
97 pex_run (struct pex_obj *obj, int flags, const char *executable,
98          char * const * argv, const char *orig_outname, const char *errname,
99          int *err)
100 {
101   const char *errmsg;
102   int in, out, errdes;
103   char *outname;
104   int outname_allocated;
105   int p[2];
106   int toclose;
107   long pid;
108
109   in = -1;
110   out = -1;
111   errdes = -1;
112   outname = (char *) orig_outname;
113   outname_allocated = 0;
114
115   /* Set IN.  */
116
117   if (obj->next_input_name != NULL)
118     {
119       /* We have to make sure that the previous process has completed
120          before we try to read the file.  */
121       if (!pex_get_status_and_time (obj, 0, &errmsg, err))
122         goto error_exit;
123
124       in = obj->funcs->open_read (obj, obj->next_input_name,
125                                   (flags & PEX_BINARY_INPUT) != 0);
126       if (in < 0)
127         {
128           *err = errno;
129           errmsg = "open temporary file";
130           goto error_exit;
131         }
132       if (obj->next_input_name_allocated)
133         {
134           free (obj->next_input_name);
135           obj->next_input_name_allocated = 0;
136         }
137       obj->next_input_name = NULL;
138     }
139   else
140     {
141       in = obj->next_input;
142       if (in < 0)
143         {
144           *err = 0;
145           errmsg = "pipeline already complete";
146           goto error_exit;
147         }
148     }
149
150   /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
151
152   if ((flags & PEX_LAST) != 0)
153     {
154       if (outname == NULL)
155         out = STDOUT_FILE_NO;
156       else if ((flags & PEX_SUFFIX) != 0)
157         {
158           outname = concat (obj->tempbase, outname, NULL);
159           outname_allocated = 1;
160         }
161       obj->next_input = -1;
162     }
163   else if ((obj->flags & PEX_USE_PIPES) == 0)
164     {
165       if (outname == NULL)
166         {
167           if (obj->tempbase == NULL)
168             {
169               outname = make_temp_file (NULL);
170               outname_allocated = 1;
171             }
172           else
173             {
174               int len = strlen (obj->tempbase);
175
176               if (len >= 6
177                   && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
178                 outname = xstrdup (obj->tempbase);
179               else
180                 outname = concat (obj->tempbase, "XXXXXX", NULL);
181
182               outname_allocated = 1;
183
184               out = mkstemps (outname, 0);
185               if (out < 0)
186                 {
187                   *err = 0;
188                   errmsg = "could not create temporary output file";
189                   goto error_exit;
190                 }
191
192               /* This isn't obj->funcs->close because we got the
193                  descriptor from mkstemps, not from a function in
194                  obj->funcs.  Calling close here is just like what
195                  make_temp_file does.  */
196               close (out);
197               out = -1;
198             }
199         }
200       else if ((flags & PEX_SUFFIX) != 0)
201         {
202           if (obj->tempbase == NULL)
203             outname = make_temp_file (outname);
204           else
205             outname = concat (obj->tempbase, outname, NULL);
206           outname_allocated = 1;
207         }
208
209       if ((obj->flags & PEX_SAVE_TEMPS) == 0)
210         {
211           pex_add_remove (obj, outname, outname_allocated);
212           outname_allocated = 0;
213         }
214
215       if (!outname_allocated)
216         {
217           obj->next_input_name = outname;
218           obj->next_input_name_allocated = 0;
219         }
220       else
221         {
222           obj->next_input_name = outname;
223           outname_allocated = 0;
224           obj->next_input_name_allocated = 1;
225         }
226     }
227   else
228     {
229       if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
230         {
231           *err = errno;
232           errmsg = "pipe";
233           goto error_exit;
234         }
235
236       out = p[WRITE_PORT];
237       obj->next_input = p[READ_PORT];
238     }
239
240   if (out < 0)
241     {
242       out = obj->funcs->open_write (obj, outname,
243                                     (flags & PEX_BINARY_OUTPUT) != 0);
244       if (out < 0)
245         {
246           *err = errno;
247           errmsg = "open temporary output file";
248           goto error_exit;
249         }
250     }
251
252   if (outname_allocated)
253     {
254       free (outname);
255       outname_allocated = 0;
256     }
257
258   /* Set ERRDES.  */
259
260   if (errname == NULL)
261     errdes = STDERR_FILE_NO;
262   else
263     {
264       /* We assume that stderr is in text mode--it certainly shouldn't
265          be controlled by PEX_BINARY_OUTPUT.  If necessary, we can add
266          a PEX_BINARY_STDERR flag.  */
267       errdes = obj->funcs->open_write (obj, errname, 0);
268       if (errdes < 0)
269         {
270           *err = errno;
271           errmsg = "open error file";
272           goto error_exit;
273         }
274     }
275
276   /* If we are using pipes, the child process has to close the next
277      input pipe.  */
278
279   if ((obj->flags & PEX_USE_PIPES) == 0)
280     toclose = -1;
281   else
282     toclose = obj->next_input;
283
284   /* Run the program.  */
285
286   pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
287                                 toclose, &errmsg, err);
288   if (pid < 0)
289     goto error_exit;
290
291   ++obj->count;
292   obj->children = XRESIZEVEC (long, obj->children, obj->count);
293   obj->children[obj->count - 1] = pid;
294
295   return NULL;
296
297  error_exit:
298   if (in >= 0 && in != STDIN_FILE_NO)
299     obj->funcs->close (obj, in);
300   if (out >= 0 && out != STDOUT_FILE_NO)
301     obj->funcs->close (obj, out);
302   if (errdes >= 0 && errdes != STDERR_FILE_NO)
303     obj->funcs->close (obj, errdes);
304   if (outname_allocated)
305     free (outname);
306   return errmsg;
307 }
308
309 /* Return a FILE pointer for the output of the last program
310    executed.  */
311
312 FILE *
313 pex_read_output (struct pex_obj *obj, int binary)
314 {
315   if (obj->next_input_name != NULL)
316     {
317       const char *errmsg;
318       int err;
319
320       /* We have to make sure that the process has completed before we
321          try to read the file.  */
322       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
323         {
324           errno = err;
325           return NULL;
326         }
327
328       obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
329
330       if (obj->next_input_name_allocated)
331         {
332           free (obj->next_input_name);
333           obj->next_input_name_allocated = 0;
334         }
335       obj->next_input_name = NULL;
336     }
337   else
338     {
339       int o;
340
341       o = obj->next_input;
342       if (o < 0 || o == STDIN_FILE_NO)
343         return NULL;
344       obj->read_output = obj->funcs->fdopenr (obj, o, binary);
345       obj->next_input = -1;
346     }
347
348   return obj->read_output;
349 }
350
351 /* Get the exit status and, if requested, the resource time for all
352    the child processes.  Return 0 on failure, 1 on success.  */
353
354 static int
355 pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
356                          int *err)
357 {
358   int ret;
359   int i;
360
361   if (obj->number_waited == obj->count)
362     return 1;
363
364   obj->status = XRESIZEVEC (int, obj->status, obj->count);
365   if ((obj->flags & PEX_RECORD_TIMES) != 0)
366     obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
367
368   ret = 1;
369   for (i = obj->number_waited; i < obj->count; ++i)
370     {
371       if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
372                             obj->time == NULL ? NULL : &obj->time[i],
373                             done, errmsg, err) < 0)
374         ret = 0;
375     }
376   obj->number_waited = i;
377
378   return ret;
379 }
380
381 /* Get exit status of executed programs.  */
382
383 int
384 pex_get_status (struct pex_obj *obj, int count, int *vector)
385 {
386   if (obj->status == NULL)
387     {
388       const char *errmsg;
389       int err;
390
391       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
392         return 0;
393     }
394
395   if (count > obj->count)
396     {
397       memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
398       count = obj->count;
399     }
400
401   memcpy (vector, obj->status, count * sizeof (int));
402
403   return 1;
404 }
405
406 /* Get process times of executed programs.  */
407
408 int
409 pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
410 {
411   if (obj->status == NULL)
412     {
413       const char *errmsg;
414       int err;
415
416       if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
417         return 0;
418     }
419
420   if (obj->time == NULL)
421     return 0;
422
423   if (count > obj->count)
424     {
425       memset (vector + obj->count, 0,
426               (count - obj->count) * sizeof (struct pex_time));
427       count = obj->count;
428     }
429
430   memcpy (vector, obj->time, count * sizeof (struct pex_time));
431
432   return 1;
433 }
434
435 /* Free a pex_obj structure.  */
436
437 void
438 pex_free (struct pex_obj *obj)
439 {
440   if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
441     obj->funcs->close (obj, obj->next_input);
442
443   /* If the caller forgot to wait for the children, we do it here, to
444      avoid zombies.  */
445   if (obj->status == NULL)
446     {
447       const char *errmsg;
448       int err;
449
450       obj->flags &= ~ PEX_RECORD_TIMES;
451       pex_get_status_and_time (obj, 1, &errmsg, &err);
452     }
453
454   if (obj->next_input_name_allocated)
455     free (obj->next_input_name);
456   if (obj->children != NULL)
457     free (obj->children);
458   if (obj->status != NULL)
459     free (obj->status);
460   if (obj->time != NULL)
461     free (obj->time);
462   if (obj->read_output != NULL)
463     fclose (obj->read_output);
464
465   if (obj->remove_count > 0)
466     {
467       int i;
468
469       for (i = 0; i < obj->remove_count; ++i)
470         {
471           remove (obj->remove[i]);
472           free (obj->remove[i]);
473         }
474       free (obj->remove);
475     }
476
477   if (obj->funcs->cleanup != NULL)
478     obj->funcs->cleanup (obj);
479
480   free (obj);
481 }