#!/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/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..." > "${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..." > "${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..." > "${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" < "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" <> "${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..."