rewrote boot.sh to src/pvmboot.sh, using libretools components and more robust shell style
This commit is contained in:
parent
342af012f1
commit
6fa8b39787
40
README
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
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
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 "$@"
|
Loading…
Reference in New Issue
Block a user