Pārlūkot izejas kodu

LibC: Implement popen() and pclose().

I feel reasonably confident that I might have gotten these right. :^)
Andreas Kling 6 gadi atpakaļ
vecāks
revīzija
ccc6e69a29
3 mainītis faili ar 89 papildinājumiem un 5 dzēšanām
  1. 26 0
      AK/ValueRestorer.h
  2. 62 5
      LibC/stdio.cpp
  3. 1 0
      LibC/stdio.h

+ 26 - 0
AK/ValueRestorer.h

@@ -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;

+ 62 - 5
LibC/stdio.cpp

@@ -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" {
@@ -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)

+ 1 - 0
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;