Installing Debian GNU/Linux in a chroot on a Samsung Galaxy S II

(Last updated 2011-11-26)

There are numerous how-tos on the web for installing a Debian chroot onto a smartphone running Android, but most of them either give you an image to install on your phone (which doesn't teach you anything) or have you set up the Debian system on your desktop and copy it to the phone. Neither of these options appeals to me, so I've done it my own way and written this document to light the way for others, too.

Assumptions made:

If not all of these assumptions are true, please don't contact me just to complain if something doesn't go right for you when following this how-to. Of course, alternative suggestions are welcome!

Preparation

The first thing you need to do is install cdebootstrap on your phone. cdebootstrap is a tool for bootstrapping a Debian system, usually from another Debian system, but in this case we'll be doing it from Android.

So, to install cdebootstrap:

Bootstrapping the Debian system

Now that you have a working cdebootstrap on your phone, you can use it to bootstrap Debian. First, however, you will need to create a file system for Debian to live on. It may be possible to create such a file system directly on the SD card, but as I don't really understand Android partitioning, I decided not to try this and risk losing data. (If someone knows of a way to do this, please contact me and let me know!) The reason you need a separate file system for Debian is that Android mounts its own file systems with options like noexec, which would disallow executing all binaries placed on them (thus defeating the purpose of an operating system).

The easiest way to set up a file system is to simply create a file in /mnt/sdcard and format that -- but beware, if you make this file larger than 2 GiB, the FAT file system it lives on will complain and you will lose the image next time you reboot. This happened to me the first time I tried it, and I hadn't made a backup, so I had to do it all over again. :-(

So, ssh to your phone, and run the following commands:

# dd if=/dev/zero of=/mnt/sdcard/debian.img bs=1024 count=2000000
# mke2fs -Fj /mnt/sdcard/debian.img
# mkdir /debian
# mount -t ext3 -o noatime,errors=remount-ro /mnt/sdcard/debian.img /debian
# for fs in /dev /proc /sys; do mount -o bind "$fs" "/debian$fs"; done

One last thing you need to do before setting up Debian: cdebootstrap expects the system shell to be at /bin/sh and fails without telling you why if it isn't. Since Android's system shell is /system/bin/sh, you have to appease cdebootstrap like so:

# mkdir /bin && ln -s /system/bin/sh /bin/sh

Now comes the fun bit, where we actually set up a Debian system. Still on your phone, run cdebootstrap to set up a file system tree in /debian. You may want to tweak the options below; I'm using ftp.debian-ports.org as my mirror because (at the time of writing) the armhf architecture is not yet fully integrated into the official archive. If you're using armel, or if you happen to live in the future, you can use your normal Debian mirror for this. Don't forget to replace unstable with whichever suite you want to install, but be aware that (at the time of writing) armhf only exists in unstable -- if you want stable or testing, and you downloaded an armhf cdebootstrap binary, you will need to specify the -aarmel option to cdebootstrap.

# cdebootstrap --allow-unauthenticated -c/data/local/bin/cdebootstrap-support/ unstable /debian http://ftp.debian-ports.org/debian/

We have to use --allow-unauthenticated because gpgv isn't available to authenticate signatures on Android. This command can take a while to complete, so go and have a coffee or something while you wait for Debian to download and install.

Fixing broken packages

It was the case for me that some packages failed to install from cdebootstrap. Fortunately, it had at least progressed to the point where a shell and dpkg were installed and usable in the chroot, so now we can leave cdebootstrap behind and work in Debian:

# chroot /debian /bin/bash
# cd /var/cache/bootstrap
# dpkg -i *.deb

At this point, dpkg may run into some problems. As the package archive changes over time and different people install different suites, your problems will very likely not be the same as mine, so here's where your familiarity with the Debian package tools comes in. ;-)

The main issue I ran into here was circular dependencies. These can be fixed by the use of the --force-depends option to dpkg, to allow it to install and configure one of the packages in the dependency loop, so that you can then install the others normally. For example, I found that libc6 depends on libgcc1, which pre-depends on multiarch-support, which depends on libc6. After running:

# dpkg --force-depends --configure multiarch-support

this circular dependency was no longer a problem, although there were other remaining circular dependencies that could be fixed in a similar way.

Once you have resolved a few circular dependencies and want to try again, it is a good idea to run:

# dpkg --configure -a

before telling dpkg to try installing packages again, as the shell glob *.deb will simply present the packages in alphabetical order, which is usually not a sensible order in terms of satisyfing dependencies. dpkg --configure -a will make sure that packages which are already installed (and thus don't depend on any which aren't installed yet) get configured before those which aren't already installed (and might depend on installed packages being configured).

Installing a standard Debian package set

cdebootstrap will only install packages with a priority of required or important. While this will give you a powerful Unix-like base system, it doesn't include many utilities that you would get with a standard Debian system. Once all of your package dependency issues have been resolved, and everything in /var/cache/bootstrap/ is installed, you can use aptitude to install a standard Debian system:

# echo 'deb http://ftp.debian-ports.org/debian unstable main' >/etc/apt/sources.list
# echo 'nameserver 8.8.8.8' >/etc/resolv.conf
# aptitude update
# aptitude install debian-ports-archive-keyring
# aptitude install '~prequired|~pimportant|~pstandard'

What you choose to install beyond this depends on your wants and needs, and how you like your Debian. ;-)

Initialising the Debian system at boot time

I have written a couple of simple scripts to ease getting Debian up and running. They come in pairs; one of them lives in Android and chroots to Debian, and the other lives in Debian and gets run after the chroot. You can find a copy of these scripts in Gitweb, or clone the git repository with:

$ git clone git://git.steven-mcdonald.id.au/android-debian.git

For usage information, please refer to the README in that git repository.

Security considerations

Doing everything as root is less than desirable; however, Android seems to have prevented ordinary users from doing things such as resolving hostnames. When I have time, I'd certainly like to fix this properly, but for now, it seems a Debian chroot on Android must be used as root in order to be useful.