2009年1月16日金曜日

(FreeBSD) gdm-2.24.1になったらXDMCPが使えなくなった。gdmのバグらしい

先日portsのGNOME2がごっそりとアップデートされて、gdmがgdm-2.24.1_4になったのですが、そうしたら、gdmが動かなくなってしまいました。



まず最初に気がついたのは、ローカルホスト上でXサーバを起動しようとして、コケてること。



「--debug」オプションをつけて「gdm --debug」で起動すると、いろいろメッセージが表示されるのですが、ローカルホスト上でXサーバを起動しようとしたけど失敗、それを10回くらい繰り返した後、エラーばっかだから、やめちゃうよ、といって終わってるみたいです。



gdm-binary[53863]: DEBUG(+): GdmDisplay: Unmanaging display
gdm-binary[53863]: DEBUG(+): GdmDisplay: unmanage display
gdm-binary[53863]: DEBUG(+): GdmSlaveProxy: Killing slave
gdm-binary[53863]: DEBUG(+): GdmSlaveProxy: Disposing slave proxy
gdm-binary[53863]: DEBUG(+): GdmSlaveProxy: Killing slave
gdm-binary[53863]: WARNING: GdmDisplay: display lasted 0.999561 seconds
gdm-binary[53863]: DEBUG(+): GdmLocalDisplayFactory: static display status changed: 3
gdm-binary[53863]: DEBUG(+): GdmDisplayStore: Unreffing display: 0x812ba28
gdm-binary[53863]: WARNING: GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors



そのホストはサーバー用に使っているので、もともとXサーバは動かしていませんでした。また、driかなんかの問題で、うまくXサーバが動かなかった、という理由もあります。



そういうことから、gdmがXサーバを起動しないようにするために、/usr/local/etc/gdm/custom.confの[servers]のところに、

0=inactive

と書いてありました。



gdm-2.24.1になると、この0=inactiveという記述は、考慮されなくなっているようです。



gdm-2.24のドキュメントを探しても、どうやったら0=inactiveと同じことを実現できるのか、ぜんぜんわからず、ソースコードを斜め読みまでしたんですが、よくわからず。



gdm-manager.cの、このあたりが関係しそうなんだけど。



void
gdm_manager_start (GdmManager *manager)
{
        g_debug ("GdmManager: GDM starting to manage");
        if (! manager->priv->wait_for_go) {
                gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory));
        }



それから、子プロセスで、こんなのを実行しようとしてるんですよね。
/usr/local/libexec/gdm-simple-slave --display-id /org/gnome/DisplayManager/Display1



最初は、grepであたりをつけてソースコードを眺める、ということをやってたんですが、どうもよくわかんないので、portsでビルドするとき、デバッグ機能を有効にするために



# make WITH_DEBUG=yes



して、gdbでgdm-binをトレース実行までしてみたんですけど・・・



この辺を見てみたり



(gdb) where
#0  gdm_local_display_factory_new (store=0x8102e30)
    at gdm-local-display-factory.c:620
#1  0x08057af1 in gdm_manager_constructor (type=135434096,
    n_construct_properties=1, construct_properties=0x8114570)
    at gdm-manager.c:328
#2  0x48226643 in g_object_newv () from /usr/local/lib/libgobject-2.0.so.0
#3  0x482271f1 in g_object_new_valist ()
   from /usr/local/lib/libgobject-2.0.so.0
#4  0x48227360 in g_object_new () from /usr/local/lib/libgobject-2.0.so.0
#5  0x08057e63 in gdm_manager_new () at gdm-manager.c:424
#6  0x0804d8aa in main (argc=239172, argv=0x480a3200) at main.c:605



とりあえず、/usr/local/bin/Xを起動することになっているのはわかったので(これにコマンドライン引数を指定する方法はわかんなかった・・・Xserversとかいうファイルを見ないのかねぇ?)、/usr/local/bin/Xを、Xvfbを起動するラッパースクリプトに置き換えてしまいました(笑)。



Xvfbには、-verboseオプションが無いんですね。



Unrecognized option: -verbose



% cat /usr/local/bin/X
#! /bin/sh



command=$*
echo  $command
command2=`echo $command | sed 's/-verbose//'`
exec /usr/local/bin/Xvfb $command2



セキュリティホールがありそうな気もしないでもないので、あくまでもテスト用。





あとでまともな解決方法を考えることにして、とりあえず、これれOK・・・と思いきや、今度は、XDMCPが使えていないことに気がつきました。



ネット検索してみると、このあたりに情報がでてました。どうも、gdm-2.24でXDMCPが使えないバグがあるみたいです。



http://shirata.ddo.jp/papa/blog/2008/11/fedora10gdmxdmcpmasapatch.html



http://forums.fedoraforum.org/showthread.php?t=203674



http://bugzilla.gnome.org/show_bug.cgi?id=561396



3つめのURLのページには、1つめのページで示されたパッチは正しいようには思えない、という開発者(?)からのコメントがついています。どうやら、revision 6610のgdmで、あれこれ修正されているみたいです。



subversionってほとんど使ったことがないんですが、とりあえず、ソースコードをとりよせてみましょうか。



% svn checkout --revision 6610 http://svn.gnome.org/svn/gdm/trunk gdm
A    gdm/m4
A    gdm/m4/.cvsignore
A    gdm/gui
A    gdm/gui/user-switch-applet
A    gdm/gui/user-switch-applet/gdm-user-menu-item.c
A    gdm/gui/user-switch-applet/gdm-entry-menu-item.c
~~~ おぉ!でてくる、でてくる ~~~
A    gdm/po/oc.po
U   gdm
リビジョン 6610 をチェックアウトしました。



取り出したファイルを確認してみると・・・



% head gdm/NEWS
===============
Version 2.24.0
===============



- Allow the build to succeed without a gdm user (Frederic Peters)
- Use Bourne shell syntax in Xsession.solaris (Brian Cameron)
- Set ownership of .gconf.mandatory (William Jon McCann)



portsでインストールしたgdm-2.24.1よりも、revision 6610のほうが古いじゃん。
う~ん???よくわかんないので、2.24.1を展開して、



% tar zxf /usr/ports/distfiles/gnome2/gdm-2.24.1.tar.bz2



svnでcheckoutしたコードと差分をもとめ



% diff -ur gdm-2.24.1/daemon/ gdm/daemon/ >/tmp/gdm.diff



portsでパッチをあてるところまでやって、



# make patch



svnとの差分をパッチあてして(強引だけど、一応、これでもよさそうな雰囲気であることは確認。daemonディレクトリだけ差分をもとめたのは、docsの中がかなり違ってたので)



# cd (portsの作業ディレクトリ)/x11/gdm/work/gdm-2.24.1/daemon/
# patch -p2 < /tmp/gdm.diff



コンパイルしなおして、再インストール。



# cd /usr/ports/x11/gdm/
# make
# make install FORCE_PKG_REGISTER=yes


さて、これでgdmを実行してみると、ポート番号177が開いてたので、XDMCPが有効になっていることは確認できました。



とりあえずVNC serverを使ってXDMCPが使えているか確認。



% Xvnc :1 -query サーバ



すると、だらだら~とメッセージが表示され・・・



gdm-binary[56430]: WARNING: Unable lookup hostname: Non-recoverable failure in name resolution
gdm-binary[56430]: WARNING: Unable lookup hostname: Non-recoverable failure in name resolution
gdm-binary[56430]: WARNING: Unable lookup hostname: Non-recoverable failure in name resolution
gdm-binary[56430]: WARNING: Unable lookup hostname: Non-recoverable failure in name resolution
Illegal instruction



あらあら、gdmが、おっこちました。



gdbで落っこちるまでの動きを調べてみると・・・



(gdb) where
#0  gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfc8d8) at gdm-address.c:220
#1  0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#2  0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfcd78) at gdm-address.c:220
#3  0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#4  0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfd218) at gdm-address.c:220
#5  0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#6  0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfd6b8) at gdm-address.c:220
#7  0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#8  0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfdb58) at gdm-address.c:220
#9  0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#10 0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfdff8) at gdm-address.c:220
#11 0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#12 0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfe498) at gdm-address.c:220
#13 0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#14 0x0805fbac in gdm_address_get_hostname (address=0x810710c, hostnamep=0xbfbfe938) at gdm-address.c:220
#15 0x08060526 in gdm_address_debug (address=0x810710c) at gdm-address.c:516
#16 0x0805e1fa in decode_packet (source=0x8129980, cond=G_IO_IN, factory=0x810e818) at gdm-xdmcp-display-factory.c:2840
#17 0x482bd76d in g_io_channel_unix_get_fd () from /usr/local/lib/libglib-2.0.so.0
#18 0x48289226 in g_main_context_dispatch () from /usr/local/lib/libglib-2.0.so.0
#19 0x4828c5c2 in g_main_context_check () from /usr/local/lib/libglib-2.0.so.0
#20 0x4828c9a7 in g_main_loop_run () from /usr/local/lib/libglib-2.0.so.0
#21 0x0804da50 in main (argc=1, argv=0xbfbfebc8) at main.c:639


gdm_address_debug() と gdm_address_get_hostname() が交互に呼び出されて、無限ループして、きっとスタックがあふれたんでしょう。



ソースコードを眺めてみると



gboolean
gdm_address_get_hostname (GdmAddress *address,
                          char      **hostnamep)
{
        char     host [NI_MAXHOST];
        int      res;
        gboolean ret;

        g_return_val_if_fail (address != NULL || address->ss != NULL, FALSE);

        ret = FALSE;

        host [0] = '\0';
        res = getnameinfo ((const struct sockaddr *)address->ss,
                           sizeof (struct sockaddr_storage),
                           host, sizeof (host),
                           NULL, 0,
                           0);
        if (res == 0) {
                ret = TRUE;
                goto done;
        } else {
                g_warning ("Unable lookup hostname: %s", gai_strerror (res));
                gdm_address_debug (address);


gdm_address_get_hostnameでエラーが出たとき、そのエラーメッセージを出すためにgdm_address_debugを呼び出すのですが・・・



void
gdm_address_debug (GdmAddress *address)
{
        char *hostname;
        char *host;
        char *port;

        g_return_if_fail (address != NULL);

        hostname = NULL;
        host = NULL;
        port = NULL;

        gdm_address_get_hostname (address, &hostname);



呼び出された先のgdm_address_debugで、また、gdm_address_get_hostnameを使ってます。
だめぢゃん・・・



とりあえずこの辺については、なんとか回避するコードを追加。



でも、やっぱり動かない。



gdmにXDMCPのリクエストが届いたとき、



        res = getnameinfo ((const struct sockaddr *)address->ss,
                           sizeof (struct sockaddr_storage),
                           host, sizeof (host),
                           NULL, 0,
                           0);



みたいな感じで、リクエストの出所のアドレスを求めているんですが、なぜか、そのアドレスが正しく取り出せないんです。うちの環境の問題かなぁ?



リクエスト元がわからないので、gdmも、返事を返せず、という状況になっているようでした。



address->ssの先に、IPアドレスが埋め込まれているのはgdbで確認ずみなんですが、sockaddr_inとか、もうすっかり忘れちゃってる。どういうデータが正しいんだったかなぁ。





というわけで、旧バージョンのgdmをpkg_addしちゃいました。せっかく消したgailが、またインストールされちゃいましたが・・・


svnで最新のgdmのコードを取り出して差分を眺めてみたんですが、6610とあまり変わらないんですよねぇ。
どうしたものか。



ちなみに、Xvfbの中では、gdmのログインウインドウが表示されていました。きっと、inetではなくunixドメインだから動いてるんでしょうね。





0 件のコメント:

コメントを投稿