mirror of
https://github.com/phantomptr/ps5upload.git
synced 2026-10-19 02:20:02 -05:00
Pin v0.44 (sha256 4d06eab7...). Its crt/ and prospero-nid are identical to v0.43, so the vendored sdk-crt (+ ps5upload.patch) and the portable prospero-nid stay as they are; the helper, installer and elfldr build to the same code (only the build-id differs). v0.44 adds LLVM 23 to the candidate list, so the Makefile comment and Homebrew fallbacks move too. scripts/update-ps5-sdk.sh (make update-sdk): finds the latest release (or --tag), checks the zip, rewrites the pin, re-vendors prospero-nid and crt only when upstream changed them (stops if our crt patch no longer applies), moves the "SDK vX.Y" doc mentions and installs with install-ps5-sdk.sh, keeping the old SDK as a backup. --check only reports. The installer names its backups after the release they hold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
211 lines
8.0 KiB
Bash
Executable File
211 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Install the repository-pinned PS5 Payload SDK release on POSIX hosts.
|
|
#
|
|
# The release archive is checksum-verified before extraction. Existing SDKs
|
|
# without the matching version marker are moved aside, not deleted, so an
|
|
# upgrade can be rolled back. The v0.42 archive was assembled on Linux and
|
|
# contains a Linux/x86-64 prospero-nid binary even though the upstream source
|
|
# is portable Python; install that exact tagged source implementation so the
|
|
# SDK also works on macOS and ARM Linux.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SDK_METADATA="$SCRIPT_DIR/ps5-sdk.env"
|
|
PORTABLE_NID="$SCRIPT_DIR/ps5-sdk/prospero-nid"
|
|
|
|
[ -f "$SDK_METADATA" ] || { echo "ERROR: missing $SDK_METADATA" >&2; exit 1; }
|
|
# shellcheck disable=SC1090
|
|
source "$SDK_METADATA"
|
|
|
|
SDK_DIR="${PS5_SDK_INSTALL_DIR:-$HOME/ps5-payload-sdk}"
|
|
SDK_URL="https://github.com/ps5-payload-dev/sdk/releases/download/${PS5_SDK_TAG}/ps5-payload-sdk.zip"
|
|
VERSION_MARKER=".ps5upload-sdk-version"
|
|
EXPECTED_NID="4J2sUJmuHZQ"
|
|
TMP_DIR=""
|
|
|
|
log() { printf '\n==> %s\n' "$*"; }
|
|
ok() { printf '✓ %s\n' "$*"; }
|
|
die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
|
|
|
|
cleanup() {
|
|
if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
|
|
rm -rf -- "$TMP_DIR"
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
sha256_file() {
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum "$1" | awk '{print $1}'
|
|
elif command -v shasum >/dev/null 2>&1; then
|
|
shasum -a 256 "$1" | awk '{print $1}'
|
|
else
|
|
die "need sha256sum or shasum to verify the SDK download"
|
|
fi
|
|
}
|
|
|
|
validate_metadata() {
|
|
case "$PS5_SDK_TAG" in
|
|
v[0-9]*.[0-9]*) ;;
|
|
*) die "invalid PS5_SDK_TAG in $SDK_METADATA: $PS5_SDK_TAG" ;;
|
|
esac
|
|
case "$PS5_SDK_SHA256" in
|
|
""|*[!0-9a-f]*) die "invalid PS5_SDK_SHA256 in $SDK_METADATA" ;;
|
|
esac
|
|
case "$PS5_SDK_NID_SHA256" in
|
|
""|*[!0-9a-f]*) die "invalid PS5_SDK_NID_SHA256 in $SDK_METADATA" ;;
|
|
esac
|
|
[ "${#PS5_SDK_SHA256}" -eq 64 ] || die "PS5_SDK_SHA256 must contain 64 hex characters"
|
|
[ "${#PS5_SDK_NID_SHA256}" -eq 64 ] || die "PS5_SDK_NID_SHA256 must contain 64 hex characters"
|
|
case "$PS5_SQLITE_VERSION" in
|
|
""|*[!0-9]*) die "invalid PS5_SQLITE_VERSION in $SDK_METADATA" ;;
|
|
esac
|
|
case "$PS5_SQLITE_YEAR" in
|
|
""|*[!0-9]*) die "invalid PS5_SQLITE_YEAR in $SDK_METADATA" ;;
|
|
esac
|
|
case "$PS5_SQLITE_SHA256" in
|
|
""|*[!0-9a-f]*) die "invalid PS5_SQLITE_SHA256 in $SDK_METADATA" ;;
|
|
esac
|
|
[ "${#PS5_SQLITE_SHA256}" -eq 64 ] || die "PS5_SQLITE_SHA256 must contain 64 hex characters"
|
|
[ -f "$PORTABLE_NID" ] || die "missing portable prospero-nid at $PORTABLE_NID"
|
|
[ "$(sha256_file "$PORTABLE_NID")" = "$PS5_SDK_NID_SHA256" ] || \
|
|
die "portable prospero-nid checksum does not match $SDK_METADATA"
|
|
}
|
|
|
|
install_portable_nid() {
|
|
local root="$1"
|
|
command -v python3 >/dev/null 2>&1 || die "python3 is required by the portable prospero-nid tool"
|
|
install -m 0755 "$PORTABLE_NID" "$root/bin/prospero-nid"
|
|
local actual
|
|
actual="$("$root/bin/prospero-nid" sceKernelGetProcessTime)"
|
|
[ "$actual" = "$EXPECTED_NID" ] || die "prospero-nid self-test failed (got $actual)"
|
|
}
|
|
|
|
# ── SQLite amalgamation ──────────────────────────────────────────────────
|
|
#
|
|
# The payload links a real SQLite so it can read (and repair) the console's
|
|
# content databases with the actual record parser instead of a hand-rolled
|
|
# b-tree walker. No firmware ships libSceSqlite.sprx, so this cannot come
|
|
# from the console — it is compiled into the payload from these sources.
|
|
#
|
|
# Sources are fetched rather than committed: the amalgamation is a 9 MB
|
|
# generated file, pinned by version and SHA-256 in ps5-sdk.env. Only
|
|
# sqlite3.c and sqlite3.h are kept; shell.c and sqlite3ext.h are dropped
|
|
# (a CLI shell and the extension ABI, neither of which the payload builds).
|
|
install_sqlite_amalgamation() {
|
|
local dir="$SCRIPT_DIR/../payload/third_party/sqlite3"
|
|
local stamp="$dir/.version"
|
|
|
|
if [ -f "$dir/sqlite3.c" ] && [ -f "$dir/sqlite3.h" ] \
|
|
&& [ -f "$stamp" ] \
|
|
&& [ "$(tr -d '[:space:]' < "$stamp")" = "$PS5_SQLITE_VERSION" ]; then
|
|
ok "SQLite $PS5_SQLITE_VERSION amalgamation already present"
|
|
return 0
|
|
fi
|
|
|
|
log "Downloading SQLite $PS5_SQLITE_VERSION amalgamation"
|
|
local tmp zip
|
|
tmp="$(mktemp -d)"
|
|
zip="$tmp/sqlite-amalgamation.zip"
|
|
curl --retry 3 --retry-delay 2 --retry-connrefused \
|
|
--fail --location --silent --show-error --output "$zip" \
|
|
"https://www.sqlite.org/${PS5_SQLITE_YEAR}/sqlite-amalgamation-${PS5_SQLITE_VERSION}.zip"
|
|
|
|
local actual
|
|
actual="$(sha256_file "$zip")"
|
|
if [ "$actual" != "$PS5_SQLITE_SHA256" ]; then
|
|
rm -rf -- "$tmp"
|
|
die "SQLite checksum mismatch: expected $PS5_SQLITE_SHA256, got $actual"
|
|
fi
|
|
ok "Verified SQLite archive SHA-256 $actual"
|
|
|
|
# Same archive-layout guard the SDK download uses: every entry must live
|
|
# under the single documented top-level directory, with no traversal.
|
|
local top="sqlite-amalgamation-${PS5_SQLITE_VERSION}"
|
|
while IFS= read -r entry; do
|
|
case "$entry" in
|
|
"$top"/*) ;;
|
|
*) rm -rf -- "$tmp"; die "unexpected SQLite archive entry: $entry" ;;
|
|
esac
|
|
case "/$entry/" in
|
|
*/../*|*/./*) rm -rf -- "$tmp"; die "unsafe SQLite archive entry: $entry" ;;
|
|
esac
|
|
done < <(unzip -Z1 "$zip")
|
|
|
|
unzip -q "$zip" -d "$tmp"
|
|
[ -f "$tmp/$top/sqlite3.c" ] || { rm -rf -- "$tmp"; die "SQLite archive is missing sqlite3.c"; }
|
|
[ -f "$tmp/$top/sqlite3.h" ] || { rm -rf -- "$tmp"; die "SQLite archive is missing sqlite3.h"; }
|
|
|
|
mkdir -p "$dir"
|
|
install -m 0644 "$tmp/$top/sqlite3.c" "$dir/sqlite3.c"
|
|
install -m 0644 "$tmp/$top/sqlite3.h" "$dir/sqlite3.h"
|
|
printf '%s\n' "$PS5_SQLITE_VERSION" > "$stamp"
|
|
chmod 0644 "$stamp"
|
|
rm -rf -- "$tmp"
|
|
ok "Installed SQLite $PS5_SQLITE_VERSION sources at $dir"
|
|
}
|
|
|
|
validate_metadata
|
|
install_sqlite_amalgamation
|
|
|
|
if [ -f "$SDK_DIR/toolchain/prospero.mk" ] \
|
|
&& [ -f "$SDK_DIR/$VERSION_MARKER" ] \
|
|
&& [ "$(tr -d '[:space:]' < "$SDK_DIR/$VERSION_MARKER")" = "$PS5_SDK_TAG" ]; then
|
|
install_portable_nid "$SDK_DIR"
|
|
ok "PS5 Payload SDK $PS5_SDK_TAG already installed at $SDK_DIR"
|
|
exit 0
|
|
fi
|
|
|
|
log "Downloading PS5 Payload SDK $PS5_SDK_TAG"
|
|
TMP_DIR="$(mktemp -d)"
|
|
ZIP_PATH="$TMP_DIR/ps5-payload-sdk.zip"
|
|
curl --retry 3 --retry-delay 2 --retry-connrefused \
|
|
--fail --location --silent --show-error \
|
|
--output "$ZIP_PATH" "$SDK_URL"
|
|
|
|
ACTUAL_SHA256="$(sha256_file "$ZIP_PATH")"
|
|
[ "$ACTUAL_SHA256" = "$PS5_SDK_SHA256" ] || \
|
|
die "SDK checksum mismatch: expected $PS5_SDK_SHA256, got $ACTUAL_SHA256"
|
|
ok "Verified official archive SHA-256 $ACTUAL_SHA256"
|
|
|
|
# Refuse unexpected archive layouts before invoking unzip. Every entry must be
|
|
# below the single documented ps5-payload-sdk/ top-level directory and may not
|
|
# contain traversal components.
|
|
while IFS= read -r entry; do
|
|
case "$entry" in
|
|
ps5-payload-sdk/*) ;;
|
|
*) die "unexpected SDK archive entry: $entry" ;;
|
|
esac
|
|
case "/$entry/" in
|
|
*/../*|*/./*) die "unsafe SDK archive entry: $entry" ;;
|
|
esac
|
|
done < <(unzip -Z1 "$ZIP_PATH")
|
|
|
|
unzip -q "$ZIP_PATH" -d "$TMP_DIR"
|
|
STAGED_SDK="$TMP_DIR/ps5-payload-sdk"
|
|
[ -f "$STAGED_SDK/toolchain/prospero.mk" ] || die "SDK archive is missing toolchain/prospero.mk"
|
|
[ -f "$STAGED_SDK/target/lib/crt1.o" ] || die "SDK archive is missing target/lib/crt1.o"
|
|
install_portable_nid "$STAGED_SDK"
|
|
printf '%s\n' "$PS5_SDK_TAG" > "$STAGED_SDK/$VERSION_MARKER"
|
|
|
|
mkdir -p "$(dirname "$SDK_DIR")"
|
|
BACKUP_DIR=""
|
|
if [ -e "$SDK_DIR" ]; then
|
|
# Name the backup after the release it holds when it says (backup-v0.43-...).
|
|
OLD_TAG="$(tr -d '[:space:]' < "$SDK_DIR/$VERSION_MARKER" 2>/dev/null || true)"
|
|
case "$OLD_TAG" in v[0-9]*) OLD_TAG="$OLD_TAG-" ;; *) OLD_TAG="" ;; esac
|
|
BACKUP_DIR="${SDK_DIR}.backup-${OLD_TAG}$(date +%Y%m%d-%H%M%S)-$$"
|
|
mv "$SDK_DIR" "$BACKUP_DIR"
|
|
ok "Moved the previous SDK to $BACKUP_DIR"
|
|
fi
|
|
|
|
if ! mv "$STAGED_SDK" "$SDK_DIR"; then
|
|
if [ -n "$BACKUP_DIR" ] && [ -e "$BACKUP_DIR" ] && [ ! -e "$SDK_DIR" ]; then
|
|
mv "$BACKUP_DIR" "$SDK_DIR"
|
|
fi
|
|
die "could not install the SDK at $SDK_DIR"
|
|
fi
|
|
|
|
ok "Installed PS5 Payload SDK $PS5_SDK_TAG at $SDK_DIR"
|