OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [libiberty/] [pex-unix.c] - Blame information for rev 309

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 274 jeremybenn
/* 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, 2009
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
#if defined(VMS) && defined (__LONG_POINTERS)
69
#ifndef __CHAR_PTR32
70
typedef char * __char_ptr32
71
__attribute__ ((mode (SI)));
72
#endif
73
 
74
typedef __char_ptr32 *__char_ptr_char_ptr32
75
__attribute__ ((mode (SI)));
76
 
77
/* Return a 32 bit pointer to an array of 32 bit pointers
78
   given a 64 bit pointer to an array of 64 bit pointers.  */
79
 
80
static __char_ptr_char_ptr32
81
to_ptr32 (char **ptr64)
82
{
83
  int argc;
84
  __char_ptr_char_ptr32 short_argv;
85
 
86
  for (argc=0; ptr64[argc]; argc++);
87
 
88
  /* Reallocate argv with 32 bit pointers.  */
89
  short_argv = (__char_ptr_char_ptr32) decc$malloc
90
    (sizeof (__char_ptr32) * (argc + 1));
91
 
92
  for (argc=0; ptr64[argc]; argc++)
93
    short_argv[argc] = (__char_ptr32) decc$strdup (ptr64[argc]);
94
 
95
  short_argv[argc] = (__char_ptr32) 0;
96
  return short_argv;
97
 
98
}
99
#else
100
#define to_ptr32(argv) argv
101
#endif
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
{
371
  int retval = 0;
372
#define writeerr(s) retval |= (write (STDERR_FILE_NO, s, strlen (s)) < 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");
381
#undef writeerr
382
  /* Exit with -2 if the error output failed, too.  */
383
  _exit (retval == 0 ? -1 : -2);
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
 
403
  /* We vfork and then set environ in the child before calling execvp.
404
     This clobbers the parent's environ so we need to restore it.
405
     It would be nice to use one of the exec* functions that takes an
406
     environment as a parameter, but that may have portability issues.  */
407
  char **save_environ = environ;
408
 
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)
462
        {
463
          /* NOTE: In a standard vfork implementation this clobbers the
464
             parent's copy of environ "too" (in reality there's only one copy).
465
             This is ok as we restore it below.  */
466
          environ = (char**) env;
467
        }
468
 
469
      if ((flags & PEX_SEARCH) != 0)
470
        {
471
          execvp (executable, to_ptr32 (argv));
472
          pex_child_error (obj, executable, "execvp", errno);
473
        }
474
      else
475
        {
476
          execv (executable, to_ptr32 (argv));
477
          pex_child_error (obj, executable, "execv", errno);
478
        }
479
 
480
      /* NOTREACHED */
481
      return (pid_t) -1;
482
 
483
    default:
484
      /* Parent process.  */
485
 
486
      /* Restore environ.
487
         Note that the parent either doesn't run until the child execs/exits
488
         (standard vfork behaviour), or if it does run then vfork is behaving
489
         more like fork.  In either case we needn't worry about clobbering
490
         the child's copy of environ.  */
491
      environ = save_environ;
492
 
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.