| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- #!/bin/bash
- # System-level state that dotsync cannot manage.
- #
- # dotsync deals in unprivileged $HOME symlinks; this covers the things that live
- # outside $HOME and need root: enabled units and /etc drop-ins. Kept as a plain
- # script rather than using the @host/@group markers, because those only apply to
- # files deployed into $HOME.
- #
- # Idempotent -- safe to re-run. Run after 'dotsync packages'.
- #
- # ./bootstrap
- set -euo pipefail
- hostname_id=$(uname -n)
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- NC='\033[0m'
- log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
- log_warn() { echo -e "${YELLOW}[WARN]${NC} $*" >&2; }
- log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
- if [[ $EUID -eq 0 ]]; then
- log_error "Run as your normal user, not root -- user units need your session."
- exit 1
- fi
- # Acquire sudo up front. Without this the first privileged command fails on a
- # non-interactive shell and, because install_file runs as an `if` condition
- # (where bash disables set -e), the failure would be swallowed and the script
- # would report writes that never happened.
- if ! sudo -v; then
- log_error "Could not obtain sudo credentials."
- log_error "Run this from a real terminal -- sudo needs a tty to prompt."
- exit 1
- fi
- # Write a file only if its content differs, so re-runs stay quiet and we avoid
- # needlessly restarting units. Aborts on failure rather than reporting a
- # phantom success -- see the set -e note above.
- install_file() {
- local dest="$1" content="$2"
- if [[ -f "$dest" ]] && [[ "$(cat "$dest")" == "$content" ]]; then
- return 1
- fi
- if ! sudo mkdir -p "$(dirname "$dest")"; then
- log_error "Failed to create $(dirname "$dest")"
- exit 1
- fi
- if ! printf '%s\n' "$content" | sudo tee "$dest" >/dev/null; then
- log_error "Failed to write $dest"
- exit 1
- fi
- log_info "Wrote $dest"
- return 0
- }
- # Units are skipped when their package isn't installed on this host -- the
- # package lists are per-host (tlp is jellyfish-only, for instance), so this
- # file is shared while the set of units that actually exist is not.
- enable_unit() {
- local unit="$1"
- if ! systemctl cat "$unit" &>/dev/null; then
- log_warn "Skipping $unit -- not installed on this host"
- return 0
- fi
- if systemctl is-enabled --quiet "$unit" 2>/dev/null; then
- return 0
- fi
- log_info "Enabling $unit"
- if ! sudo systemctl enable "$unit"; then
- log_error "Failed to enable $unit"
- exit 1
- fi
- }
- enable_user_unit() {
- local unit="$1"
- if ! systemctl --user cat "$unit" &>/dev/null; then
- log_warn "Skipping user unit $unit -- not installed on this host"
- return 0
- fi
- if systemctl --user is-enabled --quiet "$unit" 2>/dev/null; then
- return 0
- fi
- log_info "Enabling (user) $unit"
- if ! systemctl --user enable "$unit"; then
- log_error "Failed to enable user unit $unit"
- exit 1
- fi
- }
- log_info "Bootstrapping system state for $hostname_id"
- reload_needed=0
- # ---------------------------------------------------------------------------
- # logind: do not kill user processes at session end.
- #
- # The default (KillUserProcesses=yes) tears down lingering processes when the
- # last session for a user closes. That kills etterminal, which aborts the whole
- # etserver -- it broke Eternal Terminal on tompot. Declared explicitly on every
- # host so the two machines cannot drift on it again.
- #
- # A drop-in rather than an edit to /etc/systemd/logind.conf: package upgrades
- # replace that file, drop-ins survive.
- # ---------------------------------------------------------------------------
- if install_file /etc/systemd/logind.conf.d/10-kill-user-processes.conf \
- "[Login]
- KillUserProcesses=no"; then
- reload_needed=1
- fi
- # ---------------------------------------------------------------------------
- # greetd: autologin straight into sway.
- #
- # The stock package config drops you at an agreety prompt running /bin/sh, so
- # without this greetd starts but never gets you into a session. Declared here
- # because it lives in /etc, outside what dotsync can manage -- it was previously
- # hand-edited on jellyfish only, which is exactly the drift this file exists to
- # stop.
- # ---------------------------------------------------------------------------
- if install_file /etc/greetd/config.toml \
- "[terminal]
- vt = 1
- [default_session]
- command = \"agreety --cmd sway\"
- user = \"greeter\"
- [initial_session]
- command = \"sway\"
- user = \"$USER\""; then
- log_warn "greetd config changed -- takes effect at next logout/reboot"
- fi
- # ---------------------------------------------------------------------------
- # iwd: shorten the stop timeout so shutdown isn't held up for 90s.
- # ---------------------------------------------------------------------------
- if install_file /etc/systemd/system/iwd.service.d/timeout.conf \
- "[Service]
- TimeoutStopSec=5"; then
- reload_needed=1
- fi
- if [[ $reload_needed -eq 1 ]]; then
- log_info "Reloading systemd"
- sudo systemctl daemon-reload
- fi
- # ---------------------------------------------------------------------------
- # System units
- # ---------------------------------------------------------------------------
- for unit in bluetooth.service greetd.service iwd.service \
- systemd-timesyncd.service tlp.service; do
- enable_unit "$unit"
- done
- # ---------------------------------------------------------------------------
- # User units
- # ---------------------------------------------------------------------------
- for unit in wluma.service; do
- enable_user_unit "$unit"
- done
- log_info "Bootstrap complete"
- log_warn "logind changes only take full effect after a reboot or full logout."
|