This is all whitespace changes - the result of pressing alt+shift+f on all bash scripts. Utilising the vscode extension shell-format

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
This commit is contained in:
Adam Warner 2025-02-28 21:56:32 +00:00
parent 821c953216
commit c1936a52b8
No known key found for this signature in database
11 changed files with 468 additions and 419 deletions

View file

@ -10,14 +10,12 @@
# This file is copyright under the latest version of the EUPL. # This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
# The basic usage steps are # The basic usage steps are
# 1) Test Availability of the API # 1) Test Availability of the API
# 2) Try to authenticate (read password if needed) # 2) Try to authenticate (read password if needed)
# 3) Get the data from the API endpoint # 3) Get the data from the API endpoint
# 4) Delete the session # 4) Delete the session
TestAPIAvailability() { TestAPIAvailability() {
# as we are running locally, we can get the port value from FTL directly # as we are running locally, we can get the port value from FTL directly
@ -115,14 +113,13 @@ LoginAPI() {
echo "API Authentication: CLI password not available" echo "API Authentication: CLI password not available"
fi fi
# If this did not work, ask the user for the password # If this did not work, ask the user for the password
while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do while [ "${validSession}" = false ] || [ -z "${validSession}" ]; do
echo "Authentication failed. Please enter your Pi-hole password" echo "Authentication failed. Please enter your Pi-hole password"
# secretly read the password # secretly read the password
secretRead; printf '\n' secretRead
printf '\n'
# Try to authenticate again # Try to authenticate again
Authentication "${1}" Authentication "${1}"
@ -131,23 +128,23 @@ LoginAPI() {
} }
Authentication() { Authentication() {
sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "Pi-hole cli " --data "{\"password\":\"${password}\"}" )" sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "Pi-hole cli " --data "{\"password\":\"${password}\"}")"
if [ -z "${sessionResponse}" ]; then if [ -z "${sessionResponse}" ]; then
echo "No response from FTL server. Please check connectivity" echo "No response from FTL server. Please check connectivity"
exit 1 exit 1
fi fi
# obtain validity and session ID from session response # obtain validity and session ID from session response
validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) validSession=$(echo "${sessionResponse}" | jq .session.valid 2>/dev/null)
SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) SID=$(echo "${sessionResponse}" | jq --raw-output .session.sid 2>/dev/null)
if [ "${1}" = "verbose" ]; then if [ "${1}" = "verbose" ]; then
if [ "${validSession}" = true ]; then if [ "${validSession}" = true ]; then
echo "API Authentication: ${COL_GREEN}Success${COL_NC}" echo "API Authentication: ${COL_GREEN}Success${COL_NC}"
else else
echo "API Authentication: ${COL_RED}Failed${COL_NC}" echo "API Authentication: ${COL_RED}Failed${COL_NC}"
fi
fi fi
fi
} }
LogoutAPI() { LogoutAPI() {
@ -155,56 +152,56 @@ LogoutAPI() {
# SID is not null (successful Authentication only), delete the session # SID is not null (successful Authentication only), delete the session
if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then if [ "${validSession}" = true ] && [ ! "${SID}" = null ]; then
# Try to delete the session. Omit the output, but get the http status code # Try to delete the session. Omit the output, but get the http status code
deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}") deleteResponse=$(curl -skS -o /dev/null -w "%{http_code}" -X DELETE "${API_URL}auth" -H "Accept: application/json" -H "sid: ${SID}")
case "${deleteResponse}" in case "${deleteResponse}" in
"401") echo "Logout attempt without a valid session. Unauthorized!";; "401") echo "Logout attempt without a valid session. Unauthorized!" ;;
"204") if [ "${1}" = "verbose" ]; then echo "API Logout: ${COL_GREEN}Success${COL_NC} (session deleted)"; fi;; "204") if [ "${1}" = "verbose" ]; then echo "API Logout: ${COL_GREEN}Success${COL_NC} (session deleted)"; fi ;;
esac; esac
elif [ "${1}" = "verbose" ]; then elif [ "${1}" = "verbose" ]; then
echo "API Logout: ${COL_GREEN}Success${COL_NC} (no valid session)" echo "API Logout: ${COL_GREEN}Success${COL_NC} (no valid session)"
fi fi
} }
GetFTLData() { GetFTLData() {
local data response status local data response status
# get the data from querying the API as well as the http status code # get the data from querying the API as well as the http status code
response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}")
if [ "${2}" = "raw" ]; then if [ "${2}" = "raw" ]; then
# return the raw response # return the raw response
echo "${response}" echo "${response}"
else
# status are the last 3 characters
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses
status=$(printf "%s" "${response}" | tail -c 3)
# data is everything from response without the last 3 characters
data="${response%???}"
# return only the data
if [ "${status}" = 200 ]; then
# response OK
echo "${data}"
else else
# connection lost
echo "${status}" # status are the last 3 characters
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses
status=$(printf "%s" "${response}" | tail -c 3)
# data is everything from response without the last 3 characters
data="${response%???}"
# return only the data
if [ "${status}" = 200 ]; then
# response OK
echo "${data}"
else
# connection lost
echo "${status}"
fi
fi fi
fi
} }
PostFTLData() { PostFTLData() {
local data response status local data response status
# send the data to the API # send the data to the API
response=$(curl -skS -w "%{http_code}" -X POST "${API_URL}$1" --data-raw "$2" -H "Accept: application/json" -H "sid: ${SID}" ) response=$(curl -skS -w "%{http_code}" -X POST "${API_URL}$1" --data-raw "$2" -H "Accept: application/json" -H "sid: ${SID}")
# data is everything from response without the last 3 characters # data is everything from response without the last 3 characters
if [ "${3}" = "status" ]; then if [ "${3}" = "status" ]; then
# Keep the status code appended if requested # Keep the status code appended if requested
printf %s "${response}" printf %s "${response}"
else else
# Strip the status code # Strip the status code
printf %s "${response%???}" printf %s "${response%???}"
fi fi
} }
secretRead() { secretRead() {
@ -216,18 +213,16 @@ secretRead() {
# `-s` option (suppressing the input) or # `-s` option (suppressing the input) or
# `-n` option (reading n chars) # `-n` option (reading n chars)
# This workaround changes the terminal characteristics to not echo input and later resets this option # This workaround changes the terminal characteristics to not echo input and later resets this option
# credits https://stackoverflow.com/a/4316765 # credits https://stackoverflow.com/a/4316765
# showing asterisk instead of password # showing asterisk instead of password
# https://stackoverflow.com/a/24600839 # https://stackoverflow.com/a/24600839
# https://unix.stackexchange.com/a/464963 # https://unix.stackexchange.com/a/464963
# Save current terminal settings (needed for later restore after password prompt) # Save current terminal settings (needed for later restore after password prompt)
stty_orig=$(stty -g) stty_orig=$(stty -g)
stty -echo # do not echo user input stty -echo # do not echo user input
stty -icanon min 1 time 0 # disable canonical mode https://man7.org/linux/man-pages/man3/termios.3.html stty -icanon min 1 time 0 # disable canonical mode https://man7.org/linux/man-pages/man3/termios.3.html
unset password unset password
@ -235,20 +230,20 @@ secretRead() {
unset charcount unset charcount
charcount=0 charcount=0
while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input while key=$(dd ibs=1 count=1 2>/dev/null); do #read one byte of input
if [ "${key}" = "$(printf '\0' | tr -d '\0')" ] ; then if [ "${key}" = "$(printf '\0' | tr -d '\0')" ]; then
# Enter - accept password # Enter - accept password
break break
fi fi
if [ "${key}" = "$(printf '\177')" ] ; then if [ "${key}" = "$(printf '\177')" ]; then
# Backspace # Backspace
if [ $charcount -gt 0 ] ; then if [ $charcount -gt 0 ]; then
charcount=$((charcount-1)) charcount=$((charcount - 1))
printf '\b \b' printf '\b \b'
password="${password%?}" password="${password%?}"
fi fi
else else
# any other character # any other character
charcount=$((charcount+1)) charcount=$((charcount + 1))
printf '*' printf '*'
password="$password$key" password="$password$key"
fi fi
@ -259,41 +254,41 @@ secretRead() {
} }
apiFunc() { apiFunc() {
local data response status status_col local data response status status_col
# Authenticate with the API # Authenticate with the API
LoginAPI verbose LoginAPI verbose
echo "" echo ""
echo "Requesting: ${COL_PURPLE}GET ${COL_CYAN}${API_URL}${COL_YELLOW}$1${COL_NC}" echo "Requesting: ${COL_PURPLE}GET ${COL_CYAN}${API_URL}${COL_YELLOW}$1${COL_NC}"
echo "" echo ""
# Get the data from the API # Get the data from the API
response=$(GetFTLData "$1" raw) response=$(GetFTLData "$1" raw)
# status are the last 3 characters # status are the last 3 characters
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses # not using ${response#"${response%???}"}" here because it's extremely slow on big responses
status=$(printf "%s" "${response}" | tail -c 3) status=$(printf "%s" "${response}" | tail -c 3)
# data is everything from response without the last 3 characters # data is everything from response without the last 3 characters
data="${response%???}" data="${response%???}"
# Output the status (200 -> green, else red) # Output the status (200 -> green, else red)
if [ "${status}" = 200 ]; then if [ "${status}" = 200 ]; then
status_col="${COL_GREEN}" status_col="${COL_GREEN}"
else else
status_col="${COL_RED}" status_col="${COL_RED}"
fi fi
echo "Status: ${status_col}${status}${COL_NC}" echo "Status: ${status_col}${status}${COL_NC}"
# Output the data. Format it with jq if available and data is actually JSON. # Output the data. Format it with jq if available and data is actually JSON.
# Otherwise just print it # Otherwise just print it
echo "Data:" echo "Data:"
if command -v jq >/dev/null && echo "${data}" | jq . >/dev/null 2>&1; then if command -v jq >/dev/null && echo "${data}" | jq . >/dev/null 2>&1; then
echo "${data}" | jq . echo "${data}" | jq .
else else
echo "${data}" echo "${data}"
fi fi
# Delete the session # Delete the session
LogoutAPI verbose LogoutAPI verbose
} }

View file

@ -12,7 +12,7 @@
readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity" readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity"
upgrade_gravityDB(){ upgrade_gravityDB() {
local database piholeDir version local database piholeDir version
database="${1}" database="${1}"
piholeDir="${2}" piholeDir="${2}"
@ -29,7 +29,7 @@ upgrade_gravityDB(){
# This migration script upgraded the gravity.db file by # This migration script upgraded the gravity.db file by
# adding the domain_audit table. It is now a no-op # adding the domain_audit table. It is now a no-op
echo -e " ${INFO} Upgrading gravity database from version 1 to 2" echo -e " ${INFO} Upgrading gravity database from version 1 to 2"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/1_to_2.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/1_to_2.sql"
version=2 version=2
fi fi
if [[ "$version" == "2" ]]; then if [[ "$version" == "2" ]]; then
@ -37,28 +37,28 @@ upgrade_gravityDB(){
# renaming the regex table to regex_blacklist, and # renaming the regex table to regex_blacklist, and
# creating a new regex_whitelist table + corresponding linking table and views # creating a new regex_whitelist table + corresponding linking table and views
echo -e " ${INFO} Upgrading gravity database from version 2 to 3" echo -e " ${INFO} Upgrading gravity database from version 2 to 3"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/2_to_3.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/2_to_3.sql"
version=3 version=3
fi fi
if [[ "$version" == "3" ]]; then if [[ "$version" == "3" ]]; then
# This migration script unifies the formally separated domain # This migration script unifies the formally separated domain
# lists into a single table with a UNIQUE domain constraint # lists into a single table with a UNIQUE domain constraint
echo -e " ${INFO} Upgrading gravity database from version 3 to 4" echo -e " ${INFO} Upgrading gravity database from version 3 to 4"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/3_to_4.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/3_to_4.sql"
version=4 version=4
fi fi
if [[ "$version" == "4" ]]; then if [[ "$version" == "4" ]]; then
# This migration script upgrades the gravity and list views # This migration script upgrades the gravity and list views
# implementing necessary changes for per-client blocking # implementing necessary changes for per-client blocking
echo -e " ${INFO} Upgrading gravity database from version 4 to 5" echo -e " ${INFO} Upgrading gravity database from version 4 to 5"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/4_to_5.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/4_to_5.sql"
version=5 version=5
fi fi
if [[ "$version" == "5" ]]; then if [[ "$version" == "5" ]]; then
# This migration script upgrades the adlist view # This migration script upgrades the adlist view
# to return an ID used in gravity.sh # to return an ID used in gravity.sh
echo -e " ${INFO} Upgrading gravity database from version 5 to 6" echo -e " ${INFO} Upgrading gravity database from version 5 to 6"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/5_to_6.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/5_to_6.sql"
version=6 version=6
fi fi
if [[ "$version" == "6" ]]; then if [[ "$version" == "6" ]]; then
@ -66,7 +66,7 @@ upgrade_gravityDB(){
# which is automatically associated to all clients not # which is automatically associated to all clients not
# having their own group assignments # having their own group assignments
echo -e " ${INFO} Upgrading gravity database from version 6 to 7" echo -e " ${INFO} Upgrading gravity database from version 6 to 7"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/6_to_7.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/6_to_7.sql"
version=7 version=7
fi fi
if [[ "$version" == "7" ]]; then if [[ "$version" == "7" ]]; then
@ -74,21 +74,21 @@ upgrade_gravityDB(){
# to ensure uniqueness on the group name # to ensure uniqueness on the group name
# We also add date_added and date_modified columns # We also add date_added and date_modified columns
echo -e " ${INFO} Upgrading gravity database from version 7 to 8" echo -e " ${INFO} Upgrading gravity database from version 7 to 8"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/7_to_8.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/7_to_8.sql"
version=8 version=8
fi fi
if [[ "$version" == "8" ]]; then if [[ "$version" == "8" ]]; then
# This migration fixes some issues that were introduced # This migration fixes some issues that were introduced
# in the previous migration script. # in the previous migration script.
echo -e " ${INFO} Upgrading gravity database from version 8 to 9" echo -e " ${INFO} Upgrading gravity database from version 8 to 9"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/8_to_9.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/8_to_9.sql"
version=9 version=9
fi fi
if [[ "$version" == "9" ]]; then if [[ "$version" == "9" ]]; then
# This migration drops unused tables and creates triggers to remove # This migration drops unused tables and creates triggers to remove
# obsolete groups assignments when the linked items are deleted # obsolete groups assignments when the linked items are deleted
echo -e " ${INFO} Upgrading gravity database from version 9 to 10" echo -e " ${INFO} Upgrading gravity database from version 9 to 10"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/9_to_10.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/9_to_10.sql"
version=10 version=10
fi fi
if [[ "$version" == "10" ]]; then if [[ "$version" == "10" ]]; then
@ -98,57 +98,57 @@ upgrade_gravityDB(){
# to keep the copying process generic (needs the same columns in both the # to keep the copying process generic (needs the same columns in both the
# source and the destination databases). # source and the destination databases).
echo -e " ${INFO} Upgrading gravity database from version 10 to 11" echo -e " ${INFO} Upgrading gravity database from version 10 to 11"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/10_to_11.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/10_to_11.sql"
version=11 version=11
fi fi
if [[ "$version" == "11" ]]; then if [[ "$version" == "11" ]]; then
# Rename group 0 from "Unassociated" to "Default" # Rename group 0 from "Unassociated" to "Default"
echo -e " ${INFO} Upgrading gravity database from version 11 to 12" echo -e " ${INFO} Upgrading gravity database from version 11 to 12"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/11_to_12.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/11_to_12.sql"
version=12 version=12
fi fi
if [[ "$version" == "12" ]]; then if [[ "$version" == "12" ]]; then
# Add column date_updated to adlist table # Add column date_updated to adlist table
echo -e " ${INFO} Upgrading gravity database from version 12 to 13" echo -e " ${INFO} Upgrading gravity database from version 12 to 13"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/12_to_13.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/12_to_13.sql"
version=13 version=13
fi fi
if [[ "$version" == "13" ]]; then if [[ "$version" == "13" ]]; then
# Add columns number and status to adlist table # Add columns number and status to adlist table
echo -e " ${INFO} Upgrading gravity database from version 13 to 14" echo -e " ${INFO} Upgrading gravity database from version 13 to 14"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/13_to_14.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/13_to_14.sql"
version=14 version=14
fi fi
if [[ "$version" == "14" ]]; then if [[ "$version" == "14" ]]; then
# Changes the vw_adlist created in 5_to_6 # Changes the vw_adlist created in 5_to_6
echo -e " ${INFO} Upgrading gravity database from version 14 to 15" echo -e " ${INFO} Upgrading gravity database from version 14 to 15"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/14_to_15.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/14_to_15.sql"
version=15 version=15
fi fi
if [[ "$version" == "15" ]]; then if [[ "$version" == "15" ]]; then
# Add column abp_entries to adlist table # Add column abp_entries to adlist table
echo -e " ${INFO} Upgrading gravity database from version 15 to 16" echo -e " ${INFO} Upgrading gravity database from version 15 to 16"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/15_to_16.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/15_to_16.sql"
version=16 version=16
fi fi
if [[ "$version" == "16" ]]; then if [[ "$version" == "16" ]]; then
# Add antigravity table # Add antigravity table
# Add column type to adlist table (to support adlist types) # Add column type to adlist table (to support adlist types)
echo -e " ${INFO} Upgrading gravity database from version 16 to 17" echo -e " ${INFO} Upgrading gravity database from version 16 to 17"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/16_to_17.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/16_to_17.sql"
version=17 version=17
fi fi
if [[ "$version" == "17" ]]; then if [[ "$version" == "17" ]]; then
# Add adlist.id to vw_gravity and vw_antigravity # Add adlist.id to vw_gravity and vw_antigravity
echo -e " ${INFO} Upgrading gravity database from version 17 to 18" echo -e " ${INFO} Upgrading gravity database from version 17 to 18"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/17_to_18.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/17_to_18.sql"
version=18 version=18
fi fi
if [[ "$version" == "18" ]]; then if [[ "$version" == "18" ]]; then
# Modify DELETE triggers to delete BEFORE instead of AFTER to prevent # Modify DELETE triggers to delete BEFORE instead of AFTER to prevent
# foreign key constraint violations # foreign key constraint violations
echo -e " ${INFO} Upgrading gravity database from version 18 to 19" echo -e " ${INFO} Upgrading gravity database from version 18 to 19"
pihole-FTL sqlite3 -ni "${database}" < "${scriptPath}/18_to_19.sql" pihole-FTL sqlite3 -ni "${database}" <"${scriptPath}/18_to_19.sql"
version=19 version=19
fi fi
} }

View file

@ -53,7 +53,7 @@ Options:
-l, --list Display domains -l, --list Display domains
--comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all" --comment \"text\" Add a comment to the domain. If adding multiple domains the same comment will be used for all"
exit 0 exit 0
} }
CreateDomainList() { CreateDomainList() {
@ -89,7 +89,7 @@ AddDomain() {
num=$(echo "${data}" | jq '.processed.success | length') num=$(echo "${data}" | jq '.processed.success | length')
if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then
echo -e " ${TICK} Added ${num} domain(s):" echo -e " ${TICK} Added ${num} domain(s):"
for i in $(seq 0 $((num-1))); do for i in $(seq 0 $((num - 1))); do
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.success[$i].item")${COL_NC}" echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.success[$i].item")${COL_NC}"
done done
fi fi
@ -98,7 +98,7 @@ AddDomain() {
num=$(echo "${data}" | jq '.processed.errors | length') num=$(echo "${data}" | jq '.processed.errors | length')
if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then if [[ "${num}" -gt 0 ]] && [[ "${verbose}" == true ]]; then
echo -e " ${CROSS} Failed to add ${num} domain(s):" echo -e " ${CROSS} Failed to add ${num} domain(s):"
for i in $(seq 0 $((num-1))); do for i in $(seq 0 $((num - 1))); do
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.errors[$i].item")${COL_NC}" echo -e " - ${COL_BLUE}$(echo "${data}" | jq --raw-output ".processed.errors[$i].item")${COL_NC}"
error=$(echo "${data}" | jq --raw-output ".processed.errors[$i].error") error=$(echo "${data}" | jq --raw-output ".processed.errors[$i].error")
if [[ "${error}" == "UNIQUE constraint failed: domainlist.domain, domainlist.type" ]]; then if [[ "${error}" == "UNIQUE constraint failed: domainlist.domain, domainlist.type" ]]; then
@ -137,10 +137,10 @@ RemoveDomain() {
# If there is an .error object in the returned data, display it # If there is an .error object in the returned data, display it
local error local error
error=$(jq --compact-output <<< "${data}" '.error') error=$(jq --compact-output '.error' <<<"${data}")
if [[ $error != "null" && $error != "" ]]; then if [[ $error != "null" && $error != "" ]]; then
echo -e " ${CROSS} Failed to remove domain(s):" echo -e " ${CROSS} Failed to remove domain(s):"
echo -e " $(jq <<< "${data}" '.error')" echo -e " $(jq <<<"${data}" '.error')"
elif [[ "${verbose}" == true && "${status}" == "204" ]]; then elif [[ "${verbose}" == true && "${status}" == "204" ]]; then
echo -e " ${TICK} Domain(s) removed from the ${kindId} ${typeId}list" echo -e " ${TICK} Domain(s) removed from the ${kindId} ${typeId}list"
elif [[ "${verbose}" == true && "${status}" == "404" ]]; then elif [[ "${verbose}" == true && "${status}" == "404" ]]; then
@ -170,7 +170,7 @@ Displaylist() {
num=$(echo "${data}" | jq '.domains | length') num=$(echo "${data}" | jq '.domains | length')
if [[ "${num}" -gt 0 ]]; then if [[ "${num}" -gt 0 ]]; then
echo -e " ${TICK} Found ${num} domain(s) in the ${kindId} ${typeId}list:" echo -e " ${TICK} Found ${num} domain(s) in the ${kindId} ${typeId}list:"
for i in $(seq 0 $((num-1))); do for i in $(seq 0 $((num - 1))); do
echo -e " - ${COL_BLUE}$(echo "${data}" | jq --compact-output ".domains[$i].domain")${COL_NC}" echo -e " - ${COL_BLUE}$(echo "${data}" | jq --compact-output ".domains[$i].domain")${COL_NC}"
echo -e " Comment: $(echo "${data}" | jq --compact-output ".domains[$i].comment")" echo -e " Comment: $(echo "${data}" | jq --compact-output ".domains[$i].comment")"
echo -e " Groups: $(echo "${data}" | jq --compact-output ".domains[$i].groups")" echo -e " Groups: $(echo "${data}" | jq --compact-output ".domains[$i].groups")"
@ -196,20 +196,49 @@ GetComment() {
fi fi
} }
while (( "$#" )); do while (("$#")); do
case "${1}" in case "${1}" in
"allow" | "allowlist" ) kindId="exact"; typeId="allow"; abbrv="allow";; "allow" | "allowlist")
"deny" | "denylist" ) kindId="exact"; typeId="deny"; abbrv="deny";; kindId="exact"
"--allow-regex" | "allow-regex" ) kindId="regex"; typeId="allow"; abbrv="--allow-regex";; typeId="allow"
"--allow-wild" | "allow-wild" ) kindId="regex"; typeId="allow"; wildcard=true; abbrv="--allow-wild";; abbrv="allow"
"--regex" | "regex" ) kindId="regex"; typeId="deny"; abbrv="--regex";; ;;
"--wild" | "wildcard" ) kindId="regex"; typeId="deny"; wildcard=true; abbrv="--wild";; "deny" | "denylist")
"-d" | "remove" | "delete" ) addmode=false;; kindId="exact"
"-q" | "--quiet" ) verbose=false;; typeId="deny"
"-h" | "--help" ) helpFunc;; abbrv="deny"
"-l" | "--list" ) Displaylist;; ;;
"--comment" ) GetComment "${2}"; shift;; "--allow-regex" | "allow-regex")
* ) CreateDomainList "${1}";; kindId="regex"
typeId="allow"
abbrv="--allow-regex"
;;
"--allow-wild" | "allow-wild")
kindId="regex"
typeId="allow"
wildcard=true
abbrv="--allow-wild"
;;
"--regex" | "regex")
kindId="regex"
typeId="deny"
abbrv="--regex"
;;
"--wild" | "wildcard")
kindId="regex"
typeId="deny"
wildcard=true
abbrv="--wild"
;;
"-d" | "remove" | "delete") addmode=false ;;
"-q" | "--quiet") verbose=false ;;
"-h" | "--help") helpFunc ;;
"-l" | "--list") Displaylist ;;
"--comment")
GetComment "${2}"
shift
;;
*) CreateDomainList "${1}" ;;
esac esac
shift shift
done done

View file

@ -25,7 +25,7 @@ if [ -z "$DBFILE" ]; then
DBFILE="/etc/pihole/pihole-FTL.db" DBFILE="/etc/pihole/pihole-FTL.db"
fi fi
flushARP(){ flushARP() {
local output local output
if [[ "${args[1]}" != "quiet" ]]; then if [[ "${args[1]}" != "quiet" ]]; then
echo -ne " ${INFO} Flushing network table ..." echo -ne " ${INFO} Flushing network table ..."
@ -78,5 +78,5 @@ flushARP(){
args=("$@") args=("$@")
case "${args[0]}" in case "${args[0]}" in
"arpflush" ) flushARP;; "arpflush") flushARP ;;
esac esac

View file

@ -28,14 +28,14 @@ warning1() {
echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}" echo -e " ${COL_LIGHT_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
read -r -p " Have you read and understood this? [y/N] " response read -r -p " Have you read and understood this? [y/N] " response
case "${response}" in case "${response}" in
[yY][eE][sS]|[yY]) [yY][eE][sS] | [yY])
echo "" echo ""
return 0 return 0
;; ;;
*) *)
echo -e "\\n ${INFO} Branch change has been canceled" echo -e "\\n ${INFO} Branch change has been canceled"
return 1 return 1
;; ;;
esac esac
} }
@ -53,16 +53,16 @@ checkout() {
set -f set -f
# This is unlikely # This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then if ! is_repo "${PI_HOLE_FILES_DIR}"; then
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!" echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1; exit 1
fi fi
if ! is_repo "${webInterfaceDir}" ; then if ! is_repo "${webInterfaceDir}"; then
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!" echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1; exit 1
fi fi
if [[ -z "${1}" ]]; then if [[ -z "${1}" ]]; then
@ -71,41 +71,53 @@ checkout() {
exit 1 exit 1
fi fi
if ! warning1 ; then if ! warning1; then
exit 1 exit 1
fi fi
if [[ "${1}" == "dev" ]] ; then if [[ "${1}" == "dev" ]]; then
# Shortcut to check out development branches # Shortcut to check out development branches
echo -e " ${INFO} Shortcut \"${COL_YELLOW}dev${COL_NC}\" detected - checking out development branches..." echo -e " ${INFO} Shortcut \"${COL_YELLOW}dev${COL_NC}\" detected - checking out development branches..."
echo "" echo ""
echo -e " ${INFO} Pi-hole Core" echo -e " ${INFO} Pi-hole Core"
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core development branch"; exit 1; } fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || {
echo " ${CROSS} Unable to pull Core development branch"
exit 1
}
echo "" echo ""
echo -e " ${INFO} Web interface" echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "development" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; } fetch_checkout_pull_branch "${webInterfaceDir}" "development" || {
echo " ${CROSS} Unable to pull Web development branch"
exit 1
}
#echo -e " ${TICK} Pi-hole Core" #echo -e " ${TICK} Pi-hole Core"
local path local path
path="development/${binary}" path="development/${binary}"
echo "development" > /etc/pihole/ftlbranch echo "development" >/etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch chmod 644 /etc/pihole/ftlbranch
elif [[ "${1}" == "master" ]] ; then elif [[ "${1}" == "master" ]]; then
# Shortcut to check out master branches # Shortcut to check out master branches
echo -e " ${INFO} Shortcut \"${COL_YELLOW}master${COL_NC}\" detected - checking out master branches..." echo -e " ${INFO} Shortcut \"${COL_YELLOW}master${COL_NC}\" detected - checking out master branches..."
echo -e " ${INFO} Pi-hole core" echo -e " ${INFO} Pi-hole core"
fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo " ${CROSS} Unable to pull Core master branch"; exit 1; } fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || {
echo " ${CROSS} Unable to pull Core master branch"
exit 1
}
echo -e " ${INFO} Web interface" echo -e " ${INFO} Web interface"
fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; } fetch_checkout_pull_branch "${webInterfaceDir}" "master" || {
echo " ${CROSS} Unable to pull Web master branch"
exit 1
}
#echo -e " ${TICK} Web Interface" #echo -e " ${TICK} Web Interface"
local path local path
path="master/${binary}" path="master/${binary}"
echo "master" > /etc/pihole/ftlbranch echo "master" >/etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch chmod 644 /etc/pihole/ftlbranch
elif [[ "${1}" == "core" ]] ; then elif [[ "${1}" == "core" ]]; then
str="Fetching branches from ${piholeGitUrl}" str="Fetching branches from ${piholeGitUrl}"
echo -ne " ${INFO} $str" echo -ne " ${INFO} $str"
if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}"; then
echo -e "${OVER} ${CROSS} $str" echo -e "${OVER} ${CROSS} $str"
exit 1 exit 1
fi fi
@ -129,10 +141,10 @@ checkout() {
exit 1 exit 1
fi fi
checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}" checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
elif [[ "${1}" == "web" ]] ; then elif [[ "${1}" == "web" ]]; then
str="Fetching branches from ${webInterfaceGitUrl}" str="Fetching branches from ${webInterfaceGitUrl}"
echo -ne " ${INFO} $str" echo -ne " ${INFO} $str"
if ! fully_fetch_repo "${webInterfaceDir}" ; then if ! fully_fetch_repo "${webInterfaceDir}"; then
echo -e "${OVER} ${CROSS} $str" echo -e "${OVER} ${CROSS} $str"
exit 1 exit 1
fi fi
@ -158,7 +170,7 @@ checkout() {
checkout_pull_branch "${webInterfaceDir}" "${2}" checkout_pull_branch "${webInterfaceDir}" "${2}"
# Update local and remote versions via updatechecker # Update local and remote versions via updatechecker
/opt/pihole/updatecheck.sh /opt/pihole/updatecheck.sh
elif [[ "${1}" == "ftl" ]] ; then elif [[ "${1}" == "ftl" ]]; then
local path local path
local oldbranch local oldbranch
local existing=false local existing=false
@ -167,7 +179,7 @@ checkout() {
# Check if requested branch is available # Check if requested branch is available
echo -e " ${INFO} Checking for availability of branch ${COL_CYAN}${2}${COL_NC} on GitHub" echo -e " ${INFO} Checking for availability of branch ${COL_CYAN}${2}${COL_NC} on GitHub"
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -) ) ftlbranches=($(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -))
# If returned array is empty -> connectivity issue # If returned array is empty -> connectivity issue
if [[ ${#ftlbranches[@]} -eq 0 ]]; then if [[ ${#ftlbranches[@]} -eq 0 ]]; then
echo -e " ${CROSS} Unable to fetch branches from GitHub. Please check your Internet connection and try again later." echo -e " ${CROSS} Unable to fetch branches from GitHub. Please check your Internet connection and try again later."
@ -187,7 +199,7 @@ checkout() {
if check_download_exists "$path"; then if check_download_exists "$path"; then
echo " ${TICK} Binary exists" echo " ${TICK} Binary exists"
echo "${2}" > /etc/pihole/ftlbranch echo "${2}" >/etc/pihole/ftlbranch
chmod 644 /etc/pihole/ftlbranch chmod 644 /etc/pihole/ftlbranch
echo -e " ${INFO} Switching to branch: ${COL_CYAN}${2}${COL_NC} from ${COL_CYAN}${oldbranch}${COL_NC}" echo -e " ${INFO} Switching to branch: ${COL_CYAN}${2}${COL_NC} from ${COL_CYAN}${oldbranch}${COL_NC}"
FTLinstall "${binary}" FTLinstall "${binary}"
@ -198,7 +210,7 @@ checkout() {
# Wait until name resolution is working again after restarting FTL, # Wait until name resolution is working again after restarting FTL,
# so that the updatechecker can run successfully and does not fail # so that the updatechecker can run successfully and does not fail
# trying to resolve github.com # trying to resolve github.com
until getent hosts github.com &> /dev/null; do until getent hosts github.com &>/dev/null; do
# Append one dot for each second waiting # Append one dot for each second waiting
str="${str}." str="${str}."
echo -ne " ${OVER} ${INFO} ${str}" echo -ne " ${OVER} ${INFO} ${str}"
@ -230,7 +242,7 @@ checkout() {
fi fi
# Force updating everything # Force updating everything
if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
echo -e " ${INFO} Running installer to upgrade your installation" echo -e " ${INFO} Running installer to upgrade your installation"
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
exit 0 exit 0

View file

@ -106,27 +106,27 @@ RESOLVCONF="${ETC}/resolv.conf"
DNSMASQ_CONF="${ETC}/dnsmasq.conf" DNSMASQ_CONF="${ETC}/dnsmasq.conf"
# Store Pi-hole's processes in an array for easy use and parsing # Store Pi-hole's processes in an array for easy use and parsing
PIHOLE_PROCESSES=( "pihole-FTL" ) PIHOLE_PROCESSES=("pihole-FTL")
# Store the required directories in an array so it can be parsed through # Store the required directories in an array so it can be parsed through
REQUIRED_FILES=("${PIHOLE_CRON_FILE}" REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
"${PIHOLE_INSTALL_LOG_FILE}" "${PIHOLE_INSTALL_LOG_FILE}"
"${PIHOLE_RAW_BLOCKLIST_FILES}" "${PIHOLE_RAW_BLOCKLIST_FILES}"
"${PIHOLE_LOCAL_HOSTS_FILE}" "${PIHOLE_LOCAL_HOSTS_FILE}"
"${PIHOLE_LOGROTATE_FILE}" "${PIHOLE_LOGROTATE_FILE}"
"${PIHOLE_FTL_CONF_FILE}" "${PIHOLE_FTL_CONF_FILE}"
"${PIHOLE_DNSMASQ_CONF_FILE}" "${PIHOLE_DNSMASQ_CONF_FILE}"
"${PIHOLE_COMMAND}" "${PIHOLE_COMMAND}"
"${PIHOLE_COLTABLE_FILE}" "${PIHOLE_COLTABLE_FILE}"
"${FTL_PID}" "${FTL_PID}"
"${PIHOLE_LOG}" "${PIHOLE_LOG}"
"${PIHOLE_LOG_GZIPS}" "${PIHOLE_LOG_GZIPS}"
"${PIHOLE_DEBUG_LOG}" "${PIHOLE_DEBUG_LOG}"
"${PIHOLE_FTL_LOG}" "${PIHOLE_FTL_LOG}"
"${PIHOLE_WEBSERVER_LOG}" "${PIHOLE_WEBSERVER_LOG}"
"${RESOLVCONF}" "${RESOLVCONF}"
"${DNSMASQ_CONF}" "${DNSMASQ_CONF}"
"${PIHOLE_VERSIONS_FILE}") "${PIHOLE_VERSIONS_FILE}")
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net. DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
@ -135,7 +135,7 @@ The intent of this script is to allow users to self-diagnose their installations
NOTE: All log files auto-delete after 48 hours and ONLY the Pi-hole developers can access your data via the given token. We have taken these extra steps to secure your data and will work to further reduce any personal information gathered. NOTE: All log files auto-delete after 48 hours and ONLY the Pi-hole developers can access your data via the given token. We have taken these extra steps to secure your data and will work to further reduce any personal information gathered.
" "
show_disclaimer(){ show_disclaimer() {
log_write "${DISCLAIMER}" log_write "${DISCLAIMER}"
} }
@ -158,7 +158,7 @@ log_write() {
copy_to_debug_log() { copy_to_debug_log() {
# Copy the contents of file descriptor 3 into the debug log # Copy the contents of file descriptor 3 into the debug log
cat /proc/$$/fd/3 > "${PIHOLE_DEBUG_LOG}" cat /proc/$$/fd/3 >"${PIHOLE_DEBUG_LOG}"
} }
initialize_debug() { initialize_debug() {
@ -196,16 +196,16 @@ compare_local_version_to_git_version() {
# If the pihole git directory exists, # If the pihole git directory exists,
if [[ -d "${git_dir}" ]]; then if [[ -d "${git_dir}" ]]; then
# move into it # move into it
cd "${git_dir}" || \ cd "${git_dir}" ||
# If not, show an error # If not, show an error
log_write "${COL_RED}Could not cd into ${git_dir}$COL_NC" log_write "${COL_RED}Could not cd into ${git_dir}$COL_NC"
if git status &> /dev/null; then if git status &>/dev/null; then
# The current version the user is on # The current version the user is on
local local_version local local_version
local_version=$(git describe --tags --abbrev=0 2> /dev/null); local_version=$(git describe --tags --abbrev=0 2>/dev/null)
# What branch they are on # What branch they are on
local local_branch local local_branch
local_branch=$(git rev-parse --abbrev-ref HEAD); local_branch=$(git rev-parse --abbrev-ref HEAD)
# The commit they are on # The commit they are on
local local_commit local local_commit
local_commit=$(git describe --long --dirty --tags --always) local_commit=$(git describe --long --dirty --tags --always)
@ -214,11 +214,11 @@ compare_local_version_to_git_version() {
local_status=$(git status -s) local_status=$(git status -s)
# echo this information out to the user in a nice format # echo this information out to the user in a nice format
if [ ${local_version} ]; then if [ ${local_version} ]; then
log_write "${TICK} Version: ${local_version}" log_write "${TICK} Version: ${local_version}"
elif [ -n "${DOCKER_VERSION}" ]; then elif [ -n "${DOCKER_VERSION}" ]; then
log_write "${TICK} Version: Pi-hole Docker Container ${COL_BOLD}${DOCKER_VERSION}${COL_NC}" log_write "${TICK} Version: Pi-hole Docker Container ${COL_BOLD}${DOCKER_VERSION}${COL_NC}"
else else
log_write "${CROSS} Version: not detected" log_write "${CROSS} Version: not detected"
fi fi
# Print the repo upstreams # Print the repo upstreams
@ -238,13 +238,13 @@ compare_local_version_to_git_version() {
log_write "${INFO} Commit: ${local_commit}" log_write "${INFO} Commit: ${local_commit}"
# if `local_status` is non-null, then the repo is not clean, display details here # if `local_status` is non-null, then the repo is not clean, display details here
if [[ ${local_status} ]]; then if [[ ${local_status} ]]; then
# Replace new lines in the status with 12 spaces to make the output cleaner # Replace new lines in the status with 12 spaces to make the output cleaner
log_write "${INFO} Status: ${local_status//$'\n'/'\n '}" log_write "${INFO} Status: ${local_status//$'\n'/'\n '}"
local local_diff local local_diff
local_diff=$(git diff) local_diff=$(git diff)
if [[ ${local_diff} ]]; then if [[ ${local_diff} ]]; then
log_write "${INFO} Diff: ${local_diff//$'\n'/'\n '}" log_write "${INFO} Diff: ${local_diff//$'\n'/'\n '}"
fi fi
fi fi
# If git status failed, # If git status failed,
else else
@ -269,7 +269,6 @@ check_ftl_version() {
FTL_BRANCH=$(pihole-FTL branch) FTL_BRANCH=$(pihole-FTL branch)
FTL_COMMIT=$(pihole-FTL --hash) FTL_COMMIT=$(pihole-FTL --hash)
log_write "${TICK} Version: ${FTL_VERSION}" log_write "${TICK} Version: ${FTL_VERSION}"
# If they use the master branch, they are on the stable codebase # If they use the master branch, they are on the stable codebase
@ -305,7 +304,10 @@ os_check() {
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"') detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"') detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
cmdResult="$(dig -4 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)" cmdResult="$(
dig -4 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1
echo $?
)"
#Get the return code of the previous command (last line) #Get the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}" digReturnCode="${cmdResult##*$'\n'}"
@ -319,7 +321,10 @@ os_check() {
log_write "${CROSS} dig response: ${response}" log_write "${CROSS} dig response: ${response}"
log_write "${INFO} Retrying via IPv6" log_write "${INFO} Retrying via IPv6"
cmdResult="$(dig -6 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)" cmdResult="$(
dig -6 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1
echo $?
)"
#Get the return code of the previous command (last line) #Get the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}" digReturnCode="${cmdResult##*$'\n'}"
@ -333,16 +338,14 @@ os_check() {
log_write "${CROSS} Error: ${COL_RED}dig command failed - Unable to check OS${COL_NC}" log_write "${CROSS} Error: ${COL_RED}dig command failed - Unable to check OS${COL_NC}"
else else
IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"') IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"')
for distro_and_versions in "${supportedOS[@]}" for distro_and_versions in "${supportedOS[@]}"; do
do
distro_part="${distro_and_versions%%=*}" distro_part="${distro_and_versions%%=*}"
versions_part="${distro_and_versions##*=}" versions_part="${distro_and_versions##*=}"
if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then
valid_os=true valid_os=true
IFS="," read -r -a supportedVer <<<"${versions_part}" IFS="," read -r -a supportedVer <<<"${versions_part}"
for version in "${supportedVer[@]}" for version in "${supportedVer[@]}"; do
do
if [[ "${detected_version}" =~ $version ]]; then if [[ "${detected_version}" =~ $version ]]; then
valid_version=true valid_version=true
break break
@ -388,7 +391,7 @@ diagnose_operating_system() {
[ -n "${DOCKER_VERSION}" ] && log_write "${INFO} Pi-hole Docker Container: ${DOCKER_VERSION}" [ -n "${DOCKER_VERSION}" ] && log_write "${INFO} Pi-hole Docker Container: ${DOCKER_VERSION}"
# If there is a /etc/*release file, it's probably a supported operating system, so we can # If there is a /etc/*release file, it's probably a supported operating system, so we can
if ls /etc/*release 1> /dev/null 2>&1; then if ls /etc/*release 1>/dev/null 2>&1; then
# display the attributes to the user from the function made earlier # display the attributes to the user from the function made earlier
os_check os_check
else else
@ -405,25 +408,25 @@ check_selinux() {
# If a SELinux configuration file was found, check the default SELinux mode. # If a SELinux configuration file was found, check the default SELinux mode.
DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config) DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
case "${DEFAULT_SELINUX,,}" in case "${DEFAULT_SELINUX,,}" in
enforcing) enforcing)
log_write "${CROSS} ${COL_RED}Default SELinux: $DEFAULT_SELINUX${COL_NC}" log_write "${CROSS} ${COL_RED}Default SELinux: $DEFAULT_SELINUX${COL_NC}"
;; ;;
*) # 'permissive' and 'disabled' *) # 'permissive' and 'disabled'
log_write "${TICK} ${COL_GREEN}Default SELinux: $DEFAULT_SELINUX${COL_NC}"; log_write "${TICK} ${COL_GREEN}Default SELinux: $DEFAULT_SELINUX${COL_NC}"
;; ;;
esac esac
# Check the current state of SELinux # Check the current state of SELinux
CURRENT_SELINUX=$(getenforce) CURRENT_SELINUX=$(getenforce)
case "${CURRENT_SELINUX,,}" in case "${CURRENT_SELINUX,,}" in
enforcing) enforcing)
log_write "${CROSS} ${COL_RED}Current SELinux: $CURRENT_SELINUX${COL_NC}" log_write "${CROSS} ${COL_RED}Current SELinux: $CURRENT_SELINUX${COL_NC}"
;; ;;
*) # 'permissive' and 'disabled' *) # 'permissive' and 'disabled'
log_write "${TICK} ${COL_GREEN}Current SELinux: $CURRENT_SELINUX${COL_NC}"; log_write "${TICK} ${COL_GREEN}Current SELinux: $CURRENT_SELINUX${COL_NC}"
;; ;;
esac esac
else else
log_write "${INFO} ${COL_GREEN}SELinux not detected${COL_NC}"; log_write "${INFO} ${COL_GREEN}SELinux not detected${COL_NC}"
fi fi
} }
@ -432,11 +435,11 @@ check_firewalld() {
# FirewallD is not configured by the installer and is the responsibility of the user # FirewallD is not configured by the installer and is the responsibility of the user
echo_current_diagnostic "FirewallD" echo_current_diagnostic "FirewallD"
# Check if FirewallD service is enabled # Check if FirewallD service is enabled
if command -v systemctl &> /dev/null; then if command -v systemctl &>/dev/null; then
# get its status via systemctl # get its status via systemctl
local firewalld_status local firewalld_status
firewalld_status=$(systemctl is-active firewalld) firewalld_status=$(systemctl is-active firewalld)
log_write "${INFO} ${COL_GREEN}Firewalld service ${firewalld_status}${COL_NC}"; log_write "${INFO} ${COL_GREEN}Firewalld service ${firewalld_status}${COL_NC}"
if [ "${firewalld_status}" == "active" ]; then if [ "${firewalld_status}" == "active" ]; then
# test common required service ports # test common required service ports
local firewalld_enabled_services local firewalld_enabled_services
@ -444,7 +447,7 @@ check_firewalld() {
local firewalld_expected_services=("http" "dns" "dhcp" "dhcpv6") local firewalld_expected_services=("http" "dns" "dhcp" "dhcpv6")
for i in "${firewalld_expected_services[@]}"; do for i in "${firewalld_expected_services[@]}"; do
if [[ "${firewalld_enabled_services}" =~ ${i} ]]; then if [[ "${firewalld_enabled_services}" =~ ${i} ]]; then
log_write "${TICK} ${COL_GREEN} Allow Service: ${i}${COL_NC}"; log_write "${TICK} ${COL_GREEN} Allow Service: ${i}${COL_NC}"
else else
log_write "${CROSS} ${COL_RED} Allow Service: ${i}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})" log_write "${CROSS} ${COL_RED} Allow Service: ${i}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi fi
@ -453,12 +456,12 @@ check_firewalld() {
local firewalld_zones local firewalld_zones
firewalld_zones=$(firewall-cmd --get-zones) firewalld_zones=$(firewall-cmd --get-zones)
if [[ "${firewalld_zones}" =~ "ftl" ]]; then if [[ "${firewalld_zones}" =~ "ftl" ]]; then
log_write "${TICK} ${COL_GREEN}FTL Custom Zone Detected${COL_NC}"; log_write "${TICK} ${COL_GREEN}FTL Custom Zone Detected${COL_NC}"
# check FTL custom zone interface: lo # check FTL custom zone interface: lo
local firewalld_ftl_zone_interfaces local firewalld_ftl_zone_interfaces
firewalld_ftl_zone_interfaces=$(firewall-cmd --zone=ftl --list-interfaces) firewalld_ftl_zone_interfaces=$(firewall-cmd --zone=ftl --list-interfaces)
if [[ "${firewalld_ftl_zone_interfaces}" =~ "lo" ]]; then if [[ "${firewalld_ftl_zone_interfaces}" =~ "lo" ]]; then
log_write "${TICK} ${COL_GREEN} Local Interface Detected${COL_NC}"; log_write "${TICK} ${COL_GREEN} Local Interface Detected${COL_NC}"
else else
log_write "${CROSS} ${COL_RED} Local Interface Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})" log_write "${CROSS} ${COL_RED} Local Interface Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi fi
@ -466,7 +469,7 @@ check_firewalld() {
local firewalld_ftl_zone_ports local firewalld_ftl_zone_ports
firewalld_ftl_zone_ports=$(firewall-cmd --zone=ftl --list-ports) firewalld_ftl_zone_ports=$(firewall-cmd --zone=ftl --list-ports)
if [[ "${firewalld_ftl_zone_ports}" =~ "4711/tcp" ]]; then if [[ "${firewalld_ftl_zone_ports}" =~ "4711/tcp" ]]; then
log_write "${TICK} ${COL_GREEN} FTL Port 4711/tcp Detected${COL_NC}"; log_write "${TICK} ${COL_GREEN} FTL Port 4711/tcp Detected${COL_NC}"
else else
log_write "${CROSS} ${COL_RED} FTL Port 4711/tcp Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})" log_write "${CROSS} ${COL_RED} FTL Port 4711/tcp Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi fi
@ -475,7 +478,7 @@ check_firewalld() {
fi fi
fi fi
else else
log_write "${TICK} ${COL_GREEN}Firewalld service not detected${COL_NC}"; log_write "${TICK} ${COL_GREEN}Firewalld service not detected${COL_NC}"
fi fi
} }
@ -534,9 +537,9 @@ disk_usage() {
# only show those lines not containing a sensitive phrase # only show those lines not containing a sensitive phrase
for line in "${file_system[@]}"; do for line in "${file_system[@]}"; do
if [[ ! $line =~ $hide ]]; then if [[ ! $line =~ $hide ]]; then
log_write " ${line}" log_write " ${line}"
fi fi
done done
} }
@ -574,7 +577,7 @@ ping_gateway() {
log_write "${INFO} Default IPv${protocol} gateway(s):" log_write "${INFO} Default IPv${protocol} gateway(s):"
while IFS= read -r gateway; do while IFS= read -r gateway; do
log_write " $(cut -d ' ' -f 3 <<< "${gateway}")%$(cut -d ' ' -f 5 <<< "${gateway}")" log_write " $(cut -d ' ' -f 3 <<<"${gateway}")%$(cut -d ' ' -f 5 <<<"${gateway}")"
done < <(ip -"${protocol}" route | grep default) done < <(ip -"${protocol}" route | grep default)
gateway_addr=$(ip -"${protocol}" route | grep default | cut -d ' ' -f 3 | head -n 1) gateway_addr=$(ip -"${protocol}" route | grep default | cut -d ' ' -f 3 | head -n 1)
@ -652,8 +655,8 @@ check_required_ports() {
ports_in_use=() ports_in_use=()
# Sort the addresses and remove duplicates # Sort the addresses and remove duplicates
while IFS= read -r line; do while IFS= read -r line; do
ports_in_use+=( "$line" ) ports_in_use+=("$line")
done < <( ss --listening --numeric --tcp --udp --processes --no-header ) done < <(ss --listening --numeric --tcp --udp --processes --no-header)
local ports_configured local ports_configured
# Get all configured ports # Get all configured ports
@ -676,10 +679,10 @@ check_required_ports() {
# Check if the right services are using the right ports # Check if the right services are using the right ports
if [[ ${ports_configured[*]} =~ $(echo "${port_number}" | rev | cut -d: -f1 | rev) ]]; then if [[ ${ports_configured[*]} =~ $(echo "${port_number}" | rev | cut -d: -f1 | rev) ]]; then
compare_port_to_service_assigned "${ftl}" "${service_name}" "${protocol_type}:${port_number}" compare_port_to_service_assigned "${ftl}" "${service_name}" "${protocol_type}:${port_number}"
else else
# If it's not a default port that Pi-hole needs, just print it out for the user to see # If it's not a default port that Pi-hole needs, just print it out for the user to see
log_write " ${protocol_type}:${port_number} is in use by ${service_name:=<unknown>}"; log_write " ${protocol_type}:${port_number} is in use by ${service_name:=<unknown>}"
fi fi
done done
} }
@ -775,7 +778,7 @@ dig_at() {
# Removes everything after the interface name # Removes everything after the interface name
interfaces="$(ip link show | sed "/ master /d;/UP/!d;s/^[0-9]*: //g;s/@.*//g;s/: <.*//g;")" interfaces="$(ip link show | sed "/ master /d;/UP/!d;s/^[0-9]*: //g;s/@.*//g;s/: <.*//g;")"
while IFS= read -r iface ; do while IFS= read -r iface; do
# Get addresses of current interface # Get addresses of current interface
# sed logic breakdown: # sed logic breakdown:
# /inet(|6) /!d; # /inet(|6) /!d;
@ -786,13 +789,13 @@ dig_at() {
# Removes CIDR and everything thereafter (e.g., scope properties) # Removes CIDR and everything thereafter (e.g., scope properties)
addresses="$(ip address show dev "${iface}" | sed "/${sed_selector} /!d;s/^.*${sed_selector} //g;s/\/.*$//g;")" addresses="$(ip address show dev "${iface}" | sed "/${sed_selector} /!d;s/^.*${sed_selector} //g;s/\/.*$//g;")"
if [ -n "${addresses}" ]; then if [ -n "${addresses}" ]; then
while IFS= read -r local_address ; do while IFS= read -r local_address; do
# If ${local_address} is an IPv6 link-local address, append the interface name to it # If ${local_address} is an IPv6 link-local address, append the interface name to it
if [[ "${local_address}" =~ ^fe80 ]]; then if [[ "${local_address}" =~ ^fe80 ]]; then
local_address="${local_address}%${iface}" local_address="${local_address}%${iface}"
fi fi
# Check if Pi-hole can use itself to block a domain # Check if Pi-hole can use itself to block a domain
if local_dig="$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${local_address}" "${record_type}")"; then if local_dig="$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${local_address}" "${record_type}")"; then
# If it can, show success # If it can, show success
if [[ "${local_dig}" == *"status: NOERROR"* ]]; then if [[ "${local_dig}" == *"status: NOERROR"* ]]; then
@ -809,11 +812,11 @@ dig_at() {
# Otherwise, show a failure # Otherwise, show a failure
log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} on ${COL_RED}${iface}${COL_NC} (${COL_RED}${local_address}${COL_NC})" log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} on ${COL_RED}${iface}${COL_NC} (${COL_RED}${local_address}${COL_NC})"
fi fi
done <<< "${addresses}" done <<<"${addresses}"
else else
log_write "${TICK} No IPv${protocol} address available on ${COL_CYAN}${iface}${COL_NC}" log_write "${TICK} No IPv${protocol} address available on ${COL_CYAN}${iface}${COL_NC}"
fi fi
done <<< "${interfaces}" done <<<"${interfaces}"
# Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server # Finally, we need to make sure legitimate queries can out to the Internet using an external, public DNS server
# We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6 # We are using the static remote_url here instead of a random one because we know it works with IPv4 and IPv6
@ -826,7 +829,7 @@ dig_at() {
fi fi
} }
process_status(){ process_status() {
# Check to make sure Pi-hole's services are running and active # Check to make sure Pi-hole's services are running and active
echo_current_diagnostic "Pi-hole processes" echo_current_diagnostic "Pi-hole processes"
@ -838,7 +841,7 @@ process_status(){
local status_of_process local status_of_process
# If systemd # If systemd
if command -v systemctl &> /dev/null; then if command -v systemctl &>/dev/null; then
# get its status via systemctl # get its status via systemctl
status_of_process=$(systemctl is-active "${i}") status_of_process=$(systemctl is-active "${i}")
else else
@ -848,8 +851,8 @@ process_status(){
if [ -n "${DOCKER_VERSION}" ]; then if [ -n "${DOCKER_VERSION}" ]; then
: :
else else
# non-Docker system # non-Docker system
if service "${i}" status | grep -E 'is\srunning' &> /dev/null; then if service "${i}" status | grep -E 'is\srunning' &>/dev/null; then
status_of_process="active" status_of_process="active"
else else
status_of_process="inactive" status_of_process="inactive"
@ -871,17 +874,17 @@ process_status(){
done done
} }
ftl_full_status(){ ftl_full_status() {
# if using systemd print the full status of pihole-FTL # if using systemd print the full status of pihole-FTL
echo_current_diagnostic "Pi-hole-FTL full status" echo_current_diagnostic "Pi-hole-FTL full status"
local FTL_status local FTL_status
if command -v systemctl &> /dev/null; then if command -v systemctl &>/dev/null; then
FTL_status=$(systemctl status --full --no-pager pihole-FTL.service) FTL_status=$(systemctl status --full --no-pager pihole-FTL.service)
log_write " ${FTL_status}" log_write " ${FTL_status}"
elif [ -n "${DOCKER_VERSION}" ]; then elif [ -n "${DOCKER_VERSION}" ]; then
log_write "${INFO} systemctl/service not installed inside docker container ${COL_YELLOW}(skipped)${COL_NC}" log_write "${INFO} systemctl/service not installed inside docker container ${COL_YELLOW}(skipped)${COL_NC}"
else else
log_write "${INFO} systemctl: command not found" log_write "${INFO} systemctl: command not found"
fi fi
} }
@ -898,7 +901,7 @@ make_array_from_file() {
: :
else else
# Otherwise, read the file line by line # Otherwise, read the file line by line
while IFS= read -r line;do while IFS= read -r line; do
# Otherwise, strip out comments and blank lines # Otherwise, strip out comments and blank lines
new_line=$(echo "${line}" | sed -e 's/^\s*#.*$//' -e '/^$/d') new_line=$(echo "${line}" | sed -e 's/^\s*#.*$//' -e '/^$/d')
# If the line still has content (a non-zero value) # If the line still has content (a non-zero value)
@ -913,7 +916,7 @@ make_array_from_file() {
log_write " ${new_line}" log_write " ${new_line}"
fi fi
# Increment the iterator +1 # Increment the iterator +1
i=$((i+1)) i=$((i + 1))
# but if the limit of lines we want to see is exceeded # but if the limit of lines we want to see is exceeded
if [[ -z ${limit} ]]; then if [[ -z ${limit} ]]; then
# do nothing # do nothing
@ -921,7 +924,7 @@ make_array_from_file() {
elif [[ $i -eq ${limit} ]]; then elif [[ $i -eq ${limit} ]]; then
break break
fi fi
done < "${filename}" done <"${filename}"
fi fi
} }
@ -936,7 +939,7 @@ parse_file() {
#shellcheck disable=SC2016 #shellcheck disable=SC2016
IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )' IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
else else
read -r -a file_info <<< "$filename" read -r -a file_info <<<"$filename"
fi fi
# Set a named variable for better readability # Set a named variable for better readability
local file_lines local file_lines
@ -944,7 +947,7 @@ parse_file() {
for file_lines in "${file_info[@]}"; do for file_lines in "${file_info[@]}"; do
if [[ -n "${file_lines}" ]]; then if [[ -n "${file_lines}" ]]; then
# skip empty and comment lines line # skip empty and comment lines line
[[ "${file_lines}" =~ ^[[:space:]]*\#.*$ || ! "${file_lines}" ]] && continue [[ "${file_lines}" =~ ^[[:space:]]*\#.*$ || ! "${file_lines}" ]] && continue
# remove the password hash from the output (*"pwhash = "*) # remove the password hash from the output (*"pwhash = "*)
[[ "${file_lines}" == *"pwhash ="* ]] && file_lines=$(echo "${file_lines}" | sed -e 's/\(pwhash = \).*/\1<removed>/') [[ "${file_lines}" == *"pwhash ="* ]] && file_lines=$(echo "${file_lines}" | sed -e 's/\(pwhash = \).*/\1<removed>/')
# otherwise, display the lines of the file # otherwise, display the lines of the file
@ -972,7 +975,7 @@ dir_check() {
# For each file in the directory, # For each file in the directory,
for filename in ${directory}; do for filename in ${directory}; do
# check if exists first; if it does, # check if exists first; if it does,
if ls "${filename}" 1> /dev/null 2>&1; then if ls "${filename}" 1>/dev/null 2>&1; then
# do nothing # do nothing
true true
return return
@ -1002,10 +1005,10 @@ list_files_in_dir() {
if [[ -d "${dir_to_parse}/${each_file}" ]]; then if [[ -d "${dir_to_parse}/${each_file}" ]]; then
# If it's a directory, do nothing # If it's a directory, do nothing
: :
elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \ elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] ||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_RAW_BLOCKLIST_FILES}" ]] || \ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_RAW_BLOCKLIST_FILES}" ]] ||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] ||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] ||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG_GZIPS}" ]]; then [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG_GZIPS}" ]]; then
: :
elif [[ "${dir_to_parse}" == "${DNSMASQ_D_DIRECTORY}" ]]; then elif [[ "${dir_to_parse}" == "${DNSMASQ_D_DIRECTORY}" ]]; then
@ -1020,14 +1023,16 @@ list_files_in_dir() {
log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}" log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
# Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing) # Check if the file we want to view has a limit (because sometimes we just need a little bit of info from the file, not the entire thing)
case "${dir_to_parse}/${each_file}" in case "${dir_to_parse}/${each_file}" in
# If it's Web server log, give the first and last 25 lines # If it's Web server log, give the first and last 25 lines
"${PIHOLE_WEBSERVER_LOG}") head_tail_log "${dir_to_parse}/${each_file}" 25 "${PIHOLE_WEBSERVER_LOG}")
;; head_tail_log "${dir_to_parse}/${each_file}" 25
# Same for the FTL log ;;
"${PIHOLE_FTL_LOG}") head_tail_log "${dir_to_parse}/${each_file}" 35 # Same for the FTL log
;; "${PIHOLE_FTL_LOG}")
# parse the file into an array in case we ever need to analyze it line-by-line head_tail_log "${dir_to_parse}/${each_file}" 35
*) make_array_from_file "${dir_to_parse}/${each_file}"; ;;
# parse the file into an array in case we ever need to analyze it line-by-line
*) make_array_from_file "${dir_to_parse}/${each_file}" ;;
esac esac
else else
# Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it # Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it
@ -1096,12 +1101,12 @@ show_db_entries() {
OLD_IFS="$IFS" OLD_IFS="$IFS"
IFS=$'\r\n' IFS=$'\r\n'
local entries=() local entries=()
mapfile -t entries < <(\ mapfile -t entries < <(
pihole-FTL sqlite3 -ni "${PIHOLE_GRAVITY_DB_FILE}" \ pihole-FTL sqlite3 -ni "${PIHOLE_GRAVITY_DB_FILE}" \
-cmd ".headers on" \ -cmd ".headers on" \
-cmd ".mode column" \ -cmd ".mode column" \
-cmd ".width ${widths}" \ -cmd ".width ${widths}" \
"${query}"\ "${query}"
) )
for line in "${entries[@]}"; do for line in "${entries[@]}"; do
@ -1121,12 +1126,12 @@ show_FTL_db_entries() {
OLD_IFS="$IFS" OLD_IFS="$IFS"
IFS=$'\r\n' IFS=$'\r\n'
local entries=() local entries=()
mapfile -t entries < <(\ mapfile -t entries < <(
pihole-FTL sqlite3 -ni "${PIHOLE_FTL_DB_FILE}" \ pihole-FTL sqlite3 -ni "${PIHOLE_FTL_DB_FILE}" \
-cmd ".headers on" \ -cmd ".headers on" \
-cmd ".mode column" \ -cmd ".mode column" \
-cmd ".width ${widths}" \ -cmd ".width ${widths}" \
"${query}"\ "${query}"
) )
for line in "${entries[@]}"; do for line in "${entries[@]}"; do
@ -1142,7 +1147,10 @@ check_dhcp_servers() {
OLD_IFS="$IFS" OLD_IFS="$IFS"
IFS=$'\n' IFS=$'\n'
local entries=() local entries=()
mapfile -t entries < <(pihole-FTL dhcp-discover & spinner) mapfile -t entries < <(
pihole-FTL dhcp-discover &
spinner
)
for line in "${entries[@]}"; do for line in "${entries[@]}"; do
log_write " ${line}" log_write " ${line}"
@ -1216,39 +1224,44 @@ analyze_ftl_db() {
fi fi
} }
database_integrity_check(){ database_integrity_check() {
local result local result
local database="${1}" local database="${1}"
log_write "${INFO} Checking integrity of ${database} ... (this can take several minutes)" log_write "${INFO} Checking integrity of ${database} ... (this can take several minutes)"
result="$(pihole-FTL sqlite3 -ni "${database}" "PRAGMA integrity_check" 2>&1 & spinner)" result="$(
pihole-FTL sqlite3 -ni "${database}" "PRAGMA integrity_check" 2>&1 &
spinner
)"
if [[ ${result} = "ok" ]]; then if [[ ${result} = "ok" ]]; then
log_write "${TICK} Integrity of ${database} intact" log_write "${TICK} Integrity of ${database} intact"
log_write "${INFO} Checking foreign key constraints of ${database} ... (this can take several minutes)"
log_write "${INFO} Checking foreign key constraints of ${database} ... (this can take several minutes)" unset result
unset result result="$(
result="$(pihole-FTL sqlite3 -ni "${database}" -cmd ".headers on" -cmd ".mode column" "PRAGMA foreign_key_check" 2>&1 & spinner)" pihole-FTL sqlite3 -ni "${database}" -cmd ".headers on" -cmd ".mode column" "PRAGMA foreign_key_check" 2>&1 &
if [[ -z ${result} ]]; then spinner
log_write "${TICK} No foreign key errors in ${database}" )"
else if [[ -z ${result} ]]; then
log_write "${CROSS} ${COL_RED}Foreign key errors in ${database} found.${COL_NC}" log_write "${TICK} No foreign key errors in ${database}"
while IFS= read -r line ; do else
log_write " $line" log_write "${CROSS} ${COL_RED}Foreign key errors in ${database} found.${COL_NC}"
done <<< "$result" while IFS= read -r line; do
fi log_write " $line"
done <<<"$result"
fi
else else
log_write "${CROSS} ${COL_RED}Integrity errors in ${database} found.\n${COL_NC}" log_write "${CROSS} ${COL_RED}Integrity errors in ${database} found.\n${COL_NC}"
while IFS= read -r line ; do while IFS= read -r line; do
log_write " $line" log_write " $line"
done <<< "$result" done <<<"$result"
fi fi
} }
# Show a text spinner during a long process run # Show a text spinner during a long process run
spinner(){ spinner() {
# Show the spinner only if there is a tty # Show the spinner only if there is a tty
if tty -s; then if tty -s; then
# PID of the most recent background process # PID of the most recent background process
@ -1262,18 +1275,18 @@ spinner(){
_start=$(date +%s) _start=$(date +%s)
# Hide the cursor # Hide the cursor
tput civis > /dev/tty tput civis >/dev/tty
# ensures cursor is visible again, in case of premature exit # ensures cursor is visible again, in case of premature exit
trap 'tput cnorm > /dev/tty' EXIT trap 'tput cnorm > /dev/tty' EXIT
while [ -d /proc/$_PID ]; do while [ -d /proc/$_PID ]; do
_elapsed=$(( $(date +%s) - _start )) _elapsed=$(($(date +%s) - _start))
# use hours only if needed # use hours only if needed
if [ "$_elapsed" -lt 3600 ]; then if [ "$_elapsed" -lt 3600 ]; then
printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d" $((_elapsed/60)) $((_elapsed%60)) >"$(tty)" printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d" $((_elapsed / 60)) $((_elapsed % 60)) >"$(tty)"
else else
printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d:%02d" $((_elapsed/3600)) $(((_elapsed/60)%60)) $((_elapsed%60)) >"$(tty)" printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d:%02d" $((_elapsed / 3600)) $(((_elapsed / 60) % 60)) $((_elapsed % 60)) >"$(tty)"
fi fi
sleep 0.25 sleep 0.25
done done
@ -1282,25 +1295,25 @@ spinner(){
printf "\r" >"$(tty)" printf "\r" >"$(tty)"
# Restore cursor visibility # Restore cursor visibility
tput cnorm > /dev/tty tput cnorm >/dev/tty
fi fi
} }
analyze_pihole_log() { analyze_pihole_log() {
echo_current_diagnostic "Pi-hole log" echo_current_diagnostic "Pi-hole log"
local pihole_log_permissions local pihole_log_permissions
local queryLogging local queryLogging
queryLogging="$(get_ftl_conf_value "dns.queryLogging")" queryLogging="$(get_ftl_conf_value "dns.queryLogging")"
if [[ "${queryLogging}" == "false" ]]; then if [[ "${queryLogging}" == "false" ]]; then
# Inform user that logging has been disabled and pihole.log does not contain queries # Inform user that logging has been disabled and pihole.log does not contain queries
log_write "${INFO} Query logging is disabled" log_write "${INFO} Query logging is disabled"
log_write "" log_write ""
fi fi
pihole_log_permissions=$(ls -lhd "${PIHOLE_LOG}") pihole_log_permissions=$(ls -lhd "${PIHOLE_LOG}")
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}" log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
head_tail_log "${PIHOLE_LOG}" 20 head_tail_log "${PIHOLE_LOG}" 20
} }
curl_to_tricorder() { curl_to_tricorder() {
@ -1318,7 +1331,6 @@ curl_to_tricorder() {
fi fi
} }
upload_to_tricorder() { upload_to_tricorder() {
local username="pihole" local username="pihole"
# Set the permissions and owner # Set the permissions and owner
@ -1347,10 +1359,13 @@ upload_to_tricorder() {
# Users can review the log file locally (or the output of the script since they are the same) and try to self-diagnose their problem # Users can review the log file locally (or the output of the script since they are the same) and try to self-diagnose their problem
read -r -p "[?] Would you like to upload the log? [y/N] " response read -r -p "[?] Would you like to upload the log? [y/N] " response
case ${response} in case ${response} in
# If they say yes, run our function for uploading the log # If they say yes, run our function for uploading the log
[yY][eE][sS]|[yY]) curl_to_tricorder;; [yY][eE][sS] | [yY]) curl_to_tricorder ;;
# If they choose no, just exit out of the script # If they choose no, just exit out of the script
*) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit; *)
log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n"
exit
;;
esac esac
fi fi
# Check if tricorder.pi-hole.net is reachable and provide token # Check if tricorder.pi-hole.net is reachable and provide token

View file

@ -55,7 +55,7 @@ if [[ "$*" == *"once"* ]]; then
echo -ne " ${INFO} Rotating ${LOGFILE} ..." echo -ne " ${INFO} Rotating ${LOGFILE} ..."
fi fi
cp -p "${LOGFILE}" "${LOGFILE}.1" cp -p "${LOGFILE}" "${LOGFILE}.1"
echo " " > "${LOGFILE}" echo " " >"${LOGFILE}"
chmod 640 "${LOGFILE}" chmod 640 "${LOGFILE}"
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Rotated ${LOGFILE} ..." echo -e "${OVER} ${TICK} Rotated ${LOGFILE} ..."
@ -66,7 +66,7 @@ if [[ "$*" == *"once"* ]]; then
echo -ne " ${INFO} Rotating ${FTLFILE} ..." echo -ne " ${INFO} Rotating ${FTLFILE} ..."
fi fi
cp -p "${FTLFILE}" "${FTLFILE}.1" cp -p "${FTLFILE}" "${FTLFILE}.1"
echo " " > "${FTLFILE}" echo " " >"${FTLFILE}"
chmod 640 "${FTLFILE}" chmod 640 "${FTLFILE}"
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Rotated ${FTLFILE} ..." echo -e "${OVER} ${TICK} Rotated ${FTLFILE} ..."
@ -79,10 +79,10 @@ else
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing ${LOGFILE} ..." echo -ne " ${INFO} Flushing ${LOGFILE} ..."
fi fi
echo " " > "${LOGFILE}" echo " " >"${LOGFILE}"
chmod 640 "${LOGFILE}" chmod 640 "${LOGFILE}"
if [ -f "${LOGFILE}.1" ]; then if [ -f "${LOGFILE}.1" ]; then
echo " " > "${LOGFILE}.1" echo " " >"${LOGFILE}.1"
chmod 640 "${LOGFILE}.1" chmod 640 "${LOGFILE}.1"
fi fi
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
@ -93,10 +93,10 @@ else
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing ${FTLFILE} ..." echo -ne " ${INFO} Flushing ${FTLFILE} ..."
fi fi
echo " " > "${FTLFILE}" echo " " >"${FTLFILE}"
chmod 640 "${FTLFILE}" chmod 640 "${FTLFILE}"
if [ -f "${FTLFILE}.1" ]; then if [ -f "${FTLFILE}.1" ]; then
echo " " > "${FTLFILE}.1" echo " " >"${FTLFILE}.1"
chmod 640 "${FTLFILE}.1" chmod 640 "${FTLFILE}.1"
fi fi
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
@ -119,4 +119,3 @@ else
echo -e "${OVER} ${TICK} Deleted ${deleted} queries from long-term query database" echo -e "${OVER} ${TICK} Deleted ${deleted} queries from long-term query database"
fi fi
fi fi

View file

@ -41,7 +41,7 @@ GitCheckUpdateAvail() {
cd "${directory}" || exit 1 cd "${directory}" || exit 1
# Fetch latest changes in this repo # Fetch latest changes in this repo
if ! git fetch --quiet origin ; then if ! git fetch --quiet origin; then
echo -e "\\n ${COL_LIGHT_RED}Error: Unable to update local repository. Contact Pi-hole Support.${COL_NC}" echo -e "\\n ${COL_LIGHT_RED}Error: Unable to update local repository. Contact Pi-hole Support.${COL_NC}"
exit 1 exit 1
fi fi
@ -69,7 +69,6 @@ GitCheckUpdateAvail() {
REMOTE="$(git rev-parse "@{upstream}")" REMOTE="$(git rev-parse "@{upstream}")"
fi fi
if [[ "${#LOCAL}" == 0 ]]; then if [[ "${#LOCAL}" == 0 ]]; then
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support" echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
echo -e " Additional debugging output:${COL_NC}" echo -e " Additional debugging output:${COL_NC}"
@ -116,15 +115,15 @@ main() {
install_dependent_packages install_dependent_packages
# This is unlikely # This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then if ! is_repo "${PI_HOLE_FILES_DIR}"; then
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!" echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}" echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1; exit 1
fi fi
echo -e " ${INFO} Checking for updates..." echo -e " ${INFO} Checking for updates..."
if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}"; then
core_update=true core_update=true
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}" echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
else else
@ -132,13 +131,13 @@ main() {
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}" echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
fi fi
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then if ! is_repo "${ADMIN_INTERFACE_DIR}"; then
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!" echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}" echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1; exit 1
fi fi
if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}"; then
web_update=true web_update=true
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}" echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
else else
@ -156,19 +155,20 @@ main() {
echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
else else
case $? in case $? in
1) 1)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
;; ;;
2) 2)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch." echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
;; ;;
3) 3)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, cannot reach download server${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, cannot reach download server${COL_NC}"
exit 1 exit 1
;; ;;
*) *)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}"
exit 1 exit 1
;;
esac esac
FTL_update=false FTL_update=false
fi fi
@ -218,7 +218,7 @@ main() {
fi fi
if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended || \ ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --repair --unattended ||
echo -e "${basicError}" && exit 1 echo -e "${basicError}" && exit 1
fi fi
@ -230,7 +230,7 @@ main() {
# if there was only a web update, show the new versions # if there was only a web update, show the new versions
# (on core and FTL updates, this is done as part of the installer run) # (on core and FTL updates, this is done as part of the installer run)
if [[ "${web_update}" == true && "${FTL_update}" == false && "${core_update}" == false ]]; then if [[ "${web_update}" == true && "${FTL_update}" == false && "${core_update}" == false ]]; then
"${PI_HOLE_BIN_DIR}"/pihole version "${PI_HOLE_BIN_DIR}"/pihole version
fi fi

View file

@ -27,20 +27,20 @@
# addOrEditKeyValPair "/etc/pihole/setupVars.conf" "BLOCKING_ENABLED" "true" # addOrEditKeyValPair "/etc/pihole/setupVars.conf" "BLOCKING_ENABLED" "true"
####################### #######################
addOrEditKeyValPair() { addOrEditKeyValPair() {
local file="${1}" local file="${1}"
local key="${2}" local key="${2}"
local value="${3}" local value="${3}"
# touch file to prevent grep error if file does not exist yet # touch file to prevent grep error if file does not exist yet
touch "${file}" touch "${file}"
if grep -q "^${key}=" "${file}"; then if grep -q "^${key}=" "${file}"; then
# Key already exists in file, modify the value # Key already exists in file, modify the value
sed -i "/^${key}=/c\\${key}=${value}" "${file}" sed -i "/^${key}=/c\\${key}=${value}" "${file}"
else else
# Key does not already exist, add it and it's value # Key does not already exist, add it and it's value
echo "${key}=${value}" >> "${file}" echo "${key}=${value}" >>"${file}"
fi fi
} }
####################### #######################
@ -58,13 +58,13 @@ getFTLPID() {
FTL_PID="$(cat "${FTL_PID_FILE}")" FTL_PID="$(cat "${FTL_PID_FILE}")"
# Exploit prevention: unset the variable if there is malicious content # Exploit prevention: unset the variable if there is malicious content
# Verify that the value read from the file is numeric # Verify that the value read from the file is numeric
expr "${FTL_PID}" : "[^[:digit:]]" > /dev/null && unset FTL_PID expr "${FTL_PID}" : "[^[:digit:]]" >/dev/null && unset FTL_PID
fi fi
# If FTL is not running, or the PID file contains malicious stuff, substitute # If FTL is not running, or the PID file contains malicious stuff, substitute
# negative PID to signal this # negative PID to signal this
FTL_PID=${FTL_PID:=-1} FTL_PID=${FTL_PID:=-1}
echo "${FTL_PID}" echo "${FTL_PID}"
} }
####################### #######################
@ -73,8 +73,8 @@ getFTLPID() {
# Takes one argument: key # Takes one argument: key
# Example getFTLConfigValue dns.piholePTR # Example getFTLConfigValue dns.piholePTR
####################### #######################
getFTLConfigValue(){ getFTLConfigValue() {
pihole-FTL --config -q "${1}" pihole-FTL --config -q "${1}"
} }
####################### #######################
@ -86,10 +86,10 @@ getFTLConfigValue(){
# Note, for complex values such as dns.upstreams, you should wrap the value in single quotes: # Note, for complex values such as dns.upstreams, you should wrap the value in single quotes:
# setFTLConfigValue dns.upstreams '[ "8.8.8.8" , "8.8.4.4" ]' # setFTLConfigValue dns.upstreams '[ "8.8.8.8" , "8.8.4.4" ]'
####################### #######################
setFTLConfigValue(){ setFTLConfigValue() {
pihole-FTL --config "${1}" "${2}" >/dev/null pihole-FTL --config "${1}" "${2}" >/dev/null
if [[ $? -eq 5 ]]; then if [[ $? -eq 5 ]]; then
echo -e " ${CROSS} ${1} set by environment variable. Please unset it to use this function" echo -e " ${CROSS} ${1} set by environment variable. Please unset it to use this function"
exit 5 exit 5
fi fi
} }

View file

@ -219,19 +219,20 @@ is_command() {
command -v "${check_command}" >/dev/null 2>&1 command -v "${check_command}" >/dev/null 2>&1
} }
os_check_dig(){ os_check_dig() {
local protocol="$1" local protocol="$1"
local domain="$2" local domain="$2"
local nameserver="$3" local nameserver="$3"
local response local response
response="$(dig -"${protocol}" +short -t txt "${domain}" "${nameserver}" 2>&1 response="$(
echo $? dig -"${protocol}" +short -t txt "${domain}" "${nameserver}" 2>&1
echo $?
)" )"
echo "${response}" echo "${response}"
} }
os_check_dig_response(){ os_check_dig_response() {
# Checks the reply from the dig command to determine if it's a valid response # Checks the reply from the dig command to determine if it's a valid response
local digReply="$1" local digReply="$1"
local response local response
@ -432,7 +433,7 @@ package_manager_detect() {
fi fi
} }
build_dependency_package(){ build_dependency_package() {
# This function will build a package that contains all the dependencies needed for Pi-hole # This function will build a package that contains all the dependencies needed for Pi-hole
# remove any leftover build directory that may exist # remove any leftover build directory that may exist
@ -456,13 +457,13 @@ build_dependency_package(){
touch "${tempdir}"/DEBIAN/control touch "${tempdir}"/DEBIAN/control
# Write the control file # Write the control file
echo "${PIHOLE_META_PACKAGE_CONTROL_APT}" > "${tempdir}"/DEBIAN/control echo "${PIHOLE_META_PACKAGE_CONTROL_APT}" >"${tempdir}"/DEBIAN/control
# Build the package # Build the package
local str="Building dependency package pihole-meta.deb" local str="Building dependency package pihole-meta.deb"
printf " %b %s..." "${INFO}" "${str}" printf " %b %s..." "${INFO}" "${str}"
if dpkg-deb --build --root-owner-group "${tempdir}" pihole-meta.deb &>/dev/null; then if dpkg-deb --build --root-owner-group "${tempdir}" pihole-meta.deb &>/dev/null; then
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
@ -471,7 +472,7 @@ build_dependency_package(){
fi fi
# Move back into the directory the user started in # Move back into the directory the user started in
popd &> /dev/null || return 1 popd &>/dev/null || return 1
elif is_command rpm; then elif is_command rpm; then
# move into the tmp directory # move into the tmp directory
@ -483,7 +484,7 @@ build_dependency_package(){
# Prepare directory structure and spec file # Prepare directory structure and spec file
mkdir -p "${tempdir}"/SPECS mkdir -p "${tempdir}"/SPECS
touch "${tempdir}"/SPECS/pihole-meta.spec touch "${tempdir}"/SPECS/pihole-meta.spec
echo "${PIHOLE_META_PACKAGE_CONTROL_RPM}" > "${tempdir}"/SPECS/pihole-meta.spec echo "${PIHOLE_META_PACKAGE_CONTROL_RPM}" >"${tempdir}"/SPECS/pihole-meta.spec
# check if we need to install the build dependencies # check if we need to install the build dependencies
if ! is_command rpmbuild; then if ! is_command rpmbuild; then
@ -512,7 +513,7 @@ build_dependency_package(){
fi fi
# Move back into the directory the user started in # Move back into the directory the user started in
popd &> /dev/null || return 1 popd &>/dev/null || return 1
# If neither apt-get or yum/dnf package managers were found # If neither apt-get or yum/dnf package managers were found
else else
@ -539,9 +540,9 @@ is_repo() {
pushd "${directory}" &>/dev/null || return 1 pushd "${directory}" &>/dev/null || return 1
# Use git to check if the directory is a repo # Use git to check if the directory is a repo
# git -C is not used here to support git versions older than 1.8.4 # git -C is not used here to support git versions older than 1.8.4
git status --short &> /dev/null || rc=$? git status --short &>/dev/null || rc=$?
# Move back into the directory the user started in # Move back into the directory the user started in
popd &> /dev/null || return 1 popd &>/dev/null || return 1
else else
# Set a non-zero return code if directory does not exist # Set a non-zero return code if directory does not exist
rc=1 rc=1
@ -1430,7 +1431,7 @@ disable_resolved_stublistener() {
# Note that this breaks dns functionality on host until FTL is up and running # Note that this breaks dns functionality on host until FTL is up and running
printf "%b %b Disabling systemd-resolved DNSStubListener\\n" "${OVER}" "${TICK}" printf "%b %b Disabling systemd-resolved DNSStubListener\\n" "${OVER}" "${TICK}"
mkdir -p /etc/systemd/resolved.conf.d mkdir -p /etc/systemd/resolved.conf.d
cat > /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf << EOF cat >/etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf <<EOF
[Resolve] [Resolve]
DNSStubListener=no DNSStubListener=no
EOF EOF
@ -1653,7 +1654,7 @@ compress
delaycompress delaycompress
notifempty notifempty
nomail nomail
}" >> ${target} }" >>${target}
printf "\\n\\t%b webserver.log added to logrotate file. \\n" "${INFO}" printf "\\n\\t%b webserver.log added to logrotate file. \\n" "${INFO}"
logfileUpdate=true logfileUpdate=true
@ -2227,7 +2228,7 @@ disableLighttpd() {
# The terminal is interactive # The terminal is interactive
dialog --no-shadow --keep-tite \ dialog --no-shadow --keep-tite \
--title "Pi-hole v6.0 no longer uses lighttpd" \ --title "Pi-hole v6.0 no longer uses lighttpd" \
--yesno "\\n\\nPi-hole v6.0 has its own embedded web server so lighttpd is no longer needed *unless* you have custom configurations.\\n\\nIn this case, you can opt-out of disabling lighttpd and pihole-FTL will try to bind to an alternative port such as 8080.\\n\\nDo you want to disable lighttpd (recommended)?" "${r}" "${c}" && response=0 || response="$?" --yesno "\\n\\nPi-hole v6.0 has its own embedded web server so lighttpd is no longer needed *unless* you have custom configurations.\\n\\nIn this case, you can opt-out of disabling lighttpd and pihole-FTL will try to bind to an alternative port such as 8080.\\n\\nDo you want to disable lighttpd (recommended)?" "${r}" "${c}" && response=0 || response="$?"
else else
# The terminal is non-interactive, assume yes. Lighttpd will be stopped # The terminal is non-interactive, assume yes. Lighttpd will be stopped
# but keeps being installed and can easily be re-enabled by the user # but keeps being installed and can easily be re-enabled by the user
@ -2419,7 +2420,6 @@ main() {
# Download or reset the appropriate git repos depending on the 'repair' flag # Download or reset the appropriate git repos depending on the 'repair' flag
clone_or_reset_repos clone_or_reset_repos
# Create the pihole user # Create the pihole user
create_pihole_user create_pihole_user
@ -2448,11 +2448,9 @@ main() {
# Copy the temp log file into final log location for storage # Copy the temp log file into final log location for storage
copy_to_install_log copy_to_install_log
# Migrate existing install to v6.0 # Migrate existing install to v6.0
migrate_dnsmasq_configs migrate_dnsmasq_configs
# Check for and disable systemd-resolved-DNSStubListener before reloading resolved # Check for and disable systemd-resolved-DNSStubListener before reloading resolved
# DNSStubListener needs to remain in place for installer to download needed files, # DNSStubListener needs to remain in place for installer to download needed files,
# so this change needs to be made after installation is complete, # so this change needs to be made after installation is complete,
@ -2514,7 +2512,7 @@ main() {
if [[ "${useUpdateVars}" == false ]]; then if [[ "${useUpdateVars}" == false ]]; then
# Get the Web interface port, return only the first port and strip all non-numeric characters # Get the Web interface port, return only the first port and strip all non-numeric characters
WEBPORT=$(getFTLConfigValue webserver.port|cut -d, -f1 | tr -cd '0-9') WEBPORT=$(getFTLConfigValue webserver.port | cut -d, -f1 | tr -cd '0-9')
# Display the completion dialog # Display the completion dialog
displayFinalMessage "${pw}" displayFinalMessage "${pw}"

View file

@ -13,8 +13,11 @@ source "/opt/pihole/COL_TABLE"
while true; do while true; do
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " answer read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " answer
case ${answer} in case ${answer} in
[Yy]* ) break;; [Yy]*) break ;;
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;; *)
echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"
exit 0
;;
esac esac
done done
@ -42,26 +45,24 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# package_manager_detect() sourced from basic-install.sh # package_manager_detect() sourced from basic-install.sh
package_manager_detect package_manager_detect
removeMetaPackage() { removeMetaPackage() {
# Purge Pi-hole meta package # Purge Pi-hole meta package
echo "" echo ""
echo -ne " ${INFO} Removing Pi-hole meta package..."; echo -ne " ${INFO} Removing Pi-hole meta package..."
eval "${SUDO}" "${PKG_REMOVE}" "pihole-meta" &> /dev/null; eval "${SUDO}" "${PKG_REMOVE}" "pihole-meta" &>/dev/null
echo -e "${OVER} ${INFO} Removed Pi-hole meta package"; echo -e "${OVER} ${INFO} Removed Pi-hole meta package"
} }
removePiholeFiles() { removePiholeFiles() {
# Only web directories/files that are created by Pi-hole should be removed # Only web directories/files that are created by Pi-hole should be removed
echo -ne " ${INFO} Removing Web Interface..." echo -ne " ${INFO} Removing Web Interface..."
${SUDO} rm -rf /var/www/html/admin &> /dev/null ${SUDO} rm -rf /var/www/html/admin &>/dev/null
# If the web directory is empty after removing these files, then the parent html directory can be removed. # If the web directory is empty after removing these files, then the parent html directory can be removed.
if [ -d "/var/www/html" ]; then if [ -d "/var/www/html" ]; then
if [[ ! "$(ls -A /var/www/html)" ]]; then if [[ ! "$(ls -A /var/www/html)" ]]; then
${SUDO} rm -rf /var/www/html &> /dev/null ${SUDO} rm -rf /var/www/html &>/dev/null
fi fi
fi fi
echo -e "${OVER} ${TICK} Removed Web Interface" echo -e "${OVER} ${TICK} Removed Web Interface"
@ -78,30 +79,30 @@ removePiholeFiles() {
fi fi
# Attempt to preserve backwards compatibility with older versions # Attempt to preserve backwards compatibility with older versions
if [[ -f /etc/cron.d/pihole ]];then if [[ -f /etc/cron.d/pihole ]]; then
${SUDO} rm -f /etc/cron.d/pihole &> /dev/null ${SUDO} rm -f /etc/cron.d/pihole &>/dev/null
echo -e " ${TICK} Removed /etc/cron.d/pihole" echo -e " ${TICK} Removed /etc/cron.d/pihole"
fi fi
${SUDO} rm -rf /var/log/*pihole* &> /dev/null ${SUDO} rm -rf /var/log/*pihole* &>/dev/null
${SUDO} rm -rf /var/log/pihole/*pihole* &> /dev/null ${SUDO} rm -rf /var/log/pihole/*pihole* &>/dev/null
${SUDO} rm -rf /etc/pihole/ &> /dev/null ${SUDO} rm -rf /etc/pihole/ &>/dev/null
${SUDO} rm -rf /etc/.pihole/ &> /dev/null ${SUDO} rm -rf /etc/.pihole/ &>/dev/null
${SUDO} rm -rf /opt/pihole/ &> /dev/null ${SUDO} rm -rf /opt/pihole/ &>/dev/null
${SUDO} rm -f /usr/local/bin/pihole &> /dev/null ${SUDO} rm -f /usr/local/bin/pihole &>/dev/null
${SUDO} rm -f /etc/bash_completion.d/pihole &> /dev/null ${SUDO} rm -f /etc/bash_completion.d/pihole &>/dev/null
${SUDO} rm -f /etc/sudoers.d/pihole &> /dev/null ${SUDO} rm -f /etc/sudoers.d/pihole &>/dev/null
echo -e " ${TICK} Removed config files" echo -e " ${TICK} Removed config files"
# Restore Resolved # Restore Resolved
if [[ -e /etc/systemd/resolved.conf.orig ]] || [[ -e /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ]]; then if [[ -e /etc/systemd/resolved.conf.orig ]] || [[ -e /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ]]; then
${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf &> /dev/null || true ${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf &>/dev/null || true
${SUDO} rm -f /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ${SUDO} rm -f /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf
systemctl reload-or-restart systemd-resolved systemctl reload-or-restart systemd-resolved
fi fi
# Remove FTL # Remove FTL
if command -v pihole-FTL &> /dev/null; then if command -v pihole-FTL &>/dev/null; then
echo -ne " ${INFO} Removing pihole-FTL..." echo -ne " ${INFO} Removing pihole-FTL..."
if [[ -x "$(command -v systemctl)" ]]; then if [[ -x "$(command -v systemctl)" ]]; then
systemctl stop pihole-FTL systemctl stop pihole-FTL
@ -112,12 +113,12 @@ removePiholeFiles() {
if [[ -d '/etc/systemd/system/pihole-FTL.service.d' ]]; then if [[ -d '/etc/systemd/system/pihole-FTL.service.d' ]]; then
read -rp " ${QST} FTL service override directory /etc/systemd/system/pihole-FTL.service.d detected. Do you wish to remove this from your system? [y/N] " answer read -rp " ${QST} FTL service override directory /etc/systemd/system/pihole-FTL.service.d detected. Do you wish to remove this from your system? [y/N] " answer
case $answer in case $answer in
[yY]*) [yY]*)
echo -ne " ${INFO} Removing /etc/systemd/system/pihole-FTL.service.d..." echo -ne " ${INFO} Removing /etc/systemd/system/pihole-FTL.service.d..."
${SUDO} rm -R /etc/systemd/system/pihole-FTL.service.d ${SUDO} rm -R /etc/systemd/system/pihole-FTL.service.d
echo -e "${OVER} ${INFO} Removed /etc/systemd/system/pihole-FTL.service.d" echo -e "${OVER} ${INFO} Removed /etc/systemd/system/pihole-FTL.service.d"
;; ;;
*) echo -e " ${INFO} Leaving /etc/systemd/system/pihole-FTL.service.d in place.";; *) echo -e " ${INFO} Leaving /etc/systemd/system/pihole-FTL.service.d in place." ;;
esac esac
fi fi
${SUDO} rm -f /etc/init.d/pihole-FTL ${SUDO} rm -f /etc/init.d/pihole-FTL
@ -133,16 +134,16 @@ removePiholeFiles() {
fi fi
# If the pihole user exists, then remove # If the pihole user exists, then remove
if id "pihole" &> /dev/null; then if id "pihole" &>/dev/null; then
if ${SUDO} userdel -r pihole 2> /dev/null; then if ${SUDO} userdel -r pihole 2>/dev/null; then
echo -e " ${TICK} Removed 'pihole' user" echo -e " ${TICK} Removed 'pihole' user"
else else
echo -e " ${CROSS} Unable to remove 'pihole' user" echo -e " ${CROSS} Unable to remove 'pihole' user"
fi fi
fi fi
# If the pihole group exists, then remove # If the pihole group exists, then remove
if getent group "pihole" &> /dev/null; then if getent group "pihole" &>/dev/null; then
if ${SUDO} groupdel pihole 2> /dev/null; then if ${SUDO} groupdel pihole 2>/dev/null; then
echo -e " ${TICK} Removed 'pihole' group" echo -e " ${TICK} Removed 'pihole' group"
else else
echo -e " ${CROSS} Unable to remove 'pihole' group" echo -e " ${CROSS} Unable to remove 'pihole' group"