Additional userdb carefulness

see #1

Bug 1 fixed — revert_userdb blindly reloaded userdbd (30-userdb.sh): During --revert, analyze_userdb is never called so DM_NAME is always "unknown". The unconditional userdbd reload would break the lock screen again for users reverting while SDDM was active. Now it detects the active DM directly and skips the reload with a warning if one is found.

Bug 2 fixed — revert_no_conf printed rm -rf /etc/userdb (99-main.sh): The legacy manual-revert instructions nuked all of /etc/userdb, including any pre-existing records that ageless had backed up. Now it prints per-file commands: mv *.pre-ageless where a backup exists, rm only where there's no backup.
This commit is contained in:
John McCardle committed 2026-04-27 15:16:23 -04:00
1 parent fd430934ad
commit 1e1b00f45d
4 files changed
+160 -12

No files matched your search

+32 -4
View File
@@ -629,11 +629,25 @@ revert_userdb() {
fi
fi
# Restart userdbd to clear any cached records (safe during revert)
# Restart userdbd to clear cached records — but NOT if a display manager
# is active: reloading userdbd mid-session breaks the lock screen (same
# bug that affected the install path).
if command -v systemctl &>/dev/null; then
if systemctl list-unit-files systemd-userdbd.service &>/dev/null 2>&1; then
systemctl try-reload-or-restart systemd-userdbd.service 2>/dev/null || true
echo -e " [${GREEN}✓${NC}] Reloaded systemd-userdbd"
local active_dm=""
for dm in sddm gdm gdm3 lightdm lxdm nodm; do
if systemctl is-active "${dm}.service" &>/dev/null; then
active_dm="$dm"
break
fi
done
if [[ -n "$active_dm" ]]; then
echo -e " [${YELLOW}!${NC}] Skipped userdbd reload — ${active_dm} is active."
echo -e " ${YELLOW} Do NOT lock your screen. Log out and back in (or reboot).${NC}"
else
systemctl try-reload-or-restart systemd-userdbd.service 2>/dev/null || true
echo -e " [${GREEN}✓${NC}] Reloaded systemd-userdbd"
fi
fi
fi
}
@@ -1279,7 +1293,21 @@ revert_no_conf() {
fi
echo " sudo rm -rf /etc/ageless"
if [[ -d /etc/userdb ]]; then
echo " sudo rm -rf /etc/userdb"
# Restore per-user backups where they exist; only remove files without one.
# rm -rf /etc/userdb would destroy any pre-existing userdb records.
local has_userdb_files=0
for f in /etc/userdb/*.user; do
[[ -f "$f" ]] || continue
has_userdb_files=1
if [[ -f "${f}.pre-ageless" ]]; then
echo " sudo mv ${f}.pre-ageless ${f}"
else
echo " sudo rm -f ${f}"
fi
done
if [[ $has_userdb_files -eq 0 ]]; then
echo " sudo rmdir /etc/userdb 2>/dev/null || true"
fi
fi
if command -v systemctl &>/dev/null; then
if systemctl list-unit-files agelessd.timer &>/dev/null 2>&1; then
+17 -3
View File
@@ -262,11 +262,25 @@ revert_userdb() {
fi
fi
# Restart userdbd to clear any cached records (safe during revert)
# Restart userdbd to clear cached records — but NOT if a display manager
# is active: reloading userdbd mid-session breaks the lock screen (same
# bug that affected the install path).
if command -v systemctl &>/dev/null; then
if systemctl list-unit-files systemd-userdbd.service &>/dev/null 2>&1; then
systemctl try-reload-or-restart systemd-userdbd.service 2>/dev/null || true
echo -e " [${GREEN}✓${NC}] Reloaded systemd-userdbd"
local active_dm=""
for dm in sddm gdm gdm3 lightdm lxdm nodm; do
if systemctl is-active "${dm}.service" &>/dev/null; then
active_dm="$dm"
break
fi
done
if [[ -n "$active_dm" ]]; then
echo -e " [${YELLOW}!${NC}] Skipped userdbd reload — ${active_dm} is active."
echo -e " ${YELLOW} Do NOT lock your screen. Log out and back in (or reboot).${NC}"
else
systemctl try-reload-or-restart systemd-userdbd.service 2>/dev/null || true
echo -e " [${GREEN}✓${NC}] Reloaded systemd-userdbd"
fi
fi
fi
}
+15 -1
View File
@@ -414,7 +414,21 @@ revert_no_conf() {
fi
echo " sudo rm -rf /etc/ageless"
if [[ -d /etc/userdb ]]; then
echo " sudo rm -rf /etc/userdb"
# Restore per-user backups where they exist; only remove files without one.
# rm -rf /etc/userdb would destroy any pre-existing userdb records.
local has_userdb_files=0
for f in /etc/userdb/*.user; do
[[ -f "$f" ]] || continue
has_userdb_files=1
if [[ -f "${f}.pre-ageless" ]]; then
echo " sudo mv ${f}.pre-ageless ${f}"
else
echo " sudo rm -f ${f}"
fi
done
if [[ $has_userdb_files -eq 0 ]]; then
echo " sudo rmdir /etc/userdb 2>/dev/null || true"
fi
fi
if command -v systemctl &>/dev/null; then
if systemctl list-unit-files agelessd.timer &>/dev/null 2>&1; then
+96 -4
View File
@@ -84,8 +84,8 @@ echo " Human users: ${HUMAN_USERS:-none}"
section "--version"
version_out=$(bash "$SCRIPT" --version 2>&1)
if [[ "$version_out" == *"0.1.0"* ]]; then
pass "--version prints 0.1.0"
if [[ "$version_out" == *"0.1.1"* ]]; then
pass "--version prints 0.1.1"
else
fail "--version" "got: $version_out"
fi
@@ -273,8 +273,8 @@ if [[ -f /etc/agelesslinux.conf ]]; then
# Verify key fields
# shellcheck disable=SC1091
source /etc/agelesslinux.conf
if [[ "${AGELESS_VERSION:-}" == "0.1.0" ]]; then
pass "conf records version 0.1.0"
if [[ "${AGELESS_VERSION:-}" == "0.1.1" ]]; then
pass "conf records version 0.1.1"
else
fail "conf version" "got: ${AGELESS_VERSION:-unset}"
fi
@@ -392,6 +392,98 @@ else
skip "--persistent error test" "systemctl is available"
fi
# ── Test: revert skips userdbd reload when DM is active ──────────────────────
#
# Regression test for issue #1: reloading systemd-userdbd mid-session breaks
# the SDDM (and LightDM) lock screen. The fix in revert_userdb must detect
# an active display manager and skip the reload, warning the user instead.
section "revert: DM lock-screen safety (issue #1 fix)"
bash "$SCRIPT" --accept >/dev/null 2>&1
mkdir -p /tmp/mock-bin
RELOAD_FLAG=/tmp/mock-bin/userdbd-reload-called
rm -f "$RELOAD_FLAG"
cat > /tmp/mock-bin/systemctl << 'MOCK_EOF'
#!/bin/bash
# Mock: sddm is active, userdbd is installed. Reloading userdbd must not happen.
case "${1:-} ${2:-}" in
"is-active sddm.service") exit 0 ;;
"is-active "*.service) exit 1 ;;
"list-unit-files systemd-userdbd.service") exit 0 ;;
"try-reload-or-restart systemd-userdbd.service")
touch /tmp/mock-bin/userdbd-reload-called ; exit 0 ;;
*) exit 0 ;;
esac
MOCK_EOF
chmod +x /tmp/mock-bin/systemctl
dm_revert_out=$(PATH="/tmp/mock-bin:$PATH" bash "$SCRIPT" --revert 2>&1)
if echo "$dm_revert_out" | grep -q "Skipped userdbd reload"; then
pass "revert: skips userdbd reload when SDDM is active"
else
fail "revert DM reload check" "expected 'Skipped userdbd reload'; got: $(echo "$dm_revert_out" | grep -i 'userdbd\|reload\|sddm' | head -3)"
fi
if echo "$dm_revert_out" | grep -qi "log out\|lock"; then
pass "revert: warns about lock screen when DM active"
else
fail "revert DM warning" "no lock-screen warning in output"
fi
if [[ ! -f "$RELOAD_FLAG" ]]; then
pass "revert: userdbd was NOT reloaded (lock screen protected)"
else
fail "revert DM safety" "userdbd try-reload-or-restart was called despite active SDDM"
fi
rm -rf /tmp/mock-bin
# ── Test: revert_no_conf prints per-file userdb instructions ─────────────────
#
# Regression test for issue #1 (legacy path): the old revert_no_conf printed
# "rm -rf /etc/userdb" which destroyed any pre-existing userdb records that
# ageless had backed up before modifying. The fix prints per-file instructions:
# - "mv backup → original" when a .pre-ageless backup exists
# - "rm -f file" when no backup exists (ageless created it fresh)
section "revert_no_conf: per-file userdb instructions (not rm -rf)"
cp /etc/os-release /etc/os-release.pre-ageless
mkdir -p /etc/userdb
printf '{"userName":"testuser","uid":1000,"birthDate":"1970-01-01"}\n' \
> /etc/userdb/testuser.user
printf '{"userName":"testuser","uid":1000,"birthDate":null}\n' \
> /etc/userdb/testuser.user.pre-ageless
printf '{"userName":"orphan","uid":1001,"birthDate":"1970-01-01"}\n' \
> /etc/userdb/orphan.user
no_conf_out=$(bash "$SCRIPT" --revert 2>&1 || true)
if echo "$no_conf_out" | grep -q "mv.*testuser\.user\.pre-ageless.*testuser\.user"; then
pass "revert_no_conf: prints 'mv backup → original' for backed-up user"
else
fail "revert_no_conf mv" "no mv instruction for testuser.user.pre-ageless"
fi
if echo "$no_conf_out" | grep -q "rm -f.*orphan\.user"; then
pass "revert_no_conf: prints 'rm -f' for un-backed-up user"
else
fail "revert_no_conf rm" "no rm -f instruction for orphan.user"
fi
if echo "$no_conf_out" | grep -q "rm -rf /etc/userdb"; then
fail "revert_no_conf safety" "still prints 'rm -rf /etc/userdb' (too broad)"
else
pass "revert_no_conf: does NOT print 'rm -rf /etc/userdb'"
fi
rm -f /etc/os-release.pre-ageless
rm -rf /etc/userdb
# ── Results ──────────────────────────────────────────────────────────────────
section "RESULTS"