OLD | NEW |
(Empty) | |
| 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 FLOCK(f); |
| 35 |
| 36 /* If the child's end of the pipe happens to already be on the final |
| 37 * fd number to which it will be assigned (either 0 or 1), it must |
| 38 * be moved to a different fd. Otherwise, there is no safe way to |
| 39 * remove the close-on-exec flag in the child without also creating |
| 40 * a file descriptor leak race condition in the parent. */ |
| 41 if (p[1-op] == 1-op) { |
| 42 int tmp = fcntl(1-op, F_DUPFD_CLOEXEC, 0); |
| 43 if (tmp < 0) { |
| 44 e = errno; |
| 45 goto fail; |
| 46 } |
| 47 __syscall(SYS_close, p[1-op]); |
| 48 p[1-op] = tmp; |
| 49 } |
| 50 |
| 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 }, __environ)
)) { |
| 56 posix_spawn_file_actions_destroy(&fa); |
| 57 f->pipe_pid = pid; |
| 58 if (!strchr(mode, 'e')) |
| 59 fcntl(p[op], F_SETFD, 0); |
| 60 __syscall(SYS_close, p[1-op]); |
| 61 FUNLOCK(f); |
| 62 return f; |
| 63 } |
| 64 } |
| 65 posix_spawn_file_actions_destroy(&fa); |
| 66 } |
| 67 fail: |
| 68 fclose(f); |
| 69 __syscall(SYS_close, p[1-op]); |
| 70 |
| 71 errno = e; |
| 72 return 0; |
| 73 } |
OLD | NEW |