revert(linux): drop journal-based recovery of a removed Service

The journal cannot tell an upgrade's prerm removal from an explicit
uninstall, nor restore the previous enablement, so it must not trigger
an automatic reinstall. Upgrades from packages whose prerm removes the
Service are left unrecovered.

Refs #8515
This commit is contained in:
Tunglies
2026-11-10 07:52:59 +08:00
parent 2ecefeddf3
commit 9618dcd4a4
3 changed files with 10 additions and 78 deletions
+10 -28
View File
@@ -7,8 +7,6 @@ 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"
# Written by the preinst for this transaction only.
UPGRADE_EVIDENCE="/run/clash-verge-service-upgrade-evidence"
write_upgrade_marker() {
(umask 022 && printf 'gid=%s\nid=%s\n' "$1" "$(date +%s%N)" >"$UPGRADE_MARKER")
@@ -52,32 +50,16 @@ reinstall_existing_service() {
# 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 ]; then
if [ -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 "$gid"
fi
elif [ -f "$UPGRADE_EVIDENCE" ]; then
evidence="$(cat "$UPGRADE_EVIDENCE")"
rm -f "$UPGRADE_EVIDENCE"
gid="$(printf '%s\n' "$evidence" | sed -n 's/^gid=//p')"
if [ "$(printf '%s\n' "$evidence" | sed -n 's/^old=//p')" != "$2" ]; then
echo "Warning: ignoring Clash Verge Service evidence from another upgrade." >&2
elif [ -z "$gid" ]; then
echo "Warning: the previous package removed Clash Verge Service and its group is unknown; Clash Verge will offer to reinstall it." >&2
write_upgrade_marker ""
elif CLASH_VERGE_SERVICE_GID="$gid" /usr/bin/clash-verge-service-install --install-service; then
rm -f "$UPGRADE_MARKER"
else
echo "Warning: reinstalling Clash Verge Service failed; Clash Verge will offer to reinstall it." >&2
write_upgrade_marker "$gid"
fi
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 "$gid"
fi
fi
-49
View File
@@ -1,49 +0,0 @@
#!/bin/bash
# Previous packages' prerm uninstalls the Service before this script runs, deleting the unit that names
# its group. The journal still shows whether this dpkg run stopped a running Service and which group that
# invocation ran with; the postinst reinstalls only from that evidence.
SERVICE_UNIT="clash-verge-service.service"
UPGRADE_EVIDENCE="/run/clash-verge-service-upgrade-evidence"
# systemd's "unit stopped" catalog entry; restart jobs share it, so JOB_TYPE is required too.
UNIT_STOPPED_MESSAGE_ID="9d1aaa27d60140bd96365438aad20286"
dpkg_start_epoch() {
local stat start btime ticks
read -r stat <"/proc/$PPID/stat" || return 1
start="$(printf '%s\n' "${stat##*) }" | cut -d' ' -f20)"
btime="$(sed -n 's/^btime //p' /proc/stat)"
ticks="$(getconf CLK_TCK)"
[ -n "$start" ] && [ -n "$btime" ] && [ -n "$ticks" ] || return 1
echo $((btime + start / ticks))
}
# Only a prerm that uninstalls on every invocation explains a missing unit during an upgrade.
old_prerm_uninstalls() {
local prerm="${DPKG_ADMINDIR:-/var/lib/dpkg}/info/$DPKG_MAINTSCRIPT_PACKAGE.prerm"
[ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] && [ -f "$prerm" ] &&
grep -qx '/usr/bin/clash-verge-service-uninstall' "$prerm" && ! grep -q 'upgrade' "$prerm"
}
rm -f "$UPGRADE_EVIDENCE"
if [ "$1" = "upgrade" ] && [ -n "$2" ] && [ ! -e "/etc/systemd/system/$SERVICE_UNIT" ] &&
[ -d /run/systemd/system ] && [ "$(cat "/proc/$PPID/comm" 2>/dev/null)" = "dpkg" ] &&
command -v journalctl >/dev/null && old_prerm_uninstalls; then
since="$(dpkg_start_epoch)"
invocation=""
if [ -n "$since" ]; then
invocation="$(journalctl -q --no-pager --since "@$since" _PID=1 UNIT="$SERVICE_UNIT" \
MESSAGE_ID="$UNIT_STOPPED_MESSAGE_ID" JOB_TYPE=stop JOB_RESULT=done -n 1 -o export 2>/dev/null |
sed -n 's/^INVOCATION_ID=//p')"
fi
if printf '%s' "$invocation" | grep -qx '[0-9a-f]\{32\}'; then
# Stdout entries carry the credentials systemd connected the stream with, which are the unit's Group=.
gid="$(journalctl -q --no-pager _SYSTEMD_INVOCATION_ID="$invocation" _SYSTEMD_UNIT="$SERVICE_UNIT" \
_TRANSPORT=stdout -n 1 -o export 2>/dev/null | sed -n 's/^_GID=//p')"
if [ -z "$gid" ] || [ "$gid" = "0" ] || ! getent group "$gid" >/dev/null; then
gid=""
fi
echo "Clash Verge Service invocation $invocation was removed by the previous package; it will be reinstalled."
(umask 022 && printf 'old=%s\ngid=%s\n' "$2" "$gid" >"$UPGRADE_EVIDENCE")
fi
fi
exit 0
-1
View File
@@ -10,7 +10,6 @@
"provides": ["clash-verge"],
"conflicts": ["clash-verge"],
"replaces": ["clash-verge"],
"preInstallScript": "./packages/linux/pre-install.sh",
"postInstallScript": "./packages/linux/post-install.sh",
"preRemoveScript": "./packages/linux/pre-remove.sh"
},