~ubuntu-branches/ubuntu/breezy/gettext/breezy

« back to all changes in this revision

Viewing changes to gettext-tools/lib/execute.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2004-03-14 17:40:02 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040314174002-p1ad5ldve1hqzhye
Tags: 0.14.1-2
* Added libexpat1-dev to Build-Depends, for glade support.
* Added libc0.1-dev to Build-Depends, for GNU/kFreeBSD.
* Removed special-casing of knetbsd-gnu in debian/rules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Creation of autonomous subprocesses.
 
2
   Copyright (C) 2001-2003 Free Software Foundation, Inc.
 
3
   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
4
 
 
5
   This program is free software; you can redistribute it and/or modify
 
6
   it under the terms of the GNU General Public License as published by
 
7
   the Free Software Foundation; either version 2, or (at your option)
 
8
   any later version.
 
9
 
 
10
   This program is distributed in the hope that it will be useful,
 
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
   GNU General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License
 
16
   along with this program; if not, write to the Free Software Foundation,
 
17
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
18
 
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
# include "config.h"
 
22
#endif
 
23
 
 
24
/* Specification.  */
 
25
#include "execute.h"
 
26
 
 
27
#include <errno.h>
 
28
#include <fcntl.h>
 
29
#include <stdbool.h>
 
30
#include <stdlib.h>
 
31
#include <signal.h>
 
32
 
 
33
#ifdef HAVE_UNISTD_H
 
34
# include <unistd.h>
 
35
#endif
 
36
 
 
37
#include "error.h"
 
38
#include "exit.h"
 
39
#include "fatal-signal.h"
 
40
#include "wait-process.h"
 
41
#include "gettext.h"
 
42
 
 
43
#define _(str) gettext (str)
 
44
 
 
45
#if defined _MSC_VER || defined __MINGW32__
 
46
 
 
47
/* Native Woe32 API.  */
 
48
# include <process.h>
 
49
# include "w32spawn.h"
 
50
 
 
51
#else
 
52
 
 
53
/* Unix API.  */
 
54
# ifdef HAVE_POSIX_SPAWN
 
55
#  include <spawn.h>
 
56
# else
 
57
#  ifdef HAVE_VFORK_H
 
58
#   include <vfork.h>
 
59
#  endif
 
60
# endif
 
61
 
 
62
#endif
 
63
 
 
64
#ifndef STDIN_FILENO
 
65
# define STDIN_FILENO 0
 
66
#endif
 
67
#ifndef STDOUT_FILENO
 
68
# define STDOUT_FILENO 1
 
69
#endif
 
70
#ifndef STDERR_FILENO
 
71
# define STDERR_FILENO 2
 
72
#endif
 
73
 
 
74
 
 
75
#ifdef EINTR
 
76
 
 
77
/* EINTR handling for close(), open().
 
78
   These functions can return -1/EINTR even though we don't have any
 
79
   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
 
80
 
 
81
static inline int
 
82
nonintr_close (int fd)
 
83
{
 
84
  int retval;
 
85
 
 
86
  do
 
87
    retval = close (fd);
 
88
  while (retval < 0 && errno == EINTR);
 
89
 
 
90
  return retval;
 
91
}
 
92
#define close nonintr_close
 
93
 
 
94
static inline int
 
95
nonintr_open (const char *pathname, int oflag, mode_t mode)
 
96
{
 
97
  int retval;
 
98
 
 
99
  do
 
100
    retval = open (pathname, oflag, mode);
 
101
  while (retval < 0 && errno == EINTR);
 
102
 
 
103
  return retval;
 
104
}
 
105
#undef open /* avoid warning on VMS */
 
106
#define open nonintr_open
 
107
 
 
108
#endif
 
109
 
 
110
 
 
111
/* Execute a command, optionally redirecting any of the three standard file
 
112
   descriptors to /dev/null.  Return its exit code.
 
113
   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
 
114
   return 127.
 
115
   If slave_process is true, the child process will be terminated when its
 
116
   creator receives a catchable fatal signal.  */
 
117
int
 
118
execute (const char *progname,
 
119
         const char *prog_path, char **prog_argv,
 
120
         bool ignore_sigpipe,
 
121
         bool null_stdin, bool null_stdout, bool null_stderr,
 
122
         bool slave_process, bool exit_on_error)
 
123
{
 
124
#if defined _MSC_VER || defined __MINGW32__
 
125
 
 
126
  /* Native Woe32 API.  */
 
127
  int orig_stdin;
 
128
  int orig_stdout;
 
129
  int orig_stderr;
 
130
  int exitcode;
 
131
  int nullinfd;
 
132
  int nulloutfd;
 
133
 
 
134
  prog_argv = prepare_spawn (prog_argv);
 
135
 
 
136
  /* Save standard file handles of parent process.  */
 
137
  if (null_stdin)
 
138
    orig_stdin = dup_noinherit (STDIN_FILENO);
 
139
  if (null_stdout)
 
140
    orig_stdout = dup_noinherit (STDOUT_FILENO);
 
141
  if (null_stderr)
 
142
    orig_stderr = dup_noinherit (STDERR_FILENO);
 
143
  exitcode = -1;
 
144
 
 
145
  /* Create standard file handles of child process.  */
 
146
  nullinfd = -1;
 
147
  nulloutfd = -1;
 
148
  if ((!null_stdin
 
149
       || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0
 
150
           && (nullinfd == STDIN_FILENO
 
151
               || (dup2 (nullinfd, STDIN_FILENO) >= 0
 
152
                   && close (nullinfd) >= 0))))
 
153
      && (!(null_stdout || null_stderr)
 
154
          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
 
155
              && (!null_stdout
 
156
                  || nulloutfd == STDOUT_FILENO
 
157
                  || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
 
158
              && (!null_stderr
 
159
                  || nulloutfd == STDERR_FILENO
 
160
                  || dup2 (nulloutfd, STDERR_FILENO) >= 0)
 
161
              && ((null_stdout && nulloutfd == STDOUT_FILENO)
 
162
                  || (null_stderr && nulloutfd == STDERR_FILENO)
 
163
                  || close (nulloutfd) >= 0))))
 
164
    exitcode = spawnvp (P_WAIT, prog_path, prog_argv);
 
165
  if (nulloutfd >= 0)
 
166
    close (nulloutfd);
 
167
  if (nullinfd >= 0)
 
168
    close (nullinfd);
 
169
 
 
170
  /* Restore standard file handles of parent process.  */
 
171
  if (null_stderr)
 
172
    dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
 
173
  if (null_stdout)
 
174
    dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
 
175
  if (null_stdin)
 
176
    dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
 
177
 
 
178
  if (exitcode == -1)
 
179
    {
 
180
      if (exit_on_error || !null_stderr)
 
181
        error (exit_on_error ? EXIT_FAILURE : 0, errno,
 
182
               _("%s subprocess failed"), progname);
 
183
      return 127;
 
184
    }
 
185
 
 
186
  return exitcode;
 
187
 
 
188
#else
 
189
 
 
190
  /* Unix API.  */
 
191
  /* Note about 127: Some errors during posix_spawnp() cause the function
 
192
     posix_spawnp() to return an error code; some other errors cause the
 
193
     subprocess to exit with return code 127.  It is implementation
 
194
     dependent which error is reported which way.  We treat both cases as
 
195
     equivalent.  */
 
196
#if HAVE_POSIX_SPAWN
 
197
  sigset_t blocked_signals;
 
198
  posix_spawn_file_actions_t actions;
 
199
  bool actions_allocated;
 
200
  posix_spawnattr_t attrs;
 
201
  bool attrs_allocated;
 
202
  int err;
 
203
  pid_t child;
 
204
#else
 
205
  int child;
 
206
#endif
 
207
 
 
208
#if HAVE_POSIX_SPAWN
 
209
  if (slave_process)
 
210
    {
 
211
      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
 
212
      block_fatal_signals ();
 
213
    }
 
214
  actions_allocated = false;
 
215
  attrs_allocated = false;
 
216
  if ((err = posix_spawn_file_actions_init (&actions)) != 0
 
217
      || (actions_allocated = true,
 
218
          (null_stdin
 
219
            && (err = posix_spawn_file_actions_addopen (&actions,
 
220
                                                        STDIN_FILENO,
 
221
                                                        "/dev/null", O_RDONLY,
 
222
                                                        0))
 
223
               != 0)
 
224
          || (null_stdout
 
225
              && (err = posix_spawn_file_actions_addopen (&actions,
 
226
                                                          STDOUT_FILENO,
 
227
                                                          "/dev/null", O_RDWR,
 
228
                                                          0))
 
229
                 != 0)
 
230
          || (null_stderr
 
231
              && (err = posix_spawn_file_actions_addopen (&actions,
 
232
                                                          STDERR_FILENO,
 
233
                                                          "/dev/null", O_RDWR,
 
234
                                                          0))
 
235
                 != 0)
 
236
          || (slave_process
 
237
              && ((err = posix_spawnattr_init (&attrs)) != 0
 
238
                  || (attrs_allocated = true,
 
239
                      (err = posix_spawnattr_setsigmask (&attrs,
 
240
                                                         &blocked_signals))
 
241
                      != 0
 
242
                      || (err = posix_spawnattr_setflags (&attrs,
 
243
                                                        POSIX_SPAWN_SETSIGMASK))
 
244
                         != 0)))
 
245
          || (err = posix_spawnp (&child, prog_path, &actions,
 
246
                                  attrs_allocated ? &attrs : NULL, prog_argv,
 
247
                                  environ))
 
248
             != 0))
 
249
    {
 
250
      if (actions_allocated)
 
251
        posix_spawn_file_actions_destroy (&actions);
 
252
      if (attrs_allocated)
 
253
        posix_spawnattr_destroy (&attrs);
 
254
      if (slave_process)
 
255
        unblock_fatal_signals ();
 
256
      if (exit_on_error || !null_stderr)
 
257
        error (exit_on_error ? EXIT_FAILURE : 0, err,
 
258
               _("%s subprocess failed"), progname);
 
259
      return 127;
 
260
    }
 
261
  posix_spawn_file_actions_destroy (&actions);
 
262
  if (attrs_allocated)
 
263
    posix_spawnattr_destroy (&attrs);
 
264
#else
 
265
  if (slave_process)
 
266
    block_fatal_signals ();
 
267
  /* Use vfork() instead of fork() for efficiency.  */
 
268
  if ((child = vfork ()) == 0)
 
269
    {
 
270
      /* Child process code.  */
 
271
      int nullinfd;
 
272
      int nulloutfd;
 
273
 
 
274
      if ((!null_stdin
 
275
           || ((nullinfd = open ("/dev/null", O_RDONLY, 0)) >= 0
 
276
               && (nullinfd == STDIN_FILENO
 
277
                   || (dup2 (nullinfd, STDIN_FILENO) >= 0
 
278
                       && close (nullinfd) >= 0))))
 
279
          && (!(null_stdout || null_stderr)
 
280
              || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
 
281
                  && (!null_stdout
 
282
                      || nulloutfd == STDOUT_FILENO
 
283
                      || dup2 (nulloutfd, STDOUT_FILENO) >= 0)
 
284
                  && (!null_stderr
 
285
                      || nulloutfd == STDERR_FILENO
 
286
                      || dup2 (nulloutfd, STDERR_FILENO) >= 0)
 
287
                  && ((null_stdout && nulloutfd == STDOUT_FILENO)
 
288
                      || (null_stderr && nulloutfd == STDERR_FILENO)
 
289
                      || close (nulloutfd) >= 0)))
 
290
          && (!slave_process || (unblock_fatal_signals (), true)))
 
291
        execvp (prog_path, prog_argv);
 
292
      _exit (127);
 
293
    }
 
294
  if (child == -1)
 
295
    {
 
296
      if (slave_process)
 
297
        unblock_fatal_signals ();
 
298
      if (exit_on_error || !null_stderr)
 
299
        error (exit_on_error ? EXIT_FAILURE : 0, errno,
 
300
               _("%s subprocess failed"), progname);
 
301
      return 127;
 
302
    }
 
303
#endif
 
304
  if (slave_process)
 
305
    {
 
306
      register_slave_subprocess (child);
 
307
      unblock_fatal_signals ();
 
308
    }
 
309
 
 
310
  return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
 
311
                          slave_process, exit_on_error);
 
312
 
 
313
#endif
 
314
}