]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/pex-unix.c
Bump BASE-VER.
[thirdparty/gcc.git] / libiberty / pex-unix.c
CommitLineData
55d0e5e0
ZW
1/* Utilities to execute a program in a subprocess (possibly linked by pipes
2 with other subprocesses), and wait for it. Generic Unix version
3 (also used for UWIN and VMS).
a945c346 4 Copyright (C) 1996-2024 Free Software Foundation, Inc.
55d0e5e0
ZW
5
6This file is part of the libiberty library.
7Libiberty is free software; you can redistribute it and/or
8modify it under the terms of the GNU Library General Public
9License as published by the Free Software Foundation; either
10version 2 of the License, or (at your option) any later version.
11
12Libiberty is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15Library General Public License for more details.
16
17You should have received a copy of the GNU Library General Public
18License along with libiberty; see the file COPYING.LIB. If not,
ee58dffd
NC
19write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20Boston, MA 02110-1301, USA. */
55d0e5e0 21
a584cf65
ILT
22#include "config.h"
23#include "libiberty.h"
55d0e5e0 24#include "pex-common.h"
efd40fc4 25#include "environ.h"
55d0e5e0
ZW
26
27#include <stdio.h>
a584cf65 28#include <signal.h>
55d0e5e0
ZW
29#include <errno.h>
30#ifdef NEED_DECLARATION_ERRNO
31extern int errno;
32#endif
a584cf65
ILT
33#ifdef HAVE_STDLIB_H
34#include <stdlib.h>
35#endif
55d0e5e0
ZW
36#ifdef HAVE_STRING_H
37#include <string.h>
38#endif
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
a584cf65
ILT
42
43#include <sys/types.h>
44
45#ifdef HAVE_FCNTL_H
46#include <fcntl.h>
55d0e5e0
ZW
47#endif
48#ifdef HAVE_SYS_WAIT_H
49#include <sys/wait.h>
50#endif
a584cf65
ILT
51#ifdef HAVE_GETRUSAGE
52#include <sys/time.h>
53#include <sys/resource.h>
54#endif
55#ifdef HAVE_SYS_STAT_H
56#include <sys/stat.h>
55d0e5e0 57#endif
3b63ca7e
RH
58#ifdef HAVE_PROCESS_H
59#include <process.h>
60#endif
879cf9ff
BS
61#ifdef HAVE_SPAWN_H
62#include <spawn.h>
63#endif
a584cf65 64
fed8129b
ILT
65#ifdef vfork /* Autoconf may define this to fork for us. */
66# define VFORK_STRING "fork"
67#else
68# define VFORK_STRING "vfork"
69#endif
70#ifdef HAVE_VFORK_H
71#include <vfork.h>
72#endif
b303ef51
DR
73#if defined(VMS) && defined (__LONG_POINTERS)
74#ifndef __CHAR_PTR32
75typedef char * __char_ptr32
76__attribute__ ((mode (SI)));
77#endif
78
79typedef __char_ptr32 *__char_ptr_char_ptr32
80__attribute__ ((mode (SI)));
81
82/* Return a 32 bit pointer to an array of 32 bit pointers
83 given a 64 bit pointer to an array of 64 bit pointers. */
84
85static __char_ptr_char_ptr32
86to_ptr32 (char **ptr64)
87{
88 int argc;
89 __char_ptr_char_ptr32 short_argv;
90
c1a96977
TG
91 /* Count number of arguments. */
92 for (argc = 0; ptr64[argc] != NULL; argc++)
93 ;
fed8129b 94
b303ef51
DR
95 /* Reallocate argv with 32 bit pointers. */
96 short_argv = (__char_ptr_char_ptr32) decc$malloc
97 (sizeof (__char_ptr32) * (argc + 1));
98
c1a96977 99 for (argc = 0; ptr64[argc] != NULL; argc++)
b303ef51
DR
100 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
101
102 short_argv[argc] = (__char_ptr32) 0;
103 return short_argv;
104
105}
106#else
107#define to_ptr32(argv) argv
108#endif
55d0e5e0 109
a584cf65
ILT
110/* File mode to use for private and world-readable files. */
111
112#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
113#define PUBLIC_MODE \
114 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
115#else
116#define PUBLIC_MODE 0666
117#endif
118
119/* Get the exit status of a particular process, and optionally get the
120 time that it took. This is simple if we have wait4, slightly
121 harder if we have waitpid, and is a pain if we only have wait. */
122
123static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *);
124
125#ifdef HAVE_WAIT4
126
127static pid_t
128pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
129 struct pex_time *time)
130{
131 pid_t ret;
132 struct rusage r;
133
134#ifdef HAVE_WAITPID
135 if (time == NULL)
136 return waitpid (pid, status, 0);
137#endif
138
139 ret = wait4 (pid, status, 0, &r);
140
141 if (time != NULL)
142 {
143 time->user_seconds = r.ru_utime.tv_sec;
144 time->user_microseconds= r.ru_utime.tv_usec;
145 time->system_seconds = r.ru_stime.tv_sec;
146 time->system_microseconds= r.ru_stime.tv_usec;
147 }
148
149 return ret;
150}
151
152#else /* ! defined (HAVE_WAIT4) */
153
154#ifdef HAVE_WAITPID
155
156#ifndef HAVE_GETRUSAGE
157
158static pid_t
159pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
160 struct pex_time *time)
161{
162 if (time != NULL)
163 memset (time, 0, sizeof (struct pex_time));
164 return waitpid (pid, status, 0);
165}
166
167#else /* defined (HAVE_GETRUSAGE) */
168
169static pid_t
170pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status,
171 struct pex_time *time)
172{
173 struct rusage r1, r2;
174 pid_t ret;
175
176 if (time == NULL)
177 return waitpid (pid, status, 0);
178
179 getrusage (RUSAGE_CHILDREN, &r1);
180
181 ret = waitpid (pid, status, 0);
182 if (ret < 0)
183 return ret;
184
185 getrusage (RUSAGE_CHILDREN, &r2);
186
187 time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
188 time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
189 if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec)
190 {
191 --time->user_seconds;
192 time->user_microseconds += 1000000;
193 }
194
195 time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
196 time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
197 if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec)
198 {
199 --time->system_seconds;
200 time->system_microseconds += 1000000;
201 }
fed8129b 202
a584cf65
ILT
203 return ret;
204}
55d0e5e0 205
a584cf65 206#endif /* defined (HAVE_GETRUSAGE) */
55d0e5e0 207
a584cf65
ILT
208#else /* ! defined (HAVE_WAITPID) */
209
210struct status_list
211{
212 struct status_list *next;
213 pid_t pid;
214 int status;
215 struct pex_time time;
216};
217
218static pid_t
219pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time)
220{
221 struct status_list **pp;
222
223 for (pp = (struct status_list **) &obj->sysdep;
224 *pp != NULL;
225 pp = &(*pp)->next)
55d0e5e0 226 {
a584cf65 227 if ((*pp)->pid == pid)
55d0e5e0 228 {
a584cf65
ILT
229 struct status_list *p;
230
231 p = *pp;
232 *status = p->status;
233 if (time != NULL)
234 *time = p->time;
235 *pp = p->next;
236 free (p);
237 return pid;
55d0e5e0 238 }
55d0e5e0 239 }
a584cf65
ILT
240
241 while (1)
55d0e5e0 242 {
a584cf65
ILT
243 pid_t cpid;
244 struct status_list *psl;
245 struct pex_time pt;
246#ifdef HAVE_GETRUSAGE
247 struct rusage r1, r2;
248#endif
249
250 if (time != NULL)
251 {
252#ifdef HAVE_GETRUSAGE
253 getrusage (RUSAGE_CHILDREN, &r1);
254#else
255 memset (&pt, 0, sizeof (struct pex_time));
256#endif
257 }
258
259 cpid = wait (status);
260
261#ifdef HAVE_GETRUSAGE
262 if (time != NULL && cpid >= 0)
263 {
264 getrusage (RUSAGE_CHILDREN, &r2);
265
266 pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
267 pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
268 if (pt.user_microseconds < 0)
269 {
270 --pt.user_seconds;
271 pt.user_microseconds += 1000000;
272 }
273
274 pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
275 pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
276 if (pt.system_microseconds < 0)
277 {
278 --pt.system_seconds;
279 pt.system_microseconds += 1000000;
280 }
281 }
282#endif
283
284 if (cpid < 0 || cpid == pid)
285 {
286 if (time != NULL)
287 *time = pt;
288 return cpid;
289 }
290
d7cf8390 291 psl = XNEW (struct status_list);
a584cf65
ILT
292 psl->pid = cpid;
293 psl->status = *status;
294 if (time != NULL)
295 psl->time = pt;
296 psl->next = (struct status_list *) obj->sysdep;
297 obj->sysdep = (void *) psl;
55d0e5e0 298 }
a584cf65
ILT
299}
300
301#endif /* ! defined (HAVE_WAITPID) */
302#endif /* ! defined (HAVE_WAIT4) */
303
a584cf65 304static int pex_unix_open_read (struct pex_obj *, const char *, int);
29ce50b0 305static int pex_unix_open_write (struct pex_obj *, const char *, int, int);
1651030c 306static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *,
ea60341e 307 char * const *, char * const *,
5317e1c7
ILT
308 int, int, int, int,
309 const char **, int *);
a584cf65 310static int pex_unix_close (struct pex_obj *, int);
691858d2
RO
311static pid_t pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
312 int, const char **, int *);
a584cf65
ILT
313static int pex_unix_pipe (struct pex_obj *, int *, int);
314static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
8eff378c 315static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
a584cf65
ILT
316static void pex_unix_cleanup (struct pex_obj *);
317
318/* The list of functions we pass to the common routines. */
319
320const struct pex_funcs funcs =
321{
322 pex_unix_open_read,
323 pex_unix_open_write,
324 pex_unix_exec_child,
325 pex_unix_close,
326 pex_unix_wait,
327 pex_unix_pipe,
328 pex_unix_fdopenr,
8eff378c 329 pex_unix_fdopenw,
a584cf65
ILT
330 pex_unix_cleanup
331};
332
333/* Return a newly initialized pex_obj structure. */
334
335struct pex_obj *
336pex_init (int flags, const char *pname, const char *tempbase)
337{
338 return pex_init_common (flags, pname, tempbase, &funcs);
339}
340
341/* Open a file for reading. */
342
343static int
344pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
345 int binary ATTRIBUTE_UNUSED)
346{
347 return open (name, O_RDONLY);
348}
349
350/* Open a file for writing. */
351
352static int
353pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name,
29ce50b0 354 int binary ATTRIBUTE_UNUSED, int append)
a584cf65
ILT
355{
356 /* Note that we can't use O_EXCL here because gcc may have already
357 created the temporary file via make_temp_file. */
29ce50b0
MO
358 return open (name, O_WRONLY | O_CREAT
359 | (append ? O_APPEND : O_TRUNC), PUBLIC_MODE);
a584cf65 360}
55d0e5e0 361
a584cf65
ILT
362/* Close a file. */
363
364static int
365pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
366{
367 return close (fd);
368}
369
a584cf65
ILT
370/* Execute a child. */
371
3b63ca7e
RH
372#if defined(HAVE_SPAWNVE) && defined(HAVE_SPAWNVPE)
373/* Implementation of pex->exec_child using the Cygwin spawn operation. */
374
375/* Subroutine of pex_unix_exec_child. Move OLD_FD to a new file descriptor
376 to be stored in *PNEW_FD, save the flags in *PFLAGS, and arrange for the
377 saved copy to be close-on-exec. Move CHILD_FD into OLD_FD. If CHILD_FD
378 is -1, OLD_FD is to be closed. Return -1 on error. */
379
380static int
381save_and_install_fd(int *pnew_fd, int *pflags, int old_fd, int child_fd)
382{
383 int new_fd, flags;
384
385 flags = fcntl (old_fd, F_GETFD);
386
387 /* If we could not retrieve the flags, then OLD_FD was not open. */
388 if (flags < 0)
389 {
390 new_fd = -1, flags = 0;
391 if (child_fd >= 0 && dup2 (child_fd, old_fd) < 0)
392 return -1;
393 }
394 /* If we wish to close OLD_FD, just mark it CLOEXEC. */
395 else if (child_fd == -1)
396 {
397 new_fd = old_fd;
398 if ((flags & FD_CLOEXEC) == 0 && fcntl (old_fd, F_SETFD, FD_CLOEXEC) < 0)
399 return -1;
400 }
401 /* Otherwise we need to save a copy of OLD_FD before installing CHILD_FD. */
402 else
403 {
404#ifdef F_DUPFD_CLOEXEC
405 new_fd = fcntl (old_fd, F_DUPFD_CLOEXEC, 3);
406 if (new_fd < 0)
407 return -1;
408#else
409 /* Prefer F_DUPFD over dup in order to avoid getting a new fd
410 in the range 0-2, right where a new stderr fd might get put. */
411 new_fd = fcntl (old_fd, F_DUPFD, 3);
412 if (new_fd < 0)
413 return -1;
414 if (fcntl (new_fd, F_SETFD, FD_CLOEXEC) < 0)
415 return -1;
416#endif
417 if (dup2 (child_fd, old_fd) < 0)
418 return -1;
419 }
420
421 *pflags = flags;
422 if (pnew_fd)
423 *pnew_fd = new_fd;
424 else if (new_fd != old_fd)
425 abort ();
426
427 return 0;
428}
429
430/* Subroutine of pex_unix_exec_child. Move SAVE_FD back to OLD_FD
431 restoring FLAGS. If SAVE_FD < 0, OLD_FD is to be closed. */
432
433static int
434restore_fd(int old_fd, int save_fd, int flags)
435{
436 /* For SAVE_FD < 0, all we have to do is restore the
437 "closed-ness" of the original. */
438 if (save_fd < 0)
439 return close (old_fd);
440
441 /* For SAVE_FD == OLD_FD, all we have to do is restore the
442 original setting of the CLOEXEC flag. */
443 if (save_fd == old_fd)
444 {
445 if (flags & FD_CLOEXEC)
446 return 0;
447 return fcntl (old_fd, F_SETFD, flags);
448 }
449
450 /* Otherwise we have to move the descriptor back, restore the flags,
451 and close the saved copy. */
452#ifdef HAVE_DUP3
453 if (flags == FD_CLOEXEC)
454 {
455 if (dup3 (save_fd, old_fd, O_CLOEXEC) < 0)
456 return -1;
457 }
458 else
459#endif
460 {
461 if (dup2 (save_fd, old_fd) < 0)
462 return -1;
463 if (flags != 0 && fcntl (old_fd, F_SETFD, flags) < 0)
464 return -1;
465 }
466 return close (save_fd);
467}
468
469static pid_t
470pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
471 int flags, const char *executable,
472 char * const * argv, char * const * env,
473 int in, int out, int errdes, int toclose,
474 const char **errmsg, int *err)
475{
476 int fl_in = 0, fl_out = 0, fl_err = 0, fl_tc = 0;
477 int save_in = -1, save_out = -1, save_err = -1;
478 int max, retries;
479 pid_t pid;
480
481 if (flags & PEX_STDERR_TO_STDOUT)
482 errdes = out;
483
484 /* We need the three standard file descriptors to be set up as for
485 the child before we perform the spawn. The file descriptors for
486 the parent need to be moved and marked for close-on-exec. */
487 if (in != STDIN_FILE_NO
488 && save_and_install_fd (&save_in, &fl_in, STDIN_FILE_NO, in) < 0)
489 goto error_dup2;
490 if (out != STDOUT_FILE_NO
491 && save_and_install_fd (&save_out, &fl_out, STDOUT_FILE_NO, out) < 0)
492 goto error_dup2;
493 if (errdes != STDERR_FILE_NO
494 && save_and_install_fd (&save_err, &fl_err, STDERR_FILE_NO, errdes) < 0)
495 goto error_dup2;
496 if (toclose >= 0
497 && save_and_install_fd (NULL, &fl_tc, toclose, -1) < 0)
498 goto error_dup2;
499
500 /* Now that we've moved the file descriptors for the child into place,
501 close the originals. Be careful not to close any of the standard
502 file descriptors that we just set up. */
503 max = -1;
504 if (errdes >= 0)
505 max = STDERR_FILE_NO;
506 else if (out >= 0)
507 max = STDOUT_FILE_NO;
508 else if (in >= 0)
509 max = STDIN_FILE_NO;
510 if (in > max)
511 close (in);
512 if (out > max)
513 close (out);
514 if (errdes > max && errdes != out)
515 close (errdes);
516
517 /* If we were not given an environment, use the global environment. */
518 if (env == NULL)
519 env = environ;
520
521 /* Launch the program. If we get EAGAIN (normally out of pid's), try
522 again a few times with increasing backoff times. */
523 retries = 0;
524 while (1)
525 {
526 typedef const char * const *cc_cp;
527
528 if (flags & PEX_SEARCH)
529 pid = spawnvpe (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
530 else
531 pid = spawnve (_P_NOWAITO, executable, (cc_cp)argv, (cc_cp)env);
532
533 if (pid > 0)
534 break;
535
536 *err = errno;
537 *errmsg = "spawn";
538 if (errno != EAGAIN || ++retries == 4)
539 return (pid_t) -1;
540 sleep (1 << retries);
541 }
542
543 /* Success. Restore the parent's file descriptors that we saved above. */
544 if (toclose >= 0
545 && restore_fd (toclose, toclose, fl_tc) < 0)
546 goto error_dup2;
547 if (in != STDIN_FILE_NO
548 && restore_fd (STDIN_FILE_NO, save_in, fl_in) < 0)
549 goto error_dup2;
550 if (out != STDOUT_FILE_NO
551 && restore_fd (STDOUT_FILE_NO, save_out, fl_out) < 0)
552 goto error_dup2;
553 if (errdes != STDERR_FILE_NO
554 && restore_fd (STDERR_FILE_NO, save_err, fl_err) < 0)
555 goto error_dup2;
556
557 return pid;
558
559 error_dup2:
560 *err = errno;
561 *errmsg = "dup2";
562 return (pid_t) -1;
563}
564
879cf9ff
BS
565#elif defined(HAVE_POSIX_SPAWN) && defined(HAVE_POSIX_SPAWNP)
566/* Implementation of pex->exec_child using posix_spawn. */
567
568static pid_t
569pex_unix_exec_child (struct pex_obj *obj ATTRIBUTE_UNUSED,
570 int flags, const char *executable,
571 char * const * argv, char * const * env,
572 int in, int out, int errdes,
573 int toclose, const char **errmsg, int *err)
574{
575 int ret;
576 pid_t pid = -1;
577 posix_spawnattr_t attr;
578 posix_spawn_file_actions_t actions;
579 int attr_initialized = 0, actions_initialized = 0;
580
581 *err = 0;
582
583 ret = posix_spawnattr_init (&attr);
584 if (ret)
585 {
586 *err = ret;
587 *errmsg = "posix_spawnattr_init";
588 goto exit;
589 }
590 attr_initialized = 1;
591
592 /* Use vfork() on glibc <=2.24. */
593#ifdef POSIX_SPAWN_USEVFORK
594 ret = posix_spawnattr_setflags (&attr, POSIX_SPAWN_USEVFORK);
595 if (ret)
596 {
597 *err = ret;
598 *errmsg = "posix_spawnattr_setflags";
599 goto exit;
600 }
601#endif
602
603 ret = posix_spawn_file_actions_init (&actions);
604 if (ret)
605 {
606 *err = ret;
607 *errmsg = "posix_spawn_file_actions_init";
608 goto exit;
609 }
610 actions_initialized = 1;
611
612 if (in != STDIN_FILE_NO)
613 {
614 ret = posix_spawn_file_actions_adddup2 (&actions, in, STDIN_FILE_NO);
615 if (ret)
616 {
617 *err = ret;
618 *errmsg = "posix_spawn_file_actions_adddup2";
619 goto exit;
620 }
621
622 ret = posix_spawn_file_actions_addclose (&actions, in);
623 if (ret)
624 {
625 *err = ret;
626 *errmsg = "posix_spawn_file_actions_addclose";
627 goto exit;
628 }
629 }
630
631 if (out != STDOUT_FILE_NO)
632 {
633 ret = posix_spawn_file_actions_adddup2 (&actions, out, STDOUT_FILE_NO);
634 if (ret)
635 {
636 *err = ret;
637 *errmsg = "posix_spawn_file_actions_adddup2";
638 goto exit;
639 }
640
641 ret = posix_spawn_file_actions_addclose (&actions, out);
642 if (ret)
643 {
644 *err = ret;
645 *errmsg = "posix_spawn_file_actions_addclose";
646 goto exit;
647 }
648 }
649
650 if (errdes != STDERR_FILE_NO)
651 {
652 ret = posix_spawn_file_actions_adddup2 (&actions, errdes, STDERR_FILE_NO);
653 if (ret)
654 {
655 *err = ret;
656 *errmsg = "posix_spawn_file_actions_adddup2";
657 goto exit;
658 }
659
660 ret = posix_spawn_file_actions_addclose (&actions, errdes);
661 if (ret)
662 {
663 *err = ret;
664 *errmsg = "posix_spawn_file_actions_addclose";
665 goto exit;
666 }
667 }
668
669 if (toclose >= 0)
670 {
671 ret = posix_spawn_file_actions_addclose (&actions, toclose);
672 if (ret)
673 {
674 *err = ret;
675 *errmsg = "posix_spawn_file_actions_addclose";
676 goto exit;
677 }
678 }
679
680 if ((flags & PEX_STDERR_TO_STDOUT) != 0)
681 {
682 ret = posix_spawn_file_actions_adddup2 (&actions, STDOUT_FILE_NO, STDERR_FILE_NO);
683 if (ret)
684 {
685 *err = ret;
686 *errmsg = "posix_spawn_file_actions_adddup2";
687 goto exit;
688 }
689 }
690
691 if ((flags & PEX_SEARCH) != 0)
692 {
693 ret = posix_spawnp (&pid, executable, &actions, &attr, argv, env ? env : environ);
694 if (ret)
695 {
696 *err = ret;
697 *errmsg = "posix_spawnp";
20e57660 698 pid = -1; /* The value of pid is unspecified on failure. */
879cf9ff
BS
699 goto exit;
700 }
701 }
702 else
703 {
704 ret = posix_spawn (&pid, executable, &actions, &attr, argv, env ? env : environ);
705 if (ret)
706 {
707 *err = ret;
708 *errmsg = "posix_spawn";
20e57660 709 pid = -1;
879cf9ff
BS
710 goto exit;
711 }
712 }
713
714exit:
715 if (actions_initialized)
716 posix_spawn_file_actions_destroy (&actions);
717 if (attr_initialized)
718 posix_spawnattr_destroy (&attr);
719
720 if (!*err && in != STDIN_FILE_NO)
721 if (close (in))
722 *errmsg = "close", *err = errno, pid = -1;
723 if (!*err && out != STDOUT_FILE_NO)
724 if (close (out))
725 *errmsg = "close", *err = errno, pid = -1;
726 if (!*err && errdes != STDERR_FILE_NO)
727 if (close (errdes))
728 *errmsg = "close", *err = errno, pid = -1;
729
730 return pid;
731}
3b63ca7e
RH
732#else
733/* Implementation of pex->exec_child using standard vfork + exec. */
734
1651030c 735static pid_t
a584cf65 736pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
ea60341e
MS
737 char * const * argv, char * const * env,
738 int in, int out, int errdes,
5317e1c7 739 int toclose, const char **errmsg, int *err)
a584cf65 740{
5c12a855 741 pid_t pid = -1;
df1346b4
NS
742 /* Tuple to communicate error from child to parent. We can safely
743 transfer string literal pointers as both run with identical
744 address mappings. */
745 struct fn_err
746 {
747 const char *fn;
748 int err;
749 };
750 volatile int do_pipe = 0;
751 volatile int pipes[2]; /* [0]:reader,[1]:writer. */
752#ifdef O_CLOEXEC
753 do_pipe = 1;
754#endif
755 if (do_pipe)
756 {
757#ifdef HAVE_PIPE2
758 if (pipe2 ((int *)pipes, O_CLOEXEC))
759 do_pipe = 0;
760#else
761 if (pipe ((int *)pipes))
762 do_pipe = 0;
763 else
764 {
765 if (fcntl (pipes[1], F_SETFD, FD_CLOEXEC) == -1)
766 {
767 close (pipes[0]);
768 close (pipes[1]);
769 do_pipe = 0;
770 }
771 }
772#endif
773 }
ea60341e 774
a584cf65
ILT
775 /* We declare these to be volatile to avoid warnings from gcc about
776 them being clobbered by vfork. */
5c12a855 777 volatile int sleep_interval = 1;
a584cf65 778 volatile int retries;
fed8129b 779
698861dc
DE
780 /* We vfork and then set environ in the child before calling execvp.
781 This clobbers the parent's environ so we need to restore it.
782 It would be nice to use one of the exec* functions that takes an
5c12a855 783 environment as a parameter, but that may have portability
df1346b4
NS
784 issues. It is marked volatile so the child doesn't consider it a
785 dead variable and therefore clobber where ever it is stored. */
786 char **volatile save_environ = environ;
698861dc 787
a584cf65 788 for (retries = 0; retries < 4; ++retries)
55d0e5e0 789 {
fed8129b 790 pid = vfork ();
55d0e5e0
ZW
791 if (pid >= 0)
792 break;
793 sleep (sleep_interval);
794 sleep_interval *= 2;
795 }
796
797 switch (pid)
798 {
799 case -1:
df1346b4
NS
800 if (do_pipe)
801 {
802 close (pipes[0]);
803 close (pipes[1]);
804 }
a584cf65
ILT
805 *err = errno;
806 *errmsg = VFORK_STRING;
1651030c 807 return (pid_t) -1;
55d0e5e0 808
a584cf65
ILT
809 case 0:
810 /* Child process. */
5c12a855 811 {
df1346b4
NS
812 struct fn_err failed;
813 failed.fn = NULL;
832c74d9 814
df1346b4
NS
815 if (do_pipe)
816 close (pipes[0]);
817 if (!failed.fn && in != STDIN_FILE_NO)
832c74d9
NS
818 {
819 if (dup2 (in, STDIN_FILE_NO) < 0)
df1346b4 820 failed.fn = "dup2", failed.err = errno;
832c74d9 821 else if (close (in) < 0)
df1346b4 822 failed.fn = "close", failed.err = errno;
832c74d9 823 }
df1346b4 824 if (!failed.fn && out != STDOUT_FILE_NO)
832c74d9
NS
825 {
826 if (dup2 (out, STDOUT_FILE_NO) < 0)
df1346b4 827 failed.fn = "dup2", failed.err = errno;
832c74d9 828 else if (close (out) < 0)
df1346b4 829 failed.fn = "close", failed.err = errno;
832c74d9 830 }
df1346b4 831 if (!failed.fn && errdes != STDERR_FILE_NO)
832c74d9
NS
832 {
833 if (dup2 (errdes, STDERR_FILE_NO) < 0)
df1346b4 834 failed.fn = "dup2", failed.err = errno;
832c74d9 835 else if (close (errdes) < 0)
df1346b4 836 failed.fn = "close", failed.err = errno;
832c74d9 837 }
df1346b4 838 if (!failed.fn && toclose >= 0)
832c74d9
NS
839 {
840 if (close (toclose) < 0)
df1346b4 841 failed.fn = "close", failed.err = errno;
832c74d9 842 }
df1346b4 843 if (!failed.fn && (flags & PEX_STDERR_TO_STDOUT) != 0)
832c74d9
NS
844 {
845 if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
df1346b4 846 failed.fn = "dup2", failed.err = errno;
832c74d9 847 }
df1346b4 848 if (!failed.fn)
832c74d9
NS
849 {
850 if (env)
851 /* NOTE: In a standard vfork implementation this clobbers
852 the parent's copy of environ "too" (in reality there's
853 only one copy). This is ok as we restore it below. */
854 environ = (char**) env;
855 if ((flags & PEX_SEARCH) != 0)
856 {
857 execvp (executable, to_ptr32 (argv));
df1346b4 858 failed.fn = "execvp", failed.err = errno;
832c74d9
NS
859 }
860 else
861 {
862 execv (executable, to_ptr32 (argv));
df1346b4 863 failed.fn = "execv", failed.err = errno;
832c74d9
NS
864 }
865 }
866
867 /* Something failed, report an error. We don't use stdio
868 routines, because we might be here due to a vfork call. */
5c12a855 869 ssize_t retval = 0;
df1346b4
NS
870
871 if (!do_pipe
872 || write (pipes[1], &failed, sizeof (failed)) != sizeof (failed))
873 {
874 /* The parent will not see our scream above, so write to
875 stdout. */
5c12a855 876#define writeerr(s) (retval |= write (STDERR_FILE_NO, s, strlen (s)))
df1346b4
NS
877 writeerr (obj->pname);
878 writeerr (": error trying to exec '");
879 writeerr (executable);
880 writeerr ("': ");
881 writeerr (failed.fn);
882 writeerr (": ");
883 writeerr (xstrerror (failed.err));
884 writeerr ("\n");
5c12a855 885#undef writeerr
df1346b4 886 }
fed8129b 887
5c12a855
NS
888 /* Exit with -2 if the error output failed, too. */
889 _exit (retval < 0 ? -2 : -1);
890 }
55d0e5e0 891 /* NOTREACHED */
1651030c 892 return (pid_t) -1;
55d0e5e0
ZW
893
894 default:
a584cf65 895 /* Parent process. */
832c74d9 896 {
832c74d9
NS
897 /* Restore environ. Note that the parent either doesn't run
898 until the child execs/exits (standard vfork behaviour), or
899 if it does run then vfork is behaving more like fork. In
900 either case we needn't worry about clobbering the child's
901 copy of environ. */
902 environ = save_environ;
903
df1346b4
NS
904 struct fn_err failed;
905 failed.fn = NULL;
906 if (do_pipe)
907 {
908 close (pipes[1]);
909 ssize_t len = read (pipes[0], &failed, sizeof (failed));
910 if (len < 0)
911 failed.fn = NULL;
912 close (pipes[0]);
913 }
914
915 if (!failed.fn && in != STDIN_FILE_NO)
832c74d9 916 if (close (in) < 0)
df1346b4
NS
917 failed.fn = "close", failed.err = errno;
918 if (!failed.fn && out != STDOUT_FILE_NO)
832c74d9 919 if (close (out) < 0)
df1346b4
NS
920 failed.fn = "close", failed.err = errno;
921 if (!failed.fn && errdes != STDERR_FILE_NO)
832c74d9 922 if (close (errdes) < 0)
df1346b4 923 failed.fn = "close", failed.err = errno;
698861dc 924
df1346b4 925 if (failed.fn)
832c74d9 926 {
df1346b4
NS
927 *err = failed.err;
928 *errmsg = failed.fn;
832c74d9
NS
929 return (pid_t) -1;
930 }
931 }
1651030c 932 return pid;
55d0e5e0
ZW
933 }
934}
3b63ca7e 935#endif /* SPAWN */
55d0e5e0 936
a584cf65
ILT
937/* Wait for a child process to complete. */
938
691858d2 939static pid_t
1651030c 940pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status,
a584cf65
ILT
941 struct pex_time *time, int done, const char **errmsg,
942 int *err)
55d0e5e0 943{
a584cf65
ILT
944 /* If we are cleaning up when the caller didn't retrieve process
945 status for some reason, encourage the process to go away. */
946 if (done)
947 kill (pid, SIGTERM);
948
949 if (pex_wait (obj, pid, status, time) < 0)
950 {
951 *err = errno;
952 *errmsg = "wait";
953 return -1;
954 }
955
956 return 0;
957}
958
959/* Create a pipe. */
960
961static int
962pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p,
963 int binary ATTRIBUTE_UNUSED)
964{
965 return pipe (p);
966}
967
968/* Get a FILE pointer to read from a file descriptor. */
969
970static FILE *
971pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
972 int binary ATTRIBUTE_UNUSED)
973{
974 return fdopen (fd, "r");
975}
976
8eff378c
JB
977static FILE *
978pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
979 int binary ATTRIBUTE_UNUSED)
980{
981 if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
982 return NULL;
983 return fdopen (fd, "w");
984}
985
a584cf65
ILT
986static void
987pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
988{
989#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
990 while (obj->sysdep != NULL)
991 {
992 struct status_list *this;
993 struct status_list *next;
994
995 this = (struct status_list *) obj->sysdep;
996 next = this->next;
997 free (this);
998 obj->sysdep = (void *) next;
999 }
1000#endif
55d0e5e0 1001}