La session alpicache a essayé le relevé sur une machine réelle et en a tiré trois défauts, tous vérifiés là-bas : Le verdict ne sortait qu'en session live. Relancé après installation, le relevé ne disait donc rien de l'état des disques — précisément ce dont on voulait parler au propriétaire pendant qu'il est encore là. Il sort maintenant à tous les coups, sauf en mode --montrer. Un disque mécanique n'était signalé qu'au-delà de cinq ans de marche, ce qui laissait passer sans un mot un disque de trois ans — alors que c'est le premier frein d'une machine par ailleurs correcte. Il se signale désormais quel que soit son âge, qui est simplement rappelé. Le verdict défilait sans que personne ne le lise : trois secondes quand tout va bien, vingt avec des réserves, et il attend une touche — deux minutes au plus — quand il dit de ne pas installer. Jamais indéfiniment, ni du tout sans terminal : le script tourne aussi appelé par install.sh. La détection de session live est reprise dans sa version, plus fine que celle que j'avais faite : /cdrom et /rofs comptent de nouveau, mais seulement montés, et pour /cdrom seulement avec un système de fichiers de média. Un répertoire vide ne prouve plus rien. Seul l'en-tête reste de moi : le script se prend dans ce dépôt, pas sur le serveur. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BE4rvHVETRoWnYNDTGssdo
462 lines
21 KiB
Bash
Executable file
462 lines
21 KiB
Bash
Executable file
#!/bin/bash
|
|
# Relève la fiche d'une machine, et l'envoie au serveur de l'install party.
|
|
#
|
|
# Ce script vit dans le dépôt du wiki, à côté d'install.sh : il est lu et
|
|
# versionné comme lui, et c'est de là qu'il faut le prendre.
|
|
#
|
|
# 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é : le modèle, le processeur, la mémoire, les disques et
|
|
# leur santé, le système installé.
|
|
#
|
|
# Deux de ces champs touchent à la personne, et il faut le dire plutôt que de
|
|
# prétendre le contraire — la première version de cet en-tête annonçait « rien
|
|
# qui touche à la personne », ce qui était faux :
|
|
#
|
|
# · le NOM DE LA MACHINE, choisi pendant l'installation, contient très
|
|
# souvent un prénom ;
|
|
# · l'ADRESSE MATÉRIELLE de la carte réseau identifie durablement l'appareil.
|
|
#
|
|
# Les deux servent : le nom pour s'y retrouver, l'adresse pour rapprocher la
|
|
# fiche du bail DHCP. Mais ils appartiennent à la personne dont on installe
|
|
# l'ordinateur — il faut le lui dire. Ne sont en revanche jamais envoyés : son
|
|
# nom d'utilisateur, ses fichiers, son historique, ni rien de ce qu'elle a
|
|
# installé. Le numéro de série est tronqué à quatre caractères.
|
|
#
|
|
# 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
|
|
|
|
# smartctl et dmidecode vivent dans /usr/sbin, que le PATH d'un shell ordinaire
|
|
# ne contient pas toujours — un « command -v » y échouait alors que le binaire
|
|
# était là.
|
|
PATH="$PATH:/usr/sbin:/sbin"
|
|
|
|
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
|
|
|
|
# Ce dont le relevé a besoin, et qu'il installe lui-même plutôt que de rendre
|
|
# un verdict à trous.
|
|
#
|
|
# « état des disques inconnu » n'aide personne : c'est précisément la réponse
|
|
# qu'on était venu chercher. Les deux paquets pèsent moins de deux mégaoctets,
|
|
# ils sont dans le cache, et l'installation prend deux secondes sur le réseau
|
|
# de l'install party. On ne le fait qu'en root, qu'avec apt, et sans rien
|
|
# demander d'autre.
|
|
completer_outils() {
|
|
[ "$(id -u)" = "0" ] || return 0
|
|
command -v apt-get >/dev/null 2>&1 || return 0
|
|
|
|
local manquants=""
|
|
command -v smartctl >/dev/null 2>&1 || manquants="$manquants smartmontools"
|
|
command -v dmidecode >/dev/null 2>&1 || manquants="$manquants dmidecode"
|
|
[ -z "$manquants" ] && return 0
|
|
|
|
echo "==> Installation de ce qui manque au relevé :$manquants"
|
|
# Par le cache s'il répond, directement sinon. « -qq » pour ne pas noyer
|
|
# l'écran : ce n'est pas l'objet de la manœuvre.
|
|
local proxy=""
|
|
if command -v wget >/dev/null 2>&1 \
|
|
&& wget -q --spider --timeout=3 "$SERVEUR/" 2>/dev/null; then
|
|
proxy="-o Acquire::http::Proxy=http://apt-proxy:3142"
|
|
fi
|
|
DEBIAN_FRONTEND=noninteractive apt-get $proxy -qq -y install $manquants \
|
|
>/dev/null 2>&1 \
|
|
|| echo " (échec — le relevé se fera sans)"
|
|
# Ce qui vient d'arriver est dans /usr/sbin, que le PATH d'un shell
|
|
# ordinaire ne contient pas toujours.
|
|
PATH="$PATH:/usr/sbin:/sbin"
|
|
}
|
|
|
|
completer_outils
|
|
|
|
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, et la première version de ce script
|
|
# a donc déclaré « session live » une machine parfaitement installée. On ne les
|
|
# retient que s'ils sont réellement montés.
|
|
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.
|
|
|
|
# Le verdict sort toujours, live ou non. C'est l'information qu'on est venu
|
|
# chercher : la première version ne le rendait qu'en session live, et le
|
|
# relevé d'après installation défilait sans rien dire de l'état des disques —
|
|
# précisément ce dont on voulait parler au propriétaire.
|
|
[ "$MONTRER" = 1 ] || 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)"
|
|
# Un disque mécanique se signale toujours, et pas seulement quand il
|
|
# est vieux. C'est le premier frein d'une machine par ailleurs
|
|
# correcte : remplacer un plateau par un SSD fait plus pour elle que
|
|
# n'importe quel réglage, et c'est le genre de conseil qu'on donne
|
|
# pendant qu'on a la machine ouverte devant soi.
|
|
if [ "$rotatif" = "1" ]; then
|
|
age=""
|
|
case "$heures" in
|
|
''|*[!0-9]*) ;;
|
|
*) annees=$(( heures / 8760 ))
|
|
[ "$annees" -gt 0 ] && age=" de $annees an$([ "$annees" -gt 1 ] && echo s)"
|
|
[ "$annees" = "0" ] && age=" ($heures h de marche)" ;;
|
|
esac
|
|
note 1 " ${O}!${Z} /dev/$nom est un ${B}disque mécanique${Z}$age.
|
|
${D}Le remplacer par un SSD ferait plus pour cette machine que
|
|
tout le reste réuni — démarrage, ouverture des programmes, réactivité.${Z}"
|
|
fi
|
|
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"
|
|
|
|
# Une pause, sans quoi tout cela défile et personne ne le lit. Sa durée
|
|
# suit la gravité, et l'on n'attend jamais indéfiniment : le script tourne
|
|
# aussi sans personne devant l'écran, appelé par install.sh.
|
|
if [ -t 0 ]; then
|
|
case "$GRAVITE" in
|
|
2) printf " %sEn parler au propriétaire AVANT de toucher à quoi que ce soit.%s\n" "$D" "$Z"
|
|
printf " %sEntrée pour continuer malgré tout%s " "$B" "$Z"
|
|
read -r -t "${ALPI_PAUSE_ALERTE:-120}" _ || echo ;;
|
|
1) printf " %sEntrée pour continuer (reprise automatique dans %ss)%s " \
|
|
"$D" "${ALPI_PAUSE:-20}" "$Z"
|
|
read -r -t "${ALPI_PAUSE:-20}" _ || echo ;;
|
|
*) sleep "${ALPI_PAUSE_OK:-3}" ;;
|
|
esac
|
|
echo
|
|
fi
|
|
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
|