installer no-bugs pass: IME bound, evict race, EAGAIN cap, net probe-init

This commit is contained in:
SirHumza committed 2026-09-24 17:14:41 +02:00
1 parent 88815e232f
commit 65350d9cea
5 files changed
+41 -20

No files matched your search

Binary file not shown.
+8 -9
View File
@@ -25,7 +25,6 @@ static long file_mtime(const char *p){
static void step_inject_body(void){
int port = 0;
long before;
char msg[160];
if(ui_progress_open("Injecting orbisRPC...") != 0){
ui_ok("Could not open progress dialog. Continuing.");
@@ -35,18 +34,17 @@ static void step_inject_body(void){
* would stand a fresh inject down. Evict exits instantly when nothing
* runs, so this is zero-harm in every case. */
ui_progress_msg("Stopping old daemon (if any)...");
before = file_mtime(EVICT_RESULT);
remove(EVICT_RESULT); /* any appearance below = this run finished */
if(send_file_loopback(EVICT_ELF, &port, NULL) == 0){
/* No prior result file means first-ever run (or wiped data):
* evict answers instantly there, so only wait briefly. An
* existing install gets the full grace period (clean stop is
* fast; a wedged holder needs the SIGKILL fallback window). */
int budget = (before == 0) ? 10 : 40;
/* Removal above makes the wait self-limiting: instant evict
* answers break the first poll. The full budget only ever
* runs when a wedged holder needs the SIGKILL fallback. */
int budget = 40;
int waited = 0;
while(waited < budget){
sleep(2);
waited += 2;
if(file_mtime(EVICT_RESULT) != before) break;
if(file_mtime(EVICT_RESULT) != 0) break;
snprintf(msg, sizeof msg, "Stopping old daemon... (%ds)", waited);
ui_progress_msg(msg);
}
@@ -110,7 +108,7 @@ static void step_nettest(void){
used += (size_t)snprintf(out + used, sizeof out - used,
"\n%s: %s", t[i].label, ok ? "OK" : "FAIL");
if(used >= sizeof out - 64) break;
ui_progress_set((i + 1) * 100 / 4);
ui_progress_set((unsigned)((i + 1) * 100u / (sizeof t / sizeof t[0])));
}
ui_progress_close();
ui_ok(out);
@@ -131,6 +129,7 @@ static void step_tweaks(void){
}
/* Poll interval */
if(ui_confirm("Change the poll interval (seconds)?") == 1){
buf[0] = 0; /* never prefill a number field with prior text */
if(ui_input("Poll interval", "5 to 60", buf, sizeof buf) == 1 && buf[0]){
n = strtol(buf, &end, 10);
if(end != buf && *end == 0 && n >= 5 && n <= 60){
+1 -1
View File
@@ -3,7 +3,7 @@
<volume>
<volume_type>pkg_ps4_app</volume_type>
<volume_id>PS4VOLUME</volume_id>
<volume_ts>2026-09-24 17:08:35</volume_ts>
<volume_ts>2026-09-24 17:14:20</volume_ts>
<package content_id="IV0000-ORPC00001_00-ORBISRPCSETUP000" passcode="00000000000000000000000000000000"
storage_type="digital50" app_type="full" />
<chunk_info chunk_count="1" scenario_count="1">
+15 -3
View File
@@ -20,9 +20,15 @@ static const int SEND_PORTS[] = { 9090, 9021, 9020 };
int net_init(void){
#ifdef INSTALLER_PS4
static int done = 0;
int probe;
if(done) return 0;
if(sceNetInit() < 0) return -1;
if(sceNetPoolCreate("orbisrpc", 64*1024, 0) < 0) return -1;
/* Best-effort: the stack may already be up (re-init calls then fail
* harmlessly). Ground truth is a probe socket, not return codes. */
(void)sceNetInit();
(void)sceNetPoolCreate("orbisrpc", 64*1024, 0);
probe = socket(AF_INET, SOCK_STREAM, 0);
if(probe < 0) return -1;
close(probe);
done = 1;
#endif
return 0;
@@ -41,13 +47,19 @@ static int send_one(int fd, const char *path, void (*progress)(unsigned)){
if(progress) progress(0);
while((n = fread(buf, 1, sizeof buf, f)) > 0){
size_t off = 0;
int stalls = 0;
while(off < n){
ssize_t w = send(fd, buf + off, n - off, 0);
if(w <= 0){
if(errno == EAGAIN || errno == EWOULDBLOCK) continue;
/* Blocking socket + SNDTIMEO: EAGAIN means the loader
* stopped reading. Retry briefly, then fail instead of
* spinning forever. */
if((errno == EAGAIN || errno == EWOULDBLOCK) && ++stalls < 4)
continue;
fclose(f);
return -1;
}
stalls = 0;
off += (size_t)w;
}
sent += (long)n;
+17 -7
View File
@@ -1,6 +1,6 @@
/* ui.c - native PS4 dialogs: MsgDialog (ok / yes-no / progress) + ImeDialog.
* Host-testable pure parts live in ui_text.c; everything here needs the
* console (dialog system calls). */
* Everything here needs the console (dialog system calls); pure logic
* (validation, config merge) lives in icfg.c and is host-tested. */
#include "ui.h"
#include <stdio.h>
#include <string.h>
@@ -137,11 +137,21 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
st.verticalAlignment = ORBIS_V_CENTER;
st.placeholder = wplace;
st.title = wtitle;
sceImeDialogInit(&st, NULL);
/* Pump until the OSK stops (IME uses its own status enum). */
while(sceImeDialogGetStatus() != ORBIS_DIALOG_STATUS_STOPPED){
/* The dialog system needs no explicit pump; yield briefly. */
sceKernelUsleep(20000);
if(sceImeDialogInit(&st, NULL) < 0) return -1;
/* Pump until the OSK stops (IME uses its own status enum). Bounded:
* a dialog stuck in NONE (failed init we couldn't see) aborts instead
* of hanging the installer forever. */
{
int spins = 0;
OrbisDialogStatus ds;
while((ds = sceImeDialogGetStatus()) != ORBIS_DIALOG_STATUS_STOPPED){
if(ds == ORBIS_DIALOG_STATUS_NONE && ++spins > 250){
sceImeDialogTerm();
return -1;
}
if(ds != ORBIS_DIALOG_STATUS_NONE) spins = 0;
sceKernelUsleep(20000);
}
}
memset(&res, 0, sizeof res);
if(sceImeDialogGetResult(&res) < 0){ sceImeDialogTerm(); return -1; }