Como faço para que um aplicativo SDL (não executando como root) use o console

14

Desejo 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, eu quero poder executá-lo via ssh. O SO 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 no console e via ssh se eu o executar como root.

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

Eu usei o 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 comum via ssh (não funciona).

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

A saída strace diverge nesta chamada ioctl - a falha é mostrada aqui; O ioctl retorna 0 quando o programa é executado no console ou no 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 meu programa funciona quando é executado como root, acho que isso significa que tenho um problema de permissões. Como concedo as permissões necessárias ao meu usuário para poder executar este programa sem fazer logon no console (e sem executar como root)?

Michael
fonte
Qual é a propriedade / permissões no seu dispositivo buffer de estrutura?
Bandrami
Também / dev / tty geralmente requer associação no grupo do console para gravar.
Bandrami
ajclarkson.co.uk/blog/pygame-no-root parece uma solução.
Arthur2e5

Respostas:

3

Meu objetivo era o mesmo do pôster 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 SSH. Meu aplicativo SDL é realmente um aplicativo baseado em Pygame . Defino pygame / SDL para usar o driver framebuffer "fbcon" por meio da variável de ambiente SDL_VIDEODRIVER. Minha systemd --versionsaída é:

systemd 215 + PAM + AUDITORIA + 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 do 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 os arquivos / dev / tty e / dev / fb0, conforme descrito na resposta do UDude. Descobri que as alterações de permissão do / dev / console não são necessárias no Raspbian Jessie.
  2. Adicione estas linhas à seção [Serviço] do arquivo .service do seu 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
    

    Caso alguém esteja interessado, aqui está o arquivo pyscopefb.service completo que eu 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 (presumo que o arquivo pyscopefb.service já esteja colocado no local correto onde o systemd pode encontrá-lo):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Isso está funcionando para mim. Observe que 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 também podem ser interessantes

  1. Havia um cursor de texto piscando na parte inferior da tela com gráficos do buffer de moldura. Para resolver isso, adicionei ao meu aplicativo o seguinte 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, a tela conectada à saída HDMI do Raspberry Pi ficou preta (mas não desligada) e meus gráficos não foram exibidos, embora o Pygame não tenha relatado erros. Isso acabou sendo um recurso de economia de energia. Para desativar isso, adicionei o seguinte código Python, 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
    
Roman Me
fonte
1
Isso foi extremamente útil para mim para iniciar o pygame sem ter um teclado conectado ao meu Pi, então obrigado! Eu queria mencionar que achei simples o suficiente executar o pygame /dev/tty7e emitir um ExecStartPre=/bin/chvt 7para evitar a coisa do cursor, e ele tem o bônus de não colidir com o agetty, que é executado por padrão em tty1 – tty6.
Dctucker 13/1218
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 que você precisa. Assumimos que o nome de usuário é "myuser".

Veja as permissões do dispositivo (este é 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 uma atitude

/ dev / console

o grupo é "raiz", mas nenhum acesso ao grupo é permitido. Não gosto apenas de adicionar permissões ao grupo raiz, então, em vez disso, crio um grupo e chgrp o arquivo e altero 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 também, se essa for sua necessidade.

UDude
fonte
-1

Pela minha experiência recente, além de conceder permissão ao seu dispositivo tty (como mencionado anteriormente), você precisa fazer duas coisas adicionais:

  • concedendo a capacidade cap_sys_tty_config para o executável. Se você estiver usando o programa python, poderá fazê-lo como setcap cap_sys_tty_config+eip /usr/bin/python3.5(substitua o caminho do python pelo seu). Obviamente, leve em consideração que você está concedendo esse recurso a qualquer script python.
  • executando o processo em um novo terminal virtual, por exemplo, usando o openvt: openvt ./your_script.py
Eriks Dobelis
fonte