| 136 | }; |
| 137 | |
| 138 | int SubProcess::spawn() { |
| 139 | ceph_assert(!is_spawned()); |
| 140 | ceph_assert(stdin_pipe_out_fd == -1); |
| 141 | ceph_assert(stdout_pipe_in_fd == -1); |
| 142 | ceph_assert(stderr_pipe_in_fd == -1); |
| 143 | |
| 144 | enum { IN = 0, OUT = 1 }; |
| 145 | |
| 146 | int ipipe[2], opipe[2], epipe[2]; |
| 147 | |
| 148 | ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = epipe[0] = epipe[1] = -1; |
| 149 | |
| 150 | int ret = 0; |
| 151 | |
| 152 | if ((stdin_op == PIPE && pipe_cloexec(ipipe, 0) == -1) || |
| 153 | (stdout_op == PIPE && pipe_cloexec(opipe, 0) == -1) || |
| 154 | (stderr_op == PIPE && pipe_cloexec(epipe, 0) == -1)) { |
| 155 | ret = -errno; |
| 156 | errstr << "pipe failed: " << cpp_strerror(errno); |
| 157 | goto fail; |
| 158 | } |
| 159 | |
| 160 | pid = fork(); |
| 161 | |
| 162 | if (pid > 0) { // Parent |
| 163 | stdin_pipe_out_fd = ipipe[OUT]; close(ipipe[IN ]); |
| 164 | stdout_pipe_in_fd = opipe[IN ]; close(opipe[OUT]); |
| 165 | stderr_pipe_in_fd = epipe[IN ]; close(epipe[OUT]); |
| 166 | return 0; |
| 167 | } |
| 168 | |
| 169 | if (pid == 0) { // Child |
| 170 | close(ipipe[OUT]); |
| 171 | close(opipe[IN ]); |
| 172 | close(epipe[IN ]); |
| 173 | |
| 174 | if (ipipe[IN] >= 0) { |
| 175 | if (ipipe[IN] == STDIN_FILENO) { |
| 176 | ::fcntl(STDIN_FILENO, F_SETFD, 0); /* clear FD_CLOEXEC */ |
| 177 | } else { |
| 178 | ::dup2(ipipe[IN], STDIN_FILENO); |
| 179 | ::close(ipipe[IN]); |
| 180 | } |
| 181 | } |
| 182 | if (opipe[OUT] >= 0) { |
| 183 | if (opipe[OUT] == STDOUT_FILENO) { |
| 184 | ::fcntl(STDOUT_FILENO, F_SETFD, 0); /* clear FD_CLOEXEC */ |
| 185 | } else { |
| 186 | ::dup2(opipe[OUT], STDOUT_FILENO); |
| 187 | ::close(opipe[OUT]); |
| 188 | static fd_buf buf(STDOUT_FILENO); |
| 189 | std::cout.rdbuf(&buf); |
| 190 | } |
| 191 | } |
| 192 | if (epipe[OUT] >= 0) { |
| 193 | if (epipe[OUT] == STDERR_FILENO) { |
| 194 | ::fcntl(STDERR_FILENO, F_SETFD, 0); /* clear FD_CLOEXEC */ |
| 195 | } else { |
no test coverage detected