Files
PSBBN-Definitive-English-Patch/scripts/PSBBN-Installer.sh
CosmicScale 13813c3c62 Multilingual Support
PSBBN Installer:
- Add an option to select a language when installing PSBBN
- Install Japanese online game channels when Japanese is selected

PSBBN Updater:
- Install updates for the PSBBN System Software and language pack
- Install updates for online channels when the language is set to Japanese

Optional Extras:
- Add an option to change the PSBBN language in the Optional Extras menu

Game Installer:
- Display Japanese-region game titles in Japanese and sort them in gojūon (五十音) order when Japanese is selected
- Install the POPS IGR message for the selected language
- Install PS1 game manuals for the selected language

TitlesDB_PS1.csv and TitlesDB_PS2.csv:
- Add Japanese titles for all Japanese-region games

list-builder.py:
- Update to handle Japanese game titles

General:
- Add libicu-dev and pkg-config to the dependencies
2026-01-08 17:20:53 +00:00

1339 lines
47 KiB
Bash
Executable File

#!/usr/bin/env bash
if [[ "$LAUNCHED_BY_MAIN" != "1" ]]; then
echo "This script should not be run directly. Please run: PSBBN-Definitive-Patch.sh"
exit 1
fi
# Set paths
version_check="2.10"
TOOLKIT_PATH="$(pwd)"
SCRIPTS_DIR="${TOOLKIT_PATH}/scripts"
ASSETS_DIR="${SCRIPTS_DIR}/assets"
HELPER_DIR="${SCRIPTS_DIR}/helper"
STORAGE_DIR="${SCRIPTS_DIR}/storage"
OPL="${SCRIPTS_DIR}/OPL"
LOG_FILE="${TOOLKIT_PATH}/logs/PSBBN-installer.log"
arch="$(uname -m)"
URL="https://archive.org/download/psbbn-definitive-patch-v4.1"
if [[ "$arch" = "x86_64" ]]; then
# x86-64
CUE2POPS="${HELPER_DIR}/cue2pops"
HDL_DUMP="${HELPER_DIR}/HDL Dump.elf"
MKFS_EXFAT="${HELPER_DIR}/mkfs.exfat"
PFS_FUSE="${HELPER_DIR}/PFS Fuse.elf"
PFS_SHELL="${HELPER_DIR}/PFS Shell.elf"
APA_FIXER="${HELPER_DIR}/PS2 APA Header Checksum Fixer.elf"
PSU_EXTRACT="${HELPER_DIR}/PSU Extractor.elf"
SQLITE="${HELPER_DIR}/sqlite"
elif [[ "$arch" = "aarch64" ]]; then
# ARM64
CUE2POPS="${HELPER_DIR}/aarch64/cue2pops"
HDL_DUMP="${HELPER_DIR}/aarch64/HDL Dump.elf"
MKFS_EXFAT="${HELPER_DIR}/aarch64/mkfs.exfat"
PFS_FUSE="${HELPER_DIR}/aarch64/PFS Fuse.elf"
PFS_SHELL="${HELPER_DIR}/aarch64/PFS Shell.elf"
APA_FIXER="${HELPER_DIR}/aarch64/PS2 APA Header Checksum Fixer.elf"
PSU_EXTRACT="${HELPER_DIR}/aarch64/PSU Extractor.elf"
SQLITE="${HELPER_DIR}/aarch64/sqlite"
fi
serialnumber="$2"
path_arg="$3"
case "$1" in
-install)
MODE="install"
;;
-update)
MODE="update"
;;
*)
echo "Usage: $0 -install | -update"
exit 1
;;
esac
version_le() { # returns 0 (true) if $1 < $2
[ "$1" = "$2" ] && return 1
smallest=$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)
[ "$smallest" = "$1" ]
}
if [ "$MODE" = "install" ]; then
LINUX_PARTITIONS=("__linux.1" "__linux.4" "__linux.5" "__linux.6" "__linux.7" "__linux.8" "__linux.9" )
PFS_PARTITIONS=("__contents" "__system" "__sysconf" "__common" )
else
LINUX_PARTITIONS=("__linux.1" "__linux.4" "__linux.5" "__linux.6" "__linux.7" "__linux.9" )
PFS_PARTITIONS=("__system" "__sysconf" )
fi
error_msg() {
error_1="[X] Error: $1"
error_2="$2"
error_3="$3"
error_4="$4"
echo | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
echo "$error_1" | tee -a "${LOG_FILE}"
[ -n "$error_2" ] && echo "$error_2" | tee -a "${LOG_FILE}"
[ -n "$error_3" ] && echo "$error_3" | tee -a "${LOG_FILE}"
[ -n "$error_4" ] && echo "$error_4" | tee -a "${LOG_FILE}"
echo
read -n 1 -s -r -p "Press any key to return to the menu..." </dev/tty
echo
exit 1
}
spinner() {
local pid=$1
local message=$2
local delay=0.1
local spinstr='|/-\'
local exit_code
# Print initial spinner
echo
printf "\r[%c] %s" "${spinstr:0:1}" "$message"
# Animate while the process is running
while kill -0 "$pid" 2>/dev/null; do
for i in {0..3}; do
printf "\r[%c] %s" "${spinstr:i:1}" "$message"
sleep $delay
done
done
# Wait for the process to capture its exit code
wait "$pid"
exit_code=$?
# Replace spinner with success/failure
if [ $exit_code -eq 0 ]; then
printf "\r[✓] %s\n" "$message" | tee -a "${LOG_FILE}"
else
printf "\r[X] %s\n" "$message" | tee -a "${LOG_FILE}"
fi
}
clean_up() {
failure=0
if [ -d "${STORAGE_DIR}" ]; then
submounts=$(findmnt -nr -o TARGET | grep "^${STORAGE_DIR}/")
if [ -z "$submounts" ]; then
echo "Deleting ${STORAGE_DIR}..." >> "$LOG_FILE"
sudo rm -rf "${STORAGE_DIR}" || { echo "[X] Error: Failed to delete ${STORAGE_DIR}" >> "$LOG_FILE"; failure=1; }
echo "Deleted ${STORAGE_DIR}." >> "$LOG_FILE"
else
echo "Some mounts remain under ${STORAGE_DIR}, not deleting." >> "$LOG_FILE"
failure=1
fi
else
echo "Directory ${STORAGE_DIR} does not exist." >> "$LOG_FILE"
fi
# Abort if any failures occurred
if [ "$failure" -ne 0 ]; then
error_msg "Error" "Cleanup error(s) occurred. Aborting."
fi
# Clean up directories and temp files
sudo rm -rf /tmp/{apa_header_checksum.bin,apa_header_full.bin,apajail_magic_number.bin,apa_index.xz,gpt_2nd.xz} >> "${LOG_FILE}" 2>&1
sudo rm -f "$HTML_FILE"
sudo rm -rf "${SCRIPTS_DIR}/tmp"
# Abort if any failures occurred
if [ "$failure" -ne 0 ]; then
error_msg "Cleanup error(s) occurred. Aborting."
fi
}
exit_script() {
UNMOUNT_ALL
clean_up
if [[ -n "$path_arg" ]]; then
cp "${LOG_FILE}" "${path_arg}" > /dev/null 2>&1
fi
}
get_latest_file() {
local prefix="$1" # e.g., "psbbn-eng" or "psbbn-definitive-patch"
local display="$2" # e.g., "English language pack"
local remote_list remote_versions remote_version
local local_file local_version
# Reset globals
LATEST_FILE=""
# Extract .gz filenames from the HTML
remote_list=$(grep -oP "${prefix}-v[0-9]+\.[0-9]+\.[0-9]+\.tar\.gz" "$HTML_FILE" 2>/dev/null)
if [[ -n "$remote_list" ]]; then
# Extract version numbers and sort them
remote_versions=$(echo "$remote_list" | \
grep -oP 'v[0-9]+\.[0-9]+\.[0-9]+' | \
sed 's/v//' | \
sort -V)
remote_version=$(echo "$remote_versions" | tail -n1)
echo | tee -a "${LOG_FILE}"
echo "Found $display version $remote_version" | tee -a "${LOG_FILE}"
else
echo | tee -a "${LOG_FILE}"
echo "Could not find the latest version of the $display." | tee -a "${LOG_FILE}"
echo "Please check the status of archive.org. You may need to use a VPN depending on your location."
fi
# Check if any local file is newer than the remote version
local_file=$(ls "${ASSETS_DIR}/${prefix}"*.tar.gz 2>/dev/null | sort -V | tail -n1)
if [[ -n "$local_file" ]]; then
local_version=$(basename "$local_file" | sed -E 's/.*-v([0-9.]+)\.tar\.gz/\1/')
fi
#Decide which file wins
if [[ -n "$local_file" ]]; then
if [[ -z "$remote_version" ]] || \
[[ "$(printf '%s\n' "$remote_version" "$local_version" | sort -V | tail -n1)" == "$local_version" ]]; then
# Local is equal/newer then local wins
LATEST_FILE=$(basename "$local_file")
echo "Newer local file found: ${LATEST_FILE}" | tee -a "${LOG_FILE}"
# Only set LATEST_VERSION for the patch prefix
if [[ "$prefix" == "psbbn-definitive-patch" ]]; then
LATEST_VERSION="$local_version"
elif [[ "$prefix" == "language-pak-$LANG" ]]; then
LATEST_LANG="$local_version"
elif [[ "$prefix" == "channels-$LANG" ]]; then
LATEST_CHAN="$local_version"
fi
return 0
fi
fi
# Remote exists and is newer then remote wins
if [[ -n "$remote_version" ]]; then
LATEST_FILE="${prefix}-v${remote_version}.tar.gz"
# Only set LATEST_VERSION for the patch prefix
if [[ "$prefix" == "psbbn-definitive-patch" ]]; then
LATEST_VERSION="$remote_version"
elif [[ "$prefix" == "language-pak-$LANG" ]]; then
LATEST_LANG="$remote_version"
elif [[ "$prefix" == "channels-$LANG" ]]; then
LATEST_CHAN="$remote_version"
fi
return 0
fi
# If neither version exists error
error_msg "Failed to find ${display}. Aborting."
}
downoad_latest_file() {
local prefix="$1"
# Check if the latest file exists in ${ASSETS_DIR}
if [[ -f "${ASSETS_DIR}/${LATEST_FILE}" && ! -f "${ASSETS_DIR}/${LATEST_FILE}.st" ]]; then
echo | tee -a "${LOG_FILE}"
echo "File ${LATEST_FILE} exists. Skipping download." | tee -a "${LOG_FILE}"
else
# Check for and delete older files
for file in "${ASSETS_DIR}"/$prefix*.tar.gz; do
if [[ -f "$file" && "$(basename "$file")" != "$LATEST_FILE" ]]; then
echo "Deleting old file: $file" | tee -a "${LOG_FILE}"
rm -f "$file"
fi
done
# Construct the full URL for the .gz file and download it
TAR_URL="$URL/$LATEST_FILE"
echo "Downloading ${LATEST_FILE}..." | tee -a "${LOG_FILE}"
axel -n 8 -a "$TAR_URL" -o "${ASSETS_DIR}"
# Check if the file was downloaded successfully
if [[ -f "${ASSETS_DIR}/${LATEST_FILE}" && ! -f "${ASSETS_DIR}/${LATEST_FILE}.st" ]]; then
echo "Download completed: ${LATEST_FILE}" | tee -a "${LOG_FILE}"
else
error_msg "Download failed for ${LATEST_FILE}." "Please check your internet connection and try again."
fi
fi
}
PFS_COMMANDS() {
PFS_COMMANDS=$(echo -e "$COMMANDS" | sudo "${PFS_SHELL}" >> "${LOG_FILE}" 2>&1)
if echo "$PFS_COMMANDS" | grep -q "Exit code is"; then
error_msg "PFS Shell returned an error. See ${LOG_FILE}"
fi
}
mapper_probe() {
DEVICE_CUT=$(basename "${DEVICE}")
# 1) Remove existing maps for this device
existing_maps=$(sudo dmsetup ls 2>/dev/null | awk -v p="^${DEVICE_CUT}-" '$1 ~ p {print $1}')
for map in $existing_maps; do
sudo dmsetup remove "$map" 2>/dev/null
done
# 2) Build keep list
keep_partitions=( "${LINUX_PARTITIONS[@]}" "${PFS_PARTITIONS[@]}" )
if [ "$MODE" = "install" ]; then
keep_partitions+=("__linux.2")
fi
# 3) Get HDL Dump --dm output, split semicolons into lines
dm_output=$(sudo "${HDL_DUMP}" toc "${DEVICE}" --dm | tr ';' '\n')
# 4) Create each kept partition individually
while IFS= read -r line; do
for part in "${keep_partitions[@]}"; do
if [[ "$line" == "${DEVICE_CUT}-${part},"* ]]; then
echo "$line" | sudo dmsetup create --concise | tee -a "${LOG_FILE}"
break
fi
done
done <<< "$dm_output"
# 5) Export base mapper path
MAPPER="/dev/mapper/${DEVICE_CUT}-"
}
mount_cfs() {
for PARTITION_NAME in "${LINUX_PARTITIONS[@]}"; do
MOUNT_PATH="${STORAGE_DIR}/${PARTITION_NAME}"
if [ -e "${MAPPER}${PARTITION_NAME}" ]; then
if [[ "$PARTITION_NAME" = "__linux.9" ]] && ! version_le "${psbbn_version:-0}" "4.1.0"; then
echo "Skipping mke2fs for __linux.9" >>"${LOG_FILE}"
elif [[ "$PARTITION_NAME" =~ ^__linux\.(1|4|5|7)$ ]] && [ "$MODE" = "update" ] && ! version_le "${psbbn_version:-0}" "4.0.0"; then
echo "Skipping mke2fs for $PARTITION_NAME" >>"${LOG_FILE}"
elif [[ "$PARTITION_NAME" = "__linux.8" ]]; then
if ! sudo mkfs.vfat -F 32 "${MAPPER}${PARTITION_NAME}" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to create filesystem ${PARTITION_NAME}."
fi
else
if ! sudo mke2fs -t ext2 -b 4096 -I 128 -O ^large_file,^dir_index,^extent,^huge_file,^flex_bg,^has_journal,^ext_attr,^resize_inode "${MAPPER}${PARTITION_NAME}" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to create filesystem ${PARTITION_NAME}."
fi
fi
[ -d "${MOUNT_PATH}" ] || mkdir -p "${MOUNT_PATH}"
if [[ "$PARTITION_NAME" = "__linux.7" ]] && [ "$MODE" = "update" ]; then
echo echo "Skipping mount for __linux.7" >>"${LOG_FILE}"
else
if ! sudo mount "${MAPPER}${PARTITION_NAME}" "${MOUNT_PATH}" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to mount ${PARTITION_NAME} partition."
fi
fi
else
error_msg "Partition ${PARTITION_NAME} not found on disk."
fi
done
if [ "$MODE" = "install" ]; then
if ! sudo mkswap "${MAPPER}__linux.2" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to create swap filesystem."
fi
fi
}
mount_pfs() {
for PARTITION_NAME in "${PFS_PARTITIONS[@]}"; do
MOUNT_POINT="${STORAGE_DIR}/$PARTITION_NAME/"
mkdir -p "$MOUNT_POINT"
if ! sudo "${PFS_FUSE}" \
-o allow_other \
--partition="$PARTITION_NAME" \
"${DEVICE}" \
"$MOUNT_POINT" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to mount $PARTITION_NAME partition." "Check the device or filesystem and try again."
fi
done
}
apa_checksum_fix() {
sudo dd if=${DEVICE} of=/tmp/apa_header_full.bin bs=512 count=2 >> "${LOG_FILE}" 2>&1
"${APA_FIXER}" /tmp/apa_header_full.bin | sed -n 8p | awk '{print $6}' | xxd -r -p > /tmp/apa_header_checksum.bin 2>> "${LOG_FILE}"
sudo dd if=/tmp/apa_header_checksum.bin of=${DEVICE} conv=notrunc >> "${LOG_FILE}" 2>&1
}
apajail_magic_number() {
echo ${MAGIC_NUMBER} | xxd -r -p > /tmp/apajail_magic_number.bin
sudo dd if=/tmp/apajail_magic_number.bin of=${DEVICE} bs=8 count=1 seek=28 conv=notrunc >> "${LOG_FILE}" 2>&1
}
BOOTSTRAP() {
if [ -f "${ASSETS_DIR}/osdmenu/OSDMBR.XLF" ]; then
# BOOTSTRAP METADATA:
BOOTSTRAP_ADDRESS_HEX_BE=0020
BOOTSTRAP_SIZE=$(wc -c "${ASSETS_DIR}/osdmenu/OSDMBR.XLF" | cut -d' ' -f 1)
BOOTSTRAP_SIZE_LBA=$(echo "$((${BOOTSTRAP_SIZE}/512))")
BOOTSTRAP_SIZE_LBA_HEX_BE=$(printf "%04X" ${BOOTSTRAP_SIZE_LBA} | tac -rs .. | echo "$(tr -d '\n')")
echo "${BOOTSTRAP_ADDRESS_HEX_BE}0000${BOOTSTRAP_SIZE_LBA_HEX_BE}0000" | xxd -r -p > /tmp/apa_header_boot.bin 2>> "${LOG_FILE}"
# METADATA & BOOTSTRAP WRITING:
# 130h = 304d
sudo dd if=/tmp/apa_header_boot.bin of=${DEVICE} bs=1 seek=304 >> "${LOG_FILE}" 2>&1
# 2000h * 200h = 8192d * 512d = 4194304d = 400000h
sudo dd if="${ASSETS_DIR}/osdmenu/OSDMBR.XLF" of=${DEVICE} bs=1M count=1 seek=4 conv=notrunc >> "${LOG_FILE}" 2>&1
else
error_msg "Failed to inject OSDMenu MBR."
fi
}
CHECK_PARTITIONS() {
TOC_OUTPUT=$(sudo "${HDL_DUMP}" toc "${DEVICE}")
STATUS=$?
if [ $STATUS -ne 0 ]; then
error_msg "APA partition is broken on ${DEVICE}. Install failed."
fi
# List of required partitions
required=(__linux.1 __linux.4 __linux.5 __linux.6 __linux.7 __linux.8 __linux.9 __contents __system __sysconf __.POPS __common)
# Check all required partitions
for part in "${required[@]}"; do
if ! echo "$TOC_OUTPUT" | grep -Fq "$part"; then
error_msg "Some partitions are missing on ${DEVICE}. See log for details."
fi
done
}
UNMOUNT_ALL() {
# Find all mounted volumes associated with the device
mounted_volumes=$(lsblk -ln -o MOUNTPOINT "$DEVICE" | grep -v "^$")
# Iterate through each mounted volume and unmount it
echo "Unmounting volumes associated with $DEVICE..." >> "${LOG_FILE}"
for mount_point in $mounted_volumes; do
echo "Unmounting $mount_point..." >> "${LOG_FILE}"
if sudo umount "$mount_point"; then
echo "[✓] Successfully unmounted $mount_point." >> "${LOG_FILE}"
else
error_msg "Failed to unmount $mount_point. Please unmount manually."
fi
done
submounts=$(findmnt -nr -o TARGET | grep "^${STORAGE_DIR}/" | sort -r)
if [ -n "$submounts" ]; then
echo "Found mounts under ${STORAGE_DIR}, attempting to unmount..." >> "$LOG_FILE"
while read -r mnt; do
[ -z "$mnt" ] && continue
echo "Unmounting $mnt..." >> "$LOG_FILE"
sudo umount "$mnt" || error_msg "Error" "Failed to unmount $mnt"
done <<< "$submounts"
fi
# Get the device basename
DEVICE_CUT=$(basename "$DEVICE")
# List all existing maps for this device
existing_maps=$(sudo dmsetup ls 2>/dev/null | awk -v dev="$DEVICE_CUT" '$1 ~ "^"dev"-" {print $1}')
# Force-remove each existing map
for map_name in $existing_maps; do
echo "Removing existing mapper $map_name..." >> "$LOG_FILE"
if ! sudo dmsetup remove -f "$map_name" 2>/dev/null; then
error_msg "Error" "Failed to delete mapper $map_name."
fi
done
}
UNMOUNT_OPL() {
sync
if ! sudo umount -l "${OPL}" >> "${LOG_FILE}" 2>&1; then
error_msg "Failed to unmount $DEVICE"
fi
}
MOUNT_OPL() {
echo "Mounting OPL partition." >> "${LOG_FILE}"
mkdir -p "${OPL}" 2>>"${LOG_FILE}" || error_msg "Failed to create ${OPL}."
sudo mount -o uid=$UID,gid=$(id -g) ${DEVICE}3 "${OPL}" >> "${LOG_FILE}" 2>&1
# Handle possibility host system's `mount` is using Fuse
if [ $? -ne 0 ] && hash mount.exfat-fuse; then
echo "Attempting to use exfat.fuse..." >> "${LOG_FILE}"
sudo mount.exfat-fuse -o uid=$UID,gid=$(id -g) ${DEVICE}3 "${OPL}" >> "${LOG_FILE}" 2>&1
fi
if [ $? -ne 0 ]; then
error_msg "Failed to mount the PS2 drive."
fi
}
HDL_TOC() {
rm -f "$hdl_output"
hdl_output=$(mktemp)
if ! sudo "${HDL_DUMP}" toc "$DEVICE" 2>>"${LOG_FILE}" > "$hdl_output"; then
rm -f "$hdl_output"
error_msg "Failed to extract list of partitions." "APA partition could be broken on ${DEVICE}"
fi
}
INSTALL_SPLASH(){
clear
cat << "EOF"
______ _________________ _ _ _____ _ _ _
| ___ \/ ___| ___ \ ___ \ \ | | |_ _| | | | | |
| |_/ /\ `--.| |_/ / |_/ / \| | | | _ __ ___| |_ __ _| | | ___ _ __
| __/ `--. \ ___ \ ___ \ . ` | | || '_ \/ __| __/ _` | | |/ _ \ '__|
| | /\__/ / |_/ / |_/ / |\ | _| || | | \__ \ || (_| | | | __/ |
\_| \____/\____/\____/\_| \_/ \___/_| |_|___/\__\__,_|_|_|\___|_|
EOF
}
UPDATE_SPLASH(){
clear
cat << "EOF"
______ _________________ _ _ _ _ _ _
| ___ \/ ___| ___ \ ___ \ \ | | | | | | | | | |
| |_/ /\ `--.| |_/ / |_/ / \| | | | | |_ __ __| | __ _| |_ ___ _ __
| __/ `--. \ ___ \ ___ \ . ` | | | | | '_ \ / _` |/ _` | __/ _ \ '__|
| | /\__/ / |_/ / |_/ / |\ | | |_| | |_) | (_| | (_| | || __/ |
\_| \____/\____/\____/\_| \_/ \___/| .__/ \__,_|\__,_|\__\___|_|
| |
|_|
EOF
}
mkdir -p "${TOOLKIT_PATH}/logs" >/dev/null 2>&1
echo "########################################################################################################" | tee -a "${LOG_FILE}" >/dev/null 2>&1
if [ $? -ne 0 ]; then
sudo rm -f "${LOG_FILE}"
echo "########################################################################################################" | tee -a "${LOG_FILE}" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo
echo "Error: Cannot to create log file."
read -n 1 -s -r -p "Press any key to return to the menu..." </dev/tty
echo
exit 1
fi
fi
cd "${TOOLKIT_PATH}"
date >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
echo "Tootkit path: $TOOLKIT_PATH" >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
cat /etc/*-release >> "${LOG_FILE}" 2>&1
echo >> "${LOG_FILE}"
echo "Type: $MODE" >> "${LOG_FILE}"
echo "Disk Serial: $serialnumber" >> "${LOG_FILE}"
echo "Path: $path_arg" >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
trap 'echo; exit 130' INT
trap exit_script EXIT
if [ "$MODE" = "install" ]; then
INSTALL_SPLASH
# Choose the PS2 storage device
if [[ -n "$serialnumber" ]]; then
DEVICE=$(lsblk -p -o NAME,SERIAL | awk -v sn="$serialnumber" '$2 == sn {print $1; exit}')
drive_model=$(lsblk -ndo VENDOR,MODEL,SIZE,SERIAL "$DEVICE" | xargs)
fi
if [ -z "$DEVICE" ]; then
while true; do
INSTALL_SPLASH
lsblk -dp -o NAME,MODEL,SIZE,SERIAL | tee -a "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
read -p "Choose your PS2 HDD from the list above (e.g., /dev/sdx): " DEVICE
# Check if the device exists
if [[ -n "$DEVICE" ]] && lsblk -dp -n -o NAME | grep -q "^$DEVICE$"; then
break
else
echo
echo -n "Invalid input. Please enter a valid device name (e.g., /dev/sdx)."
sleep 3
fi
done
drive_model=$(lsblk -ndo MODEL,SIZE,SERIAL "$DEVICE" | xargs)
fi
# Check the size of the chosen device
SIZE_CHECK=$(lsblk -o NAME,SIZE -b | grep -w $(basename $DEVICE) | awk '{print $2}')
# Convert size to GB (1 GB = 1,000,000,000 bytes)
size_gb=$(echo "$SIZE_CHECK / 1000000000" | bc)
if (( size_gb < 31 )); then
error_msg "Device is $size_gb GB. Required minimum is 32 GB."
else
echo "Device Name: $DEVICE" >> "${LOG_FILE}"
[[ -z "$drive_model" ]] && drive_model="$DEVICE"
echo
echo "Selected drive: $drive_model" | tee -a "${LOG_FILE}"
while true; do
echo
echo "Are you sure you want to install to the selected drive?" | tee -a "${LOG_FILE}"
echo
read -p "This will erase all data on the drive. (yes/no): " CONFIRM
case "$CONFIRM" in
yes)
# Valid confirmation → break out of loop and continue
break
;;
no)
echo
read -n 1 -s -r -p "Aborted. Press any key to return to the menu..." </dev/tty
echo
exit 1
;;
*)
echo
echo "Please enter 'yes' or 'no'."
;;
esac
done
fi
echo
echo "Please select a language from the list below:"
echo
echo "1) English"
echo "2) Japanese"
echo "3) German"
echo
read -p "Enter the number for your chosen language: " choice
case "$choice" in
1)
LANG="eng"
LANG_DISPLAY="English"
;;
2)
LANG="jpn"
LANG_DISPLAY="Japanese"
CHAN_UPDATE="yes"
;;
3)
LANG="ger"
LANG_DISPLAY="German"
;;
*)
echo
echo "Invalid selection. Defaulting to English." | tee -a "${LOG_FILE}"
LANG="eng"
LANG_DISPLAY="English"
;;
esac
echo "Language set to: $LANG" >> "${LOG_FILE}"
else
UPDATE_SPLASH
DEVICE=$(sudo blkid -t TYPE=exfat | grep OPL | awk -F: '{print $1}' | sed 's/[0-9]*$//')
if [[ -z "$DEVICE" ]]; then
error_msg "Unable to detect the PS2 drive. Please ensure the drive is properly connected." " " "You must install PSBBN first before updating."
fi
echo "OPL partition found on $DEVICE" >> "${LOG_FILE}"
UNMOUNT_ALL
clean_up
HDL_TOC
CHECK_PARTITIONS
MOUNT_OPL
psbbn_version=$(head -n 1 "$OPL/version.txt" 2>/dev/null)
# Compare using sort -V
if [ "$(printf '%s\n' "$psbbn_version" "$version_check" | sort -V | head -n1)" != "$version_check" ]; then
UNMOUNT_OPL
error_msg "The installed PSBBN Definitive Patch is older than version $version_check and cannot be updated" "directly. Please select 'Install PSBBN' from the main menu to perform a full installation."
fi
LANG=$(awk -F' *= *' '$1=="LANG"{print $2}' "${OPL}/version.txt")
if [[ "$LANG" != "jpn" && "$LANG" != "ger" ]]; then
LANG="eng"
fi
LANG_VER=$(awk -F' *= *' '$1=="LANG_VER"{print $2}' "${OPL}/version.txt")
CHAN_VER=$(awk -F' *= *' '$1=="CHAN_VER"{print $2}' "${OPL}/version.txt")
UNMOUNT_OPL
fi
if [ "$MODE" = "install" ]; then
INSTALL_SPLASH
UNMOUNT_ALL
clean_up
fi
# Download the HTML of the page
HTML_FILE=$(mktemp)
timeout 20 wget -O "$HTML_FILE" "$URL" -o - >> "$LOG_FILE" 2>&1 &
WGET_PID=$!
spinner $WGET_PID "Checking for latest version of the PSBBN Definitive Patch"
get_latest_file "psbbn-definitive-patch" "PSBBN Definitive English patch"
if [ "$MODE" = "update" ]; then
echo "Current version: $psbbn_version" | tee -a "${LOG_FILE}"
if [ "$(printf '%s\n' "$LATEST_VERSION" "$psbbn_version" | sort -V | tail -n1)" = "$psbbn_version" ]; then
echo
echo "You already have the latest PSBBN system software installed." | tee -a "${LOG_FILE}"
PSBBN_UPDATE="no"
fi
fi
if [ "$PSBBN_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
if [[ "$(printf '%s\n' "$LATEST_VERSION" "4.0.0" | sort -V | head -n1)" != "4.0.0" ]]; then
error_msg "The latest version currently available is v$LATEST_VERSION." "The installer requires version v4.1.0 or higher. Please try again later."
fi
downoad_latest_file "psbbn-definitive-patch"
PSBBN_PATCH="${ASSETS_DIR}/${LATEST_FILE}"
fi
get_latest_file "language-pak-$LANG" "$LANG_DISPLAY language pack"
echo "Current language pack version: $LANG_VER" | tee -a "${LOG_FILE}"
if [ "$(printf '%s\n' "$LATEST_LANG" "$LANG_VER" | sort -V | tail -n1)" = "$LANG_VER" ]; then
echo
echo "You already have the latest language pack installed." | tee -a "${LOG_FILE}"
LANG_UPDATE="no"
fi
if [ "$LANG_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
downoad_latest_file "language-pak"
LANG_PACK="${ASSETS_DIR}/${LATEST_FILE}"
fi
if [[ "$LANG" == "jpn" ]]; then
get_latest_file "channels-$LANG" "$LANG_DISPLAY channels"
echo "Current channels version: $CHAN_VER" | tee -a "${LOG_FILE}"
if [ "$(printf '%s\n' "$LATEST_CHAN" "$CHAN_VER" | sort -V | tail -n1)" = "$CHAN_VER" ]; then
echo
echo "You already have the latest game channels installed." | tee -a "${LOG_FILE}"
CHAN_UPDATE="no"
else
CHAN_UPDATE="yes"
fi
if [ "$CHAN_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
downoad_latest_file "channels"
CHANNELS="${ASSETS_DIR}/${LATEST_FILE}"
fi
else
CHAN_UPDATE="no"
fi
if [ "$PSBBN_UPDATE" == "no" ] && [ "$LANG_UPDATE" == "no" ] && [ "$CHAN_UPDATE" == "no" ]; then
echo
echo "You are already running the latest version. No need to update." | tee -a "${LOG_FILE}"
echo
read -n 1 -s -r -p "Press any key to return to the menu..." </dev/tty
echo
exit 0
fi
if [ "$MODE" = "install" ]; then
INSTALL_SPLASH
fi
if [ "$PSBBN_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
if [ "$MODE" = "update" ]; then
UPDATE_SPLASH
fi
echo "================================== PSBBN Definitive Patch v$LATEST_VERSION ==================================="
if [ "$LATEST_VERSION" = "4.1.0" ]; then
echo
echo " NEW! Multilingual Support:"
echo " - The PSBBN Definitive Patch now supports English, Japanese and German"
echo " - Select your preferred language during PSBBN installation"
echo " - The language can also be changed later from the Extras menu"
echo " - When the language is set to Japanese, Japan-region games will be displayed in the"
echo " Game Collection on HOSDMenu using their Japanese titles."
echo " - When the language is set to Japanese, the original Japanese online Game Channels"
echo " can be accessed from the Game Channel."
echo
echo " Full Release notes on GitHub: https://github.com/CosmicScale/PSBBN-Definitive-English-Patch"
echo
echo " Watch the latest video covering this update: https://youtu.be/dvCt_ExHwro"
fi
echo
echo "===================================================================================================="
echo
read -n 1 -s -r -p " Press any key to return to continue..." </dev/tty
echo
fi
if [ "$MODE" = "install" ]; then
echo | tee -a "${LOG_FILE}"
INSTALL_SPLASH
echo -n "Initialising the drive..." | tee -a "${LOG_FILE}"
{
sudo wipefs -a ${DEVICE} &&
sudo dd if=/dev/zero of="${DEVICE}" bs=1M count=100 status=progress &&
sudo dd if=/dev/zero of="${DEVICE}" bs=1M seek=$(( $(sudo blockdev --getsz "${DEVICE}") / 2048 - 100 )) count=100 status=progress
} >> "${LOG_FILE}" 2>&1 || error_msg "Failed to Initialising drive"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="initialize yes\n"
COMMANDS+="mkpart __linux.1 512M EXT2\n"
COMMANDS+="mkpart __linux.2 128M EXT2SWAP\n"
COMMANDS+="mkpart __linux.4 512M EXT2\n"
COMMANDS+="mkpart __linux.5 512M EXT2\n"
COMMANDS+="mkpart __linux.6 128M EXT2\n"
COMMANDS+="mkpart __linux.7 256M EXT2\n"
COMMANDS+="mkpart __linux.9 2048M EXT2\n"
COMMANDS+="exit"
PFS_COMMANDS
# Retreive avaliable space
output=$(sudo "${HDL_DUMP}" toc ${DEVICE} 2>&1)
# Extract the "used" value, remove "MB" and any commas
used=$(echo "$output" | awk '/used:/ {print $6}' | sed 's/,//; s/MB//')
capacity=131072
# Calculate available space (capacity - used)
available=$((capacity - used - 6400 - 128))
free_space=$((available / 1024))
max_pops=$(((available - 2048) / 1024))
echo | tee -a "${LOG_FILE}"
# Prompt user for partition size for POPS, Music and Contents, validate input, and keep asking until valid input is provided
while true; do
INSTALL_SPLASH
echo "====================================== Partitioning the Drive ======================================"
echo | tee -a "${LOG_FILE}"
echo "Partitioning the first 128 GB of the drive."
echo "Remaining space: $free_space GB" | tee -a "${LOG_FILE}"
echo
echo "What size would you like the \"POPS\" partition to be?"
echo "This partition is used to store PS1 games."
echo "Minimum 1 GB, maximum $max_pops GB"
echo
read -p "Enter partition size (in GB): " pops_gb
if [[ ! "$pops_gb" =~ ^[0-9]+$ ]]; then
echo
echo -n "Invalid input. Please enter a valid number."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
if (( pops_gb < 1 || pops_gb > max_pops )); then
echo
echo -n "Invalid size. Please enter a value between 1 and $max_pops GB."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
remaining_gb=$((free_space - pops_gb -1))
echo
echo "What size would you like the \"Music\" partition to be?"
echo "Minimum 1 GB, maximum $remaining_gb GB"
echo
read -p "Enter partition size (in GB): " music_gb
if [[ ! "$music_gb" =~ ^[0-9]+$ ]]; then
echo
echo -n "Invalid input. Please enter a valid number."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
if (( music_gb < 1 || music_gb > remaining_gb )); then
echo
echo -n "Invalid size. Please enter a value between 1 and $remaining_gb GB."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
remaining_gb=$((free_space - pops_gb - music_gb))
echo
echo "What size would you like the \"Contents\" partition to be?"
echo "This partition is used to store movies and photos."
echo "Minimum 1 GB, maximum $remaining_gb GB"
echo
read -p "Enter partition size (in GB): " contents_gb
if [[ ! "$contents_gb" =~ ^[0-9]+$ ]]; then
echo
echo -n "Invalid input. Please enter a valid number."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
if (( contents_gb < 1 || contents_gb > remaining_gb )); then
echo
echo -n "Invalid size. Please enter a value between 1 and $remaining_gb GB."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
remaining_gb=$((free_space - pops_gb - music_gb - contents_gb ))
if (( remaining_gb > 0 )); then
echo
echo "Would you like to reserve some space for future use?"
echo "You'll need at least 3 GB reserved to install PS2 Linux."
echo
read -p "Reserve space? (y/n): " answer
if [[ "$answer" =~ ^[Yy]$ ]]; then
echo
echo "How much space would you like to reserve?"
echo "Minimum 1 GB, maximum $remaining_gb GB"
echo
read -rp "Enter partition size (in GB): " reserve_gb
# Check if input is a valid number
if [[ ! "$reserve_gb" =~ ^[0-9]+$ ]]; then
echo
echo "Invalid input. Please enter a valid number."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
# Check if input is within valid range
if (( reserve_gb < 1 || reserve_gb > remaining_gb )); then
echo
echo "Invalid size. Please enter a value between 1 and $remaining_gb GB."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
elif [[ "$answer" =~ ^[Nn]$ ]]; then
reserve_gb="0"
else
echo
echo -n "Invalid input. Please enter y or n."
sleep 3
echo | tee -a "${LOG_FILE}"
continue
fi
else
reserve_gb="0"
fi
allocated_mb=$(( (music_gb + pops_gb + contents_gb + reserve_gb) * 1024 ))
SIZE_MB=$(( SIZE_CHECK / 1024 / 1024 ))
APA_MiB=$(( allocated_mb + used + 6400 +128 ))
DIFF_MB=$(( SIZE_MB - APA_MiB - 32 ))
# Convert to GiB for display (1 GiB = 1024 MiB) with 2 decimal places
OPL_GB=$(awk "BEGIN { printf \"%.2f\", ${DIFF_MB}/1024 }")
if awk "BEGIN {exit !($OPL_GB >= 1000)}"; then
# Store difference as TB with one decimal
difference="$(awk "BEGIN {printf \"%.1f TB\", $OPL_GB/1024}")"
# Cap at 2 TB
CAP=$(awk "BEGIN {print ($difference > 2.0) ? 2.0 : $difference}")
OPL_SIZE="${CAP} TB"
else
# Store as GB
OPL_SIZE="${OPL_GB} GB"
fi
echo
echo "The following partitions will be created:"
echo "- OPL partition: $OPL_SIZE"
echo "- POPS partition: $pops_gb GB"
echo "- Music partition: $music_gb GB"
echo "- Contents partition: $contents_gb GB"
echo "- Reserved space: $reserve_gb GB"
echo
read -p "Do you wish to proceed? (y/n): " confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
music_partition=$((music_gb * 1024))
pops_partition=$((pops_gb * 1024))
contents_partition=$((contents_gb * 1024))
reserved_space=$((reserve_gb * 1024))
break
fi
done
echo >> "${LOG_FILE}"
echo "##########################################################################" >> "${LOG_FILE}"
echo "Music partition size: $music_partition" >> "${LOG_FILE}"
echo "POPS partition size: $pops_partition" >> "${LOG_FILE}"
echo "Contents partition size: $contents_partition" >> "${LOG_FILE}"
echo "Reserved space: $reserved_space MB" >> "${LOG_FILE}"
echo "Total APA size: $APA_MiB MB" >> "${LOG_FILE}"
echo "OPL partition size: $DIFF_MB MB" >> "${LOG_FILE}"
echo "##########################################################################" >> "${LOG_FILE}"
COMMANDS="device ${DEVICE}\n"
COMMANDS+="mkpart __linux.8 ${music_partition}M EXT2\n"
COMMANDS+="mkpart __.POPS ${pops_partition}M PFS\n"
COMMANDS+="mkpart __contents ${contents_partition}M PFS\n"
COMMANDS+="exit"
echo "Creating partitions..." >>"${LOG_FILE}"
PFS_COMMANDS
fi
echo | tee -a "${LOG_FILE}"
if [ "$MODE" = "update" ]; then
if [ "$PSBBN_UPDATE" != "no" ]; then
UPDATE_SPLASH
fi
echo -n "Updating PSBBN..." | tee -a "${LOG_FILE}"
if version_le "${psbbn_version:-0}" "4.1.0"; then
COMMANDS="device ${DEVICE}\n"
COMMANDS+="rmpart __linux.9\n"
COMMANDS+="mkpart __linux.9 2048M EXT2\n"
COMMANDS+="exit"
echo "Deleting and recreating __linux.9..." >>"${LOG_FILE}"
PFS_COMMANDS
fi
else
echo -n "Installing PSBBN..." | tee -a "${LOG_FILE}"
fi
mapper_probe
mount_cfs
mount_pfs
if [ "$MODE" = "install" ]; then
sudo mkdir -p "${STORAGE_DIR}/__linux.8/MusicCh/contents" || error_msg "Failed to create __linux.8/MusicCh/contents"
mkdir -p "${STORAGE_DIR}/__common/Your Saves" 2>> "${LOG_FILE}"
fi
if [ "$PSBBN_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
echo "Installing PSBBN Update..." >> "${LOG_FILE}"
ALL_ERRORS=$(sudo tar zxpf "${PSBBN_PATCH}" -C "${STORAGE_DIR}/" 2>&1 >/dev/null)
FILTERED_ERRORS=$(echo "$ALL_ERRORS" | grep -v -e "Cannot change ownership" -e "tar: Exiting with failure status")
if [ -n "$FILTERED_ERRORS" ]; then
echo "$FILTERED_ERRORS" >> "${LOG_FILE}"
error_msg "Failed to install PSBBN." "See ${LOG_FILE} for details."
fi
fi
if [ "$LANG_UPDATE" != "no" ] || [ "$MODE" != "update" ]; then
echo "Installing PSBBN Language Pack..." >> "${LOG_FILE}"
sudo tar zxpf "$LANG_PACK" -C "${STORAGE_DIR}/" >> "${LOG_FILE}" 2>&1 || error_msg "Failed to install $LANG_DISPLAY language pack." "See ${LOG_FILE} for details."
if [[ "$LANG" == "jpn" ]]; then
cp -f "${ASSETS_DIR}/kernel/vmlinux_jpn" "${STORAGE_DIR}/__system/p2lboot/vmlinux" 2>> "${LOG_FILE}" || error_msg "Failed to copy kernel file."
fi
fi
if [ "$CHAN_UPDATE" == "yes" ]; then
echo "Installing Online Channels..." >> "${LOG_FILE}"
sudo tar zxpf "${CHANNELS}" -C "${STORAGE_DIR}/" >> "${LOG_FILE}" 2>&1 || error_msg "Failed to install channels." "See ${LOG_FILE} for details."
fi
cp -f "${ASSETS_DIR}/osdmenu/"{hosdmenu.elf,version.txt} "${STORAGE_DIR}/__system/osdmenu/" 2>> "${LOG_FILE}" || error_msg "Failed to copy hosdmenu.elf."
# Check if OSDMBR.CNF exists
if [ ! -f "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" ]; then
if sudo "${HDL_DUMP}" toc ${DEVICE} | grep -q "__linux.3"; then
cp -f "${ASSETS_DIR}/kernel/ps2-linux-"{ntsc,vga} "${STORAGE_DIR}/__system/p2lboot/" 2>> "${LOG_FILE}" || error_msg "Failed to copy kernel files."
cat > "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" <<EOL || error_msg "Error" "Failed to write OSDMBR.CNF."
boot_auto = \$PSBBN
boot_cross = \$HOSDSYS
boot_circle = \$PSBBN
boot_circle_arg1 = --kernel
boot_circle_arg2 = pfs0:/p2lboot/ps2-linux-ntsc
boot_circle_arg3 = -noflags
boot_square =
boot_triangle =
boot_start =
cdrom_skip_ps2logo = 1
cdrom_disable_gameid = 0
cdrom_use_dkwdrv = 0
ps1drv_enable_fast = 0
ps1drv_enable_smooth = 0
ps1drv_use_ps1vn = 1
app_gameid = 1
prefer_bbn = 1
osd_language = $LANG
EOL
else
cat > "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" <<EOL || error_msg "Error" "Failed to write OSDMBR.CNF."
boot_auto = \$PSBBN
boot_cross = \$HOSDSYS
boot_circle =
boot_square =
boot_triangle =
boot_start =
cdrom_skip_ps2logo = 1
cdrom_disable_gameid = 0
cdrom_use_dkwdrv = 0
ps1drv_enable_fast = 0
ps1drv_enable_smooth = 0
ps1drv_use_ps1vn = 1
app_gameid = 1
prefer_bbn = 1
osd_language = $LANG
EOL
fi
fi
# Check if OSDMENU.CNF exists
if [ ! -f "${STORAGE_DIR}/__sysconf/osdmenu/OSDMENU.CNF" ]; then
echo "OSDMENU.CNF not found — creating default version." >> "${LOG_FILE}"
cat > "${STORAGE_DIR}/__sysconf/osdmenu/OSDMENU.CNF" <<'EOL' || error_msg "Error" "Failed to write OSDMBR.CNF."
boot_auto = $HOSDSYS
OSDSYS_video_mode = AUTO
OSDSYS_Inner_Browser = 0
OSDSYS_selected_color = 0x10,0x80,0xE0,0x80
OSDSYS_unselected_color = 0x33,0x33,0x33,0x80
OSDSYS_scroll_menu = 1
OSDSYS_menu_x = 320
OSDSYS_menu_y = 110
OSDSYS_enter_x = 30
OSDSYS_enter_y = -1
OSDSYS_version_x = -1
OSDSYS_version_y = -1
OSDSYS_cursor_max_velocity = 1500
OSDSYS_cursor_acceleration = 150
OSDSYS_left_cursor =
OSDSYS_right_cursor =
OSDSYS_menu_top_delimiter =
OSDSYS_menu_bottom_delimiter =
OSDSYS_num_displayed_items = 5
OSDSYS_Skip_Disc = 0
OSDSYS_Skip_Logo = 1
cdrom_skip_ps2logo = 1
cdrom_disable_gameid = 0
cdrom_use_dkwdrv = 0
ps1drv_enable_fast = 0
ps1drv_enable_smooth = 0
ps1drv_use_ps1vn = 1
app_gameid = 1
EOL
else
echo "OSDMENU.CNF already exists — skipping." >> "${LOG_FILE}"
fi
if [ "$MODE" = "update" ] && version_le "${psbbn_version:-0}" "4.0.0"; then
echo "Cleaning up files from older installs:" >> "${LOG_FILE}"
rm -rf "${STORAGE_DIR}/__system/osd110u" 2>> "${LOG_FILE}"
rm -f "${STORAGE_DIR}/__system/p2lboot/PSBBN.ELF" 2>> "${LOG_FILE}"
rm -rf "${STORAGE_DIR}/__sysconf/PS2BBL" 2>> "${LOG_FILE}"
if [ "$MODE" = "update" ] && [ "${psbbn_version:-0}" = "3.00" ]; then
if ! sudo mount "${MAPPER}__linux.7" "${STORAGE_DIR}/__linux.7" >>"${LOG_FILE}" 2>&1; then
error_msg "Failed to mount __linux.7 partition."
fi
mkdir -p "${SCRIPTS_DIR}/tmp"
sudo cp "${STORAGE_DIR}/__linux.7/bn/sysconf/shortcut_0" "${SCRIPTS_DIR}/tmp" >> "${LOG_FILE}" 2>&1
TARGET="${SCRIPTS_DIR}/tmp/shortcut_0"
# If TARGET exists, remove lines ending with PP.LAUNCHELF, PP.HOSDMENU and PP.LAUNCHDISC
if [ -f "$TARGET" ]; then
sudo sed -i '/PP\.LAUNCHELF$/d' "$TARGET" >> "${LOG_FILE}" 2>&1
sudo sed -i '/PP\.HOSDMENU\.HIDDEN$/d' "$TARGET" >> "${LOG_FILE}" 2>&1
sudo sed -i '/PP\.LAUNCHDISC$/d' "$TARGET" >> "${LOG_FILE}" 2>&1
fi
sudo cp -f "${TARGET}" "${STORAGE_DIR}/__linux.7/bn/sysconf/shortcut_0" >> "${LOG_FILE}" 2>&1
fi
fi
UNMOUNT_ALL
if [ "$MODE" = "update" ] && version_le "${psbbn_version:-0}" "4.0.0"; then
COMMANDS="device ${DEVICE}\n"
COMMANDS+="rmpart PP.LAUNCHDISC\n"
COMMANDS+="rmpart PP.HDDOSD\n"
COMMANDS+="rmpart PP.LAUNCHELF\n"
COMMANDS+="rmpart PP.BBNAVIGATOR\n"
COMMANDS+="exit"
echo -e "$COMMANDS" | sudo "${PFS_SHELL}" >> "${LOG_FILE}" 2>&1
fi
clean_up
BOOTSTRAP
echo | tee -a "${LOG_FILE}"
################################### APA-Jail code by Berion ###################################
if [ "$MODE" = "install" ]; then
echo | tee -a "${LOG_FILE}"
echo -n "Running APA-Jail..." | tee -a "${LOG_FILE}"
# Signature injection (type A2):
MAGIC_NUMBER="4150414A2D413200"
apajail_magic_number
# Setting up MBR:
{
echo -e ",${APA_MiB}MiB,17\n,32MiB,17\n,,07" | sudo sfdisk ${DEVICE}
sudo partprobe ${DEVICE}
if [ "$(echo ${DEVICE} | grep -o /dev/loop)" = "/dev/loop" ]; then
sudo mke2fs -t ext2 -L "RECOVERY" ${DEVICE}p2
sudo "${MKFS_EXFAT}" -c 32K -L "OPL" ${DEVICE}p3
else
sleep 4
sudo mke2fs -t ext2 -L "RECOVERY" ${DEVICE}2
sudo "${MKFS_EXFAT}" -c 32K -L "OPL" ${DEVICE}3
fi
} >> "${LOG_FILE}" 2>&1
PARTITION_NUMBER=3
# Finalising recovery:
if [ ! -d "${STORAGE_DIR}/recovery" ]; then
sudo mkdir -p "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
fi
if [ "$(echo ${DEVICE} | grep -o /dev/loop)" = "/dev/loop" ]; then
sudo mount ${DEVICE}p2 "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
else
sudo mount ${DEVICE}2 "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
fi
sudo dd if=${DEVICE} bs=128M count=1 status=noxfer 2>> "${LOG_FILE}" | xz -z > /tmp/apa_index.xz 2>> "${LOG_FILE}"
sudo cp /tmp/apa_index.xz "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
LBA_MAX=$(sudo blockdev --getsize ${DEVICE})
LBA_GPT_BUP=$(echo $(($LBA_MAX-33)))
sudo dd if=${DEVICE} skip=${LBA_GPT_BUP} bs=512 count=33 status=noxfer 2>> "${LOG_FILE}" | xz -z > /tmp/gpt_2nd.xz 2>> "${LOG_FILE}"
sudo cp /tmp/gpt_2nd.xz "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
sync 2>> "${LOG_FILE}"
sudo umount -l "${STORAGE_DIR}/recovery" 2>> "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
fi
apa_checksum_fix
###############################################################################################
CHECK_PARTITIONS
MOUNT_OPL
if [ "$MODE" = "update" ] && version_le "${psbbn_version:-0}" "4.0.0"; then
rm -rf "${OPL}/APPS/LAUNCHDISC" 2>> "${LOG_FILE}"
rm -rf "${OPL}/APPS/HDDOSD" 2>> "${LOG_FILE}"
rm -rf "${OPL}/APPS/LAUNCHELF" 2>> "${LOG_FILE}"
rm -rf "${OPL}/APPS/BBNAVIGATOR" 2>> "${LOG_FILE}"
rm -f "${TOOLKIT_PATH}/games/APPS/"{Launch-Disc.elf,HDD-OSD.elf,PSBBN.ELF,BOOT.ELF}
fi
if [ "$MODE" = "install" ]; then
mkdir -p "${OPL}"/{APPS,ART,CFG,CHT,LNG,THM,VMC,CD,DVD,bbnl} 2>>"${LOG_FILE}" || error_msg "Failed to create OPL folders."
echo "$LATEST_VERSION" > "${OPL}/version.txt"
echo "APA_SIZE = $APA_MiB" >> "${OPL}/version.txt"
echo "LANG = $LANG" >> "${OPL}/version.txt"
echo "LANG_VER = $LATEST_LANG" >> "${OPL}/version.txt"
echo "CHAN_VER = $LATEST_CHAN" >> "${OPL}/version.txt"
else
if [[ -f "${OPL}/version.txt" ]]; then
sed -i "1s|.*|$LATEST_VERSION|" "${OPL}/version.txt"
if ! grep -q "APA_SIZE *=" "${OPL}/version.txt"; then
echo "APA_SIZE = 131072" >> "${OPL}/version.txt"
fi
# Delete any line beginning with "eng"
sed -i '/^eng/d' "${OPL}/version.txt"
# If no line begins with "LANG =" then append it
if ! grep -q "^LANG =" "${OPL}/version.txt"; then
echo "LANG = $LANG" >> "${OPL}/version.txt"
fi
# Update or add LANG_VER
if grep -q "^LANG_VER =" "${OPL}/version.txt"; then
sed -i "s|^LANG_VER =.*|LANG_VER = $LATEST_LANG|" "${OPL}/version.txt"
else
echo "LANG_VER = $LATEST_LANG" >> "${OPL}/version.txt"
fi
# Update or add CHAN_VER
if grep -q "^CHAN_VER =" "${OPL}/version.txt"; then
sed -i "s|^CHAN_VER =.*|CHAN_VER = $LATEST_CHAN|" "${OPL}/version.txt"
else
echo "CHAN_VER = $LATEST_CHAN" >> "${OPL}/version.txt"
fi
else
error_msg "Error" "Failed to update version.txt."
fi
fi
# Add disk icon
cp -f "${ASSETS_DIR}/autorun.ico" "${OPL}"
cat << EOF > "${OPL}/autorun.inf"
[AutoRun]
icon=autorun.ico
label=OPL
EOF
UNMOUNT_OPL
echo >> "${LOG_FILE}"
echo "${TOC_OUTPUT}" >> "${LOG_FILE}"
echo >> "${LOG_FILE}"
lsblk -p -o MODEL,NAME,SIZE,LABEL,MOUNTPOINT >> "${LOG_FILE}"
echo | tee -a "${LOG_FILE}"
if [ "$MODE" = "install" ]; then
echo "[✓] PSBBN Successfully Installed!" | tee -a "${LOG_FILE}"
else
UPDATE_SPLASH
echo " ================================== [✓] PSBBN Successfully Updated =================================" | tee -a "${LOG_FILE}"
echo
if [ "$PSBBN_UPDATE" != "no" ]; then
echo " PSBBN System Software updated to version: $LATEST_VERSION"
fi
if [ "$LANG_UPDATE" != "no" ]; then
echo " Language Pack updated to version: $LANG $LATEST_LANG"
fi
if [ "$CHAN_UPDATE" == "yes" ]; then
echo " Online Channels uptaded to version: $LANG $LATEST_CHAN"
fi
echo
if [ "$PSBBN_UPDATE" != "no" ] && version_le "${psbbn_version:-0}" "3.00"; then
echo " Now connect the drive to your PS2 console and boot into PSBBN to complete the installation."
echo " This must be done before running the Game Installer."
echo
fi
if [ "$PSBBN_UPDATE" != "no" ] && version_le "${psbbn_version:-0}" "4.0.0"; then
echo " It's recommended to rerun the Game Installer and choose \"Add Additional Games and Apps\" to"
echo " improve game startup times and add apps to the System Menu in HOSDMenu."
echo
fi
if [ "$PSBBN_UPDATE" != "no" ] || [ "$LANG_UPDATE" != "no" ]; then
echo " If you had previously swapped the X and O buttons, you'll need to do it again in the Extras menu."
echo
fi
echo " ===================================================================================================="
fi
echo
read -n 1 -s -r -p "Press any key to return to the menu..." </dev/tty
echo