LoginSignup
10

More than 5 years have passed since last update.

Linux on Android

Last updated at Posted at 2015-03-02

はじめに

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

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

  • Androidのrootを取得します。

  • BusyBoxをインストールします。

  • Android Terminal Emulatorをインストールします。

  • archlinux-CORE.ext4.zipをダウンロードし、/sdcard/archlinux/に解凍して出てきたarchlinux-CORE.ext4.imgarchlinux-CORE.ext4.img.md5を置きます。

  • bootscript-devfix.shをダウンロードし、/data/data/com.zpwebsites.linuxonandroid/files/bootscript.shに上書きコピーします。

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

su

cd /sdcard/archlinux

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

実際に使ってみた感触

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

よく分からない場合

よく分からない場合は、Complete Linux Installerも便利かもしれません。ドキュメントとGUIでLinuxを起動できるようになります。また、設定なども簡単に反映できるようになっています。

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

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

エラーの修正

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

Linux-on-Android project

$ unset LD_PRELOAD

$ touch ~/.bashrc

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

Error: Unable to mount the loop device!

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

sh bootscript-devfix.sh
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

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

$ pacman -Syu

$ df -H

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

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

$ pacman -Syu
$ pacman -Rc xorg

$ pacman -Qdtq | pacman -Rs -

$ pacman -Scc

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

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

$ 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
~/.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

/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もモバイルで頑張って欲しいので、管理とかも頑張って欲しい。

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

$ pacman -S zsh

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

# 結局、このファイルが原因だった。Androidイメージのオリジナル設定
$ sed -i 's/bash/zsh/g' ~/init.sh
# 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とかエラーが出ますので、イメージの容量を増やす方法です。

#!/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が起動しました。

~/.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
## }}}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10