Launchd
# Launchd

launchd ist ein einheitliches Framework zum Starten, Verwalten und Beenden von Daemons, Programmen und Shellskripten im Betriebssystem-Kontext. Eingeführt wurde es mit Mac OS X Tiger (10.4) bzw. Darwin 8.0, wo es den traditionellen Unix-init-Prozess ersetzt. Nutzungsrechtlich steht es unter der Apache-Lizenz. Entwickelt wurde launchd von Dave Zarzycki, im Zuge seiner Anstellung beim US-amerikanischen Unternehmen Apple.

## init-Prozess

Der launchd-Daemon soll folgende Funktionen übernehmen:

* init
* rc
* init.d
* rc.d-Skripte
* SystemStarter
* inetd
* xinetd
* atd
* crond
* watchdogd

Mit Mac OS X Tiger (10.4) hat Apple die meisten Aufgaben an launchd übertragen. Durch die Vereinheitlichung des Dienste-Starten auf einem einzigen Prozess beschleunigt launchd die notwendige Startzeit, insbesondere auf langsamen Computern.

## Komponenten von launchd

Die Kernbestandteile des launchd-Systems sind:

* launchd
* launchctl

launchd verwaltet die „Daemons“ sowohl auf Nutzer- als auch auf Systemebene. Ähnlich xinetd kann launchd auf Anforderung „Daemons“ starten. Wie watchdogd kann auch launchd „Daemons“ überwachen und sicherstellen, dass sie immer laufen. Außerdem hat launchd init als PID 1 auf Mac OS X ersetzt und ist somit verantwortlich für den Systemstart (Bootvorgang).

Die Parameter der Dienste, welche von launchd gestartet werden können, werden in Konfigurationsdateien definiert. Diese Dateien befinden sich in den Verzeichnissen LaunchAgents und LaunchDaemons des Verzeichnisses "Library" und basieren auf property List (plist), haben in etwa dreißig editierbare Schlüsselwerte.

launchctl ist ein Kommandozeilen-Programm, welches die Aufgabe des Ladens und Entladens von „Daemons“ hat. Weiterhin kann es verwendet werden zum Starten und Stoppen von launchd-gesteuerten Diensten, zum Ermitteln von Statistiken über die Systemauslastung für launchd und seine Kindprozesse und schließlich zum Setzen von Umgebungsvariablen.

### launchd

launchd hat zwei Aufgaben:

* das System zu starten (booten),
* die Dienste (services) zu laden und zu überwachen (d. h. sicherzustellen, dass sie noch laufen und sich nicht ungeplant beendet haben).

Der folgende Abschnitt zeigt eine vereinfachte Darstellung des Systemstarts von Mac OS X 10.4 auf einem PowerPC-Mac (auf einem Intel-Mac ersetzt EFI die Open Firmware, und boot.efi ersetzt BootX):

* Open Firmware wird aktiviert, initialisiert und prüft die Hardware und lädt dann BootX.
* BootX lädt den Betriebssystem-Kernel, zeigt die Start-Animation (das rotierende Windrad) und lädt alle benötigten Kernel-Erweiterungen (kexts). Dann lädt der Kernel launchd.
* launchd startet /etc/rc, durchsucht die Verzeichnisse /System/Library/LaunchDaemons und /Library/LaunchDaemons, reagiert entsprechend den Einstellungen in den plist-Dateien und startet das Anmeldefenster.

In Schritt 3 durchsucht launchd einige Verzeichnisse nach Diensten, die ausgeführt werden müssen. Es gibt hierfür zwei Verzeichnisse: Das Verzeichnis LaunchDaemons enthält Kommandos, welche als root (d. h. mit Systemverwalter-Rechten) ausgeführt werden, üblicherweise sind dies Hintergrundprozesse. Die Verzeichnisse namens LaunchAgents enthalten bestimmte Kommandos, sogenannte agent applications, welche mit Nutzer-Rechten ausgeführt werden. Dies können Skripte sein oder andere Vordergrund-Kommandos (d. h. sichtbare), welche sogar eine Benutzeroberfläche haben können. Diese Verzeichnisse liegen alle in den Library-Ordnern von Mac OS X.

Launchd unterscheidet sich sehr von SystemStarter, und zwar dahingehend, dass es tatsächlich nicht notwendigerweise alle „Daemons“ beim Systemstart lädt. Die Grundidee bei launchd ist es, wie auch ähnlich bei xinetd, die „Daemons“ erst dann zu laden, wenn sie benötigt werden. Während launchd beim Systemstart die plist-Dateien mit den Kommandos durchsucht, reserviert es alle dort angeforderten (IP-)Ports und lauscht auf ihnen, d. h. wartet auf Anfragen auf diesen Ports. Wenn in der plist-Datei der Schlüssel "OnDemand" definiert ist, wird der „Daemon“ zu diesem Zeitpunkt noch nicht gestartet. Stattdessen „horcht“ launchd an diesem Port und startet den „Daemon“ erst, wenn er benötigt wird, und beendet ihn, wenn er nicht mehr benötigt wird. Nachdem ein „Daemon“ geladen worden ist, wird er von launchd überwacht. launchd stellt dabei sicher, dass er läuft, wann immer er auch benötigt wird. In dieser Hinsicht arbeitet lauchd wie watchdogd und stellt wie watchdogd die Anforderung an den Prozess, dass er nicht versucht, selbständig ein "fork" oder "daemonize" auszuführen. Sobald ein Prozess in den Hintergrund verschoben wird, verliert launchd die Kontrolle über ihn und versucht, ihn neu zu starten.

Als Ergebnis dieses Konzepts startet Mac OS X 10.4 wesentlich schneller als seine Vorgänger. Das System braucht lediglich die „Daemons“ zu registrieren und nicht sofort zu starten. Tatsächlich ist der grafische Fortschrittsbalken beim Startvorgang des Mac lediglich ein „Placebo“-Programm (namens WaitingForLoginWindow), welches nichts anderes zeigt als den Ablauf einer bestimmten Zeitspanne.

Der am schwierigsten zu bewältigende Aspekt beim Systemstart via launchd sind die Abhängigkeiten der Dienste untereinander. Das bisherige Verfahren über "SystemStarter" bot ein sehr einfaches Konzept der Festlegung von Abhängigkeiten, und zwar durch die Schlüsselwörter "Uses", "Requires" und "Provides" in der plist-Datei eines Autostart-Objekts. Dagegen gibt es zwei Hauptstrategien, um Abhängigkeiten in MacOS 10.4 aufzulösen. Die Interprozesskommunikation ermöglicht den „Daemons“, miteinander zu kommunizieren und Abhängigkeiten auszuhandeln, oder man beobachtet Dateien oder Verzeichnispfade bezüglich Änderungen. Die Verwendung von IPC ist sehr viel geschickter und raffinierter als die Schlüsselwörter des SystemStarter-Konzepts, und dies verlangt auch mehr Arbeit bei der Programmentwicklung, aber es kann zu saubereren und schnelleren Systemstarts führen. Der SystemStarter ist eine Option, welche auch in Mac OS X Tiger (10.4) noch verfügbar ist und unterstützt wird.

### launchctl

Eine der wichtigsten Beanstandungen an der Umsetzung anderer Dienste-Verwaltungen ist es, dass sie über das System verstreut sind und es kein zentrales Administrationstool dafür gibt. Apple verwendet launchctl, um dieses Problem zu lösen.

Wenn dies eigenständig verwendet wird, akzeptiert launchctl Kommandos von der Kommandozeile, von der Standardeingabe, oder arbeitet interaktiv. Eine Folge von Kommandos kann dauerhaft gespeichert werden durch Verwendung der Datei ~/.launchd.conf oder /etc/launchd.conf. In Verbindung mit sudo kann launchctl verwendet werden, um Änderungen mit globalen Auswirkungen vorzunehmen.

### Property list

Eine Property List (plist) ist eine Dateierweiterung, die von Apple verwendet wird, um Programmeinstellungen zu speichern. Wenn dann launchd ein Verzeichnis durchsucht oder eine Aufgabe an launchd übermittelt wird, liest es die plist-Datei, die beschreibt, wie das Programm gestartet werden muss.

Die nun folgende Tabelle zeigt eine Liste von häufig verwendeten Schlüsselwörtern. Für weitergehende Informationen siehe Apples "man page".

| Schlüsselwort | Beschreibung | benötigt |
| - | - | - |
| Label | Der Name der Aufgabe | Ja |
| ProgramArguments | Zeichenketten als Parameter an das Programm | Ja |
| UserName | Die Aufgabe wird unter dem angegebenen Benutzernamen gestartet. Dies braucht nicht notwendigerweise derjenige zu sein, welcher ihn an launchd übergeben hat. | Nein |
| inetdCompatibility | Zeigt an, dass der Daemon erwartet, ausgeführt zu werden, als sei er von inetd gestartet worden. | Nein |
| Program | Der Pfad zu der ausführbaren Datei (Programm oder Shell-Skript). Dieser Schlüssel kann auch die Argumente enthalten, so dass der Schlüsselwert ProgramArguments nicht mehr benötigt wird. | Nein |
| onDemand | Ein Schalter (boolean), welcher festlegt, ob eine Aufgabe unabhängig davon, ob benötigt, gestartet werden soll. | Nein |
| RootDirectory | Die Aufgabe läuft unter einem virtuellen Dateiumgebung (per chroot). | Nein |
| ServiceIPC | Gibt an, ob der Daemon via IPC mit launchd kommunizieren kann. | Nein |
| WatchPaths | Ermöglicht launchd, eine Aufgabe über Änderungen in einem Verzeichnis zu starten. | Nein |
| QueueDirectories | Ähnlich wie WatchPath, warten, bis in einem leeren Verzeichnis neue Dateien erzeugt werden. | Nein |
| StartInterval | Wird benötigt, um eine Aufgabe regelmäßig auszuführen, ähnlich cron. | Nein |
| StartCalendarInterval | Regelmäßiges starten von Aufgaben. Der Syntax ist ähnlich dem von cron. | Nein |
| HardResourceLimits | Steuert die Einschränkung bestimmter Ressourcen, die von Aufgaben gestellt werden. | Nein |
| LowPriorityIO | Teilt dem Betriebssystem-Kernel mit, dass diese Aufgabe eine geringere Priorität erhalten soll, während er auf Datei-Operationen wartet. | Nein |
| Sockets | Eine Liste kann verwendet werden, um festzulegen, an welchem "Socket" der Daemon lauschen soll. Wird verwendet, wenn ein Dienst erst gestartet werden soll, wenn er benötigt wird. | Nein |

## Kritik

Von einigen Leuten wird kritisiert, dass launchd zu sehr im Hinblick auf Startgeschwindigkeit und zu wenig mit dem Ziel der Korrektheit und Flexibilität entwickelt worden ist. Insbesondere sind dies:

* Während einerseits der Startvorgang auf einem einfachen, eigenständigen System immens beschleunigt wird, werden andererseits die Verhältnisse auf komplexeren Systemen verkompliziert. Beispielsweise sind Fehler beim Systemstart sehr schwer zu lokalisieren und korrigieren, da alle Dienste von einem einzigen Script gestartet werden. System V dagegen trennt die Dienste in vier "Levels" und minimiert damit die Anzahl der Dienste, die es im Fall von Problemen zu untersuchen gilt.
* Konzeptionell verliert launchd die Flexibilität von System V, da es nicht möglich ist, eine Startreihenfolge festzulegen oder selektiv Dienste während des Boot-Vorgangs zu starten.

Dies kann zu Problemen führen, wenn z. B. ein NetInfo- oder LDAP-Server für die Authentifizierung verwendet wird oder wenn das private Benutzerverzeichnis (home directory) auf einem Netzwerk-Server liegt. Denn das Anmeldefenster wird nicht blockiert, bis diese Dienste aktiv und verfügbar sind. Andererseits gilt: Wenn in dem genannten Beispiel die vom Anmeldefenster verwendeten APIs zum Ermitteln von Informationen in den Directory Services blockieren, bis die "Directory Services" die Verbindung zum NetInfo- oder LDAP-Server hergestellt haben oder feststellen, dass kein solcher Server verfügbar ist, und wenn der Zugriff auf das Benutzerverzeichnis blockiert wird, bis es vom Server eingehängt werden kann, dann ist das kein Problem.

Die Idee dabei ist, dass ein Programm, sofern es erst laufen kann, wenn Dienst x zur Verfügung steht, solange blockiert, bis Dienst x tatsächlich zur Verfügung steht; die Abhängigkeit wird also implizit in der Software selbst festgelegt anstatt durch Konfigurationsdateien. (Man beachte, dass in Unix-ähnlichen Systemen, die nicht launchd verwenden, eine Festlegung der Startreihenfolge lediglich verhindert, dass spätere (d. h. abhängige) Dienste gestartet werden, bevor diejenigen Dienste gestartet werden, von dem ersterer abhängt. Jedoch blockiert dieses Konzept nicht notwendigerweise den späteren (abhängigen) Dienst lange genug, bis der benötigte Dienst initialisiert und bereit zur Verwendung ist.)

Wenn man beispielsweise zwei „Daemons“ nacheinander durch eine Konfigurationsdatei (rc file) startet, könnte es passieren, dass der zweite Dienst Funktionen des ersteren benötigt, bevor dieser seinen Startvorgang beendet hat.

