Initial commit: DarkForge Linux — Phases 0-12

Complete from-scratch Linux distribution targeting AMD Ryzen 9 9950X3D +
NVIDIA RTX 5090 on ASUS ROG CROSSHAIR X870E HERO.

Deliverables:
- dpack: custom package manager in Rust (3,800 lines)
  - TOML package parser, dependency resolver, build sandbox
  - CRUX Pkgfile and Gentoo ebuild converters
  - Shared library conflict detection
- 124 package definitions across 4 repos (core/extra/desktop/gaming)
- 34 toolchain bootstrap scripts (LFS 13.0 adapted for Zen 5)
- Linux 6.19.8 kernel config (hardware-specific, fully commented)
- SysVinit init system with rc.d service scripts
- Live ISO builder (UEFI-only, squashfs+xorriso)
- Interactive installer (GPT partitioning, EFISTUB boot)
- Integration test checklist (docs/TESTING.md)

No systemd. No bootloader. No display manager.
Kernel boots via EFISTUB → auto-login → dwl Wayland compositor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 11:30:40 +01:00
commit 029642ae5b
206 changed files with 14696 additions and 0 deletions

20
configs/fstab.template Normal file
View File

@@ -0,0 +1,20 @@
# ============================================================================
# DarkForge Linux — /etc/fstab
# ============================================================================
# Filesystem table. Populated by the installer with actual UUIDs.
# Partition scheme: GPT with ESP + root (ext4) + swap (96GB)
# ============================================================================
# <device> <mount> <type> <options> <dump> <pass>
# Root filesystem — ext4 on NVMe
UUID=__ROOT_UUID__ / ext4 defaults,noatime 0 1
# EFI System Partition — kernel lives here
UUID=__ESP_UUID__ /boot/efi vfat defaults,noatime 0 2
# Swap partition — 96GB for hibernation support
UUID=__SWAP_UUID__ none swap defaults 0 0
# Pseudo-filesystems (mounted by rc.sysinit, listed here for completeness)
tmpfs /tmp tmpfs defaults,nosuid,nodev 0 0

34
configs/inittab Normal file
View File

@@ -0,0 +1,34 @@
# ============================================================================
# DarkForge Linux — /etc/inittab
# ============================================================================
# SysVinit configuration. Defines runlevels and getty spawning.
# Runlevel 3 = multi-user with networking (our default).
# No display manager — tty1 auto-logs in 'danny' and starts dwl.
# ============================================================================
# Default runlevel
id:3:initdefault:
# System initialization script (runs once at boot)
si::sysinit:/etc/rc.d/rc.sysinit
# Runlevel scripts
l0:0:wait:/etc/rc.d/rc.shutdown
l3:3:wait:/etc/rc.d/rc.multi
l6:6:wait:/etc/rc.d/rc.reboot
# --- Virtual consoles -------------------------------------------------------
# tty1: Auto-login danny — no password prompt, launches dwl via .zprofile
1:2345:respawn:/sbin/agetty --autologin danny --noclear 38400 tty1 linux
# tty2-4: Standard login prompts (for emergency access)
2:2345:respawn:/sbin/agetty 38400 tty2 linux
3:2345:respawn:/sbin/agetty 38400 tty3 linux
4:2345:respawn:/sbin/agetty 38400 tty4 linux
# --- Special keys -----------------------------------------------------------
# Ctrl+Alt+Del triggers a clean reboot
ca::ctrlaltdel:/sbin/shutdown -r now
# Power key triggers a clean shutdown (if ACPI sends it)
pf::powerfail:/sbin/shutdown -h +0 "Power failure — shutting down"

69
configs/rc.conf Normal file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — System Configuration
# ============================================================================
# /etc/rc.conf — sourced by all rc.d scripts and the init system.
# This is the single place to configure hostname, locale, timezone,
# network, daemons, and kernel modules.
# ============================================================================
# --- System identity --------------------------------------------------------
HOSTNAME="darkforge"
# --- Locale and language ----------------------------------------------------
LOCALE="en_US.UTF-8"
KEYMAP="us"
TIMEZONE="America/New_York"
# These are set during installation and can be changed here post-install.
# --- Console font -----------------------------------------------------------
FONT="ter-v18n"
# Terminus font at 18px — crisp on high-DPI displays. Requires kbd package.
# Set to "" to use the kernel default.
# --- Daemons to start at boot ----------------------------------------------
# Order matters. Each name corresponds to a script in /etc/rc.d/
# Scripts are started in listed order at boot, stopped in reverse at shutdown.
DAEMONS=(
eudev # Device manager — must be first for hardware detection
syslog # System logging
dbus # D-Bus message bus — needed by polkit, PipeWire
dhcpcd # DHCP client for ethernet
pipewire # Audio server (replaces PulseAudio)
)
# --- Kernel modules to load at boot ----------------------------------------
# Modules not auto-loaded by eudev that we need explicitly.
MODULES=(
nvidia
nvidia-modeset
nvidia-drm
nvidia-uvm
)
# --- Module parameters ------------------------------------------------------
# Pass parameters to kernel modules when loading.
# Format: "module_name parameter=value"
MODULE_PARAMS=(
"nvidia-drm modeset=1"
# nvidia-drm modeset=1 — required for Wayland DRM/KMS support
)
# --- Network ----------------------------------------------------------------
NETWORK_INTERFACE="enp6s0"
# The primary ethernet interface. Detected by eudev.
# Verify with: ip link show
# X870E Hero Realtek 2.5GbE is typically enp6s0 or similar.
NETWORK_DHCP=yes
# Use DHCP for automatic IP configuration.
# Set to "no" for static IP and configure NETWORK_IP/MASK/GATEWAY below.
#NETWORK_IP="192.168.1.100"
#NETWORK_MASK="255.255.255.0"
#NETWORK_GATEWAY="192.168.1.1"
#NETWORK_DNS="1.1.1.1 8.8.8.8"
# --- Miscellaneous ----------------------------------------------------------
HARDWARECLOCK="UTC"
# The hardware clock is set to UTC. localtime is computed from TIMEZONE.

35
configs/rc.d/dbus Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — D-Bus service
# ============================================================================
# D-Bus message bus — required by polkit, PipeWire, and many desktop apps.
# ============================================================================
DAEMON="/usr/bin/dbus-daemon"
PIDFILE="/run/dbus/pid"
case "$1" in
start)
echo " Starting dbus..."
mkdir -p /run/dbus
dbus-uuidgen --ensure
${DAEMON} --system && echo " dbus started"
;;
stop)
echo " Stopping dbus..."
if [ -f ${PIDFILE} ]; then
kill $(cat ${PIDFILE}) 2>/dev/null
rm -f ${PIDFILE}
fi
echo " dbus stopped"
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

48
configs/rc.d/dhcpcd Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — dhcpcd service
# ============================================================================
# DHCP client daemon for ethernet. Uses interface from rc.conf.
# ============================================================================
. /etc/rc.conf
DAEMON="/usr/sbin/dhcpcd"
PIDFILE="/run/dhcpcd-${NETWORK_INTERFACE}.pid"
case "$1" in
start)
echo " Starting dhcpcd on ${NETWORK_INTERFACE}..."
if [ "${NETWORK_DHCP}" = "yes" ]; then
${DAEMON} -q "${NETWORK_INTERFACE}" && echo " dhcpcd started"
else
# Static IP configuration
ip addr add "${NETWORK_IP}/${NETWORK_MASK}" dev "${NETWORK_INTERFACE}"
ip link set "${NETWORK_INTERFACE}" up
ip route add default via "${NETWORK_GATEWAY}"
if [ -n "${NETWORK_DNS}" ]; then
echo "# Generated by rc.d/dhcpcd" > /etc/resolv.conf
for dns in ${NETWORK_DNS}; do
echo "nameserver ${dns}" >> /etc/resolv.conf
done
fi
echo " Static IP configured: ${NETWORK_IP}"
fi
;;
stop)
echo " Stopping dhcpcd..."
if [ -f "${PIDFILE}" ]; then
${DAEMON} -x "${NETWORK_INTERFACE}" 2>/dev/null
fi
echo " dhcpcd stopped"
;;
restart)
$0 stop
sleep 2
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

32
configs/rc.d/eudev Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — eudev service
# ============================================================================
# Device manager — must be the first daemon started.
# Populates /dev with device nodes and triggers udev rules.
# ============================================================================
case "$1" in
start)
echo " Starting eudev..."
/sbin/udevd --daemon
udevadm trigger --action=add --type=subsystems
udevadm trigger --action=add --type=devices
udevadm settle
echo " eudev started"
;;
stop)
echo " Stopping eudev..."
udevadm control --exit 2>/dev/null
echo " eudev stopped"
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

34
configs/rc.d/pipewire Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — PipeWire service
# ============================================================================
# PipeWire audio server + WirePlumber session manager.
# NOTE: PipeWire is designed to run as a user service, not system-wide.
# This script starts it for the auto-login user (danny) on tty1.
# For the system-level boot, we just ensure the prerequisites are ready.
# The actual PipeWire startup is handled in the user's shell profile.
# ============================================================================
case "$1" in
start)
echo " PipeWire: ready (will start with user session)"
# Ensure runtime directory exists for the user
mkdir -p /run/user/1000
chown danny:danny /run/user/1000
chmod 700 /run/user/1000
;;
stop)
echo " Stopping PipeWire..."
killall pipewire wireplumber pipewire-pulse 2>/dev/null
echo " PipeWire stopped"
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

21
configs/rc.d/rc.multi Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — Multi-User Startup
# ============================================================================
# /etc/rc.d/rc.multi — starts all daemons listed in rc.conf DAEMONS array.
# Called by init when entering runlevel 3.
# ============================================================================
. /etc/rc.conf
echo ":: Starting daemons..."
for daemon in "${DAEMONS[@]}"; do
if [ -x "/etc/rc.d/${daemon}" ]; then
"/etc/rc.d/${daemon}" start
else
echo "!! Daemon script not found: /etc/rc.d/${daemon}"
fi
done
echo ":: All daemons started"

9
configs/rc.d/rc.reboot Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — System Reboot
# ============================================================================
# /etc/rc.d/rc.reboot — runs shutdown then reboots.
# ============================================================================
/etc/rc.d/rc.shutdown
reboot -f

40
configs/rc.d/rc.shutdown Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — System Shutdown
# ============================================================================
# /etc/rc.d/rc.shutdown — stops daemons and cleans up before halt/reboot.
# ============================================================================
. /etc/rc.conf
echo ":: Shutting down..."
# --- Stop daemons in reverse order ------------------------------------------
REVERSED=()
for daemon in "${DAEMONS[@]}"; do
REVERSED=("${daemon}" "${REVERSED[@]}")
done
for daemon in "${REVERSED[@]}"; do
if [ -x "/etc/rc.d/${daemon}" ]; then
"/etc/rc.d/${daemon}" stop
fi
done
# --- Save random seed -------------------------------------------------------
dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null
# --- Write wtmp shutdown entry ----------------------------------------------
halt -w
# --- Deactivate swap --------------------------------------------------------
swapoff -a
# --- Unmount filesystems ----------------------------------------------------
echo ":: Unmounting filesystems..."
umount -a -r 2>/dev/null
# --- Remount root read-only -------------------------------------------------
mount -o remount,ro /
echo ":: Shutdown complete"

104
configs/rc.d/rc.sysinit Executable file
View File

@@ -0,0 +1,104 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — System Initialization
# ============================================================================
# /etc/rc.d/rc.sysinit — runs once at boot before daemons start.
# Sets up: hostname, clock, filesystems, kernel modules, swap, sysctl.
# ============================================================================
. /etc/rc.conf
echo "DarkForge Linux — booting..."
# --- Mount virtual filesystems (if not already by kernel) -------------------
mountpoint -q /proc || mount -t proc proc /proc
mountpoint -q /sys || mount -t sysfs sysfs /sys
mountpoint -q /run || mount -t tmpfs tmpfs /run
mountpoint -q /dev || mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /run/lock
mountpoint -q /dev/pts || mount -t devpts devpts /dev/pts
mountpoint -q /dev/shm || mount -t tmpfs tmpfs /dev/shm
# --- Set hostname -----------------------------------------------------------
echo "${HOSTNAME}" > /proc/sys/kernel/hostname
echo ":: Hostname set to ${HOSTNAME}"
# --- Set hardware clock -----------------------------------------------------
if [ "${HARDWARECLOCK}" = "UTC" ]; then
hwclock --systohc --utc 2>/dev/null
else
hwclock --systohc --localtime 2>/dev/null
fi
# --- Set timezone -----------------------------------------------------------
if [ -f "/usr/share/zoneinfo/${TIMEZONE}" ]; then
ln -sf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime
echo ":: Timezone set to ${TIMEZONE}"
fi
# --- Set console keymap -----------------------------------------------------
if [ -n "${KEYMAP}" ]; then
loadkeys "${KEYMAP}" 2>/dev/null && echo ":: Keymap set to ${KEYMAP}"
fi
# --- Set console font -------------------------------------------------------
if [ -n "${FONT}" ]; then
setfont "${FONT}" 2>/dev/null && echo ":: Console font set to ${FONT}"
fi
# --- Filesystem check -------------------------------------------------------
echo ":: Checking filesystems..."
fsck -A -T -C -a
if [ $? -gt 1 ]; then
echo "!! Filesystem errors detected. Dropping to emergency shell."
echo "!! Run 'fsck' manually, then 'exit' to continue boot."
/bin/bash
fi
# --- Mount all filesystems from fstab ---------------------------------------
echo ":: Mounting filesystems..."
mount -a
mount -o remount,rw /
# --- Activate swap ----------------------------------------------------------
echo ":: Activating swap..."
swapon -a
# --- Load kernel modules from rc.conf --------------------------------------
echo ":: Loading kernel modules..."
for mod in "${MODULES[@]}"; do
modprobe "${mod}" && echo " Loaded: ${mod}"
done
# --- Apply module parameters ------------------------------------------------
for param in "${MODULE_PARAMS[@]}"; do
mod=$(echo "${param}" | awk '{print $1}')
args=$(echo "${param}" | cut -d' ' -f2-)
# Module params are passed at load time, but if already loaded,
# try writing to sysfs
if [ -d "/sys/module/${mod}/parameters" ]; then
key=$(echo "${args}" | cut -d'=' -f1)
val=$(echo "${args}" | cut -d'=' -f2)
echo "${val}" > "/sys/module/${mod}/parameters/${key}" 2>/dev/null
fi
done
# --- Apply sysctl settings --------------------------------------------------
if [ -f /etc/sysctl.conf ]; then
sysctl -p /etc/sysctl.conf >/dev/null 2>&1
echo ":: Applied sysctl settings"
fi
# --- Set up /tmp ------------------------------------------------------------
chmod 1777 /tmp
# --- Seed random number generator ------------------------------------------
if [ -f /var/lib/random-seed ]; then
cat /var/lib/random-seed > /dev/urandom
fi
dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null
# --- Clear old PID files and locks ------------------------------------------
rm -f /run/*.pid /var/lock/* 2>/dev/null
echo ":: System initialization complete"

32
configs/rc.d/syslog Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
# ============================================================================
# DarkForge Linux — syslog service
# ============================================================================
# System logging daemon. Uses sysklogd or syslog-ng.
# ============================================================================
DAEMON="/usr/sbin/syslogd"
PIDFILE="/run/syslogd.pid"
case "$1" in
start)
echo " Starting syslog..."
${DAEMON} -m 0 && echo " syslog started"
/usr/sbin/klogd && echo " klogd started"
;;
stop)
echo " Stopping syslog..."
killall syslogd klogd 2>/dev/null
rm -f ${PIDFILE}
echo " syslog stopped"
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

48
configs/zprofile Normal file
View File

@@ -0,0 +1,48 @@
# ============================================================================
# DarkForge Linux — User Shell Profile (~/.zprofile)
# ============================================================================
# Sourced on login to zsh. Auto-starts PipeWire and dwl on tty1.
# This file is installed to /home/danny/.zprofile during system installation.
# ============================================================================
# --- Environment variables for Wayland + NVIDIA ----------------------------
export XDG_SESSION_TYPE=wayland
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
export XDG_CONFIG_HOME="${HOME}/.config"
export XDG_CACHE_HOME="${HOME}/.cache"
export XDG_DATA_HOME="${HOME}/.local/share"
export XDG_STATE_HOME="${HOME}/.local/state"
# NVIDIA Wayland-specific environment
export GBM_BACKEND=nvidia-drm
export __GLX_VENDOR_LIBRARY_NAME=nvidia
export WLR_NO_HARDWARE_CURSORS=1
# WLR_NO_HARDWARE_CURSORS may be needed for wlroots + nvidia
# Remove if hardware cursors work correctly
export MOZ_ENABLE_WAYLAND=1
# Firefox: use Wayland backend
export QT_QPA_PLATFORM=wayland
# Qt applications: use Wayland backend
export SDL_VIDEODRIVER=wayland
# SDL2 games: prefer Wayland (falls back to X11 via XWayland)
# --- Ensure XDG runtime directory exists ------------------------------------
if [ ! -d "${XDG_RUNTIME_DIR}" ]; then
mkdir -p "${XDG_RUNTIME_DIR}"
chmod 700 "${XDG_RUNTIME_DIR}"
fi
# --- Auto-start Wayland compositor on tty1 ----------------------------------
if [ -z "${WAYLAND_DISPLAY}" ] && [ "$(tty)" = "/dev/tty1" ]; then
# Start PipeWire audio stack (runs as user, not system service)
pipewire &
pipewire-pulse &
wireplumber &
# Start the dwl Wayland compositor
# dwl will set WAYLAND_DISPLAY and become the session leader
exec dwl -s "foot" 2>/dev/null
fi