Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ daemon.lock
debug.log
notify.txt
src/notify_icon_asset.c
src/config_ini_example_asset.c
src/web_index_asset.c
src/shell_icon_param_asset.c
refs/*
docs/*
15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,17 @@ CFLAGS += -DSHADOWMOUNT_VERSION=\"$(VERSION_TAG)\"
LDFLAGS := -flto=thin -Wl,--gc-sections

# Libraries
LIBS := -lSceNotification -lSceSystemService -lSceUserService -lSceAppInstUtil -lSceNet -lSceSsl -lSceHttp -lsqlite3 $(HOMEBREW_ROOT)/lib/libjson-c.a $(MHD_LIB) $(PNG_LIB) $(ZLIB_LIB) -lpthread -lm
LIBS := -lSceNotification -lSceSystemService -lSceUserService -lSceIpmi -lSceAppInstUtil -lSceNet -lSceSsl -lSceHttp -lsqlite3 $(HOMEBREW_ROOT)/lib/libjson-c.a $(MHD_LIB) $(PNG_LIB) $(ZLIB_LIB) -lpthread -lm
PS5_SCE_STUBS_DIR ?= $(PS5_PAYLOAD_SDK)/src/sce_stubs
PS5_SCE_STUB_SOURCE ?= $(firstword \
$(wildcard $(PS5_SCE_STUBS_DIR)/libkernel_sys.c) \
$(wildcard $(PS5_PAYLOAD_SDK)/src/sce_stubs/libkernel_sys.c) \
$(wildcard third_party/ps5-sdk/sce_stubs/libkernel_sys.c))
ifeq ($(strip $(PS5_SCE_STUB_SOURCE)),)
$(error Missing libkernel_sys.c. Set PS5_SCE_STUB_SOURCE or PS5_SCE_STUBS_DIR, or provide the SDK source checkout)
endif
KERNEL_SYS_STUB_SO := src/libkernel_sys_ext.so
KERNEL_SYS_STUB_SRCS := $(PS5_SCE_STUBS_DIR)/libkernel_sys.c src/libkernel_sys_ext.c
KERNEL_SYS_STUB_SRCS := $(PS5_SCE_STUB_SOURCE) src/libkernel_sys_ext.c

ASSET_SRCS := src/notify_icon_asset.c src/config_ini_example_asset.c src/web_index_asset.c
ASSET_SRCS += src/shell_icon_param_asset.c
Expand All @@ -43,7 +50,7 @@ shadowmountplus.elf: $(OBJS) $(KERNEL_SYS_STUB_SO)
$(PS5_PAYLOAD_SDK)/bin/prospero-strip --strip-all $@

$(KERNEL_SYS_STUB_SO): $(KERNEL_SYS_STUB_SRCS)
test -f "$(PS5_SCE_STUBS_DIR)/libkernel_sys.c"
test -f "$(PS5_SCE_STUB_SOURCE)"
$(CC) -shared -Wl,-soname=libkernel_sys.sprx -o $@ $^

src/notify_icon_asset.c: smp_icon.png
Expand All @@ -58,7 +65,7 @@ src/web_index_asset.c: web/index.html
src/shell_icon_param_asset.c: assets/shell_icon_param.json
xxd -i $< > $@

src/sm_api_service.o src/sm_icon_thumb.o src/sm_gameinfo.o: CFLAGS += $(HOMEBREW_CFLAGS)
src/%.o: CFLAGS += $(HOMEBREW_CFLAGS)
src/main.o src/sm_image_index.o: CFLAGS += -DSHADOWMOUNT_BUILD_TIME=\"$(BUILD_TIME)\"
src/main.o src/sm_image_index.o: FORCE

Expand Down
5 changes: 5 additions & 0 deletions config.ini.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
# Default: 0 on FW below 12.00, forced to 1 on FW 12.00 and newer
# app_install_all=0

# Automatically install standalone regular .pkg files discovered below scan roots.
# Uses the native AppInstUtil installer and a console-local loopback source.
# Default: 0
# pkg_install_enabled=0

# Automatically remove games from the system library when their source
# is no longer available:
# 1/true/yes/on -> remove after the configured missing delay
Expand Down
4 changes: 2 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ device.
| `/api/v1/manual/add` | `{"path":"/mnt/usb0/games/PPSA12345"}` | Idempotently add one game source to `manual.lst` |
| `/api/v1/manual/remove` | `{"path":"/mnt/usb0/games/PPSA12345"}` | Remove matching source lines from `manual.lst` |
| `/api/v1/settings` | `{}` | Read web-managed runtime settings and scan paths |
| `/api/v1/settings/update` | `{"debug":true,"quiet_mode":false,"update_emulators":true,"fakelib_default_mode":"full","auto_update_ampr":false,"auto_remove_missing_games":false,"auto_remove_missing_delay_seconds":300,"allow_lan_access":true,"fan_target_temperature":0,"scan_paths":["/mnt/usb0/games"]}` | Atomically update the web-managed part of `config.ini` |
| `/api/v1/settings/update` | `{"debug":true,"quiet_mode":false,"update_emulators":true,"fakelib_default_mode":"full","auto_update_ampr":false,"auto_remove_missing_games":false,"pkg_install_enabled":false,"auto_remove_missing_delay_seconds":300,"allow_lan_access":true,"fan_target_temperature":0,"scan_paths":["/mnt/usb0/games"]}` | Atomically update the web-managed part of `config.ini` |
| `/api/v1/debug-log` | `{"max_bytes":131072}` | Read a bounded tail of `debug.log` for the web log dialog |
| `/api/v1/kernel-log` | `{"max_bytes":131072}` | Read a bounded tail of the SDK kernel-log stream used by crash detection |
| `/api/v1/games` | `{"include_size":false}` | Detailed game snapshot; optional physical source-size calculation |
Expand Down Expand Up @@ -283,7 +283,7 @@ included. A missing `manual.lst` is reported as an empty list.

The settings update owns only `debug`, `quiet_mode`, `update_emulators`,
`fakelib_default_mode`, `auto_update_ampr`, `auto_remove_missing_games`,
`auto_remove_missing_delay_seconds`,
`pkg_install_enabled`, `auto_remove_missing_delay_seconds`,
`api_bind_address`, `fan_target_temperature`, and repeated `scanpath` keys. The
`allow_lan_access` field maps to `0.0.0.0` when enabled and `127.0.0.1` when
disabled. It atomically rewrites those keys while preserving every unrelated
Expand Down
3 changes: 3 additions & 0 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,9 @@ components:
auto_remove_missing_games:
type: boolean
description: Remove app registrations whose source remains unavailable. Omission preserves the current value for compatibility with older web clients.
pkg_install_enabled:
type: boolean
description: Automatically install supported standalone PKG files discovered below scan roots. Omission preserves the current value for compatibility with older web clients.
auto_remove_missing_delay_seconds:
type: integer
minimum: 1
Expand Down
11 changes: 11 additions & 0 deletions include/sm_appinst.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef SM_APPINST_H
#define SM_APPINST_H

#include <stdbool.h>

int sm_appinst_initialize(void);
int sm_appinst_install_by_package(const char *uri, const char *title_name);
int sm_appinst_install_all(void *reserved);
int sm_appinst_uninstall(const char *title_id);

#endif
1 change: 1 addition & 0 deletions include/sm_config_mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bool sm_config_write_web_settings(bool debug_enabled, bool quiet_mode,
bool auto_remove_missing_games,
uint32_t auto_remove_missing_delay_seconds,
bool allow_lan_access,
bool pkg_install_enabled,
uint32_t fan_target_temperature_c,
const char *const *scan_paths,
size_t scan_path_count,
Expand Down
17 changes: 17 additions & 0 deletions include/sm_pkg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef SM_PKG_H
#define SM_PKG_H

#include <stdbool.h>
#include <sys/stat.h>

#include "sm_types.h"

bool sm_pkg_path_is_candidate(const char *path, const char *name);
bool sm_pkg_is_installed_content_path(const char *path);
bool sm_pkg_parse_file(const char *path, const struct stat *st,
scan_candidate_t *candidate);
const char *sm_pkg_kind_name(pkg_kind_t kind);
bool sm_pkg_kind_is_installable(pkg_kind_t kind);
int sm_pkg_compare_versions(const char *left, const char *right);

#endif
16 changes: 16 additions & 0 deletions include/sm_pkg_install.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef SM_PKG_INSTALL_H
#define SM_PKG_INSTALL_H

#include <stdbool.h>
#include <stdint.h>

#include "sm_types.h"

bool sm_pkg_install_queue_candidate(const scan_candidate_t *candidate);
uint64_t sm_pkg_install_next_wake_us(uint64_t now_us);
void sm_pkg_install_service(void);
bool sm_pkg_install_has_pending_work(void);
void sm_pkg_install_forget_path(const char *path);
void sm_pkg_install_shutdown(void);

#endif
18 changes: 18 additions & 0 deletions include/sm_pkg_server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef SM_PKG_SERVER_H
#define SM_PKG_SERVER_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

typedef struct sm_pkg_server sm_pkg_server_t;

int sm_pkg_server_start(sm_pkg_server_t **out, const char *pkg_path,
const char *attempt, uint16_t *port_out);
uint64_t sm_pkg_server_bytes_served(sm_pkg_server_t *server);
uint64_t sm_pkg_server_total(sm_pkg_server_t *server);
bool sm_pkg_server_complete(sm_pkg_server_t *server);
uint64_t sm_pkg_server_last_request_us(sm_pkg_server_t *server);
void sm_pkg_server_stop(sm_pkg_server_t *server);

#endif
5 changes: 5 additions & 0 deletions include/sm_scan_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ typedef bool (*sm_scan_tree_image_fn)(const char *image_path,
const char *image_name,
unsigned int depth_from_root,
void *ctx);
typedef bool (*sm_scan_tree_pkg_fn)(const char *pkg_path,
const char *pkg_name,
unsigned int depth_from_root,
void *ctx);

typedef struct {
sm_scan_tree_dir_fn on_directory;
sm_scan_tree_image_fn on_image_file;
sm_scan_tree_pkg_fn on_pkg_file;
} sm_scan_tree_callbacks_t;

// Walk a managed scan subtree using the shared scan-depth and path filtering rules.
Expand Down
30 changes: 30 additions & 0 deletions include/sm_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <stdbool.h>
#include <stdint.h>
#include <time.h>

#include "sm_limits.h"

Expand Down Expand Up @@ -91,11 +92,39 @@ struct AppDbTitleList {
int capacity;
};

typedef enum {
SCAN_CANDIDATE_DIRECTORY = 0,
SCAN_CANDIDATE_PKG,
} scan_candidate_kind_t;

typedef enum {
PKG_KIND_UNKNOWN = 0,
PKG_KIND_BASE,
PKG_KIND_PATCH,
PKG_KIND_DLC,
} pkg_kind_t;

typedef struct scan_candidate {
char path[MAX_PATH];
char title_id[MAX_TITLE_ID];
char title_name[MAX_TITLE_NAME];
char manual_source_path[MAX_PATH];
char content_id[MAX_CONTENT_ID];
char category[16];
char app_ver[MAX_GAME_VERSION];
uint32_t content_type;
uint32_t content_flags;
uint32_t outer_content_type;
uint32_t outer_content_flags;
uint64_t source_size;
uint64_t source_device;
uint64_t source_inode;
uint64_t source_ctime;
uint64_t source_fingerprint;
time_t source_mtime;
pkg_kind_t pkg_kind;
bool pkg_classification_confident;
scan_candidate_kind_t kind;
bool installed;
bool in_app_db;
bool manual;
Expand Down Expand Up @@ -147,6 +176,7 @@ typedef struct runtime_config {
bool force_mount;
bool persistent_image_mounts;
bool app_install_all_enabled;
bool pkg_install_enabled;
bool auto_remove_missing_games;
bool auto_remove_games_with_dlc;
bool backport_fakelib_enabled;
Expand Down
8 changes: 7 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "sm_scanner.h"
#include "sm_time.h"
#include "sm_install.h"
#include "sm_appinst.h"
#include "sm_pkg_install.h"
#include "sm_appdb.h"
#include "sm_kstuff.h"
#include "sm_limits.h"
Expand Down Expand Up @@ -559,7 +561,10 @@ int main(void) {
pid_t existing_pid = 0;

sceUserServiceInitialize(0);
sceAppInstUtilInitialize();
int appinst_result = sm_appinst_initialize();
if (appinst_result != 0)
log_debug(" [APPINST] initialization failed: 0x%08X",
(uint32_t)appinst_result);
kernel_set_ucred_authid(-1, AUTHID_BASE);
install_signal_handlers();

Expand Down Expand Up @@ -695,6 +700,7 @@ int main(void) {
sm_shellcore_flags_stop();
sm_shellcore_hooks_stop();
stop_game_lifecycle_watcher();
sm_pkg_install_shutdown();
sm_shellcore_service_stop();
sm_scanner_shutdown();
sm_mdbg_shutdown();
Expand Down
10 changes: 9 additions & 1 deletion src/sm_api_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "sm_api_protocol.h"
#include "sm_api_service.h"
#include "sm_appdb.h"
#include "sm_appinst.h"
#include "sm_config_mount.h"
#include "sm_filesystem.h"
#include "sm_game_cache.h"
Expand Down Expand Up @@ -1913,6 +1914,8 @@ static void handle_settings(struct MHD_Connection *connection) {
cfg.auto_update_ampr_enabled) ||
!add_json_bool(response, "auto_remove_missing_games",
cfg.auto_remove_missing_games) ||
!add_json_bool(response, "pkg_install_enabled",
cfg.pkg_install_enabled) ||
!add_json_int(response, "auto_remove_missing_delay_seconds",
cfg.auto_remove_missing_delay_seconds) ||
!add_json_int(response, "fan_target_temperature",
Expand All @@ -1934,6 +1937,7 @@ static void handle_settings_update(struct MHD_Connection *connection,
bool update_emulators = false;
bool auto_update_ampr = current_cfg.auto_update_ampr_enabled;
bool auto_remove_missing_games = current_cfg.auto_remove_missing_games;
bool pkg_install_enabled = current_cfg.pkg_install_enabled;
bool allow_lan_access = false;
sm_fakelib_mode_t fakelib_default_mode = current_cfg.fakelib_default_mode;
struct json_object *mode_value = NULL;
Expand All @@ -1949,6 +1953,9 @@ static void handle_settings_update(struct MHD_Connection *connection,
!get_optional_bool(request, "auto_remove_missing_games",
current_cfg.auto_remove_missing_games,
&auto_remove_missing_games) ||
!get_optional_bool(request, "pkg_install_enabled",
current_cfg.pkg_install_enabled,
&pkg_install_enabled) ||
!get_required_bool(request, "allow_lan_access", &allow_lan_access) ||
!json_object_object_get_ex(request, "fan_target_temperature",
&fan_value) ||
Expand Down Expand Up @@ -2024,6 +2031,7 @@ static void handle_settings_update(struct MHD_Connection *connection,
auto_update_ampr, auto_remove_missing_games,
(uint32_t)remove_delay_int,
allow_lan_access,
pkg_install_enabled,
(uint32_t)fan_value_int, paths, path_count,
fakelib_default_mode)) {
int status = valid && errno != 0 ? errno : EINVAL;
Expand Down Expand Up @@ -2222,7 +2230,7 @@ static int request_game_uninstall(const char *title_id,
source_missing = source_error && strcmp(source_error, "source_missing") == 0;
}

int platform_status = sceAppInstUtilAppUnInstall(title_id);
int platform_status = sm_appinst_uninstall(title_id);
if (platform_status != 0) {
log_debug(" [API] uninstall request failed: title=%s code=0x%08X",
title_id, (uint32_t)platform_status);
Expand Down
Loading
Loading