mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-10 04:12:08 +08:00
The deb and rpm packages never refreshed an installed Service, and the previous package's prerm/%preun uninstalls it unconditionally. When the Service unit existed before the upgrade, the new postinst/%post now reinstalls it with its group and restores disabled, enabled-runtime, masked-runtime and stopped states. First installs and explicit removals never add a Service. rpm runs the new %post before the old %preun. %post records the transaction process (pid and start time) in /run, and /usr/bin/clash-verge-service-uninstall becomes a wrapper that skips only that %preun call and otherwise runs the real uninstaller, now under /usr/lib/clash-verge-rev. deb has no such ordering: an upgrade from a released version still loses the Service, and later deb upgrades reinstall it in place only once the prerm upgrade guard from #8240 ships. The scripts exit 0, because a failing postinst or %post cannot restore the Service. On failure they write /run/clash-verge-service-upgrade instead; package script output never reaches the GUI. At startup the app offers a reinstall if the Service is not ready and warns if its previous state was not restored. Both notices replay when a window subscribes, and the marker is acknowledged only after both are taken. In-app updates stop a Service-run core and hold the core lifecycle until the package manager exits, including after the 30-second startup timeout. Refs #8515 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
97 lines
3.8 KiB
Bash
97 lines
3.8 KiB
Bash
#!/bin/bash
|
|
chmod +x /usr/bin/clash-verge-service-install
|
|
chmod +x /usr/bin/clash-verge-service-uninstall
|
|
# The /usr/bin uninstaller is the service-uninstall.sh wrapper; this is the real binary it runs.
|
|
chmod +x /usr/lib/clash-verge-rev/clash-verge-service-uninstall
|
|
chmod +x /usr/bin/clash-verge-service
|
|
|
|
SERVICE_UNIT="clash-verge-service.service"
|
|
SERVICE_UNIT_FILE="/etc/systemd/system/$SERVICE_UNIT"
|
|
# Read by the app, which offers a reinstall when the package could not keep the Service.
|
|
UPGRADE_MARKER="/run/clash-verge-service-upgrade"
|
|
|
|
# Set to the previous state when restoring it fails; the app shows it even if the Service is ready.
|
|
UNRESTORED_STATE=""
|
|
|
|
write_upgrade_marker() {
|
|
(
|
|
umask 022
|
|
{
|
|
printf 'id=%s\n' "$(date +%s%N)"
|
|
if [ -n "$UNRESTORED_STATE" ]; then
|
|
printf 'restore=%s\n' "$UNRESTORED_STATE"
|
|
fi
|
|
} >"$UPGRADE_MARKER"
|
|
)
|
|
}
|
|
|
|
existing_service_gid() {
|
|
local group
|
|
group="$(sed -n 's/^Group=//p' "$SERVICE_UNIT_FILE" | head -n 1)"
|
|
if [ -n "$group" ]; then
|
|
getent group "$group" | cut -d: -f3
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Failures only warn: dpkg and rpm cannot restore the previous Service from a failed postinst,
|
|
# and a failing script would leave the package unconfigured or make the app report a failed update.
|
|
# The installer always enables and starts the unit, so the previous enablement and activity are restored.
|
|
reinstall_existing_service() {
|
|
local gid="$1" enabled active=no
|
|
enabled="$(systemctl is-enabled "$SERVICE_UNIT" 2>/dev/null)"
|
|
if systemctl is-active --quiet "$SERVICE_UNIT"; then
|
|
active=yes
|
|
fi
|
|
local status=0 restored=yes
|
|
if [ "$enabled" = "masked-runtime" ]; then
|
|
systemctl unmask --runtime --quiet "$SERVICE_UNIT" || restored=no
|
|
fi
|
|
if ! CLASH_VERGE_SERVICE_GID="$gid" /usr/bin/clash-verge-service-install --install-service; then
|
|
echo "Warning: reinstalling Clash Verge Service failed; Clash Verge will offer to reinstall it." >&2
|
|
status=1
|
|
fi
|
|
case "$enabled" in
|
|
disabled) systemctl disable --quiet "$SERVICE_UNIT" || restored=no ;;
|
|
enabled-runtime) { systemctl disable --quiet "$SERVICE_UNIT" && systemctl enable --runtime --quiet "$SERVICE_UNIT"; } || restored=no ;;
|
|
masked-runtime) systemctl mask --runtime --quiet "$SERVICE_UNIT" || restored=no ;;
|
|
esac
|
|
if [ "$active" = "no" ]; then
|
|
systemctl stop "$SERVICE_UNIT" || restored=no
|
|
fi
|
|
if [ "$restored" = "no" ]; then
|
|
UNRESTORED_STATE="${enabled:-unknown},$([ "$active" = yes ] && echo active || echo inactive)"
|
|
echo "Warning: restoring the previous Clash Verge Service state ($UNRESTORED_STATE) failed; check it with systemctl." >&2
|
|
status=1
|
|
fi
|
|
return "$status"
|
|
}
|
|
|
|
# Upgrades keep an existing Service current; first installs and explicit removals never add one.
|
|
# A symlinked unit is masked or managed by the administrator and is left alone.
|
|
if [ "$1" = "configure" ] && [ -n "$2" ] && [ -d /run/systemd/system ] &&
|
|
[ -f "$SERVICE_UNIT_FILE" ] && [ ! -L "$SERVICE_UNIT_FILE" ]; then
|
|
gid="$(existing_service_gid)"
|
|
if [ -z "$gid" ]; then
|
|
echo "Warning: the Clash Verge Service group could not be resolved; Clash Verge will offer to reinstall the Service." >&2
|
|
write_upgrade_marker
|
|
elif reinstall_existing_service "$gid"; then
|
|
rm -f "$UPGRADE_MARKER"
|
|
else
|
|
write_upgrade_marker
|
|
fi
|
|
fi
|
|
|
|
. /etc/os-release
|
|
|
|
if [ "$ID" = "deepin" ]; then
|
|
PACKAGE_NAME="$DPKG_MAINTSCRIPT_PACKAGE"
|
|
DESKTOP_FILES=$(dpkg -L "$PACKAGE_NAME" 2>/dev/null | grep "\.desktop$")
|
|
echo "$DESKTOP_FILES" | while IFS= read -r f; do
|
|
if [ "$(basename "$f")" == "Clash Verge.desktop" ]; then
|
|
echo "Fixing deepin desktop file"
|
|
mv -vf "$f" "/usr/share/applications/clash-verge.desktop"
|
|
fi
|
|
done
|
|
fi
|