#!/bin/bash # ============================================================================ # Install the SyncYomi library integrity guard as a user systemd timer. # # TachiyomiSY 1.13.2 can finish a backup restore, report success, and have # written almost nothing (upstream jobobby04/TachiyomiSY#1634, #1638). The app # then syncs that near-empty library up, replacing the good server copy. On # 2026-08-09 the real library survived only as stale pages in the SQLite WAL. # # The guard cannot fix the app. It makes the silent case loud, and keeps # restorable .tachibk snapshots so recovery never again depends on WAL forensics. # ============================================================================ set -euo pipefail SCRIPT_NAME="$(basename "$0")" readonly SCRIPT_NAME REPO_ROOT="$(cd "$(dirname "$0")/../../../.." && pwd)" readonly REPO_ROOT readonly UNIT_DIR="${HOME}/.config/systemd/user" readonly SERVICE_NAME="syncyomi-guard.service" readonly TIMER_NAME="syncyomi-guard.timer" readonly SNAPSHOT_DIR="${HOME}/syncyomi/snapshots" readonly STATE_DIR="${HOME}/.local/share/syncyomi_guard" readonly DB_PATH="${HOME}/syncyomi/config/syncyomi.db" log_info() { echo "[*] $*"; } log_ok() { echo "[+] $*"; } die() { echo "[!] $*" >&2 exit 1 } usage() { echo "Usage: ${SCRIPT_NAME} [--uninstall]" echo " Installs a user timer that verifies the SyncYomi payload every 30 min." exit 0 } require_python() { command -v python3 >/dev/null 2>&1 || die "python3 not found — install it with: sudo pacman -S python" } # The guard reads the database through sudo-less paths, so it must be able to # open it. A root-owned db (the container writes as root) is readable only if # the mode allows it; check now rather than failing silently on the first timer. check_readable() { [[ -f ${DB_PATH} ]] || die "no SyncYomi database at ${DB_PATH}" if ! head -c 1 "${DB_PATH}" >/dev/null 2>&1; then die "cannot read ${DB_PATH} as $(whoami) — run: sudo chmod o+r '${DB_PATH}'" fi } write_units() { mkdir -p "${UNIT_DIR}" "${SNAPSHOT_DIR}" "${STATE_DIR}" cat >"${UNIT_DIR}/${SERVICE_NAME}" <"${UNIT_DIR}/${TIMER_NAME}" </dev/null || true rm -f "${UNIT_DIR}/${SERVICE_NAME}" "${UNIT_DIR}/${TIMER_NAME}" systemctl --user daemon-reload log_ok "Removed timer and service (snapshots in ${SNAPSHOT_DIR} kept)" } main() { case "${1:-}" in --uninstall) uninstall_timer ;; -h | --help) usage ;; "") install_timer ;; *) die "Unknown option: $1" ;; esac } main "$@"