Ich habe Raspberry Pi mit installiertem Standard-Raspbian. Ich habe auch RetroPI installiert, das einwandfrei funktioniert.
Ich wollte ein kleines Autostart-Skript schreiben, das Emulationstation (Retropi-Hauptlaufskript) startet, wenn das Gamepad über Bluetooth verbunden ist. Ich habe eine einfache Udev-Regel erstellt.
pi@raspberrypi:~ $ cat /etc/udev/rules.d/99-zlocal.rules
SUBSYSTEM=="bluetooth",SUBSYSTEMS=="amba", ATTRS{id}=="00241011", ACTION=="add", RUN+="/usr/local/bin/emulator-controll.sh start"
das funktioniert wie erwartet, das Skript wird ausgeführt, wenn das Gamepad gekoppelt wird.
Das Problem ist, dass wenn ich mein Skript über SSH ausführe, wie
sudo emulator-controll.sh start #sudo is optional here, but I want the same conditions as in udev trigger context
Emulationstation wie erwartet.Wenn jedoch dasselbe Skript als Aktionsauslöser für die obige udev-Regel verwendet wird, schlägt es fehlmit Fehlern wie
Wed Aug 21 00:02:33 CEST 2019
Invoking user: root
Invoked start command
Invoking emulation station start command
Done
'unknown': I need something more specific.
tput: unknown terminal "unknown"
Segmentation fault
/usr/bin/emulationstation: line 23: /dev/tty: No such device or address
tput: unknown terminal "unknown"
Ich glaube, dass aus irgendeinem Grund (ich bin ein Linux-Neuling) TTY vom Udev-Triggerkontext aus nicht zugänglich ist. Kann ich das irgendwie beheben?
PS. Ich habe versucht, einen Hintergrund-Daemon auszuführen (um benannte Pipes zu verwenden), der beim Booten gestartet wird, aber der Effekt ist genau der gleiche – kein TTY im Kontext der Skriptausführung, was mich glauben lässt, dass dies das allgemeine Verhalten von Hintergrundaufgaben ist
Das Skript selbst ist meiner Meinung nach irrelevant, aber ich werde es der Übersichtlichkeit halber ebenfalls angeben:
#!/bin/bash
#/bin/date >> /tmp/udev.log
#env >> /tmp/udev.log
#echo "Connected" > /dev/pts/2
log=/var/log/emulator-controll.log
{
readarray -t PIDS <<< $(ps aux | grep [e]mulationstation | awk '{print $2}')
echo ">${PIDS[@]}<"
echo >> $log
/bin/date >> $log
echo "Invoking user: $(whoami)"
case "$1" in
start )
echo "Invoked start command" >> $log
if [[ "${#PIDS[@]}" -ge 3 ]]; then
echo "Emulator is already running. No action is taken" >> $log
else
echo "Invoking emulation station start command" >> $log
export DISPLAY=:0
sudo -u pi nohup emulationstation &
fi
echo "Done" >> $log
;;
stop )
echo "Invoked stop command" >> $log
if [[ -z "${PIDS[0]}" ]]; then
echo "Emulator is not running, no action is taken" >> $log
else
echo "Killing processes with PIDs ${PIDS[@]}" >> $log
for pid in "${PIDS[@]}"; do
kill $pid
done
echo "Done" >> $log
fi
;;
*)
echo "Usage: $0 {start|stop}"
esac
} >> $log 2>>$log
Antwort1
Anstatt zu versuchen, ein Skript an TTY anzuhängen oder TTY dem Skript zuzuweisen, habe ich mein Ziel erreicht, indem ich den Befehl folgendermaßen direkt in den Eingabepuffer des Ziel-TTY eingefügt habe:
sudo writevt /dev/tty1 "emulationstation $(echo -ne '\r')"
Geben Sie dazu den Befehl ein und drücken Sie auf dem Hauptterminal die Eingabetaste.
PS. writevt
ist Teil von console-tools
und das ist auf Raspbian verfügbar (zumindest heute)
Antwort2
Wenn der Kernel udev
im Rahmen der Regeln Aktionen auslöst und Skripte ausführt, ist die Umgebung dieser Skripte sehr eingeschränkt.
An einem einzigen Linux-Computer können mehrere Benutzer gleichzeitig angemeldet sein, jeder Benutzer mit mehreren TTYs.Natürlichein vom Kernel ausgeführtes Skript hat kein TTY: Dieses Skript wurde von keinem Benutzer gestartet. Selbst wenn man ihm also ein TTY zuweisen könnte, welches der vielen verwendeten TTYs sollte es sein? Und dasselbe gilt für eine X-Verbindung (was ebenfalls häufig gefragt wird).
Es gibt noch weitere Einschränkungen, wie Sie hier sehen können man 7 udev
:
LAUFEN
Fügt ein Programm zur Liste der Programme hinzu, die für ein bestimmtes Gerät ausgeführt werden sollen. Dies kann nur für sehr kurz laufende Aufgaben verwendet werden. Das Ausführen eines Ereignisprozesses über einen langen Zeitraum kann alle weiteren Ereignisse für dieses oder ein abhängiges Gerät blockieren. Lang laufende Aufgaben müssen sofort vom Ereignisprozess selbst getrennt werden. Wenn die Option RUN{fail_event_on_error} angegeben ist und das ausgeführte Programm einen Wert ungleich Null zurückgibt, wird das Ereignis für eine mögliche spätere Bearbeitung als fehlgeschlagen markiert.
Wenn ich Ihr Skript richtig verstehe, möchten Sie auf einer bestimmten X-Verbindung etwas starten oder stoppen, das sehr lange laufen wird. Dies kann nur funktionieren, wenn Sie Ihre Aufgabe in zwei Aufgaben aufteilen: Lassen Sie eine Art Dämon starten, der gestartet wird, wenn der entsprechende X-Server gestartet wird (der X-Server muss gestartet werden, damit Sie das Autorisierungscookie erhalten können), und sagen Sie dem Dämon dann im udev-Ausführungsskript, dass er bestimmte Dinge tun soll, z. B. einen Dienst starten oder stoppen.
Auf diese Weise kann das Udev-Run-Skript sofort beendet werden.
Wenn Sie systemd verwenden, können Sie eine Unit auch über eine udev-Regel starten (siehe z. B.Hier).
Bearbeiten
Wenn Sie verwenden möchten , sollten Sie den darauf ausgeführten tty1
Anmeldedienst ( ) in Ihren Dämon ändern, den Sie dann vom Skript aus auslösen können.getty
tty1
Also zBHierEinzelheiten zu einer möglichen Vorgehensweise können je nach Bedarf variieren.