From c8890c81b8c667b6fc9c9f7a32b37df04418db4b Mon Sep 17 00:00:00 2001 From: DevomB Date: Fri, 2 Oct 2026 01:07:17 -0700 Subject: [PATCH 1/2] First boot asks again for a user name it refused, and says why: the setup ended on one, leaving no account until the next boot --- build/service-scripts/firstboot.sh | 20 +++++++++++++------- tools/tests/firstboot.sh | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/build/service-scripts/firstboot.sh b/build/service-scripts/firstboot.sh index be817058..87875f52 100755 --- a/build/service-scripts/firstboot.sh +++ b/build/service-scripts/firstboot.sh @@ -28,7 +28,7 @@ complete() { u="$(regular_user)"; [ -n "$u" ] && has_password "$u" && has_passwo create_user() { # create_user NAME case "$1" in - ''|*[!a-z0-9_-]*|-*) say "refusing user name '$1'"; return 1 ;; + ''|*[!a-z0-9_-]*|-*) say "refusing user name '$1': lower-case letters, digits, _ and - only"; return 1 ;; esac getent group seat >/dev/null 2>&1 || groupadd -r seat getent group kryptik >/dev/null 2>&1 || groupadd -r kryptik @@ -80,18 +80,24 @@ set_password() { # set_password USER: two matching answers, through chpasswd done return 1 } +new_user() { # new_user: sets name to the user made; a refused name is asked for again + local made + for _ in 1 2 3; do + name=$(ask "$PROMPT_SECS" "User name: ") || return 1 + name="$(printf '%s' "$name" | tr -d '[:space:]')" + made=$(create_user "$name" 2>&1) && { tell "$made"; return 0; } + tell "$made" + done + return 1 +} name="$(regular_user)" if [ -z "$name" ]; then tell "" "===== Kryptik first-boot setup =====" \ "No user account exists yet. Create the desktop user now." - if ! name=$(ask "$PROMPT_SECS" "User name: "); then - say "no answer within 10 minutes; the next boot asks again" + if ! new_user; then + say "no user created; the next boot asks again" exit 0 fi - name="$(printf '%s' "$name" | tr -d '[:space:]')" - made=$(create_user "$name" 2>&1) && ok=1 || ok= - tell "$made" - [ -n "$ok" ] || exit 0 fi if ! has_password "$name"; then tell "Set a password for $name:" diff --git a/tools/tests/firstboot.sh b/tools/tests/firstboot.sh index f8674a0c..f4281c5a 100755 --- a/tools/tests/firstboot.sh +++ b/tools/tests/firstboot.sh @@ -70,6 +70,26 @@ answer '\n\n\n\n\n\n' [[ "$RC|$GOT" == "1|" ]] && ok "three empty answers set nothing" || bad "empty answers: rc=$RC chpasswd got '$GOT'" start=$SECONDS; answer '' [[ "$RC|$GOT" == "1|" && $((SECONDS - start)) -le 3 ]] && ok "no answer: the question gives up at its time limit" || bad "no answer: rc=$RC after $((SECONDS - start)) s" + +# new_user, with useradd recording the name it was given. +sed -n '/^create_user() /,/^}/p; /^new_user() /,/^}/p' "$SRC" > "$T/newuser.sh" +# shellcheck source=/dev/null +. "$T/newuser.sh" +declare -F create_user >/dev/null || { echo "no create_user in $SRC"; exit 1; } +declare -F new_user >/dev/null || { echo "no new_user in $SRC"; exit 1; } +say() { echo "kryptik-firstboot: $*"; } +getent() { return 0; } +useradd() { printf '%s' "${@: -1}" > "$T/useradd.in"; } +names() { rm -f "$T/useradd.in"; : > "$T/screen"; name=""; printf '%b' "$1" >&7; new_user; RC=$?; GOT="$(cat "$T/useradd.in" 2>/dev/null)"; } +names 'ana\n' +[[ "$RC|$GOT|$name" == "0|ana|ana" ]] && ok "a name of lower-case letters makes the user" || bad "a plain name: rc=$RC useradd got '$GOT', name '$name'" +names 'Ana\nana\n' +[[ "$RC|$GOT" == "0|ana" ]] && grep -qF "refusing user name 'Ana': lower-case" "$T/screen" \ + && ok "a refused name is told why and asked for again" || bad "a refused name: rc=$RC useradd got '$GOT', screen: $(tr '\n' '|' < "$T/screen")" +names 'A\n-b\n\n' +[[ "$RC|$GOT" == "1|" ]] && ok "three refused names make no user" || bad "three refused names: rc=$RC useradd got '$GOT'" +start=$SECONDS; names '' +[[ "$RC|$GOT" == "1|" && $((SECONDS - start)) -le 3 ]] && ok "no name: the question gives up at its time limit" || bad "no name: rc=$RC after $((SECONDS - start)) s" exec 7<&- printf '\n%d passed, %d failed\n' "$PASS" "$FAIL" From 411b2361c959b86c41c46c5e31365ae72e050d9e Mon Sep 17 00:00:00 2001 From: DevomB Date: Fri, 2 Oct 2026 01:07:18 -0700 Subject: [PATCH 2/2] A second apply is told to reboot: rollback arms the slot the trial already holds, so it never cleared the way --- tools/update/kryptik-update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/update/kryptik-update b/tools/update/kryptik-update index 7204456d..da4e7cb5 100755 --- a/tools/update/kryptik-update +++ b/tools/update/kryptik-update @@ -308,7 +308,7 @@ cmd_apply() { slot="$(running_slot)"; target="$(other_slot "$slot")" [ -n "$target" ] || die "cannot tell which slot is running (kryptik.slot= missing)" if [ -f "$B/trial" ]; then - die "a trial of slot $(sed -n 1p "$B/trial") is already armed; reboot first, or run rollback" + die "a trial of slot $(sed -n 1p "$B/trial") is already armed; reboot first" fi if [ "$retry" != 1 ] && [ -f "$B/trial.failed" ]; then die "the last trial of slot $(cat "$B/trial.failed") failed to boot. To try it again, run as root: kryptik-update apply $dir --retry"