diff --git a/scripts/setup/machine-setup/lib/system.sh b/scripts/setup/machine-setup/lib/system.sh index 0bd40550..5c819f12 100644 --- a/scripts/setup/machine-setup/lib/system.sh +++ b/scripts/setup/machine-setup/lib/system.sh @@ -88,3 +88,49 @@ locale_set() { ;; esac } + +# ----------------------------------------------------------------------------- +# Timezone +# ----------------------------------------------------------------------------- + +# The shortlist offered at the prompt. Any zone name can be typed instead, so +# this is a convenience rather than a limit. +TZ_OPTIONS=(UTC Europe/Lisbon Europe/London Europe/Berlin Europe/Stockholm US/Eastern US/Pacific Asia/Tokyo) + +# What the machine is set to now. +# +# Three sources because they disagree about availability rather than about the +# answer: timedatectl is absent without systemd (containers, WSL), /etc/timezone +# is Debian-specific, and the /etc/localtime symlink is the one thing that is +# always true when any of them are. +timezone_current() { + if command -v timedatectl &>/dev/null && timedatectl show -p Timezone --value 2>/dev/null | grep -q .; then + timedatectl show -p Timezone --value 2>/dev/null + elif [[ -r /etc/timezone ]]; then + tr -d '[:space:]' /dev/null ;; + *) + # timedatectl where there is a systemd to talk to; the files directly + # otherwise, which is the same thing it would have written. + if command -v timedatectl &>/dev/null && [[ "$IS_WSL" != true ]]; then + timedatectl set-timezone "$tz" + else + ln -sf "/usr/share/zoneinfo/${tz}" /etc/localtime + echo "$tz" >/etc/timezone + fi + ;; + esac +} diff --git a/scripts/setup/machine-setup/machine-setup.sh b/scripts/setup/machine-setup/machine-setup.sh index 1aa8b3c9..69709e86 100755 --- a/scripts/setup/machine-setup/machine-setup.sh +++ b/scripts/setup/machine-setup/machine-setup.sh @@ -187,13 +187,79 @@ if ! skip; then step_ok fi +# ============================================================================= +# 6. Timezone +# ============================================================================= +# +# TIMEZONE in the environment answers the prompt ahead of time. + +step "Timezone" +if ! skip; then + CURRENT_TZ="$(timezone_current)" + + echo "" + info "Timezone — what logs, timers and every printed date are relative to" + echo " current: ${CURRENT_TZ:-unknown}" + + if [[ -z "${TIMEZONE:-}" ]]; then + echo "" + for i in "${!TZ_OPTIONS[@]}"; do + printf ' [%d] %s\n' "$((i + 1))" "${TZ_OPTIONS[$i]}" + done + echo "" + + while [[ -z "${TIMEZONE:-}" ]]; do + if ! read -rp " Pick a number, or type a zone name — Enter keeps ${CURRENT_TZ:-the current one}: " TZ_CHOICE; then + echo "" + fail "No answer. Set TIMEZONE= to answer this ahead of time." + fi + + if [[ -z "$TZ_CHOICE" ]]; then + TIMEZONE="$CURRENT_TZ" + elif [[ "$TZ_CHOICE" =~ ^[0-9]+$ ]]; then + if ((TZ_CHOICE >= 1 && TZ_CHOICE <= ${#TZ_OPTIONS[@]})); then + TIMEZONE="${TZ_OPTIONS[$((TZ_CHOICE - 1))]}" + else + warn "There is no option ${TZ_CHOICE}." + fi + else + # Validated here rather than left to timedatectl, which fails on an + # unknown name and would take the whole run down over a typo. + if timezone_is_valid "$TZ_CHOICE"; then + TIMEZONE="$TZ_CHOICE" + else + warn "Not a zone this machine knows: '${TZ_CHOICE}' — try e.g. Europe/Berlin" + fi + fi + done + elif ! timezone_is_valid "$TIMEZONE"; then + fail "TIMEZONE='${TIMEZONE}' is not a zone this machine knows." + fi + + if [[ "$TIMEZONE" == "$CURRENT_TZ" ]]; then + echo " keeping ${CURRENT_TZ}, nothing to do" + SUMMARY+=("Timezone: already ${CURRENT_TZ}") + else + echo " to set: ${TIMEZONE}" + if confirm "Proceed?"; then + timezone_set "$TIMEZONE" + ok "Timezone set to ${TIMEZONE}" + SUMMARY+=("Timezone: ${TIMEZONE}") + else + warn "skipped by request" + SUMMARY+=("Timezone: SKIPPED by request — left at ${CURRENT_TZ:-unknown}") + fi + fi + step_ok +fi + # ============================================================================= # NOT PORTED YET # ============================================================================= # # Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order: # -# timezone · swap · auto-suspend · boot-hang fix · user creation · +# swap · auto-suspend · boot-hang fix · user creation · # ssh keys · ssh hardening · dns · static ip · fail2ban · unattended-upgrades · # git config · docker · zsh + prompt · tailscale · neovim · js runtimes · # dev tools · ufw · zshrc · disk ballast