#!/bin/sh # Upgrade the existing installation, retaining its data and administrator account. set -eu PATH=/usr/sbin:/usr/bin:/sbin:/bin export PATH umask 077 usage() { cat <<'HELP' 用法:sudo ./upgrade.sh [--prefix /opt/bluebird] [--access-url URL ...] [--lan-url URL] [--listen IP:端口] [--no-start] 保留当前配置参数、文件、密钥和管理员密码;新增入口与指定监听地址会合并到配置中。 默认停止服务、一致性备份、更新程序及配置、检查后启动。失败时恢复旧程序和配置。 --no-start用于已手动停服的离线升级,升级后暂不启动服务。 HELP } die(){ printf '%s\n' "升级失败:$*" >&2;exit 1; } value(){ [ "$#" -ge 2 ] && [ -n "$2" ] || die "$1缺少参数"; } prefix=/opt/bluebird additions= lan_url= listen= no_start=false while [ "$#" -gt 0 ];do case "$1" in --prefix) value "$@";prefix=$2;shift 2 ;; --access-url) value "$@";case "$2" in *[[:space:]]*) die '访问地址不能含空白' ;;esac;additions="$additions $2";shift 2 ;; --lan-url) value "$@";lan_url=$2;shift 2 ;; --listen) value "$@";listen=$2;shift 2 ;; --no-start) no_start=true;shift ;; -h|--help) usage;exit 0 ;; *) die "未知选项:$1" ;; esac done [ "$(id -u)" = 0 ] || die '请使用sudo或root运行' [ "$(uname -s)" = Linux ] || die '仅支持Linux' prefix=$(realpath -m -- "$prefix") [ -x "$prefix/bluebird" ] && [ -f "$prefix/config.toml" ] || die '未找到已有安装,请使用install.sh' exec 9>"$prefix/.upgrade.lock" flock -n 9 || die '另一升级进程正在运行' package_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) [ -x "$package_dir/bluebird" ] && [ -r "$package_dir/ARCH" ] || die '请在新版发布包目录运行' case "$(cat "$package_dir/ARCH"):$(uname -m)" in amd64:x86_64|arm64:aarch64) ;;*) die '发布包架构与主机不匹配' ;;esac if [ "$no_start" = false ];then [ -d /run/systemd/system ] && command -v systemctl >/dev/null || die 'systemd未运行,先手动停服再使用--no-start';fi candidate=$(mktemp "$prefix/.upgrade-config-XXXXXX.toml") backup= changed=false was_active=false success=false cleanup(){ rm -f -- "$candidate" "$prefix/bluebird.new" if [ "$success" = false ];then if [ "$changed" = true ];then if [ "$no_start" = false ];then systemctl stop bluebird.service || :;fi install -o root -g bluebird -m 0750 "$backup/bluebird" "$prefix/bluebird.rollback" mv -f -- "$prefix/bluebird.rollback" "$prefix/bluebird" cp -p -- "$backup/config.toml" "$prefix/config.toml" printf '%s\n' "已恢复旧程序和配置;备份保留在$backup" >&2 fi if [ "$was_active" = true ] && [ "$no_start" = false ];then systemctl start bluebird.service || :;fi fi } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM HUP cp -p -- "$prefix/config.toml" "$candidate" set -- "$package_dir/bluebird" configure-access --config "$candidate" [ -z "$listen" ] || set -- "$@" --listen "$listen" [ -z "$lan_url" ] || set -- "$@" --lan-url "$lan_url" # URLs are separate argv values, never shell code. Globbing is disabled. set -f for item in $additions;do set -- "$@" --access-url "$item";done "$@" "$package_dir/bluebird" validate-config --config "$candidate" if [ "$no_start" = false ];then if systemctl is-active --quiet bluebird.service;then was_active=true;fi systemctl stop bluebird.service fi backup="$prefix/backups/upgrade-$(date -u +%Y%m%dT%H%M%SZ)-$$" install -d -o bluebird -g bluebird -m 0700 "$backup" cp -p -- "$prefix/config.toml" "$backup/config.toml" install -o root -g bluebird -m 0750 "$prefix/bluebird" "$backup/bluebird" runuser -u bluebird -- "$prefix/bluebird" backup --config "$prefix/config.toml" --output "$backup/data.tar.gz" # No configuration/data reinitialization; keep all existing administrator hashes. install -o root -g bluebird -m 0750 "$package_dir/bluebird" "$prefix/bluebird.new" changed=true mv -f -- "$prefix/bluebird.new" "$prefix/bluebird" mv -f -- "$candidate" "$prefix/config.toml" runuser -u bluebird -- "$prefix/bluebird" check --config "$prefix/config.toml" if [ "$no_start" = false ];then systemctl start bluebird.service;systemctl is-active --quiet bluebird.service;fi success=true printf '%s\n' "升级完成:$prefix" "旧版本、配置及一致性数据备份:$backup" if [ "$no_start" = true ];then printf '%s\n' '服务尚未启动,请执行:systemctl start bluebird.service';fi