188 lines
7.4 KiB
C++
188 lines
7.4 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
extern "C" {
|
|
int APS5_VABI tcgetattr_nid_postfix(int, void*);
|
|
int APS5_VABI tcsetattr_nid_postfix(int, int, const void*);
|
|
int APS5_VABI tcsendbreak_nid_postfix(int, int);
|
|
int APS5_VABI tcdrain_nid_postfix(int);
|
|
int APS5_VABI tcflush_nid_postfix(int, int);
|
|
int APS5_VABI tcflow_nid_postfix(int, int);
|
|
int APS5_VABI tcgetpgrp_nid_postfix(int);
|
|
int APS5_VABI tcsetpgrp_nid_postfix(int, int);
|
|
int APS5_VABI open_nid_postfix(const char*, int, int);
|
|
int APS5_VABI pipe_nid_postfix(int*);
|
|
int APS5_VABI socket_nid_postfix(int, int, int);
|
|
int APS5_VABI socketpair_nid_postfix(int, int, int, int*);
|
|
int APS5_VABI mkdir_nid_postfix(const char*, unsigned short);
|
|
int APS5_VABI close_nid_postfix(int);
|
|
int* APS5_VABI __error_nid_postfix();
|
|
}
|
|
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "terminal check failed at line %d, errno %d\n", line, *__error_nid_postfix());
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
|
|
constexpr int Now = 0;
|
|
constexpr int Drain = 1;
|
|
constexpr int Flush = 2;
|
|
constexpr int Soft = 0x10;
|
|
constexpr int NotTerminal = 25;
|
|
constexpr int BadDescriptor = 9;
|
|
constexpr int InvalidArgument = 22;
|
|
constexpr int BadAddress = 14;
|
|
constexpr int AddressNotAvailable = 49;
|
|
constexpr int OperationNotSupported = 45;
|
|
|
|
static bool Fails(int result, int error) { return result == -1 && *__error_nid_postfix() == error; }
|
|
|
|
static void RequireControlFails(int descriptor, int error) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcsendbreak_nid_postfix(descriptor, 0), error));
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcsendbreak_nid_postfix(descriptor, 5), error));
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcdrain_nid_postfix(descriptor), error));
|
|
for (const int queue : {1, 2, 3}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcflush_nid_postfix(descriptor, queue), error));
|
|
}
|
|
for (const int action : {1, 2, 3, 4}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcflow_nid_postfix(descriptor, action), error));
|
|
}
|
|
}
|
|
|
|
static void RequireProcessGroupFails(int descriptor, int error) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcgetpgrp_nid_postfix(descriptor), error));
|
|
for (const int group : {0, 1}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcsetpgrp_nid_postfix(descriptor, group), error));
|
|
}
|
|
}
|
|
|
|
template <typename TCall> static bool Throws(TCall call) {
|
|
try {
|
|
call();
|
|
} catch (const std::runtime_error&) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void RequireNotTerminal(int descriptor) {
|
|
unsigned char attributes[44];
|
|
std::memset(attributes, 0xaa, sizeof(attributes));
|
|
unsigned char untouched[44];
|
|
std::memset(untouched, 0xaa, sizeof(untouched));
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcgetattr_nid_postfix(descriptor, attributes), NotTerminal));
|
|
Require(std::memcmp(attributes, untouched, sizeof(attributes)) == 0);
|
|
for (const int action : {Now, Drain, Flush, Now | Soft, Flush | Soft}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcsetattr_nid_postfix(descriptor, action, attributes), NotTerminal));
|
|
}
|
|
RequireControlFails(descriptor, NotTerminal);
|
|
}
|
|
|
|
int main() {
|
|
const auto name = "anyps5-terminal-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
|
|
const int file = open_nid_postfix(name.c_str(), 0x202, 0644);
|
|
Require(file >= 0);
|
|
RequireNotTerminal(file);
|
|
RequireProcessGroupFails(file, NotTerminal);
|
|
for (const int stream : {0, 1, 2}) {
|
|
RequireNotTerminal(stream);
|
|
RequireProcessGroupFails(stream, NotTerminal);
|
|
}
|
|
|
|
int ends[2] = {-1, -1};
|
|
Require(pipe_nid_postfix(ends) == 0);
|
|
for (const int end : ends) {
|
|
RequireNotTerminal(end);
|
|
Require(Throws([end] { tcgetpgrp_nid_postfix(end); }));
|
|
Require(Throws([end] { tcsetpgrp_nid_postfix(end, 0); }));
|
|
}
|
|
|
|
const int socket = socket_nid_postfix(2, 2, 0);
|
|
Require(socket >= 0);
|
|
unsigned char untouched[44];
|
|
std::memset(untouched, 0xaa, sizeof(untouched));
|
|
unsigned char probe[44];
|
|
std::memset(probe, 0xaa, sizeof(probe));
|
|
Require(Fails(tcgetattr_nid_postfix(socket, probe), AddressNotAvailable));
|
|
Require(std::memcmp(probe, untouched, sizeof(probe)) == 0);
|
|
Require(Fails(tcsetattr_nid_postfix(socket, Flush, probe), AddressNotAvailable));
|
|
RequireControlFails(socket, AddressNotAvailable);
|
|
RequireProcessGroupFails(socket, AddressNotAvailable);
|
|
|
|
int pair[2] = {-1, -1};
|
|
Require(socketpair_nid_postfix(1, 1, 0, pair) == 0);
|
|
for (const int end : pair) {
|
|
Require(Fails(tcgetattr_nid_postfix(end, probe), OperationNotSupported));
|
|
RequireControlFails(end, OperationNotSupported);
|
|
RequireProcessGroupFails(end, OperationNotSupported);
|
|
}
|
|
Require(close_nid_postfix(pair[0]) == 0 && close_nid_postfix(pair[1]) == 0);
|
|
|
|
const auto directoryName = name + "-directory";
|
|
Require(mkdir_nid_postfix(directoryName.c_str(), 0755) == 0);
|
|
const int directory = open_nid_postfix(directoryName.c_str(), 0x00020000, 0);
|
|
Require(directory >= 0);
|
|
RequireNotTerminal(directory);
|
|
RequireProcessGroupFails(directory, NotTerminal);
|
|
Require(close_nid_postfix(directory) == 0);
|
|
RequireControlFails(directory, BadDescriptor);
|
|
std::filesystem::remove(directoryName);
|
|
|
|
unsigned char attributes[44]{};
|
|
Require(Fails(tcsetattr_nid_postfix(file, 3, attributes), InvalidArgument));
|
|
Require(Fails(tcsetattr_nid_postfix(file, -1, attributes), InvalidArgument));
|
|
Require(Fails(tcsetattr_nid_postfix(file, Soft | 3, attributes), InvalidArgument));
|
|
Require(Fails(tcsetattr_nid_postfix(-1, 3, attributes), InvalidArgument));
|
|
Require(Fails(tcsetattr_nid_postfix(file, Now, nullptr), BadAddress));
|
|
Require(Fails(tcsetattr_nid_postfix(-1, Now, nullptr), BadAddress));
|
|
Require(Fails(tcgetattr_nid_postfix(-1, attributes), BadDescriptor));
|
|
Require(Fails(tcsetattr_nid_postfix(-1, Now, attributes), BadDescriptor));
|
|
for (const int descriptor : {file, -1}) {
|
|
for (const int queue : {0, 4, -1}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcflush_nid_postfix(descriptor, queue), InvalidArgument));
|
|
}
|
|
for (const int action : {0, 5, -1}) {
|
|
*__error_nid_postfix() = 0;
|
|
Require(Fails(tcflow_nid_postfix(descriptor, action), InvalidArgument));
|
|
}
|
|
}
|
|
RequireControlFails(-1, BadDescriptor);
|
|
RequireProcessGroupFails(-1, BadDescriptor);
|
|
|
|
Require(close_nid_postfix(socket) == 0);
|
|
Require(Fails(tcgetattr_nid_postfix(socket, attributes), BadDescriptor));
|
|
Require(Fails(tcsetattr_nid_postfix(socket, Now, attributes), BadDescriptor));
|
|
RequireControlFails(socket, BadDescriptor);
|
|
RequireProcessGroupFails(socket, BadDescriptor);
|
|
Require(close_nid_postfix(ends[0]) == 0 && close_nid_postfix(ends[1]) == 0);
|
|
RequireControlFails(ends[0], BadDescriptor);
|
|
RequireProcessGroupFails(ends[0], BadDescriptor);
|
|
Require(close_nid_postfix(file) == 0);
|
|
Require(Fails(tcgetattr_nid_postfix(file, attributes), BadDescriptor));
|
|
Require(Fails(tcsetattr_nid_postfix(file, Flush, attributes), BadDescriptor));
|
|
RequireControlFails(file, BadDescriptor);
|
|
RequireProcessGroupFails(file, BadDescriptor);
|
|
std::filesystem::remove(name);
|
|
return 0;
|
|
}
|