| OLD | NEW |
| 1 #include <fcntl.h> | 1 #include <fcntl.h> |
| 2 #include <unistd.h> | 2 #include <unistd.h> |
| 3 #include <errno.h> | 3 #include <errno.h> |
| 4 #include <string.h> | 4 #include <string.h> |
| 5 #include <spawn.h> | 5 #include <spawn.h> |
| 6 #include "stdio_impl.h" | 6 #include "stdio_impl.h" |
| 7 #include "syscall.h" | 7 #include "syscall.h" |
| 8 | 8 |
| 9 extern char **__environ; | 9 extern char** __environ; |
| 10 | 10 |
| 11 FILE *popen(const char *cmd, const char *mode) | 11 FILE* popen(const char* cmd, const char* mode) { |
| 12 { | 12 int p[2], op, e; |
| 13 » int p[2], op, e; | 13 pid_t pid; |
| 14 » pid_t pid; | 14 FILE* f; |
| 15 » FILE *f; | 15 posix_spawn_file_actions_t fa; |
| 16 » posix_spawn_file_actions_t fa; | |
| 17 | 16 |
| 18 » if (*mode == 'r') { | 17 if (*mode == 'r') { |
| 19 » » op = 0; | 18 op = 0; |
| 20 » } else if (*mode == 'w') { | 19 } else if (*mode == 'w') { |
| 21 » » op = 1; | 20 op = 1; |
| 22 » } else { | 21 } else { |
| 23 » » errno = EINVAL; | 22 errno = EINVAL; |
| 24 » » return 0; | 23 return 0; |
| 25 » } | 24 } |
| 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 » FLOCK(f); | |
| 35 | 25 |
| 36 » /* If the child's end of the pipe happens to already be on the final | 26 if (pipe2(p, O_CLOEXEC)) |
| 37 » * fd number to which it will be assigned (either 0 or 1), it must | 27 return NULL; |
| 38 » * be moved to a different fd. Otherwise, there is no safe way to | 28 f = fdopen(p[op], mode); |
| 39 » * remove the close-on-exec flag in the child without also creating | 29 if (!f) { |
| 40 » * a file descriptor leak race condition in the parent. */ | 30 __syscall(SYS_close, p[0]); |
| 41 » if (p[1-op] == 1-op) { | 31 __syscall(SYS_close, p[1]); |
| 42 » » int tmp = fcntl(1-op, F_DUPFD_CLOEXEC, 0); | 32 return NULL; |
| 43 » » if (tmp < 0) { | 33 } |
| 44 » » » e = errno; | 34 FLOCK(f); |
| 45 » » » goto fail; | |
| 46 » » } | |
| 47 » » __syscall(SYS_close, p[1-op]); | |
| 48 » » p[1-op] = tmp; | |
| 49 » } | |
| 50 | 35 |
| 51 » e = ENOMEM; | 36 /* If the child's end of the pipe happens to already be on the final |
| 52 » if (!posix_spawn_file_actions_init(&fa)) { | 37 * fd number to which it will be assigned (either 0 or 1), it must |
| 53 » » if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) { | 38 * be moved to a different fd. Otherwise, there is no safe way to |
| 54 » » » if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0, | 39 * remove the close-on-exec flag in the child without also creating |
| 55 » » » (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ)
)) { | 40 * a file descriptor leak race condition in the parent. */ |
| 56 » » » » posix_spawn_file_actions_destroy(&fa); | 41 if (p[1 - op] == 1 - op) { |
| 57 » » » » f->pipe_pid = pid; | 42 int tmp = fcntl(1 - op, F_DUPFD_CLOEXEC, 0); |
| 58 » » » » if (!strchr(mode, 'e')) | 43 if (tmp < 0) { |
| 59 » » » » » fcntl(p[op], F_SETFD, 0); | 44 e = errno; |
| 60 » » » » __syscall(SYS_close, p[1-op]); | 45 goto fail; |
| 61 » » » » FUNLOCK(f); | 46 } |
| 62 » » » » return f; | 47 __syscall(SYS_close, p[1 - op]); |
| 63 » » » } | 48 p[1 - op] = tmp; |
| 64 » » } | 49 } |
| 65 » » posix_spawn_file_actions_destroy(&fa); | 50 |
| 66 » } | 51 e = ENOMEM; |
| 52 if (!posix_spawn_file_actions_init(&fa)) { |
| 53 if (!posix_spawn_file_actions_adddup2(&fa, p[1 - op], 1 - op)) { |
| 54 if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0, |
| 55 (char* []){"sh", "-c", (char*)cmd, 0}, |
| 56 __environ))) { |
| 57 posix_spawn_file_actions_destroy(&fa); |
| 58 f->pipe_pid = pid; |
| 59 if (!strchr(mode, 'e')) |
| 60 fcntl(p[op], F_SETFD, 0); |
| 61 __syscall(SYS_close, p[1 - op]); |
| 62 FUNLOCK(f); |
| 63 return f; |
| 64 } |
| 65 } |
| 66 posix_spawn_file_actions_destroy(&fa); |
| 67 } |
| 67 fail: | 68 fail: |
| 68 » fclose(f); | 69 fclose(f); |
| 69 » __syscall(SYS_close, p[1-op]); | 70 __syscall(SYS_close, p[1 - op]); |
| 70 | 71 |
| 71 » errno = e; | 72 errno = e; |
| 72 » return 0; | 73 return 0; |
| 73 } | 74 } |
| OLD | NEW |