#!/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 TOOLKIT_PATH="$(pwd)" SCRIPTS_DIR="${TOOLKIT_PATH}/scripts" HELPER_DIR="${SCRIPTS_DIR}/helper" ASSETS_DIR="${SCRIPTS_DIR}/assets" STORAGE_DIR="${SCRIPTS_DIR}/storage" OPL="${SCRIPTS_DIR}/OPL" OSDMBR_CNF="${SCRIPTS_DIR}/tmp/OSDMBR.CNF" LOG_FILE="${TOOLKIT_PATH}/logs/extras.log" path_arg="$1" 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 error_msg() { error_1="$1" error_2="$2" error_3="$3" error_4="$4" echo 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() { sudo umount -l "${OPL}" >> "${LOG_FILE}" 2>&1 sudo rm -rf "${SCRIPTS_DIR}/tmp" failure=0 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" >> "${LOG_FILE}" 2>&1 || failure=1 done <<< "$submounts" fi if [ -d "${STORAGE_DIR}" ]; then submounts=$(findmnt -nr -o TARGET | grep "^${STORAGE_DIR}/" | sort -r) 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 # 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 echo "Failed to delete mapper $map_name." >> "$LOG_FILE" failure=1 fi done # Abort if any failures occurred if [ "$failure" -ne 0 ]; then echo | tee -a "${LOG_FILE}" error_msg "[X] Error: Cleanup error(s) occurred. Aborting." return 1 fi } exit_script() { clean_up if [[ -n "$path_arg" ]]; then cp "${LOG_FILE}" "${path_arg}" > /dev/null 2>&1 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[@]}" "${APA_PARTITIONS[@]}" ) # 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 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 [ -d "${MOUNT_PATH}" ] || mkdir -p "${MOUNT_PATH}" if ! sudo mount "${MAPPER}${PARTITION_NAME}" "${MOUNT_PATH}" >>"${LOG_FILE}" 2>&1; then error_msg "[X] Error: Failed to mount ${PARTITION_NAME} partition." clean_up return 1 fi else error_msg "[X] Error: Partition ${PARTITION_NAME} not found on disk." clean_up return 1 fi done } mount_pfs() { for PARTITION_NAME in "${APA_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 "[X] Error: Failed to mount $PARTITION_NAME partition." "Check the device or filesystem and try again." clean_up return 1 fi done } detect_drive() { DEVICE=$(sudo blkid -t TYPE=exfat | grep OPL | awk -F: '{print $1}' | sed 's/[0-9]*$//') if [[ -z "$DEVICE" ]]; then echo | tee -a "${LOG_FILE}" echo "[X] Error: Unable to detect the PS2 drive. Please ensure the drive is properly connected." | tee -a "${LOG_FILE}" echo echo "You must install PSBBN first before insalling extras." echo read -n 1 -s -r -p "Press any key to return to the menu..." > "${LOG_FILE}" # 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 echo echo "Failed to unmount $mount_point. Please unmount manually." | tee -a "${LOG_FILE}" read -n 1 -s -r -p "Press any key to return to the menu..." > "${LOG_FILE}" 2>&1; then echo echo "[X] Error: APA partition is broken on ${DEVICE}." | tee -a "${LOG_FILE}" read -n 1 -s -r -p "Press any key to return to the menu..." > "${LOG_FILE}" fi } MOUNT_OPL() { echo | tee -a "${LOG_FILE}" echo "Mounting OPL partition..." >> "${LOG_FILE}" if ! mkdir -p "${OPL}" 2>>"${LOG_FILE}"; then read -n 1 -s -r -p "Failed to create ${OPL}. Press any key to return to the menu..." > "${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..." | tee -a "${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 "[X] Error: Failed to mount ${DEVICE}3" return 1 fi } UNMOUNT_OPL() { sync if ! sudo umount -l "${OPL}" >> "${LOG_FILE}" 2>&1; then read -n 1 -s -r -p "Failed to unmount $DEVICE. Press any key to return to the menu..." > "${LOG_FILE}" 2>&1) if echo "$PFS_COMMANDS" | grep -q "Exit code is"; then error_msg "PFS Shell returned an error. See ${LOG_FILE}" return 1 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 "[X] Error: Failed to extract list of partitions." "APA partition could be broken on ${DEVICE}" return 1 fi } AVAILABLE_SPACE(){ HDL_TOC || return 1 # Extract the "used" value, remove "MB" and any commas used=$(cat "$hdl_output" | awk '/used:/ {print $6}' | sed 's/,//; s/MB//') # Calculate available space (APA_SIZE - used) available=$((APA_SIZE - used - 6400 - 128)) free_space=$((available / 1024)) echo "Free Space: $free_space GB" >> "${LOG_FILE}" } 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 echo "Newer local file found: ${LATEST_FILE}" | tee -a "${LOG_FILE}" # Only set LATEST_VERSION for the patch prefix if [[ "$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" == "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 "[X] Error: Failed to find ${display}. Aborting." return 1 } 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 "[X] Error: Download failed for ${LATEST_FILE}." "Please check your internet connection and try again." return 1 fi fi } SWAP_SPLASH(){ clear cat << "EOF" ______ _ ______ _ _ | ___ \ (_) | ___ \ | | | | | |_/ /___ __ _ ___ ___ _ __ _ _ __ | |_/ /_ _| |_| |_ ___ _ __ ___ | // _ \/ _` / __/ __| |/ _` | '_ \ | ___ \ | | | __| __/ _ \| '_ \/ __| | |\ \ __/ (_| \__ \__ \ | (_| | | | | | |_/ / |_| | |_| || (_) | | | \__ \ \_| \_\___|\__,_|___/___/_|\__, |_| |_| \____/ \__,_|\__|\__\___/|_| |_|___/ __/ | |___/ EOF } LINUX_SPLASH(){ clear cat << "EOF" ______ _____ _____ _ _ | ___ \/ ___|/ __ \ | | (_) | |_/ /\ `--. `' / /' | | _ _ __ _ ___ __ | __/ `--. \ / / | | | | '_ \| | | \ \/ / | | /\__/ /./ /___ | |___| | | | | |_| |> < \_| \____/ \_____/ \_____/_|_| |_|\__,_/_/\_\ EOF } LANGUAGE_SPLASH(){ clear cat << "EOF" _____ _ _ / __ \ | | | | / \/ |__ __ _ _ __ __ _ ___ | | __ _ _ __ __ _ _ _ __ _ __ _ ___ | | | '_ \ / _` | '_ \ / _` |/ _ \ | | / _` | '_ \ / _` | | | |/ _` |/ _` |/ _ \ | \__/\ | | | (_| | | | | (_| | __/ | |___| (_| | | | | (_| | |_| | (_| | (_| | __/ \____/_| |_|\__,_|_| |_|\__, |\___| \_____/\__,_|_| |_|\__, |\__,_|\__,_|\__, |\___| __/ | __/ | __/ | |___/ |___/ |___/ EOF } # Function for Option 1 - Install PS2 Linux option_one() { echo "########################################################################################################" >> "${LOG_FILE}" echo "Install PS2 Linux:" >> "${LOG_FILE}" LINUX_SPLASH detect_drive && \ MOUNT_OPL || return 1 psbbn_version=$(head -n 1 "$OPL/version.txt" 2>/dev/null) APA_SIZE=$(awk -F' *= *' '$1=="APA_SIZE"{print $2}' "${OPL}/version.txt") UNMOUNT_OPL || return 1 version_check="4.0.0" HDL_TOC || return 1 if cat "${hdl_output}" | grep -q '\b__linux\.3\b'; then linux3="yes" if [ "$(printf '%s\n' "$psbbn_version" "$version_check" | sort -V | head -n1)" != "$version_check" ]; then error_msg "Linux is already installed." "If you want to reinstall Linux, update to PSBBN version 4.0.0 or higher first." return 0 else while true; do LINUX_SPLASH echo " Linux is already installed on your PS2. Do you want to reinstall it?" | tee -a "${LOG_FILE}" if cat "${hdl_output}" | grep -q '\b__linux\.10\b'; then echo echo " - All Linux system files will be reinstalled." | tee -a "${LOG_FILE}" echo " - Your personal files in the home directory will not be affected." | tee -a "${LOG_FILE}" else echo echo " ============================== WARNING =============================" echo echo " All PS2 Linux data will be erased, including your home direcrtory." | tee -a "${LOG_FILE}" echo " Make sure to back up your files before continuing." echo echo " ====================================================================" fi echo read -p " Reinstall PS2 Linux? (y/n): " answer case "$answer" in [Yy]) break ;; [Nn]) return 0 ;; *) echo echo -n " Please enter y or n." sleep 3 ;; esac done fi fi LINUX_SPLASH if [ "$linux3" != "yes" ]; then if [ "$(printf '%s\n' "$psbbn_version" "$version_check" | sort -V | head -n1)" != "$version_check" ]; then error_msg "To install or reinstall PS2 Linux, update to PSBBN version 4.0.0 or higher." return 0 else if [ -z "$APA_SIZE" ]; then error_msg "[X] Error: Unable to determine APA free space." return 1 else AVAILABLE_SPACE || return 1 if [ "$free_space" -lt 3 ]; then error_msg "[X] Error: Insufficient disk space. At least 3 GB of free space is required to install Linux." return 1 else free_space=$((free_space -2)) fi fi fi fi download_linux || return 1 if [ "$linux3" == "yes" ]; then HDL_TOC || return 1 LINUX_SIZE=$(grep '__\linux.3' "$hdl_output" | awk '{print $4}' | grep -oE '[0-9]+') if [ "$LINUX_SIZE" -gt 2048 ]; then COMMANDS="device ${DEVICE}\n" COMMANDS+="rmpart __linux.3\n" COMMANDS+="exit" PFS_COMMANDS || return 1 linux3="no" fi fi if ! cat "${hdl_output}" | grep -q '\b__linux\.10\b'; then echo "Free Space available for home partition: $free_space GB" >> "${LOG_FILE}" while true; do echo | tee -a "${LOG_FILE}" echo "APA Space Available: $free_space GB" >> "${LOG_FILE}" echo "What size would you like the \"home\" partition to be?" echo "Minimum 1 GB, maximum $free_space GB" echo read -p "Enter partition size (in GB): " home_gb if [[ ! "$home_gb" =~ ^[0-9]+$ ]]; then echo echo -n "Invalid input. Please enter a valid number." sleep 3 continue fi if (( home_gb < 1 || home_gb > free_space )); then echo echo "Invalid size. Please enter a value between 1 and $free_space GB." sleep 3 continue fi break done echo "Home partition size: $home_gb" >> "${LOG_FILE}" home_mb=$((home_gb * 1024)) fi if [[ "$linux3" != "yes" || -n "$home_gb" ]]; then COMMANDS="device ${DEVICE}\n" if [ "$linux3" != "yes" ]; then COMMANDS+="mkpart __linux.3 2048M EXT2\n" fi if [ -n "$home_gb" ]; then COMMANDS+="mkpart __linux.10 ${home_mb}M EXT2\n" fi COMMANDS+="exit" echo "Creating partitions..." >>"${LOG_FILE}" PFS_COMMANDS || return 1 fi echo | tee -a "${LOG_FILE}" echo -n "Installing PS2 Linux..." | tee -a "${LOG_FILE}" LINUX_PARTITIONS=("__linux.3" ) APA_PARTITIONS=("__system" "__sysconf" ) clean_up && \ mapper_probe || return 1 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}__linux.3" >>"${LOG_FILE}" 2>&1; then error_msg "[X] Error: Failed to create filesystem __linux.3." return 1 fi mount_cfs && \ mount_pfs || return 1 if ! sudo tar zxpf "${ASSETS_DIR}/PS2Linux.tar.gz" -C "${STORAGE_DIR}/__linux.3" >>"${LOG_FILE}" 2>&1; then error_msg "Failed to extract files. Install Failed." return 1 fi cp -f "${ASSETS_DIR}/kernel/ps2-linux-"{ntsc,vga} "${STORAGE_DIR}/__system/p2lboot/" 2>> "${LOG_FILE}" || { error_msg "Failed to copy kernel files."; return 1; } TMP_FILE=$(mktemp /tmp/OSDMBR.XXXXXX) cp -f "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" "$TMP_FILE" 2>> "${LOG_FILE}" || { error_msg "Failed to copy OSDMBR.CNF."; return 1; } # Remove any existing boot_circle lines sed -i '/^boot_circle/d' "$TMP_FILE" 2>> "${LOG_FILE}" # Append new PSBBN boot entries { echo 'boot_circle = $PSBBN' echo 'boot_circle_arg1 = --kernel' echo 'boot_circle_arg2 = pfs0:/p2lboot/ps2-linux-ntsc' echo 'boot_circle_arg3 = -noflags' } >> "$TMP_FILE" cp -f $TMP_FILE "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" 2>> "${LOG_FILE}" || { error_msg "Failed to copy OSDMBR.CNF."; return 1; } clean_up || return 1 LINUX_SPLASH echo "=============================== [✓] PS2 Linux Successfully Installed ==============================" | tee -a "${LOG_FILE}" cat << "EOF" To launch PS2 Linux, power on your PS2 console and hold the CIRCLE button on the controller. PS2 Linux requires a USB keyboard; a mouse is optional but recommended. Default "root" password: password Default password for "ps2" user account: password To launch a graphical interface type: startx ==================================================================================================== EOF read -n 1 -s -r -p " Press any key to return to the menu..." > "${LOG_FILE}" echo "Reassign Buttons:" >> "${LOG_FILE}" SWAP_SPLASH detect_drive && \ MOUNT_OPL || return 1 psbbn_version=$(head -n 1 "$OPL/version.txt" 2>/dev/null) UNMOUNT_OPL || return 1 if [[ "$(printf '%s\n' "$psbbn_version" "2.10" | sort -V | head -n1)" != "2.10" ]]; then # $psbbn_version < 2.10 error_msg "[X] Error: PSBBN Definitive Patch version is lower than the required version of 3.00." "To update, please select 'Install PSBBN' from the main menu and try again." exit 1 elif [[ "$(printf '%s\n' "$psbbn_version" "3.00" | sort -V | head -n1)" = "$psbbn_version" ]] \ && [[ "$psbbn_version" != "3.00" ]]; then error_msg "[X] Error: PSBBN Definitive Patch version is lower than the required version of 3.00." "To update, please select “Update PSBBN Software” from the main menu and try again." exit 1 fi LINUX_PARTITIONS=("__linux.4" ) APA_PARTITIONS=("__system" ) clean_up && \ mapper_probe && \ mount_cfs && \ mount_pfs || return 1 ls -l /dev/mapper >> "${LOG_FILE}" df >> "${LOG_FILE}" choice="" while :; do SWAP_SPLASH cat << "EOF" Please select a button layout: 1) Cross = Enter, Circle = Back 2) Circle = Enter, Cross = Back b) Back EOF read -rp " Select an option: " choice case "$choice" in 1) echo "Western layout selected." >> "${LOG_FILE}" if sudo cp -f "${ASSETS_DIR}/kernel/vmlinux" "${STORAGE_DIR}/__system/p2lboot/vmlinux" >> "${LOG_FILE}" 2>&1 \ && sudo cp -f "${ASSETS_DIR}/kernel/x.tm2" "${STORAGE_DIR}/__linux.4/bn/data/tex/btn_r.tm2" >> "${LOG_FILE}" 2>&1 \ && sudo cp -f "${ASSETS_DIR}/kernel/o.tm2" "${STORAGE_DIR}/__linux.4/bn/data/tex/btn_d.tm2" >> "${LOG_FILE}" 2>&1 then SWAP_SPLASH echo "================================= [✓] Buttons Swapped Successfully =================================" | tee -a "${LOG_FILE}" echo read -n 1 -s -r -p " Press any key to return to the menu..." > "${LOG_FILE}" if sudo cp -f "${ASSETS_DIR}/kernel/vmlinux_jpn" "${STORAGE_DIR}/__system/p2lboot/vmlinux" >> "${LOG_FILE}" 2>&1 \ && sudo cp -f "${ASSETS_DIR}/kernel/o.tm2" "${STORAGE_DIR}/__linux.4/bn/data/tex/btn_r.tm2" >> "${LOG_FILE}" 2>&1 \ && sudo cp -f "${ASSETS_DIR}/kernel/x.tm2" "${STORAGE_DIR}/__linux.4/bn/data/tex/btn_d.tm2" >> "${LOG_FILE}" 2>&1 then SWAP_SPLASH echo "================================= [✓] Buttons Swapped Successfully =================================" | tee -a "${LOG_FILE}" echo read -n 1 -s -r -p " Press any key to return to the menu..." > "${LOG_FILE}" ls -l /dev/mapper >> "${LOG_FILE}" df >> "${LOG_FILE}" } option_three() { echo "########################################################################################################" >> "${LOG_FILE}" echo "Change Language:" >> "${LOG_FILE}" LANGUAGE_SPLASH detect_drive && \ MOUNT_OPL || return 1 psbbn_version=$(head -n 1 "$OPL/version.txt" 2>/dev/null) if [[ "$(printf '%s\n' "$psbbn_version" "2.10" | sort -V | head -n1)" != "2.10" ]]; then # $psbbn_version < 2.10 error_msg "[X] Error: PSBBN Definitive Patch version is lower than the required version of 4.1.0." "To update, please select 'Install PSBBN' from the main menu and try again." exit 1 elif [[ "$(printf '%s\n' "$psbbn_version" "4.1.0" | sort -V | head -n1)" = "$psbbn_version" ]] \ && [[ "$psbbn_version" != "4.1.0" ]]; then error_msg "[X] Error: PSBBN Definitive Patch version is lower than the required version of 4.1.0." "To update, please select “Update PSBBN Software” from the main menu and try again." exit 1 fi while :; do LANGUAGE_SPLASH cat << "EOF" Please select a language from the list below: 1) English 2) Japanese 3) German EOF read -rp " Select an option: " choice case "$choice" in 1) LANG="eng" LANG_DISPLAY="English" break ;; 2) LANG="jpn" LANG_DISPLAY="Japanese" break ;; 3) LANG="ger" LANG_DISPLAY="German" break ;; *) echo echo -n " Invalid choice, enter a number between 1 and 3." sleep 3 ;; esac done echo "Language selected: $LANG_DISPLAY" >> "${LOG_FILE}" LANGUAGE_SPLASH # 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 "language-pak-$LANG" "$LANG_DISPLAY language pack" || return 1 downoad_latest_file "language-pak" || return 1 LANG_PACK="${ASSETS_DIR}/${LATEST_FILE}" if [[ "$LANG" == "jpn" ]]; then get_latest_file "channels-$LANG" "$LANG_DISPLAY channels" || return 1 downoad_latest_file "channels" || return 1 CHANNELS="${ASSETS_DIR}/${LATEST_FILE}" fi sed -i "s/^LANG =.*/LANG = $LANG/" "$OPL/version.txt" || { error_msg "[X] Error: Failed to update language in version.txt."; return 1; } sed -i "s|^LANG_VER =.*|LANG_VER = $LATEST_LANG|" "${OPL}/version.txt" || { error_msg "[X] Error: Failed to update language in version.txt."; return 1; } sed -i "s|^CHAN_VER =.*|CHAN_VER = $LATEST_CHAN|" "${OPL}/version.txt" || { error_msg "[X] Error: Failed to update language in version.txt."; return 1; } LINUX_PARTITIONS=("__linux.1" "__linux.4" "__linux.5" "__linux.9" ) APA_PARTITIONS=("__system" "__sysconf" "__common") clean_up && \ mapper_probe || return 1 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}__linux.9" >> "${LOG_FILE}" 2>&1 || { error_msg "[X] Error: Failed to initialise channels filesystem." "See ${LOG_FILE} for details."; return 1; } mount_cfs && \ mount_pfs || return 1 ls -l /dev/mapper >> "${LOG_FILE}" df >> "${LOG_FILE}" echo echo -n "Installing language pack..." sudo tar zxpf "$LANG_PACK" -C "${STORAGE_DIR}/" >> "${LOG_FILE}" 2>&1 || { error_msg "[X] Error: Failed to install $LANG_DISPLAY language pack." "See ${LOG_FILE} for details."; return 1; } if [[ "$LANG" == "jpn" ]]; then cp -f "${ASSETS_DIR}/kernel/vmlinux_jpn" "${STORAGE_DIR}/__system/p2lboot/vmlinux" 2>> "${LOG_FILE}" || { error_msg "[X] Error: Failed to copy kernel file."; return 1; } sudo tar zxpf "${CHANNELS}" -C "${STORAGE_DIR}/" >> "${LOG_FILE}" 2>&1 || { error_msg "[X] Error: Failed to install channels." "See ${LOG_FILE} for details."; return 1; } else cp -f "${ASSETS_DIR}/kernel/vmlinux" "${STORAGE_DIR}/__system/p2lboot/vmlinux" 2>> "${LOG_FILE}" || { error_msg "[X] Error: Failed to copy kernel file."; return 1; } fi mkdir -p "${SCRIPTS_DIR}/tmp" cp "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" "${OSDMBR_CNF}" || { error_msg "[X] Error: Failed to copy OSDMBR.CNF."; return 1; } sed -i "s/^osd_language =.*/osd_language = $LANG/" "${OSDMBR_CNF}" || { error_msg "[X] Error: Failed to update language in OSDMBR.CNF."; return 1; } cp -f "${OSDMBR_CNF}" "${STORAGE_DIR}/__sysconf/osdmenu/OSDMBR.CNF" || { error_msg "[X] Error: Failed to replace OSDMBR.CNF."; return 1; } if [[ "$LANG" == "jpn" ]]; then rm -f "${STORAGE_DIR}/__common/POPS/"{IGR_BG.TM2,IGR_NO.TM2,IGR_YES.TM2} 2>> "${LOG_FILE}" || { error_msg "[X] Error: Update POPS IGR textures."; return 1; } else mkdir -p "${STORAGE_DIR}/__common/POPS" cp -f "${ASSETS_DIR}/POPStarter/$LANG/"{IGR_BG.TM2,IGR_NO.TM2,IGR_YES.TM2} "${STORAGE_DIR}/__common/POPS/" 2>> "${LOG_FILE}" || { error_msg "[X] Error: Update POPS IGR textures."; return 1; } fi clean_up || return 1 echo clean up afterwards: >> "${LOG_FILE}" ls -l /dev/mapper >> "${LOG_FILE}" df >> "${LOG_FILE}" msg=" [✓] Language Successfully Changed to $LANG_DISPLAY " total_width=100 # Length of the message including spaces around it msg_len=${#msg} # Calculate number of "=" on each side pad=$(( (total_width - msg_len) / 2 )) # If odd padding required, right side will get one more "=", so account for it extra=$(( (total_width - msg_len) % 2 )) left_pad=$(printf '%*s' "$pad" | tr ' ' '=') right_pad=$(printf '%*s' $((pad + extra)) | tr ' ' '=') LANGUAGE_SPLASH echo " ${left_pad}${msg}${right_pad}" echo echo " It's recommended to rerun the Game Installer and choose \"Add Additional Games and Apps\" to" echo " update the game titles and PlaySation game manuals to your selected language." echo echo " If you had previously swapped the X and O buttons, you'll need to do it again in the Extras menu." echo echo " ====================================================================================================" echo read -n 1 -s -r -p " Press any key to return to the menu..." <| |_| | | (_| \__ \ \____/_/\_\\__|_| \__,_|___/ EOF } # Function to display the menu display_menu() { EXTRAS_SPLASH cat << "EOF" 1) Install PS2 Linux 2) Reassign Cross and Circle Buttons 3) Change Language b) Back to Main Menu EOF } clear trap 'echo; exit 130' INT trap exit_script EXIT cd "${TOOLKIT_PATH}" 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 "[X] Error: Cannot to create log file." read -n 1 -s -r -p "Press any key to exit..." > "${LOG_FILE}" echo >> "${LOG_FILE}" cat /etc/*-release >> "${LOG_FILE}" 2>&1 EXTRAS_SPLASH detect_drive || exit 1 CHECK_PARTITIONS if ! sudo rm -rf "${STORAGE_DIR}"; then error_msg "Failed to remove $STORAGE_DIR folder." fi # Main loop while true; do display_menu read -p " Select an option: " choice case $choice in 1) option_one ;; 2) option_two ;; 3) option_three ;; b|B) break ;; *) echo echo -n " Invalid option, please try again." sleep 2 ;; esac done