pex-common.c revision 1.1.1.4 1 1.1 christos /* Common code for executing a program in a sub-process.
2 1.1.1.4 christos Copyright (C) 2005-2020 Free Software Foundation, Inc.
3 1.1 christos Written by Ian Lance Taylor <ian (at) airs.com>.
4 1.1 christos
5 1.1 christos This file is part of the libiberty library.
6 1.1 christos Libiberty is free software; you can redistribute it and/or
7 1.1 christos modify it under the terms of the GNU Library General Public
8 1.1 christos License as published by the Free Software Foundation; either
9 1.1 christos version 2 of the License, or (at your option) any later version.
10 1.1 christos
11 1.1 christos Libiberty is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 1.1 christos Library General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU Library General Public
17 1.1 christos License along with libiberty; see the file COPYING.LIB. If not,
18 1.1 christos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 1.1 christos Boston, MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "config.h"
22 1.1 christos #include "libiberty.h"
23 1.1 christos #include "pex-common.h"
24 1.1 christos
25 1.1 christos #include <stdio.h>
26 1.1 christos #include <errno.h>
27 1.1 christos #ifdef NEED_DECLARATION_ERRNO
28 1.1 christos extern int errno;
29 1.1 christos #endif
30 1.1 christos #ifdef HAVE_STDLIB_H
31 1.1 christos #include <stdlib.h>
32 1.1 christos #endif
33 1.1 christos #ifdef HAVE_STRING_H
34 1.1 christos #include <string.h>
35 1.1 christos #endif
36 1.1 christos #ifdef HAVE_UNISTD_H
37 1.1 christos #include <unistd.h>
38 1.1 christos #endif
39 1.1 christos
40 1.1 christos extern int mkstemps (char *, int);
41 1.1 christos
42 1.1 christos /* This file contains subroutines for the program execution routines
43 1.1 christos (pex_init, pex_run, etc.). This file is compiled on all
44 1.1 christos systems. */
45 1.1 christos
46 1.1 christos static void pex_add_remove (struct pex_obj *, const char *, int);
47 1.1 christos static int pex_get_status_and_time (struct pex_obj *, int, const char **,
48 1.1 christos int *);
49 1.1 christos
50 1.1 christos /* Initialize a pex_obj structure. */
51 1.1 christos
52 1.1 christos struct pex_obj *
53 1.1 christos pex_init_common (int flags, const char *pname, const char *tempbase,
54 1.1 christos const struct pex_funcs *funcs)
55 1.1 christos {
56 1.1 christos struct pex_obj *obj;
57 1.1 christos
58 1.1 christos obj = XNEW (struct pex_obj);
59 1.1 christos obj->flags = flags;
60 1.1 christos obj->pname = pname;
61 1.1 christos obj->tempbase = tempbase;
62 1.1 christos obj->next_input = STDIN_FILE_NO;
63 1.1 christos obj->next_input_name = NULL;
64 1.1 christos obj->next_input_name_allocated = 0;
65 1.1 christos obj->stderr_pipe = -1;
66 1.1 christos obj->count = 0;
67 1.1 christos obj->children = NULL;
68 1.1 christos obj->status = NULL;
69 1.1 christos obj->time = NULL;
70 1.1 christos obj->number_waited = 0;
71 1.1 christos obj->input_file = NULL;
72 1.1 christos obj->read_output = NULL;
73 1.1 christos obj->read_err = NULL;
74 1.1 christos obj->remove_count = 0;
75 1.1 christos obj->remove = NULL;
76 1.1 christos obj->funcs = funcs;
77 1.1 christos obj->sysdep = NULL;
78 1.1 christos return obj;
79 1.1 christos }
80 1.1 christos
81 1.1 christos /* Add a file to be removed when we are done. */
82 1.1 christos
83 1.1 christos static void
84 1.1 christos pex_add_remove (struct pex_obj *obj, const char *name, int allocated)
85 1.1 christos {
86 1.1 christos char *add;
87 1.1 christos
88 1.1 christos ++obj->remove_count;
89 1.1 christos obj->remove = XRESIZEVEC (char *, obj->remove, obj->remove_count);
90 1.1 christos if (allocated)
91 1.1 christos add = (char *) name;
92 1.1 christos else
93 1.1 christos add = xstrdup (name);
94 1.1 christos obj->remove[obj->remove_count - 1] = add;
95 1.1 christos }
96 1.1 christos
97 1.1 christos /* Generate a temporary file name based on OBJ, FLAGS, and NAME.
98 1.1 christos Return NULL if we were unable to reserve a temporary filename.
99 1.1 christos
100 1.1 christos If non-NULL, the result is either allocated with malloc, or the
101 1.1 christos same pointer as NAME. */
102 1.1 christos static char *
103 1.1 christos temp_file (struct pex_obj *obj, int flags, char *name)
104 1.1 christos {
105 1.1 christos if (name == NULL)
106 1.1 christos {
107 1.1 christos if (obj->tempbase == NULL)
108 1.1 christos {
109 1.1 christos name = make_temp_file (NULL);
110 1.1 christos }
111 1.1 christos else
112 1.1 christos {
113 1.1 christos int len = strlen (obj->tempbase);
114 1.1 christos int out;
115 1.1 christos
116 1.1 christos if (len >= 6
117 1.1 christos && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
118 1.1 christos name = xstrdup (obj->tempbase);
119 1.1 christos else
120 1.1 christos name = concat (obj->tempbase, "XXXXXX", NULL);
121 1.1 christos
122 1.1 christos out = mkstemps (name, 0);
123 1.1 christos if (out < 0)
124 1.1 christos {
125 1.1 christos free (name);
126 1.1 christos return NULL;
127 1.1 christos }
128 1.1 christos
129 1.1 christos /* This isn't obj->funcs->close because we got the
130 1.1 christos descriptor from mkstemps, not from a function in
131 1.1 christos obj->funcs. Calling close here is just like what
132 1.1 christos make_temp_file does. */
133 1.1 christos close (out);
134 1.1 christos }
135 1.1 christos }
136 1.1 christos else if ((flags & PEX_SUFFIX) != 0)
137 1.1 christos {
138 1.1 christos if (obj->tempbase == NULL)
139 1.1 christos name = make_temp_file (name);
140 1.1 christos else
141 1.1 christos name = concat (obj->tempbase, name, NULL);
142 1.1 christos }
143 1.1 christos
144 1.1 christos return name;
145 1.1 christos }
146 1.1 christos
147 1.1 christos
148 1.1 christos /* As for pex_run (), but permits the environment for the child process
149 1.1 christos to be specified. */
150 1.1 christos
151 1.1 christos const char *
152 1.1 christos pex_run_in_environment (struct pex_obj *obj, int flags, const char *executable,
153 1.1 christos char * const * argv, char * const * env,
154 1.1 christos const char *orig_outname, const char *errname,
155 1.1 christos int *err)
156 1.1 christos {
157 1.1 christos const char *errmsg;
158 1.1 christos int in, out, errdes;
159 1.1 christos char *outname;
160 1.1 christos int outname_allocated;
161 1.1 christos int p[2];
162 1.1 christos int toclose;
163 1.1 christos pid_t pid;
164 1.1 christos
165 1.1 christos in = -1;
166 1.1 christos out = -1;
167 1.1 christos errdes = -1;
168 1.1 christos outname = (char *) orig_outname;
169 1.1 christos outname_allocated = 0;
170 1.1 christos
171 1.1 christos /* If the user called pex_input_file, close the file now. */
172 1.1 christos if (obj->input_file)
173 1.1 christos {
174 1.1 christos if (fclose (obj->input_file) == EOF)
175 1.1 christos {
176 1.1 christos errmsg = "closing pipeline input file";
177 1.1 christos goto error_exit;
178 1.1 christos }
179 1.1 christos obj->input_file = NULL;
180 1.1 christos }
181 1.1 christos
182 1.1 christos /* Set IN. */
183 1.1 christos
184 1.1 christos if (obj->next_input_name != NULL)
185 1.1 christos {
186 1.1 christos /* We have to make sure that the previous process has completed
187 1.1 christos before we try to read the file. */
188 1.1 christos if (!pex_get_status_and_time (obj, 0, &errmsg, err))
189 1.1 christos goto error_exit;
190 1.1 christos
191 1.1 christos in = obj->funcs->open_read (obj, obj->next_input_name,
192 1.1 christos (flags & PEX_BINARY_INPUT) != 0);
193 1.1 christos if (in < 0)
194 1.1 christos {
195 1.1 christos *err = errno;
196 1.1 christos errmsg = "open temporary file";
197 1.1 christos goto error_exit;
198 1.1 christos }
199 1.1 christos if (obj->next_input_name_allocated)
200 1.1 christos {
201 1.1 christos free (obj->next_input_name);
202 1.1 christos obj->next_input_name_allocated = 0;
203 1.1 christos }
204 1.1 christos obj->next_input_name = NULL;
205 1.1 christos }
206 1.1 christos else
207 1.1 christos {
208 1.1 christos in = obj->next_input;
209 1.1 christos if (in < 0)
210 1.1 christos {
211 1.1 christos *err = 0;
212 1.1 christos errmsg = "pipeline already complete";
213 1.1 christos goto error_exit;
214 1.1 christos }
215 1.1 christos }
216 1.1 christos
217 1.1 christos /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME. */
218 1.1 christos
219 1.1 christos if ((flags & PEX_LAST) != 0)
220 1.1 christos {
221 1.1 christos if (outname == NULL)
222 1.1 christos out = STDOUT_FILE_NO;
223 1.1 christos else if ((flags & PEX_SUFFIX) != 0)
224 1.1 christos {
225 1.1 christos outname = concat (obj->tempbase, outname, NULL);
226 1.1 christos outname_allocated = 1;
227 1.1 christos }
228 1.1 christos obj->next_input = -1;
229 1.1 christos }
230 1.1 christos else if ((obj->flags & PEX_USE_PIPES) == 0)
231 1.1 christos {
232 1.1 christos outname = temp_file (obj, flags, outname);
233 1.1 christos if (! outname)
234 1.1 christos {
235 1.1 christos *err = 0;
236 1.1 christos errmsg = "could not create temporary file";
237 1.1 christos goto error_exit;
238 1.1 christos }
239 1.1 christos
240 1.1 christos if (outname != orig_outname)
241 1.1 christos outname_allocated = 1;
242 1.1 christos
243 1.1 christos if ((obj->flags & PEX_SAVE_TEMPS) == 0)
244 1.1 christos {
245 1.1 christos pex_add_remove (obj, outname, outname_allocated);
246 1.1 christos outname_allocated = 0;
247 1.1 christos }
248 1.1 christos
249 1.1 christos /* Hand off ownership of outname to the next stage. */
250 1.1 christos obj->next_input_name = outname;
251 1.1 christos obj->next_input_name_allocated = outname_allocated;
252 1.1 christos outname_allocated = 0;
253 1.1 christos }
254 1.1 christos else
255 1.1 christos {
256 1.1 christos if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
257 1.1 christos {
258 1.1 christos *err = errno;
259 1.1 christos errmsg = "pipe";
260 1.1 christos goto error_exit;
261 1.1 christos }
262 1.1 christos
263 1.1 christos out = p[WRITE_PORT];
264 1.1 christos obj->next_input = p[READ_PORT];
265 1.1 christos }
266 1.1 christos
267 1.1 christos if (out < 0)
268 1.1 christos {
269 1.1 christos out = obj->funcs->open_write (obj, outname,
270 1.1.1.2 christos (flags & PEX_BINARY_OUTPUT) != 0,
271 1.1.1.2 christos (flags & PEX_STDOUT_APPEND) != 0);
272 1.1 christos if (out < 0)
273 1.1 christos {
274 1.1 christos *err = errno;
275 1.1 christos errmsg = "open temporary output file";
276 1.1 christos goto error_exit;
277 1.1 christos }
278 1.1 christos }
279 1.1 christos
280 1.1 christos if (outname_allocated)
281 1.1 christos {
282 1.1 christos free (outname);
283 1.1 christos outname_allocated = 0;
284 1.1 christos }
285 1.1 christos
286 1.1 christos /* Set ERRDES. */
287 1.1 christos
288 1.1 christos if (errname != NULL && (flags & PEX_STDERR_TO_PIPE) != 0)
289 1.1 christos {
290 1.1 christos *err = 0;
291 1.1 christos errmsg = "both ERRNAME and PEX_STDERR_TO_PIPE specified.";
292 1.1 christos goto error_exit;
293 1.1 christos }
294 1.1 christos
295 1.1 christos if (obj->stderr_pipe != -1)
296 1.1 christos {
297 1.1 christos *err = 0;
298 1.1 christos errmsg = "PEX_STDERR_TO_PIPE used in the middle of pipeline";
299 1.1 christos goto error_exit;
300 1.1 christos }
301 1.1 christos
302 1.1 christos if (errname == NULL)
303 1.1 christos {
304 1.1 christos if (flags & PEX_STDERR_TO_PIPE)
305 1.1 christos {
306 1.1 christos if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_ERROR) != 0) < 0)
307 1.1 christos {
308 1.1 christos *err = errno;
309 1.1 christos errmsg = "pipe";
310 1.1 christos goto error_exit;
311 1.1 christos }
312 1.1 christos
313 1.1 christos errdes = p[WRITE_PORT];
314 1.1 christos obj->stderr_pipe = p[READ_PORT];
315 1.1 christos }
316 1.1 christos else
317 1.1 christos {
318 1.1 christos errdes = STDERR_FILE_NO;
319 1.1 christos }
320 1.1 christos }
321 1.1 christos else
322 1.1 christos {
323 1.1.1.2 christos errdes = obj->funcs->open_write (obj, errname,
324 1.1.1.2 christos (flags & PEX_BINARY_ERROR) != 0,
325 1.1.1.2 christos (flags & PEX_STDERR_APPEND) != 0);
326 1.1 christos if (errdes < 0)
327 1.1 christos {
328 1.1 christos *err = errno;
329 1.1 christos errmsg = "open error file";
330 1.1 christos goto error_exit;
331 1.1 christos }
332 1.1 christos }
333 1.1 christos
334 1.1 christos /* If we are using pipes, the child process has to close the next
335 1.1 christos input pipe. */
336 1.1 christos
337 1.1 christos if ((obj->flags & PEX_USE_PIPES) == 0)
338 1.1 christos toclose = -1;
339 1.1 christos else
340 1.1 christos toclose = obj->next_input;
341 1.1 christos
342 1.1 christos /* Run the program. */
343 1.1 christos
344 1.1 christos pid = obj->funcs->exec_child (obj, flags, executable, argv, env,
345 1.1 christos in, out, errdes, toclose, &errmsg, err);
346 1.1 christos if (pid < 0)
347 1.1 christos goto error_exit;
348 1.1 christos
349 1.1 christos ++obj->count;
350 1.1 christos obj->children = XRESIZEVEC (pid_t, obj->children, obj->count);
351 1.1 christos obj->children[obj->count - 1] = pid;
352 1.1 christos
353 1.1 christos return NULL;
354 1.1 christos
355 1.1 christos error_exit:
356 1.1 christos if (in >= 0 && in != STDIN_FILE_NO)
357 1.1 christos obj->funcs->close (obj, in);
358 1.1 christos if (out >= 0 && out != STDOUT_FILE_NO)
359 1.1 christos obj->funcs->close (obj, out);
360 1.1 christos if (errdes >= 0 && errdes != STDERR_FILE_NO)
361 1.1 christos obj->funcs->close (obj, errdes);
362 1.1 christos if (outname_allocated)
363 1.1 christos free (outname);
364 1.1 christos return errmsg;
365 1.1 christos }
366 1.1 christos
367 1.1 christos /* Run a program. */
368 1.1 christos
369 1.1 christos const char *
370 1.1 christos pex_run (struct pex_obj *obj, int flags, const char *executable,
371 1.1 christos char * const * argv, const char *orig_outname, const char *errname,
372 1.1 christos int *err)
373 1.1 christos {
374 1.1 christos return pex_run_in_environment (obj, flags, executable, argv, NULL,
375 1.1 christos orig_outname, errname, err);
376 1.1 christos }
377 1.1 christos
378 1.1 christos /* Return a FILE pointer for a temporary file to fill with input for
379 1.1 christos the pipeline. */
380 1.1 christos FILE *
381 1.1 christos pex_input_file (struct pex_obj *obj, int flags, const char *in_name)
382 1.1 christos {
383 1.1 christos char *name = (char *) in_name;
384 1.1 christos FILE *f;
385 1.1 christos
386 1.1 christos /* This must be called before the first pipeline stage is run, and
387 1.1 christos there must not have been any other input selected. */
388 1.1 christos if (obj->count != 0
389 1.1 christos || (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
390 1.1 christos || obj->next_input_name)
391 1.1 christos {
392 1.1 christos errno = EINVAL;
393 1.1 christos return NULL;
394 1.1 christos }
395 1.1 christos
396 1.1 christos name = temp_file (obj, flags, name);
397 1.1 christos if (! name)
398 1.1 christos return NULL;
399 1.1 christos
400 1.1 christos f = fopen (name, (flags & PEX_BINARY_OUTPUT) ? "wb" : "w");
401 1.1 christos if (! f)
402 1.1 christos {
403 1.1 christos free (name);
404 1.1 christos return NULL;
405 1.1 christos }
406 1.1 christos
407 1.1 christos obj->input_file = f;
408 1.1 christos obj->next_input_name = name;
409 1.1 christos obj->next_input_name_allocated = (name != in_name);
410 1.1 christos
411 1.1 christos return f;
412 1.1 christos }
413 1.1 christos
414 1.1 christos /* Return a stream for a pipe connected to the standard input of the
415 1.1 christos first stage of the pipeline. */
416 1.1 christos FILE *
417 1.1 christos pex_input_pipe (struct pex_obj *obj, int binary)
418 1.1 christos {
419 1.1 christos int p[2];
420 1.1 christos FILE *f;
421 1.1 christos
422 1.1 christos /* You must call pex_input_pipe before the first pex_run or pex_one. */
423 1.1 christos if (obj->count > 0)
424 1.1 christos goto usage_error;
425 1.1 christos
426 1.1 christos /* You must be using pipes. Implementations that don't support
427 1.1 christos pipes clear this flag before calling pex_init_common. */
428 1.1 christos if (! (obj->flags & PEX_USE_PIPES))
429 1.1 christos goto usage_error;
430 1.1 christos
431 1.1 christos /* If we have somehow already selected other input, that's a
432 1.1 christos mistake. */
433 1.1 christos if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
434 1.1 christos || obj->next_input_name)
435 1.1 christos goto usage_error;
436 1.1 christos
437 1.1 christos if (obj->funcs->pipe (obj, p, binary != 0) < 0)
438 1.1 christos return NULL;
439 1.1 christos
440 1.1 christos f = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
441 1.1 christos if (! f)
442 1.1 christos {
443 1.1 christos int saved_errno = errno;
444 1.1 christos obj->funcs->close (obj, p[READ_PORT]);
445 1.1 christos obj->funcs->close (obj, p[WRITE_PORT]);
446 1.1 christos errno = saved_errno;
447 1.1 christos return NULL;
448 1.1 christos }
449 1.1 christos
450 1.1 christos obj->next_input = p[READ_PORT];
451 1.1 christos
452 1.1 christos return f;
453 1.1 christos
454 1.1 christos usage_error:
455 1.1 christos errno = EINVAL;
456 1.1 christos return NULL;
457 1.1 christos }
458 1.1 christos
459 1.1 christos /* Return a FILE pointer for the output of the last program
460 1.1 christos executed. */
461 1.1 christos
462 1.1 christos FILE *
463 1.1 christos pex_read_output (struct pex_obj *obj, int binary)
464 1.1 christos {
465 1.1 christos if (obj->next_input_name != NULL)
466 1.1 christos {
467 1.1 christos const char *errmsg;
468 1.1 christos int err;
469 1.1 christos
470 1.1 christos /* We have to make sure that the process has completed before we
471 1.1 christos try to read the file. */
472 1.1 christos if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
473 1.1 christos {
474 1.1 christos errno = err;
475 1.1 christos return NULL;
476 1.1 christos }
477 1.1 christos
478 1.1 christos obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
479 1.1 christos
480 1.1 christos if (obj->next_input_name_allocated)
481 1.1 christos {
482 1.1 christos free (obj->next_input_name);
483 1.1 christos obj->next_input_name_allocated = 0;
484 1.1 christos }
485 1.1 christos obj->next_input_name = NULL;
486 1.1 christos }
487 1.1 christos else
488 1.1 christos {
489 1.1 christos int o;
490 1.1 christos
491 1.1 christos o = obj->next_input;
492 1.1 christos if (o < 0 || o == STDIN_FILE_NO)
493 1.1 christos return NULL;
494 1.1 christos obj->read_output = obj->funcs->fdopenr (obj, o, binary);
495 1.1 christos obj->next_input = -1;
496 1.1 christos }
497 1.1 christos
498 1.1 christos return obj->read_output;
499 1.1 christos }
500 1.1 christos
501 1.1 christos FILE *
502 1.1 christos pex_read_err (struct pex_obj *obj, int binary)
503 1.1 christos {
504 1.1 christos int o;
505 1.1 christos
506 1.1 christos o = obj->stderr_pipe;
507 1.1 christos if (o < 0 || o == STDIN_FILE_NO)
508 1.1 christos return NULL;
509 1.1 christos obj->read_err = obj->funcs->fdopenr (obj, o, binary);
510 1.1 christos obj->stderr_pipe = -1;
511 1.1 christos return obj->read_err;
512 1.1 christos }
513 1.1 christos
514 1.1 christos /* Get the exit status and, if requested, the resource time for all
515 1.1 christos the child processes. Return 0 on failure, 1 on success. */
516 1.1 christos
517 1.1 christos static int
518 1.1 christos pex_get_status_and_time (struct pex_obj *obj, int done, const char **errmsg,
519 1.1 christos int *err)
520 1.1 christos {
521 1.1 christos int ret;
522 1.1 christos int i;
523 1.1 christos
524 1.1 christos if (obj->number_waited == obj->count)
525 1.1 christos return 1;
526 1.1 christos
527 1.1 christos obj->status = XRESIZEVEC (int, obj->status, obj->count);
528 1.1 christos if ((obj->flags & PEX_RECORD_TIMES) != 0)
529 1.1 christos obj->time = XRESIZEVEC (struct pex_time, obj->time, obj->count);
530 1.1 christos
531 1.1 christos ret = 1;
532 1.1 christos for (i = obj->number_waited; i < obj->count; ++i)
533 1.1 christos {
534 1.1 christos if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
535 1.1 christos obj->time == NULL ? NULL : &obj->time[i],
536 1.1 christos done, errmsg, err) < 0)
537 1.1 christos ret = 0;
538 1.1 christos }
539 1.1 christos obj->number_waited = i;
540 1.1 christos
541 1.1 christos return ret;
542 1.1 christos }
543 1.1 christos
544 1.1 christos /* Get exit status of executed programs. */
545 1.1 christos
546 1.1 christos int
547 1.1 christos pex_get_status (struct pex_obj *obj, int count, int *vector)
548 1.1 christos {
549 1.1 christos if (obj->status == NULL)
550 1.1 christos {
551 1.1 christos const char *errmsg;
552 1.1 christos int err;
553 1.1 christos
554 1.1 christos if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
555 1.1 christos return 0;
556 1.1 christos }
557 1.1 christos
558 1.1 christos if (count > obj->count)
559 1.1 christos {
560 1.1 christos memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
561 1.1 christos count = obj->count;
562 1.1 christos }
563 1.1 christos
564 1.1 christos memcpy (vector, obj->status, count * sizeof (int));
565 1.1 christos
566 1.1 christos return 1;
567 1.1 christos }
568 1.1 christos
569 1.1 christos /* Get process times of executed programs. */
570 1.1 christos
571 1.1 christos int
572 1.1 christos pex_get_times (struct pex_obj *obj, int count, struct pex_time *vector)
573 1.1 christos {
574 1.1 christos if (obj->status == NULL)
575 1.1 christos {
576 1.1 christos const char *errmsg;
577 1.1 christos int err;
578 1.1 christos
579 1.1 christos if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
580 1.1 christos return 0;
581 1.1 christos }
582 1.1 christos
583 1.1 christos if (obj->time == NULL)
584 1.1 christos return 0;
585 1.1 christos
586 1.1 christos if (count > obj->count)
587 1.1 christos {
588 1.1 christos memset (vector + obj->count, 0,
589 1.1 christos (count - obj->count) * sizeof (struct pex_time));
590 1.1 christos count = obj->count;
591 1.1 christos }
592 1.1 christos
593 1.1 christos memcpy (vector, obj->time, count * sizeof (struct pex_time));
594 1.1 christos
595 1.1 christos return 1;
596 1.1 christos }
597 1.1 christos
598 1.1 christos /* Free a pex_obj structure. */
599 1.1 christos
600 1.1 christos void
601 1.1 christos pex_free (struct pex_obj *obj)
602 1.1 christos {
603 1.1 christos /* Close pipe file descriptors corresponding to child's stdout and
604 1.1 christos stderr so that the child does not hang trying to output something
605 1.1 christos while we're waiting for it. */
606 1.1 christos if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
607 1.1 christos obj->funcs->close (obj, obj->next_input);
608 1.1 christos if (obj->stderr_pipe >= 0 && obj->stderr_pipe != STDIN_FILE_NO)
609 1.1 christos obj->funcs->close (obj, obj->stderr_pipe);
610 1.1 christos if (obj->read_output != NULL)
611 1.1 christos fclose (obj->read_output);
612 1.1 christos if (obj->read_err != NULL)
613 1.1 christos fclose (obj->read_err);
614 1.1 christos
615 1.1 christos /* If the caller forgot to wait for the children, we do it here, to
616 1.1 christos avoid zombies. */
617 1.1 christos if (obj->status == NULL)
618 1.1 christos {
619 1.1 christos const char *errmsg;
620 1.1 christos int err;
621 1.1 christos
622 1.1 christos obj->flags &= ~ PEX_RECORD_TIMES;
623 1.1 christos pex_get_status_and_time (obj, 1, &errmsg, &err);
624 1.1 christos }
625 1.1 christos
626 1.1 christos if (obj->next_input_name_allocated)
627 1.1 christos free (obj->next_input_name);
628 1.1 christos free (obj->children);
629 1.1 christos free (obj->status);
630 1.1 christos free (obj->time);
631 1.1 christos
632 1.1 christos if (obj->remove_count > 0)
633 1.1 christos {
634 1.1 christos int i;
635 1.1 christos
636 1.1 christos for (i = 0; i < obj->remove_count; ++i)
637 1.1 christos {
638 1.1 christos remove (obj->remove[i]);
639 1.1 christos free (obj->remove[i]);
640 1.1 christos }
641 1.1 christos free (obj->remove);
642 1.1 christos }
643 1.1 christos
644 1.1 christos if (obj->funcs->cleanup != NULL)
645 1.1 christos obj->funcs->cleanup (obj);
646 1.1 christos
647 1.1 christos free (obj);
648 1.1 christos }
649