rewrote boot.sh to src/pvmboot.sh, using libretools components and more robust shell style

This commit is contained in:
Andreas Grapentin 2019-03-15 16:37:47 +01:00
parent 342af012f1
commit 6fa8b39787
No known key found for this signature in database
GPG Key ID: 7171986E4B745536
3 changed files with 225 additions and 183 deletions

40
README

@ -1,11 +1,12 @@
parabola-imagebuilder parabola-vmbootstrap
===================== ====================
This is a collection of scripts creating parabola images for use with qemu. This is a collection of scripts for creating and booting parabola virtual
machine images for use with qemu.
image creation virtual machine image creation
-------------- ------------------------------
To create a new virtual machine image, run To create a new virtual machine image, run
$> sudo ./create.sh $> sudo ./create.sh
@ -23,12 +24,27 @@ The creation is influenced by the following environment variables:
The created images are stored in the build/ directory. The created images are stored in the build/ directory.
virtual machine start virtual machine boot
--------------------- --------------------
To boot a created virtual machine, run To boot a created virtual machine, run:
$> sudo ./boot.sh [path to created image]
The start.sh script assumes that you want a throwaway session, so it will start $> ./pvmboot.sh [path to image] [additional qemu args...]
the virtual machine in snapshot mode, and changes during the session will be
discarded. the script will attempt to determine the architecture of the provided virtual
machine image, and set the qemu executable and sane default flags for the qemu
invocation automatically, including kvm acceleration, if available for the
target architecture.
additionally, the script will evaluate the DISPLAY environment variable to
determine whether a graphical desktop environment is available, and will start
the image in serial console mode if necessary. This behavior can be forced by
unsetting DISPLAY before executing the script:
$> DISPLAY= ./pvmboot.sh [...]
The default flags can be overwritten or extended, for example to allocate more
memory to the machine, by specifying additional qemu parameters on the command
line following the virtual machine image name:
$> DISPLAY= ./pvmboot [path to image] -m 2G

171
boot.sh

@ -1,171 +0,0 @@
#!/bin/bash
##############################################################################
# parabola-imagebuilder #
# #
# Copyright (C) 2017 Andreas Grapentin #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
##############################################################################
# this is a convenience script to start a parabola VM using qemu
##############################################################################
# common directories
startdir="$(pwd)"
export TOPBUILDDIR="$startdir"/build
export TOPSRCDIR="$startdir"/src
mkdir -p "$TOPBUILDDIR"
chown "$SUDO_USER" "$TOPBUILDDIR"
# shellcheck source=src/shared/common.sh
. "$TOPSRCDIR"/shared/common.sh
# sanity checks
if [ "$(id -u)" -ne 0 ]; then
die -e "$ERROR_INVOCATION" "must be root"
fi
# shellcheck source=src/qemu.sh
. "$TOPSRCDIR"/qemu.sh
check_kernel_arch() {
echo -n "checking for kernel name ..."
local kernel
kernel=$(find "$1" -maxdepth 1 -type f -iname '*vmlinu*' | head -n1)
[ -n "$kernel" ] || kernel=no
echo "$(basename "$kernel")"
[ "x$kernel" != "xno" ] || return
# check if the kernel has an elf header and extract arch
echo -n "checking for kernel elf header ... "
set -o pipefail
machine=$(readelf -h "$kernel" 2>/dev/null | grep Machine | awk '{print $2}') || machine=no
set +o pipefail
echo "$machine"
[ "x$machine" != "xno" ] && return
# check if the kernel arch can be gathered from objdump
echo -n "checking for kernel binary header ... "
set -o pipefail
machine=$(objdump -f "$kernel" 2>/dev/null | grep architecture: | awk '{print $2}' | tr -d ',') \
|| machine=no
set +o pipefail
echo "$machine"
[ "x$machine" != "xno" ] && return
# no usable binary headers? maybe arm?
echo -n "checking for ARM boot executable ... "
local is_arm=no
file "$kernel" | grep -q 'ARM boot executable' && is_arm=yes
echo "$is_arm"
[ "x$is_arm" == "xyes" ] && machine=ARM
[ "x$machine" != "xno" ] && return
# no idea; bail.
error "unable to extract kernel arch from image"
return "$ERROR_MISSING"
}
qemu_setargs_arm() {
qemu_args+=(
-machine vexpress-a9
-cpu cortex-a9
-m 1G
-kernel "$1"/vmlinuz-linux-libre
-dtb "$1"/dtbs/linux-libre/vexpress-v2p-ca9.dtb
-initrd "$1"/initramfs-linux-libre.img
--append "console=ttyAMA0 rw root=/dev/mmcblk0p3"
-drive if=sd,driver=raw,cache=writeback,file="$2"
)
}
qemu_setargs_riscv64() {
qemu_args+=(
-machine virt
-m 2G
-kernel "$1"/bbl
-append "console=ttyS0 rw root=/dev/vda"
-drive file="${3}p3",format=raw,id=hd0
-device virtio-blk-device,drive=hd0
-object rng-random,filename=/dev/urandom,id=rng0
-device virtio-rng-device,rng=rng0
-device virtio-net-device,netdev=usernet
-netdev user,id=usernet
)
}
qemu_setargs_ppc64() {
qemu_args+=(
-machine pseries
-m 2G
-kernel "$1"/vmlinuz-linux-libre
-initrd "$1"/initramfs-linux-libre.img
-append "console=ttyS0 rw root=/dev/sda3"
-drive file="$2"
)
}
qemu_setargs_i386() {
qemu_setargs_x86_64 "$@"
}
qemu_setargs_x86_64() {
qemu_args+=(
-m 2G
-kernel "$1"/vmlinuz-linux-libre
-initrd "$1"/initramfs-linux-libre.img
-append "console=ttyS0 rw root=/dev/sda3"
-drive file="$2"
)
}
boot_from_image() {
[ -f "$1" ] || die "$1: image does not exist"
local loopdev
qemu_img_losetup "$1" || return
# mount the boot partition
mkdir -p "$TOPBUILDDIR"/mnt
mount "${loopdev}p1" "$TOPBUILDDIR"/mnt || return
trap_add "umount -R $TOPBUILDDIR/mnt" INT TERM EXIT
local machine
check_kernel_arch "$TOPBUILDDIR"/mnt || return
case "$machine" in
RISC-V) arch=riscv64 ;;
PowerPC64) arch=ppc64 ;;
ARM) arch=arm ;;
i386) arch=i386 ;;
i386:*) arch=x86_64 ;;
*) error "unrecognized machine '$machine'"
return "$ERROR_UNSPECIFIED" ;;
esac
#qemu_args=(-snapshot -nographic)
qemu_args=(-nographic)
"qemu_setargs_$arch" "$TOPBUILDDIR"/mnt "$1" "$loopdev"
qemu_arch_is_foreign "$arch" || qemu_args+=(-enable-kvm)
QEMU_AUDIO_DRV=none "qemu-system-$arch" "${qemu_args[@]}"
}
boot_from_image "$1" || die "boot failed"

197
src/pvmboot.sh Normal file

@ -0,0 +1,197 @@
#!/bin/bash
###############################################################################
# parabola-vmbootstrap -- create and start parabola virtual machines #
# #
# Copyright (C) 2017 - 2019 Andreas Grapentin #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
###############################################################################
# shellcheck source=/usr/lib/libretools/messages.sh
. "$(librelib messages)"
usage() {
print "usage: %s [-h] filename [args...]" "${0##*/}"
echo
prose " this script is designed to smartly boot a parabola GNU/Linux-libre
virtual machine with qemu. It takes the path to a virtual machine image
as parameter, and determines the architecture of that image. It sets
default qemu parameters for the target architecture, and determines
whether kvm acceleration is available."
echo
prose " the script also determines whether a graphical desktop environment
is available by evaluating the DISPLAY environment variable, and sets
default options accordingly."
echo
prose " the default qemu parameters can be overwritten and extended by adding
custom arguments after the image file name."
echo
echo "this script is developed as part of parabola-vmbootstrap."
}
pvm_mount() {
if ! file "$1" | grep -q ' DOS/MBR '; then
error "$1: does not seem to be a raw qemu image."
return "$EXIT_FAILURE"
fi
trap 'pvm_umount' INT TERM EXIT
workdir="$(mktemp -d -t pvm-XXXXXXXXXX)" || return
loopdev="$(sudo losetup -fLP --show "$1")" || return
sudo mount "$loopdev"p1 "$workdir" || return
}
pvm_umount() {
trap - INT TERM EXIT
[ -n "$workdir" ] && (sudo umount "$workdir"; rmdir "$workdir")
unset workdir
[ -n "$loopdev" ] && sudo losetup -d "$loopdev"
unset loopdev
}
pvm_probe_arch() {
local kernel
kernel=$(find "$workdir" -maxdepth 1 -type f -iname '*vmlinu*' | head -n1)
if [ -z "$kernel" ]; then
warning "%s: unable to find kernel binary" "$1"
return
fi
# attempt to get kernel arch from elf header
arch="$(readelf -h "$kernel" 2>/dev/null | grep Machine | awk '{print $2}')"
case "$arch" in
PowerPC64) arch=ppc64; return;;
RISC-V) arch=riscv64; return;;
*) arch="";;
esac
# attempt to get kernel arch from objdump
arch="$(objdump -f "$kernel" 2>/dev/null | grep architecture: | awk '{print $2}' | tr -d ',')"
case "$arch" in
i386) arch=i386; return;;
i386:*) arch=x86_64; return;;
*) arch="";;
esac
# attempt to get kernel arch from file magic
arch="$(file "$kernel")"
case "$arch" in
*"ARM boot executable"*) arch=arm; return;;
*) arch="";;
esac
# no more ideas; giving up.
}
pvm_native_arch() {
local arch
case "$1" in
arm*) arch=armv7l;;
*) arch="$1";;
esac
setarch "$arch" /bin/true 2>/dev/null || return
}
pvm_build_qemu_args() {
# if we're not running on X / wayland, disable graphics
if [ -z "$DISPLAY" ]; then qemu_args+=(-nographic); fi
# if we're running a supported arch, enable kvm
if pvm_native_arch "$2"; then qemu_args+=(-enable-kvm); fi
# otherwise, decide by target arch
case "$2" in
i386|x86_64|ppc64)
qemu_args+=(-m 1G "$1")
if [ -z "$DISPLAY" ]; then qemu_args+=(-append "console=ttyS0"); fi
# unmount the drive early
pvm_umount ;;
arm)
qemu_args+=(
-machine vexpress-a9
-cpu cortex-a9
-m 1G
-kernel "$workdir"/vmlinuz-linux-libre
-dtb "$workdir"/dtbs/linux-libre/vexpress-v2p-ca9.dtb
-initrd "$workdir"/initramfs-linux-libre.img
-append " rw root=/dev/mmcblk0p3"
-drive "if=sd,driver=raw,cache=writeback,file=$1")
if [ -z "$DISPLAY" ]; then qemu_args+=(-append " console=ttyAMA0"); fi ;;
riscv64)
qemu_args+=(
-machine virt
-m 1G
-kernel "$workdir"/bbl
-append " rw root=/dev/vda"
-drive "file=${loopdev}p3,format=raw,id=hd0"
-device "virtio-blk-device,drive=hd0"
-object "rng-random,filename=/dev/urandom,id=rng0"
-device "virtio-rng-device,rng=rng0"
-device "virtio-net-device,netdev=usernet"
-netdev "user,id=usernet")
if [ -z "$DISPLAY" ]; then qemu_args+=(-append " console=ttyS0"); fi ;;
*)
error "%s: unable to determine default qemu args" "$1"
return "$EXIT_FAILURE" ;;
esac
}
main() {
if [ "$(id -u)" -eq 0 ]; then
error "This program must be run as regular user"
exit "$EXIT_NOPERMISSION"
fi
# parse options
while getopts 'h' arg; do
case "$arg" in
h) usage; return "$EXIT_SUCCESS";;
*) usage >&2; exit "$EXIT_INVALIDARGUMENT";;
esac
done
local shiftlen=$(( OPTIND - 1 ))
shift $shiftlen
if [ "$#" -lt 1 ]; then usage >&2; exit "$EXIT_INVALIDARGUMENT"; fi
local imagefile="$1"
shift
if [ ! -e "$imagefile" ]; then
error "%s: file not found" "$imagefile"
exit "$EXIT_FAILURE"
fi
local workdir loopdev
pvm_mount "$imagefile" || exit
local arch
pvm_probe_arch "$imagefile" || exit
if [ -z "$arch" ]; then
error "%s: arch is unknown" "$imagefile"
exit "$EXIT_FAILURE"
fi
local qemu_args=()
pvm_build_qemu_args "$imagefile" "$arch" || exit
qemu_args+=("$@")
(set -x; qemu-system-"$arch" "${qemu_args[@]}")
pvm_umount
}
main "$@"