2011年10月15日

存在しないコマンドを入力したとき、パッケージをインストールするか聞かれる仕組み

Fedora 13 でターミナルを使っているとき、存在しないコマンドを入力すると、パッケージをインストールするか聞かれることがあります。例えば以下のような感じです。


$ sl
コマンドが見つかりません。 コマンド sl' を提供するためにパッケージ 'sl' をインストールしますか? [N/y]


どうやら、コマンドが含まれているパッケージを自動的に教えてくれるようです。ここでリターンを押せばそのまま終了します。また、y を入力してリターンを押すと、その場でパッケージのインストールが始まります。以下のような感じ(途中でrootパスワードを聞かれます)。


$ sl
コマンドが見つかりません。 コマンド sl' を提供するためにパッケージ 'sl' をインストールしますか? [N/y]
* ソフトウェアソースについての詳細をダウンロード中。..
* 実行中..
* 依存関係を解決中..
* 認証を待ち受け中..
* 実行中..
* 依存関係を解決中..
* パッケージをダウンロード中..
* 変更をテスト中..
* パッケージのインストール中..
* アプリケーションをスキャン中..
$


インストールが終わると、自動的にコマンドが実行されます。今回の場合は、sl コマンドが実行されます。

さて、私としては、これがいったいどのような仕組みなのかが気になります。そこで、仕組みを(twitter で何人かの方にヒントをいただきながら)調べました。

実は、Fedora の Wiki にこの機能についての情報が記載されています(調べた後で気づきました・・・)。この記事では、私の調べたことを記載してみます。


コマンドが見つからないと通知するのはシェル(今回の環境では bash)です。bash 4.0 以降には、コマンドが見つからなかったときに実行されるフック関数を指定できます(この機能は、もともと Debian/Ubuntu の独自拡張だったのが、bash 本家に取り込まれたそうです)。

bash で set コマンドを実行すると、command_not_found_handle という関数が見つかりました。これがフック関数で、/etc/profile.d/PackageKit.sh というファイルの中で定義されていました。

command_not_found_handle () {
runcnf=1
retval=127

# don't run if DBus isn't running
[ ! -S /var/run/dbus/system_bus_socket ] && runcnf=0

# don't run if packagekitd doesn't exist in the _system_ root
[ ! -x /usr/libexec/packagekitd ] && runcnf=0

# run the command, or just print a warning
if [ $runcnf -eq 1 ]; then
/usr/libexec/pk-command-not-found $1
retval=$?
else
echo "bash: $1: command not found"
fi

# return success or failure
return $retval
}


このフック関数の中で pk-command-not-found というプログラムが呼ばれます。このソースコードは、PackageKit の contrib ディレクトリに含まれています。この中で PackageKit の機能を使って、コマンドを含むパッケージを探し、インストールするようになっています。

分かってしまえば、わりと単純な仕組みですね。でも、発想が面白い。

なお、この機能は、PackageKit-command-not-found という rpm パッケージがインストールされているときのみ機能します。上記の /etc/profile.d/PackageKit.sh も pk-command-not-found もこのパッケージに含まれています。


$ rpm -qi PackageKit-command-not-found
Name : PackageKit-command-not-found Relocations: (not relocatable)
Version : 0.6.6 Vendor: Fedora Project
Release : 3.fc13 Build Date: 2011年03月25日 18時44分28秒
Install Date: 2011年06月21日 11時45分32秒 Build Host: x86-03.phx2.fedoraproject.org
Group : Development/Libraries Source RPM: PackageKit-0.6.6-3.fc13.src.rpm
Size : 307334 License: GPLv2+ and LGPLv2+
Signature : RSA/SHA256, 2011年03月25日 18時07分04秒, Key ID 7edc6ad6e8e40fde
Packager : Fedora Project
URL : http://www.packagekit.org
Summary : Ask the user to install command line programs automatically
Description :
A simple helper that offers to install new packages on the command line
using PackageKit.
$ rpm -ql PackageKit-command-not-found
/etc/PackageKit/CommandNotFound.conf
/etc/profile.d/PackageKit.sh
/usr/libexec/pk-command-not-found
/usr/share/doc/PackageKit-command-not-found-0.6.6
/usr/share/doc/PackageKit-command-not-found-0.6.6/AUTHORS
/usr/share/doc/PackageKit-command-not-found-0.6.6/COPYING
/usr/share/doc/PackageKit-command-not-found-0.6.6/NEWS
/usr/share/doc/PackageKit-command-not-found-0.6.6/README


最近、久しぶりに Linux を使っていますが、こんな感じで新たな発見があると嬉しくなります。業務上の都合で、ディストリビューションが Fedora 13 固定だったり(ちょっと古いよなあ)、シェルは bash だったり(普段の Mac では zsh なのに)、とかいう制限はあるものの、Linux ってやっぱり楽しい。
posted by usami-k at 13:45| Comment(0) | TrackBack(0) | 雑文 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/230537273
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。