From 86bf209c7fe48a7d80ac74fdfa2c3ea824a2cb3c Mon Sep 17 00:00:00 2001 From: ipitio <21136719+ipitio@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:05:02 -0400 Subject: [PATCH 1/5] shellcheck, multiplex the test, pushd/popd, no seconds in log --- advanced/Scripts/speedtestmod/mod.sh | 505 ++++++++++++++------- advanced/Scripts/speedtestmod/speedtest.sh | 312 +++++++++---- advanced/Scripts/updatecheck.sh | 22 +- advanced/Scripts/webpage.sh | 145 +++--- 4 files changed, 664 insertions(+), 320 deletions(-) diff --git a/advanced/Scripts/speedtestmod/mod.sh b/advanced/Scripts/speedtestmod/mod.sh index d469c70144..8d23ae955c 100755 --- a/advanced/Scripts/speedtestmod/mod.sh +++ b/advanced/Scripts/speedtestmod/mod.sh @@ -1,52 +1,84 @@ #!/bin/bash - +# +# The Mod Script, Speedtest Mod for Pi-hole Installation Manager +# Please run this with the --help option for usage information +# +# shellcheck disable=SC2015 +# + +####################################### +# Get the version of a repository, either from a local clone or from the installed package +# Globals: +# None +# Arguments: +# $1: The path to, or name of, the repository +# $2: Non-empty string to get the hash, empty string to get the tag if it exists +# Returns: +# The version of the repository +####################################### getVersion() { - local foundVersion="" - - if [ -d $1 ]; then - cd $1 - foundVersion=$(git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}') - - if [ -z "${2:-}" ]; then - local tags=$(git ls-remote -t origin) - local foundTag=$foundVersion - ! grep -q "$foundVersion" <<<"$tags" || foundTag=$(grep "$foundVersion" <<<"$tags" | awk '{print $2;}' | cut -d '/' -f 3 | sort -V | tail -n1) - [ -z "$foundTag" ] || foundVersion=$foundTag + local found_version="" + + if [[ -d "$1" ]]; then + pushd "$1" &>/dev/null || exit 1 + found_version=$(git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}') + + if [[ -z "${2:-}" ]]; then + local tags + local found_tag=$found_version + tags=$(git ls-remote -t origin) + ! grep -q "$found_version" <<<"$tags" || found_tag=$(grep "$found_version" <<<"$tags" | awk '{print $2;}' | cut -d '/' -f 3 | sort -V | tail -n1) + [[ -z "$found_tag" ]] || found_version=$found_tag fi - cd - &>/dev/null - elif [ -x "$(command -v pihole)" ]; then - local versions=$(pihole -v | grep "$1") - foundVersion=$(cut -d ' ' -f 6 <<<"$versions") + popd &>/dev/null + elif [[ -x "$(command -v pihole)" ]]; then + local versions + versions=$(pihole -v | grep "$1") + found_version=$(cut -d ' ' -f 6 <<<"$versions") - if [[ "$foundVersion" != *.* ]]; then - [ "$foundVersion" != "$(git rev-parse --abbrev-ref HEAD)" ] || foundVersion=$(cut -d ' ' -f 7 <<<"$versions") + if [[ "$found_version" != *.* ]]; then + [[ "$found_version" != "$(git status --porcelain=2 -b | grep branch.head | awk '{print $3;}')" ]] || found_version=$(cut -d ' ' -f 7 <<<"$versions") fi fi - echo $foundVersion + echo "$found_version" } +####################################### +# Fetch a repository, optionally a specific version +# Globals: +# None +# Arguments: +# $1: The path to download the repository to +# $2: The name of the repository +# $3: The URL of the repository +# $4: The desired version, hash or tag, to download (optional, none by default) +# $5: The branch to download (optional, master by default) +# $6: Whether to snap to the tag (optional, true by default) +# Outputs: +# The repository at the desired version +####################################### download() { local path=$1 local name=$2 local url=$3 - local desiredVersion="${4:-}" + local desired_version="${4:-}" local branch="${5:-master}" - local snapToTag="${6:-true}" + local snap_to_tag="${6:-true}" local dest=$path/$name local aborting=false - [ -d "$dest" ] && [ ! -d "$dest/.git" ] && mv -f "$dest" "$dest.old" || : - [ -d "$dest" ] || git clone --depth=1 -b "$branch" "$url" "$dest" -q - cd "$dest" + [[ ! -d "$dest" || -d "$dest/.git" ]] || mv -f "$dest" "$dest.old" + [[ -d "$dest" ]] || git clone --depth=1 -b "$branch" "$url" "$dest" -q + pushd "$dest" &>/dev/null || exit 1 git config --global --add safe.directory "$dest" - if [ ! -z "$desiredVersion" ] && [[ "$desiredVersion" != *.* ]]; then + if [[ -n "$desired_version" && "$desired_version" != *.* ]]; then local repos=("Pi-hole" "web" "speedtest") for repo in "${repos[@]}"; do - if [[ "$desiredVersion" == *"$repo"* ]]; then + if [[ "$desired_version" == *"$repo"* ]]; then aborting=true break fi @@ -63,38 +95,48 @@ download() { url=$(git remote get-url origin) fi - [[ "$url" == *"ipitio"* ]] && snapToTag=$(grep -q "true" <<<"$snapToTag" && echo "false" || echo "true") - git fetch origin --depth=1 $branch:refs/remotes/origin/$branch -q + [[ "$url" != *"ipitio"* ]] || snap_to_tag=$(grep -q "true" <<<"$snap_to_tag" && echo "false" || echo "true") + git fetch origin --depth=1 "$branch":refs/remotes/origin/"$branch" -q git reset --hard origin/"$branch" -q git checkout -B "$branch" -q - local currentHash=$(getVersion "$dest" hash) - local tags=$(git ls-remote -t origin) - - if [ -z "$desiredVersion" ]; then # if empty, get the latest version - if [ "$snapToTag" == "true" ]; then - local latestTag=$(awk -F/ '{print $3}' <<<"$tags" | grep '^v[0-9]' | grep -v '\^{}' | sort -V | tail -n1) - [ ! -z "$latestTag" ] && desiredVersion=$latestTag || desiredVersion=$currentHash - fi + local current_hash + local tags + current_hash=$(getVersion "$dest" hash) + tags=$(git ls-remote -t origin) + + if [[ -z "$desired_version" ]]; then # if empty, get the latest version + local latest_tag="" + [[ "$snap_to_tag" != "true" ]] || latest_tag=$(awk -F/ '{print $3}' <<<"$tags" | grep '^v[0-9]' | grep -v '\^{}' | sort -V | tail -n1) + [[ -n "$latest_tag" ]] && desired_version=$latest_tag || desired_version=$current_hash elif $aborting; then - desiredVersion=$(getVersion "$desiredVersion" hash) + desired_version=$(getVersion "$desired_version" hash) fi - if [[ "$desiredVersion" == *.* ]]; then - grep -q "$desiredVersion$" <<<"$tags" && desiredVersion=$(grep "$desiredVersion$" <<<"$tags" | awk '{print $1;}') || desiredVersion=$currentHash + if [[ "$desired_version" == *.* ]]; then + grep -q "$desired_version$" <<<"$tags" && desired_version=$(grep "$desired_version$" <<<"$tags" | awk '{print $1;}') || desired_version=$current_hash fi - if [ "$currentHash" != "$desiredVersion" ]; then - git fetch origin --depth=1 $desiredVersion -q - git reset --hard $desiredVersion -q + if [[ "$current_hash" != "$desired_version" ]]; then + git fetch origin --depth=1 "$desired_version" -q + git reset --hard "$desired_version" -q fi - cd .. + popd &>/dev/null } +####################################### +# Check if a package is installed, only used below when --continuous is not +# Globals: +# None +# Arguments: +# $1: The package to check +# Returns: +# 0 if the package is not installed, 1 if it is +####################################### notInstalled() { - if [ -x "$(command -v apt-get)" ]; then + if [[ -x "$(command -v apt-get)" ]]; then dpkg -s "$1" &>/dev/null || return 0 - elif [ -x "$(command -v dnf)" ] || [ -x "$(command -v yum)" ]; then + elif [[ -x "$(command -v dnf)" ]] || [[ -x "$(command -v yum)" ]]; then rpm -q "$1" &>/dev/null || return 0 else echo "Unsupported package manager!" @@ -104,68 +146,96 @@ notInstalled() { return 1 } +####################################### +# Set a key-value pair in a configuration file, used below for --reinstall +# Globals: +# None +# Arguments: +# $1: The key to set +# $2: The value to set +# $3: The configuration file to set the key-value pair in +# $4: Whether to replace the value if it already exists +# Outputs: +# The configuration file with the key-value pair set +####################################### setCnf() { - grep -q "^$1=" $3 || echo "$1=$2" >>$3 - [ "${4:-false}" == "true" ] || sed -i "s|^$1=.*|$1=$2|" $3 + grep -q "^$1=" "$3" || echo "$1=$2" >>"$3" + [[ "${4:-false}" == "true" ]] || sed -i "s|^$1=.*|$1=$2|" "$3" } +####################################### +# Get a key-value pair from a configuration file, used below for --reinstall +# Globals: +# None +# Arguments: +# $1: The configuration file to get the key-value pair from +# $2: The key to get the value of +# $3: Non-empty string to get the hash, empty string to get the tag if it exists +# Returns: +# The value of the key-value pair +####################################### getCnf() { - local keydir=$(echo $2 | sed 's/^mod-//;s/^org-//') - local value=$(grep "^$2=" $1 | cut -d '=' -f 2) - [ ! -z "$value" ] || value=$(getVersion $keydir "${3:-}") - - if [ ! -z "${3:-}" ] && [[ "$value" == *.* ]]; then - cd $keydir - local tags=$(git ls-remote -t origin) - grep -q "$value$" <<<"$tags" && ver=$(grep "$value$" <<<"$tags" | awk '{print $1;}') || value=$(git rev-parse HEAD) - cd - &>/dev/null - fi - - echo $value + local keydir + local value + keydir=$(echo "$2" | sed 's/^mod-//;s/^org-//') + value=$(grep "^$2=" "$1" | cut -d '=' -f 2) + [[ -n "$value" ]] || value=$(getVersion "$keydir" "${3:-}") + echo "$value" } # allow to source the above helper functions without running the whole script if [[ "${SKIP_MOD:-}" != true ]]; then - html_dir=/var/www/html - core_dir=/etc/.pihole - opt_dir=/opt/pihole - etc_dir=/etc/pihole - mod_dir=/etc/pihole-speedtest - curr_wp=$opt_dir/webpage.sh - curr_db=$etc_dir/speedtest.db - last_db=$curr_db.old - db_table="speedtest" + declare -r HTML_DIR="/var/www/html" + declare -r CORE_DIR="/etc/.pihole" + declare -r OPT_DIR="/opt/pihole" + declare -r ETC_DIR="/etc/pihole" + declare -r MOD_DIR="/etc/pihole-speedtest" + declare -r CURR_WP="$OPT_DIR/webpage.sh" + declare -r CURR_DB="$ETC_DIR/speedtest.db" + declare -r LAST_DB="$CURR_DB.old" + declare -r DB_TABLE="speedtest" + declare -i aborted=0 st_ver="" mod_core_ver="" mod_admin_ver="" cleanup=true - aborted=0 set +u + # shellcheck disable=SC2034 SKIP_INSTALL=true - source "$core_dir/automated install/basic-install.sh" + # shellcheck disable=SC1091 + source "$CORE_DIR/automated install/basic-install.sh" set -u + ####################################### + # Display the help message + # Globals: + # None + # Arguments: + # None + # Outputs: + # The help message + ####################################### help() { - local helpText=( + local -r help_text=( "The Mod Script" "Usage: sudo bash /path/to/mod.sh [options]" " or: curl -sSLN //link/to/mod.sh | sudo bash [-s -- options]" "(Re)install the latest release of the Speedtest Mod, and/or the following options:" "" "Options:" - " -u, --update, up also update Pi-hole, unless Systemd is not being used (ie. not in Docker)" " -b, --backup preserve stock Pi-hole files for faster offline restore" " -o, --online force online restore of stock Pi-hole files even if a backup exists" " -i, --install skip restore of stock Pi-hole*" + " -c, --continuous skip check for missing dependencies" " -r, --reinstall keep current version of the mod, if installed*" " -t, --testing install the latest commit" + " -u, --update, up also update Pi-hole, unless Systemd is not being used (ie. not in Docker)" " -n, --uninstall, un remove the mod and its files, but keep the database" " -d, --database, db flush/restore the database if it's not/empty (and exit if this is the only arg given)" - " -v, --version display the version of the mod" " -x, --verbose show the commands being run" - " -c, --continuous skip check for missing dependencies" - " -h, --help display this help message" + " -v, --version display the version of the mod and exit" + " -h, --help display this help message and exit" "" " *for when not updating Pi-hole nor switching repos" "" @@ -176,82 +246,171 @@ if [[ "${SKIP_MOD:-}" != true ]]; then " curl -sSLN https://github.com/arevindh/pi-hole/raw/master/advanced/Scripts/speedtestmod/mod.sh | sudo bash -s -- -u" ) - printf "%s\n" "${helpText[@]}" + printf "%s\n" "${help_text[@]}" } + ####################################### + # Check if a database is empty + # Globals: + # DB_TABLE + # Arguments: + # $1: The database to check + # Returns: + # 0 if the database is empty, 1 if it is not + ####################################### isEmpty() { - [ -f $1 ] && sqlite3 "$1" "select * from $db_table limit 1;" &>/dev/null && [ ! -z "$(sqlite3 "$1" "select * from $db_table limit 1;")" ] && return 1 || return 0 + [[ -f "$1" ]] && sqlite3 "$1" "select * from $DB_TABLE limit 1;" &>/dev/null && [[ -n "$(sqlite3 "$1" "select * from $DB_TABLE limit 1;")" ]] && return 1 || return 0 } + ####################################### + # Copy scripts from the CORE to the OPT repository + # Globals: + # OPT_DIR + # Arguments: + # None + # Outputs: + # The scripts copied to the OPT repository + ####################################### swapScripts() { set +u installScripts >/dev/null 2>&1 set -u } + ####################################### + # Restore a backup, used after --backup unless --online or --install are used + # Globals: + # None + # Arguments: + # $1: The backup to restore + # Returns: + # 1 if the backup does not exist or is stale, 0 if it does and isn't + # Outputs: + # The backup restored + ####################################### restore() { - [ -d $1.bak ] || return 1 - [ ! -e $1 ] || rm -rf $1 - mv -f $1.bak $1 - cd $1 - git tag -l | xargs git tag -d >/dev/null 2>&1 - git fetch --tags -f -q + [[ -d "$1".bak && "$(getVersion "$1".bak hash)" == "$(getCnf $MOD_DIR/cnf org-"$1" hash)" ]] || return 1 + [[ ! -e "$1" ]] || rm -rf "$1" + mv -f "$1".bak "$1" } + ####################################### + # Purge the mod, used for --uninstall + # Globals: + # CORE_DIR + # HTML_DIR + # OPT_DIR + # CURR_DB + # ETC_DIR + # Arguments: + # None + # Outputs: + # The mod purged + ####################################### purge() { - if [ -f /etc/systemd/system/pihole-speedtest.timer ]; then + if [[ -f /etc/systemd/system/pihole-speedtest.timer ]]; then rm -f /etc/systemd/system/pihole-speedtest.service rm -f /etc/systemd/system/pihole-speedtest.timer systemctl daemon-reload fi - rm -rf $opt_dir/speedtestmod - rm -rf $core_dir.bak - rm -rf $html_dir/admin.bak - rm -rf $core_dir.mod - rm -rf $html_dir/admin.mod - rm -f "$curr_db".* - rm -f $etc_dir/last_speedtest.* - ! isEmpty $curr_db || rm -f $curr_db + rm -rf $OPT_DIR/speedtestmod + rm -rf $CORE_DIR.bak + rm -rf $HTML_DIR/admin.bak + rm -rf $CORE_DIR.mod + rm -rf $HTML_DIR/admin.mod + rm -f "$CURR_DB".* + rm -f $ETC_DIR/last_speedtest.* + ! isEmpty $CURR_DB || rm -f $CURR_DB } + ####################################### + # Abort the process + # Globals: + # CORE_DIR + # HTML_DIR + # MOD_DIR + # OPT_DIR + # CURR_WP + # CURR_DB + # LAST_DB + # ETC_DIR + # cleanup + # aborted + # Arguments: + # None + # Outputs: + # The changes reverted + # shellcheck disable=SC2317 ########### abort() { if $cleanup; then echo "Process Aborting..." aborted=1 - if [ -d $core_dir/.git/refs/remotes/old ]; then + if [[ -d "$CORE_DIR"/.git/refs/remotes/old ]]; then download /etc .pihole "" Pi-hole swapScripts - if [ -d $core_dir/advanced/Scripts/speedtestmod ]; then - \cp -af $core_dir/advanced/Scripts/speedtestmod/. $opt_dir/speedtestmod/ + if [[ -d "$CORE_DIR"/advanced/Scripts/speedtestmod ]]; then + \cp -af "$CORE_DIR"/advanced/Scripts/speedtestmod/. "$OPT_DIR"/speedtestmod/ pihole -a -s fi fi - [ -d $mod_dir ] && [ -d $mod_dir/.git/refs/remotes/old ] && download /etc pihole-speedtest "" speedtest || : - [ ! -d $html_dir/admin/.git/refs/remotes/old ] || download $html_dir admin "" web - [ -f $last_db ] && [ ! -f $curr_db ] && mv $last_db $curr_db || : - [ -f $curr_wp ] && ! cat $curr_wp | grep -q SpeedTest && purge || : - printf "Please try again before reporting an issue.\n\n$(date)\n" + [[ ! -d "$MOD_DIR" || ! -d "$MOD_DIR"/.git/refs/remotes/old ]] || download /etc pihole-speedtest "" speedtest + [[ ! -d "$HTML_DIR"/admin/.git/refs/remotes/old ]] || download "$HTML_DIR" admin "" web + [[ ! -f "$LAST_DB" || -f "$CURR_DB" ]] || mv "$LAST_DB" "$CURR_DB" + [[ -f "$CURR_WP" ]] && ! grep -q SpeedTest "$CURR_WP" && purge || : + printf "Please try again before reporting an issue.\n\n%s\n" "$(date)" fi } + ####################################### + # Commit the changes + # Globals: + # CORE_DIR + # HTML_DIR + # cleanup + # Arguments: + # None + # Outputs: + # The repositories cleaned up + # shellcheck disable=SC2317 ########### commit() { if $cleanup; then - for dir in $core_dir $html_dir/admin; do - [ ! -d $dir ] && continue || cd $dir + for dir in $CORE_DIR $HTML_DIR/admin; do + [[ ! -d "$dir" ]] && continue || pushd "$dir" &>/dev/null || exit 1 ! git remote -v | grep -q "old" || git remote remove old git clean -ffdx + popd &>/dev/null done - printf "Done!\n\n$(date)\n" + printf "Done!\n\n%s\n" "$(date)" fi } + ####################################### + # Manage the installation + # Globals: + # CORE_DIR + # HTML_DIR + # MOD_DIR + # OPT_DIR + # CURR_WP + # CURR_DB + # LAST_DB + # ETC_DIR + # st_ver + # mod_core_ver + # mod_admin_ver + # cleanup + # Arguments: + # $@: The options for managing the installation + # Outputs: + # The installation managed + ####################################### main() { set -Eeuo pipefail - trap 'abort' INT TERM + trap 'abort' INT TERM ERR shopt -s dotglob local update=false @@ -264,13 +423,13 @@ if [[ "${SKIP_MOD:-}" != true ]]; then local database=false local verbose=false local chk_dep=true - local dashes=0 - local SHORT=-uboirtndvxch - local LONG=update,backup,online,install,reinstall,testing,uninstall,database,version,verbose,continuous,help - declare -a EXTRA_ARGS - declare -a POSITIONAL - PARSED=$(getopt --options ${SHORT} --longoptions ${LONG} --name "$0" -- "$@") - eval set -- "${PARSED}" + local -i dashes=0 + local -r short_opts=-uboirtndvxch + local -r long_opts=update,backup,online,install,reinstall,testing,uninstall,database,version,verbose,continuous,help + local -r parsed_opts=$(getopt --options ${short_opts} --longoptions ${long_opts} --name "$0" -- "$@") + declare -a POSITIONAL EXTRA_ARGS + eval set -- "${parsed_opts}" + local -ri num_args=$# while [[ $# -gt 0 ]]; do case "$1" in @@ -283,7 +442,7 @@ if [[ "${SKIP_MOD:-}" != true ]]; then -n | --uninstall) uninstall=true ;; -d | --database) database=true ;; -v | --version) - getVersion $mod_dir + getVersion $MOD_DIR cleanup=false exit 0 ;; @@ -315,47 +474,49 @@ if [[ "${SKIP_MOD:-}" != true ]]; then esac done + readonly update backup online install reinstall stable uninstall database verbose chk_dep cleanup trap '[ "$?" -eq "0" ] && commit || abort' EXIT - printf "Thanks for using Speedtest Mod!\nScript by @ipitio\n\n$(date)\n\n" + printf "%s\n\nRunning The Mod Script by @ipitio...\n" "$(date)" ! $verbose || set -x if $database; then - if [ -f $curr_db ] && ! isEmpty $curr_db; then + if [[ -f $CURR_DB ]] && ! isEmpty $CURR_DB; then echo "Flushing Database..." - mv -f $curr_db $last_db - [ ! -f $etc_dir/last_speedtest ] || mv -f $etc_dir/last_speedtest $etc_dir/last_speedtest.old + mv -f $CURR_DB $LAST_DB + [[ ! -f $ETC_DIR/last_speedtest ]] || mv -f $ETC_DIR/last_speedtest $ETC_DIR/last_speedtest.old - if [ -f /var/log/pihole/speedtest.log ]; then + if [[ -f /var/log/pihole/speedtest.log ]]; then mv -f /var/log/pihole/speedtest.log /var/log/pihole/speedtest.log.old - rm -f $etc_dir/speedtest.log + rm -f $ETC_DIR/speedtest.log fi - elif [ -f $last_db ]; then + elif [[ -f $LAST_DB ]]; then echo "Restoring Database..." - mv -f $last_db $curr_db - [ ! -f $etc_dir/last_speedtest.old ] || mv -f $etc_dir/last_speedtest.old $etc_dir/last_speedtest + mv -f $LAST_DB $CURR_DB + [[ ! -f $ETC_DIR/last_speedtest.old ]] || mv -f $ETC_DIR/last_speedtest.old $ETC_DIR/last_speedtest - if [ -f /var/log/pihole/speedtest.log.old ]; then + if [[ -f /var/log/pihole/speedtest.log.old ]]; then mv -f /var/log/pihole/speedtest.log.old /var/log/pihole/speedtest.log - \cp -af /var/log/pihole/speedtest.log $etc_dir/speedtest.log + \cp -af /var/log/pihole/speedtest.log $ETC_DIR/speedtest.log fi fi fi - if ! $database || [ "$#" -gt 1 ]; then - local working_dir=$(pwd) - cd ~ + if ! $database || [[ "$num_args" -gt 1 ]]; then + pushd ~ >/dev/null || exit 1 + pihole -v - if [ -f $curr_wp ] && cat $curr_wp | grep -q SpeedTest; then + if [[ -f $CURR_WP ]] && grep -q SpeedTest "$CURR_WP"; then if $reinstall; then - for repo in $core_dir $html_dir/admin $mod_dir; do - if [ -d $repo ]; then - local hashTag=$(getVersion $repo) # if hashes are the same, we may be on an older tag - [ "$(getVersion $repo hash)" != "$(getCnf $mod_dir/cnf mod-$repo hash)" ] || hashTag=$(getCnf $mod_dir/cnf mod-$repo) + for repo in $CORE_DIR $HTML_DIR/admin $MOD_DIR; do + if [[ -d "$repo" ]]; then + local hash_tag + hash_tag=$(getVersion "$repo") # if hashes are the same, we may be on an older tag + [[ "$(getVersion "$repo" hash)" != "$(getCnf $MOD_DIR/cnf mod-"$repo" hash)" ]] || hash_tag=$(getCnf $MOD_DIR/cnf mod-"$repo") case "$repo" in - "$core_dir") mod_core_ver=$hashTag ;; - "$html_dir/admin") mod_admin_ver=$hashTag ;; - "$mod_dir") st_ver=$hashTag ;; + "$CORE_DIR") mod_core_ver=$hash_tag ;; + "$HTML_DIR/admin") mod_admin_ver=$hash_tag ;; + "$MOD_DIR") st_ver=$hash_tag ;; esac fi done @@ -367,20 +528,23 @@ if [[ "${SKIP_MOD:-}" != true ]]; then local core_ver="" local admin_ver="" - if [ -f $mod_dir/cnf ]; then - core_ver=$(getCnf $mod_dir/cnf org-$core_dir) - admin_ver=$(getCnf $mod_dir/cnf org-$html_dir/admin) + + if [[ -f $MOD_DIR/cnf ]]; then + core_ver=$(getCnf $MOD_DIR/cnf org-$CORE_DIR) + admin_ver=$(getCnf $MOD_DIR/cnf org-$HTML_DIR/admin) fi - ! $online && restore $html_dir/admin || download $html_dir admin https://github.com/pi-hole/AdminLTE "$admin_ver" - ! $online && restore $core_dir || download /etc .pihole https://github.com/pi-hole/pi-hole "$core_ver" - [ ! -d $mod_dir ] || rm -rf $mod_dir + readonly core_ver admin_ver + + ! $online && restore $HTML_DIR/admin || download $HTML_DIR admin https://github.com/pi-hole/AdminLTE "$admin_ver" + ! $online && restore $CORE_DIR || download /etc .pihole https://github.com/pi-hole/pi-hole "$core_ver" + [[ ! -d $MOD_DIR ]] || rm -rf $MOD_DIR swapScripts fi fi if ! $install && $update; then - if [ -d /run/systemd/system ]; then + if [[ -d /run/systemd/system ]]; then echo "Updating Pi-hole..." PIHOLE_SKIP_OS_CHECK=true sudo -E pihole -up else @@ -393,73 +557,76 @@ if [[ "${SKIP_MOD:-}" != true ]]; then purge else if $chk_dep; then - if [ ! -f /usr/local/bin/pihole ]; then + if [[ ! -f /usr/local/bin/pihole ]]; then echo "Installing Pi-hole..." curl -sSL https://install.pi-hole.net | sudo bash fi echo "Checking Dependencies..." - local PHP_VERSION=$(php -v | head -n 1 | awk '{print $2}' | cut -d "." -f 1,2) - local PKG_MANAGER=$(command -v apt-get || command -v dnf || command -v yum) - local PKGS=(bc sqlite3 jq tar tmux wget "php$PHP_VERSION-sqlite3") - local missingPkgs=() + local -r php_version=$(php -v | head -n 1 | awk '{print $2}' | cut -d "." -f 1,2) + local -r pkg_manager=$(command -v apt-get || command -v dnf || command -v yum) + local -r pkgs=(bc nano sqlite3 jq tar tmux wget "php$php_version-sqlite3") + local missingpkgs=() - for pkg in "${PKGS[@]}"; do - ! notInstalled "$pkg" || missingPkgs+=("$pkg") + for pkg in "${pkgs[@]}"; do + ! notInstalled "$pkg" || missingpkgs+=("$pkg") done - if [ ${#missingPkgs[@]} -gt 0 ]; then - [[ "$PKG_MANAGER" != *"apt-get"* ]] || apt-get update >/dev/null + readonly missingpkgs + if [[ ${#missingpkgs[@]} -gt 0 ]]; then + [[ "$pkg_manager" != *"apt-get"* ]] || apt-get update >/dev/null echo "Installing Missing..." - $PKG_MANAGER install -y "${missingPkgs[@]}" + $pkg_manager install -y "${missingpkgs[@]}" &>/dev/null # hide an unimportant warning in docker fi fi if $backup; then echo "Backing up Pi-hole..." download /etc .pihole.mod https://github.com/arevindh/pi-hole "$mod_core_ver" master $stable - download $html_dir admin.mod https://github.com/arevindh/AdminLTE "$mod_admin_ver" master $stable + download $HTML_DIR admin.mod https://github.com/arevindh/AdminLTE "$mod_admin_ver" master $stable fi $reinstall && echo "Reinstalling Mod..." || echo "Installing Mod..." download /etc pihole-speedtest https://github.com/arevindh/pihole-speedtest "$st_ver" master $stable - [ -f $mod_dir/cnf ] || touch $mod_dir/cnf - setCnf mod-$mod_dir "$(getVersion $mod_dir)" $mod_dir/cnf $reinstall + [[ -f $MOD_DIR/cnf ]] || touch $MOD_DIR/cnf + setCnf mod-$MOD_DIR "$(getVersion $MOD_DIR)" $MOD_DIR/cnf $reinstall + local stock_tag - for repo in $core_dir $html_dir/admin; do - if [ -d $repo ]; then - local stockTag=$(getVersion $repo) - setCnf org-$repo $stockTag $mod_dir/cnf + for repo in $CORE_DIR $HTML_DIR/admin; do + if [[ -d "$repo" ]]; then + stock_tag=$(getVersion "$repo") + setCnf org-"$repo" "$stock_tag" $MOD_DIR/cnf if $backup; then - if [ ! -d $repo.bak ] || [ "$(getVersion $repo.bak)" != "$stockTag" ]; then - rm -rf $repo.bak - mv -f $repo $repo.bak + if [[ ! -d "$repo".bak || "$(getVersion "$repo".bak)" != "$stock_tag" ]]; then + rm -rf "$repo".bak + mv -f "$repo" "$repo".bak fi - rm -rf $repo - mv -f $repo.mod $repo + rm -rf "$repo" + mv -f "$repo".mod "$repo" fi fi done $backup || download /etc .pihole https://github.com/arevindh/pi-hole "$mod_core_ver" master $stable swapScripts - \cp -af $core_dir/advanced/Scripts/speedtestmod/. $opt_dir/speedtestmod/ + \cp -af $CORE_DIR/advanced/Scripts/speedtestmod/. $OPT_DIR/speedtestmod/ pihole -a -s - $backup || download $html_dir admin https://github.com/arevindh/AdminLTE "$mod_admin_ver" master $stable - setCnf mod-$core_dir "$(getVersion $core_dir)" $mod_dir/cnf $reinstall - setCnf mod-$html_dir/admin "$(getVersion $html_dir/admin)" $mod_dir/cnf $reinstall + $backup || download $HTML_DIR admin https://github.com/arevindh/AdminLTE "$mod_admin_ver" master $stable + setCnf mod-$CORE_DIR "$(getVersion $CORE_DIR)" $MOD_DIR/cnf $reinstall + setCnf mod-$HTML_DIR/admin "$(getVersion $HTML_DIR/admin)" $MOD_DIR/cnf $reinstall fi pihole updatechecker - [ -d $working_dir ] && cd $working_dir + pihole -v + popd >/dev/null fi exit 0 } - if [ $EUID != 0 ]; then + if [[ $EUID != 0 ]]; then sudo "$0" "$@" exit $? fi diff --git a/advanced/Scripts/speedtestmod/speedtest.sh b/advanced/Scripts/speedtestmod/speedtest.sh index 8d0c9be25e..77eb06db13 100755 --- a/advanced/Scripts/speedtestmod/speedtest.sh +++ b/advanced/Scripts/speedtestmod/speedtest.sh @@ -1,8 +1,13 @@ #!/bin/bash -start=$(date -u --rfc-3339='seconds') -out=/tmp/speedtest.log -serverid=$(grep 'SPEEDTEST_SERVER' "/etc/pihole/setupVars.conf" | cut -d '=' -f2) -create_table="create table if not exists speedtest ( +# +# The Test Script, Speedtest Mod for Pi-hole Run Supervisor +# Please run this with the --help option for usage information +# +# shellcheck disable=SC2015 +# + +declare -r OUT_FILE=/tmp/speedtest.log +declare -r CREATE_TABLE="create table if not exists speedtest ( id integer primary key autoincrement, start_time text, stop_time text, @@ -15,51 +20,97 @@ download real, upload real, share_url text );" +declare START +declare PKG_MANAGER +declare SERVER_ID +START=$(date -u --rfc-3339='seconds') +PKG_MANAGER=$(command -v apt-get || command -v dnf || command -v yum) +SERVER_ID=$(grep 'SPEEDTEST_SERVER' "/etc/pihole/setupVars.conf" | cut -d '=' -f2) +readonly START PKG_MANAGER SERVER_ID + +# shellcheck disable=SC2034 SKIP_MOD=true +# shellcheck disable=SC1091 source /opt/pihole/speedtestmod/mod.sh +####################################### +# Run the speedtest +# Globals: +# SERVER_ID +# Arguments: +# None +# Returns: +# None +####################################### speedtest() { if grep -q official <<<"$(/usr/bin/speedtest --version)"; then - [[ ! -z "${serverid}" ]] && /usr/bin/speedtest -s $serverid --accept-gdpr --accept-license -f json || /usr/bin/speedtest --accept-gdpr --accept-license -f json + [[ -n "${SERVER_ID}" ]] && /usr/bin/speedtest -s "$SERVER_ID" --accept-gdpr --accept-license -f json || /usr/bin/speedtest --accept-gdpr --accept-license -f json else - [[ ! -z "${serverid}" ]] && /usr/bin/speedtest --server $serverid --json --share --secure || /usr/bin/speedtest --json --share --secure + [[ -n "${SERVER_ID}" ]] && /usr/bin/speedtest --server "$SERVER_ID" --json --share --secure || /usr/bin/speedtest --json --share --secure fi } +####################################### +# Save the results of the speedtest to the database +# Globals: +# OUT_FILE +# CREATE_TABLE +# Arguments: +# $1: Start time +# $2: Stop time +# $3: ISP +# $4: From IP +# $5: Server +# $6: Server Distance +# $7: Server Ping +# $8: Download +# $9: Upload +# $10: Share URL +# Returns: +# None +####################################### savetest() { - local start_time=$1 - local stop_time=$2 - local isp=${3:-"No Internet"} - local from_ip=${4:-"-"} - local server=${5:-"-"} - local server_dist=${6:-0} - local server_ping=${7:-0} - local download=${8:-0} - local upload=${9:-0} - local share_url=${10:-"#"} - local rm_empty=' + local -r start_time=$1 + local -r stop_time=$2 + local -r isp=${3:-"No Internet"} + local -r from_ip=${4:-"-"} + local -r server=${5:-"-"} + local -r server_dist=${6:-0} + local -r server_ping=${7:-0} + local -r download=${8:-0} + local -r upload=${9:-0} + local -r share_url=${10:-"#"} + local -r rm_empty=' def nonempty: . and length > 0 and (type != "object" or . != {}) and (type != "array" or any(.[]; . != "")); if type == "array" then map(walk(if type == "object" then with_entries(select(.value | nonempty)) else . end)) else walk(if type == "object" then with_entries(select(.value | nonempty)) else . end) end ' - local temp_file=$(mktemp) - local json_file="/tmp/speedtest_results" + local -r temp_file=$(mktemp) + local -r json_file="/tmp/speedtest_results" jq "$rm_empty" "$json_file" >"$temp_file" && mv -f "$temp_file" "$json_file" rm -f "$temp_file" chmod 644 /tmp/speedtest_results mv -f /tmp/speedtest_results /var/log/pihole/speedtest.log \cp -af /var/log/pihole/speedtest.log /etc/pihole/speedtest.log - rm -f "$out" - sqlite3 /etc/pihole/speedtest.db "$create_table" + rm -f "$OUT_FILE" + sqlite3 /etc/pihole/speedtest.db "$CREATE_TABLE" sqlite3 /etc/pihole/speedtest.db "insert into speedtest values (NULL, '${start_time}', '${stop_time}', '${isp}', '${from_ip}', '${server}', ${server_dist}, ${server_ping}, ${download}, ${upload}, '${share_url}');" - [ "$isp" == "No Internet" ] && exit 1 || exit 0 + [[ "$isp" == "No Internet" ]] && exit 1 || exit 0 } +####################################### +# Check if the package is available +# Globals: +# PKG_MANAGER +# Arguments: +# $1: Package name +# Returns: +# 0 if available, 1 if not +####################################### isAvailable() { - if [ -x "$(command -v apt-get)" ]; then + if [[ "$PKG_MANAGER" == "/usr/bin/apt-get" ]]; then # Check if there is a candidate and it is not "(none)" apt-cache policy "$1" | grep -q "Candidate:" && ! apt-cache policy "$1" | grep -q "Candidate: (none)" && return 0 || return 1 - elif [ -x "$(command -v dnf)" ] || [ -x "$(command -v yum)" ]; then - local PKG_MANAGER=$(command -v dnf || command -v yum) + elif [[ "$PKG_MANAGER" == "/usr/bin/dnf" || "$PKG_MANAGER" == "/usr/bin/yum" ]]; then $PKG_MANAGER list available "$1" &>/dev/null && return 0 || return 1 else echo "Unsupported package manager!" @@ -67,33 +118,62 @@ isAvailable() { fi } +####################################### +# Change between two conflicting packages +# Globals: +# PKG_MANAGER +# Arguments: +# $1: Package to install +# $2: Package to remove +# Returns: +# None +####################################### swaptest() { - if isAvailable $1; then - [ -x "$(command -v apt-get)" ] && apt-get install -y $1 $2- || { [ -x "$(command -v dnf)" ] && dnf install -y --allowerasing $1 || yum install -y --allowerasing $1; } + if isAvailable "$1"; then + [[ "$PKG_MANAGER" == "/usr/bin/apt-get" ]] && apt-get install -y "$1" "$2"- || { [[ "$PKG_MANAGER" == "/usr/bin/dnf" ]] && dnf install -y --allowerasing "$1" || yum install -y --allowerasing "$1"; } fi } +####################################### +# Check if a package is installed +# Globals: +# PKG_MANAGER +# OUT_FILE +# Arguments: +# $1: The package to check +# Returns: +# 0 if the package is not installed, 1 if it is +####################################### notInstalled() { - if [ -x "$(command -v apt-get)" ]; then + if [[ "$PKG_MANAGER" == "/usr/bin/apt-get" ]]; then dpkg -s "$1" &>/dev/null || return 0 - elif [ -x "$(command -v dnf)" ] || [ -x "$(command -v yum)" ]; then + elif [[ "$PKG_MANAGER" == "/usr/bin/dnf" || "$PKG_MANAGER" == "/usr/bin/yum" ]]; then rpm -q "$1" &>/dev/null || return 0 else echo "Unsupported package manager!" - mv -f "$out" /var/log/pihole/speedtest.log + mv -f "$OUT_FILE" /var/log/pihole/speedtest.log exit 1 fi return 1 } +####################################### +# Download and install librespeed +# Globals: +# PKG_MANAGER +# Arguments: +# None +# Returns: +# None +####################################### librespeed() { if notInstalled golang; then if grep -q "Raspbian" /etc/os-release; then - if [ ! -f /etc/apt/sources.list.d/testing.list ] && ! grep -q "testing" /etc/apt/sources.list; then + if [[ ! -f /etc/apt/sources.list.d/testing.list ]] && ! grep -q "testing" /etc/apt/sources.list; then echo "Adding testing repo to sources.list.d" echo "deb http://archive.raspbian.org/raspbian/ testing main" >/etc/apt/sources.list.d/testing.list - echo "Package: *\nPin: release a=testing\nPin-Priority: 50" >/etc/apt/preferences.d/limit-testing + printf "Package: *\nPin: release a=testing\nPin-Priority: 50" >/etc/apt/preferences.d/limit-testing $PKG_MANAGER update fi @@ -103,34 +183,45 @@ librespeed() { fi fi download /etc/pihole librespeed https://github.com/librespeed/speedtest-cli - cd librespeed - [ ! -d out ] || rm -rf out + cd librespeed || exit + [[ ! -d out ]] || rm -rf out ./build.sh mv -f out/* /usr/bin/speedtest chmod +x /usr/bin/speedtest } +####################################### +# Add the Ookla speedtest CLI source +# Globals: +# PKG_MANAGER +# Arguments: +# None +# Returns: +# None +####################################### addSource() { if [[ "$PKG_MANAGER" == *"yum"* || "$PKG_MANAGER" == *"dnf"* ]]; then - if [ ! -f /etc/yum.repos.d/ookla_speedtest-cli.repo ]; then + if [[ ! -f /etc/yum.repos.d/ookla_speedtest-cli.repo ]]; then echo "Adding speedtest source for RPM..." curl -sSLN https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh | sudo bash fi yum list speedtest | grep -q "Available Packages" && $PKG_MANAGER install -y speedtest || : elif [[ "$PKG_MANAGER" == *"apt-get"* ]]; then - if [ ! -f /etc/apt/sources.list.d/ookla_speedtest-cli.list ]; then + if [[ ! -f /etc/apt/sources.list.d/ookla_speedtest-cli.list ]]; then echo "Adding speedtest source for DEB..." - if [ -e /etc/os-release ]; then - . /etc/os-release - local base="ubuntu debian" + if [[ -e /etc/os-release ]]; then + # shellcheck disable=SC1091 + source /etc/os-release + local -r base="ubuntu debian" local os=${ID} local dist=${VERSION_CODENAME} - if [ ! -z "${ID_LIKE-}" ] && [[ "${base//\"/}" =~ "${ID_LIKE//\"/}" ]] && [ "${os}" != "ubuntu" ]; then + # shellcheck disable=SC2076 + if [[ -n "${ID_LIKE:-}" && "${base//\"/}" =~ "${ID_LIKE//\"/}" && "${os}" != "ubuntu" ]]; then os=${ID_LIKE%% *} - [ -z "${UBUNTU_CODENAME-}" ] && UBUNTU_CODENAME=$(/usr/bin/lsb_release -cs) + [[ -z "${UBUNTU_CODENAME:-}" ]] && UBUNTU_CODENAME=$(/usr/bin/lsb_release -cs) dist=${UBUNTU_CODENAME} - [ -z "$dist" ] && dist=${VERSION_CODENAME} + [[ -z "$dist" ]] && dist=${VERSION_CODENAME} fi wget -O /tmp/script.deb.sh https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh >/dev/null 2>&1 chmod +x /tmp/script.deb.sh @@ -149,53 +240,65 @@ addSource() { fi } +####################################### +# Run the speedtest and save the results +# Globals: +# PKG_MANAGER +# START +# Arguments: +# $1: Number of attempts (optional, 3 by default) +# $2: Current attempt (optional, 0 by default) +# Returns: +# None +####################################### run() { speedtest | jq . >/tmp/speedtest_results || echo "Attempt ${2:-1} Failed!" >/tmp/speedtest_results - local stop=$(date -u --rfc-3339='seconds') + local -r stop=$(date -u --rfc-3339='seconds') if jq -e '.server' /tmp/speedtest_results &>/dev/null; then - local res=$(/dev/null; then # librespeed - local res=$(/tmp/speedtest_results - savetest "$start" "$stop" + savetest "$START" "$stop" else if notInstalled speedtest && notInstalled speedtest-cli; then - [ ! -f /usr/bin/speedtest ] || rm -f /usr/bin/speedtest + [[ ! -f /usr/bin/speedtest ]] || rm -f /usr/bin/speedtest addSource isAvailable speedtest && $PKG_MANAGER install -y speedtest || : elif ! notInstalled speedtest; then @@ -209,21 +312,64 @@ run() { fi } +####################################### +# Display the help message +# Globals: +# None +# Arguments: +# None +# Returns: +# None +####################################### +help() { + echo "Usage: $0 [attempts]" + echo " attempts: Number of attempts to run the speedtest, cycling through the packages (default: 3)" + exit 1 +} + +####################################### +# Main function +# Globals: +# PKG_MANAGER +# Arguments: +# None +# Returns: +# None +####################################### main() { - if [ $EUID != 0 ]; then + local -r short_opts=-h + local -r long_opts=help + local -r parsed_opts=$(getopt --options ${short_opts} --longoptions ${long_opts} --name "$0" -- "$@") + local POSITIONAL=() + local attempts="3" + eval set -- "${parsed_opts}" + + while [[ $# -gt 0 ]]; do + case "$1" in + -h | --help) help ;; + *) POSITIONAL+=("$1") ;; + esac + shift + done + + set -- "${POSITIONAL[@]}" + + if [[ "$1" != "--" ]]; then + [[ "$1" =~ ^[0-9]+$ ]] && attempts="$1" || help + fi + + if [[ $EUID != 0 ]]; then sudo "$0" "$@" exit $? fi - PKG_MANAGER=$(command -v apt-get || command -v dnf || command -v yum) - - if [ ! -f /usr/bin/speedtest ]; then + if [[ ! -f /usr/bin/speedtest ]]; then addSource isAvailable speedtest && $PKG_MANAGER install -y speedtest || { isAvailable speedtest-cli && $PKG_MANAGER install -y speedtest-cli || librespeed; } fi echo "Running Test..." - run $1 # Number of attempts + run $attempts } -main ${1:-3} >"$out" +main "$@" >"$OUT_FILE" diff --git a/advanced/Scripts/updatecheck.sh b/advanced/Scripts/updatecheck.sh index 04fd7deab1..d886e4acb5 100755 --- a/advanced/Scripts/updatecheck.sh +++ b/advanced/Scripts/updatecheck.sh @@ -11,28 +11,32 @@ function get_local_branch() { # Return active branch cd "${1}" 2> /dev/null || return 1 - local foundBranch=$(git status --porcelain=2 -b | grep branch.head | awk '{print $3;}') + local foundBranch + foundBranch=$(git status --porcelain=2 -b | grep branch.head | awk '{print $3;}') echo "${foundBranch:-HEAD}" } function get_local_version() { # Return active version cd "${1}" 2> /dev/null || return 1 - local tags=$(git ls-remote -t origin) - local foundVersion=$(git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}' | cut -c1-8) + local tags + local foundVersion + tags=$(git ls-remote -t origin) + foundVersion=$(git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}') local foundTag=$foundVersion + # shellcheck disable=SC2015 grep -q "^$foundVersion" <<<"$tags" && foundTag=$(grep "^$foundVersion.*/v[0-9].*$" <<<"$tags" | awk '{print $2;}' | cut -d '/' -f 3 | sort -V | tail -n1) || : - [ -z "${foundTag}" ] || foundVersion="${foundTag}" + [[ -z "${foundTag}" ]] || foundVersion="${foundTag}" echo "${foundVersion}" } function get_local_hash() { cd "${1}" 2> /dev/null || return 1 - git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}' | cut -c1-8 || return 1 + git status --porcelain=2 -b | grep branch.oid | awk '{print $3;}' || return 1 } function get_remote_version() { - if [ "${1}" == "docker-pi-hole" ] || [ "${1}" == "FTL" ]; then + if [[ "${1}" == "docker-pi-hole" || "${1}" == "FTL" ]]; then curl -s "https://api.github.com/repos/pi-hole/${1}/releases/latest" 2> /dev/null | jq --raw-output .tag_name || return 1 else curl -s "https://api.github.com/repos/arevindh/${1}/releases/latest" 2> /dev/null | jq --raw-output .tag_name || { curl -s "https://api.github.com/repos/pi-hole/${1}/releases/latest" 2> /dev/null | jq --raw-output .tag_name || return 1; } @@ -43,11 +47,11 @@ function get_remote_hash(){ local foundHash="" for repo in "arevindh" "pi-hole" "ipitio"; do - foundHash=$(git ls-remote "https://github.com/${repo}/${1}" --tags "${2}" | awk '{print $1;}' | cut -c1-8 2> /dev/null) - [ -n "${foundHash}" ] && break + foundHash=$(git ls-remote "https://github.com/${repo}/${1}" --tags "${2}" | awk '{print $1;}' 2> /dev/null) + [[ -n "${foundHash}" ]] && break done - [ ! -z "${foundHash}" ] && echo "${foundHash}" || return 1 + [[ -n "${foundHash}" ]] && echo "${foundHash}" || return 1 } # Source the setupvars config file diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index 97db21c8dc..b63bc6fd8f 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -24,7 +24,6 @@ readonly gravityDBfile="/etc/pihole/gravity.db" # speedtest mod readonly speedtestmod="/opt/pihole/speedtestmod/mod.sh" readonly speedtestfile="/opt/pihole/speedtestmod/speedtest.sh" -readonly speedtestdb="/etc/pihole/speedtest.db" readonly setupVars="/etc/pihole/setupVars.conf" readonly PI_HOLE_BIN_DIR="/usr/local/bin" @@ -438,7 +437,7 @@ ProcessDHCPSettings() { interface="${PIHOLE_INTERFACE}" # Use eth0 as fallback interface - if [ -z ${interface} ]; then + if [ -z "${interface}" ]; then interface="eth0" fi @@ -548,44 +547,52 @@ SetWebUILayout() { generate_systemd_calendar() { local interval_hours="$1" - local total_seconds=$(echo "$interval_hours * 3600" | bc) + local total_seconds + total_seconds=$(echo "$interval_hours * 3600" | bc) local freq_entries=() - if (( $(echo "$total_seconds < 60" | bc -l) )); then # less than a minute + if (($(echo "$total_seconds < 60" | bc -l))); then # less than a minute total_seconds=60 addOrEditKeyValPair "${setupVars}" "SPEEDTESTSCHEDULE" "0.017" fi - if (( $(echo "$total_seconds >= 60 && $total_seconds < 3600" | bc -l) )); then # less than an hour - local minute_interval=$(echo "$total_seconds / 60" | bc) + if (($(echo "$total_seconds >= 60 && $total_seconds < 3600" | bc -l))); then # less than an hour + local minute_interval + minute_interval=$(echo "$total_seconds / 60" | bc) freq_entries+=("*-*-* *:00/$minute_interval:00") - elif (( $(echo "$total_seconds == 3600" | bc -l) )); then # exactly an hour + elif (($(echo "$total_seconds == 3600" | bc -l))); then # exactly an hour freq_entries+=("*-*-* *:00:00") - elif (( $(echo "$total_seconds < 86400" | bc -l) )); then # less than a day - if (( $(awk "BEGIN {print ($total_seconds / 3600) % 1}") == 0 )); then # divides evenly into an hour - local hour_interval=$(echo "$total_seconds / 3600" | bc) + elif (($(echo "$total_seconds < 86400" | bc -l))); then # less than a day + if (($(awk "BEGIN {print ($total_seconds / 3600) % 1}") == 0)); then # divides evenly into an hour + local hour_interval + hour_interval=$(echo "$total_seconds / 3600" | bc) freq_entries+=("*-*-* 00/$hour_interval:00:00") else # does not divide evenly into an hour local current_second=0 - while (( $(echo "$current_second < 86400" | bc -l) )); do - local hour=$(echo "$current_second / 3600" | bc) - local minute=$(awk "BEGIN {print ($current_second % 3600) / 60}") + while (($(echo "$current_second < 86400" | bc -l))); do + local hour + hour=$(echo "$current_second / 3600" | bc) + local minute + minute=$(awk "BEGIN {print ($current_second % 3600) / 60}") hour=${hour%.*} minute=${minute%.*} - freq_entries+=("*-*-* $(printf "%02d:%02d:00" $hour $minute)") + freq_entries+=("*-*-* $(printf "%02d:%02d:00" "$hour" "$minute")") current_second=$(echo "$current_second + $total_seconds" | bc) done fi else # more than a day - local full_days=$(echo "$interval_hours / 24" | bc) - local remaining_hours=$(echo "$interval_hours - ($full_days * 24)" | bc) - if (( $(echo "$full_days > 0" | bc -l) )); then - freq_entries+=("*-*-1/$(printf "%02.0f" $full_days)") + local full_days + full_days=$(echo "$interval_hours / 24" | bc) + local remaining_hours + remaining_hours=$(echo "$interval_hours - ($full_days * 24)" | bc) + if (($(echo "$full_days > 0" | bc -l))); then + freq_entries+=("*-*-1/$(printf "%02.0f" "$full_days")") fi - if (( $(echo "$remaining_hours > 0" | bc -l) )); then # partial day - local remaining_minutes=$(echo "($remaining_hours - ($remaining_hours / 1)) * 60" | bc) + if (($(echo "$remaining_hours > 0" | bc -l))); then # partial day + local remaining_minutes + remaining_minutes=$(echo "($remaining_hours - ($remaining_hours / 1)) * 60" | bc) remaining_hours=${remaining_hours%.*} remaining_minutes=${remaining_minutes%.*} - freq_entries+=("*-*-* $(printf "%02d:%02d:00" $remaining_hours $remaining_minutes)") + freq_entries+=("*-*-* $(printf "%02d:%02d:00" "$remaining_hours" "$remaining_minutes")") fi fi @@ -597,14 +604,15 @@ generate_cron_schedule() { local total_seconds="nan" local schedule_script="/opt/pihole/speedtestmod/schedule_check.sh" - if [[ "$1" != "nan" ]] && [[ "$1" =~ ^([0-9]+(\.[0-9]*)?|\.[0-9]+)$ ]] && (( $(echo "$1 > 0" | bc -l) )); then + if [[ "$1" != "nan" ]] && [[ "$1" =~ ^([0-9]+(\.[0-9]*)?|\.[0-9]+)$ ]] && (($(echo "$1 > 0" | bc -l))); then total_seconds=$(echo "$1 * 3600" | bc) - if (( $(echo "$total_seconds < 60" | bc -l) )); then + if (($(echo "$total_seconds < 60" | bc -l))); then total_seconds=60 fi - local remainder=$(awk "BEGIN {print $total_seconds % 60}") - if (( $(echo "$remainder < 30" | bc -l) )); then + local remainder + remainder=$(awk "BEGIN {print $total_seconds % 60}") + if (($(echo "$remainder < 30" | bc -l))); then total_seconds=$(echo "$total_seconds - $remainder" | bc -l) else total_seconds=$(echo "$total_seconds + (60 - $remainder)" | bc -l) @@ -613,50 +621,58 @@ generate_cron_schedule() { fi [ -d /opt/pihole/speedtestmod ] || return - sudo bash -c "cat > $(printf %q "$schedule_script")" << EOF + sudo bash -c "cat > $(printf %q "$schedule_script")" < 0" | bc -l) )) || exit 0 -if [[ -f "\$last_run_file" ]]; then - last_run=\$(cat "\$last_run_file") +if [[ -f "\$LAST_RUN_FILE" ]]; then + declare last_run + last_run=\$(<"\$LAST_RUN_FILE") current_time=\$(date +%s) - if (( \$(echo "\$current_time - \$last_run < \$interval_seconds" | bc -l) )); then - exit 0 - fi + (( \$(echo "\$current_time - \$last_run >= \$INTERVAL_SECONDS" | bc -l) )) || exit 0 fi -echo \$(date +%s) > "\$last_run_file" -cat $speedtestfile | sudo bash +[[ \$(/usr/bin/tmux list-sessions 2>/dev/null | grep -c pimodtest) -eq 0 ]] || exit 0 +echo "\$current_time" > "\$LAST_RUN_FILE" +/usr/bin/tmux new-session -d -s pimodtest "sudo bash $speedtestfile" EOF sudo chmod +x "$schedule_script" crontab -l 2>/dev/null | grep -v "$schedule_script" | crontab - - if [[ "$total_seconds" == "nan" ]] || (( $(echo "$total_seconds > 0" | bc -l) )); then - crontab -l &> /dev/null || crontab -l 2>/dev/null | { cat; echo ""; } | crontab - - (crontab -l; echo "* * * * * /bin/bash $schedule_script") | crontab - + if [[ "$total_seconds" == "nan" ]] || (($(echo "$total_seconds > 0" | bc -l))); then + crontab -l &>/dev/null || crontab -l 2>/dev/null | { + cat + echo "" + } | crontab - + ( + crontab -l + echo "* * * * * /bin/bash $schedule_script" + ) | crontab - fi } ChangeSpeedTestSchedule() { local interval="${args[2]%\.}" if [[ "${interval-}" =~ ^-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$ ]]; then - if (( $(echo "$interval < 0" | bc -l) )); then + if (($(echo "$interval < 0" | bc -l))); then interval="0" else addOrEditKeyValPair "${setupVars}" "SPEEDTESTSCHEDULE" "$interval" @@ -671,9 +687,10 @@ ChangeSpeedTestSchedule() { if [[ ! -d /run/systemd/system ]]; then generate_cron_schedule "$interval" elif [[ "$interval" == "0" ]] || [[ "$interval" == "nan" ]]; then - systemctl disable --now pihole-speedtest.timer &> /dev/null + systemctl disable --now pihole-speedtest.timer &>/dev/null else - local freq=$(generate_systemd_calendar "$interval") + local freq + freq=$(generate_systemd_calendar "$interval") sudo bash -c 'cat > /etc/systemd/system/pihole-speedtest.service << EOF [Unit] Description=Pi-hole Speedtest @@ -699,10 +716,10 @@ Persistent=true EOF' while IFS= read -r line; do sudo bash -c "echo 'OnCalendar=$line' >> /etc/systemd/system/pihole-speedtest.timer" - done <<< "$freq" + done <<<"$freq" systemctl daemon-reload - systemctl reenable pihole-speedtest.timer &> /dev/null + systemctl reenable pihole-speedtest.timer &>/dev/null systemctl restart pihole-speedtest.timer fi } @@ -733,25 +750,35 @@ SpeedtestServer() { } RunSpeedtestNow() { - if [[ $(tmux list-sessions 2>/dev/null | grep -c pimod) -eq 0 ]]; then - tmux new-session -d -s pimod "cat $speedtestfile | sudo bash" - fi + # if there is a running session, wait for it to finish + # if the session is still running after 5 minutes, kill it + while [[ $(tmux list-sessions 2>/dev/null | grep -c pimodtest) -gt 0 ]]; do + sleep 1 + ((counter++)) + + if [[ $counter -gt 300 ]]; then + tmux kill-session -t pimodtest + break + fi + done + + tmux new-session -d -s pimodtest "sudo bash $speedtestfile" } ReinstallSpeedTest() { - tmux new-session -d -s pimod "cat $speedtestmod | sudo bash" + tmux new-session -d -s pimod "sudo bash $speedtestmod" } UpdateSpeedTest() { - tmux new-session -d -s pimod "cat $speedtestmod | sudo bash -s -- up ${args[2]} ${args[3]}" + tmux new-session -d -s pimod "sudo bash $speedtestmod up ${args[2]} ${args[3]}" } UninstallSpeedTest() { - tmux new-session -d -s pimod "cat $speedtestmod | sudo bash -s -- un ${args[2]}" + tmux new-session -d -s pimod "sudo bash $speedtestmod un ${args[2]}" } ClearSpeedtestData() { - tmux new-session -d -s pimod "cat $speedtestmod | sudo bash -s -- db" + tmux new-session -d -s pimod "sudo bash $speedtestmod db" } SetWebUITheme() { From 3379ac89f1d0074a17dcb88b54cf7073ccee47c4 Mon Sep 17 00:00:00 2001 From: ipitio <21136719+ipitio@users.noreply.github.com> Date: Thu, 25 Apr 2024 23:33:49 -0400 Subject: [PATCH 2/5] there were no quotes here --- advanced/Scripts/webpage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index b63bc6fd8f..da508ba0b8 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -437,7 +437,7 @@ ProcessDHCPSettings() { interface="${PIHOLE_INTERFACE}" # Use eth0 as fallback interface - if [ -z "${interface}" ]; then + if [ -z ${interface} ]; then interface="eth0" fi From b2dda166c7ea95718809e4013161ab3a45890eef Mon Sep 17 00:00:00 2001 From: ipitio <21136719+ipitio@users.noreply.github.com> Date: Fri, 26 Apr 2024 21:51:25 -0400 Subject: [PATCH 3/5] update package cache only if needed --- advanced/Scripts/speedtestmod/mod.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/speedtestmod/mod.sh b/advanced/Scripts/speedtestmod/mod.sh index 8d23ae955c..ae7439e799 100755 --- a/advanced/Scripts/speedtestmod/mod.sh +++ b/advanced/Scripts/speedtestmod/mod.sh @@ -574,8 +574,12 @@ if [[ "${SKIP_MOD:-}" != true ]]; then readonly missingpkgs if [[ ${#missingpkgs[@]} -gt 0 ]]; then - [[ "$pkg_manager" != *"apt-get"* ]] || apt-get update >/dev/null - echo "Installing Missing..." + if [[ "$pkg_manager" == *"apt-get"* ]] && apt-cache show "${missingpkgs[@]}" | grep -q "Unable to locate package"; then + echo "Updating Package Cache..." + apt-get update -y &>/dev/null + fi + + echo "Installing Missing Dependencies..." $pkg_manager install -y "${missingpkgs[@]}" &>/dev/null # hide an unimportant warning in docker fi fi From 51911f47c17b59cfa2ae3fad0239e46055865836 Mon Sep 17 00:00:00 2001 From: ipitio <21136719+ipitio@users.noreply.github.com> Date: Sat, 27 Apr 2024 00:01:58 -0400 Subject: [PATCH 4/5] try using local tags --- advanced/Scripts/speedtestmod/mod.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/Scripts/speedtestmod/mod.sh b/advanced/Scripts/speedtestmod/mod.sh index ae7439e799..dbd72ed516 100755 --- a/advanced/Scripts/speedtestmod/mod.sh +++ b/advanced/Scripts/speedtestmod/mod.sh @@ -26,7 +26,7 @@ getVersion() { if [[ -z "${2:-}" ]]; then local tags local found_tag=$found_version - tags=$(git ls-remote -t origin) + tags=$(git ls-remote -t origin || git tag -l) ! grep -q "$found_version" <<<"$tags" || found_tag=$(grep "$found_version" <<<"$tags" | awk '{print $2;}' | cut -d '/' -f 3 | sort -V | tail -n1) [[ -z "$found_tag" ]] || found_version=$found_tag fi From 3d9d498746a9f3d83cf3c49e8dd0a2d4cc694df7 Mon Sep 17 00:00:00 2001 From: ipitio <21136719+ipitio@users.noreply.github.com> Date: Sat, 27 Apr 2024 00:08:11 -0400 Subject: [PATCH 5/5] use show-ref --- advanced/Scripts/speedtestmod/mod.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced/Scripts/speedtestmod/mod.sh b/advanced/Scripts/speedtestmod/mod.sh index dbd72ed516..403814cd27 100755 --- a/advanced/Scripts/speedtestmod/mod.sh +++ b/advanced/Scripts/speedtestmod/mod.sh @@ -26,7 +26,7 @@ getVersion() { if [[ -z "${2:-}" ]]; then local tags local found_tag=$found_version - tags=$(git ls-remote -t origin || git tag -l) + tags=$(git ls-remote -t origin || git show-ref --tags) ! grep -q "$found_version" <<<"$tags" || found_tag=$(grep "$found_version" <<<"$tags" | awk '{print $2;}' | cut -d '/' -f 3 | sort -V | tail -n1) [[ -z "$found_tag" ]] || found_version=$found_tag fi @@ -102,7 +102,7 @@ download() { local current_hash local tags current_hash=$(getVersion "$dest" hash) - tags=$(git ls-remote -t origin) + tags=$(git ls-remote -t origin || git show-ref --tags) if [[ -z "$desired_version" ]]; then # if empty, get the latest version local latest_tag=""