Greboca  

Suport technique et veille technologique

Aujourd’hui, les grandes entreprises et administrations publiques hésitent entre continuer à utiliser des logiciels propriétaires ou basculer vers les Logiciels Libres. Pourtant, la plupart des logiciels libres sont capables de bien traiter les données issues des logiciels propriétaire, et parfois avec une meilleur compatibilité.

C’est alors la barrière de la prise en main qui fait peur, et pourtant...

Les logiciels libres

L’aspect « Logiciel Libre » permet une évolution rapide et une plus grande participation des utilisateurs. Les aides et tutoriels foisonnent sur Internet ou sont directement inclus dans le logiciel lui-même.

Enfin, les concepteurs sont plus proches des utilisateurs, ce qui rend les logiciels libres plus agréable à utiliser et conviviaux.

Grâce à la disponibilité des logiciels libres, vous trouverez facilement des services de support techniques et la licence n’est plus un frein à l’utilisation de ces logiciels par votre personnel.

Notre support technique concerne essentiellement les logiciels libres, que ce soit sous forme de services ponctuels ou de tutoriels.

DLFP - Dépêches  -  Bogue, fonctionnalité, mauvais usage ? Un cas pratique

 -  Mars 2019 - 

Dans la rétrospective LinuxFr.org de la première quinzaine de mars 2019, il était question de la réponse surprenante de diff : « Le fichier /var/lib/lxc/alpha/rootfs/dev/full est un fichier spécial‐caractères alors que le fichier /var/lib/lxc/beta/rootfs/dev/full est un fichier spécial‐caractères. »

Les choses auraient pu en rester là. Mais quand même, ça reste une bonne occasion de se demander si c’est un bogue, une fonctionnalité ou un mauvais usage, non ? Jouons un peu avec ce cas pratique.

Sommaire

De quels fichiers parlions‐nous ?

$ ls -l /var/lib/lxc/alpha/rootfs/dev/full /var/lib/lxc/beta/rootfs/dev/full
crw-rw-rw- 1 root root 1, 7 mars   4  2011 /var/lib/lxc/alpha/rootfs/dev/full
crw-rw-rw- 1 root root 1, 7 oct.  21  2017 /var/lib/lxc/beta/rootfs/dev/full

Il s’agit donc de fichiers spéciaux en mode caractère (le c au début de la ligne), ayant pour majeur 1 et pour mineur 7. Ce type de fichiers peut être créé avec la commande mknod (paquet coreutils chez Debian, logiciel tiré du projet GNU coreutils).

Et le binaire /usr/bin/diff provenait du paquet Debian Stretch diffutils 1:3.5-3, également tiré du projet GNU diffutils.

$ diff --version
diff (GNU diffutils) 3.5

Reproduire le problème

D’abord créons un petit labo pour reproduire :

$ mkdir dir1 dir2
$ sudo mknod dir1/file c 1 7
$ sudo mknod dir2/file c 1 7
$ ls -l dir*/file
crw-r--r-- 1 root root 1, 7 mars  28 17:43 dir1/file
crw-r--r-- 1 root root 1, 7 mars  28 17:43 dir2/file
$ diff -r dir1 dir2
Le fichier dir1/file est un fichier spécial-caractères alors que le fichier dir2/file est un fichier spécial-caractères

OK, c’est reproduit, ça arrive (au moins) sur la comparaison récursive entre deux répertoires contenant chacun un fichier spécial en mode caractère avec même majeur, même mineur, même nom.

Un problème de traduction ?

Un effet de la langue ? Il s’agit peut‐être juste d’une erreur de traduction en français ?

$ export LC_ALL=C
$ export LANG=C
$ diff -r dir1 dir2
File dir1/file is a character special file while file dir2/file is a character special file

Pas mieux en anglais. Et d’ailleurs ce n’est pas mieux avec diffutils 1:3.7-2 de Debian Sid, en sachant que la 3.7 est la dernière version publiée par le projet GNU.

Avant de continuer à creuser, notons que la comparaison directe des deux fichiers est une mauvaise idée :

$ diff dir1/file dir2/file
(ne rend pas la main)

Débogage

Par curiosité un coup d’œil avec l’outil de débogage (sous GNU/Linux) strace (logiciel venant de strace.io) pour voir les appels système utilisés par un programme et les signaux reçus :

$ strace -f diff dir1/file dir2/file
…
stat("dir1/file", {st_mode=S_IFCHR|0644, st_rdev=makedev(0x1, 0x7), ...}) = 0
stat("dir2/file", {st_mode=S_IFCHR|0644, st_rdev=makedev(0x1, 0x7), ...}) = 0
openat(AT_FDCWD, "dir1/file", O_RDONLY) = 3
openat(AT_FDCWD, "dir2/file", O_RDONLY) = 4
read(3, "(que des NUL)"..., 4096) = 4096
read(4, "(que des NUL)"..., 4096) = 4096
read(3, "(que des NUL)"..., 4096) = 4096
read(4, "(que des NUL)"..., 4096) = 4096
…

Comme on peut lire en boucle sur ces fichiers, ça peut durer longtemps…

En revanche, on peut essayer sur la version récursive sur les deux répertoires :

$ strace -f diff -r dir1 dir2
…
stat("dir1/file", {st_mode=S_IFCHR|0644, st_rdev=makedev(0x1, 0x7), ...}) = 0
stat("dir2/file", {st_mode=S_IFCHR|0644, st_rdev=makedev(0x1, 0x7), ...}) = 0
fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0x3), ...}) = 0
write(1, "File dir1/file is a character sp"..., 92File dir1/file is a character special file while file dir2/file is a character special file
) = 92
…

OK, il n’a pas l’air de pousser la comparaison bien loin… On regarde les attributs des deux fichiers, ce sont des fichiers spéciaux, alors on sort la phrase peu explicative.

Les sources

Et si on regardait les sources du paquet Debian ?

$ apt source diffutils
$ cd diffutils-3.7/

La traduction ?

$ grep -1 "character special file" ./po/fr.po
#: lib/file-type.c:69
msgid "character special file"
msgstr "fichier spécial-caractères"
--
#: lib/file-type.c:84
msgid "multiplexed character special file"
msgstr "fichier spécial avec des caractères multiplexés"

Le premier cas est celui qui nous intéresse. On retrouve bien les lignes attendues côté code en excluant les fichiers de traduction :

$ grep -nr "character special file" .|grep -v "/po/"
./lib/file-type.c:69:    return _("character special file");
./lib/file-type.c:84:    return _("multiplexed character special file");

Il s’agit en gros d’une fonction file_type qui écrit « character special file » ou sa traduction lorsqu’elle croise un fichier spécial de type caractère.

Reste à trouver d’où vient le reste de la phrase :

$ grep -2 while po/fr.po
#: src/diff.c:1337 src/diff.c:1387
#, c-format
msgid "File %s is a %s while file %s is a %s\n"
msgstr "Le fichier %s est un %s alors que le fichier %s est un %s\n"

Visiblement une phrase générique prévue pour dire « ah, flûte, dommage, le premier fichier est un machin, tandis que le second est un bidule », sauf qu’ici machin == bidule (ici on sourit légèrement parce qu’on va aller voir la ligne 1 337 de diff.c, et que c’est l33t).

Le code

La portion de code concernée :

  {
    /* We have two files that are not to be compared.  */

    /* See POSIX 1003.1-2001 for this format.  */
    message5 ("File %s is a %s while file %s is a %s\n",
        file_label[0] ? file_label[0] : cmp.file[0].name,
        file_type (&cmp.file[0].stat),
        file_label[1] ? file_label[1] : cmp.file[1].name,
        file_type (&cmp.file[1].stat));

    /* This is a difference.  */
    status = EXIT_FAILURE;
  }

En gros, on est dans une zone concernant les fichiers non comparables, alors on affiche le message à base de machin et de bidule sans se poser la question du cas machin == bidule.

Le même code est utilisé ligne 1387, mais il semble plus pertinent, d’après le commentaire qui précise que l’un des fichiers est un lien symbolique et l’autre non, donc ici machin != bidule.

  {
    /* We have two files that are not to be compared, because
       one of them is a symbolic link and the other one is not.  */

    message5 ("File %s is a %s while file %s is a %s\n",
        file_label[0] ? file_label[0] : cmp.file[0].name,
        file_type (&cmp.file[0].stat),
        file_label[1] ? file_label[1] : cmp.file[1].name,
        file_type (&cmp.file[1].stat));

    /* This is a difference.  */
    status = EXIT_FAILURE;
  }

Tout laisse à penser que nous sommes en présence d’un bogue, ou en tout cas d’une imprécision dans la réponse fournie à l’utilisateur : la réponse sera toujours la même lorsque l’on compare deux fichiers spéciaux‐caractères, indépendamment de leurs majeur et mineur d’ailleurs, et le fait qu’ils soient différents (le but de diff donc) est seulement sous‐entendu, par le fait que le message apparaît (il n’y aurait pas de tel message sur deux fichiers comparables identiques).

Et avec un autre diff ?

Le commentaire côté GNU « See POSIX 1003.1-2001 for this format » pourrait laisser penser qu’il s’agit d’une contrainte de la norme POSIX. Mais sous FreeBSD diff se comporte différemment :

$ mkdir t1 t2
$ mkfifo t1/toto 
$ mkfifo t2/toto 
$ diff -r t1 t2
File t1/toto is not a regular file or directory and was skipped

Le BSD diff bloque aussi sur la comparaison entre les deux fichiers. Mais le message est donc plus explicite lorsqu’il s’agit d’une comparaison de deux répertoires.

De la sorte, ce comportement est tel que défini par l’open Group :

« If both file1 and file2 are directories, diff shall not compare block special files, character special files, or FIFO special files to any files and shall not compare regular files to directories. Further details are as specified in Diff Directory Comparison Format. The behavior of diff on other file types is implementation‐defined when found in directories. »

Si file1 et file2 sont des répertoires, diff ne devrait pas entreprendre la comparaison des fichiers spéciaux de type blocs ou caractères ou les tubes nommés (FIFO) à n’importe quel autre fichier ni comparer un fichier à un répertoire.

Ouvrir des bogues ?

Passons à l’étape suivante, récupérer le code source directement du projet en amont et soumettre une proposition de correction ? Cette partie est laissée à l’attention du lecteur.

$ git clone https://git.savannah.gnu.org/git/diffutils.git

ou https://svnweb.freebsd.org/base/release/12.0.0/usr.bin/diff/.

Commentaires : voir le flux atom ouvrir dans le navigateur

par Benoît Sibaud, Davy Defaud, David Marec, ZeroHeure, tankey

DLFP - Dépêches

LinuxFr.org

Entretien avec GValiente à propos de Butano

 -  16 avril - 

GValiente développe un SDK pour créer des jeux pour la console Game Boy Advance : Butano.Cet entretien revient sur son parcours et les raisons (...)


Nouveautés d'avril 2024 de la communauté Scenari

 -  11 avril - 

Scenari est un ensemble de logiciels open source dédiés à la production collaborative, publication et diffusion de documents multi-support. Vous (...)


Annuaire de projets libres (mais pas de logiciels)

 -  9 avril - 

Les communs sont une source énorme de partage !S’il est plutôt facile dans le monde francophone de trouver des ressources logicielles (Merci (...)


Les enchères en temps réel, un danger pour la vie privée mais aussi pour la sécurité européenne

 -  7 avril - 

Les enchères en temps réel, ou Real-Time Bidding (RTB), sont une technologie publicitaire omniprésente sur les sites web et applications mobiles (...)


XZ et liblzma: Faille de sécurité volontairement introduite depuis au moins deux mois

 -  31 mars - 

Andres Freund, un développeur Postgres, s’est rendu compte dans les derniers jours que xz et liblzma ont été corrompus par l’un des mainteneurs du (...)