Script nach boot automatisch ausführen

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
Ich möchte ein Script beim boot von osx (11.5.2) automatisch starten. Dazu habe ich eine Anleitung gefunden, mit der die Datei rc.local beim boot ausgeführt werden soll. Daraus würde ich dann mein Script starten. Leider funktioniert das Ganze nicht.

Ich habe zuerst folgende Datei erstellt:


Code:
ls -l /Library/LaunchDaemons/local.localhost.startup.plist
-rw-r--r--  1 root  wheel  724 30 Aug 21:13 /Library/LaunchDaemons/local.localhost.startup.plist

mit folgendem Inhalt:

Code:
<?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>local.localhost.startup</string>
   <key>Disabled</key>
   <false/>
   <key>RunAtLoad</key>
   <true/>
   <key>KeepAlive</key>
   <false/>
   <key>LaunchOnlyOnce</key>
   <true/>
   <key>Program</key>
   <string>/bin/bash</string>
   <key>ProgramArguments</key>
   <array>
      <string>/etc/rc.local</string>
     </array>
   <key>StandardErrorPath</key>
   <string>/tmp/mycommand.err</string>
   <key>StandardOutPath</key>
  <string>/tmp/mycommand.out</string>
</dict>
</plist>

Außerdem habe rc.local erstellt:

Code:
ls -l /etc/rc.local
-rwxr-xr-x  1 root  wheel  134 Aug 30 21:01 /etc/rc.local

mit folgendem Inhalt:

Code:
#!/bin/bash
# rc.local script
# jba 2021-08-29

/bin/date >> /Users/jba/out.log

exit 0

Wenn ich rc.local von der Kommandozeile ausführe, funktioniert es (ein Zeitstempel erscheint in out.log). Beim booten passiert aber nichts. Auch
/tmp/mycommand.err und /tmp/mycommand.out sind leer. Es sieht so aus, als ob rc.local nicht ausgeführt wird.

Ich habe dann noch folgendes versucht:

Code:
launchctl load /Library/LaunchDaemons/local.localhost.startup.plist

oder

Code:
launchctl start /Library/LaunchDaemons/local.localhost.startup.plist

Aber auch hier passiert nichts.

Was stimmt hier nicht? Habe das in älteren Posts als Anleitungen gefunden und da scheint es funktioniert zu haben. Liegt es an der neueren osx Version?

Bin für jeden Hinweis dankbar.

jba
 

mausfang

Aktives Mitglied
Registriert
04.08.2016
Beiträge
2.221
Hol Dir die Software LaunchControl … musst Du nicht registrieren … tuts für das Debuggen in der Demo-Version … dann schau mal ob Du da Fehler angezeigt bekommst in Deiner plist …
 

lisanet

Aktives Mitglied
Registriert
05.12.2006
Beiträge
4.362
hhmm, du brauchst etliche keys überhaupt nicht. Es reicht folgende plist:

Code:
<?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>local.localhost.startup</string>
   <key>RunAtLoad</key>
   <true/>
   <key>Program</key>
   <string>/etc/rc.local</string>
   <key>StandardErrorPath</key>
   <string>/tmp/mycommand.err</string>
</dict>
</plist>

(wurde mit launchControl generiert)

Der redirect-Key für standard-out muss entfallen, sonst klappt dein redirect im script nicht. Es kann auch sein, dass auch der redirect für standard-error entfallen muss, damit das script läuft. Musst du probieren.

Beim Load-Kommando fehlt -w, also launchctl load -w ...

Zudem ist das kein daemon, sondern ein agent, also /Library/LaunchAgents. Und da das dann systemweit gelten soll, musst du das mit sudo launchctl load -w .... laden
 

oneOeight

Aktives Mitglied
Registriert
23.11.2004
Beiträge
59.987
Du solltest das aber nicht rc.local nennen.
Die Datei hatte in Unix Systemen eine andere Bedeutung.
Besser wäre doch so was wie logstartdate.sh
 

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
Du solltest das aber nicht rc.local nennen.
Die Datei hatte in Unix Systemen eine andere Bedeutung.
Besser wäre doch so was wie logstartdate.sh

Meiner Meinung nach ist das genau der richtige Name. rc.local wird unter vielen UNIXen beim booten aufgerufen und kann dazu benutzt werden, lokale Scripte zu starten. Und genau das möchte ich tun. Auch wenn osx mittlerweile keine rc.local mehr hat.

Das Datum zu schreiben, war ja nur ein Test um zu schauen, ob das Script ausgeführt wird. Also nur zum debuggen. Wenn es läuft kommt das raus.

jba
 

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
hhmm, du brauchst etliche keys überhaupt nicht. Es reicht folgende plist:

....

Zudem ist das kein daemon, sondern ein agent, also /Library/LaunchAgents. Und da das dann systemweit gelten soll, musst du das mit sudo launchctl load -w .... laden
Danke, jetzt scheint es zu laufen. Bin mir jetzt nicht ganz sicher, was den Unterschied gemacht hat. Ich vermute aber es lag vor allem daran, dass ich den falschen Ordner verwendet hatte.

jba
 

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
Hat leider doch nicht so funktioniert. Falls jemand anders später das gleiche Problem hat, hier die Lösung.

Zum einen funktioniert es leider nicht, eine /etc/rc.local Datei über launchd zu starten und daraus dann beliebige andere Sachen zu starten (so wie es unter Linux geht). Ist nämlich rc.local abgearbeitet, dann werden auch alle darin angestoßenen Prozesse gestoppt. Auch solche, die im Hintergrund weiterlaufen sollten - d.h. die mit "&" gestartet wurden.

Zum anderen konnte ich zwar mit
Code:
launchctl load -w /Library/LaunchAgents/local.localhost.startup.plist
das Skript starten, beim booten passierte jedoch nichts.

Deshalb habe ich jetzt folgendes gemacht: Ich habe das Script, das ich letztendlich starten möchte, direkt in die plist eingetragen (ursprünglich wollte ich es aus rc.local starten). Und da dann auch direkt notwendige Umleitungen definiert. Und ich habe das Script unter /Library/LaunchDaemons abgelegt.

Die plist sieht jetzt so aus:

Code:
<?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>local.batlog.startup</string>
   <key>RunAtLoad</key>          <true/>
   <key>Program</key>            <string>/usr/local/bin/batlog</string>
   <key>StandardErrorPath</key>  <string>/var/log/bat.log</string>
   <key>StandardOutPath</key>    <string>/var/log/bat.log</string>
</dict>
</plist>

Damit funktioniert es. Das Script /usr/local/bin/batlog wird bei jedem boot gestartet und die komplette Ausgabe auf /var/log/bat.log umgeleitet.

jba
 

lisanet

Aktives Mitglied
Registriert
05.12.2006
Beiträge
4.362
du denkst noch sehr in Linux-Wegen.

launchd ist da viel mächtiger als einfach nur was über ein script zu starten.


Ist nämlich rc.local abgearbeitet, dann werden auch alle darin angestoßenen Prozesse gestoppt. Auch solche, die im Hintergrund weiterlaufen sollten - d.h. die mit "&" gestartet wurden.

ist doch eigentlich klar, dass das so abläuft. Du hast rc.local als Batch script implementiert und rufst darin ein anderes script / binary auf und setzt das in den Hintegrund. Wenn du rc.local startest wird eine Shell-erzeugt, in der dann rc.local läuft. Beim Aufruf der enthaltenen scripte / binaries wird jeweils eine neue Sub-Shell erzeugt, deren Lebensdauer spätestens dann beendet wird, wenn die parent-shell (also diejenige in der rc.local läuft) beendet wird.

Und ich habe das Script unter /Library/LaunchDaemons abgelegt.

Auch wenn das nur deklaratorisch ist, und auf die Funktion keinen Einfluss hat, LauchDaemons ist für daemons (das sind Dienste die dauernd laufen und nicht beendet werden sollen, wie z.B. ein smb-server) und LaunchAgents ist für agents (das ist das was du programmierst. agents, starten, führen eine Funktion aus und werden dann wieder beendet)

launchd übenimmt unter anderem nun, anders als rc.local (SystemV init) aber ähnlich wie systemd unter Linux, das handling für die daemons und sorgt dafür, dass ein daemon, sollte er mal durch einen Fehler oder ähnliches, beendet werden, wieder erneut gestartet wird.

launchd ersetzt auch komplett cron und sorgt z.Bsp, anders als cron, auch dafür, dass ein agent, der zu einer bestimmten Uhrzeit gestartet werden soll, dann "nachgeholt" wird, wenn zur Uhrzeit der Rechner gerade im Sleep ist.
 

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
du denkst noch sehr in Linux-Wegen.

Nunja, beides sind Unixe. Der Versionsstand mag da anders sein. Bin z.B. darüber gestolpert, dass sich head anders verhält. Das liegt aber wohl daran, dass die osx-Version von 1993 ist.

Ansonsten ist da sehr viel identisch. launchd ist aber eben nicht systemd.


jba66 schrieb:

Ist nämlich rc.local abgearbeitet, dann werden auch alle darin angestoßenen Prozesse gestoppt. Auch solche, die im Hintergrund weiterlaufen sollten - d.h. die mit "&" gestartet wurden.

ist doch eigentlich klar, dass das so abläuft. Du hast rc.local als Batch script implementiert und rufst darin ein anderes script / binary auf und setzt das in den Hintegrund. Wenn du rc.local startest wird eine Shell-erzeugt, in der dann rc.local läuft. Beim Aufruf der enthaltenen scripte / binaries wird jeweils eine neue Sub-Shell erzeugt, deren Lebensdauer spätestens dann beendet wird, wenn die parent-shell (also diejenige in der rc.local läuft) beendet wird.

Das ist nicht ganz richtig. Starte ich aus einem Script einen anderen Prozess und setze diesen mit "&" in den Hintergrund, dann läuft dieser Prozess auch weiter, wenn der ursprüngliche Prozess beendet ist.

Wenn alle erzeugten Prozesse hier beendet werden, dann muss das explizit von launchd gemacht werden. Das liegt zumindest nicht an der Shell.


jba66 schrieb:

Und ich habe das Script unter /Library/LaunchDaemons abgelegt.

Auch wenn das nur deklaratorisch ist, und auf die Funktion keinen Einfluss hat, LauchDaemons ist für daemons (das sind Dienste die dauernd laufen und nicht beendet werden sollen, wie z.B. ein smb-server) und LaunchAgents ist für agents (das ist das was du programmierst. agents, starten, führen eine Funktion aus und werden dann wieder beendet)
Ich hatte das nicht erwähnt, aber was ich vorhatte war einen Daemon zu starten. LaunchDaemons passt also.

Was ist dann aber der genaue Unterschied zwischen Daemons und Agents? Wenn ich dich richtig verstehe werden die doch gleich gestartet. Killt launchd einen Agent, wenn er nicht nach bestimmter Zeit fertig ist? Aber woher weiß launchd, wie lange der Agent für seine Aufgabe braucht? Und wenn er ihn nicht kilt, was ist dann der Unterschied zwischen den beiden Kategorien?

Kann es eventuell sein, dass der Agent einen Trigger braucht, um gestartet zu werden? Da hatte ich nichts angegeben. Und das booten reicht offensichtlich nicht aus, um ihn zu starten. Erst als ich die plist nach LaunchDaemons verschoben hatte, wurde das Script beim booten ausgeführt.

launchd übenimmt unter anderem nun, anders als rc.local (SystemV init) aber ähnlich wie systemd unter Linux, das handling für die daemons und sorgt dafür, dass ein daemon, sollte er mal durch einen Fehler oder ähnliches, beendet werden, wieder erneut gestartet wird.

launchd ersetzt auch komplett cron und sorgt z.Bsp, anders als cron, auch dafür, dass ein agent, der zu einer bestimmten Uhrzeit gestartet werden soll, dann "nachgeholt" wird, wenn zur Uhrzeit der Rechner gerade im Sleep ist.

Unter Linux gibt es ja sytemd als init-System, was ziemlich vergleichbare Aufgaben erfüllt. Trotzdem gibt es eine rc.local und das ist sehr praktisch. Da kann man kleiner Hacks einfach eintragen und weiß, dass sie beim nächsten boot ausgeführt werden. Und mit "&" laufen sie auch weiter, wenn rc.local durch ist.

jba
 

appelg4

Neues Mitglied
Registriert
02.08.2021
Beiträge
6
Agents werden im Auftrag eines Users ausgeführt der dafür angemeldet sein muss.
Daemons werden unabhängig davon gestartet, sie können auch ausgeführt werden wenn kein Benutzer am System angemeldet ist. Deshalb gibt es auch kein ~/Library/LaunchDaemons
 

oneOeight

Aktives Mitglied
Registriert
23.11.2004
Beiträge
59.987
Das ist nicht ganz richtig. Starte ich aus einem Script einen anderen Prozess und setze diesen mit "&" in den Hintergrund, dann läuft dieser Prozess auch weiter, wenn der ursprüngliche Prozess beendet ist.

Wenn alle erzeugten Prozesse hier beendet werden, dann muss das explizit von launchd gemacht werden. Das liegt zumindest nicht an der Shell.
Das ist auch nicht ganz richtig, wenn der Parent geschlossen wird, dann werden auch die Child Prozesse geschlossen.
Das merkst bei anderen Systemen auch, speziell wenn du dich remote einloggst und nicht mit nohup oder screen die Prozesse am laufen hältst, bevor du dich ausloggst.
 

lisanet

Aktives Mitglied
Registriert
05.12.2006
Beiträge
4.362
Das ist nicht ganz richtig. Starte ich aus einem Script einen anderen Prozess und setze diesen mit "&" in den Hintergrund, dann läuft dieser Prozess auch weiter, wenn der ursprüngliche Prozess beendet ist.

nee. Endet der Parent-Prozess (hier die shell von rc.local) enden auch die childs (hier die sub-Shell).

Was ist dann aber der genaue Unterschied zwischen Daemons und Agents? Wenn ich dich richtig verstehe werden die doch gleich gestartet. Killt launchd einen Agent, wenn er nicht nach bestimmter Zeit fertig ist? Aber woher weiß launchd, wie lange der Agent für seine Aufgabe braucht? Und wenn er ihn nicht kilt, was ist dann der Unterschied zwischen den beiden Kategorien?

dameons laufen üblicher "dauerhaft" im Hintergrund. Sie sind services für alle User. Werden sie beendet, startet launchd sie erneut. Keyword: KeepAlive = true

agents starten, erledigen eine Aufgabe, enden. KeepAlive = true macht sie zu services für den User und im Grunde dann zu daemons. Agents benötigen immer einen eingeloggten User: /Library/LauchAgents = irgendein User, ~/Library/LaunchAgents = nur der spezifische User

Die manpage von launchd.plist gibt dir auch weitere Infos, was ein daemon bzw agent machen sollte / nicht machen sollte oder machen muss.

launchd erlaubt es, bis auf die Usergebundenheit, beides gleich zu nutzen, wobei eben die Konvention daemon für dauerhaft laufende Dienste steht.

Kann es eventuell sein, dass der Agent einen Trigger braucht, um gestartet zu werden? Da hatte ich nichts angegeben. Und das booten reicht offensichtlich nicht aus, um ihn zu starten. Erst als ich die plist nach LaunchDaemons verschoben hatte, wurde das Script beim booten ausgeführt.

Jeder Job benötigt einen Trigger um gestartet zu werden, sei es nun das daemons bei booten gestartet werden, agents bei login eines Users, oder durch explizites starten oder durch einen Trigger der Keys StartIntervall, StartCalenderIntervall.
 

jba66

Neues Mitglied
Thread Starter
Registriert
06.09.2021
Beiträge
6
jba66 schrieb:
Das ist nicht ganz richtig. Starte ich aus einem Script einen anderen Prozess und setze diesen mit "&" in den Hintergrund, dann läuft dieser Prozess auch weiter, wenn der ursprüngliche Prozess beendet ist.

nee. Endet der Parent-Prozess (hier die shell von rc.local) enden auch die childs (hier die sub-Shell).
Vielleicht reden wir hier aneinander vorbei, aber wenn ich folgendes Script starte, geht die Ausgabe von ping weiter, auch wenn das Script selber längst durch ist.

Bash:
#!/bin/bash
ping www.heise.de &
exit 0

Das ist auch nicht ganz richtig, wenn der Parent geschlossen wird, dann werden auch die Child Prozesse geschlossen.
Das merkst bei anderen Systemen auch, speziell wenn du dich remote einloggst und nicht mit nohup oder screen die Prozesse am laufen hältst, bevor du dich ausloggst.
Zumindest unter Linux laufen die Prozesse auch nach dem ausloggen weiter. Kanns grad nicht unter osx ausprobieren, aber ich nehme an da ist es nicht anders.

Oder meint ihr etwas anderes?

Agents benötigen immer einen eingeloggten User: /Library/LauchAgents = irgendein User, ~/Library/LaunchAgents = nur der spezifische User

Damit ist ein Agent dann auch ungeeignet für meine Aufgabe, da ich ja etwas beim booten starten möchte. da muss sich ja nicht unbedingt ein spezieller User einloggen.

jba
 

lisanet

Aktives Mitglied
Registriert
05.12.2006
Beiträge
4.362
stimmt. Dann kann ich es dir nicht anders erklären, als dass ping ein SIGTERM und/oder SIGINT anders handhabt, als die Befehle in deinem bash-script. Oder eben launchd explizit SIGTERM an alle Prozesse sendet. Sieh dir mal die manpage von launchd.plist an.

Edit:

Zudem ist in launchd.plist explizit angegeben, dass daemons nicht explizit in den Hintergrund geschickt werden sollen.
 
Oben Unten