Inventaire, mise à jour et nettoyage contrôlé des versions installées.
Linux Kernel Scripts
Scripts Bash pour fiabiliser le cycle de vie des noyaux Linux Mint.
Ce que le projet démontre
Simulation complète avant toute modification du système.
Conservation d’une stratégie de retour arrière avec GRUB.
Historique horodaté des décisions et commandes exécutées.
Description
Linux Kernel Scripts est une suite d’outils Bash destinée à encadrer les opérations sensibles autour des noyaux Linux Mint. Le principe est de rendre chaque action lisible, vérifiable et réversible avant de toucher au système.
Les scripts utilisent le strict mode Bash, distinguent clairement simulation et exécution réelle, et demandent une confirmation avant les étapes destructives. Le nettoyage conserve toujours des noyaux de secours afin de limiter le risque après une mise à jour.
La journalisation permet de retrouver ce qui a été détecté, installé ou supprimé. Le projet illustre une approche d’administration système basée sur l’automatisation prudente plutôt que sur une succession de commandes manuelles.
Fonctionnalités & points techniques
- ▹Détection des noyaux installés et disponibles.
- ▹Installation contrôlée avec vérifications préalables.
- ▹Nettoyage des versions obsolètes tout en conservant un secours.
- ▹Mode --dry-run pour prévisualiser toutes les actions.
- ▹Bash strict mode : set -Eeuo pipefail.
- ▹Confirmation avant les opérations destructives.
- ▹Journalisation horodatée des opérations.
- ▹Aide au rollback et gestion de GRUB.
Extraits des scripts Kernel Auto Cleaner PRO et fullupdate
Extraits représentatifs de Kernel Auto Cleaner PRO v5.7, un script Bash d’administration destiné à sécuriser la maintenance, la conservation et le nettoyage des noyaux Linux. Le script fullupdate v1.5 complète l’ensemble en orchestrant les mises à jour APT, deb-get, Flatpak, Snap, firmware et pipx.
Initialisation, journalisation et verrouillage
Strict mode Bash, journalisation, rotation des logs, verrouillage exclusif et gestion de la ligne de commande.
#!/usr/bin/env bash# =============================================================================# kernel_auto_cleaner_pro — v5.7# -----------------------------------------------------------------------------# Changelog v5.7 vs v5.6 (correctifs issus des tests sur machine réelle):# - set -e: header() et check_boot_full() n'utilisent plus `[[ ]] && log`# (le script s'arrêtait juste après le header hors dry-run)# - set -e: `(( ++REMOVED_COUNT ))` au lieu de `(( REMOVED_COUNT++ ))`# (le post-incrément valait 0 au 1er kernel purgé -> arrêt du script)# - Dry-run: ensure_headers_for / ensure_modules_extra_for n'appellent plus apt# - apt update/install/purge: sortie capturée via log() + DEBIAN_FRONTEND=noninteractive# - apt autoremove: uniquement si au moins un kernel est à supprimer# - modules-extra: test du Candidate réel (apt-cache policy, LC_ALL=C) au lieu de# apt-cache show, qui réussit pour un paquet sans version installable# - GRUB: grub-set-default ignoré si GRUB_DEFAULT n'est pas "saved" (sans effet sinon)# - KEEP_BRANCH6_PREFIX="6.8": conserve le kernel GA 24.04 (support jusqu'en 2029)# et non plus "le dernier 6.x", qui peut être un HWE abandonné# -----------------------------------------------------------------------------# Changelog v5.6 vs v5.5:# - DRYRUN: standardise toutes les comparaisons sur [[ "$DRYRUN" == "true" ]]# (plus de $DRYRUN || ... mélangé avec [[ "$DRYRUN" == true ]])# - rotate_log() extraite de header() (séparation des responsabilités)# - CLI: --help, --version, --keep-kernels N# - Attente du verrou APT (apt_wait_lock) avant chaque appel apt# - apt_install_safe: --no-install-recommends par défaut# - stats(): compteur de kernels supprimés affiché# - Trap SIGINT/SIGTERM pour sortie propre# - clean_apt_kernel_archives: suppression du double-check keep_regex redondant# - Messages de log uniformisés en anglais# - detect_kernels: sed simplifié en une passe# - Correction: flock libère correctement le lockfile à EXIT# =============================================================================set -Eeuo pipefailIFS=$'\n\t'VERSION="5.7"HOST="$(hostname)"LOG="/var/log/kernel_cleaner.log"LOCKFILE="/run/kernel_auto_cleaner.lock"# ---- Logging ----------------------------------------------------------------log() { local ts ts="$(date +"%F %T")" echo "[$ts] $*" | tee -a "$LOG"}die() { log "ERROR: $*" exit 1}# ---- Log rotation (séparée de header) ---------------------------------------rotate_log() { if [[ -f "$LOG" ]]; then local size size="$(stat -c%s "$LOG" 2>/dev/null || echo 0)" if (( size > 1048576 )); then local rotated="$LOG.$(date +%Y%m%d%H%M%S)" mv "$LOG" "$rotated" gzip -f "$rotated" 2>/dev/null || true fi fi}# ---- Lock -------------------------------------------------------------------acquire_lock() { exec 9>"$LOCKFILE" # Libère le lockfile à la sortie (succès ou erreur) trap 'rm -f "$LOCKFILE"; exit' EXIT INT TERM if ! flock -n 9; then echo "Another instance is running (lock: $LOCKFILE)" exit 1 fi}# ---- CLI --------------------------------------------------------------------usage() { cat <<EOFUsage: $(basename "$0") [OPTIONS]Options: --dry-run Simulate all actions, no changes applied --keep-kernels N Number of recent kernels to keep (default: $KEEP_KERNELS) --version Print version and exit --help Show this helpEOF exit 0}# ---- Policy -----------------------------------------------------------------SAFE_VMWARE_PREFIX="7.0"KEEP_BRANCH6_PREFIX="6.8" # kernel GA Ubuntu 24.04, supporté jusqu en 2029KEEP_KERNELS=1AUTO_INSTALL_SAFE_KERNEL=trueAUTO_MARK_SAFE_MANUAL=trueDO_VBOX_REBUILD=trueDO_VMWARE_REBUILD=trueBOOT_WARN_PCT=90DRYRUN=false# Parse argumentswhile [[ $# -gt 0 ]]; do case "${1:-}" in --dry-run) DRYRUN=true ;; --keep-kernels) shift; KEEP_KERNELS="${1:?'--keep-kernels requires a value'}" ;; --version) echo "kernel_auto_cleaner_pro v$VERSION"; exit 0 ;; --help|-h) usage ;; *) echo "Unknown option: $1"; usage ;; esac shiftdoneGestion sécurisée d’APT
Attente des verrous APT et fonctions sécurisées pour les mises à jour, installations et suppressions.
# ---- Helpers ----------------------------------------------------------------header() { echo echo "==========================================" echo " Kernel Auto Cleaner PRO v$VERSION" echo " Host: $HOST" echo "==========================================" echo " Running kernel: $(uname -r)" echo "==========================================" # NE PAS utiliser [[ ]] && log : si DRYRUN=false, la fonction retourne 1 # et set -e arrête le script juste après le header. if [[ "$DRYRUN" == "true" ]]; then log "DRY RUN mode — no changes will be applied" fi}require_root() { if [[ ${EUID} -ne 0 ]]; then echo "Run as root" exit 1 fi}has_cmd() { command -v "$1" >/dev/null 2>&1; }pkg_installed() { dpkg-query -W -f='${Status}\n' "$1" 2>/dev/null | grep -q "install ok installed"}# Attend que le verrou APT soit libéré (max 120s)apt_wait_lock() { local i=0 while fuser /var/lib/dpkg/lock-frontend /var/cache/apt/archives/lock >/dev/null 2>&1; do if (( i == 0 )); then log "Waiting for APT lock..." fi sleep 5 (( i += 5 )) if (( i >= 120 )); then log "WARNING: APT lock still held after 120s — proceeding anyway" break fi done}apt_update_safe() { apt_wait_lock local out # DEBIAN_FRONTEND=noninteractive empêche apt d'écrire directement sur /dev/tty if ! out="$(DEBIAN_FRONTEND=noninteractive apt-get update -qq 2>&1)"; then log "WARNING: apt update failed" [[ -n "$out" ]] && log " Detail: $out" fi}# --no-install-recommends évite d'installer des paquets non essentielsapt_install_safe() { apt_wait_lock local out if ! out="$(DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "$@" 2>&1)"; then log "WARNING: install failed for packages: $*" log " Detail: $out" fi}apt_purge_safe() { apt_wait_lock local out if ! out="$(DEBIAN_FRONTEND=noninteractive apt-get purge -y "$@" 2>&1)"; then log "WARNING: purge failed for packages: $*" log " Detail: $out" fi}Détection et protection des noyaux
Inventaire des noyaux, détection HWE et constitution de l’ensemble des noyaux protégés.
# ---- HWE detection ----------------------------------------------------------detect_hwe() { local metas metas="$(dpkg-query -W -f='${Package}\n' \ 'linux-generic-hwe-*' 'linux-image-generic-hwe-*' 'linux-headers-generic-hwe-*' \ 2>/dev/null || true)" if [[ -n "$metas" ]]; then log "HWE meta packages detected:" printf "%s\n" "$metas" | tee -a "$LOG" >/dev/null || true else log "HWE meta packages: none detected" fi local mint_hwe mint_hwe="$(dpkg-query -W -f='${Package}\n' 'linux-hwe-*' 2>/dev/null | head -n 50 || true)" if [[ -n "$mint_hwe" ]]; then log "Mint/Ubuntu HWE-related packages detected (linux-hwe-*):" printf "%s\n" "$mint_hwe" | tee -a "$LOG" >/dev/null || true fi}# ---- Kernel discovery -------------------------------------------------------detect_kernels() { CURRENT_KERNEL="$(uname -r)" # Une seule passe sed pour strip linux-image- et unsigned- mapfile -t INSTALLED_KERNELS < <( dpkg-query -W -f='${Package}\n' 'linux-image-*' 2>/dev/null \ | sed -E 's/^linux-image-(unsigned-)?//' \ | grep -E '^[0-9]' \ | sort -u -V ) SAFE_KERNEL="" if (( ${#INSTALLED_KERNELS[@]} > 0 )); then SAFE_KERNEL="$(printf "%s\n" "${INSTALLED_KERNELS[@]}" \ | grep -E "^${SAFE_VMWARE_PREFIX//./\\.}" \ | tail -n1 || true)" fi}detect_mainline_kernel() { if [[ "$CURRENT_KERNEL" =~ 0[0-9]{5} ]]; then log "Mainline kernel detected: $CURRENT_KERNEL" log "Warning: mainline kernels may break DKMS builds" fi}detect_virtualization() { HAS_VMWARE=false HAS_VBOX=false has_cmd vmware-modconfig || has_cmd vmware && HAS_VMWARE=true || true has_cmd vboxmanage && HAS_VBOX=true || true}check_secureboot() { if has_cmd mokutil; then if mokutil --sb-state 2>/dev/null | grep -qi enabled; then log "WARNING: SecureBoot enabled — unsigned modules may fail to load (VMware/VBox DKMS)" fi fi}# ---- Branch 6.x retention --------------------------------------------------detect_branch6_kernel() { BRANCH6_KERNEL="" [[ -z "${KEEP_BRANCH6_PREFIX:-}" ]] && return 0 (( ${#INSTALLED_KERNELS[@]} > 0 )) || return 0 local prefix_re="^${KEEP_BRANCH6_PREFIX//./\\.}\." BRANCH6_KERNEL="$(printf "%s\n" "${INSTALLED_KERNELS[@]}" \ | grep -E "$prefix_re" \ | tail -n1)" || BRANCH6_KERNEL="" if [[ -n "$BRANCH6_KERNEL" ]]; then log "Branch ${KEEP_BRANCH6_PREFIX}.x retention: keeping $BRANCH6_KERNEL" else log "Branch ${KEEP_BRANCH6_PREFIX}.x retention: no kernel found" fi}protect_kernels() { PROTECTED_KERNELS=("$CURRENT_KERNEL") if [[ -n "${SAFE_KERNEL:-}" && "${SAFE_KERNEL}" != "${CURRENT_KERNEL}" ]]; then PROTECTED_KERNELS+=("$SAFE_KERNEL") fi if [[ -n "${BRANCH6_KERNEL:-}" \ && "${BRANCH6_KERNEL}" != "${CURRENT_KERNEL}" \ && "${BRANCH6_KERNEL}" != "${SAFE_KERNEL:-}" ]]; then PROTECTED_KERNELS+=("$BRANCH6_KERNEL") log "Branch 6.x kernel added to protected set: $BRANCH6_KERNEL" fi}is_protected_kernel() { local k="$1" p for p in "${PROTECTED_KERNELS[@]}"; do [[ "$k" == "$p" ]] && return 0 done return 1}Politique de purge sécurisée
Sélection des noyaux conservés, protections de sécurité et nettoyage contrôlé des anciennes versions.
# ---- Purge policy -----------------------------------------------------------REMOVED_COUNT=0purge_old_kernels() { log "Active kernel : $CURRENT_KERNEL" log "VMware-safe : ${SAFE_KERNEL:-none}" if (( ${#INSTALLED_KERNELS[@]} == 0 )); then log "No installed kernel packages detected. Skipping kernel purge." return 0 fi mapfile -t NEWEST < <(printf "%s\n" "${INSTALLED_KERNELS[@]}" | tail -n "$KEEP_KERNELS") KEEP_SET=() KEEP_SET+=("${NEWEST[@]}") KEEP_SET+=("${PROTECTED_KERNELS[@]}") mapfile -t KEEP_SET < <(printf "%s\n" "${KEEP_SET[@]}" | sort -u -V) (( ${#KEEP_SET[@]} >= 1 )) || die "Safety check failed: KEEP_SET is empty" printf "%s\n" "${KEEP_SET[@]}" | grep -qx "$CURRENT_KERNEL" \ || die "Safety check failed: current kernel not in KEEP_SET" log "Installed kernels : ${INSTALLED_KERNELS[*]}" log "Protected kernels : ${PROTECTED_KERNELS[*]}" log "Kernels to keep : ${KEEP_SET[*]}" mapfile -t TO_REMOVE < <( printf "%s\n" "${INSTALLED_KERNELS[@]}" \ | sort -u -V \ | grep -vxFf <(printf "%s\n" "${KEEP_SET[@]}") || true ) if (( ${#TO_REMOVE[@]} == 0 )); then log "No kernels to remove" else log "Kernels to remove : ${TO_REMOVE[*]}" fi local k pkgs p local candidates for k in "${TO_REMOVE[@]}"; do [[ "$k" == "$CURRENT_KERNEL" ]] && { log "HARD STOP: refusing to purge running kernel: $k"; continue; } log "Purging kernel: $k" pkgs=() candidates=( "linux-image-$k" "linux-image-unsigned-$k" "linux-modules-$k" "linux-modules-extra-$k" "linux-headers-$k" "linux-tools-$k" "linux-cloud-tools-$k" ) for p in "${candidates[@]}"; do pkg_installed "$p" && pkgs+=("$p") done if (( ${#pkgs[@]} == 0 )); then log "No installed packages found for kernel: $k" continue fi log "Packages: ${pkgs[*]}" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would purge: ${pkgs[*]}" else apt_purge_safe "${pkgs[@]}" # (( REMOVED_COUNT++ )) évalue à 0 quand count=0 → exit code 1 → set -e crashe # (( ++REMOVED_COUNT )) évalue à la NOUVELLE valeur (≥1) → exit code 0 (( ++REMOVED_COUNT )) fi done if (( ${#TO_REMOVE[@]} > 0 )); then if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: apt autoremove" else apt-get autoremove -y >/dev/null 2>&1 || true fi fi}is_kept_kernel() { local k="$1" printf "%s\n" "${KEEP_SET[@]}" | grep -qx "$k"}DKMS et virtualisation
Contrôles DKMS et reconstruction des modules VMware et VirtualBox après évolution du noyau.
# ---- DKMS ------------------------------------------------------------------clean_dkms() { has_cmd dkms || return 0 log "DKMS status:" dkms status 2>/dev/null | tee -a "$LOG" >/dev/null || true}clean_broken_dkms() { has_cmd dkms || return 0 log "Checking DKMS broken modules (missing dkms.conf)" local mod ver src shopt -s nullglob for mod in /var/lib/dkms/*; do [[ -d "$mod" ]] || continue mod="$(basename "$mod")" for ver in /var/lib/dkms/"$mod"/*; do [[ -d "$ver" ]] || continue ver="$(basename "$ver")" src="/var/lib/dkms/$mod/$ver/source/dkms.conf" if [[ ! -f "$src" ]]; then log "Broken DKMS module: $mod/$ver (missing dkms.conf)" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: dkms remove \"$mod/$ver\" --all" else dkms remove "$mod/$ver" --all >/dev/null 2>&1 || true rm -rf "/var/lib/dkms/$mod/$ver" fi fi done done shopt -u nullglob}clean_dkms_orphans() { log "Checking DKMS orphan builds" shopt -s nullglob local mod ver build k for mod in /var/lib/dkms/*; do [[ -d "$mod" ]] || continue mod="$(basename "$mod")" for ver in /var/lib/dkms/"$mod"/*; do [[ -d "$ver" ]] || continue ver="$(basename "$ver")" for build in /var/lib/dkms/"$mod"/"$ver"/*; do [[ -d "$build" ]] || continue k="$(basename "$build")" [[ "$k" == "source" || "$k" == "build" || "$k" == "kernel" ]] && continue if [[ ! -d "/lib/modules/$k" && ! -d "/usr/lib/modules/$k" ]]; then log "Removing DKMS orphan build: $mod/$ver/$k" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would remove: $build" else rm -rf "$build" fi fi done done done shopt -u nullglob}# ---- Virtualization rebuild -------------------------------------------------rebuild_virtualbox() { [[ "$DO_VBOX_REBUILD" == "true" ]] || return 0 "$HAS_VBOX" || return 0 log "Rebuilding VirtualBox modules" ensure_headers_for "$CURRENT_KERNEL" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: /sbin/vboxconfig"; return 0 fi if [[ -x /sbin/vboxconfig ]]; then /sbin/vboxconfig >/dev/null 2>&1 || true else log "VirtualBox: /sbin/vboxconfig not found (skip)"; return 0 fi modinfo -k "$CURRENT_KERNEL" vboxdrv >/dev/null 2>&1 \ && log "VirtualBox modules OK" \ || log "WARNING: VirtualBox modules missing"}rebuild_vmware() { [[ "$DO_VMWARE_REBUILD" == "true" ]] || return 0 "$HAS_VMWARE" || return 0 if [[ -n "${SAFE_KERNEL:-}" && "$CURRENT_KERNEL" != "$SAFE_KERNEL" ]]; then log "WARNING: Current kernel is not VMware-safe: $CURRENT_KERNEL" log " Recommended VMware-safe kernel: $SAFE_KERNEL" fi log "Rebuilding VMware modules" ensure_headers_for "$CURRENT_KERNEL" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would install build-essential gcc make perl dkms" log "[DRYRUN] Would run: vmware-modconfig --console --install-all"; return 0 fi apt_install_safe build-essential gcc make perl dkms vmware-modconfig --console --install-all >/dev/null 2>&1 || true modinfo -k "$CURRENT_KERNEL" vmmon >/dev/null 2>&1 \ && log "VMware modules OK" \ || log "WARNING: VMware modules missing" local VMWARE_VERSION VMWARE_VERSION="$(vmware --version 2>/dev/null | awk '{print $3}' || true)" [[ -n "$VMWARE_VERSION" ]] && log "VMware version: $VMWARE_VERSION"}Nettoyage APT, statistiques et programme principal
Nettoyage final, statistiques d’exécution et orchestration générale du script.
# ---- APT cache cleanup ------------------------------------------------------clean_apt_kernel_archives() { local cache="/var/cache/apt/archives" [[ -d "$cache" ]] || return 0 log "Cleaning APT kernel archives not in KEEP_SET" shopt -s nullglob local f base ver for f in "$cache"/linux-*.deb; do base="$(basename "$f")" # Extrait la version depuis le nom du paquet if [[ "$base" =~ ^linux-(image|modules|modules-extra|headers|tools)-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+(\.[0-9]+)?-generic)_.*\.deb$ ]]; then ver="${BASH_REMATCH[2]}" # Garde si présent dans KEEP_SET (qui inclut déjà CURRENT_KERNEL) if printf "%s\n" "${KEEP_SET[@]}" | grep -qx "$ver"; then continue fi log "Removing cached deb: $f" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would remove: $f" else rm -f "$f" || true fi fi done shopt -u nullglob}# ---- Stats ------------------------------------------------------------------stats() { local after freed after="$(du -sb /boot /lib/modules /usr/lib/modules 2>/dev/null | awk '{s+=$1} END{print s+0}')" freed=$(( BEFORE_SIZE - after )) if (( freed < 0 )); then log "Space change: +$(( -freed )) bytes used (new kernel installed?)" else log "Space freed: $freed bytes" fi log "Kernels removed: $REMOVED_COUNT"}# ---- Main -------------------------------------------------------------------main() { rotate_log header require_root acquire_lock check_boot_full fix_dpkg_state detect_hwe BEFORE_SIZE="$(du -sb /boot /lib/modules /usr/lib/modules 2>/dev/null | awk '{s+=$1} END{print s+0}')" detect_kernels detect_mainline_kernel detect_virtualization check_secureboot ensure_safe_kernel_installed detect_kernels detect_branch6_kernel protect_kernels purge_old_kernels clean_orphan_modules clean_boot protect_grub_default_current_kernel refresh_boot clean_dkms clean_broken_dkms clean_dkms_orphans intel_wifi_fallback rebuild_virtualbox rebuild_vmware # Snapshot DKMS final après rebuilds clean_dkms clean_dkms_orphans clean_apt_kernel_archives check_boot_full stats log "Kernel cleaner completed successfully"}main "$@"fullupdate : initialisation et verrouillage
Strict mode Bash, options --dry-run, vérification root, rotation du journal, journalisation horodatée et verrou exclusif.
#!/usr/bin/env bash# -----------------------------------------------------------------------------# fullupdate - System update utility# Version: 1.5 "deb-get cache sync + Flatpak XDG"# -----------------------------------------------------------------------------# Changelog v1.5 vs v1.4:# - Reboot: kernel le plus récent détecté par tri de version (sort -V) au lieu# de la date de modification (ls -t), qui désignait à tort un kernel plus# ancien installé après un plus récent (ex. 6.8 installé après 7.0)# -----------------------------------------------------------------------------# Changelog v1.4 vs v1.3:# - deb-get: utilise DEBGET_TOKEN déjà chargé dans l'environnement# - deb-get: fallback sécurisé vers /etc/deb-get/token# - Suppression de l'ancien chemin /root/.config/deb-get/token# - deb-get: attente de la reconstruction asynchrone du cache après update# - Utilise le verrou natif /var/cache/deb-get/updating_supported.lock# - Vérifie supported.list et supported_apps.list avant upgrade# - Timeout deb-get cache fixé à 120 secondes# - Aucun nettoyage automatique de /var/cache/deb-get# - Flatpak user: fournit HOME, XDG_DATA_HOME et XDG_DATA_DIRS explicitement# afin d'inclure les exports Flatpak utilisateur et système# -----------------------------------------------------------------------------set -Eeuo pipefailVERSION="1.5"LOG_FILE="/var/log/fullupdate.log"LOCK_FILE="/run/fullupdate.lock"MAX_SIZE=1048576 # 1 MBDRYRUN=falseSTART_TIME=$(date +%s)# -----------------------------------------------------------------------------# CLI# -----------------------------------------------------------------------------while [[ $# -gt 0 ]]; do case "${1:-}" in --dry-run) DRYRUN=true ;; --version) echo "fullupdate v$VERSION" exit 0 ;; --help|-h) echo "Usage: $(basename "$0") [--dry-run] [--version] [--help]" exit 0 ;; *) echo "Unknown option: $1" exit 1 ;; esac shiftdone# -----------------------------------------------------------------------------# Root check# -----------------------------------------------------------------------------if [[ $EUID -ne 0 ]]; then echo "Please run as root: sudo $0" exit 1fiexport HOME=/rootexport USER=rootexport LOGNAME=root# -----------------------------------------------------------------------------# Log rotation# -----------------------------------------------------------------------------if [[ -f "$LOG_FILE" && $(stat -c%s "$LOG_FILE") -gt $MAX_SIZE ]]; then local_rot="${LOG_FILE}.$(date +%Y%m%d%H%M%S)" mv "$LOG_FILE" "$local_rot" gzip -f "$local_rot" 2>/dev/null || truefiexec > >(tee -a "$LOG_FILE") 2>&1log() { echo "[$(date +"%F %T")] $*"}# -----------------------------------------------------------------------------# Lock fullupdate# -----------------------------------------------------------------------------exec 9>"$LOCK_FILE" || { echo "Cannot open lock file $LOCK_FILE" exit 1}trap 'rm -f "$LOCK_FILE"' EXIT INT TERMif ! flock -n 9; then log "Another instance is already running (lock: $LOCK_FILE)" exit 1fifullupdate : verrous APT et jeton deb-get
Attente du verrou APT, chargement sécurisé du jeton GitHub et attente de la reconstruction du cache deb-get.
# -----------------------------------------------------------------------------# Attente verrou APT# -----------------------------------------------------------------------------apt_wait_lock() { local i=0 while fuser \ /var/lib/dpkg/lock-frontend \ /var/cache/apt/archives/lock \ >/dev/null 2>&1 do if (( i == 0 )); then log "Waiting for APT lock..." fi sleep 5 (( i += 5 )) if (( i >= 120 )); then log "WARNING: APT lock still held after 120s — proceeding anyway" break fi done}# -----------------------------------------------------------------------------# Token deb-get# -----------------------------------------------------------------------------TOKEN="${DEBGET_TOKEN:-}"DEBGET_TOKEN_FILE="/etc/deb-get/token"if [[ -z "$TOKEN" && -r "$DEBGET_TOKEN_FILE" ]]; then TOKEN="$(< "$DEBGET_TOKEN_FILE")"fi# -----------------------------------------------------------------------------# Attente reconstruction cache deb-get# -----------------------------------------------------------------------------debget_wait_cache() { local cache_dir="/var/cache/deb-get" local lock_file="${cache_dir}/updating_supported.lock" local supported_file="${cache_dir}/supported.list" local supported_apps_file="${cache_dir}/supported_apps.list" local timeout=120 local elapsed=0 log ">>> Waiting for deb-get supported-app cache" sleep 1 while (( elapsed < timeout )); do if [[ ! -e "$lock_file" ]] \ && [[ -s "$supported_file" ]] \ && [[ -s "$supported_apps_file" ]] then log " deb-get cache ready" return 0 fi sleep 1 (( elapsed += 1 )) if (( elapsed % 10 == 0 )); then log " Still waiting for deb-get cache (${elapsed}s)" fi done log "WARNING: deb-get cache not confirmed ready after ${timeout}s" [[ -e "$lock_file" ]] && log " Lock still present: $lock_file" [[ ! -s "$supported_file" ]] && log " Missing/empty: $supported_file" [[ ! -s "$supported_apps_file" ]] && log " Missing/empty: $supported_apps_file" return 1}fullupdate : mises à jour APT et deb-get
Bannière de démarrage, APT full-upgrade et deb-get avec synchronisation du cache avant la mise à niveau.
# -----------------------------------------------------------------------------# Header# -----------------------------------------------------------------------------CURRENT_KERNEL=$(uname -r)log "================================================================"log "Starting fullupdate v$VERSION"log "Host: $(hostname) | Kernel: $CURRENT_KERNEL"if [[ "$DRYRUN" == "true" ]]; then log "DRY RUN mode — no changes will be applied"fiif [[ -n "$TOKEN" ]]; then log "deb-get GitHub token: available"else log "WARNING: deb-get GitHub token: unavailable"filog "================================================================"# -----------------------------------------------------------------------------# APT# -----------------------------------------------------------------------------log ">>> APT update"apt_wait_lockif [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: apt update && apt full-upgrade"else apt update log ">>> APT full-upgrade" apt full-upgrade -yfi# -----------------------------------------------------------------------------# deb-get# -----------------------------------------------------------------------------if command -v deb-get >/dev/null 2>&1; then log ">>> deb-get update" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: deb-get update" log "[DRYRUN] Would wait for deb-get supported-app cache" log "[DRYRUN] Would run: deb-get upgrade" else if [[ -n "$TOKEN" ]]; then if DEBGET_TOKEN="$TOKEN" deb-get update; then log "deb-get update completed" else log "WARNING: deb-get update failed" fi else if deb-get update; then log "deb-get update completed" else log "WARNING: deb-get update failed" fi fi if debget_wait_cache; then log ">>> deb-get cache synchronized" else log "WARNING: proceeding with deb-get upgrade despite cache wait timeout" fi log ">>> deb-get upgrade" if [[ -n "$TOKEN" ]]; then DEBGET_TOKEN="$TOKEN" deb-get upgrade \ || log "WARNING: deb-get upgrade failed" else deb-get upgrade \ || log "WARNING: deb-get upgrade failed" fi fielse log ">>> deb-get not installed, skipping"fifullupdate : Flatpak, Snap, firmware et pipx
Mises à jour Flatpak (système et utilisateur avec environnement XDG explicite), Snap, firmware fwupd et pipx.
# -----------------------------------------------------------------------------# Flatpak (system + user)# -----------------------------------------------------------------------------if command -v flatpak >/dev/null 2>&1; then log ">>> Flatpak update (system)" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: flatpak update --system -y" else flatpak update --system -y \ || log "WARNING: flatpak system update failed" fi if [[ -n "${SUDO_USER:-}" ]] \ && [[ "$SUDO_USER" != "root" ]] \ && id "$SUDO_USER" >/dev/null 2>&1 then USER_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6)" if [[ -n "$USER_HOME" && -d "$USER_HOME" ]]; then USER_XDG_DATA_HOME="${USER_HOME}/.local/share" USER_XDG_DATA_DIRS="${USER_HOME}/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share" log ">>> Flatpak update (user: $SUDO_USER)" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run Flatpak user update with explicit XDG_DATA_HOME/XDG_DATA_DIRS" else sudo -u "$SUDO_USER" \ env \ HOME="$USER_HOME" \ XDG_DATA_HOME="$USER_XDG_DATA_HOME" \ XDG_DATA_DIRS="$USER_XDG_DATA_DIRS" \ flatpak update -y \ || log "WARNING: flatpak user update failed" fi else log "WARNING: unable to determine HOME for user $SUDO_USER; skipping user Flatpak update" fi fielse log ">>> Flatpak not installed, skipping"fi# -----------------------------------------------------------------------------# Snap# -----------------------------------------------------------------------------if command -v snap >/dev/null 2>&1; then log ">>> Snap refresh" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: snap refresh" else snap refresh \ || log "WARNING: snap refresh failed" fielse log ">>> Snap not installed, skipping"fi# -----------------------------------------------------------------------------# Firmware (fwupd)# -----------------------------------------------------------------------------if command -v fwupdmgr >/dev/null 2>&1; then log ">>> fwupd: refreshing metadata" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: fwupdmgr refresh --force && fwupdmgr update" else fwupdmgr refresh --force 2>/dev/null \ || log "WARNING: fwupd refresh failed" fwupdmgr update -y 2>/dev/null \ || log "WARNING: fwupd update failed (no updates or unsupported hardware)" fielse log ">>> fwupd not installed, skipping"fi# -----------------------------------------------------------------------------# pipx# -----------------------------------------------------------------------------if command -v pipx >/dev/null 2>&1; then log ">>> pipx upgrade-all" if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: pipx upgrade-all" else pipx upgrade-all 2>/dev/null \ || log "WARNING: pipx upgrade-all failed" fielse log ">>> pipx not installed, skipping"fifullupdate : nettoyage, redémarrage et durée
Nettoyage APT, détection du redémarrage requis avec le noyau le plus récent (tri par version) et durée d’exécution.
# -----------------------------------------------------------------------------# Cleanup APT# -----------------------------------------------------------------------------log ">>> APT autoremove + autoclean"if [[ "$DRYRUN" == "true" ]]; then log "[DRYRUN] Would run: apt autoremove --purge -y && apt autoclean"else apt autoremove --purge -y apt autocleanfi# -----------------------------------------------------------------------------# Reboot detection# -----------------------------------------------------------------------------if [[ -f /run/reboot-required ]]; then log ">>> REBOOT REQUIRED" log " Current kernel: $CURRENT_KERNEL" if [[ -f /run/reboot-required.pkgs ]]; then log " Packages requiring reboot: $(tr '\n' ' ' < /run/reboot-required.pkgs)" fi local_new_kernel="$( ls -1 /boot/vmlinuz-* 2>/dev/null \ | sed 's|/boot/vmlinuz-||' \ | sort -V \ | tail -n1 \ || true )" if [[ -n "$local_new_kernel" \ && "$local_new_kernel" != "$CURRENT_KERNEL" ]] then log " New kernel available: $local_new_kernel" fielse log ">>> No reboot required"fi# -----------------------------------------------------------------------------# Durée# -----------------------------------------------------------------------------END_TIME=$(date +%s)DURATION=$((END_TIME - START_TIME))log "================================================================"log "fullupdate v$VERSION completed in ${DURATION}s"log "================================================================"echoexit 0