2022-11-06

win-ssh-agentをMSYS2で使う

長年win-ssh-agentを使っているのですが、ふとMSYS2で動作するのか、また、ビルドできるのか気になったので試してみました。

MSYS2でwin-ssh-agentをビルドする

ビルドするには、おそらく

pacman -S base-devel
pacman -S msys2-devel
pacman -S msys2-runtime-devel

あたりが入っていれば良いのだと思います。色々やった後の環境なので、いつの間にか入っているパッケージで必要なものがまだあるかもしれません。

それらを入れてMSYS環境からmakeしてみたところ、無事ビルドが成功して動作もしました。出来上がったexeはCygwinと同じように専用のDLL(msys-2.0.dll)に依存します。win-ssh-agentはpopenやらwait3やらcygwin_internalやら素のWindowsには無い関数を使用しているので仕方ないところです。全部Win32で書き直せば依存関係を減らせますが、CygwinかMSYS2環境下で動かすのが目的なのでやる必要は無いでしょう。

CygwinとMSYS2の両方で使う

通常Cygwin側でwin-ssh-agentを実行してもMSYS2側のsshでは認識されません(毎回パスフレーズが求められます)。反対にMSYS2側でwin-ssh-agentを実行してもCygwin側のsshでは認識されません。

なぜかというと環境変数に保存されるパスがそれぞれの環境独自のパスになっているからです。例えば次のように。

SSH_ASKPASS=/usr/loca/bin/win-ssh-askpass.exe
SSH_AUTH_SOCK=/tmp/ssh-????????????\agent.????

/usr/tmp がどこにマップされているかは環境(CygwinかMSYS2か)で異なります。

これをc:から始まる通常のフルパスに直すとCygwinからでもMSYS2からでも認識されます。

SSH_ASKPASS=c:\cygwin\usr\local\bin\win-ssh-agent/win-ssh-askpass.exe
SSH_AUTH_SOCK=c:\cygwin\tmp\ssh-????????????\agent.????

MSYS2も元はCygwinということできっと方式は同じなのでしょう。

win-ssh-agentではわざわざWindows標準のパスをCygwin用のパスに変換している場所があります(SSH_ASKPASS設定時)。また、ssh-agentから返ってくるCygwin用のパスを変換せずにSSH_AUTH_SOCKに設定しています。これらの場所で確実にWindows用のフルパスに変換してしまえば、CygwinからでもMSYS2からちゃんと認識してくれるようになります。

具体的には、 misc.h, misc.cpp に conv_path_posix_to_win という関数があるので、それをコピーしてstd::stringを返すバージョン(conv_path_posix_to_win_aとか)を作り、setenvするところ(こことかこことか)で変換してしまえばOKです。ちゃんとやるなら全部ワイド文字列にすべきですが、面倒なのでいいや。

最近の事情

最近はWindows版のOpenSSHだとかWSLだとかもあるので状況はより複雑なようです(see: 混沌を極めるWindowsのssh-agent事情 - Qiita)。幸い私はそれらを使っていないのでまだまだこのままで大丈夫なようです。

最近の悩みと言えばCygwinとMSYS2で同じような物を二つ入れておくのが何だか無駄に思えてきたことです。どちらも数GBくらい容量を食いますからね。昔から(それこそMeadowの頃から)常用しているのはCygwinでMSYS2はたまにしか使っていませんが、GitにせよEmacsにせよUnix由来のソフトウェアのWindows版はMSYS2でビルドすることが多いので、それならMSYS2で統一してしまおうかなと考えています。今回のはそのための布石です。ただ、Emacsの設定からCygwin依存部分を除去するのが案外面倒なので二の足を踏んでいます。不具合を無理矢理直している所もあるので。