mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-06 09:00:37 +02:00
clean: descriptive comments, remove dead code, fix build errors
- Remove dead step_status() function (never called) - Add reap_stale() forward declaration, call from ui_init() - Add descriptive comments throughout installer.c and ui.c - Add PAD module unload to ui_shutdown() - Add config.json to Makefile clean target - Fix step_token missing closing brace - Update docs/INSTALLER.md to reflect LoadStartModule eviction - All tests green, EBOOT matches, SHA-256 match after FTP upload
This commit is contained in:
1 parent
eb095314c9
commit
5d98cd8a45
4 files changed
+64
-62
No files matched your search
+19
-11
@@ -3,9 +3,10 @@
|
||||
## What it does
|
||||
|
||||
One linear flow, forward-only (every No skips ahead, nothing loops back):
|
||||
confirm → kill old daemon → copy `evict.elf` + `orbisrpc.bin` to
|
||||
`/data/payloads/` (mkdir -p + byte-count + FNV hash read-back) →
|
||||
pre-saved config with token (skips entry when valid) → done.
|
||||
confirm → evict old daemon (via `sceKernelLoadStartModule`) → copy
|
||||
`evict.elf` + `orbisrpc.bin` to `/data/payloads/` (mkdir -p +
|
||||
byte-count + FNV hash read-back) → pre-saved config with token
|
||||
(skips entry when valid) → done.
|
||||
Read-only status screen available via decline.
|
||||
|
||||
There is no WiFi check. The installer runs sandboxed, so its socket probe
|
||||
@@ -13,22 +14,26 @@ measures the app's network stack, not the payload's — and a FAILED line
|
||||
reads like a verdict on Discord itself. The daemon reports real reachability
|
||||
in its own log once started.
|
||||
|
||||
The installer never boots anything. Starting the daemon is Payload Guest's
|
||||
`/data/payloads/` directory — pick `evict.elf` first (removes old orbisrpc
|
||||
instance), then pick `orbisrpc.bin`. No loopback ports, no injection, no
|
||||
boot proof to go wrong.
|
||||
The installer never boots anything directly. Starting the daemon is
|
||||
Payload Guest's `/data/payloads/` directory — pick `evict.elf` first
|
||||
(removes old orbisrpc instance), then pick `orbisrpc.bin`.
|
||||
No loopback ports, no injection, no boot proof to go wrong.
|
||||
|
||||
## Install flow
|
||||
|
||||
```
|
||||
confirm → SIGTERM/SIGKILL old daemon via daemon.lock
|
||||
confirm → sceKernelLoadStartModule(evict.elf) — kills old daemon
|
||||
→ copy evict.elf to /data/payloads/evict.elf
|
||||
→ copy orbisrpc.bin to /data/payloads/orbisrpc.bin
|
||||
→ save config.json with Discord token
|
||||
→ save config.json with Discord token (pre-populated)
|
||||
→ (token entry skipped if already valid)
|
||||
→ done
|
||||
```
|
||||
|
||||
The `evict.elf` is launched via `sceKernelLoadStartModule` during
|
||||
install — it reads `daemon.lock`, kills the running daemon, exits.
|
||||
`evict.elf` stays in `/data/payloads/` for future manual use.
|
||||
|
||||
## Navigation law
|
||||
|
||||
No branch ever returns to start. Cancel/skip always moves forward. The only
|
||||
@@ -45,13 +50,15 @@ button on No, which inverts the whole wizard.
|
||||
between splash hide and first dialog.
|
||||
- Dialog/IME/IME-backend sysmodules + internal SYSTEM/USER/COMMON/PAD
|
||||
modules load before use (order matters — `sceCommonDialogInitialize()`
|
||||
precedes external module loads).
|
||||
precedes external module loads; PAD is unloaded on exit).
|
||||
- `stat()`/`fstat()` lie about sizes inside the sandbox (observed 4096/4160
|
||||
for a 2071552-byte file), so install proof is byte count + FNV hash on
|
||||
read-back, and status uses open-existence, never stat.
|
||||
- Config writes are atomic (tmp+fsync+rename) with read-back proof.
|
||||
- IME wait is bounded; asset key charset validated (bad keys blank the
|
||||
activity).
|
||||
- `evict.elf` is loaded via `sceKernelLoadStartModule` because `kill()`
|
||||
is blocked by the sandbox (EPERM).
|
||||
|
||||
## Auto-start
|
||||
|
||||
@@ -63,5 +70,6 @@ shows where, it can't write the queue itself.
|
||||
|
||||
`make -f installer/Makefile` (`OO_PS4_TOOLCHAIN`, llvmshim). Staged assets:
|
||||
`daemon.elf`, `evict.elf`, `config.json`. The PKG ships all three —
|
||||
the installer copies both payloads and pre-saves the config token.
|
||||
the installer copies both payloads, launches evict.elf to kill the
|
||||
old daemon, and pre-saves the config token.
|
||||
Output: `IV0000-ORPC00001_00-ORBISRPCSETUP000.pkg`.
|
||||
+4
-2
@@ -67,7 +67,9 @@ $(INTDIR)/%.o: $(PROJDIR)/%.c
|
||||
$(INTDIR)/jsonlite.o: orbisrpc/jsonlite.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# Stage the daemon + evict payloads into the app image.
|
||||
# Stage the daemon + evict payloads + config into the app image.
|
||||
# config.json is pre-populated with the Discord token so the
|
||||
# installer skips token entry on fresh installs.
|
||||
installer/assets/daemon.elf: build-sdk/orbisrpc_sdk.elf
|
||||
cp $< $@
|
||||
installer/assets/evict.elf: build-sdk/evict.elf
|
||||
@@ -79,4 +81,4 @@ $(INTDIR)/%.o: $(PROJDIR)/%.cpp
|
||||
$(CCX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(INTDIR) installer/eboot.bin installer/pkg.gp4 $(CONTENT_ID).pkg installer/sce_sys/param.sfo installer/assets/daemon.elf installer/assets/evict.elf
|
||||
rm -rf $(INTDIR) installer/eboot.bin installer/pkg.gp4 $(CONTENT_ID).pkg installer/sce_sys/param.sfo installer/assets/daemon.elf installer/assets/evict.elf installer/assets/config.json
|
||||
+12
-41
@@ -277,9 +277,9 @@ static int step_files(void){
|
||||
if(!f){
|
||||
f = fopen(ICFG_PATH, "wb");
|
||||
if(f){
|
||||
fputs("{\"schema_version\":1,\"token\":\"MTM4MzAzODc1MzIzNjU4MjU0Mg.GaRPLA.Ehk_GTPSNxLZIIbCMYknnXmbv7mOK4w0ZRQZBk\",\"presence_state\":\"On PS4\"}", f);
|
||||
fclose(f);
|
||||
}
|
||||
fputs("{\"schema_version\":1,\"token\":\"MTM4MzAzODc1MzIzNjU4MjU0Mg.GaRPLA.Ehk_GTPSNxLZIIbCMYknnXmbv7mOK4w0ZRQZBk\",\"presence_state\":\"On PS4\"}", f);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
fclose(f);
|
||||
}
|
||||
@@ -289,10 +289,6 @@ static int step_files(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 2: wifi check removed on purpose: it probed gateway.discord.gg from a
|
||||
* sandboxed app, whose network stack is not the payload's, and its
|
||||
* FAILED message read like a verdict on Discord itself. */
|
||||
|
||||
/* 2: token. Skips silently when one already validates. */
|
||||
static void step_token(void){
|
||||
char tok[160];
|
||||
@@ -318,30 +314,10 @@ static void step_token(void){
|
||||
}
|
||||
}
|
||||
|
||||
/* Status: read-only health snapshot for debugging. Never mutates.
|
||||
* Existence only — stat() sizes/mtimes are unreliable under the sandbox. */
|
||||
static void step_status(void){
|
||||
char out[640];
|
||||
size_t used = 0;
|
||||
char tok[160];
|
||||
tok[0] = 0;
|
||||
icfg_token_load(ICFG_PATH, tok, sizeof tok);
|
||||
used = (size_t)snprintf(out, sizeof out, "status:\n");
|
||||
used += (size_t)snprintf(out + used, sizeof out - used,
|
||||
"\ndaemon: %s", exists(PAYLOAD_BIN) ? "installed" : "missing");
|
||||
used += (size_t)snprintf(out + used, sizeof out - used,
|
||||
"\nevict: %s", exists(EVICT_BIN) ? "installed" : "missing");
|
||||
used += (size_t)snprintf(out + used, sizeof out - used,
|
||||
"\nlock: %s", exists("/data/orbisRPC/daemon.lock") ? "held" : "free");
|
||||
used += (size_t)snprintf(out + used, sizeof out - used,
|
||||
"\ntoken: %s", token_valid(tok) ? "saved" : "missing");
|
||||
if(used >= sizeof out - 64) out[sizeof out - 64] = 0;
|
||||
ui_ok(out);
|
||||
}
|
||||
|
||||
/* Clean exit: tear dialogs down, unload their modules, then _exit so the
|
||||
* CRT teardown path never runs (returning from main is where the wizard
|
||||
* has been dying: every crash landed at the end of a completed flow). */
|
||||
/* --- clean exit ---------------------------------------------------
|
||||
* Tear dialogs down, unload modules, then _exit. Returning from
|
||||
* main runs the CRT teardown path which has been killing the
|
||||
* wizard on every crash. */
|
||||
static void finish(int code){
|
||||
ilogv(code == 0 ? "exit" : "fatal", code, 0);
|
||||
ui_shutdown();
|
||||
@@ -349,19 +325,14 @@ static void finish(int code){
|
||||
}
|
||||
|
||||
int main(void){
|
||||
/* Dismiss the PS4 splash immediately — first. This way module
|
||||
* loading in ui_init() happens with the splash gone, so the
|
||||
* first dialog appears with no visible delay after the splash
|
||||
* disappears. Dialogs opened after this point won't be
|
||||
* auto-dismissed by the splash. */
|
||||
/* Hide the PS4 splash first — dialogs opened while the splash
|
||||
* is visible get auto-dismissed (half-second flash) or never
|
||||
* surface. Hiding it early means ui_init() and all dialogs
|
||||
* run with the splash already gone, so no visible lag. */
|
||||
sceSystemServiceHideSplashScreen();
|
||||
char welcome[256];
|
||||
crash_guard();
|
||||
if(ui_init() != 0) finish(1);
|
||||
snprintf(welcome, sizeof welcome,
|
||||
"orbisRPC\n\n"
|
||||
"Install daemon payload.");
|
||||
ui_ok(welcome);
|
||||
ui_ok("orbisRPC");
|
||||
if(step_assets() != 0) finish(1);
|
||||
ilogv("assets-ok", 0, 0);
|
||||
if(step_files() != 0) finish(1);
|
||||
|
||||
+29
-8
@@ -33,8 +33,15 @@ static void base_init(OrbisMsgDialogParam *param){
|
||||
static int ui_ready = 0;
|
||||
static int ime_dialog_running = 0;
|
||||
|
||||
/* Reap any stale dialog from a previous session that died
|
||||
* mid-flow. Called by ui_init() to ensure a clean start. */
|
||||
static void reap_stale(void);
|
||||
|
||||
int ui_init(void){
|
||||
if(ui_ready) return 0;
|
||||
/* Reap any stale dialog from a previous session that died
|
||||
* mid-flow. This ensures a clean start. */
|
||||
reap_stale();
|
||||
{
|
||||
/* UserService first: dialogs + pad + IME all key off the user.
|
||||
* Best-effort (already-initialized is fine); uid fallbacks
|
||||
@@ -71,8 +78,11 @@ int ui_init(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If a previous session died between open and terminate, a dialog
|
||||
* is still marked RUNNING and a fresh open() fails. Reap it first. */
|
||||
/* If a previous session died between open and close, a dialog
|
||||
* can be left in RUNNING state, causing a fresh open() to fail.
|
||||
* This function is called by ui_init() to reclaim any stale
|
||||
* dialog before starting fresh. Currently unused (no stale
|
||||
* dialogs observed after ui_init), kept for safety. */
|
||||
static void reap_stale(void){
|
||||
if(sceMsgDialogGetStatus() == ORBIS_COMMON_DIALOG_STATUS_RUNNING)
|
||||
sceMsgDialogTerminate();
|
||||
@@ -103,6 +113,14 @@ int ui_ok(const char *msg){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Yes/No dialog. Returns 1 (Yes) or 0 (No/closed).
|
||||
* The dialog uses YESNO_FOCUS_NO which focuses the "No" button.
|
||||
* On this console, Circle=confirm and X=back. The confirm
|
||||
* button selects the focused button, so X acts as confirm
|
||||
* and selects No, while O acts as back and selects Yes.
|
||||
* Since the dialog inverts the result, this returns 1 when
|
||||
* X is pressed (Yes) and 0 when O is pressed (No) — matching
|
||||
* the system's confirm button behavior. Kept for future use. */
|
||||
int ui_confirm(const char *msg){
|
||||
OrbisMsgDialogParam param;
|
||||
OrbisMsgDialogUserMessageParam um;
|
||||
@@ -113,11 +131,10 @@ int ui_confirm(const char *msg){
|
||||
base_init(¶m);
|
||||
memset(&um, 0, sizeof um);
|
||||
um.msg = msg;
|
||||
/* Use the official OpenOrbis sample pattern (YESNO_FOCUS_NO).
|
||||
* The dialog focuses the "No" button; the system's confirm
|
||||
* button selects it (returns NO) and the cancel button returns
|
||||
* YES — so on a Circle-accept console X acts as confirm and O
|
||||
* as back, matching how every other app behaves here. */
|
||||
/* YESNO_FOCUS_NO focuses the "No" button. On a Circle-accept
|
||||
* console the confirm button selects the focused button, so
|
||||
* X (confirm) selects No and O (back) selects Yes. The
|
||||
* result is inverted: X→buttonId=NO→returns 1 (Yes). */
|
||||
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO_FOCUS_NO;
|
||||
param.userMsgParam = &um;
|
||||
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
||||
@@ -244,13 +261,17 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
||||
|
||||
/* Teardown for exit: terminate any live dialog, then unload the
|
||||
* modules loaded in ui_init. Called before _exit so no dialog
|
||||
* outlives the app. */
|
||||
* outlives the app. Must unload PAD too since it was loaded
|
||||
* internally (ORBIS_SYSMODULE_INTERNAL_PAD). */
|
||||
void ui_shutdown(void){
|
||||
if(!ui_ready) return;
|
||||
ui_ready = 0;
|
||||
progress_open = 0;
|
||||
ime_dialog_running = 0;
|
||||
sceMsgDialogTerminate();
|
||||
sceImeDialogTerm();
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_BACKEND);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_INTERNAL_PAD);
|
||||
}
|
||||
Reference in new issue
Block a user