mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-10-10 04:03:04 +08:00
Fix clashoff stopping runtime
This commit is contained in:
@@ -296,15 +296,21 @@ cmd_on() {
|
||||
}
|
||||
|
||||
cmd_off() {
|
||||
local system_proxy_rc
|
||||
local system_proxy_rc stop_rc
|
||||
local system_proxy_state_before system_proxy_cleanup_blocked="false"
|
||||
|
||||
prepare
|
||||
|
||||
system_proxy_state_before="$(system_proxy_status 2>/dev/null || echo off)"
|
||||
|
||||
if system_proxy_disable; then
|
||||
:
|
||||
else
|
||||
system_proxy_rc=$?
|
||||
write_runtime_value "RUNTIME_BOOT_PROXY_KEEP" "false" 2>/dev/null || true
|
||||
|
||||
if [ "$system_proxy_state_before" = "on" ]; then
|
||||
system_proxy_cleanup_blocked="true"
|
||||
if [ "$system_proxy_rc" -eq 2 ]; then
|
||||
ui_warn "当前环境不支持清理系统代理持久块,已继续关闭运行时"
|
||||
else
|
||||
@@ -312,11 +318,42 @@ cmd_off() {
|
||||
ui_next "clashctl doctor"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if status_is_running 2>/dev/null; then
|
||||
stop_rc=0
|
||||
service_stop || stop_rc=$?
|
||||
if [ "$stop_rc" -ne 0 ]; then
|
||||
die_state "关闭运行时失败:运行后端 stop 返回 ${stop_rc}" "clashctl logs"
|
||||
fi
|
||||
|
||||
if ! wait_runtime_stopped 8; then
|
||||
die_state "关闭运行时失败:代理内核仍在运行" "clashctl logs"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$system_proxy_cleanup_blocked" = "true" ]; then
|
||||
die_state "系统代理持久块未清理:$(system_proxy_env_file)" "请使用有权限的用户执行 clashctl off,或手动清理该文件中的 clash-for-linux 代理块"
|
||||
fi
|
||||
|
||||
ui_blank
|
||||
echo "🧹 系统代理已关闭"
|
||||
echo "🧹 代理已关闭"
|
||||
ui_blank
|
||||
}
|
||||
|
||||
wait_runtime_stopped() {
|
||||
local timeout="${1:-8}"
|
||||
local elapsed=0
|
||||
|
||||
while status_is_running 2>/dev/null; do
|
||||
[ "$elapsed" -lt "$timeout" ] || return 1
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
ui_internal_url() {
|
||||
local controller host port
|
||||
controller="${1:-}"
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/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 the real functions; suppress the no-arg usage printed by the command dispatcher.
|
||||
source "$PROJECT_DIR/scripts/core/clashctl.sh" >/dev/null
|
||||
}
|
||||
|
||||
source_clashctl_for_tests
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' EXIT
|
||||
|
||||
prepare() { :; }
|
||||
ui_warn() { printf 'warn: %s\n' "$*" >> "$tmp_dir/output"; }
|
||||
ui_next() { printf 'next: %s\n' "$*" >> "$tmp_dir/output"; }
|
||||
ui_blank() { :; }
|
||||
system_proxy_env_file() { printf '%s\n' "$tmp_dir/environment"; }
|
||||
write_runtime_value() { :; }
|
||||
die_state() {
|
||||
printf 'die: %s\nnext: %s\n' "$1" "$2" >> "$tmp_dir/output"
|
||||
exit 1
|
||||
}
|
||||
|
||||
run_case() {
|
||||
local name="$1"
|
||||
local proxy_rc="$2"
|
||||
local stop_calls_file="$tmp_dir/stop-calls"
|
||||
local output_file="$tmp_dir/output"
|
||||
|
||||
: > "$stop_calls_file"
|
||||
: > "$output_file"
|
||||
|
||||
system_proxy_disable() { return "$proxy_rc"; }
|
||||
service_stop() { printf 'stop\n' >> "$stop_calls_file"; }
|
||||
status_is_running() {
|
||||
[ ! -s "$stop_calls_file" ]
|
||||
}
|
||||
|
||||
cmd_off > "$output_file"
|
||||
|
||||
if [ "$(wc -l < "$stop_calls_file" | tr -d ' ')" != "1" ]; then
|
||||
echo "not ok - $name: service_stop was not called exactly once" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "代理已关闭" "$output_file"; then
|
||||
echo "not ok - $name: success feedback missing" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "ok - $name"
|
||||
}
|
||||
|
||||
run_case "stops runtime after disabling system proxy" 0
|
||||
run_case "still stops runtime when system proxy cleanup is unsupported" 2
|
||||
|
||||
run_stop_failure_case() {
|
||||
local stop_calls_file="$tmp_dir/stop-failure-calls"
|
||||
local output_file="$tmp_dir/output"
|
||||
|
||||
: > "$stop_calls_file"
|
||||
: > "$output_file"
|
||||
|
||||
system_proxy_disable() { return 0; }
|
||||
service_stop() {
|
||||
printf 'stop\n' >> "$stop_calls_file"
|
||||
return 7
|
||||
}
|
||||
status_is_running() { return 0; }
|
||||
|
||||
if ( cmd_off ) > "$output_file"; then
|
||||
echo "not ok - stop failure: cmd_off unexpectedly succeeded" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "运行后端 stop 返回 7" "$output_file"; then
|
||||
echo "not ok - stop failure: missing stop failure detail" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -Fq "代理已关闭" "$output_file"; then
|
||||
echo "not ok - stop failure: printed success after stop failure" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "ok - stop failure returns non-zero"
|
||||
}
|
||||
|
||||
run_persistent_cleanup_blocked_case() {
|
||||
local stop_calls_file="$tmp_dir/persistent-cleanup-blocked-calls"
|
||||
local output_file="$tmp_dir/output"
|
||||
|
||||
: > "$stop_calls_file"
|
||||
: > "$output_file"
|
||||
|
||||
system_proxy_status() { printf 'on\n'; }
|
||||
system_proxy_disable() { return 2; }
|
||||
service_stop() { printf 'stop\n' >> "$stop_calls_file"; }
|
||||
status_is_running() {
|
||||
[ ! -s "$stop_calls_file" ]
|
||||
}
|
||||
|
||||
if ( cmd_off ) > "$output_file"; then
|
||||
echo "not ok - persistent cleanup blocked: cmd_off unexpectedly succeeded" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$(wc -l < "$stop_calls_file" | tr -d ' ')" != "1" ]; then
|
||||
echo "not ok - persistent cleanup blocked: service_stop was not called exactly once" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "系统代理持久块未清理" "$output_file"; then
|
||||
echo "not ok - persistent cleanup blocked: missing cleanup failure detail" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -Fq "代理已关闭" "$output_file"; then
|
||||
echo "not ok - persistent cleanup blocked: printed success while persistent proxy remained" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "ok - persistent cleanup failure returns non-zero after stopping runtime"
|
||||
}
|
||||
|
||||
run_still_running_case() {
|
||||
local stop_calls_file="$tmp_dir/still-running-calls"
|
||||
local output_file="$tmp_dir/output"
|
||||
|
||||
: > "$stop_calls_file"
|
||||
: > "$output_file"
|
||||
|
||||
system_proxy_disable() { return 0; }
|
||||
service_stop() { printf 'stop\n' >> "$stop_calls_file"; }
|
||||
status_is_running() { return 0; }
|
||||
wait_runtime_stopped() { return 1; }
|
||||
|
||||
if ( cmd_off ) > "$output_file"; then
|
||||
echo "not ok - still running: cmd_off unexpectedly succeeded" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! grep -Fq "代理内核仍在运行" "$output_file"; then
|
||||
echo "not ok - still running: missing still-running detail" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -Fq "代理已关闭" "$output_file"; then
|
||||
echo "not ok - still running: printed success while runtime stayed up" >&2
|
||||
sed 's/^/ /' "$output_file" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "ok - still running returns non-zero"
|
||||
}
|
||||
|
||||
run_stop_failure_case
|
||||
run_persistent_cleanup_blocked_case
|
||||
run_still_running_case
|
||||
Reference in New Issue
Block a user