Jak pozwolić aplikacji SDL (nie działającej jako root) korzystać z konsoli

14

Chcę używać programu opartego na SDL do wyświetlania grafiki na konsoli, bez konieczności logowania się z konsoli i bez uruchamiania programu jako root. Na przykład chcę móc go uruchomić za pośrednictwem ssh. Docelowym systemem operacyjnym jest raspbian.

Oto krótki przykład w Pythonie, aby zilustrować problem:

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

Działa to (działa do końca, nie zgłasza wyjątków), jeśli uruchomię go z konsoli i działa przez ssh, jeśli uruchomię go jako root.

Sprawdziłem, czy mój użytkownik jest w grupach audio i wideo.

Użyłem strace, aby zobaczyć, co różni się między uruchomieniem go z konsoli (co działa), uruchomieniem go jako root za pośrednictwem ssh (również działa) i uruchomieniem go jako zwykłego użytkownika za pomocą ssh (nie działa).

Pierwszą różnicą było to, że mój użytkownik nie miał uprawnień dostępu do / dev / tty0. Utworzyłem nową grupę (tty0), umieściłem mojego użytkownika w tej grupie i dodałem regułę udev, aby dać tej grupie dostęp do / dev / tty0.

Wyjście strace różni się przy tym wywołaniu ioctl - tutaj pokazana jest awaria; ioctl zwraca 0, gdy program jest uruchamiany z konsoli lub z ssh jako root:

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

(Adresy też się różnią, ale to nie jest ważne).

Biorąc pod uwagę, że mój program działa, gdy działa jako root, myślę, że to oznacza, że ​​mam problem z uprawnieniami. Jak przyznać mojemu użytkownikowi niezbędne uprawnienia, aby móc uruchomić ten program bez logowania się na konsoli (i bez uruchamiania jako root)?

Michael
źródło
Jakie są prawa własności / uprawnienia do urządzenia buforującego ramki?
Bandrami
Również / dev / tty zazwyczaj wymaga członkostwa w grupie konsoli, aby pisać.
Bandrami
ajclarkson.co.uk/blog/pygame-no-root wygląda jak rozwiązanie.
Arthur2e5

Odpowiedzi:

3

Mój cel był taki sam jak w przypadku oryginalnego plakatu, ale z jedną różnicą: musiałem uruchomić aplikację SDL jako demon systemd. Mój komputer z systemem Linux to Raspberry Pi 3, a system operacyjny to Raspbian Jessie. Do RPi nie jest podłączona klawiatura ani mysz. Łączę się z nim za pomocą SSH. Moja aplikacja SDL jest w rzeczywistości aplikacją opartą na Pygame . Ustawiam pygame / SDL, aby używało sterownika bufora ramki „fbcon” za pośrednictwem zmiennej środowiskowej SDL_VIDEODRIVER. Moje systemd --versionwyniki to:

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

Moja wersja pakietu pygame to: ( aptitude show python-pygame):

1.9.2 ~ pre ~ r3348-2 ~ bpo8 + rpi1

Moja wersja libSDL 1.2 to: ( aptitude show libsdl1.2debian- na twoim komputerze nazwa pakietu może być inna):

1.2.15-10 + rpi1

Przepis

  1. Ustaw uprawnienia dla plików / dev / tty i / dev / fb0 zgodnie z opisem w odpowiedzi UDude. Odkryłem, że zmiany uprawnień / dev / console nie są konieczne w Raspbian Jessie.
  2. Dodaj następujące wiersze do sekcji [Service] pliku .service demona:

    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
    

    Jeśli ktoś jest zainteresowany, oto kompletny plik pyscopefb.service, którego użyłem:

    [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. Wydaj te polecenia w wierszu polecenia (zakładam, że plik pyscopefb.service jest już umieszczony we właściwej lokalizacji, w której systemd może go znaleźć):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

To działa dla mnie. Uwaga: nie testowałem, czy aplikacja pygame może odbierać zdarzenia z klawiatury i myszy, czy nie.

Premia

Musiałem też rozwiązać kolejne 2 problemy, które również mogą być interesujące

  1. Na dole ekranu migał kursor tekstowy z grafiką bufora ramki. Aby rozwiązać ten problem, dodałem do mojej aplikacji następujący kod Python, który działa w mojej aplikacji przed inicjalizacją Pygame / SDL:

    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. Po około 10 minutach ekran podłączony do wyjścia HDMI Raspberry Pi stał się czarny (ale nie wyłączony) i moja grafika nie wyświetlała się, chociaż Pygame nie zgłosiła błędów. Okazało się to funkcją oszczędzania energii. Aby to wyłączyć, dodałem następujący kod Python, który również działa przed inicjalizacją Pygame / SDL:

    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
    
Roman Me
źródło
1
Pomogło mi to w rozpoczęciu gry bez konieczności podłączania klawiatury do mojego Pi, więc dziękuję! Chciałem wspomnieć, że uznałem, że dość łatwo jest uruchomić grę pygame /dev/tty7i wydać ExecStartPre=/bin/chvt 7polecenie unikania kursora, i ma tę zaletę, że nie koliduje z agetty, które domyślnie działa na tty1 – tty6.
dctucker
2

Chociaż pytanie jest nieco dwuznaczne (co rozumie się przez konsolę), spróbuję odpowiedzieć na najczęstsze przypadki: / dev / console, / dev / tty, / dev / fb0 ... dostosuj to do potrzebnych urządzeń. Zakładamy, że nazwa użytkownika to „mój użytkownik”.

Spójrz na uprawnienia urządzenia (jest to 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

Działaj

/ dev / console

grupa jest „root”, ale dostęp do grupy nie jest dozwolony. Nie lubię tylko dodawać uprawnień do grupy głównej, więc zamiast tego tworzę grupę, chgrp plik i zmieniam uprawnienia

$ 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> 

Możesz użyć polecenia usermod, aby dodać użytkownika również do wszystkich powyższych grup, jeśli tego potrzebujesz.

UDude
źródło
-1

Z mojego niedawnego doświadczenia, oprócz udzielenia pozwolenia na twoje urządzenie tty (jak wspomniano wcześniej), musisz zrobić 2 dodatkowe rzeczy:

  • przyznanie możliwości cap_sys_tty_config dla pliku wykonywalnego. Jeśli używasz programu python, możesz to zrobić podobnie setcap cap_sys_tty_config+eip /usr/bin/python3.5(zastąp ścieżkę python swoją). Oczywiście, weź pod uwagę, że przyznajesz tę możliwość dla dowolnego skryptu Pythona.
  • uruchomienie procesu w nowym terminalu wirtualnym, np. przy użyciu openvt: openvt ./your_script.py
Eriks Dobelis
źródło