Ne plus prendre une machine installée pour une session live #14
3 changed files with 449 additions and 0 deletions
401
code/linux/linux-mint/alpi-fiche.sh
Executable file
401
code/linux/linux-mint/alpi-fiche.sh
Executable file
|
|
@ -0,0 +1,401 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Relève la fiche d'une machine, et l'envoie au serveur de l'install party.
|
||||||
|
#
|
||||||
|
# À récupérer depuis le dépôt du wiki, comme les autres scripts d'Alpinux :
|
||||||
|
#
|
||||||
|
# wget https://gitea.alpinux.org/alpinux.cedrica5l/alpinux-wiki/raw/branch/main/code/linux/linux-mint/alpi-fiche.sh
|
||||||
|
# chmod +x alpi-fiche.sh
|
||||||
|
# sudo ./alpi-fiche.sh --check # depuis la session live, avant d'installer
|
||||||
|
# sudo ./alpi-fiche.sh # après l'installation
|
||||||
|
#
|
||||||
|
# Sur le réseau de l'install party, plus court :
|
||||||
|
#
|
||||||
|
# wget http://10.0.0.1/alpi-fiche.sh && chmod +x alpi-fiche.sh && sudo ./alpi-fiche.sh --check
|
||||||
|
#
|
||||||
|
# Pourquoi la garder sur le serveur plutôt que sur le poste : trois semaines
|
||||||
|
# plus tard, quand quelqu'un rappelle parce que « ça rame », on n'a plus la
|
||||||
|
# machine sous la main. Savoir qu'elle a huit ans, quatre gigaoctets de
|
||||||
|
# mémoire et un disque mécanique qui commence à réallouer des secteurs répond
|
||||||
|
# à la question avant de l'avoir posée.
|
||||||
|
#
|
||||||
|
# Ce qui est envoyé, et rien d'autre : le modèle et la marque, les quatre
|
||||||
|
# derniers caractères du numéro de série, la date du BIOS, le processeur, la
|
||||||
|
# mémoire et le détail de ses connecteurs, les disques avec leur santé SMART,
|
||||||
|
# l'occupation des systèmes de fichiers, le système installé, l'architecture,
|
||||||
|
# l'adresse matérielle de l'interface réseau et le nom de la machine.
|
||||||
|
#
|
||||||
|
# Ni nom d'utilisateur, ni fichiers, ni historique, ni adresse IP publique.
|
||||||
|
#
|
||||||
|
# Deux réserves à connaître avant de s'en servir, parce qu'elles concernent
|
||||||
|
# des gens et pas des machines :
|
||||||
|
#
|
||||||
|
# - le **nom de la machine** est celui choisi pendant l'installation, et il
|
||||||
|
# contient souvent un prénom (« portable-jean ») ;
|
||||||
|
# - l'**adresse matérielle** identifie durablement la carte réseau ; elle
|
||||||
|
# sert ici à rapprocher la fiche du bail DHCP, rien de plus.
|
||||||
|
#
|
||||||
|
# Le relevé part en clair sur le réseau local de la salle, vers le serveur de
|
||||||
|
# l'association, et n'en sort pas. Prévenez-en la personne dont vous installez
|
||||||
|
# la machine : c'est la sienne.
|
||||||
|
#
|
||||||
|
# alpi-fiche relève et envoie
|
||||||
|
# alpi-fiche --montrer relève et affiche, sans rien envoyer
|
||||||
|
# alpi-fiche --check relève, envoie, et rend un verdict
|
||||||
|
#
|
||||||
|
# Le mode « --check » est fait pour tourner **depuis la clé USB, avant
|
||||||
|
# d'installer** : c'est le seul moment où l'on peut encore renoncer. Un disque
|
||||||
|
# qui se déclare défaillant, on ne passe pas une heure à installer dessus — on
|
||||||
|
# le dit à son propriétaire et on cherche une autre solution.
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
SERVEUR="${ALPI_SERVEUR:-http://alpicache.lan}"
|
||||||
|
MONTRER=0
|
||||||
|
CHECK=0
|
||||||
|
case "${1:-}" in
|
||||||
|
--montrer) MONTRER=1 ;;
|
||||||
|
--check) CHECK=1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
V=$'\e[32m'; O=$'\e[33m'; R=$'\e[31m'; B=$'\e[1m'; D=$'\e[2m'; Z=$'\e[0m'
|
||||||
|
else
|
||||||
|
V=""; O=""; R=""; B=""; D=""; Z=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
lire_dmi() {
|
||||||
|
cat "/sys/class/dmi/id/$1" 2>/dev/null | tr -d '\n' | sed 's/^ *//; s/ *$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
echapper() {
|
||||||
|
# De quoi écrire du JSON sans rien installer : guillemets, antislashs et
|
||||||
|
# sauts de ligne, et c'est tout ce qui peut nous arriver ici.
|
||||||
|
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr -d '\n\r'
|
||||||
|
}
|
||||||
|
|
||||||
|
champ() { printf '"%s":"%s"' "$1" "$(echapper "${2:-}")"; }
|
||||||
|
|
||||||
|
# --- La machine ------------------------------------------------------------
|
||||||
|
|
||||||
|
MODELE="$(lire_dmi product_name)"
|
||||||
|
MARQUE="$(lire_dmi sys_vendor)"
|
||||||
|
SERIE="$(lire_dmi product_serial)"
|
||||||
|
# Le numéro de série identifie un objet, pas une personne, mais il n'a rien à
|
||||||
|
# faire dans un fichier qu'on partage : on n'en garde que les quatre derniers
|
||||||
|
# caractères, assez pour distinguer deux machines du même modèle.
|
||||||
|
SERIE="${SERIE: -4}"
|
||||||
|
BIOS="$(lire_dmi bios_date)"
|
||||||
|
|
||||||
|
PROCESSEUR="$(awk -F': ' '/^model name/{print $2; exit}' /proc/cpuinfo)"
|
||||||
|
COEURS="$(nproc 2>/dev/null || echo '?')"
|
||||||
|
MEMOIRE_KO="$(awk '/^MemTotal/{print $2}' /proc/meminfo)"
|
||||||
|
|
||||||
|
SYSTEME=""
|
||||||
|
if [ -r /etc/os-release ]; then
|
||||||
|
SYSTEME="$(. /etc/os-release; echo "${PRETTY_NAME:-$NAME $VERSION}")"
|
||||||
|
fi
|
||||||
|
NOYAU="$(uname -r)"
|
||||||
|
ARCHITECTURE="$(uname -m)"
|
||||||
|
|
||||||
|
# Sommes-nous sur la clé USB, ou sur le système installé ?
|
||||||
|
#
|
||||||
|
# La distinction n'est pas cosmétique : les deux relevés répondent à deux
|
||||||
|
# questions différentes. Celui de la session live dit « peut-on installer sur
|
||||||
|
# cette machine ? » et se fait avant d'effacer quoi que ce soit. Celui d'après
|
||||||
|
# dit « qu'avons-nous installé, et sur quoi ». Les garder séparés permet de
|
||||||
|
# comparer — un disque qui allait bien le matin et qui se plaint le soir, cela
|
||||||
|
# se voit.
|
||||||
|
#
|
||||||
|
# Le signe qui ne trompe pas est la racine : une session live la monte en
|
||||||
|
# overlay au-dessus d'un squashfs, ce qu'aucun système installé ne fait. S'y
|
||||||
|
# ajoute « boot=casper » ou « boot=live » sur la ligne de commande du noyau.
|
||||||
|
#
|
||||||
|
# L'existence de /cdrom ou de /rofs, elle, ne prouve rien : l'installateur de
|
||||||
|
# Mint laisse un /cdrom vide derrière lui. La première version de ce test a
|
||||||
|
# donc déclaré « session live » une machine parfaitement installée — constaté
|
||||||
|
# le 24/09/2026 sur un HP 250 G4. Ce n'est pas anodin : la durée d'une
|
||||||
|
# installation se mesure entre le relevé d'avant et celui d'après, et deux
|
||||||
|
# relevés « avant » ne se soustraient pas. On ne retient donc ces répertoires
|
||||||
|
# que s'ils sont réellement montés, et montés depuis un support en lecture
|
||||||
|
# seule.
|
||||||
|
MOMENT="post-installation"
|
||||||
|
if findmnt -n -o FSTYPE / 2>/dev/null | grep -qE '^(overlay|aufs|squashfs)$' \
|
||||||
|
|| grep -qE '(^| )boot=(casper|live)( |$)' /proc/cmdline 2>/dev/null \
|
||||||
|
|| mountpoint -q /rofs 2>/dev/null \
|
||||||
|
|| { mountpoint -q /cdrom 2>/dev/null \
|
||||||
|
&& findmnt -n -o FSTYPE /cdrom 2>/dev/null | grep -qE '^(iso9660|squashfs)$'; }; then
|
||||||
|
MOMENT="live"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- La mémoire, barrette par barrette ------------------------------------
|
||||||
|
#
|
||||||
|
# La question qu'on pose vraiment devant une machine lente : peut-on en
|
||||||
|
# ajouter ? Elle demande trois réponses — combien de connecteurs, combien
|
||||||
|
# d'occupés, et de quel type. Un slot libre en DDR3 ne se remplit pas avec ce
|
||||||
|
# qu'on a dans le tiroir.
|
||||||
|
#
|
||||||
|
# dmidecode lit cela dans la table du BIOS. Il est présent par défaut sur
|
||||||
|
# Debian, Ubuntu et Mint ; s'il manque, on ne prétend rien plutôt que de
|
||||||
|
# deviner.
|
||||||
|
|
||||||
|
BARRETTES="["
|
||||||
|
SLOTS_TOTAL=0
|
||||||
|
SLOTS_PRIS=0
|
||||||
|
TYPE_MEMOIRE=""
|
||||||
|
VITESSE_MEMOIRE=""
|
||||||
|
if command -v dmidecode >/dev/null 2>&1 && [ "$(id -u)" = "0" ]; then
|
||||||
|
premier=1
|
||||||
|
# Chaque bloc « Memory Device » décrit un connecteur, occupé ou non.
|
||||||
|
while IFS= read -r bloc; do
|
||||||
|
emplacement="$(printf '%s' "$bloc" | sed -n 's/.*|Locator:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
taille="$(printf '%s' "$bloc" | sed -n 's/.*|Size:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
type_="$(printf '%s' "$bloc" | sed -n 's/.*|Type:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
vitesse="$(printf '%s' "$bloc" | sed -n 's/.*|Speed:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
forme="$(printf '%s' "$bloc" | sed -n 's/.*|Form Factor:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
reference="$(printf '%s' "$bloc" | sed -n 's/.*|Part Number:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
# La vitesse configurée est celle à laquelle la barrette travaille
|
||||||
|
# vraiment ; « Speed » n'est que ce dont elle serait capable. L'écart
|
||||||
|
# entre les deux explique bien des machines qui « rament » sans raison
|
||||||
|
# apparente : une DDR4-3200 bridée à 2133 par la carte mère, ou deux
|
||||||
|
# barrettes dépareillées qui s'alignent sur la plus lente.
|
||||||
|
vitesse_reelle="$(printf '%s' "$bloc" | sed -n 's/.*|Configured Memory Speed:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
fabricant="$(printf '%s' "$bloc" | sed -n 's/.*|Manufacturer:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
rang="$(printf '%s' "$bloc" | sed -n 's/.*|Rank:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
tension="$(printf '%s' "$bloc" | sed -n 's/.*|Configured Voltage:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
largeur="$(printf '%s' "$bloc" | sed -n 's/.*|Data Width:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
detail="$(printf '%s' "$bloc" | sed -n 's/.*|Type Detail:\([^|]*\).*/\1/p' | sed 's/^ *//; s/ *$//')"
|
||||||
|
[ -z "$emplacement" ] && continue
|
||||||
|
|
||||||
|
SLOTS_TOTAL=$(( SLOTS_TOTAL + 1 ))
|
||||||
|
case "$taille" in
|
||||||
|
*"No Module"*|""|"Unknown") taille="" ;;
|
||||||
|
*) SLOTS_PRIS=$(( SLOTS_PRIS + 1 ))
|
||||||
|
[ -z "$TYPE_MEMOIRE" ] && [ "$type_" != "Unknown" ] && TYPE_MEMOIRE="$type_"
|
||||||
|
# Deux barrettes de vitesses différentes s'alignent sur la plus
|
||||||
|
# lente : c'est celle-là qu'il faut retenir pour la machine.
|
||||||
|
if [ -n "$vitesse_reelle" ] && [ "$vitesse_reelle" != "Unknown" ]; then
|
||||||
|
nombre="${vitesse_reelle%% *}"
|
||||||
|
case "$nombre" in
|
||||||
|
''|*[!0-9]*) ;;
|
||||||
|
*) if [ -z "$VITESSE_MEMOIRE" ] || [ "$nombre" -lt "$VITESSE_MEMOIRE" ]; then
|
||||||
|
VITESSE_MEMOIRE="$nombre"
|
||||||
|
fi ;;
|
||||||
|
esac
|
||||||
|
fi ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ "$premier" = 0 ] && BARRETTES="$BARRETTES,"
|
||||||
|
premier=0
|
||||||
|
BARRETTES="$BARRETTES{$(champ emplacement "$emplacement"),$(champ taille "$taille"),\
|
||||||
|
$(champ type "$type_"),$(champ vitesse "$vitesse"),$(champ vitesse_reelle "$vitesse_reelle"),\
|
||||||
|
$(champ forme "$forme"),$(champ reference "$reference"),$(champ fabricant "$fabricant"),\
|
||||||
|
$(champ rang "$rang"),$(champ tension "$tension"),$(champ largeur "$largeur"),\
|
||||||
|
$(champ detail "$detail")}"
|
||||||
|
done < <(dmidecode -t memory 2>/dev/null \
|
||||||
|
| awk '/^Memory Device$/{bloc=""; dedans=1; next}
|
||||||
|
/^$/{if (dedans && bloc != "") print bloc; dedans=0; bloc=""}
|
||||||
|
dedans {gsub(/^[ \t]+/, ""); bloc = bloc "|" $0}
|
||||||
|
END{if (dedans && bloc != "") print bloc}')
|
||||||
|
fi
|
||||||
|
BARRETTES="$BARRETTES]"
|
||||||
|
|
||||||
|
# --- Les disques -----------------------------------------------------------
|
||||||
|
#
|
||||||
|
# lsblk donne la taille et le type ; le drapeau « rotational » du noyau
|
||||||
|
# distingue un disque mécanique d'un SSD sans rien installer. C'est la
|
||||||
|
# distinction qui compte : une machine lente avec un disque mécanique de dix
|
||||||
|
# ans ne s'arrangera pas avec un système plus léger.
|
||||||
|
|
||||||
|
DISQUES="["
|
||||||
|
premier=1
|
||||||
|
for chemin in /sys/block/*; do
|
||||||
|
nom="$(basename "$chemin")"
|
||||||
|
case "$nom" in loop*|ram*|sr*|zram*|dm-*) continue ;; esac
|
||||||
|
[ -r "$chemin/size" ] || continue
|
||||||
|
taille=$(( $(cat "$chemin/size") * 512 ))
|
||||||
|
[ "$taille" -lt 1000000000 ] && continue # moins d'un Go : pas un disque
|
||||||
|
rotatif="$(cat "$chemin/queue/rotational" 2>/dev/null || echo '?')"
|
||||||
|
modele="$(cat "$chemin/device/model" 2>/dev/null | sed 's/ *$//')"
|
||||||
|
|
||||||
|
# L'état SMART, s'il est lisible. Sans smartctl on ne prétend rien.
|
||||||
|
sante=""
|
||||||
|
reallocations=""
|
||||||
|
heures=""
|
||||||
|
if command -v smartctl >/dev/null 2>&1; then
|
||||||
|
sortie="$(smartctl -H -A "/dev/$nom" 2>/dev/null)"
|
||||||
|
sante="$(printf '%s' "$sortie" | grep -iE 'overall-health|SMART Health' \
|
||||||
|
| sed 's/.*: *//' | head -1)"
|
||||||
|
reallocations="$(printf '%s' "$sortie" \
|
||||||
|
| awk '/Reallocated_Sector_Ct|Reallocated_Event/{print $10; exit}')"
|
||||||
|
heures="$(printf '%s' "$sortie" | awk '/Power_On_Hours/{print $10; exit}')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$premier" = 0 ] && DISQUES="$DISQUES,"
|
||||||
|
premier=0
|
||||||
|
DISQUES="$DISQUES{$(champ nom "$nom"),$(champ modele "$modele"),\
|
||||||
|
\"octets\":$taille,$(champ type "$([ "$rotatif" = 1 ] && echo mécanique || echo SSD)"),\
|
||||||
|
$(champ sante "$sante"),$(champ reallocations "$reallocations"),$(champ heures "$heures")}"
|
||||||
|
done
|
||||||
|
DISQUES="$DISQUES]"
|
||||||
|
|
||||||
|
# L'occupation, telle qu'elle est maintenant.
|
||||||
|
OCCUPATION="["
|
||||||
|
premier=1
|
||||||
|
while read -r point taille utilise dispo pourcent; do
|
||||||
|
[ "$premier" = 0 ] && OCCUPATION="$OCCUPATION,"
|
||||||
|
premier=0
|
||||||
|
OCCUPATION="$OCCUPATION{$(champ point "$point"),\"taille\":$taille,\
|
||||||
|
\"utilise\":$utilise,$(champ pourcent "$pourcent")}"
|
||||||
|
done < <(df -B1 --output=target,size,used,avail,pcent 2>/dev/null \
|
||||||
|
| awk 'NR>1 && $2+0 > 1000000000 {print $1, $2, $3, $4, $5}')
|
||||||
|
OCCUPATION="$OCCUPATION]"
|
||||||
|
|
||||||
|
# --- Le rapport ------------------------------------------------------------
|
||||||
|
|
||||||
|
# L'adresse matérielle de l'interface par laquelle on sort — celle que le
|
||||||
|
# serveur a vue en donnant le bail, donc celle qui permettra de rapprocher
|
||||||
|
# cette fiche de la machine servie. « ip -o link » a failli nous donner
|
||||||
|
# l'adresse de diffusion, qui est la même pour tout le monde.
|
||||||
|
INTERFACE="$(ip -o -4 route show default 2>/dev/null | awk '{print $5; exit}')"
|
||||||
|
[ -z "$INTERFACE" ] && INTERFACE="$(ls /sys/class/net 2>/dev/null \
|
||||||
|
| grep -v '^lo$' | head -1)"
|
||||||
|
MAC="$(cat "/sys/class/net/$INTERFACE/address" 2>/dev/null)"
|
||||||
|
|
||||||
|
RAPPORT="{$(champ machine "$(hostname)"),$(champ mac "$MAC"),\
|
||||||
|
$(champ marque "$MARQUE"),$(champ modele "$MODELE"),$(champ serie "$SERIE"),\
|
||||||
|
$(champ bios "$BIOS"),$(champ processeur "$PROCESSEUR"),\"coeurs\":${COEURS:-0},\
|
||||||
|
\"memoire_ko\":${MEMOIRE_KO:-0},$(champ systeme "$SYSTEME"),$(champ noyau "$NOYAU"),\
|
||||||
|
$(champ architecture "$ARCHITECTURE"),$(champ moment "$MOMENT"),\
|
||||||
|
$(champ type_memoire "$TYPE_MEMOIRE"),\
|
||||||
|
$(champ vitesse_memoire "$VITESSE_MEMOIRE"),\
|
||||||
|
\"slots_total\":$SLOTS_TOTAL,\"slots_pris\":$SLOTS_PRIS,\"barrettes\":$BARRETTES,\
|
||||||
|
\"disques\":$DISQUES,\"occupation\":$OCCUPATION}"
|
||||||
|
|
||||||
|
if [ "$MONTRER" = 1 ]; then
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
printf '%s' "$RAPPORT" | python3 -m json.tool 2>/dev/null || printf '%s\n' "$RAPPORT"
|
||||||
|
else
|
||||||
|
printf '%s\n' "$RAPPORT"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$CHECK" = 1 ] && printf " %sLa fiche est envoyée à alpicache…%s\n\n" "$D" "$Z"
|
||||||
|
echo "Relevé : $([ "$MOMENT" = live ] && echo "session live, avant installation" \
|
||||||
|
|| echo "système installé")"
|
||||||
|
echo "Machine : $MARQUE $MODELE"
|
||||||
|
echo "Processeur : $PROCESSEUR ($COEURS cœurs)"
|
||||||
|
if [ "$SLOTS_TOTAL" -gt 0 ]; then
|
||||||
|
echo "Mémoire : $(( MEMOIRE_KO / 1024 )) Mo ${TYPE_MEMOIRE:+$TYPE_MEMOIRE }\
|
||||||
|
${VITESSE_MEMOIRE:+à $VITESSE_MEMOIRE MT/s }· \
|
||||||
|
$SLOTS_PRIS connecteur(s) occupé(s) sur $SLOTS_TOTAL"
|
||||||
|
else
|
||||||
|
echo "Mémoire : $(( MEMOIRE_KO / 1024 )) Mo"
|
||||||
|
fi
|
||||||
|
echo "Système : $SYSTEME"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- Le verdict ------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Trois réponses possibles, et une seule question : peut-on installer sur cette
|
||||||
|
# machine ? Les seuils viennent de ce qu'on rencontre en install party, pas
|
||||||
|
# d'un idéal — une machine de dix ans avec 4 Go et un disque sain fait très
|
||||||
|
# bien l'affaire, et c'est souvent celle qu'on nous apporte.
|
||||||
|
|
||||||
|
# Depuis une session live, le verdict est tout l'intérêt de l'exercice : on
|
||||||
|
# le rend sans qu'on ait à le demander.
|
||||||
|
[ "$MOMENT" = "live" ] && CHECK=1
|
||||||
|
|
||||||
|
if [ "$CHECK" = 1 ]; then
|
||||||
|
GRAVITE=0 # 0 rien à signaler · 1 à surveiller · 2 ne pas installer
|
||||||
|
REMARQUES=""
|
||||||
|
|
||||||
|
note() {
|
||||||
|
[ "$1" -gt "$GRAVITE" ] && GRAVITE="$1"
|
||||||
|
REMARQUES="$REMARQUES$2"$'\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Les disques. C'est pour eux qu'on fait ce contrôle.
|
||||||
|
for chemin in /sys/block/*; do
|
||||||
|
nom="$(basename "$chemin")"
|
||||||
|
case "$nom" in loop*|ram*|sr*|zram*|dm-*) continue ;; esac
|
||||||
|
[ -r "$chemin/size" ] || continue
|
||||||
|
taille=$(( $(cat "$chemin/size") * 512 ))
|
||||||
|
[ "$taille" -lt 1000000000 ] && continue
|
||||||
|
|
||||||
|
if ! command -v smartctl >/dev/null 2>&1; then
|
||||||
|
note 1 " ${O}?${Z} état des disques inconnu — smartmontools n'est pas installé.
|
||||||
|
${D}sudo apt install -y smartmontools${Z} ${D}(il passera par le cache)${Z}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
sortie="$(smartctl -H -A "/dev/$nom" 2>/dev/null)"
|
||||||
|
if printf '%s' "$sortie" | grep -qiE 'overall-health.*(FAILED|FAILING)'; then
|
||||||
|
note 2 " ${R}✗${Z} ${B}/dev/$nom se déclare défaillant${Z} — ne pas installer dessus."
|
||||||
|
fi
|
||||||
|
for attribut in Reallocated_Sector_Ct Current_Pending_Sector Offline_Uncorrectable; do
|
||||||
|
valeur="$(printf '%s' "$sortie" | awk -v a="$attribut" '$2 == a {print $10; exit}')"
|
||||||
|
case "$valeur" in ''|*[!0-9]*) continue ;; esac
|
||||||
|
[ "$valeur" = "0" ] && continue
|
||||||
|
if [ "$valeur" -ge 50 ]; then
|
||||||
|
note 2 " ${R}✗${Z} /dev/$nom : $valeur $attribut — disque à remplacer."
|
||||||
|
else
|
||||||
|
note 1 " ${O}!${Z} /dev/$nom : $valeur $attribut — à surveiller."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
heures="$(printf '%s' "$sortie" | awk '/Power_On_Hours/{print $10; exit}')"
|
||||||
|
rotatif="$(cat "$chemin/queue/rotational" 2>/dev/null)"
|
||||||
|
case "$heures" in
|
||||||
|
''|*[!0-9]*) ;;
|
||||||
|
*) if [ "$rotatif" = "1" ] && [ "$heures" -gt 43800 ]; then
|
||||||
|
note 1 " ${O}!${Z} /dev/$nom : disque mécanique de $(( heures / 8760 )) ans.
|
||||||
|
${D}Un SSD changerait tout sur cette machine.${Z}"
|
||||||
|
fi ;;
|
||||||
|
esac
|
||||||
|
if [ "$taille" -lt 32000000000 ]; then
|
||||||
|
note 1 " ${O}!${Z} /dev/$nom ne fait que $(( taille / 1000000000 )) Go — c'est juste."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# La mémoire, le processeur.
|
||||||
|
MEMOIRE_MO=$(( MEMOIRE_KO / 1024 ))
|
||||||
|
if [ "$MEMOIRE_MO" -lt 2048 ]; then
|
||||||
|
note 2 " ${R}✗${Z} ${B}${MEMOIRE_MO} Mo de mémoire${Z} — trop peu pour Mint.
|
||||||
|
${D}Envisager une version légère, ou ajouter de la mémoire.${Z}"
|
||||||
|
elif [ "$MEMOIRE_MO" -lt 4096 ]; then
|
||||||
|
libres=$(( SLOTS_TOTAL - SLOTS_PRIS ))
|
||||||
|
note 1 " ${O}!${Z} ${MEMOIRE_MO} Mo de mémoire — Mint tournera, mais sans aisance.$(
|
||||||
|
[ "$libres" -gt 0 ] && printf '\n %s' "${D}$libres connecteur(s) ${TYPE_MEMOIRE} libre(s) : la machine est extensible.${Z}")"
|
||||||
|
fi
|
||||||
|
if [ "$ARCHITECTURE" != "x86_64" ] && [ "$ARCHITECTURE" != "aarch64" ]; then
|
||||||
|
note 2 " ${R}✗${Z} processeur ${ARCHITECTURE} — les versions 64 bits ne s'installeront pas."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
case "$GRAVITE" in
|
||||||
|
0) printf " %s%s BON POUR L'INSTALLATION %s\n" "$B$V" "✓" "$Z" ;;
|
||||||
|
1) printf " %s%s INSTALLATION POSSIBLE, AVEC DES RÉSERVES %s\n" "$B$O" "!" "$Z" ;;
|
||||||
|
2) printf " %s%s NE PAS INSTALLER EN L'ÉTAT %s\n" "$B$R" "✗" "$Z" ;;
|
||||||
|
esac
|
||||||
|
echo
|
||||||
|
[ -n "$REMARQUES" ] && printf "%s\n" "$REMARQUES"
|
||||||
|
[ "$GRAVITE" = 2 ] && printf " %sEn parler au propriétaire avant de toucher à quoi que ce soit.%s\n\n" "$D" "$Z"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
reponse="$(printf '%s' "$RAPPORT" | curl -s --max-time 15 \
|
||||||
|
-H 'Content-Type: application/json' --data-binary @- "$SERVEUR/fiche")"
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
reponse="$(printf '%s' "$RAPPORT" | wget -qO- --timeout=15 \
|
||||||
|
--header='Content-Type: application/json' --post-file=- "$SERVEUR/fiche")"
|
||||||
|
else
|
||||||
|
echo "Ni curl ni wget : la fiche n'a pas pu être envoyée." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$reponse" ]; then
|
||||||
|
echo "$reponse"
|
||||||
|
else
|
||||||
|
echo "Le serveur n'a pas répondu — la fiche n'est pas enregistrée." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
@ -1,4 +1,26 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# Fiche matérielle pour le serveur de l'install party
|
||||||
|
#
|
||||||
|
# Placée au début, et non à la fin : si un disque faiblit, autant le savoir
|
||||||
|
# avant d'avoir passé une heure à installer dessus — c'est le moment où l'on
|
||||||
|
# peut encore en parler à son propriétaire. Et si l'installation s'arrête en
|
||||||
|
# route, on a tout de même la fiche.
|
||||||
|
#
|
||||||
|
# Le relevé est le script voisin du dépôt, lu et versionné comme celui-ci :
|
||||||
|
# rien n'est téléchargé ni exécuté depuis le réseau. S'il n'est pas là, on
|
||||||
|
# passe — la machine d'un particulier qui rejoue ce script chez elle ne doit
|
||||||
|
# rien avoir à faire de tout ceci.
|
||||||
|
#
|
||||||
|
# C'est la seconde passe, celle que « sudo » relance, qui l'exécute :
|
||||||
|
# dmidecode et smartctl demandent les droits d'administration.
|
||||||
|
##################################################
|
||||||
|
|
||||||
|
if [ "$(id -u)" = "0" ] && [ -x "$(dirname "$0")/alpi-fiche.sh" ]; then
|
||||||
|
"$(dirname "$0")/alpi-fiche.sh" || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Script de post-installation pour Linux Mint 22.3
|
# Script de post-installation pour Linux Mint 22.3
|
||||||
# testé le 25/03/2026
|
# testé le 25/03/2026
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,32 @@ les vérifications qui le nécessitent, puis passe en revue :
|
||||||
|
|
||||||
Il finit par deux listes : *à régler avant d'installer*, et *à savoir*.
|
Il finit par deux listes : *à régler avant d'installer*, et *à savoir*.
|
||||||
|
|
||||||
|
### Relever la fiche de la machine
|
||||||
|
|
||||||
|
En install party, un second script complète l'état des lieux : il relève la **fiche
|
||||||
|
matérielle** — modèle, processeur, mémoire et ses connecteurs, disques et leur santé —
|
||||||
|
et l'envoie au serveur de l'association.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget http://10.0.0.1/alpi-fiche.sh && chmod +x alpi-fiche.sh && sudo ./alpi-fiche.sh --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Lancé depuis la session live, il rend en plus un verdict en trois états : **bon pour
|
||||||
|
l'installation**, **possible avec des réserves**, ou **ne pas installer en l'état** — un
|
||||||
|
disque qui se déclare défaillant, des secteurs réalloués, moins de 2 Go de mémoire, un
|
||||||
|
processeur 32 bits. C'est le dernier moment où l'on peut encore renoncer et en parler au
|
||||||
|
propriétaire.
|
||||||
|
|
||||||
|
Le même script, relancé après l'installation (sans `--check`), enregistre ce qui a
|
||||||
|
finalement été installé. Les deux relevés se comparent : un disque qui allait bien le
|
||||||
|
matin et se plaint le soir, cela se voit.
|
||||||
|
|
||||||
|
!!! warning "Dites-le à la personne dont vous installez la machine"
|
||||||
|
La fiche part sur le réseau local, vers le serveur de l'association, et n'en sort
|
||||||
|
pas. Elle ne contient ni fichiers, ni historique, ni nom d'utilisateur — mais elle
|
||||||
|
contient le **nom de la machine**, souvent un prénom, et l'**adresse matérielle** de
|
||||||
|
la carte réseau. C'est son ordinateur : cela se demande, cela ne se suppose pas.
|
||||||
|
|
||||||
!!! danger "BitLocker : ne touchez à rien"
|
!!! danger "BitLocker : ne touchez à rien"
|
||||||
Si le script annonce une partition chiffrée par BitLocker, **arrêtez-vous là**. Le
|
Si le script annonce une partition chiffrée par BitLocker, **arrêtez-vous là**. Le
|
||||||
chiffrement doit être suspendu depuis Windows — *Paramètres → Confidentialité et
|
chiffrement doit être suspendu depuis Windows — *Paramètres → Confidentialité et
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue