mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:57:34 +00:00
LibC: Implement popen() and pclose().
I feel reasonably confident that I might have gotten these right. :^)
This commit is contained in:
parent
e92fe52031
commit
ccc6e69a29
3 changed files with 89 additions and 5 deletions
26
AK/ValueRestorer.h
Normal file
26
AK/ValueRestorer.h
Normal file
|
@ -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;
|
|
@ -10,6 +10,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <AK/printf.cpp>
|
#include <AK/printf.cpp>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
|
#include <AK/ValueRestorer.h>
|
||||||
#include <Kernel/Syscall.h>
|
#include <Kernel/Syscall.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -458,14 +459,70 @@ char* tmpnam(char*)
|
||||||
|
|
||||||
FILE* popen(const char* command, const char* type)
|
FILE* popen(const char* command, const char* type)
|
||||||
{
|
{
|
||||||
(void)command;
|
if (!type || (*type != 'r' && *type != 'w')) {
|
||||||
(void)type;
|
errno = EINVAL;
|
||||||
ASSERT_NOT_REACHED();
|
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)
|
int remove(const char* pathname)
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct __STDIO_FILE {
|
||||||
int eof;
|
int eof;
|
||||||
int error;
|
int error;
|
||||||
int mode;
|
int mode;
|
||||||
|
pid_t popen_child;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
size_t buffer_index;
|
size_t buffer_index;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue