minimal qemu-binfmt root with multistrap

categories: code

In this earlier post I listed the following manual method to fill /etc/qemu-binfmt/arm/ with shared libraries of the foreign architecture:

wget http://ftp.debian.org/debian/pool/main/e/eglibc/libc6_2.11.2-11_armel.deb
sudo mkdir -p /etc/qemu-binfmt/arm/
sudo dpkg -x libc6_2.11.2-11_armel.deb /etc/qemu-binfmt/arm/
rm libc6_2.11.2-11_armel.deb

This approach has two disadvantages. Firstly when some other library is required one again has to manually look up the url to the latest deb of the package that contains it and manually extract it to the target directory. Secondly, whenever one wants to upgrade the libraries because of incompatibilities, one has to repeat the whole process. The downloading is hard to script because version numbers and thus, urls to packages change. Fortunately apt can be used to to automatically get the latest binary packages for any architecture and suite. This is the same mechanism that multistrap uses to setup a rootfs. Without further thinking I hacked together a small script that basically does, was the core of what multistrap does:

#!/bin/sh -ex

usage() {
echo "Usage: $0 arch suite rootdir [mirror]" }

MIRROR="http://127.0.0.1:3142/ftp.de.debian.org/debian"

[ "$#" -ne 3 ] && [ "$#" -ne 4 ] && { usage; exit; }

ARCH="$1"
SUITE="$2"
ROOTDIR="$3"
MIRROR=${4:-$MIRROR}

[ -e "$ROOTDIR" ] && { echo "root directory still exists"; exit; }

mkdir "$ROOTDIR"

ROOTDIR=`realpath "$ROOTDIR"`

# apt options
APT_OPTS="-y"
APT_OPTS=$APT_OPTS" -o Apt::Architecture=$ARCH"
APT_OPTS=$APT_OPTS" -o Dir::Etc::TrustedParts=$ROOTDIR/etc/apt/trusted.gpg.d"
APT_OPTS=$APT_OPTS" -o Dir::Etc::Trusted=$ROOTDIR/etc/apt/trusted.gpg"
APT_OPTS=$APT_OPTS" -o Apt::Get::AllowUnauthenticated=true"
APT_OPTS=$APT_OPTS" -o Apt::Get::Download-Only=true"
APT_OPTS=$APT_OPTS" -o Apt::Install-Recommends=false"
APT_OPTS=$APT_OPTS" -o Dir=$ROOTDIR/"
APT_OPTS=$APT_OPTS" -o Dir::Etc=$ROOTDIR/etc/apt/"
APT_OPTS=$APT_OPTS" -o Dir::Etc::SourceList=$ROOTDIR/etc/apt/sources.list"
APT_OPTS=$APT_OPTS" -o Dir::State=$ROOTDIR/var/lib/apt/"
APT_OPTS=$APT_OPTS" -o Dir::State::Status=$ROOTDIR/var/lib/dpkg/status"
APT_OPTS=$APT_OPTS" -o Dir::Cache=$ROOTDIR/var/cache/apt/"

# initial setup for apt and dpkg to work properly
mkdir -p $ROOTDIR
mkdir -p $ROOTDIR/etc/apt/
mkdir -p $ROOTDIR/etc/apt/sources.list.d/
mkdir -p $ROOTDIR/etc/apt/preferences.d/
mkdir -p $ROOTDIR/var/lib/apt/
mkdir -p $ROOTDIR/var/lib/apt/lists/partial/
mkdir -p $ROOTDIR/var/lib/dpkg/
mkdir -p $ROOTDIR/var/cache/apt/
touch $ROOTDIR/var/lib/dpkg/status

# fill sources.list
echo deb $MIRROR $SUITE main > $ROOTDIR/etc/apt/sources.list

# update and install git and ruby
apt-get $APT_OPTS update
apt-get $APT_OPTS install libc6 libselinux1 libacl1 man-db libstdc++6

# unpack downloaded archives
for deb in $ROOTDIR/var/cache/apt/archives/*.deb; do
dpkg -x $deb $ROOTDIR
done

# cleanup
rm -rf $ROOTDIR/var/lib/apt/lists
rm -rf $ROOTDIR/var/cache/apt/

One would invoke it like that:

./create-binfmt-tree.sh armel sid binfmt-root

I did something like that before (documented here) so it seemed straight forward to do it like that. It was only after I was done and everything was working when I realized that multistrap has the omitrequired option with which one can do exactly what I wanted: not build a whole rootfs but just get some packages with apt and extract them to a directory. This is the much simpler multistrap config that does the same as the script above:

[General]
arch=
directory=
cleanup=true
unpack=true
noauth=true
aptsources=Debian
bootstrap=Debian
allowrecommends=false
addimportant=false
omitrequired=true

[Debian]
packages=libc6 libselinux1 libacl1 man-db libstdc++6
source=http://ftp.de.debian.org/debian
suite=sid
omitdebsrc=true

Invoking it like that will produce a rootfs I can put into /etc/qemu-binfmt/arm right away:

multistrap -a armel -d binfmt-root -f multistrap-binfmt.conf
View Comments
blog comments powered by Disqus