Commit | Line | Data |
---|---|---|
5a17353c DD |
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). | |
12a7367e | 4 | Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 |
5a17353c DD |
5 | Free Software Foundation, Inc. |
6 | ||
7 | This file is part of the libiberty library. | |
8 | Libiberty is free software; you can redistribute it and/or | |
9 | modify it under the terms of the GNU Library General Public | |
10 | License as published by the Free Software Foundation; either | |
11 | version 2 of the License, or (at your option) any later version. | |
12 | ||
13 | Libiberty is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Library General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Library General Public | |
19 | License along with libiberty; see the file COPYING.LIB. If not, | |
20 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 | Boston, MA 02111-1307, USA. */ | |
22 | ||
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_STRING_H | |
31 | #include <string.h> | |
32 | #endif | |
33 | #ifdef HAVE_UNISTD_H | |
34 | #include <unistd.h> | |
35 | #endif | |
36 | #ifdef HAVE_STDLIB_H | |
37 | #include <stdlib.h> | |
38 | #endif | |
39 | #ifdef HAVE_SYS_WAIT_H | |
40 | #include <sys/wait.h> | |
41 | #endif | |
42 | ||
43 | #ifndef HAVE_WAITPID | |
44 | #define waitpid(pid, status, flags) wait(status) | |
45 | #endif | |
46 | ||
12a7367e DD |
47 | #ifdef vfork /* Autoconf may define this to fork for us. */ |
48 | # define VFORK_STRING "fork" | |
49 | #else | |
50 | # define VFORK_STRING "vfork" | |
51 | #endif | |
52 | #ifdef HAVE_VFORK_H | |
53 | #include <vfork.h> | |
54 | #endif | |
55 | #ifdef VMS | |
56 | #define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \ | |
57 | lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1) | |
58 | #endif /* VMS */ | |
59 | ||
60 | /* Execute a program, possibly setting up pipes to programs executed | |
61 | via other calls to this function. | |
62 | ||
63 | This version of the function uses vfork. In general vfork is | |
64 | similar to setjmp/longmp, in that any variable which is modified by | |
65 | the child process has an indeterminate value in the parent process. | |
66 | We follow a safe approach here by not modifying any variables at | |
67 | all in the child process (with the possible exception of variables | |
68 | modified by xstrerror if exec fails, but this is unlikely to be | |
69 | detectable). | |
70 | ||
71 | We work a little bit harder to avoid gcc warnings. gcc will warn | |
72 | about any automatic variable which is live at the time of the | |
73 | vfork, which is non-volatile, and which is either set more than | |
74 | once or is an argument to the function. This warning isn't quite | |
75 | right, since what we really care about is whether the variable is | |
76 | live at the time of the vfork and set afterward by the child | |
77 | process, but gcc only checks whether the variable is set more than | |
78 | once. To avoid this warning, we ensure that any variable which is | |
79 | live at the time of the vfork (i.e., used after the vfork) is set | |
80 | exactly once and is not an argument, or is marked volatile. */ | |
5a17353c DD |
81 | |
82 | int | |
12a7367e DD |
83 | pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, |
84 | flagsarg) | |
5a17353c DD |
85 | const char *program; |
86 | char * const *argv; | |
87 | const char *this_pname; | |
88 | const char *temp_base ATTRIBUTE_UNUSED; | |
89 | char **errmsg_fmt, **errmsg_arg; | |
12a7367e | 90 | int flagsarg; |
5a17353c | 91 | { |
5a17353c DD |
92 | int pid; |
93 | int pdes[2]; | |
12a7367e | 94 | int out; |
5a17353c | 95 | int input_desc, output_desc; |
12a7367e DD |
96 | int flags; |
97 | /* We declare these to be volatile to avoid warnings from gcc about | |
98 | them being clobbered by vfork. */ | |
99 | volatile int retries, sleep_interval; | |
5a17353c DD |
100 | /* Pipe waiting from last process, to be used as input for the next one. |
101 | Value is STDIN_FILE_NO if no pipe is waiting | |
102 | (i.e. the next command is the first of a group). */ | |
103 | static int last_pipe_input; | |
104 | ||
12a7367e DD |
105 | flags = flagsarg; |
106 | ||
5a17353c DD |
107 | /* If this is the first process, initialize. */ |
108 | if (flags & PEXECUTE_FIRST) | |
109 | last_pipe_input = STDIN_FILE_NO; | |
110 | ||
111 | input_desc = last_pipe_input; | |
112 | ||
113 | /* If this isn't the last process, make a pipe for its output, | |
114 | and record it as waiting to be the input to the next process. */ | |
115 | if (! (flags & PEXECUTE_LAST)) | |
116 | { | |
117 | if (pipe (pdes) < 0) | |
118 | { | |
119 | *errmsg_fmt = "pipe"; | |
120 | *errmsg_arg = NULL; | |
121 | return -1; | |
122 | } | |
12a7367e | 123 | out = pdes[WRITE_PORT]; |
5a17353c DD |
124 | last_pipe_input = pdes[READ_PORT]; |
125 | } | |
126 | else | |
127 | { | |
128 | /* Last process. */ | |
12a7367e | 129 | out = STDOUT_FILE_NO; |
5a17353c DD |
130 | last_pipe_input = STDIN_FILE_NO; |
131 | } | |
132 | ||
12a7367e DD |
133 | output_desc = out; |
134 | ||
5a17353c DD |
135 | /* Fork a subprocess; wait and retry if it fails. */ |
136 | sleep_interval = 1; | |
137 | pid = -1; | |
138 | for (retries = 0; retries < 4; retries++) | |
139 | { | |
12a7367e | 140 | pid = vfork (); |
5a17353c DD |
141 | if (pid >= 0) |
142 | break; | |
143 | sleep (sleep_interval); | |
144 | sleep_interval *= 2; | |
145 | } | |
146 | ||
147 | switch (pid) | |
148 | { | |
149 | case -1: | |
150 | *errmsg_fmt = "fork"; | |
151 | *errmsg_arg = NULL; | |
152 | return -1; | |
153 | ||
154 | case 0: /* child */ | |
155 | /* Move the input and output pipes into place, if necessary. */ | |
156 | if (input_desc != STDIN_FILE_NO) | |
157 | { | |
158 | close (STDIN_FILE_NO); | |
159 | dup (input_desc); | |
160 | close (input_desc); | |
161 | } | |
162 | if (output_desc != STDOUT_FILE_NO) | |
163 | { | |
164 | close (STDOUT_FILE_NO); | |
165 | dup (output_desc); | |
166 | close (output_desc); | |
167 | } | |
168 | ||
169 | /* Close the parent's descs that aren't wanted here. */ | |
170 | if (last_pipe_input != STDIN_FILE_NO) | |
171 | close (last_pipe_input); | |
172 | ||
173 | /* Exec the program. */ | |
12a7367e DD |
174 | if (flags & PEXECUTE_SEARCH) |
175 | execvp (program, argv); | |
176 | else | |
177 | execv (program, argv); | |
178 | ||
179 | /* We don't want to call fprintf after vfork. */ | |
180 | #define writeerr(s) write (STDERR_FILE_NO, s, strlen (s)) | |
181 | writeerr (this_pname); | |
182 | writeerr (": "); | |
183 | writeerr ("installation problem, cannot exec '"); | |
184 | writeerr (program); | |
185 | writeerr ("': "); | |
186 | writeerr (xstrerror (errno)); | |
187 | writeerr ("\n"); | |
188 | _exit (-1); | |
5a17353c DD |
189 | /* NOTREACHED */ |
190 | return 0; | |
191 | ||
192 | default: | |
193 | /* In the parent, after forking. | |
194 | Close the descriptors that we made for this child. */ | |
195 | if (input_desc != STDIN_FILE_NO) | |
196 | close (input_desc); | |
197 | if (output_desc != STDOUT_FILE_NO) | |
198 | close (output_desc); | |
199 | ||
200 | /* Return child's process number. */ | |
201 | return pid; | |
202 | } | |
203 | } | |
204 | ||
205 | int | |
206 | pwait (pid, status, flags) | |
207 | int pid; | |
208 | int *status; | |
209 | int flags ATTRIBUTE_UNUSED; | |
210 | { | |
211 | /* ??? Here's an opportunity to canonicalize the values in STATUS. | |
212 | Needed? */ | |
213 | pid = waitpid (pid, status, 0); | |
214 | return pid; | |
215 | } |