RASCSI/easyinstall.sh
2024-04-23 08:00:42 +09:00

1629 lines
62 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# BSD 3-Clause License
# Author @sonique6784
# Copyright (c) 2020, sonique6784
function showPiSCSILogo(){
logo="""
    .~~.   .~~.\n
  '. \ ' ' / .'\n
   .╔═══════╗.\n
  : ║|¯¯¯¯¯|║ :\n
 ~ (║|_____|║) ~\n
( : ║ .  __ ║ : )\n
 ~ .╚╦═════╦╝. ~\n
  (  ¯¯¯¯¯¯¯  ) PiSCSI 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
}
CONNECT_TYPE="FULLSPEC"
COMPILER="clang++"
MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
CORES=`expr $MEM / 450000`
if [ $CORES -gt $(nproc) ]; then
CORES=$(nproc)
elif [ $CORES -lt 1 ]; then
CORES=1
fi
USER=$(whoami)
BASE=$(dirname "$(readlink -f "${0}")")
CPP_PATH="$BASE/cpp"
VIRTUAL_DRIVER_PATH="$HOME/images"
CFG_PATH="$HOME/.config/piscsi"
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=""
AUTH_GROUP="piscsi"
SECRET_FILE="$HOME/.config/piscsi/secret"
FILE_SHARE_PATH="$HOME/shared_files"
FILE_SHARE_NAME="Pi File Server"
APT_PACKAGES_COMMON="build-essential git protobuf-compiler bridge-utils ca-certificates rsyslog"
APT_PACKAGES_BACKEND="libspdlog-dev libpcap-dev libprotobuf-dev protobuf-compiler libgmock-dev clang"
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 gettext"
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
}
# Only to be used for pi-gen automated install
function sudoCache() {
echo "Caching sudo password"
echo raspberry | sudo -v -S
}
# 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
}
# Delete file if it exists
function deleteFile() {
if sudo test -f "$1/$2"; then
sudo rm "$1/$2" || exit 1
echo "Deleted file $1/$2"
fi
}
# Delete dir if it exists
function deleteDir() {
if sudo test -d "$1"; then
sudo rm -rf "$1" || exit 1
echo "Deleted directory $1"
fi
}
# install all dependency packages for PiSCSI 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 --assume-yes -qq \
$APT_PACKAGES_COMMON \
$APT_PACKAGES_BACKEND \
$APT_PACKAGES_PYTHON \
$APT_PACKAGES_WEB
}
# install Debian packages for PiSCSI 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 --assume-yes -qq \
$APT_PACKAGES_COMMON \
$APT_PACKAGES_BACKEND
}
# install Debian packages for PiSCSI 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 --assume-yes -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 PiSCSI binaries
function compilePiscsi() {
cd "$CPP_PATH" || exit 1
echo "Compiling $CONNECT_TYPE with $COMPILER on $CORES simultaneous cores..."
if [[ $SKIP_MAKE_CLEAN ]]; then
echo "Skipping 'make clean'"
else
make clean </dev/null
fi
make CXX="$COMPILER" CONNECT_TYPE="$CONNECT_TYPE" -j "$CORES" all </dev/null
}
# install the PiSCSI binaries and modify the service configuration
function installPiscsi() {
OUTDATED_MAN_PAGE_DIR="/usr/share/man/man1"
CURRENT_MAN_PAGE_DIR="/usr/local/man/man1"
CURRENT_BIN_DIR="/usr/local/bin"
# clean up outdated binaries and man pages if they exist
deleteFile "$OUTDATED_MAN_PAGE_DIR" "rascsi.1"
deleteFile "$OUTDATED_MAN_PAGE_DIR" "rasctl.1"
deleteFile "$OUTDATED_MAN_PAGE_DIR" "scsimon.1"
deleteFile "$OUTDATED_MAN_PAGE_DIR" "rasdump.1"
deleteFile "$OUTDATED_MAN_PAGE_DIR" "sasidump.1"
deleteFile "$CURRENT_MAN_PAGE_DIR" "rascsi.1"
deleteFile "$CURRENT_MAN_PAGE_DIR" "rasctl.1"
deleteFile "$CURRENT_MAN_PAGE_DIR" "rasdump.1"
deleteFile "$CURRENT_MAN_PAGE_DIR" "sasidump.1"
deleteFile "$CURRENT_BIN_DIR" "rascsi"
deleteFile "$CURRENT_BIN_DIR" "rasctl"
deleteFile "$CURRENT_BIN_DIR" "rasdump"
deleteFile "$CURRENT_BIN_DIR" "sasidump"
# install
sudo make install CONNECT_TYPE="$CONNECT_TYPE" </dev/null
}
# Update the systemd configuration for piscsi
function configurePiscsiService() {
if [[ -f $SECRET_FILE ]]; then
sudo sed -i "\@^ExecStart.*@ s@@& -F $VIRTUAL_DRIVER_PATH -P $SECRET_FILE@" "$SYSTEMD_PATH/piscsi.service"
echo "Secret token file $SECRET_FILE detected. Using it to enable back-end authentication."
else
sudo sed -i "\@^ExecStart.*@ s@@& -F $VIRTUAL_DRIVER_PATH@" "$SYSTEMD_PATH/piscsi.service"
fi
echo "Configured piscsi.service to use $VIRTUAL_DRIVER_PATH as default image dir."
}
# Prepare shared Python code
function preparePythonCommon() {
PISCSI_PYTHON_PROTO="piscsi_interface_pb2.py"
deleteFile "$WEB_INSTALL_PATH/src" "rascsi_interface_pb2.py"
deleteFile "$OLED_INSTALL_PATH/src" "rascsi_interface_pb2.py"
deleteFile "$PYTHON_COMMON_PATH/src" "rascsi_interface_pb2.py"
deleteFile "$WEB_INSTALL_PATH/src" "$PISCSI_PYTHON_PROTO"
deleteFile "$OLED_INSTALL_PATH/src" "$PISCSI_PYTHON_PROTO"
deleteFile "$PYTHON_COMMON_PATH/src" "$PISCSI_PYTHON_PROTO"
echo "Compiling the Python protobuf library $PISCSI_PYTHON_PROTO..."
protoc -I="$CPP_PATH" --python_out="$PYTHON_COMMON_PATH/src" piscsi_interface.proto
}
# install everything required to run an HTTP server (Nginx + Python Flask App)
function installPiscsiWebInterface() {
sudo cp -f "$WEB_INSTALL_PATH/service-infra/nginx-default.conf" /etc/nginx/sites-available/default
sudo cp -f "$WEB_INSTALL_PATH/service-infra/502.html" /var/www/html/502.html
deleteFile "$SSL_CERTS_PATH" "rascsi-web.crt"
deleteFile "$SSL_KEYS_PATH" "rascsi-web.key"
# Deleting previous venv dir, if one exists, to avoid the common issue of broken python dependencies
deleteDir "$WEB_INSTALL_PATH/venv"
if [ -f "$SSL_CERTS_PATH/piscsi-web.crt" ]; then
echo "SSL certificate $SSL_CERTS_PATH/piscsi-web.crt already exists."
else
echo "SSL certificate $SSL_CERTS_PATH/piscsi-web.crt does not exist; creating self-signed certificate..."
sudo mkdir -p "$SSL_CERTS_PATH" || true
sudo mkdir -p "$SSL_KEYS_PATH" || true
sudo openssl req -x509 -nodes -sha256 -days 3650 \
-newkey rsa:4096 \
-keyout "$SSL_KEYS_PATH/piscsi-web.key" \
-out "$SSL_CERTS_PATH/piscsi-web.crt" \
-subj '/CN=piscsi' \
-addext 'subjectAltName=DNS:piscsi' \
-addext 'extendedKeyUsage=serverAuth'
fi
sudo systemctl reload nginx || true
}
# Creates the dir that PiSCSI uses to store image files
function createImagesDir() {
if [ -d "$VIRTUAL_DRIVER_PATH" ]; then
echo "The $VIRTUAL_DRIVER_PATH directory already exists."
else
echo "The $VIRTUAL_DRIVER_PATH directory does not exist; creating..."
mkdir -p "$VIRTUAL_DRIVER_PATH"
chmod -R 775 "$VIRTUAL_DRIVER_PATH"
fi
}
# Creates the dir that the Web Interface uses to store configuration files
function createCfgDir() {
if [ -d "$HOME/.config/rascsi" ]; then
sudo mv "$HOME/.config/rascsi" "$CFG_PATH"
echo "Renamed the rascsi config dir as $CFG_PATH."
elif [ -d "$CFG_PATH" ]; then
echo "The $CFG_PATH directory already exists."
else
echo "The $CFG_PATH directory does not exist; creating..."
mkdir -p "$CFG_PATH"
chmod -R 775 "$CFG_PATH"
fi
}
# Checks for upstream changes to the git repo and fast-forwards changes if needed
function updatePiscsiGit() {
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 PiSCSI code; we will stash and reapply them."
git -c user.name="${GIT_COMMITTER_NAME-piscsi}" -c user.email="${GIT_COMMITTER_EMAIL-piscsi@piscsi.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 piscsi.service file if it exists
function backupPiscsiService() {
if [ -f "$SYSTEMD_PATH/piscsi.service" ]; then
sudo mv "$SYSTEMD_PATH/piscsi.service" "$SYSTEMD_PATH/piscsi.service.old"
SYSTEMD_BACKUP=true
echo "Existing version of piscsi.service detected; Backing up to piscsi.service.old"
else
SYSTEMD_BACKUP=false
fi
}
# Offers the choice of enabling token-based authentication for PiSCSI, or disables it if enabled
function configureTokenAuth() {
if [[ -f "$HOME/.rascsi_secret" ]]; then
sudo mv "$HOME/.rascsi_secret" "$SECRET_FILE"
echo "Renamed legacy RaSCSI token file for use with PiSCSI"
return
fi
if [[ -f "$CFG_PATH/rascsi_secret" ]]; then
sudo mv "$CFG_PATH/rascsi_secret" "$SECRET_FILE"
echo "Renamed legacy RaSCSI token file for use with PiSCSI"
return
fi
if [[ -f $SECRET_FILE ]]; then
sudo rm "$SECRET_FILE"
echo "PiSCSI 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/piscsi.service"
return
fi
fi
echo -n "Enter the token password for protecting PiSCSI: "
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/piscsi.service"
echo ""
echo "Configured PiSCSI 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 scsictl and other PiSCSI clients."
echo "If you have PiSCSI clients installed, please re-run the installation scripts, or update the systemd config manually."
}
# Enables and starts the piscsi service
function enablePiscsiService() {
sudo systemctl daemon-reload
sudo systemctl restart rsyslog
sudo systemctl enable piscsi # start piscsi at boot
sudo systemctl start piscsi
}
# Modifies and installs the piscsi-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 piscsi-web.service configuration..."
sudo cp -f "$WEB_INSTALL_PATH/service-infra/piscsi-web.service" "$SYSTEMD_PATH/piscsi-web.service"
sudo sed -i /^ExecStart=/d "$SYSTEMD_PATH/piscsi-web.service"
if [ ! -z "$TOKEN" ]; then
sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh --password=$TOKEN" "$SYSTEMD_PATH/piscsi-web.service"
# Make the service file readable by root only, to protect the token string
sudo chmod 600 "$SYSTEMD_PATH/piscsi-web.service"
echo "Granted access to the Web Interface with the token password that you configured for PiSCSI."
else
sudo sed -i "8 i ExecStart=$WEB_INSTALL_PATH/start.sh" "$SYSTEMD_PATH/piscsi-web.service"
fi
sudo systemctl daemon-reload
sudo systemctl enable piscsi-web
sudo systemctl start piscsi-web
}
# Checks for and disables legacy systemd services
function migrateLegacyData() {
if [[ -f "$SYSTEMD_PATH/rascsi.service" ]]; then
stopService "rascsi"
disableService "rascsi"
sudo mv "$SYSTEMD_PATH/rascsi.service" "$SYSTEMD_PATH/piscsi.service"
echo "Renamed rascsi.service to piscsi.service"
fi
if [[ -f "$SYSTEMD_PATH/rascsi-web.service" ]]; then
stopService "rascsi-web"
disableService "rascsi-web"
sudo mv "$SYSTEMD_PATH/rascsi-web.service" "$SYSTEMD_PATH/piscsi-web.service"
echo "Renamed rascsi-web.service to piscsi-web.service"
fi
if [[ -f "$SYSTEMD_PATH/rascsi-oled.service" ]]; then
stopService "rascsi-oled"
disableService "rascsi-oled"
sudo mv "$SYSTEMD_PATH/rascsi-oled.service" "$SYSTEMD_PATH/piscsi-oled.service"
echo "Renamed rascsi-oled.service to piscsi-oled.service"
elif [[ -f "$SYSTEMD_PATH/monitor_rascsi.service" ]]; then
stopService "monitor_rascsi"
disableService "monitor_rascsi"
sudo mv "$SYSTEMD_PATH/monitor_rascsi.service" "$SYSTEMD_PATH/piscsi-oled.service"
echo "Renamed monitor_rascsi.service to piscsi-oled.service"
fi
if [[ -f "$SYSTEMD_PATH/rascsi-ctrlboard.service" ]]; then
stopService "rascsi-ctrlboard"
disableService "rascsi-ctrlboard"
sudo mv "$SYSTEMD_PATH/rascsi-ctrlboard.service" "$SYSTEMD_PATH/piscsi-ctrlboard.service"
echo "Renamed rascsi-ctrlboard.service to piscsi-ctrlboard.service"
fi
if [[ -f "/etc/rsyslog.d/rascsi.conf" ]]; then
sudo rm "/etc/rsyslog.d/rascsi.conf"
sudo cp "$BASE/os_integration/piscsi.conf" "/etc/rsyslog.d"
echo "Replaced rascsi.conf with piscsi.conf"
fi
if [[ -f "/etc/network/interfaces.d/rascsi_bridge" ]]; then
sudo rm "/etc/network/interfaces.d/rascsi_bridge"
sudo cp "$BASE/os_integration/piscsi_bridge" "/etc/network/interfaces.d"
echo "Replaced rascsi_bridge with piscsi_bridge"
fi
if [[ $(getent group rascsi) && $(getent group "$AUTH_GROUP") ]]; then
sudo groupdel rascsi
echo "Deleted the rascsi group in favor of the existing piscsi group"
elif [ $(getent group rascsi) ]; then
sudo groupmod --new-name piscsi rascsi
echo "Renamed the rascsi group to piscsi"
fi
}
# Stops a service if it is running
function stopService() {
if [[ -f "$SYSTEMD_PATH/$1.service" ]]; then
SERVICE_RUNNING=0
sudo systemctl is-active --quiet "$1.service" >/dev/null 2>&1 || SERVICE_RUNNING=$?
if [[ $SERVICE_RUNNING -eq 0 ]]; then
sudo systemctl stop "$1.service"
fi
fi
}
# disables a service if it is enabled
function disableService() {
if [ -f "$SYSTEMD_PATH/$1.service" ]; then
SERVICE_ENABLED=0
sudo systemctl is-enabled --quiet "$1.service" >/dev/null 2>&1 || SERVICE_ENABLED=$?
if [[ $SERVICE_ENABLED -eq 0 ]]; then
sudo systemctl disable "$1.service"
fi
fi
}
# Checks whether the piscsi-oled service is installed
function isPiscsiScreenInstalled() {
SERVICE_PISCSI_OLED_ENABLED=0
if [[ -f "$SYSTEMD_PATH/piscsi-oled.service" ]]; then
sudo systemctl is-enabled --quiet piscsi-oled.service >/dev/null 2>&1 || SERVICE_PISCSI_OLED_ENABLED=$?
else
SERVICE_PISCSI_OLED_ENABLED=1
fi
echo $SERVICE_PISCSI_OLED_ENABLED
}
# Checks whether the piscsi-ctrlboard service is installed
function isPiscsiCtrlBoardInstalled() {
SERVICE_PISCSI_CTRLBOARD_ENABLED=0
if [[ -f "$SYSTEMD_PATH/piscsi-ctrlboard.service" ]]; then
sudo systemctl is-enabled --quiet piscsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_PISCSI_CTRLBOARD_ENABLED=$?
else
SERVICE_PISCSI_CTRLBOARD_ENABLED=1
fi
echo $SERVICE_PISCSI_CTRLBOARD_ENABLED
}
# Checks whether the piscsi-oled service is running
function isPiscsiScreenRunning() {
SERVICE_PISCSI_OLED_RUNNING=0
if [[ -f "$SYSTEMD_PATH/piscsi-oled.service" ]]; then
sudo systemctl is-active --quiet piscsi-oled.service >/dev/null 2>&1 || SERVICE_PISCSI_OLED_RUNNING=$?
else
SERVICE_PISCSI_OLED_RUNNING=1
fi
echo $SERVICE_PISCSI_OLED_RUNNING
}
# Checks whether the piscsi-oled service is running
function isPiscsiCtrlBoardRunning() {
SERVICE_PISCSI_CTRLBOARD_RUNNING=0
if [[ -f "$SYSTEMD_PATH/piscsi-ctrlboard.service" ]]; then
sudo systemctl is-active --quiet piscsi-ctrlboard.service >/dev/null 2>&1 || SERVICE_PISCSI_CTRLBOARD_RUNNING=$?
else
SERVICE_PISCSI_CTRLBOARD_RUNNING=1
fi
echo $SERVICE_PISCSI_CTRLBOARD_RUNNING
}
# Starts the piscsi-oled service if installed
function startPiscsiScreen() {
if [[ $(isPiscsiScreenInstalled) -eq 0 ]] && [[ $(isPiscsiScreenRunning) -ne 1 ]]; then
sudo systemctl start piscsi-oled.service
showServiceStatus "piscsi-oled"
fi
}
# Starts the piscsi-ctrlboard service if installed
function startPiscsiCtrlBoard() {
if [[ $(isPiscsiCtrlBoardInstalled) -eq 0 ]] && [[ $(isPiscsiCtrlBoardRunning) -ne 1 ]]; then
sudo systemctl start piscsi-ctrlboard.service
showServiceStatus "piscsi-ctrlboard"
fi
}
# Starts the macproxy service if installed
function startMacproxy() {
if [ -f "$SYSTEMD_PATH/macproxy.service" ]; then
sudo systemctl start macproxy.service
showServiceStatus "macproxy"
fi
}
# Shows status for the piscsi service
function showServiceStatus() {
systemctl status "$1.service" | tee
}
# 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" </dev/null
tar -xzvf "hfdisk-$HFDISK_VERSION.tar.gz"
rm "hfdisk-$HFDISK_VERSION.tar.gz"
cd "hfdisk-$HFDISK_VERSION" || exit 1
make
sudo cp hfdisk "$HFDISK_BIN"
echo "Installed $HFDISK_BIN"
fi
}
# Fetch HFS drivers that the Web Interface uses
function fetchHardDiskDrivers() {
DRIVER_ARCHIVE="mac-hard-disk-drivers"
if [ ! -d "$BASE/$DRIVER_ARCHIVE" ]; then
cd "$BASE" || exit 1
# -N option overwrites if downloaded file is newer than existing file
wget -N "https://www.dropbox.com/s/gcs4v5pcmk7rxtb/$DRIVER_ARCHIVE.zip?dl=1" -O "$DRIVER_ARCHIVE.zip"
unzip -d "$DRIVER_ARCHIVE" "$DRIVER_ARCHIVE.zip"
rm "$DRIVER_ARCHIVE.zip"
fi
}
# Modifies system configurations for a wired network bridge
function setupWiredNetworking() {
echo "Setting up wired network..."
if [[ -z $HEADLESS ]]; then
LAN_INTERFACE=`ip -o addr show scope link | awk '{split($0, a); print $2}' | grep 'eth\|enx' | head -n 1`
else
LAN_INTERFACE="eth0"
fi
if [[ -z "$LAN_INTERFACE" ]]; then
echo "No usable wired network interfaces detected. Have you already enabled the bridge? Aborting..."
return 1
fi
echo "Network interface '$LAN_INTERFACE' will be configured for network forwarding with DHCP."
echo ""
echo "WARNING: If you continue, the IP address of your Pi may change upon reboot."
echo "Please make sure you will not lose access to the Pi system."
echo ""
if [[ -z $HEADLESS ]]; then
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 wired interfaces on this system:"
echo `ip -o addr show scope link | awk '{split($0, a); print $2}' | grep 'eth\|enx'`
echo "Please type the wired interface you want to use and press Enter:"
read SELECTED
LAN_INTERFACE=$SELECTED
fi
fi
if [ "$(grep -c "^denyinterfaces" /etc/dhcpcd.conf)" -ge 1 ]; then
echo "WARNING: Network forwarding may already have been configured. Proceeding will overwrite the configuration."
if [[ -z $HEADLESS ]]; then
echo "Press enter to continue or CTRL-C to exit"
read REPLY
fi
sudo sed -i /^denyinterfaces/d /etc/dhcpcd.conf
fi
sudo bash -c 'echo "denyinterfaces '$LAN_INTERFACE'" >> /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 '"$BASE"'/os_integration/piscsi_bridge > /etc/network/interfaces.d/piscsi_bridge'
echo "Modified /etc/network/interfaces.d/piscsi_bridge"
echo "Configuration completed!"
echo "Please make sure you attach a DaynaPORT network adapter to your PiSCSI configuration."
echo "Either use the Web UI, or do this on the command line (assuming SCSI ID 6):"
echo "scsictl -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
if [[ -z $HEADLESS ]]; then
WLAN_INTERFACE=`ip -o addr show scope link | awk '{split($0, a); print $2}' | grep 'wlan\|wlx' | head -n 1`
else
WLAN_INTERFACE="wlan0"
fi
if [[ -z "$WLAN_INTERFACE" ]]; then
echo "No usable wireless network interfaces detected. Have you already enabled the bridge? Aborting..."
return 1
fi
echo "Network interface '$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\|wlx'`
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 --no-install-recommends </dev/null
fi
sudo iptables --flush
sudo iptables -t nat -F
sudo iptables -X
sudo iptables -Z
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -t nat -A POSTROUTING -o "$WLAN_INTERFACE" -s "$ROUTING_ADDRESS" -j MASQUERADE
# Check if iptables-persistent is installed
if [ `apt-cache policy iptables-persistent | grep Installed | grep -c "(none)"` -eq 0 ]; then
echo "iptables-persistent is already installed"
sudo iptables-save --file /etc/iptables/rules.v4
else
sudo apt-get install iptables-persistent --assume-yes --no-install-recommends </dev/null
fi
echo "Modified /etc/iptables/rules.v4"
echo "Configuration completed!"
echo ""
echo "Please make sure you attach a DaynaPORT network adapter to your PiSCSI configuration"
echo "Either use the Web UI, or do this on the command line (assuming SCSI ID 6):"
echo "scsictl -i 6 -c attach -t scdp -f $WLAN_INTERFACE:$ROUTER_IP/$CIDR"
echo ""
echo "We need to reboot your Pi"
echo "Press Enter to reboot or CTRL-C to exit"
read REPLY
echo "Rebooting..."
sleep 3
sudo reboot
}
# Detects or creates the file sharing directory
function createFileSharingDir() {
if [ ! -d "$FILE_SHARE_PATH" ] && [ -d "$HOME/afpshare" ]; then
echo
echo "File server dir $HOME/afpshare detected. This script will rename it to $FILE_SHARE_PATH."
echo
echo "Do you want to proceed with the installation? [y/N]"
read -r REPLY
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
sudo mv "$HOME/afpshare" "$FILE_SHARE_PATH" || exit 1
else
exit 0
fi
elif [ -d "$FILE_SHARE_PATH" ]; then
echo "Found a $FILE_SHARE_PATH directory; will use it for file sharing."
else
echo "Creating the $FILE_SHARE_PATH directory and granting read/write permissions to all users..."
sudo mkdir -p "$FILE_SHARE_PATH"
sudo chown -R "$USER:$USER" "$FILE_SHARE_PATH"
chmod -Rv 775 "$FILE_SHARE_PATH"
fi
}
# Downloads, compiles, and installs Netatalk (AppleShare server)
function installNetatalk() {
NETATALK_VERSION="2.3.2"
NETATALK_CONFIG_PATH="/etc/netatalk"
NETATALK_OPTIONS="--base-dir=$BASE/tmp/netatalk-$NETATALK_VERSION --cores=$CORES --share-name='$FILE_SHARE_NAME' --share-path='$FILE_SHARE_PATH'"
if [ -d "$NETATALK_CONFIG_PATH" ]; then
echo
echo "WARNING: Netatalk configuration dir $NETATALK_CONFIG_PATH already exists."
echo "This installation process will overwrite existing binaries and configurations."
echo "No shared files will be deleted, but you may have to manually restore your settings after the installation."
echo
echo "Do you want to proceed with the installation? [y/N]"
read -r REPLY
if ! [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
exit 0
fi
fi
echo
echo "Downloading tarball to $BASE/tmp..."
mkdir -p "$BASE/tmp"
cd "$BASE/tmp" || exit 1
wget -O "netatalk-$NETATALK_VERSION.tar.gz" \
"https://github.com/Netatalk/netatalk/releases/download/netatalk-`echo $NETATALK_VERSION | sed 's/\./-/g'`/netatalk-$NETATALK_VERSION.tar.xz" </dev/null
echo "Unpacking tarball..."
tar -xf "netatalk-$NETATALK_VERSION.tar.gz"
rm "netatalk-$NETATALK_VERSION.tar.gz"
if [ -f "/etc/network/interfaces.d/piscsi_bridge" ]; then
echo "PiSCSI network bridge detected. Using 'piscsi_bridge' interface for AppleTalk."
NETATALK_OPTIONS="$NETATALK_OPTIONS --appletalk-interface=piscsi_bridge"
fi
[[ $HEADLESS ]] && NETATALK_OPTIONS="$NETATALK_OPTIONS --headless"
[[ $SKIP_PACKAGES ]] && NETATALK_OPTIONS="$NETATALK_OPTIONS --no-packages"
[[ $SKIP_MAKE_CLEAN ]] && NETATALK_OPTIONS="$NETATALK_OPTIONS --no-make-clean"
bash -c "$BASE/shell_scripts/netatalk_install.sh $NETATALK_OPTIONS" || exit 1
rm -rf "$BASE/tmp"
}
# Appends the images dir as a shared Netatalk volume
function shareImagesWithNetatalk() {
APPLEVOLUMES_PATH="/etc/netatalk/AppleVolumes.default"
if ! [ -f "$APPLEVOLUMES_PATH" ]; then
echo "Could not find $APPLEVOLUMES_PATH ... is Netatalk installed?"
exit 1
fi
if [ "$(grep -c "$VIRTUAL_DRIVER_PATH" "$APPLEVOLUMES_PATH")" -ge 1 ]; then
echo "The $VIRTUAL_DRIVER_PATH dir is already shared in $APPLEVOLUMES_PATH"
echo "Do you want to turn off the sharing? [y/N]"
read -r REPLY
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
sudo systemctl stop afpd
sudo sed -i '\,^'"$VIRTUAL_DRIVER_PATH"',d' "$APPLEVOLUMES_PATH"
echo "Sharing for $VIRTUAL_DRIVER_PATH disabled!"
sudo systemctl start afpd
exit 0
fi
exit 0
fi
sudo systemctl stop afpd
echo "Appended to AppleVolumes.default:"
echo "$VIRTUAL_DRIVER_PATH \"PiSCSI Images\"" | sudo tee -a "$APPLEVOLUMES_PATH"
sudo systemctl start afpd
echo
echo "WARNING: Do not inadvertently move or rename image files that are in use by PiSCSI."
echo "Doing so may lead to data loss."
echo
}
# Downloads, compiles, and installs Macproxy (web proxy)
function installMacproxy {
PORT=5000
echo "Macproxy is a Web Proxy for all vintage Web Browsers -- not only for Macs!"
echo ""
echo "By default, Macproxy listens to port $PORT, but you can choose any other available port."
echo -n "Enter a port number 1024 - 65535, or press Enter to use the default port: "
read -r CHOICE
if [[ $CHOICE -ge "1024" ]] && [[ $CHOICE -le "65535" ]]; then
PORT=$CHOICE
else
echo "Using the default port $PORT"
fi
if [[ $SKIP_PACKAGES ]]; then
echo "Skipping package installation"
else
sudo apt-get update && sudo apt-get install python3 python3-venv --assume-yes --no-install-recommends </dev/null
fi
MACPROXY_VER="22.8"
MACPROXY_PATH="$HOME/macproxy-$MACPROXY_VER"
if [ -d "$MACPROXY_PATH" ]; then
echo "The $MACPROXY_PATH directory already exists. Deleting before downloading again..."
sudo rm -rf "$MACPROXY_PATH"
fi
cd "$HOME" || exit 1
wget -O "macproxy-$MACPROXY_VER.tar.gz" "https://github.com/rdmark/macproxy/archive/refs/tags/v$MACPROXY_VER.tar.gz" </dev/null
tar -xzvf "macproxy-$MACPROXY_VER.tar.gz"
sudo cp "$MACPROXY_PATH/macproxy.service" "$SYSTEMD_PATH"
sudo sed -i /^ExecStart=/d "$SYSTEMD_PATH/macproxy.service"
sudo sed -i "8 i ExecStart=$MACPROXY_PATH/start_macproxy.sh -p=$PORT" "$SYSTEMD_PATH/macproxy.service"
sudo systemctl daemon-reload
sudo systemctl enable macproxy
startMacproxy
echo -n "Macproxy is now running on IP "
echo -n `ip -4 addr show scope global | grep -o -m 1 -P '(?<=inet\s)\d+(\.\d+){3}'`
echo " port $PORT"
echo "Configure your browser to use the above as http (and https) proxy."
echo ""
}
# Installs vsftpd (FTP server)
function installFtp() {
echo
echo "Installing packages..."
sudo apt-get update && sudo apt-get install vsftpd --assume-yes --no-install-recommends </dev/null
echo
echo "Connect to the FTP server with:"
echo -n "ftp://"
echo -n `ip -4 addr show scope global | grep -o -m 1 -P '(?<=inet\s)\d+(\.\d+){3}'`
echo "/"
echo
echo "Authenticate with username '$USER' and your password on this Pi."
echo
}
# Installs and configures Samba (SMB server)
function installSamba() {
SAMBA_CONFIG_PATH="/etc/samba"
if [ -d "$SAMBA_CONFIG_PATH" ]; then
echo
echo "Samba configuration dir $SAMBA_CONFIG_PATH already exists."
echo "This installation process may overwrite existing binaries and configurations."
echo "No shared files will be deleted, but you may have to manually restore your settings after the installation."
echo
echo "Do you want to proceed with the installation? [y/N]"
read -r REPLY
if ! [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
exit 0
fi
fi
echo
echo "Installing packages..."
sudo apt-get update || true
sudo apt-get install samba --no-install-recommends --assume-yes </dev/null
echo
echo "Modifying $SAMBA_CONFIG_PATH/smb.conf ..."
if [[ `sudo grep -c "server min protocol = NT1" $SAMBA_CONFIG_PATH/smb.conf` -eq 0 ]]; then
# Allow Windows XP clients and earlier to connect to the server
sudo sed -i 's/\[global\]/\[global\]\nserver min protocol = NT1/' "$SAMBA_CONFIG_PATH/smb.conf"
echo "server min prototol = NT1"
fi
if [[ `sudo grep -c "\[Pi File Server\]" $SAMBA_CONFIG_PATH/smb.conf` -eq 0 ]]; then
# Define a shared directory with full read/write privileges, while aggressively hiding dot files
echo -e '\n[Pi File Server]\npath = '"$FILE_SHARE_PATH"'\nbrowseable = yes\nwriteable = yes\nhide dot files = yes\nveto files = /.*/' | sudo tee -a "$SAMBA_CONFIG_PATH/smb.conf"
fi
sudo systemctl restart smbd
echo "Please create a Samba password for user $USER"
sudo smbpasswd -a "$USER"
}
# Installs and configures Webmin
function installWebmin() {
WEBMIN_PATH="/usr/share/webmin"
WEBMIN_NETATALK_MODULE_CONFIG="/etc/webmin/netatalk2/config"
WEBMIN_NETATALK_MODULE_VERSION="1.3"
WEBMIN_VSFTPD_MODULE_VERSION="2024-01-26"
if [ -d "$WEBMIN_PATH" ]; then
echo
echo "Webmin dir $WEBMIN_PATH already exists."
echo "This installation process may overwrite existing software."
echo
echo "Do you want to proceed with the installation? [y/N]"
read -r REPLY
if ! [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
exit 0
fi
fi
echo
echo "Installing packages..."
sudo apt-get install curl libcgi-session-perl --no-install-recommends --assume-yes </dev/null
curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh
sudo sh setup-repos.sh -f
rm setup-repos.sh
sudo apt-get install webmin --no-install-recommends --assume-yes </dev/null
echo
echo "Downloading and installing Webmin modules..."
if [[ -f "$WEBMIN_NETATALK_MODULE_CONFIG" ]]; then
echo "$WEBMIN_NETATALK_MODULE_CONFIG already exists; will not modify..."
WEBMIN_MODULE_FLAG=1
fi
rm netatalk2-wbm.tgz 2> /dev/null || true
wget -O netatalk2-wbm.tgz "https://github.com/Netatalk/netatalk-webmin/releases/download/netatalk2-$WEBMIN_NETATALK_MODULE_VERSION/netatalk2-wbm-$WEBMIN_NETATALK_MODULE_VERSION.tgz" </dev/null
sudo "$WEBMIN_PATH/install-module.pl" netatalk2-wbm.tgz
if [[ ! $WEBMIN_MODULE_FLAG ]]; then
echo "Modifying $WEBMIN_NETATALK_MODULE_CONFIG..."
sudo sed -i 's@/usr/sbin@/usr/local/sbin@' "$WEBMIN_NETATALK_MODULE_CONFIG"
fi
rm netatalk2-wbm.tgz || true
rm vsftpd.wbm.gz 2> /dev/null || true
wget -O vsftpd.wbm.tgz "https://github.com/rdmark/vsftpd-webmin/releases/download/$WEBMIN_VSFTPD_MODULE_VERSION/vsftpd-$WEBMIN_VSFTPD_MODULE_VERSION.wbm.gz" </dev/null
sudo "$WEBMIN_PATH/install-module.pl" vsftpd.wbm.tgz
rm vsftpd.wbm.tgz || true
}
# updates configuration files and installs packages needed for the OLED screen script
function installPiscsiScreen() {
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 "IMPORTANT: This configuration requires a OLED screen to be installed onto your PiSCSI board."
echo "See wiki for more information: https://github.com/akuker/PISCSI/wiki/OLED-Status-Display-(Optional)"
echo ""
echo "Choose screen rotation:"
echo " 1) 0 degrees"
echo " 2) 180 degrees (default)"
read REPLY
if [ "$REPLY" == "1" ]; then
echo "Proceeding with 0 degrees rotation."
ROTATION="0"
else
echo "Proceeding with 180 degrees rotation."
ROTATION="180"
fi
echo ""
echo "Choose screen resolution:"
echo " 1) 128x32 pixels (default)"
echo " 2) 128x64 pixels"
read REPLY
if [ "$REPLY" == "2" ]; then
echo "Proceeding with 128x64 pixel resolution."
SCREEN_HEIGHT="64"
else
echo "Proceeding with 128x32 pixel resolution."
SCREEN_HEIGHT="32"
fi
stopService "piscsi-oled"
stopService "piscsi-ctrlboard"
disableService "piscsi-ctrlboard"
updatePiscsiGit
if [[ $SKIP_PACKAGES ]]; then
echo "Skipping package installation"
else
sudo apt-get update && sudo apt-get install libjpeg-dev libpng-dev libopenjp2-7-dev i2c-tools raspi-config --assume-yes --no-install-recommends </dev/null
fi
if [[ $(grep -c "^dtparam=i2c_arm=on" /boot/config.txt) -ge 1 ]]; then
echo "NOTE: I2C support seems to have been configured already."
REBOOT=0
else
sudo raspi-config nonint do_i2c 0 </dev/null
echo "Modified the Raspberry Pi boot configuration to enable I2C."
echo "A reboot will be required for the change to take effect."
REBOOT=1
fi
# Deleting previous venv dir, if one exists, to avoid the common issue of broken python dependencies
deleteDir "$OLED_INSTALL_PATH/venv"
echo "Installing the piscsi-oled.service configuration..."
sudo cp -f "$OLED_INSTALL_PATH/service-infra/piscsi-oled.service" "$SYSTEMD_PATH/piscsi-oled.service"
sudo sed -i /^ExecStart=/d "$SYSTEMD_PATH/piscsi-oled.service"
if [ ! -z "$TOKEN" ]; then
sudo sed -i "8 i ExecStart=$OLED_INSTALL_PATH/start.sh --rotation=$ROTATION --height=$SCREEN_HEIGHT --password=$TOKEN" "$SYSTEMD_PATH/piscsi-oled.service"
# Make the service file readable by root only, to protect the token string
sudo chmod 600 "$SYSTEMD_PATH/piscsi-oled.service"
echo "Granted access to the OLED Monitor with the password that you configured for PiSCSI."
else
sudo sed -i "8 i ExecStart=$OLED_INSTALL_PATH/start.sh --rotation=$ROTATION --height=$SCREEN_HEIGHT" "$SYSTEMD_PATH/piscsi-oled.service"
fi
sudo systemctl daemon-reload
sudo systemctl daemon-reload
sudo systemctl enable piscsi-oled
if [ $REBOOT -eq 1 ]; then
echo ""
echo "The piscsi-oled service will start on the next Pi boot."
echo "Press Enter to reboot or CTRL-C to exit"
read
echo "Rebooting..."
sleep 3
sudo reboot
fi
sudo systemctl start piscsi-oled
}
# updates configuration files and installs packages needed for the CtrlBoard script
function installPiscsiCtrlBoard() {
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 "IMPORTANT: This configuration requires a PiSCSI Control Board connected to your PiSCSI board."
echo "See wiki for more information: https://github.com/akuker/PISCSI/wiki/PiSCSI-Control-Board"
echo ""
echo "Choose screen rotation:"
echo " 1) 0 degrees"
echo " 2) 180 degrees (default)"
read REPLY
if [ "$REPLY" == "1" ]; then
echo "Proceeding with 0 degrees rotation."
ROTATION="0"
else
echo "Proceeding with 180 degrees rotation."
ROTATION="180"
fi
stopService "piscsi-ctrlboard"
updatePiscsiGit
if [[ $SKIP_PACKAGES ]]; then
echo "Skipping package installation"
else
sudo apt-get update && sudo apt-get install libjpeg-dev libpng-dev libopenjp2-7-dev i2c-tools raspi-config python3-rpi.gpio --assume-yes --no-install-recommends </dev/null
# install python packages through apt that need compilation
sudo apt-get install python3-cbor2 --assume-yes --no-install-recommends </dev/null
fi
# enable i2c
if [[ $(grep -c "^dtparam=i2c_arm=on" /boot/config.txt) -ge 1 ]]; then
echo "NOTE: I2C support seems to have been configured already."
REBOOT=0
else
sudo raspi-config nonint do_i2c 0 </dev/null
echo "Modified the Raspberry Pi boot configuration to enable I2C."
echo "A reboot will be required for the change to take effect."
REBOOT=1
fi
# determine target baudrate
PI_MODEL=$(/usr/bin/tr -d '\0' < /proc/device-tree/model)
TARGET_I2C_BAUDRATE=100000
if [[ ${PI_MODEL} =~ "Raspberry Pi 4" ]]; then
echo "Detected: Raspberry Pi 4"
TARGET_I2C_BAUDRATE=1000000
elif [[ ${PI_MODEL} =~ "Raspberry Pi 3" ]] || [[ ${PI_MODEL} =~ "Raspberry Pi Zero 2" ]]; then
echo "Detected: Raspberry Pi 3 or Zero 2"
TARGET_I2C_BAUDRATE=400000
else
echo "No Raspberry Pi 4, Pi 3 or Pi Zero 2 detected. Falling back on low i2c baudrate."
echo "Transition animations will be disabled."
fi
# adjust i2c baudrate according to the raspberry pi model detection
set +e
GREP_PARAM="^dtparam=i2c_arm=on,i2c_arm_baudrate=${TARGET_I2C_BAUDRATE}$"
ADJUST_BAUDRATE=$(grep -c "${GREP_PARAM}" /boot/config.txt)
if [[ $ADJUST_BAUDRATE -eq 0 ]]; then
echo "Adjusting I2C baudrate in /boot/config.txt"
sudo sed -i "s/dtparam=i2c_arm=on.*/dtparam=i2c_arm=on,i2c_arm_baudrate=${TARGET_I2C_BAUDRATE}/g" /boot/config.txt
REBOOT=1
else
echo "I2C baudrate already correct in /boot/config.txt"
fi
set -e
# Deleting previous venv dir, if one exists, to avoid the common issue of broken python dependencies
deleteDir "$CTRLBOARD_INSTALL_PATH/venv"
echo "Installing the piscsi-ctrlboard.service configuration..."
sudo cp -f "$CTRLBOARD_INSTALL_PATH/service-infra/piscsi-ctrlboard.service" "$SYSTEMD_PATH/piscsi-ctrlboard.service"
sudo sed -i /^ExecStart=/d "$SYSTEMD_PATH/piscsi-ctrlboard.service"
if [ ! -z "$TOKEN" ]; then
sudo sed -i "8 i ExecStart=$CTRLBOARD_INSTALL_PATH/start.sh --rotation=$ROTATION --password=$TOKEN" "$SYSTEMD_PATH/piscsi-ctrlboard.service"
sudo chmod 600 "$SYSTEMD_PATH/piscsi-ctrlboard.service"
echo "Granted access to the PiSCSI Control Board UI with the password that you configured for PiSCSI."
else
sudo sed -i "8 i ExecStart=$CTRLBOARD_INSTALL_PATH/start.sh --rotation=$ROTATION" "$SYSTEMD_PATH/piscsi-ctrlboard.service"
fi
sudo systemctl daemon-reload
stopService "piscsi-oled"
disableService "piscsi-oled"
sudo systemctl daemon-reload
sudo systemctl enable piscsi-ctrlboard
if [ $REBOOT -eq 1 ]; then
echo ""
echo "The piscsi-ctrlboard service will start on the next Pi boot."
echo "Press Enter to reboot or CTRL-C to exit"
read
echo "Rebooting..."
sleep 3
sudo reboot
fi
sudo systemctl start piscsi-ctrlboard
}
# Prints a notification if the piscsi.service file was backed up
function notifyBackup {
if "$SYSTEMD_BACKUP"; then
echo ""
echo "IMPORTANT: $SYSTEMD_PATH/piscsi.service has been overwritten."
echo "A backup copy was saved as piscsi.service.old in the same directory."
echo "Please inspect the backup file and restore configurations that are important to your setup."
echo ""
fi
}
# Creates the group and modifies current user for Web Interface auth
function enableWebInterfaceAuth {
if [ $(getent group "$AUTH_GROUP") ]; then
echo "The '$AUTH_GROUP' group already exists."
echo "Do you want to disable Web Interface authentication? (y/N)"
read -r REPLY
if [ "$REPLY" == "y" ] || [ "$REPLY" == "Y" ]; then
sudo groupdel "$AUTH_GROUP"
echo "The '$AUTH_GROUP' group has been deleted."
exit 0
fi
else
echo "Creating the '$AUTH_GROUP' group."
sudo groupadd "$AUTH_GROUP"
fi
echo "Adding user '$USER' to the '$AUTH_GROUP' group."
sudo usermod -a -G "$AUTH_GROUP" "$USER"
}
# Executes the keyword driven scripts for a particular action in the main menu
function runChoice() {
case $1 in
1)
echo "Installing / Updating PiSCSI Service ($CONNECT_TYPE) + Web Interface"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
echo "- Install the Nginx web server"
echo "- Create files and directories"
echo "- Change permissions of files and directories"
echo "- Modify user groups and permissions"
echo "- Install binaries to /usr/local/bin"
echo "- Install manpages to /usr/local/man"
echo "- Create a self-signed certificate in /etc/ssl"
sudoCheck
createImagesDir
createCfgDir
migrateLegacyData
stopService "piscsi-web"
updatePiscsiGit
installPackages
installHfdisk
fetchHardDiskDrivers
stopService "piscsi-ctrlboard"
stopService "piscsi-oled"
stopService "piscsi"
compilePiscsi
backupPiscsiService
installPiscsi
configurePiscsiService
enablePiscsiService
preparePythonCommon
if [[ $(isPiscsiScreenInstalled) -eq 0 ]]; then
echo "Detected piscsi oled service; will run the installation steps for the OLED monitor."
installPiscsiScreen
elif [[ $(isPiscsiCtrlBoardInstalled) -eq 0 ]]; then
echo "Detected piscsi control board service; will run the installation steps for the control board ui."
installPiscsiCtrlBoard
fi
installPiscsiWebInterface
installWebInterfaceService
showServiceStatus "piscsi-oled"
showServiceStatus "piscsi-ctrlboard"
showServiceStatus "piscsi"
showServiceStatus "piscsi-web"
notifyBackup
echo "Installing / Updating PiSCSI Service ($CONNECT_TYPE) + Web Interface - Complete!"
;;
2)
echo "Installing / Updating PiSCSI Service ($CONNECT_TYPE)"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
echo "- Create files ans directories"
echo "- Change permissions of files and directories"
echo "- Modify user groups and permissions"
echo "- Install binaries to /usr/local/bin"
echo "- Install manpages to /usr/local/man"
sudoCheck
createImagesDir
createCfgDir
updatePiscsiGit
installPackagesStandalone
migrateLegacyData
stopService "piscsi-ctrlboard"
stopService "piscsi-oled"
stopService "piscsi"
compilePiscsi
backupPiscsiService
preparePythonCommon
installPiscsi
configurePiscsiService
enablePiscsiService
if [[ $(isPiscsiScreenInstalled) -eq 0 ]]; then
echo "Detected piscsi oled service; will run the installation steps for the OLED monitor."
installPiscsiScreen
elif [[ $(isPiscsiCtrlBoardInstalled) -eq 0 ]]; then
echo "Detected piscsi control board service; will run the installation steps for the control board ui."
installPiscsiCtrlBoard
fi
showServiceStatus "piscsi-oled"
showServiceStatus "piscsi-ctrlboard"
showServiceStatus "piscsi"
notifyBackup
echo "Installing / Updating PiSCSI Service ($CONNECT_TYPE) - Complete!"
;;
3)
echo "Installing / Updating PiSCSI OLED Screen"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
echo "- Modify the Raspberry Pi boot configuration (may require a reboot)"
sudoCheck
preparePythonCommon
migrateLegacyData
installPiscsiScreen
showServiceStatus "piscsi-oled"
echo "Installing / Updating PiSCSI OLED Screen - Complete!"
;;
4)
echo "Installing / Updating PiSCSI Control Board UI"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
echo "- Stop and disable the PiSCSI OLED service if it is running"
echo "- Modify the Raspberry Pi boot configuration (may require a reboot)"
sudoCheck
preparePythonCommon
migrateLegacyData
installPiscsiCtrlBoard
showServiceStatus "piscsi-ctrlboard"
echo "Installing / Updating PiSCSI Control Board UI - Complete!"
;;
5)
echo "Configuring wired network bridge"
echo "This script will make the following changes to your system:"
echo "- Create a virtual network bridge interface in /etc/network/interfaces.d"
echo "- Modify /etc/dhcpcd.conf to bridge the Ethernet interface (may change the IP address; requires a reboot)"
sudoCheck
showMacNetworkWired
setupWiredNetworking
echo "Configuring wired network bridge - Complete!"
;;
6)
echo "Configuring wifi network bridge"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Modify /etc/sysctl.conf to enable IPv4 forwarding"
echo "- Add NAT rules for the wlan interface (requires a reboot)"
sudoCheck
showMacNetworkWireless
setupWirelessNetworking
echo "Configuring wifi network bridge - Complete!"
;;
7)
echo "Installing AppleShare File Server"
createFileSharingDir
installNetatalk
echo "Installing AppleShare File Server - Complete!"
;;
8)
echo "Installing FTP File Server"
echo "This script will make the following changes to your system:"
echo " - Install packages with apt-get"
echo " - Enable the vsftpd systemd service"
echo "WARNING: The FTP server may transfer unencrypted data over the network."
echo "Proceed with this installation only if you are on a private, secure network."
sudoCheck
createFileSharingDir
installFtp
echo "Installing FTP File Server - Complete!"
;;
9)
echo "Installing SMB File Server"
echo "This script will make the following changes to your system:"
echo " - Install packages with apt-get"
echo " - Enable Samba systemd services"
echo " - Create a directory in the current user's home directory where shared files will be stored"
echo " - Create a Samba user for the current user"
sudoCheck
createFileSharingDir
installSamba
echo "Installing SMB File Server - Complete!"
;;
10)
echo "Installing Web Proxy Server"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
sudoCheck
stopService "macproxy"
installMacproxy
echo "Installing Web Proxy Server - Complete!"
;;
11)
echo "Configuring PiSCSI stand-alone ($CONNECT_TYPE)"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Create directories and change permissions"
echo "- Install binaries to /usr/local/bin"
echo "- Install manpages to /usr/local/man"
sudoCheck
createImagesDir
updatePiscsiGit
installPackagesStandalone
stopService "piscsi"
compilePiscsi
installPiscsi
echo "Configuring PiSCSI stand-alone ($CONNECT_TYPE) - Complete!"
echo "Use 'piscsi' to launch PiSCSI, and 'scsictl' to control the running process."
;;
12)
echo "Configuring PiSCSI Web Interface stand-alone"
echo "This script will make the following changes to your system:"
echo "- Install additional packages with apt-get"
echo "- Add and modify systemd services"
echo "- Modify and enable Apache2 and Nginx web service"
echo "- Create directories and change permissions"
echo "- Create a self-signed certificate in /etc/ssl"
sudoCheck
createCfgDir
updatePiscsiGit
installPackagesWeb
installHfdisk
fetchHardDiskDrivers
preparePythonCommon
cachePipPackages
installPiscsiWebInterface
echo "Configuring PiSCSI Web Interface stand-alone - Complete!"
echo "Launch the Web Interface with the 'start.sh' script. To use a custom port for the web server: 'start.sh --web-port=8081"
;;
13)
echo "Enabling or disabling PiSCSI back-end authentication"
echo "This script will make the following changes to your system:"
echo "- Modify user groups and permissions"
sudoCheck
stopService "piscsi"
configureTokenAuth
enablePiscsiService
echo "Enabling or disabling PiSCSI back-end authentication - Complete!"
;;
14)
echo "Enabling or disabling Web Interface authentication"
echo "This script will make the following changes to your system:"
echo "- Modify user groups and permissions"
sudoCheck
enableWebInterfaceAuth
echo "Enabling or disabling Web Interface authentication - Complete!"
;;
15)
shareImagesWithNetatalk
echo "Configuring AppleShare File Server - Complete!"
;;
16)
installPackagesStandalone
compilePiscsi
;;
17)
echo "Install Webmin"
echo "This script will make the following changes to your system:"
echo "- Add a 3rd party apt repository"
echo "- Install and start the Webmin webapp"
echo "- Install the netatalk2 Webmin module"
echo "- Install the vsftpd Webmin module"
installWebmin
echo "Install Webmin - Complete!"
echo "The Webmin webapp should now be listening to port 10000 on this system"
;;
99)
echo "Hidden setup mode for running the pi-gen utility"
echo "This shouldn't be used by normal users"
sudoCache
createImagesDir
createCfgDir
updatePiscsiGit
installPackages
installHfdisk
fetchHardDiskDrivers
compilePiscsi
installPiscsi
configurePiscsiService
enablePiscsiService
preparePythonCommon
cachePipPackages
installPiscsiWebInterface
installWebInterfaceService
echo "Automated install of the PiSCSI Service $(CONNECT_TYPE) complete!"
;;
*)
echo "${1} is not a valid option, exiting..."
exit 1
esac
}
# Reads and validates the main menu choice
function readChoice() {
choice=-1
until [ $choice -ge "1" ] && ([ $choice -eq "99" ] || [ $choice -le "17" ]) ; do
echo -n "Enter your choice (1-17) or CTRL-C to exit: "
read -r choice
done
runChoice "$choice"
}
# Shows the interactive main menu of the script
function showMenu() {
echo "For command line options, rerun with ./easyinstall.sh --help"
echo "Board Type: $CONNECT_TYPE | Compiler: $COMPILER | Compiler Cores: $CORES"
if [[ $SKIP_MAKE_CLEAN ]]; then
echo "Skip 'make clean': YES"
else
echo "Skip 'make clean': NO (will compile from scratch every time!)"
fi
echo ""
echo "Choose among the following options:"
echo "INSTALL/UPDATE PISCSI"
echo " 1) Install or update PiSCSI Service + Web Interface"
echo " 2) Install or update PiSCSI Service"
echo " 3) Install or update PiSCSI OLED Screen (requires hardware)"
echo " 4) Install or update PiSCSI Control Board UI (requires hardware)"
echo "NETWORK BRIDGE ASSISTANT"
echo " 5) Configure network bridge for Ethernet (DHCP)"
echo " 6) Configure network bridge for WiFi (static IP + NAT)"
echo "INSTALL COMPANION APPS"
echo " 7) Install AppleShare File Server (Netatalk)"
echo " 8) Install FTP File Server (vsftpd)"
echo " 9) Install SMB File Server (Samba)"
echo " 10) Install Web Proxy Server (Macproxy)"
echo "ADVANCED OPTIONS"
echo " 11) Compile and install PiSCSI stand-alone"
echo " 12) Configure the PiSCSI Web Interface stand-alone"
echo " 13) Enable or disable PiSCSI back-end authentication"
echo " 14) Enable or disable PiSCSI Web Interface authentication"
echo "EXPERIMENTAL FEATURES"
echo " 15) Share the images dir over AppleShare (requires Netatalk)"
echo " 16) Compile PiSCSI binaries"
echo " 17) Install Webmin to manage the system and companion apps"
}
# parse arguments passed to the script
while [ "$1" != "" ]; do
PARAM=$(echo "$1" | awk -F= '{print $1}')
VALUE=$(echo "$1" | awk -F= '{print $2}')
case $PARAM in
-c | --connect_type)
if ! [[ $VALUE =~ ^(FULLSPEC|STANDARD|AIBOM|GAMERNIUM)$ ]]; then
echo "ERROR: The connect type parameter must have a value of: FULLSPEC, STANDARD, AIBOM or GAMERNIUM"
exit 1
fi
CONNECT_TYPE=$VALUE
;;
-r | --run_choice)
if ! [[ $VALUE =~ ^[1-9][0-9]?$ && $VALUE -ge 1 && $VALUE -le 16 ]]; then
echo "ERROR: The run choice parameter must have a numeric value between 1 and 16"
exit 1
fi
RUN_CHOICE=$VALUE
;;
-j | --cores)
if ! [[ $VALUE =~ ^[1-9][0-9]?$ ]]; then
echo "ERROR: The cores parameter must have a numeric value of at least 1"
exit 1
fi
CORES=$VALUE
;;
-t | --token)
if [[ -z $VALUE ]]; then
echo "ERROR: The token parameter cannot be empty"
exit 1
fi
TOKEN=$VALUE
;;
-h | --headless)
HEADLESS=1
;;
-g | --with_gcc)
COMPILER="g++"
;;
-s | --skip_packages)
SKIP_PACKAGES=1
;;
-l | --skip_make_clean)
SKIP_MAKE_CLEAN=1
;;
--help)
echo "Usage: ./easyinstall.sh [options]"
echo
echo "-c=TYPE, --connect_type=TYPE Connect type (FULLSPEC, STANDARD, AIBOM, GAMERNIUM)"
echo "-r=CHOICE, --run_choice=CHOICE Choose a menu option (1 to 16)"
echo "-j=CORES, --cores=CORES Compile on this many cores in parallel"
echo "-t=TOKEN, --token=TOKEN Token password for protecting PiSCSI"
echo "-h, --headless Don't ask questions (use with -r=CHOICE)"
echo "-g, --with_gcc Compile with g++ instead of clang++"
echo "-s, --skip_packages Don't install Debian packages"
echo "-l, --skip_make_clean Don't recompile from scratch every time"
exit
;;
*)
echo "ERROR: Unknown parameter \"$PARAM\""
exit 1
;;
esac
shift
done
showPiSCSILogo
initialChecks
if [ -z "${RUN_CHOICE}" ]; then # RUN_CHOICE is unset, show menu
showMenu
readChoice
else
runChoice "$RUN_CHOICE"
fi