Files
NeoTachyon/uninstall.sh
T

457 lines
20 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# shellcheck shell=dash
# ==============================================================================
# Tachyon Uninstaller & Cleanup Script
# Полное чистое удаление Tachyon с сохранением резервной копии конфигурации.
# ==============================================================================
set -u
UNINSTALLER_VERSION="1.3.0"
# ─── TUI helpers & Color detection ───────────────────────────────────────────
ESC="$(printf '\033')"
_tui_colors=0
if [ -t 1 ] 2>/dev/null; then
case "${TERM:-dumb}" in
dumb) _tui_colors=0 ;;
*) _tui_colors=1 ;;
esac
fi
if [ "$_tui_colors" -eq 1 ]; then
_c_reset="${ESC}[0m"
_c_bold="${ESC}[1m"
_c_dim="${ESC}[2m"
_c_red="${ESC}[31;1m"
_c_green="${ESC}[32;1m"
_c_yellow="${ESC}[33;1m"
_c_blue="${ESC}[34;1m"
_c_cyan="${ESC}[36;1m"
_c_magenta="${ESC}[35;1m"
else
_c_reset=''
_c_bold=''
_c_dim=''
_c_red=''
_c_green=''
_c_yellow=''
_c_blue=''
_c_cyan=''
_c_magenta=''
fi
_tui_width() {
if [ -t 1 ] 2>/dev/null && command -v stty >/dev/null 2>&1; then
_w="$(stty size 2>/dev/null | awk '{print $2}')"
[ -n "$_w" ] && [ "$_w" -gt 0 ] 2>/dev/null && printf '%s' "$_w" && return 0
fi
printf '70'
}
_tui_hline() {
_w="$(_tui_width)"
_char="${1:--}"
_i=0
while [ "$_i" -lt "$_w" ]; do
printf '%s' "$_char"
_i=$((_i + 1))
done
}
tui_banner() {
printf '\n'
printf ' %s%s⚡ Tachyon Clean Uninstaller%s v%s\n' "$_c_cyan" "$_c_bold" "$_c_reset" "$UNINSTALLER_VERSION"
printf ' %sПолное удаление пакетов, сетевых правил и восстановление DNS%s\n' "$_c_dim" "$_c_reset"
printf ' %s%s%s\n\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
}
tui_step() {
_step_no="$1"
_step_total="$2"
_step_text="$3"
printf ' %s%s[ %s/%s ]%s %s%s%s\n' \
"$_c_blue" "$_c_bold" \
"$_step_no" "$_step_total" \
"$_c_reset" \
"$_c_bold" "$_step_text" "$_c_reset"
}
tui_ok() {
printf ' %s%s✓%s %s\n' "$_c_green" "$_c_bold" "$_c_reset" "$1"
}
tui_warn() {
printf ' %s%s⚠%s %s\n' "$_c_yellow" "$_c_bold" "$_c_reset" "$1"
}
tui_info() {
printf ' %s%sℹ%s %s\n' "$_c_cyan" "$_c_dim" "$_c_reset" "$1"
}
# ─── Options parsing ─────────────────────────────────────────────────────────
OPT_PURGE=0
OPT_YES=0
OPT_KEEP_BINARIES=0
for _arg in "$@"; do
case "$_arg" in
--purge|-p)
OPT_PURGE=1
;;
--yes|-y)
OPT_YES=1
;;
--keep-binaries)
OPT_KEEP_BINARIES=1
;;
--help|-h)
printf 'Использование: %s [ОПЦИИ]\n' "$0"
printf 'Опции:\n'
printf ' -y, --yes Выполнить удаление без подтверждения\n'
printf ' -p, --purge Полное удаление вместе с резервными копиями конфига\n'
printf ' --keep-binaries Не удалять бинарники sing-box / zapret / byedpi\n'
printf ' -h, --help Показать эту справку\n\n'
exit 0
;;
*)
;;
esac
done
# ─── Root check ──────────────────────────────────────────────────────────────
if [ "$(id -u 2>/dev/null || echo 1)" -ne 0 ]; then
printf '%sОшибка: скрипт удаления должен запускаться с правами root!%s\n' "$_c_red" "$_c_reset" >&2
exit 1
fi
tui_banner
# ─── Confirmation prompt ─────────────────────────────────────────────────────
if [ "$OPT_YES" -eq 0 ] && [ -t 0 ] 2>/dev/null; then
printf ' Вы действительно хотите удалить %sTachyon%s с этого роутера?\n' "$_c_bold" "$_c_reset"
if [ "$OPT_PURGE" -eq 1 ]; then
printf ' %sВнимание: указан флаг --purge. Все конфигурации и бэкапы будут удалены!%s\n' "$_c_red" "$_c_reset"
else
printf ' Рабочая конфигурация будет сохранена в резервную копию.\n'
fi
printf ' Продолжить? [y/N]: '
read -r _answer
case "$_answer" in
y|Y|yes|Yes|YES|да|Да|ДА)
;;
*)
printf '\n %sУдаление отменено пользователем.%s\n\n' "$_c_yellow" "$_c_reset"
exit 0
;;
esac
printf '\n'
fi
TOTAL_STEPS=6
CURRENT_STEP=1
# ─── STEP 1: Backup Configuration ────────────────────────────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Создание резервной копии конфигурации..."
BACKUP_PATH=""
if [ "$OPT_PURGE" -eq 0 ]; then
TIMESTAMP="$(date +%Y%m%d_%H%M%S 2>/dev/null || date +%s)"
if [ -f "/etc/config/tachyon" ]; then
BACKUP_PATH="/etc/config/tachyon.backup-${TIMESTAMP}"
cp -af "/etc/config/tachyon" "$BACKUP_PATH" 2>/dev/null || true
cp -af "/etc/config/tachyon" "/etc/config/tachyon.bak" 2>/dev/null || true
chmod 600 "$BACKUP_PATH" "/etc/config/tachyon.bak" 2>/dev/null || true
tui_ok "Конфигурация успешно сохранена в: ${BACKUP_PATH}"
else
tui_info "Конфигурационный файл /etc/config/tachyon не найден, бэкап пропущен."
fi
else
tui_warn "Режим --purge: резервное копирование конфигурации отключено."
fi
CURRENT_STEP=$((CURRENT_STEP + 1))
# ─── STEP 2: Stop Services & Daemons ─────────────────────────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Остановка служб и фоновых процессов..."
# Remove stale locks so stop doesn't block on orphaned states
rm -f /var/run/tachyon/starting /var/run/tachyon/reloading /var/run/tachyon*.lock 2>/dev/null || true
if [ -f "/etc/init.d/tachyon" ]; then
if command -v timeout >/dev/null 2>&1; then
timeout 8 /etc/init.d/tachyon stop >/dev/null 2>&1 || true
else
/etc/init.d/tachyon stop >/dev/null 2>&1 || true
fi
/etc/init.d/tachyon disable >/dev/null 2>&1 || true
tui_ok "Служба /etc/init.d/tachyon остановлена и отключена"
fi
# Stop and remove managed sing-box service if created by Tachyon
if [ -f "/etc/init.d/sing-box" ]; then
if grep -q "Tachyon managed sing-box" "/etc/init.d/sing-box" 2>/dev/null; then
if command -v timeout >/dev/null 2>&1; then
timeout 8 /etc/init.d/sing-box stop >/dev/null 2>&1 || true
else
/etc/init.d/sing-box stop >/dev/null 2>&1 || true
fi
/etc/init.d/sing-box disable >/dev/null 2>&1 || true
rm -f /etc/init.d/sing-box /etc/rc.d/*sing-box* 2>/dev/null || true
tui_ok "Управляемый сервис sing-box остановлен и удален"
fi
fi
# Terminate running DPI and proxy processes if any
killall -9 sing-box >/dev/null 2>&1 || true
killall -9 nfqws >/dev/null 2>&1 || true
killall -9 nfqws2 >/dev/null 2>&1 || true
killall -9 ciadpi >/dev/null 2>&1 || true
killall -9 tachyon >/dev/null 2>&1 || true
# Terminate running background Tachyon daemons (watchdog, telegram, failover, etc.)
_self_pid="$$"
ps 2>/dev/null | grep -E 'dns_failover|watchdog|telegram' | grep -v grep | awk '{print $1}' | while read -r _pid; do
if [ -n "$_pid" ] && [ "$_pid" != "$_self_pid" ]; then
kill -9 "$_pid" 2>/dev/null || true
fi
done
tui_ok "Фоновые процессы sing-box, zapret, byedpi и сервисы Tachyon завершены"
CURRENT_STEP=$((CURRENT_STEP + 1))
# ─── STEP 3: Clean up Network, nftables & Policy Routing ─────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Очистка сетевых таблиц nftables и политик маршрутизации..."
# Remove nftables tables & drop-in file
if command -v nft >/dev/null 2>&1; then
nft delete table inet TachyonTable >/dev/null 2>&1 || true
nft delete table inet tachyon >/dev/null 2>&1 || true
nft delete table ip tachyon >/dev/null 2>&1 || true
nft delete table ip6 tachyon >/dev/null 2>&1 || true
rm -f /usr/share/nftables.d/chain-pre/input/10-tachyon.nft 2>/dev/null || true
# Restart firewall to purge in-memory dynamic rules from inet fw4
if [ -x "/etc/init.d/firewall" ]; then
/etc/init.d/firewall restart >/dev/null 2>&1 || true
fi
tui_ok "Таблицы nftables (TachyonTable) удалены, фаервол сброшен"
fi
# Remove IP policy routing rules & flush routing tables
if command -v ip >/dev/null 2>&1; then
# IPv4 and IPv6 rules used by Tachyon (0x04000000 / table tachyon / priority 105)
ip -4 rule del fwmark 0x04000000/0x04000000 table tachyon priority 105 >/dev/null 2>&1 || true
ip -6 rule del fwmark 0x04000000/0x04000000 table tachyon priority 105 >/dev/null 2>&1 || true
ip -4 rule del fwmark 0x10000000/0x10000000 lookup 100 >/dev/null 2>&1 || true
ip -4 rule del fwmark 0x1/0x1 lookup 100 >/dev/null 2>&1 || true
ip -4 rule del fwmark 0x2/0x2 lookup 100 >/dev/null 2>&1 || true
ip route flush table tachyon >/dev/null 2>&1 || true
ip route flush table 105 >/dev/null 2>&1 || true
ip route flush table 100 >/dev/null 2>&1 || true
# Clean /etc/iproute2/rt_tables entry
if [ -f "/etc/iproute2/rt_tables" ]; then
sed -i '/105[[:space:]]\+tachyon/d' /etc/iproute2/rt_tables 2>/dev/null || true
fi
# Clean network namespaces and diagnostic veth pairs
ip netns del fkpsc >/dev/null 2>&1 || true
ip link del fkpsc0 >/dev/null 2>&1 || true
rm -rf /etc/netns/fkpsc 2>/dev/null || true
tui_ok "Политики маршрутизации (table tachyon/105/100, fwmark) полностью сброшены"
fi
CURRENT_STEP=$((CURRENT_STEP + 1))
# ─── STEP 4: Restore DNS & dnsmasq ───────────────────────────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Восстановление конфигурации DNS и dnsmasq..."
rm -f /etc/dnsmasq.d/tachyon*.conf 2>/dev/null || true
rm -f /tmp/dnsmasq.d/tachyon*.conf 2>/dev/null || true
rm -rf /tmp/tachyon 2>/dev/null || true
# Restore /etc/config/dhcp via UCI
if command -v uci >/dev/null 2>&1 && [ -f "/etc/config/dhcp" ]; then
# Remove sing-box DNS 127.0.0.42
uci -q del_list dhcp.@dnsmasq[0].server="127.0.0.42" 2>/dev/null || true
# Restore original servers from tachyon_server backup
_orig_servers="$(uci -q get dhcp.@dnsmasq[0].tachyon_server 2>/dev/null || true)"
if [ -n "$_orig_servers" ]; then
uci -q delete dhcp.@dnsmasq[0].server 2>/dev/null || true
for _srv in $_orig_servers; do
[ "$_srv" != "127.0.0.42" ] && uci -q add_list dhcp.@dnsmasq[0].server="$_srv" 2>/dev/null || true
done
uci -q delete dhcp.@dnsmasq[0].tachyon_server 2>/dev/null || true
fi
# Restore backed-up options
for _opt in noresolv cachesize rebind_protection localuse addn_hosts notinterface; do
_val="$(uci -q get "dhcp.@dnsmasq[0].tachyon_${_opt}" 2>/dev/null || true)"
if [ -n "$_val" ]; then
uci -q set "dhcp.@dnsmasq[0].${_opt}=${_val}" 2>/dev/null || true
uci -q delete "dhcp.@dnsmasq[0].tachyon_${_opt}" 2>/dev/null || true
fi
done
# Failsafe: if noresolv remains 1, reset to 0 so router queries ISP/upstream resolvers
if [ "$(uci -q get dhcp.@dnsmasq[0].noresolv 2>/dev/null)" = "1" ]; then
uci -q set dhcp.@dnsmasq[0].noresolv="0" 2>/dev/null || true
fi
# Failsafe: if cachesize remains 0, restore standard default 150
if [ "$(uci -q get dhcp.@dnsmasq[0].cachesize 2>/dev/null)" = "0" ]; then
uci -q set dhcp.@dnsmasq[0].cachesize="150" 2>/dev/null || true
fi
uci -q delete dhcp.tachyon 2>/dev/null || true
uci -q commit dhcp 2>/dev/null || true
tui_ok "Параметры DHCP и DNS dnsmasq возвращены в исходное состояние"
fi
# Restart dnsmasq to apply clean DNS configuration
if [ -f "/etc/init.d/dnsmasq" ]; then
/etc/init.d/dnsmasq restart >/dev/null 2>&1 || true
tui_ok "Служба dnsmasq перезапущена в штатном режиме"
fi
CURRENT_STEP=$((CURRENT_STEP + 1))
# ─── STEP 5: Clean Crontabs & Remove Packages ────────────────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Очистка crontab и удаление установленных пакетов..."
# Clean root crontab from Tachyon jobs
if command -v crontab >/dev/null 2>&1; then
_crontmp="$(mktemp /tmp/cron.XXXXXX 2>/dev/null || echo '/tmp/cron.tachyon.tmp')"
crontab -l 2>/dev/null | grep -v -E 'tachyon|parental_quota_tick' > "$_crontmp" || true
crontab "$_crontmp" 2>/dev/null || true
rm -f "$_crontmp" 2>/dev/null || true
tui_ok "Задачи планировщика crontab очищены"
fi
if command -v apk >/dev/null 2>&1 && [ -d "/lib/apk/db" ]; then
for _pkg in luci-i18n-tachyon-ru luci-app-tachyon tachyon; do
if apk info -e "$_pkg" >/dev/null 2>&1; then
apk del "$_pkg" >/dev/null 2>&1 || true
fi
done
tui_ok "Пакеты удалены через apk-tools"
elif command -v opkg >/dev/null 2>&1; then
_wait=0
while [ -f /var/lock/opkg.lock ] || [ -f /var/run/opkg.lock ]; do
_wait=$((_wait + 1))
[ "$_wait" -ge 10 ] && break
sleep 1
done
for _pkg in luci-i18n-tachyon-ru luci-app-tachyon tachyon; do
if opkg list-installed "$_pkg" 2>/dev/null | grep -q "^$_pkg "; then
opkg remove --force-depends --force-remove "$_pkg" >/dev/null 2>&1 || true
fi
done
if [ "$OPT_KEEP_BINARIES" -eq 0 ]; then
for _pkg in sing-box-extended sing-box-tiny; do
if opkg list-installed "$_pkg" 2>/dev/null | grep -q "^$_pkg "; then
opkg remove --force-depends --force-remove "$_pkg" >/dev/null 2>&1 || true
fi
done
if [ ! -f /etc/init.d/sing-box ] || grep -q "Tachyon managed sing-box" /etc/init.d/sing-box 2>/dev/null; then
if opkg list-installed "sing-box" 2>/dev/null | grep -q "^sing-box "; then
opkg remove --force-depends --force-remove "sing-box" >/dev/null 2>&1 || true
fi
rm -f /usr/bin/sing-box 2>/dev/null || true
fi
fi
tui_ok "Пакеты удалены через opkg"
fi
CURRENT_STEP=$((CURRENT_STEP + 1))
# ─── STEP 6: Remove Leftover Files & LuCI Cache ──────────────────────────────
tui_step "$CURRENT_STEP" "$TOTAL_STEPS" "Очистка оставшихся файлов, хуков и кэша LuCI..."
rm -rf /usr/lib/tachyon 2>/dev/null || true
rm -rf /usr/share/tachyon 2>/dev/null || true
rm -rf /www/luci-static/resources/view/tachyon 2>/dev/null || true
rm -f /usr/share/luci/menu.d/luci-app-tachyon.json 2>/dev/null || true
rm -f /usr/share/rpcd/acl.d/luci-app-tachyon.json 2>/dev/null || true
rm -f /etc/uci-defaults/50_luci-tachyon 2>/dev/null || true
rm -f /etc/tachyon_commit 2>/dev/null || true
rm -f /usr/bin/tachyon 2>/dev/null || true
rm -f /etc/init.d/tachyon 2>/dev/null || true
rm -f /etc/hotplug.d/iface/99-tachyon-wan-monitor 2>/dev/null || true
rm -f /www/cgi-bin/tachyon-agent 2>/dev/null || true
rm -f /usr/lib/cgi-bin/tachyon-agent 2>/dev/null || true
# Optional binary removal
if [ "$OPT_KEEP_BINARIES" -eq 0 ]; then
# Remove sing-box binary if it was managed by Tachyon
if [ ! -f "/lib/apk/db/installed" ] && command -v opkg >/dev/null 2>&1; then
if ! opkg list-installed "sing-box*" 2>/dev/null | grep -q "^sing-box"; then
rm -f /usr/bin/sing-box 2>/dev/null || true
fi
fi
rm -f /usr/lib/libcronet.so 2>/dev/null || true
fi
# Clean translations
rm -f /usr/lib/lua/luci/i18n/tachyon.* 2>/dev/null || true
find /usr/lib/lua/luci/i18n/ -name "tachyon.*" -delete 2>/dev/null || true
# Clear runtime and temporary state
rm -rf /var/run/tachyon* /var/log/tachyon* /tmp/sing-box /tmp/tachyon* /tmp/ai_doctor* /tmp/tg_* /tmp/warp_* 2>/dev/null || true
# Clear LuCI index and module caches
rm -f /var/luci-indexcache* /tmp/luci-indexcache* /tmp/luci-modulecache/* 2>/dev/null || true
# Clean ucitrack entry
if [ -f "/etc/config/ucitrack" ]; then
uci -q delete ucitrack.@tachyon[0] 2>/dev/null || true
uci -q commit ucitrack 2>/dev/null || true
fi
# Purge configs and persistent state if requested
if [ "$OPT_PURGE" -eq 1 ]; then
rm -f /etc/config/tachyon* 2>/dev/null || true
rm -rf /etc/tachyon /etc/.tachyon /etc/backup/tachyon_config /etc/sing-box 2>/dev/null || true
tui_ok "Все конфигурации и скрытые состояния Tachyon удалены (--purge)"
fi
# Restart rpcd and uhttpd to immediately update LuCI menu
if [ -f "/etc/init.d/rpcd" ]; then
/etc/init.d/rpcd restart >/dev/null 2>&1 || true
fi
if [ -f "/etc/init.d/uhttpd" ]; then
/etc/init.d/uhttpd restart >/dev/null 2>&1 || true
fi
# Check if parent Forkop / Podkop / NetShift services exist and restore them
if [ -f "/etc/init.d/forkop" ]; then
/etc/init.d/forkop enable >/dev/null 2>&1 || true
/etc/init.d/forkop restart >/dev/null 2>&1 || true
tui_ok "Обнаружен родительский сервис Forkop — восстановлен и запущен"
elif [ -f "/etc/init.d/podkop" ]; then
/etc/init.d/podkop enable >/dev/null 2>&1 || true
/etc/init.d/podkop restart >/dev/null 2>&1 || true
tui_ok "Обнаружен родительский сервис Podkop — восстановлен и запущен"
elif [ -f "/etc/init.d/netshift" ]; then
/etc/init.d/netshift enable >/dev/null 2>&1 || true
/etc/init.d/netshift restart >/dev/null 2>&1 || true
tui_ok "Обнаружен родительский сервис NetShift — восстановлен и запущен"
fi
tui_ok "Кэш LuCI очищен, файлы и остаточные фрагменты полностью удалены"
# ─── Final Summary ───────────────────────────────────────────────────────────
printf '\n'
printf ' %s%s%s\n' "$_c_dim" "$(_tui_hline '─')" "$_c_reset"
printf ' %s%s✓ Tachyon успешно и чисто удален с вашего роутера!%s\n' "$_c_green" "$_c_bold" "$_c_reset"
if [ "$OPT_PURGE" -eq 0 ] && [ -n "$BACKUP_PATH" ]; then
printf ' %s📁 Резервная копия конфигурации сохранена:%s %s%s%s\n' "$_c_cyan" "$_c_reset" "$_c_bold" "$BACKUP_PATH" "$_c_reset"
printf ' %s (а также продублирована в /etc/config/tachyon.bak)%s\n' "$_c_dim" "$_c_reset"
fi
printf ' %s🌐 Сетевой стек и DNS возвращены в штатный режим OpenWrt.%s\n\n' "$_c_dim" "$_c_reset"
exit 0