#!/usr/bin/env bash export TERM="${TERM:-xterm}" clear || true # === PinCabOS standard installer header === ORANGE=$'\033[38;5;208m' PURPLE=$'\033[38;5;93m' RED=$'\033[1;31m' CYAN=$'\033[38;5;51m' GREEN=$'\033[1;32m' WHITE=$'\033[1;37m' GRAY=$'\033[38;5;245m' RESET=$'\033[0m' pincabos_install_header() { local script_name script_name="$(basename "$0")" echo perl -CS -Mutf8 -e ' binmode(STDOUT, ":utf8"); my $orange = "\033[38;5;208m"; my $purple = "\033[38;5;93m"; my $reset = "\033[0m"; my @logo = ( "██████╗ ██╗███╗ ██╗ ██████╗ █████╗ ██████╗ ██████╗ ███████╗", "██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██╔══██╗██╔═══██╗██╔════╝", "██████╔╝██║██╔██╗ ██║██║ ███████║██████╔╝██║ ██║███████╗", "██╔═══╝ ██║██║╚██╗██║██║ ██╔══██║██╔══██╗██║ ██║╚════██║", "██║ ██║██║ ╚████║╚██████╗██║ ██║██████╔╝╚██████╔╝███████║", "╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝" ); for my $line (@logo) { $line =~ s/(█+)/$orange$1$reset/g; $line =~ s/([╔╗╚╝═║]+)/$purple$1$reset/g; print "$line\n"; } ' echo printf "${ORANGE} Ultimate VPinball Linux Cabinet System${RESET}\n" printf "${CYAN} VPX • VPinFE • DOF • WebApp${RESET}\n" echo printf "${CYAN}────────────────────────────────────────────────────────────────${RESET}\n" printf "${GRAY} Script :${RESET} ${WHITE}%s${RESET}\n" "$script_name" printf "${GRAY} By :${RESET} ${WHITE}Karots Sugarpie${RESET}\n" printf "${GRAY} Hostname :${RESET} %s\n" "$(hostname)" printf "${GRAY} User :${RESET} %s\n" "$(whoami)" printf "${CYAN}────────────────────────────────────────────────────────────────${RESET}\n" echo } pincabos_install_header PCO_CURRENT_STEP="" PCO_STEPS=() PCO_STATUS=() PCO_FINAL_SUMMARY_DONE=0 pco_line() { printf "${CYAN}────────────────────────────────────────────────────────────────${RESET}\n" } pco_split_step() { local raw="${1:-}" PCO_STEP_NUM="**" PCO_STEP_TITLE="$raw" if [[ "$raw" =~ ^([0-9]+)\)\ (.*)$ ]]; then PCO_STEP_NUM="${BASH_REMATCH[1]}" PCO_STEP_TITLE="${BASH_REMATCH[2]}" fi } pco_title() { local raw="$1" pco_split_step "$raw" printf "\n${CYAN}─[%s]─►${ORANGE} %s ${CYAN}◄────${RESET}\n\n" "$PCO_STEP_NUM" "$PCO_STEP_TITLE" } pco_step() { local step="$1" PCO_CURRENT_STEP="$step" PCO_STEPS+=("$step") PCO_STATUS+=("RUNNING") pco_title "$step" } pco_check() { local step="$1" local i pco_split_step "$step" for i in "${!PCO_STEPS[@]}"; do if [ "${PCO_STEPS[$i]}" = "$step" ]; then PCO_STATUS[$i]="OK" fi done printf "${GREEN}─[%s]─► %s ◄──── Check [√]${RESET}\n" "$PCO_STEP_NUM" "$PCO_STEP_TITLE" } pco_fail_current() { local i if [ -n "${PCO_CURRENT_STEP:-}" ]; then for i in "${!PCO_STEPS[@]}"; do if [ "${PCO_STEPS[$i]}" = "$PCO_CURRENT_STEP" ]; then PCO_STATUS[$i]="FAIL" fi done fi } pco_final_summary() { local exit_code="${1:-0}" local i local failed=0 if [ "${PCO_FINAL_SUMMARY_DONE:-0}" -eq 1 ]; then return 0 fi PCO_FINAL_SUMMARY_DONE=1 echo pco_line printf "${ORANGE}Résumé complet des checks PinCabOS - %s${RESET}\n" "$(basename "$0")" pco_line for i in "${!PCO_STEPS[@]}"; do pco_split_step "${PCO_STEPS[$i]}" case "${PCO_STATUS[$i]}" in OK) printf "${GREEN}─[%s]─► %s ◄──── Check [√]${RESET}\n" "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; FAIL|RUNNING) failed=1 printf "${RED}─[%s]─► %s ◄──NOGOOD [X]${RESET}\n" "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; *) failed=1 printf "${RED}─[%s]─► %s ◄──NOGOOD [X]${RESET}\n" "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; esac done pco_line if [ "$failed" -eq 0 ] && [ "$exit_code" -eq 0 ]; then printf "${GREEN}Tous les checks sont réussis. PinCabOS system install OK.${RESET}\n" else printf "${RED}Un ou plusieurs checks ont échoué. Code retour: %s${RESET}\n" "$exit_code" fi pco_line printf "${ORANGE}Espace utilisé système :${RESET} %s\n" "$(df -h / | awk 'NR==2 {print $3}')" printf "${ORANGE}Espace disponible :${RESET} %s\n" "$(df -h / | awk 'NR==2 {print $4}')" printf "${ORANGE}Utilisation système :${RESET} %s\n" "$(df -h / | awk 'NR==2 {print $5}')" pco_line echo printf "${RED}AVERTISSEMENT:${RESET}\n" printf "${RED}Il est fortement recommandé de redémarrer le système après 01-install-system.sh.${RESET}\n" printf "${RED}Cela permet de recharger proprement les services système, nginx, Python, DBus, X11, Chrome, LightDM, Plymouth et les dépendances installées.${RESET}\n" pco_line echo if [ -n "${LOG:-}" ] && [ -f "${LOG:-}" ]; then printf "${ORANGE}Rapport local:${RESET} %s\n" "$LOG" echo fi } pco_on_error() { local exit_code="$?" pco_fail_current pco_final_summary "$exit_code" exit "$exit_code" } trap pco_on_error ERR trap 'pco_final_summary "$?"' EXIT set -euo pipefail pco_spinner_wait() { local pid="$1" local label="$2" local spin='|/-\' local i=0 while kill -0 "$pid" 2>/dev/null; do i=$(( (i + 1) % 4 )) printf "\r${CYAN}[%c]${ORANGE} %s...${RESET}" "${spin:$i:1}" "$label" sleep 0.15 done wait "$pid" local rc="$?" printf "\r%80s\r" " " return "$rc" } run_spin() { local label="$1" shift local tmp="/tmp/pincabos-spin-${RANDOM}-${RANDOM}.log" "$@" >"$tmp" 2>&1 & local pid="$!" if pco_spinner_wait "$pid" "$label"; then cat "$tmp" rm -f "$tmp" return 0 else local rc="$?" cat "$tmp" rm -f "$tmp" return "$rc" fi } run_spin_bash() { local label="$1" shift local tmp="/tmp/pincabos-spin-${RANDOM}-${RANDOM}.log" bash -c "$*" >"$tmp" 2>&1 & local pid="$!" if pco_spinner_wait "$pid" "$label"; then cat "$tmp" rm -f "$tmp" return 0 else local rc="$?" cat "$tmp" rm -f "$tmp" return "$rc" fi } pco_install_temporary_plymouth_theme() { local install_base="${INSTALL_BASE:-http://192.168.254.55/install}" local src_local="/opt/pincabos/install/PCOSInstallWP.png" local src_url="${install_base}/PCOSInstallWP.png" local theme_dir="/usr/share/plymouth/themes/pincabos-install" local image="$theme_dir/PCOSInstallWP.png" echo "Création thème Plymouth temporaire installation PinCabOS" echo "Source locale : $src_local" echo "Source HTTP : $src_url" mkdir -p "$theme_dir" if [ -s "$src_local" ]; then cp -f "$src_local" "$image" else if command -v curl >/dev/null 2>&1; then curl -fsSL "$src_url" -o "$image" elif command -v wget >/dev/null 2>&1; then wget -qO "$image" "$src_url" else echo "NOGOOD: curl/wget absent pour télécharger $src_url" return 1 fi fi if [ ! -s "$image" ]; then echo "NOGOOD: image Plymouth install absente/vide: $image" return 1 fi file "$image" || true chmod 644 "$image" cat > "$theme_dir/pincabos-install.plymouth" <<'PLY' [Plymouth Theme] Name=PinCabOS Installer Description=PinCabOS temporary installation boot splash ModuleName=script [script] ImageDir=/usr/share/plymouth/themes/pincabos-install ScriptFile=/usr/share/plymouth/themes/pincabos-install/pincabos-install.script PLY cat > "$theme_dir/pincabos-install.script" <<'SCRIPT' screen_w = Window.GetWidth(); screen_h = Window.GetHeight(); bg = Image("PCOSInstallWP.png"); bg_w = bg.GetWidth(); bg_h = bg.GetHeight(); scale_x = screen_w / bg_w; scale_y = screen_h / bg_h; if (scale_x > scale_y) { scale = scale_x; } else { scale = scale_y; } bg = bg.Scale(bg_w * scale, bg_h * scale); sprite = Sprite(bg); sprite.SetX((screen_w - bg.GetWidth()) / 2); sprite.SetY((screen_h - bg.GetHeight()) / 2); sprite.SetZ(-100); fun refresh_callback () { sprite.SetX((Window.GetWidth() - bg.GetWidth()) / 2); sprite.SetY((Window.GetHeight() - bg.GetHeight()) / 2); } Plymouth.SetRefreshFunction(refresh_callback); SCRIPT chmod 644 "$theme_dir/pincabos-install.plymouth" "$theme_dir/pincabos-install.script" update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "$theme_dir/pincabos-install.plymouth" 700 update-alternatives --set default.plymouth "$theme_dir/pincabos-install.plymouth" if command -v plymouth-set-default-theme >/dev/null 2>&1; then plymouth-set-default-theme pincabos-install || true fi readlink -f /usr/share/plymouth/themes/default.plymouth || true update-alternatives --display default.plymouth || true run_spin "update-initramfs thème install" update-initramfs -u if command -v update-grub >/dev/null 2>&1; then run_spin "update-grub thème install" update-grub || true fi } # === PINCABOS STAGE5C14 PACKAGE ASSET EXTRACT HELPERS START === # Les assets media PinCabOS ne sont plus servis en fichiers directs sous /updates/opt/... # Ils sont inclus dans le package engine pincabos-engine-latest.tar.zst. # Ce helper télécharge latest.json, retélécharge le .zst au besoin, vérifie le SHA, # décompresse dans /opt/pincabos/tmp, puis copie uniquement les assets requis. pco_pkg_json_get() { local file="$1" local expr="$2" python3 - "$file" "$expr" <<'PYJSON' import json, sys path, expr = sys.argv[1], sys.argv[2] data = json.load(open(path, "r", encoding="utf-8")) cur = data for part in expr.strip(".").split("."): if not part: continue if isinstance(cur, dict) and part in cur: cur = cur[part] else: print("") sys.exit(0) print(cur) PYJSON } pco_download_extract_engine_assets() { local update_base="${PIN_UPDATE_BASE:-${UPDATE_BASE:-http://192.168.254.55/updates}}" local work="/opt/pincabos/tmp/engine-assets-for-system-${TS}" local latest="$work/latest.json" local pkg="$work/package.tar.zst" local root="$work/root" local file="" local sha="" local url="" mkdir -p "$work" "$root" /opt/pincabos/media/plymouth-assets /opt/pincabos/media/wallpapers echo echo "=== PinCabOS - Extraction assets depuis package engine ===" echo "Update base : $update_base" echo "Work : $work" if ! command -v curl >/dev/null 2>&1; then echo "ERREUR: curl absent, impossible de télécharger latest.json/package engine." return 1 fi if ! command -v python3 >/dev/null 2>&1; then echo "ERREUR: python3 absent, impossible de lire latest.json." return 1 fi if ! command -v zstd >/dev/null 2>&1; then echo "zstd absent: installation rapide." DEBIAN_FRONTEND=noninteractive apt-get install -y zstd || return 1 fi echo echo "=== 1) Télécharger latest.json ===" curl -fL --connect-timeout 15 --max-time 90 --retry 3 "$update_base/latest.json" -o "$latest" || return 1 python3 -m json.tool "$latest" >/dev/null || return 1 file="$(pco_pkg_json_get "$latest" '.packages.engine.file')" sha="$(pco_pkg_json_get "$latest" '.packages.engine.sha256')" url="$(pco_pkg_json_get "$latest" '.packages.engine.url')" # Compatibilité PUBLY latest.json top-level. if [ -z "$file" ]; then file="$(pco_pkg_json_get "$latest" '.package')" fi if [ -z "$sha" ]; then sha="$(pco_pkg_json_get "$latest" '.sha256')" fi if [ -z "$url" ]; then url="$(pco_pkg_json_get "$latest" '.url')" fi if [ -z "$file" ] || [ -z "$sha" ]; then echo "ERREUR: latest.json ne contient pas de package/sha256 engine compatible." echo "Formats acceptés:" echo " .packages.engine.file + .packages.engine.sha256" echo " .package + .sha256 + optionnel .url" return 1 fi echo "Package engine: $file" echo "SHA attendu : $sha" echo "URL package : ${url:-${update_base}/${file}}" echo echo "=== 2) Télécharger package engine ===" if [ -n "${url:-}" ] && [ "${url:-}" != "null" ]; then curl -fL --connect-timeout 15 --max-time 1800 --retry 3 "$url" -o "$pkg" || return 1 else curl -fL --connect-timeout 15 --max-time 1800 --retry 3 "$update_base/$file" -o "$pkg" || return 1 fi echo echo "=== 3) Vérifier SHA256 ===" printf "%s %s\n" "$sha" "$pkg" | sha256sum -c - || return 1 echo echo "=== 4) Décompresser package engine dans tmp ===" rm -rf "$root" mkdir -p "$root" tar --use-compress-program=unzstd -xf "$pkg" -C "$root" || return 1 echo echo "=== 5) Copier Plymouth assets ===" local ply_src="" for d in \ "$root/opt/pincabos/media/plymouth-assets" \ "$root/usr/share/plymouth/themes/pincabos" \ "$root/opt/pincabos/config/update-assets-20260603-015702/plymouth" \ "$root/opt/pincabos/config/update-assets-20260602-163542/plymouth" do if [ -d "$d" ]; then ply_src="$d" break fi done if [ -z "$ply_src" ]; then ply_src="$(find "$root" -type d \( -path "*/opt/pincabos/media/plymouth-assets" -o -path "*/usr/share/plymouth/themes/pincabos" -o -path "*/update-assets-*/plymouth" \) 2>/dev/null | head -n 1 || true)" fi echo "Plymouth source: ${ply_src:-ABSENT}" if [ -n "$ply_src" ] && [ -d "$ply_src" ]; then mkdir -p /opt/pincabos/media/plymouth-assets cp -av "$ply_src/." /opt/pincabos/media/plymouth-assets/ else echo "ERREUR: aucun dossier Plymouth PinCabOS trouvé dans le package engine." echo "Debug Plymouth trouvé:" find "$root" -maxdepth 10 -type d -iname "*plymouth*" 2>/dev/null | head -n 100 || true return 1 fi echo "=== 6) Copier wallpapers ===" local wall_src="" for d in \ "$root/opt/pincabos/media/wallpapers" \ "$root/opt/pincabos/essentials/publish-tree-staging/current/opt/pincabos/media/wallpapers" do if [ -d "$d" ]; then wall_src="$d" break fi done if [ -z "$wall_src" ]; then wall_src="$(find "$root" -type d -path "*/opt/pincabos/media/wallpapers" 2>/dev/null | head -n 1 || true)" fi echo "Wallpapers source: ${wall_src:-ABSENT}" if [ -n "$wall_src" ] && [ -d "$wall_src" ]; then mkdir -p /opt/pincabos/media/wallpapers cp -av "$wall_src/." /opt/pincabos/media/wallpapers/ else echo "AVERTISSEMENT: aucun dossier wallpapers trouvé dans le package engine." echo "INFO: on continue; les wallpapers manquants seront corrigés dans le prochain package." fi return 0 } # === PINCABOS STAGE5C14 PACKAGE ASSET EXTRACT HELPERS END === if [ "$(id -u)" -ne 0 ]; then echo "ERREUR: ce script doit être lancé en root." exit 1 fi TS="$(date +%Y%m%d-%H%M%S)" LOG="/opt/pincabos/logs/01-install-system-${TS}.log" UPDATE_BASE="http://192.168.254.55/updates" STAGE="/opt/pincabos/config/update-assets-${TS}" mkdir -p /opt/pincabos/{install,logs,config,tools,essentials,apps,web} exec > >(tee -a "$LOG") 2>&1 pco_step "1) Préparation dossiers PinCabOS" mkdir -p \ /opt/pincabos/logs \ /opt/pincabos/config \ /opt/pincabos/config/backups \ "$STAGE" chmod 755 /opt/pincabos /opt/pincabos/logs /opt/pincabos/config /opt/pincabos/install pco_check "1) Préparation dossiers PinCabOS" pco_step "2) Validation réseau ins.pincabos.cc updates" curl -fsSL "$UPDATE_BASE/latest.json" -o "$STAGE/latest.json" python3 -m json.tool "$STAGE/latest.json" >/dev/null # manifest.json/checksums.sha256 ne sont plus requis: les assets viennent du package engine. if curl -fsI "$UPDATE_BASE/" >/dev/null; then echo "Update server OK: $UPDATE_BASE" else echo "ERREUR: update server inaccessible: $UPDATE_BASE" exit 1 fi pco_check "2) Validation réseau ins.pincabos.cc updates" pco_step "3) Backup dépôts APT originaux" APT_BACKUP="/opt/pincabos/config/backups/apt-system-${TS}" mkdir -p "$APT_BACKUP" cp -a /etc/apt/sources.list "$APT_BACKUP/sources.list" 2>/dev/null || true cp -a /etc/apt/sources.list.d "$APT_BACKUP/sources.list.d" 2>/dev/null || true cp -a /etc/apt/preferences.d "$APT_BACKUP/preferences.d" 2>/dev/null || true pco_check "3) Backup dépôts APT originaux" pco_step "4) Restauration dépôts Ubuntu officiels forcée" mkdir -p /etc/apt/sources.list.d.disabled-pincabos . /etc/os-release OS_ID="${ID:-unknown}" OS_LIKE="${ID_LIKE:-}" DETECTED_CODENAME="${VERSION_CODENAME:-${UBUNTU_CODENAME:-unknown}}" # PinCabOS cible Ubuntu Server. # Le codename doit venir de la VM cible Ubuntu, pas du WebServer. # PINCABOS_UBUNTU_CODENAME permet de forcer explicitement au besoin. CODENAME="${PINCABOS_UBUNTU_CODENAME:-${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}}" if [ -z "$CODENAME" ] || [ "$CODENAME" = "unknown" ]; then echo "NOGOOD: codename Ubuntu introuvable dans /etc/os-release." echo "Définis PINCABOS_UBUNTU_CODENAME avant de lancer 01." exit 1 fi case "$CODENAME" in trixie|bookworm|bullseye|sid) echo "NOGOOD: codename Debian détecté sur la machine qui exécute 01: $CODENAME" echo "01-install-system.sh doit être exécuté sur la VM cible Ubuntu Server, pas sur le WebServer Debian." echo "Si c'est vraiment une image Ubuntu spéciale, force explicitement:" echo "PINCABOS_UBUNTU_CODENAME= bash <(curl -fsSL http://192.168.254.55/install/01-install-system.sh)" exit 1 ;; esac echo "OS détecté : $OS_ID" echo "OS like : $OS_LIKE" echo "Codename détecté : $DETECTED_CODENAME" echo "Codename Ubuntu : $CODENAME" echo "Mode dépôts : Ubuntu forcé" find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name "*.list" -o -name "*.sources" \) 2>/dev/null | while read -r src; do base="$(basename "$src")" case "$base" in ubuntu.sources|ubuntu.list|google-chrome.list|google-chrome.sources) echo "Garde dépôt autorisé: $src" ;; *) echo "Désactive dépôt non Ubuntu/tiers: $src" mv "$src" "/etc/apt/sources.list.d.disabled-pincabos/${base}.disabled-${TS}" || true ;; esac done # Ne jamais garder debian.sources dans l'installation officielle PinCabOS Ubuntu. rm -f /etc/apt/sources.list.d/debian.sources /etc/apt/sources.list.d/debian.list 2>/dev/null || true cat > /etc/apt/sources.list.d/ubuntu.sources </dev/null 2>&1; then echo "gpg absent: installation gnupg minimale." DEBIAN_FRONTEND=noninteractive apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl gnupg fi if [ ! -f /etc/apt/keyrings/google-chrome.gpg ]; then curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg chmod 0644 /etc/apt/keyrings/google-chrome.gpg fi cat > /etc/apt/sources.list.d/google-chrome.sources <<'SRC' Types: deb URIs: https://dl.google.com/linux/chrome/deb/ Suites: stable Components: main Architectures: amd64 Signed-By: /etc/apt/keyrings/google-chrome.gpg SRC grep -nE 'URIs:|Suites:|Components:|Architectures:|Signed-By:' /etc/apt/sources.list.d/google-chrome.sources || true pco_check "5) Préparation dépôt Google Chrome" pco_step "6) apt-get update" rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* 2>/dev/null || true dpkg --configure -a || true run_spin "apt-get update" apt-get update pco_check "6) apt-get update" pco_step "7) Installation Plymouth" run_spin_bash "Installation Plymouth" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ plymouth \ plymouth-label \ plymouth-themes' pco_check "7) Installation Plymouth" pco_step "8) Installation nginx" run_spin_bash "Installation nginx" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ nginx' systemctl enable nginx systemctl restart nginx nginx -t systemctl is-enabled nginx systemctl is-active nginx pco_check "8) Installation nginx" pco_step "9) Installation Python WebApp base" run_spin_bash "Installation Python WebApp base" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ python3 \ python3-pip \ python3-venv \ python3-flask \ python3-requests \ python3-yaml \ python3-psutil' python3 --version pip3 --version pco_check "9) Installation Python WebApp base" pco_step "10) Installation X11 LightDM Openbox" echo "Réparation dpkg/apt avant X11..." dpkg --configure -a || true apt-get -f install -y || true run_spin_bash "Installation X11 core" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ xorg \ xserver-xorg \ xserver-xorg-core \ xserver-xorg-video-all \ xserver-xorg-input-all \ xinit \ x11-xserver-utils \ x11-utils' echo "Préseed Ubuntu LightDM comme display-manager par défaut" printf 'lightdm shared/default-x-display-manager select lightdm\n' | debconf-set-selections || true printf 'lightdm lightdm/daemon_name string /usr/sbin/lightdm\n' | debconf-set-selections || true echo "Nettoyage config LightDM cassée avant installation Ubuntu" rm -f /etc/lightdm/lightdm.conf.d/50-pincabos.conf.dpkg-* 2>/dev/null || true rm -f /etc/lightdm/lightdm.conf.d/50-pincabos-autologin.conf.dpkg-* 2>/dev/null || true rm -f /etc/lightdm/lightdm.conf.d/*.ucf-* 2>/dev/null || true run_spin_bash "Installation LightDM Ubuntu sans prompt dpkg" 'export NEEDRESTART_MODE=a; export UCF_FORCE_CONFFNEW=1; env DEBIAN_FRONTEND=noninteractive apt-get install -y \ -o Dpkg::Options::="--force-confnew" \ -o Dpkg::Options::="--force-confdef" \ lightdm \ lightdm-gtk-greeter' echo "Finalisation dpkg Ubuntu LightDM sans prompt" export NEEDRESTART_MODE=a export UCF_FORCE_CONFFNEW=1 env DEBIAN_FRONTEND=noninteractive dpkg --force-confnew --force-confdef --configure -a || true env DEBIAN_FRONTEND=noninteractive apt-get -f install -y \ -o Dpkg::Options::="--force-confnew" \ -o Dpkg::Options::="--force-confdef" || true run_spin_bash "Installation Openbox + DBus" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ openbox \ dbus-x11 \ dbus-user-session \ xdg-utils' echo "Installation outils graphiques optionnels..." DEBIAN_FRONTEND=noninteractive apt-get install -y \ x11-apps \ obconf \ unclutter \ feh \ mesa-utils || true echo echo "Validation paquets graphiques critiques:" for pkg in xorg xserver-xorg lightdm lightdm-gtk-greeter openbox dbus-x11 dbus-user-session; do if dpkg -s "$pkg" >/dev/null 2>&1; then echo "Check [√] $pkg" else echo "ERREUR: paquet critique manquant: $pkg" exit 1 fi done pco_check "10) Installation X11 LightDM Openbox" pco_step "11) Installation Google Chrome" run_spin_bash "Installation Google Chrome" 'DEBIAN_FRONTEND=noninteractive apt-get install -y google-chrome-stable' pco_check "11) Installation Google Chrome" pco_step "12) Extraction assets media depuis package engine" pco_download_extract_engine_assets pco_check "12) Extraction assets media depuis package engine" pco_step "13) Import assets Plymouth PinCabOS" PLY_STAGE="$STAGE/plymouth" THEME_DIR="/usr/share/plymouth/themes/pincabos" mkdir -p "$PLY_STAGE" "$THEME_DIR" echo "Source assets Plymouth locale:" echo "/opt/pincabos/media/plymouth-assets" echo PLY_ASSETS=( "PCOLoading.png" "pincabos.png" "progress_bar.png" "progress_box.png" "pincabos.plymouth" "pincabos.script" ) for asset in "${PLY_ASSETS[@]}"; do if [ -f "/opt/pincabos/media/plymouth-assets/$asset" ]; then echo "Copie Plymouth asset local: $asset" cp -f "/opt/pincabos/media/plymouth-assets/$asset" "$PLY_STAGE/$asset" else echo "ERREUR: asset Plymouth requis absent après extraction engine: $asset" echo "Chemin attendu: /opt/pincabos/media/plymouth-assets/$asset" exit 1 fi if [ ! -s "$PLY_STAGE/$asset" ]; then echo "ERREUR: asset Plymouth vide ou introuvable: $asset" exit 1 fi file "$PLY_STAGE/$asset" || true done cp -av "$PLY_STAGE"/* "$THEME_DIR"/ chmod 644 "$THEME_DIR"/* pco_check "13) Import assets Plymouth PinCabOS" pco_step "14) Validation assets Plymouth PinCabOS" echo "Dossier thème: $THEME_DIR" echo echo "=== Fichiers importés ===" find "$THEME_DIR" -maxdepth 1 -type f \ \( -iname "*.png" -o -iname "*.plymouth" -o -iname "*.script" \) \ -printf '%m %s bytes %p\n' 2>/dev/null | sort echo echo "=== Validation fichiers requis ===" for f in \ "$THEME_DIR/PCOLoading.png" \ "$THEME_DIR/pincabos.png" \ "$THEME_DIR/progress_bar.png" \ "$THEME_DIR/progress_box.png" \ "$THEME_DIR/pincabos.plymouth" \ "$THEME_DIR/pincabos.script" do if [ ! -s "$f" ]; then echo "ERREUR: fichier Plymouth requis absent ou vide: $f" exit 1 fi echo "Check [√] $f" done echo echo "=== Validation fichier .plymouth ===" grep -nE 'ImageDir=|ScriptFile=|ModuleName=' "$THEME_DIR/pincabos.plymouth" || true echo echo "=== Validation script Plymouth ===" grep -nE 'PCOLoading\.png|pincabos\.png|progress_bar\.png|progress_box\.png|SetBootProgressFunction|Image\.Rectangle|Scale' "$THEME_DIR/pincabos.script" || true pco_check "14) Validation assets Plymouth PinCabOS" pco_step "15) Activation thème Plymouth PinCabOS" update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "$THEME_DIR/pincabos.plymouth" 600 update-alternatives --set default.plymouth "$THEME_DIR/pincabos.plymouth" if command -v plymouth-set-default-theme >/dev/null 2>&1; then plymouth-set-default-theme pincabos || true else echo "Info: plymouth-set-default-theme absent, utilisation de update-alternatives seulement." fi readlink -f /usr/share/plymouth/themes/default.plymouth || true update-alternatives --display default.plymouth || true if [ -f /etc/default/grub ]; then cp -a /etc/default/grub "/opt/pincabos/config/backups/grub-plymouth-${TS}.backup" 2>/dev/null || true if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub; then sed -i -E 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' /etc/default/grub else echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"' >> /etc/default/grub fi grep '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub || true fi run_spin "update-initramfs" update-initramfs -u if command -v update-grub >/dev/null 2>&1; then run_spin "update-grub" update-grub || true fi pco_check "15) Activation thème Plymouth PinCabOS" pco_step "15B) Activation thème Plymouth temporaire installation" pco_install_temporary_plymouth_theme pco_check "15B) Activation thème Plymouth temporaire installation" pco_step "16) Validation wallpapers PinCabOS" WALL_DIR="/opt/pincabos/media/wallpapers" mkdir -p "$WALL_DIR" for img in \ PCOSPFWall.png \ PCOSBGWall.png \ PCOSDMDWall.png do if [ ! -s "$WALL_DIR/$img" ]; then echo "ERREUR: wallpaper requis absent après extraction engine: $img" echo "Chemin attendu: $WALL_DIR/$img" exit 1 fi file "$WALL_DIR/$img" || true done chmod 644 "$WALL_DIR"/*.png pco_check "16) Validation wallpapers PinCabOS" pco_step "17) Création session X11 PinCabOS Openbox" install -d -m 0755 /usr/share/xsessions cat > /usr/share/xsessions/pincabos-openbox.desktop <<'DESK' [Desktop Entry] Name=PinCabOS Openbox Comment=PinCabOS X11 Openbox Session Exec=openbox-session TryExec=openbox-session Type=Application DesktopNames=OPENBOX DESK if [ ! -f /etc/X11/Xwrapper.config ]; then install -d -m 0755 /etc/X11 cat > /etc/X11/Xwrapper.config <<'XWRAP' allowed_users=anybody needs_root_rights=yes XWRAP fi pco_check "17) Création session X11 PinCabOS Openbox" pco_step "18) Configuration LightDM autologin pinball" id pinball >/dev/null 2>&1 || useradd -m -s /bin/bash pinball install -d -m 0755 /etc/lightdm/lightdm.conf.d cat > /etc/lightdm/lightdm.conf.d/50-pincabos.conf <<'LDM' [Seat:*] autologin-user=pinball autologin-user-timeout=0 user-session=pincabos-openbox greeter-session=lightdm-gtk-greeter allow-guest=false LDM usermod -aG video,audio,input,render,tty pinball 2>/dev/null || true pco_check "18) Configuration LightDM autologin pinball" # === PINCABOS FIX LIGHTDM AUTOLOGIN ROBUST START === pco_step "18B) Fix robuste LightDM autologin pinball" id pinball >/dev/null 2>&1 || useradd -m -s /bin/bash pinball passwd -d pinball 2>/dev/null || true usermod -aG audio,video,input,plugdev,dialout,tty pinball 2>/dev/null || true # LightDM peut utiliser le groupe autologin selon PAM/config distro. if getent group autologin >/dev/null 2>&1; then usermod -aG autologin pinball 2>/dev/null || true fi mkdir -p /usr/share/xsessions /home/pinball/.config/openbox /etc/lightdm/lightdm.conf.d cat > /usr/share/xsessions/pincabos-openbox.desktop <<'EOF_XSESSION' [Desktop Entry] Name=PinCabOS Openbox Comment=PinCabOS Openbox Session Exec=/usr/local/bin/pincabos-openbox-session Type=Application EOF_XSESSION cat > /usr/local/bin/pincabos-openbox-session <<'EOF_SESSION' #!/usr/bin/env bash export HOME="/home/pinball" export USER="pinball" export LOGNAME="pinball" export DISPLAY="${DISPLAY:-:0}" export XDG_CONFIG_HOME="/home/pinball/.config" xset s off -dpms 2>/dev/null || true unclutter -idle 0.5 -root 2>/dev/null & if command -v openbox-session >/dev/null 2>&1; then exec openbox-session fi exec openbox EOF_SESSION chmod 755 /usr/local/bin/pincabos-openbox-session cat > /home/pinball/.config/openbox/autostart <<'EOF_AUTOSTART' #!/usr/bin/env bash export DISPLAY="${DISPLAY:-:0}" xset s off -dpms 2>/dev/null || true unclutter -idle 0.5 -root 2>/dev/null & if command -v google-chrome >/dev/null 2>&1; then google-chrome \ --no-first-run \ --disable-session-crashed-bubble \ --start-fullscreen \ --kiosk \ http://127.0.0.1/ & fi EOF_AUTOSTART chmod 755 /home/pinball/.config/openbox/autostart chown -R pinball:pinball /home/pinball/.config cat > /etc/lightdm/lightdm.conf <<'EOF_LIGHTDM' [LightDM] run-directory=/run/lightdm [Seat:*] greeter-session=lightdm-gtk-greeter user-session=pincabos-openbox autologin-user=pinball autologin-user-timeout=0 autologin-session=pincabos-openbox allow-guest=false greeter-hide-users=true greeter-show-manual-login=false EOF_LIGHTDM cat > /etc/lightdm/lightdm.conf.d/50-pincabos-autologin.conf <<'EOF_LIGHTDM_DROPIN' [Seat:*] user-session=pincabos-openbox autologin-user=pinball autologin-user-timeout=0 autologin-session=pincabos-openbox allow-guest=false greeter-hide-users=true greeter-show-manual-login=false EOF_LIGHTDM_DROPIN # Écraser aussi l'ancien fichier 50-pincabos.conf si présent. cat > /etc/lightdm/lightdm.conf.d/50-pincabos.conf <<'EOF_LIGHTDM_OLD_COMPAT' [Seat:*] user-session=pincabos-openbox autologin-user=pinball autologin-user-timeout=0 autologin-session=pincabos-openbox allow-guest=false greeter-hide-users=true greeter-show-manual-login=false EOF_LIGHTDM_OLD_COMPAT chmod 644 /etc/lightdm/lightdm.conf /etc/lightdm/lightdm.conf.d/50-pincabos-autologin.conf /etc/lightdm/lightdm.conf.d/50-pincabos.conf systemctl set-default graphical.target 2>/dev/null || true systemctl enable lightdm.service 2>/dev/null || true systemctl daemon-reload 2>/dev/null || true echo "LightDM autologin pinball forcé." grep -RInE "autologin-user|autologin-session|user-session|greeter-hide-users|greeter-show-manual-login" /etc/lightdm || true ls -lah /usr/share/xsessions/pincabos-openbox.desktop /usr/local/bin/pincabos-openbox-session || true id pinball || true pco_check "18B) Fix robuste LightDM autologin pinball" # === PINCABOS FIX LIGHTDM AUTOLOGIN ROBUST END === pco_step "19) Configuration Openbox pinball" install -d -o pinball -g pinball -m 0755 /home/pinball/.config/openbox if [ ! -f /home/pinball/.config/openbox/autostart ]; then cat > /home/pinball/.config/openbox/autostart <<'OB' #!/usr/bin/env bash xset -dpms xset s off xset s noblank unclutter -idle 1 -root & # PinCabOS WebApp / dashboard peut être lancé plus tard par service dédié. OB fi if [ ! -f /home/pinball/.config/openbox/rc.xml ] && [ -f /etc/xdg/openbox/rc.xml ]; then cp -a /etc/xdg/openbox/rc.xml /home/pinball/.config/openbox/rc.xml fi chown -R pinball:pinball /home/pinball/.config chmod +x /home/pinball/.config/openbox/autostart pco_check "19) Configuration Openbox pinball" pco_step "20) Déploiement Chrome X11" install -d -o pinball -g pinball -m 0755 /home/pinball/.config/google-chrome install -d -o pinball -g pinball -m 0755 /home/pinball/.config/autostart cat > /usr/local/bin/pincabos-chrome-x11 <<'CHROME' #!/usr/bin/env bash export DISPLAY="${DISPLAY:-:0}" export XAUTHORITY="${XAUTHORITY:-/home/pinball/.Xauthority}" export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/1000/bus}" exec google-chrome \ --no-first-run \ --disable-session-crashed-bubble \ --disable-gpu \ --disable-dev-shm-usage \ --disable-features=UseChromeOSDirectVideoDecoder \ --ignore-gpu-blocklist \ "$@" CHROME chmod +x /usr/local/bin/pincabos-chrome-x11 cat > /usr/share/applications/pincabos-chrome-x11.desktop <<'DESK' [Desktop Entry] Name=PinCabOS Chrome X11 Comment=Launch Google Chrome for PinCabOS X11 Exec=/usr/local/bin/pincabos-chrome-x11 Terminal=false Type=Application Categories=Network;WebBrowser; DESK pco_check "20) Déploiement Chrome X11" pco_step "21) Activation services graphiques" systemctl set-default graphical.target systemctl enable lightdm systemctl restart dbus || true pco_check "21) Activation services graphiques" pco_step "22) Validation finale système graphique" echo "Plymouth:" readlink -f /usr/share/plymouth/themes/default.plymouth || true update-alternatives --display default.plymouth 2>/dev/null || true echo echo "LightDM:" systemctl is-enabled lightdm || true systemctl status lightdm --no-pager -l | sed -n '1,14p' || true echo echo "Openbox:" command -v openbox || true ls -lah /usr/share/xsessions || true echo echo "Chrome:" command -v google-chrome || true google-chrome --version || true echo echo "Log: $LOG" echo "Assets: $STAGE" pco_check "22) Validation finale système graphique" pco_step "23) Validation nginx et Python" echo "nginx:" nginx -v nginx -t systemctl is-enabled nginx systemctl is-active nginx echo echo "Python:" python3 --version pip3 --version python3 - <<'PYTEST' mods = ["flask", "requests", "yaml", "psutil", "venv"] for mod in mods: __import__(mod) print(f"Module Python OK: {mod}") PYTEST pco_check "23) Validation nginx et Python" pco_step "24) Résumé final" echo "Plymouth: installé/configuré" echo "Dépôts originaux: restaurés/protégés" echo "nginx: $(nginx -v 2>&1 || true)" echo "nginx service enabled: $(systemctl is-enabled nginx 2>/dev/null || true)" echo "nginx service active : $(systemctl is-active nginx 2>/dev/null || true)" echo "Python: $(python3 --version 2>&1 || true)" echo "pip: $(pip3 --version 2>&1 || true)" echo "LightDM: installé/activé" echo "Openbox: installé/configuré" echo "X11: installé" echo "Chrome: installé/déployé" echo "Espace utilisé système : $(df -h / | awk 'NR==2 {print $3}')" echo "Espace disponible : $(df -h / | awk 'NR==2 {print $4}')" echo "Utilisation système : $(df -h / | awk 'NR==2 {print $5}')" echo "Update assets: $STAGE" echo "Backup APT: $APT_BACKUP" pco_check "24) Résumé final"