From ccc6e69a294edacf7bec77cb2c2640ada7fe1f77 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 3 Jun 2019 19:52:31 +0200 Subject: [PATCH] LibC: Implement popen() and pclose(). I feel reasonably confident that I might have gotten these right. :^) --- AK/ValueRestorer.h | 26 ++++++++++++++++++ LibC/stdio.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++---- LibC/stdio.h | 1 + 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 AK/ValueRestorer.h diff --git a/AK/ValueRestorer.h b/AK/ValueRestorer.h new file mode 100644 index 00000000000000..99fa43e18767be --- /dev/null +++ b/AK/ValueRestorer.h @@ -0,0 +1,26 @@ +#pragma once + +namespace AK { + +template +class ValueRestorer { +public: + ValueRestorer(T& variable) + : m_variable(variable) + , m_saved_value(variable) + { + } + + ~ValueRestorer() + { + m_variable = m_saved_value; + } + +private: + T& m_variable; + T m_saved_value; +}; + +} + +using AK::ValueRestorer; diff --git a/LibC/stdio.cpp b/LibC/stdio.cpp index e94ac7322a557e..3aae74ec52629f 100644 --- a/LibC/stdio.cpp +++ b/LibC/stdio.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include extern "C" { @@ -458,14 +459,70 @@ char* tmpnam(char*) FILE* popen(const char* command, const char* type) { - (void)command; - (void)type; - ASSERT_NOT_REACHED(); + if (!type || (*type != 'r' && *type != 'w')) { + errno = EINVAL; + return nullptr; + } + + int pipe_fds[2]; + + int rc = pipe(pipe_fds); + if (rc < 0) { + ValueRestorer restorer(errno); + perror("pipe"); + return nullptr; + } + + pid_t child_pid = fork(); + if (!child_pid) { + if (*type == 'r') { + int rc = dup2(pipe_fds[1], STDOUT_FILENO); + if (rc < 0) { + perror("dup2"); + exit(1); + } + close(pipe_fds[0]); + close(pipe_fds[1]); + } else if (*type == 'w') { + int rc = dup2(pipe_fds[0], STDIN_FILENO); + if (rc < 0) { + perror("dup2"); + exit(1); + } + close(pipe_fds[0]); + close(pipe_fds[1]); + } + + int rc = execl("/bin/sh", "sh", "-c", command, nullptr); + if (rc < 0) + perror("execl"); + exit(1); + } + + FILE* fp = nullptr; + if (*type == 'r') { + fp = make_FILE(pipe_fds[0]); + close(pipe_fds[1]); + } else if (*type == 'w') { + fp = make_FILE(pipe_fds[1]); + close(pipe_fds[0]); + } + + fp->popen_child = child_pid; + return fp; } -int pclose(FILE*) +int pclose(FILE* fp) { - ASSERT_NOT_REACHED(); + ASSERT(fp); + ASSERT(fp->popen_child != 0); + + int wstatus = 0; + int rc = waitpid(fp->popen_child, &wstatus, 0); + if (rc < 0) + return rc; + + return wstatus; } int remove(const char* pathname) diff --git a/LibC/stdio.h b/LibC/stdio.h index 8da83d9cfb416b..a8d4c7269fd59a 100644 --- a/LibC/stdio.h +++ b/LibC/stdio.h @@ -29,6 +29,7 @@ struct __STDIO_FILE { int eof; int error; int mode; + pid_t popen_child; char* buffer; size_t buffer_size; size_t buffer_index;