| 55 | } |
| 56 | |
| 57 | int read_command_output_through_clone(std::ostream& os, const char* cmd) { |
| 58 | int pipe_fd[2]; |
| 59 | if (pipe(pipe_fd) != 0) { |
| 60 | PLOG(ERROR) << "Fail to pipe"; |
| 61 | return -1; |
| 62 | } |
| 63 | int saved_errno = 0; |
| 64 | int wstatus = 0; |
| 65 | pid_t cpid; |
| 66 | int rc = 0; |
| 67 | ChildArgs args = { cmd, pipe_fd[0], pipe_fd[1] }; |
| 68 | char buffer[1024]; |
| 69 | |
| 70 | char* child_stack = NULL; |
| 71 | char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE); |
| 72 | if (!child_stack_mem) { |
| 73 | LOG(ERROR) << "Fail to alloc stack for the child process"; |
| 74 | rc = -1; |
| 75 | goto END; |
| 76 | } |
| 77 | child_stack = child_stack_mem + CHILD_STACK_SIZE; |
| 78 | // ^ Assume stack grows downward |
| 79 | cpid = clone(launch_child_process, child_stack, |
| 80 | __WCLONE | CLONE_VM | SIGCHLD | CLONE_UNTRACED, &args); |
| 81 | if (cpid < 0) { |
| 82 | PLOG(ERROR) << "Fail to clone child process"; |
| 83 | rc = -1; |
| 84 | goto END; |
| 85 | } |
| 86 | close(pipe_fd[1]); |
| 87 | pipe_fd[1] = -1; |
| 88 | |
| 89 | for (;;) { |
| 90 | const ssize_t nr = read(pipe_fd[0], buffer, sizeof(buffer)); |
| 91 | if (nr > 0) { |
| 92 | os.write(buffer, nr); |
| 93 | continue; |
| 94 | } else if (nr == 0) { |
| 95 | break; |
| 96 | } else if (errno != EINTR) { |
| 97 | LOG(ERROR) << "Encountered error while reading for the pipe"; |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | close(pipe_fd[0]); |
| 103 | pipe_fd[0] = -1; |
| 104 | |
| 105 | for (;;) { |
| 106 | pid_t wpid = waitpid(cpid, &wstatus, WNOHANG | __WALL); |
| 107 | if (wpid > 0) { |
| 108 | break; |
| 109 | } |
| 110 | if (wpid == 0) { |
| 111 | if (bthread_usleep != NULL) { |
| 112 | bthread_usleep(1000); |
| 113 | } else { |
| 114 | usleep(1000); |