#!/usr/bin/env bash # YAMA Ghost (Linux client) — install + autostart deployment # # 用法(在解压/克隆后的 linux/ 目录下): # ./install.sh # 默认安装到 ~/.local/bin/ghost # ./install.sh /opt/yama # 安装到 /opt/yama/ghost(如需要会自动 sudo) # # 行为: # 1. 复制 ghost 二进制到目标位置并加可执行权 # 2. 注册 XDG Autostart(~/.config/autostart/ghost.desktop) # 3. 可选立即启动一次(继承当前桌面会话的 X 环境) set -euo pipefail # ---- 防止以 root 直接运行 ---- # 用 sudo 跑会让 $HOME 变成 /root(或 sudo 配置决定的值), # autostart 写到 /root/.config/autostart/,桌面用户的 session 看不见, # 自启动完全失效。需要 sudo 的地方(如装到 /opt/...),脚本会按需自调用 sudo。 if [[ "${EUID:-$(id -u)}" -eq 0 ]]; then echo "请用普通用户身份运行此脚本,不要 sudo。" >&2 echo "如目标目录需要 root 权限,脚本会按需自动调用 sudo。" >&2 exit 1 fi # ---- 颜色 ---- if [[ -t 1 ]]; then C_RED=$'\033[31m'; C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m' C_BLUE=$'\033[34m'; C_BOLD=$'\033[1m'; C_RESET=$'\033[0m' else C_RED=''; C_GREEN=''; C_YELLOW=''; C_BLUE=''; C_BOLD=''; C_RESET='' fi info() { echo "${C_BLUE}[INFO]${C_RESET} $*"; } ok() { echo "${C_GREEN}[ OK ]${C_RESET} $*"; } warn() { echo "${C_YELLOW}[WARN]${C_RESET} $*"; } error() { echo "${C_RED}[FAIL]${C_RESET} $*" >&2; } # ---- 路径解析 ---- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SRC_BIN="${SCRIPT_DIR}/ghost" # 安装目标目录(参数 $1,默认 ~/.local/bin) INSTALL_DIR="${1:-${HOME}/.local/bin}" DEST_BIN="${INSTALL_DIR}/ghost" AUTOSTART_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/autostart" AUTOSTART_FILE="${AUTOSTART_DIR}/ghost.desktop" echo "${C_BOLD}YAMA Ghost Linux 安装${C_RESET}" echo " 源: ${SRC_BIN}" echo " 目标: ${DEST_BIN}" echo " 自启动: ${AUTOSTART_FILE}" echo "" # ---- 前置检查 ---- if [[ ! -f "${SRC_BIN}" ]]; then error "找不到 ghost 二进制 ${SRC_BIN}" error "请把 install.sh 放在 ghost 同目录后再运行" exit 1 fi if ! file "${SRC_BIN}" 2>/dev/null | grep -q "ELF.*executable"; then error "${SRC_BIN} 不是有效的 ELF 可执行文件" exit 1 fi # 判断目标目录是否需要 sudo # 三种情况都要走 sudo 分支: # a) 目录不存在且父目录无写权(如 /opt/yama 父是 /opt root-owned) # b) 目录已存在但当前用户无写权(如已存在的 /usr/local/bin root-owned) # c) 介于两者之间的情况由 mkdir 的退出码决定 NEED_SUDO="" if [[ -d "${INSTALL_DIR}" ]]; then [[ -w "${INSTALL_DIR}" ]] || NEED_SUDO="sudo" else if ! mkdir -p "${INSTALL_DIR}" 2>/dev/null; then NEED_SUDO="sudo" fi fi if [[ -n "${NEED_SUDO}" ]]; then info "目标目录需要 root 权限,将使用 sudo(可能需要输入密码)" ${NEED_SUDO} mkdir -p "${INSTALL_DIR}" fi # ---- 1. 如已运行则先停止 ---- if pgrep -x ghost > /dev/null; then warn "检测到 ghost 进程正在运行,先停止以替换二进制" pkill -x ghost || true sleep 1 if pgrep -x ghost > /dev/null; then warn "进程未优雅退出,强制 kill" pkill -9 -x ghost || true sleep 1 fi ok "旧进程已停止" fi # ---- 2. 复制二进制 ---- info "复制 ghost 到 ${DEST_BIN}" ${NEED_SUDO} install -m 0755 "${SRC_BIN}" "${DEST_BIN}" ok "二进制已部署 (mode 0755)" # ---- 3. 写 XDG Autostart 文件 ---- mkdir -p "${AUTOSTART_DIR}" cat > "${AUTOSTART_FILE}" </dev/null 2>&1; then if desktop-file-validate "${AUTOSTART_FILE}" >/dev/null 2>&1; then ok "Autostart 文件格式验证通过" else warn "desktop-file-validate 报告了警告,但通常不影响功能" fi fi # ---- 4. 可选:立即启动 ---- echo "" echo -n "${C_BOLD}是否立即启动 ghost(验证 X 环境)?[Y/n]${C_RESET} " read -r ans if [[ -z "${ans}" || "${ans}" =~ ^[Yy]$ ]]; then if [[ -z "${DISPLAY:-}" ]]; then warn "当前 shell 没有 DISPLAY 变量,可能不在桌面会话内 — 启动后远控仍可能 0x0" warn "建议在 GNOME 终端/桌面环境的终端里运行此脚本" fi nohup "${DEST_BIN}" >/dev/null 2>&1 & sleep 1 if pgrep -x ghost > /dev/null; then ok "ghost 已启动 (PID=$(pgrep -x ghost | head -1))" else error "启动失败,请手动跑 ${DEST_BIN} 看错误输出" exit 1 fi fi echo "" echo "${C_GREEN}${C_BOLD}✓ 安装完成${C_RESET}" echo "" echo "下次开机将自动启动;如需立即测试,重启或在桌面终端跑:" echo " ${DEST_BIN}" echo "" echo "卸载请运行同目录的 ./uninstall.sh"