Run two commands connected by a pipe: lhs | rhs. Returns the exit code of the rhs process.
| 169 | /// Run two commands connected by a pipe: lhs | rhs. |
| 170 | /// Returns the exit code of the rhs process. |
| 171 | int runPipeline(const std::vector<std::string> & lhs, const std::vector<std::string> & rhs) |
| 172 | { |
| 173 | int pipefd[2]; |
| 174 | if (pipe(pipefd) < 0) |
| 175 | return -1; |
| 176 | |
| 177 | pid_t lhs_pid = fork(); |
| 178 | if (lhs_pid < 0) |
| 179 | { |
| 180 | (void)close(pipefd[0]); |
| 181 | (void)close(pipefd[1]); |
| 182 | return -1; |
| 183 | } |
| 184 | if (lhs_pid == 0) |
| 185 | { |
| 186 | (void)close(pipefd[0]); |
| 187 | (void)dup2(pipefd[1], STDOUT_FILENO); |
| 188 | (void)close(pipefd[1]); |
| 189 | auto argv = buildArgv(lhs); |
| 190 | execvp(argv[0], argv.data()); |
| 191 | _exit(127); |
| 192 | } |
| 193 | |
| 194 | pid_t rhs_pid = fork(); |
| 195 | if (rhs_pid < 0) |
| 196 | { |
| 197 | (void)close(pipefd[0]); |
| 198 | (void)close(pipefd[1]); |
| 199 | kill(lhs_pid, SIGTERM); |
| 200 | while (waitpid(lhs_pid, nullptr, 0) < 0 && errno == EINTR) {} |
| 201 | return -1; |
| 202 | } |
| 203 | if (rhs_pid == 0) |
| 204 | { |
| 205 | (void)close(pipefd[1]); |
| 206 | (void)dup2(pipefd[0], STDIN_FILENO); |
| 207 | (void)close(pipefd[0]); |
| 208 | auto argv = buildArgv(rhs); |
| 209 | execvp(argv[0], argv.data()); |
| 210 | _exit(127); |
| 211 | } |
| 212 | |
| 213 | (void)close(pipefd[0]); |
| 214 | (void)close(pipefd[1]); |
| 215 | |
| 216 | int lhs_status = 0; |
| 217 | int rhs_status = 0; |
| 218 | while (waitpid(lhs_pid, &lhs_status, 0) < 0 && errno == EINTR) {} |
| 219 | while (waitpid(rhs_pid, &rhs_status, 0) < 0 && errno == EINTR) {} |
| 220 | |
| 221 | return WIFEXITED(rhs_status) ? WEXITSTATUS(rhs_status) : -1; |
| 222 | } |
| 223 | |
| 224 | /// Returns true if the string is a safe ClickHouse identifier: |
| 225 | /// alphanumeric + underscore, not starting with a digit. |
no test coverage detected