Compare commits

..

No commits in common. "8cc60e3daefa8ce32c56e839a41dc30783d36ec5" and "667453596a1f20bd81e80f838b2242348bdde9f4" have entirely different histories.

8 changed files with 124 additions and 636 deletions

203
README.md
View File

@ -1,176 +1,59 @@
# Void Bootstrapp - Vollständiger CLI-Installer
# Void Bootstrapp Wrapper
Ein vollautomatischer Bash-Installer für verschlüsselte Void Linux Installationen.
Ein Bash-Wrapper, der die kritischen Vorarbeiten fuer eine verschluesselte Void-Linux-Installation erledigt und danach den offiziellen `void-installer` nutzt.
## Überblick
## Ablauf
Dieser Installer automatisiert die komplette Installation von Void Linux mit LUKS2-Verschlüsselung, btrfs/ext4-Dateisystem und allen erforderlichen System-Konfigurationen - **ohne manuelle Eingriffe**.
1. Sanity Checks (Root, UEFI, Zielplatte)
2. Partitionierung (GPT, ESP + Root)
3. LUKS-Verschluesselung und Mapping
4. Dateisysteme (btrfs oder ext4)
5. Mounts fuer den Installer
6. Installer-Handoff (manuelle Mountpoints, kein Reformat)
7. Post-Install (crypttab, dracut, GRUB, optional Swapfile)
**Was ist neu (v2.0):**
- Vollständig automatisiert - keine manuelle void-installer Navigation mehr
- Package-Installation (Base-System, Kernel, Tools)
- Locale/Timezone/Keyboard-Konfiguration
- User-Management (Root + Standard-User mit sudo)
- Service-Aktivierung (dhcpcd für Netzwerk)
## Installation-Workflow
Der Installer führt folgende Phasen automatisch aus:
1. **Sanity Checks** - Root-Rechte, UEFI-Modus, Zielplatte validieren
2. **Konfiguration** - Interaktive Eingabe aller Parameter
3. **Partitionierung** - GPT-Layout (ESP + Root-Partition)
4. **Verschlüsselung** - LUKS2/LUKS1 auf Root-Partition
5. **Dateisysteme** - btrfs (mit Subvolumes) oder ext4
6. **Mounts** - Alle Dateisysteme mounten
7. **Packages** - Base-System, Kernel, Network-Tools installieren
8. **Locale** - System-Sprache, Timezone, Keyboard konfigurieren
9. **Users** - Root-Passwort + Standard-User mit sudo anlegen
10. **Services** - dhcpcd (Netzwerk) aktivieren
11. **Post-Install** - initramfs, GRUB, crypttab, Swap-File
## Verwendung
## Usage
```bash
sudo ./src/main.sh [--dry-run]
sudo ./src/main.sh [--dry-run] [--skip-installer]
```
### Flags
## Flags
- `--dry-run`: Zeigt die Konfiguration und bricht ohne Änderungen ab
- `--dry-run`: Zeigt die Konfiguration und bricht ohne Aenderungen ab.
- `--skip-installer`: Laesst den Start von `void-installer` aus (manuell starten).
## Konfiguration
## Installer Bedienung nach dem Script
Während der Installation werden folgende Parameter abgefragt:
Im `void-installer` musst du die vorbereiteten Mounts uebernehmen und darfst nichts formatieren.
### Disk-Konfiguration
- **Target Disk**: Zielplatte (z.B. `/dev/sda`)
- **Hostname**: System-Hostname
- **Filesystem**: `btrfs` (Standard) oder `ext4`
- **LUKS Version**: `2` (Standard) oder `1` (für ältere GRUB-Versionen)
- **ESP Size**: EFI System Partition Größe (Standard: `1GiB`)
- **Root End**: Ende der Root-Partition (Standard: `100%`)
- **Swap Size**: Swap-File Größe (Standard: `4GiB`, `0` zum Deaktivieren)
1. Waehle die manuelle Partitionierung.
2. Setze nur die Mountpoints, ohne Formatierung.
3. Root:
- Device: `/dev/mapper/cryptroot`
- Label: `void-root` (btrfs und ext4)
- Mountpoint: `/`
- Format: aus
4. ESP:
- Device: erste Partition der Disk (meist `...1`)
- Label: `EFI`
- Mountpoint: `/boot/efi`
- Format: aus
### Locale-Konfiguration
- **Locale**: System-Sprache (Standard: `en_US.UTF-8`)
- **Timezone**: Zeitzone (Standard: `UTC`, z.B. `Europe/Berlin`)
- **Keyboard**: Console-Keyboard-Layout (Standard: `us`, z.B. `de-latin1`)
### User-Konfiguration
- **Username**: Name des Standard-Benutzers (erforderlich)
- **Root-Passwort**: Wird interaktiv gesetzt
- **User-Passwort**: Wird interaktiv gesetzt
Der Standard-User wird automatisch folgenden Gruppen zugeordnet:
- `wheel` - sudo-Zugang
- `audio` - Audio-Geräte
- `video` - Video-Geräte
- `storage` - Speicher-Geräte
- `network` - Netzwerk-Konfiguration
## Btrfs Subvolumes
Bei Auswahl von btrfs werden automatisch folgende Subvolumes angelegt:
- `@``/` (Root)
- `@home``/home` (Benutzer-Daten)
- `@var``/var` (Variable Daten)
- `@log``/var/log` (System-Logs)
- `@snapshots``/.snapshots` (Snapshot-Speicher)
- `@swap``/swap` (Swap-File Container)
## Package-Liste
Der Installer installiert standardmäßig folgende Pakete:
**Base-System:**
- `base-system` - Essential base packages
- `linux` - Linux Kernel
- `linux-firmware` - Hardware-Firmware
- `grub` - Bootloader
- `cryptsetup` - LUKS-Tools
- `dracut` - initramfs Generator
**Netzwerk:**
- `dhcpcd` - DHCP-Client
- `iproute2` - IP-Konfiguration
- `iputils` - ping, traceroute
**System-Tools:**
- `vim` - Text-Editor
- `nano` - Alternative Editor
- `sudo` - Privilege Escalation
## Nach der Installation
Nach erfolgreichem Abschluss:
1. System neustarten: `reboot`
2. LUKS-Passphrase beim Boot eingeben
3. Mit Standard-User einloggen
4. Netzwerk ist via dhcpcd automatisch verfügbar
5. `sudo` funktioniert für wheel-Gruppen-Mitglieder
## Systemanforderungen
- **Boot-Modus**: UEFI (BIOS wird nicht unterstützt)
- **Architektur**: x86_64
- **Live-Medium**: Void Linux Live-ISO
- **Netzwerk**: Für Package-Download erforderlich
Wenn Labels nicht angezeigt werden, pruefe mit `lsblk -f`, welches Device `void-root` bzw. `EFI` traegt.
Bei btrfs sind Subvolumes bereits angelegt und gemountet: `@`, `@home`, `@var`, `@log`, `@snapshots`, `@swap`.
Der Installer soll keine neuen Subvolumes anlegen oder formatieren, sondern die vorhandenen Mounts unveraendert lassen.
Es reicht, im Installer nur `/` und `/boot/efi` zu setzen; die Subvolumes werden im Post-Install in `/etc/fstab` eingetragen.
Mapping der Subvolumes (gesetzt durch den Wrapper/Post-Install):
- `@` -> `/`
- `@home` -> `/home`
- `@var` -> `/var`
- `@log` -> `/var/log`
- `@snapshots` -> `/.snapshots`
- `@swap` -> `/swap`
## Hinweise
- **Destruktiv**: Der Installer löscht die Zielplatte nach expliziter Bestätigung
- **Interaktiv**: Passwörter werden aus Sicherheitsgründen interaktiv abgefragt
- **Logs**: Unter `/tmp/void-wrapper-YYYY-MM-DD-HHMMSS.log`
## Fehlerbehebung
Bei Fehlern während der Installation:
1. **Fehler in Packages-Phase**: Netzwerk-Konnektivität und Mirror-Status prüfen
2. **Fehler in Users-Phase**: Passwort-Eingabe wiederholen
3. **Rollback angeboten**: Bei Fehler werden Mounts und LUKS-Mappings automatisch aufgeräumt
Für detaillierte Fehleranalyse siehe Log-Datei.
## Entwicklung
### Struktur
```
src/
├── main.sh # Orchestrierung aller Phasen
├── logging.sh # Logging-Funktionen
├── config.sh # Konfigurations-Prompts und Validierung
├── sanity.sh # System-Checks
├── partitioning.sh # GPT-Partitionierung
├── encryption.sh # LUKS-Setup
├── filesystems.sh # Dateisystem-Formatierung
├── mounts.sh # Mount-Management
├── packages.sh # Package-Installation
├── locale.sh # Locale/Timezone/Keyboard
├── users.sh # User-Management
├── services.sh # Service-Aktivierung
├── postinstall.sh # initramfs, GRUB, crypttab
└── rollback.sh # Cleanup bei Fehlern
```
### Architektur-Prinzipien
- **Narrative Documentation**: Jedes Modul dokumentiert Motivation, Decisions, Alternatives
- **Modulare Phasen**: Jede Phase ist eigenständig und testbar
- **Error Handling**: `set -euo pipefail` + trap-basiertes Rollback
- **Logging**: Alle Operationen werden geloggt
## Zukünftige Erweiterungen
- Config-File Support (JSON) für unattended Installations
- Desktop-Environment Auswahl (XFCE, KDE, GNOME)
- Zusätzliche Service-Optionen (sshd, chronyd)
- Checkpoint-System für Phase-Wiederaufnahme
## Lizenz
Dieses Projekt ist für Void Linux Installationen optimiert und folgt den Best Practices der Void Linux Dokumentation.
- Der Wrapper ist destruktiv und loescht die Zielplatte nach expliziter Bestaetigung.
- UEFI ist Pflicht; BIOS-Installationen sind nicht unterstuetzt.
- Logs landen unter `/tmp/void-wrapper-YYYY-MM-DD-HHMMSS.log`.

View File

@ -53,14 +53,6 @@ export ESP_MOUNT="/mnt/boot/efi"
export ROOT_LABEL="void-root"
export EFI_LABEL="EFI"
# Locale and user configuration
export LOCALE="en_US.UTF-8"
export TIMEZONE="UTC"
export KEYBOARD="us"
export USERNAME=""
export USER_SHELL="/bin/bash"
export USER_GROUPS="wheel,audio,video,storage,network"
validate_size() {
local size="$1"
# Allow sizes like: 1GiB, 100MB, 50%, 100%
@ -142,12 +134,6 @@ config_prompt_interactive() {
prompt_with_default ESP_SIZE "ESP size (e.g. 1GiB)" "${ESP_SIZE}"
prompt_with_default ROOT_END "Root partition end (e.g. 100% or 200GiB)" "${ROOT_END}"
prompt_with_default SWAP_SIZE "Swap size (e.g. 4GiB, 0 to disable)" "${SWAP_SIZE}"
# Locale and user configuration
prompt_with_default LOCALE "Locale (e.g. en_US.UTF-8, de_DE.UTF-8)" "${LOCALE}"
prompt_with_default TIMEZONE "Timezone (e.g. UTC, Europe/Berlin, America/New_York)" "${TIMEZONE}"
prompt_with_default KEYBOARD "Keyboard layout (e.g. us, de-latin1, fr)" "${KEYBOARD}"
prompt_required USERNAME "Username for standard user" "${USERNAME}"
}
config_validate() {
@ -157,9 +143,6 @@ config_validate() {
if [[ -z "$HOSTNAME" ]]; then
die "Hostname is required."
fi
if [[ -z "$USERNAME" ]]; then
die "Username is required."
fi
case "$FS_TYPE" in
btrfs|ext4) ;;
@ -186,16 +169,6 @@ config_validate() {
if [[ "$SWAP_SIZE" != "0" ]] && ! validate_size "$SWAP_SIZE"; then
die "Invalid swap size format: $SWAP_SIZE (expected: 4GiB, 8GB, 0 to disable)"
fi
# Validate locale format (basic check)
if [[ ! "$LOCALE" =~ ^[a-z]{2}_[A-Z]{2}\.(UTF-8|utf8)$ ]]; then
log_warn "Locale format may be invalid: $LOCALE (expected: en_US.UTF-8)"
fi
# Validate username (alphanumeric, underscore, hyphen)
if [[ ! "$USERNAME" =~ ^[a-z_][a-z0-9_-]*$ ]]; then
die "Invalid username: $USERNAME (must start with lowercase letter or underscore, contain only lowercase alphanumeric, underscore, hyphen)"
fi
}
config_print_summary() {
@ -205,7 +178,6 @@ config_print_summary() {
: "${LUKS_VERSION:?LUKS version is required}"
: "${MOUNT_ROOT:?Mount root is required}"
: "${ESP_MOUNT:?ESP mount path is required}"
: "${USERNAME:?Username is required}"
log_info "Configuration summary:"
log_info " Disk: $DISK"
log_info " Hostname: $HOSTNAME"
@ -216,10 +188,6 @@ config_print_summary() {
log_info " Swap size: ${SWAP_SIZE}"
log_info " Mount root: $MOUNT_ROOT"
log_info " ESP mount: $ESP_MOUNT"
log_info " Locale: $LOCALE"
log_info " Timezone: $TIMEZONE"
log_info " Keyboard: $KEYBOARD"
log_info " Username: $USERNAME"
}
config_confirm_destructive() {

71
src/installer.sh Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env bash
# === Motivation ===
# Keep the official installer as the configuration authority.
# === Problem Statement ===
# We need a clean handoff so the installer uses existing mounts without reformatting.
# === Scope ===
# In scope: instructions and guardrails for the user during the installer run.
# Out of scope: automated installer configuration.
# === Concepts ===
# Handoff: a pause where the wrapper delegates to the installer.
# === Decisions ===
# Provide clear, minimal guidance to avoid overriding prepared filesystems.
# Support only CLI installer flow to keep guidance consistent.
# === Alternatives Considered ===
# Fully scripted installation rejected for this phase.
# === Constraints ===
# The wrapper must not hide or alter installer behavior.
# === Open Questions ===
# Should we provide a checklist or step-by-step guide during the installer handoff?
# How do we detect if the installer reformatted filesystems against our intent?
# Should we monitor the installer process, or fully delegate control?
# === Success Criteria ===
# The installer completes using the prepared mounts without reformatting.
run_installer() {
: "${MOUNT_ROOT:?Mount root is required}"
: "${ESP_MOUNT:?ESP mount path is required}"
if ! findmnt "$MOUNT_ROOT" >/dev/null 2>&1; then
die "Mount root not found: $MOUNT_ROOT"
fi
if ! findmnt "$ESP_MOUNT" >/dev/null 2>&1; then
die "ESP mount not found: $ESP_MOUNT"
fi
log_info "Installer handoff: use the prepared mounts without formatting."
log_info "In the installer: choose manual partitioning and only set mountpoints."
if [[ "${SKIP_INSTALLER:-0}" -eq 1 ]]; then
log_warn "Skipping installer per request."
return 0
fi
read -r -p "Press Enter to launch void-installer..." _
if command -v void-installer >/dev/null 2>&1; then
void-installer
else
log_warn "void-installer not found. Run it manually in another shell."
fi
read -r -p "Press Enter once the installer is complete..." _
# Verify critical mounts are still intact after installer
if ! findmnt "$MOUNT_ROOT" >/dev/null 2>&1; then
die "Root mount disappeared after installer. The installer may have reformatted the filesystem."
fi
if ! findmnt "$ESP_MOUNT" >/dev/null 2>&1; then
die "ESP mount disappeared after installer. The installer may have reformatted the filesystem."
fi
log_info "Mount verification passed."
}

View File

@ -1,117 +0,0 @@
#!/usr/bin/env bash
# === Motivation ===
# Configure system locale, timezone, and keyboard layout for international users.
# === Problem Statement ===
# A freshly installed system needs localization configuration to support user language and region.
# === Scope ===
# In scope: locale generation, timezone configuration, keyboard layout.
# Out of scope: X11 keyboard configuration, font selection, language packs.
# === Concepts ===
# Locale: Defines language, character encoding, and formatting conventions (LC_*).
# Timezone: Maps local time to UTC with regional rules (DST, etc.).
# Keyboard layout: Console keymap for character input.
# === Decisions ===
# Default locale is en_US.UTF-8 for broadest compatibility.
# Default timezone will be configured based on user prompt (see config.sh).
# Default keyboard layout is 'us' (can be overridden via config).
# Use /etc/default/libc-locales for locale configuration (Void standard).
# Use symlink for timezone (/etc/localtime → /usr/share/zoneinfo/<zone>).
# Use /etc/rc.conf for console keyboard layout (KEYMAP variable).
# === Alternatives Considered ===
# systemd-localed rejected (Void uses runit).
# Generating all locales rejected (wastes disk space and time).
# Auto-detection of timezone rejected (unreliable without network/GeoIP).
# === Constraints ===
# Target system must be mounted at $MOUNT_ROOT.
# Locale must be generated before it can be used.
# Timezone must exist in /usr/share/zoneinfo.
# === Open Questions ===
# Should we support multiple locales (e.g., en_US + de_DE)?
# Should we validate timezone path before creating symlink?
# Should we configure X11 keyboard layout as well?
# === Success Criteria ===
# Locale is generated and available in the installed system.
# Timezone is correctly configured and persists after reboot.
# Keyboard layout matches user selection on console login.
locale_configure() {
: "${MOUNT_ROOT:?Mount root is required}"
: "${LOCALE:?Locale is required}"
: "${TIMEZONE:?Timezone is required}"
: "${KEYBOARD:?Keyboard layout is required}"
log_info "Locale configuration: setting up locale, timezone, and keyboard"
# Configure locale in /etc/default/libc-locales
log_info "Configuring locale: $LOCALE"
local locale_file="$MOUNT_ROOT/etc/default/libc-locales"
mkdir -p "$(dirname "$locale_file")"
# Ensure locale file exists
if [[ ! -f "$locale_file" ]]; then
touch "$locale_file"
fi
# Uncomment or add the selected locale
if grep -q "^#${LOCALE}" "$locale_file"; then
# Locale exists but is commented - uncomment it
sed -i "s/^#${LOCALE}/${LOCALE}/" "$locale_file"
elif grep -q "^${LOCALE}" "$locale_file"; then
# Locale already enabled
log_info "Locale $LOCALE already enabled"
else
# Add locale to file
echo "$LOCALE UTF-8" >> "$locale_file"
fi
# Generate locales
log_info "Generating locales (this may take a moment)..."
if ! chroot "$MOUNT_ROOT" xbps-reconfigure -f glibc-locales; then
log_warn "Failed to reconfigure glibc-locales, but continuing"
fi
# Configure timezone
log_info "Configuring timezone: $TIMEZONE"
local timezone_source="/usr/share/zoneinfo/$TIMEZONE"
local timezone_target="$MOUNT_ROOT/etc/localtime"
if [[ ! -f "$MOUNT_ROOT$timezone_source" ]]; then
log_warn "Timezone file not found: $timezone_source - using UTC as fallback"
TIMEZONE="UTC"
timezone_source="/usr/share/zoneinfo/UTC"
fi
# Remove existing symlink or file
rm -f "$timezone_target"
# Create symlink
ln -sf "$timezone_source" "$timezone_target"
# Also set timezone in /etc/timezone for compatibility
echo "$TIMEZONE" > "$MOUNT_ROOT/etc/timezone"
# Configure keyboard layout
log_info "Configuring keyboard layout: $KEYBOARD"
local rc_conf="$MOUNT_ROOT/etc/rc.conf"
mkdir -p "$(dirname "$rc_conf")"
touch "$rc_conf"
# Update or add KEYMAP entry in /etc/rc.conf
if grep -q "^KEYMAP=" "$rc_conf"; then
sed -i "s/^KEYMAP=.*/KEYMAP=\"$KEYBOARD\"/" "$rc_conf"
else
echo "KEYMAP=\"$KEYBOARD\"" >> "$rc_conf"
fi
log_info "Locale configuration complete."
}

View File

@ -72,27 +72,23 @@ source "$SCRIPT_DIR/encryption.sh"
source "$SCRIPT_DIR/filesystems.sh"
# shellcheck source=src/mounts.sh
source "$SCRIPT_DIR/mounts.sh"
# shellcheck source=src/packages.sh
source "$SCRIPT_DIR/packages.sh"
# shellcheck source=src/locale.sh
source "$SCRIPT_DIR/locale.sh"
# shellcheck source=src/users.sh
source "$SCRIPT_DIR/users.sh"
# shellcheck source=src/services.sh
source "$SCRIPT_DIR/services.sh"
# shellcheck source=src/installer.sh
source "$SCRIPT_DIR/installer.sh"
# shellcheck source=src/postinstall.sh
source "$SCRIPT_DIR/postinstall.sh"
# shellcheck source=src/rollback.sh
source "$SCRIPT_DIR/rollback.sh"
DRY_RUN=0
SKIP_INSTALLER=0
CURRENT_PHASE=""
usage() {
cat <<USAGE
Usage: ./main.sh [--dry-run]
Usage: ./main.sh [--dry-run] [--skip-installer]
--dry-run Print configuration summary and exit
--skip-installer Skip launching void-installer (manual run)
USAGE
}
@ -102,6 +98,9 @@ parse_args() {
--dry-run)
DRY_RUN=1
;;
--skip-installer)
SKIP_INSTALLER=1
;;
-h|--help)
usage
exit 0
@ -154,14 +153,10 @@ main() {
run_phase "encryption" encrypt_root
run_phase "filesystems" format_filesystems
run_phase "mounts" mount_filesystems
run_phase "packages" packages_install
run_phase "locale" locale_configure
run_phase "users" users_setup
run_phase "services" services_configure
run_phase "installer" run_installer
run_phase "post-install" postinstall_run
log_info "Installation completed successfully."
log_info "System is ready to boot."
log_info "Installation wrapper completed."
log_info "Log file: ${LOG_FILE}"
}

View File

@ -1,97 +0,0 @@
#!/usr/bin/env bash
# === Motivation ===
# Install all required packages for a bootable Void Linux system.
# === Problem Statement ===
# The installer must provide a minimal base system without relying on void-installer.
# === Scope ===
# In scope: package installation, repository synchronization, dependency resolution.
# Out of scope: package selection UI, custom repository configuration.
# === Concepts ===
# XBPS: Void's package manager, handles installation and dependency resolution.
# chroot: Execute package installation in the target system environment.
# Repository sync: Update package index before installation.
# === Decisions ===
# Install minimal package set by default for base CLI system.
# Support optional package installation via config (future: config file support).
# Use xbps-install with sync (-S) and yes (-y) flags for non-interactive installation.
# Ensure network connectivity before package installation (handled by live environment).
# Package list is conservative: only essentials for boot + network + basic tools.
# === Alternatives Considered ===
# Interactive package selection rejected (violates CLI-only requirement).
# Separate kernel installation rejected (included in base-system dependency).
# systemd-based packages rejected (Void uses runit).
# === Constraints ===
# Target system must be mounted at $MOUNT_ROOT.
# Repository must be accessible via network.
# xbps must be available in live environment.
# === Open Questions ===
# Should firmware packages beyond linux-firmware be included (e.g., nvidia, AMD)?
# Should we validate package availability before installation?
# How to handle optional packages (desktop environments, development tools)?
# === Success Criteria ===
# All required packages are installed in the target system.
# Package manager can be used in the installed system post-reboot.
# System can boot with network connectivity and basic tools available.
packages_install() {
: "${MOUNT_ROOT:?Mount root is required}"
require_command xbps-install
log_info "Package installation: installing base system"
# Define minimal package set for bootable CLI system
local base_packages=(
"base-system" # Essential base packages (includes kernel via dependency)
"linux" # Linux kernel
"linux-firmware" # Firmware blobs for hardware
"grub" # Bootloader
"cryptsetup" # LUKS encryption tools
"dracut" # initramfs generator
)
local network_packages=(
"dhcpcd" # DHCP client for network
"iproute2" # ip command for network configuration
"iputils" # ping, traceroute, etc.
)
local system_tools=(
"vim" # Text editor
"nano" # Alternative text editor
"sudo" # Privilege escalation
)
# Combine all package arrays
local all_packages=("${base_packages[@]}" "${network_packages[@]}" "${system_tools[@]}")
log_info "Package list: ${all_packages[*]}"
log_info "Installing ${#all_packages[@]} packages (this may take several minutes)..."
# Ensure repository is accessible and synchronized
# Use chroot to install packages into target system
if ! chroot "$MOUNT_ROOT" xbps-install -Syu "${all_packages[@]}"; then
die "Package installation failed. Check network connectivity and repository status."
fi
log_info "Package installation complete."
# Verify critical packages are installed
log_info "Verifying package installation..."
local critical_packages=("base-system" "linux" "grub" "cryptsetup")
for pkg in "${critical_packages[@]}"; do
if ! chroot "$MOUNT_ROOT" xbps-query "$pkg" >/dev/null 2>&1; then
die "Critical package not found: $pkg"
fi
done
log_info "Package verification passed."
}

View File

@ -1,95 +0,0 @@
#!/usr/bin/env bash
# === Motivation ===
# Enable essential system services for network connectivity and basic functionality.
# === Problem Statement ===
# A freshly installed system needs service activation to function properly at boot.
# === Scope ===
# In scope: network service activation, optional services (SSH, NTP).
# Out of scope: service configuration, firewall rules, custom service creation.
# === Concepts ===
# runit: Void's init system and service supervisor.
# Service directory: /etc/sv/<service> contains service definition.
# Service activation: Symlink from /etc/runit/runsvdir/default/<service> to /etc/sv/<service>.
# dhcpcd: DHCP client for automatic network configuration.
# sshd: OpenSSH server for remote access.
# chronyd: NTP client for time synchronization.
# === Decisions ===
# Enable dhcpcd by default for network connectivity (required for most systems).
# Disable sshd by default for security (can be enabled via config).
# Disable chronyd by default (optional service, can be enabled via config).
# Use absolute symlinks for service activation (Void standard).
# Validate service directory exists before creating symlink.
# === Alternatives Considered ===
# NetworkManager rejected as default (dhcpcd is lighter and sufficient for server/minimal systems).
# systemd-networkd rejected (Void uses runit).
# Enabling all services rejected (security and resource waste).
# Auto-detection of network interface rejected (dhcpcd handles this).
# === Constraints ===
# Target system must be mounted at $MOUNT_ROOT.
# Service packages must be installed before activation.
# Service definitions must exist in /etc/sv/.
# === Open Questions ===
# Should we detect network interface type and choose NetworkManager vs dhcpcd?
# Should we prompt for optional services interactively or only via config?
# Should we enable dbus by default for desktop environments?
# === Success Criteria ===
# dhcpcd is enabled and system has network connectivity after reboot.
# Optional services are enabled if requested via configuration.
# Services start successfully on boot.
services_configure() {
: "${MOUNT_ROOT:?Mount root is required}"
local runsvdir="$MOUNT_ROOT/etc/runit/runsvdir/default"
log_info "Service configuration: enabling system services"
# Ensure runsvdir exists
mkdir -p "$runsvdir"
# Enable dhcpcd for network connectivity
log_info "Enabling dhcpcd service"
enable_service "dhcpcd"
# Optional services (can be extended with config file support)
# For now, we only enable essential services
# Future: Add support for ENABLE_SSHD, ENABLE_CHRONYD via config
log_info "Service configuration complete."
}
enable_service() {
local service="$1"
local service_dir="/etc/sv/$service"
local runsvdir="$MOUNT_ROOT/etc/runit/runsvdir/default"
local service_link="$runsvdir/$service"
# Check if service definition exists
if [[ ! -d "$MOUNT_ROOT$service_dir" ]]; then
log_warn "Service definition not found: $service_dir (service may not be installed)"
return 1
fi
# Check if service is already enabled
if [[ -L "$service_link" ]]; then
log_info "Service $service already enabled"
return 0
fi
# Create symlink to enable service
if ! ln -sf "$service_dir" "$service_link"; then
log_warn "Failed to enable service: $service"
return 1
fi
log_info "Service $service enabled"
return 0
}

View File

@ -1,120 +0,0 @@
#!/usr/bin/env bash
# === Motivation ===
# Create user accounts with proper permissions for system access.
# === Problem Statement ===
# A bootable system needs at least root access and a non-privileged user account.
# === Scope ===
# In scope: root password, standard user creation, group membership, sudo configuration.
# Out of scope: multiple users, password policies, PAM configuration.
# === Concepts ===
# Root user: Administrative account with UID 0, full system access.
# Standard user: Non-privileged account for daily tasks, can escalate via sudo.
# wheel group: Traditional Unix group for sudo access.
# useradd: Creates user accounts with home directory and group membership.
# === Decisions ===
# Root password is set interactively (security requirement).
# Standard user is created with wheel group for sudo access.
# Additional groups (audio, video, storage, network) are added for hardware access.
# User password is set interactively (same security requirement as root).
# sudo is configured by uncommenting wheel group in /etc/sudoers.
# Default shell is /bin/bash (most common, widely supported).
# === Alternatives Considered ===
# Hash-based password rejected for initial implementation (requires additional config).
# Passwordless sudo rejected (security risk).
# Creating user without sudo rejected (user would be unable to administer system).
# systemd-homed rejected (Void uses traditional user management).
# === Constraints ===
# Target system must be mounted at $MOUNT_ROOT.
# sudo package must be installed before configuration.
# Interactive password input requires TTY.
# === Open Questions ===
# Should we support multiple user creation?
# Should we validate password strength?
# Should we configure shell based on user preference?
# === Success Criteria ===
# Root password is set and login works.
# Standard user can log in with password.
# Standard user can execute sudo commands.
# User has access to audio, video, and network hardware.
users_setup() {
: "${MOUNT_ROOT:?Mount root is required}"
: "${USERNAME:?Username is required}"
local user_shell="${USER_SHELL:-/bin/bash}"
local user_groups="${USER_GROUPS:-wheel,audio,video,storage,network}"
log_info "User setup: configuring root and creating standard user"
# Set root password interactively
log_info "Setting root password"
log_info "Please enter the root password when prompted:"
if ! chroot "$MOUNT_ROOT" passwd; then
die "Failed to set root password"
fi
# Create standard user
log_info "Creating user: $USERNAME"
if chroot "$MOUNT_ROOT" id "$USERNAME" >/dev/null 2>&1; then
log_warn "User $USERNAME already exists, skipping creation"
else
# Create user with home directory and group membership
if ! chroot "$MOUNT_ROOT" useradd -m -G "$user_groups" -s "$user_shell" "$USERNAME"; then
die "Failed to create user: $USERNAME"
fi
log_info "User $USERNAME created with groups: $user_groups"
fi
# Set user password interactively
log_info "Setting password for user: $USERNAME"
log_info "Please enter the password for $USERNAME when prompted:"
if ! chroot "$MOUNT_ROOT" passwd "$USERNAME"; then
die "Failed to set password for user: $USERNAME"
fi
# Configure sudo for wheel group
log_info "Configuring sudo access for wheel group"
local sudoers_file="$MOUNT_ROOT/etc/sudoers"
if [[ ! -f "$sudoers_file" ]]; then
die "Sudoers file not found. Ensure sudo package is installed."
fi
# Backup sudoers file
cp "$sudoers_file" "${sudoers_file}.bak"
# Uncomment wheel group line (allow members of wheel to execute any command)
if grep -q "^# %wheel ALL=(ALL:ALL) ALL" "$sudoers_file"; then
sed -i 's/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' "$sudoers_file"
log_info "Enabled sudo for wheel group"
elif grep -q "^%wheel ALL=(ALL:ALL) ALL" "$sudoers_file"; then
log_info "sudo for wheel group already enabled"
elif grep -q "^# %wheel ALL=(ALL) ALL" "$sudoers_file"; then
# Alternative format
sed -i 's/^# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/' "$sudoers_file"
log_info "Enabled sudo for wheel group (alternative format)"
else
# Add wheel group entry if not present
echo "%wheel ALL=(ALL:ALL) ALL" >> "$sudoers_file"
log_info "Added sudo configuration for wheel group"
fi
# Validate sudoers file syntax
if ! chroot "$MOUNT_ROOT" visudo -c -f /etc/sudoers >/dev/null 2>&1; then
log_warn "Sudoers file validation failed, restoring backup"
mv "${sudoers_file}.bak" "$sudoers_file"
die "Failed to configure sudo (syntax error)"
fi
rm -f "${sudoers_file}.bak"
log_info "User setup complete."
}