Nach dem Einschalten zeigt ein Computer viele kryptische Nachrichten an, bevor er sich mit dem Login-Bildschirm bereit meldet. Wir zeigen, was im Hintergrund des Boot-Vorgangs abläuft.
Der Boot-Vorgang hat schon etwas Faszinierendes. Am Anfang steht ein Haufen Silizium mit einem winzigen Progrämmchen im BIOS, das gerade einmal ein ebenso winziges Programm von der Festplatte nachladen kann. Dann passiert irgend etwas, und am Ende bietet eine vollwertige Workstation ihre Dienste an – mit der Herrschaft über komplexe Hardware-Merkmale und Peripheriegeräte, mit einer Netzwerk-Anbindung und zahlreichen laufenden Servern, kurz – ein richtiges Linux-System.
Die wesentliche Aufgabe des Boot-Vorgangs ist, ganz einfach zusammengefasst, die Initialisierung der Hard- und Software. Zuerst werden die Datenstrukturen des Betriebssystemkerns vorbereitet, anschließend die vorhandene Hardware rudimentär geprüft und alle passenden Treiber gestartet. Damit schafft das System vor allem die Voraussetzung für das Nachladen des eigentlichen Betriebssystems. Wenn BIOS und Boot-Sektor ihre Aufgabe getan haben, geht das Wissen über die Festplatte nämlich zunächst wieder verloren.
Anschließend führt Linux bereits normale Programme aus. Diese beschäftigen sich am Anfang ebenfalls noch mit der Hardware: Jetzt werden exotischere Peripheriegeräte initialisiert. Daneben finden Wartungsaufgaben statt, z. B. prüft das System die Festplatte ganz kurz auf Fehler oder räumt Bereiche mit temporären Daten auf. Schließlich werden die diversen Daemons und Server-Dienste gestartet, die ein Unix-System erst richtig zum Leben erwecken. Dieses geschieht in einer genau abgestimmten und sorgfältig durchdachten Reihenfolge.
Kernelspace und Userspace
Bevor wir uns die einzelnen Schritte im Detail ansehen, sollten wir noch eine wichtige Unterscheidung treffen: Wo und wie werden die einzelnen Funktionen ausgeführt? Davon hängt schließlich ab, ob und wie leicht wir die Vorgänge manipulieren können.
Die allerersten Schritte nach dem Einschalten gehören noch gar nicht in den Aufgabenbereich von Linux. Das BIOS ist für Normalsterbliche ohnehin unantastbar; allenfalls installiert man einmal ein Update. Auch das erste vom BIOS geladene Programm aus dem Boot-Sektor ist noch kein Teil des eigentlichen Betriebssystems. Dieser so genannte Bootloader hat lediglich die Aufgabe, das Betriebssystem zu starten. Bekannte Exemplare dieser Gattung sind neben dem Bootloader von Windows NT die in der Linux-Welt verbreiteten Programme LILO und GRUB. Allen gemeinsam: Sie laden einen Betriebssystemkern und starten ihn.
Bei allen folgenden Aktionen gibt es bei Unix-Betriebssystemen zwei grundlegend verschiedene Möglichkeiten: Funktionen können im Kernel- oder im Userspace ablaufen. Zu den Kernel-Funktionen gehört beim Booten die Initialisierung der wichtigsten Hardware-Treiber. Was im Kernel passiert, lässt sich nur durch eine Änderung des Linux-Quelltextes und eine Neuübersetzung modifizieren. Stoff für echte Hacker!
Mit Userspace meint man alles, was durch “normale” Programme oder Skripte gesteuert wird. Natürlich interagieren die beiden: Wenn ein Programm aus dem Userspace zum Beispiel auf die Festplatte zugreifen will, ruft es eine entsprechende Funktion aus dem Kernel auf. Und bei Linux wird die Sache durch die Kernel-Module besonders kompliziert. Module sind zwar eindeutig Kernel-Funktionen, doch sie werden durch Programme aus dem Userspace geladen und kontrolliert.
Hardware
Die ersten Meldungen, die an uns vorbeiflimmern, werden also vom Kernel generiert – wir werden uns in diesem Artikel nicht weiter um diese kümmern; schließlich können wir sie ohne tiefes Hintergrundwissen nicht beeinflussen.
Nach zehn oder zwanzig Sekunden ist der Kernel jedoch mit seinen Vorbereitungen fertig und ruft das erste Programm aus dem Userspace auf. Hierbei handelt es sich bei den heute üblichen Distributionen oft um ein ganz kurzes Skript namens linuxrc, das auf einer RAM-Disk gemeinsam mit ein paar Modulen abgelegt ist und noch vom Boot-Sektor geladen wurde. linuxrc soll Treiber und Funktionen laden, die zwar für den weiteren Boot-Vorgang unerlässlich sind, aber nicht in den Kernel einkompiliert wurden. Dazu können Treiber für eine SCSI-Festplatte, verschlüsselte Dateisysteme oder essentielle Netzwerktreiber gehören.
Die Funktionalität rund um linuxrc ist optional – wenn bei der Übersetzung des Kernels bereits alle notwendigen Treiber fest einkompiliert wurden, also keine Module nachgeladen werden müssen, verzichtet man auf linuxrc einschließlich der RAM-Disk. Sie selbst werden sich kaum jemals um dieses Skript kümmern, da das Installationsprogramm Ihrer Distribution ein solches Skript mit allen für Ihren Computer notwendigen Befehlen geschrieben und eine passende RAM-Disk erstellt hat. Wenn Sie Ihren Kernel später einmal verändern sollten, erleichtern Sie sich die Arbeit, indem Sie alle lebensnotwendigen Funktionen fest einkompilieren und nicht in Module auslagern.
Am Ende dieses Abschnittes muss ein wichtiges Ziel erreicht sein: Die weiteren Bestandteile können von der Festplatte nachgeladen werden, d. h. zumindest die so genannte Root-Partition mit den Verzeichnissen /bin, /sbin, /lib, /etc, /dev und /tmp muss zugänglich sein. Sie ist in der Regel noch nicht voll vorbereitet; beispielsweise sind Schreibzugriffe meist noch verboten. Aber zumindest kann der Kernel gezielt auf vordefinierte Abschnitte dieser Partition zugreifen.
init: Die Mutter aller Prozesse
Wenn die Hardware soweit vorbereitet ist, startet der Kernel den eigentlichen Boot-Vorgang aus Benutzersicht. Egal was später umkonfiguriert wird: Das erste Programm, das gestartet wird, heißt immer /sbin/init. Alles, was auf einem Unix-System passiert, geht letztlich auf init zurück; es startet alle weiteren Programme und Skripte.
Leider wird es an dieser Stelle schon wieder kompliziert. Zwar ist klar definiert, dass der erste gestartete Prozess init heißt, aber es ist längst nicht so klar, wie dieses init nun genau arbeitet. Unter Linux gibt es zwei verbreitete Varianten. Die erste heißt simpleinit und arbeitet im Prinzip nur ein einfaches Skript ab. Die zweite nennt sich SysVinit und wird bei den gängigen Distributionen, wie z. B. Red Hat, SuSE oder Mandrake, verwendet.
Der Name SysVinit leitet sich von Unix System V ab – eine ähnliche Funktionsweise von init finden Sie daher auch auf anderen Unix-Distributionen, wie z. B. bei Solaris. Die Konfiguration von SysVinit ist zweigeteilt; die eigentliche Konfigurationsdatei heißt /etc/inittab. Sie enthält eine Tabelle, die bestimmten Ereignissen Programme zuordnet. Wenn ein Ereignis eintritt, wird ein Programm gestartet. Beispiele für solche “Ereignisse” sind “Boot-Vorgang”, “Übergang zum vernetzen Arbeiten” oder “Computer soll ausgeschaltet werden”. Der zweite Teil der init-Konfiguration besteht in den so genannten init-Skripten, auf die wir gleich noch näher eingehen.
Runlevel
Ein wichtiges Konzept des SysVinit sind die so genannten Runlevel. Ein Runlevel beschreibt einen Betriebszustand eines Unix-Systems. Die üblicherweise definierten Zustände sind in Tabelle 1 zusammengefasst.
Tabelle 1: Typische Runlevel eines Unix-Systems
| Runlevel | Zustandsbeschreibung |
|---|---|
| 0 | Das System wird gerade angehalten. |
| 1 | Das System wird gewartet (“Single User Mode”; Einzelplatzmodus, nur der Administrator kann arbeiten). |
| 2 | Das System ist nur eingeschränkt funktionsfähig, z. B. fehlen Netzwerk-Services oder der Grafikmodus. |
| 3 | Das System ist voll funktionsfähig. |
| 4 | Der Runlevel ist frei für eigene Einstellungen. Meistens wird man bei Änderungswünschen jedoch nicht den Runlevel 4 neu definieren, sondern einen bestehenden Runlevel entsprechend modifizieren. |
| 5 | Das System ist voll funktionsfähig. Ob für diesen Zustand Runlevel 3 oder 5 benutzt wird, hängt von Ihrer Distribution ab. |
| 6 | Das System wird gerade für einen Reboot vorbereitet. |
/etc/inittab
Die Datei inittab steuert das Verhalten von init und enthält Kommentare, die mit einem Doppelkreuz # beginnen, sowie tabellarische Anweisungen. Einen kurzen Auszug mit den allerwichtigsten Einträgen sehen Sie in Listing 1.
Listing 1
Die wichtigsten Einträge aus
/etc/inittab
# Voreingestellter Runlevel nach dem Einschalten id:3:initdefault: # Vorbereitung si::sysinit:/etc/rc.d/rc.sysinit # Die einzelnen Runlevel l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # Was passiert bei Strg-Alt-Entf? ca::ctrlaltdel:/sbin/shutdown -t3 -r now # Login für den Textmodus 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 # Login für den Grafikmodus x:5:respawn:/usr/X11R6/bin/xdm -nodaemon
Jede Tabellenzeile enthält vier Einträge, die durch Doppelpunkte voneinander getrennt sind. An erster Stelle stehen ein oder zwei Buchstaben oder Ziffern als mnemonisches Kürzel für den betreffenden Eintrag. Danach kann durch ein oder mehrere Ziffern festgelegt werden, dass dieser Eintrag nur in den angegebenen Runleveln Gültigkeit besitzt. Beispielsweise wird mingetty in Listing 1 nur in den Runleveln 2 bis 5 aufgerufen; die Zeile mit shutdown gleich davor macht hingegen keine Einschränkung des Runlevels und gilt daher immer.
Der dritte Eintrag jeder Zeile darf ein Schlüsselwort für zusätzliche Bedingungen enthalten. Am häufigsten benutzt man hier respawn, d. h. das zugehörige Programm wird immer wieder neu gestartet, sobald es sich beendet. Ein mingetty beispielsweise sorgt für eine Login-Aufforderung. Sobald ein Benutzer seine Sitzung beendet, wird der mingetty erneut gestartet und steht für den nächsten Anwender zur Verfügung.
Eine Alternative ist once, d. h. ein Programm wird nur ein einziges Mal beim Erreichen des Runlevels aufgerufen. Dieser Betriebsmodus ist für Daemons und andere Programme notwendig, die nach dem Start sofort in den Hintergrund wechseln und dort weiterlaufen. Wenn init diese Programme gleich wieder starten würde, wären binnen kürzester Zeit eine größere Menge von diesen gleichzeitig aktiv – der Computer würde abstürzen. Der Nachteil ist, dass init eine vorzeitige Beendigung solch eines Programmes nicht bemerkt.
Im Listing sehen Sie außerdem ein paar besondere Schlüsselwörter: initdefault legt fest, welcher Runlevel beim Boot-Vorgang ausgewählt wird; sysinit beschreibt ein Programm, das nur beim Booten ausgeführt wird. Zeilen mit wait enthalten Skripte, die bei jedem Wechsel in den betreffenden Runlevel ausgeführt werden. Sie halten unpassende Programme an, z. B. wird vor dem Reboot des Computers ein eventuell laufender Webserver heruntergefahren. Umgekehrt starten die wait-Skripte auch neue Software, die für den jeweiligen Betriebszustand benötigt wird.
Die vierte Spalte der inittab-Einträge schließlich beschreibt das jeweilige Programm einschließlich seiner Parameter, das aufgerufen wird, sofern alle Bedingungen erfüllt sind.
Aktivitäten von <C>init<C>
In einer typischen Konfiguration, wie sie hier gezeigt ist, führt init nach dem Booten drei Aufgaben aus:
- Als Erstes werden durch das Skript
rc.sysinitgrundlegende Einstellungen vorgenommen. - Zweitens wechselt
initin den durchinitdefaultfestgelegten Runlevel, wodurch alle möglichen Daemons und Server-Programme gestartet werden. - Drittens wird Software für Login-Prompts gestartet. Je nach angeschlossener Peripherie können das normale Logins im Text- oder Grafikmodus sein, oder auch die Initialisierung eines Modems oder einer ISDN-Karte. Lediglich Netzwerk-Logins sind Aufgabe eigener Daemons.
Die Grundkonfiguration durch rc.sysinit beinhaltet bei den meisten Distributionen die folgenden Aufgaben: Die Uhr des Betriebssystems wird nach der Hardware-Uhr gestellt; die Festplatten werden auf Fehler überprüft und anschließend gemountet. Die Swap-Partition wird aktiviert; gegebenenfalls wird bereits ein Tastaturtreiber geladen für den Fall, dass beim Festplatten-Check ein Fehler auftritt und der Administrator per Hand eingreifen muss. Das Netzwerk-Subsystem wird vorbereitet, indem z. B. der Rechnername gesetzt wird. Hinzu kommen noch Aufräumaktionen aller Art. Alle diese Aktivitäten sind sehr stark von der Distribution abhängig – frühere Linux-Systeme beschränkten sich hier im wesentlichen auf die Uhr, den Hostname und den Festplatten-Check.
Wie beschreibt man einen Runlevel?
Wir wissen jetzt, dass beim Boot-Vorgang ein Programm namens init die aufgerufenen Programme kontrolliert. Wir kennen die Konfigurationsdatei /etc/inittab, die unter anderem festlegt, in welchen Runlevel das System beim Booten wechselt. Aber woher weiß der Computer, wie solch ein Runlevel aussieht?
Für jeden Runlevel von 0 bis 6 (siehe Tabelle 1) existiert ein eigenes Verzeichnis, das den Runlevel detailliert beschreibt. Auf einem “normalen” Linux-System heißt dieses Verzeichnis für Runlevel 5 beispielsweise /etc/rc.d/rc5.d, aber der genaue Name kann je nach Distribution abweichen – verbreitete Alternativen sind /etc/rc5.d oder auch /etc/init.d/rc5.d.
In diesen Verzeichnissen stehen die so genannten Init-Skripte. Jedes davon kontrolliert ein Subsystem Ihres Computers, z. B. die Uhr, den Mail-Server oder den Drucker-Spooler. Alle Init-Skripte folgen einer einheitlichen Syntax: Beim Aufruf wird genau ein Argument übergeben, entweder start oder stop, je nachdem, ob der betreffende Dienst gestartet oder angehalten wird. Viele Skripte kennen noch weitere Argumente für andere Aufgaben, aber jedes Init-Skript weiß über start und stop Bescheid. So kann init jeden Teil des Systems vollautomatisch kontrollieren.
Beim Wechsel in einen Runlevel (siehe auch Abbildung 2) ruft init alle Init-Skripte im zugehörigen Runlevel-Verzeichnis auf. Wenn Sie in den Runlevel 2 wechseln, werden alle Skripte aus /etc/rc.d/rc2.d gestartet. Werfen Sie einen Blick in dieses Verzeichnis:
$ ls /etc/rc.d/rc2.d K09sshd S16apmd S75keytable K75netfs S20random S90xfs K89portmap S30syslogd S99local S08ipchains S40crond S10network S60lpd
Der Name jedes Skriptes besteht aus drei Bestandteilen:
- Ein Buchstabe “K” oder “S” entscheidet, ob das Subsystem angehalten (“geKillt”) oder geStartet wird.
- Eine zweistellige Zahl von 00 bis 99 legt die Reihenfolge fest, in der die Skripte aufgerufen werden.
- Ein Kürzel beschreibt das Subsystem für menschliche Administratoren.
Das im Beispiel gezeigte Runlevel-Verzeichnis wird demnach die Dienste sshd, netfs und portmap anhalten. Anschließend initialisiert es diverse Subsysteme neu, wodurch zum Beispiel Netzwerkeinstellungen korrigiert oder ein Tastaturtreiber geladen werden. Aktuelle Distributionen rufen ein Subsystem dabei nicht noch einmal auf, wenn es bereits läuft; es kommt also nicht zu doppelten Daemons.
Der gute Stil der Unix-Systemadministration fordert übrigens, dass die init-Skripte der Runlevel-Verzeichnisse Links in ein anderes Verzeichnis sind. Die eigentlichen Skripte stehen dann z. B. in /etc/init.d oder /etc/rc.d/init.d. Wenn Sie ein dadurch beschriebenes Subsystem für einen bestimmten Runlevel aktivieren möchten, legen Sie einfach einen neuen Link an:
# cd /etc/rc.d/rc5.d # ln ../init.d/mysql S97mysql # cd ../rc0.d # ln ../init.d/mysql K02mysql # cd ../rc1.d # ln ../init.d/mysql K02mysql # cd ../rc6.d # ln ../init.d/mysql K02mysql
Der Vorteil: Änderungen am init-Skript wirken sich sofort auf alle Kopien aus; es kommt zu keinem Versions-Wirrwarr. Am Beispiel sehen Sie noch einen weiteren wichtigen Tipp: Wenn Sie einen neuen Start-Link anlegen, erstellen Sie am besten gleich die symmetrischen Stopp-Links für die Runlevel 0, 1 und 6.
Ausblick
Wenn Sie gerade ein Stündchen Zeit haben, sehen Sie sich doch einmal die init-Skripte für die wichtigsten Runlevel an. Dabei lernt man eine Menge über das System – und nebenbei auch über die Programmierung mit der Shell. Eine kleine Warnung an dieser Stelle: Mit init ist nicht gut Kirschen essen. Ein Fehler in der Boot-Konfiguration kann einen Computer lahmlegen. Und das bemerkt man erst am nächsten Morgen, wenn man den Rechner das nächste Mal einschaltet.
Glossar
-
BIOS
-
Das BIOS (Basic Input/Output System) ist meistens in einem programmierbaren Festspeicher (in aktuellen Geräten sind das EEPROMs) auf der Hauptplatine des Computers gespeichert. Es enthält neben dem Setup-Programm zur Steuerung einiger Hardware-Funktionen die Boot-Logik des PCs. Diese liest den Boot-Sektorder Festplatte ein, also ein paar Kilobyte Daten, und führt ihn aus – fertig. Alles andere muss die Software aus dem Boot-Sektor tun. Theoretisch enthält das BIOS auch noch Gerätetreiber für DOS-basierte Betriebssysteme, doch werden diese unter Linux in der Regel nicht benutzt.
-
Boot-Sektor
-
Am Anfang der Festplatte liegt ein Boot-Sektor, der ein Programm enthalten kann, das für das Laden des Betriebssystems zuständig ist. Es gibt einen Haupt-Boot-Sektor pro Festplatte, den Master Boot Record (MBR), sowie einen zusätzlichen Boot-Sektor für jede einzelne Partition. Der MBR wird meist für die Auswahl zwischen den installierten Betriebssystemen benutzt, oder er lädt seinerseits den Boot-Sektor einer Festplattenpartition. Dieser startet das eigentliche Betriebssystem.
-
Links
-
Links sind ein wichtiges Konzept bei Unix-artigen Betriebssystemen. Anstatt eine Datei zu kopieren, erstellt man einen neuen Verzeichniseintrag, der auf die ursprüngliche Datei zeigt. Wenn ein Programm diesen neuen Eintrag öffnet, sieht es den Inhalt der ursprünglichen Datei. Dabei unterscheidet man harte von symbolischen Links – bei harten Links ist die Kopie vom Original überhaupt nicht mehr zu unterscheiden, wohingegen symbolische Links wirklich nur Zeiger sind.






