Revert "refactor: remove kill disc player on startup functionality"

This reverts commit ba529e8917.

Restore the startup option, config persistence, API fields, and translated settings toggle while preserving later validation, atomic writes, HTTP response handling, and launcher changes. Use the validated shared process lookup and cover restored behavior with regression checks.
This commit is contained in:
najdek committed 2026-10-14 21:17:08 +02:00
1 parent fe5ca8121c
commit 71f983f4c5
29 files changed
+213 -28

No files matched your search

@@ -44,6 +44,7 @@ const SettingRow = ({ title, description, children, icon: Icon, vertical }) => (
const SettingsView = ({ config, onSaveConfig, setShowLogs, onNavigate, onClearCache }) => {
const { t, i18n } = useTranslation()
const autoOpen = config.AUTO_BROWSER_OPEN !== false
const killDiscPlayer = config.KILL_DISC_PLAYER_ON_STARTUP !== false
const autoInstall = config.AUTO_INSTALL_APP !== false
const autoloadDelay = config.AUTOLOAD_DELAY ?? 5
const multiSources = config.MULTI_SOURCES_ENABLED === true
@@ -164,6 +165,24 @@ const SettingsView = ({ config, onSaveConfig, setShowLogs, onNavigate, onClearCa
</button>
</SettingRow>
<SettingRow
title={t("settings.kill_disc_title", "Kill Disc Player")}
description={t("settings.kill_disc_desc", "Automatically terminate the Disc Player application on startup (for BD-JB users).")}
>
<button
onClick={() => onSaveConfig({ KILL_DISC_PLAYER_ON_STARTUP: !killDiscPlayer })}
className={cn(
"w-14 h-7 md:w-20 md:h-10 rounded-full transition-all relative p-1 md:p-1.5",
killDiscPlayer ? "bg-ps-blue" : "bg-white/10"
)}
>
<div className={cn(
"w-5 h-5 md:w-7 md:h-7 bg-white rounded-full transition-all",
killDiscPlayer ? "translate-x-7 md:translate-x-10" : "translate-x-0"
)} />
</button>
</SettingRow>
<SettingRow
title={t("settings.scan_usb_title", "Scan USB Payloads")}
description={t("settings.scan_usb_desc", "Enable scanning for .elf and .bin files in the root directory of USB drives (/mnt/usb0-7).")}
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "تشغيل المتصفح تلقائيًا عند تشغيل حمولة مدير الحمولة.",
"settings.auto_install_title": "تثبيت مشغل التطبيقات تلقائيًا",
"settings.auto_install_desc": "تثبيت تطبيق مدير الحمولات تلقائيًا على الشاشة الرئيسة لجهاز PS5.",
"settings.kill_disc_title": "إغلاق مشغل الأقراص",
"settings.kill_disc_desc": "إغلاق تطبيق مشغل الأقراص تلقائيًا عند بدء التشغيل (لمستخدمي BD-JB).",
"settings.scan_usb_title": "بحث عن الحمولات في USB",
"settings.scan_usb_desc": "تمكين البحث عن ملفات .elf و .bin في الدليل الجذر لمحركات أقراص USB (/mnt/usb0-7).",
"settings.autoload_delay_title": "تأخير التحميل التلقائي",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Startet den Browser automatisch, sobald der Payload Manager ausgeführt wird.",
"settings.auto_install_title": "App Launcher automatisch installieren",
"settings.auto_install_desc": "Installiert den Payload Manager automatisch auf dem PS5-Startbildschirm.",
"settings.kill_disc_title": "Disc-Player beenden",
"settings.kill_disc_desc": "Disc-Player beim Start automatisch beenden (für BD-JB-Nutzer).",
"settings.scan_usb_title": "USB-Payloads durchsuchen",
"settings.scan_usb_desc": "Durchsucht das Stammverzeichnis angeschlossener USB-Speicher (/mnt/usb0-7) nach .elf- und .bin-Dateien.",
"settings.autoload_delay_title": "Autoload-Verzögerung",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Automatically launch the browser when Payload Manager payload is executed.",
"settings.auto_install_title": "Auto-install App Launcher",
"settings.auto_install_desc": "Automatically install the Payload Manager app to the PS5 home screen.",
"settings.kill_disc_title": "Kill Disc Player",
"settings.kill_disc_desc": "Automatically terminate the Disc Player application on startup (for BD-JB users).",
"settings.scan_usb_title": "Scan USB Payloads",
"settings.scan_usb_desc": "Enable scanning for .elf and .bin files in the root directory of USB drives (/mnt/usb0-7).",
"settings.autoload_delay_title": "Autoload Delay",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Iniciar automáticamente el navegador cuando se ejecute Payload Manager.",
"settings.auto_install_title": "Instalar automáticamente el Menú de Aplicaciones",
"settings.auto_install_desc": "Instalar automáticamente la aplicación Payload Manager en la pantalla de inicio de PS5.",
"settings.kill_disc_title": "Cerrar el reproductor de discos",
"settings.kill_disc_desc": "Cerrar automáticamente el reproductor de discos al iniciar (para usuarios de BD-JB).",
"settings.scan_usb_title": "Escanear Payloads en el USB",
"settings.scan_usb_desc": "Habilitar el escaneo de archivos .elf y .bin en el directorio raíz de las unidades USB (/mnt/usb0-7).",
"settings.autoload_delay_title": "Retardo de la carga automática",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "هنگامی که پیلود منیجر اجرا شد، مرورگر به طور خودکار راه‌اندازی شود.",
"settings.auto_install_title": "نصب خودکار لانچر برنامه",
"settings.auto_install_desc": "اضافه کردن خودکار اپلیکیشن پیلود منیجر به صفحه خانه PS5.",
"settings.kill_disc_title": "بستن پخش‌کننده دیسک",
"settings.kill_disc_desc": "بستن خودکار برنامه پخش‌کننده دیسک هنگام راه‌اندازی (برای کاربران BD-JB).",
"settings.scan_usb_title": "اسکن کردن پیلودهای USB",
"settings.scan_usb_desc": "فعال کردن اسکن فایل‌های elf. و bin. در حافظه روت فلش (/mnt/usb0-7)",
"settings.autoload_delay_title": "تاخیر شروع اجرای خودکار",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Lancer automatiquement le navigateur internet lorsque le payload de Payload Manager est exécuté.",
"settings.auto_install_title": "Installer l'App Launcher auto",
"settings.auto_install_desc": "Installer automatiquement l'application Payload Manager sur l'écran d'accueil de la PS5.",
"settings.kill_disc_title": "Fermer le lecteur de disque",
"settings.kill_disc_desc": "Fermer automatiquement le lecteur de disque au démarrage (pour les utilisateurs de BD-JB).",
"settings.scan_usb_title": "Scanner les payloads USB",
"settings.scan_usb_desc": "Activer la recherche de fichiers .elf et .bin à la racine des périphériques USB (/mnt/usb0-7).",
"settings.autoload_delay_title": "Délai de lancement auto",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Avvia automaticamente il browser quando viene eseguito il payload di Payload Manager.",
"settings.auto_install_title": "Installazione automatica App",
"settings.auto_install_desc": "Installa automaticamente l'app Payload Manager sulla schermata iniziale della PS5.",
"settings.kill_disc_title": "Chiudi il lettore di dischi",
"settings.kill_disc_desc": "Chiudi automaticamente il lettore di dischi all’avvio (per gli utenti BD-JB).",
"settings.scan_usb_title": "Scansiona USB Payload",
"settings.scan_usb_desc": "Abilita la scansione dei file .elf e .bin nella directory principale delle unità USB (/mnt/usb0-7).",
"settings.autoload_delay_title": "Ritardo Autoload",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "ペイロードマネージャーが実行された時に、ブラウザを自動的に起動します。",
"settings.auto_install_title": "アプリランチャーの自動インストール",
"settings.auto_install_desc": "ペイロードマネージャーアプリをPS5のホーム画面に自動でインストールします。",
"settings.kill_disc_title": "ディスクプレーヤーを終了",
"settings.kill_disc_desc": "起動時にディスクプレーヤーを自動的に終了します(BD-JBユーザー向け)。",
"settings.scan_usb_title": "USBペイロード検索",
"settings.scan_usb_desc": "USBドライブのルートディレクトリ(/mnt/usb0-7)から .elf および .bin ファイルを検索します。",
"settings.autoload_delay_title": "自動実行の遅延",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "페이로드 매니저가 실행될 때 브라우저를 자동으로 실행합니다.",
"settings.auto_install_title": "앱 런처 자동 설치",
"settings.auto_install_desc": "페이로드 매니저 앱을 PS5 홈 화면에 자동으로 설치합니다.",
"settings.kill_disc_title": "디스크 플레이어 종료",
"settings.kill_disc_desc": "시작 시 디스크 플레이어 앱을 자동으로 종료합니다(BD-JB 사용자용).",
"settings.scan_usb_title": "USB 페이로드 검색",
"settings.scan_usb_desc": "USB 드라이브 루트 디렉토리(/mnt/usb0-7)에서 .elf 및 .bin 파일을 검색합니다.",
"settings.autoload_delay_title": "자동 실행 지연",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Open de browser automatisch wanneer de Payload Manager-payload wordt uitgevoerd.",
"settings.auto_install_title": "App automatisch installeren",
"settings.auto_install_desc": "Installeer de Payload Manager-app automatisch op het startscherm van de PS5.",
"settings.kill_disc_title": "Discspeler afsluiten",
"settings.kill_disc_desc": "Sluit de Discspeler automatisch af bij het opstarten (voor BD-JB-gebruikers).",
"settings.scan_usb_title": "USB-payloads zoeken",
"settings.scan_usb_desc": "Zoek naar .elf- en .bin-bestanden in de hoofdmap van USB-stations (/mnt/usb0-7).",
"settings.autoload_delay_title": "Wachttijd voor automatisch laden",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Automatycznie uruchamiaj przeglądarkę po wykonaniu payloadu.",
"settings.auto_install_title": "Autoinstalacja skrótu",
"settings.auto_install_desc": "Automatycznie instaluj skrót do aplikacji na ekranie głównym PS5.",
"settings.kill_disc_title": "Zamknij odtwarzacz płyt",
"settings.kill_disc_desc": "Automatycznie zamykaj odtwarzacz płyt przy uruchamianiu (dla użytkowników BD-JB).",
"settings.scan_usb_title": "Skanuj USB",
"settings.scan_usb_desc": "Włącz skanowanie w poszukiwaniu plików .elf/.bin w głównym katalogu dysków USB.",
"settings.autoload_delay_title": "Opóźnienie autostartu",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Abrir automaticamente o navegador quando o Payload Manager for executado.",
"settings.auto_install_title": "Instalar o atalho do App",
"settings.auto_install_desc": "Incluir automaticamente o atalho do Payload Manager na tela principal do PS5.",
"settings.kill_disc_title": "Fechar o reprodutor de discos",
"settings.kill_disc_desc": "Fechar automaticamente o reprodutor de discos na inicialização (para usuários do BD-JB).",
"settings.scan_usb_title": "Verificar payloads no dispositivo USB",
"settings.scan_usb_desc": "Ative a busca por arquivos .elf e .bin no caminho padrão nas unidades USB (/mnt/usb0-7).",
"settings.autoload_delay_title": "Atraso do carregamento automático",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Автоматически запускать браузер при выполнении полезной нагрузки в Менеджере полезных нагрузок.",
"settings.auto_install_title": "Автоматическая установка лаунчера приложений",
"settings.auto_install_desc": "Автоматически установить приложение Менеджер полезных нагрузок на главный экран PS5.",
"settings.kill_disc_title": "Закрыть проигрыватель дисков",
"settings.kill_disc_desc": "Автоматически закрывать проигрыватель дисков при запуске (для пользователей BD-JB).",
"settings.scan_usb_title": "Сканировать полезные нагрузки на USB",
"settings.scan_usb_desc": "Включить сканирование файлов .elf и .bin в корневом каталоге USB-накопителей (/mnt/usb0-7).",
"settings.autoload_delay_title": "Задержка автозагрузки",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "เปิดเบราว์เซอร์โดยอัตโนมัติเมื่อ payload Payload Manager ถูกดำเนินการ",
"settings.auto_install_title": "ติดตั้ง App Launcher อัตโนมัติ",
"settings.auto_install_desc": "ติดตั้งแอป Payload Manager บนหน้าจอหลักของ PS5 โดยอัตโนมัติ",
"settings.kill_disc_title": "ปิดเครื่องเล่นดิสก์",
"settings.kill_disc_desc": "ปิดแอปเครื่องเล่นดิสก์โดยอัตโนมัติเมื่อเริ่มต้น (สำหรับผู้ใช้ BD-JB)",
"settings.scan_usb_title": "สแกน USB Payloads",
"settings.scan_usb_desc": "เปิดการสแกนไฟล์ .elf และ .bin ในไดเรกทอรีรากของไดรฟ์ USB (/mnt/usb0-7)",
"settings.autoload_delay_title": "หน่วงเวลาการโหลดอัตโนมัติ",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Payload Manager yürütüldüğünde tarayıcıyı otomatik olarak başlatın.",
"settings.auto_install_title": "Otomatik Uygulama Başlatıcısı",
"settings.auto_install_desc": "Payload Manager uygulamasını otomatik olarak PS5 ana ekranına yükleyin.",
"settings.kill_disc_title": "Disk oynatıcıyı kapat",
"settings.kill_disc_desc": "Başlangıçta disk oynatıcı uygulamasını otomatik olarak kapat (BD-JB kullanıcıları için).",
"settings.scan_usb_title": "USB Veri Paketlerini Tara",
"settings.scan_usb_desc": "USB sürücülerinin kök dizininde (/mnt/usb0-7) .elf ve .bin dosyalarının taranmasını etkinleştirin.",
"settings.autoload_delay_title": "Otomatik Gecikmesi",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "Автоматично запускати браузер при виконанні навантаження Менеджера.",
"settings.auto_install_title": "Автоматично встановлювати іконку Менеджера",
"settings.auto_install_desc": "Автоматично встановлювати додаток менеджера на головний екран PS5.",
"settings.kill_disc_title": "Закрити програвач дисків",
"settings.kill_disc_desc": "Автоматично закривати програвач дисків під час запуску (для користувачів BD-JB).",
"settings.scan_usb_title": "Сканувати навантаження з USB",
"settings.scan_usb_desc": "Увімкнути сканування файлів .elf та .bin у кореневому каталозі USB-накопичувачів (/mnt/usb0-7).",
"settings.autoload_delay_title": "Затримка автозавантаження",
+2
View File
@@ -172,6 +172,8 @@
"settings.auto_open_desc": "启动 Payload 管理器时自动打开浏览器。",
"settings.auto_install_title": "自动安装应用启动器图标",
"settings.auto_install_desc": "自动将 Payload 管理器的网页快捷方式安装到 PS5 主屏幕。",
"settings.kill_disc_title": "关闭光盘播放器",
"settings.kill_disc_desc": "启动时自动关闭光盘播放器应用(适用于 BD-JB 用户)。",
"settings.scan_usb_title": "扫描 USB 存储中的 Payload",
"settings.scan_usb_desc": "启用对 USB 存储根目录(/mnt/usb0-7)中 .elf 和 .bin 文件的扫描。",
"settings.autoload_delay_title": "自动加载延迟",
+3 -1
View File
@@ -9,6 +9,7 @@ typedef struct PldmgrConfig {
long last_repository_update; /* Default: 0 */
int auto_browser_open; /* Default: 1 (on) */
int autoload_delay; /* Default: 5 (seconds) */
int kill_disc_player; /* Default: 1 (on) */
int scan_usb_payloads; /* Default: 0 (off) */
int auto_install_app; /* Default: 1 (on) */
int multi_sources_enabled; /* Default: 0 (off) */
@@ -30,7 +31,8 @@ enum { CONFIG_INVALID = -2 };
/* Apply a JSON config update sent from the frontend /set_config route.
* Handles AUTOLOAD_ENABLED, AUTO_BROWSER_OPEN, AUTOLOAD_DELAY,
* SCAN_USB_PAYLOADS, AUTO_INSTALL_APP, MULTI_SOURCES_ENABLED, and AUTOLOAD_LIST.
* KILL_DISC_PLAYER_ON_STARTUP, SCAN_USB_PAYLOADS, AUTO_INSTALL_APP,
* MULTI_SOURCES_ENABLED, and AUTOLOAD_LIST.
* Booleans must be JSON booleans; delay is an integer from 0 to 3600 seconds.
* Returns 0, CONFIG_INVALID for bad input, or -1 for persistence failure.
* All input is validated first; each file publishes atomically, but a multi-file
+5
View File
@@ -24,4 +24,9 @@ int ps5_launch_elf_cancellable(const char *path, PayloadLaunchCancelled cancelle
*/
int ps5_launch_browser(const char* uri);
/**
* Kill the "Disc Player" app (NPXS40140) if it is running.
* @return 0 if not running or successfully killed, -1 on error.
*/
int ps5_kill_disc_player(void);
+20 -20
View File
@@ -16,10 +16,10 @@ static pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
#define CONFIG_LIMIT (64 * 1024)
static const char *setting_keys[] = {"AUTOLOAD_ENABLED", "AUTO_BROWSER_OPEN",
"AUTOLOAD_DELAY", "SCAN_USB_PAYLOADS", "AUTO_INSTALL_APP", "MULTI_SOURCES_ENABLED"};
"AUTOLOAD_DELAY", "SCAN_USB_PAYLOADS", "AUTO_INSTALL_APP", "MULTI_SOURCES_ENABLED", "KILL_DISC_PLAYER_ON_STARTUP"};
static void defaults(PldmgrConfig *cfg) {
*cfg = (PldmgrConfig){.auto_browser_open=1, .autoload_delay=5, .auto_install_app=1};
*cfg = (PldmgrConfig){.auto_browser_open=1, .autoload_delay=5, .auto_install_app=1, .kill_disc_player=1};
}
static int read_config(PldmgrConfig *cfg) {
defaults(cfg);
@@ -36,8 +36,8 @@ static int read_config(PldmgrConfig *cfg) {
if (errno || *end || end == equal) continue;
if (!strcmp(line, "LAST_REPOSITORY_UPDATE")) { if (value >= 0) cfg->last_repository_update = value; continue; }
int *fields[] = {&cfg->autoload_enabled, &cfg->auto_browser_open, &cfg->autoload_delay,
&cfg->scan_usb_payloads, &cfg->auto_install_app, &cfg->multi_sources_enabled};
for (size_t i = 0; i < 6; i++) if (!strcmp(line, setting_keys[i])) {
&cfg->scan_usb_payloads, &cfg->auto_install_app, &cfg->multi_sources_enabled, &cfg->kill_disc_player};
for (size_t i = 0; i < 7; i++) if (!strcmp(line, setting_keys[i])) {
if (i == 2 ? value >= 0 && value <= 3600 : value == 0 || value == 1) *fields[i] = (int)value;
}
}
@@ -48,9 +48,9 @@ static int write_config(const PldmgrConfig *cfg) {
char text[512];
int length = snprintf(text, sizeof(text),
"AUTOLOAD_ENABLED=%d\nLAST_REPOSITORY_UPDATE=%ld\nAUTO_BROWSER_OPEN=%d\n"
"AUTOLOAD_DELAY=%d\nSCAN_USB_PAYLOADS=%d\nAUTO_INSTALL_APP=%d\nMULTI_SOURCES_ENABLED=%d\n",
"AUTOLOAD_DELAY=%d\nSCAN_USB_PAYLOADS=%d\nAUTO_INSTALL_APP=%d\nMULTI_SOURCES_ENABLED=%d\nKILL_DISC_PLAYER_ON_STARTUP=%d\n",
!!cfg->autoload_enabled, cfg->last_repository_update, !!cfg->auto_browser_open,
cfg->autoload_delay, !!cfg->scan_usb_payloads, !!cfg->auto_install_app, !!cfg->multi_sources_enabled);
cfg->autoload_delay, !!cfg->scan_usb_payloads, !!cfg->auto_install_app, !!cfg->multi_sources_enabled, !!cfg->kill_disc_player);
if (length < 0 || (size_t)length >= sizeof(text) || ensure_dir_recursive(BASE_DATA_DIR)) return -1;
char *old = NULL; size_t size = 0;
if (read_file_text(PLDMGR_CONFIG_PATH, &old, &size) && errno != ENOENT) return -1;
@@ -65,7 +65,7 @@ static int write_config(const PldmgrConfig *cfg) {
if (!end) end = old + size;
size_t n = (size_t)(end - line);
int known = n >= 23 && !memcmp(line, "LAST_REPOSITORY_UPDATE=", 23);
for (size_t i = 0; i < 6; i++) {
for (size_t i = 0; i < 7; i++) {
size_t k = strlen(setting_keys[i]);
if (n > k && !memcmp(line, setting_keys[i], k) && line[k] == '=') known = 1;
}
@@ -165,7 +165,7 @@ static int save_csv(const char *path, const char *csv) {
if (csv_lines(csv, lines, sizeof(lines)) || ensure_dir_recursive(BASE_DATA_DIR)) return -1;
return write_file_text(path, lines, strlen(lines));
}
typedef struct { unsigned seen; int values[6]; char autoload[LIST_CAPACITY], favorites[LIST_CAPACITY]; } Update;
typedef struct { unsigned seen; int values[7]; char autoload[LIST_CAPACITY], favorites[LIST_CAPACITY]; } Update;
static int favorite_item(const char *start, const char *end, void *context) {
Update *update = context;
char item[LIST_CAPACITY];
@@ -178,10 +178,10 @@ static int favorite_item(const char *start, const char *end, void *context) {
static int update_member(const char *key, const char *start, const char *end, void *context) {
Update *update = context;
size_t index = 0;
for (; index < 6; index++) if (!strcmp(key, setting_keys[index])) break;
if (!strcmp(key, "AUTOLOAD_LIST")) index = 6;
else if (!strcmp(key, "FAVORITES")) index = 7;
if (index == 6 && strcmp(key, "AUTOLOAD_LIST")) return 0; /* read-only/unknown fields */
for (; index < 7; index++) if (!strcmp(key, setting_keys[index])) break;
if (!strcmp(key, "AUTOLOAD_LIST")) index = 7;
else if (!strcmp(key, "FAVORITES")) index = 8;
if (index == 7 && strcmp(key, "AUTOLOAD_LIST")) return 0; /* read-only/unknown fields */
unsigned bit = 1u << index;
if (update->seen & bit) return -1;
update->seen |= bit;
@@ -192,13 +192,13 @@ static int update_member(const char *key, const char *start, const char *end, vo
for (const char *p = start; p < end; p++) { if (*p < '0' || *p > '9') return -1; value = value * 10 + *p - '0'; }
if (value > 3600) return -1;
update->values[index] = (int)value;
} else if (index < 6) {
} else if (index < 7) {
if (size == 4 && !memcmp(start, "true", 4)) update->values[index] = 1;
else if (size == 5 && !memcmp(start, "false", 5)) update->values[index] = 0;
else return -1;
} else {
char *csv = index == 6 ? update->autoload : update->favorites;
if (index == 7 && *start == '[') {
char *csv = index == 7 ? update->autoload : update->favorites;
if (index == 8 && *start == '[') {
if (json_visit_array(start, end, favorite_item, update)) return -1;
} else if (json_decode_string(start, end, csv, LIST_CAPACITY)) return -1;
char lines[LIST_CAPACITY];
@@ -213,14 +213,14 @@ int config_handle_set_json(const char *json) {
PldmgrConfig cfg;
int result = read_config(&cfg);
int *fields[] = {&cfg.autoload_enabled, &cfg.auto_browser_open, &cfg.autoload_delay,
&cfg.scan_usb_payloads, &cfg.auto_install_app, &cfg.multi_sources_enabled};
for (size_t i = 0; i < 6; i++) if (update.seen & (1u << i)) *fields[i] = update.values[i];
&cfg.scan_usb_payloads, &cfg.auto_install_app, &cfg.multi_sources_enabled, &cfg.kill_disc_player};
for (size_t i = 0; i < 7; i++) if (update.seen & (1u << i)) *fields[i] = update.values[i];
/* Validate the entire request before any write. Individual files publish
* atomically; on I/O failure prior successful file publications remain.
* Lists go first, enabled/settings last: never enable an unsaved new list. */
if (!result && (update.seen & (1u << 6))) result = save_csv(AUTOLOAD_CONFIG_PATH, update.autoload);
if (!result && (update.seen & (1u << 7))) result = save_csv(FAVORITES_CONFIG_PATH, update.favorites);
if (!result && (update.seen & 63)) result = write_config(&cfg);
if (!result && (update.seen & (1u << 7))) result = save_csv(AUTOLOAD_CONFIG_PATH, update.autoload);
if (!result && (update.seen & (1u << 8))) result = save_csv(FAVORITES_CONFIG_PATH, update.favorites);
if (!result && (update.seen & 127)) result = write_config(&cfg);
pthread_mutex_unlock(&config_mutex);
if (!result && (update.seen & 1) && !update.values[0]) pldmgr_autoload_abort();
return result;
+6 -3
View File
@@ -990,15 +990,17 @@ enum MHD_Result http_on_request(void *cls, struct MHD_Connection *conn,
pldmgr_json_escape(snapshot.list,list_escaped,sizeof(list_escaped)))
return send_request_error(conn,MHD_HTTP_INTERNAL_SERVER_ERROR,"Invalid autoload snapshot");
PldmgrConfig cfg;
config_read(&cfg);
char *resp_buf;
if (!alloc_response_buffer_small(&resp_buf))
return send_out_of_memory(conn);
json_format(resp_buf, SMALL_RESPONSE_BUFFER_SIZE,
"{\"remaining\":%d,\"remaining_ms\":%lld,\"total\":%d,\"done\":%d,\"current\":\"%s\","
"\"list\":\"%s\",\"delay\":%d,\"SCAN_USB_PAYLOADS\":%s,"
"\"list\":\"%s\",\"delay\":%d,\"KILL_DISC_PLAYER_ON_STARTUP\":%s,\"SCAN_USB_PAYLOADS\":%s,"
"\"state\":\"%s\",\"successful\":%d,\"failed\":%d,\"skipped\":%d,\"outcomes\":\"%s\",\"entry_index\":%d,\"entry_duration_ms\":%d,\"entry_remaining_ms\":%lld}",
snapshot.remaining, snapshot.remaining_ms, snapshot.total, snapshot.done, current_escaped,
list_escaped, snapshot.delay, snapshot.scan_usb_payloads ? "true" : "false",
list_escaped, snapshot.delay, cfg.kill_disc_player ? "true" : "false", snapshot.scan_usb_payloads ? "true" : "false",
pldmgr_autoload_state_name(snapshot.state),snapshot.successful,snapshot.failed,snapshot.skipped,snapshot.outcomes,
snapshot.entry_index,snapshot.entry_duration_ms,snapshot.entry_remaining_ms);
if (!resp_buf[0]) return send_serialization_error(conn, resp_buf);
@@ -1043,11 +1045,12 @@ enum MHD_Result http_on_request(void *cls, struct MHD_Connection *conn,
json_format(resp_buf, SMALL_RESPONSE_BUFFER_SIZE,
"{\"AUTOLOAD_ENABLED\":%s,\"AUTOLOAD_LIST\":\"%s\",\"LAST_"
"REPOSITORY_UPDATE\":%ld,"
"\"AUTO_BROWSER_OPEN\":%s,\"AUTOLOAD_DELAY\":%d,"
"\"AUTO_BROWSER_OPEN\":%s,\"AUTOLOAD_DELAY\":%d,\"KILL_DISC_PLAYER_ON_STARTUP\":%s,"
"\"SCAN_USB_PAYLOADS\":%s,\"AUTO_INSTALL_APP\":%s,"
"\"MULTI_SOURCES_ENABLED\":%s,\"FAVORITES\":\"%s\",\"FAVORITES_INITIALIZED\":%s}",
cfg.autoload_enabled ? "true" : "false", list_escaped, cfg.last_repository_update,
cfg.auto_browser_open ? "true" : "false", cfg.autoload_delay,
cfg.kill_disc_player ? "true" : "false",
cfg.scan_usb_payloads ? "true" : "false",
cfg.auto_install_app ? "true" : "false",
cfg.multi_sources_enabled ? "true" : "false",
+5
View File
@@ -115,6 +115,11 @@ int main(int argc, char *argv[]) {
pldmgr_install_app_if_needed();
}
/* Kill Disc Player if running (BD-JB host) and enabled in config */
if (cfg.kill_disc_player) {
ps5_kill_disc_player();
}
/* Signal Resilience */
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
+66
View File
@@ -1,4 +1,5 @@
#include "ps5_launcher.h"
#include "process_mgr.h"
#include "pldmgr.h"
#include "slot.h"
#include "repository.h"
@@ -14,6 +15,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>
@@ -122,3 +124,67 @@ int ps5_launch_browser(const char *uri) {
}
return 0;
}
/* LncUtil Externs */
extern int sceLncUtilGetAppIdOfRunningBigApp(void);
extern int sceLncUtilGetAppTitleId(uint32_t app_id, char *title_id);
extern int sceLncUtilSuspendApp(uint32_t app_id);
extern int sceLncUtilKillApp(uint32_t app_id);
int ps5_kill_disc_player(void) {
const char *target_process = "SceDiscPlayer";
const char *target_title_id = "NPXS40140";
uint32_t app_id = sceLncUtilGetAppIdOfRunningBigApp();
if (app_id == UINT32_MAX) {
return 0; /* No app running */
}
char title_id[16] = {0};
if (sceLncUtilGetAppTitleId(app_id, title_id) != 0) {
return 0; /* Could not get title ID */
}
if (strcmp(title_id, target_title_id) != 0) {
return 0; /* Not the disc player */
}
pldmgr_notify("Disc Player detected. Terminating...\n");
/* 1. Suspend */
if (sceLncUtilSuspendApp(app_id) != 0) {
pldmgr_notify("Failed to suspend Disc Player");
return -1;
}
/* Wait for home screen transition stability */
sleep(2);
/* 2. SIGKILL */
pid_t pid = process_find_pid(target_process);
if (pid != -1) {
pldmgr_log("Sending SIGKILL to %s (PID: %d)\n", target_process, pid);
if (kill(pid, SIGKILL) == 0) {
pldmgr_log("SIGKILL Sent to Disc Player");
} else {
pldmgr_notify("Warning: SIGKILL Failed");
}
sleep(1);
}
/* 3. LncUtil Kill */
int result = sceLncUtilKillApp(app_id);
if (result == 0) {
pldmgr_log("Disc Player Fully Closed");
} else {
/* Check if it's already gone (crashed/closed) */
if ((uint32_t)sceLncUtilGetAppIdOfRunningBigApp() == UINT32_MAX) {
pldmgr_log("Disc Player Closed");
} else {
pldmgr_notify("!!! Failed to kill Disc Player (result: %d)", result);
return -1;
}
}
return 0;
}
+12 -2
View File
@@ -43,9 +43,19 @@ static void fault(const char *name,int at) { fault_name=name; fault_at=at; fault
static char *read_text(const char *path) { char *text; size_t size; CHECK(!read_file_text(path,&text,&size)); return text; }
static void expect_text(const char *path,const char *expected) { char *text=read_text(path); CHECK(!strcmp(text,expected)); free(text); }
static void scalar(void) {
PldmgrConfig initial; config_read(&initial); CHECK(initial.kill_disc_player==1);
/* Legacy values survive unrelated saves; toggling writes one canonical key. */
CHECK(!config_upsert_value("KILL_DISC_PLAYER_ON_STARTUP","0"));
CHECK(config_read_bool("KILL_DISC_PLAYER_ON_STARTUP",1)==0);
CHECK(config_read_bool("AUTOLOAD_ENABLED",1)==1);
CHECK(!config_handle_set_json("{\"AUTO_BROWSER_OPEN\":false}"));
PldmgrConfig cfg; config_read(&cfg); CHECK(cfg.auto_browser_open==0); CHECK(cfg.autoload_delay==5); CHECK(cfg.auto_install_app==1);
PldmgrConfig cfg; config_read(&cfg); CHECK(cfg.auto_browser_open==0); CHECK(cfg.autoload_delay==5); CHECK(cfg.auto_install_app==1 && cfg.kill_disc_player==0);
CHECK(!config_handle_set_json("{\"KILL_DISC_PLAYER_ON_STARTUP\":true}")); config_read(&cfg); CHECK(cfg.kill_disc_player==1 && cfg.auto_browser_open==0);
CHECK(!config_handle_set_json("{\"KILL_DISC_PLAYER_ON_STARTUP\":false,\"FAVORITES\":\"local/keep\",\"AUTOLOAD_LIST\":\"local/keep\"}"));
config_read(&cfg); CHECK(cfg.kill_disc_player==0);
CHECK(config_read_bool("KILL_DISC_PLAYER_ON_STARTUP",1)==0);
char *disc_saved=read_text(PLDMGR_CONFIG_PATH);
char *key=strstr(disc_saved,"KILL_DISC_PLAYER_ON_STARTUP=0\n"); CHECK(key && !strstr(key+1,"KILL_DISC_PLAYER_ON_STARTUP=")); free(disc_saved);
CHECK(!config_handle_set_json("{\"SCAN_USB_PAYLOADS\":true}")); config_read(&cfg); CHECK(cfg.scan_usb_payloads==1 && cfg.auto_browser_open==0);
CHECK(!config_handle_set_json("{\"AUTO_INSTALL_APP\":false}")); config_read(&cfg); CHECK(cfg.auto_install_app==0 && cfg.scan_usb_payloads==1);
CHECK(!config_handle_set_json("{\"MULTI_SOURCES_ENABLED\":true}")); config_read(&cfg); CHECK(cfg.multi_sources_enabled==1);
@@ -67,7 +77,7 @@ static void scalar(void) {
static void validation(void) {
CHECK(!config_handle_set_json("{\"AUTOLOAD_ENABLED\":true,\"FAVORITES\":\"local/keep\",\"AUTOLOAD_LIST\":\"local/keep\"}"));
char *old=read_text(PLDMGR_CONFIG_PATH);
const char *invalid[]={"{", "{} garbage", "[]", "{\"AUTOLOAD_ENABLED\":false,\"AUTOLOAD_DELAY\":-1}",
const char *invalid[]={"{\"KILL_DISC_PLAYER_ON_STARTUP\":0}", "{\"KILL_DISC_PLAYER_ON_STARTUP\":null}", "{\"KILL_DISC_PLAYER_ON_STARTUP\":true,\"KILL_DISC_PLAYER_ON_STARTUP\":false}", "{", "{} garbage", "[]", "{\"AUTOLOAD_ENABLED\":false,\"AUTOLOAD_DELAY\":-1}",
"{\"FAVORITES\":\"local/change\",\"AUTO_BROWSER_OPEN\":0}", "{\"AUTOLOAD_ENABLED\":null}", "{\"AUTOLOAD_ENABLED\":\"true\"}",
"{\"AUTOLOAD_DELAY\":1.5}", "{\"AUTOLOAD_DELAY\":1e2}", "{\"AUTOLOAD_DELAY\":3601}", "{\"AUTOLOAD_DELAY\":999999999999999999999999}",
"{\"AUTOLOAD_ENABLED\":true,\"AUTOLOAD_ENABLED\":false}", "{\"AUTOLOAD_DELAY\":1,\"AUTOLOAD_D\\u0045LAY\":2}",
+30
View File
@@ -29,6 +29,35 @@ int slot_open_payload(const char *path,char *canonical,size_t size) { CHECK(!str
int slot_open_self_update(const char *path) { (void)path; abort(); }
int repository_self_update_version_fd(int fd, char *version, size_t size) { (void)fd; (void)version; (void)size; abort(); }
int slot_version_compare(const char *a, const char *b) { (void)a; (void)b; abort(); }
/* Disc-player calls are recorded; host tests never signal a real process. */
static int suspends, app_kills, signals, lookups, slept, app_queries;
void pldmgr_notify(const char *fmt,...) { (void)fmt; }
int sceLncUtilGetAppIdOfRunningBigApp(void) {
app_queries++;
return !strcmp(mode,"disc-none") || (!strcmp(mode,"disc-gone") && app_queries>1) ? -1 : 42;
}
int sceLncUtilGetAppTitleId(uint32_t app_id,char *title) {
CHECK(app_id==42);
if(!strcmp(mode,"disc-title-error")) return -1;
strcpy(title,!strcmp(mode,"disc-other") ? "OTHERAPP" : "NPXS40140"); return 0;
}
int sceLncUtilSuspendApp(uint32_t app_id) { CHECK(app_id==42); suspends++; return !strcmp(mode,"disc-suspend-error") ? -1 : 0; }
int sceLncUtilKillApp(uint32_t app_id) { CHECK(app_id==42 && suspends==1); app_kills++; return !strcmp(mode,"disc-kill-error") || !strcmp(mode,"disc-gone") ? -1 : 0; }
pid_t process_find_pid(const char *name) { CHECK(!strcmp(name,"SceDiscPlayer") && suspends==1); lookups++; return !strcmp(mode,"disc-no-pid") ? -1 : 123; }
int launcher_test_kill(pid_t pid,int sig) { CHECK(pid==123 && sig==SIGKILL && suspends==1); signals++; return 0; }
unsigned int launcher_test_sleep(unsigned int seconds) { slept+=(int)seconds; return 0; }
static int disc_test(void) {
int rc=ps5_kill_disc_player();
int skipped=!strcmp(mode,"disc-none") || !strcmp(mode,"disc-other") || !strcmp(mode,"disc-title-error");
int suspend_failed=!strcmp(mode,"disc-suspend-error");
CHECK(rc== (suspend_failed || !strcmp(mode,"disc-kill-error") ? -1 : 0));
CHECK(suspends==(skipped ? 0 : 1));
CHECK(app_kills==(skipped || suspend_failed ? 0 : 1));
CHECK(lookups==app_kills);
CHECK(signals==(!strcmp(mode,"disc-no-pid") ? 0 : app_kills));
CHECK(slept==2*app_kills+signals);
printf("Disc Player: %s passed\n",mode); return 0;
}
static void *receive_bytes(void *unused) {
(void)unused;
for(;;) { ssize_t n=recv(peer,received+received_bytes,expected_size-received_bytes,0); if(n==0)break;CHECK(n>0);received_bytes+=(size_t)n;if(received_bytes==expected_size)break; }
@@ -66,6 +95,7 @@ ssize_t launcher_test_read(int fd,void *buffer,size_t size) { if(!strcmp(mode,"r
static int cancelled(void *context) { (void)context;return !strcmp(mode,"cancel-before") || (!strcmp(mode,"cancel-send") && sent_bytes>=68) || (!strcmp(mode,"cancel-wait") && now_ms()-started>=100); }
int main(int argc,char **argv) {
CHECK(argc==3);mode=argv[1];fixture=argv[2];signal(SIGPIPE,SIG_IGN);
if(!strncmp(mode,"disc-",5)) return disc_test();
FILE *f=fopen(fixture,"rb");CHECK(f);CHECK(!fseek(f,0,SEEK_END));long length=ftell(f);CHECK(length>0);expected_size=(size_t)length;CHECK(!fclose(f));
received=malloc(expected_size);CHECK(received);started=now_ms();
int rc=ps5_launch_elf_cancellable(fixture,cancelled,NULL);
+5
View File
@@ -15,3 +15,8 @@ int launcher_test_fcntl(int,int,...);
#define poll launcher_test_poll
#define getsockopt launcher_test_getsockopt
#define fcntl launcher_test_fcntl
int launcher_test_kill(pid_t,int);
unsigned int launcher_test_sleep(unsigned int);
#define kill launcher_test_kill
#define sleep launcher_test_sleep
+7 -1
View File
@@ -375,7 +375,13 @@ def config_network_tests(binary, storage):
assert request("POST", "/set_config", '{"AUTO_BROWSER_OPEN":false}')[0] == 200
status, body = request("GET", "/get_config")
assert status == 200 and json.loads(body)["AUTO_BROWSER_OPEN"] is False
for bad in ['{', '{"AUTOLOAD_ENABLED":false,"AUTOLOAD_DELAY":-1}', '{"FAVORITES":[1]}']:
assert json.loads(body)["KILL_DISC_PLAYER_ON_STARTUP"] is True
for enabled in [False, True]:
assert request("POST", "/set_config", json.dumps({"KILL_DISC_PLAYER_ON_STARTUP": enabled}))[0] == 200
for route in ["/get_config", "/autoload_status"]:
status, body = request("GET", route)
assert status == 200 and json.loads(body)["KILL_DISC_PLAYER_ON_STARTUP"] is enabled
for bad in ['{', '{"AUTOLOAD_ENABLED":false,"AUTOLOAD_DELAY":-1}', '{"FAVORITES":[1]}', '{"KILL_DISC_PLAYER_ON_STARTUP":0}']:
assert request("POST", "/set_config", bad)[0] == 400
# A genuine filesystem failure must produce 500 and retain old config.
old = (storage / "pldmgr_config.txt").read_bytes()
+1 -1
View File
@@ -17,7 +17,7 @@ with tempfile.TemporaryDirectory(prefix='pldmgr-loader-') as temp:
subprocess.run(flags+[str(obj),'tests/launcher_driver.c','-Wl,-dead_strip' if sys.platform=='darwin' else '-Wl,--gc-sections','-o',str(binary)],cwd=ROOT,check=True)
small=build/'small.elf';small.write_bytes(bytes(range(256))*80)
big=build/'big.elf';big.write_bytes(bytes(range(256))*4096)
for case in ['ok','partial','interrupt','socket','fcntl','connect','socket-error','read','zero','connect-stall','send-stall','cancel-before','cancel-send','cancel-wait']:
for case in ['ok','partial','interrupt','socket','fcntl','connect','socket-error','read','zero','connect-stall','send-stall','cancel-before','cancel-send','cancel-wait','disc-none','disc-other','disc-title-error','disc-suspend-error','disc-ok','disc-no-pid','disc-kill-error','disc-gone']:
fixture=big if case in ['send-stall','cancel-wait'] else small
result=subprocess.run([str(binary),case,str(fixture)],text=True,capture_output=True,timeout=10)
assert result.returncode==0,result.stdout+result.stderr