# はじめに
ご承知のように、ChromeBookには何通りかの方法で、Linuxもしくはその環境をインストールできます。
私の使っているAsusFlipでの代表的なやり方としても、以下のようなものがあります。
- ChromeBrew(ChromeOSにコマンドを追加)
- Crouton(Androidのように、ChromeOSと同時にUbuntu,Debian等を稼働させる)
- KaliLinux, Archlinux(外部SD,USBから切替ブート)
切替ブートについては、ChromeOSのブートイメージを借用→再署名する方法で、Fedoraなどでも可能なようです。
私は、おもにKaliを使っています。
理由は、ChromeBrewについては、環境が中途半端で使いにくいと感じました。たとえば、ロケールのインストールが中途半端で、これで設定してもプレインストールされているBashには認識させられませんでした。
反対に、Croutonはものすごく高度なアプリケーションで、ソースを読むと「これぞ超一流のプロのコードだ」と感銘します。しかしそれでも、少しやり過ぎで不安定です。何度も起動・再起動を繰り返すと、そのうちChromeOSそのものがシャットダウンすらできなくなります。
で、Kaliを使うようになったのですが、しかしこれは、ChromeBrewやCroutonのようにChromeOSと同時に使えません。
そこで、切替ブート用のKaliを、なんとかChromeOSと同時に使う方法が無いか、それを実験してみました。
なお、今回の実験では、/usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification、は実行しません。あくまでChromeOSのオリジナル環境には手を入れず、実行時だけテンポラリーに環境を変更します。したがって、リブートすると当然普通の環境に戻ります。
# KaliのルートファイルシステムにChroot、どこまで使えるか
(sudo /usr/local/bin/kali.sh)
#! /bin/bash
kali_root=/media/removable/rootfs(kaliのroot)
mount -o remount,exec,suid,dev $kali_root
mount --bind /dev $kali_root/dev
mount --bind /dev/pts $kali_root/dev/pts
mount --bind /dev/shm $kali_root/dev/shm
mount --bind /tmp $kali_root/tmp
mount -i -o remount,exec $kali_root/tmp
mount --bind /proc $kali_root/proc
mount -i -t tmpfs -o rw,noexec,nosuid,mode=0755,size=10% tmpfs $kali_root/run
mkdir -p $kali_root/run/lock
mount -i -t tmpfs -o rw,noexec,nosuid,nodev,size=5120k tmpfs $kali_root/run/lock
mkdir -p $kali_root/run/dbus
mount --bind /run/dbus $kali_root/run/dbus
mkdir -p $kali_root/run/NetworkManager
mount --bind /run/shill $kali_root/run/NetworkManager
mkdir -p $kali_root/run/udev
mount --bind /run/udev $kali_root/run/udev
mkdir -p $kali_root/run/cras
mount --bind /run/cras $kali_root/run/cras
mkdir -p $kali_root/run/chrome
mount --bind /run/chrome $kali_root/run/chrome
mkdir -p $kali_root/media/removable (共有のデータ領域)
mkdir -p $kali_root/media/removable/data
mount --bind /media/removable/data $kali_root/media/removable/data
chroot $kali_root bash
umount $kali_root/media/removable/data > /dev/null 2>&1 || umount -l $kali_root/media/removable/data > /dev/null 2>&1
rm -r $kali_root/media/*
umount $kali_root/run/chrome >> /dev/null 2>&1 || umount -l $kali_root/run/chrome >> /dev/null 2>&1
umount $kali_root/run/cras >> /dev/null 2>&1 || umount -l $kali_root/run/cras >> /dev/null 2>&1
umount $kali_root/run/udev >> /dev/null 2>&1 || umount -l $kali_root/run/udev >> /dev/null 2>&1
umount $kali_root/run/NetworkManager >> /dev/null 2>&1 || umount -l $kali_root/run/NetworkManager >> /dev/null 2>&1
umount $kali_root/run/dbus >> /dev/null 2>&1 || umount -l $kali_root/run/dbus >> /dev/null 2>&1
umount $kali_root/run/lock >> /dev/null 2>&1 || umount -l $kali_root/run/lock >> /dev/null 2>&1
umount $kali_root/run >> /dev/null 2>&1 || umount -l $kali_root/run >> /dev/null 2>&1
umount $kali_root/proc > /dev/null 2>&1 || umount -l $kali_root/proc > /dev/null 2>&1
umount $kali_root/tmp > /dev/null 2>&1 || umount -l $kali_root/tmp > /dev/null 2>&1
umount $kali_root/dev > /dev/null 2>&1 || umount -l $kali_root/dev > /dev/null 2>&1
umount $kali_root/dev/pts > /dev/null 2>&1 || umount -l $kali_root/dev/pts > /dev/null 2>&1
umount $kali_root/dev/shm > /dev/null 2>&1 || umount -l $kali_root/dev/shm > /dev/null 2>&1
驚くべきことに、こんな単純な設定で、ほとんどのコンソールプログラムがきちんと動作します。
vimその他のテキスト・エディターはもちろん、gdiskやsgdisk、apt-get, apt-file, dpkgなども動作します。nslookup, netcatなどのネットワーク系も大丈夫である。
実験では、/sysはmount --bindしていません。単純にこれをやると、セキュリティー違反で動作しないプログラムが多数発生したからです。きちんとマウントされた/sysでなければ動作しないプログラムは非常に限られており、空のディレクトリ/sysが存在していれば、ほとんどのプログラムは機嫌よく動いてくれます。
この環境、私は気に入っています。
あたり前かもしれませんが、chrootした内側から外側に対して、シグナルも送信できます。
なんといっても、kaliを立ち上げずにパッケージ管理ができます。
# Kaliのルートファイルシステムのプログラムを直接実行、どこまで使えるか
export LD_LIBRARY_PATH=/usr/local/lib
kali_root=/media/removable/rootfs
cp -P $kali_root/lib/arm-linux-gnueabihf/libz.so.1* /usr/local/lib
cp -P $kali_root/lib/arm-linux-gnueabihf/libc.so.6* /usr/local/lib
mount -o remount,exec,suid,dev $kali_root
/media/removable/rootfs/usr/bin/file -m $kali_root/usr/local/lib/file/magic.mgc /etc/hosts
上記は、何の問題もなく実行できます。
もちろん、あらかじめ必要な共有ライブラリを、ChromeOSとKaliの両方でlddを実行して調べて、足りないものだけ/usr/local/libにコピーしておく必要があります。
実行依存環境が共有ライブラリだけのプログラムなら、共有ライブラリを片っ端から/usr/local/libにコピーするだけでよい。
常用するようなら、
alias file='/media/removable/rootfs/usr/bin/file -m /media/removable/rootfs/usr/local/lib/file/magic.mgc'
などとしておけばよい。
また上記例のように、実行依存の環境ファイルがある場合でも、コマンドラインパラメータ、もしくは環境変数で指定できる場合、環境ファイルを所定の位置にコピーする必要はない。
結構面倒なのは事実であるが、それでもChromebrewの環境で一からコンパイルするよりは、ましである。
必要なパーツが揃わなかったり、コンパイルエラーを調べるのに難渋することに比べて、こちらは機械的に処理さえすれば動作することが保証されている。人間パッケージマネージメントである。
そもそも、tarでパッケージが配られていた、初期のlinuxの世界では、この程度のことは誰でもやっていたと思う。
# KaliのプログラムをChromeOSにコピーして動作させる
単純なケースでは、上記の方法を模索すべきでしょうが、もっと複雑な事例では、すぐに手に負えなくなります。
具体的には、/usr/lib, /usr/share などに位置が固定された環境ファイル郡やオプションモジュールが存在し、その場所をコマンドラインパラメータや環境変数で指定しきれないようなケースです。
今回の実験では、以下のことをやってみます。
- ロケール環境を構築する
- マルチバイト対応のvimをインストールする
- uim-fep, uim-mozcをインストールする
ようするに、Croshでも日本語入力ができる環境を構築します。
なお、結論を先に言いますが、上記は問題なくできました。
しかし、ChromeOSのクリップボードとのデータのやり取りについては、不完全です。
Chrosh→クリップボードについては、日本語を含めて正しくコピーできましたが、クリップボード→Chroshについては、アルファベットだけしかできませんでした。文字化けします。
したがって、vimで編集した日本語文書をコピーしてブログなどに貼り付けることはできますが、Webページ上の日本語文書をvimに貼り付けることはできません。
これについては、随分悩みましたが、どうやらChromeのタブ上で動作しているCroshが英語決め打ちで作られているいるようで、どうにもなりません。こればかりは、独立して動作する多言語ターミナルが登場しないと、解決しません。
さて、上記について、基本方針は以下です。
- すべての実行プログラムは、/usr/local/bin にコピーする
- すべての共有ライブラリは、/usr/local/lib にコピーする
- 環境ファイル、拡張モジュールは、オリジナルロケーションを変えず、myroot配下の/usr/lib, /usr/shareに配置する。
- ChromeOSのルートファイルシステムは書込禁止、かつ十分な空きスペースが存在しないので、/etc, /root, /usr/lib, /usr/share は、/usr/local/myroot配下の/etc, /root, /usr/lib, /usr/share から mount --(r)bind して書込みを可能にし、領域を確保する
- apt-cache depends を使って、各プログラムの依存ファイル群を調査する。ドキュメント、パッケージ管理情報は無視する
まず、マウント元の準備(初回のみ)
myroot=/usr/local/myroot
mkdir -p $myroot
mkdir -p $myroot/root
mkdir -p $myroot/etc
mkdir -p $myroot/usr
mkdir -p $myroot/usr/lib
mkdir -p $myroot/usr/share
cp -r -P /etc/* /usr/local/myroot/etc
cp -r -P /usr/lib/* /usr/local/myroot/usr/lib
cp -r -P /usr/share/* /usr/local/myroot/share
以下は、ChromeOSブート後、最初にシェルを立ち上げるごとに実行
(bind-mount.sh)
#! /bin/bash
myroot=/usr/local/myroot
mount --bind -o rw $myroot/root /root
mount --rbind -o rw $myroot/etc /etc
mount --rbind -o rw $myroot/usr/lib /usr/lib
mount --rbind -o rw $myroot/usr/share /usr/share
準備ができたので、各プログラムを手動インストール
(locale)
(on chroot kali)
dpkg -S `which locale` (--> libc-bin)
dpkg -L libc-bin (出力略)
dpkg -L locales (出力略)
apt-cache depends locales (--> cdebconf, debconf)
dpkg -L cdebconf (--> not install)
dpkg -L debconf (--> not install)
上記の出力結果からインストールするものを判断する。
まず、共有ライブラリについては、とりあえず、無視する。これは、後にlddで判定させた方がてっとりばやい。
実行プログラムと環境ファイルおよび拡張モジュールだけに注目する。環境ファイルや拡張モジュールについては、当該プログラムのものだけ神経質にコピーするのではなく、同様の仕組みで動く他のプログラムのものもまとめてコピーしてしまう。その方が後々楽である。
で、結論は以下のようになる。
kali_root=/media/removable/rootfs
cp /etc/locale.alias $myroot/etc
cp $kali_root/usr/bin/locale /usr/local/bin
cp $kali_root/usr/bin/localedef /usr/local/bin
cp $kali_root/sbin/locale-gen /usr/local/bin
cp $kali_root/sbin/update-locale /usr/local/bin
cp $kali_root/sbin/validlocale /usr/local/bin
cp -r -P $kali_root/usr/lib/locale $myroot/usr/lib
cp -r -P $kali_root/usr/share/i18n $myroot/usr/share
cp -r -P $kali_roor/usr/share/locale $myroot/usr/share
共有ライブラリについては、まずChromeOS側で判断
ldd $kali_root/usr/local/bin/locale (--> ld-linux-armhf.so.3 欠落)
ldd $kali_root/usr/local/bin/localedef (--> ld-linux-armhf.so.3 欠落)
つぎに、kali側でも同じことをして、コピーソースを調べて、欠落しているものをコピーする。
cp -P \$kali_root/lib/ld-linux-armhf.so.3* /usr/local/lib
以上、正しく動作するか、確認してみる。
export LD_LIBRARY_PATH=/usr/local/lib
locale -a
上記と同じことを、vim, uim-fep, uim-mozcについても、実行する。
vim, vim-common, vim-runtime, uim-fep, uim-utils, uim-common, uim-mozc, mozc-server, mozc-dataの実行プログラムは全て/usr/local/binに、共有ライブラリは/usr/local/libにコピーする。それ以外は、$myrootの対応する場所にそれぞれコピーする。
共有ライブラリは、やはりlddを両方のOSで実行して調べる。
面倒なだけで、何も難しくないので、具体的に書かないが、丁寧に作業すれば必ずインストールできる。
全部終了したら、.uim を作成する。
(define default-im-name 'mozc)
(define-key generic-on-key? '("<Control>\\" "`"))
(define-key generic-off-key? '("<Control>\\" "`"))
最後に、
export LANG=ja_JP.utf8
export LC_ALL=ja_JP.utf8
uim-fep (mozc-serverが自動的に起動される)
vim
以上で、ChromeOSのCroshでも日本語入力ができるようになる(<ctrl>+\)。
vimだけでなくnanoでも、マルチバイトに対応しているプログラムなら日本語入力が可能になる。もちろん、bashのコマンド行にも日本語を入力できるし、そのメッセージも日本語に変わる。
上記でほとんどは対応可能だが、唯一困るのは、同一ファイル名かつ同一バージョンであるにもかかわらず、ChromeOS側とkaliLinux側がそれぞれ固有の共有ライブラリを必要とする場合である。これについては、とりあえずkali側を優先させる。ChromeOS側の当該プログラムを実行する必要が生じたら、/usr/lib, /usr/share の --bind を解除すればよい。
以上、Asus Flip上で、kaliのルートシステムを使って、遊んでみました。
chrootするもよし、直接実行するもよし、人間パッケージマネージャーになってChromeOSにインストールするもよし、遊び方はいろいろある。
USBブートのルートシステムは、こういう変則的な使い方だってできるのです。
結構、便利ですよ。