1 1.1 christos /* Common code for executing a program in a sub-process. 2 1.10 christos Copyright (C) 2005-2024 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.3 christos (flags & PEX_BINARY_OUTPUT) != 0, 271 1.3 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.3 christos errdes = obj->funcs->open_write (obj, errname, 324 1.3 christos (flags & PEX_BINARY_ERROR) != 0, 325 1.3 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