| 118 | } |
| 119 | |
| 120 | pid_t __popen3(const char* cmd, FILE** strm_w, FILE** strm_r, FILE** strm_e) |
| 121 | { |
| 122 | #define OPEN_PIPE(strm, fds) \ |
| 123 | do { \ |
| 124 | if (strm) { \ |
| 125 | if (pipe(fds) != 0) { \ |
| 126 | LM_ERR("failed to create reading pipe (%d: %s)\n", \ |
| 127 | errno, strerror(errno)); \ |
| 128 | return -1; \ |
| 129 | } \ |
| 130 | } \ |
| 131 | } while (0); |
| 132 | |
| 133 | /* |
| 134 | * cl - pipe end to be closed |
| 135 | * op - pipe end to be redirected |
| 136 | * re - fds where to redirect 'op' |
| 137 | */ |
| 138 | #define CLOSE_AND_REDIRECT(strm, fds, cl, op, re) \ |
| 139 | do { \ |
| 140 | if (strm) { \ |
| 141 | close(fds[cl]); \ |
| 142 | dup2(fds[op], re); \ |
| 143 | close(fds[op]); \ |
| 144 | } \ |
| 145 | } while (0); |
| 146 | |
| 147 | #define CLOSE_END_AND_OPEN_STREAM(strm, way, fds, end2close) \ |
| 148 | do { \ |
| 149 | if (strm) { \ |
| 150 | close(fds[end2close]); \ |
| 151 | *strm = fdopen(fds[(1^end2close)], way); \ |
| 152 | } \ |
| 153 | }while (0); |
| 154 | |
| 155 | pid_t ret; |
| 156 | int r_fds[2], w_fds[2], e_fds[2]; |
| 157 | |
| 158 | if (strm_r == NULL && strm_w == NULL && strm_e == NULL) { |
| 159 | LM_WARN("no descriptor redirect required\n"); |
| 160 | } |
| 161 | |
| 162 | |
| 163 | OPEN_PIPE(strm_w, w_fds); |
| 164 | OPEN_PIPE(strm_r, r_fds); |
| 165 | OPEN_PIPE(strm_e, e_fds); |
| 166 | |
| 167 | ret=fork(); |
| 168 | |
| 169 | if (ret==0) { |
| 170 | /* write pipe */ |
| 171 | CLOSE_AND_REDIRECT(strm_w, w_fds, 1, 0, STDIN_FILENO); |
| 172 | |
| 173 | /* read pipe */ |
| 174 | CLOSE_AND_REDIRECT(strm_r, r_fds, 0, 1, STDOUT_FILENO); |
| 175 | |
| 176 | /* error pipe */ |
| 177 | CLOSE_AND_REDIRECT(strm_e, e_fds, 0, 1, STDERR_FILENO); |
no test coverage detected