SDLベースのプログラムを使用して、コンソールからログオンする必要がなく、プログラムをrootとして実行することなく、コンソールにグラフィックを表示したいと考えています。たとえば、ssh経由で実行できるようにしたいと考えています。ターゲットOSはraspbianです。
問題を説明するためのpythonの短い例を以下に示します。
import os, pygame
os.environ['SDL_VIDEODRIVER'] = 'fbcon'
pygame.init()
s = pygame.display.set_mode()
print "Success"
これは、コンソールから実行すると機能します(完了するまで実行され、例外はスローされません)。ルートとして実行すると、sshを介して機能します。
ユーザーがオーディオグループとビデオグループに属していることを確認しました。
私はstraceを使用して、コンソールから実行する(機能する)、sshを介してrootとして実行する(機能する)、およびsshを介して通常のユーザーとして実行する(機能しない)の違いを確認しました。
最初の違いは、私のユーザーが/ dev/tty0にアクセスする権限を持っていなかったことです。新しいグループ(tty0)を作成し、ユーザーをそのグループに入れ、udevルールを追加して、そのグループに/ dev/tty0へのアクセスを許可しました。
Straceの出力は、このioctl呼び出しで分岐します-失敗はここに表示されます。プログラムがコンソールから実行されるか、sshからrootとして実行されると、ioctlは0を返します。
open("/dev/tty", O_RDWR) = 4
ioctl(4, VT_GETSTATE, 0xbeaa01f8) = -1 EINVAL (Invalid argument)
(アドレスも異なりますが、それは重要ではありません。)
Rootとして実行してもプログラムが機能するので、これはアクセス許可の問題があることを意味すると思います。コンソールにログオンせずに(およびrootとして実行せずに)このプログラムを実行できるようにするには、ユーザーに必要なアクセス許可をどのように付与しますか?
私の目的は元のポスターと同じでしたが、1つ異なる点があります。それは、systemdデーモンとしてSDLアプリケーションを実行する必要があったことです。私のLinuxマシンはRaspberry Pi 3で、オペレーティングシステムはRaspbian Jessieです。 RPiに接続されているキーボードまたはマウスはありません。 SSHを使用して接続します。私のSDLアプリは実際には Pygame ベースのアプリです。 SDL_VIDEODRIVER環境変数を介して「fbcon」フレームバッファードライバーを使用するようにpygame/SDLを設定しました。ぼくの systemd --version
出力は次のとおりです。
systemd 215 + PAM + AUDIT + SELINUX + IMA + SYSVINIT + LIBCRYPTSETUP + GCRYPT + ACL + XZ -SECCOMP -APPARMOR
私のpygameパッケージのバージョンは:(aptitude show python-pygame
):
1.9.2〜pre〜r3348-2〜bpo8 + rpi1
私のlibSDL 1.2バージョンは(aptitude show libsdl1.2debian
-ご使用のマシンではパッケージ名が異なる場合があります):
1.2.15-10 + rpi1
デーモンの.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
コマンドプロンプトで次のコマンドを発行します(pyscopefb.serviceファイルは、systemdが検出できる正しい場所に既に配置されていると想定しています)。
Sudo systemctl daemon-reload
Sudo systemctl start pyscopefb
これは私のために働いています。 pygameアプリケーションがキーボードとマウスのイベントを受信できるかどうかはテストしていません。
また、興味深い2つの問題も解決する必要がありました。
画面の下部に、フレームバッファグラフィックスのテキストカーソルが点滅していました。これを解決するために、アプリケーションに次の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
約10分後、Raspberry PiのHDMI出力に接続された画面が黒くなり(電源はオフになりません)、グラフィックが表示されませんでしたが、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
あなたの質問は少しあいまいですが(コンソールの意味)、私は最も一般的なケースである/ dev/console、/ dev/tty、/ dev/fb0に答えようとします...必要なデバイスにこれを適応させます。ユーザー名は「myuser」とします。
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
グループは「ルート」ですが、グループアクセスは許可されません。ルートグループに権限を追加するのは好きではないので、代わりにグループを作成してファイルをchgrpし、権限を変更します
$ Sudo addgroup --system console
$ Sudo chgrp console /dev/console
$ Sudo chmod g+rw /dev/console
$ Sudo usermod -a -G console <myuser> <==== replace <myuser>
$ Sudo usermod -a -G tty <myuser>
$ Sudo usermod -a -G video <myuser>
sermodコマンドを使用して、上記のすべてのグループにユーザーを追加することもできます(必要な場合)。
私の最近の経験から、(前述のように)ttyデバイスに許可を与えることに加えて、さらに2つのことを行う必要があります。
setcap cap_sys_tty_config+eip /usr/bin/python3.5
(pythonをあなたのパスに置き換えてください。)もちろん、pythonスクリプトにこの機能を付与することを考慮してください。openvt ./your_script.py