Sunday, June 17, 2012

Welcome Back GNU! My Revenge on Android

In my last post I discussed that the lack of GNU on android devices was limiting the software available and didn't bring new libraries to linux. Unfortunately for me I don't have a MeeGo device and am stuck with the Java beast.

One of the things that bothered my the most was that I could not sync my music using Unison like I do across my other three computers. If I was on MeeGo it would be as simple as apt-get install unison.

The solution for this was installing GNU on my phone, the basic concept is that you have a Linux kernel so if you install the user-land you can simply chroot into that environment and enjoy the true GNU/Linux experience.

There are many apps on the market that will assist you in installing Linux on your device but they all follow the same basic principle,

  1. Create an image file that will hold your OS. This will be formatted ext2 because this is what the Android kernels support. In here you will have everything you are used to (/etc, /bin, /home...)
  2. Then you mount the image to a directory and mount the system directories to the appropriate locations, (/proc, /sys, /dev).
  3. Chroot into the image.
  4. Enjoy!

That's the basics and here is exactaly how I accomplished that for ArchLinux, other distributions should be very similar, just make sure they have an ARM build. I based most of my instructions off of this post on the ArchLinuxARM Forum.

Step 1, get the tools.

You need to have root access to your phone and I would recommend an ssh server so that you can execute the commands from your computer. I use SSHDroid. If you don't want to use ssh go find yourself a terminal emulator.

Step 2, Start.

Get a command line and for the remainder of this post I will assume that you have run the following commands.

$ cd /sdcard/
$ img=/sdcard/linux.img
$ dir=/sdcard/linux/
I will always use $ for the shell prompt because my highlighter thinks # is a comment. In reality I just ran everything as root.

Step 3, make the filesystem image.

This step creates the filesystem image that we will be using for our linux environment. You probably don't need more than a gig as most of your files will be outside of this image. It depends on how many programs you wish to install. I found that my busybox mkfs.ext2 can't handle large filesystems (a couple of gigs) so I did this on my computer and then transferred it over.

$ dd if=/dev/zero of="$img" obs=1M seek=2048 count=0 # Create 2G file.
$ mkfs.ext2 -F "$img" # Create an ext2 filesystem on the image.
The two gigs is huge but I have a large SD card so I could spare the space.

Step 3, download and install.

You need to find an image of your distro of choice, if you want to use ArchLinux go to http://archlinuxarm.org/ and find your ARM version under platforms, the higher the version the better the performance will be. My phone said it was ARMv7 but it turns out it was actually a v6. If you get segfaults when you try to run a program you probably have too high of a version. Then go to http://archlinuxarm.org/os/ and select a package for the right version of ARM (it doesn't matter if it isn't for your phone) and use that url.

$ url=http://archlinuxarm.org/os/ArchLinuxARM-oxnas-latest.tar.gz # This is ARMv6 for my phone.
$ tarball=ArchLinuxARM-oxnas-latest.tar.gz
$ cd "$dir"
$ wget "$url"
$ tar xzfv "$tarball" 

Step 4, mount everything.

$ mknod /dev/loop256 b 7 256        # Mount the image
$ losetup /dev/loop256 "$img"       #
$ mount -t ext2 /dev/loop256 "$dir" #
$ 
$ mount -o bind /dev/ "$dir/dev" # Mount /dev/ inside the chroot.
$ mount -o bind /sdcard/ "$dir/medit/sdcard" # Mount your SD card if you want to be able to access it.

Step 5, Enter the GNU.

Now that you have access to everything you need you are ready to enter the chroot.

$ chroot "$dir" /bin/bash
$ echo "nameserver 8.8.8.8" > /etc/resolv.conf # Set some defaults
$ echo "export TERM=xterm" >> /etc/profile     #
$ echo "export HOME=/root" >> /etc/profile     #
$ 
$ /etc/rc.sysinit # ArchLinux init scripts.

Once you are in your distro you need to mount the required filesystems and start the processes it needs. The init scripts that come with the distro are very good at that so we will just pretend we are init and call them.

Step 6, convenience.

The following scripts make it easier to enter your distro. First we will create the file that prepares and chroots. I called this file linux.sh and put it in /sdcard/linux.sh

#! /bin/bash

dir=/sdcard/linux/

if ( mountpoint -q "$dir" ); then  # If already mounted
        chroot "$dir" /bin/bash -i # Enter and start a shell.
else
        mknod /dev/loop256 b 7 256              # Mount the filesystem image.
        losetup /dev/loop256 /sdcard/linux.img  #
        mount -t ext2 /dev/block/loop256 "$dir" #
        mount -o bind /dev/ "$dir/dev"
        mount -o bind /sdcard/ "$dir/media/sdcard/" # Mound the SD card.
        chroot "$dir" /bin/bash /start.sh # Enter the chroot and run the initscripts.
fi

Next we will create the script that sets up the chroot once you are there.

#! /bin/bash

/etc/rc.sysinit # ArchLinux init scripts.
/etc/rc.multi   # Start Deamons.

. /etc/profile # Get your settings
/bin/bash -i   # Start a Shell

Step 7, enjoy.

Now all you have to do is run bash /sdcard/linux.sh as root to start your linux. I like to use GScript to run the file as root. If you want to learn how to do things like start ssh see the ArchLinux docs.

I hoped all of the code is clear and you managed to get it working, if you have any questions ask and I'll try to help. So enjoy your GNU and try not to destroy your phone :)