88 miles à l'heure !

GNU/Linux Magazine n° 102 | février 2008 | Emile (iMil) Heitor
Creative Commons
  • Actuellement 4 sur 5 étoiles
4
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
Le 23 janvier 2002, la société Caldera publiait les sources de la vie. Avant que cette dernière ne devienne SCO [insérez des noms d’animaux ici], elle fournit en effet à la communauté l’ensemble des travaux effectués sur UNIX depuis ses premiers pas en 1972, peuplant ainsi de trésors le légendaire site « The Unix Heritage Society » [http://www.tuhs.org]. Parmi les perles disponibles sur TUHS, certaines permettent au commun des mortels de réaliser un voyage dans le temps aussi instructif que fabuleux, car non content de disposer de moult codes source, le site contient également des images disque bootables à l’aide d’un émulateur PDP11. Sortez les pattes d’éph’...

Est-ce bien raisonnable ?

Ce que nous nous proposons de réaliser ici, c’est de ressusciter un des ancêtres de nos UNICES libres d’aujourd’hui, la dernière version de BSD UNIX pour PDP-11, dont le patch le plus récent date d’avril 2007 (!). J’ai nommé 2.11BSD.

Il existe de nombreux émulateurs PDP-11 disponibles pour nos systèmes libres, une liste exhaustive de ces derniers est disponible à l’adresse http://www.aracnet.com/~healyzh/pdp11emu.html. Nous utiliserons pour notre expérience l’un des plus populaires, simh, un émulateur multi-système dont la dernière modification date de décembre 2006 !

Sur un système Debian ou Debian-like, installez simplement simh grâce à APT :

$ sudo aptitude install simh

C’est le site « The Unix Heritage Society » (http://www.tuhs.org/) qui sera le point de départ de notre voyage dans le temps. Attention, il est fortement déconseillé de vous rendre sur ce site depuis votre lieu de travail. En effet, sous son allure très Web 0.1, ce site est en réalité ce qu’on appelle un « gouffre à temps », celui qui n’y prend pas garde ne relève le nez que plusieurs heures plus tard sans réellement avoir compris où ces centaines de minutes ont pu passer.

Depuis la section « Unix Archive Sites », nous nous rendons sur l’un des miroirs officiels contenant les sources de la vie, accessibles via FTP ou HTTP, et plus particulièrement, dans la section « PDP-11/Boot_Images ».

imil@tatooine:~/emu/211bsd$ lftp ftp://ftp.gcu-squad.org/pub/tuhs/PDP-11/Boot_Images/

cd ok, cwd=/pub/tuhs/PDP-11/Boot_Images               

lftp ftp.gcu-squad.org:/pub/tuhs/PDP-11/Boot_Images> cls

2.11_on_Simh/       2.9BSD_rl02_1145.gz v6_rl02_unknown.gz    

2.11_on_rl02/       README               v7_rk05_1145.gz

2.11_rp_unknown.gz Ultrix-3.1/          v7_rl02_1145.gz

Diverses images amorçables sont disponibles ici, et je ne saurais que trop vous conseiller de tester également ces morceaux d’histoires que sont UNIX v6 et v7. Allumons quelques cierges et regardons pieusement démarrer la toute première version publique d’UNIX :

imil@tatooine:~/emu/211bsd$ pdp11

PDP-11 simulator V3.7-

sim> set cpu u18

Disabling XQ

sim> attach rl0 v6_rl02_unknown

sim> boot rl

!unix

unix v6 11/23

mem = 99 KW max = 63

# STTY -LCASE

# ls /

a.out           junk            mnt2            src             unix.rxrl

bin             lib             names           sys             unix.tmp

dev             lib.old         oldunix         tmp             usr

etc             loop            oldunix.25.7    unix            v7boot

fixowner        mnt             rluboot         unix.jones      x

hmboot          mnt1            rx              unix.mlab       xlib

Comme nous l’avons annoncé plus haut, notre choix se porte sur l’émulateur simh pour faire démarrer cette ancienne image. Simh est en réalité composé de nombreux émulateurs dits « historiques », parmi eux pdp7, pdp11, vax ou encore altair.

Nous utilisons évidemment pdp11, et nous n’avons besoin, dans notre expérience, que d’une connaissance très rudimentaire de l’émulateur :

- spécifier le type de processeur, ici u18 ;

- attacher l’image du disque à un device virtuel, ici v6_rl02_unknown sur rl0 ;

- démarrer sur le device : boot rl.

Nous poursuivons dans notre exploration et tentons de passer en mode multi-utilisateur en appuyant sur ^D ([Control]-D)

# ^D

Fri Feb 2 15:26:27 PST 1990

enter reason for re-boot, then ^D (control D)

please note your UNIX id at the end of the message

Going to multi-user mode now.

ka6 = 2326

aps = 141634

regs 104266 141624 1 134554 176500 141646 141624 56612 30010

trap type 0

panic: trap

Mais, manifestement, UNIX v6 ne semble pas apprécier notre environnement émulé. Nous ne passerons pas plus de temps en 1975, car il est temps de partir trois ans plus tard, alors qu’un certain Bill Joy inclut dans 2BSD deux petits programmes de sa création : le C-Shell et... vi.

Premier contact

En 1978, Joy, qui a créé un an plus tôt la first Berkeley Software Distribution” ou 1BSD, publie la seconde version de sa distribution (on parlait effectivement ici de « distribution »), 2BSD. Si cette version a effectivement 30 ans d’âge, et que le système de base a finalement peu changé, nous allons pour notre part nous familiariser avec 2.11BSD, soit la dernière révision de 2BSD sortie en 1992, qui a bénéficié de nombreux patches et backports. C’est ainsi qu’on retrouve dans 2.11BSD du code issu, entre autres, de 4BSD, et que le plus ancien bénéficie par exemple d’une pile IP.

Nous utiliserons pour notre séance de réanimation l’image présente dans l’archive 2.11_on_Simh/211bsd.tar.gz. Cette dernière comprend entre autres des fichiers de démarrage pour simh et l’image du disque sur laquelle nous allons voyager.

Comme l’indique le fichier README présent dans l’archive, nous démarrons l’émulateur de cette façon :

imil@tatooine:~/emu/211bsd$ pdp11 211bsd.simh

Et après avoir appuyé sur [Entrée] à la présentation du prompt « : », nous pouvons alors admirer un boot UNIX des plus classiques :

PDP-11 simulator V3.7-0

Listening on port 4000 (socket 4)

Modem control activated

Auto disconnect activated

211bsd.simh> attach xq0 tun1

Command not allowed

Disabling CR

73Boot from ra(0,0,0) at 0172150

:

: ra(0,0,0)unix

Boot: bootdev=02400 bootcsr=0172150

2.11 BSD UNIX #1: Fri Jun 9 08:42:54 PDT 1995

    root@SSU-64EN137:/usr/src/sys/SYSTEM

ra0: Ver 3 mod 3

ra0: RD54 size=311200

attaching qe0 csr 174440

qe0: DEC DELQA addr 00:50:56:01:01:01

attaching lo0

phys mem = 3145728

avail mem = 1737664

user mem = 307200

June 9 12:18:30 init: configure system

dz 0 csr 160100 vector 300 attached

ra 0 csr 172150 vector 154 vectorset attached

ts 0 csr 172520 vector 224 attached

erase, kill ^U, intr ^C

#

Notons qu’une interface réseau munie d’une adresse MAC semble être initialisée, mais nous y reviendrons. Cette fois, un ^D nous propulse bien en mode multi-utilisateur :

# Fast boot ... skipping disk checks

checking quotas: done.

*** You need to edit /etc/netstart and /etc/hosts ***

Assuming NETWORKING system ...

add host 2bsd: gateway localhost

add net default: gateway 192.168.1.254

starting system logger

Jun 9 12:10:04 2bsd vmunix: ra0: Ver 3 mod 3

Jun 9 12:10:04 2bsd vmunix: ra0: RD54 size=311200

checking for core dump...

preserving editor files

clearing /tmp

standard daemons: update cron accounting.

starting network daemons: inetd.

starting local daemons:Fri Jun 9 12:10:04 PDT 1995

Jun 9 12:10:04 2bsd June 9 12:10:04 init: kernel security level changed from 0 to 1

2.11 BSD UNIX (2bsd) (console)

login:

On se rend compte à cet instant que les choses n’ont pas changé tant que ça en 30 ans... La lecture de la documentation nous informe que nous pouvons nous loguer en root avec le mot de passe Hithere. On remarque qu’un telnet localhost 4000 sur le host permet d’obtenir une console sur la machine virtuelle :

imil@tatooine:~/emu/211bsd$ telnet localhost 4000

Trying 127.0.0.1...

Connected to localhost.localdomain.

Escape character is '^]'.

Connected to the PDP-11 simulator

2.11 BSD UNIX (2bsd) (tty00)

login:

Une fois connecté, nous voyons que, comme le laissait présumer la séquence d’amorçage, nous disposons effectivement d’une interface réseau munie d’une IP :

# ifconfig qe0

qe0: flags=63<UP,BROADCAST,NOTRAILERS,RUNNING>

        inet 192.168.1.1 netmask ffffff00 broadcast 192.168.1.255

Encore un peu loin des nouveaux systèmes de rc imbriqués des BSD modernes ou des init scripts façon SysV, la configuration IP de la machine s’effectue brutalement dans le fichier /etc/netstart :

# [...]

hostname=2bsd

netmask=255.255.255.0

broadcast=192.168.1.255

default=192.168.1.254

# [...]

ifconfig qe0 inet netmask $netmask $hostname broadcast $broadcast up -trailers >/dev/console 2>&1

# [...]

ifconfig lo0 inet localhost up -trailers        >/dev/console 2>&1

route add $hostname localhost 0         >/dev/console 2>&1

route add default $default 1            >/dev/console 2>&1

Et finalement, je me mets à penser qu’en comparaison des usines à gaz modernes, c’était pas si mal...

Une balade dans le filesystem me fait me demander si, par hasard, ce système ne disposerait pas d’un /usr/src, tout comme ses filleuls. Ce qu’on trouve à cet endroit de l’arborescence me laisse sans voix : non seulement, il existe bel et bien, mais, de surcroît, il est pratiquement identique à ce que nous connaissons aujourd’hui. Pire encore, le système de compilation/installation lui-même est, à peu de choses près, le même :

# ls /usr/src

Makefile     bin          lib          new          sys          usr.sbin

asm.sed      etc          libexec      old          ucb

asm.sed.pdp games        local        sbin         usr.bin

asm.sed.vax include      man          share        usr.lib

Voici un extrait du makefile de base :

# This makefile is designed to be run as:

#       make build

#       make installsrc

# The `make build' will compile and install the libraries

# before building the rest of the sources. The `make installsrc'

# will then install the remaining binaries.

On est tout de même à deux doigts des make buildworld buildkernel installworld installkernel de FreeBSD pour ne prendre que cet exemple.

Le démarrage du système se déroule comme nous l’imaginons. La lecture du fichier docs/2.11bsd_setup.txt inclus dans l’archive, ainsi que celle de src/sys/pdp/mch_start.s nous informent qu’init se trouve dans /etc. Dans l’arbre des sources, son code se situe dans src/sbin/init :

# ls sbin/init

Makefile init.8    init.c

Une rapide lecture du code de ce dernier nous montre que, comme sur les BSD modernes, il exécute /etc/rc :

/*

* Copyright (c) 1980,1986 Regents of the University of California.

* All rights reserved. The Berkeley software License Agreement

* specifies the terms and conditions for redistribution.

*/

#if     defined(DOSCCS) && !defined(lint)

static char sccsid[] = "@(#)init.c      5.6.4 (2.11BSD) 1999/2/23";

#endif

[...]

char    runc[] = "/etc/rc";

[...]

                execl(shell, shell, runc, arg1, arg2, (char *)0);

[...]

Mais, contrairement à ses récents successeurs, la lecture du script rc est tout à fait accessible. On y trouve les initialisations classiques d’un système UNIX, création d’un RAMDISK, mount -a, exécution de divers démons tels qu’inetd, lpd ou cron, le fameux /etc/netstart et, finalement, le légendaire /etc/rc.local. Et tout ça, dans un script de 165 lignes.

I can has netwurk ?

Évidemment, sans plus de configuration, si grand-mère possède bien une IP, elle n’en est pas moins isolée du reste du monde.

J’entreprends donc, comme je l’ai lu dans les quelques documents traitant de ce sujet, d’« attacher » une interface virtuelle à une interface de type tunnel qui servira de pont vers mon réseau. Nous reviendrons en détail sur cette configuration.

Le lecteur attentif aura remarqué dans le déroulement du précédent boot le message d’erreur suivant :

211bsd.simh> attach xq0 tun1

Command not allowed

Ce message, s’il semble dire que vous avez simplement commis une erreur de syntaxe, signifie en réalité que la version de simh que nous utilisons a été compilée sans support Ethernet. Rien n’est jamais simple dans la vie des explorateurs. Nous nous voyons donc contraints de recompiler les sources de l’émulateur, en n’oubliant pas le support réseau.

Nous récupérons simh 3.7 à l’adresse suivante : http://simh.trailing-edge.com/sources/simhv37-3.zip. Quelques petits ajustements sont nécessaires afin que la compilation puisse s’effectuer sans encombre :

- Cette archive a été réalisée par une de ces personnes qui considèrent convenable de ne pas avoir de répertoire contenant l’ensemble des fichiers. Aussi, créez un répertoire d’extraction si vous ne souhaitez pas voir votre ~/src pollué :

mkdir simh && cd simh && unzip ../simhv37-3.zip

- Il vous faudra installer libpcap-dev version 0.9, disponible via APT, puis remplacer dans le fichier makefile :

/usr/local/lib/libpcap.a

par

/usr/lib/libpcap.a

dans la variable NETWORK_OPT.

- Afin d’éviter des erreurs de compilation du type :

/home/imil/emu/simh/sim_timer.c:302: undefined reference to `clock_getres'

il faudra ajouter la directive le linkage -lrt à la ligne :

OS_CCDEFS = -D_GNU_SOURCE

- Le makefile ne crée pas tout seul le répertoire de destination des binaires. Aussi, à l’endroit où se trouve la racine de l’archive décompressée, effectuez un simple :

mkdir BIN

- Et enfin, pour effectivement compiler l’émulateur avec le support réseau, lancez la compilation de cette façon :

make USE_NETWORK=1

À l’issue de la compilation, un exécutable BIN/pdp11 devrait être disponible. Testons ce dernier :

root@tatooine:~/emu/211bsd# ./pdp11

PDP-11 simulator V3.7-3

sim> attach xq0 tun1

Eth: opened tun1

Beaucoup mieux.

Reprenons. L’idée ici est d’attacher une interface réseau fournie par simh, XQ, émulation logicielle de cartes Ethernet Digital, sur une interface de type Tun/Tap, présente sur n’importe quel Unix moderne. Nous obtenons le modèle suivant :

Hôte

[eth0] 192.168.10.2/24

  |

  +---+---------(pont)----------+

      | |

   [tun0] 192.168.11.254/24   [tun1]

                                |

  +-----------------------------+

  |

[qe0] 192.168.11.1/24

2bsd

Pour réaliser cette opération, nous allons utiliser un petit outil trouvé chez http://www.itsecuritygeek.com/, taptap-modified.c :

wget http://www.itsecuritygeek.com/files/taptap-modified.c

Notons que, toujours du même auteur, nous trouverons à cette adresse http://www.retrocomputinggeek.com/index/retrowiki/SIMHNetworking/ une version bridgée de notre petit montage.

taptap-modified.c est un programme sans prétention, un rapide coup d’œil au code source de ce dernier finit de nous en convaincre : ce dernier crée simplement deux interfaces de type Tap. Voici l’exemple de la création de la première :

        ifr1.ifr_flags = IFF_TAP | IFF_NO_PI;

        strncpy(ifr1.ifr_name, "tun%d", IFNAMSIZ);

        if(ioctl(dev1, TUNSETIFF, (void*) &ifr1) < 0) {

                perror("ioctl()");

                exit(2);

}

Le programme passe ensuite en background et copie à l’infini les données d’une interface à l’autre :

        if( (child1 = fork()) == 0 ) {

                while(1) {

                        cnt=read(dev1,(void*)&buf,1518);

                        write(dev2,(void*)&buf,cnt);

                }

        }

Compilons :

$ cc -o taptap taptap-modified.c

Et exécutons :

$ sudo ./taptap

Un appel à ifconfig nous montre bien nos deux interfaces tunX et tunX+1. Reste à affecter une IP à la première et simplement à « monter » la seconde :

$ sudo ifconfig tun0 192.168.11.254 netmask 255.255.255.0 up

$ sudo ifconfig tun1 up

Nous pouvons maintenant redémarrer 2bsd. Mais avant de repasser en mode multi-utilisateur, nous prendrons soin de renseigner correctement les fichiers /etc/netstart et /etc/hosts avec les informations adéquates :

# plein de trucs

hostname=2bsd

netmask=255.255.255.0

broadcast=192.168.11.255

default=192.168.11.254

# plein d'autres trucs

...

# cat /etc/hosts

127.0.0.1       localhost

192.168.1.1     2bsd 2bsd.example.com

Nous y sommes ! Appuyons fébrilement sur ^D et loguons-nous :

# ping -c 1 192.168.11.254

PING 192.168.11.254 (192.168.11.254): 56 data bytes

64 bytes from 192.168.11.254: icmp_seq=0 ttl=64 time=50.001 ms

--- 192.168.11.254 ping statistics ---

1 packets transmitted, 1 packets received, 0% packet loss

round-trip min/avg/max = 50.001/0/50.001 ms

Mieux, après avoir placé une règle de NAT sur la machine hôte et autorisé l’IP forwarding :

# ping -c1 www.gnulinuxmag.com

PING www.gnulinuxmag.com (213.186.60.195): 56 data bytes

64 bytes from 213.186.60.195: icmp_seq=0 ttl=47 time=50.001 ms

--- www.gnulinuxmag.com ping statistics ---

1 packets transmitted, 1 packets received, 0% packet loss

round-trip min/avg/max = 50.001/0/50.001 ms

Que d’émotions mes amis, que d’émotions ! Notre 2.11BSD issu d’un autre temps peut désormais se connecter à un réseau qu’il n’imaginait même pas qu’il existerait vraiment un jour : Internet.

Hello ! I'm coming from the past

Notre OS du passé bénéficiant d’un accès vers le monde, la tentation était trop grande : je dois aller faire le kéké sur IRC. Me doutant que le portage d’un client IRC récent muni de toutes ses features serait un casse-tête sans nom, j’ai jeté mon dévolu sur un minuscule client du nom de tinyirc, trouvé après un brin de recherche.

GZip étant plus récent que 2.11BSD, il n’est pas présent dans la distribution. Aussi, il faudra prendre soin de « dé-GZipper » l’archive pour ne transmettre que le .tar dans notre machine émulée. Fort heureusement, tar faisait déjà partie de la fête.

Le code source du client, qui se matérialise par un unique fichier C, pèse à peine 25 k. Cela facilitera grandement son « portage » (considérant ce que j’ai fait pour le compiler, il est plus que prétentieux de parler de portage). Le code en lui-même, par contre, est une insulte à la bienséance ; j’ai rarement vu code aussi abscons et peu commenté.

La lecture du makefile nous informe que le code est portable sur quelques systèmes, ce qui laisse présumer que derrière son apparence chaotique, le code devrait malgré tout être portable. Nous choisirons la cible generic du makefile :

generic:

          $(MAKE) tinyirc CFLAGS=-O LDFLAGS=-s LIBS=-ltermcap

On note immédiatement que la variable MAKE n’est renseignée nulle part. Nous ajoutons donc en haut du makefile, MAKE = make. Ensuite, comme il est assez prévisible que nous risquons de recompiler plusieurs fois et que notre shell n’a pas de retour de commande, et encore moins de complétion automatique, nous ajoutons la cible suivante :

clean:

        rm -f tinyirc tinyirc.o

Une dernière chose avant de tenter une première compilation, une chose qui à l’époque où j’avais pour la première fois fait cette expérience m’avait pratiquement ému. Vous avez probablement lu le contenu de la variable LIBS ci-dessus sans même y réfléchir. Instinctivement, vous pensez « shared library ». Oui. Sauf que non :

# ls /lib

c0       c1       c2       cpp      crt0.o   libc.a   mcrt0.o

# ls /usr/lib

lib2648.a        libc_p.a         libm.a           libstubs.a

lib300.a         libcurses.a      libm_p.a         libstubs_p.a

lib300s.a        libcurses_p.a    libmp.a          libtermcap.a

lib4013.a        libdbm.a         libom.a          libtermcap_p.a

lib4014.a        libdbm_p.a       libom_p.a        libtermlib.a

lib450.a         liberrlst.a      libplot.a        libtermlib_p.a

libF77.a         liberrlst_p.a    libplot2648.a    libutil.a

libF77_p.a       libf77plot.a     libplot7221.a    libutil_p.a

libI66.a         libident.a       libplotaed.a     libvmf.a

libI77.a         libident_p.a     libplotbg.a      libvmf_p.a

libI77_p.a       libkern.a        libplotdumb.a    libvt0.a

libU77.a         libl.a           libplotgigi.a    liby.a

libU77_p.a       libln.a          libplotimagen.a

Point de bibliothèques dynamiques ! De bons gros .a statiques à coller à votre .o. Probable que nous ayons à changer quelques petites choses dans notre makefile. Mais, comme nous trépignons tous d’impatience, jetons-nous à l’eau :

# make generic

Et comme on pouvait s’y attendre :

make tinyirc CFLAGS=-O LDFLAGS=-s LIBS=-ltermcap

cc -O -DDEFAULTSERVER=\"irc.linpeople.org\" -DDEFAULTPORT=7000 -c tinyirc.c -o tinyirc.o

tinyirc.c:645: Expression syntax

tinyirc.c:645: Nonterminated string

tinyirc.c:964: warning: illegal combination of pointer and integer, op =

tinyirc.c:964: ut_addr undefined; func. main

tinyirc.c:964: Illegal structure ref

tinyirc.c:970: Illegal structure ref

tinyirc.c:970: warning: illegal combination of pointer and integer, op =

*** Exit 1

N’étant pas d’un naturel patient, et notre expérience n’étant pas destinée à fouler des repositories publics, je réaliserai ces corrections avec mon plus beau masque de bovin :

# diff -r tinyirc.c.orig tinyirc.c

645c645

<           strcat(lineout, " :" RELEASE);

---

>           strcat(lineout, RELEASE);

962,976d961

<       setutent();

<       strcpy(ut.ut_line, strrchr(ttyname(0), '/') + 1);

<       if ((utmp = getutline(&ut)) == NULL || !(utmp->ut_addr) ||

<           *((char *) utmp->ut_host) == ':' /* X connection */ )

<           tmp = userinfo->pw_gecos;

<       else {

<           struct hostent *h;

<           struct in_addr a;

<           a.s_addr = utmp->ut_addr;

<           if (!(h = gethostbyaddr((char *) &a.s_addr,

<                                   sizeof(a.s_addr), AF_INET)))

<               tmp = (char *) inet_ntoa(a);

<           else

<               tmp = (char *) h->h_name;

<       }

Oui, je sais.

Nous y sommes presque :

# make generic

make tinyirc CFLAGS=-O LDFLAGS=-s LIBS=-ltermcap

cc -O -DDEFAULTSERVER=\"irc.linpeople.org\" -DDEFAULTPORT=7000 -c tinyirc.c -o tinyirc.o

cc -s -o tinyirc tinyirc.o -ltermcap

Undefined:

_endutent

*** Exit 1

Même cause, même conséquence (le lecteur averti aura compris que la flemme m’empêche de porter quelques structures et primitives utmp), on supprime l’appel à la fonction endutent. À l’issue de quoi, ça compile ! Afin de rejoindre un canal connu, nous modifions les définitions de DEFAULTSERVER et DEFAULTPORT dans notre makefile, et enfin :

puis :

Me voici, fier, sur IRC avec un client qui n’affiche même pas correctement les retours chariot, mais qu’importe, j’ai la sensation d’être Michael J. Fox dans la Delorean™ de Doc’.

Retour en 2008

D’aucuns s’interrogeront peut-être sur la finalité de cette expérience ; personnellement, la première fois que je l’ai réalisée, juste après la libération de ces sources, j’ai ressenti un immense plaisir à découvrir l’histoire par la pratique, un peu comme si je me téléportais dans le laboratoire d’AT&T et regardais par-dessus l’épaule des dieux. Mais plus important encore, ce périple m’a instruit : essayez par exemple de compiler une application de plus de 64 k et découvrez les joies du linkage par padding, et vous ne regarderez plus jamais votre quad-core muni de 2 Go de RAM de la même manière.

Liens

- Berkeley Software Distribution sur Wikipédia, http://fr.wikipedia.org/wiki/Berkeley_Software_Distribution

- The Unix Heritage Society, http://www.tuhs.org/

- The DEC PDP-11 Emulation Webpage, http://www.aracnet.com/~healyzh/pdp11emu.html

- Les archives TUHS chez GCU, ftp://ftp.gcu-squad.org/pub/tuhs/

- The Computer History Simulation Project, http://simh.trailing-edge.com/

- SIMHNetworking, http://www.retrocomputinggeek.com/retrowiki/SIMHNetworking/

- taptap-modified, http://www.itsecuritygeek.com/itsgeek/comments/simh-modified-version-of-taptapc/

- Vintage Computer Festival, http://www.flickr.com/photos/hollyward/sets/1303317/