Detect stale systemd service templates in doctor

This commit is contained in:
Arvin
2026-07-02 17:30:55 +08:00
parent df859b0a6d
commit f782fbc7e0
2 changed files with 148 additions and 1 deletions
+58 -1
View File
@@ -3129,6 +3129,51 @@ logs_service() {
esac
}
systemd_unit_file_path() {
printf '/etc/systemd/system/%s\n' "$(service_unit_name)"
}
systemd_user_unit_file_path() {
printf '%s/.config/systemd/user/%s\n' "$(user_home_dir)" "$(service_unit_name)"
}
systemd_unit_has_stale_runtime_template() {
local unit_file="$1"
[ -f "$unit_file" ] || return 1
grep -Eq '^[[:space:]]*Type=forking([[:space:]]|$)|^[[:space:]]*PIDFile=|clashctl[[:space:]]+start-direct' "$unit_file"
}
systemd_unit_stale_runtime_template_warning() {
local backend="$1"
local unit_file label refresh_cmd restart_cmd
case "$backend" in
systemd)
unit_file="$(systemd_unit_file_path)"
label="systemd"
refresh_cmd="sudo bash install.sh system"
restart_cmd="sudo systemctl restart $(service_unit_name)"
;;
systemd-user)
unit_file="$(systemd_user_unit_file_path)"
label="用户级 systemd"
refresh_cmd="bash install.sh user"
restart_cmd="systemctl --user restart $(service_unit_name)"
;;
*)
return 1
;;
esac
systemd_unit_has_stale_runtime_template "$unit_file" || return 1
echo "${label} 服务文件仍是旧模板:$unit_file"
echo "建议刷新服务文件:$refresh_cmd"
echo "刷新后重启服务:$restart_cmd"
}
cmd_logs() {
prepare
@@ -3595,7 +3640,7 @@ doctor_build() {
}
doctor_service() {
local backend
local backend stale_warning
doctor_print_title "服务检查"
@@ -3608,6 +3653,12 @@ doctor_service() {
case "$backend" in
systemd)
stale_warning="$(systemd_unit_stale_runtime_template_warning systemd 2>/dev/null || true)"
if [ -n "${stale_warning:-}" ]; then
doctor_warn "$stale_warning"
else
doctor_ok "systemd 服务模板:当前版本"
fi
if systemctl is-active --quiet "$(service_unit_name)"; then
doctor_ok "systemd 服务运行中"
systemctl show "$(service_unit_name)" --property MainPID --value 2>/dev/null | awk '{print " 进程号:" $1}'
@@ -3616,6 +3667,12 @@ doctor_service() {
fi
;;
systemd-user)
stale_warning="$(systemd_unit_stale_runtime_template_warning systemd-user 2>/dev/null || true)"
if [ -n "${stale_warning:-}" ]; then
doctor_warn "$stale_warning"
else
doctor_ok "用户级 systemd 服务模板:当前版本"
fi
if systemctl --user is-active --quiet "$(service_unit_name)"; then
doctor_ok "用户级 systemd 服务运行中"
systemctl --user show "$(service_unit_name)" --property MainPID --value 2>/dev/null | awk '{print " 进程号:" $1}'
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
source_clashctl_for_tests() {
set -- ""
source "$PROJECT_DIR/scripts/core/clashctl.sh" >/dev/null
}
source_clashctl_for_tests
tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT
test_unit_file="$tmp_dir/clash-for-linux.service"
service_unit_name() { printf 'clash-for-linux.service\n'; }
run_case() {
local name="$1"
local expected="$2"
local content="$3"
printf '%s\n' "$content" > "$test_unit_file"
case "$expected" in
stale)
if ! systemd_unit_has_stale_runtime_template "$test_unit_file"; then
echo "not ok - $name: stale unit was not detected" >&2
return 1
fi
;;
fresh)
if systemd_unit_has_stale_runtime_template "$test_unit_file"; then
echo "not ok - $name: fresh unit was marked stale" >&2
return 1
fi
;;
*)
echo "not ok - bad expected value: $expected" >&2
return 1
;;
esac
echo "ok - $name"
}
run_case "detects forking type" stale '[Service]
Type=forking
ExecStart=/usr/local/bin/clashctl run-direct'
run_case "detects pid file" stale '[Service]
Type=simple
PIDFile=/tmp/mihomo.pid
ExecStart=/usr/local/bin/clashctl run-direct'
run_case "detects old start direct command" stale '[Service]
Type=simple
ExecStart=/usr/local/bin/clashctl start-direct'
run_case "accepts current run direct template" fresh '[Service]
Type=simple
ExecStart=/usr/local/bin/clashctl run-direct
ExecStopPost=/bin/rm -f /tmp/mihomo.pid'
systemd_unit_file_path() { printf '%s\n' "$test_unit_file"; }
systemd_user_unit_file_path() { printf '%s\n' "$test_unit_file"; }
printf '%s\n' '[Service]
Type=forking
PIDFile=/tmp/mihomo.pid
ExecStart=/usr/local/bin/clashctl start-direct' > "$test_unit_file"
output="$(systemd_unit_stale_runtime_template_warning systemd)"
if ! printf '%s\n' "$output" | grep -Fq "systemd 服务文件仍是旧模板"; then
echo "not ok - systemd warning missing" >&2
printf '%s\n' "$output" >&2
exit 1
fi
output="$(systemd_unit_stale_runtime_template_warning systemd-user)"
if ! printf '%s\n' "$output" | grep -Fq "用户级 systemd 服务文件仍是旧模板"; then
echo "not ok - systemd-user warning missing" >&2
printf '%s\n' "$output" >&2
exit 1
fi
echo "ok - stale unit warning text"