Reformatted the code

This commit is contained in:
Giulio Coa 2022-07-27 14:53:36 +02:00
parent 47e8908489
commit af20461590
24 changed files with 2655 additions and 2021 deletions

View file

@ -1,20 +1,22 @@
#!/usr/bin/env bash
#!/bin/bash
# PiVPN: Uninstall Script
### FIXME: global: config storage, refactor all scripts to adhere to the storage
### FIXME: use variables where appropriate, reduce magic numbers by 99.9%, at least.
### FIXME:
### global: config storage, refactor all scripts to adhere to the storage
### FIXME:
### use variables where appropriate, reduce magic numbers by 99.9%, at least.
# Find the rows and columns. Will default to 80x24 if it can not be detected.
screen_size=$(stty size 2>/dev/null || echo 24 80)
rows=$(echo "$screen_size" | awk '{print $1}')
columns=$(echo "$screen_size" | awk '{print $2}')
screen_size="$(stty size 2> /dev/null || echo 24 80)"
rows="$(echo "${screen_size}" | awk '{print $1}')"
columns="$(echo "${screen_size}" | awk '{print $2}')"
# Divide by two so the dialogs take up half of the screen, which looks nice.
r=$(( rows / 2 ))
c=$(( columns / 2 ))
r=$((rows / 2))
c=$((columns / 2))
# Unless the screen is tiny
r=$(( r < 20 ? 20 : r ))
c=$(( c < 70 ? 70 : c ))
r=$((r < 20 ? 20 : r))
c=$((c < 70 ? 70 : c))
PKG_MANAGER="apt-get"
PKG_REMOVE="${PKG_MANAGER} -y remove --purge"
@ -24,295 +26,393 @@ setupConfigDir="/etc/pivpn"
pivpnFilesDir="/usr/local/src/pivpn"
pivpnScriptDir="/opt/pivpn"
PLAT=$(grep -sEe '^NAME\=' /etc/os-release | sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/")
PLAT="$(grep -sEe '^NAME\=' /etc/os-release |
sed -E -e "s/NAME\=[\'\"]?([^ ]*).*/\1/")"
if [ "${PLAT}" == 'Alpine' ]; then
PKG_MANAGER='apk'
PKG_REMOVE="${PKG_MANAGER} --no-cache --purge del -r"
if [[ "${PLAT}" == 'Alpine' ]]; then
PKG_MANAGER='apk'
PKG_REMOVE="${PKG_MANAGER} --no-cache --purge del -r"
fi
UPDATE_PKG_CACHE="${PKG_MANAGER} update"
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ] && [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then
vpnStillExists=1
if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]] &&
[[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
vpnStillExists=1
# Two protocols have been installed, check if the script has passed
# an argument, otherwise ask the user which one he wants to remove
if [ $# -ge 1 ]; then
VPN="$1"
echo "::: Uninstalling VPN: $VPN"
else
chooseVPNCmd=(whiptail --backtitle "Setup PiVPN" --title "Uninstall" --separate-output --radiolist "Both OpenVPN and WireGuard are installed, choose a VPN to uninstall (press space to select):" "${r}" "${c}" 2)
VPNChooseOptions=(WireGuard "" on
OpenVPN "" off)
# Two protocols have been installed, check if the script has passed
# an argument, otherwise ask the user which one he wants to remove
if [[ "$#" -ge 1 ]]; then
VPN="${1}"
echo "::: Uninstalling VPN: ${VPN}"
else
chooseVPNCmd=(whiptail
--backtitle "Setup PiVPN"
--title "Uninstall"
--separate-output
--radiolist "Both OpenVPN and WireGuard are installed, \
choose a VPN to uninstall (press space to select):"
"${r}" "${c}" 2)
VPNChooseOptions=(WireGuard "" on
OpenVPN "" off)
if VPN=$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 >/dev/tty) ; then
echo "::: Uninstalling VPN: $VPN"
VPN="${VPN,,}"
else
echo "::: Cancel selected, exiting...."
exit 1
fi
fi
if VPN="$("${chooseVPNCmd[@]}" "${VPNChooseOptions[@]}" 2>&1 \
> /dev/tty)"; then
echo "::: Uninstalling VPN: ${VPN}"
VPN="${VPN,,}"
else
err "::: Cancel selected, exiting...."
exit 1
fi
fi
setupVars="${setupConfigDir}/${VPN}/${setupVarsFile}"
setupVars="${setupConfigDir}/${VPN}/${setupVarsFile}"
else
vpnStillExists=0
vpnStillExists=0
if [ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]; then
setupVars="${setupConfigDir}/wireguard/${setupVarsFile}"
elif [ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]; then
setupVars="${setupConfigDir}/openvpn/${setupVarsFile}"
fi
if [[ -r "${setupConfigDir}/wireguard/${setupVarsFile}" ]]; then
setupVars="${setupConfigDir}/wireguard/${setupVarsFile}"
elif [[ -r "${setupConfigDir}/openvpn/${setupVarsFile}" ]]; then
setupVars="${setupConfigDir}/openvpn/${setupVarsFile}"
fi
fi
if [ ! -f "${setupVars}" ]; then
echo "::: Missing setup vars file!"
exit 1
if [[ ! -f "${setupVars}" ]]; then
err "::: Missing setup vars file!"
exit 1
fi
# shellcheck disable=SC1090
source "${setupVars}"
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
### FIXME: introduce global lib
spinner(){
local pid=$1
local delay=0.50
local spinstr='/-\|'
while ps a | awk '{print $1}' | grep -q "$pid"; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\\b\\b\\b\\b\\b\\b"
done
printf " \\b\\b\\b\\b"
spinner() {
local pid="${1}"
local delay=0.50
local spinstr='/-\|'
while ps a | awk '{print $1}' | grep -q "${pid}"; do
local temp="${spinstr#?}"
printf " [%c] " "${spinstr}"
local spinstr="${temp}${spinstr%"$temp"}"
sleep "${delay}"
printf "\\b\\b\\b\\b\\b\\b"
done
printf " \\b\\b\\b\\b"
}
removeAll(){
# Stopping and disabling services
echo "::: Stopping and disabling services..."
removeAll() {
# Stopping and disabling services
echo "::: Stopping and disabling services..."
if [ "${PLAT}" == 'Alpine' ]; then
if [ "${VPN}" = "wireguard" ]; then
rc-service wg-quick stop
rc-update del wg-quick default &> /dev/null
elif [ "${VPN}" = "openvpn" ]; then
rc-service openvpn stop
rc-update del openvpn default &> /dev/null
fi
else
if [ "${VPN}" = "wireguard" ]; then
systemctl stop wg-quick@wg0
systemctl disable wg-quick@wg0 &> /dev/null
elif [ "${VPN}" = "openvpn" ]; then
systemctl stop openvpn
systemctl disable openvpn &> /dev/null
fi
fi
if [[ "${PLAT}" == 'Alpine' ]]; then
if [[ "${VPN}" == "wireguard" ]]; then
rc-service wg-quick stop
rc-update del wg-quick default &> /dev/null
elif [[ "${VPN}" == "openvpn" ]]; then
rc-service openvpn stop
rc-update del openvpn default &> /dev/null
fi
else
if [[ "${VPN}" == "wireguard" ]]; then
systemctl stop wg-quick@wg0
systemctl disable wg-quick@wg0 &> /dev/null
elif [[ "${VPN}" == "openvpn" ]]; then
systemctl stop openvpn
systemctl disable openvpn &> /dev/null
fi
fi
# Removing firewall rules.
echo "::: Removing firewall rules..."
if [ "$USING_UFW" -eq 1 ]; then
# Removing firewall rules.
echo "::: Removing firewall rules..."
if [[ "${USING_UFW}" -eq 1 ]]; then
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw delete allow "${pivpnPORT}"/"${pivpnPROTO}" > /dev/null
# shellcheck disable=SC2154
ufw delete allow "${pivpnPORT}/${pivpnPROTO}" > /dev/null
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
ufw route delete allow in on "${pivpnDEV}" from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any > /dev/null
ufw delete allow in on "${pivpnDEV}" to any port 53 from "${pivpnNET}/${subnetClass}" >/dev/null
sed "/-I POSTROUTING -s ${pivpnNET}\\/${subnetClass} -o ${IPv4dev} -j MASQUERADE -m comment --comment ${VPN}-nat-rule/d" -i /etc/ufw/before.rules
iptables -t nat -D POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule"
ufw reload &> /dev/null
# shellcheck disable=SC2154
ufw route delete allow in on "${pivpnDEV}" \
from "${pivpnNET}/${subnetClass}" out on "${IPv4dev}" to any > /dev/null
ufw delete allow in on "${pivpnDEV}" to any port 53 \
from "${pivpnNET}/${subnetClass}" > /dev/null
elif [ "$USING_UFW" -eq 0 ]; then
sed_pattern='/-I POSTROUTING'
sed_pattern="${sed_pattern} -s ${pivpnNET}\\/${subnetClass}"
sed_pattern="${sed_pattern} -o ${IPv4dev}"
sed_pattern="${sed_pattern} -j MASQUERADE"
sed_pattern="${sed_pattern} -m comment"
sed_pattern="${sed_pattern} --comment ${VPN}-nat-rule/d"
sed "${sed_pattern}" -i /etc/ufw/before.rules
unset sed_pattern
if [ "$INPUT_CHAIN_EDITED" -eq 1 ]; then
iptables -D INPUT -i "${IPv4dev}" -p "${pivpnPROTO}" --dport "${pivpnPORT}" -j ACCEPT -m comment --comment "${VPN}-input-rule"
fi
iptables \
-t nat \
-D POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule"
if [ "$FORWARD_CHAIN_EDITED" -eq 1 ]; then
iptables -D FORWARD -d "${pivpnNET}/${subnetClass}" -i "${IPv4dev}" -o "${pivpnDEV}" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment "${VPN}-forward-rule"
iptables -D FORWARD -s "${pivpnNET}/${subnetClass}" -i "${pivpnDEV}" -o "${IPv4dev}" -j ACCEPT -m comment --comment "${VPN}-forward-rule"
fi
ufw reload &> /dev/null
elif [[ "${USING_UFW}" -eq 0 ]]; then
if [[ "${INPUT_CHAIN_EDITED}" -eq 1 ]]; then
iptables \
-D INPUT \
-i "${IPv4dev}" \
-p "${pivpnPROTO}" \
--dport "${pivpnPORT}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-input-rule"
fi
iptables -t nat -D POSTROUTING -s "${pivpnNET}/${subnetClass}" -o "${IPv4dev}" -j MASQUERADE -m comment --comment "${VPN}-nat-rule"
iptables-save > /etc/iptables/rules.v4
if [[ "${FORWARD_CHAIN_EDITED}" -eq 1 ]]; then
iptables \
-D FORWARD \
-d "${pivpnNET}/${subnetClass}" \
-i "${IPv4dev}" \
-o "${pivpnDEV}" \
-m conntrack \
--ctstate RELATED,ESTABLISHED \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
fi
iptables \
-D FORWARD \
-s "${pivpnNET}/${subnetClass}" \
-i "${pivpnDEV}" \
-o "${IPv4dev}" \
-j ACCEPT \
-m comment \
--comment "${VPN}-forward-rule"
fi
# Disable IPv4 forwarding
if [ "${vpnStillExists}" -eq 0 ]; then
sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf
sysctl -p
fi
iptables \
-t nat \
-D POSTROUTING \
-s "${pivpnNET}/${subnetClass}" \
-o "${IPv4dev}" \
-j MASQUERADE \
-m comment \
--comment "${VPN}-nat-rule"
# Purge dependencies
echo "::: Purge dependencies..."
iptables-save > /etc/iptables/rules.v4
fi
for i in "${INSTALLED_PACKAGES[@]}"; do
while true; do
read -rp "::: Do you wish to remove $i from your system? [Y/n]: " yn
case $yn in
[Yy]* )
if [ "${PLAT}" == 'Alpine' ]; then
if [ "${i}" == 'openvpn' ]; then
deluser openvpn
rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn
fi
else
if [ "${i}" == "wireguard-tools" ]; then
# The bullseye repo may not exist if wireguard was available at the
# time of installation.
if [ -f /etc/apt/sources.list.d/pivpn-bullseye-repo.list ]; then
echo "::: Removing Debian Bullseye repo..."
# Disable IPv4 forwarding
if [[ "${vpnStillExists}" -eq 0 ]]; then
sed -i '/net.ipv4.ip_forward=1/c\#net.ipv4.ip_forward=1' /etc/sysctl.conf
sysctl -p
fi
rm -f /etc/apt/sources.list.d/pivpn-bullseye-repo.list
rm -f /etc/apt/preferences.d/pivpn-limit-bullseye
# Purge dependencies
echo "::: Purge dependencies..."
echo "::: Updating package cache..."
for i in "${INSTALLED_PACKAGES[@]}"; do
while true; do
read -rp "::: Do you wish to remove ${i} from your system? [Y/n]: " yn
${UPDATE_PKG_CACHE} &> /dev/null &
spinner $!
fi
case "${yn}" in
[Yy]*)
if [[ "${PLAT}" == 'Alpine' ]]; then
if [[ "${i}" == 'openvpn' ]]; then
deluser openvpn
rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn
fi
else
if [[ "${i}" == "wireguard-tools" ]]; then
# The bullseye repo may not exist if wireguard was available at
# the time of installation.
tmp_path='/etc/apt/sources.list.d/pivpn-bullseye-repo.list'
if [ -f /etc/systemd/system/wg-quick@.service.d/override.conf ]; then
rm -f /etc/systemd/system/wg-quick@.service.d/override.conf
fi
elif [ "${i}" = "unattended-upgrades" ]; then
rm -rf /var/log/unattended-upgrades /etc/apt/apt.conf.d/*periodic
rm -rf /etc/apt/apt.conf.d/*unattended-upgrades
elif [ "${i}" = "openvpn" ]; then
if [ -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list ]; then
echo "::: Removing OpenVPN software repo..."
if [[ -f "${tmp_path}" ]]; then
echo "::: Removing Debian Bullseye repo..."
rm -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list
rm -f "${tmp_path}"
rm -f /etc/apt/preferences.d/pivpn-limit-bullseye
echo "::: Updating package cache..."
echo "::: Updating package cache..."
${UPDATE_PKG_CACHE} &> /dev/null &
spinner $!
fi
${UPDATE_PKG_CACHE} &> /dev/null &
spinner "$!"
fi
deluser openvpn
rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn
fi
fi
tmp_path='/etc/systemd/system/wg-quick@.service.d/override.conf'
printf ":::\\tRemoving %s..." "$i"
if [[ -f "${tmp_path}" ]]; then
rm -f "${tmp_path}"
fi
"${PKG_REMOVE}" "$i" &> /dev/null &
spinner $!
unset tmp_path
elif [[ "${i}" == "unattended-upgrades" ]]; then
rm -rf /var/log/unattended-upgrades /etc/apt/apt.conf.d/*periodic
rm -rf /etc/apt/apt.conf.d/*unattended-upgrades
elif [[ "${i}" == "openvpn" ]]; then
if [[ -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list ]]; then
echo "::: Removing OpenVPN software repo..."
printf "done!\\n";
break
;;
[Nn]* )
printf ":::\\tSkipping %s\\n" "$i";
break
;;
* )
printf "::: You must answer yes or no!\\n"
;;
esac
done
done
rm -f /etc/apt/sources.list.d/pivpn-openvpn-repo.list
if [ "${PLAT}" != 'Alpine' ]; then
# Take care of any additional package cleaning
printf "::: Auto removing remaining dependencies..."
echo "::: Updating package cache..."
"${PKG_MANAGER}" -y autoremove &> /dev/null &
spinner $!
${UPDATE_PKG_CACHE} &> /dev/null &
spinner "$!"
fi
printf "done!\\n";
printf "::: Auto cleaning remaining dependencies..."
deluser openvpn
rm -f /etc/rsyslog.d/30-openvpn.conf /etc/logrotate.d/openvpn
fi
fi
"${PKG_MANAGER}" -y autoclean &> /dev/null &
spinner $!
printf ":::\\tRemoving %s..." "${i}"
printf "done!\\n";
fi
${PKG_REMOVE} "${i}" &> /dev/null &
spinner "$!"
if [ -f "$dnsmasqConfig" ]; then
rm -f "$dnsmasqConfig"
pihole restartdns
fi
printf "done!\\n"
break
;;
[Nn]*)
printf ":::\\tSkipping %s\\n" "${i}"
break
;;
*)
err "::: You must answer yes or no!"
;;
esac
done
done
echo ":::"
echo "::: Removing VPN configuration files..."
if [[ "${PLAT}" != 'Alpine' ]]; then
# Take care of any additional package cleaning
printf "::: Auto removing remaining dependencies..."
if [ "$VPN" = "wireguard" ]; then
rm -f /etc/wireguard/wg0.conf
rm -rf /etc/wireguard/configs
rm -rf /etc/wireguard/keys
"${PKG_MANAGER}" -y autoremove &> /dev/null &
spinner "$!"
printf "done!\\n"
printf "::: Auto cleaning remaining dependencies..."
"${PKG_MANAGER}" -y autoclean &> /dev/null &
spinner "$!"
printf "done!\\n"
fi
if [[ -f "${dnsmasqConfig}" ]]; then
rm -f "${dnsmasqConfig}"
pihole restartdns
fi
echo ":::"
echo "::: Removing VPN configuration files..."
if [[ "${VPN}" == "wireguard" ]]; then
rm -f /etc/wireguard/wg0.conf
rm -rf /etc/wireguard/configs
rm -rf /etc/wireguard/keys
### Ignoring SC2154, value sourced from setupVars file
# shellcheck disable=SC2154
rm -rf "$install_home/configs"
elif [ "$VPN" = "openvpn" ]; then
rm -rf /var/log/*openvpn*
rm -f /etc/openvpn/server.conf
rm -f /etc/openvpn/crl.pem
rm -rf /etc/openvpn/easy-rsa
rm -rf /etc/openvpn/ccd
rm -rf "$install_home/ovpns"
fi
# shellcheck disable=SC2154
rm -rf "${install_home}/configs"
elif [[ "${VPN}" == "openvpn" ]]; then
rm -rf /var/log/*openvpn*
rm -f /etc/openvpn/server.conf
rm -f /etc/openvpn/crl.pem
rm -rf /etc/openvpn/easy-rsa
rm -rf /etc/openvpn/ccd
rm -rf "${install_home}/ovpns"
fi
if [ "${vpnStillExists}" -eq 0 ]; then
echo ":::"
echo "::: Removing pivpn system files..."
rm -rf "${setupConfigDir}"
rm -rf "${pivpnFilesDir}"
rm -f /var/log/*pivpn*
rm -f /etc/bash_completion.d/pivpn
unlink "${pivpnScriptDir}"
unlink /usr/local/bin/pivpn
else
if [[ ${VPN} == 'wireguard' ]]; then
othervpn='openvpn'
else
othervpn='wireguard'
fi
if [[ "${vpnStillExists}" -eq 0 ]]; then
echo ":::"
echo "::: Removing pivpn system files..."
echo ":::"
echo "::: Other VPN ${othervpn} still present, so not"
echo "::: removing pivpn system files"
rm -f "${setupConfigDir}/${VPN}/${setupVarsFile}"
rm -rf "${setupConfigDir}"
rm -rf "${pivpnFilesDir}"
rm -f /var/log/*pivpn*
rm -f /etc/bash_completion.d/pivpn
# Restore single pivpn script and bash completion for the remaining VPN
$SUDO unlink /usr/local/bin/pivpn
$SUDO ln -s -T "${pivpnFilesDir}/scripts/${othervpn}/pivpn.sh" /usr/local/bin/pivpn
$SUDO ln -s -T "${pivpnFilesDir}/scripts/${othervpn}/bash-completion" /etc/bash_completion.d/pivpn
# shellcheck disable=SC1091
. /etc/bash_completion.d/pivpn
fi
unlink "${pivpnScriptDir}"
unlink /usr/local/bin/pivpn
else
if [[ "${VPN}" == 'wireguard' ]]; then
othervpn='openvpn'
else
othervpn='wireguard'
fi
echo ":::"
printf "::: Finished removing PiVPN from your system.\\n"
printf "::: Reinstall by simply running\\n:::\\n:::\\tcurl -L https://install.pivpn.io | bash\\n:::\\n::: at any time!\\n:::\\n"
echo ":::"
echo "::: Other VPN ${othervpn} still present, so not"
echo "::: removing pivpn system files"
rm -f "${setupConfigDir}/${VPN}/${setupVarsFile}"
# Restore single pivpn script and bash completion for the remaining VPN
${SUDO} unlink /usr/local/bin/pivpn
${SUDO} ln \
-s \
-T "${pivpnFilesDir}/scripts/${othervpn}/pivpn.sh" \
/usr/local/bin/pivpn
${SUDO} ln \
-s \
-T "${pivpnFilesDir}/scripts/${othervpn}/bash-completion" \
/etc/bash_completion.d/pivpn
# shellcheck disable=SC1091
. /etc/bash_completion.d/pivpn
fi
echo ":::"
printf "::: Finished removing PiVPN from your system.\\n"
printf "::: Reinstall by simply running\\n:::\\n:::\\t"
printf "curl -L https://install.pivpn.io | "
printf "bash\\n:::\\n::: at any time!\\n:::\\n"
}
askreboot(){
printf "It is \\e[1mstrongly\\e[0m recommended to reboot after un-installation.\\n"
read -p "Would you like to reboot now? [y/n]: " -n 1 -r
echo
if [[ ${REPLY} =~ ^[Yy]$ ]]; then
printf "\\nRebooting system...\\n"
sleep 3
reboot
fi
askreboot() {
printf "It is \\e[1mstrongly\\e[0m recommended to reboot "
printf "after un-installation.\\n"
read -p "Would you like to reboot now? [y/n]: " -n 1 -r
echo
if [[ "${REPLY}" =~ ^[Yy]$ ]]; then
printf "\\nRebooting system...\\n"
sleep 3
reboot
fi
}
######### SCRIPT ###########
echo "::: Preparing to remove packages, be sure that each may be safely removed depending on your operating system."
echo -n "::: Preparing to remove packages, be sure that each may be safely "
echo "removed depending on your operating system."
echo "::: (SAFE TO REMOVE ALL ON RASPBIAN)"
while true; do
read -rp "::: Do you wish to completely remove PiVPN configuration and installed packages from your system? (You will be prompted for each package) [y/n]: " yn
case $yn in
[Yy]* ) removeAll; askreboot; break;;
[Nn]* ) printf "::: Not removing anything, exiting...\\n"; break;;
esac
while true; do
echo -n "::: Do you wish to completely remove PiVPN configuration and "
echo -n "installed packages from your system? "
echo -n "(You will be prompted for each package) [y/n]: "
read -r yn
case "${yn}" in
[Yy]*)
removeAll
askreboot
break
;;
[Nn]*)
err "::: Not removing anything, exiting..."
break
;;
esac
done