99 lines
3.4 KiB
Bash
Executable File
99 lines
3.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# Common helpers: logging, error handling, run-as-root checks.
|
|
# Sourced by all installer modules.
|
|
|
|
set -Eeuo pipefail
|
|
|
|
# --- colors ---
|
|
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
|
|
C_RED="$(tput setaf 1)"; C_GREEN="$(tput setaf 2)"
|
|
C_YEL="$(tput setaf 3)"; C_BLUE="$(tput setaf 4)"
|
|
C_BOLD="$(tput bold)"; C_RESET="$(tput sgr0)"
|
|
else
|
|
C_RED=""; C_GREEN=""; C_YEL=""; C_BLUE=""; C_BOLD=""; C_RESET=""
|
|
fi
|
|
|
|
LOG_FILE="${LOG_FILE:-/var/log/void-installer.log}"
|
|
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
|
|
: > "$LOG_FILE" 2>/dev/null || LOG_FILE="/tmp/void-installer.log"
|
|
|
|
log() { printf '%s [%s] %s\n' "$(date +%H:%M:%S)" "INFO" "$*" | tee -a "$LOG_FILE" >&2; }
|
|
warn() { printf '%s%s [%s] %s%s\n' "$C_YEL" "$(date +%H:%M:%S)" "WARN" "$*" "$C_RESET" | tee -a "$LOG_FILE" >&2; }
|
|
err() { printf '%s%s [%s] %s%s\n' "$C_RED" "$(date +%H:%M:%S)" "ERR " "$*" "$C_RESET" | tee -a "$LOG_FILE" >&2; }
|
|
ok() { printf '%s%s [%s] %s%s\n' "$C_GREEN" "$(date +%H:%M:%S)" " OK " "$*" "$C_RESET" | tee -a "$LOG_FILE" >&2; }
|
|
step() { printf '\n%s%s==> %s%s\n' "$C_BOLD" "$C_BLUE" "$*" "$C_RESET" | tee -a "$LOG_FILE" >&2; }
|
|
|
|
die() { err "$*"; exit 1; }
|
|
|
|
trap 'err "Installer aborted at line $LINENO (exit=$?). Log: $LOG_FILE"' ERR
|
|
|
|
require_root() {
|
|
[[ "${EUID:-$(id -u)}" -eq 0 ]] || die "must run as root"
|
|
}
|
|
|
|
confirm() {
|
|
# confirm "Question" -> returns 0 on yes
|
|
local prompt="${1:-Proceed?}"
|
|
if [[ "${UNATTENDED:-0}" == "1" ]]; then
|
|
log "[unattended] auto-yes: $prompt"
|
|
return 0
|
|
fi
|
|
local ans
|
|
read -r -p "$prompt [y/N] " ans
|
|
[[ "$ans" =~ ^[Yy]$ ]]
|
|
}
|
|
|
|
run_chroot() {
|
|
# run a command inside the target chroot
|
|
local target="${TARGET:-/mnt}"
|
|
chroot "$target" /usr/bin/env -i \
|
|
HOME=/root TERM="${TERM:-linux}" \
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
|
LANG="${LANG:-en_US.UTF-8}" \
|
|
/bin/bash -c "$*"
|
|
}
|
|
|
|
is_uefi() {
|
|
[[ -d /sys/firmware/efi/efivars ]]
|
|
}
|
|
|
|
# Set a password inside the chroot without exposing it to the shell argv
|
|
# or to ${} expansion in command strings (bash injection-safe).
|
|
# Uses openssl to pre-hash, then usermod -p, because chpasswd on Void can
|
|
# silently no-op for freshly-created (locked) accounts depending on the
|
|
# default crypt method in /etc/login.defs.
|
|
set_chroot_password() {
|
|
local user="$1" password="$2"
|
|
local target="${TARGET:-/mnt}"
|
|
# Generate a SHA-512 crypt hash on the host (openssl is in the live ISO).
|
|
local hash
|
|
hash="$(openssl passwd -6 "$password")" || {
|
|
warn "openssl passwd failed for $user; falling back to chpasswd"
|
|
chroot "$target" /usr/bin/env -i \
|
|
HOME=/root TERM="${TERM:-linux}" \
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
|
chpasswd <<EOF
|
|
$user:$password
|
|
EOF
|
|
return
|
|
}
|
|
# usermod -p writes the hash directly into /etc/shadow and unlocks.
|
|
chroot "$target" /usr/bin/env -i \
|
|
HOME=/root TERM="${TERM:-linux}" \
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
|
|
usermod -p "$hash" "$user"
|
|
}
|
|
|
|
load_secrets() {
|
|
local f="${1:-/etc/installer-secrets.env}"
|
|
if [[ -r "$f" ]]; then
|
|
# shellcheck disable=SC1090
|
|
source "$f"
|
|
log "loaded secrets from $f"
|
|
else
|
|
warn "no secrets file at $f; passwords must be set in env"
|
|
fi
|
|
: "${USER_PASSWORD:?USER_PASSWORD missing}"
|
|
: "${ROOT_PASSWORD:?ROOT_PASSWORD missing}"
|
|
}
|