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