#!/bin/sh set -eu if [ "$(id -u)" -ne 0 ]; then echo "install_frpc_system.sh must run as root" >&2 exit 1 fi if [ "$(uname -m)" != "aarch64" ]; then echo "frpc system payload is only for AArch64" >&2 exit 1 fi SOURCE_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) PROJECT_ROOT=$(CDPATH= cd -- "$SOURCE_ROOT/.." && pwd) BUNDLE=${FRPC_BUNDLE:-$PROJECT_ROOT/发布更新相关/其他依赖/frp/0.71.0/linux-arm64} UNIT_SOURCE=$SOURCE_ROOT/systemd/matrix-screen-frpc.service UNIT=/etc/systemd/system/matrix-screen-frpc.service DROPIN_DIR=/etc/systemd/system/matrix-screen-frpc.service.d DROPIN=$DROPIN_DIR/user.conf BINARY=/usr/local/bin/frpc SERVICE=matrix-screen-frpc.service STATE_ROOT=/var/lib/matrix-screen-controller/frp if [ ! -f "$BUNDLE/SHA256SUMS" ] || [ ! -f "$BUNDLE/frpc" ] || [ ! -f "$BUNDLE/LICENSE" ]; then echo "verified frpc offline bundle is incomplete: $BUNDLE" >&2 exit 1 fi (cd "$BUNDLE" && sha256sum -c SHA256SUMS) RUN_USER=${FRPC_RUN_USER:-${SUDO_USER:-}} if [ -z "$RUN_USER" ] && [ -f "$DROPIN" ]; then RUN_USER=$(sed -n 's/^User=//p' "$DROPIN" | head -n 1) fi if [ -z "$RUN_USER" ]; then RUN_USER=$(python3 -c 'import sys; sys.path.insert(0, sys.argv[1]); from scripts.ota_components import account; print(account())' "$SOURCE_ROOT") fi case "$RUN_USER" in ''|root|*[!a-zA-Z0-9_-]*) echo "FRPC_RUN_USER must identify the non-root maintenance account" >&2 exit 1 ;; esac if ! getent passwd "$RUN_USER" >/dev/null 2>&1 && [ "${DEFER_SERVICE_START:-0}" != "1" ]; then echo "FRP maintenance account does not exist" >&2 exit 1 fi RUN_GROUP=$RUN_USER if getent passwd "$RUN_USER" >/dev/null 2>&1; then RUN_GROUP=$(id -gn "$RUN_USER"); fi binary_matches=0 if [ -f "$BINARY" ] && [ ! -L "$BINARY" ] && cmp -s "$BUNDLE/frpc" "$BINARY" && [ "$(stat -c %a:%u:%g "$BINARY")" = 755:0:0 ]; then binary_matches=1; fi unit_matches=0 if [ -f "$DROPIN" ] && cmp -s "$UNIT_SOURCE" "$UNIT" && [ "$(stat -c %a:%u:%g "$UNIT")" = 644:0:0 ] && [ "$(stat -c %a:%u:%g "$DROPIN")" = 644:0:0 ] && [ "$(cat "$DROPIN")" = "$(printf '[Service]\nUser=%s\nGroup=%s\n' "$RUN_USER" "$RUN_GROUP")" ]; then unit_matches=1; fi was_active=0 was_enabled=0 systemctl is-active --quiet "$SERVICE" 2>/dev/null && was_active=1 || true systemctl is-enabled --quiet "$SERVICE" 2>/dev/null && was_enabled=1 || true if [ "$was_active" -eq 1 ] && { [ "$binary_matches" -eq 0 ] || [ "$unit_matches" -eq 0 ]; }; then systemctl stop "$SERVICE"; fi install -d -m 0755 /usr/local/bin temporary=/usr/local/bin/.frpc.install.$$ cleanup() { case "$temporary" in /usr/local/bin/.frpc.install.*) rm -f -- "$temporary" ;; esac } trap cleanup EXIT HUP INT TERM if [ "$binary_matches" -eq 0 ]; then install -m 0755 "$BUNDLE/frpc" "$temporary" "$temporary" --version | grep -Fx '0.71.0' >/dev/null mv -f -- "$temporary" "$BINARY" else "$BINARY" --version | grep -Fx '0.71.0' >/dev/null echo "frpc binary already verified; skipped" fi trap - EXIT HUP INT TERM if [ "$unit_matches" -eq 0 ]; then install -m 0644 "$UNIT_SOURCE" "$UNIT" install -d -m 0755 "$DROPIN_DIR" printf '[Service]\nUser=%s\nGroup=%s\n' "$RUN_USER" "$RUN_GROUP" > "$DROPIN" chmod 0644 "$DROPIN" fi if getent passwd "$RUN_USER" >/dev/null 2>&1; then RUN_GROUP=$(id -gn "$RUN_USER") # Local accounts may only traverse (not list) the persistent root; the # FRP subtree itself remains restricted to root and the maintenance group. chmod 0711 "$(dirname -- "$STATE_ROOT")" install -d -o root -g "$RUN_GROUP" -m 2750 "$STATE_ROOT" install -d -o root -g "$RUN_GROUP" -m 2750 "$STATE_ROOT/profiles" find "$STATE_ROOT" -type d -exec chown root:"$RUN_GROUP" {} \; -exec chmod 2750 {} \; find "$STATE_ROOT" -type f -exec chown root:"$RUN_GROUP" {} \; -exec chmod 0640 {} \; if [ -f "$STATE_ROOT/active.env" ]; then chmod 0600 "$STATE_ROOT/active.env"; fi elif [ "${DEFER_SERVICE_START:-0}" != "1" ]; then echo "FRP maintenance account does not exist: $RUN_USER" >&2 exit 1 fi if [ "$unit_matches" -eq 0 ]; then systemctl daemon-reload if [ "$was_enabled" -eq 1 ]; then systemctl enable "$SERVICE" >/dev/null; else systemctl disable "$SERVICE" >/dev/null 2>&1 || true; fi fi if [ "$was_active" -eq 1 ] && { [ "$binary_matches" -eq 0 ] || [ "$unit_matches" -eq 0 ]; }; then systemctl start "$SERVICE"; fi echo "frpc 0.71.0 installed as a system component"