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