#!/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 # === PinCabOS colored step helpers + final summary === PCO_CURRENT_STEP="" PCO_STEPS=() PCO_STATUS=() PCO_FINAL_SUMMARY_DONE=0 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" # Titre: lignes cyan, titre orange printf " ${CYAN}─[%s]─►${ORANGE} %s ${CYAN}◄────${RESET} " "$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 # Check: ligne complète verte printf "${GREEN}─[%s]─► %s ◄──── Check [√]${RESET} " "$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 if command -v show_splash >/dev/null 2>&1; then show_splash || true elif [ -x /etc/update-motd.d/00-pincabos ]; then /etc/update-motd.d/00-pincabos || true fi echo printf "${CYAN}────────────────────────────────────────────────────────────────${RESET} " printf "${ORANGE}Résumé complet des checks PinCabOS - %s${RESET} " "$(basename "$0")" printf "${CYAN}────────────────────────────────────────────────────────────────${RESET} " for i in "${!PCO_STEPS[@]}"; do pco_split_step "${PCO_STEPS[$i]}" case "${PCO_STATUS[$i]}" in OK) printf "${GREEN}─[%s]─► %s ◄──── Check [√]${RESET} " "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; FAIL|RUNNING) failed=1 printf "${RED}─[%s]─► %s ◄──NOGOOD [X]${RESET} " "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; *) failed=1 printf "${RED}─[%s]─► %s ◄──NOGOOD [X]${RESET} " "$PCO_STEP_NUM" "$PCO_STEP_TITLE" ;; esac done printf "${CYAN}────────────────────────────────────────────────────────────────${RESET} " if [ "$failed" -eq 0 ] && [ "$exit_code" -eq 0 ]; then printf "${GREEN}Tous les checks sont réussis. PinCabOS admin install OK.${RESET} " else printf "${RED}Un ou plusieurs checks ont échoué. Code retour: %s${RESET} " "$exit_code" fi printf "${CYAN}────────────────────────────────────────────────────────────────${RESET} " echo } 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 } clear || true ORANGE="\033[38;5;208m" PURPLE="\033[38;5;129m" WHITE="\033[97m" RESET="\033[0m" show_splash() { if [ -x /etc/update-motd.d/00-pincabos ]; then /etc/update-motd.d/00-pincabos || true elif [ -x /opt/pincabos/install/00-pincabos-splash.sh ]; then /opt/pincabos/install/00-pincabos-splash.sh || true else echo "=== PinCabOS - VMDev Admin Installer ===" fi } show_splash pco_title "PinCabOS - 00-install-admin.sh" pco_title "APT clean + SSH root + password + splash" echo 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/00-install-admin-${TS}.log" exec > >(tee -a "$LOG") 2>&1 echo pco_step "1) Préparation dossiers PinCabOS" mkdir -p /opt/pincabos/{install,logs,config,tools,essentials,apps,web} chmod 755 /opt/pincabos /opt/pincabos/install /opt/pincabos/logs /opt/pincabos/config echo pco_check "1) Préparation dossiers PinCabOS" pco_step "2) Informations système" date hostnamectl || true lsb_release -a || true uname -a || true echo pco_check "2) Informations système" pco_step "3) Backup APT" mkdir -p "/opt/pincabos/config/apt-backup-${TS}" cp -a /etc/apt/sources.list "/opt/pincabos/config/apt-backup-${TS}/sources.list" 2>/dev/null || true cp -a /etc/apt/sources.list.d "/opt/pincabos/config/apt-backup-${TS}/sources.list.d" 2>/dev/null || true cp -a /etc/apt/preferences.d "/opt/pincabos/config/apt-backup-${TS}/preferences.d" 2>/dev/null || true echo pco_check "3) Backup APT" pco_step "4) Désactivation dépôts tiers non essentiels" mkdir -p /etc/apt/sources.list.d.disabled-pincabos 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|official-package-repositories.list) echo "Garde dépôt officiel Ubuntu: $src" ;; google-chrome.list|google-chrome.sources) echo "Garde dépôt Google Chrome: $src" ;; *) echo "Désactive dépôt tiers: $src" mv "$src" "/etc/apt/sources.list.d.disabled-pincabos/${base}.disabled-${TS}" || true ;; esac done echo pco_check "4) Désactivation dépôts tiers non essentiels" pco_step "5) Déblocage / réparation APT-DPKG" rm -f /var/lib/apt/lists/lock /var/cache/apt/archives/lock /var/lib/dpkg/lock* 2>/dev/null || true run_spin "dpkg --configure -a" dpkg --configure -a || true echo pco_check "5) Déblocage / réparation APT-DPKG" pco_step "6) apt-get update" run_spin "apt-get update" apt-get update pco_check "6) apt-get update" pco_step "7) apt-get upgrade -y" run_spin_bash "apt-get upgrade" "DEBIAN_FRONTEND=noninteractive apt-get upgrade -y" pco_check "7) apt-get upgrade -y" pco_step "8) Installation essentiels PinCabOS admin/base" run_spin_bash "apt-get install essentiels PinCabOS" 'DEBIAN_FRONTEND=noninteractive apt-get install -y \ ca-certificates \ curl \ wget \ git \ gnupg \ lsb-release \ software-properties-common \ apt-transport-https \ openssh-server \ rsync \ unzip \ zip \ zstd \ tar \ nano \ htop \ jq \ pciutils \ usbutils \ lshw \ net-tools \ iproute2 \ iputils-ping \ dnsutils \ traceroute \ bash-completion' pco_check "8) Installation essentiels PinCabOS admin/base" pco_step "9) Cleanup paquets/services non essentiels à PinCabOS" PURGE_PKGS=( snapd apport whoopsie popularity-contest ubuntu-report cups cups-browsed avahi-daemon avahi-autoipd bluetooth bluez modemmanager speech-dispatcher brltty unattended-upgrades ) for pkg in "${PURGE_PKGS[@]}"; do if dpkg -l "$pkg" >/dev/null 2>&1; then echo "Purge: $pkg" run_spin_bash "Purge $pkg" "DEBIAN_FRONTEND=noninteractive apt-get purge -y $pkg" || true else echo "Absent: $pkg" fi done echo pco_check "9) Cleanup paquets/services non essentiels à PinCabOS" pco_step "10) Désactivation services non essentiels si présents" DISABLE_SERVICES=( apt-daily.service apt-daily.timer apt-daily-upgrade.service apt-daily-upgrade.timer cups.service cups.socket cups-browsed.service avahi-daemon.service avahi-daemon.socket bluetooth.service ModemManager.service whoopsie.service apport.service ) for svc in "${DISABLE_SERVICES[@]}"; do if systemctl list-unit-files "$svc" >/dev/null 2>&1; then echo "Disable/mask: $svc" systemctl disable --now "$svc" 2>/dev/null || true systemctl mask "$svc" 2>/dev/null || true fi done echo pco_check "10) Désactivation services non essentiels si présents" pco_step "11) Bloquer retour des paquets inutiles dans les prochains upgrades" cat > /etc/apt/preferences.d/99-pincabos-block-unwanted <<'PREF' Package: snapd apport whoopsie popularity-contest ubuntu-report cups cups-browsed avahi-daemon avahi-autoipd bluetooth bluez modemmanager speech-dispatcher brltty unattended-upgrades Pin: release * Pin-Priority: -1 PREF echo pco_check "11) Bloquer retour des paquets inutiles dans les prochains upgrades" pco_step "12) Nettoyage APT" DEBIAN_FRONTEND=noninteractive apt-get autoremove --purge -y apt-get autoclean -y apt-get clean -y echo pco_check "12) Nettoyage APT" pco_step "13) Refaire le catalogue / manifest PinCabOS APT" cat > /opt/pincabos/config/pincabos-apt-essential-packages.txt <<'PKGS' ca-certificates curl wget git gnupg lsb-release software-properties-common apt-transport-https openssh-server rsync unzip zip zstd tar nano htop jq pciutils usbutils lshw net-tools iproute2 iputils-ping dnsutils traceroute bash-completion PKGS dpkg-query -W -f='${Package}\t${Version}\t${Status}\n' > "/opt/pincabos/config/apt-installed-full-${TS}.manifest" apt-mark showmanual | sort > "/opt/pincabos/config/apt-manual-${TS}.manifest" while read -r pkg; do [ -z "$pkg" ] && continue apt-mark manual "$pkg" >/dev/null 2>&1 || true done < /opt/pincabos/config/pincabos-apt-essential-packages.txt apt-mark showmanual | sort > "/opt/pincabos/config/apt-manual-after-pincabos-${TS}.manifest" echo pco_check "13) Refaire le catalogue / manifest PinCabOS APT" pco_step "14) Validation APT finale" run_spin "apt-get update" apt-get update apt-get check echo pco_check "14) Validation APT finale" pco_step "15) Activation SSH" systemctl enable --now ssh echo pco_check "15) Activation SSH" pco_step "16) Changement du mot de passe root" echo "Étape retirée: aucun changement de mot de passe root pendant l'installation automatique." echo "Mot de passe root inchangé." pco_check "16) Changement du mot de passe root" pco_step "17) Backup configuration SSH" mkdir -p "/opt/pincabos/config/ssh-backup-${TS}" cp -a /etc/ssh/sshd_config "/opt/pincabos/config/ssh-backup-${TS}/sshd_config" 2>/dev/null || true cp -a /etc/ssh/sshd_config.d "/opt/pincabos/config/ssh-backup-${TS}/sshd_config.d" 2>/dev/null || true echo pco_check "17) Backup configuration SSH" pco_step "18) Désactiver l'autorisation SSH root" mkdir -p /etc/ssh/sshd_config.d rm -f /etc/ssh/sshd_config.d/99-pincabos-root-login.conf 2>/dev/null || true cat > /etc/ssh/sshd_config.d/99-pincabos-no-root-login.conf <<'SSHCONF' PermitRootLogin no PasswordAuthentication yes KbdInteractiveAuthentication yes UsePAM yes SSHCONF if grep -Eq "^[#[:space:]]*PermitRootLogin[[:space:]]+" /etc/ssh/sshd_config; then sed -i -E 's|^[#[:space:]]*PermitRootLogin[[:space:]]+.*|PermitRootLogin no|g' /etc/ssh/sshd_config else echo "PermitRootLogin no" >> /etc/ssh/sshd_config fi # On garde PasswordAuthentication pour les utilisateurs normaux, mais root reste interdit. if grep -Eq "^[#[:space:]]*PasswordAuthentication[[:space:]]+" /etc/ssh/sshd_config; then sed -i -E 's|^[#[:space:]]*PasswordAuthentication[[:space:]]+.*|PasswordAuthentication yes|g' /etc/ssh/sshd_config else echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config fi echo pco_check "18) Désactiver l'autorisation SSH root" pco_step "19) Validation SSH" sshd -t echo pco_check "19) Validation SSH" pco_step "20) Redémarrage SSH" systemctl restart ssh echo pco_check "20) Redémarrage SSH" pco_step "21) Installation du splash ASCII système" cat > /etc/update-motd.d/00-pincabos <<'MOTD' #!/usr/bin/env bash ORANGE="\033[38;5;208m" PURPLE="\033[38;5;129m" WHITE="\033[97m" RESET="\033[0m" printf "${ORANGE}\n" cat <<'SPLASH' ██████╗ ██╗███╗ ██╗ ██████╗ █████╗ ██████╗ ██████╗ ███████╗ ██╔══██╗██║████╗ ██║██╔════╝██╔══██╗██╔══██╗██╔═══██╗██╔════╝ ██████╔╝██║██╔██╗ ██║██║ ███████║██████╔╝██║ ██║███████╗ ██╔═══╝ ██║██║╚██╗██║██║ ██╔══██║██╔══██╗██║ ██║╚════██║ ██║ ██║██║ ╚████║╚██████╗██║ ██║██████╔╝╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝ SPLASH printf "${RESET}\n" printf "${ORANGE} Ultimate VPinball Linux Cabinet System${RESET}\n" printf "${PURPLE} Karots Sugarpie${RESET}\n" printf "\n" MOTD chmod +x /etc/update-motd.d/00-pincabos cp -a /etc/update-motd.d/00-pincabos /opt/pincabos/install/00-pincabos-splash.sh chmod +x /opt/pincabos/install/00-pincabos-splash.sh echo pco_check "21) Installation du splash ASCII système" pco_step "22) État SSH" systemctl status ssh --no-pager -l | sed -n '1,14p' || true echo echo printf "${CYAN}=== Prompt console PinCabOS coloré ===${RESET}\n" cat > /etc/profile.d/pincabos-color-prompt.sh <<'PROMPT' #!/usr/bin/env bash # PinCabOS colored shell prompt # root = rouge, @ = mauve, hostname = orange, pinball = vert case "$-" in *i*) ;; *) return 0 2>/dev/null || exit 0 ;; esac RED='\[\033[1;31m\]' PURPLE='\[\033[38;5;93m\]' ORANGE='\[\033[38;5;208m\]' GREEN='\[\033[1;32m\]' BLUE='\[\033[1;34m\]' RESET='\[\033[0m\]' HOST_LABEL="PinCabOs" if [ "$(id -u)" -eq 0 ]; then PS1="${RED}\u${PURPLE}@${ORANGE}${HOST_LABEL}${RESET}:${BLUE}\w${RESET}# " elif [ "$USER" = "pinball" ]; then PS1="${GREEN}\u${PURPLE}@${ORANGE}${HOST_LABEL}${RESET}:${BLUE}\w${RESET}$ " else PS1="${GREEN}\u${PURPLE}@${ORANGE}${HOST_LABEL}${RESET}:${BLUE}\w${RESET}$ " fi PROMPT chmod +x /etc/profile.d/pincabos-color-prompt.sh # Appliquer aussi dans root et pinball pour les shells bash classiques cat >> /root/.bashrc <<'ROOTBASH' # PinCabOS colored prompt [ -f /etc/profile.d/pincabos-color-prompt.sh ] && source /etc/profile.d/pincabos-color-prompt.sh ROOTBASH if id pinball >/dev/null 2>&1; then cat >> /home/pinball/.bashrc <<'PINBALLBASH' # PinCabOS colored prompt [ -f /etc/profile.d/pincabos-color-prompt.sh ] && source /etc/profile.d/pincabos-color-prompt.sh PINBALLBASH chown pinball:pinball /home/pinball/.bashrc fi printf "${ORANGE}Prompt PinCabOS installé.${RESET}\n" printf "${GRAY}Root:${RESET} rouge | ${GRAY}@:${RESET} mauve | ${GRAY}PinCabOs:${RESET} orange | ${GRAY}pinball:${RESET} vert\n" pco_check "22) État SSH" pco_step "23) Résumé final" echo "APT update/upgrade: OK" echo "Cleanup non essentiels: OK" echo "Catalogue APT PinCabOS: OK" echo "SSH root password: DÉSACTIVÉ" echo "Mot de passe root: INCHANGÉ" echo "Splash ASCII système: INSTALLÉ" echo echo "Log: $LOG" echo "APT backup: /opt/pincabos/config/apt-backup-${TS}" echo "SSH backup: /opt/pincabos/config/ssh-backup-${TS}" echo "Manifest complet: /opt/pincabos/config/apt-installed-full-${TS}.manifest" echo "Manifest essentiels: /opt/pincabos/config/pincabos-apt-essential-packages.txt" echo echo "Test SSH:" echo "ssh pinball@IP_DE_TA_VMDEV" pco_check "23) Résumé final"