Come faccio a consentire a un'app SDL (non in esecuzione come root) di utilizzare la console


14

Voglio utilizzare un programma basato su SDL per visualizzare la grafica sulla console, senza dover accedere dalla console e senza eseguire il programma come root. Ad esempio, voglio essere in grado di eseguirlo tramite SSH. Il sistema operativo di destinazione è raspbian.

Ecco un breve esempio in Python per illustrare il problema:

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

Funziona (funziona fino al completamento, non genera eccezioni) se lo eseguo dalla console e funziona tramite ssh se lo eseguo come root.

Ho verificato che il mio utente sia nei gruppi audio e video.

Ho usato strace per vedere cosa c'è di diverso tra eseguirlo dalla console (che funziona), eseguirlo come root tramite ssh (funziona anche) ed eseguirlo come utente normale tramite ssh (non funziona).

La prima differenza era che il mio utente non aveva il permesso di accedere a / dev / tty0. Ho creato un nuovo gruppo (tty0), ho inserito il mio utente in quel gruppo e ho aggiunto una regola udev per dare a quel gruppo l'accesso a / dev / tty0.

L'output di strace differisce da questa chiamata ioctl - l'errore viene mostrato qui; ioctl restituisce 0 quando il programma viene eseguito dalla console o eseguito da ssh come root:

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

(Anche gli indirizzi differiscono, ma questo non è importante.)

Dato che il mio programma funziona quando funziona come root, penso che questo significhi che ho un problema con le autorizzazioni. Come posso fornire le autorizzazioni necessarie al mio utente per poter eseguire questo programma senza accedere alla console (e senza eseguirlo come root)?


Quali sono le proprietà / autorizzazioni sul dispositivo framebuffer?
Bandrami,

Inoltre / dev / tty richiede generalmente l'appartenenza al gruppo console su cui scrivere.
Bandrami,

Risposte:


3

Il mio obiettivo era lo stesso di quello del poster originale, ma con una differenza: dovevo eseguire l'applicazione SDL come demone systemd. La mia macchina Linux è Raspberry Pi 3 e il sistema operativo è Raspbian Jessie. Non ci sono tastiere o mouse collegati a RPi. Mi collego ad esso tramite SSH. La mia app SDL è in realtà un'app basata su Pygame . Ho impostato pygame / SDL per utilizzare il driver framebuffer "fbcon" tramite la variabile di ambiente SDL_VIDEODRIVER. La mia systemd --versionuscita è:

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

La mia versione del pacchetto pygame è: ( aptitude show python-pygame):

1.9.2 ~ pre ~ ~ r3348-2 bpo8 + rpi1

La mia versione di libSDL 1.2 è: ( aptitude show libsdl1.2debian- sul nome del pacchetto della macchina può essere diverso):

1.2.15-10 + rpi1

La ricetta

  1. Imposta le autorizzazioni per i file / dev / tty e / dev / fb0 come descritto nella risposta di UDude. Ho scoperto che le modifiche alle autorizzazioni / dev / console non sono necessarie in Raspbian Jessie.
  2. Aggiungi queste righe alla sezione [Servizio] del file .service del tuo demone:

    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
    

    Nel caso qualcuno fosse interessato, ecco il file pyscopefb.service completo che ho usato:

    [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. Immettere questi comandi nel prompt dei comandi (suppongo che il file pyscopefb.service sia già posizionato nella posizione corretta in cui systemd possa trovarlo):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Questo funziona per me. Nota che non ho verificato se l'applicazione pygame è in grado di ricevere o meno eventi da tastiera e mouse.

indennità

Ho anche dovuto risolvere altri 2 problemi che potrebbero essere di interesse

  1. C'era un cursore di testo lampeggiante nella parte inferiore dello schermo con grafica framebuffer. Per risolvere ciò, ho aggiunto alla mia applicazione il seguente codice Python che viene eseguito nella mia app prima dell'inizializzazione di 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. Dopo circa 10 minuti lo schermo collegato all'uscita HDMI di Raspberry Pi è diventato nero (ma non spento) e la mia grafica non è stata visualizzata, sebbene Pygame non abbia riportato errori. Questa si è rivelata una funzione di risparmio energetico. Per disabilitarlo, ho aggiunto il seguente codice Python che viene eseguito anche prima dell'inizializzazione 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
    

1
Questo mi è stato di grande aiuto per realizzare l'avvio di pigmei senza avere una tastiera collegata al mio Pi, quindi grazie! Volevo menzionare che ho trovato abbastanza semplice eseguire pygame /dev/tty7ed emetterne uno ExecStartPre=/bin/chvt 7per evitare la cosa del cursore, e ha il vantaggio di non scontrarsi con agetty che gira di default su tty1-tty6.
Dctucker,

2

Sebbene la tua domanda sia leggermente ambigua (cosa si intende per console), cercherò di rispondere ai casi più comuni: / dev / console, / dev / tty, / dev / fb0 ... adattalo ai dispositivi di cui hai bisogno. Supponiamo che il nome utente sia "mioutente".

Guarda i permessi del dispositivo (questo è 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

Agire

/ Dev / console

il gruppo è "root" ma non è consentito l'accesso al gruppo. Non mi piace solo aggiungere le autorizzazioni al gruppo principale, quindi invece creo un gruppo e chgrp il file e cambio le autorizzazioni

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

Puoi usare il comando usermod per aggiungere anche il tuo utente a tutti i gruppi sopra, se questo è il tuo bisogno.


-1

Dalla mia recente esperienza, oltre a concedere l'autorizzazione al tuo dispositivo tty (come menzionato prima) devi fare 2 cose aggiuntive:

  • concessione della capacità cap_sys_tty_config per l'eseguibile. Se stai usando il programma python puoi farlo come setcap cap_sys_tty_config+eip /usr/bin/python3.5(sostituisci il percorso di python con il tuo). Naturalmente, tieni presente che stai concedendo questa funzionalità per qualsiasi script Python.
  • eseguire il processo in un nuovo terminale virtuale, ad esempio usando openvt: openvt ./your_script.py
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.