Informatique

Le système Unix, ses extensions et ses applications

Écrit en 1969 sur un mini-ordinateur délaissé des laboratoires Bell, Unix fait aujourd'hui tourner les serveurs d'Internet, tous les supercalculateurs, les Mac et, par Linux et Android, des milliards de téléphones. Cinq planches pour manipuler ses idées les plus durables, jusqu'à un vrai petit terminal où taper vos propres commandes.

Un petit système qui a conquis le monde

En 1969, après l'abandon de Multics, Ken Thompson écrit un système minimal sur un PDP-7 ; Dennis Ritchie le rejoint, et en 1973 Unix est réécrit en langage C, ce qui le rend portable d'une machine à l'autre. AT&T, à qui la loi interdisait alors de vendre de l'informatique, le distribue pour presque rien aux universités, avec son code source. Des générations d'étudiants l'apprennent, le modifient et l'étendent : c'est la naissance de la famille Unix.

ExtensionAnnéeCe qu'elle apporte
BSD (université de Californie, Berkeley)1977La mémoire virtuelle sur VAX, l'éditeur vi (1976), le shell csh, puis en 1983 les sockets et la première pile TCP/IP largement diffusée : Unix devient la machine d'Internet.
System V (AT&T)1983La version commerciale, base de Solaris, AIX et HP-UX.
X Window System (MIT)1984Des fenêtres affichables à travers le réseau.
Projet GNU (Richard Stallman)1983Récrire librement tous les outils d'Unix : compilateur gcc (1987), shell bash (1989).
Norme POSIX (IEEE)1988Une définition commune des appels système et des commandes, pour que les programmes passent d'un Unix à l'autre.
Linux (Linus Torvalds)1991Un noyau libre qui, avec les outils GNU, forme un Unix complet et gratuit.
macOS, iOS (Apple)2001, 2007Un Unix certifié (norme UNIX 03 pour macOS), bâti sur NeXTSTEP et BSD.
Android (Google)2008Le noyau Linux dans les téléphones.
Planche 1

fork et exec : comment Unix crée les processus

1969

Unix crée un nouveau processus d'une façon surprenante, en deux temps. L'appel système fork() duplique le processus qui l'appelle : le parent et l'enfant, identiques, continuent tous deux juste après le fork ; seule la valeur rendue les distingue (0 dans l'enfant, le numéro de l'enfant, son PID, dans le parent). Puis exec() remplace le programme de l'enfant par un autre. Le parent attend la fin de l'enfant avec wait(). Tous les processus descendent ainsi du premier, init, de PID 1.

pid = fork();
if (pid == 0) {                 /* dans l'enfant */
    execlp("ls", "ls", NULL);    /* devenir ls    */
} else {                         /* dans le parent : le shell */
    wait(NULL);                  /* attendre la fin de ls */
}
L'arbre des processus, avec leur PID et le programme qu'ils exécutent. Le nouvel élément est en rouge.
Étape
—
for (int i = 0; i < n; i++)
    fork();
printf("bonjour\n");          /* combien de « bonjour » ? */
3
Chaque niveau correspond à un tour de boucle : chaque processus existant se dédouble. Le chiffre est le PID ; l'étiquette indique à quel tour le processus est né.
Processus créés (simulation)
—
Prévu : 2ⁿ (chaque tour double l'effectif)
—
« bonjour » affichés / appels à fork
—
Prévu : appels à fork = 2ⁿ − 1
—
Ce qu'il faut retenir. Séparer « dupliquer » et « changer de programme » paraît maladroit, mais c'est ce qui rend le shell si simple : entre le fork et l'exec, l'enfant peut rediriger son entrée ou sa sortie vers un fichier ou un tube, sans que le programme lancé n'en sache rien. L'énigme montre la puissance du mécanisme : quelques lignes suffisent à multiplier les processus de façon exponentielle (la « bombe fork », qui peut saturer une machine). Pour que la duplication ne coûte rien, les Unix modernes ne recopient pas la mémoire : parent et enfant la partagent jusqu'à ce que l'un d'eux écrive, c'est la copie sur écriture.
Planche 2

grep et les expressions régulières : chercher un motif plutôt qu'un mot

1968 – 1973

Une expression régulière décrit un ensemble de textes : . désigne n'importe quel caractère, * « zéro fois ou plus », + « au moins une fois », ? « facultatif », [0-9] un chiffre, | « ou », ^ et $ le début et la fin de ligne. En 1968, Ken Thompson publie une méthode pour les reconnaître très vite, en transformant l'expression en un automate qui avance d'un caractère à la fois. En 1973, il en tire la commande grep (de « g/re/p » : global, regular expression, print).

Fichier (modifiable)

Sortie de grep (lignes retenues)

L'automate de Thompson construit à partir du motif : chaque cercle est un état, les flèches portent le caractère à lire (les flèches grises se franchissent sans lire de caractère). Le double cercle est l'état final. Sur un petit écran, faites défiler la figure horizontalement.
États de l'automate
—
Lignes retenues
—
Contrôle : même recherche par le moteur RegExp du navigateur
—

Beaucoup de moteurs récents (Perl, Python, Java, JavaScript) n'utilisent pas l'automate de Thompson mais le retour sur trace : ils essaient une possibilité, et reviennent en arrière en cas d'échec. Sur certains motifs, le nombre d'essais explose. L'exemple classique, publié par Russ Cox en 2007 : le motif a?ⁿaⁿ (n fois « a facultatif », puis n fois « a ») appliqué au texte aⁿ.

12
Nombre de pas de calcul en échelle logarithmique. Rouge : retour sur trace (mesuré ici, pas à pas) ; bleu : automate de Thompson (mesuré aussi).
Retour sur trace : pas mesurés
—
Automate de Thompson : pas mesurés
—
Pente mesurée du retour sur trace (log₂ des pas par cran de n)
—
Les deux méthodes trouvent-elles la correspondance ?
—
Ce qu'il faut retenir. L'automate de Thompson suit en même temps tous les états possibles : son travail croît comme la longueur du texte multipliée par la taille du motif, jamais plus. Le retour sur trace essaie les possibilités une à une ; sur le motif piège, le nombre d'essais double presque à chaque cran de n. Ce n'est pas qu'une curiosité : des services web sont tombés en panne à cause d'une seule expression régulière mal choisie. Les expressions régulières sont aujourd'hui partout : éditeurs de texte, langages de programmation, formulaires de saisie, outils sed et awk d'Unix.
Planche 3

diff : ce qui a changé entre deux versions d'un fichier

1976

La commande diff, écrite par Douglas McIlroy et James Hunt en 1976, compare deux fichiers ligne par ligne et dit quelles lignes ont été retirées (−) et ajoutées (+). Son principe : trouver la plus longue sous-suite commune aux deux fichiers, les lignes qui restent dans le même ordre. Tout le reste est un changement. On la calcule en remplissant un tableau, chaque case ne dépendant que de ses voisines de gauche, du haut et de la diagonale : c'est la programmation dynamique.

Version 1

Version 2

Case (i, j) : longueur de la plus longue sous-suite commune aux i premières lignes de la version 1 et aux j premières de la version 2. Les cases vertes marquent deux lignes égales ; le chemin rouge, retrouvé en partant de la fin, donne le diff.

Sortie de diff


      
Lignes communes (LCS)
—
Retirées / ajoutées
—
Contrôle : lignes v1 − LCS et v2 − LCS
—
Contrôle : appliquer le diff à la version 1 redonne la version 2
—
Ce qu'il faut retenir. Le diff ne voit pas qu'une ligne a été « modifiée » : il voit qu'une ligne a disparu et qu'une autre est apparue. Le nombre de lignes retirées et ajoutées découle entièrement de la sous-suite commune, et appliquer ces changements à la version 1 redonne exactement la version 2 : c'est ce que fait la commande patch (Larry Wall, 1985). Ce couple diff-patch est le fondement de la collaboration sur le logiciel : les correctifs du noyau Linux circulent sous cette forme, et le gestionnaire de versions Git (Linus Torvalds, 2005), qui conserve l'historique de presque tout le code du monde, affiche ses différences avec le même algorithme amélioré.
Planche 4

Le temps Unix et le bug de l'an 2038

1971 – 2038

Unix compte le temps d'une façon très simple : le nombre de secondes écoulées depuis le 1ᵉʳ janvier 1970 à 0 h 00 UTC, l'« époque » Unix. Tous les fichiers, tous les journaux, tous les serveurs datent les événements ainsi. Pendant des décennies, ce nombre a été rangé dans un entier signé de 32 bits, qui ne peut pas dépasser 2³¹ − 1 = 2 147 483 647. Que se passe-t-il quand on atteint cette limite ?

2026
En haut, les 32 bits de l'entier (le premier est le signe). En bas, la date que lit un système 32 bits, et la vraie date, lue par un système 64 bits.
Secondes depuis 1970 (entier de 64 bits)
—
Même valeur rangée sur 32 bits signés
—
Vraie date (UTC)
—
Date lue par un système 32 bits
—
Temps restant avant le débordement
—
Ce qu'il faut retenir. Le mardi 19 janvier 2038 à 3 h 14 min 07 s UTC, le compteur atteint 2 147 483 647 ; une seconde plus tard, le bit de signe bascule et un système 32 bits croit être le vendredi 13 décembre 1901 à 20 h 45 min 52 s. C'est le cousin du « bug de l'an 2000 ». La solution est connue : passer à un entier de 64 bits, qui ne débordera que dans 292 milliards d'années. Linux, les BSD et macOS l'ont fait, y compris sur les processeurs 32 bits ; le risque demeure dans les vieux appareils embarqués et les formats de fichiers qui gardent 32 bits.
Planche 5 · signature

Un terminal Unix dans votre navigateur

Voici un petit shell qui imite Unix, avec un système de fichiers en mémoire. Il connaît une trentaine de commandes : ls, cd, pwd, cat, echo, mkdir, touch, rm, cp, mv, grep, wc, sort, uniq, head, tail, tr, chmod, ps, date, whoami, history, man… Il comprend les tubes | et les redirections > et >>. Tapez man pour la liste, ou relevez les défis ci-dessous : chacun est vérifié automatiquement (la démonstration, elle, ne compte pas).

Défis

    Commandes tapées
    0
    Processus créés (un par commande d'un tube)
    0
    Défis réussis
    0 / 6
    Ce qu'il faut retenir. En quelques minutes, on retrouve toute la philosophie d'Unix : un arbre de fichiers, des commandes courtes qui font une seule chose, du texte qui circule de l'une à l'autre. Dans un vrai Unix, chaque commande d'une ligne est un processus créé par fork et exec, ce que le compteur ci-dessus rappelle. Ces mêmes commandes fonctionnent à l'identique dans le terminal d'un Mac, d'un serveur Linux ou d'un téléphone Android : cinquante ans après, c'est la plus durable des interfaces informatiques.

    Où trouve-t-on Unix aujourd'hui ?

    Internet

    La grande majorité des serveurs web, des serveurs de noms (DNS) et des routeurs fonctionnent sous un système de la famille Unix, Linux ou BSD.

    Calcul scientifique

    Depuis novembre 2017, les 500 supercalculateurs les plus puissants du monde (classement TOP500) tournent tous sous Linux.

    Poche et bureau

    Android (noyau Linux), iOS et macOS (héritiers de BSD) : la plupart des téléphones et une partie des ordinateurs personnels sont des Unix.

    Objets et nuage

    Box Internet, téléviseurs, voitures, centres de données du nuage : Linux s'est imposé partout où il faut un système fiable et modifiable.

    Frise des jalons

    Pour aller plus loin

    Le terminal de la planche 5 est une imitation écrite en JavaScript : il reproduit le comportement de base des commandes, pas toutes leurs options.