launchd ist ein vereinheitlichtes, Open-Source-Verwaltungssystem (Framework) zum Starten, Beenden und Verwalten von Daemons, Programmen und Shell-Scripts. Eingeführt wurde es mit Mac OS X v10.4/Darwin v8.0, es ist lizenziert unter der Apache-Lizenz. Der Apple-Angestellte Dave Zarzycki entwickelte und pflegt launchd.[1]
Der launchd-Daemon ist im wesentlichen ein Ersatz für init, rc, die init.d- und rc.d-Scripte, SystemStarter, inetd und xinetd, atd, crond und watchdogd. Apple hat erklärt, dass beabsichtigt ist, alle genannten Dienste zugunsten von launchd aufzugeben.
Beginnend mit OS X v10.4 „Tiger“, hat Apple die meisten Prozesse, die von den genannten Diensten verwaltet werden, an launchd übertragen. Durch Vereinigung aller Programmstart-Funktionen ("launch services") in einem einzigen Programm beschleunigt launchd die Startzeit besonders auf langsamen Computern signifikant.
Inhaltsverzeichnis |
Es gibt zwei Hauptprogramme im launchd-System: launchd und launchctl.
launchd verwaltet die „Daemons“ sowohl auf Benutzer- als auch auf System-Ebene. Ähnlich wie xinetd kann launchd auf Anforderung „Daemons“ starten. Wie watchdogd so kann auch launchd „Daemons“ überwachen, um sicherzustellen, dass sie stets laufen. Außerdem hat launchd init als PID 1 auf Mac OS X ersetzt, und daher ist es verantwortlich für den Systemstart (Booten).
Die Parameter der Dienste, welche von launchd gestartet werden, werden über Konfigurationsdateien definiert. Diese Dateien befinden sich in den Verzeichnissen LaunchAgents und LaunchDaemons des Verzeichnisses "Library", basieren auf property list und haben etwa dreißig editierbare Schlüsselwerte.
launchctl ist ein Kommandozeilen-Programm, welches zum Laden und Entladen von „Daemons“ verwendet wird, weiterhin zum Start und Stoppen von launchd-gesteuerten Jobs, zum Ermitteln von Statistiken über die Systemauslastung für launchd und seine Kindprozesse und schließlich zum Setzen von Umgebungsvariablen (environment).
launchd hat zwei Hauptaufgaben: erstens das System zu starten (booten) und zweitens die Dienste (services) zu laden und zu überwachen (d.h. sicherzustellen, dass sie noch laufen und sich nicht ungeplant beendet haben).
Der folgenden Abschnitt zeigt eine vereinfachte Darstellung des Systemstarts von MacOS 10.4 auf einem PowerPC-Mac (auf einem Intel-Mac ersetzt EFI die Open Firmware, und boot.efi
ersetzt BootX):
/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 Jobs, die ausgeführt werden müssen. Es gibt zwei derartige 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 unter Benutzer-Rechten (des angemeldeten oder eines anderen) ausgeführt werden. Dies können Scripte sein oder andere Vordergrund-Kommandos (d.h. sichtbare), welche sogar eine Benutzeroberfläche haben können. Diese Verzeichnisse liegen alle in den typischen 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 entscheidende Idee bei launchd ist, 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 „horcht“ an ihnen (engl. "listen"), d.h. wartet auf Anforderungen auf diesen Ports. Wenn in der plist-Datei über den Schlüssel "OnDemand" angegeben, wird der „Daemon“ zu diesem Zeitpunkt tatsächlich 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, und launchd stellt sicher, dass er läuft, wenn immer er 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. Wenn immer ein Prozess in den Hintergrund geht, 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, nicht auch gleich zu starten. Tatsächlich ist der grafische Fortschrittbalken beim Startvorgang des Mac lediglich ein „Placebo“-Programm (namens WaitingForLoginWindow [1]), welches nichts anderes zeigt als den Ablauf einer bestimmten Zeitspanne (nämlich diejenige, die beim letzten Systemstart ermittelt worden war).
Der am schwierigsten zu bewältigende Aspekt beim Systemstart via launchd sind die Abhängigkeiten der Dienste (services) untereinander. Das alte Verfahren über "SystemStarter" bot ein sehr einfaches Konzept der Festlegung von Abhängigkeiten, und zwar durch die Schlüsselwörter "Uses" (verwendet), "Requires" (benötigt) und "Provides" (implementiert, stellt zur Verfügung) in der plist-Datei eines Autostart-Objekts ("startup item"). Dagegen gibt es zwei Hauptstrategien, um Abhängigkeiten in MacOS 10.4 festzulegen. Die Interprozess-Kommunikation 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 10.4 noch verfügbar ist und unterstützt wird, aber es ist ein veraltetes Konzept, d.h. es kann in zukünftigen Versionen von OS X wegfallen.
Eine der wichtigsten Beanstandungen anderer Dienst-Verwaltungen (service control) ist, dass sie weit über das Betriebssystem verstreut sind und es keine zentrale Verwaltung gibt. Apple verwendet launchctl, um dieses Problem zu lösen.
Wenn eigenständig verwendet, akzeptiert launchctl Kommandos von der Kommandozeile, von der Standard-Eingabe (stdin), oder es arbeitet interaktiv. Ein Ablauf 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 zu machen.
Eine property list (plist) ist ein Dateityp, welcher von Apple verwendet wird, um Programmkonfigurationen zu speichern. Wenn launchd ein Verzeichnis durchsucht oder wenn ein "job" an launchd übermittelt wird, liest es die plist-Datei, welche beschreibt, wie das Programm zu starten ist.
Die folgende Tabelle zeigt eine Liste von häufig verwendeten Schlüsselwörtern. Für weitergehende Informationen siehe Apples "man page" (launchd.plist).
Schlüsselwort | Beschreibung | benötigt |
---|---|---|
Label | Der Name des "Jobs" | Ja |
ProgramArguments | Zeichenketten als Parameter an das Programm | Ja |
UserName | Der "Job" 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-Script). 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 ein "Job" ständig laufen soll oder nicht. | Nein |
RootDirectory | Der "Job" läuft unter einem virtuellen Wurzelverzeichnis (per chroot). | Nein |
ServiceIPC | Gibt ab, ob der Daemon via IPC mit launchd kommunizieren kann. | Nein |
WatchPaths | Ermöglicht launchd, einen "Job" bei Änderungen in einem Verzeichnis zu starten. | Nein |
QueueDirectories | Ähnlich wie WatchPath, aber eine Warteschlange (queue) wartet, bis in einem leeren Verzeichnis neue Dateien auftauchen. | Nein |
StartInterval | Wird benötigt, um einen "Job" in zyklischen Zeitabständen (schedule) auszuführen, ähnlich cron. | Nein |
StartCalendarInterval | Regelmäßiges Starten des "Jobs" (scheduling). Die syntax ist ähnlich wie bei cron. | Nein |
HardResourceLimits | Steuert die Beschränkung bestimmter Ressourcen, die von einem beliebigen "Job" benötigt werden. | Nein |
LowPriorityIO | Teilt dem Betriebssystem-Kernel mit, dass dieser "Task" geringe 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 horchen (listen) soll. Wird verwendet, wenn ein Dienst erst gestartet werden soll, wenn er benötigt wird. | Nein |
Einige Leute sind der Meinung, dass launchd zu sehr im Hinblick auf Ausführungsgeschwindigkeit (performance) und zu wenig mit dem Ziel der Korrektheit und Flexibilität entwickelt wurde. Einige Kritikpunkte sind:
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 (LoginWindow) 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 (mount) werden kann, dann ist das kein Problem; und genau so funktioniert es in der Praxis.
Die Idee dabei ist, dass, wenn eine Software erst laufen kann, wenn der Dienst x zur Verfügung steht, dann sollte diese Software solange blockieren, bis Dienst x tatsächlich zur Verfügung steht. D.h. die Abhängigkeit wird 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.)