444 |
|
|
445 |
|
|
446 |
|
|
447 |
|
/* Work around an OpenSSH problem: it can put its standard file |
448 |
|
descriptors into nonblocking mode, which will mess us up if we |
449 |
|
share file descriptions with it. The simplest workaround is |
450 |
|
to create an intervening process between OpenSSH and the |
451 |
|
actual stderr. */ |
452 |
|
|
453 |
|
static void |
454 |
|
work_around_openssh_glitch (void) |
455 |
|
{ |
456 |
|
pid_t pid; |
457 |
|
int stderr_pipe[2]; |
458 |
|
struct stat sb; |
459 |
|
|
460 |
|
/* Do nothing unless stderr is a file that is affected by |
461 |
|
nonblocking mode. */ |
462 |
|
if (!(fstat (STDERR_FILENO, &sb) == 0 |
463 |
|
&& (S_ISFIFO (sb.st_mode) || S_ISSOCK (sb.st_mode) |
464 |
|
|| S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode)))) |
465 |
|
return; |
466 |
|
|
467 |
|
if (pipe (stderr_pipe) < 0) |
468 |
|
error (1, errno, "cannot create pipe"); |
469 |
|
pid = fork (); |
470 |
|
if (pid < 0) |
471 |
|
error (1, errno, "cannot fork"); |
472 |
|
if (pid != 0) |
473 |
|
{ |
474 |
|
/* Still in child of original process. Act like "cat -u". */ |
475 |
|
char buf[1 << 13]; |
476 |
|
ssize_t inbytes; |
477 |
|
pid_t w; |
478 |
|
int status; |
479 |
|
|
480 |
|
if (close (stderr_pipe[1]) < 0) |
481 |
|
error (1, errno, "cannot close pipe"); |
482 |
|
|
483 |
|
while ((inbytes = read (stderr_pipe[0], buf, sizeof buf)) != 0) |
484 |
|
{ |
485 |
|
size_t outbytes = 0; |
486 |
|
|
487 |
|
if (inbytes < 0) |
488 |
|
{ |
489 |
|
if (errno == EINTR) |
490 |
|
continue; |
491 |
|
error (1, errno, "reading from pipe"); |
492 |
|
} |
493 |
|
|
494 |
|
do |
495 |
|
{ |
496 |
|
ssize_t w = write (STDERR_FILENO, |
497 |
|
buf + outbytes, inbytes - outbytes); |
498 |
|
if (w < 0) |
499 |
|
{ |
500 |
|
if (errno == EINTR) |
501 |
|
w = 0; |
502 |
|
if (w < 0) |
503 |
|
_exit (1); |
504 |
|
} |
505 |
|
outbytes += w; |
506 |
|
} |
507 |
|
while (inbytes != outbytes); |
508 |
|
} |
509 |
|
|
510 |
|
/* Done processing output from grandchild. Propagate |
511 |
|
its exit status back to the parent. */ |
512 |
|
while ((w = waitpid (pid, &status, 0)) == -1 && errno == EINTR) |
513 |
|
continue; |
514 |
|
if (w < 0) |
515 |
|
error (1, errno, "waiting for child"); |
516 |
|
if (!WIFEXITED (status)) |
517 |
|
{ |
518 |
|
if (WIFSIGNALED (status)) |
519 |
|
raise (WTERMSIG (status)); |
520 |
|
error (1, errno, "child did not exit cleanly"); |
521 |
|
} |
522 |
|
_exit (WEXITSTATUS (status)); |
523 |
|
} |
524 |
|
|
525 |
|
/* Grandchild of original process. */ |
526 |
|
if (close (stderr_pipe[0]) < 0) |
527 |
|
error (1, errno, "cannot close pipe"); |
528 |
|
|
529 |
|
if (stderr_pipe[1] != STDERR_FILENO) |
530 |
|
{ |
531 |
|
if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) |
532 |
|
error (1, errno, "cannot dup2 pipe"); |
533 |
|
if (close (stderr_pipe[1]) < 0) |
534 |
|
error (1, errno, "cannot close pipe"); |
535 |
|
} |
536 |
|
} |
537 |
|
|
538 |
|
|
539 |
|
|
540 |
int |
int |
541 |
piped_child (char *const *command, int *tofdp, int *fromfdp) |
piped_child (char *const *command, int *tofdp, int *fromfdp, bool fix_stderr) |
542 |
{ |
{ |
543 |
int pid; |
int pid; |
544 |
int to_child_pipe[2]; |
int to_child_pipe[2]; |
556 |
setmode (from_child_pipe[1], O_BINARY); |
setmode (from_child_pipe[1], O_BINARY); |
557 |
#endif |
#endif |
558 |
|
|
|
#ifdef HAVE_VFORK |
|
|
pid = vfork (); |
|
|
#else |
|
559 |
pid = fork (); |
pid = fork (); |
|
#endif |
|
560 |
if (pid < 0) |
if (pid < 0) |
561 |
error (1, errno, "cannot fork"); |
error (1, errno, "cannot fork"); |
562 |
if (pid == 0) |
if (pid == 0) |
570 |
if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) |
if (dup2 (from_child_pipe[1], STDOUT_FILENO) < 0) |
571 |
error (1, errno, "cannot dup2 pipe"); |
error (1, errno, "cannot dup2 pipe"); |
572 |
|
|
573 |
/* Okay to cast out const below - execvp don't return anyhow. */ |
if (fix_stderr) |
574 |
|
work_around_openssh_glitch (); |
575 |
|
|
576 |
|
/* Okay to cast out const below - execvp don't return nohow. */ |
577 |
execvp ((char *)command[0], (char **)command); |
execvp ((char *)command[0], (char **)command); |
578 |
error (1, errno, "cannot exec %s", command[0]); |
error (1, errno, "cannot exec %s", command[0]); |
579 |
} |
} |
593 |
run_piped (int *tofdp, int *fromfdp) |
run_piped (int *tofdp, int *fromfdp) |
594 |
{ |
{ |
595 |
run_add_arg (NULL); |
run_add_arg (NULL); |
596 |
return piped_child (run_argv, tofdp, fromfdp); |
return piped_child (run_argv, tofdp, fromfdp, false); |
597 |
} |
} |
598 |
|
|
599 |
|
|