Compare commits

..

221 Commits

Author SHA1 Message Date
Adam Warner
cef7fd4b02
Pi-hole core 6.1.4 (#6347) 2025-07-14 22:15:50 +01:00
Adam Warner
c09da77e2b
Fix pihole api command by not setting the some variabes as readonly (#6346) 2025-07-14 22:09:27 +01:00
Adam Warner
18e8396a44
Fix issue where web interface cannot run gravity (#6345) 2025-07-14 22:05:18 +01:00
Adam Warner
1bef0415db
bare minimum first past fix for pihoe api command not working due to attempting to re-set readony variabes PI_HOE_SCRIPT_DIR and utisfie.
Can't compain about them being readony if they're.. not.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-07-14 22:02:02 +01:00
Adam Warner
d6a83baf4f
Allow non-root access for updateGravity command
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-07-14 21:38:59 +01:00
Dan Schaper
605ff8183a
Sync master back into development (#6341) 2025-07-14 11:45:03 -07:00
Dan Schaper
9494dc6061
Pi-hole Core v6.1.3 (#6337) 2025-07-14 07:14:43 -07:00
Dan Schaper
9605ccc178
basic-install.sh listing interfaces (#6269) 2025-07-13 11:57:32 -07:00
deHakkelaar
86bdae0076
Update basic-install.sh
Added comments
2025-07-13 11:05:58 +02:00
Dan Schaper
1e88ce4975
piholeDebug - Get default route robustly (#6303) 2025-07-11 16:19:54 -07:00
Adam Warner
bb60e2e346
Sync master back into development (#6332) 2025-07-11 21:02:14 +01:00
Adam Warner
3977a312f0
Update release.yml
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-07-11 21:01:01 +01:00
Dan Schaper
b3d193b34c
Update Firewalld tests to match v6 ports (#6307) 2025-07-10 14:15:41 -07:00
Dan Schaper
0a36e9d949
update: abort if FTL branch does not exist (#6329) 2025-07-10 12:55:12 -07:00
MichaIng
6db6c68a4e
update: abort if FTL branch does not exist
Currently, if the FTL update check returns 404, hence the FTL branch does not seem to exist, an error message is printed, but the update continues, only the FTL update is skipped.

This can lead to setups with v5 FTL and v6 core/web, failing at config migration, where FTL is invoked with a v6-only command.

With this change, the update aborts immediately if the FTL branch is invalid, like it does in case of other FTL update check errors (other HTTP error codes than 404 or other curl errors). Hence it continues only if FTL is up-to-date already, or a new version from the given branch has been found.

Signed-off-by: MichaIng <micha@dietpi.com>
2025-07-10 21:37:28 +02:00
Dan Schaper
5b5e02d492
Do not skip root check for pihole user (#6312) 2025-07-10 11:48:29 -07:00
Dan Schaper
a2dd0e2f50
Prevent gravity curl from using unset bash variable's empty string. (#6191) 2025-07-10 11:29:00 -07:00
Dan Schaper
3d75ea6df2
Only update the package cache on fresh installations (#6282) 2025-07-10 11:20:03 -07:00
Dan Schaper
080e1ccf8a
installer: exit if FTL update check fails (#6316) 2025-07-10 10:59:05 -07:00
Dan Schaper
24f32d48af
Fix pihole -q by setting PI_HOLE_SCRIPT_DIR in api.sh (#6284) 2025-07-10 10:51:20 -07:00
Dan Schaper
8486cfd95a
Update python version used in test to 3.13 (#6321) 2025-07-10 10:47:49 -07:00
yubiuser
c81d5019a3
Bump pytest-xdist from 3.7.0 to 3.8.0 in /test (#6324) 2025-07-05 23:07:49 +02:00
dependabot[bot]
c5c5116e53
Bump pytest-xdist from 3.7.0 to 3.8.0 in /test
Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.7.0 to 3.8.0.
- [Release notes](https://github.com/pytest-dev/pytest-xdist/releases)
- [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.7.0...v3.8.0)

---
updated-dependencies:
- dependency-name: pytest-xdist
  dependency-version: 3.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-05 10:28:30 +00:00
Christian König
2f9fa80d7a
Update python version used in test to 3.13
Signed-off-by: Christian König <github@yubiuser.dev>
2025-07-01 13:34:55 +02:00
Dominik
f2280eb330
taillog Prevent grep interpeting search term as an option (#6318) 2025-06-29 07:08:21 +02:00
Rob Gill
f24fc9573a
taillog Prevent grep interpeting search term as an option
Adds '--' indicating end of options before the user provided
search pattern.

Signed-off-by: Rob Gill <rrobgill@protonmail.com>
2025-06-29 06:45:02 +10:00
MichaIng
3a35e589f2
installer: exit if FTL update check fails
The return code of `FTLdetect()` is used in the installer to know whether FTL has been installed or not.

The function however returns an error only, if the download of FTL fails, not if checking for a latest version/update of FTL fails. This way, installs and rapairs can continue without or with ourdated FTL until `pihole-FTL migrate v6`, which hangs endlessly, if it is a v5 FTL.

This commit handles the return code in `FTLdetect()`, and lets it return true only if FTL download succeeded, or if the update check succeeded and FTL is up-to-date. Else, it could neither be repaired, nor installed, and the error message should give a hint what went wrong, hence exit.

`FTLdetect()` is not called by any other script, hence this change has no surprising effect elsewhere.

Additionally, a syntax error in the `FTLcheckUpdate()` function itself is fixed, which masks the `check_download_exists()` return code, hence always leads to error code 4, if the FTL branch is not `master`.

Signed-off-by: MichaIng <micha@dietpi.com>
2025-06-26 00:53:49 +02:00
Rob Gill
19d5943440
piholeDebug - Get default route robustly
Determine address and interface of default route by preceeding
    'via' and 'dev' fields in json output instead of plain text
    field position.

    Log if unable to determine default gateway

Signed-off-by: Rob Gill <rrobgill@protonmail.com>
2025-06-25 05:10:12 +10:00
Dominik
f90677a1ff
Clean COL_TABLE and allow to send color codes when invoked by FTL (${FORCE_COLOR}) (#6314) 2025-06-24 19:24:40 +02:00
Christian König
daec6f8c02
Set color codes when FORCE_COLOR is true
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-24 19:03:24 +02:00
Christian König
a48665c7bb
Remove deprecated and unused colors
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-24 18:51:01 +02:00
Adam Warner
8a97a1433a
Fix dependabot (#6297) 2025-06-22 14:28:08 +02:00
Adam Warner
f94d9f2540
Add note about adding local user to pihole group to final dialog (#6152) 2025-06-22 14:13:46 +02:00
Christian König
830c4bc049
Do not skipp root check for pihole user
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-21 22:40:43 +02:00
yubiuser
1dbe425146
Bump pytest from 8.4.0 to 8.4.1 in /test (#6311) 2025-06-21 14:31:07 +02:00
yubiuser
fc2f7795e9
Bump tox from 4.26.0 to 4.27.0 in /test (#6310) 2025-06-21 14:30:38 +02:00
dependabot[bot]
0bc06ed204
Bump pytest from 8.4.0 to 8.4.1 in /test
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.0 to 8.4.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.4.0...8.4.1)

---
updated-dependencies:
- dependency-name: pytest
  dependency-version: 8.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-21 10:10:47 +00:00
dependabot[bot]
700c892dff
Bump tox from 4.26.0 to 4.27.0 in /test
Bumps [tox](https://github.com/tox-dev/tox) from 4.26.0 to 4.27.0.
- [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.26.0...4.27.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-21 10:10:43 +00:00
RD WebDesign
405053692a
Add HTTPS and NTP services to firewalld test
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-06-17 21:32:49 -03:00
RD WebDesign
04d9d32444
Remove test for port 4711
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-06-17 20:19:13 -03:00
Christian König
c19e907c0c
Fix dependabot
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-09 19:06:15 +02:00
Christian König
7a16024020
Run package update everytime before building the meta package when invoking from the install script
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-08 21:31:56 +02:00
Christian König
5777497f52
Separate package manager detection and cache update functions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-08 21:25:43 +02:00
Adam Warner
404dc7cb88
Add 'never-stale' to the exempt issue labels of the stale workflow (#6283) 2025-06-08 15:06:33 +01:00
Adam Warner
2f3dfef862
Dependabot: group updates (#6294) 2025-06-07 18:36:35 +01:00
XhmikosR
b39c9956e8
Dependabot: group updates
Signed-off-by: XhmikosR <xhmikosr@gmail.com>
2025-06-07 18:27:46 +03:00
yubiuser
70bcb0bb2b
Bump pytest-xdist from 3.6.1 to 3.7.0 in /test (#6254) 2025-06-07 12:32:36 +02:00
dependabot[bot]
2c1032090d
Bump pytest-xdist from 3.6.1 to 3.7.0 in /test
Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.6.1 to 3.7.0.
- [Release notes](https://github.com/pytest-dev/pytest-xdist/releases)
- [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.6.1...v3.7.0)

---
updated-dependencies:
- dependency-name: pytest-xdist
  dependency-version: 3.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-07 10:07:56 +00:00
yubiuser
b5adc981c2
Bump pytest from 8.3.5 to 8.4.0 in /test (#6293) 2025-06-07 12:06:51 +02:00
dependabot[bot]
3933cb0575
Bump pytest from 8.3.5 to 8.4.0 in /test
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.5 to 8.4.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.5...8.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-07 10:01:39 +00:00
Dan Schaper
6964cd124e
Sync master back into development (#6291) 2025-06-06 16:22:37 -07:00
Christian König
d16c049768
Set PI_HOLE_SCRIPT_DIR in api.sh
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-05 14:45:29 +02:00
Christian König
5ff4f000d5
Add 'never-stale' to the exempt issue labels of the stale workflow
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-05 14:16:27 +02:00
Christian König
93ecfb9504
We test a fresh installaton, so don't pretend this is not a fresh installation
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-05 13:09:03 +02:00
Christian König
ea61755881
Only update the package cache on fresh installations
Signed-off-by: Christian König <github@yubiuser.dev>
2025-06-05 12:50:10 +02:00
deHakkelaar
6130b800e3
basic-install.sh listing interfaces
Following up on below one:

https://github.com/pi-hole/pi-hole/pull/6236

And below poor attempt:

https://github.com/pi-hole/pi-hole/pull/6256

Signed-off-by: deHakkelaar <deHakkelaar@users.noreply.github.com>
2025-06-02 03:59:36 +02:00
Dan Schaper
ec892ec096
Pi-hole Core v6.1.1 (#6267) 2025-06-01 18:35:19 -07:00
Dan Schaper
4d4195ed4e
Revert "Use PID1 to determine which command to use when toggeling services" (#6262) 2025-06-01 09:45:48 -07:00
Dan Schaper
260fa5ea40
Sync master back into development (#6253) 2025-06-01 09:15:10 -07:00
yubiuser
03b3b69617
Make LOGFILE readonly after assignment (#6261) 2025-06-01 15:47:11 +02:00
Dan Schaper
8c81335004
Don't revert the package metadata
Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
2025-05-31 11:39:13 -07:00
Dan Schaper
e1b05028a7
Revert "Use PID1 to determine which command to use when toggeling services" 2025-05-31 09:14:08 -07:00
Dan Schaper
89c4976da4
Make LOGFILE readonly after assignment
Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
2025-05-31 08:23:24 -07:00
Adam Warner
4fed49c5e5
Pi-hole Core v6.1 (#6221) 2025-05-30 22:56:55 +01:00
yubiuser
cad0d0bf1f
Allow to get API URL from local.api.ftl even if DNS port has changed (#6252) 2025-05-30 21:57:23 +02:00
Dan Schaper
42aba32ceb
Use PID1 to determine which command to use when toggeling services (#6245) 2025-05-30 12:24:09 -07:00
Christian König
6f429d82b4
Allow to get API URL from local.api.ftl even if DNS port has changed
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-30 21:05:08 +02:00
Christian König
fd40fa6f39
Test need adjustment to long arument syntax
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-30 20:52:37 +02:00
yubiuser
d177c4c776
Add useful comment
Co-authored-by: Dan Schaper <dan.schaper@pi-hole.net>
Signed-off-by: yubiuser <github@yubiuser.dev>
2025-05-30 19:03:12 +02:00
Christian König
888556278e
Add gwak to Fedorea 42 test image as other tests also rely on awk
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-28 20:47:55 +02:00
Christian König
69473a7b54
Add awk to meta package dependencie (is missing on Fedora 42 by default) and order dependencies alphabetically
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-28 19:54:44 +02:00
Christian König
f3166d7a78
Adjust test to mock PID1 to be systemd
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-27 23:52:46 +02:00
Christian König
137338e6a8
Use service wrappers in all scripts
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-27 21:23:56 +02:00
Christian König
b707890f10
Use PID1 to determine which command to use when toggeling services
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-27 20:09:59 +02:00
Dominik
822e677c5c
Use a more general method to determine whether systemd is the init system (#6043) 2025-05-27 19:33:57 +02:00
yubiuser
5aadc5f475
Function gravity_CheckDNSResolutionAvailable() should return 0 if DNS resolution is available (#6240) 2025-05-21 07:44:04 +02:00
RD WebDesign
6ba6b0f015
Return 1 only if resolution fails
Function gravity_CheckDNSResolutionAvailable() should return 0 if DNS resolution is available

Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-05-20 19:46:28 -03:00
yubiuser
5f60860a17
Bump tox from 4.25.0 to 4.26.0 in /test (#6237) 2025-05-17 13:13:30 +02:00
dependabot[bot]
86d9ac5f8f
Bump tox from 4.25.0 to 4.26.0 in /test
Bumps [tox](https://github.com/tox-dev/tox) from 4.25.0 to 4.26.0.
- [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.25.0...4.26.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-17 10:02:13 +00:00
Dan Schaper
a04ed13d0a
Allow simple pihole api output, containing only the JSON payload (#6096) 2025-05-16 13:57:04 -07:00
Dan Schaper
04e52daaf3
Update get_available_interfaces() to correctly filter loopback device (lo) (#6236) 2025-05-15 08:43:12 -07:00
Piotr Tyrakowski
88934ec818
Update basic-install.sh
Signed-off-by: Piotr Tyrakowski <verscup@gmail.com>
2025-05-14 21:47:34 +02:00
Dan Schaper
9aa005ad4c
Revert "fix(get_available_interfaces): only drop the loopback device (‘lo’), don’t filter every “lo” substring" (#6235) 2025-05-14 09:53:07 -07:00
Dan Schaper
f6d477f228
Revert "fix(get_available_interfaces): only drop the loopback device (‘lo’), don’t filter every “lo” substring" 2025-05-14 09:51:47 -07:00
Dan Schaper
3c1d8690fa
fix(get_available_interfaces): only drop the loopback device (‘lo’), don’t filter every “lo” substring (#6224) 2025-05-14 09:05:21 -07:00
Dan Schaper
3314887e65
Change FTLcheckUpdate to use api.github.com and jq to retrieve tag_name (#6229) 2025-05-14 08:32:42 -07:00
Dan Schaper
c1a5b902fb
Use shell parameter expansion to split http_code and payload for api.sh (#6230) 2025-05-14 08:31:13 -07:00
Christian König
a590b77431
Link to documentation on how to add local user to pihole group
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-14 09:36:52 +02:00
RD WebDesign
dee44cb3da
Define "silent" as default option and include "verbose" to the man page
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-05-13 14:22:41 -03:00
Dan Schaper
de31858950
Use shell parameter expansion to split http_code and payload
Codespell

editorconfig

Signed-off-by: Dan Schaper <dan.schaper@pi-hole.net>
2025-05-12 12:26:56 -07:00
Piotr Tyrakowski
13848f2da1
Update automated install/basic-install.sh
Co-authored-by: Dan Schaper <dan.schaper@pi-hole.net>
Signed-off-by: Piotr Tyrakowski <verscup@gmail.com>
2025-05-12 21:13:01 +02:00
RD WebDesign
e01d49b3ee
Change FTLcheckUpdate to use api.github.com and jq to retrieve tag_name
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-05-12 15:53:12 -03:00
RD WebDesign
190798e572
Allow simple pihole api output, containing only the JSON payload
Signed-off-by: RD WebDesign <github@rdwebdesign.com.br>
2025-05-12 14:23:15 -03:00
Dan Schaper
1bdbc26a07
Give FTL 60 seconds for graceful shutdown (#6187) 2025-05-12 10:13:29 -07:00
Christian König
842afc2475
Give FTL 60 seconds for graceful shutdown
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-12 19:02:29 +02:00
Dan Schaper
398405c303
All gravity related files and dirs should be owned by pihole:pihole (#6186) 2025-05-12 08:48:27 -07:00
yubiuser
189da82614
&& chown
Co-authored-by: Dan Schaper <dan.schaper@pi-hole.net>
Signed-off-by: yubiuser <github@yubiuser.dev>
2025-05-12 08:54:58 +02:00
Dan Schaper
99d00e0ed0
Do not try to upgrade gravity if it does not exist (#6218) 2025-05-11 08:47:46 -07:00
Dan Schaper
3c6c3d3a15
Fix API logic in api.sh (#6193) 2025-05-11 08:43:12 -07:00
Dan Schaper
3c0ff57660
Allow alternative cron daemons on Debian (#6180) 2025-05-11 08:12:29 -07:00
Piotr Tyrakowski
9f3e71b0b6
Update basic-install.sh
I have updated line 708
to use grep -v "loo" 
instead of "lo" 
the reason is with "lo" it cannot find "wlo1" interface

Signed-off-by: Piotr Tyrakowski <verscup@gmail.com>
2025-05-09 17:03:57 +02:00
Christian König
d45003a8ca
Do not try to upgrade gravity if it does not exist
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-05 17:27:53 +02:00
yubiuser
7aaaa49cf0
Set dns.interface during installation (#6216) 2025-05-05 08:39:23 +02:00
Christian König
fc103af050
Revert response code logic
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-04 21:45:44 +02:00
yubiuser
46fbd931b5
Use CODEOWNERS instead of deprecated dependbot/reviewers (#6213) 2025-05-04 20:56:09 +02:00
Christian König
96437dc913
Set dns.interface during installation
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-04 19:39:43 +02:00
yubiuser
cae558d5d4
Extend .gitignore (#6215) 2025-05-04 14:32:40 +02:00
darkexplosiveqwx
65fd0b099d
Extend .gitignore
Signed-off-by: darkexplosiveqwx <101737077+darkexplosiveqwx@users.noreply.github.com>
2025-05-04 14:22:02 +02:00
Christian König
95d27ac985
Merge branch 'development' into tweak/gravity_options
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-04 14:17:41 +02:00
yubiuser
744ac6ad88
Add Fedora 42 to tests (#6177) 2025-05-04 13:28:03 +02:00
darkexplosiveqwx
b82487ee6a
Add Fedora 42 to tests
Signed-off-by: darkexplosiveqwx <101737077+darkexplosiveqwx@users.noreply.github.com>
2025-05-04 12:02:15 +02:00
Dan Schaper
0a72e517b6
Remove reference to telnet and chronometer in README (#6188) 2025-05-03 13:38:29 -07:00
Dan Schaper
09368a77b4
Remove unused $target from gravity (#6192) 2025-05-03 13:37:45 -07:00
Dan Schaper
0e6439c6c0
Remove check for supported OS (#6206) 2025-05-03 13:17:56 -07:00
Christian König
0c533ec71b
Use CODEOWNERS instead of deprecated dependbot/reviewers
Signed-off-by: Christian König <github@yubiuser.dev>
2025-05-03 20:06:24 +02:00
Christian König
5355e9e084
Remove os_check from debug script
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-28 21:10:36 +02:00
Christian König
54c8dd3d77
Remove os_check from tests
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-28 21:06:05 +02:00
Christian König
d9f4ee7aaa
Remove os_check from update script
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-28 21:04:08 +02:00
Christian König
40da3a40ec
Remove os_check from install script
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-28 21:03:08 +02:00
yubiuser
3cbaee7b76
Fix gravity waiting forever for DNS (#6196) 2025-04-26 16:48:24 +02:00
yubiuser
3bd6a41795
Improve wording
Co-authored-by: Adam Warner <me@adamwarner.co.uk>
Signed-off-by: yubiuser <github@yubiuser.dev>
2025-04-26 15:36:22 +02:00
Christian König
4303a5868f
Only append dot
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-26 15:03:42 +02:00
Christian König
215003899d
(2+1)*40
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-26 15:03:01 +02:00
yubiuser
cf3b7d0d8e
Bump actions/setup-python from 5.5.0 to 5.6.0 (#6199) 2025-04-26 12:56:31 +02:00
dependabot[bot]
454f96d0ea
Bump actions/setup-python from 5.5.0 to 5.6.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.5.0 to 5.6.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.5.0...v5.6.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-26 10:25:43 +00:00
Christian König
1bea6db50a
Fix API logic in api.sh
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-25 21:16:52 +02:00
Christian König
72a52807d1
Fix gravity waiting forever for DNS
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-25 21:03:09 +02:00
Christian König
d7b6d6aa33
Remove unused $target from gravity
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 23:06:01 +02:00
Christian König
7a641f4c35
Use paramteter expansion to prevent adding literal '' if parameter is empty
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 22:52:33 +02:00
Rob Gill
ce0bdac1bd
Remove reference to telnet and chronometer in README
Replace with curl example and commandline example

Signed-off-by: Rob Gill <rrobgill@protonmail.com>
2025-04-23 06:41:16 +10:00
Christian König
13d76abff7
Set customUpstreamResolver empty
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 22:38:07 +02:00
Christian König
76e41aeefa
Add small note about modifiedOptions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 22:03:54 +02:00
Christian König
774037834b
Rename cmd_ext
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 22:01:21 +02:00
Christian König
89c4248315
Use quotes for all substitutions
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-22 21:57:47 +02:00
Michael Woolweaver
6fc5bf83f4
don't mute SC2086
Signed-off-by: Michael Woolweaver <michael@woolweaver.bid>
2025-04-22 21:56:21 +02:00
Christian König
4a1bcda6f1
All gravity related files and dirs should be owned by pihole:pihole
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-21 09:30:36 +02:00
yubiuser
60485fdc51
Remove duplicated code checking if adlist domain is blocked locally (#6183) 2025-04-21 09:17:39 +02:00
yubiuser
6fe77ebeed
Treat FTL return data as strings - part II (#6184) 2025-04-21 09:16:58 +02:00
Christian König
8733b429dd
Treat FTL return data as strings - part II
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-20 22:50:55 +02:00
Christian König
1432568d17
Remove duplicated code checking if adlist domain is blocked locally
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-20 20:14:41 +02:00
Ihor Urazov
cff7f40739
Allow alternative cron daemons on Debian
Add cron-daemon virtual package as an alternative dependency. This way
pihole-meta by default still depends on cron, but allows installation of
systemd-cron, which completely replaces cron daemon and package. With
systemd-cron functionality of crontab files and /etc/cron.* directories
works expected, as systemd-cron generates systemd timers from cron
files.

Signed-off-by: Ihor Urazov <iurazov@healthjoy.com>
2025-04-19 20:33:19 +03:00
yubiuser
248d25b8d0
Install on IPv6-only/DNS64/NAT64 system (#6144) 2025-04-15 17:33:09 +02:00
Dominik
95c1b1a542
Add ON DELETE CASCADE to FOREIGN KEY REFERENCES in gravity.db (#6113) 2025-04-15 06:24:52 +02:00
Rob Gill
9e62625f83
Install on IPv6-only/DNS64/NAT64 system
Alters the test for IPv4 route so the installer doesn't fail instantly on IPv6-only.

Gives user a dialog to proceed with IPv6 only installation

Switches DNS server options to only contain IPv6 addresses.

Signed-off-by: Rob Gill <rrobgill@protonmail.com>
2025-04-15 14:13:43 +10:00
Dan Schaper
faeba69090
revert a change to gravity.sh that attempted to fix an SC2086 warning… (#6162) 2025-04-09 10:07:10 -07:00
Adam Warner
48272f3393
revert a change to gravity.sh that attempted to fix an SC2086 warning from shellcheck.
Fixes #6159

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-09 18:02:40 +01:00
Adam Warner
195e65855d
Fix more shellcheck warnings (#6155) 2025-04-08 17:27:07 +01:00
Christian König
0f511ad574
Remove token and use sarif-fmt for nicer CLI output
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-08 17:50:19 +02:00
Adam Warner
323dbbe5d9
Reduce code duplication in piholeLogFlush (#6148) 2025-04-08 12:44:30 +01:00
Christian König
bda81cb2f5
Remove debug SARIF upload
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 21:25:29 +02:00
Christian König
b271dbf606
Set shellcheck level to warning, can be lowered later
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 14:11:39 +02:00
Christian König
5002ce8ba7
Source files relative to the repos root
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 14:10:01 +02:00
Christian König
135b0cce14
Switch to Differential ShellCheck
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 11:54:35 +02:00
Christian König
23fc53c618
Set -x option for shellcheck GHA
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 11:32:14 +02:00
Adam Warner
3732ea7365
Remove shellcheck directives that no longer serve any purpose
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-07 10:24:53 +01:00
Christian König
ca1bab3c1b
Fix more shellcheck warnings
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-07 10:52:57 +02:00
yubiuser
36e6c9921e
Shellcheck Tweaks (#6147) 2025-04-07 10:08:25 +02:00
Dan Schaper
6c5bc1de39
versions file should readable by others (make pihole -v work for non-root users) (#6002) 2025-04-06 12:58:16 -07:00
Christian König
9f5e18b1cd
Make it 644
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-06 21:13:47 +02:00
Christian König
d28e795266
Permissions on versions file should be 640
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-06 21:12:58 +02:00
Christian König
e579397f51
Allow all users to read the version file
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-06 20:52:57 +02:00
Adam Warner
2088601148
Add .shellcheckrc to configure shellcheck ignore SC1090-1 globally
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 18:46:47 +01:00
Adam Warner
48c59cb6cf
In ./automated install/uninstall.sh line 14:
readonly ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
         ^-----------------^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./advanced/Scripts/update.sh line 39:
readonly ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
         ^-----------------^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./advanced/Scripts/updatecheck.sh line 45:
readonly ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
         ^-----------------^ SC2155 (warning): Declare and assign separately to avoid masking return values.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:20:51 +01:00
Adam Warner
f01e8c70d9
Weirldly, GHA missed these minor warnings however have disabled them as they are due to variables either being used in or declared in basic-install,.sh
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
3a9b9c027e
In ./pihole line 20:
source "${colfile}"
       ^----------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

In ./pihole line 23:
source "${utilsfile}"
       ^------------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

In ./pihole line 27:
source "${apifile}"
       ^----------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

In ./pihole line 34:
    source "${versionsfile}"
           ^---------------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

In ./pihole line 251:
  local timer="$(echo "${data}"| jq --raw-output '.timer' )"
        ^---^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./pihole line 255:
  local str="Pi-hole $(echo "${data}" | jq --raw-output '.blocking')${extra}"
        ^-^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./pihole line 378:
  local logging_enabled=$(getFTLConfigValue dns.queryLogging)
        ^-------------^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./pihole line 385:
  readonly LOGFILE=$(getFTLConfigValue files.log.dnsmasq)
           ^-----^ SC2155 (warning): Declare and assign separately to avoid masking return values.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
f5dc337d1b
In ./advanced/Scripts/piholeLogFlush.sh line 12:
source ${colfile}
       ^--------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

In ./advanced/Scripts/piholeLogFlush.sh line 16:
source "${utilsfile}"
       ^------------^ SC1090 (warning): ShellCheck can't follow non-constant source. Use a directive to specify location.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
63623c4353
In ./advanced/Scripts/piholeCheckout.sh line 112:
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}"))
                      ^-- SC2207 (warning): Prefer mapfile or read -a to split command output (or quote to avoid splitting).

In ./advanced/Scripts/piholeCheckout.sh line 139:
        webbranches=($(get_available_branches "${webInterfaceDir}"))
                     ^-- SC2207 (warning): Prefer mapfile or read -a to split command output (or quote to avoid splitting).

In ./advanced/Scripts/piholeCheckout.sh line 170:
        ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -) )
                      ^-- SC2207 (warning): Prefer mapfile or read -a to split command output (or quote to avoid splitting).

In ./advanced/Scripts/piholeCheckout.sh line 218:
            elif [ $? -eq 2 ]; then
                   ^-- SC2319 (warning): This $? refers to a condition, not a command. Assign to a variable to avoid it being overwritten.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
59d2177271
In ./advanced/Scripts/database_migration/gravity-db.sh line 18:
piholeDir="${2}"
    ^-------^ SC2034 (warning): piholeDir appears unused. Verify use (or export if used externally).

Turns out it is _actually_ unused, the full path of the gravity database is passed to the function, so we'll tidy this up rather than supressing.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
a624d3be8d
In ./advanced/Scripts/utils.sh line 91:
if [[ $? -eq 5 ]]; then
     ^------------^ SC3010 (warning): In POSIX sh, [[ ]] is undefined.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
39f5115135
In ./automated install/basic-install.sh line 1753:
local status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1)
          ^----^ SC2155 (warning): Declare and assign separately to avoid masking return values.

In ./automated install/basic-install.sh line 2076:
            elif [ $? -eq 2 ]; then
                   ^-- SC2319 (warning): This $? refers to a condition, not a command. Assign to a variable to avoid it being overwritten.

Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
e018a37a8c
First things first - bump severity of shellcheck action from error to warning
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 14:11:40 +01:00
Adam Warner
6e06a93c31
functionise log rotation and flushing code to avoid dupliation
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-06 13:57:07 +01:00
Adam Warner
7e5d9db6b7
Remove no-longer-needed pihole sudoers file (#6143) 2025-04-06 13:52:37 +01:00
Dominik
5afab5e96c
Move list parsing entirely into FTL (#6105) 2025-04-05 20:15:16 +02:00
yubiuser
ab8b8da9c3
Bump pytest-testinfra from 10.1.1 to 10.2.2 in /test (#6151) 2025-04-05 12:11:16 +02:00
dependabot[bot]
07864032de
Bump pytest-testinfra from 10.1.1 to 10.2.2 in /test
Bumps [pytest-testinfra](https://github.com/pytest-dev/pytest-testinfra) from 10.1.1 to 10.2.2.
- [Release notes](https://github.com/pytest-dev/pytest-testinfra/releases)
- [Changelog](https://github.com/pytest-dev/pytest-testinfra/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-testinfra/compare/10.1.1...10.2.2)

---
updated-dependencies:
- dependency-name: pytest-testinfra
  dependency-version: 10.2.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-05 10:05:08 +00:00
Adam Warner
bdcb6fc88c
Update update.sh, updatecheck.sh and uninstall.sh to honour pihole.to… (#5981) 2025-04-05 01:18:49 +01:00
Adam Warner
f403468450
Add webserver log to piholeLogFlush.sh (#6049) 2025-04-05 00:33:18 +01:00
Adam Warner
097ac8336e
Add recommended fields to the deb package (#6054) 2025-04-05 00:31:26 +01:00
Christian König
fe2b22c570
Add recommended fields to the deb package
Signed-off-by: Christian König <github@yubiuser.dev>
2025-04-05 00:29:13 +01:00
Adam Warner
2477d6b184
Revert #6137 (#6146) 2025-04-04 23:28:51 +01:00
Adam Warner
f98b9520e4
v5 sudoers file that allowed www-data to run pihole command is no longer needed. "Fixes" #6066
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2025-04-04 23:19:14 +01:00
yubiuser
65b42c1c8f
Ensure gravity_Cleanup() checks the correct directory (#6131) 2025-04-04 22:50:19 +02:00
Michael Woolweaver
e548ed043f
ensure gravity_Cleanup() checks the correct directory for list data
also glob with * to ensure .etag & .sha1 are removed as well
should fix #6075

Co-authored-by: yubiuser <github@yubiuser.dev>
Signed-off-by: Michael Woolweaver <michael@woolweaver.bid>
2025-04-04 15:15:51 -05:00
Adam Warner
4108c817dc
Revert "source with source not dot (#6137)"
This reverts commit 8fd2ebd3d7bc00fe4c36dcdae0932d7bab4a3c3c, reversing
changes made to 557bc6f1794244f55b36258a51e3bd494860b439.
2025-04-04 19:12:57 +01:00
Dan Schaper
8fd2ebd3d7
source with source not dot (#6137) 2025-04-02 12:36:48 -07:00
Michael Woolweaver
4efe4dfd4b
source with source not dot
Signed-off-by: Michael Woolweaver <michael@woolweaver.bid>
2025-04-02 14:21:45 -05:00
Adam Warner
557bc6f179
Add CentOS 10 to test suite (#6126) 2025-04-02 18:24:36 +01:00
Adam Warner
8fce8f6149
build gravityDBfile_default like the other variables (#6133) 2025-04-02 17:12:21 +01:00
Michael Woolweaver
3cb6ea503a
build gravityDBfile_default like the other variables
seems this one was forgotten

Signed-off-by: Michael Woolweaver <michael@woolweaver.bid>
2025-04-01 23:57:56 -05:00
Christian König
7886cfc80b
Add CentOS 10 to test suite
Signed-off-by: Christian König <github@yubiuser.dev>
2025-03-31 12:13:34 +02:00
Adam Warner
8797a0df05
Sync master back into development (#6122) 2025-03-30 18:31:02 +01:00
Adam Warner
0f7803b775
Pi-hole Core v6.0.6 (#6118) 2025-03-30 17:54:55 +01:00
James George
0f482396ee
Update update.sh, updatecheck.sh and uninstall.sh to honour pihole.toml settings for webserver.paths.webroot and webserver.paths.webhome
When uninstalling, remove web interface parent directory empty check and possible removal.

Signed-off-by: James George <james.george@vigilantvoid.com>
2025-03-30 13:11:21 +08:00
yubiuser
73074f1557
Bump tox from 4.24.2 to 4.25.0 in /test (#6116) 2025-03-29 21:46:47 +01:00
yubiuser
bc23303788
Bump actions/setup-python from 5.4.0 to 5.5.0 (#6117) 2025-03-29 21:43:58 +01:00
dependabot[bot]
49fbdc4c00
Bump actions/setup-python from 5.4.0 to 5.5.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.4.0 to 5.5.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.4.0...v5.5.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-03-29 10:25:36 +00:00
dependabot[bot]
315528d740
Bump tox from 4.24.2 to 4.25.0 in /test
Bumps [tox](https://github.com/tox-dev/tox) from 4.24.2 to 4.25.0.
- [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.24.2...4.25.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-29 10:25:08 +00:00
DL6ER
71ec0a0244
Add ON DELETE CASCADE to FOREIGN KEY REFERENCES in gravity.db
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-03-27 13:10:53 +01:00
Adam Warner
e5cb0efd61
revert #6030 in preparation for docker-pi-hole #1794 (#6086) 2025-03-25 17:06:01 +00:00
DL6ER
dec670a6d6
Move list parsing entirely into FTL
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-03-22 09:18:02 +01:00
Michael Woolweaver
3a592471c6
revert pi-hole/pi-hole/pull/6030
in preparation for pi-hole/docker-pi-hole/pull/1786

Signed-off-by: Michael Woolweaver <michael@woolweaver.bid>
2025-03-14 14:32:29 -05:00
yubiuser
3f5c00919b
Remove WEB_CALL from COL_TABLE (#6062) 2025-03-10 06:14:47 +01:00
yubiuser
349544b24a
Create webserver.log on FTL startup (#6051) 2025-03-10 06:14:22 +01:00
yubiuser
387ec3a3c2
Bump pytest from 8.3.4 to 8.3.5 in /test (#6068) 2025-03-08 11:50:40 +01:00
dependabot[bot]
6b873b2d7f
Bump pytest from 8.3.4 to 8.3.5 in /test
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.4 to 8.3.5.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.4...8.3.5)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-08 10:46:01 +00:00
yubiuser
46e5b3b02e
Bump tox from 4.24.1 to 4.24.2 in /test (#6067) 2025-03-08 11:44:54 +01:00
dependabot[bot]
27aeed76f0
Bump tox from 4.24.1 to 4.24.2 in /test
Bumps [tox](https://github.com/tox-dev/tox) from 4.24.1 to 4.24.2.
- [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.24.1...4.24.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-08 10:30:22 +00:00
yubiuser
80d63eca93
Add 2FA handling to api.sh (#6065) 2025-03-08 10:46:54 +01:00
yubiuser
72404c983d
Add trailing / when changing ownership of /etc/pihole (#6057) 2025-03-07 23:08:04 +01:00
casperklein
9b4502a7a9
Add trailing / to directories
Signed-off-by: casperklein <casperklein@users.noreply.github.com>
2025-03-07 23:00:40 +01:00
Christian König
5de9b6ae69
Add 2FA handling to api.sh
Signed-off-by: Christian König <github@yubiuser.dev>
2025-03-07 13:43:41 +01:00
Christian König
f3dc202e36
Remove WEB_CALL from COL_TABLE
Signed-off-by: Christian König <github@yubiuser.dev>
2025-03-07 10:16:25 +01:00
yubiuser
9050e47049
version.sh: fix typo in comment (#6056) 2025-03-06 20:49:20 +01:00
XhmikosR
45cb722e50
version.sh: fix typo in comment
Signed-off-by: XhmikosR <xhmikosr@gmail.com>
2025-03-06 21:40:17 +02:00
yubiuser
98b17edfd7
README.md: switch to the SVG logo (#6052) 2025-03-06 14:27:58 +01:00
XhmikosR
d094b197e3
README.md: switch to the SVG logo
Signed-off-by: XhmikosR <xhmikosr@gmail.com>
2025-03-06 15:06:34 +02:00
Christian König
e437e3a805
Create webserver.log on FTL startup
Signed-off-by: Christian König <github@yubiuser.dev>
2025-03-06 09:48:06 +01:00
Jack'lul
4df5c0bb96
Add webserver log to piholeLogFlush.sh
Signed-off-by: Jack'lul <8418678+jacklul@users.noreply.github.com>
2025-03-05 22:25:33 +01:00
Adam Warner
411b9fcb6d
Sync master back into development (#6046) 2025-03-04 19:46:03 +00:00
DL6ER
bef8227cbd
Use a more general method to determine whether systemd is the init system
Signed-off-by: DL6ER <dl6er@dl6er.de>
2025-03-03 20:16:07 +01:00
45 changed files with 655 additions and 765 deletions

5
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,5 @@
# see https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-syntax
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
* @pi-hole/core-maintainers

View File

@ -8,8 +8,10 @@ updates:
time: "10:00" time: "10:00"
open-pull-requests-limit: 10 open-pull-requests-limit: 10
target-branch: development target-branch: development
reviewers: groups:
- "pi-hole/core-maintainers" github-actions-dependencies:
patterns:
- "*"
- package-ecosystem: pip - package-ecosystem: pip
directory: "/test" directory: "/test"
schedule: schedule:
@ -18,5 +20,7 @@ updates:
time: "10:00" time: "10:00"
open-pull-requests-limit: 10 open-pull-requests-limit: 10
target-branch: development target-branch: development
reviewers: groups:
- "pi-hole/core-maintainers" python-dependencies:
patterns:
- "*"

1
.github/release.yml vendored
View File

@ -2,6 +2,7 @@ changelog:
exclude: exclude:
labels: labels:
- internal - internal
- dependencies
authors: authors:
- dependabot - dependabot
- github-actions - github-actions

View File

@ -24,7 +24,7 @@ jobs:
days-before-close: 5 days-before-close: 5
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Please comment or update this issue or it will be closed in 5 days.' stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Please comment or update this issue or it will be closed in 5 days.'
stale-issue-label: '${{ env.stale_label }}' stale-issue-label: '${{ env.stale_label }}'
exempt-issue-labels: 'Internal, Fixed in next release, Bug: Confirmed, Documentation Needed' exempt-issue-labels: 'Internal, Fixed in next release, Bug: Confirmed, Documentation Needed, never-stale'
exempt-all-issue-assignees: true exempt-all-issue-assignees: true
operations-per-run: 300 operations-per-run: 300
close-issue-reason: 'not_planned' close-issue-reason: 'not_planned'

View File

@ -19,6 +19,8 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
with:
fetch-depth: 0 # Differential ShellCheck requires full git history
- name: Check scripts in repository are executable - name: Check scripts in repository are executable
run: | run: |
@ -28,12 +30,12 @@ jobs:
# If FAIL is 1 then we fail. # If FAIL is 1 then we fail.
[[ $FAIL == 1 ]] && exit 1 || echo "Scripts are executable!" [[ $FAIL == 1 ]] && exit 1 || echo "Scripts are executable!"
- name: Run shellcheck - name: Differential ShellCheck
uses: ludeeus/action-shellcheck@master uses: redhat-plumbers-in-action/differential-shellcheck@v5
with: with:
check_together: 'yes' severity: warning
format: tty display-engine: sarif-fmt
severity: error
- name: Spell-Checking - name: Spell-Checking
uses: codespell-project/actions-codespell@master uses: codespell-project/actions-codespell@master
@ -67,8 +69,10 @@ jobs:
ubuntu_22, ubuntu_22,
ubuntu_24, ubuntu_24,
centos_9, centos_9,
centos_10,
fedora_40, fedora_40,
fedora_41, fedora_41,
fedora_42,
] ]
env: env:
DISTRO: ${{matrix.distro}} DISTRO: ${{matrix.distro}}
@ -76,10 +80,10 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
- name: Set up Python 3.10 - name: Set up Python
uses: actions/setup-python@v5.4.0 uses: actions/setup-python@v5.6.0
with: with:
python-version: "3.10" python-version: "3.13"
- name: Install wheel - name: Install wheel
run: pip install wheel run: pip install wheel

3
.gitignore vendored
View File

@ -10,3 +10,6 @@ __pycache__
.idea/ .idea/
*.iml *.iml
.vscode/ .vscode/
.venv/
.fleet/
.cache/

2
.shellcheckrc Normal file
View File

@ -0,0 +1,2 @@
external-sources=true # allow shellcheck to read external sources
disable=SC3043 #disable SC3043: In POSIX sh, local is undefined.

View File

@ -3,13 +3,9 @@
# #
<p align="center"> <p align="center">
<picture> <img src="https://raw.githubusercontent.com/pi-hole/graphics/refs/heads/master/Vortex/vortex_with_text.svg" alt="Pi-hole website" width="168" height="270">
<source media="(prefers-color-scheme: dark)" srcset="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_darkmode.png"> <br>
<source media="(prefers-color-scheme: light)" srcset="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_lightmode.png"> <strong>Network-wide ad blocking via your own Linux hardware</strong>
<img src="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_lightmode.png" width="168" height="270" alt="Pi-hole website">
</picture>
<br>
<strong>Network-wide ad blocking via your own Linux hardware</strong>
</p> </p>
<!-- markdownlint-enable MD033 --> <!-- markdownlint-enable MD033 -->
@ -132,7 +128,10 @@ Some of the statistics you can integrate include:
- Queries cached - Queries cached
- Unique clients - Unique clients
Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863). Access the API using:
- your browser: http://pi.hole/api/docs
- `curl`: `curl --connect-timeout 2 -ks "https://pi.hole/api/stats/summary" -H "Accept: application/json"`;
- the command line - examples: `pihole api config/webserver/port` or `pihole api stats/summary`.
### The Command-Line Interface ### The Command-Line Interface

View File

@ -1,10 +1,12 @@
#!/usr/bin/env sh
# shellcheck disable=SC2034 # Disable warning about unused variables
# Determine if terminal is capable of showing colors # Determine if terminal is capable of showing colors
if ([ -t 1 ] && [ $(tput colors) -ge 8 ]) || [ "${WEBCALL}" ]; then # When COL_TABLE is sourced via gravity invoked by FTL, FORCE_COLOR is set to true
if { [ -t 1 ] && [ "$(tput colors)" -ge 8 ]; } || [ "${FORCE_COLOR}" ]; then
# Bold and underline may not show up on all clients # Bold and underline may not show up on all clients
# If something MUST be emphasized, use both # If something MUST be emphasized, use both
COL_BOLD='' COL_BOLD=''
COL_ULINE=''
COL_NC='' COL_NC=''
COL_GRAY='' COL_GRAY=''
COL_RED='' COL_RED=''
@ -16,8 +18,6 @@ if ([ -t 1 ] && [ $(tput colors) -ge 8 ]) || [ "${WEBCALL}" ]; then
else else
# Provide empty variables for `set -u` # Provide empty variables for `set -u`
COL_BOLD="" COL_BOLD=""
COL_ULINE=""
COL_NC="" COL_NC=""
COL_GRAY="" COL_GRAY=""
COL_RED="" COL_RED=""
@ -28,22 +28,8 @@ else
COL_CYAN="" COL_CYAN=""
fi fi
# Deprecated variables
COL_WHITE="${COL_BOLD}"
COL_BLACK="${COL_NC}"
COL_LIGHT_BLUE="${COL_BLUE}"
COL_LIGHT_GREEN="${COL_GREEN}"
COL_LIGHT_CYAN="${COL_CYAN}"
COL_LIGHT_RED="${COL_RED}"
COL_URG_RED="${COL_RED}${COL_BOLD}${COL_ULINE}"
COL_LIGHT_PURPLE="${COL_PURPLE}"
COL_BROWN="${COL_YELLOW}"
COL_LIGHT_GRAY="${COL_GRAY}"
COL_DARK_GRAY="${COL_GRAY}"
TICK="[${COL_GREEN}✓${COL_NC}]" TICK="[${COL_GREEN}✓${COL_NC}]"
CROSS="[${COL_RED}✗${COL_NC}]" CROSS="[${COL_RED}✗${COL_NC}]"
INFO="[i]" INFO="[i]"
QST="[?]" QST="[?]"
DONE="${COL_GREEN} done!${COL_NC}"
OVER="\\r" OVER="\\r"

View File

@ -1,5 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC3043 #https://github.com/koalaman/shellcheck/wiki/SC3043#exceptions
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net) # (c) 2017 Pi-hole, LLC (https://pi-hole.net)
@ -20,13 +19,20 @@
TestAPIAvailability() { TestAPIAvailability() {
local chaos_api_list authResponse authStatus authData apiAvailable DNSport
# as we are running locally, we can get the port value from FTL directly # as we are running locally, we can get the port value from FTL directly
local chaos_api_list availabilityResponse PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source=./advanced/Scripts/utils.sh
. "${utilsfile}"
DNSport=$(getFTLConfigValue dns.port)
# Query the API URLs from FTL using CHAOS TXT local.api.ftl # Query the API URLs from FTL using CHAOS TXT local.api.ftl
# The result is a space-separated enumeration of full URLs # The result is a space-separated enumeration of full URLs
# e.g., "http://localhost:80/api/" "https://localhost:443/api/" # e.g., "http://localhost:80/api/" "https://localhost:443/api/"
chaos_api_list="$(dig +short chaos txt local.api.ftl @127.0.0.1)" chaos_api_list="$(dig +short -p "${DNSport}" chaos txt local.api.ftl @127.0.0.1)"
# If the query was not successful, the variable is empty # If the query was not successful, the variable is empty
if [ -z "${chaos_api_list}" ]; then if [ -z "${chaos_api_list}" ]; then
@ -48,39 +54,50 @@ TestAPIAvailability() {
API_URL="${API_URL%\"}" API_URL="${API_URL%\"}"
API_URL="${API_URL#\"}" API_URL="${API_URL#\"}"
# Test if the API is available at this URL # Test if the API is available at this URL, include delimiter for ease in splitting payload
availabilityResponse=$(curl -skS -o /dev/null -w "%{http_code}" "${API_URL}auth") authResponse=$(curl --connect-timeout 2 -skS -w ">>%{http_code}" "${API_URL}auth")
# authStatus is the response http_code, eg. 200, 401.
# Shell parameter expansion, remove everything up to and including the >> delim
authStatus=${authResponse#*>>}
# data is everything from response
# Shell parameter expansion, remove the >> delim and everything after
authData=${authResponse%>>*}
# Test if http status code was 200 (OK) or 401 (authentication required) # Test if http status code was 200 (OK) or 401 (authentication required)
if [ ! "${availabilityResponse}" = 200 ] && [ ! "${availabilityResponse}" = 401 ]; then if [ "${authStatus}" = 200 ]; then
# API is not available at this port/protocol combination # API is available without authentication
API_PORT="" apiAvailable=true
else needAuth=false
# API is available at this URL combination
if [ "${availabilityResponse}" = 200 ]; then
# API is available without authentication
needAuth=false
fi
break break
fi
# Remove the first URL from the list elif [ "${authStatus}" = 401 ]; then
local last_api_list # API is available with authentication
last_api_list="${chaos_api_list}" apiAvailable=true
chaos_api_list="${chaos_api_list#* }" needAuth=true
# Check if 2FA is required
needTOTP=$(echo "${authData}"| jq --raw-output .session.totp 2>/dev/null)
break
# If the list did not change, we are at the last element else
if [ "${last_api_list}" = "${chaos_api_list}" ]; then # API is not available at this port/protocol combination
# Remove the last element apiAvailable=false
chaos_api_list="" # Remove the first URL from the list
local last_api_list
last_api_list="${chaos_api_list}"
chaos_api_list="${chaos_api_list#* }"
# If the list did not change, we are at the last element
if [ "${last_api_list}" = "${chaos_api_list}" ]; then
# Remove the last element
chaos_api_list=""
fi
fi fi
done done
# if API_PORT is empty, no working API port was found # if apiAvailable is false, no working API was found
if [ -n "${API_PORT}" ]; then if [ "${apiAvailable}" = false ]; then
echo "API not available at: ${API_URL}" echo "API not available. Please check FTL.log"
echo "Exiting." echo "Exiting."
exit 1 exit 1
fi fi
@ -108,22 +125,51 @@ LoginAPI() {
echo "API Authentication: Trying to use CLI password" echo "API Authentication: Trying to use CLI password"
fi fi
# Try to authenticate using the CLI password # If we can read the CLI password, we can skip 2FA even when it's required otherwise
Authentication "${1}" needTOTP=false
elif [ "${1}" = "verbose" ]; then elif [ "${1}" = "verbose" ]; then
echo "API Authentication: CLI password not available" echo "API Authentication: CLI password not available"
fi fi
if [ -z "${password}" ]; then
# no password read from CLI file
echo "Please enter your password:"
# secretly read the password
secretRead; printf '\n'
fi
if [ "${needTOTP}" = true ]; then
# 2FA required
echo "Please enter the correct second factor."
echo "(Can be any number if you used the app password)"
read -r totp
fi
# If this did not work, ask the user for the password # Try to authenticate using the supplied password (CLI file or user input) and TOTP
while [ "${validSession}" = false ] || [ -z "${validSession}" ] ; do Authentication "${1}"
# Try to login again until the session is valid
while [ ! "${validSession}" = true ] ; do
echo "Authentication failed. Please enter your Pi-hole password" echo "Authentication failed. Please enter your Pi-hole password"
# Print the error message if there is one
if [ ! "${sessionError}" = "null" ] && [ "${1}" = "verbose" ]; then
echo "Error: ${sessionError}"
fi
# Print the session message if there is one
if [ ! "${sessionMessage}" = "null" ] && [ "${1}" = "verbose" ]; then
echo "Error: ${sessionMessage}"
fi
# secretly read the password # secretly read the password
secretRead; printf '\n' secretRead; printf '\n'
if [ "${needTOTP}" = true ]; then
echo "Please enter the correct second factor:"
echo "(Can be any number if you used the app password)"
read -r totp
fi
# Try to authenticate again # Try to authenticate again
Authentication "${1}" Authentication "${1}"
done done
@ -131,23 +177,27 @@ LoginAPI() {
} }
Authentication() { Authentication() {
sessionResponse="$(curl -skS -X POST "${API_URL}auth" --user-agent "Pi-hole cli " --data "{\"password\":\"${password}\"}" )" sessionResponse="$(curl --connect-timeout 2 -skS -X POST "${API_URL}auth" --user-agent "Pi-hole cli" --data "{\"password\":\"${password}\", \"totp\":${totp:-null}}" )"
if [ -z "${sessionResponse}" ]; then if [ -z "${sessionResponse}" ]; then
echo "No response from FTL server. Please check connectivity" echo "No response from FTL server. Please check connectivity"
exit 1 exit 1
fi fi
# obtain validity and session ID from session response # obtain validity, session ID and sessionMessage from session response
validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null) validSession=$(echo "${sessionResponse}"| jq .session.valid 2>/dev/null)
SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null) SID=$(echo "${sessionResponse}"| jq --raw-output .session.sid 2>/dev/null)
sessionMessage=$(echo "${sessionResponse}"| jq --raw-output .session.message 2>/dev/null)
if [ "${1}" = "verbose" ]; then
if [ "${validSession}" = true ]; then # obtain the error message from the session response
echo "API Authentication: ${COL_GREEN}Success${COL_NC}" sessionError=$(echo "${sessionResponse}"| jq --raw-output .error.message 2>/dev/null)
else
echo "API Authentication: ${COL_RED}Failed${COL_NC}" if [ "${1}" = "verbose" ]; then
if [ "${validSession}" = true ]; then
echo "API Authentication: ${COL_GREEN}Success${COL_NC}"
else
echo "API Authentication: ${COL_RED}Failed${COL_NC}"
fi
fi fi
fi
} }
LogoutAPI() { LogoutAPI() {
@ -185,7 +235,7 @@ GetFTLData() {
# return only the data # return only the data
if [ "${status}" = 200 ]; then if [ "${status}" = 200 ]; then
# response OK # response OK
echo "${data}" printf %s "${data}"
else else
# connection lost # connection lost
echo "${status}" echo "${status}"
@ -259,14 +309,23 @@ secretRead() {
} }
apiFunc() { apiFunc() {
local data response status status_col local data response status status_col verbosity
# Define if the output will be silent (default) or verbose
verbosity="silent"
if [ "$1" = "verbose" ]; then
verbosity="verbose"
shift
fi
# Authenticate with the API # Authenticate with the API
LoginAPI verbose LoginAPI "${verbosity}"
echo ""
echo "Requesting: ${COL_PURPLE}GET ${COL_CYAN}${API_URL}${COL_YELLOW}$1${COL_NC}" if [ "${verbosity}" = "verbose" ]; then
echo "" echo ""
echo "Requesting: ${COL_PURPLE}GET ${COL_CYAN}${API_URL}${COL_YELLOW}$1${COL_NC}"
echo ""
fi
# Get the data from the API # Get the data from the API
response=$(GetFTLData "$1" raw) response=$(GetFTLData "$1" raw)
@ -283,11 +342,18 @@ apiFunc() {
else else
status_col="${COL_RED}" status_col="${COL_RED}"
fi fi
echo "Status: ${status_col}${status}${COL_NC}"
# Only print the status in verbose mode or if the status is not 200
if [ "${verbosity}" = "verbose" ] || [ "${status}" != 200 ]; then
echo "Status: ${status_col}${status}${COL_NC}"
fi
# Output the data. Format it with jq if available and data is actually JSON. # Output the data. Format it with jq if available and data is actually JSON.
# Otherwise just print it # Otherwise just print it
echo "Data:" if [ "${verbosity}" = "verbose" ]; then
echo "Data:"
fi
if command -v jq >/dev/null && echo "${data}" | jq . >/dev/null 2>&1; then if command -v jq >/dev/null && echo "${data}" | jq . >/dev/null 2>&1; then
echo "${data}" | jq . echo "${data}" | jq .
else else
@ -295,5 +361,5 @@ apiFunc() {
fi fi
# Delete the session # Delete the session
LogoutAPI verbose LogoutAPI "${verbosity}"
} }

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2019 Pi-hole, LLC (https://pi-hole.net) # (c) 2019 Pi-hole, LLC (https://pi-hole.net)
@ -13,9 +13,8 @@
readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity" readonly scriptPath="/etc/.pihole/advanced/Scripts/database_migration/gravity"
upgrade_gravityDB(){ upgrade_gravityDB(){
local database piholeDir version local database version
database="${1}" database="${1}"
piholeDir="${2}"
# Exit early if the database does not exist (e.g. in CI tests) # Exit early if the database does not exist (e.g. in CI tests)
if [[ ! -f "${database}" ]]; then if [[ ! -f "${database}" ]]; then

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net) # (c) 2017 Pi-hole, LLC (https://pi-hole.net)
@ -12,9 +11,11 @@
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
readonly utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" readonly utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source="./advanced/Scripts/utils.sh"
source "${utilsfile}" source "${utilsfile}"
readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh" readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh"
# shellcheck source="./advanced/Scripts/api.sh"
source "${apifile}" source "${apifile}"
# Determine database location # Determine database location
@ -39,6 +40,7 @@ typeId=""
comment="" comment=""
colfile="/opt/pihole/COL_TABLE" colfile="/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/COL_TABLE"
source ${colfile} source ${colfile}
helpFunc() { helpFunc() {

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2019 Pi-hole, LLC (https://pi-hole.net) # (c) 2019 Pi-hole, LLC (https://pi-hole.net)
@ -12,11 +11,13 @@
coltable="/opt/pihole/COL_TABLE" coltable="/opt/pihole/COL_TABLE"
if [[ -f ${coltable} ]]; then if [[ -f ${coltable} ]]; then
# shellcheck source="./advanced/Scripts/COL_TABLE"
source ${coltable} source ${coltable}
fi fi
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source=./advanced/Scripts/utils.sh
source "${utilsfile}" source "${utilsfile}"
# Determine database location # Determine database location

View File

@ -10,6 +10,7 @@
readonly PI_HOLE_FILES_DIR="/etc/.pihole" readonly PI_HOLE_FILES_DIR="/etc/.pihole"
SKIP_INSTALL="true" SKIP_INSTALL="true"
# shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# webInterfaceGitUrl set in basic-install.sh # webInterfaceGitUrl set in basic-install.sh
@ -25,7 +26,7 @@ source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
warning1() { warning1() {
echo " Please note that changing branches severely alters your Pi-hole subsystems" 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 " 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}" echo -e " ${COL_RED}This feature is NOT supported unless a Pi-hole developer explicitly asks!${COL_NC}"
read -r -p " Have you read and understood this? [y/N] " response read -r -p " Have you read and understood this? [y/N] " response
case "${response}" in case "${response}" in
[yY][eE][sS]|[yY]) [yY][eE][sS]|[yY])
@ -54,19 +55,19 @@ checkout() {
# This is unlikely # This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e " ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!" echo -e " ${COL_RED}Error: Core Pi-hole repo is missing from system!"
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1; exit 1;
fi fi
if ! is_repo "${webInterfaceDir}" ; then if ! is_repo "${webInterfaceDir}" ; then
echo -e " ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!" echo -e " ${COL_RED}Error: Web Admin repo is missing from system!"
echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}" echo -e " Please re-run install script from https://github.com/pi-hole/pi-hole${COL_NC}"
exit 1; exit 1;
fi fi
if [[ -z "${1}" ]]; then if [[ -z "${1}" ]]; then
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC}" echo -e " ${COL_RED}Invalid option${COL_NC}"
echo -e " Try 'pihole checkout --help' for more information." echo -e " Try 'pihole checkout --help' for more information."
exit 1 exit 1
fi fi
@ -109,7 +110,7 @@ checkout() {
echo -e "${OVER} ${CROSS} $str" echo -e "${OVER} ${CROSS} $str"
exit 1 exit 1
fi fi
corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}")) mapfile -t corebranches < <(get_available_branches "${PI_HOLE_FILES_DIR}")
if [[ "${corebranches[*]}" == *"master"* ]]; then if [[ "${corebranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str" echo -e "${OVER} ${TICK} $str"
@ -136,7 +137,7 @@ checkout() {
echo -e "${OVER} ${CROSS} $str" echo -e "${OVER} ${CROSS} $str"
exit 1 exit 1
fi fi
webbranches=($(get_available_branches "${webInterfaceDir}")) mapfile -t webbranches < <(get_available_branches "${webInterfaceDir}")
if [[ "${webbranches[*]}" == *"master"* ]]; then if [[ "${webbranches[*]}" == *"master"* ]]; then
echo -e "${OVER} ${TICK} $str" echo -e "${OVER} ${TICK} $str"
@ -167,7 +168,7 @@ checkout() {
# Check if requested branch is available # Check if requested branch is available
echo -e " ${INFO} Checking for availability of branch ${COL_CYAN}${2}${COL_NC} on GitHub" echo -e " ${INFO} Checking for availability of branch ${COL_CYAN}${2}${COL_NC} on GitHub"
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -) ) mapfile -t ftlbranches < <(git ls-remote https://github.com/pi-hole/ftl | grep "refs/heads" | cut -d'/' -f3- -)
# If returned array is empty -> connectivity issue # If returned array is empty -> connectivity issue
if [[ ${#ftlbranches[@]} -eq 0 ]]; then if [[ ${#ftlbranches[@]} -eq 0 ]]; then
echo -e " ${CROSS} Unable to fetch branches from GitHub. Please check your Internet connection and try again later." echo -e " ${CROSS} Unable to fetch branches from GitHub. Please check your Internet connection and try again later."
@ -209,13 +210,15 @@ checkout() {
# Update local and remote versions via updatechecker # Update local and remote versions via updatechecker
/opt/pihole/updatecheck.sh /opt/pihole/updatecheck.sh
else else
if [ $? -eq 1 ]; then local status
status=$?
if [ $status -eq 1 ]; then
# Binary for requested branch is not available, may still be # Binary for requested branch is not available, may still be
# int he process of being built or CI build job failed # int he process of being built or CI build job failed
printf " %b Binary for requested branch is not available, please try again later.\\n" ${CROSS} printf " %b Binary for requested branch is not available, please try again later.\\n" "${CROSS}"
printf " If the issue persists, please contact Pi-hole Support and ask them to re-generate the binary.\\n" printf " If the issue persists, please contact Pi-hole Support and ask them to re-generate the binary.\\n"
exit 1 exit 1
elif [ $? -eq 2 ]; then elif [ $status -eq 2 ]; then
printf " %b Unable to download from ftl.pi-hole.net. Please check your Internet connection and try again later.\\n" "${CROSS}" printf " %b Unable to download from ftl.pi-hole.net. Please check your Internet connection and try again later.\\n" "${CROSS}"
exit 1 exit 1
else else
@ -235,7 +238,7 @@ checkout() {
if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then
exit 0 exit 0
else else
echo -e " ${COL_LIGHT_RED} Error: Unable to complete update, please contact support${COL_NC}" echo -e " ${COL_RED} Error: Unable to complete update, please contact support${COL_NC}"
exit 1 exit 1
fi fi
fi fi

View File

@ -8,7 +8,6 @@
# This file is copyright under the latest version of the EUPL. # This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
# shellcheck source=/dev/null
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status # -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 # -u a reference to any variable you haven't previously defined
@ -27,6 +26,7 @@ PIHOLE_COLTABLE_FILE="${PIHOLE_SCRIPTS_DIRECTORY}/COL_TABLE"
# These provide the colors we need for making the log more readable # These provide the colors we need for making the log more readable
if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then if [[ -f ${PIHOLE_COLTABLE_FILE} ]]; then
# shellcheck source=./advanced/Scripts/COL_TABLE
source ${PIHOLE_COLTABLE_FILE} source ${PIHOLE_COLTABLE_FILE}
else else
COL_NC='\e[0m' # No Color COL_NC='\e[0m' # No Color
@ -41,7 +41,7 @@ else
#OVER="\r\033[K" #OVER="\r\033[K"
fi fi
# shellcheck disable=SC1091 # shellcheck source=/dev/null
. /etc/pihole/versions . /etc/pihole/versions
# Read the value of an FTL config key. The value is printed to stdout. # Read the value of an FTL config key. The value is printed to stdout.
@ -213,7 +213,7 @@ 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
if [ ${local_version} ]; then if [ "${local_version}" ]; then
log_write "${TICK} Version: ${local_version}" log_write "${TICK} Version: ${local_version}"
elif [ -n "${DOCKER_VERSION}" ]; then elif [ -n "${DOCKER_VERSION}" ]; then
log_write "${TICK} Version: Pi-hole Docker Container ${COL_BOLD}${DOCKER_VERSION}${COL_NC}" log_write "${TICK} Version: Pi-hole Docker Container ${COL_BOLD}${DOCKER_VERSION}${COL_NC}"
@ -296,91 +296,12 @@ check_component_versions() {
check_ftl_version check_ftl_version
} }
os_check() {
# This function gets a list of supported OS versions from a TXT record at versions.pi-hole.net
# and determines whether or not the script is running on one of those systems
local remote_os_domain valid_os valid_version detected_os detected_version cmdResult digReturnCode response
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
cmdResult="$(dig -4 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
#Get the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
# Extract dig response
response="${cmdResult%%$'\n'*}"
if [ "${digReturnCode}" -ne 0 ]; then
log_write "${INFO} Distro: ${detected_os^}"
log_write "${INFO} Version: ${detected_version}"
log_write "${CROSS} dig IPv4 return code: ${COL_RED}${digReturnCode}${COL_NC}"
log_write "${CROSS} dig response: ${response}"
log_write "${INFO} Retrying via IPv6"
cmdResult="$(dig -6 +short -t txt "${remote_os_domain}" @ns1.pi-hole.net 2>&1; echo $?)"
#Get the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
# Extract dig response
response="${cmdResult%%$'\n'*}"
fi
# If also no success via IPv6
if [ "${digReturnCode}" -ne 0 ]; then
log_write "${CROSS} dig IPv6 return code: ${COL_RED}${digReturnCode}${COL_NC}"
log_write "${CROSS} dig response: ${response}"
log_write "${CROSS} Error: ${COL_RED}dig command failed - Unable to check OS${COL_NC}"
else
IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"')
for distro_and_versions in "${supportedOS[@]}"
do
distro_part="${distro_and_versions%%=*}"
versions_part="${distro_and_versions##*=}"
if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then
valid_os=true
IFS="," read -r -a supportedVer <<<"${versions_part}"
for version in "${supportedVer[@]}"
do
if [[ "${detected_version}" =~ $version ]]; then
valid_version=true
break
fi
done
break
fi
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
if [ "$valid_os" = true ]; then
log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}"
if [ "$valid_version" = true ]; then
log_write "${TICK} Version: ${COL_GREEN}${detected_version}${COL_NC}"
finalmsg="${TICK} ${COL_GREEN}Distro and version supported${COL_NC}"
else
log_write "${CROSS} Version: ${COL_RED}${detected_version}${COL_NC}"
finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is supported but version ${detected_version} is currently unsupported ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
fi
else
log_write "${CROSS} Distro: ${COL_RED}${detected_os^}${COL_NC}"
finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is not a supported distro ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
fi
# Print dig response and the final check result
log_write "${TICK} dig return code: ${COL_GREEN}${digReturnCode}${COL_NC}"
log_write "${INFO} dig response: ${response}"
log_write "${finalmsg}"
fi
}
diagnose_operating_system() { diagnose_operating_system() {
# error message in a variable so we can easily modify it later (or reuse it) # error message in a variable so we can easily modify it later (or reuse it)
local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues." local error_msg="Distribution unknown -- most likely you are on an unsupported platform and may run into issues."
local detected_os
local detected_version
# Display the current test that is running # Display the current test that is running
echo_current_diagnostic "Operating system" echo_current_diagnostic "Operating system"
@ -389,8 +310,13 @@ diagnose_operating_system() {
# If there is a /etc/*release file, it's probably a supported operating system, so we can # If there is a /etc/*release file, it's probably a supported operating system, so we can
if ls /etc/*release 1> /dev/null 2>&1; then if ls /etc/*release 1> /dev/null 2>&1; then
# display the attributes to the user from the function made earlier # display the attributes to the user
os_check
detected_os=$(grep "\bID\b" /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
log_write "${INFO} Distro: ${detected_os^}"
log_write "${INFO} Version: ${detected_version}"
else else
# If it doesn't exist, it's not a system we currently support and link to FAQ # 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})" log_write "${CROSS} ${COL_RED}${error_msg}${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS})"
@ -441,7 +367,7 @@ check_firewalld() {
# test common required service ports # test common required service ports
local firewalld_enabled_services local firewalld_enabled_services
firewalld_enabled_services=$(firewall-cmd --list-services) firewalld_enabled_services=$(firewall-cmd --list-services)
local firewalld_expected_services=("http" "dns" "dhcp" "dhcpv6") local firewalld_expected_services=("http" "https" "dns" "dhcp" "dhcpv6" "ntp")
for i in "${firewalld_expected_services[@]}"; do for i in "${firewalld_expected_services[@]}"; do
if [[ "${firewalld_enabled_services}" =~ ${i} ]]; then if [[ "${firewalld_enabled_services}" =~ ${i} ]]; then
log_write "${TICK} ${COL_GREEN} Allow Service: ${i}${COL_NC}"; log_write "${TICK} ${COL_GREEN} Allow Service: ${i}${COL_NC}";
@ -462,14 +388,6 @@ check_firewalld() {
else else
log_write "${CROSS} ${COL_RED} Local Interface Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})" log_write "${CROSS} ${COL_RED} Local Interface Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi fi
# check FTL custom zone port: 4711
local firewalld_ftl_zone_ports
firewalld_ftl_zone_ports=$(firewall-cmd --zone=ftl --list-ports)
if [[ "${firewalld_ftl_zone_ports}" =~ "4711/tcp" ]]; then
log_write "${TICK} ${COL_GREEN} FTL Port 4711/tcp Detected${COL_NC}";
else
log_write "${CROSS} ${COL_RED} FTL Port 4711/tcp Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi
else else
log_write "${CROSS} ${COL_RED}FTL Custom Zone Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})" log_write "${CROSS} ${COL_RED}FTL Custom Zone Not Detected${COL_NC} (${FAQ_HARDWARE_REQUIREMENTS_FIREWALLD})"
fi fi
@ -488,7 +406,9 @@ run_and_print_command() {
local output local output
output=$(${cmd} 2>&1) output=$(${cmd} 2>&1)
# If the command was successful, # If the command was successful,
if [[ $? -eq 0 ]]; then local return_code
return_code=$?
if [[ "${return_code}" -eq 0 ]]; then
# show the output # show the output
log_write "${output}" log_write "${output}"
else else
@ -569,16 +489,25 @@ ping_gateway() {
ping_ipv4_or_ipv6 "${protocol}" ping_ipv4_or_ipv6 "${protocol}"
# Check if we are using IPv4 or IPv6 # Check if we are using IPv4 or IPv6
# Find the default gateways using IPv4 or IPv6 # Find the default gateways using IPv4 or IPv6
local gateway gateway_addr gateway_iface local gateway gateway_addr gateway_iface default_route
log_write "${INFO} Default IPv${protocol} gateway(s):" log_write "${INFO} Default IPv${protocol} gateway(s):"
while IFS= read -r gateway; do while IFS= read -r default_route; do
log_write " $(cut -d ' ' -f 3 <<< "${gateway}")%$(cut -d ' ' -f 5 <<< "${gateway}")" gateway_addr=$(jq -r '.gateway' <<< "${default_route}")
done < <(ip -"${protocol}" route | grep default) gateway_iface=$(jq -r '.dev' <<< "${default_route}")
log_write " ${gateway_addr}%${gateway_iface}"
done < <(ip -j -"${protocol}" route | jq -c '.[] | select(.dst == "default")')
# Find the first default route
default_route=$(ip -j -"${protocol}" route show default)
if echo "$default_route" | grep 'gateway' | grep -q 'dev'; then
gateway_addr=$(echo "$default_route" | jq -r -c '.[0].gateway')
gateway_iface=$(echo "$default_route" | jq -r -c '.[0].dev')
else
log_write " Unable to determine gateway address for IPv${protocol}"
fi
gateway_addr=$(ip -"${protocol}" route | grep default | cut -d ' ' -f 3 | head -n 1)
gateway_iface=$(ip -"${protocol}" route | grep default | cut -d ' ' -f 5 | head -n 1)
# If there was at least one gateway # If there was at least one gateway
if [ -n "${gateway_addr}" ]; then if [ -n "${gateway_addr}" ]; then
# Append the interface to the gateway address if it is a link-local address # Append the interface to the gateway address if it is a link-local address
@ -933,7 +862,6 @@ parse_file() {
# Get the lines that are in the file(s) and store them in an array for parsing later # Get the lines that are in the file(s) and store them in an array for parsing later
local file_info local file_info
if [[ -f "$filename" ]]; then if [[ -f "$filename" ]]; then
#shellcheck disable=SC2016
IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )' IFS=$'\r\n' command eval 'file_info=( $(cat "${filename}") )'
else else
read -r -a file_info <<< "$filename" read -r -a file_info <<< "$filename"

View File

@ -9,10 +9,12 @@
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
colfile="/opt/pihole/COL_TABLE" colfile="/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/COL_TABLE"
source ${colfile} source ${colfile}
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source="./advanced/Scripts/utils.sh"
source "${utilsfile}" source "${utilsfile}"
# In case we're running at the same time as a system logrotate, use a # In case we're running at the same time as a system logrotate, use a
@ -35,6 +37,46 @@ FTLFILE=$(getFTLConfigValue "files.log.ftl")
if [ -z "$FTLFILE" ]; then if [ -z "$FTLFILE" ]; then
FTLFILE="/var/log/pihole/FTL.log" FTLFILE="/var/log/pihole/FTL.log"
fi fi
WEBFILE=$(getFTLConfigValue "files.log.webserver")
if [ -z "$WEBFILE" ]; then
WEBFILE="/var/log/pihole/webserver.log"
fi
# Helper function to handle log rotation for a single file
rotate_log() {
# This function copies x.log over to x.log.1
# and then empties x.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)
local logfile="$1"
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Rotating ${logfile} ..."
fi
cp -p "${logfile}" "${logfile}.1"
echo " " > "${logfile}"
chmod 640 "${logfile}"
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Rotated ${logfile} ..."
fi
}
# Helper function to handle log flushing for a single file
flush_log() {
local logfile="$1"
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing ${logfile} ..."
fi
echo " " > "${logfile}"
chmod 640 "${logfile}"
if [ -f "${logfile}.1" ]; then
echo " " > "${logfile}.1"
chmod 640 "${logfile}.1"
fi
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Flushed ${logfile} ..."
fi
}
if [[ "$*" == *"once"* ]]; then if [[ "$*" == *"once"* ]]; then
# Nightly logrotation # Nightly logrotation
@ -46,62 +88,16 @@ if [[ "$*" == *"once"* ]]; then
fi fi
/usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate /usr/sbin/logrotate --force --state "${STATEFILE}" /etc/pihole/logrotate
else else
# Copy pihole.log over to pihole.log.1 # Handle rotation for each log file
# and empty out pihole.log rotate_log "${LOGFILE}"
# Note that moving the file is not an option, as rotate_log "${FTLFILE}"
# dnsmasq would happily continue writing into the rotate_log "${WEBFILE}"
# moved file (it will have the same file handler)
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Rotating ${LOGFILE} ..."
fi
cp -p "${LOGFILE}" "${LOGFILE}.1"
echo " " > "${LOGFILE}"
chmod 640 "${LOGFILE}"
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Rotated ${LOGFILE} ..."
fi
# Copy FTL.log over to FTL.log.1
# and empty out FTL.log
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Rotating ${FTLFILE} ..."
fi
cp -p "${FTLFILE}" "${FTLFILE}.1"
echo " " > "${FTLFILE}"
chmod 640 "${FTLFILE}"
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Rotated ${FTLFILE} ..."
fi
fi fi
else else
# Manual flushing # Manual flushing
flush_log "${LOGFILE}"
# Flush both pihole.log and pihole.log.1 (if existing) flush_log "${FTLFILE}"
if [[ "$*" != *"quiet"* ]]; then flush_log "${WEBFILE}"
echo -ne " ${INFO} Flushing ${LOGFILE} ..."
fi
echo " " > "${LOGFILE}"
chmod 640 "${LOGFILE}"
if [ -f "${LOGFILE}.1" ]; then
echo " " > "${LOGFILE}.1"
chmod 640 "${LOGFILE}.1"
fi
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Flushed ${LOGFILE} ..."
fi
# Flush both FTL.log and FTL.log.1 (if existing)
if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing ${FTLFILE} ..."
fi
echo " " > "${FTLFILE}"
chmod 640 "${FTLFILE}"
if [ -f "${FTLFILE}.1" ]; then
echo " " > "${FTLFILE}.1"
chmod 640 "${FTLFILE}.1"
fi
if [[ "$*" != *"quiet"* ]]; then
echo -e "${OVER} ${TICK} Flushed ${FTLFILE} ..."
fi
if [[ "$*" != *"quiet"* ]]; then if [[ "$*" != *"quiet"* ]]; then
echo -ne " ${INFO} Flushing database, DNS resolution temporarily unavailable ..." echo -ne " ${INFO} Flushing database, DNS resolution temporarily unavailable ..."

View File

@ -1,9 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC1090
# Ignore warning about `local` being undefinded in POSIX
# shellcheck disable=SC3043
# https://github.com/koalaman/shellcheck/wiki/SC3043#exceptions
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2023 Pi-hole, LLC (https://pi-hole.net) # (c) 2023 Pi-hole, LLC (https://pi-hole.net)
@ -22,9 +17,11 @@ domain=""
# Source color table # Source color table
colfile="/opt/pihole/COL_TABLE" colfile="/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/COL_TABLE"
. "${colfile}" . "${colfile}"
# Source api functions # Source api functions
# shellcheck source="./advanced/Scripts/api.sh"
. "${PI_HOLE_INSTALL_DIR}/api.sh" . "${PI_HOLE_INSTALL_DIR}/api.sh"
Help() { Help() {

View File

@ -12,26 +12,31 @@
# Variables # Variables
readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/web.git" readonly ADMIN_INTERFACE_GIT_URL="https://github.com/pi-hole/web.git"
readonly ADMIN_INTERFACE_DIR="/var/www/html/admin"
readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git" readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
readonly PI_HOLE_FILES_DIR="/etc/.pihole" readonly PI_HOLE_FILES_DIR="/etc/.pihole"
# shellcheck disable=SC2034
SKIP_INSTALL=true SKIP_INSTALL=true
# when --check-only is passed to this script, it will not perform the actual update # when --check-only is passed to this script, it will not perform the actual update
CHECK_ONLY=false CHECK_ONLY=false
# shellcheck disable=SC1090 # shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# shellcheck disable=SC1091 # shellcheck source=./advanced/Scripts/COL_TABLE
source "/opt/pihole/COL_TABLE" source "/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/utils.sh"
source "${PI_HOLE_INSTALL_DIR}/utils.sh"
# is_repo() sourced from basic-install.sh # is_repo() sourced from basic-install.sh
# make_repo() sourced from basic-install.sh # make_repo() sourced from basic-install.sh
# update_repo() source from basic-install.sh # update_repo() source from basic-install.sh
# getGitFiles() sourced from basic-install.sh # getGitFiles() sourced from basic-install.sh
# FTLcheckUpdate() sourced from basic-install.sh # FTLcheckUpdate() sourced from basic-install.sh
# getFTLConfigValue() sourced from utils.sh
# Honour configured paths for the web application.
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
readonly ADMIN_INTERFACE_DIR
GitCheckUpdateAvail() { GitCheckUpdateAvail() {
local directory local directory
@ -42,7 +47,7 @@ GitCheckUpdateAvail() {
# Fetch latest changes in this repo # Fetch latest changes in this repo
if ! git fetch --quiet origin ; then if ! git fetch --quiet origin ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Unable to update local repository. Contact Pi-hole Support.${COL_NC}" echo -e "\\n ${COL_RED}Error: Unable to update local repository. Contact Pi-hole Support.${COL_NC}"
exit 1 exit 1
fi fi
@ -71,13 +76,13 @@ GitCheckUpdateAvail() {
if [[ "${#LOCAL}" == 0 ]]; then if [[ "${#LOCAL}" == 0 ]]; then
echo -e "\\n ${COL_LIGHT_RED}Error: Local revision could not be obtained, please contact Pi-hole Support" echo -e "\\n ${COL_RED}Error: Local revision could not be obtained, please contact Pi-hole Support"
echo -e " Additional debugging output:${COL_NC}" echo -e " Additional debugging output:${COL_NC}"
git status git status
exit 1 exit 1
fi fi
if [[ "${#REMOTE}" == 0 ]]; then if [[ "${#REMOTE}" == 0 ]]; then
echo -e "\\n ${COL_LIGHT_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support" echo -e "\\n ${COL_RED}Error: Remote revision could not be obtained, please contact Pi-hole Support"
echo -e " Additional debugging output:${COL_NC}" echo -e " Additional debugging output:${COL_NC}"
git status git status
exit 1 exit 1
@ -98,7 +103,7 @@ GitCheckUpdateAvail() {
} }
main() { main() {
local basicError="\\n ${COL_LIGHT_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}" local basicError="\\n ${COL_RED}Unable to complete update, please contact Pi-hole Support${COL_NC}"
local core_update local core_update
local web_update local web_update
local FTL_update local FTL_update
@ -107,8 +112,6 @@ 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
@ -117,7 +120,7 @@ main() {
# This is unlikely # This is unlikely
if ! is_repo "${PI_HOLE_FILES_DIR}" ; then if ! is_repo "${PI_HOLE_FILES_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Core Pi-hole repo is missing from system!" echo -e "\\n ${COL_RED}Error: Core Pi-hole repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}" echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1; exit 1;
fi fi
@ -129,11 +132,11 @@ main() {
echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}" echo -e " ${INFO} Pi-hole Core:\\t${COL_YELLOW}update available${COL_NC}"
else else
core_update=false core_update=false
echo -e " ${INFO} Pi-hole Core:\\t${COL_LIGHT_GREEN}up to date${COL_NC}" echo -e " ${INFO} Pi-hole Core:\\t${COL_GREEN}up to date${COL_NC}"
fi fi
if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then if ! is_repo "${ADMIN_INTERFACE_DIR}" ; then
echo -e "\\n ${COL_LIGHT_RED}Error: Web Admin repo is missing from system!" echo -e "\\n ${COL_RED}Error: Web Admin repo is missing from system!"
echo -e " Please re-run install script from https://pi-hole.net${COL_NC}" echo -e " Please re-run install script from https://pi-hole.net${COL_NC}"
exit 1; exit 1;
fi fi
@ -143,7 +146,7 @@ main() {
echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}" echo -e " ${INFO} Web Interface:\\t${COL_YELLOW}update available${COL_NC}"
else else
web_update=false web_update=false
echo -e " ${INFO} Web Interface:\\t${COL_LIGHT_GREEN}up to date${COL_NC}" echo -e " ${INFO} Web Interface:\\t${COL_GREEN}up to date${COL_NC}"
fi fi
local funcOutput local funcOutput
@ -157,17 +160,18 @@ main() {
else else
case $? in case $? in
1) 1)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_GREEN}up to date${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_GREEN}up to date${COL_NC}"
;; ;;
2) 2)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_LIGHT_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch." echo -e " ${INFO} FTL:\\t\\t${COL_RED}Branch is not available.${COL_NC}\\n\\t\\t\\tUse ${COL_GREEN}pihole checkout ftl [branchname]${COL_NC} to switch to a valid branch."
exit 1
;; ;;
3) 3)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, cannot reach download server${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, cannot reach download server${COL_NC}"
exit 1 exit 1
;; ;;
*) *)
echo -e " ${INFO} FTL:\\t\\t${COL_LIGHT_RED}Something has gone wrong, contact support${COL_NC}" echo -e " ${INFO} FTL:\\t\\t${COL_RED}Something has gone wrong, contact support${COL_NC}"
exit 1 exit 1
esac esac
FTL_update=false FTL_update=false
@ -184,7 +188,7 @@ main() {
if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then if [[ ! "${ftlBranch}" == "master" && ! "${ftlBranch}" == "development" ]]; then
# Notify user that they are on a custom branch which might mean they they are lost # Notify user that they are on a custom branch which might mean they they are lost
# behind if a branch was merged to development and got abandoned # behind if a branch was merged to development and got abandoned
printf " %b %bWarning:%b You are using FTL from a custom branch (%s) and might be missing future releases.\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}" "${ftlBranch}" printf " %b %bWarning:%b You are using FTL from a custom branch (%s) and might be missing future releases.\\n" "${INFO}" "${COL_RED}" "${COL_NC}" "${ftlBranch}"
fi fi
if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then if [[ "${core_update}" == false && "${web_update}" == false && "${FTL_update}" == false ]]; then
@ -209,7 +213,7 @@ main() {
echo "" echo ""
echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo." echo -e " ${INFO} Pi-hole Web Admin files out of date, updating local repo."
getGitFiles "${ADMIN_INTERFACE_DIR}" "${ADMIN_INTERFACE_GIT_URL}" 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'" echo -e " ${INFO} If you had made any changes in '${ADMIN_INTERFACE_DIR}', they have been stashed using 'git stash'"
fi fi
if [[ "${FTL_update}" == true ]]; then if [[ "${FTL_update}" == true ]]; then

View File

@ -39,9 +39,12 @@ function get_remote_hash() {
} }
# Source the utils file for addOrEditKeyValPair() # Source the utils file for addOrEditKeyValPair()
# shellcheck disable=SC1091 # shellcheck source="./advanced/Scripts/utils.sh"
. /opt/pihole/utils.sh . /opt/pihole/utils.sh
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
readonly ADMIN_INTERFACE_DIR
# Remove the below three legacy files if they exist # Remove the below three legacy files if they exist
rm -f "/etc/pihole/GitHubVersions" rm -f "/etc/pihole/GitHubVersions"
rm -f "/etc/pihole/localbranches" rm -f "/etc/pihole/localbranches"
@ -85,13 +88,13 @@ addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_CORE_HASH" "${GITHUB_CORE_HASH}"
# get Web versions # get Web versions
WEB_VERSION="$(get_local_version /var/www/html/admin)" WEB_VERSION="$(get_local_version "${ADMIN_INTERFACE_DIR}")"
addOrEditKeyValPair "${VERSION_FILE}" "WEB_VERSION" "${WEB_VERSION}" addOrEditKeyValPair "${VERSION_FILE}" "WEB_VERSION" "${WEB_VERSION}"
WEB_BRANCH="$(get_local_branch /var/www/html/admin)" WEB_BRANCH="$(get_local_branch "${ADMIN_INTERFACE_DIR}")"
addOrEditKeyValPair "${VERSION_FILE}" "WEB_BRANCH" "${WEB_BRANCH}" addOrEditKeyValPair "${VERSION_FILE}" "WEB_BRANCH" "${WEB_BRANCH}"
WEB_HASH="$(get_local_hash /var/www/html/admin)" WEB_HASH="$(get_local_hash "${ADMIN_INTERFACE_DIR}")"
addOrEditKeyValPair "${VERSION_FILE}" "WEB_HASH" "${WEB_HASH}" addOrEditKeyValPair "${VERSION_FILE}" "WEB_HASH" "${WEB_HASH}"
GITHUB_WEB_VERSION="$(get_remote_version web "${WEB_BRANCH}")" GITHUB_WEB_VERSION="$(get_remote_version web "${WEB_BRANCH}")"

View File

@ -1,5 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# shellcheck disable=SC3043 #https://github.com/koalaman/shellcheck/wiki/SC3043#exceptions
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net) # (c) 2017 Pi-hole, LLC (https://pi-hole.net)
@ -88,8 +87,8 @@ getFTLConfigValue(){
####################### #######################
setFTLConfigValue(){ setFTLConfigValue(){
pihole-FTL --config "${1}" "${2}" >/dev/null pihole-FTL --config "${1}" "${2}" >/dev/null
if [[ $? -eq 5 ]]; then if [ $? -eq 5 ]; then
echo -e " ${CROSS} ${1} set by environment variable. Please unset it to use this function" printf " %s %s set by environment variable. Please unset it to use this function\n" "${CROSS}" "${1}"
exit 5 exit 5
fi fi
} }

View File

@ -8,20 +8,16 @@
# This file is copyright under the latest version of the EUPL. # This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
# Ignore warning about `local` being undefinded in POSIX # Source the versions file populated by updatechecker.sh
# shellcheck disable=SC3043
# https://github.com/koalaman/shellcheck/wiki/SC3043#exceptions
# Source the versions file poupulated by updatechecker.sh
cachedVersions="/etc/pihole/versions" cachedVersions="/etc/pihole/versions"
if [ -f ${cachedVersions} ]; then if [ -f ${cachedVersions} ]; then
# shellcheck disable=SC1090 # shellcheck source=/dev/null
. "$cachedVersions" . "$cachedVersions"
else else
echo "Could not find /etc/pihole/versions. Running update now." echo "Could not find /etc/pihole/versions. Running update now."
pihole updatechecker pihole updatechecker
# shellcheck disable=SC1090 # shellcheck source=/dev/null
. "$cachedVersions" . "$cachedVersions"
fi fi

View File

@ -43,8 +43,8 @@ CREATE TABLE adlist
CREATE TABLE adlist_by_group CREATE TABLE adlist_by_group
( (
adlist_id INTEGER NOT NULL REFERENCES adlist (id), adlist_id INTEGER NOT NULL REFERENCES adlist (id) ON DELETE CASCADE,
group_id INTEGER NOT NULL REFERENCES "group" (id), group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
PRIMARY KEY (adlist_id, group_id) PRIMARY KEY (adlist_id, group_id)
); );
@ -75,8 +75,8 @@ INSERT INTO "info" VALUES('gravity_restored','false');
CREATE TABLE domainlist_by_group CREATE TABLE domainlist_by_group
( (
domainlist_id INTEGER NOT NULL REFERENCES domainlist (id), domainlist_id INTEGER NOT NULL REFERENCES domainlist (id) ON DELETE CASCADE,
group_id INTEGER NOT NULL REFERENCES "group" (id), group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
PRIMARY KEY (domainlist_id, group_id) PRIMARY KEY (domainlist_id, group_id)
); );
@ -91,8 +91,8 @@ CREATE TABLE client
CREATE TABLE client_by_group CREATE TABLE client_by_group
( (
client_id INTEGER NOT NULL REFERENCES client (id), client_id INTEGER NOT NULL REFERENCES client (id) ON DELETE CASCADE,
group_id INTEGER NOT NULL REFERENCES "group" (id), group_id INTEGER NOT NULL REFERENCES "group" (id) ON DELETE CASCADE,
PRIMARY KEY (client_id, group_id) PRIMARY KEY (client_id, group_id)
); );

View File

@ -3,7 +3,7 @@
# Source utils.sh for getFTLConfigValue() # Source utils.sh for getFTLConfigValue()
PI_HOLE_SCRIPT_DIR='/opt/pihole' PI_HOLE_SCRIPT_DIR='/opt/pihole'
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck disable=SC1090 # shellcheck source="./advanced/Scripts/utils.sh"
. "${utilsfile}" . "${utilsfile}"
# Get file paths # Get file paths

View File

@ -3,7 +3,7 @@
# Source utils.sh for getFTLConfigValue() # Source utils.sh for getFTLConfigValue()
PI_HOLE_SCRIPT_DIR='/opt/pihole' PI_HOLE_SCRIPT_DIR='/opt/pihole'
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck disable=SC1090 # shellcheck source="./advanced/Scripts/utils.sh"
. "${utilsfile}" . "${utilsfile}"
# Get file paths # Get file paths
@ -11,7 +11,11 @@ FTL_PID_FILE="$(getFTLConfigValue files.pid)"
# Ensure that permissions are set so that pihole-FTL can edit all necessary files # Ensure that permissions are set so that pihole-FTL can edit all necessary files
mkdir -p /var/log/pihole mkdir -p /var/log/pihole
chown -R pihole:pihole /etc/pihole /var/log/pihole chown -R pihole:pihole /etc/pihole/ /var/log/pihole/
# allow all users read version file (and use pihole -v)
chmod 0644 /etc/pihole/versions
# allow pihole to access subdirs in /etc/pihole (sets execution bit on dirs) # allow pihole to access subdirs in /etc/pihole (sets execution bit on dirs)
find /etc/pihole/ /var/log/pihole/ -type d -exec chmod 0755 {} + find /etc/pihole/ /var/log/pihole/ -type d -exec chmod 0755 {} +
# Set all files (except TLS-related ones) to u+rw g+r # Set all files (except TLS-related ones) to u+rw g+r
@ -26,4 +30,5 @@ chown root:root /etc/pihole/logrotate
[ -f "${FTL_PID_FILE}" ] || install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}" [ -f "${FTL_PID_FILE}" ] || install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}"
[ -f /var/log/pihole/FTL.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log [ -f /var/log/pihole/FTL.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log
[ -f /var/log/pihole/pihole.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log [ -f /var/log/pihole/pihole.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log
[ -f /var/log/pihole/webserver.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/webserver.log
[ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases [ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases

View File

@ -12,7 +12,7 @@
# Source utils.sh for getFTLConfigValue(), getFTLPID() # Source utils.sh for getFTLConfigValue(), getFTLPID()
PI_HOLE_SCRIPT_DIR="/opt/pihole" PI_HOLE_SCRIPT_DIR="/opt/pihole"
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck disable=SC1090 # shellcheck source="./advanced/Scripts/utils.sh"
. "${utilsfile}" . "${utilsfile}"
@ -57,13 +57,16 @@ start() {
stop() { stop() {
if is_running; then if is_running; then
kill "${FTL_PID}" kill "${FTL_PID}"
for i in 1 2 3 4 5; do # Give FTL 60 seconds to gracefully stop
i=1
while [ "${i}" -le 60 ]; do
if ! is_running; then if ! is_running; then
break break
fi fi
printf "." printf "."
sleep 1 sleep 1
i=$((i + 1))
done done
echo echo

View File

@ -28,7 +28,7 @@ ExecReload=/bin/kill -HUP $MAINPID
ExecStopPost=/opt/pihole/pihole-FTL-poststop.sh ExecStopPost=/opt/pihole/pihole-FTL-poststop.sh
# Use graceful shutdown with a reasonable timeout # Use graceful shutdown with a reasonable timeout
TimeoutStopSec=10s TimeoutStopSec=60s
# Make /usr, /boot, /etc and possibly some more folders read-only... # Make /usr, /boot, /etc and possibly some more folders read-only...
ProtectSystem=full ProtectSystem=full

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) Pi-hole (https://pi-hole.net) # (c) Pi-hole (https://pi-hole.net)
@ -49,7 +48,6 @@ Google (ECS, DNSSEC);8.8.8.8;8.8.4.4;2001:4860:4860:0:0:0:0:8888;2001:4860:4860:
OpenDNS (ECS, DNSSEC);208.67.222.222;208.67.220.220;2620:119:35::35;2620:119:53::53 OpenDNS (ECS, DNSSEC);208.67.222.222;208.67.220.220;2620:119:35::35;2620:119:53::53
Level3;4.2.2.1;4.2.2.2;; Level3;4.2.2.1;4.2.2.2;;
Comodo;8.26.56.26;8.20.247.20;; Comodo;8.26.56.26;8.20.247.20;;
DNS.WATCH (DNSSEC);84.200.69.80;84.200.70.40;2001:1608:10:25:0:0:1c04:b12f;2001:1608:10:25:0:0:9249:d69b
Quad9 (filtered, DNSSEC);9.9.9.9;149.112.112.112;2620:fe::fe;2620:fe::9 Quad9 (filtered, DNSSEC);9.9.9.9;149.112.112.112;2620:fe::fe;2620:fe::9
Quad9 (unfiltered, no DNSSEC);9.9.9.10;149.112.112.10;2620:fe::10;2620:fe::fe:10 Quad9 (unfiltered, no DNSSEC);9.9.9.10;149.112.112.10;2620:fe::10;2620:fe::fe:10
Quad9 (filtered, ECS, DNSSEC);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11 Quad9 (filtered, ECS, DNSSEC);9.9.9.11;149.112.112.11;2620:fe::11;2620:fe::fe:11
@ -57,6 +55,17 @@ Cloudflare (DNSSEC);1.1.1.1;1.0.0.1;2606:4700:4700::1111;2606:4700:4700::1001
EOM EOM
) )
DNS_SERVERS_IPV6_ONLY=$(
cat <<EOM
Google (ECS, DNSSEC);2001:4860:4860:0:0:0:0:8888;2001:4860:4860:0:0:0:0:8844
OpenDNS (ECS, DNSSEC);2620:119:35::35;2620:119:53::53
Quad9 (filtered, DNSSEC);2620:fe::fe;2620:fe::9
Quad9 (unfiltered, no DNSSEC);2620:fe::10;2620:fe::fe:10
Quad9 (filtered, ECS, DNSSEC);2620:fe::11;2620:fe::fe:11
Cloudflare (DNSSEC);2606:4700:4700::1111;2606:4700:4700::1001
EOM
)
# Location for final installation log storage # Location for final installation log storage
installLogLoc="/etc/pihole/install.log" installLogLoc="/etc/pihole/install.log"
# This is a file used for the colorized output # This is a file used for the colorized output
@ -90,6 +99,7 @@ IPV6_ADDRESS=${IPV6_ADDRESS}
# Give settings their default values. These may be changed by prompts later in the script. # Give settings their default values. These may be changed by prompts later in the script.
QUERY_LOGGING= QUERY_LOGGING=
PRIVACY_LEVEL= PRIVACY_LEVEL=
PIHOLE_INTERFACE=
# Where old configs go to if a v6 migration is performed # Where old configs go to if a v6 migration is performed
V6_CONF_MIGRATION_DIR="/etc/pihole/migration_backup_v6" V6_CONF_MIGRATION_DIR="/etc/pihole/migration_backup_v6"
@ -106,11 +116,13 @@ c=70
PIHOLE_META_PACKAGE_CONTROL_APT=$( PIHOLE_META_PACKAGE_CONTROL_APT=$(
cat <<EOM cat <<EOM
Package: pihole-meta Package: pihole-meta
Version: 0.1 Version: 0.4
Maintainer: Pi-hole team <adblock@pi-hole.net> Maintainer: Pi-hole team <adblock@pi-hole.net>
Architecture: all Architecture: all
Description: Pi-hole dependency meta package Description: Pi-hole dependency meta package
Depends: grep,dnsutils,binutils,git,iproute2,dialog,ca-certificates,cron,curl,iputils-ping,psmisc,sudo,unzip,libcap2-bin,dns-root-data,libcap2,netcat-openbsd,procps,jq,lshw,bash-completion Depends: awk,bash-completion,binutils,ca-certificates,cron|cron-daemon,curl,dialog,dnsutils,dns-root-data,git,grep,iproute2,iputils-ping,jq,libcap2,libcap2-bin,lshw,netcat-openbsd,procps,psmisc,sudo,unzip
Section: contrib/metapackages
Priority: optional
EOM EOM
) )
@ -118,12 +130,12 @@ EOM
PIHOLE_META_PACKAGE_CONTROL_RPM=$( PIHOLE_META_PACKAGE_CONTROL_RPM=$(
cat <<EOM cat <<EOM
Name: pihole-meta Name: pihole-meta
Version: 0.1 Version: 0.2
Release: 1 Release: 1
License: EUPL License: EUPL
BuildArch: noarch BuildArch: noarch
Summary: Pi-hole dependency meta package Summary: Pi-hole dependency meta package
Requires: grep,curl,psmisc,sudo, unzip,jq,git,dialog,ca-certificates, bind-utils, iproute, procps-ng, chkconfig, binutils, cronie, findutils, libcap, nmap-ncat, lshw, bash-completion Requires: bash-completion,bind-utils,binutils,ca-certificates,chkconfig,cronie,curl,dialog,findutils,gawk,git,grep,iproute,jq,libcap,lshw,nmap-ncat,procps-ng,psmisc,sudo,unzip
%description %description
Pi-hole dependency meta package Pi-hole dependency meta package
%prep %prep
@ -131,6 +143,9 @@ Pi-hole dependency meta package
%files %files
%install %install
%changelog %changelog
* Wed May 28 2025 Pi-hole Team - 0.2
- Add gawk to the list of dependencies
* Sun Sep 29 2024 Pi-hole Team - 0.1 * Sun Sep 29 2024 Pi-hole Team - 0.1
- First version being packaged - First version being packaged
EOM EOM
@ -152,18 +167,17 @@ done
# If the color table file exists, # If the color table file exists,
if [[ -f "${coltable}" ]]; then if [[ -f "${coltable}" ]]; then
# source it # source it
# shellcheck source="./advanced/Scripts/COL_TABLE"
source "${coltable}" source "${coltable}"
# Otherwise, # Otherwise,
else else
# Set these values so the installer can still run in color # Set these values so the installer can still run in color
COL_NC='\e[0m' # No Color COL_NC='\e[0m' # No Color
COL_LIGHT_GREEN='\e[1;32m' COL_GREEN='\e[1;32m'
COL_LIGHT_RED='\e[1;31m' COL_RED='\e[1;31m'
TICK="[${COL_LIGHT_GREEN}${COL_NC}]" TICK="[${COL_GREEN}${COL_NC}]"
CROSS="[${COL_LIGHT_RED}${COL_NC}]" CROSS="[${COL_RED}${COL_NC}]"
INFO="[i]" INFO="[i]"
# shellcheck disable=SC2034
DONE="${COL_LIGHT_GREEN} done!${COL_NC}"
OVER="\\r\\033[K" OVER="\\r\\033[K"
fi fi
@ -171,13 +185,13 @@ fi
# This lets users know that it is a Pi-hole, LLC product # This lets users know that it is a Pi-hole, LLC product
show_ascii_berry() { show_ascii_berry() {
echo -e " echo -e "
${COL_LIGHT_GREEN}.;;,. ${COL_GREEN}.;;,.
.ccccc:,. .ccccc:,.
:cccclll:. ..,, :cccclll:. ..,,
:ccccclll. ;ooodc :ccccclll. ;ooodc
'ccll:;ll .oooodc 'ccll:;ll .oooodc
.;cll.;;looo:. .;cll.;;looo:.
${COL_LIGHT_RED}.. ','. ${COL_RED}.. ','.
.',,,,,,'. .',,,,,,'.
.',,,,,,,,,,. .',,,,,,,,,,.
.',,,,,,,,,,,,.... .',,,,,,,,,,,,....
@ -199,7 +213,7 @@ abort() {
# remove any leftover build directory that may exist # remove any leftover build directory that may exist
rm -rf /tmp/pihole-meta_* rm -rf /tmp/pihole-meta_*
echo -e "\\n\\n ${COL_LIGHT_RED}Installation was interrupted${COL_NC}\\n" echo -e "\\n\\n ${COL_RED}Installation was interrupted${COL_NC}\\n"
echo -e "Pi-hole's dependencies might be already installed. If you want to remove them you can try to\\n" echo -e "Pi-hole's dependencies might be already installed. If you want to remove them you can try to\\n"
echo -e "a) run 'pihole uninstall' \\n" echo -e "a) run 'pihole uninstall' \\n"
echo -e "b) Remove the meta-package 'pihole-meta' manually \\n" echo -e "b) Remove the meta-package 'pihole-meta' manually \\n"
@ -215,173 +229,10 @@ is_command() {
command -v "${check_command}" >/dev/null 2>&1 command -v "${check_command}" >/dev/null 2>&1
} }
os_check_dig(){ check_fresh_install() {
local protocol="$1" # in case of an update (can be a v5 -> v6 or v6 -> v6 update) or repair
local domain="$2" if [[ -f "${PI_HOLE_V6_CONFIG}" ]] || [[ -f "/etc/pihole/setupVars.conf" ]]; then
local nameserver="$3" fresh_install=false
local response
response="$(dig -"${protocol}" +short -t txt "${domain}" "${nameserver}" 2>&1
echo $?
)"
echo "${response}"
}
os_check_dig_response(){
# Checks the reply from the dig command to determine if it's a valid response
local digReply="$1"
local response
# Dig returned 0 (success), so get the actual response, and loop through it to determine if the detected variables above are valid
response="${digReply%%$'\n'*}"
# If the value of ${response} is a single 0, then this is the return code, not an actual response.
if [ "${response}" == 0 ]; then
echo false
else
echo true
fi
}
os_check() {
if [ "$PIHOLE_SKIP_OS_CHECK" != true ]; then
# This function gets a list of supported OS versions from a TXT record at versions.pi-hole.net
# and determines whether or not the script is running on one of those systems
local remote_os_domain valid_os valid_version valid_response detected_os detected_version display_warning cmdResult digReturnCode response
local piholeNameserver="@ns1.pi-hole.net"
remote_os_domain=${OS_CHECK_DOMAIN_NAME:-"versions.pi-hole.net"}
detected_os=$(grep '^ID=' /etc/os-release | cut -d '=' -f2 | tr -d '"')
detected_version=$(grep VERSION_ID /etc/os-release | cut -d '=' -f2 | tr -d '"')
# Test via IPv4 and hardcoded nameserver ns1.pi-hole.net
cmdResult=$(os_check_dig 4 "${remote_os_domain}" "${piholeNameserver}")
# Gets the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
if [ ! "${digReturnCode}" == "0" ]; then
valid_response=false
else
valid_response=$(os_check_dig_response cmdResult)
fi
# Try again via IPv6 and hardcoded nameserver ns1.pi-hole.net
if [ "$valid_response" = false ]; then
unset valid_response
unset cmdResult
unset digReturnCode
cmdResult=$(os_check_dig 6 "${remote_os_domain}" "${piholeNameserver}")
# Gets the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
if [ ! "${digReturnCode}" == "0" ]; then
valid_response=false
else
valid_response=$(os_check_dig_response cmdResult)
fi
fi
# Try again without hardcoded nameserver
if [ "$valid_response" = false ]; then
unset valid_response
unset cmdResult
unset digReturnCode
cmdResult=$(os_check_dig 4 "${remote_os_domain}")
# Gets the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
if [ ! "${digReturnCode}" == "0" ]; then
valid_response=false
else
valid_response=$(os_check_dig_response cmdResult)
fi
fi
if [ "$valid_response" = false ]; then
unset valid_response
unset cmdResult
unset digReturnCode
cmdResult=$(os_check_dig 6 "${remote_os_domain}")
# Gets the return code of the previous command (last line)
digReturnCode="${cmdResult##*$'\n'}"
if [ ! "${digReturnCode}" == "0" ]; then
valid_response=false
else
valid_response=$(os_check_dig_response cmdResult)
fi
fi
if [ "$valid_response" = true ]; then
response="${cmdResult%%$'\n'*}"
IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"')
for distro_and_versions in "${supportedOS[@]}"; do
distro_part="${distro_and_versions%%=*}"
versions_part="${distro_and_versions##*=}"
# If the distro part is a (case-insensitive) substring of the computer OS
if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then
valid_os=true
IFS="," read -r -a supportedVer <<<"${versions_part}"
for version in "${supportedVer[@]}"; do
if [[ "${detected_version}" =~ $version ]]; then
valid_version=true
break
fi
done
break
fi
done
fi
if [ "$valid_os" = true ] && [ "$valid_version" = true ] && [ "$valid_response" = true ]; then
display_warning=false
fi
if [ "$display_warning" != false ]; then
if [ "$valid_response" = false ]; then
if [ "${digReturnCode}" -eq 0 ]; then
errStr="dig succeeded, but response was blank. Please contact support"
else
errStr="dig failed with return code ${digReturnCode}"
fi
printf " %b %bRetrieval of supported OS list failed. %s. %b\\n" "${CROSS}" "${COL_LIGHT_RED}" "${errStr}" "${COL_NC}"
printf " %bUnable to determine if the detected OS (%s %s) is supported%b\\n" "${COL_LIGHT_RED}" "${detected_os^}" "${detected_version}" "${COL_NC}"
printf " Possible causes for this include:\\n"
printf " - Firewall blocking DNS lookups from Pi-hole device to ns1.pi-hole.net\\n"
printf " - DNS resolution issues of the host system\\n"
printf " - Other internet connectivity issues\\n"
else
printf " %b %bUnsupported OS detected: %s %s%b\\n" "${CROSS}" "${COL_LIGHT_RED}" "${detected_os^}" "${detected_version}" "${COL_NC}"
printf " If you are seeing this message and you do have a supported OS, please contact support.\\n"
fi
printf "\\n"
printf " %bhttps://docs.pi-hole.net/main/prerequisites/#supported-operating-systems%b\\n" "${COL_LIGHT_GREEN}" "${COL_NC}"
printf "\\n"
printf " If you wish to attempt to continue anyway, you can try one of the following commands to skip this check:\\n"
printf "\\n"
printf " e.g: If you are seeing this message on a fresh install, you can run:\\n"
printf " %bcurl -sSL https://install.pi-hole.net | sudo PIHOLE_SKIP_OS_CHECK=true bash%b\\n" "${COL_LIGHT_GREEN}" "${COL_NC}"
printf "\\n"
printf " If you are seeing this message after having run pihole -up:\\n"
printf " %bsudo PIHOLE_SKIP_OS_CHECK=true pihole -r%b\\n" "${COL_LIGHT_GREEN}" "${COL_NC}"
printf " (In this case, your previous run of pihole -up will have already updated the local repository)\\n"
printf "\\n"
printf " It is possible that the installation will still fail at this stage due to an unsupported configuration.\\n"
printf " If that is the case, you can feel free to ask the community on Discourse with the %bCommunity Help%b category:\\n" "${COL_LIGHT_RED}" "${COL_NC}"
printf " %bhttps://discourse.pi-hole.net/c/bugs-problems-issues/community-help/%b\\n" "${COL_LIGHT_GREEN}" "${COL_NC}"
printf "\\n"
exit 1
else
printf " %b %bSupported OS detected%b\\n" "${TICK}" "${COL_LIGHT_GREEN}" "${COL_NC}"
fi
else
printf " %b %bPIHOLE_SKIP_OS_CHECK env variable set to true - installer will continue%b\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${COL_NC}"
fi fi
} }
@ -401,8 +252,6 @@ package_manager_detect() {
PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true" PKG_COUNT="${PKG_MANAGER} -s -o Debug::NoLocking=true upgrade | grep -c ^Inst || true"
# The command we will use to remove packages (used in the uninstaller) # The command we will use to remove packages (used in the uninstaller)
PKG_REMOVE="${PKG_MANAGER} -y remove --purge" PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
# Update package cache
update_package_cache || exit 1
# If apt-get is not found, check for rpm. # If apt-get is not found, check for rpm.
elif is_command rpm; then elif is_command rpm; then
@ -462,7 +311,7 @@ build_dependency_package(){
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf "%b Error: Building pihole-meta.deb failed. %b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf "%b Error: Building pihole-meta.deb failed. %b\\n" "${COL_RED}" "${COL_NC}"
return 1 return 1
fi fi
@ -495,7 +344,7 @@ build_dependency_package(){
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
else else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf "%b Error: Building pihole-meta.rpm failed. %b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf "%b Error: Building pihole-meta.rpm failed. %b\\n" "${COL_RED}" "${COL_NC}"
return 1 return 1
fi fi
@ -637,7 +486,7 @@ getGitFiles() {
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
# Update the repo, returning an error message on failure # Update the repo, returning an error message on failure
update_repo "${directory}" || { update_repo "${directory}" || {
printf "\\n %b: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf "\\n %b: Could not update local repository. Contact support.%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
} }
# If it's not a .git repo, # If it's not a .git repo,
@ -646,7 +495,7 @@ getGitFiles() {
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
# Attempt to make the repository, showing an error on failure # Attempt to make the repository, showing an error on failure
make_repo "${directory}" "${remoteRepo}" || { make_repo "${directory}" "${remoteRepo}" || {
printf "\\n %bError: Could not update local repository. Contact support.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf "\\n %bError: Could not update local repository. Contact support.%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
} }
fi fi
@ -686,7 +535,11 @@ find_IPv4_information() {
local IPv4bare local IPv4bare
# Find IP used to route to outside world by checking the route to Google's public DNS server # Find IP used to route to outside world by checking the route to Google's public DNS server
route=$(ip route get 8.8.8.8) if ! route="$(ip route get 8.8.8.8 2> /dev/null)"; then
printf " %b No IPv4 route was detected.\n" "${INFO}"
IPV4_ADDRESS=""
return
fi
# Get just the interface IPv4 address # Get just the interface IPv4 address
# shellcheck disable=SC2059,SC2086 # shellcheck disable=SC2059,SC2086
@ -702,10 +555,35 @@ find_IPv4_information() {
IPV4_ADDRESS=$(ip -oneline -family inet address show | grep "${IPv4bare}/" | awk '{print $4}' | awk 'END {print}') IPV4_ADDRESS=$(ip -oneline -family inet address show | grep "${IPv4bare}/" | awk '{print $4}' | awk 'END {print}')
} }
confirm_ipv6_only() {
# Confirm from user before IPv6 only install
dialog --no-shadow --output-fd 1 \
--no-button "Exit" --yes-button "Install IPv6 ONLY" \
--yesno "\\n\\nWARNING - no valid IPv4 route detected.\\n\\n\
This may be due to a temporary connectivity issue,\\n\
or you may be installing on an IPv6 only system.\\n\\n\
Do you wish to continue with an IPv6-only installation?\\n\\n" \
"${r}" "${c}" && result=0 || result="$?"
case "${result}" in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %b Installer exited at IPv6 only message.\\n" "${INFO}"
exit 1
;;
esac
DNS_SERVERS="$DNS_SERVERS_IPV6_ONLY"
printf " %b Proceeding with IPv6 only installation.\\n" "${INFO}"
}
# Get available interfaces that are UP # Get available interfaces that are UP
get_available_interfaces() { get_available_interfaces() {
# There may be more than one so it's all stored in a variable # There may be more than one so it's all stored in a variable
availableInterfaces=$(ip --oneline link show up | grep -v "lo" | awk '{print $2}' | cut -d':' -f1 | cut -d'@' -f1) # The ip command list all interfaces that are in the up state
# The awk command filters out any interfaces that have the LOOPBACK flag set
# while using the characters ": " or "@" as a field separator for awk
availableInterfaces=$(ip --oneline link show up | awk -F ': |@' '!/<.*LOOPBACK.*>/ {print $2}')
} }
# A function for displaying the dialogs the user sees when first running the installer # A function for displaying the dialogs the user sees when first running the installer
@ -767,7 +645,6 @@ chooseInterface() {
# All further interfaces are deselected # All further interfaces are deselected
status="OFF" status="OFF"
done done
# shellcheck disable=SC2086
# Disable check for double quote here as we are passing a string with spaces # Disable check for double quote here as we are passing a string with spaces
PIHOLE_INTERFACE=$(dialog --no-shadow --keep-tite --output-fd 1 \ PIHOLE_INTERFACE=$(dialog --no-shadow --keep-tite --output-fd 1 \
--cancel-label "Exit" --ok-label "Select" \ --cancel-label "Exit" --ok-label "Select" \
@ -856,6 +733,9 @@ collect_v4andv6_information() {
printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}" printf " %b IPv4 address: %s\\n" "${INFO}" "${IPV4_ADDRESS}"
find_IPv6_information find_IPv6_information
printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}" printf " %b IPv6 address: %s\\n" "${INFO}" "${IPV6_ADDRESS}"
if [ "$IPV4_ADDRESS" == "" ] && [ "$IPV6_ADDRESS" != "" ]; then
confirm_ipv6_only
fi
} }
# Check an IP address to see if it is a valid one # Check an IP address to see if it is a valid one
@ -933,7 +813,7 @@ setDNS() {
result=$? result=$?
case ${result} in case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}") "${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %b Cancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Cancel was selected, exiting installer%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -970,7 +850,7 @@ If you want to specify a port other than 53, separate it with a hash.\
result=$? result=$?
case ${result} in case ${result} in
"${DIALOG_CANCEL}" | "${DIALOG_ESC}") "${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %b Cancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Cancel was selected, exiting installer%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -1024,7 +904,7 @@ If you want to specify a port other than 53, separate it with a hash.\
DNSSettingsCorrect=False DNSSettingsCorrect=False
;; ;;
"${DIALOG_ESC}") "${DIALOG_ESC}")
printf " %b Escape pressed, exiting installer at DNS Settings%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Escape pressed, exiting installer at DNS Settings%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -1075,7 +955,7 @@ setLogging() {
;; ;;
"${DIALOG_ESC}") "${DIALOG_ESC}")
# User pressed <ESC> # User pressed <ESC>
printf " %b Escape pressed, exiting installer at Query Logging choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Escape pressed, exiting installer at Query Logging choice.%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -1100,7 +980,7 @@ setPrivacyLevel() {
printf " %b Using privacy level: %s\\n" "${INFO}" "${PRIVACY_LEVEL}" printf " %b Using privacy level: %s\\n" "${INFO}" "${PRIVACY_LEVEL}"
;; ;;
"${DIALOG_CANCEL}" | "${DIALOG_ESC}") "${DIALOG_CANCEL}" | "${DIALOG_ESC}")
printf " %b Cancelled privacy level selection.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Cancelled privacy level selection.%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -1134,7 +1014,7 @@ chooseBlocklists() {
;; ;;
"${DIALOG_ESC}") "${DIALOG_ESC}")
# User pressed <ESC> # User pressed <ESC>
printf " %b Escape pressed, exiting installer at blocklist choice.%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b Escape pressed, exiting installer at blocklist choice.%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
;; ;;
esac esac
@ -1260,7 +1140,7 @@ installScripts() {
else else
# Otherwise, show an error and exit # Otherwise, show an error and exit
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf "\\t\\t%bError: Local repo %s not found, exiting installer%b\\n" "${COL_LIGHT_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}" printf "\\t\\t%bError: Local repo %s not found, exiting installer%b\\n" "${COL_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"
return 1 return 1
fi fi
} }
@ -1275,14 +1155,13 @@ installConfigs() {
# 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
printf " %b Error: Unable to initialize configuration file %s/custom.list\\n" "${COL_LIGHT_RED}" "${PI_HOLE_CONFIG_DIR}/hosts" printf " %b Error: Unable to initialize configuration file %s/custom.list\\n" "${COL_RED}" "${PI_HOLE_CONFIG_DIR}/hosts"
return 1 return 1
fi fi
fi fi
# Install pihole-FTL systemd or init.d service, based on whether systemd is the init system or not # Install pihole-FTL systemd or init.d service, based on whether systemd is the init system or not
# Follow debhelper logic, which checks for /run/systemd/system to derive whether systemd is the init system if ps -p 1 -o comm= | grep -q systemd; then
if [[ -d '/run/systemd/system' ]]; then
install -T -m 0644 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.systemd" '/etc/systemd/system/pihole-FTL.service' install -T -m 0644 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.systemd" '/etc/systemd/system/pihole-FTL.service'
# Remove init.d service if present # Remove init.d service if present
@ -1455,7 +1334,7 @@ update_package_cache() {
UPDATE_PKG_CACHE="apt update" UPDATE_PKG_CACHE="apt update"
fi fi
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %b Error: Unable to update package cache. Please try \"%s\"%b\\n" "${COL_LIGHT_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}" printf " %b Error: Unable to update package cache. Please try \"%s\"%b\\n" "${COL_RED}" "sudo ${UPDATE_PKG_CACHE}" "${COL_NC}"
return 1 return 1
fi fi
} }
@ -1473,7 +1352,7 @@ notify_package_updates_available() {
printf "%b %b %s... up to date!\\n\\n" "${OVER}" "${TICK}" "${str}" printf "%b %b %s... up to date!\\n\\n" "${OVER}" "${TICK}" "${str}"
else else
printf "%b %b %s... %s updates available\\n" "${OVER}" "${TICK}" "${str}" "${updatesToInstall}" printf "%b %b %s... %s updates available\\n" "${OVER}" "${TICK}" "${str}" "${updatesToInstall}"
printf " %b %bIt is recommended to update your OS after installing the Pi-hole!%b\\n\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${COL_NC}" printf " %b %bIt is recommended to update your OS after installing the Pi-hole!%b\\n\\n" "${INFO}" "${COL_GREEN}" "${COL_NC}"
fi fi
} }
@ -1490,11 +1369,11 @@ install_dependent_packages() {
rm /tmp/pihole-meta.deb rm /tmp/pihole-meta.deb
else else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %b Error: Unable to install Pi-hole dependency package.\\n" "${COL_LIGHT_RED}" printf " %b Error: Unable to install Pi-hole dependency package.\\n" "${COL_RED}"
return 1 return 1
fi fi
else else
printf " %b Error: Unable to find Pi-hole dependency package.\\n" "${COL_LIGHT_RED}" printf " %b Error: Unable to find Pi-hole dependency package.\\n" "${COL_RED}"
return 1 return 1
fi fi
# Install Fedora/CentOS packages # Install Fedora/CentOS packages
@ -1505,11 +1384,11 @@ install_dependent_packages() {
rm /tmp/pihole-meta.rpm rm /tmp/pihole-meta.rpm
else else
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %b Error: Unable to install Pi-hole dependency package.\\n" "${COL_LIGHT_RED}" printf " %b Error: Unable to install Pi-hole dependency package.\\n" "${COL_RED}"
return 1 return 1
fi fi
else else
printf " %b Error: Unable to find Pi-hole dependency package.\\n" "${COL_LIGHT_RED}" printf " %b Error: Unable to find Pi-hole dependency package.\\n" "${COL_RED}"
return 1 return 1
fi fi
@ -1738,19 +1617,20 @@ checkSelinux() {
if [[ "${SELINUX_ENFORCING}" -eq 1 ]] && [[ -z "${PIHOLE_SELINUX}" ]]; then if [[ "${SELINUX_ENFORCING}" -eq 1 ]] && [[ -z "${PIHOLE_SELINUX}" ]]; then
printf " Pi-hole does not provide an SELinux policy as the required changes modify the security of your system.\\n" printf " Pi-hole does not provide an SELinux policy as the required changes modify the security of your system.\\n"
printf " Please refer to https://wiki.centos.org/HowTos/SELinux if SELinux is required for your deployment.\\n" printf " Please refer to https://wiki.centos.org/HowTos/SELinux if SELinux is required for your deployment.\\n"
printf " This check can be skipped by setting the environment variable %bPIHOLE_SELINUX%b to %btrue%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" "${COL_LIGHT_RED}" "${COL_NC}" printf " This check can be skipped by setting the environment variable %bPIHOLE_SELINUX%b to %btrue%b\\n" "${COL_RED}" "${COL_NC}" "${COL_RED}" "${COL_NC}"
printf " e.g: export PIHOLE_SELINUX=true\\n" printf " e.g: export PIHOLE_SELINUX=true\\n"
printf " By setting this variable to true you acknowledge there may be issues with Pi-hole during or after the install\\n" printf " By setting this variable to true you acknowledge there may be issues with Pi-hole during or after the install\\n"
printf "\\n %bSELinux Enforcing detected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}" printf "\\n %bSELinux Enforcing detected, exiting installer%b\\n" "${COL_RED}" "${COL_NC}"
exit 1 exit 1
elif [[ "${SELINUX_ENFORCING}" -eq 1 ]] && [[ -n "${PIHOLE_SELINUX}" ]]; then elif [[ "${SELINUX_ENFORCING}" -eq 1 ]] && [[ -n "${PIHOLE_SELINUX}" ]]; then
printf " %b %bSELinux Enforcing detected%b. PIHOLE_SELINUX env variable set - installer will continue\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b %bSELinux Enforcing detected%b. PIHOLE_SELINUX env variable set - installer will continue\\n" "${INFO}" "${COL_RED}" "${COL_NC}"
fi fi
} }
check_download_exists() { check_download_exists() {
# Check if the download exists and we can reach the server # Check if the download exists and we can reach the server
local status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1) local status
status=$(curl --head --silent "https://ftl.pi-hole.net/${1}" | head -n 1)
# Check the status code # Check the status code
if grep -q "200" <<<"$status"; then if grep -q "200" <<<"$status"; then
@ -1841,13 +1721,13 @@ clone_or_reset_repos() {
# Reset the Core repo # Reset the Core repo
resetRepo ${PI_HOLE_LOCAL_REPO} || resetRepo ${PI_HOLE_LOCAL_REPO} ||
{ {
printf " %b Unable to reset %s, exiting installer%b\\n" "${COL_LIGHT_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}" printf " %b Unable to reset %s, exiting installer%b\\n" "${COL_RED}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"
exit 1 exit 1
} }
# Reset the Web repo # Reset the Web repo
resetRepo ${webInterfaceDir} || resetRepo ${webInterfaceDir} ||
{ {
printf " %b Unable to reset %s, exiting installer%b\\n" "${COL_LIGHT_RED}" "${webInterfaceDir}" "${COL_NC}" printf " %b Unable to reset %s, exiting installer%b\\n" "${COL_RED}" "${webInterfaceDir}" "${COL_NC}"
exit 1 exit 1
} }
# Otherwise, a fresh installation is happening # Otherwise, a fresh installation is happening
@ -1855,13 +1735,13 @@ clone_or_reset_repos() {
# so get git files for Core # so get git files for Core
getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} || getGitFiles ${PI_HOLE_LOCAL_REPO} ${piholeGitUrl} ||
{ {
printf " %b Unable to clone %s into %s, unable to continue%b\\n" "${COL_LIGHT_RED}" "${piholeGitUrl}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}" printf " %b Unable to clone %s into %s, unable to continue%b\\n" "${COL_RED}" "${piholeGitUrl}" "${PI_HOLE_LOCAL_REPO}" "${COL_NC}"
exit 1 exit 1
} }
# get the Web git files # get the Web git files
getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} || getGitFiles ${webInterfaceDir} ${webInterfaceGitUrl} ||
{ {
printf " %b Unable to clone %s into ${webInterfaceDir}, exiting installer%b\\n" "${COL_LIGHT_RED}" "${webInterfaceGitUrl}" "${COL_NC}" printf " %b Unable to clone %s into ${webInterfaceDir}, exiting installer%b\\n" "${COL_RED}" "${webInterfaceGitUrl}" "${COL_NC}"
exit 1 exit 1
} }
fi fi
@ -1869,7 +1749,6 @@ clone_or_reset_repos() {
# Download FTL binary to random temp directory and install FTL binary # Download FTL binary to random temp directory and install FTL binary
# Disable directive for SC2120 a value _can_ be passed to this function, but it is passed from an external script that sources this one # Disable directive for SC2120 a value _can_ be passed to this function, but it is passed from an external script that sources this one
# shellcheck disable=SC2120
FTLinstall() { FTLinstall() {
# Local, named variables # Local, named variables
local str="Downloading and Installing FTL" local str="Downloading and Installing FTL"
@ -1938,7 +1817,7 @@ FTLinstall() {
return 1 return 1
} }
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
printf " %b Error: Download of %s/%s failed (checksum error)%b\\n" "${COL_LIGHT_RED}" "${url}" "${binary}" "${COL_NC}" printf " %b Error: Download of %s/%s failed (checksum error)%b\\n" "${COL_RED}" "${url}" "${binary}" "${COL_NC}"
# Remove temp dir # Remove temp dir
remove_dir "${tempdir}" remove_dir "${tempdir}"
@ -1952,7 +1831,7 @@ FTLinstall() {
} }
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
# The URL could not be found # The URL could not be found
printf " %b Error: URL %s/%s not found%b\\n" "${COL_LIGHT_RED}" "${url}" "${binary}" "${COL_NC}" printf " %b Error: URL %s/%s not found%b\\n" "${COL_RED}" "${url}" "${binary}" "${COL_NC}"
# Remove temp dir # Remove temp dir
remove_dir "${tempdir}" remove_dir "${tempdir}"
@ -2029,7 +1908,7 @@ get_binary_name() {
# Something else - we try to use 32bit executable and warn the user # Something else - we try to use 32bit executable and warn the user
if [[ ! "${machine}" == "i686" ]]; then if [[ ! "${machine}" == "i686" ]]; then
printf "%b %b %s...\\n" "${OVER}" "${CROSS}" "${str}" printf "%b %b %s...\\n" "${OVER}" "${CROSS}" "${str}"
printf " %b %bNot able to detect architecture (unknown: %s), trying x86 (32bit) executable%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${machine}" "${COL_NC}" printf " %b %bNot able to detect architecture (unknown: %s), trying x86 (32bit) executable%b\\n" "${INFO}" "${COL_RED}" "${machine}" "${COL_NC}"
printf " %b Contact Pi-hole Support if you experience issues (e.g: FTL not running)\\n" "${INFO}" printf " %b Contact Pi-hole Support if you experience issues (e.g: FTL not running)\\n" "${INFO}"
else else
printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}" printf "%b %b Detected 32bit (i686) architecture\\n" "${OVER}" "${TICK}"
@ -2067,13 +1946,13 @@ FTLcheckUpdate() {
path="${ftlBranch}/${binary}" path="${ftlBranch}/${binary}"
# Check whether or not the binary for this FTL branch actually exists. If not, then there is no update! # Check whether or not the binary for this FTL branch actually exists. If not, then there is no update!
# shellcheck disable=SC1090 local status
if ! check_download_exists "$path"; then if ! check_download_exists "$path"; then
if [ $? -eq 1 ]; then status=$?
if [ "${status}" -eq 1 ]; then
printf " %b Branch \"%s\" is not available.\\n" "${INFO}" "${ftlBranch}" printf " %b Branch \"%s\" is not available.\\n" "${INFO}" "${ftlBranch}"
printf " %b Use %bpihole checkout ftl [branchname]%b to switch to a valid branch.\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${COL_NC}" printf " %b Use %bpihole checkout ftl [branchname]%b to switch to a valid branch.\\n" "${INFO}" "${COL_GREEN}" "${COL_NC}"
return 2 elif [ "${status}" -eq 2 ]; then
elif [ $? -eq 2 ]; then
printf " %b Unable to download from ftl.pi-hole.net. Please check your Internet connection and try again later.\\n" "${CROSS}" printf " %b Unable to download from ftl.pi-hole.net. Please check your Internet connection and try again later.\\n" "${CROSS}"
return 3 return 3
else else
@ -2101,12 +1980,14 @@ FTLcheckUpdate() {
# same as the remote one # same as the remote one
local FTLversion local FTLversion
FTLversion=$(/usr/bin/pihole-FTL tag) FTLversion=$(/usr/bin/pihole-FTL tag)
local FTLlatesttag
# Get the latest version from the GitHub API # Get the latest version from the GitHub API
if ! FTLlatesttag=$(curl -sI https://github.com/pi-hole/FTL/releases/latest | grep --color=never -i Location: | awk -F / '{print $NF}' | tr -d '[:cntrl:]'); then local FTLlatesttag
FTLlatesttag=$(curl -s https://api.github.com/repos/pi-hole/FTL/releases/latest | jq -sRr 'fromjson? | .tag_name | values')
if [ -z "${FTLlatesttag}" ]; then
# There was an issue while retrieving the latest version # There was an issue while retrieving the latest version
printf " %b Failed to retrieve latest FTL release metadata" "${CROSS}" printf " %b Failed to retrieve latest FTL release metadata\\n" "${CROSS}"
return 3 return 3
fi fi
@ -2124,6 +2005,7 @@ FTLcheckUpdate() {
# Continue further down... # Continue further down...
fi fi
else else
# FTL not installed, then download
return 0 return 0
fi fi
fi fi
@ -2155,6 +2037,11 @@ FTLdetect() {
if FTLcheckUpdate "${1}"; then if FTLcheckUpdate "${1}"; then
FTLinstall "${1}" || return 1 FTLinstall "${1}" || return 1
else
case $? in
1) :;; # FTL is up-to-date
*) exit 1;; # 404 (2), other HTTP or curl error (3), unknown (4)
esac
fi fi
} }
@ -2282,7 +2169,7 @@ main() {
else else
# Otherwise, they do not have enough privileges, so let the user know # Otherwise, they do not have enough privileges, so let the user know
printf " %b %s\\n" "${INFO}" "${str}" printf " %b %s\\n" "${INFO}" "${str}"
printf " %b %bScript called with non-root privileges%b\\n" "${INFO}" "${COL_LIGHT_RED}" "${COL_NC}" printf " %b %bScript called with non-root privileges%b\\n" "${INFO}" "${COL_RED}" "${COL_NC}"
printf " The Pi-hole requires elevated privileges to install and run\\n" printf " The Pi-hole requires elevated privileges to install and run\\n"
printf " Please check the installer for any concerns regarding this requirement\\n" printf " Please check the installer for any concerns regarding this requirement\\n"
printf " Make sure to download this script from a trusted source\\n\\n" printf " Make sure to download this script from a trusted source\\n\\n"
@ -2306,7 +2193,7 @@ main() {
# Otherwise, tell the user they need to run the script as root, and bail # Otherwise, tell the user they need to run the script as root, and bail
printf "%b %b Sudo utility check\\n" "${OVER}" "${CROSS}" printf "%b %b Sudo utility check\\n" "${OVER}" "${CROSS}"
printf " %b Sudo is needed for the Web Interface to run pihole commands\\n\\n" "${INFO}" printf " %b Sudo is needed for the Web Interface to run pihole commands\\n\\n" "${INFO}"
printf " %b %bPlease re-run this installer as root${COL_NC}\\n" "${INFO}" "${COL_LIGHT_RED}" printf " %b %bPlease re-run this installer as root${COL_NC}\\n" "${INFO}" "${COL_RED}"
exit 1 exit 1
fi fi
fi fi
@ -2317,9 +2204,17 @@ main() {
# Check for availability of either the "service" or "systemctl" commands # Check for availability of either the "service" or "systemctl" commands
check_service_command check_service_command
# Check if this is a fresh install or an update/repair
check_fresh_install
# 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
# Update package cache only on apt based systems
if is_command apt-get; then
update_package_cache || exit 1
fi
# Notify user of package availability # Notify user of package availability
notify_package_updates_available notify_package_updates_available
@ -2329,8 +2224,6 @@ main() {
# Install Pi-hole dependencies # Install Pi-hole dependencies
install_dependent_packages install_dependent_packages
# Check that the installed OS is officially supported - display warning if not
os_check
# Check if there is a usable FTL binary available on this architecture - do # Check if there is a usable FTL binary available on this architecture - do
# this early on as FTL is a hard dependency for Pi-hole # this early on as FTL is a hard dependency for Pi-hole
@ -2342,10 +2235,7 @@ main() {
exit 1 exit 1
fi fi
# in case of an update (can be a v5 -> v6 or v6 -> v6 update) or repair if [[ "${fresh_install}" == false ]]; then
if [[ -f "${PI_HOLE_V6_CONFIG}" ]] || [[ -f "/etc/pihole/setupVars.conf" ]]; then
# retain settings
fresh_install=false
# if it's running unattended, # if it's running unattended,
if [[ "${runUnattended}" == true ]]; then if [[ "${runUnattended}" == true ]]; then
printf " %b Performing unattended setup, no dialogs will be displayed\\n" "${INFO}" printf " %b Performing unattended setup, no dialogs will be displayed\\n" "${INFO}"
@ -2398,7 +2288,7 @@ main() {
# /opt/pihole/utils.sh should be installed by installScripts now, so we can use it # /opt/pihole/utils.sh should be installed by installScripts now, so we can use it
if [ -f "${PI_HOLE_INSTALL_DIR}/utils.sh" ]; then if [ -f "${PI_HOLE_INSTALL_DIR}/utils.sh" ]; then
# shellcheck disable=SC1091 # shellcheck source="./advanced/Scripts/utils.sh"
source "${PI_HOLE_INSTALL_DIR}/utils.sh" source "${PI_HOLE_INSTALL_DIR}/utils.sh"
else else
printf " %b Failure: /opt/pihole/utils.sh does not exist .\\n" "${CROSS}" printf " %b Failure: /opt/pihole/utils.sh does not exist .\\n" "${CROSS}"
@ -2411,16 +2301,28 @@ main() {
# Migrate existing install to v6.0 # Migrate existing install to v6.0
migrate_dnsmasq_configs migrate_dnsmasq_configs
# Cleanup old v5 sudoers file if it exists
sudoers_file="/etc/sudoers.d/pihole"
if [[ -f "${sudoers_file}" ]]; then
# only remove the file if it contains the Pi-hole header
if grep -q "Pi-hole: A black hole for Internet advertisements" "${sudoers_file}"; then
rm -f "${sudoers_file}"
fi
fi
# Check for and disable systemd-resolved-DNSStubListener before reloading resolved # Check for and disable systemd-resolved-DNSStubListener before reloading resolved
# DNSStubListener needs to remain in place for installer to download needed files, # DNSStubListener needs to remain in place for installer to download needed files,
# so this change needs to be made after installation is complete, # so this change needs to be made after installation is complete,
# but before starting or resttarting the ftl service # but before starting or resttarting the ftl service
disable_resolved_stublistener disable_resolved_stublistener
# Check if gravity database needs to be upgraded. If so, do it without rebuilding if [[ "${fresh_install}" == false ]]; then
# gravity altogether. This may be a very long running task needlessly blocking # Check if gravity database needs to be upgraded. If so, do it without rebuilding
# the update process. # gravity altogether. This may be a very long running task needlessly blocking
/opt/pihole/gravity.sh --upgrade # the update process.
# Only do this on updates, not on fresh installs as the database does not exit yet
/opt/pihole/gravity.sh --upgrade
fi
printf " %b Restarting services...\\n" "${INFO}" printf " %b Restarting services...\\n" "${INFO}"
# Start services # Start services
@ -2452,6 +2354,10 @@ main() {
if [ -n "${PRIVACY_LEVEL}" ]; then if [ -n "${PRIVACY_LEVEL}" ]; then
setFTLConfigValue "misc.privacylevel" "${PRIVACY_LEVEL}" setFTLConfigValue "misc.privacylevel" "${PRIVACY_LEVEL}"
fi fi
if [ -n "${PIHOLE_INTERFACE}" ]; then
setFTLConfigValue "dns.interface" "${PIHOLE_INTERFACE}"
fi
fi fi
# Download and compile the aggregated block list # Download and compile the aggregated block list
@ -2477,8 +2383,10 @@ main() {
printf " %b If you have not done so already, the above IP should be set to static.\\n" "${INFO}" printf " %b If you have not done so already, the above IP should be set to static.\\n" "${INFO}"
printf " %b View the web interface at http://pi.hole:${WEBPORT}/admin or http://%s/admin\\n\\n" "${INFO}" "${IPV4_ADDRESS%/*}:${WEBPORT}" printf " %b View the web interface at http://pi.hole:${WEBPORT}/admin or http://%s/admin\\n\\n" "${INFO}" "${IPV4_ADDRESS%/*}:${WEBPORT}"
printf " %b Web Interface password: %b%s%b\\n" "${INFO}" "${COL_LIGHT_GREEN}" "${pw}" "${COL_NC}" printf " %b Web Interface password: %b%s%b\\n" "${INFO}" "${COL_GREEN}" "${pw}" "${COL_NC}"
printf " %b This can be changed using 'pihole setpassword'\\n\\n" "${INFO}" printf " %b This can be changed using 'pihole setpassword'\\n\\n" "${INFO}"
printf " %b To allow your user to use all CLI functions without authentication, refer to\\n" "${INFO}"
printf " our documentation at: https://docs.pi-hole.net/main/post-install/\\n\\n"
# Final dialog message to the user # Final dialog message to the user
dialog --no-shadow --keep-tite \ dialog --no-shadow --keep-tite \
@ -2487,7 +2395,11 @@ main() {
\\n\\nIPv4: ${IPV4_ADDRESS%/*}\ \\n\\nIPv4: ${IPV4_ADDRESS%/*}\
\\nIPv6: ${IPV6_ADDRESS:-"Not Configured"}\ \\nIPv6: ${IPV6_ADDRESS:-"Not Configured"}\
\\nIf you have not done so already, the above IP should be set to static.\ \\nIf you have not done so already, the above IP should be set to static.\
\\nView the web interface at http://pi.hole/admin:${WEBPORT} or http://${IPV4_ADDRESS%/*}:${WEBPORT}/admin\\n\\nYour Admin Webpage login password is ${pw}" "${r}" "${c}" \\nView the web interface at http://pi.hole/admin:${WEBPORT} or http://${IPV4_ADDRESS%/*}:${WEBPORT}/admin\\n\\nYour Admin Webpage login password is ${pw}\
\\n
\\n
\\nTo allow your user to use all CLI functions without authentication,\
\\nrefer to https://docs.pi-hole.net/main/post-install/" "${r}" "${c}"
INSTALL_TYPE="Installation" INSTALL_TYPE="Installation"
else else
@ -2496,7 +2408,7 @@ main() {
# Display where the log file is # Display where the log file is
printf "\\n %b The install log is located at: %s\\n" "${INFO}" "${installLogLoc}" printf "\\n %b The install log is located at: %s\\n" "${INFO}" "${installLogLoc}"
printf " %b %b%s complete! %b\\n" "${TICK}" "${COL_LIGHT_GREEN}" "${INSTALL_TYPE}" "${COL_NC}" printf " %b %b%s complete! %b\\n" "${TICK}" "${COL_GREEN}" "${INSTALL_TYPE}" "${COL_NC}"
if [[ "${INSTALL_TYPE}" == "Update" ]]; then if [[ "${INSTALL_TYPE}" == "Update" ]]; then
printf "\\n" printf "\\n"

View File

@ -8,13 +8,19 @@
# This file is copyright under the latest version of the EUPL. # This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
# shellcheck source="./advanced/Scripts/COL_TABLE"
source "/opt/pihole/COL_TABLE" source "/opt/pihole/COL_TABLE"
# shellcheck source="./advanced/Scripts/utils.sh"
source "/opt/pihole/utils.sh"
ADMIN_INTERFACE_DIR=$(getFTLConfigValue "webserver.paths.webroot")$(getFTLConfigValue "webserver.paths.webhome")
readonly ADMIN_INTERFACE_DIR
while true; do while true; do
read -rp " ${QST} Are you sure you would like to remove ${COL_WHITE}Pi-hole${COL_NC}? [y/N] " answer read -rp " ${QST} Are you sure you would like to remove ${COL_BOLD}Pi-hole${COL_NC}? [y/N] " answer
case ${answer} in case ${answer} in
[Yy]* ) break;; [Yy]* ) break;;
* ) echo -e "${OVER} ${COL_LIGHT_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;; * ) echo -e "${OVER} ${COL_GREEN}Uninstall has been canceled${COL_NC}"; exit 0;;
esac esac
done done
@ -37,6 +43,7 @@ fi
readonly PI_HOLE_FILES_DIR="/etc/.pihole" readonly PI_HOLE_FILES_DIR="/etc/.pihole"
SKIP_INSTALL="true" SKIP_INSTALL="true"
# shellcheck source="./automated install/basic-install.sh"
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
# package_manager_detect() sourced from basic-install.sh # package_manager_detect() sourced from basic-install.sh
@ -53,17 +60,9 @@ removeMetaPackage() {
} }
removePiholeFiles() { removePiholeFiles() {
# Only web directories/files that are created by Pi-hole should be removed # Remove the web interface of Pi-hole
echo -ne " ${INFO} Removing Web Interface..." echo -ne " ${INFO} Removing Web Interface..."
${SUDO} rm -rf /var/www/html/admin &> /dev/null ${SUDO} rm -rf "${ADMIN_INTERFACE_DIR}" &> /dev/null
# If the web directory is empty after removing these files, then the parent html directory can be removed.
if [ -d "/var/www/html" ]; then
if [[ ! "$(ls -A /var/www/html)" ]]; then
${SUDO} rm -rf /var/www/html &> /dev/null
fi
fi
echo -e "${OVER} ${TICK} Removed Web Interface" echo -e "${OVER} ${TICK} Removed Web Interface"
# Attempt to preserve backwards compatibility with older versions # Attempt to preserve backwards compatibility with older versions
@ -151,11 +150,11 @@ removePiholeFiles() {
echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole! echo -e "\\n We're sorry to see you go, but thanks for checking out Pi-hole!
If you need help, reach out to us on GitHub, Discourse, Reddit or Twitter If you need help, reach out to us on GitHub, Discourse, Reddit or Twitter
Reinstall at any time: ${COL_WHITE}curl -sSL https://install.pi-hole.net | bash${COL_NC} Reinstall at any time: ${COL_BOLD}curl -sSL https://install.pi-hole.net | bash${COL_NC}
${COL_LIGHT_RED}Please reset the DNS on your router/clients to restore internet connectivity${COL_NC} ${COL_RED}Please reset the DNS on your router/clients to restore internet connectivity${COL_NC}
${INFO} Pi-hole's meta package has been removed, use the 'autoremove' function from your package manager to remove unused dependencies${COL_NC} ${INFO} Pi-hole's meta package has been removed, use the 'autoremove' function from your package manager to remove unused dependencies${COL_NC}
${COL_LIGHT_GREEN}Uninstallation Complete! ${COL_NC}" ${COL_GREEN}Uninstallation Complete! ${COL_NC}"
} }
######### SCRIPT ########### ######### SCRIPT ###########

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements # Pi-hole: A black hole for Internet advertisements
# (c) 2017 Pi-hole, LLC (https://pi-hole.net) # (c) 2017 Pi-hole, LLC (https://pi-hole.net)
@ -16,13 +15,13 @@ export LC_ALL=C
PI_HOLE_SCRIPT_DIR="/opt/pihole" PI_HOLE_SCRIPT_DIR="/opt/pihole"
# Source utils.sh for GetFTLConfigValue # Source utils.sh for GetFTLConfigValue
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck disable=SC1090 # shellcheck source=./advanced/Scripts/utils.sh
. "${utilsfile}" . "${utilsfile}"
coltable="${PI_HOLE_SCRIPT_DIR}/COL_TABLE" coltable="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
# shellcheck disable=SC1090 # shellcheck source=./advanced/Scripts/COL_TABLE
. "${coltable}" . "${coltable}"
# shellcheck disable=SC1091 # shellcheck source=./advanced/Scripts/database_migration/gravity-db.sh
. "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh" . "/etc/.pihole/advanced/Scripts/database_migration/gravity-db.sh"
basename="pihole" basename="pihole"
@ -51,14 +50,14 @@ 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
echo -e " ${COL_LIGHT_RED}Gravity temporary directory does not exist or is not a writeable directory, falling back to /tmp. ${COL_NC}" echo -e " ${COL_RED}Gravity temporary directory does not exist or is not a writeable directory, falling back to /tmp. ${COL_NC}"
GRAVITY_TMPDIR="/tmp" GRAVITY_TMPDIR="/tmp"
fi fi
# Set this only after sourcing pihole-FTL.conf as the gravity database path may # Set this only after sourcing pihole-FTL.conf as the gravity database path may
# have changed # have changed
gravityDBfile="${GRAVITYDB}" gravityDBfile="${GRAVITYDB}"
gravityDBfile_default="/etc/pihole/gravity.db" gravityDBfile_default="${piholeDir}/gravity.db"
gravityTEMPfile="${GRAVITYDB}_temp" gravityTEMPfile="${GRAVITYDB}_temp"
gravityDIR="$(dirname -- "${gravityDBfile}")" gravityDIR="$(dirname -- "${gravityDBfile}")"
gravityOLDfile="${gravityDIR}/gravity_old.db" gravityOLDfile="${gravityDIR}/gravity_old.db"
@ -127,7 +126,7 @@ 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
cp "${gravityDBfile}" "${gravityOLDfile}" cp -p "${gravityDBfile}" "${gravityOLDfile}"
fi fi
# Drop the gravity and antigravity tables + subsequent VACUUM the current # Drop the gravity and antigravity tables + subsequent VACUUM the current
@ -140,7 +139,7 @@ gravity_swap_databases() {
else else
# Check if the backup directory exists # Check if the backup directory exists
if [ ! -d "${gravityBCKdir}" ]; then if [ ! -d "${gravityBCKdir}" ]; then
mkdir -p "${gravityBCKdir}" mkdir -p "${gravityBCKdir}" && chown pihole:pihole "${gravityBCKdir}"
fi fi
# If multiple gravityBCKfile's are present (appended with a number), rotate them # If multiple gravityBCKfile's are present (appended with a number), rotate them
@ -306,7 +305,7 @@ migrate_to_database() {
fi fi
# Check if gravity database needs to be updated # Check if gravity database needs to be updated
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}" upgrade_gravityDB "${gravityDBfile}"
# Migrate list files to new database # Migrate list files to new database
if [ -e "${adListFile}" ]; then if [ -e "${adListFile}" ]; then
@ -334,7 +333,7 @@ migrate_to_database() {
fi fi
# Check if gravity database needs to be updated # Check if gravity database needs to be updated
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}" upgrade_gravityDB "${gravityDBfile}"
} }
# Determine if DNS resolution is available before proceeding # Determine if DNS resolution is available before proceeding
@ -349,17 +348,24 @@ gravity_CheckDNSResolutionAvailable() {
echo -e " ${CROSS} DNS resolution is currently unavailable" echo -e " ${CROSS} DNS resolution is currently unavailable"
fi fi
str="Waiting until DNS resolution is available..." str="Waiting up to 120 seconds for DNS resolution..."
echo -ne " ${INFO} ${str}" echo -ne " ${INFO} ${str}"
until getent hosts github.com &> /dev/null; do
# Append one dot for each second waiting # Default DNS timeout is two seconds, plus 1 second for each dot > 120 seconds
str="${str}." for ((i = 0; i < 40; i++)); do
echo -ne " ${OVER} ${INFO} ${str}" if getent hosts github.com &> /dev/null; then
sleep 1 # If we reach this point, DNS resolution is available
echo -e "${OVER} ${TICK} DNS resolution is available"
return 0
fi
# Append one dot for each second waiting
echo -ne "."
sleep 1
done done
# If we reach this point, DNS resolution is available # DNS resolution is still unavailable after 120 seconds
echo -e "${OVER} ${TICK} DNS resolution is available" return 1
} }
# Function: try_restore_backup # Function: try_restore_backup
@ -418,7 +424,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
local url domain str target compression adlist_type directory success local url domain str compression adlist_type directory success
echo "" echo ""
# Prepare new gravity database # Prepare new gravity database
@ -541,16 +547,14 @@ gravity_DownloadBlocklists() {
# it (in case it doesn't exist) # it (in case it doesn't exist)
# First, check if the directory is writable # First, check if the directory is writable
directory="$(dirname -- "${saveLocation}")" directory="$(dirname -- "${saveLocation}")"
directory_permissions=$(stat -c %a ${directory}) if [ ! -w "${directory}" ]; then
if [ $directory_permissions -lt 700 ]; then
echo -e " ${CROSS} Unable to write to ${directory}" echo -e " ${CROSS} Unable to write to ${directory}"
echo " Please run pihole -g as root" echo " Please run pihole -g as root"
echo "" echo ""
continue continue
fi fi
# Then, check if the file is writable (if it exists) # Then, check if the file is writable (if it exists)
saveLocation_permissions=$(stat -c %a ${saveLocation}) if [ -e "${saveLocation}" ] && [ ! -w "${saveLocation}" ]; then
if [ -e "${saveLocation}" ] && [ ${saveLocation_permissions} -lt 600 ]; then
echo -e " ${CROSS} Unable to write to ${saveLocation}" echo -e " ${CROSS} Unable to write to ${saveLocation}"
echo " Please run pihole -g as root" echo " Please run pihole -g as root"
echo "" echo ""
@ -569,12 +573,12 @@ gravity_DownloadBlocklists() {
if [[ "${check_url}" =~ ${regex} ]]; then if [[ "${check_url}" =~ ${regex} ]]; then
echo -e " ${CROSS} Invalid Target" echo -e " ${CROSS} Invalid Target"
else else
timeit gravity_DownloadBlocklistFromUrl "${url}" "${sourceIDs[$i]}" "${saveLocation}" "${target}" "${compression}" "${adlist_type}" "${domain}" timeit gravity_DownloadBlocklistFromUrl "${url}" "${sourceIDs[$i]}" "${saveLocation}" "${compression}" "${adlist_type}" "${domain}"
fi fi
echo "" echo ""
done done
gravity_Blackbody=true DownloadBlocklists_done=true
} }
compareLists() { compareLists() {
@ -603,9 +607,11 @@ 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}" compression="${4}" gravity_type="${5}" domain="${6}"
local modifiedOptions="" listCurlBuffer str httpCode success="" ip cmd_ext local listCurlBuffer str httpCode success="" ip customUpstreamResolver=""
local file_path permissions ip_addr port blocked=false download=true local file_path permissions ip_addr port blocked=false download=true
# modifiedOptions is an array to store all the options used to check if the adlist has been changed upstream
local modifiedOptions=()
# Create temp file to store content on disk instead of RAM # Create temp file to store content on disk instead of RAM
# We don't use '--suffix' here because not all implementations of mktemp support it, e.g. on Alpine # We don't use '--suffix' here because not all implementations of mktemp support it, e.g. on Alpine
@ -622,14 +628,14 @@ gravity_DownloadBlocklistFromUrl() {
# Save HTTP ETag to the specified file. An ETag is a caching related header, # 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 # usually returned in a response. If no ETag is sent by the server, an empty
# file is created and can later be used consistently. # file is created and can later be used consistently.
modifiedOptions="--etag-save ${saveLocation}.etag" modifiedOptions=("${modifiedOptions[@]}" --etag-save "${saveLocation}".etag)
if [[ -f "${saveLocation}.etag" ]]; then if [[ -f "${saveLocation}.etag" ]]; then
# This option makes a conditional HTTP request for the specific ETag read # 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 # 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 # stored ETag. This way, the server will only send the file if it has
# changed since the last request. # changed since the last request.
modifiedOptions="${modifiedOptions} --etag-compare ${saveLocation}.etag" modifiedOptions=("${modifiedOptions[@]}" --etag-compare "${saveLocation}".etag)
fi fi
fi fi
@ -642,39 +648,13 @@ gravity_DownloadBlocklistFromUrl() {
# Interstingly, this option is not supported by raw.githubusercontent.com # Interstingly, this option is not supported by raw.githubusercontent.com
# URLs, however, it is still supported by many older web servers which may # 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. # not support the HTTP ETag method so we keep it as a fallback.
modifiedOptions="${modifiedOptions} -z ${saveLocation}" modifiedOptions=("${modifiedOptions[@]}" -z "${saveLocation}")
fi fi
fi fi
str="Status:" str="Status:"
echo -ne " ${INFO} ${str} Pending..." echo -ne " ${INFO} ${str} Pending..."
blocked=false blocked=false
case $(getFTLConfigValue dns.blocking.mode) in
"IP-NODATA-AAAA" | "IP")
# Get IP address of this domain
ip="$(dig "${domain}" +short)"
# Check if this IP matches any IP of the system
if [[ -n "${ip}" && $(grep -Ec "inet(|6) ${ip}" <<<"$(ip a)") -gt 0 ]]; then
blocked=true
fi
;;
"NXDOMAIN")
if [[ $(dig "${domain}" | grep "NXDOMAIN" -c) -ge 1 ]]; then
blocked=true
fi
;;
"NODATA")
if [[ $(dig "${domain}" | grep "NOERROR" -c) -ge 1 ]] && [[ -z $(dig +short "${domain}") ]]; then
blocked=true
fi
;;
"NULL" | *)
if [[ $(dig "${domain}" +short | grep "0.0.0.0" -c) -ge 1 ]]; then
blocked=true
fi
;;
esac
# Check if this domain is blocked by Pi-hole but only if the domain is not a # Check if this domain is blocked by Pi-hole but only if the domain is not a
# local file or empty # local file or empty
if [[ $url != "file"* ]] && [[ -n "${domain}" ]]; then if [[ $url != "file"* ]] && [[ -n "${domain}" ]]; then
@ -734,7 +714,7 @@ gravity_DownloadBlocklistFromUrl() {
fi fi
echo -e "${OVER} ${CROSS} ${str} ${domain} is blocked by one of your lists. Using DNS server ${upstream} instead" echo -e "${OVER} ${CROSS} ${str} ${domain} is blocked by one of your lists. Using DNS server ${upstream} instead"
echo -ne " ${INFO} ${str} Pending..." echo -ne " ${INFO} ${str} Pending..."
cmd_ext="--resolve $domain:$port:$ip" customUpstreamResolver="--resolve $domain:$port:$ip"
fi fi
fi fi
@ -772,8 +752,7 @@ gravity_DownloadBlocklistFromUrl() {
fi fi
if [[ "${download}" == true ]]; then if [[ "${download}" == true ]]; then
# shellcheck disable=SC2086 httpCode=$(curl --connect-timeout ${curl_connect_timeout} -s -L ${compression:+${compression}} ${customUpstreamResolver:+${customUpstreamResolver}} "${modifiedOptions[@]}" -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
@ -823,11 +802,11 @@ gravity_DownloadBlocklistFromUrl() {
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
# Determine if blocklist is non-standard and parse as appropriate # Move the downloaded list to the final location
gravity_ParseFileIntoDomains "${listCurlBuffer}" "${saveLocation}" mv "${listCurlBuffer}" "${saveLocation}"
# Remove curl buffer file after its use # Ensure the file has the correct permissions
rm "${listCurlBuffer}" fix_owner_permissions "${saveLocation}"
# Compare lists if are they identical # Compare lists if they are identical
compareLists "${adlistID}" "${saveLocation}" 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}"
@ -842,13 +821,13 @@ gravity_DownloadBlocklistFromUrl() {
if [[ "${done}" != "true" ]]; then if [[ "${done}" != "true" ]]; then
# 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_GREEN}using previously cached list${COL_NC}"
# Set list status to "download-failed/cached" # Set list status to "download-failed/cached"
database_adlist_status "${adlistID}" "3" 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}"
else else
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}" echo -e " ${CROSS} List download failed: ${COL_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
database_adlist_number "${adlistID}" 0 0 database_adlist_number "${adlistID}" 0 0
database_adlist_status "${adlistID}" "4" database_adlist_status "${adlistID}" "4"
@ -856,37 +835,6 @@ gravity_DownloadBlocklistFromUrl() {
fi fi
} }
# Parse source files into domains format
gravity_ParseFileIntoDomains() {
local src="${1}" destination="${2}"
# Remove comments and print only the domain name
# Most of the lists downloaded are already in hosts file format but the spacing/formatting is not contiguous
# This helps with that and makes it easier to read
# It also helps with debugging so each stage of the script can be researched more in depth
# 1) Convert all characters to lowercase
tr '[:upper:]' '[:lower:]' <"${src}" >"${destination}"
# 2) Remove carriage returns
# 3) Remove lines starting with ! (ABP Comments)
# 4) Remove lines starting with [ (ABP Header)
# 5) Remove lines containing ABP extended CSS selectors ("##", "#$#", "#@#", "#?#") and Adguard JavaScript (#%#) preceded by a letter
# 6) Remove comments (text starting with "#", include possible spaces before the hash sign)
# 7) Remove leading tabs, spaces, etc. (Also removes leading IP addresses)
# 8) Remove empty lines
sed -i -r \
-e 's/\r$//' \
-e 's/\s*!.*//g' \
-e 's/\s*\[.*//g' \
-e '/[a-z]\#[$?@%]{0,3}\#/d' \
-e 's/\s*#.*//g' \
-e 's/^.*\s+//g' \
-e '/^$/d' "${destination}"
fix_owner_permissions "${destination}"
}
# Report number of entries in a table # Report number of entries in a table
gravity_Table_Count() { gravity_Table_Count() {
local table="${1}" local table="${1}"
@ -916,7 +864,7 @@ gravity_ShowCount() {
# Trap Ctrl-C # Trap Ctrl-C
gravity_Trap() { gravity_Trap() {
trap '{ echo -e "\\n\\n ${INFO} ${COL_LIGHT_RED}User-abort detected${COL_NC}"; gravity_Cleanup "error"; }' INT trap '{ echo -e "\\n\\n ${INFO} ${COL_RED}User-abort detected${COL_NC}"; gravity_Cleanup "error"; }' INT
} }
# Clean up after Gravity upon exit or cancellation # Clean up after Gravity upon exit or cancellation
@ -934,13 +882,13 @@ gravity_Cleanup() {
# invalid_domains location # invalid_domains location
rm "${GRAVITY_TMPDIR}"/*.ph-non-domains 2>/dev/null rm "${GRAVITY_TMPDIR}"/*.ph-non-domains 2>/dev/null
# Ensure this function only runs when gravity_SetDownloadOptions() has completed # Ensure this function only runs when gravity_DownloadBlocklists() has completed
if [[ "${gravity_Blackbody:-}" == true ]]; then if [[ "${DownloadBlocklists_done:-}" == true ]]; then
# Remove any unused .domains files # Remove any unused .domains/.etag/.sha files
for file in "${piholeDir}"/*."${domainsExtension}"; do for file in "${listsCacheDir}"/*."${domainsExtension}"; do
# If list is not in active array, then remove it # If list is not in active array, then remove it and all associated files
if [[ ! "${activeDomains[*]}" == *"${file}"* ]]; then if [[ ! "${activeDomains[*]}" == *"${file}"* ]]; then
rm -f "${file}" 2>/dev/null || rm -f "${file}"* 2>/dev/null ||
echo -e " ${CROSS} Failed to remove ${file##*/}" echo -e " ${CROSS} Failed to remove ${file##*/}"
fi fi
done done
@ -1074,7 +1022,7 @@ migrate_to_listsCache_dir() {
# If not, we need to migrate the old files to the new directory # If not, we need to migrate the old files to the new directory
local str="Migrating the list's cache directory to new location" local str="Migrating the list's cache directory to new location"
echo -ne " ${INFO} ${str}..." echo -ne " ${INFO} ${str}..."
mkdir -p "${listsCacheDir}" mkdir -p "${listsCacheDir}" && chown pihole:pihole "${listsCacheDir}"
# Move the old files to the new directory # Move the old files to the new directory
if mv "${piholeDir}"/list.* "${listsCacheDir}/" 2>/dev/null; then if mv "${piholeDir}"/list.* "${listsCacheDir}/" 2>/dev/null; then
@ -1133,13 +1081,19 @@ for var in "$@"; do
"-t" | "--timeit") timed=true ;; "-t" | "--timeit") timed=true ;;
"-r" | "--repair") repairSelector "$3" ;; "-r" | "--repair") repairSelector "$3" ;;
"-u" | "--upgrade") "-u" | "--upgrade")
upgrade_gravityDB "${gravityDBfile}" "${piholeDir}" upgrade_gravityDB "${gravityDBfile}"
exit 0 exit 0
;; ;;
"-h" | "--help") helpFunc ;; "-h" | "--help") helpFunc ;;
esac esac
done done
# Check if DNS is available, no need to do any database manipulation if we're not able to download adlists
if ! timeit gravity_CheckDNSResolutionAvailable; then
echo -e " ${CROSS} No DNS resolution available. Please contact support."
exit 1
fi
# Remove OLD (backup) gravity file, if it exists # Remove OLD (backup) gravity file, if it exists
if [[ -f "${gravityOLDfile}" ]]; then if [[ -f "${gravityOLDfile}" ]]; then
rm "${gravityOLDfile}" rm "${gravityOLDfile}"
@ -1180,11 +1134,6 @@ if [[ "${forceDelete:-}" == true ]]; then
fi fi
# Gravity downloads blocklists next # Gravity downloads blocklists next
if ! timeit gravity_CheckDNSResolutionAvailable; then
echo -e " ${CROSS} Can not complete gravity update, no DNS is available. Please contact support."
exit 1
fi
if ! gravity_DownloadBlocklists; then if ! gravity_DownloadBlocklists; then
echo -e " ${CROSS} Unable to create gravity database. Please try again later. If the problem persists, please contact support." echo -e " ${CROSS} Unable to create gravity database. Please try again later. If the problem persists, please contact support."
exit 1 exit 1

View File

@ -23,7 +23,7 @@ pihole -r
.br .br
\fBpihole -g\fR \fBpihole -g\fR
.br .br
\fBpihole\fR -\fBq\fR [options] \fBpihole\fR \fB-q\fR [options]
.br .br
\fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR) \fBpihole\fR \fB-l\fR (\fBon|off|off noflush\fR)
.br .br
@ -43,7 +43,7 @@ pihole -r
.br .br
\fBpihole\fR \fBcheckout\fR repo [branch] \fBpihole\fR \fBcheckout\fR repo [branch]
.br .br
\fBpihole\fR \api\fR endpoint \fBpihole\fR \fBapi\fR [verbose] endpoint
.br .br
\fBpihole\fR \fBhelp\fR \fBpihole\fR \fBhelp\fR
.br .br
@ -234,10 +234,14 @@ Available commands and options:
branchname Update subsystems to the specified branchname branchname Update subsystems to the specified branchname
.br .br
\fBapi\fR endpoint \fBapi\fR [verbose] endpoint
.br .br
Query the Pi-hole API at <endpoint> Query the Pi-hole API at <endpoint>
.br .br
verbose Show authentication and status messages
.br
.SH "EXAMPLE" .SH "EXAMPLE"
Some usage examples Some usage examples
@ -323,6 +327,11 @@ Switching Pi-hole subsystem branches
Queries FTL for the stats/summary endpoint Queries FTL for the stats/summary endpoint
.br .br
\fBpihole api verbose stats/summary\fR
.br
Same as above, but shows authentication and status messages
.br
.SH "COLOPHON" .SH "COLOPHON"
Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net. Get sucked into the latest news and community activity by entering Pi-hole's orbit. Information about Pi-hole, and the latest version of the software can be found at https://pi-hole.net.

38
pihole
View File

@ -9,7 +9,7 @@
# This file is copyright under the latest version of the EUPL. # This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license. # Please see LICENSE file for your rights under this license.
readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" PI_HOLE_SCRIPT_DIR="/opt/pihole"
# PI_HOLE_BIN_DIR is not readonly here because in some functions (checkout), # PI_HOLE_BIN_DIR is not readonly here because in some functions (checkout),
# they might get set again when the installer is sourced. This causes an # they might get set again when the installer is sourced. This causes an
@ -17,13 +17,16 @@ readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
PI_HOLE_BIN_DIR="/usr/local/bin" PI_HOLE_BIN_DIR="/usr/local/bin"
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE" readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
# shellcheck source=./advanced/Scripts/COL_TABLE
source "${colfile}" source "${colfile}"
readonly utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
# shellcheck source=./advanced/Scripts/utils.sh
source "${utilsfile}" source "${utilsfile}"
# Source api functions # Source api functions
readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh" readonly apifile="${PI_HOLE_SCRIPT_DIR}/api.sh"
# shellcheck source=./advanced/Scripts/api.sh
source "${apifile}" source "${apifile}"
versionsfile="/etc/pihole/versions" versionsfile="/etc/pihole/versions"
@ -31,6 +34,7 @@ if [ -f "${versionsfile}" ]; then
# Only source versionsfile if the file exits # Only source versionsfile if the file exits
# fixes a warning during installation where versionsfile does not exist yet # fixes a warning during installation where versionsfile does not exist yet
# but gravity calls `pihole -status` and thereby sourcing the file # but gravity calls `pihole -status` and thereby sourcing the file
# shellcheck source=/dev/null
source "${versionsfile}" source "${versionsfile}"
fi fi
@ -234,7 +238,7 @@ Time:
fi fi
if [[ ${error} == true ]];then if [[ ${error} == true ]];then
echo -e " ${COL_LIGHT_RED}Unknown format for blocking timer!${COL_NC}" echo -e " ${COL_RED}Unknown format for blocking timer!${COL_NC}"
echo -e " Try 'pihole disable --help' for more information." echo -e " Try 'pihole disable --help' for more information."
exit 1 exit 1
fi fi
@ -247,12 +251,14 @@ Time:
data=$(PostFTLData "dns/blocking" "{ \"blocking\": ${1}, \"timer\": ${tt} }") data=$(PostFTLData "dns/blocking" "{ \"blocking\": ${1}, \"timer\": ${tt} }")
# Check the response # Check the response
local extra=" forever" local extra timer
local timer="$(echo "${data}"| jq --raw-output '.timer' )" extra=" forever"
timer="$(echo "${data}"| jq --raw-output '.timer' )"
if [[ "${timer}" != "null" ]]; then if [[ "${timer}" != "null" ]]; then
extra=" for ${timer}s" extra=" for ${timer}s"
fi fi
local str="Pi-hole $(echo "${data}" | jq --raw-output '.blocking')${extra}" local str
str="Pi-hole $(echo "${data}" | jq --raw-output '.blocking')${extra}"
# Logout from the API # Logout from the API
LogoutAPI LogoutAPI
@ -287,7 +293,7 @@ Options:
echo -e " ${INFO} Enabling logging..." echo -e " ${INFO} Enabling logging..."
local str="Logging has been enabled!" local str="Logging has been enabled!"
else else
echo -e " ${COL_LIGHT_RED}Invalid option${COL_NC} echo -e " ${COL_RED}Invalid option${COL_NC}
Try 'pihole logging --help' for more information." Try 'pihole logging --help' for more information."
exit 1 exit 1
fi fi
@ -375,20 +381,22 @@ statusFunc() {
tailFunc() { tailFunc() {
# Warn user if Pi-hole's logging is disabled # Warn user if Pi-hole's logging is disabled
local logging_enabled=$(getFTLConfigValue dns.queryLogging) local logging_enabled
logging_enabled=$(getFTLConfigValue dns.queryLogging)
if [[ "${logging_enabled}" != "true" ]]; then if [[ "${logging_enabled}" != "true" ]]; then
echo " ${CROSS} Warning: Query logging is disabled" echo " ${CROSS} Warning: Query logging is disabled"
fi fi
echo -e " ${INFO} Press Ctrl-C to exit" echo -e " ${INFO} Press Ctrl-C to exit"
# Get logfile path # Get logfile path
readonly LOGFILE=$(getFTLConfigValue files.log.dnsmasq) LOGFILE=$(getFTLConfigValue files.log.dnsmasq)
readonly LOGFILE
# Strip date from each line # Strip date from each line
# Color blocklist/denylist/wildcard entries as red # Color blocklist/denylist/wildcard entries as red
# Color A/AAAA/DHCP strings as white # Color A/AAAA/DHCP strings as white
# Color everything else as gray # Color everything else as gray
tail -f $LOGFILE | grep --line-buffered "${1}" | sed -E \ tail -f $LOGFILE | grep --line-buffered -- "${1}" | sed -E \
-e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \ -e "s,($(date +'%b %d ')| dnsmasq\[[0-9]*\]),,g" \
-e "s,(.*(denied |gravity blocked ).*),${COL_RED}&${COL_NC}," \ -e "s,(.*(denied |gravity blocked ).*),${COL_RED}&${COL_NC}," \
-e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \ -e "s,.*(query\\[A|DHCP).*,${COL_NC}&${COL_NC}," \
@ -423,6 +431,7 @@ piholeCheckoutFunc() {
exit 0 exit 0
fi fi
#shellcheck source=./advanced/Scripts/piholeCheckout.sh
source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh
shift shift
checkout "$@" checkout "$@"
@ -484,6 +493,7 @@ Debugging Options:
Add an optional argument to filter the log Add an optional argument to filter the log
(regular expressions are supported) (regular expressions are supported)
api <endpoint> Query the Pi-hole API at <endpoint> api <endpoint> Query the Pi-hole API at <endpoint>
Precede <endpoint> with 'verbose' option to show authentication and status messages
Options: Options:
@ -542,7 +552,7 @@ case "${1}" in
"enable" ) need_root=0;; "enable" ) need_root=0;;
"disable" ) need_root=0;; "disable" ) need_root=0;;
"-d" | "debug" ) ;; "-d" | "debug" ) ;;
"-g" | "updateGravity" ) ;; "-g" | "updateGravity" ) need_root=0;;
"reloaddns" ) ;; "reloaddns" ) ;;
"reloadlists" ) ;; "reloadlists" ) ;;
"setpassword" ) ;; "setpassword" ) ;;
@ -560,9 +570,9 @@ if [[ -z ${USER} ]]; then
USER=$(whoami) USER=$(whoami)
fi fi
# Check if the current user is neither root nor pihole and if the command # Check if the current user is not root and if the command
# requires root. If so, exit with an error message. # requires root. If so, exit with an error message.
if [[ $EUID -ne 0 && ${USER} != "pihole" && need_root -eq 1 ]];then if [[ $EUID -ne 0 && need_root -eq 1 ]];then
echo -e " ${CROSS} The Pi-hole command requires root privileges, try:" echo -e " ${CROSS} The Pi-hole command requires root privileges, try:"
echo -e " ${COL_GREEN}sudo pihole $*${COL_NC}" echo -e " ${COL_GREEN}sudo pihole $*${COL_NC}"
exit 1 exit 1
@ -592,6 +602,6 @@ case "${1}" in
"updatechecker" ) shift; updateCheckFunc "$@";; "updatechecker" ) shift; updateCheckFunc "$@";;
"arpflush" ) arpFunc "$@";; "arpflush" ) arpFunc "$@";;
"-t" | "tail" ) tailFunc "$2";; "-t" | "tail" ) tailFunc "$2";;
"api" ) apiFunc "$2";; "api" ) shift; apiFunc "$@";;
* ) helpFunc;; * ) helpFunc;;
esac esac

View File

@ -0,0 +1,19 @@
FROM quay.io/centos/centos:stream10
# Disable SELinux
RUN echo "SELINUX=disabled" > /etc/selinux/config
RUN yum install -y --allowerasing curl git initscripts
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
RUN true && \
chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -15,6 +15,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -13,6 +13,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -13,6 +13,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -0,0 +1,17 @@
FROM fedora:42
RUN dnf install -y git initscripts
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
RUN true && \
chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -12,6 +12,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -13,6 +13,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -13,6 +13,5 @@ RUN true && \
chmod +x $SCRIPTDIR/* chmod +x $SCRIPTDIR/*
ENV SKIP_INSTALL=true 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 && \ #sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \

View File

@ -1,6 +1,6 @@
pyyaml == 6.0.2 pyyaml == 6.0.2
pytest == 8.3.4 pytest == 8.4.1
pytest-xdist == 3.6.1 pytest-xdist == 3.8.0
pytest-testinfra == 10.1.1 pytest-testinfra == 10.2.2
tox == 4.24.1 tox == 4.27.0
pytest-clarity == 1.0.1 pytest-clarity == 1.0.1

View File

@ -89,10 +89,8 @@ def test_installPihole_fresh_install_readableFiles(host):
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
umask 0027 umask 0027
runUnattended=true runUnattended=true
fresh_install=false
source /opt/pihole/basic-install.sh > /dev/null source /opt/pihole/basic-install.sh > /dev/null
runUnattended=true runUnattended=true
fresh_install=false
main main
/opt/pihole/pihole-FTL-prestart.sh /opt/pihole/pihole-FTL-prestart.sh
""" """
@ -245,6 +243,7 @@ def test_FTL_detect_no_errors(host, arch, detected_string, supported):
{ {
"-A /bin/sh": ("Tag_CPU_arch: " + arch, "0"), "-A /bin/sh": ("Tag_CPU_arch: " + arch, "0"),
"-A /usr/bin/sh": ("Tag_CPU_arch: " + arch, "0"), "-A /usr/bin/sh": ("Tag_CPU_arch: " + arch, "0"),
"-A /usr/sbin/sh": ("Tag_CPU_arch: " + arch, "0"),
}, },
host, host,
) )
@ -465,50 +464,6 @@ def test_validate_ip(host):
test_address("0.0.0.0#00001", False) test_address("0.0.0.0#00001", False)
def test_os_check_fails(host):
"""Confirms install fails on unsupported OS"""
host.run(
"""
source /opt/pihole/basic-install.sh
package_manager_detect
build_dependency_package
install_dependent_packages
cat <<EOT > /etc/os-release
ID=UnsupportedOS
VERSION_ID="2"
EOT
"""
)
detectOS = host.run(
"""t
source /opt/pihole/basic-install.sh
os_check
"""
)
expected_stdout = "Unsupported OS detected: UnsupportedOS"
assert expected_stdout in detectOS.stdout
def test_os_check_passes(host):
"""Confirms OS meets the requirements"""
host.run(
"""
source /opt/pihole/basic-install.sh
package_manager_detect
build_dependency_package
install_dependent_packages
"""
)
detectOS = host.run(
"""
source /opt/pihole/basic-install.sh
os_check
"""
)
expected_stdout = "Supported OS detected"
assert expected_stdout in detectOS.stdout
def test_package_manager_has_pihole_deps(host): def test_package_manager_has_pihole_deps(host):
"""Confirms OS is able to install the required packages for Pi-hole""" """Confirms OS is able to install the required packages for Pi-hole"""
mock_command("dialog", {"*": ("", "0")}, host) mock_command("dialog", {"*": ("", "0")}, host)
@ -516,6 +471,7 @@ def test_package_manager_has_pihole_deps(host):
""" """
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
update_package_cache
build_dependency_package build_dependency_package
install_dependent_packages install_dependent_packages
""" """
@ -532,6 +488,7 @@ def test_meta_package_uninstall(host):
""" """
source /opt/pihole/basic-install.sh source /opt/pihole/basic-install.sh
package_manager_detect package_manager_detect
update_package_cache
build_dependency_package build_dependency_package
install_dependent_packages install_dependent_packages
""" """

10
test/tox.centos_10.ini Normal file
View File

@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv:py3]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _centos_10.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py

10
test/tox.fedora_42.ini Normal file
View File

@ -0,0 +1,10 @@
[tox]
envlist = py3
[testenv]
allowlist_externals = docker
deps = -rrequirements.txt
setenv =
COLUMNS=120
commands = docker buildx build --load --progress plain -f _fedora_42.Dockerfile -t pytest_pihole:test_container ../
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py