diff --git a/pihole-cloudsync b/pihole-cloudsync index db3eae3..a06531a 100755 --- a/pihole-cloudsync +++ b/pihole-cloudsync @@ -46,7 +46,7 @@ cname_list='05-pihole-custom-cname.conf' # Force sudo if not running with root privileges SUDO='' if [ "$EUID" -ne 0 ]; then - SUDO='sudo' + SUDO='sudo' fi # Attempt to detect pihole running in Docker @@ -54,210 +54,227 @@ DOCKER='' DOCKER_CMD="$(command -v docker)" JQ_CMD="$(command -v jq)" if [ -n "${DOCKER_CMD}" ]; then - CONTAINER="$(${DOCKER_CMD} ps -f "ancestor=pihole/pihole" --format "{{.Names}}")" - if [ -n "${CONTAINER}" ]; then - if [ -n "${JQ_CMD}" ]; then - echo "Found pihole running under Docker container '${CONTAINER}'" + CONTAINER="$(${DOCKER_CMD} ps -f "ancestor=pihole/pihole" --format "{{.Names}}")" + if [ -n "${CONTAINER}" ]; then + if [ -n "${JQ_CMD}" ]; then + echo "Found pihole running under Docker container '${CONTAINER}'" - pihole_dir="$(${DOCKER_CMD} inspect -f "{{json .Mounts}}" "${CONTAINER}" | ${JQ_CMD} -r --arg dir "${pihole_dir}" '.[] | select(.Destination==$dir) | .Source')" - gravity_db="${pihole_dir}/gravity.db" - dnsmasq_dir="$(${DOCKER_CMD} inspect -f "{{json .Mounts}}" "${CONTAINER}" | ${JQ_CMD} -r --arg dir "${dnsmasq_dir}" '.[] | select(.Destination==$dir) | .Source')" + pihole_dir="$(${DOCKER_CMD} inspect -f "{{json .Mounts}}" "${CONTAINER}" | ${JQ_CMD} -r --arg dir "${pihole_dir}" '.[] | select(.Destination==$dir) | .Source')" + gravity_db="${pihole_dir}/gravity.db" + dnsmasq_dir="$(${DOCKER_CMD} inspect -f "{{json .Mounts}}" "${CONTAINER}" | ${JQ_CMD} -r --arg dir "${dnsmasq_dir}" '.[] | select(.Destination==$dir) | .Source')" - echo "Found pihole directory mapped to '${pihole_dir}'" - echo "Found dnsmasq directory mapped to '${dnsmasq_dir}'" + echo "Found pihole directory mapped to '${pihole_dir}'" + echo "Found dnsmasq directory mapped to '${dnsmasq_dir}'" - DOCKER="${DOCKER_CMD} exec -i ${CONTAINER}" - else - echo "Found Docker container '${CONTAINER}' but jq is not installed" - fi - fi + DOCKER="${DOCKER_CMD} exec -i ${CONTAINER}" + else + echo "Found Docker container '${CONTAINER}' but jq is not installed" + fi + fi fi +export_table () { + table="$1" + + $SUDO sqlite3 $gravity_db -header -csv "SELECT * FROM \"$table\"" >"${table}.csv" +} + +import_table () { + table="$1" + + $SUDO sqlite3 $gravity_db "DROP TABLE \"$table\";" + $SUDO sqlite3 $gravity_db -header -csv ".import \"${table}.csv\" \"$table\"" +} + # FUNCTIONS push_initialize () { - # Go to Pi-hole directory, exit if doesn't exist - cd $pihole_dir || exit + # Go to Pi-hole directory, exit if doesn't exist + cd $pihole_dir || exit - # Verify Custom and CNAME lists exist - $SUDO touch $custom_list - $SUDO touch $dnsmasq_dir/$cname_list + # Verify Custom and CNAME lists exist + $SUDO touch $custom_list + $SUDO touch $dnsmasq_dir/$cname_list - # Copy local Custom and CNAME lists to local Git repo - $SUDO cp $custom_list $personal_git_dir - $SUDO cp $dnsmasq_dir/$cname_list $personal_git_dir + # Copy local Custom and CNAME lists to local Git repo + $SUDO cp $custom_list $personal_git_dir + $SUDO cp $dnsmasq_dir/$cname_list $personal_git_dir - # Go to local Git repo directory - cd $personal_git_dir || exit + # Go to local Git repo directory + cd $personal_git_dir || exit - # Export Ad and Domain lists from Gravity database - $SUDO sqlite3 $gravity_db -header -csv "SELECT * FROM adlist" >$ad_list - $SUDO sqlite3 $gravity_db -header -csv "SELECT * FROM domainlist" >$domain_list + # Export Ad and Domain lists from Gravity database + export_table "adlist" + export_table "domainlist" + export_table "group" + export_table "domainlist_by_group" - # Add all lists to local Git repo - $SUDO git add . - echo "Local Pi-hole initialized in Push mode and local lists were added to local Git repo. Run 'pihole-cloudsync --push' to push to remote Git repo."; + # Add all lists to local Git repo + $SUDO git add . + echo "Local Pi-hole initialized in Push mode and local lists were added to local Git repo. Run 'pihole-cloudsync --push' to push to remote Git repo."; } pull_initialize () { - branch=$1 - if [ -z "${branch}" ]; then - branch="master" - fi + branch=$1 + if [ -z "${branch}" ]; then + branch="master" + fi - # Go to Pi-hole directory, exit if doesn't exist - cd $personal_git_dir || exit + # Go to Pi-hole directory, exit if doesn't exist + cd $personal_git_dir || exit - # Update local Git repo from remote Git repo - $SUDO git remote update > /dev/null + # Update local Git repo from remote Git repo + $SUDO git remote update > /dev/null - # Remove -q option if you don't want to run in "quiet" mode - $SUDO git fetch --all -q - $SUDO git reset --hard "origin/${branch}" -q + # Remove -q option if you don't want to run in "quiet" mode + $SUDO git fetch --all -q + $SUDO git reset --hard "origin/${branch}" -q - # Stop DNS server - $SUDO ${DOCKER} service pihole-FTL stop + # Stop DNS server + $SUDO ${DOCKER} service pihole-FTL stop - # Overwrite local files - $SUDO cp $custom_list $pihole_dir - $SUDO cp $cname_list $dnsmasq_dir + # Overwrite local files + $SUDO cp $custom_list $pihole_dir + $SUDO cp $cname_list $dnsmasq_dir - # Overwrite local database tables - $SUDO sqlite3 $gravity_db "DROP TABLE adlist;" - $SUDO sqlite3 $gravity_db -header -csv ".import adlist.csv adlist" - $SUDO sqlite3 $gravity_db "DROP TABLE domainlist;" - $SUDO sqlite3 $gravity_db -header -csv ".import domainlist.csv domainlist" + # Overwrite local database tables + import_table "adlist" + import_table "domainlist" + import_table "group" + import_table "domainlist_by_group" - # Restart Pi-hole to pick up changes - $SUDO ${DOCKER} pihole -g + # Restart Pi-hole to pick up changes + $SUDO ${DOCKER} pihole -g - # Display success messages - echo "Local Pi-hole initialized in Pull mode and first pull successfully completed."; - echo "Future pulls can now be perfomed with 'pihole-cloudsync --pull'."; + # Display success messages + echo "Local Pi-hole initialized in Pull mode and first pull successfully completed."; + echo "Future pulls can now be perfomed with 'pihole-cloudsync --pull'."; } push () { - # Go to Pi-hole directory, exit if doesn't exist - cd $pihole_dir || exit + # Go to Pi-hole directory, exit if doesn't exist + cd $pihole_dir || exit - # Copy local Custom and CNAME lists to local Git repo - $SUDO cp $custom_list $personal_git_dir - $SUDO cp $dnsmasq_dir/$cname_list $personal_git_dir + # Copy local Custom and CNAME lists to local Git repo + $SUDO cp $custom_list $personal_git_dir + $SUDO cp $dnsmasq_dir/$cname_list $personal_git_dir - # Go to local Git repo directory - cd $personal_git_dir || exit + # Go to local Git repo directory + cd $personal_git_dir || exit - # Export Ad and Domain lists from Gravity database - $SUDO sqlite3 $gravity_db -header -csv "SELECT * FROM adlist" >$ad_list - $SUDO sqlite3 $gravity_db -header -csv "SELECT * FROM domainlist" >$domain_list + # Export Ad and Domain lists from Gravity database + export_table "adlist" + export_table "domainlist" + export_table "group" + export_table "domainlist_by_group" - # Compare local files to remote Git repo - $SUDO git remote update > /dev/null + # Compare local files to remote Git repo + $SUDO git remote update > /dev/null - # If local files are different than remote, update remote Git repo - CHANGED=$($SUDO git --work-tree=$personal_git_dir status --porcelain) - if [ -n "${CHANGED}" ]; then - echo 'Local Pi-hole lists are different than remote Git repo. Updating remote repo...'; - rightnow=$(date +"%B %e, %Y %l:%M%p") - # Remove -q option if you don't want to run in "quiet" mode - $SUDO git commit -a -m "Updated $rightnow" -q - $SUDO git push -q - echo 'Done!'; - exit 0 - else - # If local files are the same as remote, do nothing and exit - echo 'Remote Git repo matches local Pi-hole lists. No further action required.'; - exit 0 - fi + # If local files are different than remote, update remote Git repo + CHANGED=$($SUDO git --work-tree=$personal_git_dir status --porcelain) + if [ -n "${CHANGED}" ]; then + echo 'Local Pi-hole lists are different than remote Git repo. Updating remote repo...'; + rightnow=$(date +"%B %e, %Y %l:%M%p") + # Remove -q option if you don't want to run in "quiet" mode + $SUDO git commit -a -m "Updated $rightnow" -q + $SUDO git push -q + echo 'Done!'; + exit 0 + else + # If local files are the same as remote, do nothing and exit + echo 'Remote Git repo matches local Pi-hole lists. No further action required.'; + exit 0 + fi } pull () { - branch=$1 - if [ -z "${branch}" ]; then - branch="master" - fi + branch=$1 + if [ -z "${branch}" ]; then + branch="master" + fi - # Go to Pi-hole directory, exit if doesn't exist - cd $personal_git_dir || exit + # Go to Pi-hole directory, exit if doesn't exist + cd $personal_git_dir || exit - # Update local Git repo from remote Git repo - $SUDO git remote update > /dev/null - CHANGED=$($SUDO git log HEAD..origin/${branch} --oneline) - if [ -n "${CHANGED}" ]; then - echo 'Remote Git repo is different than local Pi-hole lists. Updating local lists...'; - # Remove -q option if you don't want to run in "quiet" mode - $SUDO git fetch --all -q - $SUDO git reset --hard "origin/${branch}" -q - $SUDO ${DOCKER} service pihole-FTL stop - $SUDO cp $custom_list $pihole_dir - $SUDO cp $cname_list $dnsmasq_dir - $SUDO sqlite3 $gravity_db "DROP TABLE adlist;" - $SUDO sqlite3 $gravity_db -header -csv ".import adlist.csv adlist" - $SUDO sqlite3 $gravity_db "DROP TABLE domainlist;" - $SUDO sqlite3 $gravity_db -header -csv ".import domainlist.csv domainlist" - $SUDO ${DOCKER} pihole -g - echo 'Done!'; - exit 0 - else - echo 'Local Pi-hole lists match remote Git repo. No further action required.'; - exit 0 - fi + # Update local Git repo from remote Git repo + $SUDO git remote update > /dev/null + CHANGED=$($SUDO git log HEAD..origin/${branch} --oneline) + if [ -n "${CHANGED}" ]; then + echo 'Remote Git repo is different than local Pi-hole lists. Updating local lists...'; + # Remove -q option if you don't want to run in "quiet" mode + $SUDO git fetch --all -q + $SUDO git reset --hard "origin/${branch}" -q + $SUDO ${DOCKER} service pihole-FTL stop + $SUDO cp $custom_list $pihole_dir + $SUDO cp $cname_list $dnsmasq_dir + import_table "adlist" + import_table "domainlist" + import_table "group" + import_table "domainlist_by_group" + $SUDO ${DOCKER} pihole -g + echo 'Done!'; + exit 0 + else + echo 'Local Pi-hole lists match remote Git repo. No further action required.'; + exit 0 + fi } ########################################################################### # Check to see whether a command line option was provided if [ -z "$1" ]; then - echo "Missing command line option. Try --push, --pull, or --help." - exit 1 + echo "Missing command line option. Try --push, --pull, or --help." + exit 1 fi # Determine which action to perform (InitPush, InitPull, Push, Pull, or Help) for arg in "$@"; do - # Initialize - adds primary Pi-hole's lists to local Git repo before first push/upload - if [ "$arg" == "--initpush" ]; then - echo "$arg option detected. Initializing local Git repo for Push/Upload."; - push_initialize - exit 0 - # Initialize - adds primary Pi-hole's lists to local Git repo before first push/upload - elif [ "$arg" == "--initpull" ]; then - echo "$arg option detected. Initializing local Git repo for Pull/Download."; - shift - pull_initialize $1 - exit 0 - # Push / Upload - Pushes updated local Pi-hole lists to remote Git repo - elif [ "$arg" == "--push" ] || [ "$arg" == "--upload" ] || [ "$arg" == "--up" ] || [ "$arg" == "-u" ]; then - echo "$arg option detected. Running in Push/Upload mode." - push - exit 0 - # Pull / Download - Pulls updated Pi-hole lists from remote Git repo - elif [ "$arg" == "--pull" ] || [ "$arg" == "--download" ] || [ "$arg" == "--down" ]|| [ "$arg" == "-d" ]; then - echo "$arg option detected. Running in Pull/Download mode." - shift - pull $1 - exit 0 - # Help - Displays help dialog - elif [ "$arg" == "--help" ] || [ "$arg" == "-h" ] || [ "$arg" == "-?" ]; then - cat <<- EOF - Usage: pihole-cloudsync