69static char **
build_child_env_native(
const char *env_keys[],
const char *env_values[],
size_t env_count,
size_t *base_count_out,
size_t *child_count_out) {
70 size_t base_count = 0;
71 size_t child_count = 0;
72 char **child_env = NULL;
74 if (base_count_out != NULL) {
77 if (child_count_out != NULL) {
83 child_env = (
char **)malloc(
sizeof(
char *) * (base_count + env_count + 1));
84 if (child_env == NULL) {
87 for (
size_t base_index = 0; base_index < base_count; base_index++) {
88 const char *entry =
environ[base_index];
90 for (env_index = 0; env_index < env_count; env_index++) {
91 const char *key = env_keys != NULL ? env_keys[env_index] : NULL;
92 size_t key_len = key != NULL ? strlen(key) : 0;
93 if (key_len > 0 && strncmp(entry, key, key_len) == 0 && entry[key_len] ==
'=') {
99 child_env[child_count++] =
environ[base_index];
102 for (env_index = 0; env_index < env_count; env_index++) {
104 env_keys != NULL ? env_keys[env_index] : NULL,
105 env_values != NULL ? env_values[env_index] : NULL
107 if (assignment != NULL) {
108 child_env[child_count++] = assignment;
111 child_env[child_count] = NULL;
112 if (base_count_out != NULL) {
113 *base_count_out = base_count;
115 if (child_count_out != NULL) {
116 *child_count_out = child_count;
121int capture_execv_output_split_env_native(
char *
const argv[],
const char *env_keys[],
const char *env_values[],
size_t env_count,
char **stdout_output,
size_t *stdout_len,
char **stderr_output,
size_t *stderr_len) {
122 int stdout_pipefd[2];
123 int stderr_pipefd[2];
130 posix_spawn_file_actions_t file_actions;
131 char **child_env = NULL;
132 size_t base_count = 0;
133 size_t child_count = 0;
135 int file_actions_ready = 0;
138 if (stdout_output != NULL) {
139 *stdout_output = NULL;
141 if (stdout_len != NULL) {
144 if (stderr_output != NULL) {
145 *stderr_output = NULL;
147 if (stderr_len != NULL) {
150 if (argv == NULL || argv[0] == NULL) {
153 if (pipe(stdout_pipefd) != 0) {
156 if (pipe(stderr_pipefd) != 0) {
157 close(stdout_pipefd[0]);
158 close(stdout_pipefd[1]);
162 if (env_count > 0 && child_env == NULL) {
163 close(stdout_pipefd[0]);
164 close(stdout_pipefd[1]);
165 close(stderr_pipefd[0]);
166 close(stderr_pipefd[1]);
169 if (posix_spawn_file_actions_init(&file_actions) != 0) {
171 close(stdout_pipefd[0]);
172 close(stdout_pipefd[1]);
173 close(stderr_pipefd[0]);
174 close(stderr_pipefd[1]);
177 file_actions_ready = 1;
178 if (posix_spawn_file_actions_adddup2(&file_actions, stdout_pipefd[1], STDOUT_FILENO) != 0 ||
179 posix_spawn_file_actions_adddup2(&file_actions, stderr_pipefd[1], STDERR_FILENO) != 0 ||
180 posix_spawn_file_actions_addclose(&file_actions, stdout_pipefd[0]) != 0 ||
181 posix_spawn_file_actions_addclose(&file_actions, stdout_pipefd[1]) != 0 ||
182 posix_spawn_file_actions_addclose(&file_actions, stderr_pipefd[0]) != 0 ||
183 posix_spawn_file_actions_addclose(&file_actions, stderr_pipefd[1]) != 0) {
184 posix_spawn_file_actions_destroy(&file_actions);
186 close(stdout_pipefd[0]);
187 close(stdout_pipefd[1]);
188 close(stderr_pipefd[0]);
189 close(stderr_pipefd[1]);
192 spawn_errno = posix_spawn(&pid, argv[0], &file_actions, NULL, argv, child_env != NULL ? child_env :
environ);
193 if (file_actions_ready) {
194 posix_spawn_file_actions_destroy(&file_actions);
197 if (spawn_errno != 0) {
198 close(stdout_pipefd[0]);
199 close(stdout_pipefd[1]);
200 close(stderr_pipefd[0]);
201 close(stderr_pipefd[1]);
204 close(stdout_pipefd[1]);
205 close(stderr_pipefd[1]);
206 while (stdout_open || stderr_open) {
207 struct pollfd fds[2];
210 fds[nfds].fd = stdout_pipefd[0];
211 fds[nfds].events = POLLIN | POLLHUP;
215 fds[nfds].fd = stderr_pipefd[0];
216 fds[nfds].events = POLLIN | POLLHUP;
219 if (poll(fds, nfds, -1) < 0) {
220 if (stdout_open) close(stdout_pipefd[0]);
221 if (stderr_open) close(stderr_pipefd[0]);
222 waitpid(pid, NULL, 0);
229 if (fds[nfds].revents & (POLLIN | POLLHUP)) {
231 if (stdout_open) close(stdout_pipefd[0]);
232 if (stderr_open) close(stderr_pipefd[0]);
233 waitpid(pid, NULL, 0);
242 if (fds[nfds].revents & (POLLIN | POLLHUP)) {
244 if (stdout_open) close(stdout_pipefd[0]);
245 if (stderr_open) close(stderr_pipefd[0]);
246 waitpid(pid, NULL, 0);
254 waitpid(pid, &status_code, 0);
255 if (stdout_output != NULL) {
256 *stdout_output = stdout_buffer.
data;
260 if (stdout_len != NULL) {
261 *stdout_len = stdout_buffer.
len;
263 if (stderr_output != NULL) {
264 *stderr_output = stderr_buffer.
data;
268 if (stderr_len != NULL) {
269 *stderr_len = stderr_buffer.
len;
271 if (WIFEXITED(status_code)) {
272 return WEXITSTATUS(status_code);
278 char *stdout_output = NULL;
279 char *stderr_output = NULL;
280 size_t stdout_captured_len = 0;
281 size_t stderr_captured_len = 0;
285 if (stdout_output != NULL && stdout_captured_len > 0) {
286 if (
buffer_append(&combined, stdout_output, stdout_captured_len) != 0) {
292 if (stderr_output != NULL && stderr_captured_len > 0) {
293 if (
buffer_append(&combined, stderr_output, stderr_captured_len) != 0) {
302 if (output != NULL) {
303 *output = combined.
data;
307 if (output_len != NULL) {
308 *output_len = combined.
len;
int capture_execv_output_split_env_native(char *const argv[], const char *env_keys[], const char *env_values[], size_t env_count, char **stdout_output, size_t *stdout_len, char **stderr_output, size_t *stderr_len)
Executes a process with injected environment values and captures stdout and stderr separately.