/adblock/install.sh
Shell | 613 lines | 517 code | 52 blank | 44 comment | 82 complexity | 4cf811cb31b5a54ff457cfe45fbcf05e MD5 | raw file
- #!/bin/sh
- # Version: 2.0.1
- # Author: Héctor Molinero Fernández <hector@molinero.xyz>
- # Repository: https://github.com/hectorm/hblock
- # License: MIT, https://opensource.org/licenses/MIT
- set -eu
- export LC_ALL=C
- # shellcheck disable=SC2039
- HOSTNAME=${HOSTNAME-$(uname -n)}
- # Builtin values
- BUILTIN_HEADER=$(cat <<-EOF
- 127.0.0.1 localhost $HOSTNAME
- 255.255.255.255 broadcasthost
- ::1 localhost ip6-localhost ip6-loopback
- fe00::0 ip6-localnet
- ff00::0 ip6-mcastprefix
- ff02::1 ip6-allnodes
- ff02::2 ip6-allrouters
- ff02::3 ip6-allhosts
- EOF
- )
- BUILTIN_FOOTER=''
- BUILTIN_SOURCES=$(cat <<-'EOF'
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/adaway.org/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/adblock-nocoin-list/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/adguard-simplified/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-ad/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-malvertising/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-malware/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/disconnect.me-tracking/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/easylist/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/easyprivacy/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/eth-phishing-detect/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.2o7net/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.dead/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.risk/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/fademind-add.spam/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/kadhosts/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomainlist.com/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomains.com-immortaldomains/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/malwaredomains.com-justdomains/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/matomo.org-spammers/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/mitchellkrogza-badd-boyz-hosts/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/pgl.yoyo.org/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/ransomwaretracker.abuse.ch/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/someonewhocares.org/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/spam404.com/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/stevenblack/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/winhelp2002.mvps.org/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/zerodot1-coinblockerlists-browser/list.txt
- https://raw.githubusercontent.com/hectorm/hmirror/master/data/zeustracker.abuse.ch/list.txt
- https://dbl.oisd.nl/
- EOF
- )
- BUILTIN_WHITELIST=$(cat <<-'EOF'
- EOF
- )
- BUILTIN_BLACKLIST=$(cat <<-'EOF'
- pubads.g.doubleclick.net
- securepubads.g.doubleclick.net
- addthis.com
- addtoany.com
- amung.us
- bebi.com
- bodelen.com
- clcknads.pro
- coostuni.com
- defpush.com
- fuxoasim.link
- glotchat.click
- jeeshapi.net
- juicyads.com
- lovacmar.click
- mgid.com
- padstm.com
- revrtb.com
- riluaneth.com
- rudsools.net
- vidcpm.com
- vukhhjzd.com
- wallstrads.com
- wynather.com
- yadro.ru
- yandex.ru
- ytimg.com
- EOF
- )
- # Check if a program exists
- exists() {
- # shellcheck disable=SC2230
- if command -v true; then command -v -- "$1"
- elif eval type type; then eval type -- "$1"
- else which -- "$1"; fi >/dev/null 2>&1
- }
- # Escape strings in sed
- # See: https://stackoverflow.com/a/29613573
- quoteRe() { printf -- '%s' "$1" | sed -e 's/[^^]/[&]/g; s/\^/\\^/g; $!a'\\''"$(printf '\n')"'\\n' | tr -d '\n'; }
- quoteSubst() { printf -- '%s' "$1" | sed -e ':a' -e '$!{N;ba' -e '}' -e 's/[&/\]/\\&/g; s/\n/\\&/g'; }
- # Remove comments from string
- removeComments() { printf -- '%s' "$1" | sed -e 's/[[:blank:]]*#.*//'; }
- # Translate true/false to yes/no
- getBoolVal() { [ "$1" = true ] && s='yes' || s='no'; printf -- '%s' "$s"; }
- # Print to stdout if quiet mode is not enabled
- printStdout() {
- if [ "$quiet" != true ]; then
- # shellcheck disable=SC2059
- printf -- "$@"
- fi
- }
- # Print to stderr
- printStderr() {
- # shellcheck disable=SC2059
- >&2 printf -- "$@"
- }
- # Print informational message
- logInfo() {
- printStdout ' - %s\n' "$@"
- }
- # Print action message
- logAction() {
- if [ "$color" = true ]; then
- printStdout '\033[1;33m + \033[1;32m%s \033[0m\n' "$@"
- else
- printStdout ' + %s \n' "$@"
- fi
- }
- # Print error message
- logError() {
- if [ "$color" = true ]; then
- printStderr '\033[1;33m + \033[1;31m%s \033[0m\n' "$@"
- else
- printStderr ' + %s \n' "$@"
- fi
- }
- # Create temporary file
- createTempFile() {
- if exists mktemp; then mktemp
- else # Since POSIX does not specify mktemp utility, use this as fallback
- tempCounter=${tempCounter:-9999}
- tempFile="${TMPDIR:-/tmp}/hblock.$$.$((tempCounter+=1))"
- rm -f -- "$tempFile" && (umask 077 && touch -- "$tempFile")
- printf -- '%s\n' "$tempFile"
- fi
- }
- # Print to stdout the contents of a URL
- fetchUrl() {
- # If the protocol is "file://" we can omit the download and simply use cat
- if [ "${1#file://}" != "$1" ]; then cat -- "${1#file://}"
- else
- userAgent='Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0'
- if exists curl; then curl -fsSL -A "$userAgent" -- "$1";
- elif exists wget; then wget -qO- -U "$userAgent" -- "$1";
- else
- logError 'Either wget or curl are required for this script'
- exit 1
- fi
- fi
- }
- # Show help and quit
- showHelp() {
- if [ $# -eq 0 ]; then
- printStdout '%s\n' "$(cat <<-'EOF'
- Usage: hblock [options...]
- -O, --output <FILE>
- Output file location
- (default: "/etc/hosts" file)
- -H, --header <FILE>
- Content to be included at the beginning of the output file
- (default: HBLOCK_HEADER environment variable,
- "/etc/hblock.d/header" file or builtin value)
- -F, --footer <FILE>
- Content to be included at the end of the output file
- (default: HBLOCK_FOOTER environment variable,
- "/etc/hblock.d/footer" file or builtin value)
- -S, --sources <FILE>
- Newline separated URLs used to generate the blocklist
- (default: HBLOCK_SOURCES environment variable,
- "/etc/hblock.d/sources.list" file or builtin value)
- -W, --whitelist <FILE>
- Newline separated domains to be removed from the blocklist
- (default: HBLOCK_WHITELIST environment variable,
- "/etc/hblock.d/whitelist.list" file or builtin value)
- -B, --blacklist <FILE>
- Newline separated domains to be added to the blocklist
- (default: HBLOCK_BLACKLIST environment variable,
- "/etc/hblock.d/blacklist.list" file or builtin value)
- -R, --redirection <REDIRECTION>
- Redirection for all entries in the blocklist
- (default: 0.0.0.0)
- -T, --template <TEMPLATE>
- POSIX BREs replacement applied to each entry
- \1 = <DOMAIN>, \2 = <REDIRECTION>
- (default: \2 \1)
- -C, --comment <COMMENT>
- Character used for comments
- (default: #)
- -b, --backup [DIRECTORY]
- Make a time-stamped backup in <DIRECTORY>
- (default: output file directory)
- -l, --lenient
- Match all entries from sources, regardless of their IP
- (default: 0.0.0.0, 127.0.0.1 or none)
- -r, --enable-regex-whitelist
- Use POSIX BREs instead of fixed strings
- -i, --ignore-download-error
- Do not abort if a download error occurs
- -c, --color <auto|true|false>
- Colorize the output
- (default: auto)
- -q, --quiet
- Suppress non-error messages
- -v, --version
- Show version number and quit
- -h, --help
- Show this help and quit
- Report bugs to: <https://github.com/hectorm/hblock/issues>.
- EOF
- )"
- exit 0
- else
- [ -n "$1" ] && printStderr '%s\n' "Illegal option $1"
- printStderr '%s\n' "Try 'hblock --help' for more information"
- exit 1
- fi
- }
- # Show version number and quit
- showVersion() {
- printStdout '%s\n' '2.0.1'
- exit 0
- }
- main() {
- outputFile='/etc/hosts'
- headerFile='/etc/hblock.d/header'; defaultHeaderFile=$headerFile; header=''
- footerFile='/etc/hblock.d/footer'; defaultFooterFile=$footerFile; footer=''
- sourcesFile='/etc/hblock.d/sources.list'; defaultSourcesFile=$sourcesFile; sources=''
- whitelistFile='/etc/hblock.d/whitelist.list'; defaultWhitelistFile=$whitelistFile; whitelist=''
- blacklistFile='/etc/hblock.d/blacklist.list'; defaultBlacklistFile=$blacklistFile; blacklist=''
- redirection='0.0.0.0'
- template='\2 \1'
- comment='#'
- backup=false
- lenient=false
- enableWhitelistRegex=false
- ignoreDownloadError=false
- color=auto
- quiet=false
- # Transform long options to short ones
- for opt in "$@"; do
- shift
- case "$opt" in
- '--output') set -- "$@" '-O' ;;
- '--header') set -- "$@" '-H' ;;
- '--footer') set -- "$@" '-F' ;;
- '--sources') set -- "$@" '-S' ;;
- '--whitelist') set -- "$@" '-W' ;;
- '--blacklist') set -- "$@" '-B' ;;
- '--redirection') set -- "$@" '-R' ;;
- '--template') set -- "$@" '-T' ;;
- '--comment') set -- "$@" '-C' ;;
- '--backup') set -- "$@" '-b' ;;
- '--lenient') set -- "$@" '-l' ;;
- '--enable-regex-whitelist') set -- "$@" '-r' ;;
- '--ignore-download-error') set -- "$@" '-i' ;;
- '--color') set -- "$@" '-c' ;;
- '--quiet') set -- "$@" '-q' ;;
- '--version') set -- "$@" '-v' ;;
- '--help') set -- "$@" '-h' ;;
- *) set -- "$@" "$opt"
- esac
- done
- # Set omitted arguments to empty strings
- for opt in "$@"; do
- shift
- case "$opt" in
- -*b)
- if a="$*"; [ -z "$a" ] || [ "${a#\-}x" != "${a}x" ]
- then set -- "$@" "$opt" ''
- else set -- "$@" "$opt"
- fi
- ;;
- *) set -- "$@" "$opt"
- esac
- done
- # Read short options
- OPTIND=1
- while getopts ':O:H:F:S:W:B:R:T:C:b:lric:qvh-:' opt; do
- case "$opt" in
- 'O') outputFile="$OPTARG" ;;
- 'H') headerFile="$OPTARG" ;;
- 'F') footerFile="$OPTARG" ;;
- 'S') sourcesFile="$OPTARG" ;;
- 'W') whitelistFile="$OPTARG" ;;
- 'B') blacklistFile="$OPTARG" ;;
- 'R') redirection="$OPTARG" ;;
- 'T') template="$OPTARG" ;;
- 'C') comment="$OPTARG" ;;
- 'b') backup=true; backupDir="$OPTARG" ;;
- 'l') lenient=true ;;
- 'r') enableWhitelistRegex=true ;;
- 'i') ignoreDownloadError=true ;;
- 'c') color="$OPTARG" ;;
- 'q') quiet=true ;;
- 'v') showVersion ;;
- 'h') showHelp ;;
- '-') showHelp "--$OPTARG" ;;
- *) showHelp "-$OPTARG"
- esac
- done
- # Check color support
- if [ "$color" = auto ]; then
- [ -t 1 ] && color=true || color=false
- fi
- # Priority: $headerFile > $HBLOCK_HEADER > $defaultHeaderFile > builtin
- if [ "$headerFile" != "$defaultHeaderFile" ]; then
- header=$(cat -- "$headerFile")
- headerOrigin=$headerFile
- elif [ "${HBLOCK_HEADER+def}" = def ]; then
- header=$HBLOCK_HEADER
- headerOrigin=environment
- elif [ -f "$headerFile" ]; then
- header=$(cat -- "$headerFile")
- headerOrigin=$headerFile
- else
- header=$BUILTIN_HEADER
- headerOrigin=builtin
- fi
- # Priority: $footerFile > $HBLOCK_FOOTER > $defaultFooterFile > builtin
- if [ "$footerFile" != "$defaultFooterFile" ]; then
- footer=$(cat -- "$footerFile")
- footerOrigin=$footerFile
- elif [ "${HBLOCK_FOOTER+def}" = def ]; then
- footer=$HBLOCK_FOOTER
- footerOrigin=environment
- elif [ -f "$footerFile" ]; then
- footer=$(cat -- "$footerFile")
- footerOrigin=$footerFile
- else
- footer=$BUILTIN_FOOTER
- footerOrigin=builtin
- fi
- # Priority: $sourcesFile > $HBLOCK_SOURCES > $defaultSourcesFile > builtin
- if [ "$sourcesFile" != "$defaultSourcesFile" ]; then
- sources=$(cat -- "$sourcesFile")
- sourcesOrigin=$sourcesFile
- elif [ "${HBLOCK_SOURCES+def}" = def ]; then
- sources=$HBLOCK_SOURCES
- sourcesOrigin=environment
- elif [ -f "$sourcesFile" ]; then
- sources=$(cat -- "$sourcesFile")
- sourcesOrigin=$sourcesFile
- else
- sources=$BUILTIN_SOURCES
- sourcesOrigin=builtin
- fi
- sources=$(removeComments "$sources")
- # Priority: $whitelistFile > $HBLOCK_WHITELIST > $defaultWhitelistFile > builtin
- if [ "$whitelistFile" != "$defaultWhitelistFile" ]; then
- whitelist=$(cat -- "$whitelistFile")
- whitelistOrigin=$whitelistFile
- elif [ "${HBLOCK_WHITELIST+def}" = def ]; then
- whitelist=$HBLOCK_WHITELIST
- whitelistOrigin=environment
- elif [ -f "$whitelistFile" ]; then
- whitelist=$(cat -- "$whitelistFile")
- whitelistOrigin=$whitelistFile
- else
- whitelist=$BUILTIN_WHITELIST
- whitelistOrigin=builtin
- fi
- whitelist=$(removeComments "$whitelist")
- # Priority: $blacklistFile > $HBLOCK_BLACKLIST > $defaultBlacklistFile > builtin
- if [ "$blacklistFile" != "$defaultBlacklistFile" ]; then
- blacklist=$(cat -- "$blacklistFile")
- blacklistOrigin=$blacklistFile
- elif [ "${HBLOCK_BLACKLIST+def}" = def ]; then
- blacklist=$HBLOCK_BLACKLIST
- blacklistOrigin=environment
- elif [ -f "$blacklistFile" ]; then
- blacklist=$(cat -- "$blacklistFile")
- blacklistOrigin=$blacklistFile
- else
- blacklist=$BUILTIN_BLACKLIST
- blacklistOrigin=builtin
- fi
- blacklist=$(removeComments "$blacklist")
- logAction 'Configuration:'
- logInfo "Output: $outputFile"
- logInfo "Header: $headerOrigin"
- logInfo "Footer: $footerOrigin"
- logInfo "Sources: $sourcesOrigin"
- logInfo "Whitelist: $whitelistOrigin"
- logInfo "Blacklist: $blacklistOrigin"
- logInfo "Redirection: $redirection"
- logInfo "Template: $template"
- logInfo "Comment: $comment"
- logInfo "Backup: $(getBoolVal "$backup")"
- logInfo "Lenient: $(getBoolVal "$lenient")"
- logInfo "Enable regex in whitelist: $(getBoolVal "$enableWhitelistRegex")"
- logInfo "Ignore download error: $(getBoolVal "$ignoreDownloadError")"
- # Create temporary blocklist file
- blocklistFile=$(createTempFile)
- rmtemp() { rm -f -- "$blocklistFile" "$blocklistFile".aux.*; }
- trap rmtemp EXIT
- logAction 'Downloading lists...'
- _IFS=$IFS; IFS="$(printf '\nx')"; IFS="${IFS%x}"
- for url in $sources; do
- logInfo "$url"
- fetchUrl "$url" >> "$blocklistFile" && exitCode=0 || exitCode=$?
- if [ "$exitCode" -ne 0 ] && [ "$ignoreDownloadError" != true ]; then
- logError 'Download failed'
- exit 1
- fi
- done
- IFS=$_IFS
- logAction 'Parsing lists...'
- if [ -s "$blocklistFile" ]; then
- logInfo 'Remove carriage return'
- tr -d '\r' \
- < "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Transform to lowercase'
- tr '[:upper:]' '[:lower:]' \
- < "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Remove comments'
- sed -e 's/#.*//' \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Trim spaces'
- sed -e 's/^[[:blank:]]*//' \
- -e 's/[[:blank:]]*$//' \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Match hosts lines'
- if [ "$lenient" = true ]; then
- # This regex would be ideal, but it is not POSIX-compliant.
- # ipOctetRegex='\(25[0-5]\|2[0-4][0-9]\|[01]\{0,1\}[0-9][0-9]\{0,1\}\)'
- # ipRegex="\\($ipOctetRegex\\.$ipOctetRegex\\.$ipOctetRegex\\.$ipOctetRegex\\)"
- ipRegex='\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}'
- else
- # Same as above.
- # ipRegex='\(\(0\.0\.0\.0\)\|\(127\.0\.0\.1\)\)'
- ipRegex='\(0\.0\.0\.0\)\{0,1\}\(127\.0\.0\.1\)\{0,1\}'
- fi
- domainRegex='\([0-9a-z_-]\{1,63\}\.\)\{1,\}[a-z][0-9a-z_-]\{1,62\}'
- sed -n \
- -e "/^\\(${ipRegex}[[:blank:]]\\{1,\\}\\)\\{0,1\\}$domainRegex$/p" \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Remove reserved TLDs'
- sed -e '/\.example$/d' \
- -e '/\.invalid$/d' \
- -e '/\.local$/d' \
- -e '/\.localdomain$/d' \
- -e '/\.localhost$/d' \
- -e '/\.test$/d' \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- logInfo 'Remove destination IPs'
- sed -e 's/^.\{1,\}[[:blank:]]\{1,\}//' \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- fi
- # This domain is used to check if hBlock is enabled
- printf -- '%s\n' 'hblock-check.molinero.xyz' >> "$blocklistFile"
- if [ -n "$blacklist" ]; then
- logInfo 'Apply blacklist'
- printf -- '%s' "$blacklist" >> "$blocklistFile"
- fi
- logInfo 'Sort entries'
- sort -- "$blocklistFile" | uniq | sed -e '/^$/d' > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- if [ -n "$whitelist" ]; then
- logInfo 'Apply whitelist'
- if [ "$enableWhitelistRegex" = true ]; then
- _IFS=$IFS; IFS="$(printf '\nx')"; IFS="${IFS%x}"
- for regex in $whitelist; do
- sed -e "/$regex/d" \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- done
- IFS=$_IFS
- else
- printf -- '%s' "$whitelist" | sort | uniq > "$blocklistFile.aux.2"
- comm -23 -- "$blocklistFile" "$blocklistFile.aux.2" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile" \
- && rm -f -- "$blocklistFile.aux.2"
- fi
- fi
- # Count blocked domains
- blocklistCount=$(wc -l < "$blocklistFile" | tr -d ' ');
- logInfo 'Apply format template'
- sed -e "s/$/\\t$(quoteSubst "$redirection")/" \
- -e "s/^\\(.*\\)\\t\\(.*\\)$/$template/" \
- -- "$blocklistFile" > "$blocklistFile.aux.1" \
- && mv -f -- "$blocklistFile.aux.1" "$blocklistFile"
- # Define "C" variable for convenience
- C=$comment
- if [ "$outputFile" != - ] && [ -f "$outputFile" ]; then
- # Backup procedure
- if [ "$backup" = true ]; then
- logAction 'Backing up original file...'
- [ -z "$backupDir" ] && backupDir=$(dirname -- "$outputFile")
- outputBackup="$backupDir/$(basename -- "$outputFile").$(date +%s).bak"
- if touch -- "$outputBackup" >/dev/null 2>&1; then
- cp -af -- "$outputFile" "$outputBackup"
- elif exists sudo; then
- sudo cp -af -- "$outputFile" "$outputBackup"
- else
- logError "Cannot write '$outputBackup': permission denied"
- exit 1
- fi
- fi
- fi
- logAction 'Generating output file...'
- printOutputFile() {
- if [ -n "$C" ]; then
- printf -- '%s\n' "$(cat <<-EOF
- $C Author: Héctor Molinero Fernández <hector@molinero.xyz>
- $C Repository: https://github.com/hectorm/hblock
- $C Last updated: $(date -u)
- $C Blocked domains: $blocklistCount
- EOF
- )"
- fi
- if [ -n "$header" ]; then
- if [ -n "$C" ]; then printf -- '\n%s\n' "$C <header>"; fi
- printf -- '%s\n' "$header"
- if [ -n "$C" ]; then printf -- '%s\n' "$C </header>"; fi
- fi
- if [ -s "$blocklistFile" ]; then
- if [ -n "$C" ]; then printf -- '\n%s\n' "$C <blocklist>"; fi
- cat -- "$blocklistFile"
- if [ -n "$C" ]; then printf -- '%s\n' "$C </blocklist>"; fi
- fi
- if [ -n "$footer" ]; then
- if [ -n "$C" ]; then printf -- '\n%s\n' "$C <footer>"; fi
- printf -- '%s\n' "$footer"
- if [ -n "$C" ]; then printf -- '%s\n' "$C </footer>"; fi
- fi
- }
- # Print to stdout if the output value is equal to -
- if [ "$outputFile" = - ]; then
- printOutputFile
- else
- if [ -d "$outputFile" ]; then
- logError "Cannot write '$outputFile': is a directory"
- exit 1
- elif touch -- "$outputFile" >/dev/null 2>&1; then
- printOutputFile > "$outputFile"
- elif exists sudo && exists tee; then
- printOutputFile | sudo tee -- "$outputFile" >/dev/null
- else
- logError "Cannot write '$outputFile': permission denied"
- exit 1
- fi
- fi
- logAction "$blocklistCount blocked domains!"
- }
- main "$@"