【前編】ルーターのrootfsを拡張してPythonをビルドする

本記事はルーターハックAdvent Calendar 9日目の記事です。

これは、遅れを取り戻す物語。(コピー風)(このリズム感どっかで聞いたことあると思ったらFGOでした。FGO1ミリもしらんけど。)

8日目の記事では、USB ポートのないルーターに USB を生やして使えるようにするまでを書いた。こいつを使えば、USB メモリでルーターの rootfs(Windows でいう C ドライブ)の容量を拡張して好き勝手やることができる。今回は、GCCをインストールして Python をビルドしてみよう。

なぜ遅れを取り戻さなければならないのに時間がかかるネタをやろうとするのかは筆者自身でも不明である。

おことわり

技適 に関する筆者の配慮や考えについてはカレンダー1日目「技適とルーターハック」をご覧ください。本記事で紹介する内容は、法を遵守するための慎重な注意をもって書かれています。

www.zopfco.de

SDカードを準備

やろうと思えば opkg を使ってルーターに fdisk や mkfs.ext4 も入れられるのだが、面倒なのでPC側でフォーマットしてしまった。

f:id:puhitaku:20181216011450p:plain

前半 7000 MiB を ext4 でフォーマットし、残る容量を swap とした。WHR-HP-GN のメインメモリは32 MiB と大変少ないので、swap がなければまず GCC の動作は無理だろう。

f:id:puhitaku:20181216125056j:plain
接続!

SD カードを rootfs の拡張領域にする

OpenWrt は何もせずとも overlayfs を用いてメインストレージ(多くの場合 SPI Flash)の固定された rootfs と書き換え可能な領域を分割して提供する。これを pivot_root (2) で置き換える形で、外部ストレージもまた rootfs の overlay として使うことができる。

これからの作業は公式のマニュアルにも記載されている。ぜひ参照されたい。

まず必要な道具として以下を make で追加しビルド。

  • Utilities -> Filesystem -> swap-utils
  • Global build settings -> Kernel build options -> Support for paging of anonymous memory (swap)
  • Base system -> block-mount
  • Base system -> busybox -> Linux System Utilities -> swapon swapoff
    • Customize busybox options にチェックを入れると出現

生成されたら ssh で転送して sysupgrade しよう。

ここで SD カードリーダーを挿入し、 block detect を実行すると以下のようにファイルシステムが認識される。 これは /etc/config/fstab として置く設定ファイルを自動生成するコマンドだ(実行するだけでは書き換えられない)。

root@OpenWrt:~# block detect
config 'global'
        option  anon_swap       '0'
        option  anon_mount      '0'
        option  auto_swap       '1'
        option  auto_mount      '1'
        option  delay_root      '5'
        option  check_fs        '0'

config 'mount'
        option  target  '/mnt/sda1'
        option  uuid    '31407de4-3283-4dfd-b391-375cc78c9a04'
        option  enabled '0'

config 'swap'
        option  uuid    '49c9c539-29d9-4f56-b775-691b1fcdff86'
        option  enabled '0'

認識していることが確認できたら、現在の overlayfs に置いてあるファイルを SD カードにコピーする。公式ドキュメントでは tar を使ってちょっとテクいことをしているが、普通にコピーすれば OK だ。

root@OpenWrt:~# mount /dev/sda1 /mnt
[ 3669.913854] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
root@OpenWrt:~# cp -r /overlay/
.fs_state  upper/     work/
root@OpenWrt:~# cp -r /overlay/* /mnt/

最後に /etc/config/fstab を生成し、全エントリを有効にする。ext4 なパーティションの mount point は /overlay に変更する。

root@OpenWrt:~# block detect > /etc/config/fstab
root@OpenWrt:~# vi /etc/config/fstab
...
root@OpenWrt:~# cat /etc/config/fstab
config 'global'
        option  anon_swap       '0'
        option  anon_mount      '0'
        option  auto_swap       '1'
        option  auto_mount      '1'
        option  delay_root      '5'
        option  check_fs        '0'

config 'mount'
        option  target  '/mnt/sda1'
        option  uuid    '31407de4-3283-4dfd-b391-375cc78c9a04'
        option  enabled '1'

config 'swap'
        option  uuid    '49c9c539-29d9-4f56-b775-691b1fcdff86'
        option  enabled '1'

完了したらリブート!

リブート後…

以下のようなログが出て、df を見て容量が半端ないことになっていれば成功だ。

[   12.135475] block: attempting to load /tmp/jffs_cfg/upper/etc/config/fstab
[   12.276824] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts:
[   12.452555] mount_root: switched to extroot
root@OpenWrt:/# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 2.0M      2.0M         0 100% /rom
tmpfs                    13.6M     64.0K     13.5M   0% /tmp
/dev/sda1                 6.7G     16.1M      6.3G   0% /overlay
overlayfs:/overlay        6.7G     16.1M      6.3G   0% /
tmpfs                   512.0K         0    512.0K   0% /dev

あれ?swap が有効になってない。anon_swap を1にしたりしても効かないので、今回はとりあえず手動swaponすることにした。

root@OpenWrt:/# swapon /dev/sda2
[   65.211586] Adding 698364k swap on /dev/sda2.  Priority:-2 extents:1 across:698364k
root@OpenWrt:/# free
             total       used       free     shared    buffers     cached
Mem:         27840      18440       9400         60       1804       4920
-/+ buffers/cache:      11716      16124
Swap:       698364          0     698364

うん、OK。

ビルド環境を整え動作確認

ここからは楽しい冒険の始まりだ。

GCC を入れる

opkg でちゃちゃっと。と思いきや。

root@OpenWrt:/# opkg install gcc
Installing gcc (5.4.0-3) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/gcc_5.4.0-3_mips_24kc.ipk
Collected errors:
 * opkg_download: Failed to download http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/gcc_5.4.
 * opkg_download: Check your network settings and connectivity.

 * opkg_install_pkg: Failed to download gcc. Perhaps you need to run 'opkg update'?
 * opkg_install_cmd: Cannot install package gcc.

んんん???ダウンロードに失敗??PCで試すとダウンロードできるのに。

と、ここで opkg の tmpdir は /tmp なのを思い出す。そうか… gcc のパッケージがメモリに入り切らないんだな!

tmpdir を普通のディレクトリに切り替えて回避。USB 2.0 にも対応してないのでめちゃくそ遅いけど。

root@OpenWrt:~# mkdir cache
root@OpenWrt:~# opkg --tmp-dir /root/cache install gcc
Installing gcc (5.4.0-3) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/gcc_5.4.0-3_mips_24kc.ipk
Installing zlib (1.2.11-2) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/zlib_1.2.11-2_mips_24kc.ipk
Installing libbfd (2.27-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/libbfd_2.27-1_mips_24kc.ipk
Installing libopcodes (2.27-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/libopcodes_2.27-1_mips_24kc.ipk
Installing objdump (2.27-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/objdump_2.27-1_mips_24kc.ipk
Installing ar (2.27-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/ar_2.27-1_mips_24kc.ipk
Installing binutils (2.27-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/binutils_2.27-1_mips_24kc.ipk
Installing libstdcpp (7.3.0-1) to root...
Downloading http://downloads.openwrt.org/snapshots/targets/ar71xx/tiny/packages/libstdcpp_7.3.0-1_mips_24kc.ipk
Configuring zlib.
Configuring libbfd.
Configuring libopcodes.
Configuring objdump.
Configuring ar.
Configuring binutils.
Configuring libstdcpp.
Configuring gcc.

よし入った!

make を入れる

実は make はパッケージで入れなくてもソースコードから bootstrap build ができる。以前はそこまでやっていたが、今回はそれほど M なプレイをしたいわけではないので普通に入れる。

root@OpenWrt:~# opkg install make
Installing make (4.2.1-2) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/make_4.2.1-2_mips_24kc.ipk
Configuring make.

sl を落としてビルドしてみる

ここで、ほんとに make できるのか往年の sl で試してみる。GitHub から clone するために git-http をインストールする。

root@OpenWrt:~# opkg install git-http
Installing git-http (2.20.0-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/git-http_2.20.0-1_mips_24kc.ipk
Installing libopenssl (1.0.2p-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/libopenssl_1.0.2p-1_mips_24kc.ipk
Installing git (2.20.0-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/packages/git_2.20.0-1_mips_24kc.ipk
Installing libmbedtls (2.13.0-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/libmbedtls_2.13.0-1_mips_24kc.ipk
Installing ca-bundle (20180409-3) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/ca-bundle_20180409-3_all.ipk
Installing libcurl (7.62.0-1) to root...
Downloading http://downloads.openwrt.org/snapshots/packages/mips_24kc/base/libcurl_7.62.0-1_mips_24kc.ipk
Configuring libmbedtls.
Configuring ca-bundle.
Configuring libcurl.
Configuring libopenssl.
Configuring git.
Configuring git-http.

clone そして make。

github.com

root@OpenWrt:~# git clone https://github.com/mtoyoda/sl.git
Cloning into 'sl'...
remote: Enumerating objects: 97, done.
remote: Total 97 (delta 0), reused 0 (delta 0), pack-reused 97
Unpacking objects: 100% (97/97), done.
root@OpenWrt:~# cd sl
root@OpenWrt:~/sl# make
gcc -O -Wall -o sl sl.c -lncurses
sl.c:41:20: fatal error: curses.h: No such file or directory
compilation terminated.
make: *** [Makefile:15: sl] Error 1

んんっ。ncurses がない。Python でも ncurses はあったほうがいいので入れておくか。

ncurses がないので入れる

パッケージでは ncurses は用意されていない。GNU から落としてくる。

Index of /pub/gnu/ncurses

root@OpenWrt:~# wget https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz
wget: SSL support not available, please install one of the libustream-.*[ssl|tls] packages as well as

んんんっw ヤクの毛を刈る感じがしてきたぞw

httpsに必要なあれこれを入れる。

root@OpenWrt:~# opkg install libustream-openssl ca-certificates 
...
root@OpenWrt:~# wget https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz
Downloading 'https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz'
Connecting to 208.118.235.20:443
Writing to 'ncurses-6.1.tar.gz'
ncurses-6.1.tar.gz   100% |*******************************|  3286k  0:00:00 ETA
Download completed (3365395 bytes)

よし、ビルドだ!

root@OpenWrt:~# tar zxf ncurses-6.1.tar.gz
root@OpenWrt:~# cd ncurses-6.1
root@OpenWrt:~/ncurses-6.1# ./configure

もう configure だけで意味わからんぐらい遅くて最高w USB 1.1 は厳しいな…。

configure だけで40分かかった。このあと走らせた make は実に6時間ぐらいかかってしまった。かなり絶望的なスピードである。

気を取り直して sl

「sl のビルドなんかやろうと思わなきゃよかった」と若干の後悔の念はありつつ、気を取り直してビルド。

root@OpenWrt:~/sl# make
gcc -O -Wall -o sl sl.c -lncurses
root@OpenWrt:~/sl#

おお?

f:id:puhitaku:20181216102958p:plain

おおお!!!やったー!

一旦切ります

…さて。ここまでで結構な時間を使ったためちょっと疲れてしまった。この記事は前編として、後編にて Python のビルドに入りたいと思う。