iso: enable bakery user units globally for later accounts

Bins live in /usr/local, so a later useradd no longer gets
~/.local/bin copies. systemctl --global enable the bakery
--user units (bake writes /etc/systemd/user/*.wants/, and
post-install + live-setup run the same enable) so first
login starts breadd, breadbox-sync, breadclipd, breadcrumbs,
and breadmill. Stock useradd -m copies skel (Hyprland +
bakery state). Rollback is still grub-btrfs.
This commit is contained in:
Breadway 2026-08-16 00:27:14 +08:00
parent 34043086b9
commit 70d4dd424b
12 changed files with 336 additions and 21 deletions

View file

@ -0,0 +1,12 @@
# Bakery systemd --user units. `systemctl --global enable` (post-install and
# live setup) applies these so a later `useradd -m` starts them on first login.
# Bake rewrites this list from the units actually copied into the image.
#
# breadclipd is WantedBy=graphical-session.target. BOS does not activate that
# target (no uwsm); Hyprland still `systemctl --user start`s it after the
# compositor is up. --global enable still records it for every account.
enable breadd.service
enable breadbox-sync.service
enable breadclipd.service
enable breadcrumbs.service
enable breadmill.service

View file

@ -0,0 +1,90 @@
#!/bin/bash
# Enable bakery systemd --user units for every account (current and future).
#
# `systemctl --global enable` writes /etc/systemd/user/<target>.wants/ so a
# later `useradd -m` does not need per-home enablement. Bins live in
# /usr/local; only per-user state comes from skel.
#
# Safe on the live image and in the Calamares post-install chroot.
# Idempotent. Does not start units (no user session required).
#
# breadclipd is WantedBy=graphical-session.target. BOS does not activate
# that target (no uwsm), so Hyprland still `systemctl --user start`s it.
# --global enable still records it for every account / bos-settings.
set -uo pipefail
UNITS_DIR=/usr/lib/systemd/user
PRESET=/usr/lib/systemd/user-preset/90-bos-bakery.preset
is_blocked() {
case "$1" in
breadcast*|breadarr*) return 0 ;;
*) return 1 ;;
esac
}
is_bakery_unit() {
local unit="$1" path="$UNITS_DIR/$unit"
[[ -f "$path" ]] || return 1
is_blocked "$unit" && return 1
grep -qE '^ExecStart=/usr/local/bin/' "$path"
}
list_from_preset() {
[[ -f "$PRESET" ]] || return 0
awk '/^enable[[:space:]]/ { print $2 }' "$PRESET"
}
list_from_units_dir() {
[[ -d "$UNITS_DIR" ]] || return 0
local path unit
for path in "$UNITS_DIR"/*.service; do
[[ -f "$path" ]] || continue
unit="$(basename "$path")"
is_bakery_unit "$unit" && printf '%s\n' "$unit"
done
}
list_from_installed_json() {
local json=/etc/skel/.local/state/bakery/installed.json
[[ -f "$json" ]] || return 0
command -v python3 >/dev/null 2>&1 || return 0
python3 - "$json" <<'PY'
import json, sys
with open(sys.argv[1]) as f:
data = json.load(f)
for pkg in data.get("packages", data).values():
if not isinstance(pkg, dict):
continue
for svc in pkg.get("services") or []:
name = svc["unit"] if isinstance(svc, dict) else svc
if name and not str(name).startswith(("breadcast", "breadarr")):
print(name)
PY
}
mapfile -t units < <(
{ list_from_preset; list_from_units_dir; list_from_installed_json; } \
| sed '/^$/d' | sort -u
)
if [[ ${#units[@]} -eq 0 ]]; then
echo "WARN: no bakery user units found to enable globally"
exit 0
fi
if ! command -v systemctl >/dev/null 2>&1; then
echo "WARN: systemctl missing — cannot --global enable bakery user units"
exit 0
fi
for unit in "${units[@]}"; do
[[ -f "$UNITS_DIR/$unit" ]] || continue
is_blocked "$unit" && continue
if ! grep -q '^\[Install\]' "$UNITS_DIR/$unit"; then
echo "WARN: $unit has no [Install] section — skip --global enable"
continue
fi
systemctl --global enable "$unit" \
|| echo "WARN: systemctl --global enable $unit failed"
done

View file

@ -7,9 +7,17 @@
# bos-launch-calamares). Runs once at boot, before the tty1 autologin getty.
set -e
# Bakery user units live in /usr/lib/systemd/user. --global enable writes
# /etc/systemd/user/*.wants/ so liveuser (and any later account) starts
# them on first login. Idempotent; bins are already in /usr/local.
if [[ -x /usr/local/bin/bos-enable-bakery-user-units ]]; then
/usr/local/bin/bos-enable-bakery-user-units \
|| echo "WARN: enabling bakery user units globally failed"
fi
# useradd -m copies /etc/skel, so the live user gets the real BOS desktop
# (breadd + breadbar + breadbox + keybinds) — proper live-media functionality,
# not an installer kiosk.
# (hypr + bread config + bakery state) — proper live-media functionality,
# not an installer kiosk. Binaries are /usr/local, not skel.
if ! id liveuser &>/dev/null; then
useradd -m -s /usr/bin/zsh liveuser
for g in wheel video input audio storage power; do