diff --git a/.stickler.yml b/.stickler.yml
index b96fc2e7..0eaae8cb 100644
--- a/.stickler.yml
+++ b/.stickler.yml
@@ -1,3 +1,6 @@
linters:
shellcheck:
shell: bash
+ phpcs:
+ csslint:
+ flake8:
diff --git a/.travis.yml b/.travis.yml
index 2ca3b2d2..fa525e01 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,4 +7,6 @@ python:
install:
- pip install -r requirements.txt
-script: py.test -vv
+script:
+ # tox.ini handles setup, ordering of docker build first, and then run tests
+ - tox
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2b7fae5d..e32b500e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,3 @@
-_This template was created based on the work of [`udemy-dl`](https://github.com/nishad/udemy-dl/blob/master/LICENSE)._
-
# Contributors Guide
Please read and understand the contribution guide before creating an issue or pull request.
diff --git a/README.md b/README.md
index b7f4f249..77f259e6 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
Network-wide ad blocking via your own Linux hardware
-The Pi-hole is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
+The Pi-hole[®](https://pi-hole.net/trademark-rules-and-brand-guidelines/) is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content, without installing any client-side software.
- **Easy-to-install**: our versatile installer walks you through the process, and [takes less than ten minutes](https://www.youtube.com/watch?v=vKWjx1AQYgs)
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
@@ -27,7 +27,7 @@ Those who want to get started quickly and conveniently, may install Pi-hole usin
#### `curl -sSL https://install.pi-hole.net | bash`
## Alternative Install Methods
-[Piping to `bash` is controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
+[Piping to `bash` is controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash), as it prevents you from [reading code that is about to run](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) on your system. Therefore, we provide these alternative installation methods which allow code review before installation:
### Method 1: Clone our repository and run
```
@@ -60,16 +60,21 @@ Make no mistake: **your support is absolutely vital to help keep us innovating!*
### Donations
Sending a donation using our links below is **extremely helpful** in offsetting a portion of our monthly expenses:
- Donate via PayPal
- Bitcoin Address: 1GKnevUnVaQM2pQieMyeHkpr8DXfkpfAtL
+- Donate via PayPal
+- [Bitcoin](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763):
+3MDPzjXu2hjw5sGLJvKUi1uXbvQPzVrbpF
+- [Bitcoin Cash](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): qzqsz4aju2eecc6uhs7tus4vlwhhela24sdruf4qp5
+- [Ethereum](https://commerce.coinbase.com/checkout/fb7facaf-bebd-46be-bb77-b358f4546763): 0x79d4e90A4a0C732819526c93e21A3F1356A2FAe1
### Alternative support
-If you'd rather not donate (_which is okay!_), there are other ways you can help support us:
-
-- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) affiliate link
-- [Vultr](http://www.vultr.com/?ref=7190426) affiliate link
-- [UNIXstickers.com](http://unixstickers.refr.cc/jacobs) affiliate link
-- [Pi-hole Swag Store](https://pi-hole.net/shop/)
+If you'd rather not [donate](https://pi-hole.net/donate/) (_which is okay!_), there are other ways you can help support us:
+- [Patreon](https://patreon.com/pihole) _Become a patron for rewards_
+- [Digital Ocean](http://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
+- [UNIXstickers.com](http://unixstickers.refr.cc/jacobs) _save $5 when you spend $9 using our affiliate link_
+- [Pi-hole Swag Store](https://pi-hole.net/shop/) _affiliate link_
+- [Amazon](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
+- [DNS Made Easy](https://cp.dnsmadeeasy.com/u/133706) _affiliate link_
+- [Vultr](http://www.vultr.com/?ref=7190426) _affiliate link_
- Spreading the word about our software, and how you have benefited from it
### Contributing via GitHub
@@ -93,9 +98,6 @@ While we are primarily reachable on our Frequently Asked Questions
@@ -127,7 +129,7 @@ You can read our [Core Feature Breakdown](https://github.com/pi-hole/pi-hole/wik
### The Web Interface Dashboard
This [optional dashboard](https://github.com/pi-hole/AdminLTE) allows you to view stats, change settings, and configure your Pi-hole. It's the power of the Command Line Interface, with none of the learning curve!
-
+
Some notable features include:
* Mobile friendly interface
@@ -142,11 +144,11 @@ Some notable features include:
There are several ways to [access the dashboard](https://discourse.pi-hole.net/t/how-do-i-access-pi-holes-dashboard-admin-interface/3168):
1. `http:///admin/`
-2. `http:/pi.hole/admin/` (when using Pi-hole as your DNS server)
+2. `http://pi.hole/admin/` (when using Pi-hole as your DNS server)
3. `http://pi.hole/` (when using Pi-hole as your DNS server)
-## The Faster-Than-Light Engine
-The [FTL Engine](https://github.com/pi-hole/FTL) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTL does this all *very quickly*!
+## Faster-than-light Engine
+FTLDNS[™](https://pi-hole.net/trademark-rules-and-brand-guidelines/) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
Some of the statistics you can integrate include:
* Total number of domains being blocked
@@ -172,31 +174,13 @@ Pi-hole being a **advertising-aware DNS/Web server**, makes use of the following
* [AdminLTE Dashboard](https://github.com/almasaeed2010/AdminLTE) - premium admin control panel based on Bootstrap 3.x
While quite outdated at this point, [this original blog post about Pi-hole](https://jacobsalmela.com/2015/06/16/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0/) goes into **great detail** about how Pi-hole was originally setup and how it works. Syntactically, it's no longer accurate, but the same basic principles and logic still apply to Pi-hole's current state.
-
------
-
-## Pi-hole Projects
-- [The Big Blocklist Collection](https://wally3k.github.io)
-- [Docker Pi-hole container (x86 and ARM)](https://hub.docker.com/r/diginc/pi-hole/)
-- [Pi-Hole in the cloud](http://blog.codybunch.com/2015/07/28/Pi-Hole-in-the-cloud/)
-- [Pie in the Sky-Hole [A Pi-Hole in the cloud for ad-blocking via DNS]](https://dlaa.me/blog/post/skyhole)
-- [Pi-hole Enable/Disable Button](http://thetimmy.silvernight.org/pages/endisbutton/)
-- [Minibian Pi-hole](https://munkjensen.net/wiki/index.php/See_my_Pi-Hole#Minibian_Pi-hole)
-- [CHiP-hole: Network-wide Ad-blocker](https://www.hackster.io/jacobsalmela/chip-hole-network-wide-ad-blocker-98e037)
-- [Chrome Extension: Pi-Hole List Editor](https://chrome.google.com/webstore/detail/pi-hole-list-editor/hlnoeoejkllgkjbnnnhfolapllcnaglh) ([Source Code](https://github.com/packtloss/pihole-extension))
-- [Splunk: Pi-hole Visualiser](https://splunkbase.splunk.com/app/3023/)
-- [Adblocking with Pi-hole and Ubuntu 14.04 on VirtualBox](https://hbalagtas.blogspot.com.au/2016/02/adblocking-with-pi-hole-and-ubuntu-1404.html)
-- [Pi-hole stats in your Mac's menu bar](https://getbitbar.com/plugins/Network/pi-hole.1m.py)
-- [Pi-hole unRAID Template](https://forums.lime-technology.com/topic/36810-support-spants-nodered-mqtt-dashing-couchdb/)
-- [Copernicus: Windows Tray Application](https://github.com/goldbattle/copernicus)
-- [Let your blink1 device blink when Pi-hole filters ads](https://gist.github.com/elpatron68/ec0b4c582e5abf604885ac1e068d233f)
-- [Pi-hole metrics](https://github.com/nlamirault/pihole_exporter) exporter for [Prometheus](https://prometheus.io/)
-- [Magic Mirror with DNS Filtering](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
-- [Pi-hole Droid: Android client](https://github.com/friimaind/pi-hole-droid)
-- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper), see [#1400](https://github.com/pi-hole/pi-hole/issues/1400)
-----
## Coverage
+- [Software Engineering Daily: Interview with the creator of Pi-hole](https://softwareengineeringdaily.com/2018/05/29/pi-hole-ad-blocker-hardware-with-jacob-salmela/)
+- [Bloomberg Business Week: Brotherhood of the Ad blockers](https://www.bloomberg.com/news/features/2018-05-10/inside-the-brotherhood-of-pi-hole-ad-blockers)
+- [Securing DNS across all of my devices with Pi-Hole + DNS-over-HTTPS + 1.1.1.1](https://scotthelme.co.uk/securing-dns-across-all-of-my-devices-with-pihole-dns-over-https-1-1-1-1/)
+- [Adafruit: installing Pi-hole on a Pi Zero W](https://learn.adafruit.com/pi-hole-ad-blocker-with-pi-zero-w/install-pi-hole)
- [Lifehacker: Turn A Raspberry Pi Into An Ad Blocker With A Single Command](https://www.lifehacker.com.au/2015/02/turn-a-raspberry-pi-into-an-ad-blocker-with-a-single-command/)
- [MakeUseOf: Adblock Everywhere: The Raspberry Pi-Hole Way](http://www.makeuseof.com/tag/adblock-everywhere-raspberry-pi-hole-way/)
- [Catchpoint: Ad-Blocking on Apple iOS9: Valuing the End User Experience](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
@@ -215,3 +199,12 @@ While quite outdated at this point, [this original blog post about Pi-hole](http
- [CryptoAUSTRALIA: How We Tried 5 Privacy Focused Raspberry Pi Projects](https://blog.cryptoaustralia.org.au/2017/10/05/5-privacy-focused-raspberry-pi-projects/)
- [CryptoAUSTRALIA: Pi-hole Workshop](https://blog.cryptoaustralia.org.au/2017/11/02/pi-hole-network-wide-ad-blocker/)
- [Know How 355: Killing ads with a Raspberry Pi-Hole!](https://www.twit.tv/shows/know-how/episodes/355)
+
+-----
+
+## Pi-hole Projects
+- [The Big Blocklist Collection](https://wally3k.github.io)
+- [Pie in the Sky-Hole](https://dlaa.me/blog/post/skyhole)
+- [Copernicus: Windows Tray Application](https://github.com/goldbattle/copernicus)
+- [Magic Mirror with DNS Filtering](https://zonksec.com/blog/magic-mirror-dns-filtering/#dnssoftware)
+- [Windows DNS Swapper](https://github.com/roots84/DNS-Swapper)
diff --git a/adlists.default b/adlists.default
deleted file mode 100644
index cbc1bfb3..00000000
--- a/adlists.default
+++ /dev/null
@@ -1,23 +0,0 @@
-# The below list amalgamates several lists we used previously.
-# See `https://github.com/StevenBlack/hosts` for details
-##StevenBlack's list
-https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
-
-##MalwareDomains
-https://mirror1.malwaredomains.com/files/justdomains
-
-##Cameleon
-http://sysctl.org/cameleon/hosts
-
-##Zeustracker
-https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist
-
-##Disconnect.me Tracking
-https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
-
-##Disconnect.me Ads
-https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
-
-##Hosts-file.net
-https://hosts-file.net/ad_servers.txt
-
diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh
index 13d743a8..046a98c4 100755
--- a/advanced/Scripts/chronometer.sh
+++ b/advanced/Scripts/chronometer.sh
@@ -12,539 +12,537 @@ LC_NUMERIC=C
# Retrieve stats from FTL engine
pihole-FTL() {
- ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null)
- if [[ -n "$ftl_port" ]]; then
- # Open connection to FTL
- exec 3<>"/dev/tcp/127.0.0.1/$ftl_port"
+ ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null)
+ if [[ -n "$ftl_port" ]]; then
+ # Open connection to FTL
+ exec 3<>"/dev/tcp/127.0.0.1/$ftl_port"
- # Test if connection is open
- if { "true" >&3; } 2> /dev/null; then
- # Send command to FTL
- echo -e ">$1" >&3
+ # Test if connection is open
+ if { "true" >&3; } 2> /dev/null; then
+ # Send command to FTL
+ echo -e ">$1" >&3
- # Read input
- read -r -t 1 LINE <&3
- until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
- echo "$LINE" >&1
- read -r -t 1 LINE <&3
- done
+ # Read input
+ read -r -t 1 LINE <&3
+ until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do
+ echo "$LINE" >&1
+ read -r -t 1 LINE <&3
+ done
- # Close connection
- exec 3>&-
- exec 3<&-
- fi
- else
- echo "0"
- fi
+ # Close connection
+ exec 3>&-
+ exec 3<&-
+ fi
+ else
+ echo "0"
+ fi
}
# Print spaces to align right-side additional text
printFunc() {
- local text_last
+ local text_last
- title="$1"
- title_len="${#title}"
+ title="$1"
+ title_len="${#title}"
- text_main="$2"
- text_main_nocol="$text_main"
- if [[ "${text_main:0:1}" == "" ]]; then
- text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main")
- fi
- text_main_len="${#text_main_nocol}"
+ text_main="$2"
+ text_main_nocol="$text_main"
+ if [[ "${text_main:0:1}" == "" ]]; then
+ text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main")
+ fi
+ text_main_len="${#text_main_nocol}"
- text_addn="$3"
- if [[ "$text_addn" == "last" ]]; then
- text_addn=""
- text_last="true"
- fi
+ text_addn="$3"
+ if [[ "$text_addn" == "last" ]]; then
+ text_addn=""
+ text_last="true"
+ fi
- # If there is additional text, define max length of text_main
- if [[ -n "$text_addn" ]]; then
- case "$scr_cols" in
- [0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";;
- 4[5-9]) text_main_max_len="14";;
- *) text_main_max_len="19";;
- esac
- fi
+ # If there is additional text, define max length of text_main
+ if [[ -n "$text_addn" ]]; then
+ case "$scr_cols" in
+ [0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";;
+ 4[5-9]) text_main_max_len="14";;
+ *) text_main_max_len="19";;
+ esac
+ fi
- [[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))"
+ [[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))"
- # Remove excess characters from main text
- if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then
- # Trim text without colours
- text_main_trim="${text_main_nocol:0:$text_main_max_len}"
- # Replace with trimmed text
- text_main="${text_main/$text_main_nocol/$text_main_trim}"
- fi
+ # Remove excess characters from main text
+ if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then
+ # Trim text without colours
+ text_main_trim="${text_main_nocol:0:$text_main_max_len}"
+ # Replace with trimmed text
+ text_main="${text_main/$text_main_nocol/$text_main_trim}"
+ fi
- # Determine amount of spaces for each line
- if [[ -n "$text_last" ]]; then
- # Move cursor to end of screen
- spc_num=$(( scr_cols - ( title_len + text_main_len ) ))
- else
- spc_num=$(( text_main_max_len - text_main_len ))
- fi
+ # Determine amount of spaces for each line
+ if [[ -n "$text_last" ]]; then
+ # Move cursor to end of screen
+ spc_num=$(( scr_cols - ( title_len + text_main_len ) ))
+ else
+ spc_num=$(( text_main_max_len - text_main_len ))
+ fi
- [[ "$spc_num" -le 0 ]] && spc_num="0"
- spc=$(printf "%${spc_num}s")
- #spc="${spc// /.}" # Debug: Visualise spaces
+ [[ "$spc_num" -le 0 ]] && spc_num="0"
+ spc=$(printf "%${spc_num}s")
+ #spc="${spc// /.}" # Debug: Visualise spaces
- printf "%s%s$spc" "$title" "$text_main"
+ printf "%s%s$spc" "$title" "$text_main"
- if [[ -n "$text_addn" ]]; then
- printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC"
- else
- # Do not print trailing newline on final line
- [[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC"
- fi
+ if [[ -n "$text_addn" ]]; then
+ printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC"
+ else
+ # Do not print trailing newline on final line
+ [[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC"
+ fi
}
# Perform on first Chrono run (not for JSON formatted string)
get_init_stats() {
- calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; }
+ calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; }
- # Convert bytes to human-readable format
- hrBytes() {
- awk '{
- num=$1;
- if(num==0) {
- print "0 B"
- } else {
- xxx=(num<0?-num:num)
- sss=(num<0?-1:1)
- split("B KB MB GB TB PB",type)
- for(i=5;yyy < 1;i--) {
- yyy=xxx / (2^(10*i))
- }
- printf "%.0f " type[i+2], yyy*sss
- }
- }' <<< "$1";
- }
+ # Convert bytes to human-readable format
+ hrBytes() {
+ awk '{
+ num=$1;
+ if(num==0) {
+ print "0 B"
+ } else {
+ xxx=(num<0?-num:num)
+ sss=(num<0?-1:1)
+ split("B KB MB GB TB PB",type)
+ for(i=5;yyy < 1;i--) {
+ yyy=xxx / (2^(10*i))
+ }
+ printf "%.0f " type[i+2], yyy*sss
+ }
+ }' <<< "$1";
+ }
- # Convert seconds to human-readable format
- hrSecs() {
- day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 ))
- mins=$(( ($1%3600)/60 )); secs=$(( $1%60 ))
- [[ "$day" -ge "2" ]] && plu="s"
- [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days=""
- printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs"
- }
+ # Convert seconds to human-readable format
+ hrSecs() {
+ day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 ))
+ mins=$(( ($1%3600)/60 )); secs=$(( $1%60 ))
+ [[ "$day" -ge "2" ]] && plu="s"
+ [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days=""
+ printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs"
+ }
- # Set Colour Codes
- coltable="/opt/pihole/COL_TABLE"
- if [[ -f "${coltable}" ]]; then
- source ${coltable}
- else
- COL_NC="[0m"
- COL_DARK_GRAY="[1;30m"
- COL_LIGHT_GREEN="[1;32m"
- COL_LIGHT_BLUE="[1;34m"
- COL_LIGHT_RED="[1;31m"
- COL_YELLOW="[1;33m"
- COL_LIGHT_RED="[1;31m"
- COL_URG_RED="[39;41m"
- fi
-
- # Get RPi throttle state (RPi 3B only) & model number, or OS distro info
- if command -v vcgencmd &> /dev/null; then
- local sys_throttle_raw
- local sys_rev_raw
-
- sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}")
-
- # Active Throttle Notice: http://bit.ly/2gnunOo
- if [[ "$sys_throttle_raw" != "0" ]]; then
- case "$sys_throttle_raw" in
- *0001) thr_type="${COL_YELLOW}Under Voltage";;
- *0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";;
- *0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";;
- *0004) thr_type="${COL_LIGHT_RED}Throttled";;
- *0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
- *0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
- *0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
- esac
- [[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}"
+ # Set Colour Codes
+ coltable="/opt/pihole/COL_TABLE"
+ if [[ -f "${coltable}" ]]; then
+ source ${coltable}
+ else
+ COL_NC="[0m"
+ COL_DARK_GRAY="[1;30m"
+ COL_LIGHT_GREEN="[1;32m"
+ COL_LIGHT_BLUE="[1;34m"
+ COL_LIGHT_RED="[1;31m"
+ COL_YELLOW="[1;33m"
+ COL_LIGHT_RED="[1;31m"
+ COL_URG_RED="[39;41m"
fi
- sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
- case "$sys_rev_raw" in
- 000[2-6]) sys_model=" 1, Model B";; # 256MB
- 000[7-9]) sys_model=" 1, Model A";; # 256MB
- 000d|000e|000f) sys_model=" 1, Model B";; # 512MB
- 0010|0013) sys_model=" 1, Model B+";; # 512MB
- 0012|0015) sys_model=" 1, Model A+";; # 256MB
- a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB
- 900021) sys_model=" 1, Model A+";; # 512MB
- 900032) sys_model=" 1, Model B+";; # 512MB
- 90009[2-3]|920093) sys_model=" Zero";; # 512MB
- 9000c1) sys_model=" Zero W";; # 512MB
- a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
- *) sys_model="";;
- esac
- sys_type="Raspberry Pi$sys_model"
- else
- source "/etc/os-release"
- CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}")
- sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID"
- fi
+ # Get RPi throttle state (RPi 3B only) & model number, or OS distro info
+ if command -v vcgencmd &> /dev/null; then
+ local sys_throttle_raw
+ local sys_rev_raw
- # Get core count
- sys_cores=$(grep -c "^processor" /proc/cpuinfo)
+ sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}")
- # Test existence of clock speed file for ARM CPU
- if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then
- scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
- fi
+ # Active Throttle Notice: http://bit.ly/2gnunOo
+ if [[ "$sys_throttle_raw" != "0" ]]; then
+ case "$sys_throttle_raw" in
+ *0001) thr_type="${COL_YELLOW}Under Voltage";;
+ *0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";;
+ *0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";;
+ *0004) thr_type="${COL_LIGHT_RED}Throttled";;
+ *0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
+ *0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
+ *0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";;
+ esac
+ [[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}"
+ fi
- # Test existence of temperature file
- if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then
- temp_file="/sys/class/thermal/thermal_zone0/temp"
- elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then
- temp_file="/sys/class/hwmon/hwmon0/temp1_input"
- else
- temp_file=""
- fi
+ sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo)
+ case "$sys_rev_raw" in
+ 000[2-6]) sys_model=" 1, Model B";; # 256MB
+ 000[7-9]) sys_model=" 1, Model A";; # 256MB
+ 000d|000e|000f) sys_model=" 1, Model B";; # 512MB
+ 0010|0013) sys_model=" 1, Model B+";; # 512MB
+ 0012|0015) sys_model=" 1, Model A+";; # 256MB
+ a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB
+ 900021) sys_model=" 1, Model A+";; # 512MB
+ 900032) sys_model=" 1, Model B+";; # 512MB
+ 90009[2-3]|920093) sys_model=" Zero";; # 512MB
+ 9000c1) sys_model=" Zero W";; # 512MB
+ a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB
+ a020d3) sys_model=" 3, Model B+";; # 1GB
+ *) sys_model="";;
+ esac
+ sys_type="Raspberry Pi$sys_model"
+ else
+ source "/etc/os-release"
+ CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}")
+ sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID"
+ fi
- # Test existence of setupVars config
- if [[ -f "/etc/pihole/setupVars.conf" ]]; then
- setupVars="/etc/pihole/setupVars.conf"
- fi
+ # Get core count
+ sys_cores=$(grep -c "^processor" /proc/cpuinfo)
+
+ # Test existence of clock speed file for ARM CPU
+ if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then
+ scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
+ fi
+
+ # Test existence of temperature file
+ if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then
+ temp_file="/sys/class/thermal/thermal_zone0/temp"
+ elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then
+ temp_file="/sys/class/hwmon/hwmon0/temp1_input"
+ else
+ temp_file=""
+ fi
+
+ # Test existence of setupVars config
+ if [[ -f "/etc/pihole/setupVars.conf" ]]; then
+ setupVars="/etc/pihole/setupVars.conf"
+ fi
}
get_sys_stats() {
- local ph_ver_raw
- local cpu_raw
- local ram_raw
- local disk_raw
+ local ph_ver_raw
+ local cpu_raw
+ local ram_raw
+ local disk_raw
- # Update every 12 refreshes (Def: every 60s)
- count=$((count+1))
- if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then
- # Do not source setupVars if file does not exist
- [[ -n "$setupVars" ]] && source "$setupVars"
+ # Update every 12 refreshes (Def: every 60s)
+ count=$((count+1))
+ if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then
+ # Do not source setupVars if file does not exist
+ [[ -n "$setupVars" ]] && source "$setupVars"
- mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')
- if [[ -n "${ph_ver_raw[0]}" ]]; then
- ph_core_ver="${ph_ver_raw[0]}"
- ph_lte_ver="${ph_ver_raw[1]}"
- ph_ftl_ver="${ph_ver_raw[2]}"
- else
- ph_core_ver="-1"
+ mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p')
+ if [[ -n "${ph_ver_raw[0]}" ]]; then
+ ph_core_ver="${ph_ver_raw[0]}"
+ ph_lte_ver="${ph_ver_raw[1]}"
+ ph_ftl_ver="${ph_ver_raw[2]}"
+ else
+ ph_core_ver="-1"
+ fi
+
+ sys_name=$(hostname)
+
+ [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c"
+
+ # Get storage stats for partition mounted on /
+ read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')"
+ disk_used="${disk_raw[0]}"
+ disk_total="${disk_raw[1]}"
+ disk_perc="${disk_raw[2]}"
+
+ net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}')
+
+ # Get DHCP stats, if feature is enabled
+ if [[ "$DHCP_ACTIVE" == "true" ]]; then
+ ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
+ fi
+
+ # Get DNS server count
+ dns_count="0"
+ [[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1))
+ [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+"
fi
- sys_name=$(hostname)
+ # Get screen size
+ read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)"
+ scr_lines="${scr_size[0]}"
+ scr_cols="${scr_size[1]}"
- [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c"
+ # Determine Chronometer size behaviour
+ if [[ "$scr_cols" -ge 58 ]]; then
+ chrono_width="large"
+ elif [[ "$scr_cols" -gt 40 ]]; then
+ chrono_width="medium"
+ else
+ chrono_width="small"
+ fi
- # Get storage stats for partition mounted on /
- read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')"
- disk_used="${disk_raw[0]}"
- disk_total="${disk_raw[1]}"
- disk_perc="${disk_raw[2]}"
+ # Determine max length of divider string
+ scr_line_len=$(( scr_cols - 2 ))
+ [[ "$scr_line_len" -ge 58 ]] && scr_line_len="58"
+ scr_line_str=$(printf "%${scr_line_len}s")
+ scr_line_str="${scr_line_str// /—}"
- net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}')
+ sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)")
+ sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg)
+
+ # Get CPU usage, only counting processes over 1% as active
+ # shellcheck disable=SC2009
+ cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0")
+ cpu_tasks=$(wc -l <<< "$cpu_raw")
+ cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l)
+ cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw")
+
+ # Get CPU clock speed
+ if [[ -n "$scaling_freq_file" ]]; then
+ cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
+ else
+ cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}')
+ cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}")
+ fi
+
+ # Determine whether to display CPU clock speed as MHz or GHz
+ if [[ -n "$cpu_mhz" ]]; then
+ [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz"
+ [[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}"
+ fi
+
+ # Determine colour for temperature
+ if [[ -n "$temp_file" ]]; then
+ if [[ "$temp_unit" == "C" ]]; then
+ cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")")
+
+ case "${cpu_temp::-1}" in
+ -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";;
+ 4[0-9]) cpu_col="";;
+ 5[0-9]) cpu_col="$COL_YELLOW";;
+ 6[0-9]) cpu_col="$COL_LIGHT_RED";;
+ *) cpu_col="$COL_URG_RED";;
+ esac
+
+ # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
+ cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
+
+ elif [[ "$temp_unit" == "F" ]]; then
+ cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
+
+ case "${cpu_temp::-1}" in
+ -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";;
+ 1[0-1][0-9]) cpu_col="";;
+ 1[2-3][0-9]) cpu_col="$COL_YELLOW";;
+ 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";;
+ *) cpu_col="$COL_URG_RED";;
+ esac
+
+ cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
+
+ else
+ cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")")
+ fi
+ else
+ cpu_temp_str=""
+ fi
+
+ read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)"
+ ram_perc="${ram_raw[0]}"
+ ram_used="${ram_raw[1]}"
+ ram_total="${ram_raw[2]}"
+
+ if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
+ ph_status="${COL_LIGHT_GREEN}Active"
+ else
+ ph_status="${COL_LIGHT_RED}Offline"
+ fi
- # Get DHCP stats, if feature is enabled
if [[ "$DHCP_ACTIVE" == "true" ]]; then
- ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 ))
+ local ph_dhcp_range
+
+ ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}")
+
+ # Count dynamic leases from available range, and not static leases
+ ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases")
+ ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max ))
fi
-
- # Get DNS server count
- dns_count="0"
- [[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1))
- [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+"
- fi
-
- # Get screen size
- read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)"
- scr_lines="${scr_size[0]}"
- scr_cols="${scr_size[1]}"
-
- # Determine Chronometer size behaviour
- if [[ "$scr_cols" -ge 58 ]]; then
- chrono_width="large"
- elif [[ "$scr_cols" -gt 40 ]]; then
- chrono_width="medium"
- else
- chrono_width="small"
- fi
-
- # Determine max length of divider string
- scr_line_len=$(( scr_cols - 2 ))
- [[ "$scr_line_len" -ge 58 ]] && scr_line_len="58"
- scr_line_str=$(printf "%${scr_line_len}s")
- scr_line_str="${scr_line_str// /—}"
-
- sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)")
- sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg)
-
- # Get CPU usage, only counting processes over 1% as active
- # shellcheck disable=SC2009
- cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0")
- cpu_tasks=$(wc -l <<< "$cpu_raw")
- cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l)
- cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw")
-
- # Get CPU clock speed
- if [[ -n "$scaling_freq_file" ]]; then
- cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 ))
- else
- cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}')
- cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}")
- fi
-
- # Determine whether to display CPU clock speed as MHz or GHz
- if [[ -n "$cpu_mhz" ]]; then
- [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz"
- [[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}"
- fi
-
- # Determine colour for temperature
- if [[ -n "$temp_file" ]]; then
- if [[ "$temp_unit" == "C" ]]; then
- cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")")
-
- case "${cpu_temp::-1}" in
- -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";;
- 4[0-9]) cpu_col="";;
- 5[0-9]) cpu_col="$COL_YELLOW";;
- 6[0-9]) cpu_col="$COL_LIGHT_RED";;
- *) cpu_col="$COL_URG_RED";;
- esac
-
- # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED
- cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
-
- elif [[ "$temp_unit" == "F" ]]; then
- cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")")
-
- case "${cpu_temp::-1}" in
- -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";;
- 1[0-1][0-9]) cpu_col="";;
- 1[2-3][0-9]) cpu_col="$COL_YELLOW";;
- 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";;
- *) cpu_col="$COL_URG_RED";;
- esac
-
- cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY"
-
- else
- cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")")
- fi
- else
- cpu_temp_str=""
- fi
-
- read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)"
- ram_perc="${ram_raw[0]}"
- ram_used="${ram_raw[1]}"
- ram_total="${ram_raw[2]}"
-
- if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then
- ph_status="${COL_LIGHT_GREEN}Active"
- else
- ph_status="${COL_LIGHT_RED}Offline"
- fi
-
- if [[ "$DHCP_ACTIVE" == "true" ]]; then
- local ph_dhcp_range
-
- ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}")
-
- # Count dynamic leases from available range, and not static leases
- ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases")
- ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max ))
- fi
}
get_ftl_stats() {
- local stats_raw
+ local stats_raw
- mapfile -t stats_raw < <(pihole-FTL "stats")
- domains_being_blocked_raw="${stats_raw[0]#* }"
- dns_queries_today_raw="${stats_raw[1]#* }"
- ads_blocked_today_raw="${stats_raw[2]#* }"
- ads_percentage_today_raw="${stats_raw[3]#* }"
- queries_forwarded_raw="${stats_raw[5]#* }"
- queries_cached_raw="${stats_raw[6]#* }"
+ mapfile -t stats_raw < <(pihole-FTL "stats")
+ domains_being_blocked_raw="${stats_raw[0]#* }"
+ dns_queries_today_raw="${stats_raw[1]#* }"
+ ads_blocked_today_raw="${stats_raw[2]#* }"
+ ads_percentage_today_raw="${stats_raw[3]#* }"
+ queries_forwarded_raw="${stats_raw[5]#* }"
+ queries_cached_raw="${stats_raw[6]#* }"
- # Only retrieve these stats when not called from jsonFunc
- if [[ -z "$1" ]]; then
- local top_ad_raw
- local top_domain_raw
- local top_client_raw
+ # Only retrieve these stats when not called from jsonFunc
+ if [[ -z "$1" ]]; then
+ local top_ad_raw
+ local top_domain_raw
+ local top_client_raw
- domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null)
- dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}")
- ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}")
- ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}")
- queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")")
- recent_blocked=$(pihole-FTL recentBlocked)
- read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")"
- read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")"
- read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")"
+ domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null)
+ dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}")
+ ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}")
+ ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}")
+ queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")")
+ recent_blocked=$(pihole-FTL recentBlocked)
+ read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")"
+ read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")"
+ read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")"
- top_ad="${top_ad_raw[2]}"
- top_domain="${top_domain_raw[2]}"
- if [[ "${top_client_raw[3]}" ]]; then
- top_client="${top_client_raw[3]}"
- else
- top_client="${top_client_raw[2]}"
+ top_ad="${top_ad_raw[2]}"
+ top_domain="${top_domain_raw[2]}"
+ if [[ "${top_client_raw[3]}" ]]; then
+ top_client="${top_client_raw[3]}"
+ else
+ top_client="${top_client_raw[2]}"
+ fi
fi
- fi
}
get_strings() {
- # Expand or contract strings depending on screen size
- if [[ "$chrono_width" == "large" ]]; then
- phc_str=" ${COL_DARK_GRAY}Core"
- lte_str=" ${COL_DARK_GRAY}Web"
- ftl_str=" ${COL_DARK_GRAY}FTL"
- api_str="${COL_LIGHT_RED}API Offline"
+ # Expand or contract strings depending on screen size
+ if [[ "$chrono_width" == "large" ]]; then
+ phc_str=" ${COL_DARK_GRAY}Core"
+ lte_str=" ${COL_DARK_GRAY}Web"
+ ftl_str=" ${COL_DARK_GRAY}FTL"
+ api_str="${COL_LIGHT_RED}API Offline"
- host_info="$sys_type"
- sys_info="$sys_throttle"
- sys_info2="Active: $cpu_taskact of $cpu_tasks tasks"
- used_str="Used: "
- leased_str="Leased: "
- domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked")
- ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today")
- dns_queries_today=$(printf "%'.0f" "$dns_queries_today")
- ph_info="Blocking: $domains_being_blocked sites"
- total_str="Total: "
- else
- phc_str=" ${COL_DARK_GRAY}Core"
- lte_str=" ${COL_DARK_GRAY}Web"
- ftl_str=" ${COL_DARK_GRAY}FTL"
- api_str="${COL_LIGHT_RED}API Down"
- ph_info="$domains_being_blocked blocked"
- fi
+ host_info="$sys_type"
+ sys_info="$sys_throttle"
+ sys_info2="Active: $cpu_taskact of $cpu_tasks tasks"
+ used_str="Used: "
+ leased_str="Leased: "
+ domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked")
+ ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today")
+ dns_queries_today=$(printf "%'.0f" "$dns_queries_today")
+ ph_info="Blocking: $domains_being_blocked sites"
+ total_str="Total: "
+ else
+ phc_str=" ${COL_DARK_GRAY}Core"
+ lte_str=" ${COL_DARK_GRAY}Web"
+ ftl_str=" ${COL_DARK_GRAY}FTL"
+ api_str="${COL_LIGHT_RED}API Down"
+ ph_info="$domains_being_blocked blocked"
+ fi
- [[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x "
- cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str"
- ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")"
- disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")"
+ [[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x "
+ cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str"
+ ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")"
+ disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")"
- lan_info="Gateway: $net_gateway"
- dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
+ lan_info="Gateway: $net_gateway"
+ dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max"
- ads_info="$total_str$ads_blocked_today of $dns_queries_today"
- dns_info="$dns_count DNS servers"
+ ads_info="$total_str$ads_blocked_today of $dns_queries_today"
+ dns_info="$dns_count DNS servers"
- [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
+ [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}"
}
chronoFunc() {
- get_init_stats
+ get_init_stats
- for (( ; ; )); do
- get_sys_stats
- get_ftl_stats
- get_strings
+ for (( ; ; )); do
+ get_sys_stats
+ get_ftl_stats
+ get_strings
- # Strip excess development version numbers
- if [[ "$ph_core_ver" != "-1" ]]; then
- phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}"
- lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}"
- ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}"
- else
- phc_ver_str="$phc_str: $api_str${COL_NC}"
- fi
+ # Strip excess development version numbers
+ if [[ "$ph_core_ver" != "-1" ]]; then
+ phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}"
+ lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}"
+ ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}"
+ else
+ phc_ver_str="$phc_str: $api_str${COL_NC}"
+ fi
- # Get refresh number
- if [[ "$*" == *"-r"* ]]; then
- num="$*"
- num="${num/*-r /}"
- num="${num/ */}"
- num_str="Refresh set for every $num seconds"
- else
- num_str=""
- fi
+ # Get refresh number
+ if [[ "$*" == *"-r"* ]]; then
+ num="$*"
+ num="${num/*-r /}"
+ num="${num/ */}"
+ num_str="Refresh set for every $num seconds"
+ else
+ num_str=""
+ fi
- clear
+ clear
- # Remove exit message heading on third refresh
- if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then
- echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC}
- $num_str
- ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
- ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
- else
- echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str
-[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str
-[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str
- ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
- fi
+ # Remove exit message heading on third refresh
+ if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then
+ echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC}
+ $num_str
+ ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC}
+ ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
+ else
+ echo -e "[0;1;31;91m|¯[0;1;33;93m¯[0;1;32;92m¯[0;1;32;92m(¯[0;1;36;96m)[0;1;34;94m_[0;1;35;95m|[0;1;33;93m¯[0;1;31;91m|_ [0;1;32;92m__[0;1;36;96m_|[0;1;31;91m¯[0;1;34;94m|[0;1;35;95m__[0;1;31;91m_[0m$phc_ver_str[0;1;33;93m| ¯[0;1;32;92m_[0;1;36;96m/¯[0;1;34;94m|[0;1;35;95m_[0;1;31;91m| [0;1;33;93m' [0;1;32;92m\\/ [0;1;36;96m_ [0;1;34;94m\\ [0;1;35;95m/ [0;1;31;91m-[0;1;33;93m_)[0m$lte_ver_str[0;1;32;92m|_[0;1;36;96m| [0;1;34;94m|_[0;1;35;95m| [0;1;33;93m|_[0;1;32;92m||[0;1;36;96m_\\[0;1;34;94m__[0;1;35;95m_/[0;1;31;91m_\\[0;1;33;93m__[0;1;32;92m_|[0m$ftl_ver_str ${COL_DARK_GRAY}$scr_line_str${COL_NC}"
+ fi
- printFunc " Hostname: " "$sys_name" "$host_info"
- printFunc " Uptime: " "$sys_uptime" "$sys_info"
- printFunc " Task Load: " "$sys_loadavg" "$sys_info2"
- printFunc " CPU usage: " "$cpu_perc%" "$cpu_info"
- printFunc " RAM usage: " "$ram_perc%" "$ram_info"
- printFunc " HDD usage: " "$disk_perc" "$disk_info"
+ printFunc " Hostname: " "$sys_name" "$host_info"
+ printFunc " Uptime: " "$sys_uptime" "$sys_info"
+ printFunc " Task Load: " "$sys_loadavg" "$sys_info2"
+ printFunc " CPU usage: " "$cpu_perc%" "$cpu_info"
+ printFunc " RAM usage: " "$ram_perc%" "$ram_info"
+ printFunc " HDD usage: " "$disk_perc" "$disk_info"
- if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then
- printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info"
- fi
+ if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then
+ printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info"
+ fi
- if [[ "$DHCP_ACTIVE" == "true" ]]; then
- printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
- fi
+ if [[ "$DHCP_ACTIVE" == "true" ]]; then
+ printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info"
+ fi
- printFunc " Pi-hole: " "$ph_status" "$ph_info"
- printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
- printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
+ printFunc " Pi-hole: " "$ph_status" "$ph_info"
+ printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
+ printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
- printFunc " Blocked: " "$recent_blocked"
- printFunc "Top Advert: " "$top_ad"
+ printFunc " Blocked: " "$recent_blocked"
+ printFunc "Top Advert: " "$top_ad"
- # Provide more stats on screens with more lines
- if [[ "$scr_lines" -eq 17 ]]; then
- if [[ "$DHCP_ACTIVE" == "true" ]]; then
- printFunc "Top Domain: " "$top_domain" "last"
- else
- print_client="true"
- fi
- else
- print_client="true"
- fi
+ # Provide more stats on screens with more lines
+ if [[ "$scr_lines" -eq 17 ]]; then
+ if [[ "$DHCP_ACTIVE" == "true" ]]; then
+ printFunc "Top Domain: " "$top_domain" "last"
+ else
+ print_client="true"
+ fi
+ else
+ print_client="true"
+ fi
- if [[ -n "$print_client" ]]; then
- printFunc "Top Domain: " "$top_domain"
- printFunc "Top Client: " "$top_client" "last"
- fi
+ if [[ -n "$print_client" ]]; then
+ printFunc "Top Domain: " "$top_domain"
+ printFunc "Top Client: " "$top_client" "last"
+ fi
- # Handle exit/refresh options
- if [[ "$*" == *"-e"* ]]; then
- exit 0
- else
- if [[ "$*" == *"-r"* ]]; then
- sleep "$num"
- else
- sleep 5
- fi
- fi
+ # Handle exit/refresh options
+ if [[ "$*" == *"-e"* ]]; then
+ exit 0
+ else
+ if [[ "$*" == *"-r"* ]]; then
+ sleep "$num"
+ else
+ sleep 5
+ fi
+ fi
- done
+ done
}
jsonFunc() {
- get_ftl_stats "json"
- echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}"
+ get_ftl_stats "json"
+ echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}"
}
helpFunc() {
if [[ "$1" == "?" ]]; then
- echo "Unknown option. Please view 'pihole -c --help' for more information"
+ echo "Unknown option. Please view 'pihole -c --help' for more information"
else
- echo "Usage: pihole -c [options]
+ echo "Usage: pihole -c [options]
Example: 'pihole -c -j'
Calculates stats and displays to an LCD
@@ -559,15 +557,15 @@ Options:
}
if [[ $# = 0 ]]; then
- chronoFunc
+ chronoFunc
fi
for var in "$@"; do
- case "$var" in
- "-j" | "--json" ) jsonFunc;;
- "-h" | "--help" ) helpFunc;;
- "-r" | "--refresh" ) chronoFunc "$@";;
- "-e" | "--exit" ) chronoFunc "$@";;
- * ) helpFunc "?";;
- esac
+ case "$var" in
+ "-j" | "--json" ) jsonFunc;;
+ "-h" | "--help" ) helpFunc;;
+ "-r" | "--refresh" ) chronoFunc "$@";;
+ "-e" | "--exit" ) chronoFunc "$@";;
+ * ) helpFunc "?";;
+ esac
done
diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh
index 1d96ea3c..87e4ab44 100755
--- a/advanced/Scripts/list.sh
+++ b/advanced/Scripts/list.sh
@@ -13,10 +13,11 @@ basename=pihole
piholeDir=/etc/"${basename}"
whitelist="${piholeDir}"/whitelist.txt
blacklist="${piholeDir}"/blacklist.txt
-readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
+readonly regexlist="/etc/pihole/regex.list"
reload=false
addmode=true
verbose=true
+wildcard=false
domList=()
@@ -28,16 +29,19 @@ source ${colfile}
helpFunc() {
- if [[ "${listMain}" == "${whitelist}" ]]; then
- param="w"
- type="white"
- elif [[ "${listMain}" == "${wildcardlist}" ]]; then
- param="wild"
- type="wildcard black"
- else
- param="b"
- type="black"
- fi
+ if [[ "${listMain}" == "${whitelist}" ]]; then
+ param="w"
+ type="white"
+ elif [[ "${listMain}" == "${regexlist}" && "${wildcard}" == true ]]; then
+ param="-wild"
+ type="wildcard black"
+ elif [[ "${listMain}" == "${regexlist}" ]]; then
+ param="-regex"
+ type="regex black"
+ else
+ param="b"
+ type="black"
+ fi
echo "Usage: pihole -${param} [options]
Example: 'pihole -${param} site.com', or 'pihole -${param} site1.com site2.com'
@@ -55,212 +59,216 @@ Options:
}
EscapeRegexp() {
- # This way we may safely insert an arbitrary
- # string in our regular expressions
- # Also remove leading "." if present
- echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
+ # This way we may safely insert an arbitrary
+ # string in our regular expressions
+ # This sed is intentionally executed in three steps to ease maintainability
+ # The first sed removes any amount of leading dots
+ echo $* | sed 's/^\.*//' | sed "s/[]\.|$(){}?+*^]/\\\\&/g" | sed "s/\\//\\\\\//g"
}
HandleOther() {
- # Convert to lowercase
- domain="${1,,}"
+ # Convert to lowercase
+ domain="${1,,}"
- # Check validity of domain
- if [[ "${#domain}" -le 253 ]]; then
- validDomain=$(grep -P "^((-|_)*[a-z\d]((-|_)*[a-z\d])*(-|_)*)(\.(-|_)*([a-z\d]((-|_)*[a-z\d])*))*$" <<< "${domain}") # Valid chars check
- validDomain=$(grep -P "^[^\.]{1,63}(\.[^\.]{1,63})*$" <<< "${validDomain}") # Length of each label
- fi
+ # Check validity of domain (don't check for regex entries)
+ if [[ "${#domain}" -le 253 ]]; then
+ if [[ "${listMain}" == "${regexlist}" && "${wildcard}" == false ]]; then
+ validDomain="${domain}"
+ else
+ validDomain=$(grep -P "^((-|_)*[a-z\\d]((-|_)*[a-z\\d])*(-|_)*)(\\.(-|_)*([a-z\\d]((-|_)*[a-z\\d])*))*$" <<< "${domain}") # Valid chars check
+ validDomain=$(grep -P "^[^\\.]{1,63}(\\.[^\\.]{1,63})*$" <<< "${validDomain}") # Length of each label
+ fi
+ fi
- if [[ -n "${validDomain}" ]]; then
- domList=("${domList[@]}" ${validDomain})
- else
- echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
- fi
+ if [[ -n "${validDomain}" ]]; then
+ domList=("${domList[@]}" ${validDomain})
+ else
+ echo -e " ${CROSS} ${domain} is not a valid argument or domain name!"
+ fi
}
PoplistFile() {
- # Check whitelist file exists, and if not, create it
- if [[ ! -f "${whitelist}" ]]; then
- touch "${whitelist}"
- fi
-
- # Check blacklist file exists, and if not, create it
- if [[ ! -f "${blacklist}" ]]; then
- touch "${blacklist}"
- fi
-
- for dom in "${domList[@]}"; do
- # Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
- if ${addmode}; then
- AddDomain "${dom}" "${listMain}"
- RemoveDomain "${dom}" "${listAlt}"
- if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then
- RemoveDomain "${dom}" "${wildcardlist}"
- fi
- else
- RemoveDomain "${dom}" "${listMain}"
+ # Check whitelist file exists, and if not, create it
+ if [[ ! -f "${whitelist}" ]]; then
+ touch "${whitelist}"
fi
+
+ # Check blacklist file exists, and if not, create it
+ if [[ ! -f "${blacklist}" ]]; then
+ touch "${blacklist}"
+ fi
+
+ for dom in "${domList[@]}"; do
+ # Logic: If addmode then add to desired list and remove from the other; if delmode then remove from desired list but do not add to the other
+ if ${addmode}; then
+ AddDomain "${dom}" "${listMain}"
+ RemoveDomain "${dom}" "${listAlt}"
+ else
+ RemoveDomain "${dom}" "${listMain}"
+ fi
done
}
AddDomain() {
- list="$2"
- domain=$(EscapeRegexp "$1")
+ list="$2"
+ domain=$(EscapeRegexp "$1")
- [[ "${list}" == "${whitelist}" ]] && listname="whitelist"
- [[ "${list}" == "${blacklist}" ]] && listname="blacklist"
- [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
+ [[ "${list}" == "${whitelist}" ]] && listname="whitelist"
+ [[ "${list}" == "${blacklist}" ]] && listname="blacklist"
- if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
- [[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
- [[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
- bool=true
- # Is the domain in the list we want to add it to?
- grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
+ if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
+ [[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
+ [[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
+ bool=true
+ # Is the domain in the list we want to add it to?
+ grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
- if [[ "${bool}" == false ]]; then
- # Domain not found in the whitelist file, add it!
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} Adding $1 to $listname..."
- fi
- reload=true
- # Add it to the list we want to add it to
- echo "$1" >> "${list}"
- else
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
- fi
+ if [[ "${bool}" == false ]]; then
+ # Domain not found in the whitelist file, add it!
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} Adding ${1} to ${listname}..."
+ fi
+ reload=true
+ # Add it to the list we want to add it to
+ echo "$1" >> "${list}"
+ else
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${1} already exists in ${listname}, no need to add!"
+ fi
+ fi
+ elif [[ "${list}" == "${regexlist}" ]]; then
+ [[ -z "${type}" ]] && type="--wildcard-only"
+ bool=true
+ domain="${1}"
+
+ [[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
+
+ # Is the domain in the list?
+ # Search only for exactly matching lines
+ grep -Fx "${domain}" "${regexlist}" > /dev/null 2>&1 || bool=false
+
+ if [[ "${bool}" == false ]]; then
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} Adding ${domain} to regex list..."
+ fi
+ reload="restart"
+ echo "$domain" >> "${regexlist}"
+ else
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${domain} already exists in regex list, no need to add!"
+ fi
+ fi
fi
- elif [[ "${list}" == "${wildcardlist}" ]]; then
- source "${piholeDir}/setupVars.conf"
- # Remove the /* from the end of the IP addresses
- IPV4_ADDRESS=${IPV4_ADDRESS%/*}
- IPV6_ADDRESS=${IPV6_ADDRESS%/*}
- [[ -z "${type}" ]] && type="--wildcard-only"
- bool=true
- # Is the domain in the list?
- grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
-
- if [[ "${bool}" == false ]]; then
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} Adding $1 to wildcard blacklist..."
- fi
- reload="restart"
- echo "address=/$1/${IPV4_ADDRESS}" >> "${wildcardlist}"
- if [[ "${#IPV6_ADDRESS}" > 0 ]]; then
- echo "address=/$1/${IPV6_ADDRESS}" >> "${wildcardlist}"
- fi
- else
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} already exists in wildcard blacklist, no need to add!"
- fi
- fi
- fi
}
RemoveDomain() {
- list="$2"
- domain=$(EscapeRegexp "$1")
+ list="$2"
+ domain=$(EscapeRegexp "$1")
- [[ "${list}" == "${whitelist}" ]] && listname="whitelist"
- [[ "${list}" == "${blacklist}" ]] && listname="blacklist"
- [[ "${list}" == "${wildcardlist}" ]] && listname="wildcard blacklist"
+ [[ "${list}" == "${whitelist}" ]] && listname="whitelist"
+ [[ "${list}" == "${blacklist}" ]] && listname="blacklist"
- if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
- bool=true
- [[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
- [[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
- # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
- grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
- if [[ "${bool}" == true ]]; then
- # Remove it from the other one
- echo -e " ${INFO} Removing $1 from $listname..."
- # /I flag: search case-insensitive
- sed -i "/${domain}/Id" "${list}"
- reload=true
- else
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
- fi
+ if [[ "${list}" == "${whitelist}" || "${list}" == "${blacklist}" ]]; then
+ bool=true
+ [[ "${list}" == "${whitelist}" && -z "${type}" ]] && type="--whitelist-only"
+ [[ "${list}" == "${blacklist}" && -z "${type}" ]] && type="--blacklist-only"
+ # Is it in the list? Logic follows that if its whitelisted it should not be blacklisted and vice versa
+ grep -Ex -q "${domain}" "${list}" > /dev/null 2>&1 || bool=false
+ if [[ "${bool}" == true ]]; then
+ # Remove it from the other one
+ echo -e " ${INFO} Removing $1 from ${listname}..."
+ # /I flag: search case-insensitive
+ sed -i "/${domain}/Id" "${list}"
+ reload=true
+ else
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
+ fi
+ fi
+ elif [[ "${list}" == "${regexlist}" ]]; then
+ [[ -z "${type}" ]] && type="--wildcard-only"
+ domain="${1}"
+
+ [[ "${wildcard}" == true ]] && domain="(^|\\.)${domain//\./\\.}$"
+
+ bool=true
+ # Is it in the list?
+ grep -Fx "${domain}" "${regexlist}" > /dev/null 2>&1 || bool=false
+ if [[ "${bool}" == true ]]; then
+ # Remove it from the other one
+ echo -e " ${INFO} Removing $domain from regex list..."
+ local lineNumber
+ lineNumber=$(grep -Fnx "$domain" "${list}" | cut -f1 -d:)
+ sed -i "${lineNumber}d" "${list}"
+ reload=true
+ else
+ if [[ "${verbose}" == true ]]; then
+ echo -e " ${INFO} ${domain} does not exist in regex list, no need to remove!"
+ fi
+ fi
fi
- elif [[ "${list}" == "${wildcardlist}" ]]; then
- [[ -z "${type}" ]] && type="--wildcard-only"
- bool=true
- # Is it in the list?
- grep -e "address=\/${domain}\/" "${wildcardlist}" > /dev/null 2>&1 || bool=false
- if [[ "${bool}" == true ]]; then
- # Remove it from the other one
- echo -e " ${INFO} Removing $1 from $listname..."
- # /I flag: search case-insensitive
- sed -i "/address=\/${domain}/Id" "${list}"
- reload=true
- else
- if [[ "${verbose}" == true ]]; then
- echo -e " ${INFO} ${1} does not exist in ${listname}, no need to remove!"
- fi
- fi
- fi
}
# Update Gravity
Reload() {
- echo ""
- pihole -g --skip-download "${type:-}"
+ echo ""
+ pihole -g --skip-download "${type:-}"
}
Displaylist() {
- if [[ -f ${listMain} ]]; then
- if [[ "${listMain}" == "${whitelist}" ]]; then
- string="gravity resistant domains"
+ if [[ -f ${listMain} ]]; then
+ if [[ "${listMain}" == "${whitelist}" ]]; then
+ string="gravity resistant domains"
+ else
+ string="domains caught in the sinkhole"
+ fi
+ verbose=false
+ echo -e "Displaying $string:\n"
+ count=1
+ while IFS= read -r RD || [ -n "${RD}" ]; do
+ echo " ${count}: ${RD}"
+ count=$((count+1))
+ done < "${listMain}"
else
- string="domains caught in the sinkhole"
+ echo -e " ${COL_LIGHT_RED}${listMain} does not exist!${COL_NC}"
fi
- verbose=false
- echo -e "Displaying $string:\n"
- count=1
- while IFS= read -r RD; do
- echo " ${count}: ${RD}"
- count=$((count+1))
- done < "${listMain}"
- else
- echo -e " ${COL_LIGHT_RED}${listMain} does not exist!${COL_NC}"
- fi
- exit 0;
+ exit 0;
}
NukeList() {
- if [[ -f "${listMain}" ]]; then
- # Back up original list
- cp "${listMain}" "${listMain}.bck~"
- # Empty out file
- echo "" > "${listMain}"
- fi
+ if [[ -f "${listMain}" ]]; then
+ # Back up original list
+ cp "${listMain}" "${listMain}.bck~"
+ # Empty out file
+ echo "" > "${listMain}"
+ fi
}
for var in "$@"; do
- case "${var}" in
- "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
- "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
- "-wild" | "wildcard" ) listMain="${wildcardlist}";;
- "-nr"| "--noreload" ) reload=false;;
- "-d" | "--delmode" ) addmode=false;;
- "-q" | "--quiet" ) verbose=false;;
- "-h" | "--help" ) helpFunc;;
- "-l" | "--list" ) Displaylist;;
- "--nuke" ) NukeList;;
- * ) HandleOther "${var}";;
- esac
+ case "${var}" in
+ "-w" | "whitelist" ) listMain="${whitelist}"; listAlt="${blacklist}";;
+ "-b" | "blacklist" ) listMain="${blacklist}"; listAlt="${whitelist}";;
+ "--wild" | "wildcard" ) listMain="${regexlist}"; wildcard=true;;
+ "--regex" | "regex" ) listMain="${regexlist}";;
+ "-nr"| "--noreload" ) reload=false;;
+ "-d" | "--delmode" ) addmode=false;;
+ "-q" | "--quiet" ) verbose=false;;
+ "-h" | "--help" ) helpFunc;;
+ "-l" | "--list" ) Displaylist;;
+ "--nuke" ) NukeList;;
+ * ) HandleOther "${var}";;
+ esac
done
shift
if [[ $# = 0 ]]; then
- helpFunc
+ helpFunc
fi
PoplistFile
if [[ "${reload}" != false ]]; then
- # Ensure that "restart" is used for Wildcard updates
- Reload "${reload}"
+ # Ensure that "restart" is used for Wildcard updates
+ Reload "${reload}"
fi
diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh
index 21919ddf..977d1552 100644
--- a/advanced/Scripts/piholeCheckout.sh
+++ b/advanced/Scripts/piholeCheckout.sh
@@ -17,346 +17,179 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# piholeGitURL set in basic-install.sh
# is_repo() sourced from basic-install.sh
# setupVars set in basic-install.sh
+# check_download_exists sourced from basic-install.sh
+# fully_fetch_repo sourced from basic-install.sh
+# get_available_branches sourced from basic-install.sh
+# fetch_checkout_pull_branch sourced from basic-install.sh
+# checkout_pull_branch sourced from basic-install.sh
source "${setupVars}"
-update="false"
-
-coltable="/opt/pihole/COL_TABLE"
-source ${coltable}
-
-check_download_exists() {
- status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1)
- if grep -q "404" <<< "$status"; then
- return 1
- else
- return 0
- fi
-}
-
-FTLinstall() {
- # Download and install FTL binary
- local binary
- binary="${1}"
- local path
- path="${2}"
- local str
- str="Installing FTL"
- echo -ne " ${INFO} ${str}..."
-
- if curl -sSL --fail "https://ftl.pi-hole.net/${path}" -o "/tmp/${binary}"; then
- # Get sha1 of the binary we just downloaded for verification.
- curl -sSL --fail "https://ftl.pi-hole.net/${path}.sha1" -o "/tmp/${binary}.sha1"
- # Check if we just downloaded text, or a binary file.
- cd /tmp || return 1
- if sha1sum --status --quiet -c "${binary}".sha1; then
- echo -n "transferred... "
- stop_service pihole-FTL &> /dev/null
- install -T -m 0755 "/tmp/${binary}" "/usr/bin/pihole-FTL"
- rm "/tmp/${binary}" "/tmp/${binary}.sha1"
- start_service pihole-FTL &> /dev/null
- echo -e "${OVER} ${TICK} ${str}"
- return 0
- else
- echo -e "${OVER} ${CROSS} ${str}"
- echo -e " ${COL_LIGHT_RED}Error: Download of binary from ftl.pi-hole.net failed${COL_NC}"
- return 1
- fi
- else
- echo -e "${OVER} ${CROSS} ${str}"
- echo -e " ${COL_LIGHT_RED}Error: URL not found${COL_NC}"
- fi
-}
-
-get_binary_name() {
- local machine
- machine=$(uname -m)
-
- local str
- str="Detecting architecture"
- echo -ne " ${INFO} ${str}..."
- if [[ "${machine}" == "arm"* || "${machine}" == *"aarch"* ]]; then
- # ARM
- local rev
- rev=$(uname -m | sed "s/[^0-9]//g;")
- local lib
- lib=$(ldd /bin/ls | grep -E '^\s*/lib' | awk '{ print $1 }')
- if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then
- echo -e "${OVER} ${TICK} Detected ARM-aarch64 architecture"
- binary="pihole-FTL-aarch64-linux-gnu"
- elif [[ "${lib}" == "/lib/ld-linux-armhf.so.3" ]]; then
- if [[ "$rev" -gt "6" ]]; then
- echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv7+)"
- binary="pihole-FTL-arm-linux-gnueabihf"
- else
- echo -e "${OVER} ${TICK} Detected ARM-hf architecture (armv6 or lower) Using ARM binary"
- binary="pihole-FTL-arm-linux-gnueabi"
- fi
- else
- echo -e "${OVER} ${TICK} Detected ARM architecture"
- binary="pihole-FTL-arm-linux-gnueabi"
- fi
- elif [[ "${machine}" == "ppc" ]]; then
- # PowerPC
- echo -e "${OVER} ${TICK} Detected PowerPC architecture"
- binary="pihole-FTL-powerpc-linux-gnu"
- elif [[ "${machine}" == "x86_64" ]]; then
- # 64bit
- echo -e "${OVER} ${TICK} Detected x86_64 architecture"
- binary="pihole-FTL-linux-x86_64"
- else
- # Something else - we try to use 32bit executable and warn the user
- if [[ ! "${machine}" == "i686" ]]; then
- echo -e "${OVER} ${CROSS} ${str}...
- ${COL_LIGHT_RED}Not able to detect architecture (unknown: ${machine}), trying 32bit executable
- Contact support if you experience issues (e.g: FTL not running)${COL_NC}"
- else
- echo -e "${OVER} ${TICK} Detected 32bit (i686) architecture"
- fi
- binary="pihole-FTL-linux-x86_32"
- fi
-}
-
-fully_fetch_repo() {
- # Add upstream branches to shallow clone
- local directory="${1}"
-
- cd "${directory}" || return 1
- if is_repo "${directory}"; then
- git remote set-branches origin '*' || return 1
- git fetch --quiet || return 1
- else
- return 1
- fi
- return 0
-}
-
-get_available_branches() {
- # Return available branches
- local directory
- directory="${1}"
- local output
-
- cd "${directory}" || return 1
- # Get reachable remote branches, but store STDERR as STDOUT variable
- output=$( { git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g'; } 2>&1 )
- echo "$output"
- return
-}
-
-fetch_checkout_pull_branch() {
- # Check out specified branch
- local directory
- directory="${1}"
- local branch
- branch="${2}"
-
- # Set the reference for the requested branch, fetch, check it put and pull it
- cd "${directory}" || return 1
- git remote set-branches origin "${branch}" || return 1
- git stash --all --quiet &> /dev/null || true
- git clean --quiet --force -d || true
- git fetch --quiet || return 1
- checkout_pull_branch "${directory}" "${branch}" || return 1
-}
-
-checkout_pull_branch() {
- # Check out specified branch
- local directory
- directory="${1}"
- local branch
- branch="${2}"
- local oldbranch
-
- cd "${directory}" || return 1
-
- oldbranch="$(git symbolic-ref HEAD)"
-
- str="Switching to branch: '${branch}' from '${oldbranch}'"
- echo -ne " ${INFO} $str"
- git checkout "${branch}" --quiet || return 1
- echo -e "${OVER} ${TICK} $str"
-
-
- if [[ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]]; then
- update="true"
- fi
-
- git_pull=$(git pull || return 1)
-
- if [[ "$git_pull" == *"up-to-date"* ]]; then
- echo -e " ${INFO} ${git_pull}"
- else
- echo -e "$git_pull\\n"
- fi
-
- return 0
-}
warning1() {
- echo " Please note that changing branches severely alters your Pi-hole subsystems"
- echo " Features that work on the master branch, may not on a development branch"
- 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
- case "${response}" in
- [yY][eE][sS]|[yY])
- echo ""
- return 0
- ;;
- *)
- echo -e "\\n ${INFO} Branch change has been cancelled"
- return 1
- ;;
- esac
+ echo " Please note that changing branches severely alters your Pi-hole subsystems"
+ echo " Features that work on the master branch, may not on a development branch"
+ 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
+ case "${response}" in
+ [yY][eE][sS]|[yY])
+ echo ""
+ return 0
+ ;;
+ *)
+ echo -e "\\n ${INFO} Branch change has been cancelled"
+ return 1
+ ;;
+ esac
}
checkout() {
- local corebranches
- local webbranches
+ local corebranches
+ local webbranches
- # Avoid globbing
- set -f
+ # Avoid globbing
+ set -f
- # This is unlikely
- if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
- echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
- Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
- exit 1;
- fi
- if [[ "${INSTALL_WEB}" == "true" ]]; then
- if ! is_repo "${webInterfaceDir}" ; then
- echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
- Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
- exit 1;
+ # This is unlikely
+ if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
+ 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}"
+ exit 1;
fi
- fi
-
- if [[ -z "${1}" ]]; then
- echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}
- Try 'pihole checkout --help' for more information."
- exit 1
- fi
-
- if ! warning1 ; then
- exit 1
- fi
-
- if [[ "${1}" == "dev" ]] ; then
- # Shortcut to check out development branches
- echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..."
- echo ""
- echo -e " ${INFO} Pi-hole Core"
- fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
- if [[ "${INSTALL_WEB}" == "true" ]]; then
- echo ""
- echo -e " ${INFO} Web interface"
- fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
- fi
- #echo -e " ${TICK} Pi-hole Core"
-
- get_binary_name
- local path
- path="development/${binary}"
- echo "development" > /etc/pihole/ftlbranch
- FTLinstall "${binary}" "${path}"
- elif [[ "${1}" == "master" ]] ; then
- # Shortcut to check out master branches
- echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
- 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; }
- if [[ ${INSTALL_WEB} == "true" ]]; then
- echo -e " ${INFO} Web interface"
- fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
- fi
- #echo -e " ${TICK} Web Interface"
- get_binary_name
- local path
- path="master/${binary}"
- echo "master" > /etc/pihole/ftlbranch
- FTLinstall "${binary}" "${path}"
- elif [[ "${1}" == "core" ]] ; then
- str="Fetching branches from ${piholeGitUrl}"
- echo -ne " ${INFO} $str"
- if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
- echo -e "${OVER} ${CROSS} $str"
- exit 1
- fi
- corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
-
- if [[ "${corebranches[*]}" == *"master"* ]]; then
- echo -e "${OVER} ${TICK} $str
- ${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
- else
- # Print STDERR output from get_available_branches
- echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
- exit 1
+ if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
+ if ! is_repo "${webInterfaceDir}" ; then
+ 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}"
+ exit 1;
+ fi
fi
- echo ""
- # Have the user choose the branch they want
- if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
- echo -e " ${INFO} Requested branch \"${2}\" is not available"
- echo -e " ${INFO} Available branches for Core are:"
- for e in "${corebranches[@]}"; do echo " - $e"; done
- exit 1
- fi
- checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
- elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB}" == "true" ]] ; then
- str="Fetching branches from ${webInterfaceGitUrl}"
- echo -ne " ${INFO} $str"
- if ! fully_fetch_repo "${webInterfaceDir}" ; then
- echo -e "${OVER} ${CROSS} $str"
- exit 1
- fi
- webbranches=($(get_available_branches "${webInterfaceDir}"))
-
- if [[ "${webbranches[*]}" == *"master"* ]]; then
- echo -e "${OVER} ${TICK} $str
- ${INFO} ${#webbranches[@]} branches available for Web Admin"
- else
- # Print STDERR output from get_available_branches
- echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
- exit 1
- fi
-
- echo ""
- # Have the user choose the branch they want
- if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
- echo -e " ${INFO} Requested branch \"${2}\" is not available"
- echo -e " ${INFO} Available branches for Web Admin are:"
- for e in "${webbranches[@]}"; do echo " - $e"; done
- exit 1
- fi
- checkout_pull_branch "${webInterfaceDir}" "${2}"
- elif [[ "${1}" == "ftl" ]] ; then
- get_binary_name
- local path
- path="${2}/${binary}"
-
- if check_download_exists "$path"; then
- echo " ${TICK} Branch ${2} exists"
- echo "${2}" > /etc/pihole/ftlbranch
- FTLinstall "${binary}" "${path}"
- else
- echo " ${CROSS} Requested branch \"${2}\" is not available"
- ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
- echo -e " ${INFO} Available branches for FTL are:"
- for e in "${ftlbranches[@]}"; do echo " - $e"; done
+ if [[ -z "${1}" ]]; then
+ echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}"
+ echo -e " Try 'pihole checkout --help' for more information."
exit 1
fi
- else
- echo -e " ${INFO} Requested option \"${1}\" is not available"
- exit 1
- fi
-
- # Force updating everything
- if [[ ( ! "${1}" == "web" && ! "${1}" == "ftl" ) && "${update}" == "true" ]]; then
- echo -e " ${INFO} Running installer to upgrade your installation"
- if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
- exit 0
- else
- echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}"
- exit 1
+ if ! warning1 ; then
+ exit 1
+ fi
+
+ if [[ "${1}" == "dev" ]] ; then
+ # Shortcut to check out development branches
+ echo -e " ${INFO} Shortcut \"dev\" detected - checking out development / devel branches..."
+ echo ""
+ echo -e " ${INFO} Pi-hole Core"
+ fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo " ${CROSS} Unable to pull Core developement branch"; exit 1; }
+ if [[ "${INSTALL_WEB_INTERFACE}" == "true" ]]; then
+ echo ""
+ echo -e " ${INFO} Web interface"
+ fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo " ${CROSS} Unable to pull Web development branch"; exit 1; }
+ fi
+ #echo -e " ${TICK} Pi-hole Core"
+
+ get_binary_name
+ local path
+ path="development/${binary}"
+ echo "development" > /etc/pihole/ftlbranch
+ elif [[ "${1}" == "master" ]] ; then
+ # Shortcut to check out master branches
+ echo -e " ${INFO} Shortcut \"master\" detected - checking out master branches..."
+ 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; }
+ if [[ ${INSTALL_WEB_INTERFACE} == "true" ]]; then
+ echo -e " ${INFO} Web interface"
+ fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo " ${CROSS} Unable to pull Web master branch"; exit 1; }
+ fi
+ #echo -e " ${TICK} Web Interface"
+ get_binary_name
+ local path
+ path="master/${binary}"
+ echo "master" > /etc/pihole/ftlbranch
+ elif [[ "${1}" == "core" ]] ; then
+ str="Fetching branches from ${piholeGitUrl}"
+ echo -ne " ${INFO} $str"
+ if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then
+ echo -e "${OVER} ${CROSS} $str"
+ exit 1
+ fi
+ corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
+
+ if [[ "${corebranches[*]}" == *"master"* ]]; then
+ echo -e "${OVER} ${TICK} $str"
+ echo -e "${INFO} ${#corebranches[@]} branches available for Pi-hole Core"
+ else
+ # Print STDERR output from get_available_branches
+ echo -e "${OVER} ${CROSS} $str\\n\\n${corebranches[*]}"
+ exit 1
+ fi
+
+ echo ""
+ # Have the user choose the branch they want
+ if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
+ echo -e " ${INFO} Requested branch \"${2}\" is not available"
+ echo -e " ${INFO} Available branches for Core are:"
+ for e in "${corebranches[@]}"; do echo " - $e"; done
+ exit 1
+ fi
+ checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}"
+ elif [[ "${1}" == "web" ]] && [[ "${INSTALL_WEB_INTERFACE}" == "true" ]] ; then
+ str="Fetching branches from ${webInterfaceGitUrl}"
+ echo -ne " ${INFO} $str"
+ if ! fully_fetch_repo "${webInterfaceDir}" ; then
+ echo -e "${OVER} ${CROSS} $str"
+ exit 1
+ fi
+ webbranches=($(get_available_branches "${webInterfaceDir}"))
+
+ if [[ "${webbranches[*]}" == *"master"* ]]; then
+ echo -e "${OVER} ${TICK} $str"
+ echo -e "${INFO} ${#webbranches[@]} branches available for Web Admin"
+ else
+ # Print STDERR output from get_available_branches
+ echo -e "${OVER} ${CROSS} $str\\n\\n${webbranches[*]}"
+ exit 1
+ fi
+
+ echo ""
+ # Have the user choose the branch they want
+ if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then
+ echo -e " ${INFO} Requested branch \"${2}\" is not available"
+ echo -e " ${INFO} Available branches for Web Admin are:"
+ for e in "${webbranches[@]}"; do echo " - $e"; done
+ exit 1
+ fi
+ checkout_pull_branch "${webInterfaceDir}" "${2}"
+ elif [[ "${1}" == "ftl" ]] ; then
+ get_binary_name
+ local path
+ path="${2}/${binary}"
+
+ if check_download_exists "$path"; then
+ echo " ${TICK} Branch ${2} exists"
+ echo "${2}" > /etc/pihole/ftlbranch
+ FTLinstall "${binary}"
+ start_service pihole-FTL
+ enable_service pihole-FTL
+ else
+ echo " ${CROSS} Requested branch \"${2}\" is not available"
+ ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
+ echo -e " ${INFO} Available branches for FTL are:"
+ for e in "${ftlbranches[@]}"; do echo " - $e"; done
+ exit 1
+ fi
+
+ else
+ echo -e " ${INFO} Requested option \"${1}\" is not available"
+ exit 1
+ fi
+
+ # Force updating everything
+ if [[ ! "${1}" == "web" && ! "${1}" == "ftl" ]]; then
+ echo -e " ${INFO} Running installer to upgrade your installation"
+ if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
+ exit 0
+ else
+ echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}"
+ exit 1
+ fi
fi
- fi
}
diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh
index b668af94..b8377f73 100755
--- a/advanced/Scripts/piholeDebug.sh
+++ b/advanced/Scripts/piholeDebug.sh
@@ -8,6 +8,7 @@
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
+# shellcheck source=/dev/null
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
# -u a reference to any variable you haven't previously defined
@@ -28,16 +29,16 @@ PIHOLE_COLTABLE_FILE="${PIHOLE_SCRIPTS_DIRECTORY}/COL_TABLE"
if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then
source ${PIHOLE_COLTABLE_FILE}
else
- COL_NC='\e[0m' # No Color
- COL_RED='\e[1;91m'
- COL_GREEN='\e[1;32m'
- COL_YELLOW='\e[1;33m'
- COL_PURPLE='\e[1;35m'
- COL_CYAN='\e[0;36m'
- TICK="[${COL_GREEN}✓${COL_NC}]"
- CROSS="[${COL_RED}✗${COL_NC}]"
- INFO="[i]"
- OVER="\r\033[K"
+ COL_NC='\e[0m' # No Color
+ COL_RED='\e[1;91m'
+ COL_GREEN='\e[1;32m'
+ COL_YELLOW='\e[1;33m'
+ COL_PURPLE='\e[1;35m'
+ COL_CYAN='\e[0;36m'
+ TICK="[${COL_GREEN}✓${COL_NC}]"
+ CROSS="[${COL_RED}✗${COL_NC}]"
+ INFO="[i]"
+ #OVER="\r\033[K"
fi
OBFUSCATED_PLACEHOLDER=""
@@ -74,7 +75,7 @@ WEB_SERVER_LOG_DIRECTORY="${LOG_DIRECTORY}/lighttpd"
WEB_SERVER_CONFIG_DIRECTORY="/etc/lighttpd"
HTML_DIRECTORY="/var/www/html"
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
-BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
+#BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
# Files required by Pi-hole
# https://discourse.pi-hole.net/t/what-files-does-pi-hole-use/1684
@@ -85,14 +86,14 @@ PIHOLE_DHCP_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/02-pihole-dhcp.conf"
PIHOLE_WILDCARD_CONFIG_FILE="${DNSMASQ_D_DIRECTORY}/03-wildcard.conf"
WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
-WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
+#WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
PIHOLE_DEFAULT_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.default"
PIHOLE_USER_DEFINED_AD_LISTS="${PIHOLE_DIRECTORY}/adlists.list"
PIHOLE_BLACKLIST_FILE="${PIHOLE_DIRECTORY}/blacklist.txt"
PIHOLE_BLOCKLIST_FILE="${PIHOLE_DIRECTORY}/gravity.list"
PIHOLE_INSTALL_LOG_FILE="${PIHOLE_DIRECTORY}/install.log"
-PIHOLE_RAW_BLOCKLIST_FILES=${PIHOLE_DIRECTORY}/list.*
+PIHOLE_RAW_BLOCKLIST_FILES="${PIHOLE_DIRECTORY}/list.*"
PIHOLE_LOCAL_HOSTS_FILE="${PIHOLE_DIRECTORY}/local.list"
PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
@@ -105,7 +106,7 @@ FTL_PID="${RUN_DIRECTORY}/pihole-FTL.pid"
FTL_PORT="${RUN_DIRECTORY}/pihole-FTL.port"
PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log"
-PIHOLE_LOG_GZIPS=${LOG_DIRECTORY}/pihole.log.[0-9].*
+PIHOLE_LOG_GZIPS="${LOG_DIRECTORY}/pihole.log.[0-9].*"
PIHOLE_DEBUG_LOG="${LOG_DIRECTORY}/pihole_debug.log"
PIHOLE_DEBUG_LOG_SANITIZED="${LOG_DIRECTORY}/pihole_debug-sanitized.log"
PIHOLE_FTL_LOG="${LOG_DIRECTORY}/pihole-FTL.log"
@@ -115,53 +116,52 @@ PIHOLE_WEB_SERVER_ERROR_LOG_FILE="${WEB_SERVER_LOG_DIRECTORY}/error.log"
# An array of operating system "pretty names" that we officialy support
# We can loop through the array at any time to see if it matches a value
-SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
+#SUPPORTED_OS=("Raspbian" "Ubuntu" "Fedora" "Debian" "CentOS")
# Store Pi-hole's processes in an array for easy use and parsing
PIHOLE_PROCESSES=( "dnsmasq" "lighttpd" "pihole-FTL" )
# Store the required directories in an array so it can be parsed through
-REQUIRED_DIRECTORIES=(${CORE_GIT_DIRECTORY}
-${CRON_D_DIRECTORY}
-${DNSMASQ_D_DIRECTORY}
-${PIHOLE_DIRECTORY}
-${PIHOLE_SCRIPTS_DIRECTORY}
-${BIN_DIRECTORY}
-${RUN_DIRECTORY}
-${LOG_DIRECTORY}
-${WEB_SERVER_LOG_DIRECTORY}
-${WEB_SERVER_CONFIG_DIRECTORY}
-${HTML_DIRECTORY}
-${WEB_GIT_DIRECTORY}
-${BLOCK_PAGE_DIRECTORY})
+#REQUIRED_DIRECTORIES=("${CORE_GIT_DIRECTORY}"
+#"${CRON_D_DIRECTORY}"
+#"${DNSMASQ_D_DIRECTORY}"
+#"${PIHOLE_DIRECTORY}"
+#"${PIHOLE_SCRIPTS_DIRECTORY}"
+#"${BIN_DIRECTORY}"
+#"${RUN_DIRECTORY}"
+#"${LOG_DIRECTORY}"
+#"${WEB_SERVER_LOG_DIRECTORY}"
+#"${WEB_SERVER_CONFIG_DIRECTORY}"
+#"${HTML_DIRECTORY}"
+#"${WEB_GIT_DIRECTORY}"
+#"${BLOCK_PAGE_DIRECTORY}")
# Store the required directories in an array so it can be parsed through
-mapfile -t array <<< "$var"
-REQUIRED_FILES=(${PIHOLE_CRON_FILE}
-${PIHOLE_DNS_CONFIG_FILE}
-${PIHOLE_DHCP_CONFIG_FILE}
-${PIHOLE_WILDCARD_CONFIG_FILE}
-${WEB_SERVER_CONFIG_FILE}
-${PIHOLE_DEFAULT_AD_LISTS}
-${PIHOLE_USER_DEFINED_AD_LISTS}
-${PIHOLE_BLACKLIST_FILE}
-${PIHOLE_BLOCKLIST_FILE}
-${PIHOLE_INSTALL_LOG_FILE}
-${PIHOLE_RAW_BLOCKLIST_FILES}
-${PIHOLE_LOCAL_HOSTS_FILE}
-${PIHOLE_LOGROTATE_FILE}
-${PIHOLE_SETUP_VARS_FILE}
-${PIHOLE_WHITELIST_FILE}
-${PIHOLE_COMMAND}
-${PIHOLE_COLTABLE_FILE}
-${FTL_PID}
-${FTL_PORT}
-${PIHOLE_LOG}
-${PIHOLE_LOG_GZIPS}
-${PIHOLE_DEBUG_LOG}
-${PIHOLE_FTL_LOG}
-${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}
-${PIHOLE_WEB_SERVER_ERROR_LOG_FILE})
+REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
+"${PIHOLE_DNS_CONFIG_FILE}"
+"${PIHOLE_DHCP_CONFIG_FILE}"
+"${PIHOLE_WILDCARD_CONFIG_FILE}"
+"${WEB_SERVER_CONFIG_FILE}"
+"${PIHOLE_DEFAULT_AD_LISTS}"
+"${PIHOLE_USER_DEFINED_AD_LISTS}"
+"${PIHOLE_BLACKLIST_FILE}"
+"${PIHOLE_BLOCKLIST_FILE}"
+"${PIHOLE_INSTALL_LOG_FILE}"
+"${PIHOLE_RAW_BLOCKLIST_FILES}"
+"${PIHOLE_LOCAL_HOSTS_FILE}"
+"${PIHOLE_LOGROTATE_FILE}"
+"${PIHOLE_SETUP_VARS_FILE}"
+"${PIHOLE_WHITELIST_FILE}"
+"${PIHOLE_COMMAND}"
+"${PIHOLE_COLTABLE_FILE}"
+"${FTL_PID}"
+"${FTL_PORT}"
+"${PIHOLE_LOG}"
+"${PIHOLE_LOG_GZIPS}"
+"${PIHOLE_DEBUG_LOG}"
+"${PIHOLE_FTL_LOG}"
+"${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}"
+"${PIHOLE_WEB_SERVER_ERROR_LOG_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.
@@ -171,980 +171,1038 @@ NOTE: All log files auto-delete after 48 hours and ONLY the Pi-hole developers c
"
show_disclaimer(){
- log_write "${DISCLAIMER}"
+ log_write "${DISCLAIMER}"
}
source_setup_variables() {
- # Display the current test that is running
- log_write "\n${COL_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables"
- # If the variable file exists,
- if ls "${PIHOLE_SETUP_VARS_FILE}" 1> /dev/null 2>&1; then
- log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}...";
- # source it
- source ${PIHOLE_SETUP_VARS_FILE}
- else
- # If it can't, show an error
- log_write "${PIHOLE_SETUP_VARS_FILE} ${COL_RED}does not exist or cannot be read.${COL_NC}"
- fi
+ # Display the current test that is running
+ log_write "\\n${COL_PURPLE}*** [ INITIALIZING ]${COL_NC} Sourcing setup variables"
+ # If the variable file exists,
+ if ls "${PIHOLE_SETUP_VARS_FILE}" 1> /dev/null 2>&1; then
+ log_write "${INFO} Sourcing ${PIHOLE_SETUP_VARS_FILE}...";
+ # source it
+ source ${PIHOLE_SETUP_VARS_FILE}
+ else
+ # If it can't, show an error
+ log_write "${PIHOLE_SETUP_VARS_FILE} ${COL_RED}does not exist or cannot be read.${COL_NC}"
+ fi
}
make_temporary_log() {
- # Create a random temporary file for the log
- TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX)
- # Open handle 3 for templog
- # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
- exec 3>"$TEMPLOG"
- # Delete templog, but allow for addressing via file handle
- # This lets us write to the log without having a temporary file on the drive, which
- # is meant to be a security measure so there is not a lingering file on the drive during the debug process
- rm "$TEMPLOG"
+ # Create a random temporary file for the log
+ TEMPLOG=$(mktemp /tmp/pihole_temp.XXXXXX)
+ # Open handle 3 for templog
+ # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
+ exec 3>"$TEMPLOG"
+ # Delete templog, but allow for addressing via file handle
+ # This lets us write to the log without having a temporary file on the drive, which
+ # is meant to be a security measure so there is not a lingering file on the drive during the debug process
+ rm "$TEMPLOG"
}
log_write() {
- # echo arguments to both the log and the console
- echo -e "${@}" | tee -a /proc/$$/fd/3
+ # echo arguments to both the log and the console
+ echo -e "${@}" | tee -a /proc/$$/fd/3
}
copy_to_debug_log() {
- # Copy the contents of file descriptor 3 into the debug log
- cat /proc/$$/fd/3 > "${PIHOLE_DEBUG_LOG}"
- # Since we use color codes such as '\e[1;33m', they should be removed before being
- # uploaded to our server, since it can't properly display in color
- # This is accomplished by use sed to remove characters matching that patter
- # The entire file is then copied over to a sanitized version of the log
- sed 's/\[[0-9;]\{1,5\}m//g' > "${PIHOLE_DEBUG_LOG_SANITIZED}" <<< cat "${PIHOLE_DEBUG_LOG}"
+ # Copy the contents of file descriptor 3 into the debug log
+ cat /proc/$$/fd/3 > "${PIHOLE_DEBUG_LOG}"
+ # Since we use color codes such as '\e[1;33m', they should be removed before being
+ # uploaded to our server, since it can't properly display in color
+ # This is accomplished by use sed to remove characters matching that patter
+ # The entire file is then copied over to a sanitized version of the log
+ sed 's/\[[0-9;]\{1,5\}m//g' > "${PIHOLE_DEBUG_LOG_SANITIZED}" <<< cat "${PIHOLE_DEBUG_LOG}"
}
initialize_debug() {
- # Clear the screen so the debug log is readable
- clear
- show_disclaimer
- # Display that the debug process is beginning
- log_write "${COL_PURPLE}*** [ INITIALIZING ]${COL_NC}"
- # Timestamp the start of the log
- log_write "${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initialized."
+ # Clear the screen so the debug log is readable
+ clear
+ show_disclaimer
+ # Display that the debug process is beginning
+ log_write "${COL_PURPLE}*** [ INITIALIZING ]${COL_NC}"
+ # Timestamp the start of the log
+ log_write "${INFO} $(date "+%Y-%m-%d:%H:%M:%S") debug log has been initialized."
}
# This is a function for visually displaying the curent test that is being run.
# Accepts one variable: the name of what is being diagnosed
# Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗]
echo_current_diagnostic() {
- # Colors are used for visually distinguishing each test in the output
- # These colors do not show in the GUI, but the formatting will
- log_write "\n${COL_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}"
+ # Colors are used for visually distinguishing each test in the output
+ # These colors do not show in the GUI, but the formatting will
+ log_write "\\n${COL_PURPLE}*** [ DIAGNOSING ]:${COL_NC} ${1}"
}
compare_local_version_to_git_version() {
- # The git directory to check
- local git_dir="${1}"
- # The named component of the project (Core or Web)
- local pihole_component="${2}"
- # If we are checking the Core versions,
- if [[ "${pihole_component}" == "Core" ]]; then
- # We need to search for "Pi-hole" when using pihole -v
- local search_term="Pi-hole"
- elif [[ "${pihole_component}" == "Web" ]]; then
- # We need to search for "AdminLTE" so store it in a variable as well
- local search_term="AdminLTE"
- fi
- # Display what we are checking
- echo_current_diagnostic "${pihole_component} version"
- # Store the error message in a variable in case we want to change and/or reuse it
- local error_msg="git status failed"
- # If the pihole git directory exists,
- if [[ -d "${git_dir}" ]]; then
- # move into it
- cd "${git_dir}" || \
- # If not, show an error
- log_write "${COL_RED}Could not cd into ${git_dir}$COL_NC"
- if git status &> /dev/null; then
- # The current version the user is on
- local remote_version
- remote_version=$(git describe --tags --abbrev=0);
- # What branch they are on
- local remote_branch
- remote_branch=$(git rev-parse --abbrev-ref HEAD);
- # The commit they are on
- local remote_commit
- remote_commit=$(git describe --long --dirty --tags --always)
- # echo this information out to the user in a nice format
- # If the current version matches what pihole -v produces, the user is up-to-date
- if [[ "${remote_version}" == "$(pihole -v | awk '/${search_term}/ {print $6}' | cut -d ')' -f1)" ]]; then
- log_write "${TICK} ${pihole_component}: ${COL_GREEN}${remote_version}${COL_NC}"
- # If not,
- else
- # echo the current version in yellow, signifying it's something to take a look at, but not a critical error
- # Also add a URL to an FAQ
- log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
- fi
-
- # If the repo is on the master branch, they are on the stable codebase
- if [[ "${remote_branch}" == "master" ]]; then
- # so the color of the text is green
- log_write "${INFO} Branch: ${COL_GREEN}${remote_branch}${COL_NC}"
- # If it is any other branch, they are in a developement branch
- else
- # So show that in yellow, signifying it's something to take a look at, but not a critical error
- log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${FAQ_CHECKOUT_COMMAND})"
- fi
- # echo the current commit
- log_write "${INFO} Commit: ${remote_commit}"
- # If git status failed,
- else
- # Return an error message
- log_write "${error_msg}"
- # and exit with a non zero code
- return 1
+ # The git directory to check
+ local git_dir="${1}"
+ # The named component of the project (Core or Web)
+ local pihole_component="${2}"
+ # If we are checking the Core versions,
+ if [[ "${pihole_component}" == "Core" ]]; then
+ # We need to search for "Pi-hole" when using pihole -v
+ local search_term="Pi-hole"
+ elif [[ "${pihole_component}" == "Web" ]]; then
+ # We need to search for "AdminLTE" so store it in a variable as well
+ #shellcheck disable=2034
+ local search_term="AdminLTE"
+ fi
+ # Display what we are checking
+ echo_current_diagnostic "${pihole_component} version"
+ # Store the error message in a variable in case we want to change and/or reuse it
+ local error_msg="git status failed"
+ # If the pihole git directory exists,
+ if [[ -d "${git_dir}" ]]; then
+ # move into it
+ cd "${git_dir}" || \
+ # If not, show an error
+ log_write "${COL_RED}Could not cd into ${git_dir}$COL_NC"
+ if git status &> /dev/null; then
+ # The current version the user is on
+ local remote_version
+ remote_version=$(git describe --tags --abbrev=0);
+ # What branch they are on
+ local remote_branch
+ remote_branch=$(git rev-parse --abbrev-ref HEAD);
+ # The commit they are on
+ local remote_commit
+ remote_commit=$(git describe --long --dirty --tags --always)
+ # echo this information out to the user in a nice format
+ # If the current version matches what pihole -v produces, the user is up-to-date
+ if [[ "${remote_version}" == "$(pihole -v | awk '/${search_term}/ {print $6}' | cut -d ')' -f1)" ]]; then
+ log_write "${TICK} ${pihole_component}: ${COL_GREEN}${remote_version}${COL_NC}"
+ # If not,
+ else
+ # echo the current version in yellow, signifying it's something to take a look at, but not a critical error
+ # Also add a URL to an FAQ
+ log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
+ fi
+
+ # If the repo is on the master branch, they are on the stable codebase
+ if [[ "${remote_branch}" == "master" ]]; then
+ # so the color of the text is green
+ log_write "${INFO} Branch: ${COL_GREEN}${remote_branch}${COL_NC}"
+ # If it is any other branch, they are in a developement branch
+ else
+ # So show that in yellow, signifying it's something to take a look at, but not a critical error
+ log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${FAQ_CHECKOUT_COMMAND})"
+ fi
+ # echo the current commit
+ log_write "${INFO} Commit: ${remote_commit}"
+ # If git status failed,
+ else
+ # Return an error message
+ log_write "${error_msg}"
+ # and exit with a non zero code
+ return 1
+ fi
+ else
+ :
fi
- else
- :
- fi
}
check_ftl_version() {
- local ftl_name="FTL"
- echo_current_diagnostic "${ftl_name} version"
- # Use the built in command to check FTL's version
- FTL_VERSION=$(pihole-FTL version)
- # Compare the current FTL version to the remote version
- if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then
- # If they are the same, FTL is up-to-date
- log_write "${TICK} ${ftl_name}: ${COL_GREEN}${FTL_VERSION}${COL_NC}"
- else
- # If not, show it in yellow, signifying there is an update
- log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
- fi
+ local ftl_name="FTL"
+ echo_current_diagnostic "${ftl_name} version"
+ # Use the built in command to check FTL's version
+ FTL_VERSION=$(pihole-FTL version)
+ # Compare the current FTL version to the remote version
+ if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then
+ # If they are the same, FTL is up-to-date
+ log_write "${TICK} ${ftl_name}: ${COL_GREEN}${FTL_VERSION}${COL_NC}"
+ else
+ # If not, show it in yellow, signifying there is an update
+ log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
+ fi
}
# Checks the core version of the Pi-hole codebase
check_component_versions() {
- # Check the Web version, branch, and commit
- compare_local_version_to_git_version "${CORE_GIT_DIRECTORY}" "Core"
- # Check the Web version, branch, and commit
- compare_local_version_to_git_version "${WEB_GIT_DIRECTORY}" "Web"
- # Check the FTL version
- check_ftl_version
+ # Check the Web version, branch, and commit
+ compare_local_version_to_git_version "${CORE_GIT_DIRECTORY}" "Core"
+ # Check the Web version, branch, and commit
+ compare_local_version_to_git_version "${WEB_GIT_DIRECTORY}" "Web"
+ # Check the FTL version
+ check_ftl_version
}
get_program_version() {
- local program_name="${1}"
- # Create a loval variable so this function can be safely reused
- local program_version
- echo_current_diagnostic "${program_name} version"
- # Evalutate the program we are checking, if it is any of the ones below, show the version
- case "${program_name}" in
- "lighttpd") program_version="$(${program_name} -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)"
- ;;
- "dnsmasq") program_version="$(${program_name} -v |& head -n1 | awk '{print $3}')"
- ;;
- "php") program_version="$(${program_name} -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2)"
- ;;
- # If a match is not found, show an error
- *) echo "Unrecognized program";
- esac
- # If the program does not have a version (the variable is empty)
- if [[ -z "${program_version}" ]]; then
- # Display and error
- log_write "${CROSS} ${COL_RED}${program_name} version could not be detected.${COL_NC}"
- else
- # Otherwise, display the version
- log_write "${INFO} ${program_version}"
- fi
+ local program_name="${1}"
+ # Create a loval variable so this function can be safely reused
+ local program_version
+ echo_current_diagnostic "${program_name} version"
+ # Evalutate the program we are checking, if it is any of the ones below, show the version
+ case "${program_name}" in
+ "lighttpd") program_version="$(${program_name} -v |& head -n1 | cut -d '/' -f2 | cut -d ' ' -f1)"
+ ;;
+ "dnsmasq") program_version="$(${program_name} -v |& head -n1 | awk '{print $3}')"
+ ;;
+ "php") program_version="$(${program_name} -v |& head -n1 | cut -d '-' -f1 | cut -d ' ' -f2)"
+ ;;
+ # If a match is not found, show an error
+ *) echo "Unrecognized program";
+ esac
+ # If the program does not have a version (the variable is empty)
+ if [[ -z "${program_version}" ]]; then
+ # Display and error
+ log_write "${CROSS} ${COL_RED}${program_name} version could not be detected.${COL_NC}"
+ else
+ # Otherwise, display the version
+ log_write "${INFO} ${program_version}"
+ fi
}
# These are the most critical dependencies of Pi-hole, so we check for them
# and their versions, using the functions above.
check_critical_program_versions() {
- # Use the function created earlier and bundle them into one function that checks all the version numbers
- get_program_version "dnsmasq"
- get_program_version "lighttpd"
- get_program_version "php"
+ # Use the function created earlier and bundle them into one function that checks all the version numbers
+ get_program_version "dnsmasq"
+ get_program_version "lighttpd"
+ get_program_version "php"
}
is_os_supported() {
- local os_to_check="${1}"
- # Strip just the base name of the system using sed
- the_os=$(echo ${os_to_check} | sed 's/ .*//')
- # If the variable is one of our supported OSes,
- case "${the_os}" in
- # Print it in green
- "Raspbian") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
- "Ubuntu") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
- "Fedora") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
- "Debian") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
- "CentOS") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
- # If not, show it in red and link to our software requirements page
- *) log_write "${CROSS} ${COL_RED}${os_to_check}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})";
- esac
+ local os_to_check="${1}"
+ # Strip just the base name of the system using sed
+ # shellcheck disable=SC2001
+ the_os=$(echo "${os_to_check}" | sed 's/ .*//')
+ # If the variable is one of our supported OSes,
+ case "${the_os}" in
+ # Print it in green
+ "Raspbian") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
+ "Ubuntu") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
+ "Fedora") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
+ "Debian") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
+ "CentOS") log_write "${TICK} ${COL_GREEN}${os_to_check}${COL_NC}";;
+ # If not, show it in red and link to our software requirements page
+ *) log_write "${CROSS} ${COL_RED}${os_to_check}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})";
+ esac
}
get_distro_attributes() {
- # Put the current Internal Field Separator into another variable so it can be restored later
- OLD_IFS="$IFS"
- # Store the distro info in an array and make it global since the OS won't change,
- # but we'll keep it within the function for better unit testing
- IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )'
+ # Put the current Internal Field Separator into another variable so it can be restored later
+ OLD_IFS="$IFS"
+ # Store the distro info in an array and make it global since the OS won't change,
+ # but we'll keep it within the function for better unit testing
+ local distro_info
+ #shellcheck disable=SC2016
+ IFS=$'\r\n' command eval 'distro_info=( $(cat /etc/*release) )'
- # Set a named variable for better readability
- local distro_attribute
- # For each line found in an /etc/*release file,
- for distro_attribute in "${distro_info[@]}"; do
- # store the key in a variable
- local pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1)
- # we need just the OS PRETTY_NAME,
- if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then
- # so save in in a variable when we find it
- PRETTY_NAME_VALUE=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"')
- # then pass it as an argument that checks if the OS is supported
- is_os_supported "${PRETTY_NAME_VALUE}"
- else
- # Since we only need the pretty name, we can just skip over anything that is not a match
- :
- fi
- done
- # Set the IFS back to what it was
- IFS="$OLD_IFS"
+ # Set a named variable for better readability
+ local distro_attribute
+ # For each line found in an /etc/*release file,
+ for distro_attribute in "${distro_info[@]}"; do
+ # store the key in a variable
+ local pretty_name_key
+ pretty_name_key=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f1)
+ # we need just the OS PRETTY_NAME,
+ if [[ "${pretty_name_key}" == "PRETTY_NAME" ]]; then
+ # so save in in a variable when we find it
+ PRETTY_NAME_VALUE=$(echo "${distro_attribute}" | grep "PRETTY_NAME" | cut -d '=' -f2- | tr -d '"')
+ # then pass it as an argument that checks if the OS is supported
+ is_os_supported "${PRETTY_NAME_VALUE}"
+ else
+ # Since we only need the pretty name, we can just skip over anything that is not a match
+ :
+ fi
+ done
+ # Set the IFS back to what it was
+ IFS="$OLD_IFS"
}
diagnose_operating_system() {
- # error message in a variable so we can easily modify it later (or re-use it)
- local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues."
- # Display the current test that is running
- echo_current_diagnostic "Operating system"
+ # error message in a variable so we can easily modify it later (or re-use it)
+ local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues."
+ # Display the current test that is running
+ echo_current_diagnostic "Operating system"
- # 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
- # display the attributes to the user from the function made earlier
- get_distro_attributes
- else
- # If it doesn't exist, it's not a system we currently support and link to FAQ
- log_write "${CROSS} ${COL_RED}${error_msg}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})"
- fi
+ # 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
+ # display the attributes to the user from the function made earlier
+ get_distro_attributes
+ else
+ # If it doesn't exist, it's not a system we currently support and link to FAQ
+ log_write "${CROSS} ${COL_RED}${error_msg}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})"
+ fi
}
check_selinux() {
- # SELinux is not supported by the Pi-hole
- echo_current_diagnostic "SELinux"
- # Check if a SELinux configuration file exists
- if [[ -f /etc/selinux/config ]]; then
- # If a SELinux configuration file was found, check the default SELinux mode.
- DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
- case "${DEFAULT_SELINUX,,}" in
- enforcing)
- log_write "${CROSS} ${COL_RED}Default SELinux: $DEFAULT_SELINUX${COL_NC}"
- ;;
- *) # 'permissive' and 'disabled'
- log_write "${TICK} ${COL_GREEN}Default SELinux: $DEFAULT_SELINUX${COL_NC}";
- ;;
- esac
- # Check the current state of SELinux
- CURRENT_SELINUX=$(getenforce)
- case "${CURRENT_SELINUX,,}" in
- enforcing)
- log_write "${CROSS} ${COL_RED}Current SELinux: $CURRENT_SELINUX${COL_NC}"
- ;;
- *) # 'permissive' and 'disabled'
- log_write "${TICK} ${COL_GREEN}Current SELinux: $CURRENT_SELINUX${COL_NC}";
- ;;
- esac
- else
- log_write "${INFO} ${COL_GREEN}SELinux not detected${COL_NC}";
- fi
+ # SELinux is not supported by the Pi-hole
+ echo_current_diagnostic "SELinux"
+ # Check if a SELinux configuration file exists
+ if [[ -f /etc/selinux/config ]]; then
+ # If a SELinux configuration file was found, check the default SELinux mode.
+ DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
+ case "${DEFAULT_SELINUX,,}" in
+ enforcing)
+ log_write "${CROSS} ${COL_RED}Default SELinux: $DEFAULT_SELINUX${COL_NC}"
+ ;;
+ *) # 'permissive' and 'disabled'
+ log_write "${TICK} ${COL_GREEN}Default SELinux: $DEFAULT_SELINUX${COL_NC}";
+ ;;
+ esac
+ # Check the current state of SELinux
+ CURRENT_SELINUX=$(getenforce)
+ case "${CURRENT_SELINUX,,}" in
+ enforcing)
+ log_write "${CROSS} ${COL_RED}Current SELinux: $CURRENT_SELINUX${COL_NC}"
+ ;;
+ *) # 'permissive' and 'disabled'
+ log_write "${TICK} ${COL_GREEN}Current SELinux: $CURRENT_SELINUX${COL_NC}";
+ ;;
+ esac
+ else
+ log_write "${INFO} ${COL_GREEN}SELinux not detected${COL_NC}";
+ fi
}
processor_check() {
- echo_current_diagnostic "Processor"
- # Store the processor type in a variable
- PROCESSOR=$(uname -m)
- # If it does not contain a value,
- if [[ -z "${PROCESSOR}" ]]; then
- # we couldn't detect it, so show an error
- PROCESSOR=$(lscpu | awk '/Architecture/ {print $2}')
- log_write "${CROSS} ${COL_RED}${PROCESSOR}${COL_NC} has not been tested with FTL, but may still work: (${FAQ_FTL_COMPATIBILITY})"
- else
- # Check if the architecture is currently supported for FTL
- case "${PROCESSOR}" in
- "amd64") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
- ;;
- "armv6l") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
- ;;
- "armv6") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
- ;;
- "armv7l") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
- ;;
- "aarch64") "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
- ;;
- # Otherwise, show the processor type
- *) log_write "${INFO} ${PROCESSOR}";
- esac
- fi
+ echo_current_diagnostic "Processor"
+ # Store the processor type in a variable
+ PROCESSOR=$(uname -m)
+ # If it does not contain a value,
+ if [[ -z "${PROCESSOR}" ]]; then
+ # we couldn't detect it, so show an error
+ PROCESSOR=$(lscpu | awk '/Architecture/ {print $2}')
+ log_write "${CROSS} ${COL_RED}${PROCESSOR}${COL_NC} has not been tested with FTL, but may still work: (${FAQ_FTL_COMPATIBILITY})"
+ else
+ # Check if the architecture is currently supported for FTL
+ case "${PROCESSOR}" in
+ "amd64") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
+ ;;
+ "armv6l") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
+ ;;
+ "armv6") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
+ ;;
+ "armv7l") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
+ ;;
+ "aarch64") log_write "${TICK} ${COL_GREEN}${PROCESSOR}${COL_NC}"
+ ;;
+ # Otherwise, show the processor type
+ *) log_write "${INFO} ${PROCESSOR}";
+ esac
+ fi
}
parse_setup_vars() {
- echo_current_diagnostic "Setup variables"
- # If the file exists,
- if [[ -r "${PIHOLE_SETUP_VARS_FILE}" ]]; then
- # parse it
- parse_file "${PIHOLE_SETUP_VARS_FILE}"
- else
- # If not, show an error
- log_write "${CROSS} ${COL_RED}Could not read ${PIHOLE_SETUP_VARS_FILE}.${COL_NC}"
- fi
+ echo_current_diagnostic "Setup variables"
+ # If the file exists,
+ if [[ -r "${PIHOLE_SETUP_VARS_FILE}" ]]; then
+ # parse it
+ parse_file "${PIHOLE_SETUP_VARS_FILE}"
+ else
+ # If not, show an error
+ log_write "${CROSS} ${COL_RED}Could not read ${PIHOLE_SETUP_VARS_FILE}.${COL_NC}"
+ fi
+}
+
+parse_locale() {
+ local pihole_locale
+ echo_current_diagnostic "Locale"
+ pihole_locale="$(locale)"
+ parse_file "${pihole_locale}"
}
does_ip_match_setup_vars() {
- # Check for IPv4 or 6
- local protocol="${1}"
- # IP address to check for
- local ip_address="${2}"
- # See what IP is in the setupVars.conf file
- local setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} grep IPV${protocol}_ADDRESS | cut -d '=' -f2)
- # If it's an IPv6 address
- if [[ "${protocol}" == "6" ]]; then
- # Strip off the / (CIDR notation)
- if [[ "${ip_address%/*}" == "${setup_vars_ip%/*}" ]]; then
- # if it matches, show it in green
- log_write " ${COL_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
- else
- # otherwise show it in red with an FAQ URL
- log_write " ${COL_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
- fi
+ # Check for IPv4 or 6
+ local protocol="${1}"
+ # IP address to check for
+ local ip_address="${2}"
+ # See what IP is in the setupVars.conf file
+ local setup_vars_ip
+ setup_vars_ip=$(< ${PIHOLE_SETUP_VARS_FILE} grep IPV"${protocol}"_ADDRESS | cut -d '=' -f2)
+ # If it's an IPv6 address
+ if [[ "${protocol}" == "6" ]]; then
+ # Strip off the / (CIDR notation)
+ if [[ "${ip_address%/*}" == "${setup_vars_ip%/*}" ]]; then
+ # if it matches, show it in green
+ log_write " ${COL_GREEN}${ip_address%/*}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
+ else
+ # otherwise show it in red with an FAQ URL
+ log_write " ${COL_RED}${ip_address%/*}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
+ fi
- else
- # if the protocol isn't 6, it's 4 so no need to strip the CIDR notation
- # since it exists in the setupVars.conf that way
- if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then
- # show in green if it matches
- log_write " ${COL_GREEN}${ip_address}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
else
- # otherwise show it in red
- log_write " ${COL_RED}${ip_address}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
+ # if the protocol isn't 6, it's 4 so no need to strip the CIDR notation
+ # since it exists in the setupVars.conf that way
+ if [[ "${ip_address}" == "${setup_vars_ip}" ]]; then
+ # show in green if it matches
+ log_write " ${COL_GREEN}${ip_address}${COL_NC} matches the IP found in ${PIHOLE_SETUP_VARS_FILE}"
+ else
+ # otherwise show it in red
+ log_write " ${COL_RED}${ip_address}${COL_NC} does not match the IP found in ${PIHOLE_SETUP_VARS_FILE} (${FAQ_ULA})"
+ fi
fi
- fi
}
detect_ip_addresses() {
- # First argument should be a 4 or a 6
- local protocol=${1}
- # Use ip to show the addresses for the chosen protocol
- # Store the values in an arry so they can be looped through
- # Get the lines that are in the file(s) and store them in an array for parsing later
- declare -a ip_addr_list=( $(ip -${protocol} addr show dev ${PIHOLE_INTERFACE} | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }') )
+ # First argument should be a 4 or a 6
+ local protocol=${1}
+ # Use ip to show the addresses for the chosen protocol
+ # Store the values in an arry so they can be looped through
+ # Get the lines that are in the file(s) and store them in an array for parsing later
+ mapfile -t ip_addr_list < <(ip -"${protocol}" addr show dev "${PIHOLE_INTERFACE}" | awk -F ' ' '{ for(i=1;i<=NF;i++) if ($i ~ '/^inet/') print $(i+1) }')
- # If there is something in the IP address list,
- if [[ -n ${ip_addr_list} ]]; then
- # Local iterator
- local i
- # Display the protocol and interface
- log_write "${TICK} IPv${protocol} address(es) bound to the ${PIHOLE_INTERFACE} interface:"
- # Since there may be more than one IP address, store them in an array
- for i in "${!ip_addr_list[@]}"; do
- # For each one in the list, print it out
- does_ip_match_setup_vars "${protocol}" "${ip_addr_list[$i]}"
- done
- # Print a blank line just for formatting
- log_write ""
- else
- # If there are no IPs detected, explain that the protocol is not configured
- log_write "${CROSS} ${COL_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interface.\n"
- return 1
- fi
- # If the protocol is v6
- if [[ "${protocol}" == "6" ]]; then
- # let the user know that as long as there is one green address, things should be ok
- log_write " ^ Please note that you may have more than one IP address listed."
- log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\n"
- log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\n"
- fi
+ # If there is something in the IP address list,
+ if [[ -n ${ip_addr_list[*]} ]]; then
+ # Local iterator
+ local i
+ # Display the protocol and interface
+ log_write "${TICK} IPv${protocol} address(es) bound to the ${PIHOLE_INTERFACE} interface:"
+ # Since there may be more than one IP address, store them in an array
+ for i in "${!ip_addr_list[@]}"; do
+ # For each one in the list, print it out
+ does_ip_match_setup_vars "${protocol}" "${ip_addr_list[$i]}"
+ done
+ # Print a blank line just for formatting
+ log_write ""
+ else
+ # If there are no IPs detected, explain that the protocol is not configured
+ log_write "${CROSS} ${COL_RED}No IPv${protocol} address(es) found on the ${PIHOLE_INTERFACE}${COL_NC} interface.\\n"
+ return 1
+ fi
+ # If the protocol is v6
+ if [[ "${protocol}" == "6" ]]; then
+ # let the user know that as long as there is one green address, things should be ok
+ log_write " ^ Please note that you may have more than one IP address listed."
+ log_write " As long as one of them is green, and it matches what is in ${PIHOLE_SETUP_VARS_FILE}, there is no need for concern.\\n"
+ log_write " The link to the FAQ is for an issue that sometimes occurs when the IPv6 address changes, which is why we check for it.\\n"
+ fi
}
ping_ipv4_or_ipv6() {
- # Give the first argument a readable name (a 4 or a six should be the argument)
- local protocol="${1}"
- # If the protocol is 6,
- if [[ ${protocol} == "6" ]]; then
- # use ping6
- cmd="ping6"
- # and Google's public IPv6 address
- public_address="2001:4860:4860::8888"
- else
- # Otherwise, just use ping
- cmd="ping"
- # and Google's public IPv4 address
- public_address="8.8.8.8"
- fi
+ # Give the first argument a readable name (a 4 or a six should be the argument)
+ local protocol="${1}"
+ # If the protocol is 6,
+ if [[ ${protocol} == "6" ]]; then
+ # use ping6
+ cmd="ping6"
+ # and Google's public IPv6 address
+ public_address="2001:4860:4860::8888"
+ else
+ # Otherwise, just use ping
+ cmd="ping"
+ # and Google's public IPv4 address
+ public_address="8.8.8.8"
+ fi
}
ping_gateway() {
- local protocol="${1}"
- ping_ipv4_or_ipv6 "${protocol}"
- # Check if we are using IPv4 or IPv6
- # Find the default gateway using IPv4 or IPv6
- local gateway
- gateway="$(ip -${protocol} route | grep default | cut -d ' ' -f 3)"
+ local protocol="${1}"
+ ping_ipv4_or_ipv6 "${protocol}"
+ # Check if we are using IPv4 or IPv6
+ # Find the default gateway using IPv4 or IPv6
+ local gateway
+ gateway="$(ip -"${protocol}" route | grep default | cut -d ' ' -f 3)"
- # If the gateway variable has a value (meaning a gateway was found),
- if [[ -n "${gateway}" ]]; then
- log_write "${INFO} Default IPv${protocol} gateway: ${gateway}"
- # Let the user know we will ping the gateway for a response
- log_write " * Pinging ${gateway}..."
- # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only,
- # on the pihole interface, and tail the last three lines of the output
- # If pinging the gateway is not successful,
- if ! ${cmd} -c 3 -W 2 -n ${gateway} -I ${PIHOLE_INTERFACE} >/dev/null; then
- # let the user know
- log_write "${CROSS} ${COL_RED}Gateway did not respond.${COL_NC} ($FAQ_GATEWAY)\n"
- # and return an error code
- return 1
- # Otherwise,
- else
- # show a success
- log_write "${TICK} ${COL_GREEN}Gateway responded.${COL_NC}"
- # and return a success code
- return 0
+ # If the gateway variable has a value (meaning a gateway was found),
+ if [[ -n "${gateway}" ]]; then
+ log_write "${INFO} Default IPv${protocol} gateway: ${gateway}"
+ # Let the user know we will ping the gateway for a response
+ log_write " * Pinging ${gateway}..."
+ # Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only,
+ # on the pihole interface, and tail the last three lines of the output
+ # If pinging the gateway is not successful,
+ if ! ${cmd} -c 1 -W 2 -n "${gateway}" -I "${PIHOLE_INTERFACE}" >/dev/null; then
+ # let the user know
+ log_write "${CROSS} ${COL_RED}Gateway did not respond.${COL_NC} ($FAQ_GATEWAY)\\n"
+ # and return an error code
+ return 1
+ # Otherwise,
+ else
+ # show a success
+ log_write "${TICK} ${COL_GREEN}Gateway responded.${COL_NC}"
+ # and return a success code
+ return 0
+ fi
fi
- fi
}
ping_internet() {
- local protocol="${1}"
- # Ping a public address using the protocol passed as an argument
- ping_ipv4_or_ipv6 "${protocol}"
- log_write "* Checking Internet connectivity via IPv${protocol}..."
- # Try to ping the address 3 times
- if ! ${cmd} -W 2 -c 3 -n ${public_address} -I ${PIHOLE_INTERFACE} >/dev/null; then
- # if it's unsuccessful, show an error
- log_write "${CROSS} ${COL_RED}Cannot reach the Internet.${COL_NC}\n"
- return 1
- else
- # Otherwise, show success
- log_write "${TICK} ${COL_GREEN}Query responded.${COL_NC}\n"
- return 0
- fi
+ local protocol="${1}"
+ # Ping a public address using the protocol passed as an argument
+ ping_ipv4_or_ipv6 "${protocol}"
+ log_write "* Checking Internet connectivity via IPv${protocol}..."
+ # Try to ping the address 3 times
+ if ! ${cmd} -c 1 -W 2 -n ${public_address} -I "${PIHOLE_INTERFACE}" >/dev/null; then
+ # if it's unsuccessful, show an error
+ log_write "${CROSS} ${COL_RED}Cannot reach the Internet.${COL_NC}\\n"
+ return 1
+ else
+ # Otherwise, show success
+ log_write "${TICK} ${COL_GREEN}Query responded.${COL_NC}\\n"
+ return 0
+ fi
}
compare_port_to_service_assigned() {
- local service_name="${1}"
- # The programs we use may change at some point, so they are in a varible here
- local resolver="dnsmasq"
- local web_server="lighttpd"
- local ftl="pihole-FTL"
- if [[ "${service_name}" == "${resolver}" ]] || [[ "${service_name}" == "${web_server}" ]] || [[ "${service_name}" == "${ftl}" ]]; then
+ local service_name="${1}"
+ # The programs we use may change at some point, so they are in a varible here
+ local resolver="dnsmasq"
+ local web_server="lighttpd"
+ local ftl="pihole-FTL"
+ if [[ "${service_name}" == "${resolver}" ]] || [[ "${service_name}" == "${web_server}" ]] || [[ "${service_name}" == "${ftl}" ]]; then
# if port 53 is dnsmasq, show it in green as it's standard
log_write "[${COL_GREEN}${port_number}${COL_NC}] is in use by ${COL_GREEN}${service_name}${COL_NC}"
- # Otherwise,
- else
+ # Otherwise,
+ else
# Show the service name in red since it's non-standard
log_write "[${COL_RED}${port_number}${COL_NC}] is in use by ${COL_RED}${service_name}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_PORTS})"
- fi
+ fi
}
check_required_ports() {
- echo_current_diagnostic "Ports in use"
- # Since Pi-hole needs 53, 80, and 4711, check what they are being used by
- # so we can detect any issues
- local resolver="dnsmasq"
- local web_server="lighttpd"
- local ftl="pihole-FTL"
- # Create an array for these ports in use
- ports_in_use=()
- # Sort the addresses and remove duplicates
- while IFS= read -r line; do
- ports_in_use+=( "$line" )
- done < <( lsof -i -P -n | awk -F' ' '/LISTEN/ {print $9, $1}' | sort -n | uniq | cut -d':' -f2 )
+ echo_current_diagnostic "Ports in use"
+ # Since Pi-hole needs 53, 80, and 4711, check what they are being used by
+ # so we can detect any issues
+ local resolver="dnsmasq"
+ local web_server="lighttpd"
+ local ftl="pihole-FTL"
+ # Create an array for these ports in use
+ ports_in_use=()
+ # Sort the addresses and remove duplicates
+ while IFS= read -r line; do
+ ports_in_use+=( "$line" )
+ done < <( lsof -iTCP -sTCP:LISTEN -P -n +c 10 )
- # Now that we have the values stored,
- for i in "${!ports_in_use[@]}"; do
- # loop through them and assign some local variables
- local port_number
- port_number="$(echo "${ports_in_use[$i]}" | awk '{print $1}')"
- local service_name
- service_name=$(echo "${ports_in_use[$i]}" | awk '{print $2}')
- # Use a case statement to determine if the right services are using the right ports
- case "${port_number}" in
- 53) compare_port_to_service_assigned "${resolver}"
- ;;
- 80) compare_port_to_service_assigned "${web_server}"
- ;;
- 4711) compare_port_to_service_assigned "${ftl}"
- ;;
- # If it's not a default port that Pi-hole needs, just print it out for the user to see
- *) log_write "[${port_number}] is in use by ${service_name}";
- esac
- done
+ # Now that we have the values stored,
+ for i in "${!ports_in_use[@]}"; do
+ # loop through them and assign some local variables
+ local service_name
+ service_name=$(echo "${ports_in_use[$i]}" | awk '{print $1}')
+ local protocol_type
+ protocol_type=$(echo "${ports_in_use[$i]}" | awk '{print $5}')
+ local port_number
+ port_number="$(echo "${ports_in_use[$i]}" | awk '{print $9}')"
+
+ # Skip the line if it's the titles of the columns the lsof command produces
+ if [[ "${service_name}" == COMMAND ]]; then
+ continue
+ fi
+ # Use a case statement to determine if the right services are using the right ports
+ case "${port_number}" in
+ 53) compare_port_to_service_assigned "${resolver}"
+ ;;
+ 80) compare_port_to_service_assigned "${web_server}"
+ ;;
+ 4711) compare_port_to_service_assigned "${ftl}"
+ ;;
+ # If it's not a default port that Pi-hole needs, just print it out for the user to see
+ *) log_write "${port_number} ${service_name} (${protocol_type})";
+ esac
+ done
}
check_networking() {
- # Runs through several of the functions made earlier; we just clump them
- # together since they are all related to the networking aspect of things
- echo_current_diagnostic "Networking"
- detect_ip_addresses "4"
- detect_ip_addresses "6"
- ping_gateway "4"
- ping_gateway "6"
- check_required_ports
+ # Runs through several of the functions made earlier; we just clump them
+ # together since they are all related to the networking aspect of things
+ echo_current_diagnostic "Networking"
+ detect_ip_addresses "4"
+ detect_ip_addresses "6"
+ ping_gateway "4"
+ ping_gateway "6"
+ check_required_ports
}
check_x_headers() {
- # The X-Headers allow us to determine from the command line if the Web
- # lighttpd.conf has a directive to show "X-Pi-hole: A black hole for Internet advertisements."
- # in the header of any Pi-holed domain
- # Similarly, it will show "X-Pi-hole: The Pi-hole Web interface is working!" if you view the header returned
- # when accessing the dashboard (i.e curl -I pi.hole/admin/)
- # server is operating correctly
- echo_current_diagnostic "Dashboard and block page"
- # Use curl -I to get the header and parse out just the X-Pi-hole one
- local block_page
- block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r')
- # Do it for the dashboard as well, as the header is different than above
- local dashboard
- dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r')
- # Store what the X-Header shoud be in variables for comparision later
- local block_page_working
- block_page_working="X-Pi-hole: A black hole for Internet advertisements."
- local dashboard_working
- dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!"
- local full_curl_output_block_page
- full_curl_output_block_page="$(curl -Is localhost)"
- local full_curl_output_dashboard
- full_curl_output_dashboard="$(curl -Is localhost/admin/)"
- # If the X-header found by curl matches what is should be,
- if [[ $block_page == "$block_page_working" ]]; then
- # display a success message
- log_write "$TICK ${COL_GREEN}${block_page}${COL_NC}"
- else
- # Otherwise, show an error
- log_write "$CROSS ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
- log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
- fi
+ # The X-Headers allow us to determine from the command line if the Web
+ # lighttpd.conf has a directive to show "X-Pi-hole: A black hole for Internet advertisements."
+ # in the header of any Pi-holed domain
+ # Similarly, it will show "X-Pi-hole: The Pi-hole Web interface is working!" if you view the header returned
+ # when accessing the dashboard (i.e curl -I pi.hole/admin/)
+ # server is operating correctly
+ echo_current_diagnostic "Dashboard and block page"
+ # Use curl -I to get the header and parse out just the X-Pi-hole one
+ local block_page
+ block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r')
+ # Do it for the dashboard as well, as the header is different than above
+ local dashboard
+ dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r')
+ # Store what the X-Header shoud be in variables for comparision later
+ local block_page_working
+ block_page_working="X-Pi-hole: A black hole for Internet advertisements."
+ local dashboard_working
+ dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!"
+ local full_curl_output_block_page
+ full_curl_output_block_page="$(curl -Is localhost)"
+ local full_curl_output_dashboard
+ full_curl_output_dashboard="$(curl -Is localhost/admin/)"
+ # If the X-header found by curl matches what is should be,
+ if [[ $block_page == "$block_page_working" ]]; then
+ # display a success message
+ log_write "$TICK Block page X-Header: ${COL_GREEN}${block_page}${COL_NC}"
+ else
+ # Otherwise, show an error
+ log_write "$CROSS Block page X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
+ log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
+ fi
- # Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have,
- if [[ $dashboard == "$dashboard_working" ]]; then
- # then we can show a success
- log_write "$TICK ${COL_GREEN}${dashboard}${COL_NC}"
- else
- # Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way
- log_write "$CROSS ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
- log_write "${COL_RED}${full_curl_output_dashboard}${COL_NC}"
- fi
+ # Same logic applies to the dashbord as above, if the X-Header matches what a working system shoud have,
+ if [[ $dashboard == "$dashboard_working" ]]; then
+ # then we can show a success
+ log_write "$TICK Web interface X-Header: ${COL_GREEN}${dashboard}${COL_NC}"
+ else
+ # Othewise, it's a failure since the X-Headers either don't exist or have been modified in some way
+ log_write "$CROSS Web interface X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
+ log_write "${COL_RED}${full_curl_output_dashboard}${COL_NC}"
+ fi
}
dig_at() {
- # We need to test if Pi-hole can properly resolve domain names
- # as it is an essential piece of the software
+ # We need to test if Pi-hole can properly resolve domain names
+ # as it is an essential piece of the software
- # Store the arguments as variables with names
- local protocol="${1}"
- local IP="${2}"
- echo_current_diagnostic "Name resolution (IPv${protocol}) using a random blocked domain and a known ad-serving domain"
- # Set more local variables
- # We need to test name resolution locally, via Pi-hole, and via a public resolver
- local local_dig
- local pihole_dig
- local remote_dig
- # Use a static domain that we know has IPv4 and IPv6 to avoid false positives
- # Sometimes the randomly chosen domains don't use IPv6, or something else is wrong with them
- local remote_url="doubleclick.com"
+ # Store the arguments as variables with names
+ local protocol="${1}"
+ local IP="${2}"
+ echo_current_diagnostic "Name resolution (IPv${protocol}) using a random blocked domain and a known ad-serving domain"
+ # Set more local variables
+ # We need to test name resolution locally, via Pi-hole, and via a public resolver
+ local local_dig
+ local pihole_dig
+ local remote_dig
+ # Use a static domain that we know has IPv4 and IPv6 to avoid false positives
+ # Sometimes the randomly chosen domains don't use IPv6, or something else is wrong with them
+ local remote_url="doubleclick.com"
- # If the protocol (4 or 6) is 6,
- if [[ ${protocol} == "6" ]]; then
- # Set the IPv6 variables and record type
- local local_address="::1"
- local pihole_address="${IPV6_ADDRESS%/*}"
- local remote_address="2001:4860:4860::8888"
- local record_type="AAAA"
- # Othwerwise, it should be 4
- else
- # so use the IPv4 values
- local local_address="127.0.0.1"
- local pihole_address="${IPV4_ADDRESS%/*}"
- local remote_address="8.8.8.8"
- local record_type="A"
- fi
+ # If the protocol (4 or 6) is 6,
+ if [[ ${protocol} == "6" ]]; then
+ # Set the IPv6 variables and record type
+ local local_address="::1"
+ local pihole_address="${IP}"
+ local remote_address="2001:4860:4860::8888"
+ local record_type="AAAA"
+ # Othwerwise, it should be 4
+ else
+ # so use the IPv4 values
+ local local_address="127.0.0.1"
+ local pihole_address="${IP}"
+ local remote_address="8.8.8.8"
+ local record_type="A"
+ fi
- # Find a random blocked url that has not been whitelisted.
- # This helps emulate queries to different domains that a user might query
- # It will also give extra assurance that Pi-hole is correctly resolving and blocking domains
- local random_url=$(shuf -n 1 "${PIHOLE_BLOCKLIST_FILE}" | awk -F ' ' '{ print $2 }')
+ # Find a random blocked url that has not been whitelisted.
+ # This helps emulate queries to different domains that a user might query
+ # It will also give extra assurance that Pi-hole is correctly resolving and blocking domains
+ local random_url
+ random_url=$(shuf -n 1 "${PIHOLE_BLOCKLIST_FILE}")
- # First, do a dig on localhost to see if Pi-hole can use itself to block a domain
- if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then
- # If it can, show sucess
- log_write "${TICK} ${random_url} ${COL_GREEN}is ${local_dig}${COL_NC} via ${COL_CYAN}localhost$COL_NC (${local_address})"
- else
- # Otherwise, show a failure
- log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}localhost${COL_NC} (${local_address})"
- fi
+ # First, do a dig on localhost to see if Pi-hole can use itself to block a domain
+ if local_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${local_address} +short "${record_type}"); then
+ # If it can, show sucess
+ log_write "${TICK} ${random_url} ${COL_GREEN}is ${local_dig}${COL_NC} via ${COL_CYAN}localhost$COL_NC (${local_address})"
+ else
+ # Otherwise, show a failure
+ log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}localhost${COL_NC} (${local_address})"
+ fi
- # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address
- # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is
- # just asing itself locally
- # The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long
+ # Next we need to check if Pi-hole can resolve a domain when the query is sent to it's IP address
+ # This better emulates how clients will interact with Pi-hole as opposed to above where Pi-hole is
+ # just asing itself locally
+ # The default timeouts and tries are reduced in case the DNS server isn't working, so the user isn't waiting for too long
- # If Pi-hole can dig itself from it's IP (not the loopback address)
- if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @${pihole_address} +short "${record_type}"); then
- # show a success
- log_write "${TICK} ${random_url} ${COL_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})"
- else
- # Othewise, show a failure
- log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}Pi-hole${COL_NC} (${pihole_address})"
- fi
+ # If Pi-hole can dig itself from it's IP (not the loopback address)
+ if pihole_dig=$(dig +tries=1 +time=2 -"${protocol}" "${random_url}" @"${pihole_address}" +short "${record_type}"); then
+ # show a success
+ log_write "${TICK} ${random_url} ${COL_GREEN}is ${pihole_dig}${COL_NC} via ${COL_CYAN}Pi-hole${COL_NC} (${pihole_address})"
+ else
+ # Othewise, show a failure
+ log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${random_url} via ${COL_RED}Pi-hole${COL_NC} (${pihole_address})"
+ fi
- # 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
- if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then
- # If successful, the real IP of the domain will be returned instead of Pi-hole's IP
- log_write "${TICK} ${remote_url} ${COL_GREEN}is ${remote_dig}${COL_NC} via ${COL_CYAN}a remote, public DNS server${COL_NC} (${remote_address})"
- else
- # Otherwise, show an error
- log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${remote_url} via ${COL_RED}a remote, public DNS server${COL_NC} (${remote_address})"
- fi
+ # 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
+ if remote_dig=$(dig +tries=1 +time=2 -"${protocol}" "${remote_url}" @${remote_address} +short "${record_type}" | head -n1); then
+ # If successful, the real IP of the domain will be returned instead of Pi-hole's IP
+ log_write "${TICK} ${remote_url} ${COL_GREEN}is ${remote_dig}${COL_NC} via ${COL_CYAN}a remote, public DNS server${COL_NC} (${remote_address})"
+ else
+ # Otherwise, show an error
+ log_write "${CROSS} ${COL_RED}Failed to resolve${COL_NC} ${remote_url} via ${COL_RED}a remote, public DNS server${COL_NC} (${remote_address})"
+ fi
}
process_status(){
- # Check to make sure Pi-hole's services are running and active
- echo_current_diagnostic "Pi-hole processes"
- # Local iterator
- local i
- # For each process,
- for i in "${PIHOLE_PROCESSES[@]}"; do
- # If systemd
- if command -v systemctl &> /dev/null; then
- # get its status via systemctl
- local status_of_process=$(systemctl is-active "${i}")
- else
- # Otherwise, use the service command
- local status_of_process=$(service "${i}" status | awk '/Active:/ {print $2}') &> /dev/null
- fi
- # and print it out to the user
- if [[ "${status_of_process}" == "active" ]]; then
- # If it's active, show it in green
- log_write "${TICK} ${COL_GREEN}${i}${COL_NC} daemon is ${COL_GREEN}${status_of_process}${COL_NC}"
- else
- # If it's not, show it in red
- log_write "${CROSS} ${COL_RED}${i}${COL_NC} daemon is ${COL_RED}${status_of_process}${COL_NC}"
- fi
- done
+ # Check to make sure Pi-hole's services are running and active
+ echo_current_diagnostic "Pi-hole processes"
+ # Local iterator
+ local i
+ # For each process,
+ for i in "${PIHOLE_PROCESSES[@]}"; do
+ # If systemd
+ if command -v systemctl &> /dev/null; then
+ # get its status via systemctl
+ local status_of_process
+ status_of_process=$(systemctl is-active "${i}")
+ else
+ # Otherwise, use the service command
+ local status_of_process
+ status_of_process=$(service "${i}" status | awk '/Active:/ {print $2}') &> /dev/null
+ fi
+ # and print it out to the user
+ if [[ "${status_of_process}" == "active" ]]; then
+ # If it's active, show it in green
+ log_write "${TICK} ${COL_GREEN}${i}${COL_NC} daemon is ${COL_GREEN}${status_of_process}${COL_NC}"
+ else
+ # If it's not, show it in red
+ log_write "${CROSS} ${COL_RED}${i}${COL_NC} daemon is ${COL_RED}${status_of_process}${COL_NC}"
+ fi
+ done
}
make_array_from_file() {
- local filename="${1}"
- # The second argument can put a limit on how many line should be read from the file
- # Since some of the files are so large, this is helpful to limit the output
- local limit=${2}
- # A local iterator for testing if we are at the limit above
- local i=0
- # Set the array to be empty so we can start fresh when the function is used
- local file_content=()
- # If the file is a directory
- if [[ -d "${filename}" ]]; then
- # do nothing since it cannot be parsed
- :
- else
- # Otherwise, read the file line by line
- while IFS= read -r line;do
- # Othwerise, strip out comments and blank lines
- new_line=$(echo "${line}" | sed -e 's/#.*$//' -e '/^$/d')
- # If the line still has content (a non-zero value)
- if [[ -n "${new_line}" ]]; then
- # Put it into the array
- file_content+=("${new_line}")
- else
- # Otherwise, it's a blank line or comment, so do nothing
+ local filename="${1}"
+ # The second argument can put a limit on how many line should be read from the file
+ # Since some of the files are so large, this is helpful to limit the output
+ local limit=${2}
+ # A local iterator for testing if we are at the limit above
+ local i=0
+ # Set the array to be empty so we can start fresh when the function is used
+ local file_content=()
+ # If the file is a directory
+ if [[ -d "${filename}" ]]; then
+ # do nothing since it cannot be parsed
:
- fi
- # Increment the iterator +1
- i=$((i+1))
- # but if the limit of lines we want to see is exceeded
- if [[ -z ${limit} ]]; then
- # do nothing
- :
- elif [[ $i -eq ${limit} ]]; then
- break
- fi
- done < "${filename}"
- # Now the we have made an array of the file's content
- for each_line in "${file_content[@]}"; do
- # Print each line
- # At some point, we may want to check the file line-by-line, so that's the reason for an array
- log_write " ${each_line}"
- done
- fi
+ else
+ # Otherwise, read the file line by line
+ while IFS= read -r line;do
+ # Othwerise, strip out comments and blank lines
+ new_line=$(echo "${line}" | sed -e 's/#.*$//' -e '/^$/d')
+ # If the line still has content (a non-zero value)
+ if [[ -n "${new_line}" ]]; then
+ # Put it into the array
+ file_content+=("${new_line}")
+ else
+ # Otherwise, it's a blank line or comment, so do nothing
+ :
+ fi
+ # Increment the iterator +1
+ i=$((i+1))
+ # but if the limit of lines we want to see is exceeded
+ if [[ -z ${limit} ]]; then
+ # do nothing
+ :
+ elif [[ $i -eq ${limit} ]]; then
+ break
+ fi
+ done < "${filename}"
+ # Now the we have made an array of the file's content
+ for each_line in "${file_content[@]}"; do
+ # Print each line
+ # At some point, we may want to check the file line-by-line, so that's the reason for an array
+ log_write " ${each_line}"
+ done
+ fi
}
parse_file() {
- # Set the first argument passed to this function as a named variable for better readability
- local filename="${1}"
- # Put the current Internal Field Separator into another variable so it can be restored later
- OLD_IFS="$IFS"
- # Get the lines that are in the file(s) and store them in an array for parsing later
- IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
-
- # Set a named variable for better readability
- local file_lines
- # For each line in the file,
- for file_lines in "${file_info[@]}"; do
- if [[ ! -z "${file_lines}" ]]; then
- # don't include the Web password hash
- [[ "${file_linesline}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue
- # otherwise, display the lines of the file
- log_write " ${file_lines}"
+ # Set the first argument passed to this function as a named variable for better readability
+ local filename="${1}"
+ # Put the current Internal Field Separator into another variable so it can be restored later
+ OLD_IFS="$IFS"
+ # Get the lines that are in the file(s) and store them in an array for parsing later
+ local file_info
+ if [[ -f "$filename" ]]; then
+ #shellcheck disable=SC2016
+ IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
+ else
+ read -a file_info <<< $filename
fi
- done
- # Set the IFS back to what it was
- IFS="$OLD_IFS"
+ # Set a named variable for better readability
+ local file_lines
+ # For each line in the file,
+ for file_lines in "${file_info[@]}"; do
+ if [[ ! -z "${file_lines}" ]]; then
+ # don't include the Web password hash
+ [[ "${file_lines}" =~ ^\#.*$ || ! "${file_lines}" || "${file_lines}" == "WEBPASSWORD="* ]] && continue
+ # otherwise, display the lines of the file
+ log_write " ${file_lines}"
+ fi
+ done
+ # Set the IFS back to what it was
+ IFS="$OLD_IFS"
}
check_name_resolution() {
- # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs
- # using the function we created earlier
- dig_at 4 "${IPV4_ADDRESS%/*}"
- # If IPv6 enabled,
- if [[ "${IPV6_ADDRESS}" ]]; then
- # check resolution
- dig_at 6 "${IPV6_ADDRESS%/*}"
- fi
+ # Check name resoltion from localhost, Pi-hole's IP, and Google's name severs
+ # using the function we created earlier
+ dig_at 4 "${IPV4_ADDRESS%/*}"
+ # If IPv6 enabled,
+ if [[ "${IPV6_ADDRESS}" ]]; then
+ # check resolution
+ dig_at 6 "${IPV6_ADDRESS%/*}"
+ fi
}
# This function can check a directory exists
# Pi-hole has files in several places, so we will reuse this function
dir_check() {
- # Set the first argument passed to tihs function as a named variable for better readability
- local directory="${1}"
- # Display the current test that is running
- echo_current_diagnostic "contents of ${COL_CYAN}${directory}${COL_NC}"
- # For each file in the directory,
- for filename in ${directory}; do
- # check if exists first; if it does,
- if ls "${filename}" 1> /dev/null 2>&1; then
- # do nothing
- :
- else
- # Otherwise, show an error
- log_write "${COL_RED}${directory} does not exist.${COL_NC}"
- fi
- done
+ # Set the first argument passed to tihs function as a named variable for better readability
+ local directory="${1}"
+ # Display the current test that is running
+ echo_current_diagnostic "contents of ${COL_CYAN}${directory}${COL_NC}"
+ # For each file in the directory,
+ for filename in ${directory}; do
+ # check if exists first; if it does,
+ if ls "${filename}" 1> /dev/null 2>&1; then
+ # do nothing
+ :
+ else
+ # Otherwise, show an error
+ log_write "${COL_RED}${directory} does not exist.${COL_NC}"
+ fi
+ done
}
list_files_in_dir() {
- # Set the first argument passed to tihs function as a named variable for better readability
- local dir_to_parse="${1}"
- # Store the files found in an array
- local files_found=( $(ls "${dir_to_parse}") )
- # For each file in the array,
- for each_file in "${files_found[@]}"; do
- if [[ -d "${dir_to_parse}/${each_file}" ]]; then
- # If it's a directoy, do nothing
- :
- elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \
- [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \
- [[ ${dir_to_parse}/${each_file} == ${PIHOLE_RAW_BLOCKLIST_FILES} ]] || \
- [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \
- [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_SETUP_VARS_FILE}" ]] || \
- [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \
- [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \
- [[ ${dir_to_parse}/${each_file} == ${PIHOLE_LOG_GZIPS} ]]; then
- :
- else
- # Then, parse the file's content into an array so each line can be analyzed if need be
- for i in "${!REQUIRED_FILES[@]}"; do
- if [[ "${dir_to_parse}/${each_file}" == ${REQUIRED_FILES[$i]} ]]; then
- # display the filename
- log_write "\n${COL_GREEN}$(ls -ld ${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)
- case "${dir_to_parse}/${each_file}" in
- # If it's Web server error log, just give the first 25 lines
- "${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") make_array_from_file "${dir_to_parse}/${each_file}" 25
- ;;
- # Same for the FTL log
- "${PIHOLE_FTL_LOG}") make_array_from_file "${dir_to_parse}/${each_file}" 25
- ;;
- # 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
+ # Set the first argument passed to tihs function as a named variable for better readability
+ local dir_to_parse="${1}"
+ # Store the files found in an array
+ mapfile -t files_found < <(ls "${dir_to_parse}")
+ # For each file in the array,
+ for each_file in "${files_found[@]}"; do
+ if [[ -d "${dir_to_parse}/${each_file}" ]]; then
+ # If it's a directoy, do nothing
+ :
+ elif [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_BLOCKLIST_FILE}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_DEBUG_LOG}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_RAW_BLOCKLIST_FILES}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_INSTALL_LOG_FILE}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_SETUP_VARS_FILE}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \
+ [[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG_GZIPS}" ]]; then
+ :
else
- # Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it
- :
+ # Then, parse the file's content into an array so each line can be analyzed if need be
+ for i in "${!REQUIRED_FILES[@]}"; do
+ if [[ "${dir_to_parse}/${each_file}" == "${REQUIRED_FILES[$i]}" ]]; then
+ # display the filename
+ log_write "\\n${COL_GREEN}$(ls -ld "${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)
+ case "${dir_to_parse}/${each_file}" in
+ # If it's Web server error log, just give the first 25 lines
+ "${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}") make_array_from_file "${dir_to_parse}/${each_file}" 25
+ ;;
+ # Same for the FTL log
+ "${PIHOLE_FTL_LOG}") head_tail_log "${dir_to_parse}/${each_file}" 35
+ ;;
+ # 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
+ else
+ # Otherwise, do nothing since it's not a file needed for Pi-hole so we don't care about it
+ :
+ fi
+ done
fi
- done
- fi
- done
+ done
}
show_content_of_files_in_dir() {
- # Set a local variable for better readability
- local directory="${1}"
- # Check if the directory exists
- dir_check "${directory}"
- # if it does, list the files in it
- list_files_in_dir "${directory}"
+ # Set a local variable for better readability
+ local directory="${1}"
+ # Check if the directory exists
+ dir_check "${directory}"
+ # if it does, list the files in it
+ list_files_in_dir "${directory}"
}
show_content_of_pihole_files() {
- # Show the content of the files in each of Pi-hole's folders
- show_content_of_files_in_dir "${PIHOLE_DIRECTORY}"
- show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}"
- show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}"
- show_content_of_files_in_dir "${CRON_D_DIRECTORY}"
- show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}"
- show_content_of_files_in_dir "${LOG_DIRECTORY}"
+ # Show the content of the files in each of Pi-hole's folders
+ show_content_of_files_in_dir "${PIHOLE_DIRECTORY}"
+ show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}"
+ show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}"
+ show_content_of_files_in_dir "${CRON_D_DIRECTORY}"
+ show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}"
+ show_content_of_files_in_dir "${LOG_DIRECTORY}"
+}
+
+head_tail_log() {
+ # The file being processed
+ local filename="${1}"
+ # The number of lines to use for head and tail
+ local qty="${2}"
+ local head_line
+ local tail_line
+ # Put the current Internal Field Separator into another variable so it can be restored later
+ OLD_IFS="$IFS"
+ # Get the lines that are in the file(s) and store them in an array for parsing later
+ IFS=$'\r\n'
+ local log_head=()
+ mapfile -t log_head < <(head -n "${qty}" "${filename}")
+ log_write " ${COL_CYAN}-----head of $(basename "${filename}")------${COL_NC}"
+ for head_line in "${log_head[@]}"; do
+ log_write " ${head_line}"
+ done
+ log_write ""
+ local log_tail=()
+ mapfile -t log_tail < <(tail -n "${qty}" "${filename}")
+ log_write " ${COL_CYAN}-----tail of $(basename "${filename}")------${COL_NC}"
+ for tail_line in "${log_tail[@]}"; do
+ log_write " ${tail_line}"
+ done
+ # Set the IFS back to what it was
+ IFS="$OLD_IFS"
}
analyze_gravity_list() {
- echo_current_diagnostic "Gravity list"
- local head_line
- local tail_line
- # Put the current Internal Field Separator into another variable so it can be restored later
- OLD_IFS="$IFS"
- # Get the lines that are in the file(s) and store them in an array for parsing later
- IFS=$'\r\n'
- local gravity_permissions=$(ls -ld "${PIHOLE_BLOCKLIST_FILE}")
- log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
- local gravity_head=()
- gravity_head=( $(head -n 4 ${PIHOLE_BLOCKLIST_FILE}) )
- log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
- for head_line in "${gravity_head[@]}"; do
- log_write " ${head_line}"
- done
- log_write ""
- local gravity_tail=()
- gravity_tail=( $(tail -n 4 ${PIHOLE_BLOCKLIST_FILE}) )
- log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
- for tail_line in "${gravity_tail[@]}"; do
- log_write " ${tail_line}"
- done
- # Set the IFS back to what it was
- IFS="$OLD_IFS"
+ echo_current_diagnostic "Gravity list"
+ local head_line
+ local tail_line
+ # Put the current Internal Field Separator into another variable so it can be restored later
+ OLD_IFS="$IFS"
+ # Get the lines that are in the file(s) and store them in an array for parsing later
+ IFS=$'\r\n'
+ local gravity_permissions
+ gravity_permissions=$(ls -ld "${PIHOLE_BLOCKLIST_FILE}")
+ log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
+ local gravity_head=()
+ mapfile -t gravity_head < <(head -n 4 ${PIHOLE_BLOCKLIST_FILE})
+ log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
+ for head_line in "${gravity_head[@]}"; do
+ log_write " ${head_line}"
+ done
+ log_write ""
+ local gravity_tail=()
+ mapfile -t gravity_tail < <(tail -n 4 ${PIHOLE_BLOCKLIST_FILE})
+ log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_BLOCKLIST_FILE})------${COL_NC}"
+ for tail_line in "${gravity_tail[@]}"; do
+ log_write " ${tail_line}"
+ done
+ # Set the IFS back to what it was
+ IFS="$OLD_IFS"
}
analyze_pihole_log() {
- echo_current_diagnostic "Pi-hole log"
- local head_line
- # Put the current Internal Field Separator into another variable so it can be restored later
- OLD_IFS="$IFS"
- # Get the lines that are in the file(s) and store them in an array for parsing later
- IFS=$'\r\n'
- local pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
- log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
- local pihole_log_head=()
- pihole_log_head=( $(head -n 20 ${PIHOLE_LOG}) )
- log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
- local error_to_check_for
- local line_to_obfuscate
- local obfuscated_line
- for head_line in "${pihole_log_head[@]}"; do
- # A common error in the pihole.log is when there is a non-hosts formatted file
- # that the DNS server is attempting to read. Since it's not formatted
- # correctly, there will be an entry for "bad address at line n"
- # So we can check for that here and highlight it in red so the user can see it easily
- error_to_check_for=$(echo ${head_line} | grep 'bad address at')
- # Some users may not want to have the domains they visit sent to us
- # To that end, we check for lines in the log that would contain a domain name
- line_to_obfuscate=$(echo ${head_line} | grep ': query\|: forwarded\|: reply')
- # If the variable contains a value, it found an error in the log
- if [[ -n ${error_to_check_for} ]]; then
- # So we can print it in red to make it visible to the user
- log_write " ${CROSS} ${COL_RED}${head_line}${COL_NC} (${FAQ_BAD_ADDRESS})"
- else
- # If the variable does not a value (the current default behavior), so do not obfuscate anything
- if [[ -z ${OBFUSCATE} ]]; then
- log_write " ${head_line}"
- # Othwerise, a flag was passed to this command to obfuscate domains in the log
- else
- # So first check if there are domains in the log that should be obfuscated
- if [[ -n ${line_to_obfuscate} ]]; then
- # If there are, we need to use awk to replace only the domain name (the 6th field in the log)
- # so we substitue the domain for the placeholder value
- obfuscated_line=$(echo ${line_to_obfuscate} | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
- log_write " ${obfuscated_line}"
+ echo_current_diagnostic "Pi-hole log"
+ local head_line
+ # Put the current Internal Field Separator into another variable so it can be restored later
+ OLD_IFS="$IFS"
+ # Get the lines that are in the file(s) and store them in an array for parsing later
+ IFS=$'\r\n'
+ local pihole_log_permissions
+ pihole_log_permissions=$(ls -ld "${PIHOLE_LOG}")
+ log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
+ local pihole_log_head=()
+ mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
+ log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
+ local error_to_check_for
+ local line_to_obfuscate
+ local obfuscated_line
+ for head_line in "${pihole_log_head[@]}"; do
+ # A common error in the pihole.log is when there is a non-hosts formatted file
+ # that the DNS server is attempting to read. Since it's not formatted
+ # correctly, there will be an entry for "bad address at line n"
+ # So we can check for that here and highlight it in red so the user can see it easily
+ error_to_check_for=$(echo "${head_line}" | grep 'bad address at')
+ # Some users may not want to have the domains they visit sent to us
+ # To that end, we check for lines in the log that would contain a domain name
+ line_to_obfuscate=$(echo "${head_line}" | grep ': query\|: forwarded\|: reply')
+ # If the variable contains a value, it found an error in the log
+ if [[ -n ${error_to_check_for} ]]; then
+ # So we can print it in red to make it visible to the user
+ log_write " ${CROSS} ${COL_RED}${head_line}${COL_NC} (${FAQ_BAD_ADDRESS})"
else
- log_write " ${head_line}"
+ # If the variable does not a value (the current default behavior), so do not obfuscate anything
+ if [[ -z ${OBFUSCATE} ]]; then
+ log_write " ${head_line}"
+ # Othwerise, a flag was passed to this command to obfuscate domains in the log
+ else
+ # So first check if there are domains in the log that should be obfuscated
+ if [[ -n ${line_to_obfuscate} ]]; then
+ # If there are, we need to use awk to replace only the domain name (the 6th field in the log)
+ # so we substitue the domain for the placeholder value
+ obfuscated_line=$(echo "${line_to_obfuscate}" | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
+ log_write " ${obfuscated_line}"
+ else
+ log_write " ${head_line}"
+ fi
+ fi
fi
- fi
- fi
- done
- log_write ""
- # Set the IFS back to what it was
- IFS="$OLD_IFS"
+ done
+ log_write ""
+ # Set the IFS back to what it was
+ IFS="$OLD_IFS"
}
tricorder_use_nc_or_ssl() {
- # Users can submit their debug logs using nc (unencrypted) or openssl (enrypted) if available
- # Check for openssl first since encryption is a good thing
- if command -v openssl &> /dev/null; then
- # If the command exists,
- log_write " * Using ${COL_GREEN}openssl${COL_NC} for transmission."
- # encrypt and transmit the log and store the token returned in a variable
- tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null)
- # Otherwise,
- else
- # use net cat
- log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission."
- # Save the token returned by our server in a variable
- tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER})
- fi
+ # Users can submit their debug logs using nc (unencrypted) or openssl (enrypted) if available
+ # Check for openssl first since encryption is a good thing
+ if command -v openssl &> /dev/null; then
+ # If the command exists,
+ log_write " * Using ${COL_GREEN}openssl${COL_NC} for transmission."
+ # encrypt and transmit the log and store the token returned in a variable
+ tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} openssl s_client -quiet -connect tricorder.pi-hole.net:${TRICORDER_SSL_PORT_NUMBER} 2> /dev/null)
+ # Otherwise,
+ else
+ # use net cat
+ log_write "${INFO} Using ${COL_YELLOW}netcat${COL_NC} for transmission."
+ # Save the token returned by our server in a variable
+ tricorder_token=$(< ${PIHOLE_DEBUG_LOG_SANITIZED} nc tricorder.pi-hole.net ${TRICORDER_NC_PORT_NUMBER})
+ fi
}
upload_to_tricorder() {
- local username="pihole"
- # Set the permissions and owner
- chmod 644 ${PIHOLE_DEBUG_LOG}
- chown "$USER":"${username}" ${PIHOLE_DEBUG_LOG}
+ local username="pihole"
+ # Set the permissions and owner
+ chmod 644 ${PIHOLE_DEBUG_LOG}
+ chown "$USER":"${username}" ${PIHOLE_DEBUG_LOG}
- # Let the user know debugging is complete with something strikingly visual
- log_write ""
- log_write "${COL_PURPLE}********************************************${COL_NC}"
- log_write "${COL_PURPLE}********************************************${COL_NC}"
- log_write "${TICK} ${COL_GREEN}** FINISHED DEBUGGING! **${COL_NC}\n"
+ # Let the user know debugging is complete with something strikingly visual
+ log_write ""
+ log_write "${COL_PURPLE}********************************************${COL_NC}"
+ log_write "${COL_PURPLE}********************************************${COL_NC}"
+ log_write "${TICK} ${COL_GREEN}** FINISHED DEBUGGING! **${COL_NC}\\n"
- # Provide information on what they should do with their token
- log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
- log_write " * For more information, see: ${TRICORDER_CONTEST}"
- log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat."
- # If pihole -d is running automatically (usually throught the dashboard)
- if [[ "${AUTOMATED}" ]]; then
- # let the user know
- log_write "${INFO} Debug script running in automated mode"
- # and then decide again which tool to use to submit it
- tricorder_use_nc_or_ssl
- # If we're not running in automated mode,
- else
- echo ""
- # give the user a choice of uploading it or not
- # 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
- case ${response} in
- # If they say yes, run our function for uploading the log
- [yY][eE][sS]|[yY]) tricorder_use_nc_or_ssl;;
- # If they choose no, just exit out of the script
- *) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.";exit;
- esac
- fi
- # Check if tricorder.pi-hole.net is reachable and provide token
- # along with some additional useful information
- if [[ -n "${tricorder_token}" ]]; then
- # Again, try to make this visually striking so the user realizes they need to do something with this information
- # Namely, provide the Pi-hole devs with the token
- log_write ""
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write "${TICK} Your debug token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write "${COL_PURPLE}***********************************${COL_NC}"
- log_write ""
- log_write " * Provide the token above to the Pi-hole team for assistance at"
- log_write " * ${FORUMS_URL}"
- log_write " * Your log will self-destruct on our server after ${COL_RED}48 hours${COL_NC}."
- # If no token was generated
- else
- # Show an error and some help instructions
- log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}"
- log_write " * Please try again or contact the Pi-hole team for assistance."
- fi
+ # Provide information on what they should do with their token
+ log_write " * The debug log can be uploaded to tricorder.pi-hole.net for sharing with developers only."
+ log_write " * For more information, see: ${TRICORDER_CONTEST}"
+ log_write " * If available, we'll use openssl to upload the log, otherwise it will fall back to netcat."
+ # If pihole -d is running automatically (usually throught the dashboard)
+ if [[ "${AUTOMATED}" ]]; then
+ # let the user know
+ log_write "${INFO} Debug script running in automated mode"
+ # and then decide again which tool to use to submit it
+ tricorder_use_nc_or_ssl
+ # If we're not running in automated mode,
+ else
+ echo ""
+ # give the user a choice of uploading it or not
+ # 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
+ case ${response} in
+ # If they say yes, run our function for uploading the log
+ [yY][eE][sS]|[yY]) tricorder_use_nc_or_ssl;;
+ # If they choose no, just exit out of the script
+ *) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.";exit;
+ esac
+ fi
+ # Check if tricorder.pi-hole.net is reachable and provide token
+ # along with some additional useful information
+ if [[ -n "${tricorder_token}" ]]; then
+ # Again, try to make this visually striking so the user realizes they need to do something with this information
+ # Namely, provide the Pi-hole devs with the token
+ log_write ""
+ log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write "${TICK} Your debug token is: ${COL_GREEN}${tricorder_token}${COL_NC}"
+ log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write "${COL_PURPLE}***********************************${COL_NC}"
+ log_write ""
+ log_write " * Provide the token above to the Pi-hole team for assistance at"
+ log_write " * ${FORUMS_URL}"
+ log_write " * Your log will self-destruct on our server after ${COL_RED}48 hours${COL_NC}."
+ # If no token was generated
+ else
+ # Show an error and some help instructions
+ log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}"
+ log_write " * Please try again or contact the Pi-hole team for assistance."
+ fi
# Finally, show where the log file is no matter the outcome of the function so users can look at it
- log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG_SANITIZED}${COL_NC}\n"
+ log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG_SANITIZED}${COL_NC}\\n"
}
# Run through all the functions we made
@@ -1165,6 +1223,7 @@ parse_setup_vars
check_x_headers
analyze_gravity_list
show_content_of_pihole_files
+parse_locale
analyze_pihole_log
copy_to_debug_log
upload_to_tricorder
diff --git a/advanced/Scripts/piholeLogFlush.sh b/advanced/Scripts/piholeLogFlush.sh
index 5fd9832e..4847282f 100755
--- a/advanced/Scripts/piholeLogFlush.sh
+++ b/advanced/Scripts/piholeLogFlush.sh
@@ -16,48 +16,51 @@ source ${colfile}
# Constructed to return nothing when
# a) the setting is not present in the config file, or
# b) the setting is commented out (e.g. "#DBFILE=...")
-DBFILE="$(sed -n -e 's/^\s^.DBFILE\s*=\s*//p' /etc/pihole/pihole-FTL.conf)"
+FTLconf="/etc/pihole/pihole-FTL.conf"
+if [ -e "$FTLconf" ]; then
+ DBFILE="$(sed -n -e 's/^\s*DBFILE\s*=\s*//p' ${FTLconf})"
+fi
# Test for empty string. Use standard path in this case.
if [ -z "$DBFILE" ]; then
- DBFILE="/etc/pihole/pihole-FTL.db"
+ DBFILE="/etc/pihole/pihole-FTL.db"
fi
if [[ "$@" != *"quiet"* ]]; then
- echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
+ echo -ne " ${INFO} Flushing /var/log/pihole.log ..."
fi
if [[ "$@" == *"once"* ]]; then
- # Nightly logrotation
- if command -v /usr/sbin/logrotate >/dev/null; then
- # Logrotate once
- /usr/sbin/logrotate --force /etc/pihole/logrotate
- else
- # Copy pihole.log over to pihole.log.1
- # and empty out pihole.log
- # Note that moving the file is not an option, as
- # dnsmasq would happily continue writing into the
- # moved file (it will have the same file handler)
- cp /var/log/pihole.log /var/log/pihole.log.1
- echo " " > /var/log/pihole.log
- fi
-else
- # Manual flushing
- if command -v /usr/sbin/logrotate >/dev/null; then
- # Logrotate twice to move all data out of sight of FTL
- /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
- /usr/sbin/logrotate --force /etc/pihole/logrotate
- else
- # Flush both pihole.log and pihole.log.1 (if existing)
- echo " " > /var/log/pihole.log
- if [ -f /var/log/pihole.log.1 ]; then
- echo " " > /var/log/pihole.log.1
+ # Nightly logrotation
+ if command -v /usr/sbin/logrotate >/dev/null; then
+ # Logrotate once
+ /usr/sbin/logrotate --force /etc/pihole/logrotate
+ else
+ # Copy pihole.log over to pihole.log.1
+ # and empty out pihole.log
+ # Note that moving the file is not an option, as
+ # dnsmasq would happily continue writing into the
+ # moved file (it will have the same file handler)
+ cp /var/log/pihole.log /var/log/pihole.log.1
+ echo " " > /var/log/pihole.log
fi
- fi
- # Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
- deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
+else
+ # Manual flushing
+ if command -v /usr/sbin/logrotate >/dev/null; then
+ # Logrotate twice to move all data out of sight of FTL
+ /usr/sbin/logrotate --force /etc/pihole/logrotate; sleep 3
+ /usr/sbin/logrotate --force /etc/pihole/logrotate
+ else
+ # Flush both pihole.log and pihole.log.1 (if existing)
+ echo " " > /var/log/pihole.log
+ if [ -f /var/log/pihole.log.1 ]; then
+ echo " " > /var/log/pihole.log.1
+ fi
+ fi
+ # Delete most recent 24 hours from FTL's database, leave even older data intact (don't wipe out all history)
+ deleted=$(sqlite3 "${DBFILE}" "DELETE FROM queries WHERE timestamp >= strftime('%s','now')-86400; select changes() from queries limit 1")
fi
if [[ "$@" != *"quiet"* ]]; then
- echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
- echo -e " ${TICK} Deleted ${deleted} queries from database"
+ echo -e "${OVER} ${TICK} Flushed /var/log/pihole.log"
+ echo -e " ${TICK} Deleted ${deleted} queries from database"
fi
diff --git a/advanced/Scripts/query.sh b/advanced/Scripts/query.sh
new file mode 100644
index 00000000..b599aa6b
--- /dev/null
+++ b/advanced/Scripts/query.sh
@@ -0,0 +1,239 @@
+#!/usr/bin/env bash
+# shellcheck disable=SC1090
+# Pi-hole: A black hole for Internet advertisements
+# (c) 2018 Pi-hole, LLC (https://pi-hole.net)
+# Network-wide ad blocking via your own hardware.
+#
+# Query Domain Lists
+#
+# This file is copyright under the latest version of the EUPL.
+# Please see LICENSE file for your rights under this license.
+
+# Globals
+piholeDir="/etc/pihole"
+adListsList="$piholeDir/adlists.list"
+wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf"
+options="$*"
+adlist=""
+all=""
+exact=""
+blockpage=""
+matchType="match"
+
+colfile="/opt/pihole/COL_TABLE"
+source "${colfile}"
+
+# Print each subdomain
+# e.g: foo.bar.baz.com = "foo.bar.baz.com bar.baz.com baz.com com"
+processWildcards() {
+ IFS="." read -r -a array <<< "${1}"
+ for (( i=${#array[@]}-1; i>=0; i-- )); do
+ ar=""
+ for (( j=${#array[@]}-1; j>${#array[@]}-i-2; j-- )); do
+ if [[ $j == $((${#array[@]}-1)) ]]; then
+ ar="${array[$j]}"
+ else
+ ar="${array[$j]}.${ar}"
+ fi
+ done
+ echo "${ar}"
+ done
+}
+
+# Scan an array of files for matching strings
+scanList(){
+ # Escape full stops
+ local domain="${1//./\\.}" lists="${2}" type="${3:-}"
+
+ # Prevent grep from printing file path
+ cd "$piholeDir" || exit 1
+
+ # Prevent grep -i matching slowly: http://bit.ly/2xFXtUX
+ export LC_CTYPE=C
+
+ # /dev/null forces filename to be printed when only one list has been generated
+ # shellcheck disable=SC2086
+ case "${type}" in
+ "exact" ) grep -i -E -l "(^|\\s)${domain}($|\\s|#)" ${lists} /dev/null 2>/dev/null;;
+ "wc" ) grep -i -o -m 1 "/${domain}/" ${lists} 2>/dev/null;;
+ * ) grep -i "${domain}" ${lists} /dev/null 2>/dev/null;;
+ esac
+}
+
+if [[ "${options}" == "-h" ]] || [[ "${options}" == "--help" ]]; then
+ echo "Usage: pihole -q [option]
+Example: 'pihole -q -exact domain.com'
+Query the adlists for a specified domain
+
+Options:
+ -adlist Print the name of the block list URL
+ -exact Search the block lists for exact domain matches
+ -all Return all query matches within a block list
+ -h, --help Show this help dialog"
+ exit 0
+fi
+
+if [[ ! -e "$adListsList" ]]; then
+ echo -e "${COL_LIGHT_RED}The file $adListsList was not found${COL_NC}"
+ exit 1
+fi
+
+# Handle valid options
+if [[ "${options}" == *"-bp"* ]]; then
+ exact="exact"; blockpage=true
+else
+ [[ "${options}" == *"-adlist"* ]] && adlist=true
+ [[ "${options}" == *"-all"* ]] && all=true
+ if [[ "${options}" == *"-exact"* ]]; then
+ exact="exact"; matchType="exact ${matchType}"
+ fi
+fi
+
+# Strip valid options, leaving only the domain and invalid options
+# This allows users to place the options before or after the domain
+options=$(sed -E 's/ ?-(bp|adlists?|all|exact) ?//g' <<< "${options}")
+
+# Handle remaining options
+# If $options contain non ASCII characters, convert to punycode
+case "${options}" in
+ "" ) str="No domain specified";;
+ *" "* ) str="Unknown query option specified";;
+ *[![:ascii:]]* ) domainQuery=$(idn2 "${options}");;
+ * ) domainQuery="${options}";;
+esac
+
+if [[ -n "${str:-}" ]]; then
+ echo -e "${str}${COL_NC}\\nTry 'pihole -q --help' for more information."
+ exit 1
+fi
+
+# Scan Whitelist and Blacklist
+lists="whitelist.txt blacklist.txt"
+mapfile -t results <<< "$(scanList "${domainQuery}" "${lists}" "${exact}")"
+if [[ -n "${results[*]}" ]]; then
+ wbMatch=true
+ # Loop through each result in order to print unique file title once
+ for result in "${results[@]}"; do
+ fileName="${result%%.*}"
+ if [[ -n "${blockpage}" ]]; then
+ echo "π ${result}"
+ exit 0
+ elif [[ -n "${exact}" ]]; then
+ echo " ${matchType^} found in ${COL_BOLD}${fileName^}${COL_NC}"
+ else
+ # Only print filename title once per file
+ if [[ ! "${fileName}" == "${fileName_prev:-}" ]]; then
+ echo " ${matchType^} found in ${COL_BOLD}${fileName^}${COL_NC}"
+ fileName_prev="${fileName}"
+ fi
+ echo " ${result#*:}"
+ fi
+ done
+fi
+
+# Scan Wildcards
+if [[ -e "${wildcardlist}" ]]; then
+ # Determine all subdomains, domain and TLDs
+ mapfile -t wildcards <<< "$(processWildcards "${domainQuery}")"
+ for match in "${wildcards[@]}"; do
+ # Search wildcard list for matches
+ mapfile -t results <<< "$(scanList "${match}" "${wildcardlist}" "wc")"
+ if [[ -n "${results[*]}" ]]; then
+ if [[ -z "${wcMatch:-}" ]] && [[ -z "${blockpage}" ]]; then
+ wcMatch=true
+ echo " ${matchType^} found in ${COL_BOLD}Wildcards${COL_NC}:"
+ fi
+ case "${blockpage}" in
+ true ) echo "π ${wildcardlist##*/}"; exit 0;;
+ * ) echo " *.${match}";;
+ esac
+ fi
+ done
+fi
+
+# Get version sorted *.domains filenames (without dir path)
+lists=("$(cd "$piholeDir" || exit 0; printf "%s\\n" -- *.domains | sort -V)")
+
+# Query blocklists for occurences of domain
+mapfile -t results <<< "$(scanList "${domainQuery}" "${lists[*]}" "${exact}")"
+
+# Handle notices
+if [[ -z "${wbMatch:-}" ]] && [[ -z "${wcMatch:-}" ]] && [[ -z "${results[*]}" ]]; then
+ echo -e " ${INFO} No ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC} within the block lists"
+ exit 0
+elif [[ -z "${results[*]}" ]]; then
+ # Result found in WL/BL/Wildcards
+ exit 0
+elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
+ echo -e " ${INFO} Over 100 ${exact/t/t }results found for ${COL_BOLD}${domainQuery}${COL_NC}
+ This can be overridden using the -all option"
+ exit 0
+fi
+
+# Remove unwanted content from non-exact $results
+if [[ -z "${exact}" ]]; then
+ # Delete lines starting with #
+ # Remove comments after domain
+ # Remove hosts format IP address
+ mapfile -t results <<< "$(IFS=$'\n'; sed \
+ -e "/:#/d" \
+ -e "s/[ \\t]#.*//g" \
+ -e "s/:.*[ \\t]/:/g" \
+ <<< "${results[*]}")"
+ # Exit if result was in a comment
+ [[ -z "${results[*]}" ]] && exit 0
+fi
+
+# Get adlist file content as array
+if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
+ for adlistUrl in $(< "${adListsList}"); do
+ if [[ "${adlistUrl:0:4}" =~ (http|www.) ]]; then
+ adlists+=("${adlistUrl}")
+ fi
+ done
+fi
+
+# Print "Exact matches for" title
+if [[ -n "${exact}" ]] && [[ -z "${blockpage}" ]]; then
+ plural=""; [[ "${#results[*]}" -gt 1 ]] && plural="es"
+ echo " ${matchType^}${plural} for ${COL_BOLD}${domainQuery}${COL_NC} found in:"
+fi
+
+for result in "${results[@]}"; do
+ fileName="${result/:*/}"
+
+ # Determine *.domains URL using filename's number
+ if [[ -n "${adlist}" ]] || [[ -n "${blockpage}" ]]; then
+ fileNum="${fileName/list./}"; fileNum="${fileNum%%.*}"
+ fileName="${adlists[$fileNum]}"
+
+ # Discrepency occurs when adlists has been modified, but Gravity has not been run
+ if [[ -z "${fileName}" ]]; then
+ fileName="${COL_LIGHT_RED}(no associated adlists URL found)${COL_NC}"
+ fi
+ fi
+
+ if [[ -n "${blockpage}" ]]; then
+ echo "${fileNum} ${fileName}"
+ elif [[ -n "${exact}" ]]; then
+ echo " ${fileName}"
+ else
+ if [[ ! "${fileName}" == "${fileName_prev:-}" ]]; then
+ count=""
+ echo " ${matchType^} found in ${COL_BOLD}${fileName}${COL_NC}:"
+ fileName_prev="${fileName}"
+ fi
+ : $((count++))
+
+ # Print matching domain if $max_count has not been reached
+ [[ -z "${all}" ]] && max_count="50"
+ if [[ -z "${all}" ]] && [[ "${count}" -ge "${max_count}" ]]; then
+ [[ "${count}" -gt "${max_count}" ]] && continue
+ echo " ${COL_GRAY}Over ${count} results found, skipping rest of file${COL_NC}"
+ else
+ echo " ${result#*:}"
+ fi
+ fi
+done
+
+exit 0
diff --git a/advanced/Scripts/setupLCD.sh b/advanced/Scripts/setupLCD.sh
index d780da57..00eb963f 100755
--- a/advanced/Scripts/setupLCD.sh
+++ b/advanced/Scripts/setupLCD.sh
@@ -15,28 +15,28 @@
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
getInitSys() {
- if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
- SYSTEMD=1
- elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
- SYSTEMD=0
- else
- echo "Unrecognised init system"
- return 1
- fi
+ if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
+ SYSTEMD=1
+ elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
+ SYSTEMD=0
+ else
+ echo "Unrecognised init system"
+ return 1
+ fi
}
# Borrowed from adafruit-pitft-helper:
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
autoLoginPiToConsole() {
- if [ -e /etc/init.d/lightdm ]; then
- if [ ${SYSTEMD} -eq 1 ]; then
- systemctl set-default multi-user.target
- ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
- else
- update-rc.d lightdm disable 2
- sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
- fi
- fi
+ if [ -e /etc/init.d/lightdm ]; then
+ if [ ${SYSTEMD} -eq 1 ]; then
+ systemctl set-default multi-user.target
+ ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
+ else
+ update-rc.d lightdm disable 2
+ sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
+ fi
+ fi
}
######### SCRIPT ###########
diff --git a/advanced/Scripts/update.sh b/advanced/Scripts/update.sh
index a4ada4c8..59212a94 100755
--- a/advanced/Scripts/update.sh
+++ b/advanced/Scripts/update.sh
@@ -19,6 +19,9 @@ readonly PI_HOLE_FILES_DIR="/etc/.pihole"
# shellcheck disable=SC2034
PH_TEST=true
+# when --check-only is passed to this script, it will not perform the actual update
+CHECK_ONLY=false
+
# shellcheck disable=SC1090
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# shellcheck disable=SC1091
@@ -28,201 +31,161 @@ source "/opt/pihole/COL_TABLE"
# make_repo() sourced from basic-install.sh
# update_repo() source from basic-install.sh
# getGitFiles() sourced from basic-install.sh
+# get_binary_name() sourced from basic-install.sh
+# FTLcheckUpdate() sourced from basic-install.sh
GitCheckUpdateAvail() {
- local directory="${1}"
- curdir=$PWD
- cd "${directory}" || return
+ local directory
+ directory="${1}"
+ curdir=$PWD
+ cd "${directory}" || return
- # Fetch latest changes in this repo
- git fetch --quiet origin
+ # Fetch latest changes in this repo
+ git fetch --quiet origin
- # @ alone is a shortcut for HEAD. Older versions of git
- # need @{0}
- LOCAL="$(git rev-parse "@{0}")"
+ # @ alone is a shortcut for HEAD. Older versions of git
+ # need @{0}
+ LOCAL="$(git rev-parse "@{0}")"
- # The suffix @{upstream} to a branchname
- # (short form @{u}) refers
- # to the branch that the branch specified
- # by branchname is set to build on top of#
- # (configured with branch..remote and
- # branch..merge). A missing branchname
- # defaults to the current one.
- REMOTE="$(git rev-parse "@{upstream}")"
+ # The suffix @{upstream} to a branchname
+ # (short form @{u}) refers
+ # to the branch that the branch specified
+ # by branchname is set to build on top of#
+ # (configured with branch..remote and
+ # branch..merge). A missing branchname
+ # defaults to the current one.
+ REMOTE="$(git rev-parse "@{upstream}")"
- if [[ "${#LOCAL}" == 0 ]]; then
- echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support
- Additional debugging output:${COL_NC}"
- git status
- exit
- fi
- if [[ "${#REMOTE}" == 0 ]]; then
- echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support
- Additional debugging output:${COL_NC}"
- git status
- exit
- fi
+ if [[ "${#LOCAL}" == 0 ]]; then
+ 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}"
+ git status
+ exit
+ fi
+ if [[ "${#REMOTE}" == 0 ]]; then
+ echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
+ echo -e " Additional debugging output:${COL_NC}"
+ git status
+ exit
+ fi
- # Change back to original directory
- cd "${curdir}" || exit
+ # Change back to original directory
+ cd "${curdir}" || exit
- if [[ "${LOCAL}" != "${REMOTE}" ]]; then
- # Local branch is behind remote branch -> Update
- return 0
- else
- # Local branch is up-to-date or in a situation
- # where this updater cannot be used (like on a
- # branch that exists only locally)
- return 1
- fi
-}
-
-FTLcheckUpdate() {
- local FTLversion
- FTLversion=$(/usr/bin/pihole-FTL tag)
- local FTLlatesttag
- FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep 'Location' | awk -F '/' '{print $NF}' | tr -d '\r\n')
-
- if [[ "${FTLversion}" != "${FTLlatesttag}" ]]; then
- return 0
- else
- return 1
- fi
+ if [[ "${LOCAL}" != "${REMOTE}" ]]; then
+ # Local branch is behind remote branch -> Update
+ return 0
+ else
+ # Local branch is up-to-date or in a situation
+ # where this updater cannot be used (like on a
+ # branch that exists only locally)
+ return 1
+ fi
}
main() {
- local pihole_version_current
- local web_version_current
- local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
-
- # shellcheck disable=1090,2154
- source "${setupVars}"
+ local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
+ local core_update
+ local web_update
+ local FTL_update
- # This is unlikely
- if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
- echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!
- Please re-run install script from https://pi-hole.net${COL_NC}"
- exit 1;
- fi
-
- echo -e " ${INFO} Checking for updates..."
-
- if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
- core_update=true
- echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
- else
core_update=false
- echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
- fi
-
- if FTLcheckUpdate ; then
- FTL_update=true
- echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
- else
+ web_update=false
FTL_update=false
- echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
- fi
- # Logic: Don't update FTL when there is a core update available
- # since the core update will run the installer which will itself
- # re-install (i.e. update) FTL
- if ${FTL_update} && ! ${core_update}; then
- echo ""
- echo -e " ${INFO} FTL out of date"
- FTLdetect
- echo ""
- fi
+ # shellcheck disable=1090,2154
+ source "${setupVars}"
- if [[ "${INSTALL_WEB}" == true ]]; then
- if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
- echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!
- Please re-run install script from https://pi-hole.net${COL_NC}"
- exit 1;
+ # This is unlikely
+ 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 " Please re-run install script from https://pi-hole.net${COL_NC}"
+ exit 1;
fi
- if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
- web_update=true
- echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
+ echo -e " ${INFO} Checking for updates..."
+
+ if GitCheckUpdateAvail "${PI_HOLE_FILES_DIR}" ; then
+ core_update=true
+ echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
else
- web_update=false
- echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
+ core_update=false
+ echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
fi
- # Logic
- # If Core up to date AND web up to date:
- # Do nothing
- # If Core up to date AND web NOT up to date:
- # Pull web repo
- # If Core NOT up to date AND web up to date:
- # pull pihole repo, run install --unattended -- reconfigure
- # if Core NOT up to date AND web NOT up to date:
- # pull pihole repo run install --unattended
+ if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
+ if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
+ 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}"
+ exit 1;
+ fi
- if ! ${core_update} && ! ${web_update} ; then
- if ! ${FTL_update} ; then
+ if GitCheckUpdateAvail "${ADMIN_INTERFACE_DIR}" ; then
+ web_update=true
+ echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
+ else
+ web_update=false
+ echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
+ fi
+ fi
+
+ if FTLcheckUpdate > /dev/null; then
+ FTL_update=true
+ echo -e " ${INFO} FTL:\\t\\t${COL_YELLOW}update available${COL_NC}"
+ else
+ case $? in
+ 1)
+ echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}"
+ ;;
+ 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}Something has gone wrong, contact support${COL_NC}"
+ esac
+ FTL_update=false
+ fi
+
+ if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
echo ""
echo -e " ${TICK} Everything is up to date!"
exit 0
- fi
- elif ! ${core_update} && ${web_update} ; then
- echo ""
- echo -e " ${INFO} Pi-hole Web Admin files out of date"
- getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
- elif ${core_update} && ! ${web_update} ; then
- echo ""
- echo -e " ${INFO} Pi-hole core files out of date"
- getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
- ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
- echo -e "${basicError}" && exit 1
- elif ${core_update} && ${web_update} ; then
- echo ""
- echo -e " ${INFO} Updating Pi-hole core and web admin files"
- getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
- ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --unattended || \
- echo -e "${basicError}" && exit 1
- else
- echo -e " ${COL_LIGHT_RED}Update script has malfunctioned, please contact Pi-hole Support${COL_NC}"
- exit 1
fi
- else # Web Admin not installed, so only verify if core is up to date
- if ! ${core_update}; then
- if ! ${FTL_update} ; then
+
+ if [[ "${CHECK_ONLY}" == true ]]; then
echo ""
- echo -e " ${INFO} Everything is up to date!"
exit 0
- fi
- else
- echo ""
- echo -e " ${INFO} Pi-hole Core files out of date"
- getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
- ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
+ fi
+
+ if [[ "${core_update}" == true ]]; then
+ echo ""
+ echo -e " ${INFO} Pi-hole core files out of date, updating local repo."
+ getGitFiles "${PI_HOLE_FILES_DIR}" "${PI_HOLE_GIT_URL}"
+ echo -e " ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
+ fi
+
+ if [[ "${web_update}" == true ]]; then
+ echo ""
+ echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
+ getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}"
+ echo -e " ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
+ fi
+
+ if [[ "${FTL_update}" == true ]]; then
+ echo ""
+ echo -e " ${INFO} FTL out of date, it will be updated by the installer."
+ fi
+
+ if [[ "${FTL_update}" == true || "${core_update}" == true ]]; then
+ ${PI_HOLE_FILES_DIR}/automated\ install/basic-install.sh --reconfigure --unattended || \
echo -e "${basicError}" && exit 1
fi
- fi
-
- if [[ "${web_update}" == true ]]; then
- web_version_current="$(/usr/local/bin/pihole version --admin --current)"
echo ""
- echo -e " ${INFO} Web Admin version is now at ${web_version_current/* v/v}
- ${INFO} If you had made any changes in '/var/www/html/admin/', they have been stashed using 'git stash'"
- fi
-
- if [[ "${core_update}" == true ]]; then
- pihole_version_current="$(/usr/local/bin/pihole version --pihole --current)"
- echo ""
- echo -e " ${INFO} Pi-hole version is now at ${pihole_version_current/* v/v}
- ${INFO} If you had made any changes in '/etc/.pihole/', they have been stashed using 'git stash'"
- fi
-
- if [[ "${FTL_update}" == true ]]; then
- FTL_version_current="$(/usr/bin/pihole-FTL tag)"
- echo -e "\\n ${INFO} FTL version is now at ${FTL_version_current/* v/v}"
- start_service pihole-FTL
- enable_service pihole-FTL
- fi
-
- echo ""
- exit 0
+ exit 0
}
+if [[ "$1" == "--check-only" ]]; then
+ CHECK_ONLY=true
+fi
+
main
diff --git a/advanced/Scripts/updatecheck.sh b/advanced/Scripts/updatecheck.sh
index 16938a3a..767c5461 100755
--- a/advanced/Scripts/updatecheck.sh
+++ b/advanced/Scripts/updatecheck.sh
@@ -10,57 +10,57 @@
# Credit: https://stackoverflow.com/a/46324904
function json_extract() {
- local key=$1
- local json=$2
+ local key=$1
+ local json=$2
- local string_regex='"([^"\]|\\.)*"'
- local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
- local value_regex="${string_regex}|${number_regex}|true|false|null"
- local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
+ local string_regex='"([^"\]|\\.)*"'
+ local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
+ local value_regex="${string_regex}|${number_regex}|true|false|null"
+ local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
- if [[ ${json} =~ ${pair_regex} ]]; then
- echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
- else
- return 1
- fi
+ if [[ ${json} =~ ${pair_regex} ]]; then
+ echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
+ else
+ return 1
+ fi
}
function get_local_branch() {
- # Return active branch
- cd "${1}" 2> /dev/null || return 1
- git rev-parse --abbrev-ref HEAD || return 1
+ # Return active branch
+ cd "${1}" 2> /dev/null || return 1
+ git rev-parse --abbrev-ref HEAD || return 1
}
function get_local_version() {
-# Return active branch
-cd "${1}" 2> /dev/null || return 1
-git describe --long --dirty --tags || return 1
+ # Return active branch
+ cd "${1}" 2> /dev/null || return 1
+ git describe --long --dirty --tags || return 1
}
if [[ "$2" == "remote" ]]; then
- if [[ "$3" == "reboot" ]]; then
- sleep 30
- fi
+ if [[ "$3" == "reboot" ]]; then
+ sleep 30
+ fi
- GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
- GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
- GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
+ GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
+ GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
+ GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -q 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
- echo -n "${GITHUB_CORE_VERSION} ${GITHUB_WEB_VERSION} ${GITHUB_FTL_VERSION}" > "/etc/pihole/GitHubVersions"
+ echo -n "${GITHUB_CORE_VERSION} ${GITHUB_WEB_VERSION} ${GITHUB_FTL_VERSION}" > "/etc/pihole/GitHubVersions"
else
- CORE_BRANCH="$(get_local_branch /etc/.pihole)"
- WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
- FTL_BRANCH="$(pihole-FTL branch)"
+ CORE_BRANCH="$(get_local_branch /etc/.pihole)"
+ WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
+ FTL_BRANCH="$(pihole-FTL branch)"
- echo -n "${CORE_BRANCH} ${WEB_BRANCH} ${FTL_BRANCH}" > "/etc/pihole/localbranches"
+ echo -n "${CORE_BRANCH} ${WEB_BRANCH} ${FTL_BRANCH}" > "/etc/pihole/localbranches"
- CORE_VERSION="$(get_local_version /etc/.pihole)"
- WEB_VERSION="$(get_local_version /var/www/html/admin)"
- FTL_VERSION="$(pihole-FTL version)"
+ CORE_VERSION="$(get_local_version /etc/.pihole)"
+ WEB_VERSION="$(get_local_version /var/www/html/admin)"
+ FTL_VERSION="$(pihole-FTL version)"
- echo -n "${CORE_VERSION} ${WEB_VERSION} ${FTL_VERSION}" > "/etc/pihole/localversions"
+ echo -n "${CORE_VERSION} ${WEB_VERSION} ${FTL_VERSION}" > "/etc/pihole/localversions"
fi
diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh
index f5e0f51d..7dfa1a90 100755
--- a/advanced/Scripts/version.sh
+++ b/advanced/Scripts/version.sh
@@ -14,135 +14,135 @@ COREGITDIR="/etc/.pihole/"
WEBGITDIR="/var/www/html/admin/"
getLocalVersion() {
- # FTL requires a different method
- if [[ "$1" == "FTL" ]]; then
- pihole-FTL version
+ # FTL requires a different method
+ if [[ "$1" == "FTL" ]]; then
+ pihole-FTL version
+ return 0
+ fi
+
+ # Get the tagged version of the local repository
+ local directory="${1}"
+ local version
+
+ cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
+ version=$(git describe --tags --always || echo "$DEFAULT")
+ if [[ "${version}" =~ ^v ]]; then
+ echo "${version}"
+ elif [[ "${version}" == "${DEFAULT}" ]]; then
+ echo "ERROR"
+ return 1
+ else
+ echo "Untagged"
+ fi
return 0
- fi
-
- # Get the tagged version of the local repository
- local directory="${1}"
- local version
-
- cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
- version=$(git describe --tags --always || echo "$DEFAULT")
- if [[ "${version}" =~ ^v ]]; then
- echo "${version}"
- elif [[ "${version}" == "${DEFAULT}" ]]; then
- echo "ERROR"
- return 1
- else
- echo "Untagged"
- fi
- return 0
}
getLocalHash() {
- # Local FTL hash does not exist on filesystem
- if [[ "$1" == "FTL" ]]; then
- echo "N/A"
- return 0
- fi
-
- # Get the short hash of the local repository
- local directory="${1}"
- local hash
+ # Local FTL hash does not exist on filesystem
+ if [[ "$1" == "FTL" ]]; then
+ echo "N/A"
+ return 0
+ fi
- cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
- hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
- if [[ "${hash}" == "${DEFAULT}" ]]; then
- echo "ERROR"
- return 1
- else
- echo "${hash}"
- fi
- return 0
+ # Get the short hash of the local repository
+ local directory="${1}"
+ local hash
+
+ cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
+ hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
+ if [[ "${hash}" == "${DEFAULT}" ]]; then
+ echo "ERROR"
+ return 1
+ else
+ echo "${hash}"
+ fi
+ return 0
}
getRemoteHash(){
- # Remote FTL hash is not applicable
- if [[ "$1" == "FTL" ]]; then
- echo "N/A"
+ # Remote FTL hash is not applicable
+ if [[ "$1" == "FTL" ]]; then
+ echo "N/A"
+ return 0
+ fi
+
+ local daemon="${1}"
+ local branch="${2}"
+
+ hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \
+ awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}')
+ if [[ -n "$hash" ]]; then
+ echo "$hash"
+ else
+ echo "ERROR"
+ return 1
+ fi
return 0
- fi
-
- local daemon="${1}"
- local branch="${2}"
-
- hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \
- awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}')
- if [[ -n "$hash" ]]; then
- echo "$hash"
- else
- echo "ERROR"
- return 1
- fi
- return 0
}
getRemoteVersion(){
- # Get the version from the remote origin
- local daemon="${1}"
- local version
+ # Get the version from the remote origin
+ local daemon="${1}"
+ local version
- version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
- awk -F: '$1 ~/tag_name/ { print $2 }' | \
- tr -cd '[[:alnum:]]._-')
- if [[ "${version}" =~ ^v ]]; then
- echo "${version}"
- else
- echo "ERROR"
- return 1
- fi
- return 0
+ version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
+ awk -F: '$1 ~/tag_name/ { print $2 }' | \
+ tr -cd '[[:alnum:]]._-')
+ if [[ "${version}" =~ ^v ]]; then
+ echo "${version}"
+ else
+ echo "ERROR"
+ return 1
+ fi
+ return 0
}
versionOutput() {
- [[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
- [[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
- [[ "$1" == "FTL" ]] && GITDIR="FTL"
-
- [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR)
- [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
- if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
- [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR")
- [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
- fi
+ [[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
+ [[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
+ [[ "$1" == "FTL" ]] && GITDIR="FTL"
- if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
- output="${1^} version is $current (Latest: $latest)"
- elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
- output="Current ${1^} version is $current"
- elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
- output="Latest ${1^} version is $latest"
- elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
- output="${1^} hash is not applicable"
- elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
- output="${1^} hash is $curHash (Latest: $latHash)"
- elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
- output="Current ${1^} hash is $curHash"
- elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
- output="Latest ${1^} hash is $latHash"
- else
- errorOutput
- fi
+ [[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR)
+ [[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
+ if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
+ [[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR")
+ [[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
+ fi
- [[ -n "$output" ]] && echo " $output"
+ if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
+ output="${1^} version is $current (Latest: $latest)"
+ elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
+ output="Current ${1^} version is $current"
+ elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
+ output="Latest ${1^} version is $latest"
+ elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
+ output="${1^} hash is not applicable"
+ elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
+ output="${1^} hash is $curHash (Latest: $latHash)"
+ elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
+ output="Current ${1^} hash is $curHash"
+ elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
+ output="Latest ${1^} hash is $latHash"
+ else
+ errorOutput
+ fi
+
+ [[ -n "$output" ]] && echo " $output"
}
errorOutput() {
- echo " Invalid Option! Try 'pihole -v --help' for more information."
- exit 1
+ echo " Invalid Option! Try 'pihole -v --help' for more information."
+ exit 1
}
-
+
defaultOutput() {
- versionOutput "pi-hole" "$@"
- versionOutput "AdminLTE" "$@"
- versionOutput "FTL" "$@"
+ versionOutput "pi-hole" "$@"
+ versionOutput "AdminLTE" "$@"
+ versionOutput "FTL" "$@"
}
helpFunc() {
- echo "Usage: pihole -v [repo | option] [option]
+ echo "Usage: pihole -v [repo | option] [option]
Example: 'pihole -v -p -l'
Show Pi-hole, Admin Console & FTL versions
@@ -150,7 +150,7 @@ Repositories:
-p, --pihole Only retrieve info regarding Pi-hole repository
-a, --admin Only retrieve info regarding AdminLTE repository
-f, --ftl Only retrieve info regarding FTL repository
-
+
Options:
-c, --current Return the current version
-l, --latest Return the latest version
@@ -160,9 +160,9 @@ Options:
}
case "${1}" in
- "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
- "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
- "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
- "-h" | "--help" ) helpFunc;;
- * ) defaultOutput "$@";;
+ "-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
+ "-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
+ "-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
+ "-h" | "--help" ) helpFunc;;
+ * ) defaultOutput "$@";;
esac
diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh
index 5eb35e97..c3dede05 100755
--- a/advanced/Scripts/webpage.sh
+++ b/advanced/Scripts/webpage.sh
@@ -13,16 +13,17 @@
readonly setupVars="/etc/pihole/setupVars.conf"
readonly dnsmasqconfig="/etc/dnsmasq.d/01-pihole.conf"
readonly dhcpconfig="/etc/dnsmasq.d/02-pihole-dhcp.conf"
+readonly FTLconf="/etc/pihole/pihole-FTL.conf"
# 03 -> wildcards
readonly dhcpstaticconfig="/etc/dnsmasq.d/04-pihole-static-dhcp.conf"
coltable="/opt/pihole/COL_TABLE"
if [[ -f ${coltable} ]]; then
- source ${coltable}
+ source ${coltable}
fi
helpFunc() {
- echo "Usage: pihole -a [options]
+ echo "Usage: pihole -a [options]
Example: pihole -a -p password
Set options for the Admin Console
@@ -35,256 +36,278 @@ Options:
-e, email Set an administrative contact address for the Block Page
-h, --help Show this help dialog
-i, interface Specify dnsmasq's interface listening behavior
- Add '-h' for more info on interface usage"
- exit 0
+ -l, privacylevel Set privacy level (0 = lowest, 3 = highest)"
+ exit 0
}
add_setting() {
- echo "${1}=${2}" >> "${setupVars}"
+ echo "${1}=${2}" >> "${setupVars}"
}
delete_setting() {
- sed -i "/${1}/d" "${setupVars}"
+ sed -i "/${1}/d" "${setupVars}"
}
change_setting() {
- delete_setting "${1}"
- add_setting "${1}" "${2}"
+ delete_setting "${1}"
+ add_setting "${1}" "${2}"
+}
+
+addFTLsetting() {
+ echo "${1}=${2}" >> "${FTLconf}"
+}
+
+deleteFTLsetting() {
+ sed -i "/${1}/d" "${FTLconf}"
+}
+
+changeFTLsetting() {
+ deleteFTLsetting "${1}"
+ addFTLsetting "${1}" "${2}"
}
add_dnsmasq_setting() {
- if [[ "${2}" != "" ]]; then
- echo "${1}=${2}" >> "${dnsmasqconfig}"
- else
- echo "${1}" >> "${dnsmasqconfig}"
- fi
+ if [[ "${2}" != "" ]]; then
+ echo "${1}=${2}" >> "${dnsmasqconfig}"
+ else
+ echo "${1}" >> "${dnsmasqconfig}"
+ fi
}
delete_dnsmasq_setting() {
- sed -i "/${1}/d" "${dnsmasqconfig}"
+ sed -i "/${1}/d" "${dnsmasqconfig}"
}
SetTemperatureUnit() {
- change_setting "TEMPERATUREUNIT" "${unit}"
- echo -e " ${TICK} Set temperature unit to ${unit}"
+ change_setting "TEMPERATUREUNIT" "${unit}"
+ echo -e " ${TICK} Set temperature unit to ${unit}"
}
HashPassword() {
- # Compute password hash twice to avoid rainbow table vulnerability
- return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
- return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
- echo ${return}
+ # Compute password hash twice to avoid rainbow table vulnerability
+ return=$(echo -n ${1} | sha256sum | sed 's/\s.*$//')
+ return=$(echo -n ${return} | sha256sum | sed 's/\s.*$//')
+ echo ${return}
}
SetWebPassword() {
- if [ "${SUDO_USER}" == "www-data" ]; then
- echo "Security measure: user www-data is not allowed to change webUI password!"
- echo "Exiting"
- exit 1
- fi
+ if [ "${SUDO_USER}" == "www-data" ]; then
+ echo "Security measure: user www-data is not allowed to change webUI password!"
+ echo "Exiting"
+ exit 1
+ fi
- if [ "${SUDO_USER}" == "lighttpd" ]; then
- echo "Security measure: user lighttpd is not allowed to change webUI password!"
- echo "Exiting"
- exit 1
- fi
+ if [ "${SUDO_USER}" == "lighttpd" ]; then
+ echo "Security measure: user lighttpd is not allowed to change webUI password!"
+ echo "Exiting"
+ exit 1
+ fi
- if (( ${#args[2]} > 0 )) ; then
- readonly PASSWORD="${args[2]}"
- readonly CONFIRM="${PASSWORD}"
- else
- # Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
- # So we reset the terminal via stty if the user does press Ctrl+C
- trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
- read -s -p "Enter New Password (Blank for no password): " PASSWORD
- echo ""
+ if (( ${#args[2]} > 0 )) ; then
+ readonly PASSWORD="${args[2]}"
+ readonly CONFIRM="${PASSWORD}"
+ else
+ # Prevents a bug if the user presses Ctrl+C and it continues to hide the text typed.
+ # So we reset the terminal via stty if the user does press Ctrl+C
+ trap '{ echo -e "\nNo password will be set" ; stty sane ; exit 1; }' INT
+ read -s -p "Enter New Password (Blank for no password): " PASSWORD
+ echo ""
if [ "${PASSWORD}" == "" ]; then
- change_setting "WEBPASSWORD" ""
- echo -e " ${TICK} Password Removed"
- exit 0
+ change_setting "WEBPASSWORD" ""
+ echo -e " ${TICK} Password Removed"
+ exit 0
fi
read -s -p "Confirm Password: " CONFIRM
echo ""
- fi
+ fi
- if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
- hash=$(HashPassword "${PASSWORD}")
- # Save hash to file
- change_setting "WEBPASSWORD" "${hash}"
- echo -e " ${TICK} New password set"
- else
- echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
- exit 1
- fi
+ if [ "${PASSWORD}" == "${CONFIRM}" ] ; then
+ hash=$(HashPassword "${PASSWORD}")
+ # Save hash to file
+ change_setting "WEBPASSWORD" "${hash}"
+ echo -e " ${TICK} New password set"
+ else
+ echo -e " ${CROSS} Passwords don't match. Your password has not been changed"
+ exit 1
+ fi
}
ProcessDNSSettings() {
- source "${setupVars}"
+ source "${setupVars}"
- delete_dnsmasq_setting "server"
+ delete_dnsmasq_setting "server"
- COUNTER=1
- while [[ 1 ]]; do
- var=PIHOLE_DNS_${COUNTER}
- if [ -z "${!var}" ]; then
- break;
- fi
- add_dnsmasq_setting "server" "${!var}"
- let COUNTER=COUNTER+1
- done
+ COUNTER=1
+ while [[ 1 ]]; do
+ var=PIHOLE_DNS_${COUNTER}
+ if [ -z "${!var}" ]; then
+ break;
+ fi
+ add_dnsmasq_setting "server" "${!var}"
+ let COUNTER=COUNTER+1
+ done
- delete_dnsmasq_setting "domain-needed"
+ # The option LOCAL_DNS_PORT is deprecated
+ # We apply it once more, and then convert it into the current format
+ if [ ! -z "${LOCAL_DNS_PORT}" ]; then
+ add_dnsmasq_setting "server" "127.0.0.1#${LOCAL_DNS_PORT}"
+ add_setting "PIHOLE_DNS_${COUNTER}" "127.0.0.1#${LOCAL_DNS_PORT}"
+ delete_setting "LOCAL_DNS_PORT"
+ fi
- if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
- add_dnsmasq_setting "domain-needed"
- fi
+ delete_dnsmasq_setting "domain-needed"
- delete_dnsmasq_setting "bogus-priv"
+ if [[ "${DNS_FQDN_REQUIRED}" == true ]]; then
+ add_dnsmasq_setting "domain-needed"
+ fi
- if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
- add_dnsmasq_setting "bogus-priv"
- fi
+ delete_dnsmasq_setting "bogus-priv"
- delete_dnsmasq_setting "dnssec"
- delete_dnsmasq_setting "trust-anchor="
+ if [[ "${DNS_BOGUS_PRIV}" == true ]]; then
+ add_dnsmasq_setting "bogus-priv"
+ fi
- if [[ "${DNSSEC}" == true ]]; then
- echo "dnssec
+ delete_dnsmasq_setting "dnssec"
+ delete_dnsmasq_setting "trust-anchor="
+
+ if [[ "${DNSSEC}" == true ]]; then
+ echo "dnssec
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D
" >> "${dnsmasqconfig}"
- fi
+ fi
- delete_dnsmasq_setting "host-record"
+ delete_dnsmasq_setting "host-record"
- if [ ! -z "${HOSTRECORD}" ]; then
- add_dnsmasq_setting "host-record" "${HOSTRECORD}"
- fi
+ if [ ! -z "${HOSTRECORD}" ]; then
+ add_dnsmasq_setting "host-record" "${HOSTRECORD}"
+ fi
- # Setup interface listening behavior of dnsmasq
- delete_dnsmasq_setting "interface"
- delete_dnsmasq_setting "local-service"
+ # Setup interface listening behavior of dnsmasq
+ delete_dnsmasq_setting "interface"
+ delete_dnsmasq_setting "local-service"
- if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
- # Listen on all interfaces, permit all origins
- add_dnsmasq_setting "except-interface" "nonexisting"
- elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
- # Listen only on all interfaces, but only local subnets
- add_dnsmasq_setting "local-service"
- else
- # Listen only on one interface
- # Use eth0 as fallback interface if interface is missing in setupVars.conf
- if [ -z "${PIHOLE_INTERFACE}" ]; then
- PIHOLE_INTERFACE="eth0"
- fi
+ if [[ "${DNSMASQ_LISTENING}" == "all" ]]; then
+ # Listen on all interfaces, permit all origins
+ add_dnsmasq_setting "except-interface" "nonexisting"
+ elif [[ "${DNSMASQ_LISTENING}" == "local" ]]; then
+ # Listen only on all interfaces, but only local subnets
+ add_dnsmasq_setting "local-service"
+ else
+ # Listen only on one interface
+ # Use eth0 as fallback interface if interface is missing in setupVars.conf
+ if [ -z "${PIHOLE_INTERFACE}" ]; then
+ PIHOLE_INTERFACE="eth0"
+ fi
- add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
- fi
- if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
- add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
- add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
- fi
+ add_dnsmasq_setting "interface" "${PIHOLE_INTERFACE}"
+ fi
+ if [[ "${CONDITIONAL_FORWARDING}" == true ]]; then
+ add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_DOMAIN}/${CONDITIONAL_FORWARDING_IP}"
+ add_dnsmasq_setting "server=/${CONDITIONAL_FORWARDING_REVERSE}/${CONDITIONAL_FORWARDING_IP}"
+ fi
}
SetDNSServers() {
- # Save setting to file
- delete_setting "PIHOLE_DNS"
- IFS=',' read -r -a array <<< "${args[2]}"
- for index in "${!array[@]}"
- do
- add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
- done
+ # Save setting to file
+ delete_setting "PIHOLE_DNS"
+ IFS=',' read -r -a array <<< "${args[2]}"
+ for index in "${!array[@]}"
+ do
+ add_setting "PIHOLE_DNS_$((index+1))" "${array[index]}"
+ done
- if [[ "${args[3]}" == "domain-needed" ]]; then
- change_setting "DNS_FQDN_REQUIRED" "true"
- else
- change_setting "DNS_FQDN_REQUIRED" "false"
- fi
+ if [[ "${args[3]}" == "domain-needed" ]]; then
+ change_setting "DNS_FQDN_REQUIRED" "true"
+ else
+ change_setting "DNS_FQDN_REQUIRED" "false"
+ fi
- if [[ "${args[4]}" == "bogus-priv" ]]; then
- change_setting "DNS_BOGUS_PRIV" "true"
- else
- change_setting "DNS_BOGUS_PRIV" "false"
- fi
+ if [[ "${args[4]}" == "bogus-priv" ]]; then
+ change_setting "DNS_BOGUS_PRIV" "true"
+ else
+ change_setting "DNS_BOGUS_PRIV" "false"
+ fi
- if [[ "${args[5]}" == "dnssec" ]]; then
- change_setting "DNSSEC" "true"
- else
- change_setting "DNSSEC" "false"
- fi
- if [[ "${args[6]}" == "conditional_forwarding" ]]; then
- change_setting "CONDITIONAL_FORWARDING" "true"
- change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
- change_setting "CONDITIONAL_FORWARDING_DOMAIN" "${args[8]}"
- change_setting "CONDITIONAL_FORWARDING_REVERSE" "${args[9]}"
- else
- change_setting "CONDITIONAL_FORWARDING" "false"
- delete_setting "CONDITIONAL_FORWARDING_IP"
- delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
- delete_setting "CONDITIONAL_FORWARDING_REVERSE"
- fi
+ if [[ "${args[5]}" == "dnssec" ]]; then
+ change_setting "DNSSEC" "true"
+ else
+ change_setting "DNSSEC" "false"
+ fi
- ProcessDNSSettings
+ if [[ "${args[6]}" == "conditional_forwarding" ]]; then
+ change_setting "CONDITIONAL_FORWARDING" "true"
+ change_setting "CONDITIONAL_FORWARDING_IP" "${args[7]}"
+ change_setting "CONDITIONAL_FORWARDING_DOMAIN" "${args[8]}"
+ change_setting "CONDITIONAL_FORWARDING_REVERSE" "${args[9]}"
+ else
+ change_setting "CONDITIONAL_FORWARDING" "false"
+ delete_setting "CONDITIONAL_FORWARDING_IP"
+ delete_setting "CONDITIONAL_FORWARDING_DOMAIN"
+ delete_setting "CONDITIONAL_FORWARDING_REVERSE"
+ fi
- # Restart dnsmasq to load new configuration
- RestartDNS
+ ProcessDNSSettings
+
+ # Restart dnsmasq to load new configuration
+ RestartDNS
}
SetExcludeDomains() {
- change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
+ change_setting "API_EXCLUDE_DOMAINS" "${args[2]}"
}
SetExcludeClients() {
- change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
+ change_setting "API_EXCLUDE_CLIENTS" "${args[2]}"
}
Poweroff(){
- nohup bash -c "sleep 5; poweroff" &> /dev/null /dev/null /dev/null /dev/null "${dhcpconfig}"
- if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
- echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
- fi
+ if [[ "${PIHOLE_DOMAIN}" != "none" ]]; then
+ echo "domain=${PIHOLE_DOMAIN}" >> "${dhcpconfig}"
+ fi
if [[ "${DHCP_IPv6}" == "true" ]]; then
- echo "#quiet-dhcp6
+ echo "#quiet-dhcp6
#enable-ra
dhcp-option=option6:dns-server,[::]
dhcp-range=::100,::1ff,constructor:${interface},ra-names,slaac,${leasetime}
@@ -312,158 +335,160 @@ ra-param=*,0,0
" >> "${dhcpconfig}"
fi
- else
- if [[ -f "${dhcpconfig}" ]]; then
- rm "${dhcpconfig}" &> /dev/null
- fi
- fi
+ else
+ if [[ -f "${dhcpconfig}" ]]; then
+ rm "${dhcpconfig}" &> /dev/null
+ fi
+ fi
}
EnableDHCP() {
- change_setting "DHCP_ACTIVE" "true"
- change_setting "DHCP_START" "${args[2]}"
- change_setting "DHCP_END" "${args[3]}"
- change_setting "DHCP_ROUTER" "${args[4]}"
- change_setting "DHCP_LEASETIME" "${args[5]}"
- change_setting "PIHOLE_DOMAIN" "${args[6]}"
- change_setting "DHCP_IPv6" "${args[7]}"
+ change_setting "DHCP_ACTIVE" "true"
+ change_setting "DHCP_START" "${args[2]}"
+ change_setting "DHCP_END" "${args[3]}"
+ change_setting "DHCP_ROUTER" "${args[4]}"
+ change_setting "DHCP_LEASETIME" "${args[5]}"
+ change_setting "PIHOLE_DOMAIN" "${args[6]}"
+ change_setting "DHCP_IPv6" "${args[7]}"
- # Remove possible old setting from file
- delete_dnsmasq_setting "dhcp-"
- delete_dnsmasq_setting "quiet-dhcp"
+ # Remove possible old setting from file
+ delete_dnsmasq_setting "dhcp-"
+ delete_dnsmasq_setting "quiet-dhcp"
- ProcessDHCPSettings
+ ProcessDHCPSettings
- RestartDNS
+ RestartDNS
}
DisableDHCP() {
- change_setting "DHCP_ACTIVE" "false"
+ change_setting "DHCP_ACTIVE" "false"
- # Remove possible old setting from file
- delete_dnsmasq_setting "dhcp-"
- delete_dnsmasq_setting "quiet-dhcp"
+ # Remove possible old setting from file
+ delete_dnsmasq_setting "dhcp-"
+ delete_dnsmasq_setting "quiet-dhcp"
- ProcessDHCPSettings
+ ProcessDHCPSettings
- RestartDNS
+ RestartDNS
}
SetWebUILayout() {
- change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
+ change_setting "WEBUIBOXEDLAYOUT" "${args[2]}"
}
CustomizeAdLists() {
- list="/etc/pihole/adlists.list"
+ list="/etc/pihole/adlists.list"
- if [[ "${args[2]}" == "enable" ]]; then
- sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
- elif [[ "${args[2]}" == "disable" ]]; then
- sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
- elif [[ "${args[2]}" == "add" ]]; then
- echo "${args[3]}" >> ${list}
- elif [[ "${args[2]}" == "del" ]]; then
- var=$(echo "${args[3]}" | sed 's/\//\\\//g')
- sed -i "/${var}/Id" "${list}"
- else
- echo "Not permitted"
- return 1
- fi
+ if [[ "${args[2]}" == "enable" ]]; then
+ sed -i "\\@${args[3]}@s/^#http/http/g" "${list}"
+ elif [[ "${args[2]}" == "disable" ]]; then
+ sed -i "\\@${args[3]}@s/^http/#http/g" "${list}"
+ elif [[ "${args[2]}" == "add" ]]; then
+ if [[ $(grep -c "^${args[3]}$" "${list}") -eq 0 ]] ; then
+ echo "${args[3]}" >> ${list}
+ fi
+ elif [[ "${args[2]}" == "del" ]]; then
+ var=$(echo "${args[3]}" | sed 's/\//\\\//g')
+ sed -i "/${var}/Id" "${list}"
+ else
+ echo "Not permitted"
+ return 1
+ fi
}
SetPrivacyMode() {
- if [[ "${args[2]}" == "true" ]]; then
- change_setting "API_PRIVACY_MODE" "true"
- else
- change_setting "API_PRIVACY_MODE" "false"
- fi
+ if [[ "${args[2]}" == "true" ]]; then
+ change_setting "API_PRIVACY_MODE" "true"
+ else
+ change_setting "API_PRIVACY_MODE" "false"
+ fi
}
ResolutionSettings() {
- typ="${args[2]}"
- state="${args[3]}"
+ typ="${args[2]}"
+ state="${args[3]}"
- if [[ "${typ}" == "forward" ]]; then
- change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
- elif [[ "${typ}" == "clients" ]]; then
- change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
- fi
+ if [[ "${typ}" == "forward" ]]; then
+ change_setting "API_GET_UPSTREAM_DNS_HOSTNAME" "${state}"
+ elif [[ "${typ}" == "clients" ]]; then
+ change_setting "API_GET_CLIENT_HOSTNAME" "${state}"
+ fi
}
AddDHCPStaticAddress() {
- mac="${args[2]}"
- ip="${args[3]}"
- host="${args[4]}"
+ mac="${args[2]}"
+ ip="${args[3]}"
+ host="${args[4]}"
- if [[ "${ip}" == "noip" ]]; then
- # Static host name
- echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
- elif [[ "${host}" == "nohost" ]]; then
- # Static IP
- echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
- else
- # Full info given
- echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
- fi
+ if [[ "${ip}" == "noip" ]]; then
+ # Static host name
+ echo "dhcp-host=${mac},${host}" >> "${dhcpstaticconfig}"
+ elif [[ "${host}" == "nohost" ]]; then
+ # Static IP
+ echo "dhcp-host=${mac},${ip}" >> "${dhcpstaticconfig}"
+ else
+ # Full info given
+ echo "dhcp-host=${mac},${ip},${host}" >> "${dhcpstaticconfig}"
+ fi
}
RemoveDHCPStaticAddress() {
- mac="${args[2]}"
- sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
+ mac="${args[2]}"
+ sed -i "/dhcp-host=${mac}.*/d" "${dhcpstaticconfig}"
}
SetHostRecord() {
- if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
- echo "Usage: pihole -a hostrecord [IPv4-address],[IPv6-address]
+ if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
+ echo "Usage: pihole -a hostrecord [IPv4-address],[IPv6-address]
Example: 'pihole -a hostrecord home.domain.com 192.168.1.1,2001:db8:a0b:12f0::1'
Add a name to the DNS associated to an IPv4/IPv6 address
Options:
\"\" Empty: Remove host record
-h, --help Show this help dialog"
- exit 0
- fi
+ exit 0
+ fi
- if [[ -n "${args[3]}" ]]; then
- change_setting "HOSTRECORD" "${args[2]},${args[3]}"
- echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
- else
- change_setting "HOSTRECORD" ""
- echo -e " ${TICK} Removing host record"
- fi
+ if [[ -n "${args[3]}" ]]; then
+ change_setting "HOSTRECORD" "${args[2]},${args[3]}"
+ echo -e " ${TICK} Setting host record for ${args[2]} to ${args[3]}"
+ else
+ change_setting "HOSTRECORD" ""
+ echo -e " ${TICK} Removing host record"
+ fi
- ProcessDNSSettings
+ ProcessDNSSettings
- # Restart dnsmasq to load new configuration
- RestartDNS
+ # Restart dnsmasq to load new configuration
+ RestartDNS
}
SetAdminEmail() {
- if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
- echo "Usage: pihole -a email
+ if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
+ echo "Usage: pihole -a email
Example: 'pihole -a email admin@address.com'
Set an administrative contact address for the Block Page
Options:
\"\" Empty: Remove admin contact
-h, --help Show this help dialog"
- exit 0
- fi
+ exit 0
+ fi
- if [[ -n "${args[2]}" ]]; then
- change_setting "ADMIN_EMAIL" "${args[2]}"
- echo -e " ${TICK} Setting admin contact to ${args[2]}"
- else
- change_setting "ADMIN_EMAIL" ""
- echo -e " ${TICK} Removing admin contact"
- fi
+ if [[ -n "${args[2]}" ]]; then
+ change_setting "ADMIN_EMAIL" "${args[2]}"
+ echo -e " ${TICK} Setting admin contact to ${args[2]}"
+ else
+ change_setting "ADMIN_EMAIL" ""
+ echo -e " ${TICK} Removing admin contact"
+ fi
}
SetListeningMode() {
- source "${setupVars}"
+ source "${setupVars}"
- if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
- echo "Usage: pihole -a -i [interface]
+ if [[ "$3" == "-h" ]] || [[ "$3" == "--help" ]]; then
+ echo "Usage: pihole -a -i [interface]
Example: 'pihole -a -i local'
Specify dnsmasq's network interface listening behavior
@@ -472,74 +497,82 @@ Interfaces:
devices that are at most one hop away (local devices)
single Listen only on ${PIHOLE_INTERFACE} interface
all Listen on all interfaces, permit all origins"
- exit 0
+ exit 0
fi
- if [[ "${args[2]}" == "all" ]]; then
- echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
- change_setting "DNSMASQ_LISTENING" "all"
- elif [[ "${args[2]}" == "local" ]]; then
- echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
- change_setting "DNSMASQ_LISTENING" "local"
- else
- echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
- change_setting "DNSMASQ_LISTENING" "single"
- fi
+ if [[ "${args[2]}" == "all" ]]; then
+ echo -e " ${INFO} Listening on all interfaces, permiting all origins. Please use a firewall!"
+ change_setting "DNSMASQ_LISTENING" "all"
+ elif [[ "${args[2]}" == "local" ]]; then
+ echo -e " ${INFO} Listening on all interfaces, permiting origins from one hop away (LAN)"
+ change_setting "DNSMASQ_LISTENING" "local"
+ else
+ echo -e " ${INFO} Listening only on interface ${PIHOLE_INTERFACE}"
+ change_setting "DNSMASQ_LISTENING" "single"
+ fi
- # Don't restart DNS server yet because other settings
- # will be applied afterwards if "-web" is set
- if [[ "${args[3]}" != "-web" ]]; then
- ProcessDNSSettings
- # Restart dnsmasq to load new configuration
- RestartDNS
- fi
+ # Don't restart DNS server yet because other settings
+ # will be applied afterwards if "-web" is set
+ if [[ "${args[3]}" != "-web" ]]; then
+ ProcessDNSSettings
+ # Restart dnsmasq to load new configuration
+ RestartDNS
+ fi
}
Teleporter() {
- local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
- php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip"
+ local datetimestamp=$(date "+%Y-%m-%d_%H-%M-%S")
+ php /var/www/html/admin/scripts/pi-hole/php/teleporter.php > "pi-hole-teleporter_${datetimestamp}.zip"
}
audit()
{
- echo "${args[2]}" >> /etc/pihole/auditlog.list
+ echo "${args[2]}" >> /etc/pihole/auditlog.list
+}
+
+SetPrivacyLevel() {
+ # Set privacy level. Minimum is 0, maximum is 3
+ if [ "${args[2]}" -ge 0 ] && [ "${args[2]}" -le 3 ]; then
+ changeFTLsetting "PRIVACYLEVEL" "${args[2]}"
+ fi
}
main() {
- args=("$@")
+ args=("$@")
- case "${args[1]}" in
- "-p" | "password" ) SetWebPassword;;
- "-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
- "-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
- "-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
- "setdns" ) SetDNSServers;;
- "setexcludedomains" ) SetExcludeDomains;;
- "setexcludeclients" ) SetExcludeClients;;
- "poweroff" ) Poweroff;;
- "reboot" ) Reboot;;
- "restartdns" ) RestartDNS;;
- "setquerylog" ) SetQueryLogOptions;;
- "enabledhcp" ) EnableDHCP;;
- "disabledhcp" ) DisableDHCP;;
- "layout" ) SetWebUILayout;;
- "-h" | "--help" ) helpFunc;;
- "privacymode" ) SetPrivacyMode;;
- "resolve" ) ResolutionSettings;;
- "addstaticdhcp" ) AddDHCPStaticAddress;;
- "removestaticdhcp" ) RemoveDHCPStaticAddress;;
- "-r" | "hostrecord" ) SetHostRecord "$3";;
- "-e" | "email" ) SetAdminEmail "$3";;
- "-i" | "interface" ) SetListeningMode "$@";;
- "-t" | "teleporter" ) Teleporter;;
- "adlist" ) CustomizeAdLists;;
- "audit" ) audit;;
- * ) helpFunc;;
- esac
+ case "${args[1]}" in
+ "-p" | "password" ) SetWebPassword;;
+ "-c" | "celsius" ) unit="C"; SetTemperatureUnit;;
+ "-f" | "fahrenheit" ) unit="F"; SetTemperatureUnit;;
+ "-k" | "kelvin" ) unit="K"; SetTemperatureUnit;;
+ "setdns" ) SetDNSServers;;
+ "setexcludedomains" ) SetExcludeDomains;;
+ "setexcludeclients" ) SetExcludeClients;;
+ "poweroff" ) Poweroff;;
+ "reboot" ) Reboot;;
+ "restartdns" ) RestartDNS;;
+ "setquerylog" ) SetQueryLogOptions;;
+ "enabledhcp" ) EnableDHCP;;
+ "disabledhcp" ) DisableDHCP;;
+ "layout" ) SetWebUILayout;;
+ "-h" | "--help" ) helpFunc;;
+ "privacymode" ) SetPrivacyMode;;
+ "resolve" ) ResolutionSettings;;
+ "addstaticdhcp" ) AddDHCPStaticAddress;;
+ "removestaticdhcp" ) RemoveDHCPStaticAddress;;
+ "-r" | "hostrecord" ) SetHostRecord "$3";;
+ "-e" | "email" ) SetAdminEmail "$3";;
+ "-i" | "interface" ) SetListeningMode "$@";;
+ "-t" | "teleporter" ) Teleporter;;
+ "adlist" ) CustomizeAdLists;;
+ "audit" ) audit;;
+ "-l" | "privacylevel" ) SetPrivacyLevel;;
+ * ) helpFunc;;
+ esac
- shift
+ shift
- if [[ $# = 0 ]]; then
- helpFunc
- fi
+ if [[ $# = 0 ]]; then
+ helpFunc
+ fi
}
diff --git a/advanced/Scripts/wildcard_regex_converter.sh b/advanced/Scripts/wildcard_regex_converter.sh
new file mode 100644
index 00000000..8c9578a3
--- /dev/null
+++ b/advanced/Scripts/wildcard_regex_converter.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Pi-hole: A black hole for Internet advertisements
+# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
+# Network-wide ad blocking via your own hardware.
+#
+# Provides an automated migration subroutine to convert Pi-hole v3.x wildcard domains to Pi-hole v4.x regex filters
+#
+# This file is copyright under the latest version of the EUPL.
+# Please see LICENSE file for your rights under this license.
+
+# regexFile set in gravity.sh
+
+wildcardFile="/etc/dnsmasq.d/03-pihole-wildcard.conf"
+
+convert_wildcard_to_regex() {
+ if [ ! -f "${wildcardFile}" ]; then
+ return
+ fi
+ local addrlines domains uniquedomains
+ # Obtain wildcard domains from old file
+ addrlines="$(grep -oE "/.*/" ${wildcardFile})"
+ # Strip "/" from domain names and convert "." to regex-compatible "\."
+ domains="$(sed 's/\///g;s/\./\\./g' <<< "${addrlines}")"
+ # Remove repeated domains (may have been inserted two times due to A and AAAA blocking)
+ uniquedomains="$(uniq <<< "${domains}")"
+ # Automatically generate regex filters and remove old wildcards file
+ awk '{print "(^|\\.)"$0"$"}' <<< "${uniquedomains}" >> "${regexFile:?}" && rm "${wildcardFile}"
+}
diff --git a/advanced/logrotate b/advanced/Templates/logrotate
similarity index 100%
rename from advanced/logrotate
rename to advanced/Templates/logrotate
diff --git a/advanced/Templates/pihole-FTL.conf b/advanced/Templates/pihole-FTL.conf
new file mode 100644
index 00000000..03f42932
--- /dev/null
+++ b/advanced/Templates/pihole-FTL.conf
@@ -0,0 +1,84 @@
+### This file contains parameters for FTL behavior.
+### At install, all parameters are commented out. The user can select desired options.
+### Options shown are the default configuration. No modification is needed for most
+### installations.
+### Visit https://docs.pi-hole.net/ftldns/configfile/ for more detailed parameter explanations
+
+## Socket Listening
+## Listen only for local socket connections or permit all connections
+## Options: localonly, all
+#SOCKET_LISTENING=localonly
+
+## Query Display
+## Display all queries? Set to no to hide query display
+## Options: yes, no
+#QUERY_DISPLAY=yes
+
+## AAA Query Analysis
+## Allow FTL to analyze AAAA queries from pihole.log?
+## Options: yes, no
+#AAAA_QUERY_ANALYSIS=yes
+
+## Resolve IPv6
+## Should FTL try to resolve IPv6 addresses to host names?
+## Options: yes, no
+#RESOLVE_IPV6=yes
+
+## Resolve IPv4
+## Should FTL try to resolve IPv4 addresses to host names?
+## Options: yes, no
+#RESOLVE_IPV4=yes
+
+## Max Database Days
+## How long should queries be stored in the database (days)?
+## Setting this to 0 disables the database
+## See: https://docs.pi-hole.net/ftldns/database/
+## Options: number of days
+#MAXDBDAYS=365
+
+## Database Interval
+## How often do we store queries in FTL's database (minutes)?
+## See: https://docs.pi-hole.net/ftldns/database/
+## Options: number of minutes
+#DBINTERVAL=1.0
+
+## Database File
+## Specify path and filename of FTL's SQLite3 long-term database.
+## Setting this to DBFILE= disables the database altogether
+## See: https://docs.pi-hole.net/ftldns/database/
+## Option: path to db file
+#DBFILE=/etc/pihole/pihole-FTL.db
+
+## Max Log Age
+## Up to how many hours of queries should be imported from the database and logs (hours)?
+## Maximum is 744 (31 days)
+## Options: number of days
+#MAXLOGAGE=24.0
+
+## FTL Port
+## On which port should FTL be listening?
+## Options: tcp port
+#FTLPORT=4711
+
+## Privacy Level
+## Which privacy level is used?
+## See: https://docs.pi-hole.net/ftldns/privacylevels/
+## Options: 0, 1, 2, 3
+#PRIVACYLEVEL=0
+
+## Ignore Localhost
+## Should FTL ignore queries coming from the local machine?
+## Options: yes, no
+#IGNORE_LOCALHOST=no
+
+## Blocking Mode
+## How should FTL reply to blocked queries?
+## See: https://docs.pi-hole.net/ftldns/blockingmode/
+## Options: NULL, IP-AAAA-NODATA, IP, NXDOMAIN
+#BLOCKINGMODE=NULL
+
+## Regex Debug Mode
+## Controls if FTLDNS should print extended details about regex matching into pihole-FTL.log.
+## See: https://docs.pi-hole.net/ftldns/regex/overview/
+## Options: true, false
+#REGEX_DEBUGMODE=false
diff --git a/advanced/pihole-FTL.service b/advanced/Templates/pihole-FTL.service
similarity index 75%
rename from advanced/pihole-FTL.service
rename to advanced/Templates/pihole-FTL.service
index 959b7794..ecc7a52a 100644
--- a/advanced/pihole-FTL.service
+++ b/advanced/Templates/pihole-FTL.service
@@ -20,6 +20,7 @@ is_running() {
ps "$(get_pid)" > /dev/null 2>&1
}
+
# Start the service
start() {
if is_running; then
@@ -29,9 +30,12 @@ start() {
mkdir -p /var/run/pihole
mkdir -p /var/log/pihole
chown pihole:pihole /var/run/pihole /var/log/pihole
- rm /var/run/pihole/FTL.sock
- chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /etc/pihole
+ rm /var/run/pihole/FTL.sock 2> /dev/null
+ chown pihole:pihole /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port
+ chown pihole:pihole /etc/pihole /etc/pihole/dhcp.leases /var/log/pihole.log
chmod 0644 /var/log/pihole-FTL.log /run/pihole-FTL.pid /run/pihole-FTL.port /var/log/pihole.log
+ setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN+eip "$(which pihole-FTL)"
+ echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.piholeFTL
su -s /bin/sh -c "/usr/bin/pihole-FTL" "$FTLUSER"
echo
fi
@@ -40,6 +44,7 @@ start() {
# Stop the service
stop() {
if is_running; then
+ /sbin/resolvconf -d lo.piholeFTL
kill "$(get_pid)"
for i in {1..5}; do
if ! is_running; then
@@ -64,13 +69,25 @@ stop() {
echo
}
+# Indicate the service status
+status() {
+ if is_running; then
+ echo "[ ok ] pihole-FTL is running"
+ exit 0
+ else
+ echo "[ ] pihole-FTL is not running"
+ exit 1
+ fi
+}
+
+
### main logic ###
case "$1" in
stop)
stop
;;
status)
- status pihole-FTL
+ status
;;
start|restart|reload|condrestart)
stop
diff --git a/advanced/pihole.cron b/advanced/Templates/pihole.cron
similarity index 100%
rename from advanced/pihole.cron
rename to advanced/Templates/pihole.cron
diff --git a/advanced/pihole.sudo b/advanced/Templates/pihole.sudo
similarity index 100%
rename from advanced/pihole.sudo
rename to advanced/Templates/pihole.sudo
diff --git a/advanced/bash-completion/pihole b/advanced/bash-completion/pihole
index fc8f2162..c25c570b 100644
--- a/advanced/bash-completion/pihole
+++ b/advanced/bash-completion/pihole
@@ -1,11 +1,79 @@
_pihole() {
- local cur prev opts
+ local cur prev opts opts_admin opts_checkout opts_chronometer opts_debug opts_interface opts_logging opts_privacy opts_query opts_update opts_version
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
- opts="admin blacklist chronometer debug disable enable flush help logging query reconfigure restartdns setupLCD status tail uninstall updateGravity updatePihole version whitelist checkout"
+ prev2="${COMP_WORDS[COMP_CWORD-2]}"
- COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+ case "${prev}" in
+ "pihole")
+ opts="admin blacklist checkout chronometer debug disable enable flush help logging query reconfigure regex restartdns status tail uninstall updateGravity updatePihole version wildcard whitelist"
+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
+ ;;
+ "whitelist"|"blacklist"|"wildcard"|"regex")
+ opts_lists="\--delmode \--noreload \--quiet \--list \--nuke"
+ COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
+ ;;
+ "admin")
+ opts_admin="celsius email fahrenheit hostrecord interface kelvin password privacylevel"
+ COMPREPLY=( $(compgen -W "${opts_admin}" -- ${cur}) )
+ ;;
+ "checkout")
+ opts_checkout="core ftl web master dev"
+ COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
+ ;;
+ "chronometer")
+ opts_chronometer="\--exit \--json \--refresh"
+ COMPREPLY=( $(compgen -W "${opts_chronometer}" -- ${cur}) )
+ ;;
+ "debug")
+ opts_debug="-a"
+ COMPREPLY=( $(compgen -W "${opts_debug}" -- ${cur}) )
+ ;;
+ "logging")
+ opts_logging="on off 'off noflush'"
+ COMPREPLY=( $(compgen -W "${opts_logging}" -- ${cur}) )
+ ;;
+ "query")
+ opts_query="-adlist -all -exact"
+ COMPREPLY=( $(compgen -W "${opts_query}" -- ${cur}) )
+ ;;
+ "updatePihole"|"-up")
+ opts_update="--check-only"
+ COMPREPLY=( $(compgen -W "${opts_update}" -- ${cur}) )
+ ;;
+ "version")
+ opts_version="\--admin \--current \--ftl \--hash \--latest \--pihole"
+ COMPREPLY=( $(compgen -W "${opts_version}" -- ${cur}) )
+ ;;
+ "interface")
+ if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
+ opts_interface="$(cat /proc/net/dev | cut -d: -s -f1)"
+ COMPREPLY=( $(compgen -W "${opts_interface}" -- ${cur}) )
+ else
+ return 1
+ fi
+ ;;
+ "privacylevel")
+ if ( [[ "$prev2" == "admin" ]] || [[ "$prev2" == "-a" ]] ); then
+ opts_privacy="0 1 2 3"
+ COMPREPLY=( $(compgen -W "${opts_privacy}" -- ${cur}) )
+ else
+ return 1
+ fi
+ ;;
+ "core"|"admin"|"ftl")
+ if [[ "$prev2" == "checkout" ]]; then
+ opts_checkout="master dev"
+ COMPREPLY=( $(compgen -W "${opts_checkout}" -- ${cur}) )
+ else
+ return 1
+ fi
+ ;;
+ *)
+ return 1
+ ;;
+ esac
return 0
}
complete -F _pihole pihole
diff --git a/advanced/index.php b/advanced/index.php
index 14da9ecf..cad59ec7 100644
--- a/advanced/index.php
+++ b/advanced/index.php
@@ -64,7 +64,7 @@ if ($serverName === "pi.hole") {
$viewPort
- Pi-hole: Your black hole for Internet advertisements
+ Pi-hole: Your black hole for Internet advertisements Did you mean to go to the admin panel?