January 15, 2013

だからそんな事に spawn を使うなと!

この記事は 2013 年 1 月 16 日の「Syn の独り言」の記事を移行したものです。

いらん所で spawn を使おうとしている人がいたので、つい。

普通、プログラムを書くときはデフォルトで stdin, stdout, stderr という入出力ストリームが始めから開いている。でも、tty 上にはこれ以外の文字列が表示される事もある。

たとえば、sudo コマンド実行時にパスワードが聞かれたりする場合。

$ sudo env >/dev/null 2>&1

と実行すると、stdout も stderr も /dev/null へ捨てられるはず。でも、パスワードの入力を促す文字列(プロンプト)はちゃんと tty に表示される。

だから、「パスワード入力を促されたら "MyPass" と入力する」プログラムを書こうとした場合、「パスワード入力を促されたら」の確認部分を stdout や stderr を監視で実装する事はできない。繰り返しになるが、入力を促す文字列は tty にのみ出力されるからだ。

ではどうしたら良いか?

spawn を使えば実装できる。

spawn とは fork してから仮想 tty を開く関数の一般名。色々な言語で実装されている。そして、tty に出力される文字列を全て (stdout や stderr も含めて) 取得できる。もちろんプロンプトもだ。

ただ、安直に spawn を使う前に考えてほしい。

で sudo はパスワード入力を stdout や stderr ではなく、プロンプトに出力するのか?

それは、sudo 実装者が「プログラムではなく、人間に見せたい」と考えたからだろう。つまり、そもそも論として「sudo のパスワードをに入力するプロラム」自体がsudo 実装者の意図に反しており、根本の設計から良くない可能性がある。

個人的には「プロンプトを制御する」とは、「例外を握りつぶす」と似ていると思う。絶対に間違っているとは言わないが、基本的には避けて通りたい。

では、プログラムの中で sudo コマンドを実行したい場合、どうすればいいか?パスワード入力をやめればいい。sudo の場合は設定次第でパスワード無しで実行可能に出来る。だから、そもそもプログラムからパスワードを入力する必要が無いのだ。

なぜ spawn を使うよりパスワード無しにした方が良いのか。例えば、パスワードを入力させるためにはどこかにパスワードを記載する必要があるから。もしプログラムにパスワードを記載すると、subversion などのアクセス権のある人全員にパスワードがばれてしまう。

もちろんソースコードを厳重に管理するとか、実行可能な sudo コマンドを制限するとか方法はいくらでもある。でも、いらんタスクや制限を増やすのは優秀なエンジニアのする事ではない。「コード中にパスワードを絶対に書くな」とは言わないけれど、それが sudo の思想なのだ。素直に従うべきだろう。

sudo に限らず、tty に出力をするコマンドはプログラムから実行するための抜け道を用意している事が多い。その抜け道がどうしても見つからない場合や、何等かの原因で抜け道を実行する事が出来ない場合は spawn を使ってもいいかもしれない。

でも、その前に「本当にそれでいいのか?」と自問自答をする必要がある。

spawn が本当に役に立つのはクロスプラットフォームで動作する、汎用性の高いプログラムやライブラリを書く時ではないだろうか?

spawn は windows でも unix でもインターフェースが似ているのでコードの OS 依存部分が少なくなる。

また、sudo の例で言うとオプションでパスワードを入力できるようにすれば何らかの理由で sudo の設定を変更出来ない環境でも使用できるようになる。(もちろん、設定変更できる場合に備えて空パスでも動くように実装するべき)

まあ、「動けばいい」っていう考え方もあるんだけど、こういう所からバグって生まれる気がするんだよね。