mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
67 lines
2.3 KiB
C++
67 lines
2.3 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
extern "C" {
|
|
int APS5_VABI fcntl_nid_postfix(int, int, ...);
|
|
}
|
|
|
|
namespace {
|
|
|
|
constexpr int GuestGetFlags = 3;
|
|
|
|
int Child(const char* closed) {
|
|
struct stat null{};
|
|
if (::stat("/dev/null", &null) != 0) return 70;
|
|
for (int descriptor = 0; descriptor <= 2; ++descriptor) {
|
|
struct stat status{};
|
|
if (::fstat(descriptor, &status) != 0) return 71 + descriptor;
|
|
if (closed[descriptor] != '1') continue;
|
|
if (!S_ISCHR(status.st_mode) || status.st_rdev != null.st_rdev) return 74 + descriptor;
|
|
if ((::fcntl(descriptor, F_GETFL) & O_ACCMODE) != (descriptor == 0 ? O_RDONLY : O_WRONLY)) return 77 + descriptor;
|
|
}
|
|
if (closed[0] == '1' && fcntl_nid_postfix(0, GuestGetFlags) < 0) return 80;
|
|
return 0;
|
|
}
|
|
|
|
int RunClosed(const char* self, bool closeInput, bool closeOutput, bool closeError) {
|
|
const pid_t child = ::fork();
|
|
if (child < 0) return -1;
|
|
if (child == 0) {
|
|
if (closeInput) ::close(0);
|
|
if (closeOutput) ::close(1);
|
|
if (closeError) ::close(2);
|
|
char closed[] = {closeInput ? '1' : '0', closeOutput ? '1' : '0', closeError ? '1' : '0', '\0'};
|
|
char* const arguments[] = {const_cast<char*>(self), const_cast<char*>("--closed-child"), closed, nullptr};
|
|
::execv(self, arguments);
|
|
::_exit(69);
|
|
}
|
|
int status = 0;
|
|
if (::waitpid(child, &status, 0) != child) return -1;
|
|
return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
|
|
}
|
|
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc > 2 && std::strcmp(argv[1], "--closed-child") == 0 && std::strlen(argv[2]) == 3) return Child(argv[2]);
|
|
const struct { bool input, output, error; const char* name; } cases[] = {
|
|
{true, false, false, "stdin"},
|
|
{false, true, false, "stdout"},
|
|
{true, true, true, "all three"},
|
|
};
|
|
for (const auto& test : cases) {
|
|
const int result = RunClosed(argv[0], test.input, test.output, test.error);
|
|
if (result != 0) {
|
|
std::fprintf(stderr, "closed standard descriptors, %s: child exited with %d\n", test.name, result);
|
|
return 1;
|
|
}
|
|
}
|
|
std::puts("closed standard descriptors are reopened on /dev/null");
|
|
return 0;
|
|
}
|