Files
etaHEN/Source Code/daemon/source/msg.cpp
SonyUSA b41b22d768 PS4Debug 1.0b5 FW 3.00 Support (#54)
PS4Debug 1.0b5 seems to support FW 3.00 and can be used for remove save mounter
2025-09-11 18:48:19 -04:00

952 lines
27 KiB
C++

/* Copyright (C) 2025 etaHEN / LightningMods
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include "ipc.hpp"
#include "../../extern/cJSON/cJSON.hpp"
#include "../../extern/tiny-json/tiny-json.hpp"
#include "globalconf.hpp"
#include <atomic>
#include <msg.hpp>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <strings.h>
#include <sys/_pthreadtypes.h>
#include <sys/_stdint.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <ps5/kernel.h>
#include <sys/user.h>
#include <vector>
#include "../../include/ini.h"
typedef struct app_info {
uint32_t app_id;
uint64_t unknown1;
uint32_t app_type;
char title_id[10];
char unknown2[0x3c];
} app_info_t;
bool if_exists(const char *path);
extern "C" {
#include <sys/mount.h>
pid_t elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name);
int32_t sceKernelPrepareToSuspendProcess(pid_t pid);
int32_t sceKernelSuspendProcess(pid_t pid);
int32_t sceKernelPrepareToResumeProcess(pid_t pid);
int32_t sceKernelResumeProcess(pid_t pid);
int32_t sceUserServiceInitialize(int32_t *priority);
int32_t sceUserServiceGetForegroundUser(int32_t *new_id);
int32_t scePadSetProcessPrivilege(int32_t num);
int sceKernelMprotect(void *addr, size_t len, int prot);
int sceSystemServiceLoadExec(const char *path, const char *argv[]);
extern uint8_t ps5debug_start[];
extern const unsigned int ps5debug_size;
extern uint8_t shellui_elf_start[];
extern const unsigned int shellui_elf_size;
bool Inject_Toolbox(int pid, uint8_t *elf);
int sceKernelGetAppInfo(int pid, app_info_t *title);
int sceKernelGetProcessName(int pid, char *name);
}
bool is_handler_enabled = true;
using namespace std;
extern pthread_t cheat_thr;
extern struct daemon_settings global_conf;
extern atomic_bool shortcut_activated;
int launchApp(const char *titleId);
int ItemzLaunchByUri(const char *uri);
void etaHEN_log(const char *fmt, ...);
extern "C" int unmount(const char *path, int flags);
bool copyRecursive(const char *source, const char *destination);
bool rmtree(const char *path);
void calculateSize(uint64_t size, char *result);
extern std::string dump_path;
extern std::string dump_title;
extern bool is_dumper_enabled;
extern Dump_Option dump_opt;
extern "C" void sceLncUtilGetAppTitleId(uint32_t appId, char *titleId);
bool GetFileContents(const char *path, char **buffer);
uint64_t calculateTotalSize(const char *path);
bool copyFile(const char *source, const char *destination, bool for_dumper);
void notify(bool show_watermark, const char *text, ...);
bool isProcessAlive(int pid) noexcept;
int DaemonSocket = 0;
struct NonStupidIovec {
const void *iov_base;
size_t iov_length;
constexpr NonStupidIovec(const char *str)
: iov_base(str), iov_length(__builtin_strlen(str) + 1) {}
constexpr NonStupidIovec(const char *str, size_t length)
: iov_base(str), iov_length(length) {}
};
constexpr NonStupidIovec operator""_iov(const char *str, unsigned long len) {
return {str, len + 1};
}
static bool remount(const char *dev, const char *path, int mnt_flag) {
NonStupidIovec iov[]{
"fstype"_iov, "nullfs"_iov, "fspath"_iov, {path},
"target"_iov, {dev}, "rw"_iov, {nullptr, 0},
};
constexpr size_t iovlen = sizeof(iov) / sizeof(iov[0]);
return nmount(reinterpret_cast<struct iovec *>(iov), iovlen, mnt_flag) == 0;
}
bool pause_kstuff()
{
intptr_t sysentvec = 0;
intptr_t sysentvec_ps4 = 0;
switch(kernel_get_fw_version() & 0xffff0000) {
case 0x1000000:
case 0x1010000:
case 0x1020000:
case 0x1050000:
case 0x1100000:
case 0x1110000:
case 0x1120000:
case 0x1130000:
case 0x1140000:
case 0x2000000:
case 0x2200000:
case 0x2250000:
case 0x2260000:
case 0x2300000:
case 0x2500000:
case 0x2700000:
return false;
case 0x3000000:
case 0x3100000:
case 0x3200000:
case 0x3210000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xca0cd8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xca0e50;
break;
case 0x4000000:
case 0x4020000:
case 0x4030000:
case 0x4500000:
case 0x4510000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xd11bb8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xd11d30;
break;
case 0x5000000:
case 0x5020000:
case 0x5100000:
case 0x5500000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xe00be8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xe00d60;
break;
case 0x6000000:
case 0x6020000:
case 0x6500000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xe210a8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xe21220;
break;
case 0x7000000:
case 0x7010000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xe21ab8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xe21c30;
break;
case 0x7200000:
case 0x7400000:
case 0x7600000:
case 0x7610000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xe21b78;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xe21cf0;
break;
case 0x8000000:
case 0x8200000:
case 0x8400000:
case 0x8600000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xe21ca8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xe21e20;
break;
case 0x9000000:
case 0x9200000:
case 0x9400000:
case 0x9600000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xde0e18;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xde0f90;
break;
case 0x10000000:
case 0x10010000:
case 0x10200000:
case 0x10400000:
case 0x10600000:
sysentvec = KERNEL_ADDRESS_DATA_BASE + 0xde0ee8;
sysentvec_ps4 = KERNEL_ADDRESS_DATA_BASE + 0xde1060;
break;
default:
etaHEN_log("Unsupported firmware");
return false;
}
if(kernel_getshort(sysentvec_ps4 + 14) == 0xffff) {
etaHEN_log("already paused, doing nothing");
} else {
kernel_setshort(sysentvec + 14, 0xffff);
kernel_setshort(sysentvec_ps4 + 14, 0xffff);
}
return true;
}
void LoadSettings() {
if (if_exists("/data/etaHEN/config.ini")) {
IniParser parser;
if (ini_parser_load( & parser, "/data/etaHEN/config.ini")) {
const char * libhijacker_cheats_str =
ini_parser_get( & parser, "Settings.libhijacker_cheats", "0");
const char * PS5Debug_str =
ini_parser_get( & parser, "Settings.PS5Debug", "0");
const char * start_option =
ini_parser_get( & parser, "Settings.StartOption", "0");
const char * DPI_v2 = ini_parser_get( & parser, "Settings.DPI_v2", "0");
const char * auto_eject_disc = ini_parser_get( & parser, "Settings.auto_eject_disc", "0");
// Check if the std::strings are not nullptr before converting
global_conf.libhijacker_cheats =
libhijacker_cheats_str ? atoi(libhijacker_cheats_str) : 0;
global_conf.PS5Debug = PS5Debug_str ? atoi(PS5Debug_str) : 0;
global_conf.start_opt =
start_option ? (StartOpts) atoi(start_option) : NONE;
global_conf.DPIv2 = DPI_v2 ? atoi(DPI_v2) : 0;
global_conf.toolbox_auto_start = atoi(ini_parser_get( & parser, "Settings.toolbox_auto_start", "1"));
global_conf.seconds = atol(ini_parser_get( & parser, "Settings.Rest_Mode_Delay_Seconds", "0"));
global_conf.debug_app_jb_msg = atoi(ini_parser_get( & parser, "Settings.APP_JB_Debug_Msg", "0"));
global_conf.auto_eject_disc = auto_eject_disc ? atoi(auto_eject_disc) : 0;
if (if_exists("/mnt/usb0/toolbox_auto_start"))
global_conf.toolbox_auto_start = false;
} else {
notify(true, "Failed to Read the Settings file");
}
} else {
// Create default config if it doesn't exist
std::string ini_file(
"[Settings]\nPS5Debug=0\nFTP=1\nlaunch_itemzflow="
"0\ndiscord_rpc=0\nAllow_data_in_sandbox=1\nDPI=0\ntoolbox_auto_start=1\nDPI_v2=0\nKlog=0\nAPP_JB_Debug_Msg=0\nauto_eject_disc=0\n");
int fd = open("/data/etaHEN/config.ini", O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, ini_file.c_str(), ini_file.length());
close(fd);
notify(true, "etaHEN config created! @ /data/etaHEN/config.ini");
}
}
}
static pid_t find_pid(const char *name) {
int mib[4] = {1, 14, 8, 0};
pid_t pid = -1;
size_t buf_size;
uint8_t *buf;
if (sysctl(mib, 4, 0, &buf_size, 0, 0)) {
perror("sysctl");
return -1;
}
if (!(buf = (uint8_t *)malloc(buf_size))) {
perror("malloc");
return -1;
}
if (sysctl(mib, 4, buf, &buf_size, 0, 0)) {
perror("sysctl");
free(buf);
return -1;
}
for (uint8_t *ptr = buf; ptr < (buf + buf_size);) {
int ki_structsize = *(int *)ptr;
pid_t ki_pid = *(pid_t *)&ptr[72];
char *ki_tdname = (char *)&ptr[447];
ptr += ki_structsize;
if (strcmp(ki_tdname, name) == 0) {
printf("[MATCH] ki_pid: %d, ki_tdname: %s\n", ki_pid, ki_tdname);
pid = ki_pid;
break;
}
}
free(buf);
return pid;
}
int networkListen(const char *soc_path) {
struct sockaddr_un server;
unlink(soc_path);
etaHEN_log("[Daemon] Deleted Socket...");
int s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
etaHEN_log("[Daemon] Socket failed! %s", strerror(errno));
return INVAIL;
}
memset(&server, 0, sizeof(server));
server.sun_family = AF_UNIX;
strcpy(server.sun_path, soc_path);
int r = bind(s, (struct sockaddr *)&server, SUN_LEN(&server));
if (r < 0) {
etaHEN_log("[Daemon] Bind failed! %s", strerror(errno));
return INVAIL;
}
//etaHEN_log("Socket has name %s", server.sun_path);
r = listen(s, 100);
if (r < 0) {
etaHEN_log("[Daemon] listen failed! %s", strerror(errno));
return INVAIL;
}
return s;
}
int networkAccept(int socket) {
//touch_file("/system_tmp/IPC_init");
return accept(socket, 0, 0);
}
int networkReceiveData(int socket, void *buffer, int32_t size) {
int nu = recv(socket, buffer, size, 0);
etaHEN_log("got %i bytes", nu);
return nu;
}
int networkSendData(int socket, void *buffer, int32_t size) {
return send(socket, buffer, size, MSG_NOSIGNAL);
}
int networkSendDebugData(void *buffer, int32_t size) {
return networkSendData(DaemonSocket, buffer, size);
}
int networkCloseConnection(int socket) { return close(socket); }
int networkCloseDebugConnection() {
return networkCloseConnection(DaemonSocket);
}
#include <fcntl.h>
// pop -Winfinite-recursion error for this func for clang
#define MB(x) ((size_t)(x) << 20)
#define READ_SIZE 0x1024
bool test_sb_file(const char *filename) {
if (!filename) {
etaHEN_log("test_sb_file: filename is null");
return false;
}
int fd = open(filename, O_RDONLY);
if (fd < 0) {
etaHEN_log("test_sb_file: Failed to open %s", filename);
return false;
}
// Determine the size of the file
struct stat fileInfo;
if (fstat(fd, &fileInfo) < 0) {
etaHEN_log("test_sb_file: Failed to get file size for %s", filename);
close(fd);
return false;
}
off_t fileSize = fileInfo.st_size;
char buffer[READ_SIZE];
// Read start
if (read(fd, buffer, READ_SIZE) < 0) {
etaHEN_log("test_sb_file: Failed to read start of %s", filename);
close(fd);
return false;
}
// Calculate middle, ensuring we don't try to seek beyond the file size
off_t middlePosition =
fileSize / 2 > READ_SIZE ? fileSize / 2 - READ_SIZE / 2 : 0;
if (lseek(fd, middlePosition, SEEK_SET) < 0 ||
read(fd, buffer, READ_SIZE) < 0) {
etaHEN_log("test_sb_file: Failed to read middle of %s", filename);
close(fd);
return false;
}
// Read end
off_t endPosition = fileSize > READ_SIZE ? fileSize - READ_SIZE : 0;
if (lseek(fd, endPosition, SEEK_SET) < 0 || read(fd, buffer, READ_SIZE) < 0) {
etaHEN_log("test_sb_file: Failed to read end of %s", filename);
close(fd);
return false;
}
close(fd);
etaHEN_log("test_sb_file: Successfully sampled %s", filename);
return true;
}
extern "C" int sceSystemServiceKillApp(uint32_t appid, int opt, int method,
int reason);
extern "C" int sceSystemServiceGetAppId(const char *tid);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winfinite-recursion"
bool if_exists(const char *path);
extern std::string dumping_tid;
void reply(int sender_socket, bool error, std::string out_var = "Nothing") {
std::string inputStr = "{\"res\":" + std::to_string(error ? -1 : 0) +
", \"var\":\"" + out_var + "\"}";
IPCMessage outputMessage;
outputMessage.cmd = BREW_RETURN_VALUE;
outputMessage.error = error ? -1 : 0;
etaHEN_log("error: %d", outputMessage.error);
bzero(outputMessage.msg, sizeof(outputMessage.msg));
if (!inputStr.empty()) {
strncpy(outputMessage.msg, inputStr.c_str(), sizeof(outputMessage.msg) - 1);
// Null-terminate the destination array
outputMessage.msg[sizeof(outputMessage.msg) - 1] = '\0';
}
networkSendData(sender_socket, reinterpret_cast<void *>(&outputMessage),
sizeof(outputMessage));
}
int get_shellui_pid() {
int pid = -1;
size_t NumbOfProcs = 9999;
for (int j = 0; j <= NumbOfProcs; j++) {
char tmp_buf[500];
memset(tmp_buf, 0, sizeof(tmp_buf));
sceKernelGetProcessName(j, tmp_buf);
if (strcmp("SceShellUI", tmp_buf) == 0) {
pid = j;
break;
}
}
return pid == -1 ? find_pid( "SceShellUI") : pid;
}
extern "C" {
struct proc* get_proc_by_pid(pid_t pid);
uintptr_t set_proc_authid(pid_t pid, uintptr_t new_authid)
{
struct proc* proc = get_proc_by_pid(getpid());
if (proc)
{
//
// Read from kernel
//
uintptr_t authid = 0;
kernel_copyout((uintptr_t) proc->p_ucred + 0x58, &authid, sizeof(uintptr_t));
kernel_copyin(&new_authid, (uintptr_t) proc->p_ucred + 0x58, sizeof(uintptr_t));
free(proc);
return authid;
}
return 0;
}
int sceKernelTerminateProcess(int pid, int *ret);
}
void ForceKillProc(int pid) {
if (pid < 0) {
etaHEN_log("Invalid PID: %d", pid);
return;
}
#define DECID_AUTH_ID 0x4800000000000022 // required for killing with sceKernelTerminateProcess / sys_proc_term syscall
uintptr_t authid = set_proc_authid(getpid(), DECID_AUTH_ID );
int ret = 0;
if (sceKernelTerminateProcess(pid, &ret) != 0) {
etaHEN_log("Failed to terminate process with PID: %d, error: %d", pid, ret);
} else {
etaHEN_log("Successfully terminated process with PID: %d", pid);
}
set_proc_authid(getpid(), authid); // Restore original authid
}
bool cmd_enable_toolbox(){
int wait = 0;
char buz[100] = {0};
if(sceKernelMprotect(&buz[0], 100, 0x7) == 0){
if(pause_kstuff()){
etaHEN_log("Paused kstuff...");
touch_file("/system_tmp/kstuff_paused");
}
}
etaHEN_log("Activating toolbox...");
if (if_exists("/system_tmp/util_first_boot")) {
LoadSettings();
etaHEN_log("sleeping for %llu", global_conf.seconds);
sleep(global_conf.seconds);
}
notify(true, "Loading the etaHEN ToolBox...");
int pid = get_shellui_pid();
if (pid < 0) {
notify(true, "Failed to get shellui pid");
return false;
}
if (!Inject_Toolbox(pid, shellui_elf_start)) {
ForceKillProc(pid);
notify(true, "Failed to inject toolbox");
return false;
}
while (!if_exists("/system_tmp/toolbox_online")) {
etaHEN_log("waiting for toolbox to start");
sleep(1);
if(++wait >= 15){
ForceKillProc(pid);
notify(true, "Failed to load the etaHEN toolbox");
return false;
}
}
unlink("/system_tmp/toolbox_online");
return true;
}
void handleIPC(struct clientArgs *client, std::string &inputStr,
DaemonCommands command) {
constexpr uint32_t MAX_TOKENS = 256;
json_t pool[MAX_TOKENS]{};
int sender_app = client->socket;
struct stat buffer;
std::string path_buf, path_buf2, json_path;
const char *path = nullptr, *dest = nullptr;
char size_buf[0x255];
bool last_ipc_error = false;
std::string out_var = "Nothing"; // default send var
etaHEN_log("Received IPC command 0x%X", command);
json_t const *my_json =
inputStr.empty()
? NULL
: json_create((char *)inputStr.c_str(), pool, MAX_TOKENS);
if (!my_json) {
etaHEN_log("Error parsing JSON");
notify(true, "Error parsing JSON");
reply(sender_app, true);
return;
}
switch (command) {
case BREW_TEST_CONNECTION: {
reply(sender_app, false, out_var);
break;
}
case BREW_ENABLE_TOOLBOX: {
if(cmd_enable_toolbox()){
reply(sender_app, false);
} else {
reply(sender_app, true);
}
break;
}
case BREW_LAST_RET: {
reply(sender_app, last_ipc_error, last_ipc_error ? "1" : "0");
break;
}
case BREW_DECRYPT_DIR: {
reply(sender_app, false);
launchApp(dumping_tid.c_str());
std::string dump_path =
std::string(json_getPropertyValue(my_json, "dest_path"));
std::string sandbox_dir =
std::string(json_getPropertyValue(my_json, "src_path"));
etaHEN_log("Decrypt to %s", dump_path.c_str());
mkdir(dump_path.c_str(), 0777);
notify(false, "Attempting to decrypt %s -> %s", sandbox_dir.c_str(),
dump_path.c_str());
sleep(6);
last_ipc_error = !decrypt_dir(sandbox_dir, dump_path);
mkdir("/data/decryption_done.log", 0777);
launchApp("DUMP00000");
break;
}
case BREW_INSTALL_THE_STORE: {
int rv = sceAppInstUtilInitialize();
if (rv != 0) {
etaHEN_log("Store 3: Failed to initialize libSceAppInstUtil.sprx");
notify(true, "Store 3: Failed to initialize libSceAppInstUtil.sprx");
reply(sender_app, true);
break;
}
PlayGoInfo arg3;
SceAppInstallPkgInfo pkg_info;
(void)memset(&arg3, 0, sizeof(arg3));
for (size_t i = 0; i < NUM_LANGUAGES; i++) {
strncpy(arg3.languages[i], "", sizeof(language_t) - 1);
}
for (size_t i = 0; i < NUM_IDS; i++) {
strncpy(arg3.playgo_scenario_ids[i], "",
sizeof(playgo_scenario_id_t) - 1);
strncpy(*arg3.content_ids, "", sizeof(content_id_t) - 1);
}
MetaInfo arg1 = {.uri = "https://pkg-zone.com/update/Store-R2-PS5.pkg",
.ex_uri = "",
.playgo_scenario_id = "",
.content_id = "",
.content_name = "The Homebrew Store",
.icon_url = ""};
int num = sceAppInstUtilInstallByPackage(&arg1, &pkg_info, &arg3);
if (num == 0) {
notify(true, "the Store is now downloading");
} else {
notify(true,
"An error has occurred while trying to download the Store PKG "
"(error: 0x%X), Check your internet connection and try again",
num);
reply(sender_app, true);
break;
}
reply(sender_app, false);
break;
}
case BREW_ACTIVATE_DUMPER: {
dump_path = std::string(json_getPropertyValue(my_json, "dump_path"));
dump_opt =
(Dump_Option)json_getInteger(json_getProperty(my_json, "dump_opt"));
dump_title = std::string(json_getPropertyValue(my_json, "dump_title"));
reply(sender_app, false);
is_dumper_enabled = true;
break;
}
case BREW_TESTKIT_CHECK: {
reply(sender_app, !if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx"));
break;
}
case BREW_REMOUNT_FOLDER:
path_buf = std::string(json_getPropertyValue(my_json, "mount_dest"));
path_buf2 = std::string(json_getPropertyValue(my_json, "mount_src"));
json_path = path_buf + "/sce_sys/param.json";
etaHEN_log("change dir selected, %s", path_buf2.c_str());
if(path_buf.rfind("/user") == std::string::npos && path_buf.length() <= strlen("/system_ex/app/")) {
notify(true, "Invalid path of size %d", path_buf.length());
reply(sender_app, true);
break;
}
mkdir(path_buf.c_str(), 0777);
if (if_exists(json_path.c_str())) {
etaHEN_log("param.json exists, trying to unmount");
int retries = 0;
do {
if (retries == 0)
etaHEN_log("unmounting .....");
else
etaHEN_log("retrying attempt unmounting %d | prev. error %s", retries, strerror(errno));
if (retries >= 20) {
notify(true, "Failed to unmount | error %s",
strerror(errno));
reply(sender_app, true);
break;
}
retries++;
} while (unmount(path_buf.c_str(), MNT_FORCE) < 0);
}
if (!remount(path_buf2.c_str(), path_buf.c_str(), MNT_FORCE)) {
if (errno == EBADF || errno == EPERM ||
errno == EIO) { // if anyone repots a game not mounting til the 2nd
// time look at this
etaHEN_log("trying to unmount");
unmount(path_buf.c_str(), MNT_FORCE);
}
if (!remount(path_buf2.c_str(), path_buf.c_str(), MNT_UPDATE)) {
notify(true, "remount error: %s\nPath: %s", strerror(errno),
path_buf2.c_str());
etaHEN_log("remount error: %s Path: %s", strerror(errno),
path_buf2.c_str());
reply(sender_app, true);
break;
}
}
reply(sender_app, false);
break;
case BREW_STAT_CMD: {
path = json_getPropertyValue(my_json, "path");
if (stat(path, &buffer) == 0) {
snprintf(size_buf, sizeof(size_buf), "%ld", buffer.st_size);
etaHEN_log("%s exists | size %s", path, size_buf);
reply(sender_app, false, size_buf);
} else {
etaHEN_log("error for %s | %s", path, strerror(errno));
reply(sender_app, true);
}
break;
}
case BREW_CALC_DIR_SIZE: {
uint64_t size = calculateTotalSize(json_getPropertyValue(my_json, "path"));
snprintf(size_buf, sizeof(size_buf), "%lu", size);
etaHEN_log("size %lu", size_buf);
reply(sender_app, false, size_buf);
break;
}
case BREW_COPY_FILE: {
path = json_getPropertyValue(my_json, "path");
dest = json_getPropertyValue(my_json, "dest");
if (copyFile(path, dest, false)) {
reply(sender_app, false);
} else {
etaHEN_log("error for %s | %s", path, strerror(errno));
reply(sender_app, true);
}
break;
}
case BREW_COPY_DIR: {
path = json_getPropertyValue(my_json, "path");
dest = json_getPropertyValue(my_json, "dest");
snprintf(size_buf, sizeof(size_buf), "%lu", calculateTotalSize(path));
if (copyRecursive(path, dest)) {
reply(sender_app, false, size_buf);
} else {
etaHEN_log("error for %s | %s", path, strerror(errno));
reply(sender_app, true);
}
break;
}
case BREW_DELETE_DIR: {
path = json_getPropertyValue(my_json, "path");
if (rmtree(path)) {
reply(sender_app, false);
} else {
reply(sender_app, true);
}
break;
}
case BREW_TEST_SB_FILE: {
reply(sender_app, !test_sb_file(json_getPropertyValue(my_json, "path")));
break;
}
case BREW_DAEMON_PID: {
snprintf(size_buf, sizeof(size_buf), "%d", getpid());
reply(sender_app, false, size_buf);
break;
}
case BREW_TOGGLE_PS5DEBUG:{
OrbisKernelSwVersion sys_ver;
sceKernelGetProsperoSystemSwVersion(&sys_ver);
bool not_supported = ((sys_ver.version >> 16) < 0x300 || (sys_ver.version >> 16) >= 0x800);
if(not_supported){
notify(true, "PS5Debug is not supported on this firmware");
reply(sender_app, true);
break;
}
if(global_conf.PS5Debug){
notify(true, "PS5Debug is Running\nPS5Debug requires a restart to disable");
reply(sender_app, false);
break;
}
notify(true, "Loading PS5Debug...");
if (elfldr_spawn("/", STDOUT_FILENO, ps5debug_start, "PS5Debug") < 0) {
notify(true, "PS5Debug is starting\nWait for the PS5Debug welcome message");
global_conf.PS5Debug = true;
}
reply(sender_app, false);
break;
}
case BREW_UNUSED_1: {
// This command is not used anymore but kept for backwards compatibility
notify(true, "This command is not used anymore, Update itemzflow");
reply(sender_app, true);
break;
}
case BREW_KILL_DAEMON:{
is_handler_enabled = false;
exit(1337);
kill(getpid(), SIGKILL);
reply(sender_app, false);
break;
}
case BREW_FORCE_KILL_PID: {
int pid = json_getInteger(json_getProperty(my_json, "pid"));
if (pid < 0) {
etaHEN_log("Invalid PID: %d", pid);
reply(sender_app, true);
break;
}
ForceKillProc(pid);
reply(sender_app, false);
break;
}
case BREW_RELOAD_SETTINGS: {
LoadSettings();
// notify(true, "Reloaded Settings");
reply(sender_app, false);
break;
}
default:
notify(true, "Unknown command 0x%X", command);
reply(sender_app, true);
break;
}
}
void *ipc_client(void *args) {
struct clientArgs *client = (struct clientArgs *)args;
etaHEN_log("[Daemon IPC] Thread created for Socket %i", client->socket);
uint32_t readSize = 0;
IPCMessage ipcMessage; // Create an IPCMessage struct to store received data
while ((readSize = networkReceiveData(client->socket,
reinterpret_cast<void *>(&ipcMessage),
sizeof(ipcMessage))) > 0) {
if (ipcMessage.magic == 0xDEADBABE) {
// Handle IPCMessage
std::string message = ipcMessage.msg; // Retrieve the string message
handleIPC(client, message, ipcMessage.cmd);
} else {
etaHEN_log("[Daemon IPC][client %i] Invalid magic number",
client->cl_nmb);
ipcMessage.error = -1;
networkSendData(client->socket, reinterpret_cast<void *>(&ipcMessage),
sizeof(ipcMessage));
}
}
etaHEN_log(
"[Daemon IPC][client %i] IPC Connection disconnected, Shutting down ...",
client->cl_nmb);
networkCloseConnection(client->socket);
delete client;
pthread_exit(NULL);
return NULL;
}
void *IPC_loop(void *args) {
// Listen on port
int serverSocket = networkListen(CRIT_IPC_SOC);
if (serverSocket < 0) {
etaHEN_log("[Daemon IPC] networkListen error %s", strerror(errno));
return nullptr;
}
// Keep accepting client connections
int cli_new = 0;
while (true) {
// Accept a client connection
int clientSocket = networkAccept(serverSocket);
if (clientSocket < 0) {
etaHEN_log("[Daemon IPC] networkAccept error %s", strerror(errno));
break; // Breaking out of the loop on error to cleanup
}
etaHEN_log("[Daemon IPC] Connection Accepted");
etaHEN_log("[Daemon IPC] cl_nmb %i", cli_new);
// Build data to send to thread
auto clientParams = new clientArgs();
clientParams->ip = "localhost";
clientParams->socket = clientSocket;
clientParams->cl_nmb = cli_new;
etaHEN_log("[Daemon IPC] clientParams->cl_nmb %i", clientParams->cl_nmb);
pthread_t ipc_thread;
pthread_create(&ipc_thread, NULL, ipc_client, clientParams);
cli_new++;
}
// Cleanup
networkCloseConnection(serverSocket);
return nullptr;
}