Convert whiptail to dialog.

Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
This commit is contained in:
Dan Schaper 2022-06-18 17:17:10 -07:00 committed by Dan Schaper
parent 37889f27de
commit bf57a786e6

View file

@ -2,7 +2,7 @@
# shellcheck disable=SC1090 # shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2017-2021 Pi-hole, LLC (https://pi-hole.net) # (c) Pi-hole (https://pi-hole.net)
# Network-wide ad blocking via your own hardware. # Network-wide ad blocking via your own hardware.
# #
# Installs and Updates Pi-hole # Installs and Updates Pi-hole
@ -32,6 +32,14 @@ export PATH+=':/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
# Local variables will be in lowercase and will exist only within functions # Local variables will be in lowercase and will exist only within functions
# It's still a work in progress, so you may see some variance in this guideline until it is complete # It's still a work in progress, so you may see some variance in this guideline until it is complete
# Dialog result codes
# dialog code values can be set by environment variables, we only override if
# the env var is not set or empty.
: "${DIALOG_OK:=0}"
: "${DIALOG_CANCEL:=1}"
: "${DIALOG_ESC:=255}"
# List of supported DNS servers # List of supported DNS servers
DNS_SERVERS=$(cat << EOM DNS_SERVERS=$(cat << EOM
Google (ECS, DNSSEC);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844 Google (ECS, DNSSEC);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844
@ -93,7 +101,7 @@ if [ -z "${USER}" ]; then
USER="$(id -un)" USER="$(id -un)"
fi fi
# whiptail dialog dimensions: 20 rows and 70 chars width assures to fit on small screens and is known to hold all content. # dialog dimensions: 20 rows and 70 chars width assures to fit on small screens and is known to hold all content.
r=20 r=20
c=70 c=70
@ -317,7 +325,7 @@ package_manager_detect() {
# Packages required to perform the os_check (stored as an array) # Packages required to perform the os_check (stored as an array)
OS_CHECK_DEPS=(grep dnsutils) OS_CHECK_DEPS=(grep dnsutils)
# Packages required to run this install script (stored as an array) # Packages required to run this install script (stored as an array)
INSTALLER_DEPS=(git iproute2 whiptail ca-certificates) INSTALLER_DEPS=(git iproute2 dialog ca-certificates)
# Packages required to run Pi-hole (stored as an array) # Packages required to run Pi-hole (stored as an array)
PIHOLE_DEPS=(cron curl iputils-ping psmisc sudo unzip idn2 libcap2-bin dns-root-data libcap2 netcat-openbsd procps) PIHOLE_DEPS=(cron curl iputils-ping psmisc sudo unzip idn2 libcap2-bin dns-root-data libcap2 netcat-openbsd procps)
# Packages required for the Web admin interface (stored as an array) # Packages required for the Web admin interface (stored as an array)
@ -419,11 +427,18 @@ select_rpm_php(){
rpm -q ${REMI_PKG} &> /dev/null || rc=$? rpm -q ${REMI_PKG} &> /dev/null || rc=$?
if [[ $rc -ne 0 ]]; then if [[ $rc -ne 0 ]]; then
# The PHP version available via default repositories is older than version 7 # The PHP version available via default repositories is older than version 7
if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information" "${r}" "${c}"; then dialog --no-shadow --clear \
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version --title "PHP 7 Update (recommended)" \
printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}" --defaultno \
: # continue with unsupported php version --yesno "PHP 7.x is recommended for both security and language features. \
else \\nWould you like to install PHP7 via Remi's RPM repository? \
\\n\\nSee: https://rpms.remirepo.net for more information" \
"${r}" "${c}"
result=$?
case ${result} in
# User chose to install PHP 7 via Remi's RPM repository
"${DIALOG_OK}")
printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}" printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
"${PKG_INSTALL[@]}" "https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm" &> /dev/null "${PKG_INSTALL[@]}" "https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm" &> /dev/null
# enable the PHP 7 repository via yum-config-manager (provided by yum-utils) # enable the PHP 7 repository via yum-config-manager (provided by yum-utils)
@ -437,14 +452,49 @@ select_rpm_php(){
printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}" printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
exit 1 exit 1
fi fi
;;
# User chose not to install PHP 7 via Remi's RPM repository
"${DIALOG_CANCEL}")
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
;;
# User closed the dialog window
"${DIALOG_ESC}")
printf " %b Escape pressed, exiting installer at Remi dialog window\\n" "${CROSS}"
exit 1
;;
esac
fi fi
fi # Warn user of unsupported version of Fedora or CentOS
if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" "${r}" "${c}"; then # Warn user of unsupported version of Fedora or CentOS
printf " %b Aborting installation due to unsupported RPM based distribution\\n" "${CROSS}" dialog --no-shadow --clear \
exit --title "Unsupported RPM based distribution" \
else --defaultno \
printf " %b Continuing installation with unsupported RPM based distribution\\n" "${INFO}" --no-button "Exit" \
fi --yes-button "Continue" \
--yesno "Would you like to continue installation on an unsupported RPM based distribution? \
\\n\\nPlease ensure the following packages have been installed manually: \
\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+" \
"${r}" "${c}"
result=$?
case ${result} in
# User chose to continue installation on an unsupported RPM based distribution
"${DIALOG_OK}")
printf " %b User opted to continue installation on an unsupported RPM based distribution.\\n" "${INFO}"
;;
# User chose not to continue installation on an unsupported RPM based distribution
"${DIALOG_CANCEL}")
printf " %b User opted not to continue installation on an unsupported RPM based distribution.\\n" "${INFO}"
exit 1
;;
"${DIALOG_ESC}")
printf " %b Escape pressed, exiting installer at unsupported RPM based distribution dialog window\\n" "${CROSS}"
exit 1
;;
esac
fi fi
fi fi
} }
@ -636,40 +686,46 @@ get_available_interfaces() {
# A function for displaying the dialogs the user sees when first running the installer # A function for displaying the dialogs the user sees when first running the installer
welcomeDialogs() { welcomeDialogs() {
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script # Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer" "\\n\\nThis installer will transform your device into a network-wide ad blocker!" "${r}" "${c}" dialog --no-shadow --clear \
--backtitle "Welcome" \
--title "Pi-hole Automated Installer" \
--msgbox "\\n\\nThis installer will transform your device into a network-wide ad blocker!" \
"${r}" "${c}" \
--and-widget \
--backtitle "Support Pi-hole" \
--title "Open Source Software" \
--msgbox "\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/" \
"${r}" "${c}" \
--and-widget \
--colors \
--backtitle "Initiating network interface" \
--title "Static IP Needed" \
--no-button "Exit" --yes-button "Continue" \
--defaultno \
--yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.\\n\\n \
\\Zb\\Z1IMPORTANT:\\Zn If you have not already done so, you must ensure that this device has a static IP.\\n \
Depending on your operating system, there are many ways to achieve this, through DHCP reservation, or by manually assigning one.\\n\\n \
Please continue when the static addressing has been configured." \
"${r}" "${c}"
# Request that users donate if they enjoy the software since we all work on it in our free time result=$?
whiptail --msgbox --backtitle "Plea" --title "Free and open source" "\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/" "${r}" "${c}" case "${result}" in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
# Explain the need for a static address
if whiptail --defaultno --backtitle "Initiating network interface" --title "Static IP Needed" --yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.
IMPORTANT: If you have not already done so, you must ensure that this device has a static IP. Either through DHCP reservation, or by manually assigning one. Depending on your operating system, there are many ways to achieve this.
Choose yes to indicate that you have understood this message, and wish to continue" "${r}" "${c}"; then
#Nothing to do, continue
echo
else
printf " %b Installer exited at static IP message.\\n" "${INFO}" printf " %b Installer exited at static IP message.\\n" "${INFO}"
exit 1 exit 1
fi ;;
esac
} }
# A function that lets the user pick an interface to use with Pi-hole # A function that lets the user pick an interface to use with Pi-hole
chooseInterface() { chooseInterface() {
# Turn the available interfaces into an array so it can be used with a whiptail dialog # Turn the available interfaces into a string so it can be used with dialog
local interfacesArray=() local interfacesList
# Number of available interfaces # Number of available interfaces
local interfaceCount local interfaceCount
# Whiptail variable storage
local chooseInterfaceCmd
# Temporary Whiptail options storage
local chooseInterfaceOptions
# Loop sentinel variable
local firstLoop=1
# Find out how many interfaces are available to choose from # POSIX compliant way to get the number of elements in an array
interfaceCount=$(wc -l <<< "${availableInterfaces}") interfaceCount=$(printf "%s\n" "${availableInterfaces}" | wc -l)
# If there is one interface, # If there is one interface,
if [[ "${interfaceCount}" -eq 1 ]]; then if [[ "${interfaceCount}" -eq 1 ]]; then
@ -677,33 +733,32 @@ chooseInterface() {
PIHOLE_INTERFACE="${availableInterfaces}" PIHOLE_INTERFACE="${availableInterfaces}"
# Otherwise, # Otherwise,
else else
# Set status for the first entry to be selected
status="ON"
# While reading through the available interfaces # While reading through the available interfaces
while read -r line; do for interface in ${availableInterfaces}; do
# Use a variable to set the option as OFF to begin with # Put all these interfaces into a string
mode="OFF" interfacesList="${interfacesList}${interface} available ${status} "
# If it's the first loop, # All further interfaces are deselected
if [[ "${firstLoop}" -eq 1 ]]; then status="OFF"
# set this as the interface to use (ON)
firstLoop=0
mode="ON"
fi
# Put all these interfaces into an array
interfacesArray+=("${line}" "available" "${mode}")
# Feed the available interfaces into this while loop
done <<< "${availableInterfaces}"
# The whiptail command that will be run, stored in a variable
chooseInterfaceCmd=(whiptail --separate-output --radiolist "Choose An Interface (press space to toggle selection)" "${r}" "${c}" 6)
# Now run the command using the interfaces saved into the array
chooseInterfaceOptions=$("${chooseInterfaceCmd[@]}" "${interfacesArray[@]}" 2>&1 >/dev/tty) || \
# If the user chooses Cancel, exit
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
# For each interface
for desiredInterface in ${chooseInterfaceOptions}; do
# Set the one the user selected as the interface to use
PIHOLE_INTERFACE=${desiredInterface}
# and show this information to the user
printf " %b Using interface: %s\\n" "${INFO}" "${PIHOLE_INTERFACE}"
done done
# shellcheck disable=SC2086
# Disable check for double quote here as we are passing a string with spaces
PIHOLE_INTERFACE=$(dialog --no-shadow --clear --output-fd 1 \
--radiolist "Choose An Interface (press space to toggle selection)" \
${r} ${c} "${interfaceCount}" ${interfacesList})
result=$?
case ${result} in
"${DIALOG_CANCEL}"|"${DIALOG_ESC}")
# Show an error message and exit
printf " %b %s\\n" "${CROSS}" "No interface selected, exiting installer"
exit 1
;;
esac
printf " %b Using interface: %s\\n" "${INFO}" "${PIHOLE_INTERFACE}"
fi fi
} }
@ -789,57 +844,102 @@ getStaticIPv4Settings() {
local ipSettingsCorrect local ipSettingsCorrect
local DHCPChoice local DHCPChoice
# Ask if the user wants to use DHCP settings as their static IP # Ask if the user wants to use DHCP settings as their static IP
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions # This is useful for users that are using DHCP reservations; we can use the information gathered
DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n DHCPChoice=$(dialog --no-shadow --clear --output-fd 1 \
IP address: ${IPV4_ADDRESS} \\n --backtitle "Calibrating network interface" \
Gateway: ${IPv4gw} \\n" "${r}" "${c}" 3\ --title "Static IP Address" \
--menu "Do you want to use your current network settings as a static address?\\n \
IP address: ${IPV4_ADDRESS}\\n \
Gateway: ${IPv4gw}\\n" \
"${r}" "${c}" 3 \
"Yes" "Set static IP using current values" \ "Yes" "Set static IP using current values" \
"No" "Set static IP using custom values" \ "No" "Set static IP using custom values" \
"Skip" "I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3) || \ "Skip" "I will set a static IP later, or have already done so")
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
case ${DHCPChoice} in case ${DHCPChoice} in
"Skip")
return
;;
"Yes") "Yes")
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict. # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict" "It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that. dialog --no-shadow --clear \
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. --backtitle "IP information" \
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}" --title "FYI: IP Conflict" \
# Nothing else to do since the variables are already set above --msgbox "\\nIt is possible your router could still try to assign this IP to a device, which would cause a conflict. \
setDHCPCD But in most cases the router is smart enough to not do that. \
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want. \
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." \
"${r}" "${c}"
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
;; ;;
"No") "No")
# Otherwise, we need to ask the user to input their desired settings. # Otherwise, we need to ask the user to input their desired settings.
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP) # Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary # Start a loop to let the user enter their information with the chance to go back and edit it if necessary
ipSettingsCorrect=false
until [[ "${ipSettingsCorrect}" = True ]]; do until [[ "${ipSettingsCorrect}" = True ]]; do
# Ask for the IPv4 address # Ask for the IPv4 address
IPV4_ADDRESS=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 address" --inputbox "Enter your desired IPv4 address" "${r}" "${c}" "${IPV4_ADDRESS}" 3>&1 1>&2 2>&3) || \ _staticIPv4Temp=$(dialog --no-shadow --clear --output-fd 1 \
# Canceling IPv4 settings window --backtitle "Calibrating network interface" \
{ ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; } --title "IPv4 Address" \
printf " %b Your static IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}" --form "\\nEnter your desired IPv4 address" \
"${r}" "${c}" 0 \
"IPv4 Address:" 1 1 "${IPV4_ADDRESS}" 1 15 19 0 \
"IPv4 Gateway:" 2 1 "${IPv4gw}" 2 15 19 0)
# Ask for the gateway result=$?
IPv4gw=$(whiptail --backtitle "Calibrating network interface" --title "IPv4 gateway (router)" --inputbox "Enter your desired IPv4 default gateway" "${r}" "${c}" "${IPv4gw}" 3>&1 1>&2 2>&3) || \ case ${result} in
# Canceling gateway settings window "${DIALOG_CANCEL}" | "${DIALOG_ESC}")
{ ipSettingsCorrect=False; echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}"; exit 1; } printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
printf " %b Your static IPv4 gateway: %s\\n" "${INFO}" "${IPv4gw}" exit 1
# Give the user a chance to review their settings before moving on
if whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Are these settings correct?
IP address: ${IPV4_ADDRESS}
Gateway: ${IPv4gw}" "${r}" "${c}"; then
# After that's done, the loop ends and we move on
ipSettingsCorrect=True
else
# If the settings are wrong, the loop continues
ipSettingsCorrect=False
fi
done
setDHCPCD
;; ;;
esac esac
IPV4_ADDRESS=${_staticIPv4Temp%$'\n'*}
IPv4gw=${_staticIPv4Temp#*$'\n'}
# Give the user a chance to review their settings before moving on
dialog --no-shadow --clear \
--backtitle "Calibrating network interface" \
--title "Static IP Address" \
--defaultno \
--yesno "Are these settings correct?
IP address: ${IPV4_ADDRESS}
Gateway: ${IPv4gw}" \
"${r}" "${c}"
result=$?
case ${result} in
"${DIALOG_OK}")
# After that's done, the loop ends and we move on
ipSettingsCorrect=True
;;
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
done
;;
esac
setDHCPCD
} }
# Configure networking via dhcpcd # Configure networking via dhcpcd
@ -929,11 +1029,18 @@ setDNS() {
DNSChooseOptions[DNSServerCount]="" DNSChooseOptions[DNSServerCount]=""
# Restore the IFS to what it was # Restore the IFS to what it was
IFS=${OIFS} IFS=${OIFS}
# In a whiptail dialog, show the options # In a dialog, show the options
DNSchoices=$(whiptail --separate-output --menu "Select Upstream DNS Provider. To use your own, select Custom." "${r}" "${c}" 7 \ DNSchoices=$(dialog --no-shadow --clear --output-fd 1 \
"${DNSChooseOptions[@]}" 2>&1 >/dev/tty) || \ --menu "Select Upstream DNS Provider. To use your own, select Custom." "${r}" "${c}" 7 \
# Exit if the user selects "Cancel" "${DNSChooseOptions[@]}")
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
# Depending on the user's choice, set the GLOBAL variables to the IP of the respective provider # Depending on the user's choice, set the GLOBAL variables to the IP of the respective provider
if [[ "${DNSchoices}" == "Custom" ]] if [[ "${DNSchoices}" == "Custom" ]]
@ -947,7 +1054,7 @@ setDNS() {
# If the first and second upstream servers do not exist, do not prepopulate an IP address # If the first and second upstream servers do not exist, do not prepopulate an IP address
prePopulate="" prePopulate=""
else else
# Otherwise, prepopulate the whiptail dialogue with the appropriate DNS value(s) # Otherwise, prepopulate the dialogue with the appropriate DNS value(s)
prePopulate=", ${PIHOLE_DNS_2}" prePopulate=", ${PIHOLE_DNS_2}"
fi fi
elif [[ "${PIHOLE_DNS_1}" ]] && [[ ! "${PIHOLE_DNS_2}" ]]; then elif [[ "${PIHOLE_DNS_1}" ]] && [[ ! "${PIHOLE_DNS_2}" ]]; then
@ -957,8 +1064,21 @@ setDNS() {
fi fi
# Prompt the user to enter custom upstream servers # Prompt the user to enter custom upstream servers
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), separated by a comma. If you want to specify a port other than 53, separate it with a hash.\\n\\nFor example '8.8.8.8, 8.8.4.4' or '127.0.0.1#5335'" "${r}" "${c}" "${prePopulate}" 3>&1 1>&2 2>&3) || \ piholeDNS=$(dialog --no-shadow --clear --output-fd 1 \
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; } --backtitle "Specify Upstream DNS Provider(s)" \
--inputbox "Enter your desired upstream DNS provider(s), separated by a comma. \
If you want to specify a port other than 53, separate it with a hash. \
\\n\\nFor example '8.8.8.8, 8.8.4.4' or '127.0.0.1#5335'" \
"${r}" "${c}" "${prePopulate}")
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
# Clean user input and replace whitespace with comma. # Clean user input and replace whitespace with comma.
piholeDNS=$(sed 's/[, \t]\+/,/g' <<< "${piholeDNS}") piholeDNS=$(sed 's/[, \t]\+/,/g' <<< "${piholeDNS}")
@ -977,7 +1097,21 @@ setDNS() {
# If either of the DNS servers are invalid, # If either of the DNS servers are invalid,
if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]] || [[ "${PIHOLE_DNS_2}" == "${strInvalid}" ]]; then if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]] || [[ "${PIHOLE_DNS_2}" == "${strInvalid}" ]]; then
# explain this to the user, # explain this to the user,
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP" "One or both entered IP addresses were invalid. Please try again.\\n\\n DNS Server 1: $PIHOLE_DNS_1\\n DNS Server 2: ${PIHOLE_DNS_2}" ${r} ${c} dialog --no-shadow --clear \
--title "Invalid IP Address(es)" \
--backtitle "Invalid IP" \
--msgbox "\\nOne or both of the entered IP addresses were invalid. Please try again. \
\\n\\nInvalid IPs: ${PIHOLE_DNS_1}, ${PIHOLE_DNS_2}" \
"${r}" "${c}"
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
# set the variables back to nothing, # set the variables back to nothing,
if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]]; then if [[ "${PIHOLE_DNS_1}" == "${strInvalid}" ]]; then
PIHOLE_DNS_1="" PIHOLE_DNS_1=""
@ -988,12 +1122,25 @@ setDNS() {
# and continue the loop. # and continue the loop.
DNSSettingsCorrect=False DNSSettingsCorrect=False
else else
# Otherwise, show the DNS setting to the user, and break the loop if they confirm them. dialog --no-shadow --clear \
if (whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\\n DNS Server 1: $PIHOLE_DNS_1\\n DNS Server 2: ${PIHOLE_DNS_2}" "${r}" "${c}"); then --backtitle "Specify Upstream DNS Provider(s)" \
--title "Upstream DNS Provider(s)" \
--yesno "Are these settings correct?\\n\\tDNS Server 1:\\t${PIHOLE_DNS_1}\\n\\tDNS Server 2:\\t${PIHOLE_DNS_2}" \
"${r}" "${c}"
result=$?
case ${result} in
"${DIALOG_OK}")
DNSSettingsCorrect=True DNSSettingsCorrect=True
else ;;
"${DIALOG_CANCEL}")
DNSSettingsCorrect=False DNSSettingsCorrect=False
fi ;;
"${DIALOG_ESC}")
printf " %bEscape pressed, exiting installer at DNS Settings%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
fi fi
done done
else else
@ -1023,106 +1170,122 @@ setDNS() {
# Allow the user to enable/disable logging # Allow the user to enable/disable logging
setLogging() { setLogging() {
# Local, named variables # Ask the user if they want to enable logging
local LogToggleCommand dialog --no-shadow --clear \
local LogChooseOptions --backtitle "Pihole Installation" \
local LogChoices --title "Enable Logging" \
--yesno "\\n\\nWould you like to enable query logging?" \
"${r}" "${c}"
# Ask if the user wants to log queries result=$?
LogToggleCommand=(whiptail --separate-output --radiolist "Do you want to log queries?" "${r}" "${c}" 6) case ${result} in
# The default selection is on "${DIALOG_OK}")
LogChooseOptions=("On (Recommended)" "" on # If they chose yes,
Off "" off) printf " %b Query Logging on.\\n" "${INFO}"
# Get the user's choice
LogChoices=$("${LogToggleCommand[@]}" "${LogChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1)
case ${LogChoices} in
# If it's on,
"On (Recommended)")
printf " %b Logging On.\\n" "${INFO}"
# set the GLOBAL variable setting to true
QUERY_LOGGING=true QUERY_LOGGING=true
;; ;;
# Otherwise, it's off, "${DIALOG_CANCEL}")
Off) # If they chose no,
printf " %b Logging Off.\\n" "${INFO}" printf " %b Query Logging off.\\n" "${INFO}"
# set the GLOBAL variable setting to false
QUERY_LOGGING=false QUERY_LOGGING=false
;; ;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf " %bEscape pressed, exiting installer at Query Logging choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac esac
} }
# Allow the user to set their FTL privacy level # Allow the user to set their FTL privacy level
setPrivacyLevel() { setPrivacyLevel() {
local LevelCommand PRIVACY_LEVEL=$(dialog --no-shadow --clear --output-fd 1 \
local LevelOptions --radiolist "Select a privacy mode for FTL. https://docs.pi-hole.net/ftldns/privacylevels/" \
"${r}" "${c}" 6 \
LevelCommand=(whiptail --separate-output --radiolist "Select a privacy mode for FTL. https://docs.pi-hole.net/ftldns/privacylevels/" "${r}" "${c}" 6)
# The default selection is level 0 # The default selection is level 0
LevelOptions=( "0" "Show everything" on \
"0" "Show everything" on "1" "Hide domains" off \
"1" "Hide domains" off "2" "Hide domains and clients" off \
"2" "Hide domains and clients" off "3" "Anonymous mode" off)
"3" "Anonymous mode" off
)
# Get the user's choice result=$?
PRIVACY_LEVEL=$("${LevelCommand[@]}" "${LevelOptions[@]}" 2>&1 >/dev/tty) || (echo -e " ${COL_LIGHT_RED}Cancel was selected, exiting installer${COL_NC}" && exit 1) case ${result} in
"${DIALOG_OK}")
printf " %b Privacy level %d" "${INFO}" "${PRIVACY_LEVEL}" printf " %b Using privacy level: %s\\n" "${INFO}" "${PRIVACY_LEVEL}"
;;
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %b Cancelled privacy level selection.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
} }
# Function to ask the user if they want to install the dashboard # Function to ask the user if they want to install the dashboard
setAdminFlag() { setAdminFlag() {
# Local, named variables
local WebToggleCommand
local WebChooseOptions
local WebChoices
# Similar to the logging function, ask what the user wants # Similar to the logging function, ask what the user wants
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web admin interface?" "${r}" "${c}" 6) dialog --no-shadow --clear \
# with the default being enabled --backtitle "Pihole Installation" \
WebChooseOptions=("On (Recommended)" "" on --title "Admin Web Interface" \
Off "" off) --yesno "\\n\\nDo you want to install the Admin Web Interface?" \
WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1) "${r}" "${c}"
# Depending on their choice
case ${WebChoices} in result=$?
"On (Recommended)") case ${result} in
printf " %b Web Interface On\\n" "${INFO}" "${DIALOG_OK}")
# Set it to true # If they chose yes,
printf " %b Installing Admin Web Interface\\n" "${INFO}"
# Set the flag to install the web interface
INSTALL_WEB_INTERFACE=true INSTALL_WEB_INTERFACE=true
;; ;;
Off) "${DIALOG_CANCEL}")
printf " %b Web Interface Off\\n" "${INFO}" # If they chose no,
# or false printf " %b Not installing Admin Web Interface\\n" "${INFO}"
# Set the flag to not install the web interface
INSTALL_WEB_INTERFACE=false INSTALL_WEB_INTERFACE=false
# Deselect the web server as well, since it is obsolete then
INSTALL_WEB_SERVER=false INSTALL_WEB_SERVER=false
;; ;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf " %bEscape pressed, exiting installer at Admin Web Interface choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac esac
# If the user wants to install the Web admin interface (i.e. it has not been deselected above) # If the user wants to install the Web admin interface (i.e. it has not been deselected above)
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
# Get list of required PHP modules, excluding base package (common) and handler (cgi) # Get list of required PHP modules, excluding base package (common) and handler (cgi)
local i php_modules local i php_modules
for i in "${PIHOLE_WEB_DEPS[@]}"; do [[ $i == 'php'* && $i != *'-common' && $i != *'-cgi' ]] && php_modules+=" ${i#*-}"; done for i in "${PIHOLE_WEB_DEPS[@]}"; do [[ $i == 'php'* && $i != *'-common' && $i != *'-cgi' ]] && php_modules+=" ${i#*-}"; done
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web server (lighttpd) and required PHP modules?\\n\\nNB: If you disable this, and, do not have an existing web server and required PHP modules (${php_modules# }) installed, the web interface will not function. Additionally the web server user needs to be member of the \"pihole\" group for full functionality." "${r}" "${c}" 6) dialog --no-shadow --clear \
# Enable as default and recommended option --backtitle "Pi-hole Installation" \
WebChooseOptions=("On (Recommended)" "" on --title "Web Server" \
Off "" off) --yesno "\\n\\nA web server is required for the Admin Web Interface. \
WebChoices=$("${WebToggleCommand[@]}" "${WebChooseOptions[@]}" 2>&1 >/dev/tty) || (printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" && exit 1) \\n\\nDo you want to install lighttpd and the required PHP modules? \
# Depending on their choice \\n\\nNB: If you disable this, and, do not have an existing web server \
case ${WebChoices} in and required PHP modules (${php_modules# }) installed, the web interface \
"On (Recommended)") will not function. Additionally the web server user needs to be member of \
printf " %b Web Server On\\n" "${INFO}" the \"pihole\" group for full functionality." \
# set it to true, as clearly seen below. "${r}" "${c}"
result=$?
case ${result} in
"${DIALOG_OK}")
# If they chose yes,
printf " %b Installing lighttpd\\n" "${INFO}"
# Set the flag to install the web server
INSTALL_WEB_SERVER=true INSTALL_WEB_SERVER=true
;; ;;
Off) "${DIALOG_CANCEL}")
printf " %b Web Server Off\\n" "${INFO}" # If they chose no,
# or false printf " %b Not installing lighttpd\\n" "${INFO}"
# Set the flag to not install the web server
INSTALL_WEB_SERVER=false INSTALL_WEB_SERVER=false
;; ;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf " %bEscape pressed, exiting installer at web server choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac esac
fi fi
} }
@ -1133,18 +1296,33 @@ chooseBlocklists() {
if [[ -f "${adlistFile}" ]]; then if [[ -f "${adlistFile}" ]]; then
mv "${adlistFile}" "${adlistFile}.old" mv "${adlistFile}" "${adlistFile}.old"
fi fi
# Let user select (or not) blocklists via a checklist # Let user select (or not) blocklists
cmd=(whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestion below, and/or add your own after installation\\n\\nTo deselect the suggested list, use spacebar" "${r}" "${c}" 5) dialog --no-shadow --clear \
# In an array, show the options available (all off by default): --backtitle "Pi-hole Installation" \
options=(StevenBlack "StevenBlack's Unified Hosts List" on) --title "Blocklists" \
--yesno "\\nPi-hole relies on third party lists in order to block ads. \
\\n\\nYou can use the suggestion below, and/or add your own after installation. \
\\n\\nSelect 'Yes' to include: \
\\n\\nStevenBlack's Unified Hosts List" \
"${r}" "${c}"
# In a variable, show the choices available; exit if Cancel is selected result=$?
choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) || { printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; rm "${adlistFile}" ;exit 1; } case ${result} in
# Add all selected choices to the lists file "${DIALOG_OK}")
for choice in ${choices} # If they chose yes,
do printf " %b Installing StevenBlack's Unified Hosts List\\n" "${INFO}"
appendToListsFile "${choice}" echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >> "${adlistFile}"
done ;;
"${DIALOG_CANCEL}")
# If they chose no,
printf " %b Not installing StevenBlack's Unified Hosts List\\n" "${INFO}"
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf " %bEscape pressed, exiting installer at blocklist choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
# Create an empty adList file with appropriate permissions. # Create an empty adList file with appropriate permissions.
if [ ! -f "${adlistFile}" ]; then if [ ! -f "${adlistFile}" ]; then
install -m 644 /dev/null "${adlistFile}" install -m 644 /dev/null "${adlistFile}"
@ -1153,14 +1331,6 @@ chooseBlocklists() {
fi fi
} }
# Accept a string parameter, it must be one of the default lists
# This function saves duplication between chooseBlocklists and installDefaultBlocklists
appendToListsFile() {
case $1 in
StevenBlack ) echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >> "${adlistFile}";;
esac
}
# Used only in unattended setup # Used only in unattended setup
# If there is already the adListFile, we keep it, else we create it using all default lists # If there is already the adListFile, we keep it, else we create it using all default lists
installDefaultBlocklists() { installDefaultBlocklists() {
@ -1169,7 +1339,7 @@ installDefaultBlocklists() {
if [[ -f "${adlistFile}" ]]; then if [[ -f "${adlistFile}" ]]; then
return; return;
fi fi
appendToListsFile StevenBlack echo "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" >> "${adlistFile}"
} }
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory # Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
@ -1940,14 +2110,14 @@ Your Admin Webpage login password is ${pwstring}"
fi fi
# Final completion message to user # Final completion message to user
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!" "Configure your devices to use the Pi-hole as their DNS server using: dialog --no-shadow --clear \
--title "Installation Complete!" \
IPv4: ${IPV4_ADDRESS%/*} --msgbox "Configure your devices to use the Pi-hole as their DNS server using: \
IPv6: ${IPV6_ADDRESS:-"Not Configured"} \\n\\nIPv4: ${IPV4_ADDRESS%/*} \
\\nIPv6: ${IPV6_ADDRESS:-"Not Configured"} \
If you have not done so already, the above IP should be set to static. \\nIf you have not done so already, the above IP should be set to static. \
\\n${additional}"
${additional}" "${r}" "${c}" "${r}" "${c}"
} }
update_dialogs() { update_dialogs() {
@ -1967,20 +2137,32 @@ update_dialogs() {
opt2b="Resets Pi-hole and allows re-selecting settings." opt2b="Resets Pi-hole and allows re-selecting settings."
# Display the information to the user # Display the information to the user
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the following options: \\n($strAdd)" "${r}" "${c}" 2 \ UpdateCmd=$(dialog --no-shadow --clear --output-fd 1 \
--title "Existing Install Detected!" \
--menu "\\n\\nWe have detected an existing install. \
\\n\\nPlease choose from the following options: \
\\n($strAdd)" \
"${r}" "${c}" 2 \
"${opt1a}" "${opt1b}" \ "${opt1a}" "${opt1b}" \
"${opt2a}" "${opt2b}" 3>&2 2>&1 1>&3) || \ "${opt2a}" "${opt2b}")
{ printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"; exit 1; }
result=$?
case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %bCancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
exit 1
;;
esac
# Set the variable based on if the user chooses # Set the variable based on if the user chooses
case ${UpdateCmd} in case ${UpdateCmd} in
# repair, or # repair, or
${opt1a}) "${opt1a}")
printf " %b %s option selected\\n" "${INFO}" "${opt1a}" printf " %b %s option selected\\n" "${INFO}" "${opt1a}"
useUpdateVars=true useUpdateVars=true
;; ;;
# reconfigure, # reconfigure,
${opt2a}) "${opt2a}")
printf " %b %s option selected\\n" "${INFO}" "${opt2a}" printf " %b %s option selected\\n" "${INFO}" "${opt2a}"
useUpdateVars=false useUpdateVars=false
;; ;;
@ -2478,7 +2660,7 @@ main() {
if [[ -f "${setupVars}" ]]; then if [[ -f "${setupVars}" ]]; then
# if it's running unattended, # if it's running unattended,
if [[ "${runUnattended}" == true ]]; then if [[ "${runUnattended}" == true ]]; then
printf " %b Performing unattended setup, no whiptail dialogs will be displayed\\n" "${INFO}" printf " %b Performing unattended setup, no dialogs will be displayed\\n" "${INFO}"
# Use the setup variables # Use the setup variables
useUpdateVars=true useUpdateVars=true
# also disable debconf-apt-progress dialogs # also disable debconf-apt-progress dialogs