Files
AnyPS5/core/libs/tests/GuestSystemServiceLoadExecStandardError.cpp
T
Yossi Yadgar 67f08d9f27 test(libSceSystemService): check stderr after LoadExec of a redirected title
A forked child with stderr on a pipe moves the guest's descriptor 2 to a
second pipe with dup2, then starts itself again through
sceSystemServiceLoadExec("/app0/eboot.bin"). What the new image writes
to stderr must reach the first pipe and nothing the second. It fails
with the previous execv, where the text goes to the guest's pipe.
2026-10-15 18:13:12 +03:00

58 lines
1.7 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <sys/wait.h>
#include <unistd.h>
extern "C" {
int APS5_VABI sceSystemServiceLoadExec(const char*, const char* const*);
int APS5_VABI dup2_nid_postfix(int, int);
}
static void Require(bool value) { if (!value) std::abort(); }
static std::string Drain(int descriptor) {
std::string text;
char buffer[4096];
for (ssize_t count; (count = ::read(descriptor, buffer, sizeof(buffer))) > 0;) text.append(buffer, static_cast<std::size_t>(count));
::close(descriptor);
return text;
}
int main(int argc, char** argv) {
if (argc == 2 && std::strcmp(argv[1], "--after-load-exec") == 0) {
std::fputs("started\n", stderr);
return 0;
}
Require(argc == 1);
int host[2] = {-1, -1};
int guest[2] = {-1, -1};
Require(::pipe(host) == 0);
Require(::pipe(guest) == 0);
const pid_t child = ::fork();
Require(child >= 0);
if (child == 0) {
::close(host[0]);
::close(guest[0]);
if (::dup2(host[1], 2) != 2) ::_exit(70);
::close(host[1]);
if (dup2_nid_postfix(guest[1], 2) != 2) ::_exit(71);
::close(guest[1]);
const char* const arguments[] = {"--after-load-exec", nullptr};
sceSystemServiceLoadExec("/app0/eboot.bin", arguments);
::_exit(72);
}
::close(host[1]);
::close(guest[1]);
const std::string hostText = Drain(host[0]);
const std::string guestText = Drain(guest[0]);
int status = 0;
Require(::waitpid(child, &status, 0) == child);
Require(WIFEXITED(status) && WEXITSTATUS(status) == 0);
Require(hostText == "started\n");
Require(guestText.empty());
return 0;
}