Friday 03 October 2014

read/add comments (0)

Looking at the build status for Cattle on Debian, I noticed that the test suite fails on some of the more exotic architectures. Here’s the error message:

ERROR:tape.c:282:test_tape_decrease_current_value: assertion failed: (cattle_tape_get_current_value (tape) == 127)

Not exactly helpful. It would be much easier to debug the issue if I had interactive access to a computer running Debian on one of those architectures… Luckily, turns out that I do!

$ egrep '^Processor|^Hardware' /proc/cpuinfo
Processor	: ARMv7 Processor rev 0 (v7l)
Hardware	: SMDK4x12

The computer in question is my Samsung Galaxy SIII smartphone which, with a bit of work, can be used as a Debian development host, and a pretty good one at that.

The procedure I’m about to describe will work on most Android smartphones and tablets, provided that root access is available and busybox has the right commands compiled in.

If, like me, you’re running CyanogenMod on your device, you already have everything you need. Note that I’ve only tested this on CM 11, though.

First of all, you’re going to need a computer running Debian. Other Unix–like operating systems will work as well, but obtaining and running debootstrap on them is probably going to be a little convoluted, so it’s left as an exercise to the reader.

Start with

$ dd if=/dev/zero of=debian.img bs=1M count=1024
$ sudo mkfs.ext4 -F debian.img

This will create a debian.img file, 1GB in size, which will contain your Debian system. 1GB is enough for the base system, build-essential and a bunch of other libraries with 250MB to spare. Mount the image with

$ sudo mount -o loop debian.img /mnt

and complete the first stage of the bootstrap process with

$ sudo debootstrap --arch=armhf --variant=minbase --foreign unstable /mnt
$ sync
$ sudo umount /mnt

Now push debian.img to your Android device and launch a terminal emulator. Become root by running

$ su

and navigate to the directory you’ve saved your image to. Now for the interesting bits:

# mount -o rw,remount rootfs /
# mknod /dev/block/loop99 b 7 99
# mount -o ro,remount rootfs /

This creates the loopback device you’re going to use to mount the image on Android. It will be automatically deleted on reboot, so don’t bother removing it when you’re done.

# mkdir debian
# losetup /dev/block/loop99 debian.img
# mount -t ext4 /dev/block/loop99 debian

Your image is now mounted on debian/. A few filesystems are needed on top of that for the system to work properly:

# mount -o bind /dev debian/dev
# mount -t devpts none debian/dev/pts
# mount -t proc none debian/proc
# mount -t sysfs none debian/sys

Now you can finally complete the installation!

# chroot debian /bin/bash
# export PATH=/usr/sbin:/usr/bin:/sbin:/bin
# /debootstrap/debootstrap --second-stage

Once the bootstrap is complete, you can perform any customization you might want. I immediately created an unprivileged user; then, after setting up DNS with

# echo "nameserver" >/etc/resolv.conf
# echo "nameserver" >>/etc/resolv.conf

and configuring software repositories with

# echo "deb unstable main" >/etc/apt/sources.list

I was able to install openssh-server, which is crucial because, by this point, I could no longer bear to type Unix commands on a tiny virtual keyboard :)

Once the OpenSSH daemon is running, you can either login from a computer connected to the same wireless network or directly from the Android device by using something like

$ ssh user@

I prefer the second approach: I just connect the phone to my laptop with the USB cable, start a shell on the device with

$ adb shell

and login to the Debian system using the command above.

Once you’re done with your Debian work, you need to stop any daemon you’ve started inside the chroot and umount all the filesystem in reverse order from a privileged Android shell, like

# sync
# umount debian/sys
# umount debian/proc
# umount debian/dev/pts
# umount debian/dev
# umount debian

Doing this every time would become tedious, of course, so I've created a couple of shell scripts that do everything for me; they even support multiple Debian chroots running concurrently, because why not :)

You can grab the scripts, along with some documentation, from the Git repository.

Once you’re inside the chroot, it’s actually easy to forget you’re working on a phone: everything behaves exactly like it would on an Intel computer, if only a little slower. This is not a watered–down version of Debian, it’s the real deal. Kudos to all the developers who have have made such an impressive thing possible!

Now on to hunt the actual bug :)