#!/usr/bin/env bash # BSD 3-Clause License # Author @sonique6784 # Copyright (c) 2020, sonique6784 function showRaSCSILogo(){ logo="""     .~~.   .~~.\n   '. \ ' ' / .'\n    .╔═══════╗.\n   : ║|¯¯¯¯¯|║ :\n  ~ (║|_____|║) ~\n ( : ║ .  __ ║ : )\n  ~ .╚╦═════╦╝. ~\n   (  ¯¯¯¯¯¯¯  ) RaSCSI Reloaded Assistant\n    '~ .~~~. ~'\n        '~'\n """ echo -e $logo } function showMacNetworkWired(){ logo="""                               .-~-.-~~~-.~-.\n  ╔═══════╗                  .(              )\n  ║|¯¯¯¯¯|║                 /               \`.\n  ║|_____|║>--------------<~               .   )\n  ║ .  __ ║                 (              :'-'\n  ╚╦═════╦╝                  ~-.________.:'\n   ¯¯¯¯¯¯¯\n """ echo -e $logo } function showMacNetworkWireless(){ logo="""                               .-~-.-~~~-.~-.\n  ╔═══════╗        .(       .(              )\n  ║|¯¯¯¯¯|║  .(  .(        /               \`.\n  ║|_____|║ .o    o       ~               .   )\n  ║ .  __ ║  '(  '(        (              :'-'\n  ╚╦═════╦╝        '(       ~-.________.:'\n   ¯¯¯¯¯¯¯\n """ echo -e $logo } COMPILER="clang++-11" CONNECT_TYPE="FULLSPEC" CORES=1 USER=$(whoami) BASE=$(dirname "$(readlink -f "${0}")") CPP_PATH="$BASE/cpp" VIRTUAL_DRIVER_PATH="$HOME/images" CFG_PATH="$HOME/.config/rascsi" WEB_INSTALL_PATH="$BASE/python/web" OLED_INSTALL_PATH="$BASE/python/oled" CTRLBOARD_INSTALL_PATH="$BASE/python/ctrlboard" PYTHON_COMMON_PATH="$BASE/python/common" SYSTEMD_PATH="/etc/systemd/system" SSL_CERTS_PATH="/etc/ssl/certs" SSL_KEYS_PATH="/etc/ssl/private" HFDISK_BIN=/usr/bin/hfdisk GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) GIT_REMOTE=${GIT_REMOTE:-origin} TOKEN="" SECRET_FILE="$HOME/.config/rascsi/rascsi_secret" FILE_SHARE_PATH="$HOME/shared_files" FILE_SHARE_NAME="Pi File Server" APT_PACKAGES_COMMON="build-essential git protobuf-compiler bridge-utils" APT_PACKAGES_BACKEND="libspdlog-dev libpcap-dev libprotobuf-dev protobuf-compiler libgmock-dev clang-11" APT_PACKAGES_PYTHON="python3 python3-dev python3-pip python3-venv python3-setuptools python3-wheel libev-dev libevdev2" APT_PACKAGES_WEB="nginx-light genisoimage man2html hfsutils dosfstools kpartx unzip unar disktype" set -e # checks to run before entering the script main menu function initialChecks() { if [ "root" == "$USER" ]; then echo "Do not run this script as $USER or with 'sudo'." exit 1 fi } # checks that the current user has sudoers privileges function sudoCheck() { if [[ $HEADLESS ]]; then echo "Skipping password check in headless mode" return 0 fi echo "Input your password to allow this script to make the above changes." sudo -v } # install all dependency packages for RaSCSI Service function installPackages() { if [[ $SKIP_PACKAGES ]]; then echo "Skipping package installation" return 0 fi sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y -qq \ $APT_PACKAGES_COMMON \ $APT_PACKAGES_BACKEND \ $APT_PACKAGES_PYTHON \ $APT_PACKAGES_WEB } # install Debian packages for RaSCSI standalone function installPackagesStandalone() { if [[ $SKIP_PACKAGES ]]; then echo "Skipping package installation" return 0 fi sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y -qq \ $APT_PACKAGES_COMMON \ $APT_PACKAGES_BACKEND } # install Debian packages for RaSCSI web UI standalone function installPackagesWeb() { if [[ $SKIP_PACKAGES ]]; then echo "Skipping package installation" return 0 fi sudo apt-get update && sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y -qq \ $APT_PACKAGES_COMMON \ $APT_PACKAGES_PYTHON \ $APT_PACKAGES_WEB } # cache the pip packages function cachePipPackages(){ pushd $WEB_INSTALL_PATH sudo pip3 install -r ./requirements.txt popd } # compile the RaSCSI binaries function compileRaScsi() { cd "$CPP_PATH" || exit 1 echo "Compiling $CONNECT_TYPE with $COMPILER on $CORES simultaneous cores..." make clean /dev/null; echo $?) if [ "$APACHE_STATUS" -eq 0 ] ; then echo "Stopping old Apache2 RaSCSI Web..." sudo systemctl disable apache2 sudo systemctl stop apache2 fi } # Checks for upstream changes to the git repo and fast-forwards changes if needed function updateRaScsiGit() { cd "$BASE" || exit 1 set +e git rev-parse --is-inside-work-tree &> /dev/null if [[ $? -ge 1 ]]; then echo "Warning: This does not seem to be a valid clone of a git repository. I will not be able to pull the latest code." return 0 fi set -e stashed=0 if [[ $(git diff --stat) != '' ]]; then echo "There are local changes to the RaSCSI code; we will stash and reapply them." git -c user.name="${GIT_COMMITTER_NAME-rascsi}" -c user.email="${GIT_COMMITTER_EMAIL-rascsi@rascsi.com}" stash stashed=1 fi if [[ `git for-each-ref --format='%(upstream:short)' "$(git symbolic-ref -q HEAD)"` != "" ]]; then echo "Updating checked out git branch $GIT_REMOTE/$GIT_BRANCH" git pull --ff-only else echo "Detected a local git working branch; skipping the remote update step." fi if [ $stashed -eq 1 ]; then echo "Reapplying local changes..." git stash apply fi } # Takes a backup copy of the rascsi.service file if it exists function backupRaScsiService() { if [ -f "$SYSTEMD_PATH/rascsi.service" ]; then sudo mv "$SYSTEMD_PATH/rascsi.service" "$SYSTEMD_PATH/rascsi.service.old" SYSTEMD_BACKUP=true echo "Existing version of rascsi.service detected; Backing up to rascsi.service.old" else SYSTEMD_BACKUP=false fi } # Offers the choice of enabling token-based authentication for RaSCSI, or disables it if enabled function configureTokenAuth() { if [[ -f "$HOME/.rascsi_secret" ]]; then sudo rm "$HOME/.rascsi_secret" echo "Removed (legacy) RaSCSI token file" fi if [[ -f $SECRET_FILE ]]; then sudo rm "$SECRET_FILE" echo "RaSCSI token file $SECRET_FILE already exists. Do you want to disable authentication? (y/N)" read REPLY if [[ $REPLY =~ ^[Yy]$ ]]; then sudo sed -i 's@-P '"$SECRET_FILE"'@@' "$SYSTEMD_PATH/rascsi.service" return fi fi echo -n "Enter the token password for protecting RaSCSI: " read -r TOKEN echo "$TOKEN" > "$SECRET_FILE" # Make the secret file owned and only readable by root sudo chown root:root "$SECRET_FILE" sudo chmod 600 "$SECRET_FILE" sudo sed -i "s@^ExecStart.*@& -P $SECRET_FILE@" "$SYSTEMD_PATH/rascsi.service" echo "" echo "Configured RaSCSI to use $SECRET_FILE for authentication. This file is readable by root only." echo "Make note of your password: you will need it to use rasctl and other RaSCSI clients." echo "If you have RaSCSI clients installed, please re-run the installation scripts, or update the systemd config manually." } # Enables and starts the rascsi service function enableRaScsiService() { sudo systemctl daemon-reload sudo systemctl restart rsyslog sudo systemctl enable rascsi # optional - start rascsi at boot sudo systemctl start rascsi } # Modifies and installs the rascsi-web service function installWebInterfaceService() { if [[ -f "$SECRET_FILE" && -z "$TOKEN" ]] ; then echo "" echo "Secret token file $SECRET_FILE detected. You must enter the password, or press Ctrl+C to cancel installation." read -r TOKEN fi echo "Installing the rascsi-web.service configuration..." sudo cp -f "$WEB_INSTALL_PATH/service-infra/rascsi-web.service" "$SYSTEMD_PATH/rascsi-web.service" sudo sed -i /^ExecStart=/d "$SYSTEMD_PATH/rascsi-web.service" if [ ! -z "$TOKEN" ]; then sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh --password=$TOKEN" "$SYSTEMD_PATH/rascsi-web.service" # Make the service file readable by root only, to protect the token string sudo chmod 600 "$SYSTEMD_PATH/rascsi-web.service" echo "Granted access to the Web Interface with the token password that you configured for RaSCSI." else sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh" "$SYSTEMD_PATH/rascsi-web.service" fi sudo systemctl daemon-reload sudo systemctl enable rascsi-web sudo systemctl start rascsi-web } # Stops the rascsi service if it is running function stopRaScsi() { if [[ -f "$SYSTEMD_PATH/rascsi.service" ]]; then SERVICE_RASCSI_RUNNING=0 sudo systemctl is-active --quiet rascsi.service >/dev/null 2>&1 || SERVICE_RASCSI_RUNNING=$? if [[ $SERVICE_RASCSI_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi.service fi fi } # Stops the rascsi-web service if it is running function stopRaScsiWeb() { if [[ -f "$SYSTEMD_PATH/rascsi-web.service" ]]; then SERVICE_RASCSI_WEB_RUNNING=0 sudo systemctl is-active --quiet rascsi-web.service >/dev/null 2>&1 || SERVICE_RASCSI_WEB_RUNNING=$? if [[ $SERVICE_RASCSI_WEB_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi-web.service fi fi } # Stops the rascsi-oled service if it is running function stopRaScsiScreen() { if [[ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]]; then SERVICE_MONITOR_RASCSI_RUNNING=0 sudo systemctl is-active --quiet monitor_rascsi.service >/dev/null 2>&1 || SERVICE_MONITOR_RASCSI_RUNNING=$? if [[ $SERVICE_MONITOR_RASCSI_RUNNING -eq 0 ]]; then sudo systemctl stop monitor_rascsi.service fi fi if [[ -f "$SYSTEMD_PATH/rascsi-oled.service" ]]; then SERVICE_RASCSI_OLED_RUNNING=0 sudo systemctl is-active --quiet rascsi-oled.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_RUNNING=$? if [[ $SERVICE_RASCSI_OLED_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi-oled.service fi fi } # Stops the rascsi-ctrlboard service if it is running function stopRaScsiCtrlBoard() { if [[ -f "$SYSTEMD_PATH/rascsi-ctrlboard.service" ]]; then SERVICE_RASCSI_CTRLBOARD_RUNNING=0 sudo systemctl is-active --quiet rascsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_RASCSI_CTRLBOARD_RUNNING=$? if [[ SERVICE_RASCSI_CTRLBOARD_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi-ctrlboard.service fi fi } # disables and removes the old monitor_rascsi service function disableOldRaScsiMonitorService() { if [ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]; then SERVICE_MONITOR_RASCSI_RUNNING=0 sudo systemctl is-active --quiet monitor_rascsi.service >/dev/null 2>&1 || SERVICE_MONITOR_RASCSI_RUNNING=$? if [[ $SERVICE_MONITOR_RASCSI_RUNNING -eq 0 ]]; then sudo systemctl stop monitor_rascsi.service fi SERVICE_MONITOR_RASCSI_ENABLED=0 sudo systemctl is-enabled --quiet monitor_rascsi.service >/dev/null 2>&1 || SERVICE_MONITOR_RASCSI_ENABLED=$? if [[ $SERVICE_MONITOR_RASCSI_ENABLED -eq 0 ]]; then sudo systemctl disable monitor_rascsi.service fi sudo rm $SYSTEMD_PATH/monitor_rascsi.service fi } # disables the rascsi-oled service function disableRaScsiOledService() { if [ -f "$SYSTEMD_PATH/rascsi-oled.service" ]; then SERVICE_RASCSI_OLED_RUNNING=0 sudo systemctl is-active --quiet rascsi-oled.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_RUNNING=$? if [[ $SERVICE_RASCSI_OLED_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi-oled.service fi SERVICE_RASCSI_OLED_ENABLED=0 sudo systemctl is-enabled --quiet rascsi-oled.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_ENABLED=$? if [[ $SERVICE_RASCSI_OLED_ENABLED -eq 0 ]]; then sudo systemctl disable rascsi-oled.service fi fi } # disables the rascsi-ctrlboard service function disableRaScsiCtrlBoardService() { if [ -f "$SYSTEMD_PATH/rascsi-ctrlboard.service" ]; then SERVICE_RASCSI_CTRLBOARD_RUNNING=0 sudo systemctl is-active --quiet rascsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_RASCSI_CTRLBOARD_RUNNING=$? if [[ $SERVICE_RASCSI_CTRLBOARD_RUNNING -eq 0 ]]; then sudo systemctl stop rascsi-ctrlboard.service fi SERVICE_RASCSI_CTRLBOARD_ENABLED=0 sudo systemctl is-enabled --quiet rascsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_RASCSI_CTRLBOARD_ENABLED=$? if [[ $SERVICE_RASCSI_CTRLBOARD_ENABLED -eq 0 ]]; then sudo systemctl disable rascsi-ctrlboard.service fi fi } # Stops the macproxy service if it is running function stopMacproxy() { if [ -f "$SYSTEMD_PATH/macproxy.service" ]; then sudo systemctl stop macproxy.service fi } # Checks whether the rascsi-oled service is installed function isRaScsiScreenInstalled() { SERVICE_RASCSI_OLED_ENABLED=0 if [[ -f "$SYSTEMD_PATH/rascsi-oled.service" ]]; then sudo systemctl is-enabled --quiet rascsi-oled.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_ENABLED=$? elif [[ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]]; then sudo systemctl is-enabled --quiet monitor_rascsi.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_ENABLED=$? else SERVICE_RASCSI_OLED_ENABLED=1 fi echo $SERVICE_RASCSI_OLED_ENABLED } # Checks whether the rascsi-ctrlboard service is installed function isRaScsiCtrlBoardInstalled() { SERVICE_RASCSI_CTRLBOARD_ENABLED=0 if [[ -f "$SYSTEMD_PATH/rascsi-ctrlboard.service" ]]; then sudo systemctl is-enabled --quiet rascsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_RASCSI_CTRLBOARD_ENABLED=$? else SERVICE_RASCSI_CTRLBOARD_ENABLED=1 fi echo $SERVICE_RASCSI_CTRLBOARD_ENABLED } # Checks whether the rascsi-oled service is running function isRaScsiScreenRunning() { SERVICE_RASCSI_OLED_RUNNING=0 if [[ -f "$SYSTEMD_PATH/rascsi-oled.service" ]]; then sudo systemctl is-active --quiet rascsi-oled.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_RUNNING=$? elif [[ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]]; then sudo systemctl is-active --quiet monitor_rascsi.service >/dev/null 2>&1 || SERVICE_RASCSI_OLED_RUNNING=$? else SERVICE_RASCSI_OLED_RUNNING=1 fi echo $SERVICE_RASCSI_OLED_RUNNING } # Checks whether the rascsi-oled service is running function isRaScsiCtrlBoardRunning() { SERVICE_RASCSI_CTRLBOARD_RUNNING=0 if [[ -f "$SYSTEMD_PATH/rascsi-ctrlboard.service" ]]; then sudo systemctl is-active --quiet rascsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_RASCSI_CTRLBOARD_RUNNING=$? else SERVICE_RASCSI_CTRLBOARD_RUNNING=1 fi echo $SERVICE_RASCSI_CTRLBOARD_RUNNING } # Starts the rascsi-oled service if installed function startRaScsiScreen() { if [[ $(isRaScsiScreenInstalled) -eq 0 ]] && [[ $(isRaScsiScreenRunning) -ne 1 ]]; then sudo systemctl start rascsi-oled.service showRaScsiScreenStatus fi } # Starts the rascsi-ctrlboard service if installed function startRaScsiCtrlBoard() { if [[ $(isRaScsiCtrlBoardInstalled) -eq 0 ]] && [[ $(isRaScsiCtrlBoardRunning) -ne 1 ]]; then sudo systemctl start rascsi-ctrlboard.service showRaScsiCtrlBoardStatus fi } # Starts the macproxy service if installed function startMacproxy() { if [ -f "$SYSTEMD_PATH/macproxy.service" ]; then sudo systemctl start macproxy.service showMacproxyStatus fi } # Shows status for the rascsi service function showRaScsiStatus() { systemctl status rascsi | tee } # Shows status for the rascsi-web service function showRaScsiWebStatus() { systemctl status rascsi-web | tee } # Shows status for the rascsi-oled service function showRaScsiScreenStatus() { systemctl status rascsi-oled | tee } # Shows status for the rascsi-ctrlboard service function showRaScsiCtrlBoardStatus() { systemctl status rascsi-ctrlboard | tee } # Shows status for the macproxy service function showMacproxyStatus() { systemctl status macproxy | tee } # Creates a drive image file with specific parameters function createDrive600M() { createDrive 600 "HD600" } # Creates a drive image file and prompts for parameters function createDriveCustom() { driveSize=-1 until [ $driveSize -ge "10" ] && [ $driveSize -le "4000" ]; do echo "What drive size would you like (in MiB) (10-4000)" read driveSize echo "How would you like to name that drive?" read driveName done createDrive "$driveSize" "$driveName" } # Clone, compile and install 'hfdisk', partition tool function installHfdisk() { HFDISK_VERSION="2022.11" if [ ! -x "$HFDISK_BIN" ]; then cd "$BASE" || exit 1 wget -O "hfdisk-$HFDISK_VERSION.tar.gz" "https://github.com/rdmark/hfdisk/archive/refs/tags/$HFDISK_VERSION.tar.gz" > /etc/dhcpcd.conf' echo "Modified /etc/dhcpcd.conf" # default config file is made for eth0, this will set the right net interface sudo bash -c 'sed s/eth0/'"$LAN_INTERFACE"'/g '"$CPP_PATH"'/os_integration/rascsi_bridge > /etc/network/interfaces.d/rascsi_bridge' echo "Modified /etc/network/interfaces.d/rascsi_bridge" echo "Configuration completed!" echo "Please make sure you attach a DaynaPORT network adapter to your RaSCSI configuration." echo "Either use the Web UI, or do this on the command line (assuming SCSI ID 6):" echo "rasctl -i 6 -c attach -t scdp -f $LAN_INTERFACE" echo "" if [[ $HEADLESS ]]; then echo "Skipping reboot in headless mode" return 0 fi echo "We need to reboot your Pi" echo "Press Enter to reboot or CTRL-C to exit" read echo "Rebooting..." sleep 3 sudo reboot } # Modifies system configurations for a wireless network bridge with NAT function setupWirelessNetworking() { NETWORK="10.10.20" IP=$NETWORK.2 # Macintosh or Device IP NETWORK_MASK="255.255.255.0" CIDR="24" ROUTER_IP=$NETWORK.1 ROUTING_ADDRESS=$NETWORK.0/$CIDR WLAN_INTERFACE="wlan0" echo "$WLAN_INTERFACE will be configured for network forwarding with static IP assignment." echo "Configure your Macintosh or other device with the following:" echo "IP Address (static): $IP" echo "Router Address: $ROUTER_IP" echo "Subnet Mask: $NETWORK_MASK" echo "DNS Server: Any public DNS server" echo "" echo "Do you want to proceed with network configuration using the default settings? [Y/n]" read REPLY if [ "$REPLY" == "N" ] || [ "$REPLY" == "n" ]; then echo "Available wireless interfaces on this system:" echo `ip -o addr show scope link | awk '{split($0, a); print $2}' | grep wlan` echo "Please type the wireless interface you want to use and press Enter:" read -r WLAN_INTERFACE echo "Base IP address (ex. 10.10.20):" read -r NETWORK echo "CIDR for Subnet Mask (ex. '24' for 255.255.255.0):" read -r CIDR ROUTER_IP=$NETWORK.1 ROUTING_ADDRESS=$NETWORK.0/$CIDR fi if [ "$(grep -c "^net.ipv4.ip_forward=1" /etc/sysctl.conf)" -ge 1 ]; then echo "WARNING: Network forwarding may already have been configured. Proceeding will overwrite the configuration." echo "Press enter to continue or CTRL-C to exit" read REPLY else sudo bash -c 'echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf' echo "Modified /etc/sysctl.conf" fi # Check if iptables is installed if [ `apt-cache policy iptables | grep Installed | grep -c "(none)"` -eq 0 ]; then echo "iptables is already installed" else sudo apt-get install iptables --assume-yes