Faire du retro-portage, l’exemple de catium


Article pas relu. J’ai un nouveau clavier dont les touches sont très dures donc j’oublie souvent des lettres.

Le travail décrit dans cet article est le fruit d’une collaboration avec Guillaume Salagnac et Lou Paul-Dauphin, respectivement chercheur et stagiaire au CITI à l’INSA Lyon. Merci à eux.

Introduction

Phenix est une équipe de recherche s’intéressant à la frugalité dans le numérique. Dans ce cadre là elle s’intéresse aux liens entre nos pratiques du numériques et les technologies anciennes1. Elle explore ces liens en tentant de répondre à des questions du type : “Etait-il possible de faire wikipedia en 1997 ?” et “Si oui, pour quels compromis ?”. Ce faisant elle met à jour dans quelle mesure les progrés en informatique sont des conditions nécessaires ou pas à reproduire des services numériques aujourd’hui presque universellement reconnus comme souhaitables.

Par ailleurs j’avais pour envie de tester jusqu’à quand fallait-il remonter pour que catium ne fonctionne plus. Autrement dit répondre à la question “depuis quand catium peut-il fonctionner tel quel sans qu’il n’ait besoin d’être modifié ?”. Alors forcément lorsque j’en ai parlé à Guillaume et Lou ça a parfaitement matché. C’est l’occasion pour nous de tester empiriquement l’intuition que l’on a souvent tenu pour vraie à Katzele, celle que de faire des logiciels avec la boite à outil traditionnelle d’Unix permet de faire du logiciel qui nécessite peu de maintenance à long terme.

Le portage

Dans le cadre de l’archéologie wikipedienne Lou a fait fonctionné un debian bo 1.3 datant de 1997 en suivant ce tuto, corrigé depuis dans cet article suite aux problèmes rencontrés. Si vous voulez vous aussi avoir une debian 1.3 mais que vous préférez qemu vous pouvez suivre le readme de ce dépôt github.

Pour répondre à notre question il était alors plus simple de prendre le problème à l’envers, c’est à dire porter catium sous debian 1997 puis affirmer que catium fonctionne tel quel depuis cette date là. La question devient alors “Qu’est-ce que ça coûte de porter catium en 1997 ?”. Un autre question intéressante serait “Si le portage iso-fonctionnel n’est pas possible ou trop coûteux, qu’à-t-on gagné depuis 1997 ?” ou, formulé autrement, “Que perd-t-on dans catium en se limitant à des technologies de 1997 ?”.

Le makefile

Pour le makefile les modifications suivantes ont été faites :

  1. Utiliser la fonction $(shell cmd) disponible depuis au moins 19882 plutôt que l’opérateur presque équivalent != cmd introduit en 20113.
  2. Utiliser la fonction patsubt disponible depuis au moins 1988 à la place des substitutions de référence $(var:a=b) introduites en 19894.

Seule la première était nécessaire pour que le makefile fonctionne sous debian bo mais la seconde ne coûte rien alors pourquoi pas.

Le script page

A la tentative d’exécution de la page de demo index.sh nous avons obtenu l’erreur suivante :

bash: mktemp : not a command

Et pour cause, mktemp n’existe dans les GNUcoreutils que depuis décembre 20075. Le manuel d’OpenBSD dit que la commande est apparue dans OpenBSD 2.1 datant de 19976 mais je n’en trouve pas mention dans les changelog. Il est donc possible qu’un mktemp portable ait existé à ou juste après la sortie de debian bo mais il n’y était pas par défaut.

La solution retenue pour résoudre notre souci est de fabriquer un dossier temporaire “à la main” en se basant sur le pid du processus :

tmpdir="/tmp/catium-$$"
mkdir -p "$tmpdir"

J’ai connaissance des limites à la création de dossiers temporaires comme ceci et à fortiori dans le dossier /tmp mais honnêtement ici on s’en fiche un peu. Un compromis pourrait être d’utiliser le dossier ~/.tmp s’il existe mais flemme et ce ne changera rien pour notre objectif de portabilité.

Les prochaines erreurs arrivaient groupées, j’ai nommé les :

bash: syntax error near unexpected token `cat'

Ces erreurs étaient déclenchées par une syntaxe particulière de déclaration de fonction dont en voici un exemple :

save() cat >> "$tmpdir/$1"

Il se trouve que cette syntaxe n’est pas POSIX78. Les fonctions shell doivent être suivies d’une coumpound command qui doit commencer et finir par un mot réservé (for par ex) ou un opérateur de contrôle ({ par ex) et finir par le mot réservé ou l’opérateur de contrôle correspondant (done et }). cat n’est ni l’un ni l’autre donc bash ne le parse pas. J’ai longtemps cru que cette syntaxe était POSIX puisque dash le comprend et parce que j’avais mal lu la page du wiki de shellcheck sur le sujet. L’exemple donné à la fin avec la boucle for m’avait fait pensé que c’était ok de ne pas mettre de {} en toute circonstance mais ce n’est ici rai que parce que for et done sont des mot réservés qui se correspondent.

Une fois la confusion levée la correction a été très simple. Encadrer les commandes des fonctions par des {} sans oublier de terminer la dernière commande par ; si la fonction est écrite sur une seule ligne9.

Je n’ai pas résisté à l’envie d’envoyer un mail à Marc à ce sujet ce qui a été un grand succès puisque l’on a eu le droit à un magnifique pavé Chantresque salade tomates oignons :

Nouvel obstacle dans notre portage sous debian 1997, cet ensemble d’erreur :

bash: page: line 3: title: command not found
bash: page: line 3: author: command not found
...

Autrement dit bash ne semble pas instancier les alias title:, author: etc. En lisant la partie ALIAS du manuel de bash je suis tombé sur :

ALIAS

       [...]

       Les alias ne sont pas développés quand l'interpréteur n'est pas
       interactif sauf si l'option expand_aliases de l'interpréteur est
       créée par la commande shopt (consultez la descrip‐ tion de shopt dans
       COMMANDES INTERNES DE L'INTERPRÉTEUR ci-dessous).

       [...]

Il se trouve que c’est exactement ce dont on nous avions besoin mais j’ai mal compris développés. J’ai cru que le manuel parlait de développer les éventuelles variables qui se trouvait dans la déclaration de l’alias et non pas de créer l’alias tout court. J’ai donc cherché une autre explication sans succès. C’est Guillaume qui est indépendamment tombé sur cette info, a correctement compris le texte et a demandé à Lou de tester la modif avec succès. On considère souvent que le plus difficile est de trouver les informations dans les mégas pages de manuel de la mort mais une fois l’information trouvée faut-il encore la comprendre ! Idem avec la page de shellcheck au sujet des compounds commands. C’est donc ça la puissance d’un directeur de thèse ?

Il y aurait des moyens automatiques de tester si le shell utilisé est bash puis d’appliquer la configuration mais, à ma connaissance, pas de manière simple, fiable et cohérente de debian 1.3 jusqu’à debian 12. La solution retenue a donc été d’introduire la ligne de configuration spécifique à bash dans la section prévue à cet effet dans page :

##
# 3. Config si vous utilisez bash
##

# Si votre sh est bash alors décommenter la ligne suivante
# Sous linux vous pouvez vérifier en faisant
# readlink $(whereis sh)

# shopt -s expand_aliases

Et j’ai le plaisir de vous annoncer qu’avec ces modifications catium fonctionne sous debian 1.3, en 1997, sans installer de paquets.

Des bugs dans le layout

Premier bug, la présence de cette syntaxe censée mettre fin à la génération en produisant un message d’erreur en l’absence d’un titre :

<title>${title?La page dont le chemin s'affiche au dessus nécessite un titre}</title>

La syntaxe ${param?mot} n’est pas correcte. Ce doit être ${param:?mot}.

Autre bug, sur la même ligne, l’apostrophe empêche zsh et bash de parser correctement le fichier. Il s’attend à voir une apostrophe fermante. Cela fait plutôt sens et il est vrai que j’ai été surpris la première fois en constatant que dash comprenant ça correctement. J’ai cru sur le moment que la partie droite du :? était spécifiée comme étant spéciale. Il semblerait que non et que dash est simplement très permissif. A vérifier. La forme correcte pour tous les shells testés est donc :

<title>${title:?"La page dont le chemin s'affiche au dessus nécessite un titre"}</title>

Dans la même veine la ligne d’après posait problème et a été corrigée en double quotant toute la valeur par défaut :

${STYLE:+"<link rel=stylesheet href=$STYLE />"}

Le traducteur markdown

Catium a ceci de particulier qu’il ne présuppose pas en quoi vous voulez écrire vos page. C’est pourquoi à la première exécution il vous force à ouvrir le script page et à écrire/décommenter la fonction qui appelera le traducteur. En pratique le langage de markup le plus utilisé avec catium est markdown et le traducteur associé lowdown10.

Du fait de ce fonctionnement catium peut s’adapter à tous les usages. En 1997, si l’on avait utilisé catium pour écrire de l’HTML on aurait probablement écrit de l’HTML à la main. Le traducteur aurait alors été la fonction identitié :

save() { cat >> "$tmpdir/$1"; }

Cela dit, si l’on voulait se poser la question d’utiliser, en 2025 et donc avec la connaissance de markdown, une debian 1.3, il serait sympa d’avoir un traducteur. J’ai donc testé mon traducteur katdown écrit en awk POSIX. Attention, je précise que ce traducteur implémente une toute petite partie de markdown et même pas correctement. Il est ultra méga pété. Mais, mais, pour des documents très simples et dans des contextes où c’est pas forcément la mort d’avoir parfois un doc un peu cassé, il faisait le taf en 1997, interprété par mawk. C’est chouette.

Une autre alternative serait markdown.awk de Paul Hänsch mais il fait 999 lignes et semble ne pas fonctionner avec le mawk pré installé sur debian 1.3.

Discussion

Sur le nom de la pratique

Ce que l’on fait ici est de porter du logiciel d’aujourd’hui pour qu’il fonctionne sur du vieux matériel. C’est, je crois, une pratique assez rare. Le fait que l’on porte en arrière dans le temps m’a donné envie d’appeler ça du rétro-portage. Pourtant quand j’ai initiallement porté catium vers OpenBSD et MacOS je ne me suis pas demandé si je faisais quelque chose de particulier alors même que le mac de Timothée tourne sur un vieux MacOS. Je suppose que c’est la quantité de temps conséquente qui sépare 1997 de 2025 qui me donne envie de lui donner un nom particulier. Sinon on peut simplement appeler ça du portage/porting et la pratique plus large de l’arhéologie numérique.

Sur le coût

Qu’est-ce que cela a coûté de porter ?

Le portage nous a pris ~2h30. Il a initiallement mobilisé uniquement Guillaume et Lou puis, vers la fin, moi en renfort. On peut donc dire que le coût a été 2h de personnes fortes en shell et 30m du mainteneur du projet. Ce n’est pas rien.

Guillaume m’a confié s’attendre à beaucoup plus. Personnellement c’était à peu près ce à quoi je m’attendais. On peut adopter plusieurs perspectives qui ne s’excluent pas :

  1. Se dire qu’il est “normal” que le portage ait été facile puisqu’après tout le logciel est très simple.
  2. Se dire que mine de rien ces affaires de compatibilité entre les différents shells c’est bien relou et caractéristique de ce pourquoi beaucoup de personnes ne comptent pas sur cet environnement technique pour fabriquer leurs outils.
  3. Se dire que c’est assez exceptionnel qu’un logiciel écrit en 2023/2024 soit portable en 1997 en moins de deux heures.
  4. Sûrement d’autres

Quand on analyse plus en détail on se rend compte que l’histoire des alias et les bugs dans le layout sont avant tous des corrections pour porter vers bash, également nécessaires en 2025. Si c’est une bonne idée de l’avoir fait puisque de nombreuses personnes utilisent ce shell nous avons eu ici à le faire uniquement parce que bash est le seul shell installé par défaut sur debian 1.3. Cela veut dire que si l’on avait initiallement écrit catium pour fonctioner avec bash les seules modifications à faire auraient été la substitution de la syntaxe != par la fonction $(shell) dans le makefile et le retrait de la dépendance à mktemp.

Sur l’objectif

Derrière les recherches de Phenix et les intuitions de Katzele se cache un problème important. Nous aimerions pouvoir objectiver ce qui fait qu’un logiciel est fiable et réparable dans le temps mais il est impossible de prédire le futur. L’un comme l’autre nous faisons l’hypothèse que le fait qu’un logiciel fonctionnait il y a 20 ans et fonctionne encore sans changement majeur est une bonne raison de penser qu’il a une chance de fonctionner encore dans 20 ans.

Cela dit il ne faudrait pas se laisser aller à penser que cette relative fiabilité ne serait que technique et le seul et meilleur indicateur de ce qui fonctionnera dans 20 ans.

Par exemple si le shell et les commandes traditionnelles d’Unix utilisées dans catium changent suffisament peu pour pouvoir être utilisées de la même manière en 1997 et en 2025, il serait faux de dire que ce sont exactement les mêmes logiciels qui fonctionnent sous le capot. Des efforts humains non négligeables11 ont été consentis durant ces 28 ans pour maintenir ces outils en état de marche, s’adapter aux ouveau matériels, corriger des bugs etc. Il ne faut pas confondre fiabilité des “API” et fiabilité du code sous-jacent.

Par ailleurs la durabilité d’une techno peut aussi se faire malgré des mises à jour fréquentes. Il est raisonnable d’estimer qu’il est durable de faire du javascript, malgré le fait que ça n’existait pas en 1997, malgré le fait que ce soit techiquement plus compliqué que du C89, malgré le fait que de nouvelles fonctionnalités sortent “fréquemment”, parce que des entreprises extrêmement riches et puissantes dépendent de cette technologie. C’est, dans le fond, un pari assez similaire à celui que l’on fait en visant du shell et des utilitaires unix standards, mais à plus haut niveau et se reposant davantage sur la perpétuation d’entreprises “too big to fail”. Pourquoi pas ? Après tout le shell n’a pas toujours existé non plus et pourtant il aurait été bon de parier sur sa durabilité à sa création.

Finalement, comme Guillaume et Matthieu me l’avaient fait remarquer, il serait dommage de ne se poser que la question de la fiabilité dans le temps et non pas de la réparabilité et de l’appropriabilité. On pourrait imaginer créer un outil tellement sur-ingénieuré qu’il soit capable de prévoir tous les cas possibles, tous les imprévus, toutes les innovations technologiques. Cet outil imaginaire serait impossiblement complexe à écrire, à maintenir, à modifier, à adapter. Peut-être qu’il serait capable de fonctionner dans 100 ans mais personne ne serait capable de l’adapter aux inévitables changements de nos besoins durant ce centenaire. À moins qu’il remplisse le plus essentiel des besoins il deviendrait rapidement obsolète. Il faut donc s’atteler à maximiser la fiabilité et la réparabilité. Que l’outil ne nécessite pas d’être souvent réparé a fur et à mesure que son environnement technique change mais que, lorsque c’est inévitablement le cas ou lorsque le besoin change, il puisse être raisonnablement facilement modifié en fonction des ressources dont on dispose. Comme exemple on peut citer le développement de l’indice de durabilité suite aux limites de l’indice de réparabilité qui pouvait donner un 10/10 à un téléphone très facile à réparer mais tombant en panne tous les deux jours.


  1. Dans un contexte numérique donc pas forcément si anciennes que ça 

  2. https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.1#n4241 

  3. https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.3#n1475 

  4. https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.1#n3362 

  5. https://git.savannah.gnu.org/cgit/coreutils.git/tree/NEWS#n4025 

  6. https://www.openbsd.org/21.html 

  7. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05 

  8. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04 

  9. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04_01 

  10. parce que c’est celui qui était utilisé pour le site de Katzele pour son bon compromis “stabilité/taille/fonctionnalités”. 

  11. bien que possiblement asez faibles en comparaison à d’autre environnements techniques