diff --git a/Dockerfile.sparsify b/Dockerfile.sparsify new file mode 100644 index 0000000..36cfe37 --- /dev/null +++ b/Dockerfile.sparsify @@ -0,0 +1,9 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y android-sdk-libsparse-utils && \ + rm -rf /var/lib/apt/lists/* + +ENTRYPOINT ["tail", "-f", "/dev/null"] diff --git a/README.md b/README.md index 96bdc44..729ba4c 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,10 @@ NOTE: the `edk2_tici` and `agnos-firmware` submodules are internal, private repo These tools are developed on and targeted for Ubuntu 20.04. +Building requires Docker v23.0 or later and should work on any system that supports it. + Run once to set things up: ```sh -cd ~ git clone https://github.com/commaai/agnos-builder.git cd agnos-builder diff --git a/build_system.sh b/build_system.sh index 63ca4f1..e617d76 100755 --- a/build_system.sh +++ b/build_system.sh @@ -4,8 +4,6 @@ set -e UBUNTU_BASE_URL="http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release" UBUNTU_FILE="ubuntu-base-20.04.1-base-arm64.tar.gz" -export DOCKER_BUILDKIT=1 - # Make sure we're in the correct spot DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" cd $DIR @@ -38,70 +36,96 @@ if [ ! -f $UBUNTU_FILE ]; then curl -C - -o $UBUNTU_FILE $UBUNTU_BASE_URL/$UBUNTU_FILE --silent fi -if [ "$ARCH" != "arm64" ] && [ "$ARCH" != "aarch64" ]; then - # Register qemu multiarch - docker run --rm --privileged multiarch/qemu-user-static:register --reset +# Register qemu multiarch +if [ "$ARCH" = "x86_64" ]; then + echo "Registering qemu-user-static" + docker run --rm --privileged multiarch/qemu-user-static:register --reset > /dev/null fi -# Start docker build -echo "Building image" -export DOCKER_CLI_EXPERIMENTAL=enabled +# Start agnos-builder docker build and create container +echo "Building agnos-builder docker image" docker build -f Dockerfile.agnos -t agnos-builder $DIR +echo "Creating agnos-builder container" +CONTAINER_ID=$(docker container create --entrypoint /bin/bash agnos-builder:latest) -# Setup mount container -MOUNT_CONTAINER_ID=$(docker run -d --privileged --volume $BUILD_DIR:$BUILD_DIR ubuntu:latest sleep infinity) +# Setup mount container for macOS and CI support (namespace.so) +echo "Building agnos-mount docker image" +docker build -f Dockerfile.sparsify -t agnos-mount $DIR +echo "Starting agnos-mount container" +MOUNT_CONTAINER_ID=$(docker run -d --privileged -v $DIR:$DIR agnos-mount) + +# Cleanup containers on possible exit +trap "echo \"Cleaning up containers:\"; \ +docker container rm -f $CONTAINER_ID $MOUNT_CONTAINER_ID" EXIT + +# Define functions for docker execution +exec_as_user() { + docker exec -u $USERNAME $MOUNT_CONTAINER_ID "$@" +} + +exec_as_root() { + docker exec $MOUNT_CONTAINER_ID "$@" +} + +# Create host user in container (fixes namespace.so error) +USERNAME=$(whoami) +exec_as_root useradd --uid $(id -u) -U -m $USERNAME &> /dev/null # Create filesystem ext4 image echo "Creating empty filesystem" -docker exec $MOUNT_CONTAINER_ID fallocate -l $ROOTFS_IMAGE_SIZE $ROOTFS_IMAGE -docker exec $MOUNT_CONTAINER_ID mkfs.ext4 $ROOTFS_IMAGE > /dev/null +exec_as_user fallocate -l $ROOTFS_IMAGE_SIZE $ROOTFS_IMAGE +exec_as_user mkfs.ext4 $ROOTFS_IMAGE &> /dev/null # Mount filesystem echo "Mounting empty filesystem" -docker exec $MOUNT_CONTAINER_ID mkdir -p $ROOTFS_DIR -docker exec $MOUNT_CONTAINER_ID mount -o loop $ROOTFS_IMAGE $ROOTFS_DIR +exec_as_root mkdir -p $ROOTFS_DIR +exec_as_root mount $ROOTFS_IMAGE $ROOTFS_DIR + +# Also unmount filesystem (overwrite previous trap) +trap "exec_as_root umount -l $ROOTFS_DIR &> /dev/null || true; \ +echo \"Cleaning up containers:\"; \ +docker container rm -f $CONTAINER_ID $MOUNT_CONTAINER_ID" EXIT # Extract image echo "Extracting docker image" -CONTAINER_ID=$(docker container create --entrypoint /bin/bash agnos-builder:latest) docker container export -o $BUILD_DIR/filesystem.tar $CONTAINER_ID -docker container rm $CONTAINER_ID > /dev/null -docker exec $MOUNT_CONTAINER_ID tar -xf $BUILD_DIR/filesystem.tar -C $ROOTFS_DIR > /dev/null +exec_as_root tar -xf $BUILD_DIR/filesystem.tar -C $ROOTFS_DIR > /dev/null -cd $ROOTFS_DIR - -# Add hostname and hosts. This cannot be done in the docker container... echo "Setting network stuff" -HOST=comma -docker exec -w $ROOTFS_DIR $MOUNT_CONTAINER_ID bash -c "\ -ln -sf /proc/sys/kernel/hostname etc/hostname; \ -echo \"127.0.0.1 localhost.localdomain localhost\" > etc/hosts; \ -echo \"127.0.0.1 $HOST\" >> etc/hosts" +set_network_stuff() { + cd $ROOTFS_DIR + # Add hostname and hosts. This cannot be done in the docker container... + HOST=comma + bash -c "ln -sf /proc/sys/kernel/hostname etc/hostname" + bash -c "echo \"127.0.0.1 localhost.localdomain localhost\" > etc/hosts" + bash -c "echo \"127.0.0.1 $HOST\" >> etc/hosts" -# Fix resolv config -docker exec -w $ROOTFS_DIR $MOUNT_CONTAINER_ID bash -c "ln -sf /run/systemd/resolve/stub-resolv.conf etc/resolv.conf" + # Fix resolv config + bash -c "ln -sf /run/systemd/resolve/stub-resolv.conf etc/resolv.conf" -# Write build info -DATETIME=$(date '+%Y-%m-%dT%H:%M:%S') + # Write build info + DATETIME=$(date '+%Y-%m-%dT%H:%M:%S') + bash -c "printf \"$GIT_HASH\n$DATETIME\" > BUILD" +} GIT_HASH=$(git --git-dir=$DIR/.git rev-parse HEAD) -docker exec -w $ROOTFS_DIR $MOUNT_CONTAINER_ID bash -c "printf \"$GIT_HASH\n$DATETIME\" > BUILD" +exec_as_root bash -c "set -e; export ROOTFS_DIR=$ROOTFS_DIR GIT_HASH=$GIT_HASH; $(declare -f set_network_stuff); set_network_stuff" # Unmount image echo "Unmount filesystem" -docker exec $MOUNT_CONTAINER_ID umount -l $ROOTFS_DIR -docker rm -f $MOUNT_CONTAINER_ID > /dev/null - -cd $DIR +exec_as_root umount -l $ROOTFS_DIR # Sparsify -echo "Sparsify image" -TMP_SPARSE="$(mktemp)" -img2simg $ROOTFS_IMAGE $TMP_SPARSE -mv $TMP_SPARSE $SPARSE_IMAGE +echo "Sparsify image $(basename $SPARSE_IMAGE)" +exec_as_user bash -c "\ +TMP_SPARSE=\$(mktemp); \ +img2simg $ROOTFS_IMAGE \$TMP_SPARSE; \ +mv \$TMP_SPARSE $SPARSE_IMAGE" # Make image with skipped chunks -TMP_SKIP="$(mktemp)" -$DIR/tools/simg2dontcare.py $SPARSE_IMAGE $TMP_SKIP -mv $TMP_SKIP $SKIP_CHUNKS_IMAGE +echo "Sparsify image $(basename $SKIP_CHUNKS_IMAGE)" +exec_as_user bash -c "\ +TMP_SKIP=\$(mktemp); \ +$DIR/tools/simg2dontcare.py $SPARSE_IMAGE \$TMP_SKIP; \ +mv \$TMP_SKIP $SKIP_CHUNKS_IMAGE" echo "Done!"