#!/usr/bin/env bash # Действия, которые панель не может выполнить сама: она работает от # непривилегированного пользователя, а бинарник и systemd принадлежат root. # # Скрипт ставится установщиком в /usr/local/bin/pzmanager-admin (root:root) и # разрешён сервисному пользователю в /etc/sudoers.d/pzmanager — ровно эта # команда и ничего больше. Аргументы проверяются здесь: sudo пропускает любые. # # Значения ниже подставляет install.sh при установке. set -euo pipefail PZ_REPO="@PZ_REPO@" PZ_BINARY="@PZ_BINARY@" PZ_SERVICE="pzmanager" die() { echo "Ошибка: $*" >&2; exit 1; } api_base() { local url="${PZ_REPO%/}" url="${url%.git}" local host="${url%%://*}://$(printf '%s' "${url#*://}" | cut -d/ -f1)" printf '%s/api/v1/repos/%s' "$host" "${url#"$host"/}" } cmd_update() { local version="${1:-latest}" local api release tag url name tmp arch case "$(uname -m)" in x86_64 | amd64) arch=amd64 ;; aarch64 | arm64) arch=arm64 ;; *) die "архитектура $(uname -m) не поддерживается" ;; esac api="$(api_base)" if [[ "$version" == "latest" ]]; then release="$(curl -fsSL "${api}/releases/latest")" || die "не удалось запросить релиз" else # Тег приходит из панели; всё, кроме безопасных символов, отвергаем. [[ "$version" =~ ^[A-Za-z0-9._-]+$ ]] || die "недопустимая версия: $version" release="$(curl -fsSL "${api}/releases/tags/${version}")" || die "релиз ${version} не найден" fi tag="$(printf '%s' "$release" | grep -o '"tag_name" *: *"[^"]*"' | head -1 | cut -d'"' -f4)" [[ -n "$tag" ]] || die "в ответе нет тега" name="pzmanager-linux-${arch}" url="$(printf '%s' "$release" \ | grep -o '"browser_download_url" *: *"[^"]*"' | cut -d'"' -f4 \ | while read -r candidate; do [[ "${candidate##*/}" == "$name" ]] && { printf '%s' "$candidate"; break; } done)" [[ -n "$url" ]] || die "в релизе ${tag} нет файла ${name}" local sums_url sums_url="$(printf '%s' "$release" \ | grep -o '"browser_download_url" *: *"[^"]*"' | cut -d'"' -f4 \ | while read -r candidate; do [[ "${candidate##*/}" == "checksums.txt" ]] && { printf '%s' "$candidate"; break; } done)" [[ -n "$sums_url" ]] || die "в релизе ${tag} нет checksums.txt" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' RETURN echo "==> Скачиваю ${tag} (${arch})" curl -fsSL -o "${tmp}/${name}" "$url" || die "не удалось скачать ${name}" curl -fsSL -o "${tmp}/checksums.txt" "$sums_url" || die "не удалось скачать checksums.txt" echo "==> Проверяю контрольную сумму" ( cd "$tmp" && grep " ${name}\$" checksums.txt > expected.txt && sha256sum -c expected.txt ) \ || die "контрольная сумма не сошлась — файл повреждён или подменён" echo "==> Заменяю ${PZ_BINARY}" chmod 0755 "${tmp}/${name}" # Через временный файл рядом и rename: перезаписать работающий бинарник # нельзя, а переименовать поверх — можно. install -m 0755 "${tmp}/${name}" "${PZ_BINARY}.new" mv -f "${PZ_BINARY}.new" "${PZ_BINARY}" echo "==> Перезапускаю ${PZ_SERVICE}" systemctl restart "$PZ_SERVICE" echo "Обновлено до ${tag}" } case "${1:-}" in update) cmd_update "${2:-latest}" ;; restart) echo "==> Перезапускаю ${PZ_SERVICE}" systemctl restart "$PZ_SERVICE" ;; version) "$PZ_BINARY" version ;; *) echo "Использование: pzmanager-admin update [версия] | restart | version" >&2 exit 2 ;; esac