Linux on Android 


##はじめに

Androidでも`chroot`を使えば、Linuxを扱えます。仕組みとしては、イメージをマウントし、それをルートに置き換えることで、システムを実現しているような感じです。

必要なものとしては、以下の通りです。VNC無しを使います。

- Androidの[root](http://syui.github.io/blog/2015/01/29/nexus7-2012-lollipop-root/)を取得します。

- [BusyBox](https://play.google.com/store/apps/details?id=stericson.busybox)をインストールします。

- [Android Terminal Emulator](https://play.google.com/store/apps/details?id=jackpal.androidterm&hl=ja)をインストールします。

- [archlinux-CORE.ext4.zip](http://sourceforge.net/projects/linuxonandroid/files/ArchLinux/Core/)をダウンロードし、`/sdcard/archlinux/`に解凍して出てきた`archlinux-CORE.ext4.img`と`archlinux-CORE.ext4.img.md5`を置きます。

- [bootscript-devfix.sh](http://sourceforge.net/projects/linuxonandroid/files/ArchLinux/)をダウンロードし、`/data/data/com.zpwebsites.linuxonandroid/files/bootscript.sh`に上書きコピーします。

- 以下のコマンドを実行します。

```bash:
su

cd /sdcard/archlinux

sh /data/data/com.zpwebsites.linuxonandroid/files/bootscript.sh ./archlinux-CORE.ext4.img
```

##実際に使ってみた感触

普通に使えます。特に、問題はありません。いくつかエラーが出ますが、解消できます。



##よく分からない場合

よく分からない場合は、[Complete Linux Installer](https://play.google.com/store/apps/details?id=com.zpwebsites.linuxonandroid&hl=ja)も便利かもしれません。ドキュメントとGUIでLinuxを起動できるようになります。また、設定なども簡単に反映できるようになっています。


`Complete Linux Installer`を起動し、`Launcher > Setting > Edit`よりイメージファイルを指定します。


後は、`Start Linux`をタップすると、`Terminal`が起動しますので、`y`で`Arch Linux`が起動します。




##エラーの修正

###ERROR: ld.so: object 'libsigchain.so' from LD_PRELOAD cannot be preloaded: ignored.

[Linux-on-Android project](http://forum.xda-developers.com/showthread.php?p=56461883#post56461883)

```bash:
$ unset LD_PRELOAD

$ touch ~/.bashrc

$ echo "unset LD_PRELOAD;" >> ~/.bashrc
```

###Error: Unable to mount the loop device!

次回起動時からは、以下のスクリプトを実行します。

```bash:
sh bootscript-devfix.sh
```

```bash:bootscript-devfix.sh
# Linux boot script for Android v5.0.2
# OS Type : Arch Linux
# img : /sdcard/archlinux/archlinux-CORE.ext4.img

###########################################
# This is a function we use to stop the   #
# script in case of errors                #
###########################################
error_exit() {
    echo "Error: $1"
    exit 1
}

###########################################
# Set up variables                        #
###########################################
if [ -f /data/data/com.zpwebsites.linuxonandroid/files/busybox ]; then
      	export bbox=/data/data/com.zpwebsites.linuxonandroid/files/busybox
elif [ -f /data/data/com.zpwebsites.linuxonandroid.opensource/files/busybox ]; then
      	export bbox=/data/data/com.zpwebsites.linuxonandroid.opensource/files/busybox
else
	export bbox=/system/xbin/busybox
fi

export usermounts=android	# Base folder all user mounts are done in, should be moved to app later

#export imgfile=/storage/emulated/legacy/archlinux/archlinux-CORE.ext4.img
export imgfile=/sdcard/archlinux/archlinux-CORE.ext4.img   # Default image file, another can be set by using an argument

export bin=/system/bin
export mnt=/data/local/mnt
export USER=root
if [[ ! -d $mnt ]]; then mkdir $mnt; fi
export PATH=$bin:/usr/bin:/usr/local/bin:/usr/sbin:/bin:/usr/local/sbin:/usr/games:$PATH
export TERM=linux
export HOME=/root

unset LD_PRELOAD
###########################################
# Handle arguments if present             #
###########################################
if [ $# -ne 0 ]; then
    if [ -f $1 ]; then # Is full path present?
        imgfile=$1

	elif [ -f $(dirname $0)/$1 ]; then # Is only a filename present?
        imgfile=$(dirname $0)/$1

	else
        error_exit "Image file not found!($1)"
    fi
fi

###########################################
# If a md5 file is found we check it here #
###########################################
if [ -f $imgfile.md5 ]; then
        echo "MD5 file found, use to check .img file? (y/n)"
	read answer
	if [ $answer == y ]; then
	     echo -n "Validating image checksum... "
    	     $bbox md5sum -c -s $imgfile.md5
    	     if [ $? -ne 0 ];then
                  echo "FAILED!"
                  error_exit "Checksum failed! The image is corrupted!"
             else
                  echo "OK"
                  rm $imgfile.md5
             fi
	fi
   
fi
################################
# Find and read config file    #
# or use defaults if not found #
################################
use_swap=yes

cfgfile=$imgfile.config # Default config file if not specified

if [ -f $imgfile.config ]; then
	source $imgfile.config
fi

###########################################
# Set Swap up if wanted                   #
#                                         #
###########################################
if [ $use_swap == yes ]; then
	if [ -f $imgfile.swap ]; then
		echo "Swap file found, using file"
		echo "Turning on swap (if it errors here you do not have swap support"
		swapon $imgfile.swap
		
	else
		echo "Creating Swap file"
		dd if=/dev/zero of=$imgfile.swap bs=1048576 count=1024
		#dd if=/dev/zero of=$imgfile.swap bs=2000000 count=1024
		mkswap $imgfile.swap
		echo "Turning on swap (if it errors here you do not have swap support"
		swapon $imgfile.swap
			
	fi
fi
###########################################
# Set up loop device and mount image      #
###########################################
echo -n "Checking loop device... "
if [ -b /dev/block/loop255 ]; then
	echo "FOUND"
else
	echo "MISSING"
	# Loop device not found so we create it and verify it was actually created
	echo -n "Creating loop device... "
	$bbox mknod /dev/block/loop255 b 7 255
	if [ -b /dev/block/loop255 ]; then
		echo "OK"
	else
		echo "FAILED"
		#error_exit "Unable to create loop device!"
	fi
fi

$bbox losetup /dev/block/loop255 $imgfile
#if [ $? -ne 0 ];then error_exit "Unable to attach image to loop device! (Image = $imgfile)"; fi

$bbox mount -t ext4 /dev/block/loop255 $mnt
#if [ $? -ne 0 ];then error_exit "Unable to mount the loop device!"; fi

###########################################
# Mount all required partitions           #
###########################################
$bbox mount -t devpts devpts $mnt/dev/pts
if [ $? -ne 0 ];then $bbox mount -o bind /dev $mnt/dev; $bbox mount -t devpts devpts $mnt/dev/pts; fi 
#if [ $? -ne 0 ]; then error_exit "Unable to mount $mnt/dev/pts!"; fi
$bbox mount -t proc proc $mnt/proc
#if [ $? -ne 0 ];then error_exit "Unable to mount $mnt/proc!"; fi
$bbox mount -t sysfs sysfs $mnt/sys
#if [ $? -ne 0 ];then error_exit "Unable to mount $mnt/sys!"; fi
$bbox mount -o bind /sdcard $mnt/sdcard
#if [ $? -ne 0 ];then error_exit "Unable to bind $mnt/sdcard!"; fi

if [[ ! -d $mnt/root/cfg ]]; then mkdir $mnt/root/cfg; fi
$bbox mount -o bind $(dirname $imgfile) $mnt/root/cfg

$bbox mount -o bind /sys/fs/selinux $mnt/selinux

###########################################
# Checks if you have a external sdcard    #
# and mounts it if you do                 #
###########################################
if [ -d /sdcard/external_sd ]; then
	$bbox mount -o bind /sdcard/external_sd  $mnt/external_sd
fi
if [ -d /Removable/MicroSD ]; then
	$bbox mount -o bind /Removable/MicroSD  $mnt/external_sd
fi
# This is for the HD version of the Archos 70 internet tablet, may be the same for the SD card edition but i dont know.
if [ -d /storage ]; then
	$bbox mount -o bind /storage  $mnt/external_sd
fi

###########################################
# Mount all user defined mounts if any    #
###########################################
if [ -f $imgfile.mounts ]; then
	olddir=$(pwd)
	echo "Mounting user mounts"

	cd $mnt
	if [[ ! -d $mnt/$usermounts ]]; then $bbox mkdir -p $usermounts; fi

	echo "# Script to unmount user defined mounts, do not delete or edit!" > $imgfile.shutdown
	echo "cd $mnt/$usermounts" > $imgfile.shutdown

	cd $mnt/$usermounts
	for entry in $(cat "$imgfile.mounts"); do
		ANDROID=${entry%;*}
		LINUX=${entry#*;}

		if [[ -d $ANDROID ]]; then
			echo -n "Mounting $ANDROID to $usermounts/$LINUX... "
			if [[ ! -d $mnt/$usermounts/$LINUX ]]; then $bbox mkdir -p $LINUX; fi
			$bbox mount -o bind $ANDROID $mnt/$usermounts/$LINUX &> /dev/null
			if [ $? -ne 0 ];then
				echo FAIL
				if [[ -d $mnt/$usermounts/$LINUX ]]; then $bbox rmdir -p $LINUX; fi
			else
				echo OK
				echo "$bbox umount $mnt/$usermounts/$LINUX" >> $imgfile.shutdown
				echo "$bbox rmdir -p $LINUX" >> $imgfile.shutdown
			fi
		else
			echo "Android folder not found: $ANDROID"
		fi
	done
	echo "cd $mnt" >> $imgfile.shutdown
	echo "$bbox rmdir -p $usermounts" >> $imgfile.shutdown
	cd $olddir

else
	echo "No user defined mount points"
fi

###########################################
# Sets up network forwarding              #
###########################################
$bbox sysctl -w net.ipv4.ip_forward=1
if [ $? -ne 0 ];then error_exit "Unable to forward network!"; fi

# If NOT $mnt/root/DONOTDELETE.txt exists we setup hosts and resolv.conf now
if [ ! -f $mnt/root/DONOTDELETE.txt ]; then
	echo "nameserver 8.8.8.8" > $mnt/etc/resolv.conf
	if [ $? -ne 0 ];then error_exit "Unable to write resolv.conf file!"; fi
	echo "nameserver 8.8.4.4" >> $mnt/etc/resolv.conf
	echo "127.0.0.1 localhost" > $mnt/etc/hosts
	if [ $? -ne 0 ];then error_exit "Unable to write hosts file!"; fi
fi

###########################################
# Chroot into ubuntu                      #
###########################################
$bbox chroot $mnt /root/init.sh $(basename $imgfile)

unset LD_PRELOAD

###########################################
# Shut down ubuntu                        #
###########################################
echo "Shutting down Linux ARM"
#for pid in `lsof | grep $mnt | sed -e's/  / /g' | cut -d' ' -f2`; do kill -9 $pid >/dev/null 2>&1; done
for pid in `$bbox lsof | $bbox grep $mnt | $bbox sed -e's/  / /g' | $bbox cut -d' ' -f2`; do $bbox kill -9 $pid >/dev/null 2>&1; done
sleep 5

###########################################
# Unmount all user defined mounts if any  #
###########################################
if [ -f $imgfile.shutdown ]; then
	echo "Unmounting user defined mounts"
	sh $imgfile.shutdown
	rm $imgfile.shutdown
fi

$bbox umount $mnt/root/cfg
$bbox umount $mnt/sdcard
$bbox umount $mnt/external_sd
$bbox umount $mnt/dev/pts
$bbox umount $mnt/dev
$bbox umount $mnt/proc
$bbox umount $mnt/sys
$bbox umount $mnt/selinux
$bbox umount $mnt
$bbox losetup -d /dev/block/loop255 &> /dev/null
```

###ERROR: Partition / to full

容量が足りてないようです。

```bash:
$ pacman -Syu

$ df -H

$ echo "CacheDir = /sdcard/pacman/cache/pkg" >> /etc/pacman.conf

$ rm -rf /var/cache/pacman/pkg

$ pacman -Syu
```

```bash:
$ pacman -Rc xorg

$ pacman -Qdtq | pacman -Rs -

$ pacman -Scc
```

そして、なぜか、`git`をインストール出来ないというよく分からない現象に出会います。容量は足りてるはず。

ここで、以下の手順で、増やせるらしいのですが、上手く行かなかったです。しかし、これ以降、なぜか`git`をインストールできるようになりました。


```bash:
$ ls -al

$ dd if=/dev/zero of=zero.img bs=1024k count=2048

$ cat archlinux-CORE.ext4.img zero.img > tmp.img

$ e2fsck -fv tmp.img

$ resize2fs tmp.img

$ e2fsck -fv tmp.img

$ mv tmp.img archlinux-CORE.ext4.img

$ ls -al
```

元の`img`は、バックアップを取っておいて、それを使ってもインストール以降は`git`が動きますので、容量が増えてないなら、作成した`img`の上書きや削除をオススメします。


##Android Terminal Emulator

連続コマンドは改行すれば、良いです。このアプリは、GitHubでも公開されており、信頼性はそこそこ。

`設定 > 初期コマンド`

```
su
ash -
source ~/.profile
clear
```

```bash:~/.profile
alias a="sh /sdcard/archlinux/bootscript-devfix.sh"
export PATH=$PATH:/sdcard/usr/local/bin
```

こうしておけば、`a`コマンドで`arch`が起動します。直接起動してもよいのですが、やっぱり、AndroidはAndroidで操りたいので。ちなみに、マウントしてるので、ArchLinuxからもAndroidのディスクにアクセスすることはできます。ただ、エラー関連の情報を見た感じでは、AndroidとArchLinux(ext4)は、filesystemが違う感じなので、その辺を考慮して作ってかないとなあと思います。

##BusyBox

シンボリックリンク貼ってるかと思ってたのだけど、実は無かったという。したがって、以下のスクリプトを実行します。良くわからんアプリだし、こういうのはあまり使いたくないのですが。

> $ sh /sdcard/slink.sh

```bash:/sdcard/slink.sh
#!/system/bin/sh

if [ -f /data/data/com.zpwebsites.linuxonandroid/files/busybox ]; then
      	export bbox=/data/data/com.zpwebsites.linuxonandroid/files/busybox
elif [ -f /data/data/com.zpwebsites.linuxonandroid.opensource/files/busybox ]; then
      	export bbox=/data/data/com.zpwebsites.linuxonandroid.opensource/files/busybox
elif [ -f /system/xbin/busybox ]; then
	      export bbox=/system/xbin/busybox
else
  echo "Error: no busybox"
  exit
fi

for i in $($bbox --list); do
  ln -s $bbox "/system/xbin/${i}"
done
```

一部、`bootscript.sh`の記述を利用。

##Complete Linux Installer (Arch Linux)

これも、`/etc/pacman.d/mirrorlist`などを見て見る限りではリポジトリがちょっと古い感じです。それもあってか、あまり使いたい感じではないのだけど、Archもモバイルで頑張って欲しいので、管理とかも頑張って欲しい。

ちなみに、動作の方は全く問題なしです。

```bash:
$ pacman -S zsh

# ログインシェルがbashだし、chshでも変わらないので、設定を探して、編集してみる
$ grep -R '/bin/bash' /etc

# 結局、このファイルが原因だった。Androidイメージのオリジナル設定
$ sed -i 's/bash/zsh/g' ~/init.sh
```

```bash:
# percolを入れてみる, 入ってるのpython3なのでfork版
$ git clone https://github.com/osdakira/python3-percol /sdcard/bin/percol

$ sudo python /sdcard/bin/percol/setup.sh install

# 入ったものの、何か変なエラーが出て使えない, 端末関連っぽい
$ percol
Error: ttyname
```

##追記

###イメージの容量を増やす

`pacman`とかエラーが出ますので、イメージの容量を増やす方法です。

```bash:
#!/bin/bash
img=archlinux.img
dir=/media/
size=3G

qemu-img resize $img $size
sudo losetup /dev/loop0 $img 
sudo mount -t ext4 /dev/loop0 /mnt
sudo resize2fs /dev/loop0 $size
```

###pecoをインストールする

Androitd Terminal Emulatorでも`peco`が起動しました。

```bash:~/.zshrc
pacman -S go
## golang {{{
if [ -x "`which go`" ]; then
  export GOPATH=$HOME/go
  export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
fi

if [ ! -f $GOPATH/bin/peco ];then
    go get github.com/peco/peco/cmd/peco
fi
## }}}
```