Nexus7 2012でchrootなdebianを構築する

前置き

突然ですが、私がNexus7 2012を購入した理由は、外出先でプログラミングやSSHなどの作業がしたかったからです。
動画を見たかったという理由もありますが、それだけであればGalaxy Note SC-05Dを既に持っていたのでそれで事足ります。
ネットで検索してみると、Nexus7でネイティブにUbuntuを動かしたという記事がちらほら見つかります。

もちろん私も試しました。期待していた以上に使えます。
問題は、PC用の画面表示なのでキーボード、マウスがないとちょっと不便というところでしょうか。
それはまあ良いのですが、たとえばUbuntuは13.04より新しいのではサポートしないと表明していたり、12.04のイメージが無かったりという点が個人的には不満でした。debianもありませんし。
おそらくイチから作ることも出来るのだと思いますが、私の技術力では到底できそうもなさそうなので諦めていました。


ところで、ネイティブに動かす方法の他に併存して動かす方法もあります。
ご存知の通り、AndroidLinux Kernelを使っているので、UbuntudebianなどのバイナリがAndroid上で動かせるのです。
仮想化とは違い、カーネルを共有し(詳しくないので語弊があるかも)Linux環境内でプロセスを動かします。
既存の方法であれば、

などがあります。

これとか参考になります。

Linux on Android, debian kit両方とも試しましたが、SSHできないだとか、ユーザーの作成、パスワード変更ができないなどの不具合がありました。
そのときはAndroid 4.4.2 KK KOT49Hを使っていたのですが、今思うにSELinuxだとかグループ設定だとかが悪さをしてそうです。SELinuxはPermissiveにしたりして試しましたがそれでもうまく行きませんでした。何かが悪さしているのでしょう。


そこでAndroidのバージョンを変えて試しました。結果から言うと、4.3 JWR66Yでは試した範囲ではダメで、4.2.2 JDQ39ではdebian kitでsqueezeがなんとか動きました。

ただ、貪欲な私は古いsqueezeではなくwheezyが使いたいと思いました。(Ubuntuもありですが、ちゃらいOSなので相性の問題が起こりやすそうと思い見送りました。)
ネイティブでイチからやるのはさすがに無理だと思いましたが、chrootによる環境構築がちらほら情報が見つかります。そこでトライしてみることにしました。


Debian環境の構築

chroot環境にDebian環境を構築します。普通にPCにdebianUbuntuをインストールする方法は用意されていません。debootstrapというdebianの環境を構築するツールを使います。

このツールによる作業はfirst stageとsecond stageに分かれています。
first stageは別のマシンでも実行できます。armではなくx86なマシンでも構築できます。
second stageはインストール先マシンで行います。
その後はパッケージをインストールしたり設定できます。

これらのサイトの情報が役立ちました。

ところどころ上手くいかないところがあるので、私が行った手順を記します。

first stage

私はx86_64のUbuntu 12.04上でfirst stageを行いました。
debootstrapをインストールします

# on ubuntu as root
apt-get install debootstrap

debian環境を構築するためのディレクトリを用意します。

# on ubuntu as root
mkdir /path/to/dir

debootstrapのfirst stageを実行します。クロス環境用のコマンドです。

# on ubuntu as root
debootstrap --foreign --arch armhf wheezy /path/to/dir http://ftp.jp.debian.org/debian

ダウンロードしたりで少々時間かかります。

archの部分はARMの場合、armelとarmhfがあるようです。hfはHard Floatのことで、ハードウェアの浮動小数演算が速いCPUではこちらのほうが良いらしい。古いARMではarmelが良いらしい。(ということは古いのでも一応動くのか??詳しくないので分かりません。)
variantというオプションもあります。省略した場合はminbaseになっているようです。


first stageで出来上がった /path/to/dir をNexus7に転送する。が、パーミッションを保つ必要があるので転送方法と、保存場所には注意すること。/sdcardに生で置くと良くない。
私はdebian.tarに固めてadbなどで転送し、/data/local/debian に展開した。
(tarを使うのにbusyboxが必要。後の作業でも必要になるのでインストールしておこう。)

# on ubuntu root
cd /path/to/dir
tar cvf /some/dir/debian.tar .
adb push /some/dir/debian.tar /sdcard/

Nexus7上にて

# on nexus7 android as root
mkdir /data/local/debian
tar xvf /sdcard/debian.tar -C /data/local/debian


次はdebian環境用にandroidのデバイスファイルなどをマウントする。
/proc, /sys, /dev, /dev/ptsをマウントする必要がある。
エラー処理を除けば、例えば/procについては

# on nexus7 android as root
mkdir /data/local/debian/proc
mount -o bind /proc /data/local/debian/proc

と実行すれば良い。
あと、/dataにexec,dev,suidを許可してマウントし直す。

# on nexus7 android as root
mount -o remount,exec,dev,suid /data

(mountの結果が前後で変わらないので必要なのか不明。。。これが嫌であればイメージファイルを作ってマウントする手法もある。サイズ固定が嫌なので見送った)


DNSサーバーの設定をコピーする。Google Public DNSが設定されていた。(ひょっとしてsecond stage後でないとダメ?記憶があやふや)

# on nexus7 android as root
cp /etc/resolv.conf /data/local/debian/etc/
second stage

準備完了したので、とうとうchroot環境に入る。

# on nexus7 android as root
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
export HOME=/root
export SHELL=/bin/bash
chroot /data/local/debian /bin/bash -l

これでdebianになりました!と言いたいところですが、debootstrapのsecond stageを実行する必要があります。

# on nexus7 debian as root
/debootstrap/debootstrap --second-stage

少し時間がかかった後終了します。

apt-getのsources.listを編集しましょう。
chroot環境にはviもemacsもインストールされていないので、Android側から編集などするか、シェルで無理やり書き込むかしましょう。

deb http://ftp.jp.debian.org/debian/ stable main contrib non-free
deb-src http://ftp.jp.debian.org/debian/ stable main contrib non-free
deb http://ftp.jp.debian.org/ stable/updates main

シェルで書き込む場合は例えば

# on nexus7 debian as root
cat <<EOF >> /etc/apt/sources.list
deb http://ftp.jp.debian.org/debian/ wheezy main contrib non-free
deb-src http://ftp.jp.debian.org/debian/ wheezy main contrib non-free
deb http://ftp.jp.debian.org/debian/ wheezy-updates main
EOF

(2014/12/08 間違い修正)とか。


動作確認と、debianになった達成感を味わうためにアップデートをチェックしましょう。

# on nexus7 debian as root
apt-get update

ちゃんと動きましたか?
(私はresolv.confのコピーをし忘れてDNS解決できず失敗しました笑)


あとはタイムゾーンロケールの設定をしましょう。
タイムゾーンの設定

# on nexus7 debian as root
dpkg-reconfigure tzdata

ロケール

# on nexus7 debian as root
apt-get install locales
dpkg-reconfigure locales

参考まで日本語 265. ja_JP.UTF-8 UTF-8 を選んだ。


これで最低限は完了だ。


追記: dialog libreadline-dev apt-utilsをインストールしておいたほうが良い?

SSHとAvahiをインストール

私はsshとavahi-daemonを使いたかったので、この後インストールしました。xrdpも使いたいのですがまだうまくいっていません。
sshは簡単です。

# on nexus7 debian as root
apt-get install openssh-server

インストールされたら

 # on nexus7 debian as root
service ssh start

で起動します。(初回時はひょっとしたらapt-get中に起動されているかも?)


さて、avahi-daemonが曲者でした。avahiとはなにかを説明しておくと、ローカルのネットワーク機器でのマシン名からIPアドレスを解決するための仕組みです。市販ルーターを使っていてDNSサーバーをいじれない環境では便利です。Apple Bonjourとか調べてみてください。
まずホスト名を設定しましょう。grouperというホスト名にしました。
grouperとかnakasiとかって何のことなんですかね?)

# on nexus7 debian as root
hostname grouper

/etc/hostnameにgrouperと書き込む
/etc/hostsに

127.0.1.1 grouper

と書き込む。127.0.0.1でも良い?よくわからん。

avahi-daemonをインストールします。どうやらdbusが必要なようです。(依存でインストールされるか確認していない。)

# on nexus7 debian as root
apt-get install dbus avahi-daemon

そしたらavahi-daemonを起動したくなりますが、ここで試しても失敗します。
Android側の特権グループにavahiユーザーを追加する必要があるようです。

# on nexus7 debian as root
groupadd -g 3003 aid_inet
adduser avahi aid_inet

失敗した場合は/etc/groupを編集するなど試してください。(よくわからんー\(^o^)/ )

aid_inet:x:3003:avahi

そしたら起動します。dbusが起動していないと失敗するようです。
(Nexus7を再起動したらavahiが動かなくなって、原因がわかるまで苦労した。。。初回はdbusが既に起動している。)

# on nexus7 debian as root
service dbus start
service avahi-daemon start

起動しましたか?
確認で、別のマシン(Macかavahiありのマシン)から

# on a machine with bonjour installed
ping grouper.local

など実行してみてください。名前解決できましたか?


あとはgnuplotとかg++とか入れて遊んでみようと思います。

chroot環境を終了する

起動したserviceをすべて終了し、bindしたディレクトリのマウントを解除する。
例えば

# on nexus7 debian as root
service ssh stop
service avahi-daemon stop
service dbus stop
exit
# on nexus7 android root
umount /data/local/debian/proc
umount /data/local/debian/sys
umount /data/local/debian/dev/pts
umount /data/local/debian/dev

(serviceをすべて終了する方法は無いのだろうか。sysvinitというのが関係あり??)


Misc

ipconfigが無い!
# on nexus7 debian as root
apt-get install net-tools
pingが無い!
# on nexus7 debian as root
iputils-ping
Emacsが変

adb shellからchrootで入った場合、EmacsでCtrl-Sがなぜか出来ない。
保存もCtrl-X SでXの後にCtrlを離さないとダメだったりする。謎。
SSHで入った場合は大丈夫。

特権グループ

adb上でidしてshellが所属してるgroupが出てきたのでめも
uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount),1011(adb),1015(sdcard_rw),3001(net_bt_admin),3002(net_bt),3003(inet)

1023(media_rw)

一般ユーザーでsdcardに書き込みたいときはsdcard_rw(gid=1015)というグループを作って、それに追加すれば良いようだ。

インターネットに接続するには前述のaid_inetに追加している必要があるようだ。

こういう特権グループの一覧はどうやって調べればいいんだ?
/etc/groupみたいのはどこにあるんだ・・・?

おわり

お疲れ様でした。(自分へ)
これで外出先で思うように仕事が出来る環境ができました。
あ、でも持ち運びに適したマウスキーボードがまだ無い・・・


今回は4.2.2でやっとのことで動かせたが4.3 4.4.2では動くのだろうか。動かないとしたら何が原因なんだろうな。。。詳しい方いませんかね。


ちなみにうちには古いiPhone3Gがあるのだが、ホームボタンが効かないせいでJailBreakできない。
現在はSafari上でDDNS更新するだけのおもちゃとなっている。
JBできればcydiaでSSHとかいろいろできるのになあ・・・


もう一つIDEOSも使われないで放置されているのだが、今回の方法でdebian環境を構築して超省電力(ただし超貧弱)サーバーを作ろうかとか考えている。
USBは5V 1Aまでで、それで充電できているので最高5Wの消費電力だ!!


安く買えてrootが取れるAndroidがあれば、この方法で超省電力サーバーが構築できて夢が広がりますね。

雑多メモ

VNCクライエントはbVNCというのが個人的には良い

gnomeはなぜか不具合ありなのでlxdeを使う

gnuplotでshmgetがうんちゃらとかエラーでる
XServer XDSLのページに書いてあったshmemのところを参考
https://github.com/pelya/cuntubuntu/tree/master/dist
ここからlibandroid-shmem.soをダウンロードし、
/etc/environment に

LD_PRELOAD=/path/to/libandroid-shmem.so

と追記する


dpiの変更は~/.Xresourcesに

Xft.dpi: 160

( xorg - High DPI @ lxde - Raspberry Pi Stack Exchange )