| 1 | #include <fcntl.h> |
| 2 | #include <unistd.h> |
| 3 | #include <errno.h> |
| 4 | #include <string.h> |
| 5 | #include <spawn.h> |
| 6 | #include "stdio_impl.h" |
| 7 | #include "syscall.h" |
| 8 | |
| 9 | extern char **__environ; |
| 10 | |
| 11 | FILE *popen(const char *cmd, const char *mode) |
| 12 | { |
| 13 | 	int p[2], op, e; |
| 14 | 	pid_t pid; |
| 15 | 	FILE *f; |
| 16 | 	posix_spawn_file_actions_t fa; |
| 17 | |
| 18 | 	if (*mode == 'r') { |
| 19 | 		op = 0; |
| 20 | 	} else if (*mode == 'w') { |
| 21 | 		op = 1; |
| 22 | 	} else { |
| 23 | 		errno = EINVAL; |
| 24 | 		return 0; |
| 25 | 	} |
| 26 | 	 |
| 27 | 	if (pipe2(p, O_CLOEXEC)) return NULL; |
| 28 | 	f = fdopen(p[op], mode); |
| 29 | 	if (!f) { |
| 30 | 		__syscall(SYS_close, p[0]); |
| 31 | 		__syscall(SYS_close, p[1]); |
| 32 | 		return NULL; |
| 33 | 	} |
| 34 | |
| 35 | 	e = ENOMEM; |
| 36 | 	if (!posix_spawn_file_actions_init(&fa)) { |
| 37 | 		for (FILE *l = *__ofl_lock(); l; l=l->next) |
| 38 | 			if (l->pipe_pid && posix_spawn_file_actions_addclose(&fa, l->fd)) |
| 39 | 				goto fail; |
| 40 | 		if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) { |
| 41 | 			if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0, |
| 42 | 			 (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ))) { |
| 43 | 				posix_spawn_file_actions_destroy(&fa); |
| 44 | 				f->pipe_pid = pid; |
| 45 | 				if (!strchr(mode, 'e')) |
| 46 | 					fcntl(p[op], F_SETFD, 0); |
| 47 | 				__syscall(SYS_close, p[1-op]); |
| 48 | 				__ofl_unlock(); |
| 49 | 				return f; |
| 50 | 			} |
| 51 | 		} |
| 52 | fail: |
| 53 | 		__ofl_unlock(); |
| 54 | 		posix_spawn_file_actions_destroy(&fa); |
| 55 | 	} |
| 56 | 	fclose(f); |
| 57 | 	__syscall(SYS_close, p[1-op]); |
| 58 | |
| 59 | 	errno = e; |
| 60 | 	return 0; |
| 61 | } |