Die Kategorie Systemstart stellt den Linux-Systemadministrator vor mehrere Aufgaben: Neben dem Einrichten des Bootloaders (Lilo oder Grub) muss er die Runlevels richtig konfigurieren, sodass Linux in verschiedenen Lagen stets die gewünschten Dienste aktiviert.
Der Start eines Linux-Systems ist ein komplexer Vorgang, an dem viele Komponenten beteiligt sind. Er beginnt beim Bootmanager (Lilo oder Grub), der den Linux-Kernel und eventuell eine virtuelle RAM-Disk in den Speicher lädt und dann die Kontrolle an die Initialisierungsfunktionen im Kernel abgibt. Hat der Kernel die wichtigsten Hardware-Komponenten erkannt und aktiviert, folgt die Abarbeitung der Startskripte, die – dem Unix-System-V-Standard folgend – das System in einen Standard-Runlevel bringen.
Booten
Mit dem Bootmanager beginnt der Bootprozess. Das Bios sucht, abhängig von den Setup-Einstellungen, im Master Boot Record (MBR) der ersten Festplatte nach einem Bootsektor, der Anweisungen für den Systemstart enthält. Diese aktivieren entweder einen Betriebssystem-Kernel oder verweisen auf einen Partition Boot Record (PBR). So oder so startet auf einem Linux-System schließlich entweder Lilo (Linux Loader) oder Grub (Grand Unified Boot Loader).
Grub ist die modernere Variante: Der Vorteil von Grub ist, dass dieser Bootloader die Standard-Dateisysteme von Linux lesen kann und ohne genaue Positionsangaben bereits Kerneldateien auf der Festplatte findet; Lilo startet dagegen nur erfolgreich, wenn es die genaue Position des Kernels kennt.
Nach jedem Kernel-Update ist darum ein neuer Aufruf von »/sbin/lilo« nötig, während Grub nur eine Aktualisierung seiner Konfigurationsdatei benötigt. Wurde der alte Kernel einfach durch den neuen überschrieben, darf auch dieser Schritt wegfallen.
Linux Loader
Listing 1 zeigt eine einfache Lilo-Konfiguration, die neben Linux auf Wunsch auch ein parallel installiertes Windows-System bootet. Einträge für das Bootmenü beginnen mit der Angabe eines Kernel-Image (»image =…«) oder mit dem Schlüsselwort »other«, dem eine Partition folgt. Der »label«-Eintrag legt die Bezeichnung für diesen Menüpunkt fest; wenn Lilo beim Booten kein Menü, sondern nur den Lilo-Prompt anzeigt, ist dies der einzugebende Name. »root« gibt an, welche Partition das Root-Dateisystem (»/«) enthält. Falls der Kernel vor dem Einbinden der Partitionen Module nachladen muss, gehören diese in eine Initial RAM-Disk, deren Pfad der »initrd«-Eintrag nennt.
|
Listing 1: |
|---|
01 boot = /dev/hda 02 change-rules 03 reset 04 read-only 05 lba32 06 prompt 07 timeout = 80 08 message = /boot/message 09 default = linux 10 11 image = /boot/vmlinuz 12 label = linux 13 root = /dev/hda8 14 vga = 792 15 initrd = /boot/initrd 16 append = "hdc=ide-scsi acpi=off" 17 18 other = /dev/hda1 19 label = windows |
|
Listing 2: |
|---|
01 default 1 02 timeout 8 03 04 title Linux 05 kernel (hd0,5)/boot/vmlinuz root=/dev/sda6 splash=silent 06 initrd (hd0,5)/boot/initrd 07 08 title Windows 09 root (hd0,0) 10 chainloader +1 |
Fremde Betriebssysteme bringen meist einen eigenen Bootloader mit, so auch Windows. Um solche Systeme starten zu können, legt der Admin einen »other«-Eintrag an, der die zu aktivierende Partition enthält. Neben einem »label«-Eintrag für die Identifizierung sind dann keine weiteren Optionen nötig.
Das Kommando »/sbin/lilo« richtet Lilo ein, auf Basis der Konfigurationsdatei »/etc/lilo.conf«. Dieser Schritt ist nach jeder Änderung am Kernel oder an der Initial RAM-Disk zu wiederholen, weil Lilo die physikalischen Adressen dieser Dateien fest im Bootloader-Code verankert. Wohin das Programm den Bootloader schreibt, steht auch in der Konfigurationsdatei, und zwar gleich in der ersten Zeile: »boot = /dev/hda«, das ist der MBR der ersten Platte.
Grand Unified Boot Loader
Die Lilo-Alternative Grub verwendet für die wichtigsten Einstellungen die Datei »/boot/grub/menu.lst«, die anders als die Lilo-Datei aufgebaut ist. Neben der anderen Syntax liegt die größte Abweichung in der Benennung der Partitionen: Während Lilo mit den üblichen Gerätedateinamen (etwa »/dev/hda1«) arbeitet, benutzt Grub ein eigenes Schema: »(hd0)« ist die erste Festplatte, »(hd1)« die zweite und so weiter.
|
LPI-Aufgabengruppen |
|---|
|
Das Linux Professional Institute gliedert die Prüfungsfragen in Aufgabengruppen. Dieser Artikel erklärt die Abschnitte:
|
Partitionen nummeriert Grub ebenfalls ab 0 durch, wobei er ansonsten die gleiche Zählweise verwendet. Die erste logische Partition in einer erweiterten Partition erhält also die Nummer 4 (5 minus 1). Die Notation für eine Partition ist »(hdX,Y)«, so wird aus »/dev/hda6« beispielsweise »(hd0,5)«.
In welcher Weise Grub die Platten durchnummeriert, legt die Datei »/boot/grub/device.map« fest, die im Falle zweier Festplatten folgenden Aufbau hat:
(hd0) /dev/sda (hd1) /dev/hda
Zur Ersteinrichtung von Grub dient das Kommando »/usr/sbin/grub-install«, das als Argument die Gerätedatei der Festplatte oder der Partition erhält, in deren Bootsektor es den Bootloader schreiben soll. Meist ist das die erste Festplatte, also »/dev/hda« oder »/dev/sda«. Dabei ist »sda« nicht nur für SCSI-Platten die richtige Wahl, auch SATA-Platten sprechen die meisten Linux-Versionen über die SCSI-Gerätenamen an.
Bootoptionen
Mit beiden Bootmanagern ist es möglich, dem Kernel Bootoptionen zu übergeben. Bei Lilo ist dafür die Zeile
append = "..."
zuständig, die Optionen durch Leerzeichen getrennt aufnimmt (im Beispiel-Listing 1 »append = “hdc=ide-scsi acpi=off”«). Grub-Benutzer hängen Optionen, ebenfalls durch Leerzeichen getrennt, einfach an die »kernel«-Zeile an, zum Beispiel:
kernel /boot/vmlinuz-2.6.18.2-34-default root=/dev/hdc7 hda=ide_scsi vga=0x31a resume=/dev/hdc6 splash=silent showopts
Beim Booten ist es möglich, diese Optionen noch zu beeinflussen. Grub ist in diesem Punkt besonders flexibel: Über die Grub-Shell (Abbildung 1) ist nicht nur das Ändern der Kernel-Bootoptionen möglich, sondern alle Einstellungen stehen zur Disposition.
Syslog
Während des Bootvorgangs geben sich Linux-Systeme recht auskunftfreudig und informieren etwa über die erkannte (und initialisierte) Hardware – sofern der Distributionshersteller diese Ausgaben nicht mit einer grafischen Fortschrittsanzeige verdeckt. Dann führt meist der Druck auf eine Funktionstaste zur Anzeige der Meldungen. Doch auch lange nach dem Booten stehen die ersten Systemausgaben noch zur Verfügung: Das Tool »dmesg« zeigt sie an (Abbildung 2).
Mit »dmesg« arbeiten ist aber nur erforderlich, um die ersten Meldungen unmittelbar nach dem Aktivieren des Kernels zu betrachten, ansonsten ist für das Logging der Syslog-Daemon (»syslogd« oder »syslog-ng«) zuständig, der Systemereignisse in verschiedene Logdateien schreibt. Die erste Anlaufstelle für die Suche nach Logdaten ist »/var/log/messages«, je nach Distribution aber auch »/var/log/syslog«.
Runlevels
Über das Runlevel-Konzept, das Linux von Unix System V übernommen hat, ist es möglich, einen Linux-Rechner für verschiedene Aufgaben vorzukonfigurieren und je nach Anwendungszweck in den passenden Runlevel zu booten. In der Datei »/etc/inittab« legt die Zeile
id:5:initdefault:
den Standard-Runlevel (im Beispiel »5«) fest, die üblichen Runlevels haben die Nummern 0 bis 6. Dabei sind 0 und 6 für das Herunterfahren (siehe Kasten “Shutdown-Methoden”) und den Reboot reserviert, die übrigen sind prinzipiell frei konfigurierbar.
|
Shutdown-Methoden |
|---|
|
Welcher der folgenden Befehle fährt den Rechner herunter und schaltet ihn aus?
Alle drei Befehle haben diese Wirkung. »shutdown« ruft »init« auf, um die Aufgabe zu erledigen, und »halt« benutzt »shutdown«; der schnellste Weg führt also über »init 0«. Für den Neustart des Rechners lauten die entsprechenden Befehle »shutdown -r now«, »reboot« und »init 6«. |
Alle Linux-Distributionen richten einen oder mehrere Runlevels für Standardaufgaben ein: Runlevel 1 dient meist der Systemkonfiguration oder -reparatur, hier fährt das System im Single User Mode hoch. Es gibt dann keine virtuellen Konsolen und kein X11, die Dienste starten nicht, auch darf sich nur »root« am System anmelden. Die meisten Distributionen verwenden Runlevel 5 für ein Standard-Desktopsystem mit aktivierten Netzwerkdiensten und grafischer Oberfläche und Runlevel 3 für ein fast identisches Setup, bei dem nur der Start des X-Servers ausbleibt. Debian geht hier einen eigenen Weg und nutzt im Normalbetrieb den Runlevel 2.
Welche Schritte das System beim Start in einem Runlevel durchführt, legen Einträge in den Verzeichnissen »/etc/rc.d/rcX.d«, »/etc/rcX.d« beziehungsweise »/etc/init.d/rcX.d« fest, wobei »X« für einen der Runlevels steht. (Der genaue Pfad hängt von der Distribution ab.) Für Nummer 5 enthält etwa ein Suse-System im Verzeichnis »/etc/init.d/rc5.d« die in Abbildung 3 gezeigten Einträge.
Alle Dateien sind symbolische Links auf Shellskripte im Verzeichnis »/etc/init.d«, die Namen der Links beginnen stets mit »S« (Startskripte) beziehungsweise »K« (Stoppskripte, Kill).
# cd /etc/init.d/rc5.d # ls -l *cups* lrwxrwxrwx 1 root root 7 2007-01-09 11:35 K10cups -> ../cups lrwxrwxrwx 1 root root 7 2007-01-09 11:35 S12cups -> ../cups
Abhängig davon, ob ein Linkname mit »S« oder »K« beginnt, erhält das Skript beim Aufruf das Argument »start« oder »stop«. Daran erkennt es, ob es einen Dienst starten oder beenden soll.
Starten und stoppen
Der Aufbau der meisten Skripte ist ähnlich; über eine Fallunterscheidung führen sie für »start«, »stop« und meist noch einige weitere Parameter verschiedene Befehle aus. Zu den zusätzlichen Parametern, die viele Skripte verstehen, gehören »restart« und »status«. Der erste führt zu einem Neustart eines bereits laufenden Dienstes, während der zweite ausgibt, ob der Dienst läuft oder nicht. Den Neustart interpretieren verschiedene Dienste als Neu-Einlesen der Konfigurationsdatei. Das ist natürlich viel schneller, als einen Daemon zu beenden und neu zu starten.
Um einen Dienst für einen bestimmten Runlevel zu aktivieren oder deaktivieren, legt der Administrator entsprechende symbolische Links an oder löscht sie. Die Zahlen, die auf »S« oder »K« folgen, definieren die Reihenfolge, in der das System die Skripte ausführt. Wer die Links nicht von Hand manipulieren mag, findet bei vielen Distributionen das Tool »chkconfig« [2], das diese Arbeit automatisiert.
Eigene Startskripte
Die meisten Anwendungen, die beim Systemstart einen Service im Netz verankern wollen, bringen schon fertige Startskripte mit, die es nur noch in die Verzeichnishierarchie zu integrieren gilt. Ist das ausnahmsweise nicht der Fall, schreibt der Administrator schnell ein eigenes Startskript.
Listing 3 zeigt das Gerüst für eine solche Datei: Sie hält neben den Optionen »start« und »stop« für die Runlevel-Verwaltung auch »restart« und »status« bereit. Der »restart«-Code beendet den Dienst und startet ihn gleich wieder neu, indem er die Skriptdatei erst mit dem Parameter »stop« und dann mit »start« aufruft. Alternativ wäre ein Befehl wie »killall -HUP xyzd« denkbar, wenn es möglich ist, das Programm über ein Signal zum Neueinlesen seiner Konfiguration zu bewegen, wie dies etwa bei dem Internet-Daemon »xinetd« der Fall ist.
|
Listing 3: Gerüst für |
|---|
01 #!/bin/bash 02 case "$1" in 03 start) 04 echo "Starting xyz server" 05 /usr/bin/xyzd & 06 pidof xyzd > /var/run/xyzd.pid 07 ;; 08 stop) 09 echo "Shutting down xyz server" 10 killall xyzd 11 rm /var/run/xyzd.pid 12 ;; 13 restart) 14 $0 stop 15 $0 start 16 ;; 17 status) 18 if /sbin/checkproc /usr/bin/xyzd 2> /dev/null 19 # if pidof xyzd > /dev/null 20 then 21 echo "Server xyz is up" 22 else 23 echo "Server xyz is down" 24 fi 25 ;; 26 esac |
Es ist üblich, für laufende Dienste im Verzeichnis »/var/run« eine Datei anzulegen, in der die Prozess-ID des Servers enthalten ist; beim Beenden entfernen Startskripte diese Datei wieder. Das Beispielskript folgt in den Zeilen 6 und 11 dieser Konvention.
Das in Zeile 18 aufgerufene Tool »checkproc« testet, ob es einen Prozess gibt, dessen Programmdatei den übergebenen Dateinamen hat. Da nicht jede Linux-Distribution »checkproc« enthält, zeigt die auskommentierte Zeile 19 eine Alternative, die »pidof« verwendet.
Nicht alles via Startskript
Manche Programme startet Linux auch gleich direkt aus der Datei »/etc/inittab« heraus, beispielsweise die virtuellen Textkonsolen. Für solche Abläufe gibt es Einträge der folgenden Form:
1:2345:respawn:/sbin/mingetty --noclear tty1 2:2345:respawn:/sbin/mingetty tty2
Alle Zeilen in der »inittab«-Datei folgen dem gleichen Aufbau: Sie bestehen aus je drei durch »:« getrennten Feldern. Das erste Feld enthält einen eindeutigen Identifier für diese Zeile, das zweite Feld listet alle Runlevels auf, in denen »init« den Befehl im letzten Feld starten soll. Die beiden Beispielzeilen führen also dazu, dass beim Starten in einem der Runlevels 2 bis 5 (»2345«) auf den Terminals »tty1« und »tty2« Login-Prozesse (»mingetty«) starten.
Runlevel ändern
Um im laufenden Betrieb in einen anderen Runlevel zu wechseln, verwendet der Administrator das »init«-Kommando. Dessen einziger Parameter ist die Nummer des gewünschten neuen Runlevels. Bei Bedarf ist über die Option »-t Sekunden« auch das Einstellen einer Verzögerung möglich.
Beim Wechsel des Runlevels führt »init« zunächst Stopp- und dann Startskripte aus. Bei den Startskripten ist klar, um welche es sich handelt: Es sind die des neuen Runlevels. Was die Stoppskripte angeht, ist die Situation hingegen ziemlich uneinheitlich. Einige Linux-Distributionen führen jene Stoppskripte aus, die im Verzeichnis des alten Runlevels liegen, während andere die Stoppskripte des neuen Runlevels einsetzen (siehe Kasten “Runlevel-Wechsel”).
|
Runlevel-Wechsel |
|---|
|
Für den Runlevel-Wechsel ist das Skript »/etc/rc.d/rc« zuständig, es steuert den Übergang vom alten zum neuen Runlevel. Je nach Distribution ist der Ablauf unterschiedlich. Debian-Systeme führen zunächst die Stoppskripte des neuen (!) und dann die Startskripte des neuen Runlevels aus: runlevel=$RUNLEVEL previous=$PREVLEVEL for i in /etc/rc$runlevel.d/K[0-9][0-9]* [...] startup $i stop [...] for i in /etc/rc$runlevel.d/S* [...] startup $i start [...] In das »rc.d/rcX.d«-Unterverzeichnis des alten Runlevels guckt »rc« also gar nicht hinein. Die meisten anderen Distributionen führen dagegen die Stoppskripte für den alten Runlevel zuerst aus und danach folgen die Startskripte für den neuen Runlevel. Als Beispiel ein Ausschnitt aus »/etc/rc.d/rc« auf einem System mit der Suse-Version 10.2:
runrc=/etc/init.d/rc${RUNLEVEL}.d
prerc=/etc/init.d/rc${PREVLEVEL}.d
for i in $prerc/K${rex}*; do
[...]
$i stop; status=$?
[...]
for i in $runrc/S${rex}*; do
[...]
$i start; status=$?
[...]
Es ist wichtig, diesen Unterschied zu beachten, damit eine korrekte Konfiguration neuer Systemdienste möglich ist. |
Fazit
Kenntnisse über den Startvorgang eines Linux-Systems sind wichtig, denn er bietet viele Ansatzpunkte für Korrekturen, wenn der Rechner nicht rund läuft. Das LPI versieht das Thema mit einer Gewichtung von 3, für die meisten Themen liegt sie zwischen 1 und 5 (Höchstwert ist 10). Um die Runlevel- und Bootmanager-Konfiguration zu beherrschen, empfiehlt sich Experimentieren mit den Konfigurationsdateien und Tools.
|
Infos |
|---|
|
[1] LPI-Seite mit den Prüfungsinhalten: [http://www1.lpi.org/de/obj_102.html] [2] Hans-Georg Eßer, “Mit den Dienern reden”: EasyLinux 01/07, S. 126 [3] Nico Dietrich, Dirk von Suchodoletz, “Schnelles Booten mit Upstart, einem Ersatz für das betagte Sys-V-Init”: Linux-Magazin 02/07, S. 72 [4] Jens-Christoph Brendel, “Massenstart – Boot-Beschleuniger im Vergleich”: Linux-Magazin 11/05, S. 64 [5] Anke Börnig, “Platten-Aufteilung”: Linux-Magazin 09/06, S. 66 |
Copyright © 2002 Linux New Media AG




