Quand apt-get réclame une fin de ligne

mercredi 19 janvier 2011

Le système de paquets Debian/Ubuntu est diablement efficace : les dépendances sont gérées automatiquement, il suffit d'une ligne dans la console, commençant par la fameuse commande "apt-get" pour installer ou supprimer un logiciel. Mais voilà : il y a parfois des problèmes qui, si petits soient-ils, parviennent à bloquer ladite commande. Tel est le cas du problème auquel cet article est dédié qui, d'après mes recherches, ne trouve aucun écho sur Google -- il doit donc être extrêmement rare !

Le système de paquets Debian/Ubuntu est diablement efficace : les dépendances sont gérées automatiquement, il suffit d’une ligne dans la console, commençant par la fameuse commande «apt-get» pour installer ou supprimer un logiciel. Mais voilà : il y a parfois des problèmes qui, si petits soient-ils, parviennent à bloquer ladite commande. Tel est le cas du problème auquel cet article est dédié qui, d’après mes recherches, ne trouve aucun écho sur Google – il doit donc être extrêmement rare !

Je ne sais pas comment cela est arrivé. Peut-être après l’installation d’un logiciel depuis la «Logithèque Ubuntu» (qui, comme on le sait, n’est pas un modèle de stabilité), ou peut être pas. Toujours est-il que le message d’erreur était bien là, quelques lignes en dessous de celle où j’avais écrit sudo apt-get install awesome… Mais ne faisons pas durer le suspens plus longtemps :

Après cette opération, 6 676ko d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer [O/n] ? o
Sélection du paquet libev3 précédemment désélectionné.
(Lecture de la base de données... 90%dpkg : erreur fatale irréversible, abandon :
la liste des fichiers pour le paquet « linux-headers-2.6.35-22-generic » n'a pas de retour à la ligne en fin de fichier
E: Sub-process /usr/bin/dpkg returned an error code (2)

Comment ça, il n’a pas de retour à la ligne ? Et en quoi cela est-il dérangeant ? Ou plutôt : en quoi cela mérite-t-il de déclencher une erreur fatale irréversible ? – je trouve la formule un rien tragicomique. Bon, d’accord. Il faut un retour à la ligne à la fin du fichier, sinon le logiciel qui interprète ce fichier ne peut pas savoir que le fichier est fini et qu’il doit cesser de l’interpréter. Quoique s’il sait que c’est à la fin du fichier que le retour à la ligne fait défaut… Bref, mieux vaut ne pas trop chercher à comprendre, plus tôt on se résignera au retour-à-la-ligne-à-la-fin-du-fichier, plus tôt on parviendra à régler le problème.

Première tentative, tout en finesse : un fichier pose problème, très bien, on le supprime (oui, c’est fin…). Essayons : sudo apt-get remove linux-headers-2.6.35-22-generic. Mince… encore le même message ! Oui, c’est logique : s’il ne peut lire correctement la liste des fichiers, on lui pardonnera de ne pas parvenir à les supprimer.

A ce stade, on s’énerve légèrement : sudo apt-get update, …purge, …autopurge, …check, …clean, …$@&/ù%*!!, mais rien n’y fait. Il va falloir réfléchir un peu (ou fermer VirtualBox et retourner sur Mac OS X, au choix).

Deuxième tentative, en finesse – cette fois, «pour de vrai» : on rajoute le fameux retour à la ligne dans le fichier récalcitrant. Oui, mais de quel fichier s’agit-il, au juste ? L’expert de Debian ou d’Ubuntu se mettra probablement à rire à ce stade (s’il n’est pas déjà mort de rire après avoir lu ce qui précède ; ce qu’on lui souhaitera s’il a ri, soit dit en passant, car il est très vilain de se moquer). Le néophyte pestera : ce message d’erreur stupide n’est même pas fichu d’indiquer dans quel fichier il y a un problème ? L’expert, après avoir bien ri, le rejoindra : ce n’est pas très sérieux, pour un logiciel UNIX où la notion de fichier est paradigmatique, de ne pas indiquer le fichier concerné. Heureusement, le monde Linux/Unix est rempli de merveilles, et l’une d’entre elles est la commande locate. Comme dit le proverbe (ou la publicité pour une barre chocolatée, je ne sais plus trop), «un locate et ça repart !».

Allons-y : locate linux-headers-2.6.35-22-generic

Et le résultat (que le lecteur me pardonne la coupe drastique que je réalise dans le résultat de la commande, et qu’il se dise que c’est pour préserver sa santé mentale) :

# ... de très nombreuses lignes totalement inutiles en l'occurrence, vont ici
/usr/src/linux-headers-2.6.35-22-generic/scripts/selinux/mdp/dbus_contexts
/usr/src/linux-headers-2.6.35-22-generic/scripts/selinux/mdp/mdp
/usr/src/linux-headers-2.6.35-22-generic/scripts/selinux/mdp/mdp.c
/var/lib/dpkg/info/linux-headers-2.6.35-22-generic.list
/var/lib/dpkg/info/linux-headers-2.6.35-22-generic.md5sums
/var/lib/dpkg/info/linux-headers-2.6.35-22-generic.postinst

Magnifique ! Le fichier que l’on cherche est très probablement celui qui porte l’extension list (vu qu’on cherche une liste, cela paraît tout de même assez logique). Et il apparaît à la fin de la liste, pile sous nos yeux. Ai-je déjà dit à quel point le monde UNIX est merveilleux ?

Éditons ce fichier. Avec les mauvaises habitudes d’un utilisateur desktop (comprendre : par opposition aux réfractaires du mulot qui aiment la console plein écran d’une Debian sans environnement de bureau), on tape : sudo gedit /var/lib/dpkg/info/linux-headers-2.6.35-22.list. Gedit se lance, charge le fichier (avec un peu de peine, parce qu’il est vraiment long). On se rend à la fin et, en toute innocence, on rajoute un retour à la ligne. Autrement dit, on appuie sur la touche ENTRÉE, RETOUR ou RETURN du clavier. Et une nouvelle ligne se crée, vide. On sauvegarde le fichier, et on réessaye d’installer Awesome (je rappelle que c’était le but…).

Et là, rebelote (ou presque) :

Après cette opération, 6 676ko d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer [O/n] ? o
Sélection du paquet libev3 précédemment désélectionné.
(Lecture de la base de données... 90%dpkg : erreur fatale irréversible, abandon :
la liste des fichiers pour le paquet « linux-headers-2.6.35-22 » contient un nom de fichier vide
E: Sub-process /usr/bin/dpkg returned an error code (2)

Moment de lassitude. On lui a donné une ligne vide parce qu’il réclamait une fin de ligne, et maintenant ce bougre d’ectoplasme à roulettes (© Capitaine Haddock) se plaint d’avoir une ligne vide !

En fait, c’est logique. C’est encore un coup du (pas toujours si) merveilleux monde merveilleux d’UNIX : fin de ligne et retour à la ligne, ce n’est pas pareil. La fin de ligne correspond au caractère «\r» (retour de chariot ou carriage return) tandis que la nouvelle ligne correspond à «\n». Il suffisait de le savoir. Ou pas… car comment insérer une fin de ligne sans insérer une nouvelle ligne ? C’est difficile (ou peut-être impossible, je ne me prononcerai pas, je n’ai pas beaucoup cherché) lorsqu’on a les mauvaises habitudes d’un utilisateur desktop, à savoir : utiliser Gedit au lieu de la ligne de commande pour éditer un fichier système.

La solution, comme souvent avec les systèmes Unix/Linux, tient dans une commande qu’il suffit de balancer dans la console (qu’on commencera à apprécier, à ce stade, si ce n’est pas déjà le cas) :

sudo echo '\r' >> /var/lib/dpkg/info/linux-headers-2.6.35-22-generic.list

La commande echo X Y Z est tout bête : on fait avec X l’opération Y sur Z. En l’occurrence, on prend \r (X), que l’on rajoute à la fin (» = Y) du fichier (Z). Elle est toute bête, mais elle ne fonctionne pas. Ou plutôt, c’est sudo, permettant d’utiliser une commande (la commande echo, il faut suivre !) avec les privilèges d’administrateur, qui ne fonctionne pas. La console, toujours aussi laconique quand on a besoin d’aide, répond :

bash: /var/lib/dpkg/info/linux-headers-2.6.35-22-generic.list: Permission non accordée

Pour dire les choses de manière polie, cela signifie : «pauvre petit utilisateur, tu veux te faire passer pour root, mais tu n’es pas root ; je sais que tu n’es pas root, je vais t’empêcher de faire ce que tu veux faire, et je t’ai bien eu héhéhé !».

Quand sudo ne fonctionne pas, il faut sortir l’Arme Fatale : su (certes, le nom est plutôt crétin pour une Arme Fatale, mais on fait ce qu’on peut). Évidemment, les choses ne sont pas si simples avec Ubuntu, qui désactive l’utilisateur root. La commande su répond, non sans un certain sens de l’humour : su : Échec d'authentification (ce qui est rigolo, c’est qu’on ne dira jamais à l’utilisateur que la commande est désactivée : lui faire croire qu’il a tapé un mauvais mot de passe, et l’amener ainsi à bidouiller le mapping de son clavier en s’arrachant les cheveux, c’est beaucoup mieux).

Heureusement (pour la coupe de cheveux), la solution ne tarde jamais à venir avec l’ami (parfois) Google : il suffit, pour activer l’utilisateur root, de lui attribuer un mot de passe. Peu importe, à cet égard, que l’on ait déjà défini un mot de passe pour cet utilisateur lors de l’installation, il faut recommencer (le même mot de passe fonctionne très bien) à l’aide de la commande sudo passwd root.

user@ubuntu10-10:~$ sudo passwd root
Entrez le nouveau mot de passe UNIX :
Retapez le nouveau mot de passe UNIX :
passwd : le mot de passe a été mis à jour avec succès

Désormais, la commande su fonctionne :

user@ubuntu10-10:~$ su
Mot de passe :
root@ubuntu10-10:/home/user#

Et maintenant qu’on a atteint l’apothéose (car c’est un peu cela, devenir root), il n’y a plus d’interdit. On lance alors avec succès notre commande qui était précédemment vouée à l’échec :

echo '\r' >> /var/lib/dpkg/info/linux-headers-2.6.35-22-generic.list

Et puis, pour finir, la commande apt-get install awesome donne pleine satisfaction :

Après cette opération, 6 676ko d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer [O/n] ? o
Sélection du paquet libev3 précédemment désélectionné.
(Lecture de la base de données... 160926 fichiers et répertoires déjà installés.)
Dépaquetage de libev3 (à partir de .../libev3_1%3a3.9-1_amd64.deb) ...
...

Pour conclure l’aventure, relisez la première phrase de cet article.