|
0
|
1 #include <iostream> |
|
|
2 #include <unistd.h> |
|
|
3 #include <spawn.h> |
|
|
4 #include <cstring> |
|
2
|
5 #include <cerrno> |
|
0
|
6 #include <string> |
|
|
7 #include <sys/wait.h> |
|
|
8 #include "process.h" |
|
|
9 extern char** environ; |
|
2
|
10 std::string run_piped(char* const argv[], const std::string& input) |
|
0
|
11 { |
|
|
12 int status; |
|
|
13 pid_t pid; |
|
|
14 int pipeA[2]; |
|
|
15 int pipeB[2]; |
|
|
16 if (pipe(pipeA) < 0) |
|
|
17 return "error"; |
|
|
18 if (pipe(pipeB) < 0) |
|
|
19 return "error"; |
|
|
20 posix_spawn_file_actions_t actions; |
|
|
21 posix_spawn_file_actions_init(&actions); // initialize actions |
|
|
22 posix_spawn_file_actions_adddup2(&actions, pipeA[0], STDIN_FILENO); |
|
|
23 posix_spawn_file_actions_adddup2(&actions, pipeB[1], STDOUT_FILENO); |
|
|
24 posix_spawn_file_actions_addclose(&actions, pipeA[1]); // closes write end in child |
|
|
25 posix_spawn_file_actions_addclose(&actions, pipeB[0]); // makes sure child doesn't read its own output pipe |
|
|
26 posix_spawn_file_actions_addclose(&actions, pipeA[0]); // close read fd in child |
|
|
27 posix_spawn_file_actions_addclose(&actions, pipeB[1]); // close read fd in child, part 2 |
|
2
|
28 status = posix_spawnp(&pid, argv[0], &actions, NULL, const_cast<char* const*>(argv), environ); |
|
0
|
29 close(pipeA[0]); |
|
|
30 close(pipeB[1]); |
|
|
31 if (status != 0) { |
|
|
32 posix_spawn_file_actions_destroy(&actions); |
|
|
33 close(pipeA[1]); |
|
|
34 close(pipeB[0]); |
|
2
|
35 std::cerr << "posix_spawnp failed for " << argv[0] << ": " << strerror(status) << std::endl; |
|
0
|
36 return "error"; |
|
|
37 } |
|
2
|
38 size_t total_written = 0; |
|
|
39 while (total_written < input.size()) { |
|
|
40 ssize_t n = write(pipeA[1], input.c_str() + total_written, input.size() - total_written); |
|
|
41 if (n < 0) { |
|
|
42 if (errno == EINTR) { |
|
|
43 continue; // interrupted |
|
|
44 } |
|
|
45 perror("write"); |
|
|
46 break; // error, give up |
|
|
47 } |
|
|
48 total_written += n; |
|
|
49 } |
|
0
|
50 close(pipeA[1]); |
|
|
51 char buf[256]; |
|
|
52 std::string result; |
|
|
53 ssize_t n; |
|
|
54 while ((n = read(pipeB[0], buf, sizeof(buf))) > 0) { |
|
|
55 result.append(buf, n); |
|
|
56 } |
|
|
57 close(pipeB[0]); |
|
|
58 if (waitpid(pid, &status, 0) == -1) { |
|
|
59 posix_spawn_file_actions_destroy(&actions); |
|
|
60 close(pipeA[1]); |
|
|
61 close(pipeB[0]); |
|
|
62 perror("waitpid"); |
|
|
63 return "error"; |
|
|
64 } |
|
|
65 posix_spawn_file_actions_destroy(&actions); |
|
|
66 return result; |
|
|
67 } |