|
#!/bin/bash |
|
# xone install or update script for SteamOS |
|
# by cdleveille |
|
# updated by SavageCore |
|
# |
|
# https://gist.github.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d |
|
# Script version 0.9.0 |
|
|
|
# Set xone local repo location |
|
XONE_LOCAL_REPO="/home/deck/repos/xone" |
|
XPAD_NOONE_LOCAL_REPO="/home/deck/repos/xpad-noone" |
|
# Set xone remote repo location |
|
# dlundqvist is maintaining a fork that contains PRs that have not been merged into the main repo |
|
# main repo: https://github.com/medusalix/xone |
|
XONE_REMOTE_REPO="https://github.com/dlundqvist/xone" |
|
XPAD_NOONE_REMOTE_REPO="https://github.com/medusalix/xpad-noone" |
|
XPAD_NOONE_VERSION="1.0" |
|
|
|
# DO NOT EDIT BELOW THIS LINE |
|
KEEP_READ_ONLY="false" |
|
REDIRECT=">/dev/null 2>&1" |
|
DEBUG="false" |
|
CURRENT_USER=$(whoami) |
|
REQUIRED_PACKAGES=("curl" "wget" "git" "gcc" "cabextract" "dkms" "libisl" "libmpc") |
|
# If --debug is passed as an argument, enable debug mode |
|
if [[ "$1" == "--debug" ]]; then |
|
REDIRECT="" |
|
DEBUG="true" |
|
fi |
|
|
|
# compare_semver: Compare two Semantic Versioning (SemVer) strings. |
|
# Usage: compare_semver <version1> <version2> |
|
compare_semver() { |
|
# Split version strings into major, minor, and patch segments. |
|
ver1_major=$(echo "$1" | cut -d '.' -f 1) |
|
ver1_minor=$(echo "$1" | cut -d '.' -f 2) |
|
ver1_patch=$(echo "$1" | cut -d '.' -f 3) |
|
|
|
ver2_major=$(echo "$2" | cut -d '.' -f 1) |
|
ver2_minor=$(echo "$2" | cut -d '.' -f 2) |
|
ver2_patch=$(echo "$2" | cut -d '.' -f 3) |
|
|
|
# Compare major versions. |
|
if [ "$ver1_major" -gt "$ver2_major" ]; then |
|
echo "1" |
|
return |
|
elif [ "$ver1_major" -lt "$ver2_major" ]; then |
|
echo "-1" |
|
return |
|
fi |
|
|
|
# Compare minor versions. |
|
if [ "$ver1_minor" -gt "$ver2_minor" ]; then |
|
echo "1" |
|
return |
|
elif [ "$ver1_minor" -lt "$ver2_minor" ]; then |
|
echo "-1" |
|
return |
|
fi |
|
|
|
# Compare patch versions. |
|
if [ "$ver1_patch" -gt "$ver2_patch" ]; then |
|
echo "1" |
|
return |
|
elif [ "$ver1_patch" -lt "$ver2_patch" ]; then |
|
echo "-1" |
|
return |
|
fi |
|
|
|
# Versions are equal. |
|
echo "0" |
|
} |
|
|
|
install_xone() { |
|
if [ -n "$(dkms status xone)" ]; then |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "" |
|
echo "xone is already installed" |
|
fi |
|
|
|
return |
|
fi |
|
|
|
cd $XONE_LOCAL_REPO || { |
|
echo "Failed to cd into xone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
|
|
echo -e "\e[1mInstalling xone...\e[0m" |
|
echo "" |
|
|
|
# Run the xone install and get-firmware scripts |
|
eval sudo ./install.sh --release "$REDIRECT" |
|
echo -e "\e[1mGetting xone firmware...\e[0m" |
|
echo "" |
|
eval sudo xone-get-firmware.sh --skip-disclaimer "$REDIRECT" |
|
} |
|
|
|
uninstall_xone() { |
|
cd $XONE_LOCAL_REPO || { |
|
echo "Failed to cd into xone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
|
|
# Run the xone uninstall script |
|
eval sudo ./uninstall.sh "$REDIRECT" |
|
} |
|
|
|
install_xpad_noone() { |
|
if [ -n "$(dkms status xpad-noone)" ]; then |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "xpad-noone is already installed" |
|
fi |
|
|
|
return |
|
fi |
|
|
|
echo -e "\e[1mInstalling xpad-noone...\e[0m" |
|
echo "" |
|
|
|
eval sudo modprobe -r xpad "$REDIRECT" |
|
eval sudo cp -r "$XPAD_NOONE_LOCAL_REPO" /usr/src/xpad-noone-$XPAD_NOONE_VERSION "$REDIRECT" |
|
eval sudo dkms install -m xpad-noone -v $XPAD_NOONE_VERSION "$REDIRECT" |
|
} |
|
|
|
uninstall_xpad_noone() { |
|
modules=$(lsmod | grep '^xpad_noone' | cut -d ' ' -f 1 | tr '\n' ' ') |
|
version=$XPAD_NOONE_VERSION |
|
|
|
if [ -n "$modules" ]; then |
|
# shellcheck disable=SC2086 |
|
eval sudo modprobe -r -a $modules "$REDIRECT" |
|
fi |
|
|
|
if [ -n "$version" ]; then |
|
eval sudo dkms remove -m xpad-noone -v "$version" --all "$REDIRECT" |
|
sudo rm -rf "/usr/src/xpad-noone-$version" |
|
else |
|
echo 'Driver is not installed!' |
|
fi |
|
} |
|
|
|
# Returns the SteamOS version |
|
detect_os_version() { |
|
version=$(cat /etc/*-release | grep VERSION_ID) |
|
|
|
if [[ $version == *"3.6"* ]]; then |
|
echo "3.6" |
|
elif [[ $version == *"3.5"* ]]; then |
|
echo "3.5" |
|
else |
|
echo "3.4" |
|
fi |
|
} |
|
|
|
# Install linux headers (if not already installed) |
|
install_linux_headers() { |
|
echo -e "\e[1mChecking for linux headers...\e[0m" |
|
echo "" |
|
version=$(detect_os_version) |
|
kernel_headers="linux-neptune-headers" |
|
|
|
# If SteamOS 3.6 or 3.5, use the new kernel headers package |
|
if [[ $version == "3.6" ]] || [[ $version == "3.5" ]]; then |
|
kernel_headers="linux-neptune-65-headers" |
|
|
|
if [[ $version == "3.5" ]]; then |
|
kernel_headers="linux-neptune-61-headers" |
|
fi |
|
|
|
# Ensure the SteamOS 3.4 kernel package (5.13) is uninstalled if installed |
|
if pacman -Qs "linux-neptune-headers" >/dev/null; then |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Found old 3.4 kernel package - removing" |
|
fi |
|
sudo pacman -R linux-neptune-headers --noconfirm >/dev/null |
|
fi |
|
fi |
|
|
|
if [[ $DEBUG == "true" ]]; then |
|
echo "SteamOS $version detected using $kernel_headers package" "$REDIRECT" |
|
fi |
|
|
|
# Are the kernel headers already installed and up-to-date? |
|
if pacman -Qs "$kernel_headers" >/dev/null && ! pacman -Qu "$kernel_headers" >/dev/null; then |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Headers are already installed and up to date" |
|
fi |
|
return |
|
fi |
|
|
|
# If the headers are not installed or need updating, install them |
|
echo -e "\e[1mInstalling required kernel headers, this may take a while...\e[0m" |
|
echo "" |
|
eval sudo pacman -Sy "$kernel_headers" --noconfirm >/dev/null |
|
} |
|
|
|
install_base_devel() { |
|
# Get list of base-devel packages |
|
base_devel_packages=$(pacman -Sg base-devel | cut -d ' ' -f 2) |
|
|
|
# Check if any of the base-devel packages are missing or need updating |
|
for package in $base_devel_packages; do |
|
if pacman -Qs "$package" >/dev/null; then |
|
if pacman -Qu "$package" >/dev/null; then |
|
packages_to_update+=("$package") |
|
fi |
|
else |
|
packages_to_install+=("$package") |
|
fi |
|
done |
|
} |
|
|
|
install_pairing_shortcuts() { |
|
# If the pairing shortcuts are already installed (on desktop), exit |
|
if [ -f ~/Desktop/enable-pairing.desktop ] && [ -f ~/Desktop/disable-pairing.desktop ]; then |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Pairing shortcuts already installed" |
|
fi |
|
return |
|
fi |
|
|
|
# Download the pairing shortcuts |
|
curl -sSf "https://gist.githubusercontent.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d/raw/e98d6af5cba9ab4085b9e7f0c26cfd0b7c807c7d/enable-pairing.desktop?$(date +%s)" >~/Desktop/enable-pairing.desktop || { |
|
echo "Failed to download enable-pairing.desktop." |
|
} |
|
|
|
curl -sSf "https://gist.githubusercontent.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d/raw/e98d6af5cba9ab4085b9e7f0c26cfd0b7c807c7d/disable-pairing.desktop?$(date +%s)" >~/Desktop/disable-pairing.desktop || { |
|
echo "Failed to download disable-pairing.desktop." |
|
} |
|
} |
|
|
|
echo -e "\e[1mxone install script by SavageCore\e[0m" |
|
echo -e "\e[1mhttps://gist.github.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d\e[0m" |
|
echo "─────────────────────────────" |
|
echo "" |
|
echo "This script will install the xone and xpad-noone drivers for the Xbox wireless dongle and controller" |
|
echo "" |
|
|
|
# Check if script is up to date |
|
CURRENT_VERSION=$(sed -n 's/^# Script version //p' "$0") |
|
REQUIRED_VERSION=$(curl -s "https://gist.githubusercontent.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d/raw/xone_install_or_update.sh?$(date +%s)" | sed -n 's/^# Script version //p') |
|
|
|
VERSION_DIFF=$(compare_semver "$CURRENT_VERSION" "$REQUIRED_VERSION") |
|
|
|
# if [[ "$CURRENT_VERSION" != "$REQUIRED_VERSION" ]]; then |
|
if [[ $VERSION_DIFF == -1 ]]; then |
|
echo -e "\e[1mYou have an outdated version of the script. Updating...\e[0m" |
|
echo "" |
|
|
|
# Download the latest version of the script from the Gist |
|
curl -sSf "https://gist.githubusercontent.com/SavageCore/263a3413532bc181c9bb215c8fe6c30d/raw/xone_install_or_update.sh?cachebust=dd?$(date +%s)" >/tmp/xone_install_or_update.sh || { |
|
echo "Failed to download the latest version of the script. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
|
|
# Preserve the current working directory and arguments |
|
PWD=$(pwd) |
|
ARGS="$@" |
|
|
|
# Replace the current script with the new version |
|
mv /tmp/xone_install_or_update.sh "$0" |
|
|
|
read -n 1 -s -r -p "Press any key to relaunch the script..." |
|
clear |
|
# Re-run the script with the same environment variables and arguments |
|
cd "$PWD" || { |
|
echo "Failed to change directory. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
exec bash "$0" "$ARGS" |
|
fi |
|
|
|
# Does the user have a sudo password set? |
|
# If not, prompt them to set one |
|
if [ "$(passwd -S "$CURRENT_USER" | cut -d" " -f2)" != "P" ]; then |
|
echo -e "\e[1mA sudo password is required, please enter one now to create it\e[0m" |
|
PASSWORD=$(zenity --password --title="Password") |
|
CONFIRM_PASSWORD=$(zenity --password --title="Confirm password") |
|
|
|
# If the passwords don't match, exit |
|
if [ "$PASSWORD" != "$CONFIRM_PASSWORD" ]; then |
|
zenity --error --text="Passwords do not match\n\nExiting..." --title="Error" |
|
exit 1 |
|
fi |
|
|
|
{ |
|
echo -e "$PASSWORD\n$PASSWORD" | passwd |
|
# Elevate with sudo |
|
echo -e "$PASSWORD" | sudo -S echo "" "$REDIRECT" |
|
} &>/dev/null |
|
fi |
|
|
|
# Check if the user has sudo privileges |
|
# If not, prompt the user for a password |
|
if ! sudo -n true 2>/dev/null; then |
|
if ! zenity --password --title="Sudo password" | eval sudo -S echo "" "$REDIRECT"; then |
|
zenity --error --text="Sorry, you need to have sudo privileges to run this script." --title="Error" |
|
exit 1 |
|
fi |
|
fi |
|
|
|
# Rename fakeroot.conf to avoid error |
|
if [ -f /etc/ld.so.conf.d/fakeroot.conf ]; then |
|
sudo mv /etc/ld.so.conf.d/fakeroot.conf /etc/ld.so.conf.d/fakeroot.conf.bck |
|
fi |
|
|
|
# If output of `sudo steamos-readonly status` is "enabled", disable it |
|
if [ "$(sudo steamos-readonly status)" == "enabled" ]; then |
|
sudo steamos-readonly disable |
|
KEEP_READ_ONLY="true" |
|
fi |
|
|
|
# If pacman-key is not initialised, initialise it |
|
if ! eval pacman-key --list-keys >/dev/null 2>&1; then |
|
echo -e "\e[1mInitialising pacman...\e[0m" |
|
echo "" |
|
sudo pacman-key --init |
|
fi |
|
|
|
echo "Refreshing pacman keys..." |
|
# Always populate archlinux and holo keys, quick enough to do every time |
|
# TODO: Only populate if not already populated |
|
sudo pacman-key --populate archlinux holo >/dev/null 2>&1 |
|
|
|
# Install linux headers (if not already installed) |
|
install_linux_headers |
|
|
|
packages_to_install=() |
|
packages_to_update=() |
|
|
|
# Check if the required packages are installed and if they have updates |
|
for package in "${REQUIRED_PACKAGES[@]}"; do |
|
if pacman -Qs "$package" >/dev/null; then |
|
if pacman -Qu "$package" >/dev/null; then |
|
packages_to_update+=("$package") |
|
fi |
|
else |
|
packages_to_install+=("$package") |
|
fi |
|
done |
|
|
|
# Special case for base-devel, as it is a group, not a package |
|
install_base_devel |
|
|
|
# Are there any packages to install? |
|
if [ ! ${#packages_to_install[@]} -eq 0 ]; then |
|
# Install the packages |
|
echo -e "\e[1mInstalling required packages, this may take a while...\e[0m" |
|
echo "" |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Packages to install: ${packages_to_install[*]}" |
|
fi |
|
|
|
# Install the packages |
|
for package in "${packages_to_install[@]}"; do |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Installing $package" "$REDIRECT" |
|
fi |
|
sudo pacman -S "$package" --noconfirm >/dev/null |
|
done |
|
fi |
|
|
|
# Are there any packages to update? |
|
if [ ! ${#packages_to_update[@]} -eq 0 ]; then |
|
# Update the packages |
|
echo -e "\e[1mUpdating required packages, this may take a while...\e[0m" |
|
echo "" |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Packages to update: ${packages_to_update[*]}" |
|
fi |
|
|
|
# Update the packages |
|
for package in "${packages_to_update[@]}"; do |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "Updating $package" "$REDIRECT" |
|
fi |
|
|
|
sudo pacman -S "$package" --noconfirm >/dev/null |
|
done |
|
fi |
|
|
|
if [ ${#packages_to_install[@]} -eq 0 ] && [ ${#packages_to_update[@]} -eq 0 ]; then |
|
echo -e "\e[1mRequired packages installed and up to date\e[0m" |
|
echo "" |
|
fi |
|
|
|
XONE_HAS_UPDATED=false |
|
XPAD_HAS_UPDATED=false |
|
|
|
# Does the xone local repo folder already exist? |
|
if [ -d "$XONE_LOCAL_REPO" ]; then |
|
# ...if yes, run the uninstall script, and pull down any new updates from the remote repo |
|
echo -e "\e[1mChecking for xone updates...\e[0m" |
|
echo "" |
|
cd $XONE_LOCAL_REPO || { |
|
echo "Failed to cd into xone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
|
|
# Ensure the repo is in a clean state for git pull |
|
eval git reset --hard "$REDIRECT" |
|
# Check for updates with git pull, and if there are updates, uninstall |
|
git_output=$(eval git pull) |
|
|
|
if [[ $git_output != *"Already up to date."* ]]; then |
|
uninstall_xone |
|
XPAD_HAS_UPDATED=true |
|
else |
|
echo "No updates available" |
|
fi |
|
else |
|
# ...if not, clone the repo |
|
echo -e "\e[1mCloning xone repo...\e[0m" |
|
echo "" |
|
eval git clone $XONE_REMOTE_REPO $XONE_LOCAL_REPO "$REDIRECT" |
|
cd $XONE_LOCAL_REPO || { |
|
echo "Failed to clone xone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
fi |
|
|
|
# Does the xpad-noone local repo folder already exist? |
|
if [ -d "$XPAD_NOONE_LOCAL_REPO" ]; then |
|
# ...if yes, run the uninstall script, and pull down any new updates from the remote repo |
|
echo -e "\e[1mChecking for xpad-noone updates...\e[0m" |
|
echo "" |
|
cd $XPAD_NOONE_LOCAL_REPO || { |
|
echo "Failed to cd into xpad-noone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
|
|
# Ensure the repo is in a clean state for git pull |
|
eval git reset --hard "$REDIRECT" |
|
# Check for updates with git pull, and if there are updates, uninstall |
|
git_output=$(eval git pull) |
|
|
|
if [[ $git_output != *"Already up to date."* ]]; then |
|
uninstall_xpad_noone |
|
XPAD_HAS_UPDATED=true |
|
else |
|
echo "No updates available" |
|
fi |
|
else |
|
# ...if not, clone the repo |
|
echo -e "\e[1mCloning xpad-noone repo...\e[0m" |
|
echo "" |
|
eval git clone $XPAD_NOONE_REMOTE_REPO $XPAD_NOONE_LOCAL_REPO "$REDIRECT" |
|
cd $XPAD_NOONE_LOCAL_REPO || { |
|
echo "Failed to clone xpad-noone repo. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
} |
|
fi |
|
|
|
# If debug, remove xone and xpad-noone to force a reinstall |
|
if [[ $DEBUG == "true" ]]; then |
|
echo "" |
|
echo "Removing xone and xpad-noone to force a reinstall" |
|
echo "" |
|
if [ $XONE_HAS_UPDATED = "false" ]; then |
|
uninstall_xone |
|
fi |
|
if [ $XPAD_HAS_UPDATED = "false" ]; then |
|
uninstall_xpad_noone |
|
fi |
|
fi |
|
|
|
# Run the xone install function |
|
install_xone |
|
|
|
# Run the xpad-noone install function |
|
install_xpad_noone |
|
|
|
# Using lsmod check if xone_dongle is loaded, if not, load it |
|
if ! lsmod | grep -q xone_dongle; then |
|
load_cmd="sudo modprobe -q xone_dongle" |
|
if [[ $DEBUG == "true" ]]; then |
|
load_cmd="sudo modprobe xone_dongle" |
|
fi |
|
|
|
# Load the xone dongle module, if it exists |
|
if ! $load_cmd; then |
|
echo "Failed to load xone_dongle module. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
fi |
|
sudo touch /etc/modules-load.d/xone-dongle.conf |
|
echo "xone-dongle" | sudo tee /etc/modules-load.d/xone-dongle.conf >/dev/null 2>&1 |
|
fi |
|
|
|
# Using lsmod check if xpad_noone is loaded, if not, load it |
|
if ! lsmod | grep -q xpad_noone; then |
|
load_cmd="sudo modprobe -q xpad-noone" |
|
if [[ $DEBUG == "true" ]]; then |
|
load_cmd="sudo modprobe xpad-noone" |
|
fi |
|
|
|
# Load the xpad-noone module, if it exists |
|
if ! $load_cmd; then |
|
echo "Failed to load xpad-noone module. Aborting..." |
|
read -n 1 -s -r -p "Press any key to exit" |
|
exit 1 |
|
fi |
|
|
|
sudo touch /etc/modules-load.d/xpad-noone.conf |
|
echo "xpad-noone" | sudo tee /etc/modules-load.d/xpad-noone.conf >/dev/null 2>&1 |
|
fi |
|
|
|
# Re enable steamos-readonly if it was enabled before |
|
if [ $KEEP_READ_ONLY = "true" ]; then |
|
sudo steamos-readonly enable |
|
fi |
|
|
|
install_pairing_shortcuts |
|
|
|
zenity --info \ |
|
--text="Done. You may now plug in your controller/adapter." |
|
|
|
# If debug wait for user input before exiting |
|
if [ $DEBUG = "true" ]; then |
|
read -n 1 -s -r -p "Press any key to exit" |
|
fi |
Any way this will work on the Main update channel? do I need different headers and to provide the header dir to the script ?