FreeBSD Advent Calendar 2020 10日目の記事です。
今日はTigerVNCパッケージの更新でハマった話を書こうと思います。
背景
1日目の記事でFreeBSD+Jailによるコンテナ環境を気軽に作成・破棄できるようになりました。さらにVNCと組み合わせることで、GUI環境も構築できます。
FreeBSDではTigerVNCパッケージが提供されており、ことを用いることで簡単にVNCサーバを立ち上げることができます。
ところが、いつものようにTigerVNCをインストールして動かそうとしたところ、これまでの手順では動かせなくなっており、あれこれ調べて対応したというのが今日のお話になります。
設定手順の一連の流れ
今日の話はデバッグのための試行錯誤が長々と続くため、最初に一連の設定手順を載せておきます。
(なのでこの部分だけ見ればOKという話でもあります...)
$ # 必要なパッケージのインストール。
$ sudo pkg install -y \
tigervnc-server tigervnc-viewer \
perl5 xauth xterm xrdb xsetroot \
ja-uim-mozc uim-gtk ja-font-sazanami \
leafpad open-motif
$ # VNCの設定ファイル用ディレクトリを作成。
$ mkdir .vnc
$ vncpasswd .vnc/passwd
$
$ # Xvncを起動したときに実行させるスクリプト。
$ cat <<_EOF > .vnc/xstartup
#!/bin/sh
export GTK_IM_MODULE=uim
export QT_IM_MODULE=uim
export XMODIFIERS=@im=uim
export XIM=uim
mozc_process=`ps ax | grep mozc | grep -v grep | wc -l`
[ $mozc_process -eq 0 ] && /usr/local/bin/mozc start &
uim_xim_process=`ps ax | grep uim-xim | grep -v grep | wc -l`
[ $uim_xim_process -eq 0 ] && uim-xim &
xsetroot -solid midnightblue
exec mwm
_EOF
$
$ # Xvncコマンドを直接実行し、xterm経由でxstartupを実行する。
$ Xvnc -PasswordFile ~/.vnc/passwd -verbose 2 & \
sleep 2 \
&& xterm -iconic -display :0 /home/fbsd/.vnc/xstartup &
vncserverコマンドでのエラー
FreeBSDでTigerVNCを用いたGUI環境を構築する場合には、以下のようなパッケージをインストールします。
$ sudo pkg install -y \
tigervnc-server tigervnc-viewer \
perl5 xauth xterm xrdb xsetroot \
ja-uim-mozc uim-gtk ja-font-sazanami \
leafpad open-motif
これまでは必要なパッケージをインストールしたのち、 vncserver :0
でVNCサーバを起動していたのですが、パッケージをアップデートしたタイミングでコマンドが見つけられなくなってしまいました。
$ vncserver :0
-bash: vncserver: command not found
どのバージョンから変更が入っている?
VNCが利用できている既存の環境と比較すると、TigerVNCのバージョンが 1.10.1_1
から 1.11.0
に上がっていました。
-
vncserver
でVNCが起動できる環境。
$ pkg info tigervnc-server | head -n4
tigervnc-server-1.10.1_1
Name : tigervnc-server
Version : 1.10.1_1
Installed on : Tue May 19 01:20:05 2020 JST
- パッケージアップデート後の環境。
$ pkg info tigervnc-server | head -n4
tigervnc-server-1.11.0
Name : tigervnc-server
Version : 1.11.0
Installed on : Sun Oct 11 02:10:00 2020 JST
インストールされるファイルの差分確認
インストールされるファイルの差分をみると、いくつか差異があります。
$ diff -u tigervnc-server-1.10.1_1.txt tigervnc-server-1.11.0.txt
--- tigervnc-server-1.10.1_1.txt 2020-10-11 02:29:50.500981000 +0900
+++ tigervnc-server-1.11.0.txt 2020-10-11 02:30:02.870729000 +0900
@@ -1,16 +1,22 @@
/usr/local/bin/vncconfig
/usr/local/bin/vncpasswd
-/usr/local/bin/vncserver
/usr/local/bin/x0vncserver
/usr/local/bin/Xvnc
+/usr/local/etc/pam.d/tigervnc
+/usr/local/etc/tigervnc/vncserver-config-defaults
+/usr/local/etc/tigervnc/vncserver-config-mandatory
+/usr/local/etc/tigervnc/vncserver.users
/usr/local/lib/xorg/modules/extensions/libvnc.so
+/usr/local/libexec/vncserver
/usr/local/man/man1/vncconfig.1.gz
/usr/local/man/man1/vncpasswd.1.gz
-/usr/local/man/man1/vncserver.1.gz
/usr/local/man/man1/x0vncserver.1.gz
/usr/local/man/man1/Xvnc.1.gz
+/usr/local/man/man8/vncserver.8.gz
+/usr/local/man/man8/vncsession.8.gz
+/usr/local/sbin/vncsession
/usr/local/share/doc/tigervnc/tigervnc-server-LICENCE.TXT
/usr/local/share/doc/tigervnc/tigervnc-server-README.rst
-/usr/local/share/licenses/tigervnc-server-1.10.1_1/catalog.mk
-/usr/local/share/licenses/tigervnc-server-1.10.1_1/GPLv2+
-/usr/local/share/licenses/tigervnc-server-1.10.1_1/LICENSE
+/usr/local/share/licenses/tigervnc-server-1.11.0/catalog.mk
+/usr/local/share/licenses/tigervnc-server-1.11.0/GPLv2+
+/usr/local/share/licenses/tigervnc-server-1.11.0/LICENSE
vncserverをフルパス指定で実行すれば解決?
vncserver
コマンドは /usr/local/libexec
以下に移動されていました。
バージョン1.10.1_1 /usr/local/bin/vncserver
バージョン1.11.0 /usr/local/libexec/vncserver
フルパス指定で /usr/local/libexec/vncserver
を実行すれば解決するかと思ったのですが、別のエラーが出てしまいました。
$ /usr/local/libexec/vncserver :0 ; echo $?
vncserver: Couldn't find suitable Xsession.
2
そしてここから長いデバッグの旅が始まったのです...。
頑張ってデバッグする
Xsessionファイルの作成
以下に同様のエラーが報告されていた。Xsession ファイルが存在しないことが原因のようです。
手動で Xsession
ファイルを作成します。
手動で Xsession ファイルを作成する。
$ ls /etc/X11/Xsession
ls: /etc/X11/Xsession: そのようなファイルまたはディレクトリはありません
$ echo '#!/bin/sh' | sudo tee /etc/X11/Xsession
$ sudo chmod +x /etc/X11/Xsession
パスワードファイルの作成
Xsession
関連のエラーは解消しましたが、今度はVNC用のパスワードファイルが無いというエラーに遭遇しました。
$ /usr/local/libexec/vncserver :0
VNC authentication enabled, but no password file created.
対応方法は自明で、 ~/.vnc/passwd
ファイルを作成することで対応します。
$ mkdir .vnc
$ vncpasswd .vnc/passwd
Password:
Verify:
Would you like to enter a view-only password (y/n)? n
デスクトップセッションファイルの作成
今度はデスクトップセッション周りのエラーに遭遇しました。
$ /usr/local/libexec/vncserver :0 ; echo $?
Could not find a desktop session to run
255
ソースコードを参照してみると、エラーメッセージは以下の場所で出力されているようです。
ソースコード中の前後の処理をみるど、どうやら /usr/share/xsessions/*.desktop
でマッチするファイルが存在しないことが要因のようです。
if (!$sessionname) {
foreach $file (glob("/usr/share/xsessions/*.desktop")) {
($name) = $file =~ /^.*\/(.*)[.]desktop$/;
%session = LoadXSession($name);
if (%session) {
$sessionname = $name;
last;
}
}
}
if (!$sessionname) {
die "Could not find a desktop session to run\n";
}
なるほど、たしかに /usr/share/xsessions
ディレクトリの中身は空っぽになっています。
$ ls /usr/share/xsessions/*.desktop | wc -l
0
/usr/share/xsessions/mwm.desktop
ファイルを作成して以下の内容を記載します。
[Desktop Entry]
Name=MWM
Exec=mwm
TryExec=/home/fbsd/.vnc/xstartup
xinitでエラー
これで大丈夫かなと思ったのですが、今度は xinit
でエラーが出てしまいました...。
$ /usr/local/libexec/vncserver :0
...
xinit: connection to X server lost
waiting for X server to shut down
xinit
とその中から実行されそうなスクリプトは以下の場所にあるようです。とはいえ、TigerVNCパッケージを更新する前は普通に動作していたため、 xinit
側が要因である可能性は低そうです。
$ find /usr/local/etc/ | grep -i xinit | xargs file
find: /usr/local/etc/cups/ssl: パーミッションが拒絶されました
/usr/local/etc/X11/xinit: directory
/usr/local/etc/X11/xinit/xinitrc: POSIX shell script, ASCII text executable
そもそも /usr/local/libexec/vncserver
コマンドは libexec
ディレクトリに配置される形に変更されているので、このコマンドを直接実行するという事自体が推奨されない使い方になった、という話なのかもしれません。
どうやら /usr/local/sbin/vncsession
が内部的に vncserver
を実行しているようです。が、こちらも実行すると以下のようなエラーになってしまいます...。
$ sudo vncsession fbsd :0
Failure daemonizing
ソースコードと照らし合わせてみる
どうやらこれはTigerVNCのソースコードと照らし合わせながら調べないと原因特定ができなさそうです。
vncsession
で発生しているエラーをソースコードから検索してみます。
$ find . -type f -name vncsession
./unix/vncserver/vncsession
$ sudo ./unix/vncserver/vncsession fbsd :0
Failure daemonizing
$ find . -type f | xargs grep 'Failure daemonizing'
./unix/vncserver/vncsession.c: fprintf(stderr, "Failure daemonizing\n");
該当箇所の前後の処理を見てもイマイチエラーの原因が分かりません...。
vncsession
→ vncserver
の順で呼び出していることまでは把握できているので、最終的に実行される xinit
コマンドがどう実行されるかを調べるほうが早道かもしれません。
/* Wait for child to finish startup */
len = read(fds[0], buf, 1);
if (len != 1) {
fprintf(stderr, "Failure daemonizing\n");
_exit(EX_OSERR);
}
xinitコマンドはどう実行されている?
xinit
は以下の個所から実行されるようです。 @cmd
という配列にオプション等を追加していき、最終的に xinit
コマンド文字列が作り出されています。
@cmd = ("xinit");
push(@cmd, $Xsession, $session{'Exec'});
push(@cmd, '--');
# We build up our Xvnc command with options
push(@cmd, "@CMAKE_INSTALL_FULL_BINDIR@/Xvnc", ":$displayNumber");
foreach my $k (sort keys %config) {
push(@cmd, "-$k");
push(@cmd, $config{$k}) if defined($config{$k});
delete $default_opts{$k}; # file options take precedence
}
foreach my $k (sort keys %default_opts) {
push(@cmd, "-$k");
push(@cmd, $default_opts{$k}) if defined($default_opts{$k});
}
私の環境では以下のような xinit
コマンドになっていました。
xinit -- /usr/local/bin/Xvnc :0 -auth /home/fbsd/.Xauthority -desktop tmp01.furandon.net:0
xinitのオプション
xinit(1)のマニュアルを見ると、 --
の後にserverと付随するオプションを指定するという形になっています。
ということは、TigerVNCでは、 xinit
から Xvnc
が実行されるという流れになっているという話ですね。
$ man 1 xinit
NAME
xinit - X Window System initializer
SYNOPSIS
xinit [ [ client ] options ... ] [ -- [ server ] [ display ] options
... ]
Xvncを直接実行する
これは Xvnc
を直接実行すれば良さそうです。以下のようなコマンドを実行することで、無事にVNCが利用できる状態になりました。
$ Xvnc -PasswordFile ~/.vnc/passwd -verbose 2 & \
sleep 2 \
&& xterm -iconic -display :0 /home/fbsd/.vnc/xstartup &
その他のハマりどころ
今回の調査を行っている際に ~/.ssh/known_hosts
の内容と接続元PCの情報に齟齬が出ている状態だと、Xvncを直接実行する形であってもVNCに接続できないという点にハマりました。
仮想マシン等で環境を構築していると、接続元PCのIPアドレスを使いまわしたりするため、この現象に遭遇しやすいかもしれません。この場合は、 ~/.ssh/known_hosts
の該当エントリを削除することで問題が解消します。
まとめ
TigerVNCパッケージの更新でハマった話を紹介しました。思っていたよりも深くまで調べないと解消方法が見つからないため苦労しました。
最終的には Xvnc
コマンドを直接実行する方法で解消しましたが、 .xstartup
コマンドの実行はちょっとトリッキーな方法で実行しているため、より良い方法を見つけたいところです。