Como faço para deixar um aplicativo SDL (não em execução como root) usar o console

12

Eu quero usar um programa baseado em SDL para exibir gráficos no console, sem precisar fazer logon no console e sem executar o programa como root. Por exemplo, quero poder executá-lo via ssh. O sistema operacional de destino é raspbian.

Aqui está um pequeno exemplo em python para ilustrar o problema:

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

Isso funciona (executado até a conclusão, não gera exceções) se eu o executar a partir do console, e ele funciona via ssh se eu o executar como root.

Verifiquei se meu usuário está nos grupos de áudio e vídeo.

Eu usei strace para ver o que é diferente entre executá-lo no console (que funciona), executá-lo como root via ssh (também funciona) e executá-lo como um usuário regular via ssh (não funciona).

A primeira diferença foi que meu usuário não tinha permissão para acessar / dev / tty0. Eu criei um novo grupo (tty0), coloquei meu usuário nesse grupo e adicionei uma regra do udev para dar acesso ao grupo / dev / tty0.

A saída strace diverge nesta chamada ioctl - a falha é mostrada aqui; ioctl retorna 0 quando o programa é executado a partir do console ou executado a partir do ssh como root:

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

(Os endereços também diferem, mas isso não é importante.)

Dado que o meu programa funciona quando é executado como root, penso que isto significa que tenho um problema de permissões. Como eu dou as permissões necessárias ao meu usuário para poder rodar este programa sem fazer o login no console (e sem rodar como root)?

    
por michael 20.12.2012 / 09:53

2 respostas

2

Embora sua pergunta seja um pouco ambígua (o que se entende por console), tentarei responder pelos casos mais comuns: / dev / console, / dev / tty, / dev / fb0 ... adapte isso aos dispositivos você precisa. Nós assumimos que o nome de usuário é "myuser".

Olhe para as permissões do dispositivo (isto é o 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

Tome medidas

/ dev / console

o grupo é "root", mas nenhum acesso de grupo é permitido. Eu não gosto apenas de adicionar permissões ao grupo raiz, então eu criei um grupo e chgrp o arquivo e mudei as permissões

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

Você pode usar o comando usermod para adicionar seu usuário a todos os grupos acima, se necessário.

    
por 25.10.2015 / 20:15
2

Meu objetivo era o mesmo do original, mas com uma diferença: eu precisava executar o aplicativo SDL como um daemon systemd. Minha máquina Linux é Raspberry Pi 3 e o sistema operacional é Raspbian Jessie. Não há teclado ou mouse conectado ao RPi. Eu me conecto a ele usando o SSH. Meu aplicativo SDL é, na verdade, um aplicativo baseado em Pygame . Eu configurei pygame / SDL para usar o driver de buffer de quadro "fbcon" através da variável de ambiente SDL_VIDEODRIVER. Minha saída systemd --version é:

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

Minha versão do pacote pygame é: ( aptitude show python-pygame ):

1.9.2~pre~r3348-2~bpo8+rpi1

Minha versão libSDL 1.2 é: ( aptitude show libsdl1.2debian - no nome do pacote da sua máquina pode ser diferente):

1.2.15-10+rpi1

A receita

  1. Configure permissões para arquivos / dev / tty e / dev / fb0 conforme descrito em A resposta do UDude. Eu descobri que as alterações de permissão do / dev / console não são necessários em Jessie Raspbian.
  2. Adicione essas linhas à seção [Serviço] do serviço do daemon. arquivo:

    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
    

    No caso de alguém interessado, aqui está o arquivo pyscopefb.service completo que usei:

    [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 esses comandos no prompt de comando (suponho que o arquivo pyscopefb.service já esteja posicionado no local correto onde o systemd pode encontrá-lo):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Isso está funcionando para mim. Por favor, note que eu não testei se o aplicativo pygame é capaz de receber eventos de teclado e mouse ou não.

Bônus

Eu também tive que resolver outros 2 problemas que podem ser de interesse também

  1. Havia um cursor de texto piscando na parte inferior da tela com gráficos framebuffer. Para resolver isso, adicionei ao meu aplicativo seguindo o código Python que é executado no meu aplicativo antes da inicialização do 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. Após cerca de 10 minutos de tela conectada ao HDMI do Raspberry Pi saída ficou preta (mas não desligada) e meus gráficos não exibição, embora Pygame não tenha reportado nenhum erro. Isto acabou por ser um recurso de economia de energia. Para desabilitar isso, adicionei o seguinte Python código que também é executado antes da inicialização do 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
    
por 19.08.2017 / 14:05