NetBSDカーネル開発・テスト環境を構築する

[NetBSD Advent Calendar 2016](http://qiita.com/advent-calendar/2016/netbsd)、11日目の記事です。

[昨年のNetBSD Advent Calendar](http://qiita.com/advent-calendar/2015/netbsd)の[Luaカーネルモジュールでgetpid(2)やkill(2)相当の関数を呼んだりしてみる](http://qiita.com/furandon_pig/items/4f186c46a9e54e2649ae)という記事で、開発用とテスト用にNetBSDの環境を分けて作業する構成例を示していました。
単純に手を動かして設定を投入して行くだけなのですが、これが意外と煩雑です。

[Luaカーネルモジュールの記事](http://qiita.com/furandon_pig/items/4f186c46a9e54e2649ae)では、以下のような設定を開発・テスト用マシンに対して実施していました。

 * `/etc/myname`の設定
 * `/etc/rc.conf`にDHCPの設定(LAN側)
 * 開発・テスト用マシンの設定を`/etc/ifconfig.wm1`ファイルに記述
 * `/etc/hosts`に開発・テスト用マシンのエントリを追加
 * 開発用マシンでのNFSサーバ設定
 * テスト用マシンでのNFSクライアント設定
 * 開発用マシンにNetBSDソースコードをダウンロード・展開する
   * ツールチェインのビルド

NetBSDのバージョンが新しくなったり、なにか試してみたいことを思いつくたびに毎回上記の手順を実施するのは同じ作業の繰り返しということもあり、ちょっと面倒な感じです。

そこで今回は開発・テスト用マシンの環境設定をもっと楽に行うスクリプトを作成してみようと思います。つまるところ、構成管理をスクリプトで自動化してしまおうという話ですね。

## 開発・テスト用環境をスクリプトで設定する

いわゆる構成管理的なことを行いたいという話であるため、[Chef](https://www.chef.io/)とか使えば良いのですが、環境がNetBSD固定なので今回はシェルスクリプトを用いてみることにしてみます。

スクリプトは以下のリポジトリに置いてあります。

 * [furandon-pig/nbsd_devenv_setup_script](https://github.com/furandon-pig/nbsd_devenv_setup_script)

### 環境をセットアップする

[README.md](https://github.com/furandon-pig/nbsd_devenv_setup_script/blob/master/README.md)に記載していますが、以下のような環境でのセットアップを想定しています。
私の環境ではVirtualBox上にVMを用意し、LANとNFS用にVMの内部ネットワーク(`172.16.0.0/24`)を用いる構成にしています。

```
   --+-----------------------+----- LAN
     |                       |
   +-+----------------+    +-+------------------+
   |    advcal2016    |    |   advcal2016test   |
   +-+----------------+    +-+------------------+
     |172.16.0.43            |172.16.0.42
   --+-----------------------+--------------- 172.16.0.0/24
```

スクリプトは`bash`で動かすことを想定しているのと、ソースコードのダウンロードを`curl`で行っているため、あらかじめパッケージでインストールします。
上記の`advcal2016`と`advcal2016test`の両方で、最初に`bootstrap.sh`を実行します。

```
# ./bootstrap.sh
```

次に開発・テスト用環境のそれぞれでスクリプトを実行します。

 * 開発用環境(上記例における`advcal2016`)

開発用環境では内部ネットワークの設定とNFSサーバの設定、NetBSDカーネルソースコードのダウンロードと展開を行います。

```
advcal2016 # ./script/setup_remote_host.sh
```

 * テスト用環境(上記例における`advcal2016test`)

テスト用環境では内部ネットワークの設定とNFSクライアントの設定を行います。

```
advcal2016test # ./script/setup_target_host.sh
```

スクリプト実行後、開発・テスト用マシンを再起動して設定完了です。

## カーネルのビルドとテスト環境でのカーネル置き換えを試してみる

開発・テスト用マシンの設定ができたので、実際にカーネルのビルドとテスト環境でのカーネル置き換えを試してみます。

### ツールチェインの構築

カーネルビルドの準備として、開発用マシン側でツールチェィンを構築します。同様の手順でARMとかPowerPCといった他のアーキテクチャ向けのツールチェィンも必要に応じて構築します。

```
advcal2016 # time ./build.sh -m `uname -m` -a `uname -p` -T /usr/src/tooldir.NetBSD-`uname -p` -T /usr/src/tooldir.NetBSD-`uname -r`/`uname -m` -r -o -U tools
===> build.sh command:    ./build.sh -m amd64 -a x86_64 -T /usr/src/tooldir.NetBSD-7.0.2/amd64 -r -o -U tools
===> build.sh started:    Sun Dec 11 16:50:42 JST 2016
===> NetBSD version:      7.0.2
===> MACHINE:             amd64
===> MACHINE_ARCH:        x86_64
===> Build platform:      NetBSD 7.0.2 amd64
===> HOST_SH:             /bin/sh
===> No $TOOLDIR/bin/nbmake, needs building.
===> Bootstrapping nbmake
checking for sh... /bin/sh
...
         build.sh started:    Sun Dec 11 16:50:42 JST 2016
         NetBSD version:      7.0.2
         MACHINE:             amd64
         MACHINE_ARCH:        x86_64
         Build platform:      NetBSD 7.0.2 amd64
         HOST_SH:             /bin/sh
         No $TOOLDIR/bin/nbmake, needs building.
         Bootstrapping nbmake
         MAKECONF file:       /etc/mk.conf (File not found)
         TOOLDIR path:        /usr/src/tooldir.NetBSD-7.0.2/amd64
         DESTDIR path:        /usr/src/destdir.amd64
         RELEASEDIR path:     /usr/src/releasedir
         Removing /usr/src/tooldir.NetBSD-7.0.2/amd64
         Removing /usr/src/destdir.amd64
         Created /usr/src/tooldir.NetBSD-7.0.2/amd64/bin/nbmake
         Updated makewrapper: /usr/src/tooldir.NetBSD-7.0.2/amd64/bin/nbmake-amd64
         Tools built to /usr/src/tooldir.NetBSD-7.0.2/amd64
         build.sh ended:      Sun Dec 11 17:05:01 JST 2016
```

### カーネルのビルド

次にカーネルをビルドしてみます。カーネルコンフィグ名は`ADVCAL2016`にしてみます。

```
advcal2016 # cd /usr/src/sys/arch/amd64/conf/
advcal2016 # cp GENERIC ADVCAL2016
advcal2016 # /usr/src/tooldir.NetBSD-7.0.2/amd64/bin/nbconfig ADVCAL2016
Build directory is ../compile/ADVCAL2016
Don't forget to run "make depend"
# cd ../compile/ADVCAL2016/
# /usr/src/tooldir.NetBSD-7.0.2/amd64/bin/nbmake depend
# /usr/src/tooldir.NetBSD-7.0.2/amd64/bin/nbmake
...
ld -Map netbsd.map --cref -T ../../../../arch/amd64/conf/kern.ldscript -Ttext 0xffffffff80100000 -e start -z max-page-size=0x100000 -X -o netbsd ${SYSTEM_OBJ} ${EXTRA_OBJ} vers.o
NetBSD 7.0.2 (ADVCAL2016) #0: Sun Dec 11 18:48:22 JST 2016
   text    data     bss     dec     hex filename
14187604         654236  593920 15435760         eb87f0 netbsd
```

無事にカーネルが生成されました。

```
advcal2016 # file netbsd
netbsd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for NetBSD 7.0.2, not stripped
```

### テスト用環境にカーネルをインストールする

ビルドしたカーネルをテスト用環境にインストールします。VMの内部ネットワークで開発用マシンの`/usr/src`をNFSマウントしているので、そこからカーネル(`netbsd`)を持ってくるようにします。

```
advcal2016test # cd /
advcal2016test # cp -pi ./netbsd ./netbsd.ORIG
advcal2016test # cp /usr/src/sys/arch/amd64/compile/ADVCAL2016/netbsd .
```

この状態でテスト環境マシンを再起動すると、インストールしたカーネルでNetBSDが起動します。

```
advcal2016test # shutdown -r now
```

これでカーネル開発・テスト環境が構築できました。これで[printf(9)](http://netbsd.gw.com/cgi-bin/man-cgi?printf+9+NetBSD-current)デバッグは行えるようになったので、ちょっとカーネルを修正して動作を試してみるといった用途に利用できそうです。

![スクリーンショット 2016-12-11 9.52.00.png](https://qiita-image-store.s3.amazonaws.com/0/61137/2250beee-f198-ebcf-74f3-044dd4dbc992.png)

## まとめ

NetBSDカーネルの開発・テスト用環境の構築をちょっとお手軽にできるようにしてみました。環境構築スクリプトでカーネルの自動ビルドも行えるような形にすると、NetBSD-currentの追従とかにも応用できそうです。