@@ -541,40 +541,119 @@ int run(
541
541
542
542
return result;
543
543
#else
544
- std::string command;
544
+ int pipefd[2 ];
545
+ if (pipe (pipefd) == -1 )
546
+ return -1 ;
547
+
548
+ int stdin_fd = stdio_redirection (STDIN_FILENO, std_input);
549
+ int stdout_fd = pipefd[1 ];
550
+ int stderr_fd = stdio_redirection (STDERR_FILENO, std_error);
545
551
546
- bool first = true ;
552
+ if (stdin_fd == -1 || stdout_fd == -1 || stderr_fd == -1 )
553
+ return 1 ;
554
+
555
+ // temporarily suspend all signals
556
+ sigset_t new_mask, old_mask;
557
+ sigemptyset (&new_mask);
558
+ sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
547
559
548
- // note we use 'what' instead of 'argv[0]' as the name of the executable
549
- for (const auto &arg : argv)
560
+ /* now create new process */
561
+ pid_t childpid = fork ();
562
+
563
+ if (childpid >= 0 ) /* fork succeeded */
550
564
{
551
- if (first ) // this is argv[0]
565
+ if (childpid == 0 ) /* fork() returns 0 to the child process */
552
566
{
553
- command += shell_quote (what);
554
- first = false ;
567
+ // resume signals
568
+ remove_signal_catcher ();
569
+ sigprocmask (SIG_SETMASK, &old_mask, nullptr );
570
+
571
+ close (pipefd[0 ]); // unused in child
572
+
573
+ std::vector<char *> _argv (argv.size () + 1 );
574
+ for (std::size_t i = 0 ; i < argv.size (); i++)
575
+ _argv[i] = strdup (argv[i].c_str ());
576
+
577
+ _argv[argv.size ()] = nullptr ;
578
+
579
+ if (stdin_fd != STDIN_FILENO)
580
+ dup2 (stdin_fd, STDIN_FILENO);
581
+ if (stdout_fd != STDOUT_FILENO)
582
+ dup2 (stdout_fd, STDOUT_FILENO);
583
+ if (stderr_fd != STDERR_FILENO)
584
+ dup2 (stderr_fd, STDERR_FILENO);
585
+
586
+ errno = 0 ;
587
+ execvp (what.c_str (), _argv.data ());
588
+
589
+ /* usually no return */
590
+ perror (std::string (" execvp " + what + " failed" ).c_str ());
591
+ exit (1 );
555
592
}
556
- else
557
- command += " " + shell_quote (arg);
558
- }
593
+ else /* fork() returns new pid to the parent process */
594
+ {
595
+ // must do before resuming signals to avoid race
596
+ register_child (childpid);
559
597
560
- if (!std_input. empty ())
561
- command += " < " + shell_quote (std_input );
598
+ // resume signals
599
+ sigprocmask (SIG_SETMASK, &old_mask, nullptr );
562
600
563
- if (!std_error.empty ())
564
- command += " 2> " + shell_quote (std_error);
601
+ close (pipefd[1 ]); // unused in the parent
602
+
603
+ const int buffer_size = 1024 ;
604
+ std::vector<char > buffer (buffer_size);
605
+ ssize_t bytes_read;
565
606
566
- FILE *stream=popen (command.c_str (), " r" );
607
+ while ((bytes_read = read (pipefd[0 ], buffer.data (), buffer_size)) > 0 )
608
+ std_output.write (buffer.data (), bytes_read);
567
609
568
- if (stream!=nullptr )
610
+ int status; /* parent process: child's exit status */
611
+
612
+ /* wait for child to exit, and store its status */
613
+ while (waitpid (childpid, &status, 0 ) == -1 )
614
+ {
615
+ if (errno == EINTR)
616
+ continue ; // try again
617
+ else
618
+ {
619
+ unregister_child ();
620
+
621
+ perror (" Waiting for child process failed" );
622
+ if (stdin_fd != STDIN_FILENO)
623
+ close (stdin_fd);
624
+ if (stdout_fd != STDOUT_FILENO)
625
+ close (stdout_fd);
626
+ if (stderr_fd != STDERR_FILENO)
627
+ close (stderr_fd);
628
+ return 1 ;
629
+ }
630
+ }
631
+
632
+ unregister_child ();
633
+
634
+ if (stdin_fd != STDIN_FILENO)
635
+ close (stdin_fd);
636
+ if (stdout_fd != STDOUT_FILENO)
637
+ close (stdout_fd);
638
+ if (stderr_fd != STDERR_FILENO)
639
+ close (stderr_fd);
640
+
641
+ return WEXITSTATUS (status);
642
+ }
643
+ }
644
+ else /* fork returns -1 on failure */
569
645
{
570
- int ch;
571
- while ((ch=fgetc (stream))!=EOF)
572
- std_output << (unsigned char )ch;
646
+ // resume signals
647
+ sigprocmask (SIG_SETMASK, &old_mask, nullptr );
573
648
574
- int result = pclose (stream);
575
- return WEXITSTATUS (result);
649
+ if (stdin_fd != STDIN_FILENO)
650
+ close (stdin_fd);
651
+ if (stdout_fd != STDOUT_FILENO)
652
+ close (stdout_fd);
653
+ if (stderr_fd != STDERR_FILENO)
654
+ close (stderr_fd);
655
+
656
+ return 1 ;
576
657
}
577
- else
578
- return -1 ;
579
- #endif
658
+ #endif
580
659
}
0 commit comments