🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
#!/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.2}"
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}"
# Pełna natywna warstwa build-deps: core, libs, graphics, Qt/GTK, desktop.
# Można wyłączyć tylko do krótkich testów: BUILD_NATIVE_PACKAGES=0.
BUILD_NATIVE_PACKAGES="${BUILD_NATIVE_PACKAGES:-1}"
# ========================= 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" "lzip"
"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 dev proc sys 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,/hooks}
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.lz)
if command -v lzip >/dev/null 2>&1; then
lzip -t "$file" >/dev/null 2>&1
else
tar -tf "$file" >/dev/null 2>&1
fi
;;
*.tar) tar -tf "$file" >/dev/null 2>&1 ;;
*.zip) unzip -tqq "$file" >/dev/null 2>&1 ;;
*.pem|*.crt) grep -q 'BEGIN CERTIFICATE' "$file" 2>/dev/null ;;
*) ! 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.lz) lzip -d "$archive_path" -o "$SRC_DIR/${archive%.lz}" && tar -xf "$SRC_DIR/${archive%.lz}" -C "$pkg_dir" $_strip ;;
*.pem|*.crt) cp "$archive_path" "$pkg_dir/$(basename "$archive")" ;;
*) 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}" "$SRC_DIR/${archive%.lz}"
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.lz) lzip -d "$archive_path" -o "$SRC_DIR/${archive%.lz}" && tar -xf "$SRC_DIR/${archive%.lz}" -C "$pkg_dir" $_strip ;;
*.pem|*.crt) cp "$archive_path" "$pkg_dir/$(basename "$archive")" ;;
*) 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"
# Nie eksportuj LD_LIBRARY_PATH do procesu hosta: zanieczyszczałoby hostowe
# mount/umount i powodowało ładowanie bibliotek PaganOS przez hosta.
unset LD_LIBRARY_PATH
# 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 && ln -sfv libcrypt.so.1.1.0 \$PAGAN_ROOT/usr/lib/libcrypt.so.2"
"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"
# bsdtar (libarchive) – wymagany przez pagbuild do źródeł .zip/.rpm/.tar.lz
# oraz przez receptury .deb. cpio – wymagane przez część receptur.
"libarchive:3.8.9:https://github.com/libarchive/libarchive/releases/download/v3.8.9/libarchive-3.8.9.tar.xz:SKIP:./configure --prefix=/usr --disable-static && make && make install DESTDIR=\$PAGAN_ROOT"
"cpio:2.15:https://ftp.gnu.org/gnu/cpio/cpio-2.15.tar.bz2:SKIP:./configure --prefix=/usr && make && make install DESTDIR=\$PAGAN_ROOT"
# libxml2 – potrzebny gettextowi i pakietom zależnym.
"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"
# libxslt dostarcza natywne xsltproc wymagane przez GNOME/GTK/dokumentację.
"libxslt:1.1.43:https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.43.tar.xz:SKIP:CC=gcc ./configure --prefix=/usr --disable-static --without-python && 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"
"ed:1.22.5:https://ftp.gnu.org/gnu/ed/ed-1.22.5.tar.lz: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"
# CA bundle musi istnieć przed pierwszym natywnym pobieraniem przez curl.
"ca-certificates:2024:https://curl.se/ca/cacert-2024-07-02.pem:SKIP:mkdir -p \$PAGAN_ROOT/etc/ssl/certs && cp cacert-2024-07-02.pem \$PAGAN_ROOT/etc/ssl/certs/ca-certificates.crt"
# curl jest wymagany przez natywny pagbuild do pobierania źródeł.
"curl:8.9.1:https://curl.se/download/curl-8.9.1.tar.xz:SKIP:./configure --prefix=/usr --with-openssl --with-zlib --disable-static --without-libpsl --without-nghttp2 --without-librtmp --without-brotli --disable-ldap --disable-ldaps && 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:bash \"\$SCRIPT_DIR/patches/systemd-compat.sh\" && CFLAGS=\"\$CFLAGS -D_GNU_SOURCE -Wno-error=redundant-decls -Wno-error=undef -Wno-error=implicit-function-declaration -imacros \$PWD/src/include/override/pagan-compat.h\" CXXFLAGS=\"\$CXXFLAGS -D_GNU_SOURCE -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"
"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 i Mesona w chroocie..."
# Chroot korzysta z sieci hosta, ale musi mieć własny działający resolver.
mkdir -p "$PAGAN_ROOT/etc"
rm -f "$PAGAN_ROOT/etc/resolv.conf"
cp -L /etc/resolv.conf "$PAGAN_ROOT/etc/resolv.conf"
if grep -qE 'nameserver[[:space:]]+127\.0\.0\.53' "$PAGAN_ROOT/etc/resolv.conf"; then
printf 'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' > "$PAGAN_ROOT/etc/resolv.conf"
fi
chroot "$PAGAN_ROOT" python3 -m ensurepip --upgrade >/dev/null 2>&1 || true
chroot "$PAGAN_ROOT" python3 -m pip install --no-cache-dir \
flit-core packaging markupsafe jinja2 setuptools wheel pyyaml requests meson==1.10.1 \
--break-system-packages || error "Nie udało się zainstalować Python build stack/Mesona"
# -------------------------------------------------------------------------
# A. Menedżer Pakietów: /usr/bin/pag (pełna wersja)
# -------------------------------------------------------------------------
info "2. Kopiowanie pełnego pag..."
# Klient paga mieszka w katalogu projektu pag/ (1:1 z repo git.paganlinux.eu/git/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}.pag"
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
# repo-index.sh – narzędzie generowania repo.json (używane przez buildera repo).
if [[ -f "$SCRIPT_DIR/repo-index.sh" ]]; then
install -m755 "$SCRIPT_DIR/repo-index.sh" "$PAGAN_ROOT/opt/pagan/repo-index.sh"
ln -sf /opt/pagan/repo-index.sh "$PAGAN_ROOT/usr/bin/repo-index"
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}-*.pag"))
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
# Ujednolicenie libdirów dla natywnego loadera PaganOS.
mkdir -p "$PAGAN_ROOT/usr/lib" "$PAGAN_ROOT/usr/lib64"
for lib in libstdc++.so.6 libgcc_s.so.1 libgomp.so.1 libquadmath.so.0; do
[[ -e "$PAGAN_ROOT/usr/lib64/$lib" ]] && ln -sfn "../lib64/$lib" "$PAGAN_ROOT/usr/lib/$lib"
done
# libcrypt.so.2 compat — Perl i część starszych narzędzi tego wymagają.
[[ -e "$PAGAN_ROOT/usr/lib/libcrypt.so.1.1.0" ]] && ln -sfn libcrypt.so.1.1.0 "$PAGAN_ROOT/usr/lib/libcrypt.so.2"
[[ -e "$PAGAN_ROOT/usr/lib/perl5/5.42.0/x86_64-linux/CORE/libperl.so" ]] && \
ln -sfn perl5/5.42.0/x86_64-linux/CORE/libperl.so "$PAGAN_ROOT/usr/lib/libperl.so"
cat > "$PAGAN_ROOT/etc/ld.so.conf" <<EOF
/usr/lib
/usr/lib64
/lib
/lib64
EOF
chroot "$PAGAN_ROOT" /sbin/ldconfig 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
# ── Odchudzenie rootfs ──
# Baza LFS jest budowana bez strip: symbole debug potrafią zajmować >2 GB
# (gcc/libexec, python, perl). Usuwamy je przed spakowaniem.
info "Odchudzanie rootfs (strip ELF, usuwanie toolchainu i firmware)..."
find "$PAGAN_ROOT/usr/lib" "$PAGAN_ROOT/usr/lib64" "$PAGAN_ROOT/usr/libexec" \
"$PAGAN_ROOT/lib64" "$PAGAN_ROOT/lib" \
-type f -name "*.so*" -exec strip --strip-unneeded {} \; 2>/dev/null || true
find "$PAGAN_ROOT/usr/bin" "$PAGAN_ROOT/usr/sbin" "$PAGAN_ROOT/usr/libexec" \
"$PAGAN_ROOT/bin" "$PAGAN_ROOT/sbin" \
-type f -exec sh -c 'case "$(file -b "$1")" in *ELF*) strip "$1" ;; esac' _ {} \; 2>/dev/null || true
# Cross-toolchain z Ch. 5 nie jest potrzebny do natywnych buildów pagbuild.
rm -rf "$PAGAN_ROOT/tools"
# Firmware dostarczają pakiety repo (amdgpu-firmware itd.) – nie pieczemy go w bazie.
rm -rf "$PAGAN_ROOT/lib/firmware"
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() {
unset LD_LIBRARY_PATH
mkdir -p "$PAGAN_ROOT/dev" "$PAGAN_ROOT/dev/pts" "$PAGAN_ROOT/proc" "$PAGAN_ROOT/sys" "$PAGAN_ROOT/run"
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
}
prepare_udev_devel() {
local libdir="" libfile=""
libfile=$(find "$PAGAN_ROOT/usr" "$PAGAN_ROOT/lib" "$PAGAN_ROOT/lib64" \
-type f -o -type l 2>/dev/null | grep -E '/libudev\.so(\.1)?$' | head -1 || true)
if [[ -n "$libfile" ]]; then
libdir="/${libfile#"$PAGAN_ROOT/"}"
libdir="${libdir%/*}"
else
warn "Nie znaleziono libudev.so w rootfs — NetworkManager nie zbuduje się"
return 0
fi
if [[ ! -f "$PAGAN_ROOT/usr/include/libudev.h" ]]; then
warn "Brak /usr/include/libudev.h — libudev-dev jest niekompletny"
return 0
fi
mkdir -p "$PAGAN_ROOT$libdir/pkgconfig"
if [[ ! -e "$PAGAN_ROOT$libdir/libudev.so" && -e "$PAGAN_ROOT$libdir/libudev.so.1" ]]; then
ln -s libudev.so.1 "$PAGAN_ROOT$libdir/libudev.so"
fi
cat > "$PAGAN_ROOT$libdir/pkgconfig/libudev.pc" <<EOF
prefix=/usr
exec_prefix=\${prefix}
includedir=\${prefix}/include
libdir=\${prefix}${libdir}
Name: libudev
Description: libudev device database and event API
Version: 259.1
Libs: -L\${libdir} -ludev
Cflags: -I\${includedir}
EOF
ok "libudev metadata: $libdir/pkgconfig/libudev.pc"
}
prepare_locales() {
mkdir -p "$PAGAN_ROOT/usr/lib/locale" "$PAGAN_ROOT/etc"
if [[ -x "$PAGAN_ROOT/usr/bin/localedef" ]]; then
chroot "$PAGAN_ROOT" /usr/bin/localedef -i C -f UTF-8 C.UTF-8 2>/dev/null || true
fi
printf 'LANG=C.UTF-8\nLC_ALL=C.UTF-8\n' > "$PAGAN_ROOT/etc/locale.conf"
}
umount_virtual_fs() {
unset LD_LIBRARY_PATH
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
prepare_udev_devel
umount_virtual_fs
prepare_locales
# Pełna warstwa developerska jest budowana natywnie przez PaganOS.
# Nie kopiujemy bibliotek Debiana: każdy pakiet trafia do tego samego
# rootfs i staje się dostępny dla kolejnych receptur.
if _is_true "$BUILD_NATIVE_PACKAGES"; then
[[ -x "$SCRIPT_DIR/build-native-builder-rootfs.sh" ]] || \
error "Brak build-native-builder-rootfs.sh obok rootfs.sh"
NATIVE_ROOTFS="$PAGAN_ROOT" \
NATIVE_RECIPES="$SCRIPT_DIR/recipes" \
"$SCRIPT_DIR/build-native-builder-rootfs.sh"
else
warn "Pominięto natywną warstwę build-deps (BUILD_NATIVE_PACKAGES=0)"
fi
finalize_build
verify_rootfs
# ===== TEST CHROOT =====
step "TEST CHROOT – sprawdzanie rootfs"
local TARBALL="${ROOTFS_ARCHIVE:-/tmp/pagan-rootfs-${PAGAN_VERSION}.tar.xz}"
local CHECKSUM="${TARBALL}.sha256"
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
[[ -s "$TARBALL" ]] || error "Archiwum rootfs nie zostało utworzone: $TARBALL"
sha256sum "$TARBALL" > "$CHECKSUM"
ok "Archiwum: $TARBALL ($(du -h "$TARBALL" 2>/dev/null | cut -f1))"
ok "SHA256: $CHECKSUM"
echo ""
echo " Aby wysłać na VPS:"
echo " scp $TARBALL $CHECKSUM root@paganlinux.eu:/var/lib/pagan-build/"
echo " # Najpierw zweryfikuj SHA256 na VPS; nie podmieniaj aktywnego rootfs bez testu."
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-*.pag"
echo ""
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi