mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-09 20:02:20 +08:00
fix(linux): bind deb Service recovery to the removing transaction
Reinstall a Service removed by a previous prerm only when the old prerm uninstalls unconditionally, this dpkg run completed a stop job for it, and its group comes from that same invocation's stdout journal entries. Hand the evidence to the postinst through a single-use file tied to the old version and cleared by every preinst. Refs #8515 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,6 +7,8 @@ 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")
|
||||
@@ -61,15 +63,20 @@ if [ "$1" = "configure" ] && [ -n "$2" ] && [ -d /run/systemd/system ]; then
|
||||
else
|
||||
write_upgrade_marker "$gid"
|
||||
fi
|
||||
elif [ -f "$UPGRADE_MARKER" ]; then
|
||||
# The preinst found that the previous package's prerm removed a running Service.
|
||||
gid="$(sed -n 's/^gid=//p' "$UPGRADE_MARKER")"
|
||||
if [ -z "$gid" ]; then
|
||||
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
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/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 it ran with;
|
||||
# the postinst reinstalls from that evidence, and without it nothing is installed.
|
||||
# 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_MARKER="/run/clash-verge-service-upgrade"
|
||||
# systemd's "unit stopped" catalog entry.
|
||||
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() {
|
||||
@@ -17,18 +17,33 @@ dpkg_start_epoch() {
|
||||
echo $((btime + start / ticks))
|
||||
}
|
||||
|
||||
if [ "$1" = "upgrade" ] && [ ! -e "/etc/systemd/system/$SERVICE_UNIT" ] && [ -d /run/systemd/system ] &&
|
||||
[ "$(cat "/proc/$PPID/comm" 2>/dev/null)" = "dpkg" ] && command -v journalctl >/dev/null; then
|
||||
# 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)"
|
||||
if [ -n "$since" ] &&
|
||||
[ -n "$(journalctl -q --no-pager --since "@$since" _PID=1 UNIT="$SERVICE_UNIT" MESSAGE_ID="$UNIT_STOPPED_MESSAGE_ID" -o cat 2>/dev/null)" ]; then
|
||||
# The truncated process name excludes cores the Service spawned in its cgroup.
|
||||
gid="$(journalctl -q --no-pager -b _SYSTEMD_UNIT="$SERVICE_UNIT" _COMM=clash-verge-ser -n 1 -o export 2>/dev/null |
|
||||
sed -n 's/^_GID=//p')"
|
||||
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
|
||||
(umask 022 && printf 'gid=%s\nid=%s\n' "$gid" "$(date +%s%N)" >"$UPGRADE_MARKER")
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user