組込みLinux Beaglebone Black でやってみる その7 ルートファイルシステム、 BusyBoxビルド

ここでは、BusyBoxを使って組込Linux用のカスタマイズされたコンパクトなRoot File Systemを作ります。 

Busy Boxで出来ること

  • 組込Linuxのボードのメモリは限りがあるので、不要なコマンドや機能やディレクトリを削除して、組込Linuxボードのリソースにフィットするようにファイルシステムをカスタマイズすることが出来ます。
  • 更にメモリを減らすため、全てのLinuxコマンドを一つのバイナリファイルにまとめる事ができる。
  • BusyBoxはコマンド関連が種なので、生成するのは/sbin、/bin、/usrディレクトリとlinuxrcリンクのみ。 そこに生成したKernelモジュールをインストールして/libディレクトリが生成される。 しかし、これら以外にも初期設定等のファイルが必要になる。7では、/libを作るところまで。

BusyBoxのダウンロード

  1. https://busybox.net/downloads/ に行き
  2. リストの中から、busybox-1.35.0.tar.bz2 2021-12-26 17:24 2.4M をクリックしてダウンロード (この時点で最新)
  3. ~/BBB_Workspace/Downloadsに移動して展開します

過去の作業ファイル削除

展開すると、/busybox-1.35.0ディレクトリができるので、そこに移動して作業します。

U-BOOTやLinux Kernelをビルドしたときと同じで、最初から始める時に過去の設定ファイルやビルドしたファイルを削除します。

$ cd ~/BBB_Workspace/Downloads/busybox-1.35.0/
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean

環境設定(.config)ファイル生成

  • ~/BBB_Workspace/Downloads/busybox-1.35.0/ に移動して以下を実行します(上と同じディレクトリ)。
  • BusyBox用の、.configを生成するため、defconfigを指定します。
  • このディレクトリ下に.configファイルが生成されます。
  • 1分弱でできました。
$ cd ~/BBB_Workspace/Downloads/busybox-1.35.0/
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
  • 上記だけだと初期設定のままなので、不要コマンド削除や追加などは、次のmenuconfigで設定すします。
  • 静的ライブラリ化するかしないかなどの設定。 ここでは設定します。
  • Settings -> Build static binary (no shared libs) を『y』で選択(これで静的ライブラリ化する設定をする=>バイナリを生成した時に、コマンド群が一つのbusyboxバイナリファイルに統合される。各コマンド名はbusyboxにソフトリンクされる。 これで容量を大きく削減する。)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

BusyBoxのバイナリ生成

  • 上と同じディレクトリで実行します。
// <install_path>は、Root File Systemをインストールするとこをを指定
// 以下コマンドの実行は、~/BBB_Workspace/Downloads/busybox-1.35.0/ d
// make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=<install_path> install
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=~/BBB_Workspace/RFS_Static install  //5分ほどかかりました
  • /RFS_Staticディレクトリも自動で作るので用意しなくても構いません
  • /RFS_Static内に以下のディレクトリが生成されます
    • bin
    • (lib) <—- 次のKernel Module のインストール時に生成される
    • sbin
    • usr
  • 静的ライブラリでビルドすると、全てのコマンドにはソフトリンクが付き、/bin/busyboxをソフトリンクする。 /sbin/内のできるコマンドも/bin/busyboxにソフトリンクされる。
  • /binや/sbin内をls -lで表示してみてください。
  • この時点で、この/RSF_Staticディレクトリ下の容量はbusyboxの約1.5MB   du -sh で確認。
  • 次のKernel Moduleを追加すると67MBとなった

Warning

  • 上記を実行すると以下のようなWarningがいくつか表示されます。
  • あくまでWarningなので無視してください。

include/libbb.h:236:28: warning: ignoring return value of ‘fgets_unlocked’, declared with attribute warn_unused_result [-Wunused-result]
  236 | # define fgets(s,n,stream) fgets_unlocked(s,n,stream)
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~
networking/arp.c:430:2: note: in expansion of macro ‘fgets’
  430 |  fgets(line, sizeof(line), fp);
      |  ^~~~~
  CC      networking/arping.o
  • このWarningは、fgets_unlocked( )関数の返り値のエラー処理がありませんと警告しているだけです。
  • Stackoverflowにに書かれていました。 以下のような処理がないからだそうです。
int Ret = fgets_unlocked(commandLine);
if(Ret == -1){
  // The fgets_unlocked method failed
}

Kernel モジュール(driverなど)のインストール(ここまで)

  • 『Linux Kernelビルド その6』で作ってあるKernelモジュール群をBusyBoxで作ったファイルシステムに組み込みます。 ここで/libディレクトリが生成される。
  • /linuxのディレクトリに移動して実行します。
  • 2分弱かかりました。
  • ~/BBB_Workspace/RFS_Static/lib/ が出来ています。
$ cd ~/BBB_Workspace/Downloads/linux/     // 既に作ったドライバのモジュールがあるフォルダに移動する。
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=~/BBB_Workspace/RFS_Static modules_install
  • ~/BBB_Workspace/RFS_Static/lib/modules/5.10.145+/kernel/drivers に多くのドライバーがインストールされました。
  • /lib/modules/5.10.145+/modules.builtin にはモジュールにしなかったKernelイメージに組み込まれた静的コマンドがリストアップされています。 viで確認できる。 500行なので500個のドライバーがインストールされています。 これら以外にモジュール化(ファイル)したドライバーもインストールされています。
  • lib/modules/5.10.145+/modules.dep には動的にロード出来るKernelモジュール間の依存がリストアップされています。 エラーが出た時に何の依存ファイルがないか検証できます。
  • 2 kernel/arch/arm/crypto/aes-arm-bs.ko: kernel/crypto/crypto_simd.ko kernel/crypto/cryptd.ko kernel/lib/crypto/libaes.ko このようになっていたら、aes-arm-bs.koは、3つのファイルに依存しているが、一番下位のモジュールが右から並んでいます。 この場合 libaes.ko が最初の依存ファイルです。
  • 1.5MBだったBusyBoxのルートFSにKernelモジュール(ドライバ)を入れたら28MBになりました。
  • modprobe コマンドは非常に重要で、モジュールをLinux Kernelに追加やLinux Kernelから削除できます。
  • insmodも重要

『その7』はここまで、

その他 参考

runlevel

  • busyboxはrunlevelコマンドやtelinitコマンドは『not found』
  • もしランレベルが必要なら、sysvinitを使うらしい

/etc/inittab

  • busyboxのinitは、inittabがあれば優先的に実行する。
  • inittabがなければ、以下の様に/etc/init.d/rcSを実行する。
::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
tty2::askfirst:/bin/sh
tty3::askfirst:/bin/sh
tty4::askfirst:/bin/sh

  • inittabファイルはrun-levelに応じてどの様なinit processを実行するか記述したファイル。
  • 以下のように記述する
# /etc/inittab
# Copyright (C) 2001 Erik Andersen
# Note: BusyBox init doesn’t support runlevels.  The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use sysvinit.
# Format for each entry: :::
#
# id        == tty to run on, or empty for /dev/console
# runlevels == ignored
# action    == one of sysinit, respawn, askfirst, wait, and once
# process   == program to run
# <id>:<runlevels>:<action>:<process>
# ichiri::sysinit:~/ichiri.sh 

# Startup the system
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts
::sysinit:/bin/mkdir -p /dev/shm
::sysinit:/bin/mount -a
::sysinit:/bin/hostname -F /etc/hostname

# now run any rc scripts
::sysinit:/etc/init.d/rcS

# Put a getty on the serial port
console::respawn:/sbin/getty -L  console 0 vt100 # GENERIC_SERIAL

# Stuff to do for the 3-finger salute
#::ctrlaltdel:/sbin/reboot

# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

respawnの設定場所

  • respawnとは、そのプロセスが終了したら、起動をかけるアクションの事。
  • 再起動が早すぎ(too fast)などのデバッグログも出力されるので、ログを見ながらrespawn時間を設定し直す。
busybox/init/init.c
....
#define TESTTIME  90    /* Threshold for detecting "fast" spawning processes */
#define MAXSPAWN  5     /* Number of rapid respawns that counts as too fast */
#define SLEEPTIME 300   /* Fast spawn hold off period */
#define DELAYTIME 5     /* Time between successive runs of a process */
....
       now = time(NULL);
       if (a->lastrun + TESTTIME > now)
           a->runcount++;
       else
           a->runcount = 0;
       if (a->runcount >= MAXSPAWN) {
           a->runcount = MAXSPAWN-1;
           a->nextrun = now + SLEEPTIME;
           message(LOG, "Process '%s' (pid %d) is respawning "
                   "too fast.\n", a->command, wpid);
       } else {
....

BusyBox便利な機能

  • Linux Kernel menuconfig で [*] Networking support
  • Busybox menuconfig -> Networking Utilities
    • [*] dnsd
      • 初期値 [=y]
    • [*] ifconfig
      • 初期値 [=y]
    • [*] route
      • 初期値 [=y]
    • wget インターネットから不足ライブラリをダウンロードできる
      • 初期値 [=y]
    • httpd でwebserver搭載可能
      • 初期値 [=y]
    • inetd でネットワーク関連のデーモン経由の起動が可能
      • inetd.confにアクセス許可などの設定を記述する
      • 初期値 [=y]
    • ftpd  でFTPが使える。 BusyBoxではftpd単独で動作せず、必ずinetdを通す。
      • 初期値 [=y]
    • telnetd でtelnetを使える
      • 初期値 [=y]

NTPやSSHは組込まないといけない

これらはBuildrootを使うと簡単にインストールできます。 多分Yoctoでも出来ると思います。

あるいは、Dropbearやntpclientのように別途組み込んでいく必要があります

  • http://doolittle.icarus.com/ntpclient/ からダウンロードできる
      • 必要ファイルは3つのみ
        • ntpclient.c
        • ntpclient.h
        • phaselock.c
        • https://gihyo.jp/dev/serial/01/micom-linux/0007 を参考

Alpine Linux

  • BusyBoxとmuslをベースにした無料の軽量OSS Linux Distribution
  • Apk パッケージマネージャーが搭載されている
  • ARM AArch64対応
  • 組込に使えそう
  • 懸念点はmuslがまだver1.0になっていない

BusyBoxはwgetのみ

なので、apkが使えるAlpineがいいのかなと思っています。

  • aptだと、sudo apt install nano とライブラリ名だけで、ネット上を検索して、ダウンロードして、適切な場所にインストールしてくれる
  • wgetだと、以下が必要
    1. インストールする適切なディレクトリ作成
    2. ファイル名含むURLを指定してダウンロード
    3. 解凍展開
    4. 設定
    5. ビルド
    6. インストール
    7. 不要になったダウンロードした圧縮ファイルの削除
    8. PATHを通す
$ wget https://www.nano-editor.org/dist/v4/nano-4.0.tar.gz
$ tar -zxvf nano-4.0.tar.gz
$ cd nano-4.0
$ ./configure --enable-utf8
$ make
$ sudo make install
$ cd ~/
$ rm -rf nano-4.0*

コメント