• Home
  • Tags
  • RSS
  • About
  • minimal qemu-binfmt root with multistrap

    Timestamp:
    Tags: 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