Làm cách nào để ứng dụng SDL (không chạy bằng root) sử dụng bảng điều khiển


14

Tôi muốn sử dụng chương trình dựa trên SDL để hiển thị đồ họa trên bàn điều khiển, mà không phải đăng nhập từ bàn điều khiển và không chạy chương trình với quyền root. Ví dụ, tôi muốn có thể chạy nó thông qua ssh. Hệ điều hành mục tiêu là raspbian.

Dưới đây là một ví dụ ngắn trong python để minh họa vấn đề:

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

Điều này hoạt động (chạy đến hoàn thành, không ném ngoại lệ) nếu tôi chạy nó từ bàn điều khiển và nó hoạt động thông qua ssh nếu tôi chạy nó dưới quyền root.

Tôi đã kiểm tra rằng người dùng của tôi nằm trong nhóm âm thanh và video.

Tôi đã sử dụng strace để xem có gì khác biệt giữa việc chạy nó từ bàn điều khiển (hoạt động), chạy nó dưới quyền root thông qua ssh (cũng hoạt động) và chạy nó như một người dùng thông thường qua ssh (không hoạt động).

Sự khác biệt đầu tiên là người dùng của tôi không có quyền truy cập / dev / tty0. Tôi đã tạo một nhóm mới (tty0), đưa người dùng của tôi vào nhóm đó và thêm quy tắc udev để cấp cho nhóm đó quyền truy cập vào / dev / tty0.

Đầu ra strace phân kỳ tại cuộc gọi ioctl này - sự thất bại được hiển thị ở đây; ioctl trả về 0 khi chương trình được chạy từ bàn điều khiển hoặc chạy từ ssh với quyền root:

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

(Các địa chỉ cũng khác nhau, nhưng điều đó không quan trọng.)

Cho rằng chương trình của tôi hoạt động khi nó chạy bằng root, tôi nghĩ điều này có nghĩa là tôi có vấn đề về quyền. Làm cách nào để cung cấp các quyền cần thiết cho người dùng của tôi để có thể chạy chương trình này mà không cần đăng nhập tại bảng điều khiển (và không chạy bằng root)?


Quyền sở hữu / quyền trên thiết bị bộ đệm khung của bạn là gì?
Bandrami

Ngoài ra / dev / tty thường yêu cầu thành viên trong nhóm giao diện điều khiển để ghi vào.
Bandrami

ajclarkson.co.uk/blog/pygame-no-root trông giống như một giải pháp.
Arthur2e5

Câu trả lời:


3

Mục đích của tôi giống như mục đích của người gửi ban đầu, nhưng với một điểm khác biệt: tôi cần chạy ứng dụng SDL như một trình nền hệ thống. Máy Linux của tôi là Raspberry Pi 3 và hệ điều hành là Raspbian Jessie. Không có bàn phím hoặc chuột được kết nối với RPi. Tôi kết nối với nó bằng SSH. Ứng dụng SDL của tôi thực sự là một ứng dụng dựa trên Pygame . Tôi đặt pygame / SDL để sử dụng trình điều khiển bộ đệm khung hình fbcon 'thông qua biến môi trường SDL_VIDEODRIVER. systemd --versionĐầu ra của tôi là:

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

Phiên bản gói pygame của tôi là: ( aptitude show python-pygame):

1.9.2 ~ trước ~ r3348-2 ~ bpo8 + rpi1

Phiên bản libSDL 1.2 của tôi là: ( aptitude show libsdl1.2debian- trên tên gói máy của bạn có thể khác):

1.2.15-10 + rpi1

Công thức

  1. Thiết lập quyền cho các tệp / dev / tty và / dev / fb0 như được mô tả trong câu trả lời của UDude. Tôi phát hiện ra rằng những thay đổi quyền / dev / console là không cần thiết trong Raspbian Jessie.
  2. Thêm các dòng này vào phần [Dịch vụ] trong tệp .service của daemon của bạn:

    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
    

    Trong trường hợp bất cứ ai quan tâm, đây là tệp pyscopefb.service hoàn chỉnh mà tôi đã sử dụng:

    [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. Phát hành các lệnh này trong dấu nhắc lệnh (Tôi giả sử tệp pyscopefb.service đã được đặt đúng vị trí nơi systemd có thể tìm thấy nó):

    sudo systemctl daemon-reload
    sudo systemctl start pyscopefb
    

Đây là làm việc cho tôi. Xin lưu ý rằng tôi đã không kiểm tra xem ứng dụng pygame có thể nhận các sự kiện bàn phím và chuột hay không.

Tặng kem

Tôi cũng đã phải giải quyết 2 vấn đề khác có thể được quan tâm là tốt

  1. Có con trỏ văn bản nhấp nháy ở dưới cùng của màn hình với đồ họa bộ đệm khung. Để giải quyết điều đó, tôi đã thêm vào ứng dụng của mình mã Python sau chạy trong ứng dụng của mình trước khi khởi tạo 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. Sau khoảng 10 phút màn hình được kết nối với đầu ra HDMI của Raspberry Pi chuyển sang màu đen (nhưng không tắt) và đồ họa của tôi không hiển thị, mặc dù Pygame báo cáo không có lỗi. Điều này hóa ra là một tính năng tiết kiệm năng lượng. Để vô hiệu hóa điều đó, tôi đã thêm mã Python sau đây cũng chạy trước khi khởi tạo 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
Điều này cực kỳ hữu ích với tôi để hoàn thành việc bắt đầu pygame mà không cần kết nối bàn phím với Pi của tôi, cảm ơn bạn rất nhiều! Tôi muốn đề cập rằng tôi thấy nó đủ đơn giản để chạy pygame /dev/tty7và phát hành ExecStartPre=/bin/chvt 7để tránh điều con trỏ và nó có phần thưởng là không va chạm với agetty chạy theo mặc định trên tty1, tty6.
dctucker

2

Mặc dù câu hỏi của bạn hơi mơ hồ (ý nghĩa của giao diện điều khiển), tôi sẽ cố gắng trả lời cho các trường hợp phổ biến nhất: / dev / console, / dev / tty, / dev / fb0 ... thích ứng điều này với các thiết bị bạn cần. Chúng tôi giả sử tên người dùng là "myuser."

Nhìn vào các quyền của thiết bị (đây là ubfox 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

Hãy hành động

/ dev / bảng điều khiển

nhóm là "root" nhưng không cho phép truy cập nhóm. Tôi không thích chỉ thêm quyền vào nhóm gốc, vì vậy thay vào đó tôi tạo một nhóm và chỉnh sửa tệp và thay đổi quyền

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

Bạn cũng có thể sử dụng lệnh usermod để thêm người dùng của mình vào tất cả các nhóm trên, nếu đó là nhu cầu của bạn.


-1

Từ kinh nghiệm gần đây của tôi, ngoài việc cấp quyền cho thiết bị tty của bạn (như đã đề cập trước đó), bạn cần thực hiện thêm 2 điều:

  • cấp khả năng cap_sys_tty_config cho tệp thực thi. Nếu bạn đang sử dụng chương trình python, bạn có thể làm như thế setcap cap_sys_tty_config+eip /usr/bin/python3.5(thay thế đường dẫn cho python bằng của bạn). Tất nhiên, hãy tính đến việc bạn cấp khả năng này cho bất kỳ tập lệnh python nào.
  • chạy tiến trình trong một thiết bị đầu cuối ảo mới, ví dụ như sử dụng openvt: openvt ./your_script.py
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.