目次


IBM BusyBox を使って組み込み Linux システムを単純化する

小さな環境のための小さなツールキット

Comments

BusyBox の誕生

BusyBox は 1996 年に Bruce Perens によって、Debian GNU/Linux のセットアップ・ディスク用に最初に作成されました。BusyBox の目標は、ブート可能な GNU/Linux システムを 1 枚のフロッピー・ディスク上に作成し、インストールやレスキュー用に使用できるようにすることでした。1 枚のフロッピー・ディスクには 1.4 MB から 1.7MB 程度しか入らないため、Linux カーネル用や関連するユーザー・アプリケーション用に使用できるスペースは、ほとんどありません。

BusyBox は、標準的な Linux ユーティリティーの多くは共通要素を共有している、という事実を利用しています。例えばファイル・ベースのユーティリティー (grep や find など) の多くは、ファイルの検索でディレクトリーに対して再帰を行うコードを必要とします。こうしたユーティリティーを組み合わせて 1 つの実行可能ファイルにまとめると、共通要素は共有できるため、できあがる実行可能ファイルを小さくすることができます。実際 BusyBox では、約 3.5 MB のユーティリティーを約 200 KB の中に収めています。これによって、Linux を使用するブート・フロッピー・ディスクや組み込みデバイスは、強力な機能を持つことになります。BusyBox は、2.4 と 2.6 のどちらの Linux カーネルでも使用することができます。

BusyBox はどのように動作するのか

BusyBox では、1 つの実行可能ファイルが多くの実行可能ファイルのように見えるために、C の main 関数に引数を渡すという、めったに使わない機能を活用しています。C の main 関数は次のように定義されることを思い出してください。

リスト 1. C の main 関数
int main( int argc, char *argv[] )

この定義では、argc は渡される引数の数 (引数カウント) で、argv はコマンドラインから渡されるオプション (引数ベクトル) を表すストリング配列です。argv のインデックス 0 はコマンドラインから呼び出されたプログラム名です。

リスト 2 に示す単純な C プログラムは BusyBox の呼び出し動作を示しています。このプログラムは単純に argv ベクトルの内容を出力します。

リスト 2. BusyBox が argv[0] を使って、どのアプリケーションを呼び出すかを決定する
// test.c
#include <stdio.h>

int main( int argc, char *argv[] )
{
int i;

for (i = 0 ; i < argc ; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}

return 0;
}

このアプリケーションを呼び出すと、呼び出される最初の引数がプログラム名であることが分かります。実行可能ファイルをリネームして、それを呼び出すと、新しい名前になっているはずです。また、実行可能ファイルへのシンボリック・リンクを作成することもできます。その実行可能ファイルを呼び出すと、symlink の名前が得られます。

リスト 3. 新しいコマンドで BusyBox を更新した後にコマンドをテストする
$ gcc -Wall -o test test.c
$ ./test arg1 arg2
argv[0] = ./test
argv[1] = arg1
argv[2] = arg2

$ mv test newtest

$ ./newtest arg1
argv[0] = ./newtest
argv[1] = arg1

$ ln -s newtest linktest
$ ./linktest arg
argv[0] = ./linktest
argv[1] = arg

BusyBox は、シンボリック・リンクを使うことで 1 つの実行可能ファイルが多くの実行可能ファイルに見えるようにしています。BusyBox の中に含まれるユーティリティーそれぞれに対して、BusyBox を呼び出せるようにシンボリック・リンクが作成されます。そうすると BusyBox は、argv[0] で定義される内部ユーティリティーを呼び出します。

BusyBox をコンフィギュレーションし、ビルドする

最新バージョンの BusyBox は、BusyBox の Web サイト (参考文献を参照) からダウンロードすることができます。他のオープンソース・プログラムと同様、BusyBox は圧縮された tarball として配布されており、これはリスト 4 のコマンドを使ってソース・ツリーに変換することができます。(もし 1.1.1 以外のバージョンをダウンロードした場合は、ここに示す 1.1.1 を適切なバージョン番号に変更し、そのバージョン専用のコマンドを使うようにします。)

リスト 4. BusyBox の tar を解凍する
$ tar xvfz busybox-1.1.1.tar.gz
$

この結果として、BusyBox のソースコードを含んだ、 busybox-1.1.1 というディレクトリーが作られます。デフォルトのコンフィギュレーション (ほとんどすべてのものを含み、デバッグは無効になっています) を作成するためには、次のように defconfig の make target を使います。

リスト 5. デフォルトの BusyBox コンフィギュレーションをビルドする
$ cd busybox-1.1.1
$ make defconfig
$ make
$

この結果、かなり大きな BusyBox イメージができますが、最初はこれが一番単純なのです。この新しいイメージは直接呼び出すことができます。そうすると、現在コンフィギュレーションされているコマンドを表示した単純な Help ページができます。イメージをテストするために、実行用のコマンドを使って BusyBox を呼び出すこともできます。これをリスト 6 に示します。

リスト 6. BusyBox のコマンドを実行し、BusyBox の ash シェルを示す
$ ./busybox pwd
/usr/local/src/busybox-1.1.1
$ ./busybox ash
/usr/local/src/busybox-1.1.1 $ pwd
/usr/local/src/busybox-1.1.1
/usr/local/src/busybox-1.1.1 $ exit
$

この例では、 pwd (print working directory) コマンドを呼び出します。つまり、BusyBox の中の ash シェルに入り、そして ash の中の pwd を呼び出します。

手動によるコンフィギュレーション

非常に特定な目的を持った組み込みデバイスを構築する場合には、BusyBox の内容を、 menuconfig の make target を使って手動でコンフィギュレーションすることができます。Linux カーネルのビルドに慣れている人は、menuconfig が、Linux カーネルの内容をコンフィギュレーションする場合のターゲットと同じであることに注意してください。実際、ncurse ベースのアプリケーションの場合も同じです。

手動でコンフィギュレーションを行う場合には、最終的な BusyBox イメージに含まれるコマンドを指定することができます。また、BusyBox の環境をコンフィギュレーションすることもできます。例えば、(組み込み環境でのクロス・コンパイル用に) 使用するコンパイラーを指定し、また BusyBox を静的にコンパイルするか動的にコンパイルするかを指定することによって、NSA (United States National Security Agency: アメリカ国家安全保障局) の SELinux (Security-Enhanced Linux) のサポートを含める、などが可能です。図 1 は、menuconfig のメイン・スクリーンを示しています。これを見ると、BusyBox 用にコンフィギュレーション可能な、アプリケーションの主なクラス (アプレット) を見ることができます。

図 1. menuconfig を使った BusyBox のコンフィギュレーション
図 1. menuconfig を使った BusyBox のコンフィギュレーション
図 1. menuconfig を使った BusyBox のコンフィギュレーション

BusyBox を手動でコンフィギュレーションするためには、下記のコマンドを使います。

リスト 7. BusyBox を手動でコンフィギュレーションする
$ make menuconfig
$ make
$

これで、呼び出し可能な BusyBox バイナリーができました。次のステップは、標準の Linux コマンドを BusyBox バイナリーにリダイレクトするシンボリック・リンクを含めて、BusyBox を取り巻く環境を構築することです。これは、次のコマンドで簡単に行うことができます。

リスト 8. BusyBox の環境を構築する
$ make install
$

デフォルトで、基本的な Linux 環境を含んだ _install という新しいローカル・サブディレクトリーが作成されます。そのルートを見ると、BusyBox にリンクする linuxrc プログラムがあります。linuxrc プログラムは、インストール・ディスクやレスキュー・ディスク (モジュラー化された boot prior を許可します) をビルドする際に便利です。またルートには、オペレーティング・システムのバイナリー (主に管理用に使われます) を含んだ /sbin サブディレクトリーと、ユーザー向けのバイナリーを含んだ /bin サブディレクトリーもあります。フロッピー用のディストリビューションや組み込み用の初期 RAM ディスクをビルドする際に、この _install ディレクトリーをターゲット環境に移植します。また、make プログラムに PREFIX オプションを使うと、イントール・サブディレクトリーを新しい位置にリダイレクトすることもできます。例えば下記のコード断片は、./_install ディレクトリーではなく /tmp/newtarget ルート・ディレクトリーを使って symlinks をインストールします。

リスト 9. symlinks を別のディレクトリーにインストールする
$ make PREFIX=/tmp/newtarget install
$

install make target を使って作成されるリンクは、busybox.links ファイルにあったものです。このファイルは BusyBox がコンパイルされる時に作成され、コンフィギュレーションされたコマンドのリストを含んでいます。install が実行されると、busybox.links ファイルがチェックされて symlinks が作成されます。

BusyBox へのコマンド・リンクは、ランタイム時に BusyBox を使って動的に作成することもできます。この機能は、CONFIG_FEATURE_INSTALLER オプションによって有効になり、ランタイム時に、以下のように行われます。

リスト 10. ランタイム時にコマンド・リンクを作成する
$ ./busybox --install -s
$

-s オプションを使うと、強制的にシンボリック・リンクが作成されます (使わない場合はハード・リンクが作成されます)。このオプションを使うためには、 /proc ファイルシステムが存在していることが必要です。

BusyBox のビルド・オプション

BusyBox には、最適な BusyBox のビルドとデバッグが行えるよう、いくつかのビルド・オプションが用意されています。

表 1. BusyBox で利用可能な make オプションの一部
make のターゲット説明
helpmake オプションの全リストを示します
defconfigデフォルト (汎用) のコンフィギュレーションを有効にします
allnoconfigすべてのアプリケーションを無効にします (空のコンフィギュレーション)
allyesconfigすべてのアプリケーションを有効にします (完全なコンフィギュレーション)
allbareconfigすべてのアプリケーションを有効にしますが、サブ機能は有効にしません
configテキスト・ベースのコンフィギュレーターです
menuconfigN-curse (メニュー・ベース) のコンフィギュレーターです
allBusyBox のバイナリーとドキュメンテーション (./docs) をビルドします
busyboxBusyBox のバイナリーをビルドします
cleanソース・ツリーをクリーンアップします
distcleanソース・ツリーを完全にクリーンアップします
sizes有効なアプリケーションのテキスト・サイズとデータ・サイズを出力します

コンフィギュレーションが定義されると、単純に make をタイプするだけで、実際に BusyBox のバイナリーがビルドされます。例えば、すべてのアプリケーションに対して BusyBox をビルドするためには、次のようにします。

リスト 11. BusyBox のバイナリーをビルドする
$ make allyesconfig
$ make
$

BusyBox のサイズを小さくする

BusyBox イメージのサイズを本格的に小さくしようとする場合には、次の 2 点に注意する必要があります。

決して静的バイナリー (必要な全ライブラリーがイメージに含まれます) としてビルドしないこと。静的バイナリーではなく、共有イメージとしてビルドすれば、他のアプリケーションで使われる利用可能なライブラリー (/lib/libc.so.X など) を使うことができます。

標準の glibc (GNU C ライブラリー) ではなく、uClibc を使ってビルドします。uClibc は組み込みシステム用に開発され、サイズを最適化した C ライブラリーです。

BusyBox コマンドがサポートするオプション

BusyBox のコマンドは、通常利用できるすべてのオプションはサポートしていませんが、頻繁に使用されるオプションは持っています。あるコマンドに対してどのオプションがサポートされているかを知りたい場合には、リスト 12 のように --help オプションを呼び出して使います。

リスト 12. --help オプションを呼び出す
$ ./busybox wc --help
BusyBox v1.1.1 (2006.04.09-15:27+0000) multi-call binary

Usage: wc [OPTION]... [FILE]...

Print line, word, and byte counts for each FILE, and a total line if
more than one FILE is specified. With no FILE, read standard input.

Options:
-c      print the byte counts
-l      print the newline counts
-L      print the length of the longest line
-w      print the word counts

$

ここに示したデータは、CONFIG_FEATURE_VERBOSE_USAGE オプションが有効になっていないと利用できません。このオプションを使わないと詳細なデータを得られませんが、その代わり約 13 KB を節約することができます。

BusyBox に新しいコマンドを追加する

BusyBox のアーキテクチャーはしっかりと定義されているため、新しいコマンドを追加するのは簡単です。最初のステップは、新しいコマンドのソースのための位置を選択することです。位置の選択はコマンドの種類 (ネットワーク・コマンドかシェル・コマンドか、など) によって行うようにし、他のコマンドとの一貫性を保つようにします。この点は重要です。新しいコマンドはやがて menuconfig 用の特定のコンフィギュレーション・メニュー (この場合は Miscellaneous Utilities メニュー) に現れるからです。

この例の場合では、新しいコマンドを (newcmd) と呼ぶことにし、それを ./miscutils ディレクトリーに置いています。この新しいコマンドのソースをリスト 13 に示します。

リスト 13. BusyBox の中に統合する新しいコマンドのソース
#include "busybox.h"

int newcmd_main( int argc, char *argv[] )
{
int i;

printf("newcmd called:\n");

for (i = 0 ; i < argc ; i++) {

printf("arg[%d] = %s\n", i, argv[i]);

}

return 0;
}

次に、新しいコマンドのソースを、選択したサブディレクトリーの Makefile.in に追加します。この例では ./miscutils/Makefile.in を更新します。既存のコマンドとの一貫性を保つため、新しいコマンドはアルファベット順で追加します。

リスト 14. Makefile.in にコマンドを追加する
MISCUTILS-$(CONFIG_MT)          += mt.o
MISCUTILS-$(CONFIG_NEWCMD)   += newcmd.o
MISCUTILS-$(CONFIG_RUNLEVEL)    += runlevel.o

次に、コンフィギュレーション・ファイルの更新を、これも ./miscutils ディレクトリーの中で行い、新しいコマンドがコンフィギュレーション・プロセスの中で見えるようにします。このファイルは Config.in と呼ばれ、新しいコマンドが次のようにアルファベット順で追加されます。

リスト 15. Config.in にコマンドを追加する
config CONFIG_NEWCMD
        bool "newcmd"
        default n
        help
          newcmd is a new test command.

この構造では、 (config キーワードによって) 新しい config エントリーが定義され、次に config オプション (CONFIG_NEWCMD) が定義されます。この新しいコマンドは、有効にするか無効にするかのいずれかなので、コンフィギュレーションには bool (ブール型) メニュー属性を使います。デフォルトは無効 (n は No を意味します) です。そして短い Help の記述で終わります。ソース・ツリーのコンフィギュレーション構文に関する文法のすべては、./scripts/config/Kconfig-language.txt にあります。

次に、新しいコマンドを含むように ./include/applets.h ファイルを更新します。このファイルに下記のラインを追加します。この際、アルファベット順を維持することを忘れないようにします。この順序を維持することは重要です。そうしないと、このコマンドは見つからないかもしれません。

リスト 16. applets.h にコマンドを追加する
USE_NEWCMD(APPLET(newcmd, newcmd_main, _BB_DIR_USER_BIN, _BB_SUID_NEVER))

これによって、コマンドの名前 (newcmd) と Busybox ソースでの関数名 (newcmd_main)、この新しいコマンド用のリンクが作成される場所 (この場合は /usr/bin ディレクトリー)、そして最後に、このコマンドがユーザー ID を設定する権限を持っているかどうか (この場合は no) が定義されます。

最後のステップの一歩前として、./include/usage.h ファイルに詳細な Help 情報を追加します。このファイルの中の例を見るとわかる通り、使い方についての情報は非常に詳細です。この場合は、新しいコマンドをビルドするために必要な、ごくわずかの情報のみを追加しました。

リスト 17. usage.h にヘルプ情報を追加する
#define newcmd_trivial_usage    "None"
#define newcmd_full_usage       "None"

最後のステップとして、新しいコマンドを有効にし (make menuconfig を使い、次に Miscellaneous Utilities メニューのオプションを有効にします)、次に make を使って BusyBox をビルドします。

新しい BusyBox が用意できると、リスト 18 に示すように新しいコマンドをテストすることができます。

リスト 18. 新しいコマンドをテストする
$ ./busybox newcmd arg1
newcmd called:
arg[0] = newcmd
arg[1] = arg1
$ ./busybox newcmd --help
BusyBox v1.1.1 (2006.04.12-13:47+0000) multi-call binary

Usage: newcmd None

None

そう、これで終わりです。BusyBox の開発者達が作ったツールは素晴らしいだけではなく、拡張も容易なのです。

まとめ

BusyBox は、メモリーに制約のある組み込みシステムや、フロッピーディスク・ベースのシステムをビルドするための素晴らしいツールです。BusyBox は、様々な種類の必要ツールやユーティリティーを一緒にまとめて 1 つの実行可能ファイルにし、共通コード部分を共有できるようにすることによって、大幅なサイズ縮小を実現しています。BusyBox は組み込み用のツールボックスにとって便利なツールであり、様々に試してみるだけの価値のあるものです。


ダウンロード可能なリソース


関連トピック

  • uClibcglibc の置き換えですが、メモリー占有スペースの要求を削減しています。glibc よりもリソース要求は少ないのですが、アプリケーションを uClibc に移植するために必要なことは、通常は再コンパイルのみです。
  • Open Group の POSIX FAQ は、POSIX について詳しく学ぶために役立ちます。この仕様の第 3 部は、特にシェルとユーティリティーを詳細に説明しています。
  • LinuxTiny は、2.6 Linux カーネルのメモリーとディスクの占有スペースを 2 MB の RAM にまで削減するための一連のパッチです。2.6 Linux カーネルのサイズを小さくすることに関心のある人は、Matt Mackall による、この成果を調べてみてください。
  • BusyBox の最新リリースをダウンロードしてください。このサイトには最新のニュースやバグ情報の他、BusyBox を使用し、修正するためのチュートリアルなども用意されています。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=236687
ArticleTitle=IBM BusyBox を使って組み込み Linux システムを単純化する
publish-date=08152006