🔒 Repository is read-only – file editing is disabled.

PaganLinux/pagan-web-v2/rootfs.sh main

1052 linii Raw ← Powrót
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
#!/bin/bash
# =============================================================================
# build-pagan-rootfs.sh - Minimalny rootfs LFS + PAG/PAGBUILD (ROOTFS ONLY)
# =============================================================================
# Buduje minimalne środowisko LFS (Ch. 5 + 6) z pag i pagbuild do budowania
# pakietów. Bez BLFS, bez kernela, bez DE, bez IMG/ISO.
# =============================================================================

set -euo pipefail

# ========================= KONFIGURACJA =========================
# Absolutna ścieżka do katalogu skryptów – działa nawet po `cd /` w main()
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

PAGAN_ROOT="${PAGAN_ROOT:-/mnt/pagan-rootfs}"
PAGAN_VERSION="${PAGAN_VERSION:-0.0.1}"
BUILD_PROFILE="rootfs"
PAGAN_RELEASE="2026.07"
LFS_VERSION="13.0"

# Kernel
KERNEL_VERSION="${KERNEL_VERSION:-6.19.14}"
KERNEL_URL="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz"

# Hardware
MAKEFLAGS="-j$(nproc)"
LFS_TGT="$(uname -m)-pagan-linux-gnu"

# Ścieżki
SRC_DIR="$PAGAN_ROOT/sources"
TOOLS_DIR="$PAGAN_ROOT/tools"
CROSS_BIN="$TOOLS_DIR/bin"
OUTPUT_DIR="${OUTPUT_DIR:-/var/pagan-rootfs/output}"
mkdir -p "$OUTPUT_DIR"
# Wymuś pełne czyszczenie i budowę od zera: 1|true|yes
REBUILD_FROM_SCRATCH="${REBUILD_FROM_SCRATCH:-0}"

# ========================= SYSTEM LOGÓW =========================
: "${PAGAN_LOG_LEVEL:=0}"

LOG_FILE="/var/log/pagan-rootfs.log"
SUMMARY_FILE="/var/log/pagan-rootfs.summary.log"
mkdir -p "$(dirname "$LOG_FILE")"

cat > "$LOG_FILE" <<EOF
╔══════════════════════════════════════════════════════════════════╗
║  Pagan Linux Builder v${PAGAN_VERSION} – Log budowy
║  Start: $(date '+%Y-%m-%d %H:%M:%S')  |  CPU: $(nproc) rdzeni
╚══════════════════════════════════════════════════════════════════╝
EOF
echo "" > "$SUMMARY_FILE"

# ========================= KOLORY =========================
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; CYAN='\033[0;36m'
BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m'

# ========================= INTERFEJS UŻYTKOWNIKA =========================
source "$SCRIPT_DIR/ui.sh"
ui_init

# ========================= STATYSTYKI =========================
PKG_BUILT=0; PKG_FAILED=0; PKG_SKIPPED=0
RESUME_FILE="${RESUME_FILE:-/var/log/pagan-rootfs-build.done}"

_is_built() {
    local pkg="$1"
    [[ -f "$RESUME_FILE" ]] && grep -qxF "$pkg" "$RESUME_FILE" 2>/dev/null
}
_mark_built() {
    local pkg="$1"
    mkdir -p "$(dirname "$RESUME_FILE")"
    echo "$pkg" >> "$RESUME_FILE"
}

_is_true() {
    case "${1:-}" in
        1|true|TRUE|yes|YES|on|ON|y|Y) return 0 ;;
        *) return 1 ;;
    esac
}

clean_build_state() {
    step "Tryb: zbuduj od nowa"

    if [[ -z "$PAGAN_ROOT" || "$PAGAN_ROOT" == "/" ]]; then
        error "Niebezpieczny PAGAN_ROOT='$PAGAN_ROOT' - odmawiam czyszczenia"
    fi

    if declare -F umount_virtual_fs >/dev/null; then
        umount_virtual_fs >/dev/null 2>&1 || true
    fi

    warn "Czyszczenie katalogu builda: $PAGAN_ROOT"
    rm -rf --one-file-system "$PAGAN_ROOT"
    rm -f "$RESUME_FILE"

    mkdir -p "$PAGAN_ROOT" "$OUTPUT_DIR"
    ok "Wyczyszczono rootfs i stan resume; start od zera"
}

# ========================= FUNKCJE LOGOWANIA =========================
_log_raw() {
    local color="$1" lvl="$2" msg="$3"
    local ts; ts=$(date '+%H:%M:%S')
    echo -e "${color}[${ts}] [${lvl}]${NC} $msg"
    echo "[${ts}] [${lvl}] $msg" >> "$LOG_FILE"
}

dbg() { [[ $PAGAN_LOG_LEVEL -le 0 ]] && _log_raw "${DIM}" "DEBUG" "$*" || true; }
info() { [[ $PAGAN_LOG_LEVEL -le 1 ]] && _log_raw "${BLUE}" "INFO " "$*" || true; }
warn() { [[ $PAGAN_LOG_LEVEL -le 2 ]] && _log_raw "${YELLOW}" "WARN " "$*" >&2 || true; }
error() {
    _log_raw "${RED}" "ERROR" "$*" >&2
    _dump_stack
    _log_raw "${RED}" "FATAL" "Budowa przerwana. Log: $LOG_FILE" >&2
    exit 1
}
ok() {
    _log_raw "${GREEN}" "OK   " "$*"
    ((PKG_BUILT++)) || true
    echo "✓ $*" >> "$SUMMARY_FILE"
}

step() {
    local title="$*"
    echo ""
    echo -e "${MAGENTA}${BOLD}═══ ${title} ═══${NC}"
    echo "━━━ $(date '+%H:%M:%S') ━━━ ${title} ━━━" >> "$LOG_FILE"
    dbg "START: $title"
}

_dump_stack() {
    local frame=0
    echo "  Stack trace:" >> "$LOG_FILE"
    while caller $frame 2>/dev/null; do
        ((frame++))
    done >> "$LOG_FILE"
}

_on_error() {
    local lineno="$1" cmd="$2"
    echo -e "${RED}[ERROR]${NC} Linia ${lineno}: \"${cmd}\"" | tee -a "$LOG_FILE" >&2
    echo "[$(date '+%H:%M:%S')] [ERROR] Linia ${lineno}: ${cmd}" >> "$LOG_FILE"
    _dump_stack
}
trap '_on_error "${LINENO}" "${BASH_COMMAND}"' ERR

_show_summary() {
    # Best-effort cleanup: avoid stale mounts after cancel/error.
    if declare -F umount_virtual_fs >/dev/null; then
        umount_virtual_fs >/dev/null 2>&1 || true
    fi

    ui_summary
}
trap _show_summary EXIT

# ========================= BANNER =========================
show_banner() {
    cat << 'EOF'
╔═══════════════════════════════════════════════════════════════════╗
║                                                                   ║
║    ██████   █████   █████   █████  ███    ██                      ║
║    ██   ██ ██   ██ ██      ██   ██ ████   ██                      ║
║    ██████  ███████ ██████  ███████ ██ ██  ██                      ║
║    ██      ██   ██ ██   ██ ██   ██ ██  ██ ██                      ║
║    ██      ██   ██  █████  ██   ██ ██   ████                      ║
║                                                                   ║
║    ╔══════════════════════════════════════════════════════════╗    ║
EOF
    # Wiersze ze zmiennymi – padding liczony w locie, żeby ramka
    # zawsze się domykała (niezależnie od długości wersji/architektury).
    local pad entry
    for entry in \
        "  Pagan Linux Builder v${PAGAN_VERSION}" \
        "  LFS ${LFS_VERSION} + PAG/PAGBUILD (rootfs only)" \
        "  Architektura: $(uname -m)" \
        "  Data: $(date +'%Y-%m-%d %H:%M:%S')"; do
        pad=$(printf '%*s' "$((58 - ${#entry}))" "")
        printf '║    ║%s%s║    ║\n' "$entry" "$pad"
    done
    cat << 'EOF'
║    ╚══════════════════════════════════════════════════════════╝    ║
║                                                                   ║
╚═══════════════════════════════════════════════════════════════════╝
EOF
}

# ========================= SPRAWDZANIE ZALEŻNOŚCI HOST =========================
check_dependencies() {
    step "Sprawdzanie zależności systemowych hosta"
    
    local deps=(
        "gcc" "g++" "make" "bison" "flex" "texinfo"
        "wget" "curl" "tar" "xz" "bzip2" "gzip"
        "patch" "gawk" "sed" "grep" "find"
        "file" "diff" "cmp"
        "python3" "perl" "m4" "cmake"
        "git" "rsync" "cpio" "gpg" "pkg-config"
        "xorriso" "mkfs.fat" "parted" "mksquashfs"
        "ninja" "meson"
    )
    
    local missing=()
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &>/dev/null; then
            missing+=("$dep")
        fi
    done
    
    if [[ ${#missing[@]} -gt 0 ]]; then
        warn "Brakujące pakiety na hoście: ${missing[*]}"
        info "Instalowanie brakujących pakietów..."
        
        if command -v apt-get &>/dev/null; then
            apt-get update && apt-get install -y "${missing[@]}" \
                libncurses-dev libssl-dev libreadline-dev libxml2-dev libxslt1-dev \
                libxml-parser-perl libglib2.0-dev libgtk-3-dev libgtk-3-dev \
                libpango1.0-dev libcairo2-dev libgdk-pixbuf-2.0-dev \
                libdbus-1-dev libsystemd-dev libudev-dev libmnl-dev libevdev-dev \
                libacl1-dev libattr1-dev libpam0g-dev libgirepository1.0-dev \
                gobject-introspection libqt5svg5-dev qtbase5-dev qtdeclarative5-dev \
                qttools5-dev shared-mime-info intltool xsltproc gperf valac \
                gcc-multilib libc6-dev-i386 python3-pip python3-yaml
        elif command -v dnf &>/dev/null; then
            dnf install -y "${missing[@]}" python3-pip python3-pyyaml
        elif command -v pacman &>/dev/null; then
            pacman -Sy --noconfirm --needed base-devel python-pip python-yaml "${missing[@]}"
        else
            error "Nieznany menedżer pakietów hosta. Zainstaluj ręcznie: ${missing[*]}"
        fi
    fi
    
    ok "Wszystkie zależności hosta spełnione"
}

# ========================= LFS PATCH CHECK (BEST-EFFORT) =========================
check_lfs_patches() {
    step "Sprawdzanie dostępnych patchy LFS (best-effort)"

    local patch_index_url="https://www.linuxfromscratch.org/patches/lfs/${LFS_VERSION}/"
    local html
    if ! html=$(curl -fsSL --max-time 20 "$patch_index_url" 2>/dev/null); then
        warn "Nie udało się pobrać indeksu patchy LFS: $patch_index_url"
        warn "Pomijam check patchy (build będzie kontynuowany)."
        return 0
    fi

    local tracked=(
        "bash-5.2.37" "bzip2-1.0.8" "coreutils-9.5" "diffutils-3.10"
        "findutils-4.10.0" "glibc-2.44" "grep-3.11" "gzip-1.13"
        "make-4.4.1" "openssl-3.3.2" "python-3.12.5" "sed-4.9"
        "systemd-256.4" "tar-1.35" "util-linux-2.40.2"
    )

    local found=0
    for pkg in "${tracked[@]}"; do
        if echo "$html" | rg -qi "${pkg}.*\.patch"; then
            warn "LFS patch dostępny dla: $pkg"
            ((found++)) || true
        fi
    done

    if [[ $found -eq 0 ]]; then
        ok "Nie wykryto oczywistych patchy dla śledzonych pakietów LFS ${LFS_VERSION}"
    else
        warn "Wykryto $found potencjalnych patchy LFS. Rozważ integrację przed release build."
    fi
}

# ========================= INICJALIZACJA STRUKTURY =========================
init_build() {
    step "Inicjalizacja środowiska budowy PaganOS"
    cd /
    
    mkdir -p "$PAGAN_ROOT" "$SRC_DIR" "$TOOLS_DIR" "$OUTPUT_DIR"
    
    # Współdzielone źródła z głównego buildera (unikaj ponownego pobierania)
    local MAIN_SRC="/mnt/pagan/sources"
    if [[ -d "$MAIN_SRC" ]] && [[ "$SRC_DIR" != "$MAIN_SRC" ]]; then
        info "↻ Współdzielę źródła z $MAIN_SRC"
        rm -rf "$SRC_DIR"
        ln -sf "$MAIN_SRC" "$SRC_DIR"
    fi
    
    # Katalogi systemowe POSIX
    for dir in usr bin sbin lib lib64 etc var boot home root \
                opt tmp run mnt media srv; do
        mkdir -p "$PAGAN_ROOT/$dir"
    done
    mkdir -p "$PAGAN_ROOT/usr/bin" "$PAGAN_ROOT/usr/sbin"
    
    # Katalogi PaganOS Package Infrastructure
    mkdir -p "$PAGAN_ROOT/var/lib/pag"{,/packages,/snapshots}
    mkdir -p "$PAGAN_ROOT/var/cache/pag"
    mkdir -p "$PAGAN_ROOT/var/cache/pagbuild"{/sources,/output}
    mkdir -p "$PAGAN_ROOT/var/lib/pagan-build/rootfs"
    mkdir -p "$PAGAN_ROOT/var/lib/pagan-sync/recipes"
    mkdir -p "$PAGAN_ROOT/var/www/repo.paganlinux.eu"
    mkdir -p "$PAGAN_ROOT/opt/pagan"
    
    # Deploymenty dla atomic updates
    mkdir -p "$PAGAN_ROOT/.deployments"
    
    ok "Środowisko zainicjowane w: $PAGAN_ROOT"
}

_archive_is_valid() {
    local file="$1"
    [[ -s "$file" ]] || return 1

    case "$file" in
        *.tar.xz) xz -t "$file" >/dev/null 2>&1 ;;
        *.tar.gz|*.tgz) gzip -t "$file" >/dev/null 2>&1 ;;
        *.tar.bz2|*.tbz2) bzip2 -t "$file" >/dev/null 2>&1 ;;
        *.tar.zst)
            if command -v zstd >/dev/null 2>&1; then
                zstd -t "$file" >/dev/null 2>&1
            else
                unzstd -t "$file" >/dev/null 2>&1
            fi
            ;;
        *.tar) tar -tf "$file" >/dev/null 2>&1 ;;
        *.zip) unzip -tqq "$file" >/dev/null 2>&1 ;;
        *) ! file "$file" 2>/dev/null | grep -qE "HTML document|XML document|ASCII text|empty" ;;
    esac
}

download_pkg() {
    local url="$1" dest="$2" sha="${3:-SKIP}" force="${4:-0}"
    mkdir -p "$(dirname "$dest")"

    if [[ "$force" != "1" && -f "$dest" ]]; then
        if _archive_is_valid "$dest"; then
            info "  ⏭ $(basename "$dest") – już pobrany"
            return 0
        fi
        warn "Uszkodzone archiwum: $(basename "$dest") – pobieram ponownie"
        rm -f "$dest"
    fi

    wget --no-check-certificate -q --show-progress -O "$dest" "$url" 2>/dev/null || \
        curl -# -L -o "$dest" "$url" 2>/dev/null || \
        error "Nie udało się pobrać: $url"

    if ! _archive_is_valid "$dest"; then
        warn "Pobrano stronę HTML zamiast archiwum – próbuję mirror..."
        case "$url" in
            *download.savannah.gnu.org*)
                local alt_url
                alt_url=$(echo "$url" | sed 's|https://download.savannah.gnu.org|https://mirror.rabisu.com/mirrors/savannah|')
                wget --no-check-certificate -q --show-progress -O "$dest" "$alt_url" 2>/dev/null || \
                    curl -# -L -o "$dest" "$alt_url" 2>/dev/null || \
                    error "Nie udało się pobrać (mirror): $alt_url"
                _archive_is_valid "$dest" || error "Pobrany plik jest uszkodzony: $alt_url"
                ;;
            *) error "Pobrano uszkodzony plik z: $url" ;;
        esac
    fi

    info "  ✓ $(basename "$dest")"
}

build_lfs_pkg() {
    local pkg_name="$1" pkg_version="$2" pkg_url="$3" pkg_sha="$4" pkg_config="$5"
    local archive; archive=$(basename "$pkg_url" | sed 's/?.*//')
    local archive_path="$SRC_DIR/$archive"
    local pkg_dir="$SRC_DIR/build-${pkg_name}"
    
    ((UI_PKG_N++)) || true
    
    if _is_built "${pkg_name}-${pkg_version}"; then
        ui_skip "${pkg_name}-${pkg_version}"
        ((PKG_SKIPPED++)) || true
        return 0
    fi
    
    info "  Budowanie: ${pkg_name}-${pkg_version}"
    download_pkg "$pkg_url" "$archive_path" "$pkg_sha"
    
    rm -rf "$pkg_dir"
    mkdir -p "$pkg_dir"
    
    local _strip=""
    local _tar_first
    tar tf "$archive_path" > /tmp/_tar_first.tmp 2>/dev/null || true
    _tar_first=$(sed -n '1p' /tmp/_tar_first.tmp 2>/dev/null)
    rm -f /tmp/_tar_first.tmp
    if [[ "$_tar_first" == *"/"* ]]; then _strip="--strip-components=1"; fi
    
    case "$archive" in
        *.tar.xz|*.tar.gz|*.tar.bz2) tar -xf "$archive_path" -C "$pkg_dir" $_strip ;;
        *.tar.zst) unzstd -d "$archive_path" -o "$SRC_DIR/${archive%.zst}" && tar -xf "$SRC_DIR/${archive%.zst}" -C "$pkg_dir" $_strip ;;
        *) tar -xf "$archive_path" -C "$pkg_dir" $_strip ;;
    esac || {
        warn "Rozpakowanie $pkg_name nieudane – wymuszam ponowne pobranie i retry"
        rm -f "$archive_path" "$SRC_DIR/${archive%.zst}"
        download_pkg "$pkg_url" "$archive_path" "$pkg_sha" 1
        case "$archive" in
            *.tar.xz|*.tar.gz|*.tar.bz2) tar -xf "$archive_path" -C "$pkg_dir" $_strip ;;
            *.tar.zst) unzstd -d "$archive_path" -o "$SRC_DIR/${archive%.zst}" && tar -xf "$SRC_DIR/${archive%.zst}" -C "$pkg_dir" $_strip ;;
            *) tar -xf "$archive_path" -C "$pkg_dir" $_strip ;;
        esac || error "Rozpakowanie $pkg_name nieudane"
    }
    
    pushd "$pkg_dir" > /dev/null
    
    local pkg_log="$UI_LOG_DIR/${pkg_name}-${pkg_version}.log"
    
    if [[ -n "$pkg_config" && "$pkg_config" != "SKIP" ]]; then
        ui_build_eval "${pkg_name}-${pkg_version}" "$pkg_log" "$pkg_config" \
            || error "Configure failed for $pkg_name (log: $pkg_log)"
    fi
    
    local _skip_auto_make=0
    case "$pkg_config" in
        *"cp -"*|*"cp "*|*"make install"*|*"DESTDIR="*|*"ninja"*|*"pip3"*|*"pip install"*|*"cmake --install"*|*"./bootstrap"*|*"install -m"*|*"PREFIX="*) _skip_auto_make=1 ;;
        make*) _skip_auto_make=1 ;;
    esac
    
    if [[ $_skip_auto_make -eq 0 ]]; then
        ui_build_eval "${pkg_name}-${pkg_version} (make)" "$pkg_log" "make $MAKEFLAGS && make install" \
            || error "Make/Install failed for $pkg_name (log: $pkg_log)"
    fi
    
    popd > /dev/null
    rm -rf "$pkg_dir"

    # Remove .la files (libtool archives) – hardcoded host paths break later links
    find "$PAGAN_ROOT/usr/lib" -name "*.la" -delete 2>/dev/null || true

    # Fix .pc files: rewrite prefix paths so pkg-config sees target sysroot
    for pc in "$PAGAN_ROOT/usr/lib/pkgconfig/"*.pc "$PAGAN_ROOT/usr/share/pkgconfig/"*.pc; do
        if [[ -f "$pc" ]]; then
            sed -i 's|^prefix=/usr$|prefix='"$PAGAN_ROOT"'/usr|' "$pc"
            sed -i '/^Cflags:/ { s/ -I\${includedir} / /g; s/^-I\${includedir} //; s/ -I\${includedir}$// }' "$pc"
        fi
    done 2>/dev/null || true
    
    _mark_built "${pkg_name}-${pkg_version}"
    ok "  ✅ Zbudowano: $pkg_name-$pkg_version"
}

# ========================= TOOLCHAIN (Ch. 5) =========================
build_toolchain() {
    step "ROZDZIAŁ 5: BUDOWA TOOLCHAIN"
    ui_set_total 7
    export LC_ALL=POSIX
    export LFS="$PAGAN_ROOT"
    export LFS_TGT="$LFS_TGT"
    
    build_lfs_pkg "linux-headers-tc" "$KERNEL_VERSION" "$KERNEL_URL" "SKIP" \
        "make mrproper && make headers && find usr/include -type f ! -name '*.h' -delete && cp -rv usr/include $PAGAN_ROOT/usr"
    
    build_lfs_pkg "gmp-tc" "6.3.0" "https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz" "SKIP" \
        "CFLAGS='-std=gnu89 -O2' ./configure --prefix=$TOOLS_DIR --enable-cxx --disable-shared --enable-static && make CFLAGS='-O2' $MAKEFLAGS && make install"
    
    build_lfs_pkg "mpfr-tc" "4.2.1" "https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.1.tar.xz" "SKIP" \
        "CFLAGS='-std=gnu89 -O2' ./configure --prefix=$TOOLS_DIR --disable-shared --enable-static --with-gmp=$TOOLS_DIR && make CFLAGS='-O2' $MAKEFLAGS && make install"
    
    build_lfs_pkg "mpc-tc" "1.3.1" "https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz" "SKIP" \
        "CFLAGS='-std=gnu89 -O2' ./configure --prefix=$TOOLS_DIR --disable-shared --enable-static --with-gmp=$TOOLS_DIR --with-mpfr=$TOOLS_DIR && make CFLAGS='-O2' $MAKEFLAGS && make install"
    
    export PATH="$TOOLS_DIR/bin:$PATH"
    
    build_lfs_pkg "binutils-pass1" "2.43.1" "https://ftp.gnu.org/gnu/binutils/binutils-2.43.1.tar.xz" "SKIP" \
        "mkdir -v build && cd build && ../configure --prefix=$TOOLS_DIR --with-sysroot=$PAGAN_ROOT --target=$LFS_TGT --disable-nls --enable-gprofng=no --disable-werror --disable-dependency-tracking && make $MAKEFLAGS && make install"
    
    build_lfs_pkg "gcc-pass1" "14.2.0" "https://ftp.gnu.org/gnu/gcc/gcc-14.2.0/gcc-14.2.0.tar.xz" "SKIP" \
        'case $(uname -m) in x86_64) sed -e "/m64=/s/lib64/lib/" -i.orig gcc/config/i386/t-linux64 ;; esac; sed -i "s/__cplusplus != 201103/__cplusplus < 201103/g; s/__cplusplus > 201103/__cplusplus < 201103/g" libcody/configure 2>/dev/null || true; sed -i "/^#include \"safe-ctype.h\"/i #ifdef __cplusplus\n#include <cctype>\n#endif" gcc/system.h 2>/dev/null || true; sed -i "/^#include \"safe-ctype.h\"/a #ifdef __cplusplus\n#undef isalpha\n#undef isalnum\n#undef iscntrl\n#undef isdigit\n#undef isgraph\n#undef islower\n#undef isprint\n#undef ispunct\n#undef isspace\n#undef isupper\n#undef isxdigit\n#undef toupper\n#undef tolower\n#endif" gcc/system.h 2>/dev/null || true; mkdir -v build && cd build && ../configure --target='"$LFS_TGT"' --prefix='"$TOOLS_DIR"' --with-gmp='"$TOOLS_DIR"' --with-mpfr='"$TOOLS_DIR"' --with-mpc='"$TOOLS_DIR"' --with-glibc-version=2.44 --with-sysroot='"$PAGAN_ROOT"' --with-newlib --without-headers --enable-default-pie --enable-default-ssp --disable-nls --disable-shared --disable-multilib --disable-threads --disable-libatomic --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libstdcxx --enable-languages=c,c++ --enable-werror=no CXXFLAGS="-std=gnu++20 -O2 -Wno-error=return-type -fno-char8_t -Wno-deprecated-enum-enum-conversion" && make '"$MAKEFLAGS"' && make install && cd .. && ln -sf '"$LFS_TGT"'-gcc '"$CROSS_BIN"'/cc'
    
    build_lfs_pkg "glibc-tc" "2.44" "https://ftp.gnu.org/gnu/glibc/glibc-2.44.tar.xz" "SKIP" \
        "rm -rf $PAGAN_ROOT/usr/include/gnu $PAGAN_ROOT/usr/include/features.h $PAGAN_ROOT/usr/include/stdc-predef.h 2>/dev/null; mkdir -v build && cd build && ../configure --prefix=/usr --host=$LFS_TGT --build=\$(../scripts/config.guess) --enable-kernel=4.14 --with-headers=$PAGAN_ROOT/usr/include libc_cv_slibdir=/usr/lib --disable-werror CFLAGS=\"-O2 -Wno-error=maybe-uninitialized\" && make $MAKEFLAGS && make DESTDIR=$PAGAN_ROOT install"
    
    ok "Toolchain zbudowany!"
}

# ========================= PEŁNY SYSTEM KOŃCOWY (Ch. 6) =========================
build_final_system() {
    step "ROZDZIAŁ 6-8: PEŁNY SYSTEM KOŃCOWY LFS 13.0"

    export PATH="$TOOLS_DIR/bin:/usr/bin/core_perl:/usr/bin/vendor_perl:$PATH"
    export LC_ALL=POSIX

    # Globalna kompatybilność z GCC 16
    export CFLAGS="-std=gnu17 -O2 -Wno-error=implicit-function-declaration -Wno-error=int-conversion -Wno-error=return-type -Wno-error=maybe-uninitialized -Wno-error=discarded-qualifiers -Wno-error=unterminated-string-initialization -Wno-error=incompatible-pointer-types -Wno-error=null-dereference -Wno-error=override-init"
    export CXXFLAGS="-O2 -Wno-error=return-type -Wno-error=maybe-uninitialized"
    export FORCE_UNSAFE_CONFIGURE=1
    export PKG_CONFIG_DIR=""
    export PKG_CONFIG_PATH="$PAGAN_ROOT/usr/lib/pkgconfig:$PAGAN_ROOT/usr/lib/x86_64-linux-gnu/pkgconfig:$PAGAN_ROOT/usr/share/pkgconfig"
    export PKG_CONFIG_SYSROOT_DIR="$PAGAN_ROOT"
    export PKG_CONFIG_LIBDIR="$PAGAN_ROOT/usr/lib/pkgconfig:$PAGAN_ROOT/usr/lib/x86_64-linux-gnu/pkgconfig:$PAGAN_ROOT/usr/share/pkgconfig"
    # Linkuj z targetowymi libami (glibc 2.44, zgodne z hostem)
    # UWAGA: brak globalnego CPPFLAGS=-I$PAGAN_ROOT/usr/include — glibc budując sam siebie
    # nie może mieć -I na zainstalowane headery glibc (guard _LIBC w gnu/stubs-64.h)
    export LDFLAGS="-L$PAGAN_ROOT/usr/lib -L$PAGAN_ROOT/lib64 -Wl,-rpath-link,$PAGAN_ROOT/usr/lib -Wl,-rpath-link,$PAGAN_ROOT/lib64"

    local packages=(
        "man-pages:6.17:https://www.kernel.org/pub/linux/docs/man-pages/man-pages-6.17.tar.xz:SKIP:make -R prefix=/usr install"
        "iana-etc:20260202:https://github.com/Mic92/iana-etc/releases/download/20260202/iana-etc-20260202.tar.gz:SKIP:cp services protocols \$PAGAN_ROOT/etc"
        "tzdata:2025c:https://www.iana.org/time-zones/repository/releases/tzdata2025c.tar.gz:SKIP:ZONEINFO=\$PAGAN_ROOT/usr/share/zoneinfo && mkdir -p \$ZONEINFO && cp -r ./* \$ZONEINFO/"
        "glibc:2.44:https://ftp.gnu.org/gnu/glibc/glibc-2.44.tar.xz:SKIP:mkdir bld && cd bld && ../configure --prefix=/usr --enable-kernel=4.14 --enable-stack-protector=strong libc_cv_slibdir=/usr/lib --disable-werror CFLAGS=\"-O2 -Wno-error=maybe-uninitialized\" && make && make install DESTDIR=\$PAGAN_ROOT && mkdir -p \$PAGAN_ROOT/lib64 && ln -sf ../usr/lib/ld-linux-x86-64.so.2 \$PAGAN_ROOT/lib64/ld-linux-x86-64.so.2"
        "zlib:1.3.2:https://zlib.net/fossils/zlib-1.3.2.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "bzip2:1.0.8:https://www.sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz:SKIP:CC=gcc make -f Makefile-libbz2_so && CC=gcc make install PREFIX=\$PAGAN_ROOT/usr"
        "xz:5.8.2:https://github.com/tukaani-project/xz/releases/download/v5.8.2/xz-5.8.2.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "zstd:1.5.7:https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz:SKIP:CC=gcc make prefix=/usr && CC=gcc make prefix=/usr DESTDIR=\$PAGAN_ROOT install"
        "lz4:1.10.0:https://github.com/lz4/lz4/releases/download/v1.10.0/lz4-1.10.0.tar.gz:SKIP:CC=gcc make && CC=gcc make PREFIX=/usr DESTDIR=\$PAGAN_ROOT install"
        "readline:8.3:https://ftp.gnu.org/gnu/readline/readline-8.3.tar.gz:SKIP:./configure --prefix=/usr --disable-static --with-curses && make SHLIB_LIBS=-lncurses && make install DESTDIR=\$PAGAN_ROOT"
        "gmp:6.3.0:https://ftp.gnu.org/gnu/gmp/gmp-6.3.0.tar.xz:SKIP:./configure --prefix=/usr --enable-cxx --disable-static CFLAGS=\"-O2 -std=gnu89\" && make CFLAGS=\"-O2\" && make install DESTDIR=\$PAGAN_ROOT"
        "mpfr:4.2.2:https://ftp.gnu.org/gnu/mpfr/mpfr-4.2.2.tar.xz:SKIP:./configure --prefix=/usr --disable-static --enable-thread-safe && make && make install DESTDIR=\$PAGAN_ROOT"
        "mpc:1.3.1:https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz:SKIP:./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        "gcc:15.2.0:https://ftp.gnu.org/gnu/gcc/gcc-15.2.0/gcc-15.2.0.tar.xz:SKIP:sed -i 's/__cplusplus != 201103/__cplusplus < 201103/g; s/__cplusplus > 201103/__cplusplus < 201103/g' libcody/configure 2>/dev/null || true; mkdir build && cd build && ../configure --prefix=/usr --enable-languages=c,c++,fortran --enable-default-pie --enable-default-ssp --disable-multilib --disable-bootstrap --with-system-zlib --without-isl CXXFLAGS='-O2 -fno-char8_t' --disable-libsanitizer && make \$MAKEFLAGS && make DESTDIR=\$PAGAN_ROOT install && ln -sf gcc \$PAGAN_ROOT/usr/bin/cc"
        "attr:2.5.2:https://download.savannah.gnu.org/releases/attr/attr-2.5.2.tar.gz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        "acl:2.3.2:https://download.savannah.gnu.org/releases/acl/acl-2.3.2.tar.xz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        "libcap:2.77:https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-2.77.tar.xz:SKIP:CC=gcc make prefix=/usr lib=lib && CC=gcc make prefix=/usr lib=lib DESTDIR=\$PAGAN_ROOT install"
        "libxcrypt:4.5.2:https://github.com/besser82/libxcrypt/releases/download/v4.5.2/libxcrypt-4.5.2.tar.xz:SKIP:./configure --prefix=/usr --enable-hashes=strong,glibc --disable-static CFLAGS=\"-O2 -Wno-error=discarded-qualifiers -Wno-error=unterminated-string-initialization\" && make && make install DESTDIR=\$PAGAN_ROOT"
        "pcre2:10.47:https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.bz2:SKIP:./configure --prefix=/usr --enable-unicode --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        "elfutils:0.194:https://sourceware.org/ftp/elfutils/0.194/elfutils-0.194.tar.bz2:SKIP:./configure --prefix=/usr --disable-debuginfod --disable-libdebuginfod --disable-werror && make && make -C libelf install DESTDIR=\$PAGAN_ROOT"
        "libffi:3.5.2:https://github.com/libffi/libffi/releases/download/v3.5.2/libffi-3.5.2.tar.gz:SKIP:./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        "file:5.46:https://astron.com/pub/file/file-5.46.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "m4:1.4.21:https://ftp.gnu.org/gnu/m4/m4-1.4.21.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "bc:7.0.3:https://github.com/gavinhoward/bc/releases/download/7.0.3/bc-7.0.3.tar.xz:SKIP:CC=gcc CFLAGS=\"-std=c99 -O2\" ./configure --prefix=/usr -G -O3 && make && make install DESTDIR=\$PAGAN_ROOT"
        "flex:2.6.4:https://github.com/westes/flex/releases/download/v2.6.4/flex-2.6.4.tar.gz:SKIP:./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT && ln -sf flex \$PAGAN_ROOT/usr/bin/lex"
        "bison:3.8.2:https://ftp.gnu.org/gnu/bison/bison-3.8.2.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "autoconf:2.72:https://ftp.gnu.org/gnu/autoconf/autoconf-2.72.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "automake:1.18.1:https://ftp.gnu.org/gnu/automake/automake-1.18.1.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "libtool:2.5.4:https://ftp.gnu.org/gnu/libtool/libtool-2.5.4.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "expat:2.7.4:https://github.com/libexpat/libexpat/releases/download/R_2_7_4/expat-2.7.4.tar.xz:SKIP:./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        # libxml2 – potrzebny gettextowi (msgfmt) i pakietom zależnym; soname libxml2.so.16 (od 2.15)
        "libxml2:2.15.3:https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.3.tar.xz:SKIP:CC=gcc ./configure --prefix=/usr --without-python --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
        # libunistring + libidn2 – runtime dep cmake (libidn2.so.0)
        "libunistring:1.2:https://mirrors.kernel.org/gnu/libunistring/libunistring-1.2.tar.xz:SKIP:CC=gcc ./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT && rm -f \$PAGAN_ROOT/usr/lib/libunistring.la"
        "libidn2:2.3.7:https://mirrors.kernel.org/gnu/libidn/libidn2-2.3.7.tar.gz:SKIP:CC=gcc ./configure --prefix=/usr --disable-static --disable-doc --with-libunistring-prefix=\$PAGAN_ROOT/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "gettext:0.22.5:https://ftp.gnu.org/gnu/gettext/gettext-0.22.5.tar.xz:SKIP:./configure --prefix=/usr --disable-static --disable-acl && make && make install DESTDIR=\$PAGAN_ROOT"
        "ncurses:6.6:https://invisible-mirror.net/archives/ncurses/ncurses-6.6.tar.gz:SKIP:./configure --prefix=/usr --with-shared --without-debug --without-normal --enable-widec && make && make install DESTDIR=\$PAGAN_ROOT && for lib in ncurses form panel menu; do ln -sfv lib\${lib}w.so \$PAGAN_ROOT/usr/lib/lib\${lib}.so 2>/dev/null; done && ln -sfv libncursesw.so \$PAGAN_ROOT/usr/lib/libtinfo.so 2>/dev/null"
        "bash:5.3:https://ftp.gnu.org/gnu/bash/bash-5.3.tar.gz:SKIP:./configure --prefix=/usr --without-bash-malloc --with-installed-readline && make && make install DESTDIR=\$PAGAN_ROOT && ln -sf /usr/bin/bash \$PAGAN_ROOT/bin/sh && ln -sf /usr/bin/bash \$PAGAN_ROOT/bin/bash"
        "coreutils:9.10:https://ftp.gnu.org/gnu/coreutils/coreutils-9.10.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "diffutils:3.12:https://ftp.gnu.org/gnu/diffutils/diffutils-3.12.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "findutils:4.10.0:https://ftp.gnu.org/gnu/findutils/findutils-4.10.0.tar.xz:SKIP:./configure --prefix=/usr --localstatedir=/var/lib/locate && make && make install DESTDIR=\$PAGAN_ROOT"
        "gawk:5.3.2:https://ftp.gnu.org/gnu/gawk/gawk-5.3.2.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "grep:3.12:https://ftp.gnu.org/gnu/grep/grep-3.12.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "gzip:1.14:https://ftp.gnu.org/gnu/gzip/gzip-1.14.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "make:4.4.1:https://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "patch:2.8:https://ftp.gnu.org/gnu/patch/patch-2.8.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "sed:4.9:https://ftp.gnu.org/gnu/sed/sed-4.9.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "tar:1.35:https://ftp.gnu.org/gnu/tar/tar-1.35.tar.xz:SKIP:sed -i 's/acl_get_file_at/tar_acl_get_file_at/g; s/acl_set_file_at/tar_acl_set_file_at/g; s/acl_delete_def_file_at/tar_acl_delete_def_file_at/g' src/xattrs.c && ./configure --prefix=/usr --without-posix-acls && make && make install DESTDIR=\$PAGAN_ROOT"
        "openssl:3.6.1:https://github.com/openssl/openssl/releases/download/openssl-3.6.1/openssl-3.6.1.tar.gz:SKIP:./Configure --prefix=/usr --openssldir=/etc/ssl --libdir=lib shared zlib-dynamic && make && make install DESTDIR=\$PAGAN_ROOT"
        "libbsd:0.12.2:https://libbsd.freedesktop.org/releases/libbsd-0.12.2.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "shadow:4.19.3:https://github.com/shadow-maint/shadow/releases/download/4.19.3/shadow-4.19.3.tar.xz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --with-group-name-max-length=32 && make && make install DESTDIR=\$PAGAN_ROOT"
        "util-linux:2.41.3:https://www.kernel.org/pub/linux/utils/util-linux/v2.41/util-linux-2.41.3.tar.xz:SKIP:./configure --bindir=/usr/bin --libdir=/usr/lib --sbindir=/usr/sbin --disable-chfn-chsh --disable-login --disable-nologin --disable-su --disable-runuser --disable-pylibmount --disable-liblastlog2 --without-python --without-systemd && make && make install DESTDIR=\$PAGAN_ROOT"
        "e2fsprogs:1.47.3:https://downloads.sourceforge.net/project/e2fsprogs/e2fsprogs/v1.47.3/e2fsprogs-1.47.3.tar.gz:SKIP:mkdir bld && cd bld && ../configure --prefix=/usr --sysconfdir=/etc --enable-elf-shlibs --disable-fuse2fs && make && make install DESTDIR=\$PAGAN_ROOT"
        "procps-ng:4.0.6:https://sourceforge.net/projects/procps-ng/files/Production/procps-ng-4.0.6.tar.xz:SKIP:./configure --prefix=/usr --disable-static --disable-kill --without-ncurses && make && make install DESTDIR=\$PAGAN_ROOT"
        "kmod:34.2:https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-34.2.tar.xz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --disable-manpages --with-openssl --with-xz --with-zstd --with-zlib && make && make install DESTDIR=\$PAGAN_ROOT"
        "grub:2.14:https://ftp.gnu.org/gnu/grub/grub-2.14.tar.xz:SKIP:touch grub-core/extra_deps.lst && ./configure --prefix=/usr --sysconfdir=/etc --disable-werror --with-platform=efi && make && make install DESTDIR=\$PAGAN_ROOT"
        "sqlite:3510200:https://sqlite.org/2026/sqlite-autoconf-3510200.tar.gz:SKIP:CC=gcc ./configure --prefix=/usr --disable-static --enable-fts5 && make && make install DESTDIR=\$PAGAN_ROOT"
        "gdbm:1.26:https://ftp.gnu.org/gnu/gdbm/gdbm-1.26.tar.gz:SKIP:./configure --prefix=/usr --disable-static --enable-libgdbm-compat && make && make install DESTDIR=\$PAGAN_ROOT"
        "gperf:3.3:https://ftp.gnu.org/gnu/gperf/gperf-3.3.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "texinfo:7.2:https://ftp.gnu.org/gnu/texinfo/texinfo-7.2.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "less:692:https://www.greenwoodsoftware.com/less/less-692.tar.gz:SKIP:./configure --prefix=/usr --sysconfdir=/etc && make && make install DESTDIR=\$PAGAN_ROOT"
        "libpipeline:1.5.8:https://download.savannah.gnu.org/releases/libpipeline/libpipeline-1.5.8.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "man-db:2.13.1:https://download.savannah.gnu.org/releases/man-db/man-db-2.13.1.tar.xz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --disable-setuid && make && make install DESTDIR=\$PAGAN_ROOT"
        "psmisc:23.7:https://sourceforge.net/projects/psmisc/files/psmisc/psmisc-23.7.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "vim:9.2.0078:https://github.com/vim/vim/archive/v9.2.0078/vim-9.2.0078.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT && ln -sf vim \$PAGAN_ROOT/usr/bin/vi"
        "kbd:2.9.0:https://www.kernel.org/pub/linux/utils/kbd/kbd-2.9.0.tar.xz:SKIP:./configure --prefix=/usr --disable-vlock && make && make install DESTDIR=\$PAGAN_ROOT"
        "inetutils:2.7:https://ftp.gnu.org/gnu/inetutils/inetutils-2.7.tar.gz:SKIP:./configure --prefix=/usr --disable-logger --disable-whois --disable-servers && make && make install DESTDIR=\$PAGAN_ROOT"
        "iproute2:6.18.0:https://www.kernel.org/pub/linux/utils/net/iproute2/iproute2-6.18.0.tar.xz:SKIP:sed -i /ARPD/d Makefile && make && make DESTDIR=\$PAGAN_ROOT SBINDIR=/usr/sbin install"
        "intltool:0.51.0:https://deb.debian.org/debian/pool/main/i/intltool/intltool_0.51.0.orig.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "groff:1.23.0:https://ftp.gnu.org/gnu/groff/groff-1.23.0.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "sysklogd:2.7.2:https://github.com/troglobit/sysklogd/releases/download/v2.7.2/sysklogd-2.7.2.tar.gz:SKIP:./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var && make && make install DESTDIR=\$PAGAN_ROOT"
        "tcl:8.6.17:https://downloads.sourceforge.net/tcl/tcl8.6.17-src.tar.gz:SKIP:cd unix && ./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "perl:5.42.0:https://www.cpan.org/src/5.0/perl-5.42.0.tar.xz:SKIP:sh Configure -des -Dcc=gcc -Dprefix=/usr -Duseshrplib && make && make install DESTDIR=\$PAGAN_ROOT"
        "python:3.14.3:https://www.python.org/ftp/python/3.14.3/Python-3.14.3.tar.xz:SKIP:sed -i 's|^@MODULE__CRYPT_TRUE@_crypt|#_crypt|' Modules/Setup.stdlib.in && ac_cv_lib_crypt_crypt_r=no ac_cv_func_crypt_r=no ./configure --prefix=/usr --enable-shared && make && make install DESTDIR=\$PAGAN_ROOT"
        "ninja:1.13.2:https://github.com/ninja-build/ninja/archive/v1.13.2/ninja-1.13.2.tar.gz:SKIP:python3 configure.py --bootstrap && install -m755 ninja \$PAGAN_ROOT/usr/bin/"
        "meson:1.10.1:https://github.com/mesonbuild/meson/releases/download/1.10.1/meson-1.10.1.tar.gz:SKIP:pip3 wheel -w dist --no-build-isolation --no-deps \$PWD && pip3 install --no-index --find-links dist --root=\$PAGAN_ROOT meson"
        "cmake:3.31.6:https://github.com/Kitware/CMake/releases/download/v3.31.6/cmake-3.31.6.tar.gz:SKIP:CC=gcc CXX=g++ CFLAGS= CXXFLAGS= cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF && cmake --build build \$MAKEFLAGS && DESTDIR=\$PAGAN_ROOT cmake --install build"
        "git:2.47.2:https://www.kernel.org/pub/software/scm/git/git-2.47.2.tar.xz:SKIP:./configure --prefix=/usr --with-openssl --with-curl --with-expat && make && make install DESTDIR=\$PAGAN_ROOT"
        # ======== SYSTEMD / DBUS / UDEV ========
        "binutils:2.46.0:https://sourceware.org/pub/binutils/releases/binutils-2.46.0.tar.xz:SKIP:mkdir build && cd build && ../configure --prefix=/usr --sysconfdir=/etc --enable-lto --enable-gold --enable-ld=default --enable-plugins --enable-shared --disable-werror && make && make install DESTDIR=\$PAGAN_ROOT && cd .."
        # ======== DEJAGNU + TCL/EXPECT ========
        "dejagnu:1.6.3:https://ftp.gnu.org/gnu/dejagnu/dejagnu-1.6.3.tar.gz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
        "expect:5.45.4:https://prdownloads.sourceforge.net/expect/expect5.45.4.tar.gz:SKIP:cp -f pty_termios.c pty_.c 2>/dev/null || true; echo '#include \"exp_tty.h\"' > exp_tty_hack.h; for f in exp_inter.c exp_main_sub.c exp_command.c; do sed -i '1i#include \"exp_tty_hack.h\"' \"\$f\" 2>/dev/null || true; done; ./configure --prefix=/usr --with-tcl=/usr/lib --enable-shared 2>/dev/null && make 2>/dev/null && make install DESTDIR=\$PAGAN_ROOT 2>/dev/null || true"
        # ======== SYSTEMD / DBUS / UDEV ========
        "dbus:1.16.2:https://dbus.freedesktop.org/releases/dbus/dbus-1.16.2.tar.xz:SKIP:CC=gcc CXX=g++ cmake -B build -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc -DCMAKE_INSTALL_LOCALSTATEDIR=/var -DDBUS_SYSTEMD_USER_SERVICE_DIR=/usr/lib/systemd/user -DDBUS_BUILD_TESTS=OFF && make -C build && make -C build DESTDIR=\$PAGAN_ROOT install"
        "udev-lfs:20230818:https://anduin.linuxfromscratch.org/LFS/udev-lfs-20230818.tar.xz:SKIP:mkdir -p udev-lfs-20230818 2>/dev/null; find . -maxdepth 1 -type f -exec cp {} udev-lfs-20230818/ \\; 2>/dev/null; make -f Makefile.lfs DESTDIR=\$PAGAN_ROOT install"
        "keyutils:1.6.3:https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/keyutils.git/snapshot/keyutils-1.6.3.tar.gz:SKIP:make NO_ARLIB=1 NO_SOLIB_DEP=1 BINDIR=/usr/bin SBINDIR=/usr/sbin LIBDIR=/usr/lib && make NO_ARLIB=1 NO_SOLIB_DEP=1 BINDIR=/usr/bin SBINDIR=/usr/sbin LIBDIR=/usr/lib DESTDIR=\$PAGAN_ROOT install"
        "systemd:259.1:https://github.com/systemd/systemd/archive/v259.1.tar.gz:SKIP:CFLAGS=\"\$CFLAGS -Wno-error=redundant-decls\" CXXFLAGS=\"\$CXXFLAGS -Wno-error=redundant-decls\" CC=gcc CXX=g++ meson setup build --prefix=/usr --sysconfdir=/etc --localstatedir=/var -Dmode=release -Dman=disabled -Ddefault-dnssec=no -Dwerror=false && ninja -C build && DESTDIR=\$PAGAN_ROOT ninja -C build install 2>/dev/null || true"
        "pkgconf:2.5.1:https://distfiles.ariadne.space/pkgconf/pkgconf-2.5.1.tar.xz:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT && ln -sf pkgconf \$PAGAN_ROOT/usr/bin/pkg-config"
        "sysvinit:3.14:https://github.com/slicer69/sysvinit/releases/download/3.14/sysvinit-3.14.tar.xz:SKIP:CC=gcc make -C src && make -C src DESTDIR=\$PAGAN_ROOT install"
        "XML-Parser:2.47:https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-2.47.tar.gz:SKIP:perl Makefile.PL && make && make install DESTDIR=\$PAGAN_ROOT"
    )

    ui_set_total "${#packages[@]}"
    for pkg_info in "${packages[@]}"; do
        name="${pkg_info%%:*}"; rest="${pkg_info#*:}"
        ver="${rest%%:*}"; rest="${rest#*:}"
        config="${rest##*:}"; rest_no_cfg="${rest%:*}"
        sha="${rest_no_cfg##*:}"
        url="${rest_no_cfg%:*}"
        build_lfs_pkg "$name" "$ver" "$url" "$sha" "$config"
    done

    _configure_basic_system
    ok "System końcowy zbudowany!"
}

_configure_basic_system() {
    cat > "$PAGAN_ROOT/etc/passwd" <<'EOF'
root:x:0:0:root:/root:/bin/bash
nobody:x:65534:65534:nobody:/:/bin/false
EOF
    cat > "$PAGAN_ROOT/etc/group" <<'EOF'
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
usb:x:14:
cdrom:x:15:
mail:x:34:
nogroup:x:65534:
EOF
    cat > "$PAGAN_ROOT/etc/fstab" <<'EOF'
/dev/sda1       /               ext4    defaults        0       1
proc            /proc           proc    nosuid,noexec,nodev 0       0
sysfs           /sys            sysfs   nosuid,noexec,nodev 0       0
devtmpfs        /dev            devtmpfs mode=0755,nosuid 0       0
tmpfs           /tmp            tmpfs   defaults        0       0
devpts          /dev/pts        devpts  gid=5,mode=620  0       0
shm             /dev/shm        tmpfs   defaults        0       0
EOF
}

# =============================================================================
# INSTALACJA STOSU PAGAN OS (PAG, PAGBUILD, PAGSYNC) W ROOTFS
# =============================================================================
install_pagan_toolstack() {
    step "INSTALACJA STOSU PAGAN OS (pag, pagbuild, pagbuild-sync)"

    info "1. Instalowanie modułów Pythona (PyYAML, Jinja2, Requests) w chroocie..."
    chroot "$PAGAN_ROOT" pip3 install flit-core packaging markupsafe jinja2 setuptools wheel pyyaml requests --break-system-packages 2>/dev/null || true

    # -------------------------------------------------------------------------
    # A. Menedżer Pakietów: /usr/bin/pag (pełna wersja)
    # -------------------------------------------------------------------------
    info "2. Kopiowanie pełnego pag..."
    cp "$SCRIPT_DIR/pag/pag" "$PAGAN_ROOT/usr/bin/pag"
    chmod +x "$PAGAN_ROOT/usr/bin/pag"

    # -------------------------------------------------------------------------
    # A2. Kompilator Go – /usr/lib/go + symlinki /usr/bin/{go,gofmt}
    # -------------------------------------------------------------------------
    info "2b. Instalowanie Go..."
    GO_VER="${GO_VER:-1.26.5}"
    GO_TARBALL="go${GO_VER}.linux-amd64.tar.gz"
    if [[ ! -d "$PAGAN_ROOT/usr/lib/go" ]]; then
        curl -fsSL -o "/tmp/$GO_TARBALL" "https://go.dev/dl/$GO_TARBALL" \
            && mkdir -p "$PAGAN_ROOT/usr/lib" \
            && tar -xzf "/tmp/$GO_TARBALL" -C "$PAGAN_ROOT/usr/lib/" \
            && rm -f "/tmp/$GO_TARBALL"
    fi
    [[ -x "$PAGAN_ROOT/usr/lib/go/bin/go" ]] \
        && ln -sf /usr/lib/go/bin/go "$PAGAN_ROOT/usr/bin/go" \
        && ln -sf /usr/lib/go/bin/gofmt "$PAGAN_ROOT/usr/bin/gofmt" \
        && ok "Go ${GO_VER} zainstalowany" || warn "Go: instalacja nieudana (pominięto)"

    # -------------------------------------------------------------------------
    # B. Builder w Chroot: /usr/bin/pagbuild
    # -------------------------------------------------------------------------
    info "3. Tworzenie narzędzia /usr/bin/pagbuild..."
    cat > "$PAGAN_ROOT/usr/bin/pagbuild" <<'PAGBUILD_BIN'
#!/usr/bin/env bash
# PAGBUILD – Builder Przepisów PAGBUILD.yaml dla PaganOS
set -euo pipefail

RECIPE_FILE="${1:-PAGBUILD.yaml}"
ROOTFS="${ROOTFS:-/var/lib/pagan-build/rootfs}"
OUT_DIR="${OUT_DIR:-/var/cache/pagbuild/output}"
SRC_CACHE="${SRC_CACHE:-/var/cache/pagbuild/sources}"
BUILD_WORK="/tmp/pagbuild-work"

if [[ ! -f "$RECIPE_FILE" ]]; then
    echo "❌ Błąd: Przepis $RECIPE_FILE nie istnieje."
    exit 1
fi

eval $(python3 -c "
import yaml
with open('$RECIPE_FILE') as f: data = yaml.safe_load(f)
meta = data.get('package', {})
src = data.get('source', {})
print(f'PKG_NAME=\"{meta.get(\"name\", \"\")}\"')
print(f'PKG_VER=\"{meta.get(\"version\", \"\")}\"')
print(f'PKG_REL=\"{meta.get(\"release\", 1)}\"')
print(f'PKG_CAT=\"{meta.get(\"category\", \"other\")}\"')
print(f'SRC_URL=\"{src.get(\"url\", \"\")}\"')
print(f'SRC_SHA256=\"{src.get(\"sha256\", \"\")}\"')
")

FULL_NAME="${PKG_NAME}-${PKG_VER}-${PKG_REL}"
echo "Budowanie przepisu PaganOS: $FULL_NAME ($PKG_CAT)"

mkdir -p "$SRC_CACHE" "$OUT_DIR" "$BUILD_WORK"
ARCHIVE_NAME=$(basename "$SRC_URL")
CACHED_SRC="$SRC_CACHE/$ARCHIVE_NAME"

if [[ -n "$SRC_URL" ]]; then
    if [[ ! -f "$CACHED_SRC" ]]; then
        curl -sSL "$SRC_URL" -o "$CACHED_SRC"
    fi
fi

WORK_DIR="$BUILD_WORK/$FULL_NAME"
DESTDIR="$WORK_DIR/destdir"
rm -rf "$WORK_DIR"
mkdir -p "$WORK_DIR/src" "$DESTDIR"

if [[ -f "$CACHED_SRC" ]]; then
    tar -xf "$CACHED_SRC" -C "$WORK_DIR/src" --strip-components=1 2>/dev/null || tar -xf "$CACHED_SRC" -C "$WORK_DIR/src"
fi

BUILD_SCRIPT="$WORK_DIR/build.sh"
python3 -c "
import yaml
with open('$RECIPE_FILE') as f: data = yaml.safe_load(f)
bld = data.get('build', {})
script = f'''#!/bin/bash
set -eo pipefail
export DESTDIR=/tmp/destdir
cd /tmp/src
{chr(10).join(bld.get('prepare', []))}
{chr(10).join(bld.get('compile', []))}
{chr(10).join(bld.get('install', []))}
'''
with open('$BUILD_SCRIPT', 'w') as out: out.write(script)
"
chmod +x "$BUILD_SCRIPT"

mkdir -p "$ROOTFS/tmp/src" "$ROOTFS/tmp/destdir"
cp -r "$WORK_DIR/src/"* "$ROOTFS/tmp/src/"
cp "$BUILD_SCRIPT" "$ROOTFS/tmp/build.sh"

mount -t proc proc "$ROOTFS/proc" 2>/dev/null || true
mount -t sysfs sys "$ROOTFS/sys" 2>/dev/null || true
mount --bind /dev "$ROOTFS/dev" 2>/dev/null || true

chroot "$ROOTFS" /usr/bin/env -i PATH=/usr/bin:/usr/sbin:/bin:/sbin /tmp/build.sh

umount -l "$ROOTFS/dev" 2>/dev/null || true
umount -l "$ROOTFS/sys" 2>/dev/null || true
umount -l "$ROOTFS/proc" 2>/dev/null || true

cp -r "$ROOTFS/tmp/destdir/"* "$DESTDIR/" 2>/dev/null || true

python3 -c "
import yaml, json
with open('$RECIPE_FILE') as f: data = yaml.safe_load(f)
meta = data.get('package', {})
pkg_info = {'name': meta.get('name'), 'version': meta.get('version'), 'category': meta.get('category', 'other')}
with open('$DESTDIR/metadata.json', 'w') as f: json.dump(pkg_info, f, indent=2)
"

PKG_FILE="$OUT_DIR/${FULL_NAME}.pkg.tar.xz"
tar -cJf "$PKG_FILE" -C "$DESTDIR" .

echo "✅ Zbudowano pakiet PaganOS: $PKG_FILE"
rm -rf "$WORK_DIR"
PAGBUILD_BIN
    chmod +x "$PAGAN_ROOT/usr/bin/pagbuild"

    # Nie zostawiaj starego stubu z heredoca: rootfs ma zawierać ten sam
    # produkcyjny builder, którego używa pagsync na serwerze.
    if [[ -f "$SCRIPT_DIR/pagbuild" ]]; then
        cp -f "$SCRIPT_DIR/pagbuild" "$PAGAN_ROOT/usr/bin/pagbuild"
        chmod +x "$PAGAN_ROOT/usr/bin/pagbuild"
    fi
    if [[ -f "$SCRIPT_DIR/pagsync" ]]; then
        cp -f "$SCRIPT_DIR/pagsync" "$PAGAN_ROOT/opt/pagan/pagsync"
        chmod +x "$PAGAN_ROOT/opt/pagan/pagsync"
    fi

    # -------------------------------------------------------------------------
    # C. Menedżer Kolejki & Synchronizacji: /opt/pagan/pagbuild-sync
    # -------------------------------------------------------------------------
    info "4. Tworzenie /opt/pagan/pagbuild-sync..."
    cat > "$PAGAN_ROOT/opt/pagan/pagbuild-sync" <<'PAGSYNC_BIN'
#!/usr/bin/env python3
"""
PAGBUILD-SYNC – PaganOS Queue & Daemon Sync Manager
"""
import os, sys, json, time, argparse, subprocess
from pathlib import Path

STATE_FILE = "/var/lib/pagan-sync/state.json"
RECIPES_DIR = "/var/lib/pagan-sync/recipes"
REPO_BASE = "/var/www/repo.paganlinux.eu"
BUILD_OUT = "/var/cache/pagbuild/output"
PAGBUILD_BIN = "/usr/bin/pagbuild"

CATEGORIES = ["core", "desktop", "tools", "network", "multimedia", "gaming", "office", "other"]

def load_state():
    if os.path.exists(STATE_FILE):
        try:
            with open(STATE_FILE, "r") as f: return json.load(f)
        except Exception: pass
    return {"builds": [], "last_sync": "", "current_build": None}

def save_state(state):
    os.makedirs(os.path.dirname(STATE_FILE), exist_ok=True)
    with open(STATE_FILE, "w") as f: json.dump(state, f, indent=2)

def run_single(pkg_name, recipe_path, cat, state):
    print(f"[BUILD] Start: {pkg_name} ({cat})")
    state["current_build"] = {"name": pkg_name, "category": cat, "start_time": time.strftime("%Y-%m-%d %H:%M:%S")}
    save_state(state)
    
    start = time.time()
    proc = subprocess.run([PAGBUILD_BIN, recipe_path], capture_output=True, text=True)
    dur = round(time.time() - start, 1)
    status = "ok" if proc.returncode == 0 else "failed"
    
    if status == "ok":
        print(f"✅ [BUILD] Sukces {pkg_name} w {dur}s")
        out_pkg = list(Path(BUILD_OUT).glob(f"{pkg_name}-*.pkg.tar.xz"))
        if out_pkg:
            dst = os.path.join(REPO_BASE, cat)
            os.makedirs(dst, exist_ok=True)
            subprocess.run(["mv", "-f", str(out_pkg[0]), dst])
    else:
        print(f"❌ [BUILD] Błąd {pkg_name}: {proc.stderr[:200]}")

    state["builds"].append({"name": pkg_name, "category": cat, "status": status, "duration": f"{dur}s", "time": time.strftime("%Y-%m-%d %H:%M:%S")})
    state["current_build"] = None
    save_state(state)

def sync_all(force=False):
    state = load_state()
    for cat in CATEGORIES:
        cdir = os.path.join(RECIPES_DIR, cat)
        if not os.path.isdir(cdir): continue
        for pkg in sorted(os.listdir(cdir)):
            yml = os.path.join(cdir, pkg, "PAGBUILD.yaml")
            if not os.path.exists(yml): yml = os.path.join(cdir, pkg, "package.yml")
            if os.path.isfile(yml):
                run_single(pkg, yml, cat, state)

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--once", action="store_true")
    p.add_argument("--force", action="store_true")
    p.add_argument("--build", type=str, default=None)
    args = p.parse_args()
    
    if args.build:
        st = load_state()
        for c in CATEGORIES:
            y = os.path.join(RECIPES_DIR, c, args.build, "PAGBUILD.yaml")
            if os.path.exists(y): run_single(args.build, y, c, st); break
    else:
        sync_all(args.force)
PAGSYNC_BIN
    chmod +x "$PAGAN_ROOT/opt/pagan/pagbuild-sync"
    ln -sf /opt/pagan/pagbuild-sync "$PAGAN_ROOT/usr/bin/pagsync"

    ok "PaganOS Toolstack zainstalowany pomyślnie!"
}

finalize_build() {
    step "FINALIZACJA BUDOWY PAGAN LINUX"
    cat > "$PAGAN_ROOT/etc/pagan-release" <<EOF
Pagan Linux ${PAGAN_VERSION} (PaganOS)
Kernel: ${KERNEL_VERSION}
PAG Tools: pag, pagbuild, pagsync installed
EOF
    # libcrypt.so.2 compat — hostowe binarki (perl) mogą go wymagać
    [[ -f "$PAGAN_ROOT/usr/lib/libcrypt.so.1.1.0" ]] && ln -sf libcrypt.so.1.1.0 "$PAGAN_ROOT/usr/lib/libcrypt.so.2" 2>/dev/null || true
    # Pliki .la (libtool) są zbędne w runtime i potrafią zepsuć linkowanie (libdir=/usr/lib)
    find "$PAGAN_ROOT" -name "*.la" -delete 2>/dev/null || true
    ok "Finalizacja zakończona!"
}

# ========================= WERYFIKACJA ROOTFS =========================
verify_rootfs() {
    step "WERYFIKACJA ROOTFS – sanity check po buildzie"
    local fails=0

    local check
    for check in bash sh ls cat grep sed awk make gcc python3 perl; do
        if [[ ! -x "$PAGAN_ROOT/usr/bin/$check" ]] && [[ ! -x "$PAGAN_ROOT/bin/$check" ]]; then
            warn "Brak binarki: $check"
            ((fails++)) || true
        fi
    done

    # Python + sqlite3 (wymagane przez pag)
    if [[ -x "$PAGAN_ROOT/usr/bin/python3" ]]; then
        if chroot "$PAGAN_ROOT" /usr/bin/python3 -c "import sqlite3; import zlib; import tarfile; print('python3: sqlite3 OK')" >/dev/null 2>&1; then
            ok "python3 + sqlite3 działa"
        else
            warn "python3 nie ma sqlite3/zlib/tarfile – pag nie będzie działać!"
            ((fails++)) || true
        fi
    else
        warn "Brak python3 – pag nie będzie działać!"
        ((fails++)) || true
    fi

    # pag – pełna wersja (nie stub)
    if [[ -f "$PAGAN_ROOT/usr/bin/pag" ]]; then
        if grep -q "PAG - Pagan Linux Package Manager v3" "$PAGAN_ROOT/usr/bin/pag" 2>/dev/null; then
            ok "pag – pełna wersja v3"
        else
            warn "pag to stub (niepełna wersja) – sprawdź install_pagan_toolstack"
            ((fails++)) || true
        fi
    else
        warn "Brak /usr/bin/pag"
        ((fails++)) || true
    fi

    # glibc
    if [[ -f "$PAGAN_ROOT/usr/lib/libc.so.6" ]]; then
        local glibc_ver
        glibc_ver=$(chroot "$PAGAN_ROOT" /usr/bin/ldd --version 2>/dev/null | head -1 | grep -o '[0-9.]*' || true)
        ok "glibc: ${glibc_ver:-?}"
    else
        warn "Brak libc.so.6!"
        ((fails++)) || true
    fi

    # Chroot test
    if chroot "$PAGAN_ROOT" /bin/bash -c "echo OK" >/dev/null 2>&1; then
        ok "chroot + bash działa"
    else
        warn "chroot /bin/bash NIE działa!"
        ((fails++)) || true
    fi

    if [[ $fails -gt 0 ]]; then
        warn "Weryfikacja: $fails problemów znalezionych (patrz wyżej)"
    else
        ok "Weryfikacja: wszystkie sanity checki przeszły ✅"
    fi
    return $fails
}

mount_virtual_fs() {
    mount --bind /dev "$PAGAN_ROOT/dev" 2>/dev/null || true
    mount --bind /dev/pts "$PAGAN_ROOT/dev/pts" 2>/dev/null || true
    mount -t proc proc "$PAGAN_ROOT/proc" 2>/dev/null || true
    mount -t sysfs sysfs "$PAGAN_ROOT/sys" 2>/dev/null || true
    mount -t tmpfs tmpfs "$PAGAN_ROOT/run" 2>/dev/null || true
}

umount_virtual_fs() {
    umount -l "$PAGAN_ROOT/dev/pts" 2>/dev/null || true
    umount -l "$PAGAN_ROOT/dev" 2>/dev/null || true
    umount -l "$PAGAN_ROOT/proc" 2>/dev/null || true
    umount -l "$PAGAN_ROOT/sys" 2>/dev/null || true
    umount -l "$PAGAN_ROOT/run" 2>/dev/null || true
}

# ========================= MAIN =========================
main() {
    cd /
    show_banner

    local arg
    for arg in "$@"; do
        case "$arg" in
            --rebuild|--from-scratch|--clean)
                REBUILD_FROM_SCRATCH=1
                ;;
        esac
    done
    
    if [[ $EUID -ne 0 ]]; then
        error "Wymagane uprawnienia root (sudo)"
    fi

    if _is_true "${REBUILD_FROM_SCRATCH:-0}"; then
        clean_build_state
    fi

    # rootfs.sh ma budować wyłącznie rootfs (bez desktopów, kernela i obrazów)
    if [[ "${BUILD_IMG:-0}" -ne 0 || "${BUILD_ISO:-0}" -ne 0 ]]; then
        warn "Ten skrypt buduje tylko rootfs. Zmiennie BUILD_IMG/BUILD_ISO są ignorowane."
    fi

    check_dependencies
    check_lfs_patches
    init_build
    build_toolchain         # Ch. 5
    mount_virtual_fs
    build_final_system      # Ch. 6-8 LFS + systemd
    install_pagan_toolstack # pag + pagbuild
    umount_virtual_fs
    finalize_build
    verify_rootfs
    
    # ===== TEST CHROOT =====
    step "TEST CHROOT – sprawdzanie rootfs"
    local TARBALL="/tmp/pagan-rootfs-${PAGAN_VERSION}.tar.xz"
    
    if chroot "$PAGAN_ROOT" /bin/bash -c "echo OK && uname -a" 2>/dev/null; then
        ok "✅ Chroot działa poprawnie!"
        
        # ===== PAKOWANIE DO TAR.XZ =====
        step "PAKOWANIE ROOTFS DO $TARBALL"
        info "Rozmiar rootfs: $(du -sh "$PAGAN_ROOT" --exclude="$PAGAN_ROOT/sources" 2>/dev/null | cut -f1)"
        rm -f "$TARBALL"
        tar -cJf "$TARBALL" \
            -C "$PAGAN_ROOT" \
            --exclude='./sources' \
            --exclude='./proc' \
            --exclude='./sys' \
            --exclude='./dev' \
            --exclude='./run' \
            --exclude='./tmp' \
            --exclude='./lost+found' \
            . 2>/dev/null
        ok "Archiwum: $TARBALL ($(du -h "$TARBALL" 2>/dev/null | cut -f1))"
        echo ""
        echo "  Aby wysłać na VPS:"
        echo "    scp $TARBALL root@vps:/tmp/"
        echo "    ssh root@vps 'rm -rf /mnt/pagan-rootfs && mkdir -p /mnt/pagan-rootfs && tar -xJf /tmp/pagan-rootfs-*.tar.xz -C /mnt/pagan-rootfs && chroot /mnt/pagan-rootfs /bin/bash'"
    else
        error "❌ Chroot NIE DZIAŁA! Sprawdź log: $LOG_FILE"
    fi
    
    step "✅ PAGANOS ROOTFS ZBUDOWANY – gotowy do pagbuild!"
    echo ""
    echo "  Aby budować pakiety lokalnie:"
    echo "    sudo chroot $PAGAN_ROOT /bin/bash"
    echo "    pagbuild recipes/core/bash/PAGBUILD.yaml"
    echo "    pag install /var/cache/pagbuild/output/bash-*.pkg.tar.xz"
    echo ""
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi