git-daemon と xinetd

CentOS 6 で xinetd を介して git-daemon を利用するとうまくうごかなかった。
なんとかうごくようになったが、なぜうまくいかなかったのか原因がはっきりわからない。また、自分がやった対応が妥当なものかも自信はない。
ただ、とりあえず、自分とおなじようにすれば、うごくようになる環境はあると思われる。

git プロトコルでのアクセスはリードオンリーにしておくのがよくて、cloneとかが成功すればいい、push が失敗しても気にしないでおく、というのでもいいかもしれないが、なんか気になったので、いろいろと試行錯誤した。

リモートリポジトリ用マシン

リモートリポジトリ用マシンは Oracle VirtualBox仮想マシンとして構築した。

仮想マシン
ホストOS Windows 7 x64 の Virtual Box 4.1.4 上の仮想マシン
仮想マシンは「オペレーティングシステム"Linux"。ヴァージョン"Rad Hat(64 bit)"」として構築した。
OS
CentOS 6。Minimum でインストール。
yum update はかけた。VBoxLinuxAdditions はインストールした(X Window Systemを入れていないので、X関連のVBoxLinuxAdditionsは入っていない)。
IPアドレス
192.168.108.3
Git
v1.7.1(CentOS 6 リポジトリのもの)とv1.7.6.1(RPMForge extras リポジトリのもの)を試した。

試行錯誤と、その結果

リモートリポジトリのベースディレクトリーは "/var/lib/git" である。"/var/lib/git" のオーナーは以下のように設定した。

グループ:git
ユーザー:git

ユーザー git は git-daemon 用のユーザーとしてのみ利用し、作業は別のユーザーで行った。

なお、実験に使ったリポジトリディレクトリーは "test0001.git" であり(フルパスで"/var/lib/git/test0001.git")、実験のたびに作り直している。テスト時には下のようなシェルスクリプトを書いて、リポジトリの作成や、コピーをしていた。

if test -d test0001.git; then
        rm -Rf test0001.git
fi
mkdir test0001.git
git init --bare test0001.git
if test -d /var/lib/git/test0001.git; then
        rm -Rf /var/lib/git/test0001.git
fi
cp -Rf test0001.git /var/lib/git
chown -R git:git /var/lib/git/test0001.git

下のようにコマンドを叩いて、 git-daemon を起動した。

# 実行例1
$ sudo -u git git daemon --base-path=/var/lib/git --export-all --enable=receive-pack --reuseaddr --port=9418
# 実行例2
$ sudo -u git /usr/libexec/git-core/git-daemon --base-path=/var/lib/git --export-all --enable=receive-pack --reuseaddr --port=9418

実行例1、2のときは、リモートリポジトリへの push は成功した。

# リモートリポジトリへの push 。
$ git push git://192.168.108.3/test0001.git master

そのときに出力されたメッセージは下のようなもの。

$ git push git://192.168.108.3/test0001.git master
Counting objects: 34, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (34/34), 9.12 KiB, done.
Total 34 (delta 2), reused 0 (delta 0)
To git://192.168.108.3/test0001.git
 * [new branch]      master -> master

確認に clone も行ってみた。これも成功した。(出力されたメッセージは省く)

# リモートリポジトリからのクローン clone 。
$ git clone git://192.168.108.3/test0001.git

ところが、 xinetd を介して git-daemon コマンドを起動すると push に失敗する。以下のようなメッセージが出力される。

$ git push git://192.168.108.3/test0001.git master
Counting objects: 34, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (18/18), done.
fatal: Writing objectsThe remote end hung up unexpectedly:
fatal: sha1 file '' write error: Connection reset by peer
error: failed to push some refs to 'git://192.168.108.3/test0001.git'

/var/log/messages を見ると、リモートリポジトリ側でデータは受け取ったが、受け取ったデータを書き込めない、といったような内容のメッセージが出力されていた。権限が足りないとかあった*1
単純に、git-daemonを起動したときには、何も問題はなかったのに? 試しにリモートリポジトリのディレクトリー内のファイル/サブ・ディレクトリーに、otherにまで書き込み権限など与えたりしてみても、ダメだった*2
このときの xinetd 用の設定ファイル git は以下のようなもの。

#CentOS 6 では /etc/services のなかに git の情報があるので、 type と port は書かなくてもよい(書かないほうがよい?)。
service git
{
        disable         = no

        socket_type     = stream
        wait            = no
        user            = git
        server          = /usr/libexec/git-core/git-daemon
        server_args     = --base-path=/var/lib/git --export-all --enable=receive-pa
ck --syslog --inetd --verbose
        log_on_failure  += USERID
}

これを git-daemon コマンドを直接叩くのではなく、git コマンドを使って外部コマンドの git-daemon を叩くようにしてやった。

# なぜか、git コマンドから外部コマンド git-daemon を起動するとうまくいった。
service git
{
        disable         = no

        socket_type     = stream
        wait            = no
        user            = git
        server          = /usr/bin/git
        server_args     = daemon --base-path=/var/lib/git --export-all --enable=receive-pa
ck --syslog --inetd --verbose
        log_on_failure  += USERID
}

すると成功した。

Solaris であって、 Linux の事例じゃないが、次のページにあるようなことが、自分の環境でも起こっているのか?と思う。
[solaris - git push failing - Stack Overflow]
xinetd を介して起動する際に、ライブラリがうまくロードされていないとか、なんか必要なものがそろってないとか、な。git コマンドを叩いて、 git-daemon コマンドを起動すると、git コマンドがいろいろ準備するからうまくいく……というものだろうか? Linuxはときどきしか使わんから細かいことはようわからん。xinetd が git コマンドから git-daemon を叩こうが、xinetd から直接 git-daemon を叩こうが、xinetd を介すると、どんな方法をとっても、どうしようもないようだったら、 xinetd を介さず、 init で git-daemon コマンド叩くようスクリプトを書いて、デーモンが常駐するようにする必要があるかもな*3

*1:権限が足りないから書き込めないのか、書き込めないから権限が足りないとメッセージを出しよるのか、よくわからん。

*2:それ(otherにまでやたらと権限を与える)でなんとかなったとしても、あまりうれしくないが。

*3: http://d.hatena.ne.jp/juratena/20090518 とか参照。