#!/usr/bin/env bash # # bt-service - restart/start/stop the ButtonTask systemd units. # Invoked through sudo by the web configurator (tightly scoped). # # collector-on / collector-off run in the caller (the web process waits). # start/stop/restart detach via systemd-run because they restart buttontask-web. set -euo pipefail ACTION="${1:-}" ROOT="${BUTTONTASK_ROOT:-/opt/buttontask}" collector_enabled() { BUTTONTASK_ROOT="$ROOT" python3 - <<'PY' import json, os, sys root = os.environ.get("BUTTONTASK_ROOT", "/opt/buttontask") path = os.environ.get("BUTTONTASK_CONFIG", os.path.join(root, "config", "config.json")) try: with open(path, encoding="utf-8") as f: cfg = json.load(f) enabled = cfg.get("settings", {}).get("collectorEnabled", True) except FileNotFoundError: enabled = True except Exception: enabled = True sys.exit(0 if enabled else 1) PY } apply_units() { local action="$1" if collector_enabled; then systemctl "$action" buttontask-web buttontask buttontask-collector else systemctl "$action" buttontask-web buttontask fi } run_action() { case "$ACTION" in start|stop|restart) apply_units "$ACTION" ;; collector-on) systemctl unmask buttontask-collector systemctl enable --now buttontask-collector ;; collector-off) systemctl disable --now buttontask-collector ;; units) systemctl list-units --type=service --all --no-legend --plain --no-pager \ || systemctl list-units --type=service --all --no-legend --no-pager echo '@@FILES' systemctl list-unit-files --type=service --no-legend --no-pager echo '@@SINCE' systemctl show --no-pager -p Id -p ActiveEnterTimestamp '*.service' ;; journal) emit_journal ;; *) echo "usage: bt-service {start|stop|restart|collector-on|collector-off|units|journal}" >&2 exit 2 ;; esac } # Kernel log and per-boot tails. Markers are parsed by the web configurator. # Indexes passed to journalctl -b are only integers from --list-boots. emit_journal() { local list idx count=0 echo '@@BOOTS' journalctl --list-boots --no-pager 2>/dev/null || true echo '@@KERNEL' if ! journalctl -k -b 0 -n 400 --no-pager -o short-iso 2>/dev/null; then if ! journalctl -k -b 0 -n 400 --no-pager -o short 2>/dev/null; then dmesg -T 2>/dev/null | tail -n 400 || dmesg 2>/dev/null | tail -n 400 || true fi fi echo '@@TAILS' list=$(journalctl --list-boots --no-pager 2>/dev/null || true) while read -r idx _; do case "$idx" in ''|IDX) continue ;; *[!0-9-]*) continue ;; esac count=$((count + 1)) if [ "$count" -gt 12 ]; then break fi echo "@@TAIL $idx" journalctl -b "$idx" -n 80 --no-pager -o short-iso 2>/dev/null \ || journalctl -b "$idx" -n 80 --no-pager -o short 2>/dev/null \ || true done <<< "$list" echo '@@END' } if [ -z "${BT_SERVICE_DETACHED:-}" ]; then case "$ACTION" in start|stop|restart) unit="buttontask-service-$(date +%s)" exec systemd-run --no-block --collect \ "--unit=${unit}" \ "--setenv=BT_SERVICE_DETACHED=1" \ "--setenv=BUTTONTASK_ROOT=${ROOT}" \ "$0" "$@" ;; esac fi run_action