blocage
[modifier] Introduction
Document Copyright © 1997-2013 Nat Makarevitch et les autres auteurs cités
La plus récente version de ce texte est publiée en http://wiki.linux-france.org/wiki/blocage.
Seule la diffusion des versions non modifiées est autorisée.
Ce texte en cours de rédaction peut permettre de découvrir pour quelle raison un programme ne fonctionne pas correctement.
Il ne s'agit ici que de dysfonctionnements "système", c'est-à-dire causés par un contexte d'exploitation donné et non à un algorithme inadéquat sur le plan fonctionnel (qui ne "fait pas" ce que l'on souhaite). Plus explicitement le présent document n'est pas un manuel de débogage mais plutôt description de ce que l'on peut faire afin de comprendre pourquoi un programme qui censé fonctionner ne le fait pas sur une machine donnée.
Notes : cette "checklist" n'abrite rien d'original et n'intéressera pas les utilisateurs confirmés.
Un autre article décrit la « ligne de commande » (les commandes fondamentales).
[modifier] Checklist
[modifier] S'informer
Consulter Google puis le site web du logiciel (la documentation contient souvent son URL), en y cherchant des termes du message d'erreur.
Tenter de grouper les termes les plus significatifs et d'en extraire ce qui est vraisemblablement dépendant du contexte. Par exemple lorsque le programme nommé example produit le message "Syntax error line 4242: I need a variable name!" chercher ceci (guillemets inclus):
+example "Syntax error line" "I need a variable name!"
Si les résultats sont contradictoires limiter la recherche au site web le plus pertinent. Pour cela chercher le nom de nom de domaine IP du site web du projet (par exemple example.org) puis le fournir préfixé de site: . Exemple:
site:example.org "Syntax error line" "I need a variable name!"
[modifier] Fichiers de trace
Ne pas négliger que de nombreux programmes, au prix d'un paramétrage adéquat, rendent compte de façon plus ou moins complète et détaillée de leur activité dans des fichiers de traces (dits "log").
Ces derniers se trouvent le plus souvent sous le répertoire /var/log/.
Ils sont gérés par un démon utilitaire de type "syslog", nom générique d'une famille de logiciels auxquels tout programme peut à tout moment expédier un message révélateur de son activité afin qu'il connaisse le sort décidé par l'administrateur: déclenchement d'une alerte, archivage pour consultation ultérieure, destruction s'il n'est pas jugé intéressant...
syslog désignera ici le démon utilisé, même si son nom n'est pas «syslog» (il peut s'agir de «rsyslog», «dsyslog», «syslog-ng»...).
Le programme fournit à syslog, avec chaque message:
- le type de la mission concernée
- un message relatif à la messagerie, par exemple, peut ainsi être donné pour tel. C'est peu utile car les types sont prédéfinis et ceux qui le sont par les syslogs classiques ne recouvrent pas le gros des besoins
- le niveau d'importance
- le message est-il une simple information, un avertissement, une alerte...?
syslog, en fonction de ses jf:configuration paramètres, filtre chaque message afin de déterminer ce qu'il doit écrire ou non et dans quel fichier de log le faire. On peut ainsi paramétrer son comportement (stocker ou non un message, où le stocker...) selon le type du message (par exemple s'il concerne la messagerie), de son niveau d'importance (par exemple tout ce qui n'est pas au moins une alerte) voire de son contenu (par exemple tout message contenant "ProgrammeDeTest").
Un démon syslog ne nous aidera que s'il est actif actif. Pour déterminer si c'est le cas :
ps auxw | grep syslog | grep -v grep
Cela doit produire une ligne ressemblant à ceci :
root 3224 0.0 0.0 1816 628 ? Ss 20:35 0:00 /sbin/syslogd
Si ce n'est pas le cas le système est étrangement configuré ou mal en point, tenter d'installer le paquet nommé «sysklogd».
Admettons qu'un "syslog" est installé et actif.
Explorez son paramétrage afin de connaître:
- noms complets (avec chemin d'accès) des fichiers de log
- filtres (qui doivent mener au stockage dans un fichier de tout message de log potentiellement révélateur de la cause du blocage)
Ce paramétrage est établi par root et se trouve, si la machine emploie le démon "rsyslogd", dans le fichier /etc/rsyslog.conf (examiner aussi un éventuel répertoire /etc/rsyslogd.conf). Pour que "syslog" enregistre tout durant la résolution du problème il suffit de conserver ce/ces fichiers de paramètres et de les remplacer temporairement par une version consignant tout donc contenant en tout et pour tout:
*.* /var/log/total_temporaire.log
Demander au démon de relire sa configuration (sous Debian invoquer /etc/init.d/sysklogd reload). Tenter alors de nouveau les manoeuvres ne donnant pas satisfaction comme déjà décrit (debug et verbose).
ATTENTION: sitôt le problème résolu restaurer les paramètres de syslog et les lui faire relire, sous peine d'enregistrer inutilement beaucoup de logs donc de ralentir la machine et de risquer de saturer un système de fichiers.
Certains programmes ne confient pas tous leurs logs à syslog. Lire la documentation afin de déterminer :
- si le programme délègue la gestion de ses traces à "syslog" et/ou s'il s'en charge (certains délèguent partiellement: des éléments d'historique sont confiés à syslog et le programme en écrit directement d'autres),
- la configuration et/ou les options d'invocation les invitant à produire des traces détaillées
[modifier] En pratique
Dans un terminal saisir, en tant que root, la commande suivante (ne pas appuyer sur la touche « Entrée », nous la préparerons ici en vue d'une invocation ultérieure):
find /var/log -type f -mmin -1
Dans un autre terminal invoquer le programme défectueux, si possible en mode debug et verbose (lire sa doc et son man), puis revenir immédiatement au terminal root et invoquer la commande préparée durant la précédente étape. Elle produira la liste des noms des fichiers de traces modifiés durant la minute écoulée.
Examiner le contenu de tout fichier modifié grâce à tail, et si nécessaire à less et grep, afin de trouver des indices, par exemple en cherchant le nom du programme ou des fichiers qu'il traite.
Note: pour relancer automagiquement périodiquement la commande « find » utiliser l'outil « watch » (il faut peut-être l'installer au préalable):
watch find /var/log -type f -mmin -1
Si peu de noms de fichiers apparaissent, alors peu de lignes de log décrivent l'activité du programme posant problème. Vérifier les règles de filtrage des messages par "syslog".
[modifier] Environnement
[modifier] Langue
Relancer le programme après avoir invoqué (sur ligne de commande):
export LANG=C
TODO: expliquer
Le programme produira peut-être alors des messages d'erreur en anglais. Les chercher sur le Web.
[modifier] Cerner le problème
Tester diverses options, modes de fonctionnement, données à traiter afin de déterminer ce qui fonctionne ... ou pas. S'assurer que l'on dispose bien d'espace-disque (commande df), que les répertoires temporaires (/tmp, /var/tmp ...) ne sont pas saturés, essayer après mise à zéro de toutes les variables d'environnement douteuses (utiliser printenv pour les examiner et, sous bash, export NOM_VARIABLE= pour les supprimer.
Si le programme crashe sur réception d'un "signal 11" (dit "SIGSEGV") lire la FAQ signal 11
[modifier] Analyser les messages d'erreur
Dériver au besoin le canal de sortie standard et celui réservé aux erreurs vers un fichier. Invoquer pour cela (sous bash) :
nom_du_programme 2>&1 | tee nom_du_programme.sortie.tmp
Les messages (y compris d'erreur) du programme seront stockés (par tee) dans le fichier nommé nom_du_programme.sortie.tmp.
Si le programme est un script de shell l'invoquer en mode trace. Exemple (sous bash) :
bash -x nom_du_programme 2>&1 | tee nom_du_programme.sortie.tmp
[modifier] Lecture, par le programme, de ses fichiers de configuration
Déterminer comment vérifier que le programme lit et interprète correctement le contenu de ses fichiers de configuration. Pour cela chercher comment lui faire produire quelque part (dans un fichier de log, sur son stdout...) ses paramètres de fonctionnement. Il suffit parfois de lui passer un/des argument ou paramètre le faisant fonctionner en mode debug et verbose, ou de le contraindre à montrer (dump) ses paramètres...
En désespoir de cause tenter d'employer strace (lire ci-après): strace -s0 -eopen,read NomDuBinaire
[modifier] Mise à jour
Installer la plus récente version du logiciel.
[modifier] Bien lire sa documentation
En théorie mieux vaudrait toujours commencer par cela, mais les habitudes d'empirisme contractées... Bref.
Ne pas oublier les pages de manuel. Sous Debian explorer /usr/share/doc/nom_du_programme*.
S'assurer que tous les composants requis (bibliothèques, éditeur de liens dynamiques, serveur X ...) sont bien installés.
[modifier] Fichiers de verrouillage (lock)
En cas de problème de partage de ressources surveiller le contenu de /var/lock durant les essais.
[modifier] Utiliser un traceur d'appels
Lancer le programme sous "strace". Cet outil dresse, au fur et à mesure de l'exécution d'un binaire, liste des appels à la bibliothèque système (la fameuse libc).
Exemple : lorsque le programme fonctionne bien si root l'emploie mais mal sinon on pourra comparer ainsi les contextes :
su - # passer root cd /tmp touch fichier_sans_interet chown root.root fichier_sans_interet chmod g=,o= fichier_sans_interet strace -s80 -oessai_root.tmp cat fichier_sans_interet chmod a+r essai_root.tmp exit # retour sous un compte utilisateur non privilégié cd /tmp strace -s80 -oessai_user.tmp cat fichier_sans_interet # le message d'erreur apparaît, il est facile à comprendre. mais # comportons-nous comme si "cat" n'en produisait pas ... diff essai_user.tmp essai_root.tmp | tail -50
Un certain nombre de lignes apparaissent. L'une d'elle révèle de façon claire la cause du problème :
< open("fichier_sans_interet", O_RDONLY) = -1 EACCES (Permission denied)
Il suffit de lire la page de manuel de la fonction "open" pour comprendre que le processus de l'utilisateur non root a tenté d'ouvrir le fichier nommé fichier_sans_interet en mode "lecture seule" (O_RDONLY : Open ReaD-ONLY), ce que le système lui refusa en renvoyant un code de retour -1 (permissions inadéquates).
L'option -f, grâce à laquelle "strace" piste tous les processus créés par le programme examiné, est souvent utile.
"strace" peut aussi « espionner » un processus actif grâce à son option -p. Pour aller plus loin utiliser ensuite "ltrace".
[modifier] lsof
TODO
[modifier] Stockage (disque...)
[modifier] Qui lit/écrit sur une unité de stockage (« disque »)?
Il s'agit ici des seuls accès au périphérique, pas des demandes satisfaites par un cache.
iotop -o -b -qqq
[modifier] Réseau
[modifier] netstat
(sous BSD: sockstat)
TODO
[modifier] iptraf
TODO
[modifier] Recompiler
Recompiler, car certains sources de programmes (surtout des utilitaires) créent des binaires dépendants de la version du noyau utilisé lors de leur compilation.
Recompiler sans optimisations (cas de gcc: pas de "-m..." ni de "-O...").
[modifier] Debogage
Pourquoi, si vous connaissez un peu le langage utilisé par les développeurs du programme, ne pas essayer de déterminer la cause du problème ?
S'il s'agit d'un programme en C ou C++ et que vous connaissez le langage:
- le compiler (de préférence avec --prefix=/usr/local) en mode "debug" afin que le binaire intègre des informations associant chaque ligne du code source au petit morceau d'exécutable correspondant (euh ... c'est un peu simplifié). Cas du C / C++ : il suffit souvent d'ajouter "-ggdb" dans les options passées à gcc, ce qui s'effectue d'ordinaire en ajoutant ce paramètre au CFLAGS du Makefile. En cas de crash violent (message Segmentation fault) autoriser la production de fichiers core grâce à ulimit -c 0 (explications : chercher ulimit dans le man de bash), faire crasher la version compilée en mode debug, invoquer 'gdb nomdubinaire core', puis utiliser la commande 'where'.
- installer cette version de debogage ("make install")
- invoquer le binaire, le placer dans les conditions dans lesquelles il "se plante". Cela doit produire une image ("core dump"), sous forme d'un fichier nommé "core"
- installer "gdb" puis invoquer "gdb -d nom_du_répertoire_abritant_les_sources nom_du_binaire core"
- introduire "where"
[modifier] Plantages 'aléatoires' ou 'bizarres'
Voici ma recette personnelle (et néanmoins brutale). Il faut essayer d'exploiter la machine entre chacune des étapes proposées et conserver, étape après étape, les modifications opérées.
- lire et étudier les messages des programmes et des logs (configurer temporairement
syslogde sorte qu'il conserve trace de tout), en particulier du noyau. Ils se trouvent d'ordinaire dans /var/log/kernel, et la commande dmesg offre moyen de paramétrer et de consulter les messages produits par le noyau - vérifier que les programmes ne manquent pas de mémoire (commandes "free", "top" ...)
- lire la FAQ SIG 11
- examiner
/proc/pci,/proc/interruptset/proc/dmaainsi que les configs des cartes installées (config matérielle (sur la carte), logicielle (utilitaire spécifique livré par le constructeur, employer la plus récente version), afin de détecter un conflit - cesser d'employer "hdparm" (restaurer ses paramètres par défaut ou le désinstaller, puis réamorcer)
- réduire la fréquence du CPU (certains escrocs vendent des processeurs conçus pour fonctionner X MHz en tant que X+quelquechose MHz) et du bus (composants de mémoire vive inadéquats)
- renoncer temporairement à la mémoire virtuelle ("swap") : la mettre hors ligne (commande "swapoff"), réessayer, puis la reformater ("mkswap") avant ré-emploi
- déposer toutes les cartes d'extension non strictement nécessaires
- mettre hors fonction tout paramètre ou code (BIOS, module du système d'exploitation, démons, logiciels applicatifs ...) liés à l'APM ou à l'ACPI (gestion de l'énergie)
- installer un noyau compilé sans options inhabituelles et pour le processeur le plus classique (cas des PC: 386)
- restaurer les paramètres par défaut du BIOS (grâce au SETUP)
- paramètres BIOS: débrayer tous les "shadows" et caches
- se procurer et installer la plus récente version du BIOS (firmware) disponible
- installer des bibliothèques et outils (libc, gcc, ld.so, gcc ...) stables, puis recompiler les programmes
- changer de clavier (oui, oui, je sais, c'est dément, mais en fait non :-) )
- installer les utilitaires memtest86 et memtest86+, puis les lancer durant au moins 12 heures chacun
- déposer la moitié des composants (barettes) de RAM
- déposer la moitié de RAM encore montée, monter l'autre en lieu et place
- ne monter que le minimum de RAM, essayer ainsi avec toutes les barettes
- changer l'emplacement (
slot) des cartes d'extension - changer d'alimentation électrique (de prise « secteur »)
- éteindre tous les appareils électriques environnants (surtout les plus consommateurs ou ceux dont le fonctionnement est très heurté)
- changer d'alimentation électrique (l'alim à découpage, dans la machine)
- changer de disque dur
- changer de CPU
- changer de carte mère
- acheter une autre machine complète (cartes d'extension comprises)
- essayer l'hypoaristerolactothérapie : méthode de dépannage des machines par le coup de pied en bas à gauche (selon Michel Dubesset).
- renoncer à l'informatique, puisqu'elle tente manifestement de vous plaquer
[modifier] No space left on device
Vérifier, grâce à la commande df, l'espace disponible sur le système de fichiers.
Déterminer si l'utilisateur root parvient ou non à utiliser de l'espace de stockage. Si c'est le cas: l'espace disponible correspond peut-être au seul pourcentage de blocs réservés à l'utilisateur root, défini par paramètre "-m" de nombreux outils de création de système de fichiers (lire par exemple "man mkfs.ext2"). En ce cas il faut détruire des fichiers.
Déterminer s'il est possible de créer un fichier. Si ce n'est pas le cas vérifier grâce à "df -i" le nombre d'inodes disponibles. En cas de saturation il faut détruire des fichiers.
[modifier] Démontage d'un système de fichiers impossible
En cas de message "device is busy" il faut déterminer quels programmes emploient le système de fichier. Invoquer pour cela fuser -c SonNom (où SonNom est celui du device ou du répertoire de montage): les PID concernés apparaissent (chacun suivi d'un ou plusieurs caractères, que vous négligerez à ce stade). Utiliser ps afin de déterminer quel programme animent ces processus, les arrêter et démonter.
[modifier] Lenteur
Vérifier la fréquence du CPU:
grep MHz /proc/cpuinfo
[modifier] Bloqué dans un terminal (ligne de commande ou console)
Composer Control-q (maintenir la touche Contrôle ou Ctrl et enfoncer la touche Q puis )
reset console
[modifier] Bloqué sous un éditeur
[modifier] Déterminer le nom de l'éditeur
TODO
[modifier] Bloqué sous X Window (interface graphique)
TODO: passer en console, reset chipset