wren-linux / parts / startup-watch.sh
#!/bin/bash
# The startup watch: a program running as you that wants to start again at
# every login has to change one of a few files (your shell's startup files,
# sway's config, autostart, systemd user units, ~/.local/bin, tmux's and vim's,
# curl's and wget's settings, ...). This keeps
# their fingerprints where it can't change them (root's, /var/lib/wren-watch),
# compares them at boot and every 15 minutes (a root timer), and shows what
# changed: "startup changed" in the bar, with a notification, and wren-watch.
# - wren-watch lists what changed; sudo wren-watch diff shows the changes;
# sudo wren-watch accept takes them as yours (it asks your password: a
# program running as you can't accept its own change without it).
# - wrenctl install, part, remove and update accept what their run changed,
# so Wren Linux's own changes don't show (a file that had changed before
# the run is left for you to look at).
# - It notices, it doesn't prevent; and it can't see what runs from memory,
# or a file outside the ones it watches (bin/wren-watch lists them).
# Part of the base: the last part, so its first record holds what the others wrote; the extras
# picked at install go in after it, through wrenctl, which takes what each one's run changed.
# Usage: bash startup-watch.sh [--remove | --manual]
# files: bin/wren-watch
# status: file:/usr/local/bin/wren-watch
. "$(dirname -- "${BASH_SOURCE[0]}")/../lib.sh"
if [ "${1:-}" = --manual ]; then print_manual; exit; fi
need_user
CMD=/usr/local/bin/wren-watch
SERVICE=/etc/systemd/system/wren-watch.service
TIMER=/etc/systemd/system/wren-watch.timer
if [ "${1:-}" = --remove ]; then
sudo systemctl disable --now wren-watch.timer >/dev/null 2>&1 || true
sudo rm -f "$SERVICE" "$TIMER"
sudo systemctl daemon-reload
sudo rm -rf "/var/lib/wren-watch/$(id -un)" "/run/wren-watch/$(id -un)"
sudo rmdir /var/lib/wren-watch 2>/dev/null || true
# the command stays while another user is still watched
[ -d /var/lib/wren-watch ] || sudo rm -f "$CMD"
note "Your startup files are no longer watched."
exit
fi
say "The startup watch"
apt_install python3 diffutils
# Run again (update.sh does, when wren-watch changes): what is listed now is looked at again
# with the command as it was, and stays listed. Only the first run takes everything as it is.
me=$(id -un)
have_record=false pending=''
if sudo test -f "/var/lib/wren-watch/$me/manifest"; then have_record=true; fi
if $have_record && [ -x "$CMD" ]; then
sudo "$CMD" check-all >/dev/null 2>&1 || true
pending=$(cat "/run/wren-watch/$me" 2>/dev/null || true)
fi
sudo install -o root -g root -m 0755 "$WREN_DIR/bin/wren-watch" "$CMD"
# Root's, as it reads every watched home; it may write only its record and
# its list of changes, and has no network
printf '%s\n' '# Written by Wren Linux parts/startup-watch.sh' '[Unit]' \
'Description=Wren Linux: compare the startup files with their record' '' \
'[Service]' 'Type=oneshot' "ExecStart=$CMD check-all" \
'ProtectSystem=strict' 'ReadWritePaths=/var/lib/wren-watch /run/wren-watch' 'ProtectHome=read-only' \
'PrivateTmp=yes' 'PrivateNetwork=yes' 'NoNewPrivileges=yes' 'RuntimeDirectory=wren-watch' \
'RuntimeDirectoryPreserve=yes' 'StateDirectory=wren-watch' |
sudo tee "$SERVICE" >/dev/null
printf '%s\n' '# Written by Wren Linux parts/startup-watch.sh: at boot, then every 15 minutes' '[Unit]' \
'Description=Wren Linux: compare the startup files every 15 minutes' '' \
'[Timer]' 'OnBootSec=1min' 'OnUnitActiveSec=15min' '' '[Install]' 'WantedBy=timers.target' |
sudo tee "$TIMER" >/dev/null
sudo systemctl daemon-reload
sudo systemctl enable --now wren-watch.timer >/dev/null
if ! $have_record; then
say "Their record, as they are now"
note "From now on a change to them shows in the bar until you accept it."
sudo "$CMD" accept >/dev/null
else
# A newer wren-watch may watch more files: those it lists now and didn't before are taken
# as they are. What was listed before this run is never taken here: it is for you to look at.
sudo "$CMD" check-all >/dev/null
take=()
while IFS= read -r f; do
[ -n "$f" ] || continue
grep -qxF -- "$f" <<<"$pending" || take+=("$f")
done < <(cat "/run/wren-watch/$me" 2>/dev/null || true)
if [ ${#take[@]} -gt 0 ]; then sudo "$CMD" accept "${take[@]}" >/dev/null; fi
if [ -n "$pending" ]; then
warn "Still listed for you to look at (they changed before this run): $(paste -sd' ' <<<"$pending")"
note "See them: wren-watch diff Take them as yours: wren-watch accept"
fi
fi
note "Watched: your shell's startup files, sway's config, autostart, systemd user units,"
note "your ~/.local/bin and a few more (wren-watch --help). See a change: wren-watch"