• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/
1/* Creation of subprocesses, communicating via pipes.
2   Copyright (C) 2001-2004, 2006-2007 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 "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 "wait-process.h"
33#include "gettext.h"
34
35#define _(str) gettext (str)
36
37#if defined _MSC_VER || defined __MINGW32__
38
39/* Native Woe32 API.  */
40# include <process.h>
41# include "w32spawn.h"
42
43#else
44
45/* Unix API.  */
46# if HAVE_POSIX_SPAWN
47#  include <spawn.h>
48# else
49#  if HAVE_VFORK_H
50#   include <vfork.h>
51#  endif
52# endif
53
54#endif
55
56#if ! HAVE_ENVIRON_DECL
57extern char **environ;
58#endif
59
60#ifndef STDIN_FILENO
61# define STDIN_FILENO 0
62#endif
63#ifndef STDOUT_FILENO
64# define STDOUT_FILENO 1
65#endif
66#ifndef STDERR_FILENO
67# define STDERR_FILENO 2
68#endif
69
70/* The results of open() in this file are not used with fchdir,
71   therefore save some unnecessary work in fchdir.c.  */
72#undef open
73#undef close
74
75
76#ifdef EINTR
77
78/* EINTR handling for close().
79   These functions can return -1/EINTR even though we don't have any
80   signal handlers set up, namely when we get interrupted via SIGSTOP.  */
81
82static inline int
83nonintr_close (int fd)
84{
85  int retval;
86
87  do
88    retval = close (fd);
89  while (retval < 0 && errno == EINTR);
90
91  return retval;
92}
93#define close nonintr_close
94
95static inline int
96nonintr_open (const char *pathname, int oflag, mode_t mode)
97{
98  int retval;
99
100  do
101    retval = open (pathname, oflag, mode);
102  while (retval < 0 && errno == EINTR);
103
104  return retval;
105}
106#undef open /* avoid warning on VMS */
107#define open nonintr_open
108
109#endif
110
111
112/* Open a pipe connected to a child process.
113 *
114 *           write       system                read
115 *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child       if pipe_stdin
116 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child       if pipe_stdout
117 *           read        system                write
118 *
119 * At least one of pipe_stdin, pipe_stdout must be true.
120 * pipe_stdin and prog_stdin together determine the child's standard input.
121 * pipe_stdout and prog_stdout together determine the child's standard output.
122 * If pipe_stdin is true, prog_stdin is ignored.
123 * If pipe_stdout is true, prog_stdout is ignored.
124 */
125static pid_t
126create_pipe (const char *progname,
127	     const char *prog_path, char **prog_argv,
128	     bool pipe_stdin, bool pipe_stdout,
129	     const char *prog_stdin, const char *prog_stdout,
130	     bool null_stderr,
131	     bool slave_process, bool exit_on_error,
132	     int fd[2])
133{
134#if defined _MSC_VER || defined __MINGW32__
135
136  /* Native Woe32 API.
137     This uses _pipe(), dup2(), and spawnv().  It could also be implemented
138     using the low-level functions CreatePipe(), DuplicateHandle(),
139     CreateProcess() and _open_osfhandle(); see the GNU make and GNU clisp
140     and cvs source code.  */
141  int ifd[2];
142  int ofd[2];
143  int orig_stdin;
144  int orig_stdout;
145  int orig_stderr;
146  int child;
147  int nulloutfd;
148  int stdinfd;
149  int stdoutfd;
150
151  prog_argv = prepare_spawn (prog_argv);
152
153  if (pipe_stdout)
154    if (_pipe (ifd, 4096, O_BINARY | O_NOINHERIT) < 0)
155      error (EXIT_FAILURE, errno, _("cannot create pipe"));
156  if (pipe_stdin)
157    if (_pipe (ofd, 4096, O_BINARY | O_NOINHERIT) < 0)
158      error (EXIT_FAILURE, errno, _("cannot create pipe"));
159/* Data flow diagram:
160 *
161 *           write        system         read
162 *    parent  ->   ofd[1]   ->   ofd[0]   ->   child       if pipe_stdin
163 *    parent  <-   ifd[0]   <-   ifd[1]   <-   child       if pipe_stdout
164 *           read         system         write
165 *
166 */
167
168  /* Save standard file handles of parent process.  */
169  if (pipe_stdin || prog_stdin != NULL)
170    orig_stdin = dup_noinherit (STDIN_FILENO);
171  if (pipe_stdout || prog_stdout != NULL)
172    orig_stdout = dup_noinherit (STDOUT_FILENO);
173  if (null_stderr)
174    orig_stderr = dup_noinherit (STDERR_FILENO);
175  child = -1;
176
177  /* Create standard file handles of child process.  */
178  nulloutfd = -1;
179  stdinfd = -1;
180  stdoutfd = -1;
181  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
182      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
183      && (!null_stderr
184	  || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
185	      && (nulloutfd == STDERR_FILENO
186		  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
187		      && close (nulloutfd) >= 0))))
188      && (pipe_stdin
189	  || prog_stdin == NULL
190	  || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
191	      && (stdinfd == STDIN_FILENO
192		  || (dup2 (stdinfd, STDIN_FILENO) >= 0
193		      && close (stdinfd) >= 0))))
194      && (pipe_stdout
195	  || prog_stdout == NULL
196	  || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
197	      && (stdoutfd == STDOUT_FILENO
198		  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
199		      && close (stdoutfd) >= 0)))))
200    /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
201       but it inherits all open()ed or dup2()ed file handles (which is what
202       we want in the case of STD*_FILENO) and also orig_stdin,
203       orig_stdout, orig_stderr (which is not explicitly wanted but
204       harmless).  */
205    child = spawnvp (P_NOWAIT, prog_path, prog_argv);
206  if (stdinfd >= 0)
207    close (stdinfd);
208  if (stdoutfd >= 0)
209    close (stdoutfd);
210  if (nulloutfd >= 0)
211    close (nulloutfd);
212
213  /* Restore standard file handles of parent process.  */
214  if (null_stderr)
215    dup2 (orig_stderr, STDERR_FILENO), close (orig_stderr);
216  if (pipe_stdout || prog_stdout != NULL)
217    dup2 (orig_stdout, STDOUT_FILENO), close (orig_stdout);
218  if (pipe_stdin || prog_stdin != NULL)
219    dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin);
220
221  if (pipe_stdin)
222    close (ofd[0]);
223  if (pipe_stdout)
224    close (ifd[1]);
225  if (child == -1)
226    {
227      if (exit_on_error || !null_stderr)
228	error (exit_on_error ? EXIT_FAILURE : 0, errno,
229	       _("%s subprocess failed"), progname);
230      if (pipe_stdout)
231	close (ifd[0]);
232      if (pipe_stdin)
233	close (ofd[1]);
234      return -1;
235    }
236
237  if (pipe_stdout)
238    fd[0] = ifd[0];
239  if (pipe_stdin)
240    fd[1] = ofd[1];
241  return child;
242
243#else
244
245  /* Unix API.  */
246  int ifd[2];
247  int ofd[2];
248# if HAVE_POSIX_SPAWN
249  sigset_t blocked_signals;
250  posix_spawn_file_actions_t actions;
251  bool actions_allocated;
252  posix_spawnattr_t attrs;
253  bool attrs_allocated;
254  int err;
255  pid_t child;
256# else
257  int child;
258# endif
259
260  if (pipe_stdout)
261    if (pipe (ifd) < 0)
262      error (EXIT_FAILURE, errno, _("cannot create pipe"));
263  if (pipe_stdin)
264    if (pipe (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 HAVE_POSIX_SPAWN
276  if (slave_process)
277    {
278      sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
279      block_fatal_signals ();
280    }
281  actions_allocated = false;
282  attrs_allocated = false;
283  if ((err = posix_spawn_file_actions_init (&actions)) != 0
284      || (actions_allocated = true,
285	  (pipe_stdin
286	   && (err = posix_spawn_file_actions_adddup2 (&actions,
287						       ofd[0], STDIN_FILENO))
288	      != 0)
289	  || (pipe_stdout
290	      && (err = posix_spawn_file_actions_adddup2 (&actions,
291							  ifd[1], STDOUT_FILENO))
292		 != 0)
293	  || (pipe_stdin
294	      && (err = posix_spawn_file_actions_addclose (&actions, ofd[0]))
295		 != 0)
296	  || (pipe_stdout
297	      && (err = posix_spawn_file_actions_addclose (&actions, ifd[1]))
298		 != 0)
299	  || (pipe_stdin
300	      && (err = posix_spawn_file_actions_addclose (&actions, ofd[1]))
301		 != 0)
302	  || (pipe_stdout
303	      && (err = posix_spawn_file_actions_addclose (&actions, ifd[0]))
304		 != 0)
305	  || (null_stderr
306	      && (err = posix_spawn_file_actions_addopen (&actions,
307							  STDERR_FILENO,
308							  "/dev/null", O_RDWR,
309							  0))
310		 != 0)
311	  || (!pipe_stdin
312	      && prog_stdin != NULL
313	      && (err = posix_spawn_file_actions_addopen (&actions,
314							  STDIN_FILENO,
315							  prog_stdin, O_RDONLY,
316							  0))
317		 != 0)
318	  || (!pipe_stdout
319	      && prog_stdout != NULL
320	      && (err = posix_spawn_file_actions_addopen (&actions,
321							  STDOUT_FILENO,
322							  prog_stdout, O_WRONLY,
323							  0))
324		 != 0)
325	  || (slave_process
326	      && ((err = posix_spawnattr_init (&attrs)) != 0
327		  || (attrs_allocated = true,
328		      (err = posix_spawnattr_setsigmask (&attrs,
329							 &blocked_signals))
330		      != 0
331		      || (err = posix_spawnattr_setflags (&attrs,
332							POSIX_SPAWN_SETSIGMASK))
333			 != 0)))
334	  || (err = posix_spawnp (&child, prog_path, &actions,
335				  attrs_allocated ? &attrs : NULL, prog_argv,
336				  environ))
337	     != 0))
338    {
339      if (actions_allocated)
340	posix_spawn_file_actions_destroy (&actions);
341      if (attrs_allocated)
342	posix_spawnattr_destroy (&attrs);
343      if (slave_process)
344	unblock_fatal_signals ();
345      if (exit_on_error || !null_stderr)
346	error (exit_on_error ? EXIT_FAILURE : 0, err,
347	       _("%s subprocess failed"), progname);
348      if (pipe_stdout)
349	{
350	  close (ifd[0]);
351	  close (ifd[1]);
352	}
353      if (pipe_stdin)
354	{
355	  close (ofd[0]);
356	  close (ofd[1]);
357	}
358      return -1;
359    }
360  posix_spawn_file_actions_destroy (&actions);
361  if (attrs_allocated)
362    posix_spawnattr_destroy (&attrs);
363# else
364  if (slave_process)
365    block_fatal_signals ();
366  /* Use vfork() instead of fork() for efficiency.  */
367  if ((child = vfork ()) == 0)
368    {
369      /* Child process code.  */
370      int nulloutfd;
371      int stdinfd;
372      int stdoutfd;
373
374      if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
375	  && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
376	  && (!pipe_stdin || close (ofd[0]) >= 0)
377	  && (!pipe_stdout || close (ifd[1]) >= 0)
378	  && (!pipe_stdin || close (ofd[1]) >= 0)
379	  && (!pipe_stdout || close (ifd[0]) >= 0)
380	  && (!null_stderr
381	      || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
382		  && (nulloutfd == STDERR_FILENO
383		      || (dup2 (nulloutfd, STDERR_FILENO) >= 0
384			  && close (nulloutfd) >= 0))))
385	  && (pipe_stdin
386	      || prog_stdin == NULL
387	      || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
388		  && (stdinfd == STDIN_FILENO
389		      || (dup2 (stdinfd, STDIN_FILENO) >= 0
390			  && close (stdinfd) >= 0))))
391	  && (pipe_stdout
392	      || prog_stdout == NULL
393	      || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
394		  && (stdoutfd == STDOUT_FILENO
395		      || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
396			  && close (stdoutfd) >= 0))))
397	  && (!slave_process || (unblock_fatal_signals (), true)))
398	execvp (prog_path, prog_argv);
399      _exit (127);
400    }
401  if (child == -1)
402    {
403      if (slave_process)
404	unblock_fatal_signals ();
405      if (exit_on_error || !null_stderr)
406	error (exit_on_error ? EXIT_FAILURE : 0, errno,
407	       _("%s subprocess failed"), progname);
408      if (pipe_stdout)
409	{
410	  close (ifd[0]);
411	  close (ifd[1]);
412	}
413      if (pipe_stdin)
414	{
415	  close (ofd[0]);
416	  close (ofd[1]);
417	}
418      return -1;
419    }
420# endif
421  if (slave_process)
422    {
423      register_slave_subprocess (child);
424      unblock_fatal_signals ();
425    }
426  if (pipe_stdin)
427    close (ofd[0]);
428  if (pipe_stdout)
429    close (ifd[1]);
430
431  if (pipe_stdout)
432    fd[0] = ifd[0];
433  if (pipe_stdin)
434    fd[1] = ofd[1];
435  return child;
436
437#endif
438}
439
440/* Open a bidirectional pipe.
441 *
442 *           write       system                read
443 *    parent  ->   fd[1]   ->   STDIN_FILENO    ->   child
444 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
445 *           read        system                write
446 *
447 */
448pid_t
449create_pipe_bidi (const char *progname,
450		  const char *prog_path, char **prog_argv,
451		  bool null_stderr,
452		  bool slave_process, bool exit_on_error,
453		  int fd[2])
454{
455  pid_t result = create_pipe (progname, prog_path, prog_argv,
456			      true, true, NULL, NULL,
457			      null_stderr, slave_process, exit_on_error,
458			      fd);
459  return result;
460}
461
462/* Open a pipe for input from a child process.
463 * The child's stdin comes from a file.
464 *
465 *           read        system                write
466 *    parent  <-   fd[0]   <-   STDOUT_FILENO   <-   child
467 *
468 */
469pid_t
470create_pipe_in (const char *progname,
471		const char *prog_path, char **prog_argv,
472		const char *prog_stdin, bool null_stderr,
473		bool slave_process, bool exit_on_error,
474		int fd[1])
475{
476  int iofd[2];
477  pid_t result = create_pipe (progname, prog_path, prog_argv,
478			      false, true, prog_stdin, NULL,
479			      null_stderr, slave_process, exit_on_error,
480			      iofd);
481  if (result != -1)
482    fd[0] = iofd[0];
483  return result;
484}
485
486/* Open a pipe for output to a child process.
487 * The child's stdout goes to a file.
488 *
489 *           write       system                read
490 *    parent  ->   fd[0]   ->   STDIN_FILENO    ->   child
491 *
492 */
493pid_t
494create_pipe_out (const char *progname,
495		 const char *prog_path, char **prog_argv,
496		 const char *prog_stdout, bool null_stderr,
497		 bool slave_process, bool exit_on_error,
498		 int fd[1])
499{
500  int iofd[2];
501  pid_t result = create_pipe (progname, prog_path, prog_argv,
502			      true, false, NULL, prog_stdout,
503			      null_stderr, slave_process, exit_on_error,
504			      iofd);
505  if (result != -1)
506    fd[0] = iofd[1];
507  return result;
508}
509