Compare commits

...

95 Commits

Author SHA1 Message Date
Dominik
9de976cbbd Pi-hole Core 6.0.1 (#5912) 2025-02-19 17:17:57 +01:00
yubiuser
0890f67322 Fix i386 fallback download (#5903) 2025-02-19 10:12:29 +01:00
DL6ER
f7403e2ee6 Fix binary name in 32 bit x86 fallback case
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-19 08:42:32 +01:00
Dominik
51a9412c4b Sync master back into development (#5892) 2025-02-18 19:22:47 +01:00
Adam Warner
2d81552f9f Pi-hole core v6.0.0 (#5842) 2025-02-18 17:19:41 +00:00
yubiuser
2faad0b60a Fix database integrity check in debug log (#5889) 2025-02-14 07:41:07 +01:00
Christian König
c9e58adc48 DHCP discover timeout was reduced by FTL
Signed-off-by: Christian König <github@yubiuser.dev>
2025-02-10 20:41:18 +01:00
Christian König
d1639740d9 Fix database integrity check in debug log
Signed-off-by: Christian König <github@yubiuser.dev>
2025-02-10 20:29:05 +01:00
Dominik
abb94cafe4 Amend warning on gravity tree build failure (#5888) 2025-02-09 19:07:57 +01:00
DL6ER
1bebeff720 Add further info message that building the tree may have failed because of too little RAM baing available. We have see this a few times, either with way too many domains on devices like a Pi Zero or, e.g., only 256 MB RAM being allocated to VMs
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-09 10:06:24 +01:00
yubiuser
9d53ad7668 installer: use a drop-in to disable systemd-resolved stub listener (#5885) 2025-02-06 18:47:49 +01:00
Nick Rosbrook
8fb3ccc147 installer: use a drop-in to disable systemd-resolved stub listener
systemd-resolved supports drop-in config snippets, e.g. by placing .conf
files in /etc/systemd/resolved.conf.d. During install, use a drop-in
config to set DNSStubListener=no, instead of modifying the main config.

This is generally better practice, and also prevents conflicts when
distribution packages are upgraded, which may include new versions of
/etc/systemd/resolved.conf.

Signed-off-by: Nick Rosbrook <enr0n@ubuntu.com>
2025-02-04 16:18:04 -05:00
Dominik
9212a4a514 Decide if the content was changed *before* passing over to FTL (#5872) 2025-02-04 18:57:01 +01:00
Adam Warner
2ae78e02bd Add call to os_check in the update script (#5845) 2025-02-04 17:35:15 +00:00
yubiuser
330698878a Remove outdated dns-servers.conf (#5883) 2025-02-04 06:19:07 +01:00
Dominik
8e298df1e8 Show only enabled domains/regex in the final gravity message (#5884) 2025-02-03 20:37:49 +01:00
Dominik
894a9e157f Move gravity list cache into dedicated directory (#5869) 2025-02-03 20:35:38 +01:00
DL6ER
88cfda7210 Show only enabled domains/regex in the final gravity message
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-03 19:16:24 +01:00
Christian König
0da97e762f Remove outdated dns-servers.conf
Signed-off-by: Christian König <github@yubiuser.dev>
2025-02-03 08:31:33 +01:00
Christian König
94e772378e Merge branch 'development' into new/listsCacheDir
Signed-off-by: Christian König <github@yubiuser.dev>
2025-02-03 08:09:37 +01:00
Dominik
7dbf408c26 Gravity: Use ETags (#5867) 2025-02-03 06:30:11 +01:00
Dominik
ec805f9543 Fix counting of domains in the gravity summary (#5881) 2025-02-02 21:07:52 +01:00
DL6ER
7162be18e2 Remove curl -V temp variable
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-02 20:57:13 +01:00
yubiuser
9cd32bf2b7 Bump actions/setup-python from 5.3.0 to 5.4.0 (#5878) 2025-02-02 13:34:16 +01:00
DL6ER
9da1e9ab88 Fix counting of domains at the end of pihole -g. The existing schme used the SQL VIEWs for simplicitly, however, they have the unintended side-effect of - when being queried without a GROUP BY clause - returning entries multiple times if they are assigned to several groups
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-01 19:42:25 +01:00
DL6ER
37718c65e9 Simplify cURL etag feature detection following discussion in #5873
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-02-01 19:36:56 +01:00
dependabot[bot]
aadea31e52 Bump actions/setup-python from 5.3.0 to 5.4.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.3.0...v5.4.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 10:14:46 +00:00
DL6ER
9faef22061 Decide if the content was changed *before* passing over to FTL
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-31 16:46:12 +01:00
DL6ER
bf899fa57f Migrate list's files (lists themselves, their SHA1 sum and, later, their ETags) into a dedicated directory /etc/pihole/listsCache in an attempt to clean up /etc/pihole
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-30 06:12:49 +01:00
DL6ER
68b03e114c Merge branch 'development' into new/etags
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 19:24:31 +01:00
Dominik
e682f69a1d Use a different method to identify if a gravity restore succeeded (#5868) 2025-01-29 19:23:40 +01:00
DL6ER
f50c696253 Use temp variable for curl -V output
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 19:19:01 +01:00
DL6ER
6e0b16ed1a Rename heisenbergCompensator -> modifiedOptions
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 19:17:04 +01:00
DL6ER
4322299c39 Drive-by fixing of errors reported by shellcheck for gravity.sh
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 17:53:33 +01:00
DL6ER
cee021c358 Use HTTP ETags in addition to the If-Modified-Since header if supported by curl to avoid downloading from servers not using the latter method (raw.githubcontent.com)
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 17:53:33 +01:00
DL6ER
c381109dcd Use a different method to identify if a gravity restore succeeded
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-29 17:52:39 +01:00
Dominik
9a3fcf2a85 Gravity database resilience (#5818) 2025-01-27 01:29:37 +01:00
DL6ER
6d4d35e848 Merge branch 'development' into tweak/gravity_backup 2025-01-26 19:53:06 +01:00
DL6ER
69bfb3ff3b Store timestamp of the backup creation instead of the filename on restoring gravity.db
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-26 19:52:46 +01:00
yubiuser
f7727f98bd Bump actions/stale from 9.0.0 to 9.1.0 (#5863) 2025-01-26 08:44:57 +01:00
yubiuser
05f8bb128c Bump tox from 4.23.2 to 4.24.1 in /test (#5864) 2025-01-26 06:28:22 +01:00
dependabot[bot]
66757de3fb Bump tox from 4.23.2 to 4.24.1 in /test
Bumps [tox](https://github.com/tox-dev/tox) from 4.23.2 to 4.24.1.
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.23.2...4.24.1)

---
updated-dependencies:
- dependency-name: tox
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-25 10:34:03 +00:00
dependabot[bot]
08e3257f37 Bump actions/stale from 9.0.0 to 9.1.0
Bumps [actions/stale](https://github.com/actions/stale) from 9.0.0 to 9.1.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9.0.0...v9.1.0)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-25 10:08:17 +00:00
Adam Warner
0f318027fc Remove unused code from debug log and skip some tests inside containers (#5854) 2025-01-16 17:13:41 +00:00
RD WebDesign
254b67bca3 Using more user-friendly messages on git describe failure
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-13 20:11:41 -03:00
RD WebDesign
0ae50eab87 Suppress error message on git describe failure
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-12 20:25:32 -03:00
DL6ER
cc25ee940e Fix unreachable code
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-12 13:42:51 +01:00
DL6ER
12927f8a3d Put gravity backup files into dedicated directory for cleaness
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-12 13:41:27 +01:00
yubiuser
efaa0f4287 Bump eps1lon/actions-label-merge-conflict from 3.0.2 to 3.0.3 (#5856) 2025-01-11 15:04:52 +01:00
dependabot[bot]
83d464e85f Bump eps1lon/actions-label-merge-conflict from 3.0.2 to 3.0.3
Bumps [eps1lon/actions-label-merge-conflict](https://github.com/eps1lon/actions-label-merge-conflict) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/eps1lon/actions-label-merge-conflict/releases)
- [Changelog](https://github.com/eps1lon/actions-label-merge-conflict/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eps1lon/actions-label-merge-conflict/compare/v3.0.2...v3.0.3)

---
updated-dependencies:
- dependency-name: eps1lon/actions-label-merge-conflict
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-11 10:54:32 +00:00
RD WebDesign
27fb2bbe3a Replace some hardcoded paths with pihole.toml values
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-09 19:11:22 -03:00
RD WebDesign
c78be8a89d No systemctl or service inside containers
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-09 19:11:22 -03:00
RD WebDesign
0590bbba2d Skip some checks in docker container
These commands always fail in containers with "command not found" (as expected).

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-09 19:11:21 -03:00
RD WebDesign
733dce1c4c If it's a docker container, consider the OS is supported
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-09 19:11:15 -03:00
RD WebDesign
bd9cc7cbb7 Clean up unused WEBCALL code
Debug Log is no longer available via web interface

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-01-09 17:15:12 -03:00
Dominik
4902c70063 Explicitly migrate from v5 to v6 (#5830) 2025-01-09 19:39:27 +01:00
Dominik
4be130971e Update automated install/basic-install.sh
Co-authored-by: yubiuser <github@yubiuser.dev>
Signed-off-by: Dominik <DL6ER@users.noreply.github.com>
2025-01-09 18:32:04 +01:00
Dominik
211a881888 Apply suggestions from code review
Co-authored-by: yubiuser <github@yubiuser.dev>
Signed-off-by: Dominik <DL6ER@users.noreply.github.com>
2025-01-08 19:28:15 +01:00
DL6ER
4d23187f86 Add missing newline
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-07 17:49:57 +01:00
Christian König
b544b74f7a Merge branch 'development' into fix/migration 2025-01-06 16:43:18 +01:00
Dominik
6e633e4cfd Improve lighttpd disabling (#5849) 2025-01-02 15:05:00 +01:00
DL6ER
364281354c Check if service is currently enabled when checking if lighttpd may need to be disabled
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-02 13:43:32 +01:00
yubiuser
4c5285e469 Remove now unused function test_dpkg_lock() (#5848) 2025-01-01 18:56:19 +01:00
DL6ER
79087fb252 SHow lighttpd disable dialog only once during v6 migration and when lighttpd is actually installed
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-01-01 18:55:49 +01:00
DL6ER
fab1ca3a40 Merge branch 'development' into tweak/gravity_backup 2025-01-01 18:46:33 +01:00
Christian König
4fd77f57fa Remove now unused function test_dpkg_lock()
Signed-off-by: Christian König <github@yubiuser.dev>
2025-01-01 12:20:50 +01:00
Adam Warner
bd9cb00574 Perform os_check during update, in case the user has updated to an unsupported OS between Pi-hole updates.
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2024-12-31 15:31:04 +00:00
Dominik
b0e0bdc436 Disable lighttpd if found (#5835) 2024-12-30 17:01:04 +01:00
DL6ER
1835827371 Ensure Yes to keeping lighttpd doesn't trigger set -e during the upgrade
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-30 15:35:41 +01:00
Adam Warner
cb32a7f81c Merge branch 'master' into development 2024-12-29 14:06:24 +00:00
Adam Warner
2cf046d559 Fix v5 for Fedora 41 (#5839) 2024-12-29 13:53:35 +00:00
Adam Warner
a1ccee6694 use rpm -q to check if packages are already installed, this is due to a change in the behaviour of dnf in Fedora 41
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2024-12-29 13:32:07 +00:00
Adam Warner
dff0c0105d remove EOL OS from test suite
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2024-12-29 12:43:08 +00:00
Adam Warner
d972ffa53a while v6 is still not released, update tests in master to NOT use development branch of FTL
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2024-12-29 12:35:32 +00:00
Adam Warner
22b6dc7dae Add test scripts for fed 41 for v5
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2024-12-29 12:23:37 +00:00
Dominik
3406915917 Exit early when neither service nor systemctl commands are available (#5834) 2024-12-26 07:19:22 +01:00
Dominik
50645c2924 Apply suggestions from code review
Co-authored-by: Adam Warner <me@adamwarner.co.uk>
Co-authored-by: RD WebDesign <github@rdwebdesign.com.br>
Signed-off-by: Dominik <DL6ER@users.noreply.github.com>
2024-12-24 02:19:37 +01:00
DL6ER
d14273f958 Add comment where setupVars.conf goes when v6 migration is done
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-24 02:17:50 +01:00
DL6ER
47d5a08565 Ask the user if they want to disable lighttpd
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 19:12:47 +01:00
DL6ER
e08f65d1c4 Disable lighttpd if found
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 09:30:37 +01:00
yubiuser
b964657b62 Speedup api response handling (#5833) 2024-12-23 09:14:47 +01:00
DL6ER
a2a22c4e13 Exit early when neither service nor systemctl commands are available
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 09:13:34 +01:00
DL6ER
8faa28d8a0 Explicitly log migration process
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 08:57:34 +01:00
Dominik
a9948304db Fix v5 -> v6 update (#5832) 2024-12-23 08:54:26 +01:00
Christian König
3011d48b6f Use tail instead of parameter expansion
Signed-off-by: Christian König <github@yubiuser.dev>
2024-12-22 23:44:31 +01:00
Christian König
c777152c04 Only separat data and status when needed
Signed-off-by: Christian König <github@yubiuser.dev>
2024-12-22 21:57:47 +01:00
DL6ER
4f268ed193 Explicitly migrate from v5 to v6
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-21 07:10:46 +01:00
DL6ER
579dc07046 Merge branch 'development' into tweak/gravity_backup
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-26 21:08:09 +01:00
DL6ER
633c971a44 Store failed gravity restoration status in message table
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-23 09:44:39 +01:00
Dominik
9a9af719f0 Update gravity.sh
Co-authored-by: RD WebDesign <github@rdwebdesign.com.br>
Signed-off-by: Dominik <DL6ER@users.noreply.github.com>
2024-11-17 17:05:26 +01:00
DL6ER
fdf44355d2 Keep up to 10 database backups
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-16 12:08:27 +01:00
DL6ER
a5cb07c76e Attempt to restore from all possibly available gravity.db backups
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-16 11:52:31 +01:00
DL6ER
59e9bac794 Only try to obtain sources after possible database restore following a corruption
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-16 11:49:11 +01:00
DL6ER
b2ad878f4a Try to restore from gravity backup on database preparation error (if backup is available)
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-16 10:18:00 +01:00
DL6ER
6ff30f7294 Backup a stripped-down version of gravity.db after each pihole -g run
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-11-16 10:09:44 +01:00
15 changed files with 398 additions and 184 deletions

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check if PRs are have merge conflicts - name: Check if PRs are have merge conflicts
uses: eps1lon/actions-label-merge-conflict@v3.0.2 uses: eps1lon/actions-label-merge-conflict@v3.0.3
with: with:
dirtyLabel: "PR: Merge Conflict" dirtyLabel: "PR: Merge Conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}" repoToken: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -17,7 +17,7 @@ jobs:
issues: write issues: write
steps: steps:
- uses: actions/stale@v9.0.0 - uses: actions/stale@v9.1.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30 days-before-stale: 30

View File

@@ -17,7 +17,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/stale@v9.0.0 - uses: actions/stale@v9.1.0
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
# Do not automatically mark PR/issue as stale # Do not automatically mark PR/issue as stale

View File

@@ -77,7 +77,7 @@ jobs:
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
- name: Set up Python 3.10 - name: Set up Python 3.10
uses: actions/setup-python@v5.3.0 uses: actions/setup-python@v5.4.0
with: with:
python-version: "3.10" python-version: "3.10"

View File

@@ -165,15 +165,17 @@ GetFTLData() {
# get the data from querying the API as well as the http status code # get the data from querying the API as well as the http status code
response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" ) response=$(curl -skS -w "%{http_code}" -X GET "${API_URL}$1" -H "Accept: application/json" -H "sid: ${SID}" )
# status are the last 3 characters
status="${response#"${response%???}"}"
# data is everything from response without the last 3 characters
data="${response%???}"
if [ "${2}" = "raw" ]; then if [ "${2}" = "raw" ]; then
# return the raw response # return the raw response
echo "${response}" echo "${response}"
else else
# status are the last 3 characters
# not using ${response#"${response%???}"}" here because it's extremely slow on big responses
status=$(printf "%s" "${response}" | tail -c 3)
# data is everything from response without the last 3 characters
data="${response%???}"
# return only the data # return only the data
if [ "${status}" = 200 ]; then if [ "${status}" = 200 ]; then
# response OK # response OK
@@ -264,7 +266,8 @@ apiFunc() {
response=$(GetFTLData "$1" raw) response=$(GetFTLData "$1" raw)
# status are the last 3 characters # status are the last 3 characters
status="${response#"${response%???}"}" # not using ${response#"${response%???}"}" here because it's extremely slow on big responses
status=$(printf "%s" "${response}" | tail -c 3)
# data is everything from response without the last 3 characters # data is everything from response without the last 3 characters
data="${response%???}" data="${response%???}"

View File

@@ -44,6 +44,14 @@ fi
# shellcheck disable=SC1091 # shellcheck disable=SC1091
. /etc/pihole/versions . /etc/pihole/versions
# Read the value of an FTL config key. The value is printed to stdout.
get_ftl_conf_value() {
local key=$1
# Obtain setting from FTL directly
pihole-FTL --config "${key}"
}
# FAQ URLs for use in showing the debug log # FAQ URLs for use in showing the debug log
FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/${COL_NC}" FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/${COL_NC}"
FAQ_HARDWARE_REQUIREMENTS_PORTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/#ports${COL_NC}" FAQ_HARDWARE_REQUIREMENTS_PORTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/#ports${COL_NC}"
@@ -61,10 +69,10 @@ DNSMASQ_D_DIRECTORY="/etc/dnsmasq.d"
PIHOLE_DIRECTORY="/etc/pihole" PIHOLE_DIRECTORY="/etc/pihole"
PIHOLE_SCRIPTS_DIRECTORY="/opt/pihole" PIHOLE_SCRIPTS_DIRECTORY="/opt/pihole"
BIN_DIRECTORY="/usr/local/bin" BIN_DIRECTORY="/usr/local/bin"
RUN_DIRECTORY="/run"
LOG_DIRECTORY="/var/log/pihole" LOG_DIRECTORY="/var/log/pihole"
HTML_DIRECTORY="/var/www/html" HTML_DIRECTORY="$(get_ftl_conf_value "webserver.paths.webroot")"
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin" WEBHOME_PATH="$(get_ftl_conf_value "webserver.paths.webhome")"
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}${WEBHOME_PATH}"
SHM_DIRECTORY="/dev/shm" SHM_DIRECTORY="/dev/shm"
ETC="/etc" ETC="/etc"
@@ -79,14 +87,6 @@ PIHOLE_FTL_CONF_FILE="${PIHOLE_DIRECTORY}/pihole.toml"
PIHOLE_DNSMASQ_CONF_FILE="${PIHOLE_DIRECTORY}/dnsmasq.conf" PIHOLE_DNSMASQ_CONF_FILE="${PIHOLE_DIRECTORY}/dnsmasq.conf"
PIHOLE_VERSIONS_FILE="${PIHOLE_DIRECTORY}/versions" PIHOLE_VERSIONS_FILE="${PIHOLE_DIRECTORY}/versions"
# Read the value of an FTL config key. The value is printed to stdout.
get_ftl_conf_value() {
local key=$1
# Obtain setting from FTL directly
pihole-FTL --config "${key}"
}
PIHOLE_GRAVITY_DB_FILE="$(get_ftl_conf_value "files.gravity")" PIHOLE_GRAVITY_DB_FILE="$(get_ftl_conf_value "files.gravity")"
PIHOLE_FTL_DB_FILE="$(get_ftl_conf_value "files.database")" PIHOLE_FTL_DB_FILE="$(get_ftl_conf_value "files.database")"
@@ -94,7 +94,7 @@ PIHOLE_FTL_DB_FILE="$(get_ftl_conf_value "files.database")"
PIHOLE_COMMAND="${BIN_DIRECTORY}/pihole" PIHOLE_COMMAND="${BIN_DIRECTORY}/pihole"
PIHOLE_COLTABLE_FILE="${BIN_DIRECTORY}/COL_TABLE" PIHOLE_COLTABLE_FILE="${BIN_DIRECTORY}/COL_TABLE"
FTL_PID="${RUN_DIRECTORY}/pihole-FTL.pid" FTL_PID="$(get_ftl_conf_value "files.pid")"
PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log" PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log"
PIHOLE_LOG_GZIPS="${LOG_DIRECTORY}/pihole.log.[0-9].*" PIHOLE_LOG_GZIPS="${LOG_DIRECTORY}/pihole.log.[0-9].*"
@@ -202,7 +202,7 @@ compare_local_version_to_git_version() {
if git status &> /dev/null; then if git status &> /dev/null; then
# The current version the user is on # The current version the user is on
local local_version local local_version
local_version=$(git describe --tags --abbrev=0); local_version=$(git describe --tags --abbrev=0 2> /dev/null);
# What branch they are on # What branch they are on
local local_branch local local_branch
local_branch=$(git rev-parse --abbrev-ref HEAD); local_branch=$(git rev-parse --abbrev-ref HEAD);
@@ -213,7 +213,13 @@ compare_local_version_to_git_version() {
local local_status local local_status
local_status=$(git status -s) local_status=$(git status -s)
# echo this information out to the user in a nice format # echo this information out to the user in a nice format
log_write "${TICK} Version: ${local_version}" if [ ${local_version} ]; then
log_write "${TICK} Version: ${local_version}"
elif [ -n "${DOCKER_VERSION}" ]; then
log_write "${TICK} Version: Pi-hole Docker Container ${COL_BOLD}${DOCKER_VERSION}${COL_NC}"
else
log_write "${CROSS} Version: not detected"
fi
# Print the repo upstreams # Print the repo upstreams
remotes=$(git remote -v) remotes=$(git remote -v)
@@ -346,6 +352,9 @@ os_check() {
fi fi
done done
# If it is a docker container, we can assume the OS is supported
[ -n "${DOCKER_VERSION}" ] && valid_os=true && valid_version=true
local finalmsg local finalmsg
if [ "$valid_os" = true ]; then if [ "$valid_os" = true ]; then
log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}" log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}"
@@ -489,13 +498,25 @@ run_and_print_command() {
} }
hardware_check() { hardware_check() {
# Note: the checks are skipped if Pi-hole is running in a docker container
local skip_msg="${INFO} Not enough permissions inside Docker container ${COL_YELLOW}(skipped)${COL_NC}"
echo_current_diagnostic "System hardware configuration" echo_current_diagnostic "System hardware configuration"
# Store the output of the command in a variable if [ -n "${DOCKER_VERSION}" ]; then
run_and_print_command "lshw -short" log_write "${skip_msg}"
else
# Store the output of the command in a variable
run_and_print_command "lshw -short"
fi
echo_current_diagnostic "Processor details" echo_current_diagnostic "Processor details"
# Store the output of the command in a variable if [ -n "${DOCKER_VERSION}" ]; then
run_and_print_command "lscpu" log_write "${skip_msg}"
else
# Store the output of the command in a variable
run_and_print_command "lscpu"
fi
} }
disk_usage() { disk_usage() {
@@ -808,26 +829,24 @@ dig_at() {
process_status(){ process_status(){
# Check to make sure Pi-hole's services are running and active # Check to make sure Pi-hole's services are running and active
echo_current_diagnostic "Pi-hole processes" echo_current_diagnostic "Pi-hole processes"
# Local iterator # Local iterator
local i local i
# For each process, # For each process,
for i in "${PIHOLE_PROCESSES[@]}"; do for i in "${PIHOLE_PROCESSES[@]}"; do
local status_of_process
# If systemd # If systemd
if command -v systemctl &> /dev/null; then if command -v systemctl &> /dev/null; then
# get its status via systemctl # get its status via systemctl
local status_of_process
status_of_process=$(systemctl is-active "${i}") status_of_process=$(systemctl is-active "${i}")
else else
# Otherwise, use the service command and mock the output of `systemctl is-active` # Otherwise, use the service command and mock the output of `systemctl is-active`
local status_of_process
# If DOCKER_VERSION is set, the output is slightly different (s6 init system on Docker) # If it is a docker container, there is no systemctl or service. Do nothing.
if [ -n "${DOCKER_VERSION}" ]; then if [ -n "${DOCKER_VERSION}" ]; then
if service "${i}" status | grep -E '^up' &> /dev/null; then :
status_of_process="active"
else
status_of_process="inactive"
fi
else else
# non-Docker system # non-Docker system
if service "${i}" status | grep -E 'is\srunning' &> /dev/null; then if service "${i}" status | grep -E 'is\srunning' &> /dev/null; then
@@ -837,8 +856,12 @@ process_status(){
fi fi
fi fi
fi fi
# and print it out to the user # and print it out to the user
if [[ "${status_of_process}" == "active" ]]; then if [ -n "${DOCKER_VERSION}" ]; then
# If it's a Docker container, the test was skipped
log_write "${INFO} systemctl/service not installed inside docker container ${COL_YELLOW}(skipped)${COL_NC}"
elif [[ "${status_of_process}" == "active" ]]; then
# If it's active, show it in green # 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}" log_write "${TICK} ${COL_GREEN}${i}${COL_NC} daemon is ${COL_GREEN}${status_of_process}${COL_NC}"
else else
@@ -855,6 +878,8 @@ ftl_full_status(){
if command -v systemctl &> /dev/null; then if command -v systemctl &> /dev/null; then
FTL_status=$(systemctl status --full --no-pager pihole-FTL.service) FTL_status=$(systemctl status --full --no-pager pihole-FTL.service)
log_write " ${FTL_status}" log_write " ${FTL_status}"
elif [ -n "${DOCKER_VERSION}" ]; then
log_write "${INFO} systemctl/service not installed inside docker container ${COL_YELLOW}(skipped)${COL_NC}"
else else
log_write "${INFO} systemctl: command not found" log_write "${INFO} systemctl: command not found"
fi fi
@@ -1112,7 +1137,7 @@ show_FTL_db_entries() {
} }
check_dhcp_servers() { check_dhcp_servers() {
echo_current_diagnostic "Discovering active DHCP servers (takes 10 seconds)" echo_current_diagnostic "Discovering active DHCP servers (takes 6 seconds)"
OLD_IFS="$IFS" OLD_IFS="$IFS"
IFS=$'\n' IFS=$'\n'
@@ -1196,7 +1221,7 @@ database_integrity_check(){
local database="${1}" local database="${1}"
log_write "${INFO} Checking integrity of ${database} ... (this can take several minutes)" log_write "${INFO} Checking integrity of ${database} ... (this can take several minutes)"
result="$(pihole-FTL "${database}" "PRAGMA integrity_check" 2>&1 & spinner)" result="$(pihole-FTL sqlite3 -ni "${database}" "PRAGMA integrity_check" 2>&1 & spinner)"
if [[ ${result} = "ok" ]]; then if [[ ${result} = "ok" ]]; then
log_write "${TICK} Integrity of ${database} intact" log_write "${TICK} Integrity of ${database} intact"
@@ -1317,19 +1342,16 @@ upload_to_tricorder() {
curl_to_tricorder curl_to_tricorder
# If we're not running in automated mode, # If we're not running in automated mode,
else else
# if not being called from the web interface echo ""
if [[ ! "${WEBCALL}" ]]; then # give the user a choice of uploading it or not
echo "" # 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
# give the user a choice of uploading it or not read -r -p "[?] Would you like to upload the log? [y/N] " response
# 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 case ${response} in
read -r -p "[?] Would you like to upload the log? [y/N] " response # If they say yes, run our function for uploading the log
case ${response} in [yY][eE][sS]|[yY]) curl_to_tricorder;;
# If they say yes, run our function for uploading the log # If they choose no, just exit out of the script
[yY][eE][sS]|[yY]) curl_to_tricorder;; *) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit;
# If they choose no, just exit out of the script esac
*) log_write " * Log will ${COL_GREEN}NOT${COL_NC} be uploaded to tricorder.\\n * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n";exit;
esac
fi
fi fi
# Check if tricorder.pi-hole.net is reachable and provide token # Check if tricorder.pi-hole.net is reachable and provide token
# along with some additional useful information # along with some additional useful information
@@ -1349,13 +1371,8 @@ upload_to_tricorder() {
# If no token was generated # If no token was generated
else else
# Show an error and some help instructions # Show an error and some help instructions
# Skip this if being called from web interface and automatic mode was not chosen (users opt-out to upload) log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}"
if [[ "${WEBCALL}" ]] && [[ ! "${AUTOMATED}" ]]; then log_write " * Please try again or contact the Pi-hole team for assistance."
:
else
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
fi fi
# Finally, show where the log file is no matter the outcome of the function so users can look at it # 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}${COL_NC}\\n" log_write " * A local copy of the debug log can be found at: ${COL_CYAN}${PIHOLE_DEBUG_LOG}${COL_NC}\\n"

View File

@@ -107,6 +107,9 @@ main() {
web_update=false web_update=false
FTL_update=false FTL_update=false
# Perform an OS check to ensure we're on an appropriate operating system
os_check
# Install packages used by this installation script (necessary if users have removed e.g. git from their systems) # Install packages used by this installation script (necessary if users have removed e.g. git from their systems)
package_manager_detect package_manager_detect
build_dependency_package build_dependency_package

View File

@@ -67,6 +67,11 @@ CREATE TABLE info
); );
INSERT INTO "info" VALUES('version','19'); INSERT INTO "info" VALUES('version','19');
/* This is a flag to indicate if gravity was restored from a backup
false = not restored,
failed = restoration failed due to no backup
other string = restoration successful with the string being the backup file used */
INSERT INTO "info" VALUES('gravity_restored','false');
CREATE TABLE domainlist_by_group CREATE TABLE domainlist_by_group
( (

View File

@@ -388,28 +388,6 @@ os_check() {
fi fi
} }
# This function waits for dpkg to unlock, which signals that the previous apt-get command has finished.
test_dpkg_lock() {
i=0
printf " %b Waiting for package manager to finish (up to 30 seconds)\\n" "${INFO}"
# fuser is a program to show which processes use the named files, sockets, or filesystems
# So while the lock is held,
while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do
# we wait half a second,
sleep 0.5
# increase the iterator,
((i = i + 1))
# exit if waiting for more then 30 seconds
if [[ $i -gt 60 ]]; then
printf " %b %bError: Could not verify package manager finished and released lock. %b\\n" "${CROSS}" "${COL_LIGHT_RED}" "${COL_NC}"
printf " Attempt to install packages manually and retry.\\n"
exit 1
fi
done
# and then report success once dpkg is unlocked.
return 0
}
# Compatibility # Compatibility
package_manager_detect() { package_manager_detect() {
@@ -1301,13 +1279,6 @@ installConfigs() {
# Ensure that permissions are correctly set # Ensure that permissions are correctly set
chown -R pihole:pihole /etc/pihole chown -R pihole:pihole /etc/pihole
# Install list of DNS servers
# Format: Name;Primary IPv4;Secondary IPv4;Primary IPv6;Secondary IPv6
# Some values may be empty (for example: DNS servers without IPv6 support)
echo "${DNS_SERVERS}" >"${PI_HOLE_CONFIG_DIR}/dns-servers.conf"
chmod 644 "${PI_HOLE_CONFIG_DIR}/dns-servers.conf"
chown pihole:pihole "${PI_HOLE_CONFIG_DIR}/dns-servers.conf"
# Install empty custom.list file if it does not exist # Install empty custom.list file if it does not exist
if [[ ! -r "${PI_HOLE_CONFIG_DIR}/hosts/custom.list" ]]; then if [[ ! -r "${PI_HOLE_CONFIG_DIR}/hosts/custom.list" ]]; then
if ! install -D -T -o pihole -g pihole -m 660 /dev/null "${PI_HOLE_CONFIG_DIR}/hosts/custom.list" &>/dev/null; then if ! install -D -T -o pihole -g pihole -m 660 /dev/null "${PI_HOLE_CONFIG_DIR}/hosts/custom.list" &>/dev/null; then
@@ -1458,20 +1429,15 @@ disable_resolved_stublistener() {
printf " %b Testing if systemd-resolved is enabled\\n" "${INFO}" printf " %b Testing if systemd-resolved is enabled\\n" "${INFO}"
# Check if Systemd-resolved's DNSStubListener is enabled and active on port 53 # Check if Systemd-resolved's DNSStubListener is enabled and active on port 53
if check_service_active "systemd-resolved"; then if check_service_active "systemd-resolved"; then
# Check if DNSStubListener is enabled # Disable the DNSStubListener to unbind it from port 53
printf " %b %b Testing if systemd-resolved DNSStub-Listener is active" "${OVER}" "${INFO}" # Note that this breaks dns functionality on host until FTL is up and running
if (grep -E '#?DNSStubListener=yes' /etc/systemd/resolved.conf &>/dev/null); then printf "%b %b Disabling systemd-resolved DNSStubListener\\n" "${OVER}" "${TICK}"
# Disable the DNSStubListener to unbind it from port 53 mkdir -p /etc/systemd/resolved.conf.d
# Note that this breaks dns functionality on host until ftl are up and running cat > /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf << EOF
printf "%b %b Disabling systemd-resolved DNSStubListener" "${OVER}" "${TICK}" [Resolve]
# Make a backup of the original /etc/systemd/resolved.conf DNSStubListener=no
# (This will need to be restored on uninstallation) EOF
sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf systemctl reload-or-restart systemd-resolved
printf " and restarting systemd-resolved\\n"
systemctl reload-or-restart systemd-resolved
else
printf "%b %b Systemd-resolved does not need to be restarted\\n" "${OVER}" "${INFO}"
fi
else else
printf "%b %b Systemd-resolved is not enabled\\n" "${OVER}" "${INFO}" printf "%b %b Systemd-resolved is not enabled\\n" "${OVER}" "${INFO}"
fi fi
@@ -2156,7 +2122,7 @@ get_binary_name() {
else else
printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}" printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}"
fi fi
l_binary="pihole-FTL-linux-386" l_binary="pihole-FTL-386"
fi fi
# Returning a string value via echo # Returning a string value via echo
@@ -2300,6 +2266,44 @@ copy_to_install_log() {
chown pihole:pihole "${installLogLoc}" chown pihole:pihole "${installLogLoc}"
} }
disableLighttpd() {
# Return early when lighttpd is not active
if ! check_service_active lighttpd; then
return
fi
local response
# Detect if the terminal is interactive
if [[ -t 0 ]]; then
# The terminal is interactive
dialog --no-shadow --keep-tite \
--title "Pi-hole v6.0 no longer uses lighttpd" \
--yesno "\\n\\nPi-hole v6.0 has its own embedded web server so lighttpd is no longer needed *unless* you have custom configurations.\\n\\nIn this case, you can opt-out of disabling lighttpd and pihole-FTL will try to bind to an alternative port such as 8080.\\n\\nDo you want to disable lighttpd (recommended)?" "${r}" "${c}" && response=0 || response="$?"
else
# The terminal is non-interactive, assume yes. Lighttpd will be stopped
# but keeps being installed and can easily be re-enabled by the user
response=0
fi
# If the user does not want to disable lighttpd, return early
if [[ "${response}" -ne 0 ]]; then
return
fi
# Lighttpd is not needed anymore, so disable it
# We keep all the configuration files in place, so the user can re-enable it
# if needed
# Check if lighttpd is installed
if is_command lighttpd; then
# Stop the lighttpd service
stop_service lighttpd
# Disable the lighttpd service
disable_service lighttpd
fi
}
migrate_dnsmasq_configs() { migrate_dnsmasq_configs() {
# Previously, Pi-hole created a number of files in /etc/dnsmasq.d # Previously, Pi-hole created a number of files in /etc/dnsmasq.d
# During migration, their content is copied into the new single source of # During migration, their content is copied into the new single source of
@@ -2312,6 +2316,9 @@ migrate_dnsmasq_configs() {
return 0 return 0
fi fi
# Disable lighttpd server during v6 migration
disableLighttpd
# Create target directory /etc/pihole/migration_backup_v6 # Create target directory /etc/pihole/migration_backup_v6
# and make it owned by pihole:pihole # and make it owned by pihole:pihole
mkdir -p "${V6_CONF_MIGRATION_DIR}" mkdir -p "${V6_CONF_MIGRATION_DIR}"
@@ -2326,6 +2333,40 @@ migrate_dnsmasq_configs() {
mv /etc/dnsmasq.d/0{1,2,4,5}-pihole*.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true mv /etc/dnsmasq.d/0{1,2,4,5}-pihole*.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true
mv /etc/dnsmasq.d/06-rfc6761.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true mv /etc/dnsmasq.d/06-rfc6761.conf "${V6_CONF_MIGRATION_DIR}/" 2>/dev/null || true
# Finally, after everything is in place, we can create the new config file
# /etc/pihole/pihole.toml
# This file will be created with the default settings unless the user has
# changed settings via setupVars.conf or the other dnsmasq files moved above
# During migration, setupVars.conf is moved to /etc/pihole/migration_backup_v6
str="Migrating Pi-hole configuration to version 6"
printf " %b %s..." "${INFO}" "${str}"
local FTLoutput FTLstatus
FTLoutput=$(pihole-FTL migrate v6)
FTLstatus=$?
if [[ "${FTLstatus}" -eq 0 ]]; then
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
fi
# Print the output of the FTL migration prefacing every line with four
# spaces for alignment
printf "%b" "${FTLoutput}" | sed 's/^/ /'
# Print a blank line for separation
printf "\\n"
}
# Check for availability of either the "service" or "systemctl" commands
check_service_command() {
# Check for the availability of the "service" command
if ! is_command service && ! is_command systemctl; then
# If neither the "service" nor the "systemctl" command is available, inform the user
printf " %b Neither the service nor the systemctl commands are available\\n" "${CROSS}"
printf " on this machine. This Pi-hole installer cannot continue.\\n"
exit 1
fi
} }
main() { main() {
@@ -2376,6 +2417,9 @@ main() {
# Check if SELinux is Enforcing and exit before doing anything else # Check if SELinux is Enforcing and exit before doing anything else
checkSelinux checkSelinux
# Check for availability of either the "service" or "systemctl" commands
check_service_command
# Check for supported package managers so that we may install dependencies # Check for supported package managers so that we may install dependencies
package_manager_detect package_manager_detect

View File

@@ -94,8 +94,9 @@ removePiholeFiles() {
echo -e " ${TICK} Removed config files" echo -e " ${TICK} Removed config files"
# Restore Resolved # Restore Resolved
if [[ -e /etc/systemd/resolved.conf.orig ]]; then if [[ -e /etc/systemd/resolved.conf.orig ]] || [[ -e /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf ]]; then
${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf ${SUDO} cp -p /etc/systemd/resolved.conf.orig /etc/systemd/resolved.conf &> /dev/null || true
${SUDO} rm -f /etc/systemd/resolved.conf.d/90-pi-hole-disable-stub-listener.conf
systemctl reload-or-restart systemd-resolved systemctl reload-or-restart systemd-resolved
fi fi

View File

@@ -30,6 +30,9 @@ PIHOLE_COMMAND="/usr/local/bin/${basename}"
piholeDir="/etc/${basename}" piholeDir="/etc/${basename}"
# Gravity aux files directory
listsCacheDir="${piholeDir}/listsCache"
# Legacy (pre v5.0) list file locations # Legacy (pre v5.0) list file locations
whitelistFile="${piholeDir}/whitelist.txt" whitelistFile="${piholeDir}/whitelist.txt"
blacklistFile="${piholeDir}/blacklist.txt" blacklistFile="${piholeDir}/blacklist.txt"
@@ -44,6 +47,7 @@ gravityDBcopy="${piholeGitDir}/advanced/Templates/gravity_copy.sql"
domainsExtension="domains" domainsExtension="domains"
curl_connect_timeout=10 curl_connect_timeout=10
etag_support=false
# Check gravity temp directory # Check gravity temp directory
if [ ! -d "${GRAVITY_TMPDIR}" ] || [ ! -w "${GRAVITY_TMPDIR}" ]; then if [ ! -d "${GRAVITY_TMPDIR}" ] || [ ! -w "${GRAVITY_TMPDIR}" ]; then
@@ -58,6 +62,8 @@ gravityDBfile_default="/etc/pihole/gravity.db"
gravityTEMPfile="${GRAVITYDB}_temp" gravityTEMPfile="${GRAVITYDB}_temp"
gravityDIR="$(dirname -- "${gravityDBfile}")" gravityDIR="$(dirname -- "${gravityDBfile}")"
gravityOLDfile="${gravityDIR}/gravity_old.db" gravityOLDfile="${gravityDIR}/gravity_old.db"
gravityBCKdir="${gravityDIR}/gravity_backups"
gravityBCKfile="${gravityBCKdir}/gravity.db"
fix_owner_permissions() { fix_owner_permissions() {
# Fix ownership and permissions for the specified file # Fix ownership and permissions for the specified file
@@ -91,11 +97,21 @@ gravity_build_tree() {
if [[ "${status}" -ne 0 ]]; then if [[ "${status}" -ne 0 ]]; then
echo -e "\\n ${CROSS} Unable to build gravity tree in ${gravityTEMPfile}\\n ${output}" echo -e "\\n ${CROSS} Unable to build gravity tree in ${gravityTEMPfile}\\n ${output}"
echo -e " ${INFO} If you have a large amount of domains, make sure your Pi-hole has enough RAM available\\n"
return 1 return 1
fi fi
echo -e "${OVER} ${TICK} ${str}" echo -e "${OVER} ${TICK} ${str}"
} }
# Rotate gravity backup files
rotate_gravity_backup() {
for i in {9..1}; do
if [ -f "${gravityBCKfile}.${i}" ]; then
mv "${gravityBCKfile}.${i}" "${gravityBCKfile}.$((i + 1))"
fi
done
}
# Copy data from old to new database file and swap them # Copy data from old to new database file and swap them
gravity_swap_databases() { gravity_swap_databases() {
str="Swapping databases" str="Swapping databases"
@@ -111,10 +127,32 @@ gravity_swap_databases() {
oldAvail=false oldAvail=false
if [ "${availableBlocks}" -gt "$((gravityBlocks * 2))" ] && [ -f "${gravityDBfile}" ]; then if [ "${availableBlocks}" -gt "$((gravityBlocks * 2))" ] && [ -f "${gravityDBfile}" ]; then
oldAvail=true oldAvail=true
mv "${gravityDBfile}" "${gravityOLDfile}" cp "${gravityDBfile}" "${gravityOLDfile}"
else
rm "${gravityDBfile}"
fi fi
# Drop the gravity and antigravity tables + subsequent VACUUM the current
# database for compaction
output=$({ printf ".timeout 30000\\nDROP TABLE IF EXISTS gravity;\\nDROP TABLE IF EXISTS antigravity;\\nVACUUM;\\n" | pihole-FTL sqlite3 -ni "${gravityDBfile}"; } 2>&1)
status="$?"
if [[ "${status}" -ne 0 ]]; then
echo -e "\\n ${CROSS} Unable to clean current database for backup\\n ${output}"
else
# Check if the backup directory exists
if [ ! -d "${gravityBCKdir}" ]; then
mkdir -p "${gravityBCKdir}"
fi
# If multiple gravityBCKfile's are present (appended with a number), rotate them
# We keep at most 10 backups
rotate_gravity_backup
# Move the old database to the backup location
mv "${gravityDBfile}" "${gravityBCKfile}.1"
fi
# Move the new database to the correct location
mv "${gravityTEMPfile}" "${gravityDBfile}" mv "${gravityTEMPfile}" "${gravityDBfile}"
echo -e "${OVER} ${TICK} ${str}" echo -e "${OVER} ${TICK} ${str}"
@@ -324,6 +362,54 @@ gravity_CheckDNSResolutionAvailable() {
echo -e "${OVER} ${TICK} DNS resolution is available" echo -e "${OVER} ${TICK} DNS resolution is available"
} }
# Function: try_restore_backup
# Description: Attempts to restore the previous Pi-hole gravity database from a
# backup file. If a backup exists, it copies the backup to the
# gravity database file and prepares a new gravity database. If the
# restoration is successful, it returns 0. Otherwise, it returns 1.
# Returns:
# 0 - If the backup is successfully restored.
# 1 - If no backup is available or if the restoration fails.
try_restore_backup () {
local num filename timestamp
num=$1
filename="${gravityBCKfile}.${num}"
# Check if a backup exists
if [ -f "${filename}" ]; then
echo -e " ${INFO} Attempting to restore previous database from backup no. ${num}"
cp "${filename}" "${gravityDBfile}"
# If the backup was successfully copied, prepare a new gravity database from
# it
if [ -f "${gravityDBfile}" ]; then
output=$({ pihole-FTL sqlite3 -ni "${gravityTEMPfile}" <<<"${copyGravity}"; } 2>&1)
status="$?"
# Error checking
if [[ "${status}" -ne 0 ]]; then
echo -e "\\n ${CROSS} Unable to copy data from ${gravityDBfile} to ${gravityTEMPfile}\\n ${output}"
gravity_Cleanup "error"
fi
# Get the timestamp of the backup file in a human-readable format
# Note that this timestamp will be in the server timezone, this may be
# GMT, e.g., on a Raspberry Pi where the default timezone has never been
# changed
timestamp=$(date -r "${filename}" "+%Y-%m-%d %H:%M:%S %Z")
# Add a record to the info table to indicate that the gravity database was restored
pihole-FTL sqlite3 "${gravityTEMPfile}" "INSERT OR REPLACE INTO info (property,value) values ('gravity_restored','${timestamp}');"
echo -e " ${TICK} Successfully restored from backup (${gravityBCKfile}.${num} at ${timestamp})"
return 0
else
echo -e " ${CROSS} Unable to restore backup no. ${num}"
fi
fi
echo -e " ${CROSS} Backup no. ${num} not available"
return 1
}
# Retrieve blocklist URLs and parse domains from adlist.list # Retrieve blocklist URLs and parse domains from adlist.list
gravity_DownloadBlocklists() { gravity_DownloadBlocklists() {
echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..." echo -e " ${INFO} ${COL_BOLD}Neutrino emissions detected${COL_NC}..."
@@ -332,33 +418,7 @@ gravity_DownloadBlocklists() {
echo -e " ${INFO} Storing gravity database in ${COL_BOLD}${gravityDBfile}${COL_NC}" echo -e " ${INFO} Storing gravity database in ${COL_BOLD}${gravityDBfile}${COL_NC}"
fi fi
# Retrieve source URLs from gravity database local url domain str target compression adlist_type directory success
# We source only enabled adlists, SQLite3 stores boolean values as 0 (false) or 1 (true)
mapfile -t sources <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT address FROM vw_adlist;" 2>/dev/null)"
mapfile -t sourceIDs <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT id FROM vw_adlist;" 2>/dev/null)"
mapfile -t sourceTypes <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT type FROM vw_adlist;" 2>/dev/null)"
# Parse source domains from $sources
mapfile -t sourceDomains <<<"$(
# Logic: Split by folder/port
awk -F '[/:]' '{
# Remove URL protocol & optional username:password@
gsub(/(.*:\/\/|.*:.*@)/, "", $0)
if(length($1)>0){print $1}
else {print "local"}
}' <<<"$(printf '%s\n' "${sources[@]}")" 2>/dev/null
)"
local str="Pulling blocklist source list into range"
echo -e "${OVER} ${TICK} ${str}"
if [[ -z "${sources[*]}" ]] || [[ -z "${sourceDomains[*]}" ]]; then
echo -e " ${INFO} No source list found, or it is empty"
echo ""
unset sources
fi
local url domain str target compression adlist_type directory
echo "" echo ""
# Prepare new gravity database # Prepare new gravity database
@@ -390,10 +450,55 @@ gravity_DownloadBlocklists() {
if [[ "${status}" -ne 0 ]]; then if [[ "${status}" -ne 0 ]]; then
echo -e "\\n ${CROSS} Unable to copy data from ${gravityDBfile} to ${gravityTEMPfile}\\n ${output}" echo -e "\\n ${CROSS} Unable to copy data from ${gravityDBfile} to ${gravityTEMPfile}\\n ${output}"
return 1
# Try to attempt a backup restore
success=false
if [[ -d "${gravityBCKdir}" ]]; then
for i in {1..10}; do
if try_restore_backup "${i}"; then
success=true
break
fi
done
fi
# If none of the attempts worked, return 1
if [[ "${success}" == false ]]; then
pihole-FTL sqlite3 "${gravityTEMPfile}" "INSERT OR REPLACE INTO info (property,value) values ('gravity_restored','failed');"
return 1
fi
echo -e " ${TICK} ${str}"
else
echo -e "${OVER} ${TICK} ${str}"
fi fi
# Retrieve source URLs from gravity database
# We source only enabled adlists, SQLite3 stores boolean values as 0 (false) or 1 (true)
mapfile -t sources <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT address FROM vw_adlist;" 2>/dev/null)"
mapfile -t sourceIDs <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT id FROM vw_adlist;" 2>/dev/null)"
mapfile -t sourceTypes <<<"$(pihole-FTL sqlite3 -ni "${gravityDBfile}" "SELECT type FROM vw_adlist;" 2>/dev/null)"
# Parse source domains from $sources
mapfile -t sourceDomains <<<"$(
# Logic: Split by folder/port
awk -F '[/:]' '{
# Remove URL protocol & optional username:password@
gsub(/(.*:\/\/|.*:.*@)/, "", $0)
if(length($1)>0){print $1}
else {print "local"}
}' <<<"$(printf '%s\n' "${sources[@]}")" 2>/dev/null
)"
local str="Pulling blocklist source list into range"
echo -e "${OVER} ${TICK} ${str}" echo -e "${OVER} ${TICK} ${str}"
if [[ -z "${sources[*]}" ]] || [[ -z "${sourceDomains[*]}" ]]; then
echo -e " ${INFO} No source list found, or it is empty"
echo ""
unset sources
fi
# Use compression to reduce the amount of data that is transferred # Use compression to reduce the amount of data that is transferred
# between the Pi-hole and the ad list provider. Use this feature # between the Pi-hole and the ad list provider. Use this feature
# only if it is supported by the locally available version of curl # only if it is supported by the locally available version of curl
@@ -404,6 +509,15 @@ gravity_DownloadBlocklists() {
compression="" compression=""
echo -e " ${INFO} Libz compression not available\n" echo -e " ${INFO} Libz compression not available\n"
fi fi
# Check if etag is supported by the locally available version of curl
# (available as of curl 7.68.0, released Jan 2020)
# https://github.com/curl/curl/pull/4543 +
# https://github.com/curl/curl/pull/4678
if curl --help all | grep -q "etag-save"; then
etag_support=true
fi
# Loop through $sources and download each one # Loop through $sources and download each one
for ((i = 0; i < "${#sources[@]}"; i++)); do for ((i = 0; i < "${#sources[@]}"; i++)); do
url="${sources[$i]}" url="${sources[$i]}"
@@ -420,8 +534,8 @@ gravity_DownloadBlocklists() {
fi fi
# Save the file as list.#.domain # Save the file as list.#.domain
saveLocation="${piholeDir}/list.${id}.${domain}.${domainsExtension}" saveLocation="${listsCacheDir}/list.${id}.${domain}.${domainsExtension}"
activeDomains[$i]="${saveLocation}" activeDomains[i]="${saveLocation}"
# Check if we can write to the save location file without actually creating # Check if we can write to the save location file without actually creating
# it (in case it doesn't exist) # it (in case it doesn't exist)
@@ -488,7 +602,7 @@ compareLists() {
# Download specified URL and perform checks on HTTP status and file content # Download specified URL and perform checks on HTTP status and file content
gravity_DownloadBlocklistFromUrl() { gravity_DownloadBlocklistFromUrl() {
local url="${1}" adlistID="${2}" saveLocation="${3}" target="${4}" compression="${5}" gravity_type="${6}" domain="${7}" local url="${1}" adlistID="${2}" saveLocation="${3}" target="${4}" compression="${5}" gravity_type="${6}" domain="${7}"
local heisenbergCompensator="" listCurlBuffer str httpCode success="" ip cmd_ext local modifiedOptions="" listCurlBuffer str httpCode success="" ip cmd_ext
local file_path permissions ip_addr port blocked=false download=true local file_path permissions ip_addr port blocked=false download=true
# Create temp file to store content on disk instead of RAM # Create temp file to store content on disk instead of RAM
@@ -497,12 +611,37 @@ gravity_DownloadBlocklistFromUrl() {
mv "${listCurlBuffer}" "${listCurlBuffer%.*}.phgpb" mv "${listCurlBuffer}" "${listCurlBuffer%.*}.phgpb"
listCurlBuffer="${listCurlBuffer%.*}.phgpb" listCurlBuffer="${listCurlBuffer%.*}.phgpb"
# Determine if $saveLocation has read permission # For all remote files, we try to determine if the file has changed to skip
if [[ -r "${saveLocation}" && $url != "file"* ]]; then # downloading them whenever possible.
# Have curl determine if a remote file has been modified since last retrieval if [[ $url != "file"* ]]; then
# Uses "Last-Modified" header, which certain web servers do not provide (e.g: raw github urls) # Use the HTTP ETag header to determine if the file has changed if supported
# Note: Don't do this for local files, always download them # by curl. Using ETags is supported by raw.githubusercontent.com URLs.
heisenbergCompensator="-z ${saveLocation}" if [[ "${etag_support}" == true ]]; then
# Save HTTP ETag to the specified file. An ETag is a caching related header,
# usually returned in a response. If no ETag is sent by the server, an empty
# file is created and can later be used consistently.
modifiedOptions="--etag-save ${saveLocation}.etag"
if [[ -f "${saveLocation}.etag" ]]; then
# This option makes a conditional HTTP request for the specific ETag read
# from the given file by sending a custom If-None-Match header using the
# stored ETag. This way, the server will only send the file if it has
# changed since the last request.
modifiedOptions="${modifiedOptions} --etag-compare ${saveLocation}.etag"
fi
fi
# Add If-Modified-Since header to the request if we did already download the
# file once
if [[ -f "${saveLocation}" ]]; then
# Request a file that has been modified later than the given time and
# date. We provide a file here which makes curl use the modification
# timestamp (mtime) of this file.
# Interstingly, this option is not supported by raw.githubusercontent.com
# URLs, however, it is still supported by many older web servers which may
# not support the HTTP ETag method so we keep it as a fallback.
modifiedOptions="${modifiedOptions} -z ${saveLocation}"
fi
fi fi
str="Status:" str="Status:"
@@ -632,7 +771,7 @@ gravity_DownloadBlocklistFromUrl() {
if [[ "${download}" == true ]]; then if [[ "${download}" == true ]]; then
# shellcheck disable=SC2086 # shellcheck disable=SC2086
httpCode=$(curl --connect-timeout ${curl_connect_timeout} -s -L ${compression} ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" "${url}" -o "${listCurlBuffer}" 2>/dev/null) httpCode=$(curl --connect-timeout ${curl_connect_timeout} -s -L ${compression} ${cmd_ext} ${modifiedOptions} -w "%{http_code}" "${url}" -o "${listCurlBuffer}" 2>/dev/null)
fi fi
case $url in case $url in
@@ -675,9 +814,10 @@ gravity_DownloadBlocklistFromUrl() {
# Determine if the blocklist was downloaded and saved correctly # Determine if the blocklist was downloaded and saved correctly
if [[ "${success}" == true ]]; then if [[ "${success}" == true ]]; then
if [[ "${httpCode}" == "304" ]]; then if [[ "${httpCode}" == "304" ]]; then
# Set list status to "unchanged/cached"
database_adlist_status "${adlistID}" "2"
# Add domains to database table file # Add domains to database table file
pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}" pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}"
database_adlist_status "${adlistID}" "2"
done="true" done="true"
# Check if $listCurlBuffer is a non-zero length file # Check if $listCurlBuffer is a non-zero length file
elif [[ -s "${listCurlBuffer}" ]]; then elif [[ -s "${listCurlBuffer}" ]]; then
@@ -685,10 +825,10 @@ gravity_DownloadBlocklistFromUrl() {
gravity_ParseFileIntoDomains "${listCurlBuffer}" "${saveLocation}" gravity_ParseFileIntoDomains "${listCurlBuffer}" "${saveLocation}"
# Remove curl buffer file after its use # Remove curl buffer file after its use
rm "${listCurlBuffer}" rm "${listCurlBuffer}"
# Compare lists if are they identical
compareLists "${adlistID}" "${saveLocation}"
# Add domains to database table file # Add domains to database table file
pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}" pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}"
# Compare lists, are they identical?
compareLists "${adlistID}" "${saveLocation}"
done="true" done="true"
else else
# Fall back to previously cached list if $listCurlBuffer is empty # Fall back to previously cached list if $listCurlBuffer is empty
@@ -701,9 +841,10 @@ gravity_DownloadBlocklistFromUrl() {
# Determine if cached list has read permission # Determine if cached list has read permission
if [[ -r "${saveLocation}" ]]; then if [[ -r "${saveLocation}" ]]; then
echo -e " ${CROSS} List download failed: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}" echo -e " ${CROSS} List download failed: ${COL_LIGHT_GREEN}using previously cached list${COL_NC}"
# Set list status to "download-failed/cached"
database_adlist_status "${adlistID}" "3"
# Add domains to database table file # Add domains to database table file
pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}" pihole-FTL "${gravity_type}" parseList "${saveLocation}" "${gravityTEMPfile}" "${adlistID}"
database_adlist_status "${adlistID}" "3"
else else
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}" echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
# Manually reset these two numbers because we do not call parseList here # Manually reset these two numbers because we do not call parseList here
@@ -764,11 +905,11 @@ gravity_Table_Count() {
gravity_ShowCount() { gravity_ShowCount() {
# Here we use the table "gravity" instead of the view "vw_gravity" for speed. # Here we use the table "gravity" instead of the view "vw_gravity" for speed.
# It's safe to replace it here, because right after a gravity run both will show the exactly same number of domains. # It's safe to replace it here, because right after a gravity run both will show the exactly same number of domains.
gravity_Table_Count "gravity" "gravity domains" "" gravity_Table_Count "gravity" "gravity domains"
gravity_Table_Count "vw_blacklist" "exact denied domains" gravity_Table_Count "domainlist WHERE type = 1 AND enabled = 1" "exact denied domains"
gravity_Table_Count "vw_regex_blacklist" "regex denied filters" gravity_Table_Count "domainlist WHERE type = 3 AND enabled = 1" "regex denied filters"
gravity_Table_Count "vw_whitelist" "exact allowed domains" gravity_Table_Count "domainlist WHERE type = 0 AND enabled = 1" "exact allowed domains"
gravity_Table_Count "vw_regex_whitelist" "regex allowed filters" gravity_Table_Count "domainlist WHERE type = 2 AND enabled = 1" "regex allowed filters"
} }
# Trap Ctrl-C # Trap Ctrl-C
@@ -917,11 +1058,33 @@ timeit(){
elapsed_time=$((end_time - start_time)) elapsed_time=$((end_time - start_time))
# Display the elapsed time # Display the elapsed time
printf " %b--> took %d.%03d seconds%b\n" ${COL_BLUE} $((elapsed_time / 1000)) $((elapsed_time % 1000)) ${COL_NC} printf " %b--> took %d.%03d seconds%b\n" "${COL_BLUE}" $((elapsed_time / 1000)) $((elapsed_time % 1000)) "${COL_NC}"
return $ret return $ret
} }
migrate_to_listsCache_dir() {
# If the ${listsCacheDir} directory already exists, this has been done before
if [[ -d "${listsCacheDir}" ]]; then
return
fi
# If not, we need to migrate the old files to the new directory
local str="Migrating the list's cache directory to new location"
echo -ne " ${INFO} ${str}..."
mkdir -p "${listsCacheDir}"
# Move the old files to the new directory
if mv "${piholeDir}"/list.* "${listsCacheDir}/" 2>/dev/null; then
echo -e "${OVER} ${TICK} ${str}"
else
echo -e "${OVER} ${CROSS} ${str}"
fi
# Update the list's paths in the corresponding .sha1 files to the new location
sed -i "s|${piholeDir}/|${listsCacheDir}/|g" "${listsCacheDir}"/*.sha1
}
helpFunc() { helpFunc() {
echo "Usage: pihole -g echo "Usage: pihole -g
Update domains from blocklists specified in adlists.list Update domains from blocklists specified in adlists.list
@@ -997,6 +1160,9 @@ if [[ "${recover_database:-}" == true ]]; then
timeit database_recovery "$4" timeit database_recovery "$4"
fi fi
# Migrate scattered list files to the new cache directory
migrate_to_listsCache_dir
# Move possibly existing legacy files to the gravity database # Move possibly existing legacy files to the gravity database
if ! timeit migrate_to_database; then if ! timeit migrate_to_database; then
echo -e " ${CROSS} Unable to migrate to database. Please contact support." echo -e " ${CROSS} Unable to migrate to database. Please contact support."
@@ -1007,7 +1173,7 @@ if [[ "${forceDelete:-}" == true ]]; then
str="Deleting existing list cache" str="Deleting existing list cache"
echo -ne "${INFO} ${str}..." echo -ne "${INFO} ${str}..."
rm /etc/pihole/list.* 2>/dev/null || true rm "${listsCacheDir}/list.*" 2>/dev/null || true
echo -e "${OVER} ${TICK} ${str}" echo -e "${OVER} ${TICK} ${str}"
fi fi

4
pihole
View File

@@ -73,19 +73,17 @@ listFunc() {
debugFunc() { debugFunc() {
local automated local automated
local web
local check_database_integrity local check_database_integrity
# Pull off the `debug` leaving passed call augmentation flags in $1 # Pull off the `debug` leaving passed call augmentation flags in $1
shift shift
for value in "$@"; do for value in "$@"; do
[[ "$value" == *"-a"* ]] && automated="true" [[ "$value" == *"-a"* ]] && automated="true"
[[ "$value" == *"-w"* ]] && web="true"
[[ "$value" == *"-c"* ]] && check_database_integrity="true" [[ "$value" == *"-c"* ]] && check_database_integrity="true"
[[ "$value" == *"--check_database"* ]] && check_database_integrity="true" [[ "$value" == *"--check_database"* ]] && check_database_integrity="true"
done done
AUTOMATED=${automated:-} WEBCALL=${web:-} CHECK_DATABASE=${check_database_integrity:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh AUTOMATED=${automated:-} CHECK_DATABASE=${check_database_integrity:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
exit 0 exit 0
} }

View File

@@ -1,18 +0,0 @@
FROM buildpack-deps:lunar-scm
ENV GITDIR=/etc/.pihole
ENV SCRIPTDIR=/opt/pihole
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
ADD . $GITDIR
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $GITDIR/advanced/Scripts/COL_TABLE $SCRIPTDIR/
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
ENV DEBIAN_FRONTEND=noninteractive
RUN true && \
chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true
ENV OS_CHECK_DOMAIN_NAME=dev-supportedos.pi-hole.net
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@@ -2,5 +2,5 @@ pyyaml == 6.0.2
pytest == 8.3.4 pytest == 8.3.4
pytest-xdist == 3.6.1 pytest-xdist == 3.6.1
pytest-testinfra == 10.1.1 pytest-testinfra == 10.1.1
tox == 4.23.2 tox == 4.24.1
pytest-clarity == 1.0.1 pytest-clarity == 1.0.1

View File

@@ -119,11 +119,6 @@ def test_installPihole_fresh_install_readableFiles(host):
assert exit_status_success == actual_rc assert exit_status_success == actual_rc
check_leases = test_cmd.format("w", "/etc/pihole/dhcp.leases", piholeuser) check_leases = test_cmd.format("w", "/etc/pihole/dhcp.leases", piholeuser)
actual_rc = host.run(check_leases).rc actual_rc = host.run(check_leases).rc
# readable dns-servers.conf
assert exit_status_success == actual_rc
check_servers = test_cmd.format("r", "/etc/pihole/dns-servers.conf", piholeuser)
actual_rc = host.run(check_servers).rc
assert exit_status_success == actual_rc
# readable install.log # readable install.log
check_install = test_cmd.format("r", "/etc/pihole/install.log", piholeuser) check_install = test_cmd.format("r", "/etc/pihole/install.log", piholeuser)
actual_rc = host.run(check_install).rc actual_rc = host.run(check_install).rc