#!/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 <