Skip to content

Commit

Permalink
LibC: Implement popen() and pclose().
Browse files Browse the repository at this point in the history
I feel reasonably confident that I might have gotten these right. :^)
  • Loading branch information
awesomekling committed Jun 3, 2019
1 parent e92fe52 commit ccc6e69
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
26 changes: 26 additions & 0 deletions AK/ValueRestorer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

namespace AK {

template<typename T>
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;
67 changes: 62 additions & 5 deletions LibC/stdio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <fcntl.h>
#include <AK/printf.cpp>
#include <AK/StdLibExtras.h>
#include <AK/ValueRestorer.h>
#include <Kernel/Syscall.h>

extern "C" {
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions LibC/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit ccc6e69

Please sign in to comment.