Wie lasse ich eine SDL-App (die nicht als Root ausgeführt wird) die Konsole verwenden


13

Ich möchte ein SDL-basiertes Programm verwenden, um Grafiken auf der Konsole anzuzeigen, ohne mich von der Konsole aus anmelden zu müssen und ohne das Programm als Root auszuführen. Zum Beispiel möchte ich es über ssh ausführen können. Das Ziel-Betriebssystem ist Raspbian.

Hier ist ein kurzes Beispiel in Python, um das Problem zu veranschaulichen:

import os, pygame
os.environ['SDL_VIDEODRIVER'] = 'fbcon'
pygame.init()
s = pygame.display.set_mode()
print "Success"

Dies funktioniert (läuft bis zum Abschluss, wirft keine Ausnahmen), wenn ich es von der Konsole aus starte, und es funktioniert über ssh, wenn ich es als root starte.

Ich habe überprüft, ob sich mein Benutzer in den Audio- und Videogruppen befindet.

Ich habe strace benutzt, um zu sehen, was anders ist, als es von der Konsole aus (was funktioniert), als root über ssh (funktioniert auch) und als normaler Benutzer über ssh (funktioniert nicht) auszuführen.

Der erste Unterschied war, dass mein Benutzer keine Zugriffsberechtigung für / dev / tty0 hatte. Ich habe eine neue Gruppe (tty0) erstellt, meinen Benutzer in diese Gruppe aufgenommen und eine udev-Regel hinzugefügt, um dieser Gruppe Zugriff auf / dev / tty0 zu gewähren.

Die Ausgabe von strace weicht bei diesem ioctl-Aufruf ab - der Fehler wird hier angezeigt. ioctl gibt 0 zurück, wenn das Programm von der Konsole oder von ssh als root ausgeführt wird:

open("/dev/tty", O_RDWR)                = 4
ioctl(4, VT_GETSTATE, 0xbeaa01f8)       = -1 EINVAL (Invalid argument)

(Die Adressen unterscheiden sich auch, aber das ist nicht wichtig.)

Angesichts der Tatsache, dass mein Programm als Root ausgeführt wird, bedeutet dies, dass ich ein Berechtigungsproblem habe. Wie erteile ich meinem Benutzer die erforderlichen Berechtigungen, um dieses Programm ausführen zu können, ohne sich an der Konsole anzumelden (und ohne als Root ausgeführt zu werden)?


Was sind die Eigentumsrechte / Berechtigungen auf Ihrem Framebuffer-Gerät?
Bandrami

Außerdem erfordert / dev / tty im Allgemeinen eine Mitgliedschaft in der Konsolengruppe, in die geschrieben werden soll.
Bandrami

ajclarkson.co.uk/blog/pygame-no-root sieht aus wie eine Lösung.
Arthur2e5

Antworten:


3

Mein Ziel war das gleiche wie beim ursprünglichen Poster, aber mit einem Unterschied: Ich musste die SDL-Anwendung als systemd-Daemon ausführen. Mein Linux-Rechner ist Raspberry Pi 3 und das Betriebssystem ist Raspbian Jessie. Es ist keine Tastatur oder Maus mit RPi verbunden. Ich verbinde mich mit SSH. Meine SDL-App ist eigentlich eine Pygame- basierte App. Ich habe pygame / SDL so eingestellt, dass der Framebuffer-Treiber "fbcon" über die Umgebungsvariable SDL_VIDEODRIVER verwendet wird. Meine systemd --versionAusgabe ist:

systemd 215 + PAM + AUDIT + SELINUX + IMA + SYSVINIT + LIBCRYPTSETUP + GCRYPT + ACL + XZ -SECCOMP -APPARMOR

Meine Pygame-Paketversion ist: ( aptitude show python-pygame):

1.9.2 ~ pre ~ r3348-2 ~ bpo8 + rpi1

Meine libSDL 1.2 Version ist: ( aptitude show libsdl1.2debian- auf Ihrem Rechner kann der Paketname unterschiedlich sein):

1.2.15-10 + rpi1

Das Rezept

  1. Richten Sie die Berechtigungen für die Dateien / dev / tty und / dev / fb0 ein, wie in der Antwort von UDude beschrieben. Ich habe festgestellt, dass in Raspbian Jessie / dev / console keine Berechtigungsänderungen erforderlich sind.
  2. Fügen Sie diese Zeilen zum Abschnitt [Service] der .service-Datei Ihres Daemons hinzu:

    User=pi #Your limited user name goes here
    StandardInput=tty
    StandardOutput=tty
    TTYPath=/dev/tty2   # I also tried /dev/tty1 and that didn't work for me
    

    Falls jemand Interesse hat, hier ist die vollständige pyscopefb.service-Datei, die ich verwendet habe:

    [Unit]
    Description=Pyscopefb test service 
    Wants=network-online.target
    After=rsyslog.service
    After=network-online.target
    
    [Service]
    Restart=no
    ExecStart=/home/pi/Soft/Test/pygame/pyscopefb
    ExecStop=/bin/kill -INT $MAINPID
    OOMScoreAdjust=-100
    TimeoutStopSec=10s
    User=pi
    WorkingDirectory=/home/pi/Soft/Test/pygame
    StandardInput=tty
    StandardOutput=tty
    TTYPath=/dev/tty2
    
    [Install]
    WantedBy=multi-user.target
    
  3. Geben Sie diese Befehle in der Eingabeaufforderung ein (ich nehme an, dass die Datei pyscopefb.service bereits an der richtigen Stelle abgelegt ist, an der systemd sie finden kann):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Das funktioniert für mich. Bitte beachten Sie, dass ich nicht getestet habe, ob die Pygame-Anwendung Tastatur- und Mausereignisse empfangen kann oder nicht.

Bonus

Ich musste auch zwei andere Probleme lösen, die ebenfalls von Interesse sein könnten

  1. Es gab einen blinkenden Textcursor am unteren Rand des Bildschirms mit Framebuffer-Grafiken. Um dies zu beheben, habe ich meiner Anwendung den folgenden Python-Code hinzugefügt, der in meiner Anwendung vor der Pygame / SDL-Initialisierung ausgeführt wird:

    def _disable_text_cursor_blinking(self):
        command_to_run = ["/usr/bin/sudo", "sh", "-c", "echo 0 > /sys/class/graphics/fbcon/cursor_blink"]
        try:
            output = subprocess32.check_output(command_to_run, universal_newlines = True)
            self._log.info("_disable_text_cursor_blinking succeeded! Output was:\n{output}", output = output)
        except subprocess32.CalledProcessError:
            self._log.failure("_disable_text_cursor_blinking failed!")
            raise
    
  2. Nach ungefähr 10 Minuten wurde der an den HDMI-Ausgang von Raspberry Pi angeschlossene Bildschirm schwarz (aber nicht ausgeschaltet) und meine Grafiken wurden nicht angezeigt, obwohl Pygame keine Fehler meldete. Dies stellte sich als Stromsparfunktion heraus. Um dies zu deaktivieren, habe ich den folgenden Python-Code hinzugefügt, der auch vor der Pygame / SDL-Initialisierung ausgeführt wird:

    def _disable_screen_blanking(self):
        command_to_run = ["/usr/bin/setterm", "--blank", "0"]
        try:
            output = subprocess32.check_output(command_to_run, universal_newlines = True)
            self._log.info("_disable_screen_blanking succeeded! Output was:\n{output}", output = output)
        except subprocess32.CalledProcessError:
            self._log.failure("_disable_screen_blanking failed!")
            raise
    

1
Dies war sehr hilfreich für mich, um Pygame zu starten, ohne dass eine Tastatur mit meinem Pi verbunden ist. Vielen Dank! Ich wollte erwähnen, dass ich es einfach genug fand, Pygame auszuführen /dev/tty7und ein auszugeben ExecStartPre=/bin/chvt 7, um die Cursor-Sache zu vermeiden, und dass es den Bonus hat, nicht mit agetty zu kollidieren, das standardmäßig auf tty1 – tty6 läuft.
Ducker

2

Obwohl Ihre Frage etwas mehrdeutig ist (was mit Konsole gemeint ist), werde ich versuchen, die häufigsten Fälle zu beantworten: / dev / console, / dev / tty, / dev / fb0 ... passen Sie dies an die Geräte an, die Sie benötigen. Wir gehen davon aus, dass der Benutzername "myuser" ist.

Schauen Sie sich die Berechtigungen des Geräts an (dies ist Ubuntu 15.04)

odroid@mbrxu3:~/projects/sc$ ls -l /dev/console
crw------- 1 root root 5, 1 Oct  23  17:49 /dev/console

odroid@mbrxu3:~/projects/sc$ ls -l /dev/tty
crw-rw-rw- 1 root tty 5, 0 Oct 24 17:50 /dev/tty

odroid@mbrxu3:~/projects/sc$ ls -l /dev/fb0 
crw-rw---- 1 root video 29, 0 Jan  1  2000 /dev/fb0

Handeln Sie

/ dev / console

Die Gruppe ist "root", es ist jedoch kein Gruppenzugriff zulässig. Ich mag es nicht, der Stammgruppe nur Berechtigungen hinzuzufügen, sondern erstelle stattdessen eine Gruppe, chgrp die Datei und ändere die Berechtigungen

$ sudo addgroup --system console
$ sudo chgrp console /dev/console
$ sudo chmod g+rw /dev/console
$ sudo usermod -a -G console <myuser>     <==== replace <myuser>

/ dev / tty

$ sudo usermod -a -G tty <myuser>

/ dev / fb0

$ sudo usermod -a -G video <myuser> 

Sie können den Befehl usermod verwenden , um Ihren Benutzer auch allen oben genannten Gruppen hinzuzufügen, falls dies erforderlich ist.


-1

Nach meinen jüngsten Erfahrungen müssen Sie neben der Erteilung der Erlaubnis für Ihr tty-Gerät (wie oben erwähnt) zwei weitere Dinge tun:

  • Erteilen der Funktion cap_sys_tty_config für die ausführbare Datei. Wenn Sie ein Python-Programm verwenden, können Sie es wie setcap cap_sys_tty_config+eip /usr/bin/python3.5folgt machen (ersetzen Sie den Pfad für Python durch Ihren). Beachten Sie natürlich, dass Sie diese Funktion für jedes Python-Skript gewähren.
  • Den Prozess in einem neuen virtuellen Terminal ausführen, z. B. mit openvt: openvt ./your_script.py
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.