mirror of
https://github.com/ApfelTeeSaft/Itemzflow.git
synced 2026-08-26 19:23:39 +00:00
- Fixed dumping DLCs and AC w/p data - Added an Install all PKGs option for folders with more than 1 PKG - Installing a PKG will no longer boot you back to settings - Carried over some improvements from the PS5 version of IF - Replaced reg. vectors for ThreadSafeVectors - Added the Chinese lang files - Fixed a bug that would cause the Utility thread to deadlock - Fixed a Bug that caused the daemon not to give a backtrace on 9.00
453 lines
12 KiB
C++
453 lines
12 KiB
C++
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdlib.h> // malloc, qsort, free
|
|
#include <unistd.h> // close
|
|
#include <sys/signal.h>
|
|
#include <errno.h>
|
|
#include <utils.h>
|
|
//#include <sys/mount.h>
|
|
#include <dumper.h>
|
|
#include <utils.h>
|
|
#include "lang.h"
|
|
#include <libkernel.h>
|
|
#include "feature_classes.hpp"
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
|
|
extern "C" int pthread_getthreadid_np();
|
|
#define OBRIS_BACKTRACE 1
|
|
#define SYS_mount 21
|
|
using namespace multi_select_options;
|
|
|
|
extern "C" int sys_mount(const char *type, const char *dir, int flags, void *data){
|
|
return syscall(SYS_mount, type, dir, flags, data);
|
|
}
|
|
|
|
extern ItemzSettings set,
|
|
* get;
|
|
|
|
extern char* gm_p_text[20];
|
|
extern "C" int backtrace(void **buffer, int size);
|
|
Dump_Multi_Sels dump = SEL_DUMP_ALL;
|
|
// IPC IS USING C
|
|
extern std::string ipc_msg;
|
|
|
|
int wait_for_game(char *title_id)
|
|
{
|
|
int res = 0;
|
|
|
|
DIR *dir;
|
|
struct dirent *dp;
|
|
|
|
|
|
dir = opendir("/mnt/sandbox/pfsmnt");
|
|
if (!dir)
|
|
return 0;
|
|
|
|
|
|
while ((dp = readdir(dir)) != NULL)
|
|
{
|
|
|
|
log_info("%s", dp->d_name);
|
|
|
|
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
|
{
|
|
// do nothing (straight logic)
|
|
}
|
|
else
|
|
{
|
|
log_info("%s", dp->d_name);
|
|
|
|
if (strstr(dp->d_name, "-app0") != NULL)
|
|
{
|
|
res = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
closedir(dir);
|
|
log_info("wait_for_game finish");
|
|
|
|
return res;
|
|
}
|
|
|
|
bool dump_to_diff_folder(std::string &title_id, std::string& usb_p, std::string& gtitle, Dump_Multi_Sels dump)
|
|
{
|
|
std::string tmp;
|
|
// make a switch case for dump
|
|
|
|
print_memory();
|
|
if (dump != SEL_GAME_PATCH || if_exists(fmt::format("/user/patch/{}/patch.pkg", title_id).c_str()))
|
|
{
|
|
switch(dump)
|
|
{
|
|
case SEL_GAME_PATCH: {
|
|
return Dumper(usb_p, title_id, GAME_PATCH, gtitle);
|
|
break;
|
|
}
|
|
case SEL_DLC:{
|
|
return Dumper(usb_p, title_id, ADDITIONAL_CONTENT_DATA, gtitle);
|
|
break;
|
|
}
|
|
default: {
|
|
log_debug("Unknown Dump Type");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_debug("Patch doesnt exist...");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Dump_w_opts(std::string tid, std::string d_p, std::string gtitle, Dump_Multi_Sels dump)
|
|
{
|
|
std::string tmp = fmt::format("/mnt/sandbox/pfsmnt/{}-app0-nest/pfs_image.dat", tid);
|
|
if (!if_exists(tmp.c_str())) {
|
|
log_error("Dump_w_opts: %s doesnt exist", tmp.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (dump == SEL_DUMP_ALL) {
|
|
if (Dumper(d_p, tid, BASE_GAME, gtitle)) {
|
|
return dump_to_diff_folder(tid, d_p, gtitle, SEL_GAME_PATCH);
|
|
}
|
|
else {
|
|
log_debug("Dumping Base game failed, trying to dump as Remaster...");
|
|
if (Dumper(d_p, tid, REMASTER, gtitle)) {
|
|
return dump_to_diff_folder(tid, d_p, gtitle, SEL_GAME_PATCH);
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (dump == SEL_BASE_GAME) {
|
|
if (Dumper(d_p, tid, BASE_GAME, gtitle)) {
|
|
|
|
tmp = fmt::format("{}/{}.complete", d_p, tid);
|
|
touch_file(tmp.c_str());
|
|
tmp = fmt::format("{}/{}.dumping", d_p, tid);
|
|
unlink(tmp.c_str());
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else if (dump == SEL_GAME_PATCH) {
|
|
return dump_to_diff_folder(tid, d_p, gtitle, dump);
|
|
}
|
|
else if (dump == SEL_REMASTER) {
|
|
return Dumper(d_p, tid, REMASTER, gtitle);
|
|
}
|
|
else if (dump == SEL_DLC) {
|
|
return dump_to_diff_folder(tid, d_p, gtitle, dump);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int (*rejail_multi)(void) = NULL;
|
|
|
|
void Exit_Success(const char* text)
|
|
{
|
|
log_info("%s", text);
|
|
log_info("Disable Home Menu Redirect Called for Exit....");
|
|
|
|
if (rejail_multi) {
|
|
log_debug("Rejailing App >>>");
|
|
rejail_multi();
|
|
log_debug("App ReJailed");
|
|
}
|
|
|
|
if(reboot_app)
|
|
sceSystemServiceLoadExec("/app0/ItemzCore.self", 0);
|
|
|
|
log_debug("Calling SystemService Exit");
|
|
sceSystemServiceLoadExec("exit", 0);
|
|
}
|
|
|
|
void Exit_App_With_Message(int sig_numb)
|
|
{
|
|
msgok(MSG_DIALOG::NORMAL, fmt::format("############# Program has gotten a FATAL Signal/Error: {0:d} ##########\n\n {1:}\n\n", sig_numb, getLangSTR(LANG_STR::PKG_TEAM)));
|
|
|
|
std::string tmp;
|
|
|
|
if (usbpath() != -1) {
|
|
//try our best to make the name not always the same
|
|
tmp = fmt::format("/mnt/usb{0:d}/itemzflow", usbpath());
|
|
mkdir(tmp.c_str(), 0777);
|
|
tmp = fmt::format("{}/crash.log", tmp);
|
|
|
|
if (touch_file(tmp.c_str())) {
|
|
copyFile(ITEMZ_LOG, tmp, false);
|
|
|
|
if (if_exists(DUMPER_LOG))
|
|
copyFile(DUMPER_LOG, tmp, false);
|
|
|
|
}
|
|
else
|
|
log_debug("failed writing log to %s", tmp.c_str());
|
|
|
|
}
|
|
else
|
|
log_error("[DUMP] failed to get usbpath");
|
|
|
|
Exit_Success("Exit_App_With_Message ->");
|
|
}
|
|
|
|
#if OBRIS_BACKTRACE==1
|
|
|
|
void OrbisKernelBacktrace(const char* reason) {
|
|
char addr2line[MAX_STACK_FRAMES * 20];
|
|
callframe_t frames[MAX_STACK_FRAMES];
|
|
OrbisKernelVirtualQueryInfo info;
|
|
char buf[MAX_MESSAGE_SIZE + 3];
|
|
unsigned int nb_frames = 0;
|
|
char temp[80];
|
|
|
|
memset(addr2line, 0, sizeof addr2line);
|
|
memset(frames, 0, sizeof frames);
|
|
memset(buf, 0, sizeof buf);
|
|
|
|
snprintf(buf, sizeof buf, "<118>[Crashlog]: %s\n", reason);
|
|
|
|
strncat(buf, "<118>[Crashlog]: Backtrace:\n", MAX_MESSAGE_SIZE);
|
|
sceKernelBacktraceSelf(frames, sizeof frames, &nb_frames, 0);
|
|
for (unsigned int i = 0; i < nb_frames; i++) {
|
|
memset(&info, 0, sizeof info);
|
|
sceKernelVirtualQuery(frames[i].pc, 0, &info, sizeof info);
|
|
|
|
snprintf(temp, sizeof temp,
|
|
"<118>[Crashlog]: #%02d %32s: 0x%lx\n",
|
|
i + 1, info.name, frames[i].pc - info.unk01 - 1);
|
|
strncat(buf, temp, MAX_MESSAGE_SIZE);
|
|
|
|
snprintf(temp, sizeof temp,
|
|
"0x%lx ", frames[i].pc - info.unk01 - 1);
|
|
strncat(addr2line, temp, sizeof addr2line - 1);
|
|
}
|
|
|
|
strncat(buf, "<118>[Crashlog]: addr2line: ", MAX_MESSAGE_SIZE);
|
|
strncat(buf, addr2line, MAX_MESSAGE_SIZE);
|
|
strncat(buf, "\n", MAX_MESSAGE_SIZE);
|
|
|
|
buf[MAX_MESSAGE_SIZE + 1] = '\n';
|
|
buf[MAX_MESSAGE_SIZE + 2] = '\0';
|
|
|
|
log_error("%s", buf);
|
|
}
|
|
#endif
|
|
bool is_dumper_running = false;
|
|
|
|
void SIG_Handler(int sig_numb)
|
|
{
|
|
std::string profpath;
|
|
IPC_Client& ipc = IPC_Client::getInstance();
|
|
rejail_multi = (int (*)(void))prx_func_loader("/app0/Media/jb.prx", "rejail_multi");
|
|
int fw = (ps4_fw_version() >> 16);
|
|
//void* bt_array[255];
|
|
//
|
|
switch (sig_numb)
|
|
{
|
|
case SIGABRT:
|
|
log_debug("ABORT called.");
|
|
goto SIGSEGV_handler;
|
|
break;
|
|
case SIGTERM:
|
|
log_debug("TERM called");
|
|
break;
|
|
case SIGINT:
|
|
log_debug("SIGINT called");
|
|
break;
|
|
case SIGQUIT:
|
|
Exit_Success("SIGQUIT Called");
|
|
break;
|
|
case SIGKILL:
|
|
Exit_Success("SIGKILL Called");
|
|
break;
|
|
case SIGSTOP:
|
|
log_debug("App has been suspeneded");
|
|
goto App_suspended;
|
|
break;
|
|
case SIGCONT:
|
|
log_debug("App has resumed");
|
|
goto App_Resumed;
|
|
break;
|
|
case SIGUSR2:
|
|
log_debug("SIGUSER2 called, Prob from libFMT");
|
|
goto App_Resumed;
|
|
break;
|
|
case SIGSEGV: {
|
|
SIGSEGV_handler:
|
|
log_debug("App has crashed");
|
|
if (dump != SEL_RESET)
|
|
{
|
|
msgok(MSG_DIALOG::WARNING, getLangSTR(LANG_STR::FATAL_DUMP_ERROR));
|
|
sceSystemServiceLoadExec("/app0/ItemzCore.self", 0);
|
|
}
|
|
unlink("/user/app/if_update.pkg");
|
|
goto backtrace_and_exit;
|
|
}
|
|
default:
|
|
|
|
//Proc info and backtrace
|
|
goto backtrace_and_exit;
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
backtrace_and_exit:
|
|
log_debug("backtrace_and_exit called");
|
|
ipc.IPCSendCommand(IPC_Commands::DISABLE_HOME_REDIRECT, ipc_msg);
|
|
|
|
if(get->setting_bools[INTERNAL_UPDATE])
|
|
mkdir("/user/recovery.flag", 0777);
|
|
|
|
profpath = fmt::format("/mnt/proc/{0:d}/", getpid());
|
|
if (getuid() == 0 && !if_exists(profpath.c_str()))
|
|
{
|
|
int result = mkdir("/mnt/proc", 0777);
|
|
if (result < 0 && errno != 17)
|
|
log_debug("Failed to create /mnt/proc: %s", strerror(errno));
|
|
|
|
result = sys_mount("procfs", "/mnt/proc", 0, NULL);
|
|
if (result < 0)
|
|
log_debug("Failed to mount procfs: %s", strerror(errno));
|
|
}
|
|
//
|
|
log_debug("############# Program has gotten a FATAL Signal: %i ##########", sig_numb);
|
|
log_debug("# Thread ID: %i", pthread_getthreadid_np());
|
|
log_debug("# PID: %i", getpid());
|
|
|
|
if (getuid() == 0)
|
|
log_debug("# mounted ProcFS to %s", profpath.c_str());
|
|
|
|
|
|
log_debug("# UID: %i", getuid());
|
|
|
|
char buff[255];
|
|
|
|
if (getuid() == 0)
|
|
{
|
|
FILE* fp;
|
|
|
|
fp = fopen("/mnt/proc/curproc/status", "r");
|
|
fscanf(fp, "%s", &buff[0]);
|
|
log_debug("# Reading curproc...");
|
|
log_debug("# Proc Name: %s", &buff[0]);
|
|
fclose(fp);
|
|
}
|
|
log_debug("################### Backtrace ########################");
|
|
|
|
#if OBRIS_BACKTRACE==1
|
|
#if __cpplusplus
|
|
extern "C" {
|
|
#endif
|
|
OrbisKernelBacktrace("Fatal Signal");
|
|
#if __cpplusplus
|
|
}
|
|
#endif
|
|
#endif
|
|
void* bt_array[255];
|
|
|
|
if(fw <= 0x505)
|
|
backtrace(bt_array, 255);
|
|
|
|
Exit_App_With_Message(sig_numb);
|
|
|
|
|
|
|
|
App_suspended:
|
|
log_debug("App Suspended Checking for opened games...");
|
|
App_Resumed:
|
|
log_debug("App Resumed Checking for opened games...");
|
|
|
|
//lock thread mutex so it doesnt constantly continue running
|
|
//while we are dumping or checking if a game is open
|
|
// only unlcok at the end of the func
|
|
if(!is_remote_va_launched && app_status.load() != APP_NA_STATUS){
|
|
int BigAppid = sceSystemServiceGetAppIdOfBigApp();
|
|
if ((BigAppid & ~0xFFFFFF) == 0x60000000) {
|
|
log_info("[SIGNAL] FOUND Open Game: %x : Bool: %d", BigAppid, (BigAppid & ~0xFFFFFF) == 0x60000000);
|
|
if(sceLncUtilGetAppId(title_id.get().c_str()) == sceSystemServiceGetAppIdOfBigApp())
|
|
app_status = RESUMABLE;
|
|
else
|
|
app_status = OTHER_APP_OPEN;
|
|
}
|
|
else
|
|
log_info("[SIGNAL] No Open Games detected");
|
|
}
|
|
|
|
|
|
// char* title_id.get() = "CUSA02290";
|
|
if ( dump != SEL_RESET)
|
|
{
|
|
is_dumper_running = true;
|
|
std::string tmp;
|
|
std::string tmp2;
|
|
progstart((char*)getLangSTR(LANG_STR::STARTING_DUMPER).c_str());
|
|
|
|
fmt::print("title_id.get(): {}, DUMPER_PATH: {}", title_id.get(), get->setting_strings[DUMPER_PATH]);
|
|
tmp = fmt::format("{}/{}", get->setting_strings[DUMPER_PATH], title_id.get());
|
|
|
|
if (dump == SEL_BASE_GAME && if_exists(tmp.c_str()))
|
|
{
|
|
ProgSetMessagewText(5, getLangSTR(LANG_STR::DELETING_GAME_FOLDER).c_str());
|
|
rmtree(tmp.c_str());
|
|
tmp = fmt::format("{}/{}.complete", get->setting_strings[DUMPER_PATH], title_id.get());
|
|
unlink(tmp.c_str());
|
|
}
|
|
|
|
tmp = fmt::format("{}/{}-patch/", get->setting_strings[DUMPER_PATH], title_id.get());
|
|
if (dump == SEL_GAME_PATCH && if_exists(tmp.c_str()))
|
|
{
|
|
ProgSetMessagewText(5, getLangSTR(LANG_STR::DELETING_GAME_FOLDER).c_str());
|
|
rmtree(tmp.c_str());
|
|
}
|
|
|
|
//dump_game has all the dialoge for copied proc
|
|
if (Dump_w_opts(title_id.get(), get->setting_strings[DUMPER_PATH], g_idx > all_apps.size() ? "WTF" : all_apps[g_idx].info.name, dump)){
|
|
msgok(MSG_DIALOG::NORMAL, fmt::format("{0:} {1:} {2:}", getLangSTR(LANG_STR::DUMP_OF), title_id.get(), getLangSTR(LANG_STR::COMPLETE_WO_ERRORS)));
|
|
}
|
|
else{
|
|
|
|
if (usbpath() != -1) {
|
|
//try our best to make the name not always the same
|
|
tmp = fmt::format("/mnt/usb{}/itemzflow", usbpath());
|
|
mkdir(tmp.c_str(), 0777);
|
|
tmp = fmt::format("{}/dumper.log", tmp);
|
|
|
|
if (touch_file(tmp.c_str())) {
|
|
log_debug("Dump failed writing log to %s", tmp.c_str());
|
|
copyFile(DUMPER_LOG, tmp, false);
|
|
}
|
|
}
|
|
else
|
|
log_error("[DUMP] failed to get usbpath");
|
|
|
|
|
|
msgok(MSG_DIALOG::WARNING, fmt::format("{0:} {1:} {2:}", getLangSTR(LANG_STR::DUMP_OF), title_id.get(), getLangSTR(LANG_STR::DUMP_FAILED)));
|
|
}
|
|
|
|
print_memory();
|
|
|
|
log_info("finished");
|
|
is_dumper_running = false;
|
|
dump = SEL_RESET;
|
|
|
|
}
|
|
if (is_dumper_running){
|
|
msgok(MSG_DIALOG::NORMAL, getLangSTR(LANG_STR::DUMPER_CANCELLED));
|
|
dump = SEL_RESET;
|
|
is_dumper_running = false;
|
|
}
|
|
|
|
}
|