mirror of
https://github.com/wnlen/clash-for-linux.git
synced 2026-03-21 22:06:45 +08:00
214 lines
4.6 KiB
Bash
Executable File
214 lines
4.6 KiB
Bash
Executable File
resolve_clash_arch() {
|
||
local raw_arch="$1"
|
||
case "$raw_arch" in
|
||
x86_64|amd64) echo "linux-amd64" ;;
|
||
aarch64|arm64) echo "linux-arm64" ;;
|
||
armv7*|armv7l) echo "linux-armv7" ;;
|
||
*) echo "linux-${raw_arch}" ;;
|
||
esac
|
||
}
|
||
|
||
get_latest_mihomo_version() {
|
||
local url="https://api.github.com/repos/MetaCubeX/mihomo/releases/latest"
|
||
|
||
if command -v curl >/dev/null 2>&1; then
|
||
curl -fsSL "$url" \
|
||
| grep '"tag_name"' \
|
||
| sed -E 's/.*"([^"]+)".*/\1/' \
|
||
| head -n 1
|
||
elif command -v wget >/dev/null 2>&1; then
|
||
wget -qO- "$url" \
|
||
| grep '"tag_name"' \
|
||
| sed -E 's/.*"([^"]+)".*/\1/' \
|
||
| head -n 1
|
||
fi
|
||
}
|
||
|
||
download_clash_bin() {
|
||
local server_dir="$1"
|
||
local detected_arch="$2"
|
||
|
||
local resolved_arch
|
||
local version
|
||
local download_url
|
||
|
||
local download_target
|
||
local archive_file
|
||
local tmp_bin
|
||
|
||
resolved_arch="$(resolve_clash_arch "$detected_arch")"
|
||
|
||
if [ -z "$resolved_arch" ]; then
|
||
echo "[WARN] 无法识别 CPU 架构" >&2
|
||
return 1
|
||
fi
|
||
|
||
version="${MIHOMO_VERSION:-}"
|
||
if [ -z "$version" ]; then
|
||
version="$(get_latest_mihomo_version || true)"
|
||
fi
|
||
|
||
if [ -z "$version" ]; then
|
||
echo "[ERROR] 无法获取 Mihomo 版本" >&2
|
||
return 1
|
||
fi
|
||
|
||
if [ -z "${CLASH_DOWNLOAD_URL_TEMPLATE:-}" ]; then
|
||
echo "[ERROR] CLASH_DOWNLOAD_URL_TEMPLATE 未设置" >&2
|
||
return 1
|
||
fi
|
||
|
||
download_url="${CLASH_DOWNLOAD_URL_TEMPLATE//\{arch\}/${resolved_arch}}"
|
||
download_url="${download_url//\{version\}/${version}}"
|
||
|
||
download_target="${server_dir}/bin/clash-${resolved_arch}"
|
||
archive_file="${server_dir}/runtime/.clash_download.tmp"
|
||
tmp_bin="${server_dir}/runtime/.clash_bin.tmp"
|
||
|
||
mkdir -p "${server_dir}/bin" "${server_dir}/runtime"
|
||
|
||
rm -f "$archive_file" "$tmp_bin"
|
||
|
||
echo "[INFO] downloading: $download_url"
|
||
|
||
# =========================
|
||
# 下载
|
||
# =========================
|
||
if command -v curl >/dev/null 2>&1; then
|
||
if ! curl -fL -sS -o "$archive_file" "$download_url"; then
|
||
echo "[ERROR] 下载失败: $download_url" >&2
|
||
return 1
|
||
fi
|
||
elif command -v wget >/dev/null 2>&1; then
|
||
if ! wget -q -O "$archive_file" "$download_url"; then
|
||
echo "[ERROR] 下载失败: $download_url" >&2
|
||
return 1
|
||
fi
|
||
else
|
||
echo "[ERROR] 未找到 curl 或 wget" >&2
|
||
return 1
|
||
fi
|
||
|
||
# =========================
|
||
# 基础校验(防 404 / HTML)
|
||
# =========================
|
||
if [ ! -s "$archive_file" ]; then
|
||
echo "[ERROR] 下载文件为空" >&2
|
||
return 1
|
||
fi
|
||
|
||
if head -c 200 "$archive_file" | grep -qiE "not found|html"; then
|
||
echo "[ERROR] 下载内容疑似错误页面(404/HTML)" >&2
|
||
return 1
|
||
fi
|
||
|
||
# =========================
|
||
# 解压 / 直写
|
||
# =========================
|
||
if gzip -t "$archive_file" >/dev/null 2>&1; then
|
||
if ! gzip -dc "$archive_file" > "$tmp_bin"; then
|
||
echo "[ERROR] gzip 解压失败" >&2
|
||
return 1
|
||
fi
|
||
else
|
||
cp "$archive_file" "$tmp_bin"
|
||
fi
|
||
|
||
# =========================
|
||
# ELF 校验(关键)
|
||
# =========================
|
||
if ! file "$tmp_bin" | grep -q "ELF"; then
|
||
echo "[ERROR] 非有效 ELF 二进制" >&2
|
||
echo "[DEBUG] file result: $(file "$tmp_bin")" >&2
|
||
return 1
|
||
fi
|
||
|
||
chmod +x "$tmp_bin"
|
||
mv "$tmp_bin" "$download_target"
|
||
|
||
rm -f "$archive_file"
|
||
|
||
echo "[OK] downloaded: $download_target"
|
||
echo "$download_target"
|
||
}
|
||
|
||
resolve_clash_bin() {
|
||
local server_dir="$1"
|
||
local detected_arch="$2"
|
||
|
||
local resolved_arch
|
||
local candidates=()
|
||
local candidate
|
||
local downloaded_bin
|
||
local mode
|
||
|
||
if [ -n "${CLASH_BIN:-}" ]; then
|
||
if [ -x "$CLASH_BIN" ]; then
|
||
echo "$CLASH_BIN"
|
||
return 0
|
||
fi
|
||
echo "[ERROR] CLASH_BIN 不可执行: $CLASH_BIN" >&2
|
||
return 1
|
||
fi
|
||
|
||
resolved_arch="$(resolve_clash_arch "$detected_arch")"
|
||
|
||
if [ -n "$resolved_arch" ]; then
|
||
candidates+=("${server_dir}/bin/clash-${resolved_arch}")
|
||
fi
|
||
|
||
candidates+=(
|
||
"${server_dir}/bin/clash-${detected_arch}"
|
||
"${server_dir}/bin/clash"
|
||
)
|
||
|
||
mode="${CLASH_AUTO_DOWNLOAD:-auto}"
|
||
|
||
case "$mode" in
|
||
false)
|
||
for candidate in "${candidates[@]}"; do
|
||
if [ -x "$candidate" ]; then
|
||
echo "$candidate"
|
||
return 0
|
||
fi
|
||
done
|
||
;;
|
||
|
||
auto)
|
||
for candidate in "${candidates[@]}"; do
|
||
if [ -x "$candidate" ]; then
|
||
echo "$candidate"
|
||
return 0
|
||
fi
|
||
done
|
||
|
||
if downloaded_bin="$(download_clash_bin "$server_dir" "$detected_arch")"; then
|
||
echo "$downloaded_bin"
|
||
return 0
|
||
fi
|
||
;;
|
||
|
||
true)
|
||
if downloaded_bin="$(download_clash_bin "$server_dir" "$detected_arch")"; then
|
||
echo "$downloaded_bin"
|
||
return 0
|
||
fi
|
||
|
||
for candidate in "${candidates[@]}"; do
|
||
if [ -x "$candidate" ]; then
|
||
echo "$candidate"
|
||
return 0
|
||
fi
|
||
done
|
||
;;
|
||
|
||
*)
|
||
echo "[ERROR] CLASH_AUTO_DOWNLOAD 非法值: $mode" >&2
|
||
return 1
|
||
;;
|
||
esac
|
||
|
||
echo "[ERROR] 未找到可用 Mihomo 内核" >&2
|
||
echo "请放入: ${server_dir}/bin/" >&2
|
||
return 1
|
||
} |