File: | src/gnu/lib/libiberty/src/pex-unix.c |
Warning: | line 424, column 17 This assignment is prohibited after a successful vfork |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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). | |||
4 | Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 | |||
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(*__errno()).h> | |||
30 | #ifdef NEED_DECLARATION_ERRNO | |||
31 | extern int errno(*__errno()); | |||
32 | #endif | |||
33 | #ifdef HAVE_STDLIB_H1 | |||
34 | #include <stdlib.h> | |||
35 | #endif | |||
36 | #ifdef HAVE_STRING_H1 | |||
37 | #include <string.h> | |||
38 | #endif | |||
39 | #ifdef HAVE_UNISTD_H1 | |||
40 | #include <unistd.h> | |||
41 | #endif | |||
42 | ||||
43 | #include <sys/types.h> | |||
44 | ||||
45 | #ifdef HAVE_FCNTL_H1 | |||
46 | #include <fcntl.h> | |||
47 | #endif | |||
48 | #ifdef HAVE_SYS_WAIT_H1 | |||
49 | #include <sys/wait.h> | |||
50 | #endif | |||
51 | #ifdef HAVE_GETRUSAGE1 | |||
52 | #include <sys/time.h> | |||
53 | #include <sys/resource.h> | |||
54 | #endif | |||
55 | #ifdef HAVE_SYS_STAT_H1 | |||
56 | #include <sys/stat.h> | |||
57 | #endif | |||
58 | ||||
59 | ||||
60 | #ifdef vfork /* Autoconf may define this to fork for us. */ | |||
61 | # define VFORK_STRING"vfork" "fork" | |||
62 | #else | |||
63 | # define VFORK_STRING"vfork" "vfork" | |||
64 | #endif | |||
65 | #ifdef HAVE_VFORK_H | |||
66 | #include <vfork.h> | |||
67 | #endif | |||
68 | #ifdef VMS | |||
69 | #define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \ | |||
70 | lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1) | |||
71 | #endif /* VMS */ | |||
72 | ||||
73 | ||||
74 | /* File mode to use for private and world-readable files. */ | |||
75 | ||||
76 | #if defined (S_IRUSR0000400) && defined (S_IWUSR0000200) && defined (S_IRGRP0000040) && defined (S_IWGRP0000020) && defined (S_IROTH0000004) && defined (S_IWOTH0000002) | |||
77 | #define PUBLIC_MODE(0000400 | 0000200 | 0000040 | 0000020 | 0000004 | 0000002) \ | |||
78 | (S_IRUSR0000400 | S_IWUSR0000200 | S_IRGRP0000040 | S_IWGRP0000020 | S_IROTH0000004 | S_IWOTH0000002) | |||
79 | #else | |||
80 | #define PUBLIC_MODE(0000400 | 0000200 | 0000040 | 0000020 | 0000004 | 0000002) 0666 | |||
81 | #endif | |||
82 | ||||
83 | /* Get the exit status of a particular process, and optionally get the | |||
84 | time that it took. This is simple if we have wait4, slightly | |||
85 | harder if we have waitpid, and is a pain if we only have wait. */ | |||
86 | ||||
87 | static pid_t pex_wait (struct pex_obj *, pid_t, int *, struct pex_time *); | |||
88 | ||||
89 | #ifdef HAVE_WAIT41 | |||
90 | ||||
91 | static pid_t | |||
92 | pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), pid_t pid, int *status, | |||
93 | struct pex_time *time) | |||
94 | { | |||
95 | pid_t ret; | |||
96 | struct rusage r; | |||
97 | ||||
98 | #ifdef HAVE_WAITPID1 | |||
99 | if (time == NULL((void*)0)) | |||
100 | return waitpid (pid, status, 0); | |||
101 | #endif | |||
102 | ||||
103 | ret = wait4 (pid, status, 0, &r); | |||
104 | ||||
105 | if (time != NULL((void*)0)) | |||
106 | { | |||
107 | time->user_seconds = r.ru_utime.tv_sec; | |||
108 | time->user_microseconds= r.ru_utime.tv_usec; | |||
109 | time->system_seconds = r.ru_stime.tv_sec; | |||
110 | time->system_microseconds= r.ru_stime.tv_usec; | |||
111 | } | |||
112 | ||||
113 | return ret; | |||
114 | } | |||
115 | ||||
116 | #else /* ! defined (HAVE_WAIT4) */ | |||
117 | ||||
118 | #ifdef HAVE_WAITPID1 | |||
119 | ||||
120 | #ifndef HAVE_GETRUSAGE1 | |||
121 | ||||
122 | static pid_t | |||
123 | pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), pid_t pid, int *status, | |||
124 | struct pex_time *time) | |||
125 | { | |||
126 | if (time != NULL((void*)0)) | |||
127 | memset (time, 0, sizeof (struct pex_time)); | |||
128 | return waitpid (pid, status, 0); | |||
129 | } | |||
130 | ||||
131 | #else /* defined (HAVE_GETRUSAGE) */ | |||
132 | ||||
133 | static pid_t | |||
134 | pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), pid_t pid, int *status, | |||
135 | struct pex_time *time) | |||
136 | { | |||
137 | struct rusage r1, r2; | |||
138 | pid_t ret; | |||
139 | ||||
140 | if (time == NULL((void*)0)) | |||
141 | return waitpid (pid, status, 0); | |||
142 | ||||
143 | getrusage (RUSAGE_CHILDREN(-1), &r1); | |||
144 | ||||
145 | ret = waitpid (pid, status, 0); | |||
146 | if (ret < 0) | |||
147 | return ret; | |||
148 | ||||
149 | getrusage (RUSAGE_CHILDREN(-1), &r2); | |||
150 | ||||
151 | time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; | |||
152 | time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; | |||
153 | if (r2.ru_utime.tv_usec < r1.ru_utime.tv_usec) | |||
154 | { | |||
155 | --time->user_seconds; | |||
156 | time->user_microseconds += 1000000; | |||
157 | } | |||
158 | ||||
159 | time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; | |||
160 | time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; | |||
161 | if (r2.ru_stime.tv_usec < r1.ru_stime.tv_usec) | |||
162 | { | |||
163 | --time->system_seconds; | |||
164 | time->system_microseconds += 1000000; | |||
165 | } | |||
166 | ||||
167 | return ret; | |||
168 | } | |||
169 | ||||
170 | #endif /* defined (HAVE_GETRUSAGE) */ | |||
171 | ||||
172 | #else /* ! defined (HAVE_WAITPID) */ | |||
173 | ||||
174 | struct status_list | |||
175 | { | |||
176 | struct status_list *next; | |||
177 | pid_t pid; | |||
178 | int status; | |||
179 | struct pex_time time; | |||
180 | }; | |||
181 | ||||
182 | static pid_t | |||
183 | pex_wait (struct pex_obj *obj, pid_t pid, int *status, struct pex_time *time) | |||
184 | { | |||
185 | struct status_list **pp; | |||
186 | ||||
187 | for (pp = (struct status_list **) &obj->sysdep; | |||
188 | *pp != NULL((void*)0); | |||
189 | pp = &(*pp)->next) | |||
190 | { | |||
191 | if ((*pp)->pid == pid) | |||
192 | { | |||
193 | struct status_list *p; | |||
194 | ||||
195 | p = *pp; | |||
196 | *status = p->status; | |||
197 | if (time != NULL((void*)0)) | |||
198 | *time = p->time; | |||
199 | *pp = p->next; | |||
200 | free (p); | |||
201 | return pid; | |||
202 | } | |||
203 | } | |||
204 | ||||
205 | while (1) | |||
206 | { | |||
207 | pid_t cpid; | |||
208 | struct status_list *psl; | |||
209 | struct pex_time pt; | |||
210 | #ifdef HAVE_GETRUSAGE1 | |||
211 | struct rusage r1, r2; | |||
212 | #endif | |||
213 | ||||
214 | if (time != NULL((void*)0)) | |||
215 | { | |||
216 | #ifdef HAVE_GETRUSAGE1 | |||
217 | getrusage (RUSAGE_CHILDREN(-1), &r1); | |||
218 | #else | |||
219 | memset (&pt, 0, sizeof (struct pex_time)); | |||
220 | #endif | |||
221 | } | |||
222 | ||||
223 | cpid = wait (status); | |||
224 | ||||
225 | #ifdef HAVE_GETRUSAGE1 | |||
226 | if (time != NULL((void*)0) && cpid >= 0) | |||
227 | { | |||
228 | getrusage (RUSAGE_CHILDREN(-1), &r2); | |||
229 | ||||
230 | pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec; | |||
231 | pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec; | |||
232 | if (pt.user_microseconds < 0) | |||
233 | { | |||
234 | --pt.user_seconds; | |||
235 | pt.user_microseconds += 1000000; | |||
236 | } | |||
237 | ||||
238 | pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec; | |||
239 | pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec; | |||
240 | if (pt.system_microseconds < 0) | |||
241 | { | |||
242 | --pt.system_seconds; | |||
243 | pt.system_microseconds += 1000000; | |||
244 | } | |||
245 | } | |||
246 | #endif | |||
247 | ||||
248 | if (cpid < 0 || cpid == pid) | |||
249 | { | |||
250 | if (time != NULL((void*)0)) | |||
251 | *time = pt; | |||
252 | return cpid; | |||
253 | } | |||
254 | ||||
255 | psl = XNEW (struct status_list)((struct status_list *) xmalloc (sizeof (struct status_list)) ); | |||
256 | psl->pid = cpid; | |||
257 | psl->status = *status; | |||
258 | if (time != NULL((void*)0)) | |||
259 | psl->time = pt; | |||
260 | psl->next = (struct status_list *) obj->sysdep; | |||
261 | obj->sysdep = (void *) psl; | |||
262 | } | |||
263 | } | |||
264 | ||||
265 | #endif /* ! defined (HAVE_WAITPID) */ | |||
266 | #endif /* ! defined (HAVE_WAIT4) */ | |||
267 | ||||
268 | static void pex_child_error (struct pex_obj *, const char *, const char *, int) | |||
269 | ATTRIBUTE_NORETURN__attribute__ ((__noreturn__)); | |||
270 | static int pex_unix_open_read (struct pex_obj *, const char *, int); | |||
271 | static int pex_unix_open_write (struct pex_obj *, const char *, int); | |||
272 | static long pex_unix_exec_child (struct pex_obj *, int, const char *, | |||
273 | char * const *, char * const *, | |||
274 | int, int, int, int, | |||
275 | const char **, int *); | |||
276 | static int pex_unix_close (struct pex_obj *, int); | |||
277 | static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *, | |||
278 | int, const char **, int *); | |||
279 | static int pex_unix_pipe (struct pex_obj *, int *, int); | |||
280 | static FILE *pex_unix_fdopenr (struct pex_obj *, int, int); | |||
281 | static FILE *pex_unix_fdopenw (struct pex_obj *, int, int); | |||
282 | static void pex_unix_cleanup (struct pex_obj *); | |||
283 | ||||
284 | /* The list of functions we pass to the common routines. */ | |||
285 | ||||
286 | const struct pex_funcs funcs = | |||
287 | { | |||
288 | pex_unix_open_read, | |||
289 | pex_unix_open_write, | |||
290 | pex_unix_exec_child, | |||
291 | pex_unix_close, | |||
292 | pex_unix_wait, | |||
293 | pex_unix_pipe, | |||
294 | pex_unix_fdopenr, | |||
295 | pex_unix_fdopenw, | |||
296 | pex_unix_cleanup | |||
297 | }; | |||
298 | ||||
299 | /* Return a newly initialized pex_obj structure. */ | |||
300 | ||||
301 | struct pex_obj * | |||
302 | pex_init (int flags, const char *pname, const char *tempbase) | |||
303 | { | |||
304 | return pex_init_common (flags, pname, tempbase, &funcs); | |||
305 | } | |||
306 | ||||
307 | /* Open a file for reading. */ | |||
308 | ||||
309 | static int | |||
310 | pex_unix_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), const char *name, | |||
311 | int binary ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
312 | { | |||
313 | return open (name, O_RDONLY0x0000); | |||
314 | } | |||
315 | ||||
316 | /* Open a file for writing. */ | |||
317 | ||||
318 | static int | |||
319 | pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), const char *name, | |||
320 | int binary ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
321 | { | |||
322 | /* Note that we can't use O_EXCL here because gcc may have already | |||
323 | created the temporary file via make_temp_file. */ | |||
324 | return open (name, O_WRONLY0x0001 | O_CREAT0x0200 | O_TRUNC0x0400, PUBLIC_MODE(0000400 | 0000200 | 0000040 | 0000020 | 0000004 | 0000002)); | |||
325 | } | |||
326 | ||||
327 | /* Close a file. */ | |||
328 | ||||
329 | static int | |||
330 | pex_unix_close (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int fd) | |||
331 | { | |||
332 | return close (fd); | |||
333 | } | |||
334 | ||||
335 | /* Report an error from a child process. We don't use stdio routines, | |||
336 | because we might be here due to a vfork call. */ | |||
337 | ||||
338 | static void | |||
339 | pex_child_error (struct pex_obj *obj, const char *executable, | |||
340 | const char *errmsg, int err) | |||
341 | { | |||
342 | #define writeerr(s)write (2, s, strlen (s)) write (STDERR_FILE_NO2, s, strlen (s)) | |||
343 | writeerr (obj->pname)write (2, obj->pname, strlen (obj->pname)); | |||
344 | writeerr (": error trying to exec '")write (2, ": error trying to exec '", strlen (": error trying to exec '" )); | |||
345 | writeerr (executable)write (2, executable, strlen (executable)); | |||
346 | writeerr ("': ")write (2, "': ", strlen ("': ")); | |||
347 | writeerr (errmsg)write (2, errmsg, strlen (errmsg)); | |||
348 | writeerr (": ")write (2, ": ", strlen (": ")); | |||
349 | writeerr (xstrerror (err))write (2, xstrerror (err), strlen (xstrerror (err))); | |||
350 | writeerr ("\n")write (2, "\n", strlen ("\n")); | |||
351 | _exit (-1); | |||
352 | } | |||
353 | ||||
354 | /* Execute a child. */ | |||
355 | ||||
356 | extern char **environ; | |||
357 | ||||
358 | static long | |||
359 | pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable, | |||
360 | char * const * argv, char * const * env, | |||
361 | int in, int out, int errdes, | |||
362 | int toclose, const char **errmsg, int *err) | |||
363 | { | |||
364 | pid_t pid; | |||
365 | ||||
366 | /* We declare these to be volatile to avoid warnings from gcc about | |||
367 | them being clobbered by vfork. */ | |||
368 | volatile int sleep_interval; | |||
369 | volatile int retries; | |||
370 | ||||
371 | sleep_interval = 1; | |||
372 | pid = -1; | |||
373 | for (retries = 0; retries < 4; ++retries) | |||
| ||||
374 | { | |||
375 | pid = vfork (); | |||
376 | if (pid
| |||
377 | break; | |||
378 | sleep (sleep_interval); | |||
379 | sleep_interval *= 2; | |||
380 | } | |||
381 | ||||
382 | switch (pid) | |||
383 | { | |||
384 | case -1: | |||
385 | *err = errno(*__errno()); | |||
386 | *errmsg = VFORK_STRING"vfork"; | |||
387 | return -1; | |||
388 | ||||
389 | case 0: | |||
390 | /* Child process. */ | |||
391 | if (in != STDIN_FILE_NO0) | |||
392 | { | |||
393 | if (dup2 (in, STDIN_FILE_NO0) < 0) | |||
394 | pex_child_error (obj, executable, "dup2", errno(*__errno())); | |||
395 | if (close (in) < 0) | |||
396 | pex_child_error (obj, executable, "close", errno(*__errno())); | |||
397 | } | |||
398 | if (out != STDOUT_FILE_NO1) | |||
399 | { | |||
400 | if (dup2 (out, STDOUT_FILE_NO1) < 0) | |||
401 | pex_child_error (obj, executable, "dup2", errno(*__errno())); | |||
402 | if (close (out) < 0) | |||
403 | pex_child_error (obj, executable, "close", errno(*__errno())); | |||
404 | } | |||
405 | if (errdes != STDERR_FILE_NO2) | |||
406 | { | |||
407 | if (dup2 (errdes, STDERR_FILE_NO2) < 0) | |||
408 | pex_child_error (obj, executable, "dup2", errno(*__errno())); | |||
409 | if (close (errdes) < 0) | |||
410 | pex_child_error (obj, executable, "close", errno(*__errno())); | |||
411 | } | |||
412 | if (toclose >= 0) | |||
413 | { | |||
414 | if (close (toclose) < 0) | |||
415 | pex_child_error (obj, executable, "close", errno(*__errno())); | |||
416 | } | |||
417 | if ((flags & PEX_STDERR_TO_STDOUT0x8) != 0) | |||
418 | { | |||
419 | if (dup2 (STDOUT_FILE_NO1, STDERR_FILE_NO2) < 0) | |||
420 | pex_child_error (obj, executable, "dup2", errno(*__errno())); | |||
421 | } | |||
422 | ||||
423 | if (env) | |||
424 | environ = (char**) env; | |||
| ||||
425 | ||||
426 | if ((flags & PEX_SEARCH0x2) != 0) | |||
427 | { | |||
428 | execvp (executable, argv); | |||
429 | pex_child_error (obj, executable, "execvp", errno(*__errno())); | |||
430 | } | |||
431 | else | |||
432 | { | |||
433 | execv (executable, argv); | |||
434 | pex_child_error (obj, executable, "execv", errno(*__errno())); | |||
435 | } | |||
436 | ||||
437 | /* NOTREACHED */ | |||
438 | return -1; | |||
439 | ||||
440 | default: | |||
441 | /* Parent process. */ | |||
442 | if (in != STDIN_FILE_NO0) | |||
443 | { | |||
444 | if (close (in) < 0) | |||
445 | { | |||
446 | *err = errno(*__errno()); | |||
447 | *errmsg = "close"; | |||
448 | return -1; | |||
449 | } | |||
450 | } | |||
451 | if (out != STDOUT_FILE_NO1) | |||
452 | { | |||
453 | if (close (out) < 0) | |||
454 | { | |||
455 | *err = errno(*__errno()); | |||
456 | *errmsg = "close"; | |||
457 | return -1; | |||
458 | } | |||
459 | } | |||
460 | if (errdes != STDERR_FILE_NO2) | |||
461 | { | |||
462 | if (close (errdes) < 0) | |||
463 | { | |||
464 | *err = errno(*__errno()); | |||
465 | *errmsg = "close"; | |||
466 | return -1; | |||
467 | } | |||
468 | } | |||
469 | ||||
470 | return (long) pid; | |||
471 | } | |||
472 | } | |||
473 | ||||
474 | /* Wait for a child process to complete. */ | |||
475 | ||||
476 | static int | |||
477 | pex_unix_wait (struct pex_obj *obj, long pid, int *status, | |||
478 | struct pex_time *time, int done, const char **errmsg, | |||
479 | int *err) | |||
480 | { | |||
481 | /* If we are cleaning up when the caller didn't retrieve process | |||
482 | status for some reason, encourage the process to go away. */ | |||
483 | if (done) | |||
484 | kill (pid, SIGTERM15); | |||
485 | ||||
486 | if (pex_wait (obj, pid, status, time) < 0) | |||
487 | { | |||
488 | *err = errno(*__errno()); | |||
489 | *errmsg = "wait"; | |||
490 | return -1; | |||
491 | } | |||
492 | ||||
493 | return 0; | |||
494 | } | |||
495 | ||||
496 | /* Create a pipe. */ | |||
497 | ||||
498 | static int | |||
499 | pex_unix_pipe (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int *p, | |||
500 | int binary ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
501 | { | |||
502 | return pipe (p); | |||
503 | } | |||
504 | ||||
505 | /* Get a FILE pointer to read from a file descriptor. */ | |||
506 | ||||
507 | static FILE * | |||
508 | pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int fd, | |||
509 | int binary ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
510 | { | |||
511 | return fdopen (fd, "r"); | |||
512 | } | |||
513 | ||||
514 | static FILE * | |||
515 | pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__)), int fd, | |||
516 | int binary ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
517 | { | |||
518 | if (fcntl (fd, F_SETFD2, FD_CLOEXEC1) < 0) | |||
519 | return NULL((void*)0); | |||
520 | return fdopen (fd, "w"); | |||
521 | } | |||
522 | ||||
523 | static void | |||
524 | pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
525 | { | |||
526 | #if !defined (HAVE_WAIT41) && !defined (HAVE_WAITPID1) | |||
527 | while (obj->sysdep != NULL((void*)0)) | |||
528 | { | |||
529 | struct status_list *this; | |||
530 | struct status_list *next; | |||
531 | ||||
532 | this = (struct status_list *) obj->sysdep; | |||
533 | next = this->next; | |||
534 | free (this); | |||
535 | obj->sysdep = (void *) next; | |||
536 | } | |||
537 | #endif | |||
538 | } |