Mercurial > hg > CbC > CbC_gcc
annotate libiberty/pex-unix.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children | f6334be47118 |
rev | line source |
---|---|
0 | 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). | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
4 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2009 |
0 | 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., 51 Franklin Street - Fifth Floor, | |
21 Boston, MA 02110-1301, USA. */ | |
22 | |
23 #include "config.h" | |
24 #include "libiberty.h" | |
25 #include "pex-common.h" | |
26 | |
27 #include <stdio.h> | |
28 #include <signal.h> | |
29 #include <errno.h> | |
30 #ifdef NEED_DECLARATION_ERRNO | |
31 extern int errno; | |
32 #endif | |
33 #ifdef HAVE_STDLIB_H | |
34 #include <stdlib.h> | |
35 #endif | |
36 #ifdef HAVE_STRING_H | |
37 #include <string.h> | |
38 #endif | |
39 #ifdef HAVE_UNISTD_H | |
40 #include <unistd.h> | |
41 #endif | |
42 | |
43 #include <sys/types.h> | |
44 | |
45 #ifdef HAVE_FCNTL_H | |
46 #include <fcntl.h> | |
47 #endif | |
48 #ifdef HAVE_SYS_WAIT_H | |
49 #include <sys/wait.h> | |
50 #endif | |
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> | |
57 #endif | |
58 | |
59 | |
60 #ifdef vfork /* Autoconf may define this to fork for us. */ | |
61 # define VFORK_STRING "fork" | |
62 #else | |
63 # define VFORK_STRING "vfork" | |
64 #endif | |
65 #ifdef HAVE_VFORK_H | |
66 #include <vfork.h> | |
67 #endif | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
68 #if defined(VMS) && defined (__LONG_POINTERS) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
69 #ifndef __CHAR_PTR32 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
70 typedef char * __char_ptr32 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
71 __attribute__ ((mode (SI))); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
72 #endif |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
73 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
74 typedef __char_ptr32 *__char_ptr_char_ptr32 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
75 __attribute__ ((mode (SI))); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
76 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
77 /* Return a 32 bit pointer to an array of 32 bit pointers |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
78 given a 64 bit pointer to an array of 64 bit pointers. */ |
0 | 79 |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
80 static __char_ptr_char_ptr32 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
81 to_ptr32 (char **ptr64) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
82 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
83 int argc; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
84 __char_ptr_char_ptr32 short_argv; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
85 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
86 for (argc=0; ptr64[argc]; argc++); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
87 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
88 /* Reallocate argv with 32 bit pointers. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
89 short_argv = (__char_ptr_char_ptr32) decc$malloc |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
90 (sizeof (__char_ptr32) * (argc + 1)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
91 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
92 for (argc=0; ptr64[argc]; argc++) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
93 short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
94 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
95 short_argv[argc] = (__char_ptr32) 0; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
96 return short_argv; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
97 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
98 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
99 #else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
100 #define to_ptr32(argv) argv |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
101 #endif |
0 | 102 |
103 /* File mode to use for private and world-readable files. */ | |
104 | |
105 #if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH) | |
106 #define PUBLIC_MODE \ | |
107 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | |
108 #else | |
109 #define PUBLIC_MODE 0666 | |
110 #endif | |
111 | |
112 /* Get the exit status of a particular process, and optionally get the | |
113 time that it took. This is simple if we have wait4, slightly | |
114 harder if we have waitpid, and is a pain if we only have wait. */ | |
115 | |
116 static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *); | |
117 | |
118 #ifdef HAVE_WAIT4 | |
119 | |
120 static pid_t | |
121 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, | |
122 struct pex_time *time) | |
123 { | |
124 pid_t ret; | |
125 struct rusage r; | |
126 | |
127 #ifdef HAVE_WAITPID | |
128 if (time == NULL) | |
129 return waitpid (pid, status, 0); | |
130 #endif | |
131 | |
132 ret = wait4 (pid, status, 0, &r); | |
133 | |
134 if (time != NULL) | |
135 { | |
136 time->user_seconds = r.ru_utime.tv_sec; | |
137 time->user_microseconds= r.ru_utime.tv_usec; | |
138 time->system_seconds = r.ru_stime.tv_sec; | |
139 time->system_microseconds= r.ru_stime.tv_usec; | |
140 } | |
141 | |
142 return ret; | |
143 } | |
144 | |
145 #else /* ! defined (HAVE_WAIT4) */ | |
146 | |
147 #ifdef HAVE_WAITPID | |
148 | |
149 #ifndef HAVE_GETRUSAGE | |
150 | |
151 static pid_t | |
152 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, | |
153 struct pex_time *time) | |
154 { | |
155 if (time != NULL) | |
156 memset (time, 0, sizeof (struct pex_time)); | |
157 return waitpid (pid, status, 0); | |
158 } | |
159 | |
160 #else /* defined (HAVE_GETRUSAGE) */ | |
161 | |
162 static pid_t | |
163 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, | |
164 struct pex_time *time) | |
165 { | |
166 struct rusage r1, r2; | |
167 pid_t ret; | |
168 | |
169 if (time == NULL) | |
170 return waitpid (pid, status, 0); | |
171 | |
172 getrusage (RUSAGE_CHILDREN, &r1); | |
173 | |
174 ret = waitpid (pid, status, 0); | |
175 if (ret < 0) | |
176 return ret; | |
177 | |
178 getrusage (RUSAGE_CHILDREN, &r2); | |
179 | |
180 time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; | |
181 time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; | |
182 if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec) | |
183 { | |
184 --time->user_seconds; | |
185 time->user_microseconds += 1000000; | |
186 } | |
187 | |
188 time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; | |
189 time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; | |
190 if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec) | |
191 { | |
192 --time->system_seconds; | |
193 time->system_microseconds += 1000000; | |
194 } | |
195 | |
196 return ret; | |
197 } | |
198 | |
199 #endif /* defined (HAVE_GETRUSAGE) */ | |
200 | |
201 #else /* ! defined (HAVE_WAITPID) */ | |
202 | |
203 struct status_list | |
204 { | |
205 struct status_list *next; | |
206 pid_t pid; | |
207 int status; | |
208 struct pex_time time; | |
209 }; | |
210 | |
211 static pid_t | |
212 pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) | |
213 { | |
214 struct status_list **pp; | |
215 | |
216 for (pp = (struct status_list **) &obj->sysdep; | |
217 *pp != NULL; | |
218 pp = &(*pp)->next) | |
219 { | |
220 if ((*pp)->pid == pid) | |
221 { | |
222 struct status_list *p; | |
223 | |
224 p = *pp; | |
225 *status = p->status; | |
226 if (time != NULL) | |
227 *time = p->time; | |
228 *pp = p->next; | |
229 free (p); | |
230 return pid; | |
231 } | |
232 } | |
233 | |
234 while (1) | |
235 { | |
236 pid_t cpid; | |
237 struct status_list *psl; | |
238 struct pex_time pt; | |
239 #ifdef HAVE_GETRUSAGE | |
240 struct rusage r1, r2; | |
241 #endif | |
242 | |
243 if (time != NULL) | |
244 { | |
245 #ifdef HAVE_GETRUSAGE | |
246 getrusage (RUSAGE_CHILDREN, &r1); | |
247 #else | |
248 memset (&pt, 0, sizeof (struct pex_time)); | |
249 #endif | |
250 } | |
251 | |
252 cpid = wait (status); | |
253 | |
254 #ifdef HAVE_GETRUSAGE | |
255 if (time != NULL && cpid >= 0) | |
256 { | |
257 getrusage (RUSAGE_CHILDREN, &r2); | |
258 | |
259 pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; | |
260 pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; | |
261 if (pt.user_microseconds < 0) | |
262 { | |
263 --pt.user_seconds; | |
264 pt.user_microseconds += 1000000; | |
265 } | |
266 | |
267 pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; | |
268 pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; | |
269 if (pt.system_microseconds < 0) | |
270 { | |
271 --pt.system_seconds; | |
272 pt.system_microseconds += 1000000; | |
273 } | |
274 } | |
275 #endif | |
276 | |
277 if (cpid < 0 || cpid == pid) | |
278 { | |
279 if (time != NULL) | |
280 *time = pt; | |
281 return cpid; | |
282 } | |
283 | |
284 psl = XNEW (struct status_list); | |
285 psl->pid = cpid; | |
286 psl->status = *status; | |
287 if (time != NULL) | |
288 psl->time = pt; | |
289 psl->next = (struct status_list *) obj->sysdep; | |
290 obj->sysdep = (void *) psl; | |
291 } | |
292 } | |
293 | |
294 #endif /* ! defined (HAVE_WAITPID) */ | |
295 #endif /* ! defined (HAVE_WAIT4) */ | |
296 | |
297 static void pex_child_error (struct pex_obj *, const char *, const char *, int) | |
298 ATTRIBUTE_NORETURN; | |
299 static int pex_unix_open_read (struct pex_obj *, const char *, int); | |
300 static int pex_unix_open_write (struct pex_obj *, const char *, int); | |
301 static pid_t pex_unix_exec_child (struct pex_obj *, int, const char *, | |
302 char * const *, char * const *, | |
303 int, int, int, int, | |
304 const char **, int *); | |
305 static int pex_unix_close (struct pex_obj *, int); | |
306 static int pex_unix_wait (struct pex_obj *, pid_t, int *, struct pex_time *, | |
307 int, const char **, int *); | |
308 static int pex_unix_pipe (struct pex_obj *, int *, int); | |
309 static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); | |
310 static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); | |
311 static void pex_unix_cleanup (struct pex_obj *); | |
312 | |
313 /* The list of functions we pass to the common routines. */ | |
314 | |
315 const struct pex_funcs funcs = | |
316 { | |
317 pex_unix_open_read, | |
318 pex_unix_open_write, | |
319 pex_unix_exec_child, | |
320 pex_unix_close, | |
321 pex_unix_wait, | |
322 pex_unix_pipe, | |
323 pex_unix_fdopenr, | |
324 pex_unix_fdopenw, | |
325 pex_unix_cleanup | |
326 }; | |
327 | |
328 /* Return a newly initialized pex_obj structure. */ | |
329 | |
330 struct pex_obj * | |
331 pex_init (int flags, const char *pname, const char *tempbase) | |
332 { | |
333 return pex_init_common (flags, pname, tempbase, &funcs); | |
334 } | |
335 | |
336 /* Open a file for reading. */ | |
337 | |
338 static int | |
339 pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, | |
340 int binary ATTRIBUTE_UNUSED) | |
341 { | |
342 return open (name, O_RDONLY); | |
343 } | |
344 | |
345 /* Open a file for writing. */ | |
346 | |
347 static int | |
348 pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, | |
349 int binary ATTRIBUTE_UNUSED) | |
350 { | |
351 /* Note that we can't use O_EXCL here because gcc may have already | |
352 created the temporary file via make_temp_file. */ | |
353 return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE); | |
354 } | |
355 | |
356 /* Close a file. */ | |
357 | |
358 static int | |
359 pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) | |
360 { | |
361 return close (fd); | |
362 } | |
363 | |
364 /* Report an error from a child process. We don't use stdio routines, | |
365 because we might be here due to a vfork call. */ | |
366 | |
367 static void | |
368 pex_child_error (struct pex_obj *obj, const char *executable, | |
369 const char *errmsg, int err) | |
370 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
371 int retval = 0; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
372 #define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 0) |
0 | 373 writeerr (obj->pname); |
374 writeerr (": error trying to exec '"); | |
375 writeerr (executable); | |
376 writeerr ("': "); | |
377 writeerr (errmsg); | |
378 writeerr (": "); | |
379 writeerr (xstrerror (err)); | |
380 writeerr ("\n"); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
381 #undef writeerr |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
382 /* Exit with -2 if the error output failed, too. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
383 _exit (retval == 0 ? -1 : -2); |
0 | 384 } |
385 | |
386 /* Execute a child. */ | |
387 | |
388 extern char **environ; | |
389 | |
390 static pid_t | |
391 pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, | |
392 char * const * argv, char * const * env, | |
393 int in, int out, int errdes, | |
394 int toclose, const char **errmsg, int *err) | |
395 { | |
396 pid_t pid; | |
397 | |
398 /* We declare these to be volatile to avoid warnings from gcc about | |
399 them being clobbered by vfork. */ | |
400 volatile int sleep_interval; | |
401 volatile int retries; | |
402 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
403 /* We vfork and then set environ in the child before calling execvp. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
404 This clobbers the parent's environ so we need to restore it. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
405 It would be nice to use one of the exec* functions that takes an |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
406 environment as a parameter, but that may have portability issues. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
407 char **save_environ = environ; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
408 |
0 | 409 sleep_interval = 1; |
410 pid = -1; | |
411 for (retries = 0; retries < 4; ++retries) | |
412 { | |
413 pid = vfork (); | |
414 if (pid >= 0) | |
415 break; | |
416 sleep (sleep_interval); | |
417 sleep_interval *= 2; | |
418 } | |
419 | |
420 switch (pid) | |
421 { | |
422 case -1: | |
423 *err = errno; | |
424 *errmsg = VFORK_STRING; | |
425 return (pid_t) -1; | |
426 | |
427 case 0: | |
428 /* Child process. */ | |
429 if (in != STDIN_FILE_NO) | |
430 { | |
431 if (dup2 (in, STDIN_FILE_NO) < 0) | |
432 pex_child_error (obj, executable, "dup2", errno); | |
433 if (close (in) < 0) | |
434 pex_child_error (obj, executable, "close", errno); | |
435 } | |
436 if (out != STDOUT_FILE_NO) | |
437 { | |
438 if (dup2 (out, STDOUT_FILE_NO) < 0) | |
439 pex_child_error (obj, executable, "dup2", errno); | |
440 if (close (out) < 0) | |
441 pex_child_error (obj, executable, "close", errno); | |
442 } | |
443 if (errdes != STDERR_FILE_NO) | |
444 { | |
445 if (dup2 (errdes, STDERR_FILE_NO) < 0) | |
446 pex_child_error (obj, executable, "dup2", errno); | |
447 if (close (errdes) < 0) | |
448 pex_child_error (obj, executable, "close", errno); | |
449 } | |
450 if (toclose >= 0) | |
451 { | |
452 if (close (toclose) < 0) | |
453 pex_child_error (obj, executable, "close", errno); | |
454 } | |
455 if ((flags & PEX_STDERR_TO_STDOUT) != 0) | |
456 { | |
457 if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) | |
458 pex_child_error (obj, executable, "dup2", errno); | |
459 } | |
460 | |
461 if (env) | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
462 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
463 /* NOTE: In a standard vfork implementation this clobbers the |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
464 parent's copy of environ "too" (in reality there's only one copy). |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
465 This is ok as we restore it below. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
466 environ = (char**) env; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
467 } |
0 | 468 |
469 if ((flags & PEX_SEARCH) != 0) | |
470 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
471 execvp (executable, to_ptr32 (argv)); |
0 | 472 pex_child_error (obj, executable, "execvp", errno); |
473 } | |
474 else | |
475 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
476 execv (executable, to_ptr32 (argv)); |
0 | 477 pex_child_error (obj, executable, "execv", errno); |
478 } | |
479 | |
480 /* NOTREACHED */ | |
481 return (pid_t) -1; | |
482 | |
483 default: | |
484 /* Parent process. */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
485 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
486 /* Restore environ. |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
487 Note that the parent either doesn't run until the child execs/exits |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
488 (standard vfork behaviour), or if it does run then vfork is behaving |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
489 more like fork. In either case we needn't worry about clobbering |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
490 the child's copy of environ. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
491 environ = save_environ; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
492 |
0 | 493 if (in != STDIN_FILE_NO) |
494 { | |
495 if (close (in) < 0) | |
496 { | |
497 *err = errno; | |
498 *errmsg = "close"; | |
499 return (pid_t) -1; | |
500 } | |
501 } | |
502 if (out != STDOUT_FILE_NO) | |
503 { | |
504 if (close (out) < 0) | |
505 { | |
506 *err = errno; | |
507 *errmsg = "close"; | |
508 return (pid_t) -1; | |
509 } | |
510 } | |
511 if (errdes != STDERR_FILE_NO) | |
512 { | |
513 if (close (errdes) < 0) | |
514 { | |
515 *err = errno; | |
516 *errmsg = "close"; | |
517 return (pid_t) -1; | |
518 } | |
519 } | |
520 | |
521 return pid; | |
522 } | |
523 } | |
524 | |
525 /* Wait for a child process to complete. */ | |
526 | |
527 static int | |
528 pex_unix_wait (struct pex_obj *obj, pid_t pid, int *status, | |
529 struct pex_time *time, int done, const char **errmsg, | |
530 int *err) | |
531 { | |
532 /* If we are cleaning up when the caller didn't retrieve process | |
533 status for some reason, encourage the process to go away. */ | |
534 if (done) | |
535 kill (pid, SIGTERM); | |
536 | |
537 if (pex_wait (obj, pid, status, time) < 0) | |
538 { | |
539 *err = errno; | |
540 *errmsg = "wait"; | |
541 return -1; | |
542 } | |
543 | |
544 return 0; | |
545 } | |
546 | |
547 /* Create a pipe. */ | |
548 | |
549 static int | |
550 pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED, int *p, | |
551 int binary ATTRIBUTE_UNUSED) | |
552 { | |
553 return pipe (p); | |
554 } | |
555 | |
556 /* Get a FILE pointer to read from a file descriptor. */ | |
557 | |
558 static FILE * | |
559 pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, | |
560 int binary ATTRIBUTE_UNUSED) | |
561 { | |
562 return fdopen (fd, "r"); | |
563 } | |
564 | |
565 static FILE * | |
566 pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, | |
567 int binary ATTRIBUTE_UNUSED) | |
568 { | |
569 if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) | |
570 return NULL; | |
571 return fdopen (fd, "w"); | |
572 } | |
573 | |
574 static void | |
575 pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) | |
576 { | |
577 #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID) | |
578 while (obj->sysdep != NULL) | |
579 { | |
580 struct status_list *this; | |
581 struct status_list *next; | |
582 | |
583 this = (struct status_list *) obj->sysdep; | |
584 next = this->next; | |
585 free (this); | |
586 obj->sysdep = (void *) next; | |
587 } | |
588 #endif | |
589 } |