Automatische Arbeiten im Hintergrund.
Launchd ist der Hauptprozeß von Mac OS X. Er wurde mit 10.4 Tiger eingeführt und seit 10.5 Leopard sind auch die restlichen Systemdienste auf ihn umgestellt.
Im frühen UNIX hatte das Init-Programm nur drei- oder vierhundert Bytes. Im Laufe der Jahrzehnte wurde es jedoch immer größer und es sammelten sich diverse zusätzliche Initprogramme an, die typischerweise auf ".d" endeten, zum Beispiel "init", "init.d", "cron.d", "rc", "rc.d", "inet.d", "daily.out.d", "xinet.d", "systemstarter". Ihre Konfiguration war auch unterschiedlich. Nun gibt es nur noch ein "d": launchd.
Er kann andere Programme nach Bedarf starten (von "to launch", und "d" für daemon). So ein Bedarf kann sich auf verschiedene Weisen äußern: Feste Zeitpunkte, periodisch wiederkehrende Ausführungszeiten, Anfragen auf bestimmten Netzwerk-Ports oder Änderungen im Dateisystem.
Launchd bietet diverse Vorteile und Möglichkeiten:
"Für den durchschnittlichen UNIX-Hacker sieht launchd wahrscheinlich wie die Neuerfindung des Rades aus, aber es löst Probleme, von denen die UNIX-Welt nicht einmal wußte, daß es sie hat. Ähnlich wie es auch schon zuvor "UNIX für zuhause" gab, so ist Mac OS X doch in diesem Punkt einen Schritt weiter."
Frei übersetzt nach diesem Artikel von ars technica.
Apple hat launchd als Open-Source-Projekt nicht nur bei sich, sondern auch hier veröffentlicht. Apple hofft, daß launchd dadurch auch von anderen UNIX-Systemen übernommen wird. Launchd steht unter der Apache-Lizenz (Version 2.0), die den Nutzer praktisch weder einschränkt noch gängelt.
Seit circa April 2010 gibt es mit systemd eine Version, die das Konzept von launchd auch für GNU/Linux verfügbar macht. So wird systemd beispielsweise in Fedora 14 und 15 verwendet.
Siehe auch meinen Blogeintrag zur Nutzung von systemd in Linux-Distributionen.
Dämonen arbeiten immer ohne sichtbare Oberfläche im Hintergrund. Agenten können auch in der graphischen Oberfläche auftauchen. Dämonen erfüllen systemweite Aufgaben und dienen nicht einem speziellen Benutzer. Von einem Agenten wird jeweils ein eigenes Exemplar für jeden Benutzer aktiv, der sich anmeldet.
Es gibt Dämonen und (seit 10.5 Leopard auch Agenten), die mit dem Betriebssystem ausgeliefert werden. Ferner sind Dämonen und Agenten möglich, die von Administratoren hinzugefügt werden. Und drittens sind Agenten (aber keine Dämonen) möglich, die ein normaler Benutzer für sich allein installiert.
Ob ein Dämon beziehungsweise Agent vom System, einem Administrator oder einem Benutzer kam, erkennt man am Verzeichnis, in dem sie liegen:
/System/Library/LaunchDaemons
enthält Dämonen, die das Betriebssystem
standardmäßig systemweit definiert.
/Library/LaunchDaemons
enthält Dämonen, die Administratoren systemweit zur
Verfügung stellen.
/System/Library/LaunchAgents
enthält Agenten, die vom Betriebssystem
standardmäßig definiert sind und für jeden angemeldeten Benutzer gestartet werden.
Seit 10.5 Leopard liegen dort diverse.
/Library/LaunchAgents
enthält Agenten, die Administratoren definieren
können und die für jeden angemeldeten Benutzer gestartet werden.
~/Library/LaunchAgents
enthält für den jeweiligen Benutzer Agenten, die
er selbst definieren
kann und die nur für ihn, wenn er sich anmeldet, gestartet werden.
~/Library
wären unsinnig, weil Dämonen immer systemweit
tätig sind, Benutzerverzeichnisse jedoch nur dem jeweiligen Benutzer dienen.
All diese Verzeichnisse werden automatisch von launchd eingelesen.
Wie grundsätzlich, so gilt auch hier: Niemand, auch kein Administrator, hat in Verzeichnissen
von /System/Library
und darunter etwas zu ändern. Es ist auch nicht nötig, denn
den gleichen systemweiten Effekt
erzielen Administratoren, wenn sie in /Library
arbeiten. So sind die
Bereiche, die vom System definiert werden und die, die von Administratoren bearbeitet werden,
sauber getrennt.
Vergleiche dazu Apples Artikel Getting Started with launchd.
Wem das nicht einleuchtet, der möge sich bewußt machen, das etwaige Änderungen
in /System/Library
durch Aktualisierungen des Betriebssystems jederzeit vernichtet
werden, während Änderungen in /Library
erhalten bleiben. Genauso wie natürlich
Änderungen in ~/Library
erhalten bleiben, die Benutzer für sich allein vornehmen.
Die Trennung dient auch der Stabilität des Systems.
Mit launchctl
bekommt man die Kommando-Zentrale, um mit
launchd "zu reden". Der Name dürfte die Abkürzung für
"launch control" sein.
Ein Administrator
kann mit sudo launchctl mit der Instanz von launchd, die
systemweit (als root) tätig ist, reden.
Wenn man launchctl allein eingibt, dann
redet man mit der Instanz von launchd, die für den Benutzer
tätig ist, der launchctl
gerade aufrief.
Mit ls /var/launchd
kann man sich die Benutzer-Identitäts-Nummern ansehen,
für die eine Instanz von launchd läuft. Die 0 entspricht
root, also dem System.
Verlassen kann man launchctl
durch control-d. Hier sind
einige nützliche Kommandos, die man in launchctl
verwenden kann:
label
-Namens, wie er in der jeweiligen Konfiguratiosdatei
definiert ist, an.
label
-Namens, wie er in der jeweiligen Konfiguratiosdatei
definiert ist, an.
Abhängig von ihrer Konfiguration kann es natürlich sein, daß die Aufgabe von
launchd sofort wieder gestartet wird.
"Geladen" und "gestartet" ist ein Unterschied. Ein Dämon oder Agent wird von launchd verwaltet, wenn er geladen wurde. Er kann manuell geladen werden oder (das ist der Normalfall) dadurch, daß seine Konfigurationsdatei in einem der Standardverzeichnisse liegt.
Ein geladener also von launchd verwalteter Agent oder Dämon wird gestartet/aktiv, also seine Tätigkeit durchgeführt, wenn er manuell gestartet wird oder (das ist der Normalfall) wenn eine Situation eintritt, die in seiner Konfigurationsdatei definiert wurde (Zeitpunkt, Intervall, Netzanfrage, Dateiänderung und so weiter).
Dämonen und Agenten, die ein Administrator in /Library/LaunchDaemons
beziehungsweise in /Library/LaunchAgents
installiert, sollten folgende
Zugriffsrechte aufweisen:
Eigentümer ist root und Gruppe is wheel. Verzeichnisse und ausführbare Dateien sollten
nur für root änderbar sein, also 755 (rwxr-xr-x)
. Dateien sollten nur
von root änderbar und von niemandem ausführbar sein, also 644 (rw-r--r--)
.
Vergleiche dazu Apples Artikel Daemons and Agents.
Diese Einstellungen dienen dazu, daß ein normaler Benutzer nicht durch die Veränderung eines Dämons höhere Rechte erlangen kann.
Ich stelle nun einige LaunchDaemons und LaunchAgents vor, die ich für mich erstellt habe und verwende. Sie können als Vorlage für ähnliche Aufgaben dienen.
Agenten und Dämonen bestehen aus mindestens einer
XML-Datei,
die man per Hand oder
komfortabel mit Hilfe des Property List Editors,
der Teil der Developer Tools (Xcode)
ist, erstellen kann. Umfangreichere Agenten und Dämonen nutzen zusätzlich noch
Shell-Skripte. Diese Shell-Skripte
werden typischerweise in /usr/local/bin
abgelegt.
Vergleiche dazu den Abschnitt "Why are there 7 binaries directories?" des Artikels Mac OS X Hidden Files & Directories.
Dieser Dämon konfiguriert beim Start des Rechners die Netzwerk-Einstellungen von Mac OS X so, daß sie optimal sind für schnelle Internetverbindungen wie beispielsweise DSL.
Man kann diese Netzwerk-Werte auch in der Datei /etc/sysctl.conf
setzen.
Dabei verwendet man Zeilen wie beispielsweise net.inet.tcp.sendspace=49152
.
Die Datei ist normalerweise noch nicht vorhanden und da sie während des Rechnerstarts
gelesen wird, sollte der Besitzer root
und die Gruppe
wheel
sein und die Rechte 0644.
Ab 10.6 bieten die Sytem-Einstellungen Einstellmöglichkeiten für die MTU-Werte auch für das Funknetz.
Der Dämon besteht aus zwei Dateien. In /Library/LaunchDaemons
liegt die
XML-Definition des Dämons in der Datei de.realmacmark.dslnet.plist
.
Die Endung ".plist" signalisiert eine Voreinstellungsdatei (Preference List). Der Name folgt Apples Empfehlung, umgekehrte Domain-Namen zu verwenden, um eindeutige Namen zu garantieren.
Der Inhalt ist:
<?xml version="1.0" encoding="UTF-8"\?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>de.realmacmark.dslnet</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/dslnet_optimizer.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Im Property List Editor sieht es so aus:
Das Label
legt den Namen des Dämons fest, unter dem
launchd ihn kennen soll. Der Program
-Eintrag
definiert die Tätigkeit des Dämons und RunAtLoad
sorgt dafür, daß
die Tätigkeit des Dämons auch schon einmal beim Laden des Dämons
ausgeführt werden soll.
Alle verfügbaren Einstellungsmöglichkeiten für Dämonen kann man sich mit
man launchd.plist
anzeigen lassen.
Die zweite Datei ist dslnet_optimizer.sh
, die man im Verzeichnis
/usr/local/bin
speichert und mit
sudo chmod +x dslnet_optimizer.sh
ausführbar macht.
Dies ist Version 1.3 meines Shell-Skriptes:
#!/bin/sh
/usr/sbin/sysctl -w net.inet.tcp.sendspace=65536 > /dev/null
/usr/sbin/sysctl -w net.inet.tcp.recvspace=65536 > /dev/null
/usr/sbin/sysctl -w kern.ipc.maxsockbuf=524288 > /dev/null
/usr/sbin/sysctl -w net.inet.tcp.delayed_ack=0 > /dev/null
/usr/sbin/sysctl -w net.inet.udp.recvspace=73728 > /dev/null
/sbin/ifconfig en0 mtu 1492 > /dev/null
/bin/sleep 15 > /dev/null
/sbin/ifconfig en1 mtu 1484 > /dev/null
/usr/bin/say -v Boing network settings optimized > /dev/null
Hier werden die Netzwerkeinstellungen gesetzt. Vergleiche dazu meine Seite über "Maximale Geschwindigkeit mit Breitband-Internet", auf der die gesetzten Werte erläutert werden. Das Setzen dieser Werte ist mit solch einem LaunchDaemon am elegantesten. Vor dem Einstellen des Wertes für die Funkverbindung wartet das Skript 15 Sekunden, um nicht zu früh vergeblich zuzugreifen.
Eventuelle Ausgaben der Befehle werden mit > /dev/null
an ein
nicht-existierendes Gerät geschickt, also ignoriert. Die letzte Zeile nutzt die
Sprachausgabe, um mit der Stimme
(-v
bedeutet voice) von "Boing" (der Name
entspricht denen, die man in den Systemeinstellungen findet) den Erfolg zu melden.
Wenn man den Dämon soweit per Hand eingerichtet hat, dann kann man sich einen Neustart ersparen, indem man ihn selbst lädt:
sudo launchctl load /Library/LaunchDaemons/de.realmacmark.dslnet.plist
Hier ist ein Installations-Programm von mir, das den oben beschriebenen Dämon installiert.
Die Sprachausgabe ist in dieser Version auskommentiert. Ein Neustart ist nach der Installation nicht nötig, denn der Dämon wird nach der Installation sofort geladen.
MD5-Prüfsumme 0186b616bca619991e08706dd6503d7d.
Dieser Dämon ruft beim Start des Rechners und danach alle zehn Minuten eine bestimmte Internetseite auf und übergibt ihre einige Daten. Einige Macs melden auf diese Weise ihre aktuelle IP-Adresse an meiner Homepage an, so daß ich jederzeit per SSH Fernwartung machen kann.
Der Dämon besteht aus zwei Dateien. In /Library/LaunchDaemons
liegt die
XML-Definition des Dämons in der Datei de.realmacmark.ips.plist
.
Der Inhalt ist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>de.realmacmark.ips</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/publish_ip.sh</string>
<string>http://www.realmacmark.de/geheim.php</string>
<string>rechner=bigbadbabyboy</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>600</integer>
<key>UserName</key>
<string>nobody</string>
</dict>
Der Inhalt dieses Beispiels ist natürlich etwas verändert, um keine Interna meiner Homepage zu veröffentlichen.
Im Property List Editor sieht es so aus:
Der ProgramArguments
-Eintrag hat als ersten Untereintrag das aufzurufende
Programm und als folgende Untereinträge die Parameter an das Programm. Auch dieser
Dämon ist so konfiguriert, daß er seine Aufgabe bereits einmal ausführt, wenn er selbst
geladen wird. Außerdem führt er das Programm alle 600 Sekunden erneut aus.
Da das Programm, was der Dämon ausführt (curl
), keine besonderen Rechte
benötigt, um zu funktionieren, habe ich als Benutzer, der das Programm ausführen soll,
den vom System für solche Zwecke bereitgehaltenen nobody
gewählt.
Die zweite Datei ist publish_ip.sh
, die ich im Verzeichnis
/usr/local/bin
gespeichert und mit
sudo chmod +x publish_ip.sh
ausführbar gemacht habe.
#!/bin/sh
/bin/sleep 30
/usr/bin/curl $1\?$2 > /dev/null
Das Skript macht am Anfang 30 Sekunden Pause, um nicht zu früh auf das Netzwerk zuzugreifen und außerdem, um launchd nicht den Eindruck zu geben, es wäre sofort abgestürzt, weil es zu schnell beendet wird. Dann ruft es eine Adresse im Internet auf, die sich aus dem ersten Parameter, der an dieses Skript übergeben wurde, einem Fragezeichen (das leitet die Parameterliste am Ende einer Web-Adresse ein) und dem zweiten Parameter zusammensetzt.
Dieser Agent begrüßt jeden Benutzer, wenn er sich am System anmeldet, per Sprachausgabe.
Für diesen Agenten mußte ich nur eine Datei selbst erstellen, weil ich
für seine Funktionalität auf ein bereits vorhandenes
Shell-Skript zurückgreife:
In /Library/LaunchAgents
lege ich die
XML-Definition des Agenten in der Datei de.realmacmark.say.plist
ab.
Der Inhalt ist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>de.realmacmark.say</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/say</string>
<string>-v</string>
<string>Vicki</string>
<string>Welcome to Macintosh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Im Property List Editor sieht es so aus:
Ein Agent wird von launchd immer, wenn sich
ein neuer Benutzer am Rechner anmeldet, für diesen individuell (als Kopie) geladen.
Dieser Agent ist so eingestellt, daß
er seine Aufgabe (say
) ausführt, wenn er selbst
geladen wird. Ein periodisches oder wiederholtes oder datumsgesteuertes
Ausführen wäre natürlich auch (zusätzlich) möglich.
Dem Programm say
wird als Parameter übergeben, daß es die Stimme von
Vicki verwenden soll, um "Welcome to Macintosh" zu sagen.