Mercurial > hg > CbC > CbC_gcc
comparison libiberty/pex-unix.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
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.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 | |
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_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH) | |
77 #define PUBLIC_MODE \ | |
78 (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) | |
79 #else | |
80 #define PUBLIC_MODE 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_WAIT4 | |
90 | |
91 static pid_t | |
92 pex_wait (struct pex_obj *obj 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_WAITPID | |
99 if (time == NULL) | |
100 return waitpid (pid, status, 0); | |
101 #endif | |
102 | |
103 ret = wait4 (pid, status, 0, &r); | |
104 | |
105 if (time != NULL) | |
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_WAITPID | |
119 | |
120 #ifndef HAVE_GETRUSAGE | |
121 | |
122 static pid_t | |
123 pex_wait (struct pex_obj *obj ATTRIBUTE_UNUSED, pid_t pid, int *status, | |
124 struct pex_time *time) | |
125 { | |
126 if (time != NULL) | |
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, 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) | |
141 return waitpid (pid, status, 0); | |
142 | |
143 getrusage (RUSAGE_CHILDREN, &r1); | |
144 | |
145 ret = waitpid (pid, status, 0); | |
146 if (ret < 0) | |
147 return ret; | |
148 | |
149 getrusage (RUSAGE_CHILDREN, &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; | |
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) | |
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_GETRUSAGE | |
211 struct rusage r1, r2; | |
212 #endif | |
213 | |
214 if (time != NULL) | |
215 { | |
216 #ifdef HAVE_GETRUSAGE | |
217 getrusage (RUSAGE_CHILDREN, &r1); | |
218 #else | |
219 memset (&pt, 0, sizeof (struct pex_time)); | |
220 #endif | |
221 } | |
222 | |
223 cpid = wait (status); | |
224 | |
225 #ifdef HAVE_GETRUSAGE | |
226 if (time != NULL && cpid >= 0) | |
227 { | |
228 getrusage (RUSAGE_CHILDREN, &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) | |
251 *time = pt; | |
252 return cpid; | |
253 } | |
254 | |
255 psl = XNEW (struct status_list); | |
256 psl->pid = cpid; | |
257 psl->status = *status; | |
258 if (time != NULL) | |
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; | |
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 pid_t 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 *, pid_t, 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, const char *name, | |
311 int binary ATTRIBUTE_UNUSED) | |
312 { | |
313 return open (name, O_RDONLY); | |
314 } | |
315 | |
316 /* Open a file for writing. */ | |
317 | |
318 static int | |
319 pex_unix_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, const char *name, | |
320 int binary 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_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE); | |
325 } | |
326 | |
327 /* Close a file. */ | |
328 | |
329 static int | |
330 pex_unix_close (struct pex_obj *obj 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) (void) write (STDERR_FILE_NO, s, strlen (s)) | |
343 writeerr (obj->pname); | |
344 writeerr (": error trying to exec '"); | |
345 writeerr (executable); | |
346 writeerr ("': "); | |
347 writeerr (errmsg); | |
348 writeerr (": "); | |
349 writeerr (xstrerror (err)); | |
350 writeerr ("\n"); | |
351 _exit (-1); | |
352 } | |
353 | |
354 /* Execute a child. */ | |
355 | |
356 extern char **environ; | |
357 | |
358 static pid_t | |
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 >= 0) | |
377 break; | |
378 sleep (sleep_interval); | |
379 sleep_interval *= 2; | |
380 } | |
381 | |
382 switch (pid) | |
383 { | |
384 case -1: | |
385 *err = errno; | |
386 *errmsg = VFORK_STRING; | |
387 return (pid_t) -1; | |
388 | |
389 case 0: | |
390 /* Child process. */ | |
391 if (in != STDIN_FILE_NO) | |
392 { | |
393 if (dup2 (in, STDIN_FILE_NO) < 0) | |
394 pex_child_error (obj, executable, "dup2", errno); | |
395 if (close (in) < 0) | |
396 pex_child_error (obj, executable, "close", errno); | |
397 } | |
398 if (out != STDOUT_FILE_NO) | |
399 { | |
400 if (dup2 (out, STDOUT_FILE_NO) < 0) | |
401 pex_child_error (obj, executable, "dup2", errno); | |
402 if (close (out) < 0) | |
403 pex_child_error (obj, executable, "close", errno); | |
404 } | |
405 if (errdes != STDERR_FILE_NO) | |
406 { | |
407 if (dup2 (errdes, STDERR_FILE_NO) < 0) | |
408 pex_child_error (obj, executable, "dup2", errno); | |
409 if (close (errdes) < 0) | |
410 pex_child_error (obj, executable, "close", errno); | |
411 } | |
412 if (toclose >= 0) | |
413 { | |
414 if (close (toclose) < 0) | |
415 pex_child_error (obj, executable, "close", errno); | |
416 } | |
417 if ((flags & PEX_STDERR_TO_STDOUT) != 0) | |
418 { | |
419 if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0) | |
420 pex_child_error (obj, executable, "dup2", errno); | |
421 } | |
422 | |
423 if (env) | |
424 environ = (char**) env; | |
425 | |
426 if ((flags & PEX_SEARCH) != 0) | |
427 { | |
428 execvp (executable, argv); | |
429 pex_child_error (obj, executable, "execvp", errno); | |
430 } | |
431 else | |
432 { | |
433 execv (executable, argv); | |
434 pex_child_error (obj, executable, "execv", errno); | |
435 } | |
436 | |
437 /* NOTREACHED */ | |
438 return (pid_t) -1; | |
439 | |
440 default: | |
441 /* Parent process. */ | |
442 if (in != STDIN_FILE_NO) | |
443 { | |
444 if (close (in) < 0) | |
445 { | |
446 *err = errno; | |
447 *errmsg = "close"; | |
448 return (pid_t) -1; | |
449 } | |
450 } | |
451 if (out != STDOUT_FILE_NO) | |
452 { | |
453 if (close (out) < 0) | |
454 { | |
455 *err = errno; | |
456 *errmsg = "close"; | |
457 return (pid_t) -1; | |
458 } | |
459 } | |
460 if (errdes != STDERR_FILE_NO) | |
461 { | |
462 if (close (errdes) < 0) | |
463 { | |
464 *err = errno; | |
465 *errmsg = "close"; | |
466 return (pid_t) -1; | |
467 } | |
468 } | |
469 | |
470 return pid; | |
471 } | |
472 } | |
473 | |
474 /* Wait for a child process to complete. */ | |
475 | |
476 static int | |
477 pex_unix_wait (struct pex_obj *obj, pid_t 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, SIGTERM); | |
485 | |
486 if (pex_wait (obj, pid, status, time) < 0) | |
487 { | |
488 *err = 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, int *p, | |
500 int binary 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, int fd, | |
509 int binary ATTRIBUTE_UNUSED) | |
510 { | |
511 return fdopen (fd, "r"); | |
512 } | |
513 | |
514 static FILE * | |
515 pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd, | |
516 int binary ATTRIBUTE_UNUSED) | |
517 { | |
518 if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) | |
519 return NULL; | |
520 return fdopen (fd, "w"); | |
521 } | |
522 | |
523 static void | |
524 pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED) | |
525 { | |
526 #if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID) | |
527 while (obj->sysdep != NULL) | |
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 } |