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 :
- Utiliser la fonction
$(shell cmd)
disponible depuis au moins 19882 plutôt que l’opérateur presque équivalent!= cmd
introduit en 20113. - 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 :
- Réponse à un mail perso sur une liste de diff publique
- Du bashism de bash
- Un cours d’histoire sur le shell
- Des takes militantes
- Des arguments soutenus par des bouts de code ésotériques mais convaincants
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é lowdown
10.
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 :
- Se dire qu’il est “normal” que le portage ait été facile puisqu’après tout le logciel est très simple.
- 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.
- Se dire que c’est assez exceptionnel qu’un logiciel écrit en 2023/2024 soit portable en 1997 en moins de deux heures.
- 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.
-
Dans un contexte numérique donc pas forcément si anciennes que ça ↩
-
https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.1#n4241 ↩
-
https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.3#n1475 ↩
-
https://git.savannah.gnu.org/cgit/make.git/tree/ChangeLog.1#n3362 ↩
-
https://git.savannah.gnu.org/cgit/coreutils.git/tree/NEWS#n4025 ↩
-
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05 ↩
-
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04 ↩
-
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04_01 ↩
-
parce que c’est celui qui était utilisé pour le site de Katzele pour son bon compromis “stabilité/taille/fonctionnalités”. ↩
-
bien que possiblement asez faibles en comparaison à d’autre environnements techniques ↩