picobsd,nanobsd

周回遅れと言うか、月遅れと言うか、以前に買ったSDの2月号を今頃になって読んでいる。だって、月刊誌ってその時に手に入れておかないと、手に入れるのが面倒になるんだもん。取り合えず、積読状態にしておけば安心。

何が目当てだったかと言うと、systemdの特集。最近じゃFreeBSDにも導入するとか言う不穏な空気が漂ってますから、取り合えずの先行投資。で、読んでみると、未だにBug内在してるようで、Bug除けのおまじないが炸裂してた。

他の特集ではPythonのモジュール。機械学習がらみで、有名処が紹介されてた。まあ、現代風なBasicと思っておけば間違いないな。オイラーも久しぶりに触ってみるかな。解説記事をそのままなぞるのも馬鹿っぽいので、pythonにbase58が有るか探してみる。無い物は無いと言うPythonだから、きっとあるだろう。(Python頼みかよ!!)

debian:~$ pip search base58
base58 (0.2.5)        - Base58 and Base58Check implementation
base58_encoded (0.1)  - Encode an integer using base58. You know, for short
                        urls.

はて、どちらを入れればいいのでしょうか? 取り合えずbase58を選んでみる。きっとビットコインでも使われていて、信頼がおけるだろうから。

debian:~$ ipython
Python 3.6.4 |Anaconda, Inc.| (default, Mar 13 2018, 01:15:57)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import base58

In [2]: base58.
      alphabet          b58decode_int()   b58encode_int()   iseq()
      b58decode()       b58encode()       bseq              main()
      b58decode_check() b58encode_check() buffer()          sha256()

base58. まで入力してTABを叩くと、候補が色々出て来た。まずはエンコードだな。数値用と 文字用が有ると思われる。文字用を試すか。

In [2]: base58.b58encode('hello')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-ed05472b07f4> in <module>()
----> 1 base58.b58encode('hello')

~/miniconda3/lib/python3.6/site-packages/base58.py in b58encode(v)
     43     if not isinstance(v, bytes):
     44         raise TypeError("a bytes-like object is required, not '%s'" %
---> 45                         type(v).__name__)
     46
     47     origlen = len(v)

TypeError: a bytes-like object is required, not 'str'

早速エラーの洗礼。エラーを出して頭を捻って鍛えられるのさ。どうしましょ?

In [3]: base58.b58encode(b'hello')
Out[3]: 'Cn8eVZg'

門前の小僧習わぬ経を読む、ってやつかな。次は逆演算だな。

In [4]: base58.b58decode('Cn8eVZg')
Out[4]: b'hello'

普通に、元に戻った。

In [7]: base58.b58encode_int(-123)

^C---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-7-70040f583258> in <module>()
----> 1 base58.b58encode_int(-123)

~/miniconda3/lib/python3.6/site-packages/base58.py in b58encode_int(i, default_one)
     35     while i:
     36         i, idx = divmod(i, 58)
---> 37         string = alphabet[idx] + string
     38     return string
     39

KeyboardInterrupt:

さっぱり答えが返ってこないので、止めたよ。intって負数はダメなんですかと作者さんに聞いてみたいぞ、と。まあ、そんな難癖を付けるのは止めとけ。それより、FreeBSDに入ってる2系のやつでも動くかな。(なんたって、頑固物のFreeBSDですから、ちゃらちゃらしないのさ)

[fb11: ~]$ pip install --user base58
[fb11: ~]$ python2
Python 2.7.14 (default, Jan  2 2018, 01:25:01)
[GCC 4.2.1 Compatible FreeBSD Clang 4.0.0 (tags/RELEASE_400/final 297347)] on freebsd11
Type "help", "copyright", "credits" or "license" for more information.
>>> import base58
>>> base58.b58encode('hello')
'Cn8eVZg'
>>> base58.b58decode('Cn8eVZg')
'hello'

どうやら、2系もサポートしてた。(文字列の扱いが2と3では違う。2の扱いは失敗だったとPython作者さんは認めています)モジュールとしてちゃんとした作りになってた。(お前が偉そうに言うな)

[fb11: ~]$ python2 -m base58 -h
usage: base58.py [-h] [-d] [-c] [FILE]

Base58 encode or decode FILE, or standard input, to standard output.

positional arguments:
  FILE

optional arguments:
  -h, --help    show this help message and exit
  -d, --decode  decode data
  -c, --check   append a checksum before encoding

このエンコーディングを3回ぐらい繰り返せば、トリプルDESならぬトリプルBase58となって、簡易な暗号として 利用出来ますよ。(共通鍵暗号には、鍵が必要だろう。どういう風に鍵を使うかが鍵ですけどね)だって、base58なんて使う人は、コインチェックに明け暮れる、金儲け屋さんぐらいしかいませんからね。

ウォズ、ビットコインを詐取された体験を語る あっ、こんな人が居たか。

作って学ぶBitcoin!ゼロから作るSPVウォレット by Haskell

picobsd

ピコって言うぐらいだから、1e-12 なBSDって事で宜しいか。小ささを際立たせる表現。 前回picobsdなんてのを見つけてしまったものだから、寄り道してみる。picobsd(8)が登録されてるんで、正式にサポートしてますって事だな。

マニュアルを斜め読みした限りでは、

[fb11: sakae]# cd /usr/src/release/picobsd/build/
[fb11: build]# ./picobsd -n qemu
PicoBSD build -- Current parameters:

        1.  Type: qemu name qemu
        2.  MFS size: 18000 kB
        3.  Site-info:
        4.  Full-path: /usr/src/release/picobsd/qemu
---> We'll use the sources living in /usr/src

cd /usr/src/sys/amd64/conf; config -d /usr/src/release/picobsd/build/build_dir-qemu-amd64/PICOBSD-qemu PICOBSD-qemu
PICOBSD-qemu: unknown option "I586_CPU"
*** Error code 1

Stop.
make: stopped in /usr/src/release/picobsd/qemu
---> fail: Error <1> error code <missing_kernel> in <>
Error: you must build PICOBSD kernel first
---> Aborting ./picobsd

amd64な石の元で、I586な石は、理解不能と言う事だな。スクリプトを ちょい見したら、uname -mで石を割り出している。ここを強引にi386と 書き換えても、コンパイラーが今度はそんな石は知らないと言うだろう。 (前回経験済)

はて、どうする? FreeBSD 5.1が有るじゃん。同地を訪れてみたら

f51# cd /usr/src/release/picobsd/
f51# ls
README.html     build           floppy.tree     mfs_tree        tinyware
Version         dial            help            net
bridge          doc             isp             router

ダイアルアップ用とかルーター用とかあるけど、肝心のqemu用が無い。これはもう、卵になるqemuの設定をFreeBSD5.1に移して、そこで代理出産させるか。上手く生まれたら、結果だけをqemuが入っているFreeBSD11.1に戻せばいいんだから。

# -mkdir -p /usr/src/sys/i386/conf              # XXX not needed yet.
cp PICOBSD /usr/src/sys/i386/conf/PICOBSD-qemu
if [ -f PICOBSD.hints ] ; then cp PICOBSD.hints /usr/src/sys/i386/conf/PICOBSD.hints ; fi
(cd /usr/src/sys/i386/conf; config -d /usr/src/release/picobsd/build/build_dir-qemu/PICOBSD-qemu PICOBSD-qemu;  cd /usr/src/release/picobsd/build/build_dir-qemu/PICOBSD-qemu; make KERNEL=kernel -DNO_MODULES depend )
Specify machine type, e.g. ``machine i386''
*** Error code 1

Stop in /usr/src/release/picobsd/qemu.
---> fail: Error <1> error code <missing_kernel> in <>
Error: you must build PICOBSD kernel first
---> Aborting ./picobsd

走らせると上記のようなエラーを吐く。どうやらkernelを作る仕様書を手直ししないとだめみたい。picobsdを起動する時の -n オプションを省くと、インタラクティブモードになって、設定を編集してからgo出来る。

ユーザーランドの方は、リナで言うbusyboxのごとく、クランチバイナリーになるのね。関数の名前解決が出来ずにエラーになってたので、あちこち削った。最近問題になってる、デザイナーベビーを編集してる気分になったぞ。

で、最後の最後で、こんなエラーが出た。

Filesystem 1K-blocks Used Avail Capacity iused ifree %iused  Mounted on
/dev/md0c      17303  827 16476     5%      69  2233    3%   /tmp/picobsd.M5zW78AbSI
/dev/md0c: FILESYSTEM CLEAN; SKIPPING CHECKS
/dev/md0c: clean, 32953 free (17 frags, 4117 blocks, 0.0% fragmentation)
usage: bsdlabel disk
                (to read label)
        bsdlabel -w [-n] [-m machine] disk [type]
                (to write label with existing boot program)
         :

エラーは、bsdlabelの使い方を示唆したもの。エラーになったにも関わらず、 build_dir-qemu/picobsd.binが出来上がっていた。無事に出産出来たんですかね?

取り合えず、FreeBSD11.1へ持って行って、実行してみる。

[fb11: tmp]$ qemu-system-i386 -m 256 picobsd.bin
WARNING: Image format was not specified for 'picobsd.bin' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
gtk initialization failed

badlabelが認識出来ないのかなあ? もう少しpicobsdスクリプトと首っ引きにならないと、だめだろうね。まあ、いきなりデザイナーベビーが誕生する訳は無いわな。もし誕生したら、ノーベル賞ものだぞ。いや、そんな事は無い。世界中から非難轟々だぞ。(神の領域に手を出すなってね)すこしほとぼりが冷めるまで、待とう。

picobsdのmanを見てたら、1000倍大きいbsdが紹介されてた。

nanobsd

FreeBSD 6.0 からサポートされたとか。作成方法は下記。

     The necessary commands to build and install a NanoBSD image are:

           cd /usr/src/tools/tools/nanobsd
           sh nanobsd.sh
           cd /usr/obj/nanobsd.full
           dd if=_.disk.full of=/dev/da0 bs=64k

実験とか組み込み用のたたき台にどうぞって触れ込みだ。picoより1000倍は大きくて、ユーザーランド全部とカーネルを含んだものらしい。

例の所にあるddの使い方から分かるように、diskを全部使っちゃうという(ラズパイでメディアに転送すれば全て完了)仕様だ。これを使って、FreeBSDのラズパイ版が作られているんだな。

とか言っていたら、サンプルとして提供されてる、embededの中に、ずばりrpi.cfgとかrpi2.cfgなんて言う仕様書が置いてあった。ちょいと指を咥えて眺めてみる。

NANO_ARCH=armv6
NANO_KERNEL=RPI2
NANO_DRIVE=mmcsd0
NANO_NAME=rpi2
NANO_BOOT_PKG=u-boot-rpi2
NANO_CPUTYPE=cortex-a7

. common        # Pull in common definitions, keep last

ラズパイで使うSDカードは頻繁に書き込むと劣化してエラーを出す。(そういうネガティブな事は、雑誌で取り上げられない)このnanobsdでは、/varと/tmpをRAM上に取って、メディアへの書き込みを抑止してる。これらをセーブするエリアとして、/cfgってのが用意されてるそうな。

この事情は普通の人(SSDに負担をかけないように常に注意してるオイラーみたいな貧乏人)でも同じで、 FreeBSD を read-only で起動なんていう、貴重な取り組みをしてる方に出会ったよ。

興味を持った人にはmanを補う資料として、 Introduction to NanoBSDなんてのが公開されてる。アップデートの事もちゃんと考えられていて、メディアを2つに分けて、片方でシステムが動いている時、もう片方に入れて、ちゃんと動いたら切り替えて使えるそうな。

ざっとnanobsd.shを眺めると、build world と build kernel それとインストールを一気通貫に行ってくれるようだ。昔は、頻繁にbuildをやったものだけど(カスタマイズを兼ねて)、バイナリーでアップデート(主としてセキュリティーの為)出来るようになってからは、止めちゃったな。

今の巨大になったシステムだと、どれぐらい時間がかかるのだろう? 多分、途方もなくパソコンを痛めつける事になるんだろうね。そんなお悩み解消しますって手がある。例えば、zfsなんて使わないから入れなくて(コンパイルしなくて)いいよってんで、機能を削れる。 FreeBSDのsrc.conf が、その役目を果たしてくれる。有り難ーい設定ファイルです。

ちなみに今風のOSをコンパイルするのが、どのぐらい大変かを実感させてくれる記事が出てたぞ。ラズパイで動くスマートテレビOS、Palm由来の「webOS」を試す

物理4コア、メモリーが16Gのマシンで、4時間ですってさ。そしてドライブ容量100Gは必要ってんだから、呆れて物が言えませんよ。

nanobsdをコンパイルする時は、 make -j 3 で、パラレルコンパイルがデフォになってました。ネットを見てると、nanobsdやってみたーって人がいますが、どれぐらいパソコンを酷使したか言及してる人は皆無でした。みんなビットコイン(お馬さんとかお舟でもいいけど)であぶく銭を手にした人なんでしょうな。そう言えば、友達と話していた時、ビットコインをやってるのは、銀座の夜のおねーちゃんが多いと言ってたな。髪結いの亭主(ヒモ)希望!!

再び picobsd

という事で、貧乏人のためのpicobsdに戻ってきました。上で出ていたエラーを追求してみましょ。そんなの、picobsdっていうシェルスクリプトを読めってのが王道ですが、年寄りは短気なので、トレースしちゃえ。

f51# sh -x ./picobsd -n qemu | & tee LOG
f51# less LOG
   :
+ b2=/usr/src/release/picobsd/build/build_dir-qemu/boot2
+ perl -pne s/\/boot\/loader/\/kernel\0\0\0\0\0/ /boot/boot2
+ disklabel -Brw -b /boot/boot1 -s /usr/src/release/picobsd/build/build_dir-qemu/boot2 md0 auto
usage: bsdlabel disk
                (to read label)
        bsdlabel -w [-n] [-m machine] disk [type]
                (to write label with existing boot program)
                  :

スクリプト中では、disklabelを指定してるのに、実際に応答(して、使い方を開陳)したのは、bsdlabelでしたよ。どうやら、同じ名前で登録されてるようです。多分disklabelが元祖で、bsdlabelはより大容量のメディアにも対応したって事でしょう。

bsdlabelのmanを見ると、-sオプションなんてのはサポートしてない。それで、bsdlabelが怒り心頭になったのでしょう。はて、どうしてくれよう。

boot2の中にある/boot/loader文字列を/kernelに書き換えておき、それも含めてbootの一部にしたいと言う算段でしょう。boot = boot1 + boot2 らしいんで、ここは素直に/boot/bootを使うように指定。/boot/loaderが無ければ、素直にスルーしてくれるはずですから。

こうやって作ったpicobsd.binを持って行ったら、少しは進歩して、カーネルのロードが始まった。けど、ハングですよ。qemuは色々と欲張り過ぎたんかな。

方針を変えて、5.1に元々有ったdialってのに方向転換。でも、あちこち修正しないと作成が途中で止まる。特に最後のカーネルを書き込む所で、メディアの容量不足になったよ。初期はフロッピー1枚サイズだったんだ。dial/config中で、fd_size=8192に変更しといた。

f51# ls -lh build_dir-dial/
total 12388
drwxr-xr-x   2 root  wheel      12K Mar 30 00:56 PICOBSD-dial
-rw-r--r--   1 root  wheel     7.5K Mar 30 00:56 boot2
drwxr-xr-x   2 root  wheel     3.0K Mar 30 00:56 crunch
-rw-r--r--   1 root  wheel      34K Mar 30 00:56 crunch.mk
-rw-r--r--   1 root  wheel     1.8K Mar 30 00:56 crunch1.conf
drwxr-xr-x   3 root  wheel     512B Mar 30 00:56 floppy.tree
-rwxr-xr-x   1 root  wheel     4.0M Mar 30 00:56 kernel
drwxr-xr-x  20 root  wheel     512B Mar 30 00:56 mfs.tree
-rw-r--r--   1 root  wheel     8.0M Mar 30 00:56 picobsd.bin

これで、picobsd.binをqemu-system-i386に食わせたら、カーネルは無事に起動した。 でも、いよいよinitを起動しようとしてパニックたぞ。結局loginは拝めず、残念至極。

new picobsd

って、FreeBSD11.1に付いてたのを、そう呼ぶ事にする。

興味深い記述

    # select the right disklabel program
    case `uname -r` in
        4.*)
            c_label="disklabel"
            ;;
        *)
            c_label="bsdlabel"
            ;;
    esac

    ${c_label} -w -f `pwd`/${c_img} auto # write in a label
    # copy partition c: into a: with some sed magic
    ${c_label} -f `pwd`/${c_img} | sed -e '/  c:/{p;s/c:/a:/;}' | \
        ${c_label} -R -f `pwd`/${c_img} /dev/stdin
    ${c_label} -f `pwd`/${c_img}

FreeBSDの4系までは、disklabelで、それ以上はbsdlabelって振り分け。デバイスがファイルでも指定出来るように -f オプションが追加されてると読めるんだけど、5.1のbsdlabelでは サポートされていない。11.1で確認すると

[fb11: tmp]$ bsdlabel -f picobsd.bin
# picobsd.bin:
8 partitions:
#          size     offset    fstype   [fsize bsize bps/cpg]
  a:      16384          0    4.2BSD      512  4096  4104
  c:      16384          0    unused        0     0     # "raw" part, don't edit

boot系の書き込みはbsdlabelを離れて、ddの技を使ってる。

    echo "BUILDDIR ${BUILDDIR}"

    # dump the primary and secondary boot
    # XXX primary is 512 bytes
    dd if=${c_boot1} of=${BUILDDIR}/${c_img} conv=notrunc 2>/dev/null
    # XXX secondary starts after the 0x114 = dec 276 bytes of the label
    # so we skip 276 from the source, and 276+512=788 from dst
    # the old style blocks used 512 and 1024 respectively

    dd if=${c_boot2} iseek=1 ibs=276 2> /dev/null | \
        dd of=${BUILDDIR}/${c_img} oseek=1 obs=788 conv=notrunc 2>/dev/null
    log "done disk image"

一応、ファイルシステムを確認。

[fb11: tmp]$ sudo mdconfig -a -t vnode -f picobsd.bin
md0
[fb11: tmp]$ ls /dev/md*
/dev/md0        /dev/md0a       /dev/mdctl
[fb11: tmp]$ sudo mount /dev/md0a /mnt
[fb11: tmp]$ ls -l /mnt
total 1496
-rwxr-xr-x  1 root  wheel  1527431 Mar 31 02:07 kernel*
[fb11: tmp]$ sudo umount /mnt
[fb11: tmp]$ sudo mdconfig -du md0

カーネルしか無いけど、それで委員かい? ここは、ユーザーランドと言うか、dir-treeが 存在しないといけないと思うんだけど。先ほどパニックったって書いたけど、/sbin/init等が何処にも見つかりませんでしたって、断末魔の声を上げてたからなあ。 要調査だな。

build_dir-dial/mfs.treeの中は、ちゃんとツリーが出来ていて、チャンクバイナリーも存在してた。で、mfs.treeの中にinitが有るかと探したら、無かったぞ。

dial/crunch.conf に、initを追加したよ。 そしたら、ミニダエモン君のバナーと共に、loginプロンプトが出て来た。いざloginしようとすると、/usr/sbin/loginが無いですってさ。ちゃんと動くものを掲載して欲しいなあ。

多分、loginだけじゃ足らなくてgettyあたりも必要になるだろうね。それより、rootとかuserのパスワードをjoeにしておかねば、login出来ないぞ。

で、ちょいと、唯一のkernelの出来を見ておく。readelfって道具でね。

Elf file type is EXEC (Executable file)
Entry point 0x500000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x00500000 0x00500000 0x016dd 0x016dd R E 0x1000
  LOAD           0x003000 0x00502000 0x00502000 0x173992 0x183e8c RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata
   01     .data .bss

これしか無いと言う事は、bss領域にでも、ファイルシステムを埋め込んでいるんだろうね。サイズがやけに大きいぞ。以前にやったxv6方式だな。

1FD を用いたノートのルータ化

これ、picobsdなシェルを使わないで、手動でやる時参考になるよ。