~ubuntu-branches/ubuntu/precise/wget/precise-proposed

« back to all changes in this revision

Viewing changes to lib/spawn-pipe.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-10-19 00:00:09 UTC
  • mfrom: (2.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20111019000009-8p33w3wz4b1rdri0
Tags: 1.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
* Dropped changes, superseded in Debian:
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.
* Pass --with-ssl=openssl; we don't want to use gnutls, there's no udeb for
  it.
* Add a second build pass for the udeb, so we can build without libidn.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Creation of subprocesses, communicating via pipes.
 
2
   Copyright (C) 2001-2004, 2006-2011 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 3 of the License, or
 
8
   (at your option) 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, see <http://www.gnu.org/licenses/>.  */
 
17
 
 
18
 
 
19
#include <config.h>
 
20
 
 
21
/* Specification.  */
 
22
#include "spawn-pipe.h"
 
23
 
 
24
#include <errno.h>
 
25
#include <fcntl.h>
 
26
#include <stdlib.h>
 
27
#include <signal.h>
 
28
#include <unistd.h>
 
29
 
 
30
#include "error.h"
 
31
#include "fatal-signal.h"
 
32
#include "unistd-safer.h"
 
33
#include "wait-process.h"
 
34
#include "gettext.h"
 
35
 
 
36
#define _(str) gettext (str)
 
37
 
 
38
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
39
 
 
40
/* Native Woe32 API.  */
 
41
# include <process.h>
 
42
# include "w32spawn.h"
 
43
 
 
44
#else
 
45
 
 
46
/* Unix API.  */
 
47
# include <spawn.h>
 
48
 
 
49
#endif
 
50
 
 
51
/* The results of open() in this file are not used with fchdir,
 
52
   therefore save some unnecessary work in fchdir.c.  */
 
53
#undef open
 
54
#undef close
 
55
 
 
56
 
 
57
#ifdef EINTR
 
58
 
 
59
/* EINTR handling for close().
 
60
   These functions can return -1/EINTR even though we don't have any
 
61
   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
 
62
 
 
63
static inline int
 
64
nonintr_close (int fd)
 
65
{
 
66
  int retval;
 
67
 
 
68
  do
 
69
    retval = close (fd);
 
70
  while (retval < 0 && errno == EINTR);
 
71
 
 
72
  return retval;
 
73
}
 
74
#define close nonintr_close
 
75
 
 
76
static inline int
 
77
nonintr_open (const char *pathname, int oflag, mode_t mode)
 
78
{
 
79
  int retval;
 
80
 
 
81
  do
 
82
    retval = open (pathname, oflag, mode);
 
83
  while (retval < 0 && errno == EINTR);
 
84
 
 
85
  return retval;
 
86
}
 
87
#undef open /* avoid warning on VMS */
 
88
#define open nonintr_open
 
89
 
 
90
#endif
 
91
 
 
92
 
 
93
/* Open a pipe connected to a child process.
 
94
 *
 
95
 *           write       system                read
 
96
 *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
 
97
 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
 
98
 *           read        system                write
 
99
 *
 
100
 * At least one of pipe_stdin, pipe_stdout must be true.
 
101
 * pipe_stdin and prog_stdin together determine the child's standard input.
 
102
 * pipe_stdout and prog_stdout together determine the child's standard output.
 
103
 * If pipe_stdin is true, prog_stdin is ignored.
 
104
 * If pipe_stdout is true, prog_stdout is ignored.
 
105
 */
 
106
static pid_t
 
107
create_pipe (const char *progname,
 
108
             const char *prog_path, char **prog_argv,
 
109
             bool pipe_stdin, bool pipe_stdout,
 
110
             const char *prog_stdin, const char *prog_stdout,
 
111
             bool null_stderr,
 
112
             bool slave_process, bool exit_on_error,
 
113
             int fd[2])
 
114
{
 
115
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
116
 
 
117
  /* Native Woe32 API.
 
118
     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
 
119
     using the low-level functions CreatePipe(), DuplicateHandle(),
 
120
     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
 
121
     and cvs source code.  */
 
122
  int ifd[2];
 
123
  int ofd[2];
 
124
  int orig_stdin;
 
125
  int orig_stdout;
 
126
  int orig_stderr;
 
127
  int child;
 
128
  int nulloutfd;
 
129
  int stdinfd;
 
130
  int stdoutfd;
 
131
  int saved_errno;
 
132
 
 
133
  /* FIXME: Need to free memory allocated by prepare_spawn.  */
 
134
  prog_argv = prepare_spawn (prog_argv);
 
135
 
 
136
  if (pipe_stdout)
 
137
    if (pipe2_safer (ifd, O_BINARY | O_CLOEXEC) < 0)
 
138
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
 
139
  if (pipe_stdin)
 
140
    if (pipe2_safer (ofd, O_BINARY | O_CLOEXEC) < 0)
 
141
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
 
142
/* Data flow diagram:
 
143
 *
 
144
 *           write        system         read
 
145
 *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
 
146
 *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
 
147
 *           read         system         write
 
148
 *
 
149
 */
 
150
 
 
151
  /* Save standard file handles of parent process.  */
 
152
  if (pipe_stdin || prog_stdin != NULL)
 
153
    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
 
154
  if (pipe_stdout || prog_stdout != NULL)
 
155
    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
 
156
  if (null_stderr)
 
157
    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
 
158
  child = -1;
 
159
 
 
160
  /* Create standard file handles of child process.  */
 
161
  nulloutfd = -1;
 
162
  stdinfd = -1;
 
163
  stdoutfd = -1;
 
164
  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
 
165
      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
 
166
      && (!null_stderr
 
167
          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
 
168
              && (nulloutfd == STDERR_FILENO
 
169
                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
 
170
                      && close (nulloutfd) >= 0))))
 
171
      && (pipe_stdin
 
172
          || prog_stdin == NULL
 
173
          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
 
174
              && (stdinfd == STDIN_FILENO
 
175
                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
 
176
                      && close (stdinfd) >= 0))))
 
177
      && (pipe_stdout
 
178
          || prog_stdout == NULL
 
179
          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
 
180
              && (stdoutfd == STDOUT_FILENO
 
181
                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
 
182
                      && close (stdoutfd) >= 0)))))
 
183
    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
 
184
       but it inherits all open()ed or dup2()ed file handles (which is what
 
185
       we want in the case of STD*_FILENO).  */
 
186
    /* Use spawnvpe and pass the environment explicitly.  This is needed if
 
187
       the program has modified the environment using putenv() or [un]setenv().
 
188
       On Windows, programs have two environments, one in the "environment
 
189
       block" of the process and managed through SetEnvironmentVariable(), and
 
190
       one inside the process, in the location retrieved by the 'environ'
 
191
       macro.  When using spawnvp() without 'e', the child process inherits a
 
192
       copy of the environment block - ignoring the effects of putenv() and
 
193
       [un]setenv().  */
 
194
    {
 
195
      child = spawnvpe (P_NOWAIT, prog_path, (const char **) prog_argv,
 
196
                        (const char **) environ);
 
197
      if (child < 0 && errno == ENOEXEC)
 
198
        {
 
199
          /* prog is not a native executable.  Try to execute it as a
 
200
             shell script.  Note that prepare_spawn() has already prepended
 
201
             a hidden element "sh.exe" to prog_argv.  */
 
202
          --prog_argv;
 
203
          child = spawnvpe (P_NOWAIT, prog_argv[0], (const char **) prog_argv,
 
204
                            (const char **) environ);
 
205
        }
 
206
    }
 
207
  if (child == -1)
 
208
    saved_errno = errno;
 
209
  if (stdinfd >= 0)
 
210
    close (stdinfd);
 
211
  if (stdoutfd >= 0)
 
212
    close (stdoutfd);
 
213
  if (nulloutfd >= 0)
 
214
    close (nulloutfd);
 
215
 
 
216
  /* Restore standard file handles of parent process.  */
 
217
  if (null_stderr)
 
218
    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
 
219
  if (pipe_stdout || prog_stdout != NULL)
 
220
    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
 
221
  if (pipe_stdin || prog_stdin != NULL)
 
222
    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
 
223
 
 
224
  if (pipe_stdin)
 
225
    close (ofd[0]);
 
226
  if (pipe_stdout)
 
227
    close (ifd[1]);
 
228
  if (child == -1)
 
229
    {
 
230
      if (exit_on_error || !null_stderr)
 
231
        error (exit_on_error ? EXIT_FAILURE : 0, saved_errno,
 
232
               _("%s subprocess failed"), progname);
 
233
      if (pipe_stdout)
 
234
        close (ifd[0]);
 
235
      if (pipe_stdin)
 
236
        close (ofd[1]);
 
237
      errno = saved_errno;
 
238
      return -1;
 
239
    }
 
240
 
 
241
  if (pipe_stdout)
 
242
    fd[0] = ifd[0];
 
243
  if (pipe_stdin)
 
244
    fd[1] = ofd[1];
 
245
  return child;
 
246
 
 
247
#else
 
248
 
 
249
  /* Unix API.  */
 
250
  int ifd[2];
 
251
  int ofd[2];
 
252
  sigset_t blocked_signals;
 
253
  posix_spawn_file_actions_t actions;
 
254
  bool actions_allocated;
 
255
  posix_spawnattr_t attrs;
 
256
  bool attrs_allocated;
 
257
  int err;
 
258
  pid_t child;
 
259
 
 
260
  if (pipe_stdout)
 
261
    if (pipe_safer (ifd) < 0)
 
262
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
 
263
  if (pipe_stdin)
 
264
    if (pipe_safer (ofd) < 0)
 
265
      error (EXIT_FAILURE, errno, _("cannot create pipe"));
 
266
/* Data flow diagram:
 
267
 *
 
268
 *           write        system         read
 
269
 *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
 
270
 *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
 
271
 *           read         system         write
 
272
 *
 
273
 */
 
274
 
 
275
  if (slave_process)
 
276
    {
 
277
      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
 
278
      block_fatal_signals ();
 
279
    }
 
280
  actions_allocated = false;
 
281
  attrs_allocated = false;
 
282
  if ((err = posix_spawn_file_actions_init (&actions)) != 0
 
283
      || (actions_allocated = true,
 
284
          (pipe_stdin
 
285
           && (err = posix_spawn_file_actions_adddup2 (&actions,
 
286
                                                       ofd[0], STDIN_FILENO))
 
287
              != 0)
 
288
          || (pipe_stdout
 
289
              && (err = posix_spawn_file_actions_adddup2 (&actions,
 
290
                                                          ifd[1], STDOUT_FILENO))
 
291
                 != 0)
 
292
          || (pipe_stdin
 
293
              && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
 
294
                 != 0)
 
295
          || (pipe_stdout
 
296
              && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
 
297
                 != 0)
 
298
          || (pipe_stdin
 
299
              && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
 
300
                 != 0)
 
301
          || (pipe_stdout
 
302
              && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
 
303
                 != 0)
 
304
          || (null_stderr
 
305
              && (err = posix_spawn_file_actions_addopen (&actions,
 
306
                                                          STDERR_FILENO,
 
307
                                                          "/dev/null", O_RDWR,
 
308
                                                          0))
 
309
                 != 0)
 
310
          || (!pipe_stdin
 
311
              && prog_stdin != NULL
 
312
              && (err = posix_spawn_file_actions_addopen (&actions,
 
313
                                                          STDIN_FILENO,
 
314
                                                          prog_stdin, O_RDONLY,
 
315
                                                          0))
 
316
                 != 0)
 
317
          || (!pipe_stdout
 
318
              && prog_stdout != NULL
 
319
              && (err = posix_spawn_file_actions_addopen (&actions,
 
320
                                                          STDOUT_FILENO,
 
321
                                                          prog_stdout, O_WRONLY,
 
322
                                                          0))
 
323
                 != 0)
 
324
          || (slave_process
 
325
              && ((err = posix_spawnattr_init (&attrs)) != 0
 
326
                  || (attrs_allocated = true,
 
327
                      (err = posix_spawnattr_setsigmask (&attrs,
 
328
                                                         &blocked_signals))
 
329
                      != 0
 
330
                      || (err = posix_spawnattr_setflags (&attrs,
 
331
                                                        POSIX_SPAWN_SETSIGMASK))
 
332
                         != 0)))
 
333
          || (err = posix_spawnp (&child, prog_path, &actions,
 
334
                                  attrs_allocated ? &attrs : NULL, prog_argv,
 
335
                                  environ))
 
336
             != 0))
 
337
    {
 
338
      if (actions_allocated)
 
339
        posix_spawn_file_actions_destroy (&actions);
 
340
      if (attrs_allocated)
 
341
        posix_spawnattr_destroy (&attrs);
 
342
      if (slave_process)
 
343
        unblock_fatal_signals ();
 
344
      if (exit_on_error || !null_stderr)
 
345
        error (exit_on_error ? EXIT_FAILURE : 0, err,
 
346
               _("%s subprocess failed"), progname);
 
347
      if (pipe_stdout)
 
348
        {
 
349
          close (ifd[0]);
 
350
          close (ifd[1]);
 
351
        }
 
352
      if (pipe_stdin)
 
353
        {
 
354
          close (ofd[0]);
 
355
          close (ofd[1]);
 
356
        }
 
357
      errno = err;
 
358
      return -1;
 
359
    }
 
360
  posix_spawn_file_actions_destroy (&actions);
 
361
  if (attrs_allocated)
 
362
    posix_spawnattr_destroy (&attrs);
 
363
  if (slave_process)
 
364
    {
 
365
      register_slave_subprocess (child);
 
366
      unblock_fatal_signals ();
 
367
    }
 
368
  if (pipe_stdin)
 
369
    close (ofd[0]);
 
370
  if (pipe_stdout)
 
371
    close (ifd[1]);
 
372
 
 
373
  if (pipe_stdout)
 
374
    fd[0] = ifd[0];
 
375
  if (pipe_stdin)
 
376
    fd[1] = ofd[1];
 
377
  return child;
 
378
 
 
379
#endif
 
380
}
 
381
 
 
382
/* Open a bidirectional pipe.
 
383
 *
 
384
 *           write       system                read
 
385
 *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
 
386
 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
 
387
 *           read        system                write
 
388
 *
 
389
 */
 
390
pid_t
 
391
create_pipe_bidi (const char *progname,
 
392
                  const char *prog_path, char **prog_argv,
 
393
                  bool null_stderr,
 
394
                  bool slave_process, bool exit_on_error,
 
395
                  int fd[2])
 
396
{
 
397
  pid_t result = create_pipe (progname, prog_path, prog_argv,
 
398
                              true, true, NULL, NULL,
 
399
                              null_stderr, slave_process, exit_on_error,
 
400
                              fd);
 
401
  return result;
 
402
}
 
403
 
 
404
/* Open a pipe for input from a child process.
 
405
 * The child's stdin comes from a file.
 
406
 *
 
407
 *           read        system                write
 
408
 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
 
409
 *
 
410
 */
 
411
pid_t
 
412
create_pipe_in (const char *progname,
 
413
                const char *prog_path, char **prog_argv,
 
414
                const char *prog_stdin, bool null_stderr,
 
415
                bool slave_process, bool exit_on_error,
 
416
                int fd[1])
 
417
{
 
418
  int iofd[2];
 
419
  pid_t result = create_pipe (progname, prog_path, prog_argv,
 
420
                              false, true, prog_stdin, NULL,
 
421
                              null_stderr, slave_process, exit_on_error,
 
422
                              iofd);
 
423
  if (result != -1)
 
424
    fd[0] = iofd[0];
 
425
  return result;
 
426
}
 
427
 
 
428
/* Open a pipe for output to a child process.
 
429
 * The child's stdout goes to a file.
 
430
 *
 
431
 *           write       system                read
 
432
 *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
 
433
 *
 
434
 */
 
435
pid_t
 
436
create_pipe_out (const char *progname,
 
437
                 const char *prog_path, char **prog_argv,
 
438
                 const char *prog_stdout, bool null_stderr,
 
439
                 bool slave_process, bool exit_on_error,
 
440
                 int fd[1])
 
441
{
 
442
  int iofd[2];
 
443
  pid_t result = create_pipe (progname, prog_path, prog_argv,
 
444
                              true, false, NULL, prog_stdout,
 
445
                              null_stderr, slave_process, exit_on_error,
 
446
                              iofd);
 
447
  if (result != -1)
 
448
    fd[0] = iofd[1];
 
449
  return result;
 
450
}