Files
void-installer/installer/lib/common.sh

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}"
}