Skip to content

Guide Linux Commandes

hprzeta edited this page Sep 5, 2026 · 15 revisions

Fichier : Guide-Linux-Commandes.md · Dossier : wiki racine Branche : master (wiki) · Auteur : hprzeta · MAJ : 2026-09-05 (§28 diagnostic IPv6 vs VPN tiers Proton) · 2026-08-22 (référence rapide correspondance Linux↔OpenBSD ; §27 diagnostic réseau WireGuard/IPv6 ; §1/§5/§6 enrichis) · 2026-08-18 (§26 post-mortem crash machine — journalctl --list-boots, smartctl, upower, dmesg, systemd-inhibit) · 2026-08-16 (§6 OpenBSD — diagnostic arrêt brutal : logs, last/last -x, sysctl hw.sensors ; §2 exemple uname -a mis à jour — migration PC4 Compaq CQ58)

Guide Linux/BSD — Commandes du projet Riemann_Lab

📖 Guide vivant. Chaque nouvelle commande utilisée dans le projet est ajoutée ici. Couvre Linux (Ubuntu/Debian) et OpenBSD (PC4 zeta-secure). Mis à jour à chaque session où de nouvelles commandes sont découvertes.


⭐ Référence rapide — Table de correspondance Linux ↔ OpenBSD

À consulter en premier. Source d'erreur n° 1 récurrente sur PC4 (command not found) : réflexe d'utiliser une commande Linux sur OpenBSD. Détail de chaque commande dans les sections correspondantes ci-dessous.

Objectif Linux (PC1/PC2/PC3) OpenBSD (PC4)
Élévation de privilèges sudo doas
Lister les interfaces ip link show ifconfig
Adresses d'une interface ip addr show <if> ifconfig <if>
Table de routage ip route show route -n show / netstat -rn
Cache de voisinage ip neigh ndp -a / arp -a
Vider le cache de voisinage ip neigh flush all ndp -c / arp -da
Services systemctl rcctl
Journaux journalctl /var/log/messages, dmesg (pas de journal binaire)
Historique boots/reboots last -x (ajoute shutdown/reboot) last (suffit seul, pas d'option -x)
Tâches planifiées systemctl list-timers ou crontab crontab uniquement
Pare-feu iptables / nftables pfctl
Forwarding IPv4 net.ipv4.ip_forward net.inet.ip.forwarding
Téléchargement HTTP curl, wget ftp -o (client HTTP intégré)
sed -i -i seul suffit (GNU sed) -i '' avec extension obligatoire (BSD sed) — voir §13

1. Réseau — Voir les adresses IP

Linux (Ubuntu/Debian)

# Voir toutes les interfaces et IPs
ip addr show

# Voir seulement les IPv4
ip addr show | grep "inet "
ip -4 addr

# Voir une interface spécifique
ip addr show wlp2s0    # WiFi PC1
ip addr show enp0s25   # Ethernet PC2
ip addr show enp2s0    # Ethernet PC3

# Voir les routes
ip route

# Voir les IPs + interfaces en une ligne
ip -4 addr | grep inet | awk '{print $2, $NF}'

# Lister les interfaces (existence, MAC) sans afficher les adresses
ip link show
ip link show wg0             # → "Device \"wg0\" does not exist." si absente

# IPv6 globales uniquement (exclut fe80 lien-local)
ip -6 addr show scope global
ip -6 addr show wlp2s0 && ip -6 route show default

# Vider le cache de voisinage (équivalent ARP/NDP)
sudo ip neigh flush all

Lecture d'une sortie ip -6 addr :

Marqueur Signification
scope link + fe80:: Adresse lien-local, non routable sur Internet
scope global Adresse publique
temporary Adresse de confidentialité RFC 4941, tourne régulièrement
mngtmpaddr Adresse « mère » qui engendre les temporaires
valid_lft 517sec Durée de validité restante — se renouvelle à chaque RA

OpenBSD (PC4 zeta-secure)

# Voir toutes les interfaces
ifconfig

# Voir une interface spécifique
ifconfig re0           # carte réseau principale
ifconfig wg0           # interface WireGuard

# Voir seulement IPv4
ifconfig re0 | grep "inet "

# Voir IPv6 (sauf lien-local fe80 et temporary)
ifconfig re0 | grep "inet6" | grep -v "fe80\|temporary"

# Voir les routes
netstat -rn

Lecture d'une sortie ifconfig OpenBSD :

Marqueur Signification
autoconf Adresse obtenue par SLAAC
temporary Adresse de confidentialité
deprecated Encore valide en réception, plus utilisée en émission
pltime / vltime Durées preferred / valid, en secondes

Distinction utile — une adresse autoconf sans temporary est stable (RFC 7217) : elle ne change que si le préfixe ou l'interface physique change. C'est celle à publier dans le DNS. Voir Diagnostic-WireGuard-Hotspot §2 pour un cas réel où un changement d'interface (migration matérielle) a suffi à faire changer cette adresse malgré un préfixe /64 inchangé.

Test de joignabilité et lecture du TTL

ping  -c 3 [IP_PC4]                                  # IPv4
ping6 -c 3 [IPV6]       # IPv6

# Adresse publique vue depuis l'extérieur
curl -s4 https://api.ipify.org ; echo
curl -s6 --max-time 5 https://api64.ipify.org ; echo     # --max-time évite de bloquer si pas d'IPv6
TTL observé Interprétation
ttl=64 Hôte Linux, joint directement (0 saut)
ttl=63 Hôte Linux, 1 routeur traversé — preuve que le forwarding fonctionne
ttl=255 Hôte BSD ou équipement réseau, joint directement

2. Système — Voir l'OS et la version

Linux

uname -a               # noyau complet
uname -sr              # OS + version courte
cat /etc/os-release    # distribution (Ubuntu, Debian...)
lsb_release -a         # infos distribution (si installé)

OpenBSD

uname -a               # seule commande nécessaire
# Exemple : OpenBSD 'zeta-secure'.local 7.9 GENERIC.MP#449 amd64
# /etc/os-release n'existe pas sous OpenBSD

3. Système — Ressources et performances

# Charge CPU et mémoire
top                    # interactif (Linux et OpenBSD)
top -b -n 1            # une seule capture (Linux)
uptime                 # charge moyenne 1/5/15 min

# Mémoire
free -h                # Linux seulement
# OpenBSD : voir top

# Espace disque
df -h                  # tous les systèmes de fichiers
df -h /home            # dossier spécifique
du -sh ~/dossier/      # taille d'un dossier
du -sh ~/*/ | sort -h  # trier par taille

# Processus
ps aux                 # tous les processus (Linux + OpenBSD)
ps aux | grep python   # filtrer
kill -SIGTERM PID      # arrêter proprement
kill -9 PID            # forcer (dernier recours)

# Gouverneur CPU (Linux)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# performance = mode calcul, powersave = mode économie

4. SSH — Connexions entre machines

# Connexion simple
ssh user@ip
ssh hprzeta@[IP_PC2]    # PC2
ssh hprzeta@[IP_PC3]    # PC3
ssh hprzeta@[IP_PC4]    # PC4 (OpenBSD)

# Via alias (définis dans ~/.ssh/config sur PC1)
ssh zeta-calc-second
ssh zeta-backup
ssh zeta-secure

# Connexion avec clé SSH spécifique
ssh -i ~/.ssh/id_acer hprzeta@[IP_PC3]

# Mode verbose (debug)
ssh -v hprzeta@[IP_PC2]

# Copier un fichier vers une machine distante
scp fichier.txt hprzeta@[IP_PC3]:~/destination/

# Copier depuis une machine distante
scp hprzeta@[IP_PC3]:~/fichier.txt ./local/

SSH à distance avec doas/sudo — piège du TTY

doas (OpenBSD) et sudo en mode interactif ont besoin d'un pseudo-terminal pour demander le mot de passe. Sur une commande SSH non-interactive, il faut forcer le TTY avec -t :

ssh zeta-secure "doas syspatch -c"
# → doas: a tty is required

ssh -t zeta-secure "doas syspatch -c"    # ✅ TTY forcé

⚠️ Erreur de syntaxe à éviter : ssh doas zeta-secure "..." — SSH interprète doas comme un hostname, pas comme une commande à exécuter côté distant. doas/sudo doit toujours être à l'intérieur de la commande entre guillemets, jamais avant le nom d'hôte.

Pattern général :

ssh -t <alias_machine> "doas <commande>"
ssh -t <alias_machine> "sudo <commande>"

5. WireGuard

Linux (PC1 zeta-lab)

# Démarrer le tunnel
sudo wg-quick up wg0

# Arrêter le tunnel
sudo wg-quick down wg0

# Cycle complet avec observation du handshake
sudo wg-quick down wg0 ; sudo wg-quick up wg0 ; sleep 10 ; sudo wg show

# Voir l'état du tunnel
sudo wg show

# Inspecter la config sans révéler la clé privée
sudo grep -iE "PublicKey|Endpoint|AllowedIPs" /etc/wireguard/wg0.conf

# Forcer l'endpoint en IPv6 sans modifier le fichier (test temporaire)
sudo wg set wg0 peer <CLE_PUBLIQUE_DU_PAIR> \
     endpoint [[IPV6]]:51820
# ⚠️ Crochets obligatoires autour d'une adresse IPv6 suivie d'un :port,
# sans quoi le : est ambigu.

# Corriger un fichier de config corrompu (NBSP mobiles)
sudo sed -i 's/\xc2\xa0/ /g' /etc/wireguard/wg0.conf

OpenBSD (PC4 zeta-secure)

# Démarrer l'interface WireGuard
doas ifconfig wg0 up
doas sh /etc/netstart wg0

# Arrêter l'interface
doas ifconfig wg0 down

# Voir l'état WireGuard
doas wg show

# Ajouter/modifier un peer à chaud
doas wg set wg0 peer CLE_PUBLIQUE \
  allowed-ips [WG_TEL]/32

# Modifier les AllowedIPs d'un peer
doas wg set wg0 peer CLE_PUBLIQUE \
  allowed-ips [RESEAU_WG],[LAN]

Lecture de wg show

Champ Ce qu'il indique
endpoint: 93.1.105.194:51820 Résolution en IPv4 — vérifier le DNS (A périmé ?)
endpoint: [2a02:...]:51820 Résolution en IPv6
(pas de ligne latest handshake) Aucun échange établi
latest handshake: 7 seconds ago Tunnel opérationnel (contrôle uniquement — ne garantit pas le transport de données, cf. Diagnostic-WireGuard-Hotspot §7)
transfer: 0 B received, N KiB sent Émission seule → blocage sur le trajet retour
(sortie totalement vide) Aucune interface WireGuard active — vérifier avec ip link show wg0

6. OpenBSD — Commandes spécifiques

Droits et sudo

# OpenBSD utilise doas (pas sudo)
doas commande              # exécuter en root
doas whoami                # vérifier → doit afficher "root"

# Configurer doas
echo 'permit persist hprzeta' > /etc/doas.conf
# persist = pas de re-demande pendant un moment

💡 Exécution via SSH non-interactif : voir §4 « SSH à distance avec doas/sudo — piège du TTY » (nécessite ssh -t).

Patches de sécurité

# Lister les patches EN ATTENTE (dry-run, rien n'est modifié)
doas syspatch -c

# Appliquer les patches
doas syspatch

# Historique des patches déjà installés (rempli après usage, normal)
doas syspatch -l

# Si patch noyau → reboot obligatoire
doas reboot

💡 syspatch -l = historique (toujours rempli après usage). syspatch -c = ce qui reste à appliquer (vide = système à jour). Ne pas confondre les deux.

Paquets

# Installer un paquet
doas pkg_add nom_paquet

# Simuler la mise à jour de tous les paquets (dry-run, rien n'est modifié)
doas pkg_add -u -n

# Appliquer la mise à jour de tous les paquets
doas pkg_add -u

# Chercher un paquet
pkg_info -Q mot_cle

# Lister les paquets installés
pkg_info

Pare-feu pf

# Voir les règles actives
doas pfctl -sr

# Filtrer sur un critère
doas pfctl -sr | grep -iE "51820|wireguard|wg|block"
doas pfctl -sr | grep -i icmp6
doas pfctl -sr | grep -i nat-to

# Vérifier syntaxe avant chargement
doas pfctl -nf /etc/pf.conf

# Charger les règles
doas pfctl -f /etc/pf.conf

# Statistiques
doas pfctl -s info

# Activer/désactiver pf
doas pfctl -e    # enable
doas pfctl -d    # disable (ATTENTION : plus de pare-feu !)

⚠️ pfctl -sn (règles NAT) est obsolète sur OpenBSD moderne : les règles nat-to sont intégrées aux règles normales, visibles via -sr.

Réseau OpenBSD

# Reconfigurer une interface (relit /etc/hostname.re0)
doas sh /etc/netstart re0

# Voir la config d'une interface
cat /etc/hostname.re0
cat /etc/hostname.wg0

# Voir la passerelle par défaut
cat /etc/mygate
netstat -rn | grep default

# Tester la connectivité
ping -c 2 1.1.1.1
ping6 -c 2 2606:4700:4700::1111   # ping IPv6

# Vérifier la résolution DNS
host google.com
host -t AAAA [DDNS_PC4]   # enregistrement IPv6

sysctl OpenBSD

# Voir tous les sysctls
sysctl -a

# IP forwarding (pour WireGuard NAT)
doas sysctl net.inet.ip.forwarding=1

# ⚠️ net.inet6.ip6.accept_rtadv n'existe PAS sous OpenBSD
# (c'est FreeBSD/NetBSD) — SLAAC est géré nativement

Prompt ksh — personnalisation PS1 (PC4)

Le shell par défaut d'OpenBSD est ksh (pas bash), et n'interprète pas les séquences \u, \h, \w de bash. Utiliser la syntaxe ksh avec substitution de commande :

doas vi ~/.profile

Ajouter en fin de fichier :

PS1='$(whoami)@$(hostname -s):$(pwd)\$ '

Recharger sans redémarrer :

. ~/.profile

⚠️ Piège clavier AZERTY : l'apostrophe droite ' (nécessaire pour le shell) est sur la touche 4 (sans Shift). La touche 7 produit è — un caractère accentué qui ne ferme pas la chaîne shell → erreur no closing quote. Toujours vérifier visuellement que le caractère est un simple bâton vertical ', pas un accent.

Arrêter un process lié à une console (tty)

Pour stopper depuis une autre machine une boucle qui tourne sur la console physique ttyC0 de PC4 :

ssh -t zeta-secure "doas pkill -t ttyC0"

Vérification :

ssh zeta-secure "ps aux | grep sleep"

Pour supprimer une ligne ajoutée dans /etc/rc.local (empêcher qu'elle revienne au prochain boot) :

ssh -t zeta-secure "doas sed -i '/while true; do clear/d' /etc/rc.local"
ssh zeta-secure "tail -5 /etc/rc.local"   # vérifier que la ligne a disparu

Extinction / redémarrage propre

# Extinction immédiate (power off réel)
ssh -t zeta-secure "doas shutdown -p now"

# Avec délai et message
ssh -t zeta-secure "doas shutdown -p +2 'Extinction de zeta-secure dans 2 min'"

# Redémarrage
ssh -t zeta-secure "doas reboot"

⚠️ Pile CMOS morte sur PC3 et PC4 (Dell Dimension 4500 / E2140, matériel ancien) : au redémarrage, écran CMOS Checksum Bad / Press F1 to continue — un reboot ou shutdown lancé à distance ne suffit pas à faire redémarrer la machine seule, il faut intervenir physiquement (F1) pour valider le boot. Pas de contournement logiciel trouvé à ce jour sur le BIOS AMI de PC4 (Quick Boot / Silent Boot disponibles mais sans effet sur ce blocage — Silent Boot doit rester désactivé pour voir le message d'erreur). Solution durable : remplacement de la pile CMOS (CR2032) sur les deux machines.

Consoles virtuelles

Ctrl+Alt+F1   # console 1 (ttyC0, par défaut au boot)
Ctrl+Alt+F2   # console 2 (ttyC1)
Ctrl+Alt+F3   # console 3 (ttyC2)

Chaque console garde son état indépendamment (utile pour laisser un heartbeat visuel tourner sur une console pendant qu'on travaille sur une autre).

Diagnostic d'un arrêt brutal — logs et capteurs matériels (2026-08-16)

# Chercher le warning caractéristique d'un arrêt non propre (coupure secteur, crash)
doas grep 'not properly unmounted' /var/log/messages

# Chercher les événements sur une plage horaire précise (ex. 20h-23h le 15 août)
doas grep 'Aug 15 2[0-3]:' /var/log/messages

# Historique des boots/arrêts/crashes
last                    # OpenBSD — pas d'option -x
last -x                 # Linux (Debian/Ubuntu) — ajoute les événements shutdown/reboot au wtmp

# Diagnostic rapide combiné (uptime + 20 dernières entrées)
uptime && last -x | head -20      # Linux
uptime && last | head -20         # OpenBSD (sans -x)

# Capteurs matériels (température, tension, ventilateurs) — si le chipset les expose
sysctl hw.sensors

⚠️ last sans -x sous OpenBSD : OpenBSD ne supporte pas l'option -x de last (spécifique à util-linux/GNU sur Linux). Sur OpenBSD, last seul suffit à voir les cycles boot/shutdown/crash ; sur Linux, -x est nécessaire pour inclure les événements système (shutdown, runlevel) dans la sortie, sinon seules les sessions utilisateur apparaissent.

ℹ️ sysctl hw.sensors peut renvoyer une sortie vide sur du matériel ancien (chipsets pré-2005, ex. Intel 82845) — aucun capteur exposé à l'OS, pas de monitoring hardware logiciel possible sur ces machines.


7. Pare-feu pf — Règles types (OpenBSD PC4)

# Voir /etc/pf.conf actuel
doas cat /etc/pf.conf

Exemple de règles clés pour le bastion WireGuard :

# Bloquer tout en entrée par défaut
block in

# Autoriser tout en sortie
pass out

# SSH
pass in on $ext_if proto tcp to port 22

# WireGuard UDP (IPv4 et IPv6)
pass in on $ext_if proto udp to port 51820

# ICMPv6 nécessaire pour SLAAC (Router Advertisements)
pass in on $ext_if inet6 proto icmp6 \
  icmp6-type {routeradv, neighbradv, neighbrsol, redir}
# ⚠️ neighbrsol (pas neighbrsolicit — invalide sous pf)

# Trafic depuis le VPN vers le LAN
pass in on $wg_if

8. DuckDNS — DNS dynamique

# Mise à jour manuelle (depuis PC4 OpenBSD)
# ftp = équivalent de curl sous OpenBSD base
doas ftp -o /var/log/duckdns.log \
  "https://www.duckdns.org/update?domains=[DDNS_NOM]&token=TOKEN&ip=&ipv6=ADRESSE_IPv6"

# Script automatique /etc/duckdns/duck.sh
# Extrait l'IPv6 stable de re0 (pas fe80, pas temporary)
IP6=$(ifconfig re0 | awk '/inet6/ && !/fe80/ && !/temporary/ {print $2; exit}')

# Voir le résultat du dernier update
doas cat /var/log/duckdns.log
# → "OK" = succès, "KO" = échec

# Vérifier la résolution DNS (depuis n'importe quelle machine)
host -t A [DDNS_PC4]     # IPv4 (inutile car CGNAT)
host -t AAAA [DDNS_PC4]  # IPv6 (celle utilisée)

9. Cron — Tâches automatiques

Linux (PC1, PC3)

# Voir les crons de l'utilisateur courant
crontab -l

# Éditer les crons
crontab -e

# Workaround si crontab -e cassé (ex: PC3 Python 3.5)
(crontab -l; echo "*/5 * * * * /chemin/script.sh") | crontab -

OpenBSD (PC4)

# Voir les crons
doas crontab -l

# Éditer sans vi (OpenBSD n'a pas nano par défaut)
doas crontab -l > /tmp/cron.txt
echo '*/5 * * * * /etc/duckdns/duck.sh' >> /tmp/cron.txt
doas crontab /tmp/cron.txt
rm /tmp/cron.txt

Syntaxe cron

# ┌──── minute (0-59)
# │ ┌── heure (0-23)
# │ │ ┌─ jour du mois (1-31)
# │ │ │ ┌ mois (1-12)
# │ │ │ │ ┌ jour semaine (0=dim)
# │ │ │ │ │
  * * * * *  commande

*/5 * * * *        # toutes les 5 minutes
0 2 * * *          # tous les jours à 02h00
50 1 * * *         # tous les jours à 01h50

10. rsync — Synchronisation entre machines

# Sync logs de PC1 vers PC3 (backup nocturne 01h50)
rsync -avz --progress \
  ~/projet_zeta/logs/ \
  hprzeta@[IP_PC3]:~/backup/logs/

# Sync wiki
rsync -avz \
  ~/projet_zeta/Riemann_Lab.wiki/ \
  hprzeta@[IP_PC3]:~/backup/Riemann_Lab.wiki/

# Options utiles
# -a  : archive (préserve permissions, dates, liens)
# -v  : verbose
# -z  : compression
# -n  : dry-run (simuler sans modifier)
# --delete : supprimer les fichiers absents de la source
# --progress : afficher la progression

11. rclone — Sync vers Proton Drive

# Copier vers Proton Drive
rclone copy ~/projet_zeta/pdf/cours/ \
  protondrive:hprzeta/Riemann_Lab/cours/ --progress

# Lister les fichiers sur Proton Drive
rclone ls protondrive:hprzeta/Riemann_Lab/

# Re-authentifier si erreur 401
rclone config reconnect protondrive:

# Erreur 422 = fichier déjà présent → normal, ignoré

12. tmux — Gestion de sessions multi-panneaux

Commandes de base

# Créer une nouvelle session nommée
tmux new-session -s zeta
tmux new -s zeta-cluster        # forme courte

# Rejoindre une session existante
tmux attach -t zeta
tmux attach-session -t zeta-cluster

# Lister les sessions actives
tmux ls

# Tuer une session depuis l'extérieur
tmux kill-session -t zeta-cluster

Raccourcis clavier (préfixe = Ctrl+B)

Ctrl+B  d         Détacher (quitter sans fermer la session)
Ctrl+B  &         Tuer la fenêtre courante (avec confirmation)
Ctrl+B  "         Diviser horizontalement (nouveau panneau en bas)
Ctrl+B  %         Diviser verticalement (nouveau panneau à droite)
Ctrl+B  ←→↑↓     Naviguer entre les panneaux
Ctrl+B  z         Zoom sur le panneau courant (toggle)
Ctrl+B  q         Afficher les numéros des panneaux

split-window et layout

# Diviser horizontalement (panneau en bas)
tmux split-window -v

# Diviser verticalement (panneau à droite)
tmux split-window -h

# Sélectionner un panneau par numéro
tmux select-pane -t 0
tmux select-pane -t 3

# Agrandir un panneau
tmux resize-pane -D 5     # vers le bas de 5 lignes
tmux resize-pane -R 10    # vers la droite de 10 colonnes

Couleurs des panneaux — identifier la machine (select-pane -P)

# -P 'bg=couleur,fg=couleur' colorie le fond ET le texte du panneau
tmux select-pane -t 0 -P 'bg=colour3,fg=colour0'    # jaune texte noir  → PC2 Debian
tmux select-pane -t 1 -P 'bg=colour6,fg=colour0'    # cyan texte noir   → PC3 backup
tmux select-pane -t 2 -P 'bg=colour0,fg=colour2'    # noir texte vert   → PC4 OpenBSD
tmux select-pane -t 3 -P 'bg=colour5,fg=colour15'   # magenta texte blanc → PC1 local

# Changer la barre de statut globale (toute la session)
tmux set-option -g status-bg colour3    # jaune (PC2 Debian)
tmux set-option -g status-bg colour6    # cyan (PC3 backup)
tmux set-option -g status-bg colour0    # noir (PC4 OpenBSD)

send-keys — envoyer des commandes dans un panneau

# Envoyer une commande dans un panneau sans y accéder
# Format : session:fenêtre.panneau
tmux send-keys -t zeta-cluster:0.0 "ssh zeta-calc-second" Enter
tmux send-keys -t zeta-cluster:0.1 "ssh hprzeta@[IP_PC3]" Enter
tmux send-keys -t zeta-cluster:0.2 "ssh zeta-secure" Enter

# Envoyer sans Enter (pour préparer une commande)
tmux send-keys -t zeta-cluster:0.3 "python3 zeta_monitor.py" ""

Script zeta_tmux.sh — session cluster automatique

# Lancer la session cluster (4 panneaux colorés + monitor)
zeta-cluster              # alias dans ~/.bashrc

# Ou directement :
bash ~/projet_zeta/scripts/zeta_tmux.sh

Le script scripts/zeta_tmux.sh crée la session zeta-cluster avec :

  • Panneau haut-gauche : PC2 zeta-calc-second — fond jaune (colour3)
  • Panneau bas-gauche : PC3 zeta-backup — fond cyan (colour6)
  • Panneau haut-droite : PC4 zeta-secure (OpenBSD) — fond noir (colour0)
  • Panneau bas-droite : PC1 local + zeta_monitor.py — fond magenta (colour5)

Alias ~/.bashrc

# Alias cluster — à ajouter dans ~/.bashrc sur PC1
alias zeta-cluster='bash ~/projet_zeta/scripts/zeta_tmux.sh'

13. Sed — Édition rapide de fichiers

# Remplacer une chaîne dans un fichier (Linux GNU sed)
sed -i 's/ancien/nouveau/g' fichier.txt

# Remplacer avec séparateur alternatif (si / dans les chemins)
sed -i 's|/ancien/chemin|/nouveau/chemin|g' fichier.txt

# ⚠️ OpenBSD/macOS (BSD sed) : -i nécessite une extension
sed -i '' 's/ancien/nouveau/g' fichier.txt

# Supprimer les caractères NBSP (espace insécable, fréquent en copier-coller mobile)
sed -i 's/\xc2\xa0/ /g' fichier.conf
# ⚠️ Cause l'erreur "wrong length or format" dans les clés WireGuard

14. Divers utiles

# Voir les connexions réseau actives
ss -tlnp          # Linux
netstat -an       # Linux + OpenBSD

# Tester un port distant
nc -zv [IP_PC4] 51820    # test UDP WireGuard
nc -zv [IP_PC4] 22       # test SSH

# Voir les logs système
journalctl -f                   # Linux systemd (temps réel)
doas tail -f /var/log/messages  # OpenBSD

# Générer un QR code (pour WireGuard Android)
qrencode -t ansiutf8 < /tmp/phone_wg0.conf

# Voir l'IP publique vue depuis internet
curl -4 -s ifconfig.me    # IPv4 (attention : ne détecte pas CGNAT depuis l'intérieur)
curl -6 -s ifconfig.me    # IPv6

# ⚠️ CGNAT : curl -4 ifconfig.me depuis l'intérieur du réseau retourne l'IP
# vue par les services externes, pas l'IP WAN de la box.
# Pour voir la vraie IP WAN : admin box → [IP_BOX] → WAN → Caractéristiques

15. Python 3.5 — Compatibilité (PC3 zeta-backup Ubuntu 14.04)

PC3 tourne Ubuntu 14.04 LTS avec Python 3.5.2 (fin de vie 2017). Les adaptations ci-dessous sont obligatoires pour les scripts déployés sur PC3.

f-strings → .format() (Python < 3.6)

# ❌ INTERDIT sous Python 3.5 — SyntaxError immédiate
msg = f"CPU: {cpu_percent}%"

# ✅ CORRECT — .format() valide depuis Python 2
msg = "CPU: {}%".format(cpu_percent)
msg = "CPU: {cpu}%".format(cpu=cpu_percent)
msg = "Host {h} — CPU {c:.1f}%".format(h=hostname, c=cpu_pct)

PYTHONNOUSERSITE=1 — contourner distutils-precedence.pth

# Symptôme : ImportError bizarre ou exception au démarrage Python
# Cause : distutils-precedence.pth (présent sur certains Ubuntu 14.04 mis à jour)
#         modifie sys.path dès le démarrage → conflits de versions de setuptools

# Solution : désactiver le site-packages utilisateur
PYTHONNOUSERSITE=1 python3 script.py

# Dans un script SSH lancé depuis PC1 (CMD_LINUX dans zeta_monitor.py) :
CMD_LINUX = "PYTHONNOUSERSITE=1 python3 /home/hprzeta/projet_zeta/scripts/mon_script.py"

OpenBSD — CPU via top (pas /proc/stat)

# ❌ INTERDIT sous OpenBSD — /proc n'existe pas (kernel OpenBSD)
with open('/proc/stat') as f:
    ...

# ✅ CORRECT sous OpenBSD — lire top en mode batch (-b -n 1 = une seule capture)
top -b -n 1

# Extraire le % idle puis calculer cpu = 100 - idle
# Ligne typique de top OpenBSD :
# CPU:  2.3% user,  0.0% nice,  1.5% sys,  0.0% interrupt, 96.2% idle
# NF-1 = avant-dernier champ = valeur idle sans le symbole "%"
top -b -n 1 | awk '/^CPU/{gsub(/%/,"",$NF); idle=$NF; print 100-idle; exit}'

# Parser en Python (len(p) >= 5 suffit pour OpenBSD — NF ~ 10 champs)
p = line.split()           # ['CPU:', '2.3%', 'user,', ...]
if len(p) >= 5:
    idle = float(p[-1].replace('%',''))   # dernier champ = idle%
    cpu  = 100.0 - idle

Tableau de compatibilité Python

Fonctionnalité Python 3.5 Python 3.6+ Solution
f-strings f"..." ❌ SyntaxError ✅ .format() ou %
asyncio.run() ❌ ✅ 3.7+ loop.run_until_complete()
Walrus operator := ❌ ✅ 3.8+ Variable intermédiaire
dict ordonné garanti ❌ ✅ 3.7+ collections.OrderedDict
PYTHONNOUSERSITE ✅ (contournement) souvent inutile Utiliser si erreur import

Leçons importantes apprises (pièges à éviter)

Piège Explication Solution
net.inet6.ip6.accept_rtadv N'existe pas sous OpenBSD (FreeBSD/NetBSD seulement) SLAAC natif, juste passer les RA dans pf
neighbrsolicit dans pf Nom invalide sous OpenBSD Utiliser neighbrsol
NBSP dans config WireGuard Copier-coller depuis mobile insère \xc2\xa0 sed -i 's/\xc2\xa0/ /g' fichier
curl -4 ifconfig.me pour détecter CGNAT Teste depuis l'intérieur = résultat trompeur Comparer avec IP WAN de la box (admin [IP_BOX])
crontab -e cassé sur vieille machine Python 3.5 / distutils absent (crontab -l; echo "...") | crontab -
sed -i 's|...|' sous BSD BSD sed n'accepte pas | comme séparateur Utiliser -i '' et / ou #
SVG dans scripts/ Scripts .sh → scripts/, SVG → docs/images/ Toujours vérifier le bon dossier
IPv6 DuckDNS champ séparé Dashboard DuckDNS : champ A ≠ champ AAAA Remplir le champ "adresse ipv6" séparément
pf bloque SLAAC block in bloque les Router Advertisements ICMPv6 Ajouter pass in ... icmp6-type {routeradv,...}
f-string sur PC3 Python 3.5 SyntaxError: invalid syntax à l'exécution Remplacer tous les f"..." par .format()
PYTHONNOUSERSITE absent PC3 Ubuntu 14.04 : distutils-precedence.pth corrompt le path Préfixer : PYTHONNOUSERSITE=1 python3 ...
CPU OpenBSD via /proc/stat /proc n'existe pas sous OpenBSD → FileNotFoundError Utiliser top -b -n 1 + awk, len(p) >= 5 pour parser
len(p) >= 7 pour parser top OpenBSD OpenBSD top -b -n 1 produit ~10 champs (moins que Linux) Utiliser len(p) >= 5 ; idle = dernier champ (p[-1])
ssh doas host "..." SSH interprète doas comme un hostname, pas une commande doas doit être à l'intérieur des guillemets : ssh -t host "doas ..."
Apostrophe AZERTY dans PS1 ksh Touche 7 produit è accentué au lieu de ' → no closing quote Vérifier visuellement le caractère : bâton vertical ', pas un accent
reboot/shutdown à distance sur PC3/PC4 Pile CMOS morte → écran CMOS Checksum Bad, bloque au redémarrage Intervention physique (F1) obligatoire ; remplacer la pile CR2032
ping6 vers PC4 silencieux pf autorise routeradv/neighbradv/redir mais pas echoreq Ne pas conclure d'une panne — vérifier pfctl -sr | grep icmp6 avant
nc -u ... succeeded UDP sans connexion : « succeeded » dès qu'aucun ICMP d'erreur ne revient, même sur port filtré Tester depuis l'extérieur du LAN, jamais depuis le même /64 que la cible
pfctl -sn pour voir le NAT Obsolète — les règles nat-to sont intégrées aux règles normales Utiliser pfctl -sr
Règle IPv6 manuelle de la box périmée Ne suit pas automatiquement un changement d'adresse IPv6 de PC4 (contrairement au AAAA DuckDNS) Comparer dig +short AAAA <domaine> avec la règle box à chaque nouvelle panne — voir Diagnostic-WireGuard-Hotspot §2

16. nm / ldd / dpkg — Diagnostic bibliothèques partagées (.so)

Protocole de diagnostic quand un .so ne fonctionne pas ou produit des résultats suspects entre deux machines.

nm — Symboles exportés par un .so

# Lister toutes les fonctions publiques (T = text, symbole global)
nm -D scan_arb.so | grep " T "

# Exemples de sortie :
# 00000000000014c0 T scan_zeros_arb    ← fonction exportée ✅
# (rien)                               ← fonction introuvable → .so mal compilé ou mauvais fichier

# Comparer les exports entre deux machines
nm -D local/scan_arb.so | grep " T "
ssh -i ~/.ssh/id_acer hprzeta@[IP_PC2] "nm -D ~/projet_zeta/.../scan_arb.so | grep ' T '"

ldd — Dépendances d'un .so (bibliothèques liées)

# Voir toutes les dépendances
ldd scan_arb.so

# Chercher une lib spécifique ou les libs manquantes
ldd illinois_arb.so | grep -E 'arb|flint|not found'

# Sortie typique :
# libflint-arb.so.2 => /lib/x86_64-linux-gnu/libflint-arb.so.2  ← trouvé ✅
# libflint-arb.so.2 => not found                                 ← manquant ❌

# Sur une machine distante
ssh -i ~/.ssh/id_acer hprzeta@[IP_PC2] "ldd ~/projet_zeta/.../illinois_arb.so"

Note : ldd | grep arb retourne exit code 1 si aucune correspondance (comportement grep normal). Ce n'est pas une erreur si la lib utilise volontairement libm uniquement (ex: scan_arb.so = C pur sans arb).

dpkg — Paquets installés (Debian/Ubuntu)

# Chercher un paquet par nom
dpkg -l | grep -E 'flint|arb'

# Sortie typique :
# ii  libflint-arb2:amd64  1:2.23.0-1+b1  amd64  C library for arbitrary-precision ball arithmetic
# ii  libflint-arb-dev     1:2.23.0-1+b1  amd64  development files

# Installer si manquant
sudo apt install libflint-arb-dev libflint-arb2

# OpenBSD (PC4) — équivalent
pkg_info | grep flint
pkg_add flint

Distinction python-flint vs libflint-arb2

Paquet Source Usage
libflint-arb2 (apt) Bibliothèque système Liée par les .so C (illinois_arb.so)
python-flint (pip) Package Python arb_wrapper.py → arb_hardy_z() en Python

libflint-arb2 présent + python-flint absent → illinois_arb.so fonctionne (C) mais ARB_DISPONIBLE=False en Python → fallback mpmath.siegelz. Installer séparément :

# Sur PC2 (système Python3) — si pip3 disponible
pip3 install python-flint

# Vérifier
python3 -c "from arb_wrapper import ARB_DISPONIBLE; print(ARB_DISPONIBLE)"

pip sur Debian externally-managed (Python 3.11+, PEP 668)

Debian 12 et Ubuntu 23.04+ bloquent pip install système par défaut (PEP 668).

# Option 1 — install utilisateur (sans sudo, packages dans ~/.local/)
pip3 install paquet --user

# Option 2 — forcer install système (machines dédiées calcul, pas de serveur de prod)
pip3 install paquet --break-system-packages

# Option 3 — venv (isolation propre, recommandé pour projets)
python3 -m venv ~/mon_venv
source ~/mon_venv/bin/activate
pip install paquet

Attention PYTHONPATH en SSH : un package installé --user est dans ~/.local/lib/pythonX.Y/site-packages/. Si le script est lancé via ssh host "python3 script.py" (shell non-interactif), ce chemin peut être absent. Vérifier : ssh host "python3 -c 'import sys; print([p for p in sys.path if \".local\" in p])'". Si vide : passer PYTHONUSERSITE=1 dans la commande SSH, ou utiliser --break-system-packages.

Leçon session 2026-06-17 — python-flint 0.8.0 installé sur PC2 (Debian 12, Python 3.11).


17. Alias Riemann_Lab — distribution PC1+PC2

Alias ajoutés au ~/.bashrc de PC1 (session 2026-06-17) pour lancer la distribution PC1+PC2 sans passer par Claude Code — script autonome scripts/zeta_distribute_run.sh.

zeta-distribute 500000          # lance T=500k distribué PC1+PC2 + dashboard
zeta-distribute 1000000         # lance T=1M
zeta-distribute 500000 --no-dashboard  # sans dashboard tmux
zeta-progress                   # s'attacher au dashboard en cours
zeta-pid                        # voir PID du run actif
zeta-log                        # suivre le log en temps réel

Détail du script zeta_distribute_run.sh :

  • Active le turbo (sudo scripts/zeta_turbo_on.sh — sudoers NOPASSWD, non interactif).
  • Lance zeta_run_progress.py dans une session tmux zeta-progress (sauf --no-dashboard).
  • Lance zeta_distribute.py $T_MAX en nohup, détaché, avec confirmation auto-répondue (printf "O\n" |) — sans quoi le script plante en EOFError (pas de TTY pour input()).
  • PID écrit dans /tmp/zeta_distribute.pid, log dans logs/distribute_T<T_MAX>_nohup_<horodatage>.log.

Limites connues :

  • --help n'est pas géré : zeta-distribute --help lancerait un vrai run avec T_MAX="--help" (ne pas l'utiliser ; pas de validation d'argument dans le script).
  • zeta-log (tail -f ... | tail -1) ne s'arrête jamais tout seul (tail -f est bloquant) — utile pour suivre en direct, mais ne convient pas à un usage scripté/non interactif.

18. wg_auto.sh — Bascule WireGuard automatique maison/déplacement (PC1)

Règle maison / déplacement

Situation Test Action
🏠 Maison PC4 ([IP_PC4]) joignable en ping direct sur l'interface physique wg0 DOWN (LAN direct, plus rapide)
🧳 Déplacement PC4 injoignable en LAN wg0 UP (tunnel via DuckDNS)

Cause du besoin : les AllowedIPs du tunnel incluent [LAN] (LAN maison). Si wg0 reste monté à la maison, le routage tente de passer par le tunnel au lieu du LAN direct — or la box SFR ne fait pas de NAT loopback (pas de hairpinning), donc le trafic vers l'IP publique/DuckDNS depuis l'intérieur du LAN échoue ou boucle. Il faut donc désactiver wg0 quand PC4 est joignable en direct, et l'activer sinon.

Le script

scripts/wg_auto.sh :

  • Ping [IP_PC4] (PC4) en forçant l'interface physique (ip route ... | grep -v wg0, jamais wg0 lui-même, sinon le test est faussé par le tunnel en cours).
  • Maison (ping OK) → si wg0 actif : sudo wg-quick down wg0.
  • Déplacement (ping KO) → si wg0 inactif : sudo wg-quick up wg0, puis vérifie le tunnel avec un ping sur [WG_PC4] (passerelle VPN côté PC4).
  • Log dans logs/wg_auto.log (append) + notification bureau (notify-send) systématique.

Les 3 messages possibles

🏠 MAISON — WireGuard DÉSACTIVÉ                          # wg0 était up, vient d'être coupé
🏠 MAISON — WireGuard déjà désactivé                      # rien à faire (mode --quiet : silencieux)
🧳 DÉPLACEMENT — WireGuard ACTIVÉ                         # wg0 monté, tunnel [WG_PC4] répond
🧳 DÉPLACEMENT — WireGuard déjà activé                    # rien à faire (mode --quiet : silencieux)
⚠️ DÉPLACEMENT — WireGuard activé mais tunnel NE RÉPOND PAS  # wg0 up mais [WG_PC4] ne répond pas
                                                            # → vérifier connexion internet / DuckDNS

Utilisation

wg-auto                       # alias ~/.bashrc — affiche le message dans le terminal
bash scripts/wg_auto.sh       # équivalent direct
bash scripts/wg_auto.sh --quiet   # pas d'affichage terminal si déjà dans le bon état
                                   # (utilisé par le dispatcher NetworkManager)

zeta-cluster                  # scripts/zeta_tmux.sh appelle wg_auto.sh (sans --quiet)
                               # avant de monter la session tmux du cluster

Intégration NetworkManager (automatique à chaque connexion réseau)

/etc/NetworkManager/dispatcher.d/99-wg-auto appelle wg_auto.sh --quiet à chaque événement up/vpn-up — la notification bureau prévient du basculement sans action manuelle. Nécessite sudo -u riemann (le dispatcher tourne en root) et une entrée sudoers NOPASSWD ciblée pour wg-quick/wg show (sinon sudo bloque en non-interactif, faute de TTY).


19. UPower — CriticalPowerAction=PowerOff (PC1, incident run T=5M du 02-04/08/2026)

Incident

Run distribué T=5 000 000 lancé le 02/08/2026 20:29 sur PC1+PC2, jamais abouti (dossier de résultats vide). Reconstitution via sar (accounting persistant — le journal systemd, lui, est volatile et ne conserve qu'un seul boot) :

Heure Événement
02/08 20:40 CPU → 98 % (run en cours)
03/08 00:45 LINUX RESTART non planifié — run tué après ~4h, aucun résultat écrit
03/08 19:19 2ᵉ LINUX RESTART
03/08 23:34 → 04/08 18:19 Machine éteinte ~18h45

Cause : PC1 (portable) tournait sur batterie, débranché, avec deux alertes "Running on LOW Battery" le 03/08. CriticalPowerAction=HybridSleep était configuré à 5 % de batterie (action forcée à 2 %) — mais aucun resume= n'est câblé (ni dans /proc/cmdline, ni dans /etc/initramfs-tools/conf.d/resume), malgré une swapfile de 16G disponible (/mnt/data/swapfile, sur fichier — donc nécessiterait en plus un resume_offset= précis, pas juste resume=UUID). Résultat : la tentative de veille hybride ne peut pas reprendre proprement et dégénère en redémarrage/extinction sauvage au lieu d'une vraie mise en veille.

Correctif appliqué (04/08/2026)

Débranchement accidentel identifié comme cause réelle (pas une panne récurrente) → correctif volontairement simple plutôt qu'une réparation complète du hibernate/resume :

sudo sed -i 's/CriticalPowerAction=HybridSleep/CriticalPowerAction=PowerOff/' \
  /etc/UPower/UPower.conf
sudo systemctl restart upower   # sinon la nouvelle valeur n'est prise qu'au prochain démarrage du démon

/etc/UPower/UPower.conf — valeurs pertinentes après correctif :

PercentageLow=20
PercentageCritical=5
PercentageAction=2
CriticalPowerAction=PowerOff

À 2 % de batterie critique : arrêt propre et prévisible (systemctl poweroff-like), plutôt qu'une veille hybride non fiable sur ce matériel.

Vérification post-correctif

grep CriticalPowerAction /etc/UPower/UPower.conf   # → PowerOff
upower -i $(upower -e | grep -i AC)                # → online: yes (secteur branché)
ps -o pid,lstart,cmd -C upowerd                     # → démon redémarré après l'édition du fichier

État des politiques de veille — les 4 machines du cluster (04/08/2026)

Machine OS Politique de veille automatique
PC1 (zeta-lab) Linux/systemd sleep-inactive-*=nothing, idle-delay=0, IdleAction=ignore — aucune veille auto. Résiduel : HandleLidSwitch=suspend (défaut) → fermer le capot suspend la machine, à éviter pendant un run.
PC2 (zeta-calc-second) Linux/systemd Défauts systemd (IdleAction=ignore) — aucune veille auto.
PC3 (zeta-backup) Linux/systemd HandleLidSwitch=lock (override de 2017), pas de IdleAction — aucune veille auto.
PC4 (zeta-secure) OpenBSD 7.9 Aucun démon apmd actif (absent de rcctl ls on) — aucune gestion d'énergie automatique possible.

PC2/PC3/PC4 sont alimentés en continu (pas de batterie) : le risque UPower/HybridSleep ne concerne que PC1.

Leçon durable : nohup/setsid protègent un process d'une fermeture de session ou d'une déconnexion SSH, pas d'un vrai poweroff/reboot de la machine — seul un secteur branché en continu (ou un onduleur) garantit la survie d'un run long.


20. zeta_backup_status.py — vérification quotidienne du pipeline de sauvegarde (2026-08-05)

Pourquoi

Le pipeline de backup (STACK.md § Infrastructure backup) est silencieux par construction : rsync -aq (PC1→PC3) ne journalise rien, et le succès du rclone copy (PC3→ProtonDrive) n'était jusqu'ici jamais vérifié activement — le statut ✅ auto supposé pour PC3 (mémoire de session) n'avait en réalité jamais été contrôlé sur le fond. Premier lancement du script le 05/08/2026 : 7/7 jours en ÉCHEC côté rclone (crash Go répété — fatal error: found bad pointer/found pointer to free object, précédé de 401 Invalid access token et de conflits 422 — cause probable : rclone_cron.log fait partie de son propre périmètre de sauvegarde et grossit pendant la copie, provoquant source file is being updated, sur un i686 32 bits à mémoire limitée). Aucune ligne Transferred: de succès trouvée dans tout l'historique du log (50 000+ lignes). Non résolu à ce jour — nécessite une investigation dédiée (hors périmètre de cette entrée).

Script

scripts/zeta_backup_status.py — deux tableaux :

  1. Sync 1 (PC1→PC3, rsync) : déclenchement du cron via /var/log/syslog(.1) (preuve d'exécution seulement — rsync -aq ne dit rien sur son succès) + atterrissage réel via la fraîcheur des fichiers sous ~/backup/{logs,wiki,pdf} côté PC3 (find -newermt).
  2. Sync 2 (PC3→ProtonDrive, rclone) : parsing de ~/backup/rclone_cron.log — succès (ligne Transferred:), échec (ERROR/fatal error: Go), ou sauté (aucune ligne pour la date).

⚠️ Piège découvert en écrivant le script : SSH vers PC3 pour lire ~/backup/ doit utiliser l'utilisateur pjexosql (clé ~/.ssh/id_acer), pas l'alias zeta-backup du cluster (~/.ssh/config, utilisateur hprzeta) — ce sont deux comptes Unix différents sur la même machine [IP_PC3] ; le dossier ~/backup/ n'existe que sous pjexosql.

Utilisation

zeta-backup-status                       # 7 derniers jours
zeta-backup-status --date 2026-08-04     # une date précise (AAAA-MM-JJ)

Alias ~/.bashrc : zeta-backup-status='cd ~/projet_zeta && source zeta_env/bin/activate && python scripts/zeta_backup_status.py'.

Gère un PC3 injoignable proprement (timeout SSH 6-20s selon la commande, ok=False propagé sans lever d'exception) — affiche PC3 injoignable / PC3 INJOIGNABLE (timeout SSH) au lieu de planter.


21. perf record / perf report — profiling réel d'un module C (2026-08-08)

Pourquoi

Avant d'optimiser illinois_arb.c (piste v16), profiler avec de vrais chiffres plutôt que deviner où va le temps. perf (linux-tools) donne une répartition par fonction/bibliothèque directement sur le .so compilé, sans instrumentation.

perf_event_paranoid — sudo requis, pas de raccourci

cat /proc/sys/kernel/perf_event_paranoid   # 4 sur zeta-lab = perf réservé root

Niveau 4 (Ubuntu récent) : perf record échoue pour un utilisateur normal, même avec sudo -n (pas de règle NOPASSWD dédiée dans /etc/sudoers.d/zeta_turbo). Le préfixe ! de Claude Code ne peut PAS saisir de mot de passe sudo (pas de tty) — la commande doit être lancée par hprzeta directement dans un terminal réel (le prompt [sudo] Mot de passe : s'affiche normalement dans ce cas).

Commande type

sudo perf record -F 4000 -g -o sortie.data -- python3 harnais.py
sudo chown $(whoami):$(whoami) sortie.data   # rendre le fichier lisible sans sudo ensuite

perf report -i sortie.data --stdio --sort=overhead,symbol -g none   # flat, par fonction
perf report -i sortie.data --stdio --sort=dso -g none               # par bibliothèque
  • -F 4000 : fréquence d'échantillonnage (Hz) — 4000 est largement suffisant pour des appels de l'ordre de la milliseconde.
  • Le harnais Python doit boucler suffisamment longtemps (~15-20s) pour accumuler assez d'échantillons — un run trop court donne un profil bruité/vide.
  • perf report sur un binaire lié à de grosses bibliothèques (ici libflint, libgmp) peut prendre plusieurs minutes la première fois (résolution de symboles) — normal, pas un blocage.

Lecture d'un symbole global char[] en ctypes — piège segfault

Pour lire une version/chaîne exposée comme variable globale C (pas une fonction) :

# ❌ crash (segfault) : flint_version est un tableau char[], pas un char*
ver = ctypes.c_char_p.in_dll(lib, "flint_version")

# ✅ correct : lire les octets bruts à l'adresse du symbole comme un tableau
arr = (ctypes.c_char * 32).in_dll(lib, "flint_version")
print(bytes(arr))   # b'3.3.1\x00...'

c_char_p.in_dll traite la valeur au symbole comme un pointeur vers une chaîne et le déréférence — si le symbole est en réalité le buffer lui-même (char v[32]), ça lit un pointeur invalide (les premiers octets de la chaîne interprétés comme une adresse) → segfault immédiat.


22. Compiler FLINT depuis les sources — headers pour un ABI runtime précis (2026-08-08)

Pourquoi

apt install libflint-dev installe une version figée par la distribution (3.0.1 sur Ubuntu 24.04) qui peut être plus ancienne que la bibliothèque réellement chargée en runtime par un paquet Python (ex. python-flint bundlant FLINT 3.3.1). Pour des types de structure activement modifiés entre versions (dirichlet_group_t, dirichlet_char_t), compiler contre des headers d'une mauvaise version = risque de corruption mémoire silencieuse (mauvais offsets de champs), pas juste un mauvais résultat numérique. Solution : récupérer les headers de la version EXACTE utilisée au runtime, directement depuis les sources.

Identifier la version runtime exacte

nm -D chemin/vers/libflint*.so | grep flint_version   # symbole "D" = donnée, pas fonction
# cf. §21 ci-dessus pour la lecture correcte en ctypes

Récupération + configuration minimale (pas besoin de compiler toute la lib)

curl -sL -o flint-X.Y.Z.tar.gz \
  "https://github.com/flintlib/flint/releases/download/vX.Y.Z/flint-X.Y.Z.tar.gz"
tar xzf flint-X.Y.Z.tar.gz && cd flint-X.Y.Z

# ./configure génère flint.h/flint-config.h (FLINT_BITS, etc.) sans lancer la
# compilation complète — seuls ces 2 fichiers générés + les headers statiques du
# dépôt sont nécessaires pour compiler CONTRE la .so déjà présente sur le système.
./configure --with-gmp-include=/usr/include/x86_64-linux-gnu \
            --with-gmp-lib=/usr/lib/x86_64-linux-gnu \
            --with-mpfr-include=/usr/include \
            --with-mpfr-lib=/usr/lib/x86_64-linux-gnu

Dépendance cachée : m4 (souvent absent d'une installation Ubuntu minimale) — ./configure échoue tard (« checking for suitable m4 ») sans lui :

sudo apt install -y m4   # à lancer dans un terminal réel, même remarque sudo que §21

Extraire uniquement les headers réellement nécessaires

FLINT complet expose des centaines de headers (théorie des nombres, algèbre — bien au-delà de ce qu'utilise un module qui n'a besoin que de acb/arb/dirichlet). Extraire la fermeture transitive réelle plutôt que tout copier :

gcc -Iflint-X.Y.Z/src -M mon_fichier.c | tr ' \\' '\n\n' \
  | grep "^$(pwd)/flint-X.Y.Z/src" | sort -u

-M liste toutes les dépendances d'inclusion sans compiler — donne la liste exacte des .h à copier (23 fichiers / 276 Ko dans le cas illinois_arb.c, contre 800+ pour FLINT complet). Vérifier ensuite qu'aucun chemin absolu machine-spécifique ne s'est glissé dans les fichiers générés (flint.h, flint-config.h) avant de les committer :

grep -l "/home/\|/tmp/" headers_extraits/*.h   # doit être vide

23. apt — Mise à jour système à distance (Debian/Ubuntu, PC2/PC3)

Consultation avant d'installer

ssh -t zeta-calc-second "sudo apt update && apt list --upgradable"
ssh -t zeta-backup      "sudo apt update && apt list --upgradable"

Application

ssh -t zeta-calc-second "sudo apt upgrade -y"
ssh -t zeta-backup      "sudo apt upgrade -y"

Note session 15/08/2026 : PC3 (Ubuntu 14.04, Python 3.5.2 — cf. §15) a répondu 0 mise à jour, 0 installé, 0 à enlever — système déjà à jour, Python inchangé après vérification (python3 --version → toujours 3.5.2, aucun risque pour le fix f-string de zeta_monitor.py).


24. Cluster — Users locaux vs hprzeta, désactivation auto-login

Vérifier le user de connexion sur chaque machine du cluster

for h in zeta-lab zeta-calc-second zeta-backup zeta-secure; do
  echo "=== $h ==="
  ssh $h whoami
done

Version pas-à-pas (PC1 en local, pas de SSH sur lui-même) :

echo "=== PC1 (local) ===" && whoami
echo "=== PC2 ===" && ssh zeta-calc-second whoami
echo "=== PC3 ===" && ssh zeta-backup whoami
echo "=== PC4 ===" && ssh zeta-secure whoami

📌 Rappel cluster : chaque machine a un user local d'origine (propre à l'installation de la distro) en plus du user hprzeta créé pour le cluster :

  • PC2 : user local emmabuntus (distro Emmabuntüs)
  • PC3 : user local pjexosql
  • PC4 : pas de user local distinct identifié à ce jour (OpenBSD, install manuelle)

hprzeta reste identique sur les 4 machines — ne pas le renommer par machine, tout le cluster (~/.ssh/config, zeta_monitor.py, zeta_tmux.sh, cron de backup, chemins /home/hprzeta/...) suppose ce nom unique partout.

Désactiver l'auto-login (Debian/Ubuntu, PC2)

Identifier le display manager actif :

cat /etc/X11/default-display-manager

Changer le mot de passe du user local :

# En local sur la machine
passwd

# À distance depuis PC1 (avec sudo)
ssh zeta-calc-second
sudo passwd emmabuntus

Désactiver l'auto-login — si GDM3 :

sudo nano /etc/gdm3/custom.conf

Chercher et commenter/désactiver :

AutomaticLoginEnable = true
AutomaticLogin = emmabuntus

Désactiver l'auto-login — si LightDM :

sudo nano /etc/lightdm/lightdm.conf

Chercher et commenter :

autologin-user=emmabuntus

Vérification après reboot :

sudo reboot

Au redémarrage, un écran de connexion doit apparaître (au lieu du login automatique).


25. vi — Aide-mémoire minimal

Action Touche(s)
Aller à la fin du fichier G (mode normal)
Aller à une ligne précise (ex. 11) 11G
Ouvrir une nouvelle ligne en dessous + passer en insertion o
Sortir du mode insertion Échap
Supprimer la ligne courante (mode normal) dd
Sauvegarder et quitter :wq puis Entrée
Quitter sans sauvegarder :q!

Le ~ en début de ligne dans vi = ligne vide, pas de contenu. Ce n'est pas une erreur.

Règle à retenir : dd, G, les flèches sont des commandes mode normal. En cas de doute sur le mode courant, appuyer sur Échap d'abord (ramène toujours en mode normal sans risque), puis relancer la commande voulue.


26. Post-mortem d'un crash machine — commandes employées (18/08/2026)

Utilisées pour diagnostiquer le crash PC1 du 18/08 (03h12) et évaluer la fiabilité d'une machine avant un run long. Résultat de ce diagnostic : JOURNAL du 18/08.

# Historique des boots/reboots connus du journal systemd persistant
journalctl --list-boots

# Occupation disque du journal (repère un journal quasi vide = pas persistant longtemps)
journalctl --disk-usage

# Vérifier si le stockage persistant est actif et depuis quand
ls -ld /var/log/journal/                    # dossier parent
ls -la /var/log/journal/*/                  # sous-dossier machine-id — sa date de
                                             # création = début réel de la persistance,
                                             # PAS forcément celle du dossier parent
systemd-analyze cat-config systemd/journald.conf | grep -i storage

# Historique des reboots (Linux — voir §24 pour la variante OpenBSD sans -x)
last -x reboot

# Santé disque SMART — nécessite root
sudo smartctl -a /dev/sda | grep -A20 "SMART Attributes"
sudo smartctl -H /dev/sda                   # résumé PASSED/FAILED uniquement

# État et historique de la batterie
upower -e | grep BAT
upower -i $(upower -e | grep BAT)

# Erreurs matérielles/thermiques dans le tampon noyau — nécessite root,
# et ne couvre QUE le boot courant (tampon volatile, remis à zéro à chaque démarrage)
sudo dmesg | grep -iE "thermal|mce|hardware error|critical|ACPI Error"

# Empêcher toute extinction/veille système pendant un calcul long
systemd-inhibit --what=shutdown:sleep:idle --mode=block <commande longue>

Piège découvert le 18/08 : un dossier /var/log/journal peut exister depuis longtemps (créé par un paquet) sans que le journal soit réellement persistant — le sous-dossier <machine-id> à l'intérieur ne se crée qu'au premier boot où systemd-journald bascule réellement en stockage disque. Vérifier la date du sous-dossier, pas seulement celle du dossier parent.


27. Diagnostic réseau WireGuard/IPv6 à distance — session 22/08/2026

Complète §1/§5/§6 ci-dessus. Contexte complet et causes racines : Diagnostic-WireGuard-Hotspot.

Résolution DNS

# Enregistrement A (IPv4) uniquement
dig +short A [DDNS_PC4]

# Enregistrement AAAA (IPv6) uniquement
dig +short AAAA [DDNS_PC4]

# Les deux d'affilée
dig +short A [DDNS_PC4] ; dig +short AAAA [DDNS_PC4]

Une sortie vide pour A et une adresse pour AAAA = le nom résout exclusivement en IPv6 — état recherché depuis la suppression volontaire de l'enregistrement A périmé (voir Diagnostic-WireGuard-Hotspot §5.5). dig et host -t AAAA (§8 ci-dessus) sont équivalents ; dig +short est plus rapide à lire en script.

SSH — interpréter un échec

ssh hprzeta@[WG_PC4]                                          # via le tunnel
ssh -i ~/.ssh/id_acer -o IdentitiesOnly=yes hprzeta@[IP_PC2]   # clé explicite
Message Cause probable
Connection timed out Paquets perdus : pare-feu, routage absent, ou route vers une interface morte
Connection refused Hôte joint, mais rien n'écoute sur le port 22
Broken pipe Session existante coupée (changement de réseau, tunnel démonté)
The authenticity of host ... can't be established Première connexion via cette adresse

Détail rassurant — si le message ajoute This host key is known by the following other names/addresses:, la clé du serveur est déjà connue sous une autre adresse. C'est la même machine, jointe par un chemin différent. Répondre yes sans risque.

Tests trompeurs à ne pas reproduire

nc -u sur un port UDP ne prouve rien :

nc -u -v -w2 -6 [IPV6] 51820
# → "succeeded!" ... qui ne prouve rien

En UDP il n'y a pas de connexion : nc affiche « succeeded » dès qu'aucun ICMP d'erreur ne revient dans le délai — un port filtré silencieusement produit le même résultat qu'un port ouvert. Vérifier en plus que le test part bien de l'extérieur du LAN : un paquet lancé depuis le même /64 que la cible n'atteint jamais l'interface WAN de la box, donc ne traverse aucun pare-feu périmétrique.

ping6 vers PC4 échoue même quand tout va bien : voir §1 (TTL) et pfctl -sr | grep -i icmp6 (§6) avant d'interpréter un silence — les règles pf de PC4 autorisent routeradv/neighbradv/neighbrsol/redir mais pas echoreq.

Monter un tunnel depuis le réseau domestique — voir §18 (wg_auto.sh, nm-dispatcher) : aucun test de tunnel n'est possible depuis le LAN domestique, le dispatcher coupe wg0 automatiquement.

sudo wg-quick up wg0
# → "wg0 already exists"  : réseau externe, le tunnel tient
# → interface détruite     : réseau domestique, le dispatcher a coupé

Séquence de vérification complète

Après toute modification touchant l'accès distant :

# ── Étape 1 : sur le LAN — appliquer les changements (box, PC4) ──
# ── Étape 2 : basculer sur un partage de connexion mobile ──
# ── Étape 3 : sur PC1, hors réseau domestique ──

curl -s6 --max-time 5 https://api64.ipify.org ; echo   # l'IPv6 sort-elle ?
dig +short AAAA [DDNS_PC4]                # le DNS est-il à jour ?
sudo wg-quick down wg0 ; sudo wg-quick up wg0
sleep 10
sudo wg show                                           # handshake ?
ping -c 2 [WG_PC4]                                    # PC4 via le tunnel
ping -c 2 [IP_PC2]                                 # PC2 via le routage PC4
ssh hprzeta@[WG_PC4]                                  # accès complet
Étage qui échoue Où chercher
Pas d'IPv6 publique sur PC1 Le réseau d'accès (hotspot) est IPv4 seul
AAAA absent ou obsolète Updater DuckDNS sur PC4
Pas de handshake Règle IPv6 de la box, ou pf sur PC4
[WG_PC4] muet Configuration WireGuard côté serveur
[IP_PC2] muet net.inet.ip.forwarding ou nat-to sur PC4

⚠️ Inverser les étapes 2 et 3 produit un faux négatif (le dispatcher coupe wg0). Ne jamais modifier la configuration réseau de la box via le tunnel : une erreur coupe l'accès jusqu'au retour physique sur le LAN.


28. Diagnostic IPv6 vs VPN tiers (Proton) — session 05/09/2026

Complète §27. Contexte complet et cause racine : Diagnostic-WireGuard-Hotspot §9, procédure de référence : Guide-WireGuard-Acces-Distant.

Le 05/09/2026, l'accès distant semblait cassé (aucune IPv6 globale en déplacement) alors que le hotspot fournissait bien l'IPv6 depuis le début — un VPN tiers (Proton VPN) actif sur le portable la bloquait. Commandes de diagnostic utilisées, dans l'ordre :

# 1. IPv6 globale présente ? (exclut fe80:: lien-local, toujours présent)
ip -6 addr show scope global
# équivalent : ip -6 addr show | grep -v fe80

# 2. Route par défaut IPv6 ?
ip -6 route show default

# 3. Sortie IPv6 réellement fonctionnelle ?
ping6 -c2 2001:4860:4860::8888

# 4. Endpoint toujours résolu correctement côté DuckDNS ?
dig +short AAAA [DDNS_PC4]

# 5. Seul test valide du tunnel lui-même (PC4 ne répond jamais à un ping6 direct) :
sudo wg show wg0
ping -c2 [WG_PC4]

Piège : un ping6 échoue de la même façon que le réseau soit vraiment sans IPv6 ou qu'un VPN tiers la bloque en local. Les deux premières commandes (ip -6 addr/route) ne distinguent pas ces deux cas non plus — seule l'observation « ça marchait avant sur ce même réseau » (ou couper le VPN et retester immédiatement) permet de trancher. Ne pas conclure trop vite à un problème d'opérateur mobile sans avoir d'abord vérifié qu'aucun VPN commercial (Proton, Mullvad, NordVPN, etc.) n'est actif.

Garde ajoutée dans wg_auto.sh (v2)

Pour éviter que le script de bascule automatique ne spamme des notifications en tentant de réparer un tunnel injoignable par construction (pas d'IPv6), une garde a été ajoutée en tête du bloc déplacement — voir Diagnostic-WireGuard-Hotspot §9 et Guide-WireGuard-Acces-Distant §3.4 pour le détail et le diff complet.


Guide-Linux-Commandes.md · wiki racine · branche master · hprzeta · MAJ 2026-09-05 (§28 — diagnostic IPv6 vs VPN tiers, session Proton VPN du 05/09) · 1656 lignes

Clone this wiki locally