libc: Implement popen() and pclose()
This commit is contained in:
parent
706752d6b9
commit
49a6c39c38
@ -27,6 +27,7 @@ typedef struct
|
|||||||
int mode; // The buffering mode.
|
int mode; // The buffering mode.
|
||||||
} _buf;
|
} _buf;
|
||||||
int _flags; // The file access mode with which the file was opened.
|
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;
|
} FILE;
|
||||||
|
|
||||||
#define EOF -1
|
#define EOF -1
|
||||||
@ -52,6 +53,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Flush a stream's buffers. */
|
||||||
int fflush(FILE*);
|
int fflush(FILE*);
|
||||||
|
|
||||||
/* Open a file and bind a stream to it. */
|
/* Open a file and bind a stream to it. */
|
||||||
@ -201,6 +203,9 @@ extern "C"
|
|||||||
/* Move a file's location across a file system. */
|
/* Move a file's location across a file system. */
|
||||||
int rename(const char* oldpath, const char* newpath);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
FILE* stdin = nullptr;
|
FILE* stdin = nullptr;
|
||||||
@ -761,4 +762,87 @@ extern "C"
|
|||||||
unlink(oldpath);
|
unlink(oldpath);
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user