Die Runlevels und die Init-Skripte

oder: Wie steuere ich die Aktivierung verschiedener Dienste

Für alle, die mit MacOS vertraut sind, lassen sich die Runlevels wohl am ehesten mit verschiedenen Sets im Kontrollfeld Erweiterungen ein/aus vergleichen. Wie dort kann man mit Hilfe von Runlevels verschiedene Gruppen von Diensten[1] ein und ausschalten. Natürlich ist das ganze anders organisiert als bei MacOS. Aber fangen wir klein an.

Die Init-Skripte

Zu jedem Dienst[1], der über die Runlevel gesteuert werden soll, muss ein Init-Skript existieren[2]. Diese Init-Skripte sind normale (Bourne-) Shell-Skripte und liegen im Verzeichnis /etc/rc.d/init.d/ (bzw. bei der SuSE[3] direkt in /etc/rc.d/ ). Aufgerufen werden diese Skripte immer mit einem Parameter, mit dem bestimmt wird, was dieses Skript tun soll.

Grundsätzlich immer dabei sind start zum Starten eines Dienstes und stop zum Anhalten des Dienstes. Daneben bieten einige Skripte auch noch restart (zum Neustarten des Dienstes), reload (bewirkt das der Dienst seine Konfiguration neu einliest, z.B. nachdem dort etwas geändert wurde) oder status(ist der Dienst aktiv).

Die Runlevel

Nun ein Runlevel ist nun eine Zusammenstellung von Diensten, ähnlich verschiedener Sets im MacOS-Kontrollfeld Erweiterungen ein/aus (aber das hatte wir ja schon). Wenn der Runlevel gewechselt wird, werden alle (d.h. alle bei denen es darauf ankommt) Dienste des alten Runlevels angehalten. Dazu werden die entsprechenden Initskript mit dem Parameter stop aufgerufen. Danach werden alle Dienste des neuen Runlevels gestartet, indem die passenden Init-Skripte mit start aufgerufen werden.

Die Runlevel selbst haben leider keine so schönen Namen wie unter MacOS, sondern nur eine Zahl oder einen Buchstaben als Bezeichnung, und auch nicht irgendeinen Buchstaben sondern einen von diesen hier: 0123456SsQqAaBbCcUu. Diese Auswahl kommt aus der Historie von UNIX. Die Ziffer des Runlevels bezeichnet eine immer umfangreiche Funktionalität, d.h. System bewegt sich also auf einer "höheren" Ebene, die der Einfachheit halber durch eine Zahl ausgedrückt wird. Für spezielle Situationen (z.B. den Single-User-Mode wurden auch spezielle Runlevel eingeführt, bei der SuSE z.B. das 'S'). Auch dürfte der vielfältig und mitunter verwirrenden Stammbaum von UNIX einige heute nicht mehr gebräuchliche Runlevel beigesteuert haben. Bei LinuxPPC werden folgenden Runlevel üblich[4] verwendet:

0halt (Do NOT set initdefault to this)
bewirkt das Abschalten des Rechners
1Single user mode
Der Single-User-Mode ist gewissermassen ein Wartungmode in dem nur der Systemadministrator (also root) Zugriff hat.
2Multiuser, without NFS
normaler textorientierter Multi-User-Modus, aber ohne die Möglichkeit des "Filesharings". Andere Netzwerkfunktionen sind aber aktiv.
3Full multiuser mode
wie 2, nur das jetzt auch noch das "Filesharings"über das NFS (Network File System) unter UNIX/Linux-Maschinen möglich ist.
4  unused
5X11
wie 3. Nun läuft aber endlich auch die graphische Oberfläche X-Window (oder kurz X11).
6reboot
bewirkt einen Neustart.

Wofür ein bestimmter Runlevel steht sollte in der Datei /etc/inittab zu finden sein. Dort kann man auch einstellen, in welchen Runlevel das System beim Booten gehen soll. Dazu muss man nur in der Zeile

id:5:initdefault:

die unterstrichene Zahl durch die des gewünschten Runlevels ersetzen werden. Aber Achtung, man sollte hier nicht die Runlevel für halt oder shutdown (bei LinuxPPC 0) oder reboot (bei LinuxPPC 6) hier eintragen.

Wie weiß aber das System, welcher Dienst in welchem Runlevel laufen soll? Dazu gibt es zu jedem Runlevel im Verzeichnis /etc/rc.d ein Verzeichnis, das rc?.d heisst. Dabei steht das '?' für die Nummer des jeweiligen Runlevels (also z.B. /etc/rc.d/rc5.d/. In jedem dieser Verzeichnisse liegt nun eine Sammlung symbolischer Links auf einzelne Init-Skript. Diese symbolischen folgen dabei einer Namenskonvention (an die man sich auch halten muss): Sie beginnen mit einem 'S' oder einem 'K', gefolgt von einer Zweistelligen Zahl und dem Namen des Skriptes auf das sie verweisen, also z.B. S85httpd.

Die S-Links (S wie Start) werden beim Starten eines Runlevels aufgerufen, die 'K'-Links bei Verlassen (K wie Kill, also Abschießen eines Dienstes). Die S-Links werden dabei immer mit dem Parameter start aufgerufen, die 'K'-Links immer mit stop.

Nun gibt es Dienste, die erste gestartet werden können wen andere schon laufen, z.B. kann NFS erst gestartet werden, wenn das Netzwerk schon läuft. Auch sollte erst NFS abgeschaltet werden und dann das Netzwerk. Daher sind die Links nummeriert. Bei Betreten oder Verlassen des Runlevels werden die Links in numerischer Reihenfolge aufgerufen (bei gleicher Nummer in alphabetischer). Deshalb ist es wichtig jedem Link eine passende Nummer zu geben.

Booten, Init-Skripte und Runlevel

Das Booten findest in zwei Stufen statt. Zunächst lädt und initialisiert sich der Kernel. Dabei erkennt er die Hardware usw. Danach startet der Init-Prozess. Dieser startet seinerseits ein Reihe von Skripten. Der genaue Ablauf dabei ist leider von Distribution zu Distribution unterschiedlich Bei LinuxPPC 1999 sieht es so aus:

init startet das Skript /etc/rc.d/rc.sysinit. Dieses sorgt u.a. dafür, dass die Partitionen überprüft und gemountet werden, kümmert sich um Sound und RAIDs etc.

Danach folgen die Init-Skripte des default-Runlevels, wie er in der /etc/inittab angebeben ist. Es werden natürlich nur die 'S'-Links ausgeführt, da das System ja vorher in keinem Runlevel war.

Am Ende wir noch das Skript /etc/rc.d/rc.local ausgeführt. Hier kann ein Systemadministrator relativ gefahrlos Kleinigkeiten, die nur einmal beim Booten getan werden müssen (z.B. die Systemuhr nach einer Timeserver nachstellen), hinzufügen

Handarbeit

Wenn man einen Dienst starten oder stoppen will muss man dazu nicht gleich den ganzen Runlevel stoppen. Es reicht, wenn man den Dienst über sein Skript in /etc/rc.d/init.ddirekt anspricht. Man sollte nur aufpassen, ob nicht andere Dienste laufe, die von diesem Dienst abhängen Also nicht das Netzwerk stoppen, wenn man noch NFS laufen hat. SuSE-Linux macht es einem noch einfacher. Dort gibt es zu jedem Init-Skript ein Link im /sbin-Verzeichnis, der wie das Skript mit vorangestelltem rc heisst. Dadurch kann, z.B. AppleTalk durch:

rcatalk start

starten. Bei LinuxPPC heisst das äquivalent:

/etc/rc.d/init.s/atalk start

Da man jeden Dienst direkt starten kann, ist in der Regel unnötig den Rechner neu zu starten, wenn man einen Dienst hinzugefügt hat. Im Gegenteil, man kann u.U. sogar den neuen Dienst so besser austesten.

Wenn man nun einen neuen Dienst installiert hat und diesen beim Booten auch aktivieren will, so reicht es selbst symbolische Links in den Verzeichnissen, der gewünschten Runlevel anzulegen. Man sollte dabei nur auf die Abhängigkeiten zwischen den Diensten achten, d.h. zum Beispiel wenn man Appletalk hinzufügen will, muss der 'S'-Link hinter dem 'S'-Link des Netzwerkes liegen. Der 'K'-Link jedoch davor. Auch sollte man die 'K'-Links in den Runleveln 0 und 6 (shutdown und reboot) nicht vergessen, vor allem dann wenn es um Filesharing, wie bei AppleTalk geht.


Anmerkungen

  1. Mit Dienst sollen hier alle "Elemente" des Systems bezeichnet werden, die typischerweise beim Booten gestartet werden und nicht automatisch mit dem Kernel gestartet werden. Das ist zugegeben eine eher technische Definition, aber eine für diesen Text sehr praktische.
  2. Alternativ kann man auch einzelne 'Dienste' in anderen Skripten, die beim booten aufgerufen werden, einbauen, z.B. in /etc/rc.d/rc.local.
  3. Leider hat sich bei Linux noch kein einheitliche Schema für Pfade von Systemdateien durchgesetzt (Abgesehen von Grundkonventionen, wie Konfigurationsfiles in /etc u.ä.
  4. SuSE-Linux (zumindest im x86-Fall) benutzt ein abweichendes Runlevel-Schema:
    0 is halt
    S is single-user
    1 is multi-user without network
    2 is multi-user with network
    3 is multi-user with network and xdm
    6 is reboot
    Ob dies auch bei SuSE-PPC sein wird, weiss ich aber nicht.

Rüdiger Goetz
Last modified: Tue Mar 28 19:08:31 CEST 2000