[388] | 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 | }
|
---|