¿Cómo dejo que una aplicación SDL (que no se ejecuta como root) use la consola

14

Quiero usar un programa basado en SDL para mostrar gráficos en la consola, sin tener que iniciar sesión desde la consola y sin ejecutar el programa como root. Por ejemplo, quiero poder ejecutarlo a través de ssh. El sistema operativo de destino es raspbian.

Aquí hay un breve ejemplo en Python para ilustrar el problema:

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

Esto funciona (se ejecuta hasta su finalización, no arroja excepciones) si lo ejecuto desde la consola, y funciona a través de ssh si lo ejecuto como root.

Verifiqué que mi usuario está en los grupos de audio y video.

He usado strace para ver qué es diferente entre ejecutarlo desde la consola (que funciona), ejecutarlo como root a través de ssh (también funciona) y ejecutarlo como un usuario normal a través de ssh (no funciona).

La primera diferencia fue que mi usuario no tenía permiso para acceder a / dev / tty0. Creé un nuevo grupo (tty0), puse a mi usuario en ese grupo y agregué una regla udev para darle acceso a ese grupo a / dev / tty0.

La salida strace diverge en esta llamada ioctl: el fallo se muestra aquí; ioctl devuelve 0 cuando el programa se ejecuta desde la consola o se ejecuta desde ssh como root:

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

(Las direcciones también difieren, pero eso no es importante).

Dado que mi programa funciona cuando se ejecuta como root, creo que esto significa que tengo un problema de permisos. ¿Cómo otorgo los permisos necesarios a mi usuario para poder ejecutar este programa sin iniciar sesión en la consola (y sin ejecutar como root)?

Miguel
fuente
¿Cuáles son los permisos / propiedad en su dispositivo framebuffer?
Bandrami
También / dev / tty generalmente requiere membresía en el grupo de consola para escribir.
Bandrami
ajclarkson.co.uk/blog/pygame-no-root parece una solución.
Arthur2e5

Respuestas:

3

Mi objetivo era el mismo que el del póster original, pero con una diferencia: necesitaba ejecutar la aplicación SDL como un demonio systemd. Mi máquina Linux es Raspberry Pi 3 y el sistema operativo es Raspbian Jessie. No hay teclado o mouse conectado a RPi. Me conecto a él usando SSH. Mi aplicación SDL es en realidad una aplicación basada en Pygame . Configuré pygame / SDL para usar el controlador de framebuffer "fbcon" a través de la variable de entorno SDL_VIDEODRIVER. Mi systemd --versionsalida es:

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

La versión de mi paquete de pygame es: ( aptitude show python-pygame):

1.9.2 ~ pre ~ r3348-2 ~ bpo8 + rpi1

Mi versión de libSDL 1.2 es: ( aptitude show libsdl1.2debian- en el nombre del paquete de su máquina puede ser diferente):

1.2.15-10 + rpi1

La receta

  1. Configure los permisos para los archivos / dev / tty y / dev / fb0 como se describe en la respuesta de UDude. Descubrí que los cambios de permisos / dev / console no son necesarios en Raspbian Jessie.
  2. Agregue estas líneas a la sección [Servicio] del archivo .service de su daemon:

    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
    

    En caso de que alguien esté interesado, aquí está el archivo completo pyscopefb.service que utilicé:

    [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. Emita estos comandos en el símbolo del sistema (supongo que el archivo pyscopefb.service ya está ubicado en la ubicación correcta donde systemd puede encontrarlo):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Esto es trabajo para mí. Tenga en cuenta que no probé si la aplicación pygame puede recibir eventos de teclado y mouse o no.

Prima

También tuve que resolver otros 2 problemas que también pueden ser de interés

  1. Había un cursor de texto parpadeante en la parte inferior de la pantalla con gráficos de framebuffer. Para resolver eso, agregué a mi aplicación el siguiente código de Python que se ejecuta en mi aplicación antes de la inicialización de 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. Después de unos 10 minutos, la pantalla conectada a la salida HDMI de la Raspberry Pi se volvió negra (pero no apagada) y mis gráficos no aparecieron, aunque Pygame no informó errores. Esto resultó ser una función de ahorro de energía. Para deshabilitar eso, agregué el siguiente código de Python que también se ejecuta antes de la inicialización de 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
fuente
1
Esto fue extremadamente útil para mí para iniciar Pygame sin tener un teclado conectado a mi Pi, ¡así que gracias! Quería mencionar que me pareció bastante simple ejecutar pygame /dev/tty7y emitir un ExecStartPre=/bin/chvt 7para evitar el cursor, y tiene la ventaja de no chocar con agetty, que se ejecuta por defecto en tty1 – tty6.
dctucker
2

Aunque su pregunta es ligeramente ambigua (qué se entiende por consola), intentaré responder a los casos más comunes: / dev / console, / dev / tty, / dev / fb0 ... adapte esto a los dispositivos que necesita. Asumimos que el nombre de usuario es "myuser".

Mire los permisos del dispositivo (esto es 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

Tomar acción

/ dev / console

el grupo es "root" pero no se permite el acceso al grupo. No me gusta simplemente agregar permisos al grupo raíz, por lo que en su lugar creo un grupo y modifico el archivo y cambio los permisos

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

También puede usar el comando usermod para agregar su usuario a todos los grupos anteriores, si esa es su necesidad.

UDude
fuente
-1

Según mi experiencia reciente, además de otorgar permiso a su dispositivo tty (como se mencionó anteriormente) debe hacer 2 cosas adicionales:

  • otorgando la capacidad cap_sys_tty_config para el ejecutable. Si está utilizando el programa Python, puede hacerlo como setcap cap_sys_tty_config+eip /usr/bin/python3.5(sustituya la ruta de Python por la suya ). Por supuesto, tenga en cuenta que está otorgando esta capacidad para cualquier script de Python.
  • ejecutar el proceso en una nueva terminal virtual, por ejemplo, usando openvt: openvt ./your_script.py
Eriks Dobelis
fuente