Как разрешить приложению SDL (не работающему от имени root) использовать консоль

14

Я хочу использовать программу на основе SDL для отображения графики на консоли, без необходимости входа в систему с консоли и без запуска программы от имени пользователя root. Например, я хочу иметь возможность запустить его через SSH. Целевая ОС распбиана.

Вот короткий пример на python для иллюстрации проблемы:

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

Это работает (работает до завершения, не выдает исключений), если я запускаю его из консоли, и работает через ssh, если я запускаю его как root.

Я проверил, что мой пользователь в аудио и видео группах.

Я использовал strace, чтобы увидеть, что отличается от запуска его из консоли (который работает), запуска от имени пользователя root через ssh (также работает) и запуска его как обычного пользователя через ssh (не работает).

Первым отличием было то, что мой пользователь не имел разрешения на доступ к / dev / tty0. Я создал новую группу (tty0), поместил моего пользователя в эту группу и добавил правило udev, чтобы дать этой группе доступ к / dev / tty0.

Выходные данные strace расходятся при вызове ioctl - здесь показывается ошибка; ioctl возвращает 0, когда программа запускается из консоли или запускается из ssh от имени пользователя root:

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

(Адреса также различаются, но это не важно.)

Учитывая, что моя программа работает, когда она запускается с правами root, я думаю, это означает, что у меня проблема с разрешениями. Как дать пользователю необходимые полномочия для запуска этой программы без входа в систему с консоли (и без запуска с правами root)?

Майкл
источник
Каковы права собственности / разрешения на вашем устройстве кадрового буфера?
Бандрами
Также / dev / tty обычно требует членства в консольной группе для записи.
Бандрами
ajclarkson.co.uk/blog/pygame-no-root выглядит как решение.
Arthur2e5

Ответы:

3

Моя цель была такой же, как у оригинального постера, но с одним отличием: мне нужно было запускать приложение SDL как демон systemd. Моя Linux-машина - Raspberry Pi 3, а операционная система - Raspbian Jessie. К RPi не подключена клавиатура или мышь. Я подключаюсь к нему с помощью SSH. Мое SDL-приложение - это приложение на основе Pygame . Я установил pygame / SDL для использования драйвера кадрового буфера «fbcon» через переменную окружения SDL_VIDEODRIVER. Мой systemd --versionвывод:

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

Моя версия пакета pygame: ( aptitude show python-pygame):

1.9.2 ~ ~ предварительно r3348-2 ~ bpo8 + rpi1

Моя версия libSDL 1.2: ( aptitude show libsdl1.2debian- на вашем компьютере имя пакета может отличаться):

1.2.15-10 + rpi1

Рецепт

  1. Установите разрешения для файлов / dev / tty и / dev / fb0, как описано в ответе UDude. Я обнаружил, что в Raspbian Jessie не нужно менять разрешения / dev / console.
  2. Добавьте эти строки в раздел [Service] файла .service вашего демона:

    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
    

    Если кому-то интересно, вот полный файл pyscopefb.service, который я использовал:

    [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. Выполните эти команды в командной строке (я предполагаю, что файл pyscopefb.service уже находится в правильном месте, где systemd может его найти):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Это работает для меня. Обратите внимание, я не проверял, может ли приложение pygame получать события клавиатуры и мыши или нет.

бонус

Мне также пришлось решить еще 2 проблемы, которые также могут быть интересны

  1. В нижней части экрана был мигающий текстовый курсор с графикой кадрового буфера. Чтобы решить эту проблему, я добавил в свое приложение следующий код Python, который запускается в моем приложении перед инициализацией 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. Примерно через 10 минут экран, подключенный к выходу HDMI Raspberry Pi, стал черным (но не выключенным), и моя графика не отображалась, хотя Pygame не сообщала об ошибках. Это оказалось функцией энергосбережения. Чтобы отключить это, я добавил следующий код Python, который также запускается до инициализации 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
Это было чрезвычайно полезно для меня, чтобы выполнить запуск Pygame без подключения клавиатуры к моему Pi, так что спасибо! Я хотел бы упомянуть, что нашел достаточно простым запускать pygame /dev/tty7и выдавать команду, ExecStartPre=/bin/chvt 7чтобы избежать появления курсора, и он имеет преимущество в том, что не сталкивается с agetty, которое запускается по умолчанию на tty1 – tty6.
Dctucker
2

Хотя ваш вопрос немного двусмысленный (что подразумевается под консолью), я попытаюсь ответить на наиболее распространенные случаи: / dev / console, / dev / tty, / dev / fb0 ... адаптируйте это к нужным устройствам. Мы предполагаем, что имя пользователя «myuser».

Посмотрите на разрешения устройства (это 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

Принимать меры

/ DEV / консоли

группа "root", но доступ к группе запрещен. Мне не нравится просто добавлять разрешения в корневую группу, поэтому вместо этого я создаю группу, запускаю файл и меняю разрешения

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

Вы также можете использовать команду usermod для добавления вашего пользователя во все вышеперечисленные группы, если это вам нужно.

UDude
источник
-1

Исходя из моего недавнего опыта, помимо предоставления разрешения вашему устройству tty (как упоминалось ранее), вам необходимо сделать еще 2 вещи:

  • предоставление возможности cap_sys_tty_config для исполняемого файла. Если вы используете программу Python, вы можете сделать это следующим образом setcap cap_sys_tty_config+eip /usr/bin/python3.5(замените путь для Python своим). Конечно, примите во внимание, что вы предоставляете эту возможность для любого скрипта Python.
  • запуск процесса в новом виртуальном терминале, например, с использованием openvt: openvt ./your_script.py
Эрикс Добелис
источник