139 lines
7.5 KiB
Bash
139 lines
7.5 KiB
Bash
#!/usr/bin/env bash
|
|
# device-install.sh — выполняется НА устройстве (заливается через adb).
|
|
# Offline-установка пакетов + полный провижининг по образцу README.
|
|
# Идемпотентен: повторный запуск безопасен, существующий config не трогается.
|
|
set -euo pipefail
|
|
|
|
BUNDLE_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
ROOT=/opt/buttontask
|
|
USER_NAME=buttontask
|
|
VER="$(cat "$BUNDLE_DIR/VERSION" 2>/dev/null || echo 0.0)"
|
|
|
|
log() { printf '\033[1;32m[install]\033[0m %s\n' "$*"; }
|
|
warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*"; }
|
|
die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
[ "$(id -u)" -eq 0 ] || die "нужны root-права (adb root или sudo на устройстве)"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. Offline-пакеты
|
|
# ---------------------------------------------------------------------------
|
|
if ls "$BUNDLE_DIR"/debs/*.deb >/dev/null 2>&1; then
|
|
log "Установка пакетов offline (dpkg)..."
|
|
# Конфликтующие альтернативы (напр. *-gles, elogind) dpkg отвергнет — это нормально:
|
|
# нужное ставится, лишнее нам не нужно. Код возврата dpkg НЕ фатальный;
|
|
# реальный рантайм проверяем ниже.
|
|
dpkg -i "$BUNDLE_DIR"/debs/*.deb || true
|
|
dpkg -i "$BUNDLE_DIR"/debs/*.deb >/dev/null 2>&1 || true # второй проход — порядок
|
|
ldconfig
|
|
else
|
|
warn "каталог debs/ пуст — пропускаю установку пакетов"
|
|
fi
|
|
|
|
# --- проверяем, что РЕАЛЬНО нужное на месте (а не код возврата dpkg) ---
|
|
command -v python3 >/dev/null || die "python3 не установился"
|
|
python3 -c 'import flask' 2>/dev/null || die "python3-flask не установился"
|
|
command -v nmcli >/dev/null || warn "nmcli отсутствует — сетевые настройки из web не заработают"
|
|
ls /usr/lib/*/qt5/qml/QtQuick/Controls.2 >/dev/null 2>&1 \
|
|
|| warn "QML-модуль QtQuick.Controls 2 не найден — UI может не подняться"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. Системный пользователь
|
|
# ---------------------------------------------------------------------------
|
|
id "$USER_NAME" >/dev/null 2>&1 || useradd -r -s /bin/false "$USER_NAME"
|
|
# группы для eglfs/KMS/тача
|
|
usermod -aG video,render,input "$USER_NAME" 2>/dev/null || true
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. Версионированная раскладка
|
|
# ---------------------------------------------------------------------------
|
|
install -d "$ROOT"/versions/"$VER" "$ROOT"/config "$ROOT"/icons "$ROOT"/run "$ROOT"/scripts
|
|
[ -f "$BUNDLE_DIR/app/ButtonTask" ] || die "нет бинарника app/ButtonTask в бандле"
|
|
install -m0755 "$BUNDLE_DIR/app/ButtonTask" "$ROOT/versions/$VER/ButtonTask"
|
|
cp -a "$BUNDLE_DIR/webconfig" "$ROOT/versions/$VER/"
|
|
ln -sfn "$ROOT/versions/$VER" "$ROOT/current"
|
|
|
|
# config — не перезатираем существующий (apgrade-safe)
|
|
if [ -f "$ROOT/config/config.json" ]; then
|
|
log "config.json уже есть — оставляю как есть"
|
|
elif [ -f "$BUNDLE_DIR/config/config.json" ]; then
|
|
cp -a "$BUNDLE_DIR/config/config.json" "$ROOT/config/"
|
|
log "config.json установлен"
|
|
else
|
|
warn "config.json нет ни на устройстве, ни в бандле — приложение создаст дефолтный при старте"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. Привилегированные хелперы + sudoers
|
|
# ---------------------------------------------------------------------------
|
|
install -m0755 "$BUNDLE_DIR"/scripts/bt-netconfig \
|
|
"$BUNDLE_DIR"/scripts/bt-update \
|
|
"$BUNDLE_DIR"/scripts/bt-service "$ROOT"/scripts/
|
|
sed -i 's/\r$//' "$ROOT"/scripts/bt-* 2>/dev/null || true # на случай CRLF
|
|
|
|
install -m0440 "$BUNDLE_DIR/scripts/buttontask.sudoers" /etc/sudoers.d/buttontask
|
|
sed -i 's/\r$//' /etc/sudoers.d/buttontask 2>/dev/null || true
|
|
visudo -cf /etc/sudoers.d/buttontask || die "sudoers некорректен"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 5. Runtime-каталог (XDG_RUNTIME_DIR). /tmp очищается на ребуте —
|
|
# пересоздаём через tmpfiles, чтобы «и всё работает» после перезагрузки.
|
|
# ---------------------------------------------------------------------------
|
|
cat >/etc/tmpfiles.d/buttontask.conf <<EOF
|
|
d /tmp/runtime-buttontask 0700 $USER_NAME $USER_NAME -
|
|
EOF
|
|
systemd-tmpfiles --create /etc/tmpfiles.d/buttontask.conf || true
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 6. Владелец: всё buttontask, кроме root-хелперов
|
|
# ---------------------------------------------------------------------------
|
|
chown -R "$USER_NAME:$USER_NAME" "$ROOT"
|
|
chown root:root "$ROOT"/scripts/bt-*
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 7. systemd-юниты
|
|
# ---------------------------------------------------------------------------
|
|
# все юниты из бандла (buttontask, buttontask-web и, если есть, buttontask-network)
|
|
install -m0644 "$BUNDLE_DIR"/systemd/*.service /etc/systemd/system/
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 8. Авто-детект тачскрина -> override.conf (eventN зависит от платы)
|
|
# ---------------------------------------------------------------------------
|
|
detect_touch() {
|
|
awk 'BEGIN{RS="";FS="\n"}
|
|
{
|
|
ev=""; abs="";
|
|
for (i=1;i<=NF;i++) {
|
|
if ($i ~ /Handlers=/ && match($i,/event[0-9]+/)) ev=substr($i,RSTART,RLENGTH);
|
|
if ($i ~ /^B: ABS=/) abs=$i;
|
|
}
|
|
if (ev!="" && abs!="" && abs !~ /ABS=0+$/) { print ev; exit }
|
|
}' /proc/bus/input/devices 2>/dev/null
|
|
}
|
|
TOUCH_EV="$(detect_touch || true)"
|
|
EX="$BUNDLE_DIR/systemd/override.conf.example"
|
|
if [ -n "$TOUCH_EV" ] && [ -f "$EX" ]; then
|
|
install -d /etc/systemd/system/buttontask.service.d
|
|
sed "s/event[0-9]\+/$TOUCH_EV/g" "$EX" \
|
|
> /etc/systemd/system/buttontask.service.d/override.conf
|
|
log "тачскрин: /dev/input/$TOUCH_EV -> override.conf"
|
|
else
|
|
warn "тачскрин не определён автоматически — при необходимости задайте override.conf вручную"
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 9. eglfs забирает KMS/DRM напрямую -> выключаем display-manager
|
|
# ---------------------------------------------------------------------------
|
|
systemctl disable display-manager 2>/dev/null || true
|
|
systemctl stop display-manager 2>/dev/null || true
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 10. Включаем сервисы (старт — после ребута)
|
|
# ---------------------------------------------------------------------------
|
|
systemctl daemon-reload
|
|
systemctl enable buttontask buttontask-web >/dev/null 2>&1 || \
|
|
die "не удалось включить сервисы (проверьте имена юнитов)"
|
|
|
|
log "версия $VER развёрнута"
|
|
echo "INSTALL-OK"
|