Comment laisser une application SDL (ne s'exécutant pas en tant que root) utiliser la console

14

Je souhaite utiliser un programme basé sur SDL pour afficher des graphiques sur la console, sans avoir à me connecter à partir de la console et sans exécuter le programme en tant que root. Par exemple, je veux pouvoir l'exécuter via ssh. Le système d'exploitation cible est raspbian.

Voici un court exemple en python pour illustrer le problème:

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

Cela fonctionne (s'exécute jusqu'à la fin, ne lève pas d'exceptions) si je l'exécute à partir de la console, et cela fonctionne via ssh si je l'exécute en tant que root.

J'ai vérifié que mon utilisateur est dans les groupes audio et vidéo.

J'ai utilisé strace pour voir ce qui est différent entre l'exécuter à partir de la console (qui fonctionne), l'exécuter en tant que root via ssh (fonctionne également) et l'exécuter en tant qu'utilisateur normal via ssh (ne fonctionne pas).

La première différence était que mon utilisateur n'avait pas la permission d'accéder à / dev / tty0. J'ai créé un nouveau groupe (tty0), mis mon utilisateur dans ce groupe et ajouté une règle udev pour donner à ce groupe l'accès à / dev / tty0.

La sortie strace diverge à cet appel ioctl - l'échec est montré ici; ioctl renvoie 0 lorsque le programme est exécuté à partir de la console ou exécuté à partir de ssh en tant que root:

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

(Les adresses diffèrent également, mais ce n'est pas important.)

Étant donné que mon programme fonctionne lorsqu'il s'exécute en tant que root, je pense que cela signifie que j'ai un problème d'autorisations. Comment donner les autorisations nécessaires à mon utilisateur pour pouvoir exécuter ce programme sans ouvrir de session sur la console (et sans exécuter en tant que root)?

Michael
la source
Quelles sont la propriété / les autorisations sur votre appareil framebuffer?
Bandrami
De plus, / dev / tty nécessite généralement d'être membre du groupe de consoles pour écrire.
Bandrami
ajclarkson.co.uk/blog/pygame-no-root ressemble à une solution.
Arthur2e5

Réponses:

3

Mon objectif était le même que celui de l'affiche originale, mais avec une différence: j'avais besoin d'exécuter l'application SDL en tant que démon systemd. Ma machine Linux est Raspberry Pi 3 et le système d'exploitation est Raspbian Jessie. Aucun clavier ou souris n'est connecté à RPi. Je me connecte avec SSH. Mon application SDL est en fait une application basée sur Pygame . J'ai défini pygame / SDL pour utiliser le pilote framebuffer «fbcon» via la variable d'environnement SDL_VIDEODRIVER. Ma systemd --versionsortie est:

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

Ma version du package pygame est: ( aptitude show python-pygame):

1.9.2 ~ pré ~ r3348-2 ~ bpo8 + rpi1

Ma version libSDL 1.2 est: ( aptitude show libsdl1.2debian- sur votre machine le nom du package peut être différent):

1.2.15-10 + rpi1

La recette

  1. Configurez les autorisations pour les fichiers / dev / tty et / dev / fb0 comme décrit dans la réponse d'UDude. J'ai découvert que les modifications des autorisations / dev / console ne sont pas nécessaires dans Raspbian Jessie.
  2. Ajoutez ces lignes à la section [Service] du fichier .service de votre démon:

    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
    

    Si quelqu'un est intéressé, voici le fichier pyscopefb.service complet que j'ai utilisé:

    [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. Émettez ces commandes dans l'invite de commande (je suppose que le fichier pyscopefb.service est déjà placé à l'emplacement correct où systemd peut le trouver):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Cela fonctionne pour moi. Veuillez noter que je n'ai pas testé si l'application pygame est capable de recevoir des événements clavier et souris ou non.

Prime

J'ai aussi dû résoudre 2 autres problèmes qui peuvent aussi être intéressants

  1. Il y avait un curseur de texte clignotant au bas de l'écran avec des graphiques framebuffer. Pour résoudre cela, j'ai ajouté à mon application le code Python suivant qui s'exécute dans mon application avant l'initialisation 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. Après environ 10 minutes, l'écran connecté à la sortie HDMI du Raspberry Pi est devenu noir (mais pas éteint) et mes graphiques ne se sont pas affichés, bien que Pygame n'ait signalé aucune erreur. Cela s'est avéré être une fonction d'économie d'énergie. Pour désactiver cela, j'ai ajouté le code Python suivant qui s'exécute également avant l'initialisation 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
la source
1
Cela m'a été extrêmement utile pour réaliser le démarrage de Pygame sans avoir de clavier connecté à mon Pi, alors merci! Je voulais mentionner que je l'ai trouvé assez simple pour exécuter pygame /dev/tty7et émettre un ExecStartPre=/bin/chvt 7pour éviter le curseur, et il a l'avantage de ne pas entrer en collision avec agetty qui s'exécute par défaut sur tty1 – tty6.
dctucker
2

Bien que votre question soit légèrement ambiguë (ce que l'on entend par console), je vais essayer de répondre aux cas les plus courants: / dev / console, / dev / tty, / dev / fb0 ... adaptez-le aux appareils dont vous avez besoin. Nous supposons que le nom d'utilisateur est "myuser".

Regardez les autorisations de l'appareil (c'est 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

Passer à l'action

/ dev / console

le groupe est "root" mais aucun accès de groupe n'est autorisé. Je n'aime pas simplement ajouter des autorisations au groupe racine, donc à la place, je crée un groupe et chgrp le fichier et modifie les autorisations

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

Vous pouvez également utiliser la commande usermod pour ajouter votre utilisateur à tous les groupes ci-dessus, si tel est votre besoin.

UDude
la source
-1

D'après mon expérience récente, en plus d'accorder la permission à votre appareil tty (comme mentionné précédemment), vous devez faire 2 choses supplémentaires:

  • octroi de la capacité cap_sys_tty_config pour l'exécutable. Si vous utilisez un programme python, vous pouvez le faire comme setcap cap_sys_tty_config+eip /usr/bin/python3.5(remplacez le chemin d'accès de python par le vôtre). Bien sûr, tenez compte du fait que vous accordez cette capacité pour n'importe quel script python.
  • exécuter le processus dans un nouveau terminal virtuel, par exemple en utilisant openvt: openvt ./your_script.py
Eriks Dobelis
la source