#!/usr/bin/env bash set -euo pipefail TARGET_PATH="${GENARRATIVE_PINGORA_REALPATH_CANARY_TARGET_PATH:-/etc/nginx/conf.d/zz-genarrative-pingora-realpath-canary.conf}" NGINX_BINARY="${GENARRATIVE_NGINX_BINARY:-nginx}" NGINX_SERVICE="${GENARRATIVE_NGINX_SERVICE:-nginx.service}" SYSTEMCTL_BINARY="${GENARRATIVE_SYSTEMCTL_BINARY:-systemctl}" APPLY="false" STATUS_AFTER="true" usage() { cat <<'EOF' 用法: scripts/deploy/pingora-realpath-canary-disable.sh [--apply] [--target-path ] [--nginx-binary ] [--nginx-service ] [--systemctl-binary ] [--no-status] 说明: 关闭 Nginx -> Pingora 真实路径 canary:删除 /etc/nginx/conf.d/zz-genarrative-pingora-realpath-canary.conf,执行 nginx -t, 再 reload nginx。默认 dry-run,必须显式传 --apply 才会修改系统。 如果 nginx -t 或 reload 失败,脚本会恢复删除前的目标文件。 EOF } while [[ $# -gt 0 ]]; do case "$1" in -h|--help) usage exit 0 ;; --apply) APPLY="true" shift ;; --target-path) TARGET_PATH="${2:-}" if [[ -z "${TARGET_PATH}" ]]; then echo "[pingora-realpath-canary-disable] --target-path 缺少参数" >&2 exit 1 fi shift 2 ;; --nginx-binary) NGINX_BINARY="${2:-}" if [[ -z "${NGINX_BINARY}" ]]; then echo "[pingora-realpath-canary-disable] --nginx-binary 缺少参数" >&2 exit 1 fi shift 2 ;; --nginx-service) NGINX_SERVICE="${2:-}" if [[ -z "${NGINX_SERVICE}" ]]; then echo "[pingora-realpath-canary-disable] --nginx-service 缺少参数" >&2 exit 1 fi shift 2 ;; --systemctl-binary) SYSTEMCTL_BINARY="${2:-}" if [[ -z "${SYSTEMCTL_BINARY}" ]]; then echo "[pingora-realpath-canary-disable] --systemctl-binary 缺少参数" >&2 exit 1 fi shift 2 ;; --no-status) STATUS_AFTER="false" shift ;; *) echo "[pingora-realpath-canary-disable] 未知参数: $1" >&2 usage >&2 exit 1 ;; esac done reject_control_characters() { local label="$1" local value="$2" if [[ "${value}" == *$'\n'* || "${value}" == *$'\r'* ]]; then echo "[pingora-realpath-canary-disable] ${label} 不能包含换行或 NUL 字符。" >&2 exit 1 fi } is_filesystem_root_path() { local value="$1" local without_slashes="${value//\//}" [[ -n "${value}" && -z "${without_slashes}" ]] } require_absolute_path() { local label="$1" local value="$2" if [[ "${value}" != /* ]]; then echo "[pingora-realpath-canary-disable] ${label} 必须是绝对路径。" >&2 exit 1 fi if is_filesystem_root_path "${value}"; then echo "[pingora-realpath-canary-disable] ${label} 不能是文件系统根目录。" >&2 exit 1 fi } validate_command_or_absolute_path() { local label="$1" local value="$2" if [[ "${value}" == */* ]]; then require_absolute_path "${label}" "${value}" fi } print_command() { printf '+' for arg in "$@"; do printf ' %q' "${arg}" done printf '\n' } run_or_print() { if [[ "${APPLY}" == "true" ]]; then "$@" else print_command "$@" fi } restore_previous() { local backup_path="$1" cp -p -- "${backup_path}" "${TARGET_PATH}" } rollback_after_failure() { local backup_path="$1" local reason="$2" echo "[pingora-realpath-canary-disable] ${reason},恢复删除前配置。" >&2 restore_previous "${backup_path}" "${NGINX_BINARY}" -t >/dev/null 2>&1 || true "${SYSTEMCTL_BINARY}" reload "${NGINX_SERVICE}" >/dev/null 2>&1 || true } reject_control_characters "--target-path" "${TARGET_PATH}" reject_control_characters "--nginx-binary" "${NGINX_BINARY}" reject_control_characters "--nginx-service" "${NGINX_SERVICE}" reject_control_characters "--systemctl-binary" "${SYSTEMCTL_BINARY}" require_absolute_path "--target-path" "${TARGET_PATH}" validate_command_or_absolute_path "--nginx-binary" "${NGINX_BINARY}" validate_command_or_absolute_path "--systemctl-binary" "${SYSTEMCTL_BINARY}" TARGET_DIR="$(dirname -- "${TARGET_PATH}")" if [[ "${APPLY}" == "true" && ( -L "${TARGET_DIR}" || -L "${TARGET_PATH}" ) ]]; then echo "[pingora-realpath-canary-disable] 目标目录或目标文件不能是符号链接。" >&2 exit 1 fi if [[ "${APPLY}" != "true" ]]; then echo "[pingora-realpath-canary-disable] dry-run:将删除 realpath canary ${TARGET_PATH}。" print_command rm -f -- "${TARGET_PATH}" run_or_print "${NGINX_BINARY}" -t run_or_print "${SYSTEMCTL_BINARY}" reload "${NGINX_SERVICE}" exit 0 fi if [[ ! -e "${TARGET_PATH}" ]]; then echo "[pingora-realpath-canary-disable] 目标文件不存在,视为已关闭: ${TARGET_PATH}" if [[ "${STATUS_AFTER}" == "true" ]]; then "${SYSTEMCTL_BINARY}" is-active "${NGINX_SERVICE}" fi exit 0 fi if [[ ! -f "${TARGET_PATH}" ]]; then echo "[pingora-realpath-canary-disable] 目标存在但不是普通文件: ${TARGET_PATH}" >&2 exit 1 fi backup_path="$(mktemp "${TARGET_DIR}/.genarrative-pingora-realpath-canary.disable.backup.XXXXXX")" trap 'rm -f -- "${backup_path}"' EXIT cp -p -- "${TARGET_PATH}" "${backup_path}" rm -f -- "${TARGET_PATH}" if ! "${NGINX_BINARY}" -t; then rollback_after_failure "${backup_path}" "nginx -t 失败" exit 1 fi if ! "${SYSTEMCTL_BINARY}" reload "${NGINX_SERVICE}"; then rollback_after_failure "${backup_path}" "reload ${NGINX_SERVICE} 失败" exit 1 fi if [[ "${STATUS_AFTER}" == "true" ]]; then "${SYSTEMCTL_BINARY}" is-active "${NGINX_SERVICE}" fi echo "[pingora-realpath-canary-disable] 已关闭 realpath canary: ${TARGET_PATH}"