libc: Implement popen() and pclose()

This commit is contained in:
apio 2023-08-15 19:21:25 +02:00
parent 706752d6b9
commit 49a6c39c38
Signed by: apio
GPG Key ID: B8A7D06E42258954
2 changed files with 89 additions and 0 deletions

View File

@ -27,6 +27,7 @@ typedef struct
int mode; // The buffering mode.
} _buf;
int _flags; // The file access mode with which the file was opened.
pid_t _pid; // For popen(3) files, the pid of the child process.
} FILE;
#define EOF -1
@ -52,6 +53,7 @@ extern "C"
{
#endif
/* Flush a stream's buffers. */
int fflush(FILE*);
/* Open a file and bind a stream to it. */
@ -201,6 +203,9 @@ extern "C"
/* Move a file's location across a file system. */
int rename(const char* oldpath, const char* newpath);
/* Pipe a stream to or from a process. */
FILE* popen(const char* command, const char* type);
#ifdef __cplusplus
}
#endif

View File

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
FILE* stdin = nullptr;
@ -761,4 +762,87 @@ extern "C"
unlink(oldpath);
return 0;
}
FILE* popen(const char* command, const char* type)
{
int pfds[2];
if (pipe(pfds) < 0) return nullptr;
if (*type != 'r' && *type != 'w')
{
errno = EINVAL;
return nullptr;
}
pid_t child = fork();
if (child < 0)
{
close(pfds[0]);
close(pfds[1]);
return nullptr;
}
if (child == 0)
{
if (*type == 'r')
{
close(pfds[0]);
dup2(pfds[1], STDOUT_FILENO);
}
else
{
close(pfds[1]);
dup2(pfds[0], STDIN_FILENO);
}
execl("/bin/sh", "sh", "-c", command, nullptr);
_exit(127);
}
int fd;
if (*type == 'r')
{
close(pfds[1]);
fd = pfds[0];
}
else
{
close(pfds[0]);
fd = pfds[1];
}
int err = errno;
FILE* f = (FILE*)malloc(sizeof(FILE));
if (!f)
{
errno = err;
close(fd);
return nullptr;
}
f->_fd = fd;
f->_pid = child;
clearerr(f);
f->_flags = *type == 'r' ? O_RDONLY : O_WRONLY;
f->_buf.status = 0;
f->_buf.mode = _IOFBF;
f->_buf.size = f->_buf.index = 0;
f->_buf.buffer = nullptr;
setvbuf(f, NULL, f->_buf.mode, 0);
s_open_files[fd] = f;
return f;
}
int pclose(FILE* stream)
{
pid_t pid = stream->_pid;
fclose(stream);
int status;
if (waitpid(pid, &status, 0) < 0) return -1;
return status;
}
}