Plan 9 ist ein neues, verteiltes Betriebssystem für verschiedene Hardware-Architekturen, das in den letzten Jahren in den Bell Laboratorien entwickelt wurde und das seit Anfang des Jahres für Universitäten verfügbar ist. Es ist zwar noch ein experimentelles System, aber es enthält einige faszinierende neue Ideen.
Dateinamen sind noch immer Pfade, deren Komponenten durch Schrägstriche getrennt sind, und liebgewordene Programme von awk über ed bis yacc existieren nach wie vor, aber sonst sind alle weiteren Ähnlichkeiten zu einem früheren System aus der gleichen Quelle unbeabsichtigt und eher mißverständlich. Vom Super-User über harte und symbolische Links bis zum vi wurden Altlasten gründlich entfernt und durch elegante, kohärente neue Mechanismen ersetzt.
Normalerweise besteht Plan 9 aus einem Netz von Computern, in dem verschiedene Hardware mit verschiedener Software verschiedene Aufgaben übernimmt: man sitzt an einem Terminal, das ein Window-System und lokale Prozesse wie etwa den Editor sam bearbeitet (siehe unix/mail 3/93), und kontrolliert Prozesse auf einem CPU-Server, die zum Beispiel C-Quellen von einem File-Server holen und übersetzen. Alle drei Computer sowie das Ziel der Übersetzung können verschiedene Hardware-Architekturen sein; alle benützen zwar verwandte, aber genau für ihre speziellen Aufgaben zugeschnittene Betriebssysteme und ein einziges, sehr elegantes Kommunikationsprotokoll 9P, das die Architektur des Gesamtsystems entscheidend geprägt hat.
Computer sind billig und die immer kürzeren Innovationszyklen zwingen dazu, Systeme mit vollkommen austauschbaren Hardware-Komponenten zu konzipieren. Typische große Netze sind deshalb so schwer zu verwalten, weil jede Workstation mit lokaler Platte letztlich als eigenständiges System funktioniert und wohl auch als solches explizit verwaltet werden muß. Andy Tanenbaum verglich Workstations mit Zahnbürsten (``keiner kriegt meine'') -- dank Wasserleitung und Kanalisation sind wir heute von den öffentlichen Badehäusern zwar unabhängig, aber wir nehmen noch immer ganz gern die Leistungen eines Frei- oder zur Not auch Hallenbads in Anspruch.
Terminal mit Systemanschluß heißt deshalb die Plan-9-Devise, und das (relativ) zentrale System besteht im Idealfall aus dedizierten File-Servern und CPU -Servern mit schnellen lokalen Verbindungen untereinander und relativ langsamen Leitungen zu den Terminals. Nur der File-Server enthält einen persistenten Zustand, denn er verwaltet Platten. Alle anderen Systeme können jederzeit ersetzt und neu gestartet werden. Das Verwaltungsproblem reduziert sich damit wie früher auf ein zentrales System, den File-Server, und in den ist Backup in Form einer Hierarchie aus Hauptspeicher, Magnetplatte und optischen WORM -Laufwerken a priori eingebaut.
Selbst diskless entwickelt eine UNIX -Workstation immer ein Eigenleben. Man lädt einen Kern, verbindet ein Dateisystem als Wurzel und montiert den Rest vom Netz. automount (siehe unix/mail 5/92) reduziert die Wartezeiten beim Systemstart und hält trotzdem alles Nötige für den Fall der Fälle vor. Jede Workstation hat nach kurzer Zeit ihre eigene Sicht der Datei-Welt -- der nachbarliche Arbeitsplatz dürfte für meine Arbeit vollkommen unbrauchbar sein.
Natürlich kann man dies auch mit UNIX besser organisieren: man richtet einfach alle Workstations gleich ein und montiert alle Dateisysteme aller Anlagen überall. Jede Rechnerbetriebsgruppe kann aber ein Lied davon singen, wie wenig interoperabel trotz aller anderslautenden Schwüre die Systeme verschiedener Hersteller sind und wie zäh zum Beispiel ein Universitäts-Netz wird, in dem sich der backbone hauptsächlich mit dem NFS -broadcast-Verkehr der verschiedenen Fachbereiche beschäftigt. Aus reiner Verzweiflung kauft man eine kleine Platte und hält seine Daten lokal vor, damit die Workstation überhaupt noch etwas tut. Das Rechenzentrum betreibt einen schnelleren (und vor allem teureren) Zentralrechner, aber wenn dieser mit den lokalen Daten einer Workstation arbeiten soll, ist man der Netzkapazität wieder hoffnungslos ausgeliefert.
Spätestens im zentralen CPU -Server treffen sich die verschiedensten Benutzer, und wenn dort eine maschinenweite Sicht der Datei-Welt vorherrscht, ist jeder mit allem verbunden, und aus Effizienzgründen muß sich die Individualität auf ein absolutes Minimum beschränken.
Plan 9 geht korrekt und konsequent davon aus, daß in einem Netz grundsätzlich ein Unterschied besteht zwischen einem physikalisch irgendwo gespeicherten Dateisystem und der logischen Sicht, die irgendein System dafür präsentiert. Nur -- während UNIX diese Sicht maschinenweit aufbaut, ordnet sie Plan 9 den Prozessen einzeln zu: bei UNIX ändert mount die Sicht der Datei-Welt für alle Prozesse im gesamten laufenden System, bei Plan 9 beziehen sich mount und sein Partner bind nur auf eine Gruppe von Prozessen. Der Namensraum als Sicht der Datei-Welt und anderer Ressourcen ist Eigenschaft eines Prozesses und wird bei rfork wahlweise für den neuen Prozeß kopiert oder mit dem neuen Prozeß gemeinsam benützt.
Die Arbeit am Terminal beginnt bei Plan 9 damit, daß man einen Kern lädt -- in der Regel vom Netz -- und einen Namensraum aufbaut, der auch ein Dateisystem enthält. Das Terminal beschäftigt sich dann vor allem damit, ein Window-System zu betreiben und die Namensräume für die verschiedenen Windows zu unterhalten. Verbindet man ein Window mit einem CPU -Server, so wird für die eigenen Prozesse dort der gleiche Namensraum aufgebaut, und ein Prozeß hat auf beiden Systemen die gleiche Sicht der Datei-Welt.
Gleiche Sicht muß jedoch nicht die gleiche Abwicklung bedeuten. Der CPU -Server verwendet zwar die gleichen Pfade zu Dateien wie das Terminal, aber er hat in der Regel eine wesentlich schnellere Verbindung zum gleichen File-Server. Im Terminal führt /dev/cons ziemlich direkt durch den Kern zur Terminal-Emulation in einem Window; beim CPU -Server ist /dev/cons so im Namensraum gebunden, daß es übers Netz und den richtigen Terminal-Kern ebenfalls zur Terminal-Emulation im zuständigen Window führt. Terminal oder CPU -Server, Window-System oder nicht: dank dem Unterschied zwischen Namensraum und Abwicklung kann sich ein Prozeß immer darauf verlassen, daß /dev/cons zu einer Terminal-Emulation führt, über die man Ein- und Ausgaben tätigen kann. Das Window-System 81/2 ist ein File-Server-Prozeß, der die Datei /dev/cons für den jeweiligen Namensraum eines Windows individuell zur Verfügung stellt.
Sichten auf Dateisysteme oder deren komplette Unterbäume kontrolliert zwar auch UNIX -mount, aber dessen Fähigkeiten erstrecken sich nicht auf verschiedene Interpretationen eines Geräts wie /dev/cons. Plan 9 hat zwei Systemaufrufe zur Manipulation von Namensräumen: bind für Pfade im Namensraum und mount für Verbindungen nach außerhalb.
bind(neu, alt, how);
verknüpft die existenten Pfade alt und neu. Je nach Wert von how verdeckt der Inhalt von neu den Inhalt von alt vollständig, oder es entsteht ein kombinierter Katalog mit Namen alt, in dem der Inhalt von neu vor oder nach dem Inhalt von alt gefunden wird. Außerdem kann man kontrollieren, ob neu unter diesen Umständen schreibbar sein soll. bind existiert auch als Kommando. Beispielsweise sorgt
% bind -bc /usr/axel/bin /bin
dafür, daß meine privaten Kommandos in /usr/axel/bin vor (-b) den öffentlichen Kommandos in /bin gefunden werden und daß mein Katalog geändert werden kann (-c), das heißt, daß eine Operation wie
% echo '#!/bin/rc' > /bin/now % echo date >> /bin/now % chmod +x /bin/now
ein Kommando now in meinem eigenen Katalog /usr/axel/bin anlegt, denn er ist dann der erste schreibbare Teilkatalog von /bin. Der Systemaufruf bind ersetzt durchaus die Fähigkeiten, die sonst durch PATH in der Shell realisiert werden:
% bind /386/bin /bin
sorgt dafür, daß sich nur die für die 386 Architektur vorgesehenen Kommandos in /bin befinden -- dabei bleibt allerdings noch die Frage offen, woher das Kommando bind kommen soll, das dies bewerkstelligt...
Im Kern selbst existiert ein kleiner Namensraum, der einige wenige leere Kataloge wie /bin oder /dev enthält. Außerdem bedienen die Gerätetreiber jeweils eigene Dateisysteme, deren Namen mit # und einem Buchstaben beginnen, zum Beispiel:
#b Bitmap-Gerät #c Konsole #e Environment #f Floppy #I Internet-Protokolle #l Ethernet #s Server-Registratur #w Festplatte
Wie üblich wird ein Programm init als erster Prozeß zur Ausführung gebracht. Dieses Programm interpretiert eine Datei /lib/namespace, in der eine Reihe von bind-Anweisungen stehen, zum Beispiel:
bind #c /dev
Damit enthält der Namensraum dann Pfade wie die Konsole /dev/cons, die Uhrzeit /dev/time usw.
Der Systemaufruf mount beschäftigt sich mit Verbindungen zur Außenwelt. In einem UNIX -System benötigte man dazu ursprünglich ein Gerät (Platte) mit einem Dateisystem und einen Katalog, bei Plan 9 hat dies inzwischen folgende Form:
mount(fd, old, how, ...);
fd ist eine Kommunikationsverbindung für einen sicheren Message-Strom, zum Beispiel auf der Basis einer lokalen Pipe oder von TCP oder dem neuen IL -Protokoll, einem sicheren Datagramm-Service, den Plan 9 im Internet bevorzugt verwendet. old ist ein existenter Katalog im Namensraum und how kontrolliert wie bei bind die möglichen Operationen. mount sorgt nun dafür, daß ein mount-Treiber Systemaufrufe, die sich auf Pfade beziehen, die mit old beginnen, in 9P-Messages übersetzt und über die Verbindung fd schickt. Aus den Antworten werden dann die Resultate der Systemaufrufe gebildet.
Auch für mount existiert ein Kommando. Startet man einen lokalen Server, so hinterlegt er nach Konvention seine Verbindung in einem Katalog /srv, und man kann etwa folgenden Dialog führen:
% tmpfs % mount -c /srv/tmpfs /tmp
Angenommen, tmpfs ist ein Server, der seine Verbindung als /srv/tmpfs hinterlegt, dann ist jetzt dieser Server für den kompletten Katalog /tmp zuständig.
Einen derartigen Server gibt es tatsächlich: /tmp ist in der Regel schreibgeschützt. Der Terminal-Benutzer verwendet normalerweise bind und überdeckt /tmp mit seinem eigenen Katalog für temporäre Dateien. Bootet man ein Terminal aber mit einer CD als Wurzel, so liefert das Kommando ramfs ein in-core Dateisystem für /tmp.
Es gibt eine Vielzahl nützlicher Server, die man mit mount verwenden kann, zum Beispiel:
9660srv ISO-9660-Dateisystem dossrv DOS-Dateisystem ftpfs ftp-Verbindung u9fs UNIX-Dateisystem
Da Plan 9 keine Links besitzt, können ziemlich primitive Dateisysteme ganz gut abgebildet werden. Die Technik eignet sich besser zum Import als für Produktionszwecke, denn die Namenskonventionen von DOS oder ISO -9660 müssen natürlich eingehalten werden, und der UNIX -ähnliche Zugriffsschutz von Plan 9 ist aufgehoben.
ftpfs richtet eine FTP -Verbindung mit einem beliebigen System ein, die dann per mount im Namensraum als Dateisystem für Import und Export von Dateien verwendet werden kann.
u9fs ist ein Programm, das man auf einem UNIX -System übersetzen und dann mit dem inetd-Dämon als Service anbieten kann. Ein Plan 9 System erreicht über diesen Service einen UNIX -Dateibaum und kann ihn per mount in Namensräume einbinden.
Im Lauf der Jahre (Jahrzehnte?) hat UNIX eine Vielzahl von Protokollen adoptiert. Für Dateisysteme gibt es NFS und RFS , für Terminals telnet und rlogin, zum Kopieren von Dateien ftp, rcp, kermit, tip und viele, viele andere. Rechnet man die Gateways zu globalen Netzen hinzu, so ist die Vorstellung von Babel und seinen Folgen naheliegend.
Plan 9 macht mit all dem Schluß. Zur Kommunikation mit Dateisystemen -- nah und fern -- gibt es ein einziges Protokoll, 9P, unter anderem mit folgenden Nachrichten:
attach Verbindung einrichten clone Verbindung kopieren clunk Verbindung aufgeben walk Pfadkomponente suchen stat Attribute eines Objekts wstat Attribute ändern create Objekt erzeugen remove Objekt löschen open Zugriffsart prüfen read lesen write schreiben
Die Pointe liegt nicht so sehr in der Gestaltung der Nachrichten, sondern in der Art, wie darauf aufbauend ein Großteil des Systems strukturiert wird. Lokal sind die Nachrichten Systemaufrufe im Kern, das heißt, sie werden praktisch als Funktionsaufrufe abgewickelt. mount sorgt dafür, daß diese Aufrufe als Nachrichten über eine sichere Verbindung aus dem Kern zu einem lokalen oder fremden Benutzerprozeß geschickt und die Antwort-Nachrichten als Funktionsresultate zurückgegeben werden.
Sehr entscheidend ist bei dieser Lösung, daß ein lokaler Prozeß mit Systemaufrufen über den mount-Treiber direkt mit einem fremden Server kommuniziert. Der fremde Server sieht exakt die Systemaufrufe, die sein Client verwendet, und kann entsprechend reagieren. Ist eine Verbindung aufgebaut, kann man mit 9P auf Dateisysteme, Geräte und vieles andere in einem fremden System zugreifen, als ob es lokale Ressourcen wären. Dieser Mechanismus ersetzt Dinge wie rlogin, wo auf dem fremden System eine neue Datei-Sicht entsteht, oder NFS , wo fremde Dateien lokal verwendet werden müssen.
Daß ein File-Server seine Dateien als Dateisystem anbietet, ist ja nicht überraschend, aber bei Plan 9 gibt es darüber hinaus eine Vielzahl von konventionellen Ressourcen eines Betriebssystems, die sich als Dateisysteme verkleiden und folglich lokal wie im Netz mit 9P angesprochen werden können. Eine serielle Schnittstelle besteht zum Beispiel aus zwei Dateien data und ctl. An data schickt man read und write, um Daten zu transferieren, an ctl schickt man zum Beispiel den Text b9600 per write, wenn man die Baud-Rate einstellen will. Der heißgeliebte UNIX -Aufruf ioctl entfällt.
Es gibt viele weitere Beispiele für unkonventionelle Dateisysteme, die komplizierte Portabilitätsprobleme überraschend einfach lösen. Ein Prozeß ist als Katalog repräsentiert, dessen Name die Prozeßnummer ist. Der Kern enthält einen Server für das Dateisystem aller Prozesse, das normalerweise unter /proc im Namensraum zu finden ist. Jeder Prozeß ist dort mit seiner Prozeßnummer als Katalog repräsentiert. In dem Katalog gibt es eine Reihe von Dateinamen, über die nicht nur Debugger auf interessante Aspekte zugreifen können. text repräsentiert die Datei, aus der der Prozeß gestartet wurde. Ein Debugger sucht dort die Symboltabelle und liest oder schreibt mem, den virtuellen Adreßraum. Man kann aber auch text als Kommando aufrufen, um eine Kopie des Prozesses zu starten. Liest man stat, so erhält man den Prozeß-Zustand als eine Folge von Texten mit konstanter Länge -- eine vollständig portable Version von ps kann sich darauf beschränken, diese Texte je nach Optionen zu formatieren. kill ist ein Skript für die neue Shell rc:
% kill 8\(12 | rc
kill sucht in den stat-Dateien nach dem gewünschten Kommandonamen und erzeugt dann eine Folge von echo-Aufrufen, mit denen der Text halt in die note-Datei der betroffenen Prozesse geschrieben wird und auf den Prozeß dann als Signal wirkt. Man kann sich die Ausgabe von kill im Window ansehen und von dort per cut-and-paste ausführen lassen, oder man schickt sie direkt per Pipe an rc.
Das Beispiel illustriert noch einen kleinen, aber sehr signifikanten Aspekt: Plan 9 arbeitet mit unicode, einem neuen 16-Bit Zeichensatz, und kann deshalb nahezu beliebige Zeichen zum Beispiel in Dateinamen verkraften. Bearbeitet man UNIX - oder gar DOS -Dateisysteme unter Plan 9, so kann das zu interessanten Resultaten führen.
Auch das Environment wird als Dateisystem angeboten. In /lib/namespace steht die Anweisung
bind -c #e /env
und damit kann dieses Dateisystem im Namensraum unterhalb von /env modifiziert werden. Jede Variable ist dort als Datei vertreten, Funktionen haben besondere Namen. Da verwandte Prozesse einen Namensraum gemeinsam benutzen können, kann ein Prozeß das Environment eines anderen modifizieren.
Plan 9 ist als heterogenes Netz konzipiert, in dem Architekturen wie MIPS , SPARC , i386, 68020 und andere betrieben werden. Für jede Zielarchitektur gibt es einen C-Compiler und einen Lader, und diese Programme können auf allen Architekturen betrieben werden.
Heterogenität wirft normalerweise eine Reihe von Problemen auf, die in Plan 9 sehr elegant vermieden werden. Binäre Schnittstellen wie ioctl werden in Plan 9 durch die Idee der Dateisysteme als Geräte und durch die Übergabe von Text an ctl-Dateien nahezu vollständig ersetzt. Bei einem Gerät wie bitblt ist binäre Information aus Effizienzgründen notwendig, aber sie wird in einer portablen Grafik-Bibliothek verborgen.
Beim Systemstart ist eine Environment-Variable $cputype vordefiniert, mit deren Hilfe das init-Programm in einem Katalog wie /386 gefunden wird. In /lib/namespace steht die Anweisung
bind /$cputype/bin /bin
und damit enthält der Namensraum die zuständigen binären Programme im üblichen Katalog. Der Benutzer kann den Namensraum dann analog um seine eigenen Programme für die richtige Architektur erweitern.
Übersetzungen werden mit mk abgewickelt, einer Neuauflage von make. Hierbei spielt die Variable $objtype die entscheidende Rolle, denn mk liest seine impliziten Regeln aus einer Datei /$objtype/mkfile. Die Regeln enthalten dann die richtigen Compiler- und Lader-Namen für die durch $objtype ausgewählte Architektur. Normalerweise ist das $cputype, aber man kann den Wert jederzeit ändern und damit cross-compilieren.
Damit man wirklich kreuz und quer übersetzen kann, gibt es für jede Architektur ein charakteristisches Zeichen, mit dem die verschiedenen Namen und die Kennungen der Objekte gebildet werden: 8c und 8l sind Compiler und Lader für i386, ein Montageobjekt heißt hello.8, und das übersetzte Programm ist 8.out. Wenn sich Plan 9 vollständig durchsetzt, dürften dank unicode die möglichen Zeichen auch noch lange nicht ausgehen!
Über Plan 9 haben die Urheber 1990 bei einem Treffen der UKUUG in London vorgetragen (siehe unix/mail 3/90). Im Tagungsband ( ISBN 0951318179 von EurOpen zu beziehen) findet man eine Reihe von frühen Artikeln über Plan 9, die Kommunikationsmechanismen, die C-Compiler und die Shell rc. Die Artikel wurden auch zum Report CSTR 158 der Bell Laboratories zusammengefaßt.
Mindestens Universitäten können Plan 9 auf CD unter Lizenz erhalten. Dazu gehört dann ein Band mit vielen weiteren Artikeln, deren Quellen auch auf der CD zu finden sind. Artikel und das Plan 9 Manual sind allgemein auf dem ftp-Server research.att.com in den Katalogen dist/plan9* verfügbar; das Plan 9 Protokoll 9P findet man im Kapitel 5 des Manuals.