Skip to content

Instantly share code, notes, and snippets.

@JoshuaWierenga
Last active October 2, 2022 12:48
Show Gist options
  • Save JoshuaWierenga/ad1c8c4fd4c7c6f5b362d6cf400b0435 to your computer and use it in GitHub Desktop.
Save JoshuaWierenga/ad1c8c4fd4c7c6f5b362d6cf400b0435 to your computer and use it in GitHub Desktop.
Script for Ubuntu 22.04 WSL2 to setup qemu user mode emulation for a different archecture using cloud images
#! /bin/sh
# Ubuntu 22.04 WSL2 qemu user mode emulation setup 0.4.0
version="0.4.0"
usage()
{
echo "Ubuntu 22.04 WSL2 qemu user mode emulation setup $version
Usage: $0 [general and mode specific flags] [-i or -e] architecture
General Flags:
-?, -h: Display this usage information and then quit.
-v: Display version history and then quit.
-d Specify directory to use for install or access modes. Defaults to ubuntu{architecture} for install mode only.
Modes:
-i: Install new architecture to specified folder.
architecture: Specifies which architecture to install, tested architectures are amd64, arm64, s390x and riscv64, others may work.
optional directory defaults to ubuntu{architecture} if not given.
-e: Chroot into already installed architecture.
architecture: Specifies which architecture the required directory argument is for.
Install(-i) specific flags:
-a: Avoid wsl images for amd64 and arm64, use general cloud images instead."
exit
}
version()
{
echo "Ubuntu 22.04 WSL2 qemu user mode emulation setup $version
Change log:
Changes in 0.4.0:
Added support for accessing existing chroot via -e flag.
Added directory flag -d which can be used to override the install path when using -i, is also required when using -e.
Changes in 0.3.0:
Cleaned up usage info.
Moved default install action to -i flag.
Changes in 0.2.0:
Improved optional parameter handling.
Added version info.
Fixed amd64 and arm64 image downloading and finding qemu binary when -a is provided.
Fixed non wsl image extracting."
exit
}
# Helpers
checkAction()
{
if [ -n "$action" ] ; then
echo "Only one of -i and -e can be provided."
usage
fi
}
getQemuStaticName()
{
# TODO Find better method since qemu has ppc64le while ubuntu has ppc64el which are the same thing
amd64QemuPathArch="x86_64"
arm64QemuPathArch="aarch64"
qemuStaticNamePrefix="qemu-"
qemuStaticNameSuffix="-static"
if [ "$1" = amd64 ] ; then
qemuStaticArch=$amd64QemuPathArch
elif [ "$1" = arm64 ] ; then
qemuStaticArch=$arm64QemuPathArch
else
qemuStaticArch="$1"
fi
qemuStaticName=$qemuStaticNamePrefix$qemuStaticArch$qemuStaticNameSuffix
}
# Based on https://serverfault.com/a/901858
handleMountBind()
{
if ! findmnt "$2" >/dev/null ; then
sudo mount -o bind "$1" "$2"
fi
}
# Modes
# Based on https://github.com/Biswa96/WSLInstall/blob/master/docs/Chroot_ARM64_Linux_Distro.md
setupArchChroot()
{
baseUrl="https://cloud-images.ubuntu.com/releases/22.04/release/"
amd64Url="ubuntu-22.04-server-cloudimg-amd64-wsl.rootfs.tar.gz"
arm64Url="ubuntu-22.04-server-cloudimg-arm64-wsl.rootfs.tar.gz"
generalUrlPrefix="ubuntu-22.04-server-cloudimg-"
generalUrlSuffix="-root.tar.xz"
if [ -z "$avoidWSLImages" ] && [ "$architecture" = amd64 ] ; then
imageName=$amd64Url
elif [ -z "$avoidWSLImages" ] && [ "$architecture" = arm64 ] ; then
imageName=$arm64Url
else
imageName=$generalUrlPrefix$architecture$generalUrlSuffix
fi
url=$baseUrl$imageName
getQemuStaticName "$architecture"
httpCode=$(curl -I -s "$url" -o /dev/null -w "%{http_code}\n")
if [ "$httpCode" -ne 200 ] ; then
echo "Error finding ubuntu cloud image, this could be because the site couldn't be reached, the images have been moved or no image exists for the $architecture architecture."
exit
fi
sudo apt install -y \
binfmt-support \
daemonize \
qemu-user-static
# TODO Allow specifying destination
installPath=ubuntu"$architecture"
# TODO Prompt user before continuing as this may override stuff otherwise
if [ ! -d "$installPath" ] ; then
mkdir "$installPath"
fi
wget -N "$url"
sudo tar -xaf "$imageName" -C "$installPath"
# TODO: Avoid multiple instances using -l?
sudo daemonize \
/usr/bin/unshare -fp --mount-proc \
/lib/systemd/systemd --system-unit=basic.target
sudo cp /usr/bin/"$qemuStaticName" "$installPath"/usr/bin
sudo mount -o bind /proc "$installPath"/proc
sudo mount -o bind /dev "$installPath"/dev
# Attempt to fix issues with the following user setup just giving a bunch of errors if ran too early
sleep 1
# Based on https://stackoverflow.com/a/51312156
# TODO Allow specifying username and password
sudo chroot "$installPath" "$qemuStaticName" bin/bash << "EOT"
adduser --gecos "" --disabled-password test
chpasswd <<<"test:test"
usermod -aG sudo test
EOT
# TODO Fix networking
# TODO Fix pty allocation
}
enterArchChroot()
{
if [ -z "$directory" ] ; then
echo "Entering a chroot with -e requires the -d directory flag is provided as well."
usage
fi
# TODO Confirm that $directory contains an install made using setupArchChroot
# TODO Figure out based on copy installed to $directory/usr/bin
getQemuStaticName "$architecture"
# TODO: Avoid multiple instances using -l?
sudo daemonize \
/usr/bin/unshare -fp --mount-proc \
/lib/systemd/systemd --system-unit=basic.target
handleMountBind /dev "$directory"/dev
handleMountBind /proc "$directory"/proc
sudo chroot "$directory" "$qemuStaticName" bin/su - test
}
# based on https://www.shellscript.sh/tips/getopts/
unset avoidWSLImages directory action
while getopts "a?hvd:i:e:" c ; do
case $c in
a) avoidWSLImages=1 ;;
h|\?) usage ;;
v) version ;;
d) directory=$OPTARG ;;
i) checkAction
action="install" ;
architecture=$OPTARG ;;
e) checkAction
action="enter" ;
architecture=$OPTARG ;;
esac
done
if [ -z $action ] ; then
usage ;
elif [ $action = install ] ; then
setupArchChroot
elif [ $action = enter ] ; then
enterArchChroot
fi
# TODO Add options to unmount and delete chroot environment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment