improve fs detection - factor out common functions
This commit is contained in:
parent
8f102e6742
commit
4872be99ac
53
README
53
README
@ -26,6 +26,8 @@ the script will emit a warning and ask for confirmation to proceed.
|
|||||||
The creation can be influenced by providing one or more of the following
|
The creation can be influenced by providing one or more of the following
|
||||||
options to pvmbootstrap:
|
options to pvmbootstrap:
|
||||||
|
|
||||||
|
-b <base-set> -- Select one of the pre-defined package-sets described below
|
||||||
|
(default: 'standard')
|
||||||
-H <hook> -- Enable a hook to customize the created image. This can be
|
-H <hook> -- Enable a hook to customize the created image. This can be
|
||||||
the path to a custom script, or one of the predefined hooks
|
the path to a custom script, or one of the predefined hooks
|
||||||
described below. The VM will boot the newly created image,
|
described below. The VM will boot the newly created image,
|
||||||
@ -39,16 +41,21 @@ options to pvmbootstrap:
|
|||||||
-O -- Bootstrap an openrc system instead of a systemd one
|
-O -- Bootstrap an openrc system instead of a systemd one
|
||||||
-p <package> -- Specify additional packages to be installed in the VM image.
|
-p <package> -- Specify additional packages to be installed in the VM image.
|
||||||
This option can be specified multiple times.
|
This option can be specified multiple times.
|
||||||
-s <img_size> -- Set the size (in GB) of the VM image (minimum: 1, default: 64)
|
-s <root_size> -- Set the size (in MB) of the root partition (default: 32000).
|
||||||
|
If this is 0 (or less than the <base-set> requires),
|
||||||
|
the VM image will be the smallest size possible,
|
||||||
|
fit to the <base-set>; and any -p <package> will be ignored.
|
||||||
-S <swap_size> -- Set the size (in MB) of the swap partition (default: 0)
|
-S <swap_size> -- Set the size (in MB) of the swap partition (default: 0)
|
||||||
|
|
||||||
The creation hooks currently supported are:
|
Pre-defined package-sets:
|
||||||
|
minimal: base
|
||||||
|
standard: base parabola-base
|
||||||
|
devel: base parabola-base base-devel
|
||||||
|
|
||||||
'ethernet-dhcp':
|
Pre-defined hooks:
|
||||||
|
ethernet-dhcp: This hook will setup ethernet in the VM by enabling
|
||||||
This hook will setup ethernet in the VM by enabling systemd-resolved and
|
systemd-resolved and openresolv properly, as well as creating
|
||||||
openresolv properly, as well as creating and enabling a systemd-networkd
|
and enabling a systemd-networkd configuration. (systemd only)
|
||||||
configuration.
|
|
||||||
|
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
@ -59,10 +66,23 @@ To boot a created virtual machine, run:
|
|||||||
|
|
||||||
$> pvmboot [options] <path_to_image> [qemu-args ...]
|
$> pvmboot [options] <path_to_image> [qemu-args ...]
|
||||||
|
|
||||||
The script will attempt to determine the architecture of the provided virtual
|
The script will attempt to determine the architecture and partition layout
|
||||||
machine image, and set the qemu executable and sane default flags for the qemu
|
of the provided virtual machine image, and set the qemu executable and sane
|
||||||
invocation automatically, including kvm acceleration, if available for the
|
default flags for the qemu invocation automatically; and will enable KVM
|
||||||
target architecture.
|
acceleration, if available for the target architecture.
|
||||||
|
|
||||||
|
The pvmbootstrap script creates a boot partition formatted with either the
|
||||||
|
vfat or ext2 filesystems, and a root partition formatted with the ext4
|
||||||
|
filesystems. If the specified image was not created using pvmbootstrap, the
|
||||||
|
partition detection will fail unless the image coforms to this expected schema.
|
||||||
|
The first vfat or ext2 filesystem detected, will be considered as the boot
|
||||||
|
partition; and the first ext4 filesystem detected, will be considered as the
|
||||||
|
root partition.
|
||||||
|
|
||||||
|
The default kernel installed by pvmbootstrap is 'linux-libre'.
|
||||||
|
The -k option ca be used to specify an alternate kernel to boot.
|
||||||
|
|
||||||
|
$> pvmboot -k linux-libre-lts ./an.img
|
||||||
|
|
||||||
Additionally, the script will evaluate the DISPLAY environment variable to
|
Additionally, the script will evaluate the DISPLAY environment variable to
|
||||||
determine whether a graphical desktop environment is available, and will start
|
determine whether a graphical desktop environment is available, and will start
|
||||||
@ -71,12 +91,7 @@ unsetting DISPLAY before executing the script:
|
|||||||
|
|
||||||
$> DISPLAY= pvmboot ./an.img
|
$> DISPLAY= pvmboot ./an.img
|
||||||
|
|
||||||
The default kernel installed by pvmbootstrap is 'linux-libre'.
|
If qemu boots into graphical mode, the serial console can be redirected
|
||||||
The -k option ca be used to specify an alternate kernel to boot.
|
|
||||||
|
|
||||||
$> pvmboot -k linux-libre-lts ./an.img
|
|
||||||
|
|
||||||
When the VM will boot into graphical mode, the serial console can be redirected
|
|
||||||
to the host console by passing the -r option.
|
to the host console by passing the -r option.
|
||||||
|
|
||||||
$> pvmboot -r ./an.img
|
$> pvmboot -r ./an.img
|
||||||
@ -104,5 +119,5 @@ pvmbootstrap always creates a /boot partition.
|
|||||||
for example, to generate the parabola armv7h release tarball:
|
for example, to generate the parabola armv7h release tarball:
|
||||||
|
|
||||||
$> img_filename=parabola-systemd-cli-armv7h-tarball-$(date +%Y.%m).img
|
$> img_filename=parabola-systemd-cli-armv7h-tarball-$(date +%Y.%m).img
|
||||||
$> pvmbootstrap -s 1 -H ethernet-dhcp $img_filename armv7h
|
$> pvmbootstrap -b minimal -H ethernet-dhcp -s 0 -S0 $img_file armv7h
|
||||||
$> pvm2tarball $img_filename
|
$> pvm2tarball $img_file
|
||||||
|
264
src/pvm-common.sh.inc
Normal file
264
src/pvm-common.sh.inc
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
# readonly DATA_IMG=./pvmdata.img # optional large qemu disk
|
||||||
|
readonly THIS_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||||
|
readonly UNPRIVILEGED_ERR_MSG="This program must be run as a regular user"
|
||||||
|
readonly MOUNTS_ERR_MSG="some PVM mountpoints are mounted - possibly orphans from a previous run - unmount them first"
|
||||||
|
readonly MOUNTVARS_ERR_MSG="FIXME: pvm_setup_loopdev() was called in an improper state - one of [ \$bootdir , \$workdir , \$loopdev ] is already set"
|
||||||
|
|
||||||
|
|
||||||
|
# shellcheck source=/usr/lib/libretools/messages.sh
|
||||||
|
source "$(librelib messages)"
|
||||||
|
|
||||||
|
|
||||||
|
pvm_get_pvmboot_cmd()
|
||||||
|
{
|
||||||
|
local intree_cmd=$THIS_DIR/pvmboot.sh
|
||||||
|
local installed_cmd='pvmboot'
|
||||||
|
|
||||||
|
[[ -f "$intree_cmd" ]] && echo "$intree_cmd" && return "$EXIT_SUCCESS"
|
||||||
|
type -p $installed_cmd &>/dev/null && echo "$installed_cmd" && return "$EXIT_SUCCESS"
|
||||||
|
error "can not find pvmboot" && return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_get_hook() # ( hook_name )
|
||||||
|
{
|
||||||
|
local hook_name=$1
|
||||||
|
local intree_dir=$THIS_DIR/hooks
|
||||||
|
local installed_dir=/usr/lib/parabola-vmbootstrap
|
||||||
|
local hook_filename=hook-$hook_name.sh
|
||||||
|
local locations=( "$intree_dir/$hook_filename" "$installed_dir/$hook_filename" "$hook_name" '' )
|
||||||
|
local location
|
||||||
|
|
||||||
|
for location in "${locations[@]}" ; do [[ -f "$location" ]] && break ; done ;
|
||||||
|
[[ "$location" ]] && echo "$location" || warning "no such hook: '%s'" "$hook_name"
|
||||||
|
[[ "$location" ]] && return "$EXIT_SUCCESS" || return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_find_part_n() # ( imagefile fs_types ) , sets: $part_n
|
||||||
|
{
|
||||||
|
local imagefile="$1" ; shift ;
|
||||||
|
local fs_types="$@"
|
||||||
|
|
||||||
|
# try locating the partition by filesystem type
|
||||||
|
for fs_type in $fs_types
|
||||||
|
do local part_data=$(parted "$imagefile" print 2> /dev/null | grep $fs_type | head -n 1)
|
||||||
|
part_n=$( echo $part_data | cut -d ' ' -f 1 )
|
||||||
|
|
||||||
|
! [[ "$part_n" =~ ^[0-9]+$ ]] && part_n='' || break
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$part_n" =~ ^[0-9]+$ ]] && return "$EXIT_SUCCESS" || return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_find_boot_part_n() # ( imagefile ) , sets: boot_part_n
|
||||||
|
{
|
||||||
|
local imagefile="$1"
|
||||||
|
local part_n
|
||||||
|
|
||||||
|
pvm_find_part_n "$imagefile" fat32 ext2 || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
|
boot_part_n=$part_n
|
||||||
|
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_find_root_part_n() # ( imagefile ) , sets: root_part_n
|
||||||
|
{
|
||||||
|
local imagefile="$1"
|
||||||
|
local part_n
|
||||||
|
|
||||||
|
pvm_find_part_n "$imagefile" ext4 || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
|
root_part_n=$part_n
|
||||||
|
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_check_unprivileged() # exits on failure
|
||||||
|
{
|
||||||
|
[[ "$(id -u)" -eq 0 ]] && error "$UNPRIVILEGED_ERR_MSG" && exit "$EXIT_NOPERMISSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_native_arch() # ( arch )
|
||||||
|
{
|
||||||
|
local arch=$1
|
||||||
|
local native_arch=$( [[ "$arch" =~ arm.* ]] && echo 'armv7l' || echo "$arch" )
|
||||||
|
|
||||||
|
setarch "$native_arch" /bin/true 2>/dev/null && return "$EXIT_SUCCESS" || \
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_check_file_exists_writable() # (file_path [ is_error_if_not_exists ])
|
||||||
|
{
|
||||||
|
local file_path="$1"
|
||||||
|
local is_error_if_not_exists=$( [[ "$2" == 'true' ]] && echo 1 || echo 0 )
|
||||||
|
|
||||||
|
if [[ -e "$file_path" ]]
|
||||||
|
then if [[ -w "$file_path" ]]
|
||||||
|
then return "$EXIT_SUCCESS"
|
||||||
|
else error "file exists but is not writable: '%s'" "$file_path"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
elif (( ! $is_error_if_not_exists ))
|
||||||
|
then return "$EXIT_SUCCESS"
|
||||||
|
else error "no such file: %s" "$file_path"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_check_file_exists_and_writable() # (file_path)
|
||||||
|
{
|
||||||
|
local file_path="$1"
|
||||||
|
|
||||||
|
pvm_check_file_exists_writable $file_path true && return "$EXIT_SUCCESS" || \
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_check_file_not_exists_or_writable() # (file_path)
|
||||||
|
{
|
||||||
|
local file_path="$1"
|
||||||
|
|
||||||
|
pvm_check_file_exists_writable $file_path && return "$EXIT_SUCCESS" || \
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_prompt_clobber_file() # (file_path)
|
||||||
|
{
|
||||||
|
local file_path="$1"
|
||||||
|
|
||||||
|
if pvm_check_file_not_exists_or_writable "$file_path"
|
||||||
|
then if [[ -e "$file_path" ]]
|
||||||
|
then warning "file exists: '%s'\nContinue? [y/N]" "$file_path"
|
||||||
|
read -p " " -n 1 -r ; echo ;
|
||||||
|
|
||||||
|
[[ $REPLY =~ ^[Yy]$ ]] || return "$EXIT_FAILURE"
|
||||||
|
rm -f "$file_path" || return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
else return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_setup_loopdev() # assumes: $imagefile , sets: $bootdir $workdir $loopdev , traps: INT TERM EXIT
|
||||||
|
{
|
||||||
|
if file "$imagefile" | grep -Eq ': (data|DOS/MBR )'; then
|
||||||
|
if [[ -z "${bootdir}${workdir}${loopdev}" ]]; then
|
||||||
|
pvm_check_no_mounts && msg "creating loopback devices" || return "$EXIT_FAILURE"
|
||||||
|
else
|
||||||
|
error "$MOUNTVARS_ERR_MSG"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
error "not a raw qemu image: '%s'" "$imagefile"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap 'pvm_cleanup' INT TERM EXIT
|
||||||
|
|
||||||
|
# setup the loopback device
|
||||||
|
bootdir="$(mktemp -d -t pvm-bootfs-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
||||||
|
workdir="$(mktemp -d -t pvm-rootfs-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
||||||
|
loopdev="$(sudo losetup -fLP --show "$imagefile")" || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_mount() # assumes: $imagefile $loopdev $bootdir $workdir
|
||||||
|
{
|
||||||
|
pvm_setup_loopdev || return "$EXIT_FAILURE" # sets: $bootdir $workdir $loopdev
|
||||||
|
|
||||||
|
# find boot and root filesystem partitions
|
||||||
|
local boot_part_n root_part_n
|
||||||
|
pvm_find_boot_part_n "$imagefile" || return "$EXIT_FAILURE" # sets: $boot_part_n
|
||||||
|
pvm_find_root_part_n "$imagefile" || return "$EXIT_FAILURE" # sets: $root_part_n
|
||||||
|
|
||||||
|
# mount boot and root filesystems
|
||||||
|
msg "mounting image filesystems"
|
||||||
|
sudo mount "$loopdev"p$boot_part_n "$bootdir" || return "$EXIT_FAILURE"
|
||||||
|
sudo mount "$loopdev"p$root_part_n "$workdir" || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_umount() # unsets: $bootdir $workdir
|
||||||
|
{
|
||||||
|
[[ "${bootdir}${workdir}${loopdev}" ]] && msg "un-mounting image filesystems"
|
||||||
|
|
||||||
|
(sudo umount "$workdir"/boot && rmdir "$workdir") 2> /dev/null
|
||||||
|
(sudo umount "$bootdir" && rmdir "$bootdir") 2> /dev/null
|
||||||
|
(sudo umount "$workdir" && rmdir "$workdir") 2> /dev/null
|
||||||
|
|
||||||
|
unset bootdir
|
||||||
|
unset workdir
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_cleanup() # unsets: $loopdev , untraps: INT TERM EXIT
|
||||||
|
{
|
||||||
|
trap - INT TERM EXIT
|
||||||
|
|
||||||
|
pvm_umount
|
||||||
|
sudo losetup -d "$loopdev"
|
||||||
|
pvm_check_no_mounts || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
|
unset loopdev
|
||||||
|
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_check_no_mounts() # assumes: $imagefile
|
||||||
|
{
|
||||||
|
local n_pvm_mounts=$( mount | grep /tmp/pvm | wc --lines )
|
||||||
|
local n_loop_devs=$( sudo losetup --associated $imagefile | wc --lines )
|
||||||
|
local are_any_mounts=$( (( $n_pvm_mounts + $n_loop_devs )) && echo 1 || echo 0 )
|
||||||
|
|
||||||
|
(( $are_any_mounts )) && error "$MOUNTS_ERR_MSG" && return "$EXIT_FAILURE" || \
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_probe_arch() # assumes: $bootdir $workdir $imagefile , sets: $arch
|
||||||
|
{
|
||||||
|
msg "detecting CPU architecture for image"
|
||||||
|
|
||||||
|
local kernel=$(find "$bootdir" -maxdepth 1 -type f -iname '*vmlinu*' | head -n1)
|
||||||
|
local guest_arch
|
||||||
|
|
||||||
|
if [ -n "$kernel" ]; then
|
||||||
|
msg2 "found kernel binary: %s" "$kernel"
|
||||||
|
else
|
||||||
|
warning "%s: unable to find kernel binary" "$imagefile"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
guest_arch="$(readelf -h "$workdir"/bin/true 2>/dev/null | \
|
||||||
|
grep Machine | sed 's|[^:]*:\s*\([^:,]*\).*|\1|')"
|
||||||
|
|
||||||
|
case "$guest_arch" in
|
||||||
|
ARM ) arch=armv7h ;;
|
||||||
|
i386|i386:*|*\ 80386) arch=i686 ;;
|
||||||
|
PowerPC64 ) arch=ppc64le ;;
|
||||||
|
RISC-V ) arch=riscv64 ;;
|
||||||
|
x86_64|*\ X86-64 ) arch=x86_64 ;;
|
||||||
|
* ) arch='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$arch" ]]; then
|
||||||
|
msg2 "detected guest \`/bin/true\` arch: '%s'=>'%s'" "$guest_arch" "$arch"
|
||||||
|
return "$EXIT_SUCCESS"
|
||||||
|
else
|
||||||
|
error "image arch is unknown: '%s'" "$guest_arch"
|
||||||
|
return "$EXIT_FAILURE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_boot() # ( imagefile qemu_args )
|
||||||
|
{
|
||||||
|
local imagefile="$1" ; shift ;
|
||||||
|
local qemu_args=(-no-reboot $@)
|
||||||
|
local pvmboot_cmd=$(pvm_get_pvmboot_cmd)
|
||||||
|
local was_error=$?
|
||||||
|
|
||||||
|
[[ "$pvmboot_cmd" ]] || return $EXIT_FAILURE
|
||||||
|
|
||||||
|
DISPLAY='' "$pvmboot_cmd" "$imagefile" "${qemu_args[@]}" ; was_error=$? ;
|
||||||
|
|
||||||
|
(( ! $was_error )) && return $EXIT_SUCCESS || return $EXIT_FAILURE
|
||||||
|
}
|
@ -19,10 +19,9 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# shellcheck source=/usr/lib/libretools/messages.sh
|
|
||||||
source "$(librelib messages)"
|
|
||||||
|
|
||||||
usage() {
|
usage()
|
||||||
|
{
|
||||||
print "USAGE:"
|
print "USAGE:"
|
||||||
print " pvm2tarball [-h] [-o <FILENAME>] <IMG>"
|
print " pvm2tarball [-h] [-o <FILENAME>] <IMG>"
|
||||||
echo
|
echo
|
||||||
@ -41,78 +40,16 @@ usage() {
|
|||||||
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
||||||
}
|
}
|
||||||
|
|
||||||
pvm_mount() {
|
main()
|
||||||
if file "$imagefile" | grep -q ' DOS/MBR '; then
|
{
|
||||||
msg "mounting filesystems"
|
pvm_check_unprivileged # exits on failure
|
||||||
else
|
|
||||||
error "%s: does not seem to be a raw qemu image." "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
trap 'pvm_umount' INT TERM EXIT
|
|
||||||
|
|
||||||
workdir="$(mktemp -d -t pvm-XXXXXXXXXX)" || return
|
|
||||||
loopdev="$(sudo losetup -fLP --show "$imagefile")" || return
|
|
||||||
|
|
||||||
# find the root partition
|
|
||||||
local part rootpart bootpart
|
|
||||||
for part in "$loopdev"p*; do
|
|
||||||
sudo mount "$part" "$workdir" || continue
|
|
||||||
if [ -f "$workdir"/etc/fstab ]; then
|
|
||||||
rootpart="$part"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sudo umount "$workdir"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$rootpart" ]; then
|
|
||||||
msg "found root filesystem partition: %s" "$rootpart"
|
|
||||||
else
|
|
||||||
error "%s: unable to determine root partition." "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# find the boot partition
|
|
||||||
if (( $(find /boot/ -name initramfs-* | wc -l) > 0 )) && \
|
|
||||||
(( $(find /boot/ -name vmlinuz-* | wc -l) > 0 )); then
|
|
||||||
msg "found /boot on root filesystem partition"
|
|
||||||
else
|
|
||||||
bootpart="$(findmnt -senF "$workdir"/etc/fstab /boot | awk '{print $2}')"
|
|
||||||
|
|
||||||
if [ -n "$bootpart" ]; then
|
|
||||||
# mount and be happy
|
|
||||||
msg "found boot filesystem partition: %s" "$bootpart"
|
|
||||||
sudo mount "$bootpart" "$workdir"/boot || return "$EXIT_FAILURE"
|
|
||||||
else
|
|
||||||
error "%s: unable to determine boot filesystem partition." "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
pvm_umount() {
|
|
||||||
msg "un-mounting filesystems"
|
|
||||||
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
|
|
||||||
[ -n "$workdir" ] && (sudo umount -R "$workdir"; rmdir "$workdir")
|
|
||||||
unset workdir
|
|
||||||
[ -n "$loopdev" ] && sudo losetup -d "$loopdev"
|
|
||||||
unset loopdev
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
|
||||||
error "This program must be run as a regular user"
|
|
||||||
exit "$EXIT_NOPERMISSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# parse options
|
# parse options
|
||||||
local output
|
local outfile
|
||||||
while getopts 'ho:' arg; do
|
while getopts 'ho:' arg; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
h) usage; return "$EXIT_SUCCESS";;
|
h) usage; return "$EXIT_SUCCESS";;
|
||||||
o) output="$OPTARG";;
|
o) outfile="$OPTARG";;
|
||||||
*) error "invalid argument: %s\n" "$arg"; usage >&2; exit "$EXIT_INVALIDARGUMENT";;
|
*) error "invalid argument: %s\n" "$arg"; usage >&2; exit "$EXIT_INVALIDARGUMENT";;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@ -124,29 +61,16 @@ main() {
|
|||||||
image_filename="$(basename "$imagefile")"
|
image_filename="$(basename "$imagefile")"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
# check for input file presence
|
|
||||||
if [ ! -e "$imagefile" ]; then
|
|
||||||
error "%s: file not found" "$imagefile"
|
|
||||||
exit "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# determine output file
|
# determine output file
|
||||||
[ -n "$output" ] || output="${image_filename%.img*}.tar.gz"
|
[ -n "$outfile" ] || outfile="$(dirname $imagefile)/${image_filename%.img*}.tar.gz"
|
||||||
|
|
||||||
# check for output file presence
|
# ensure that the image file exists, prompt to clobber existing output file
|
||||||
if [ -e "$output" ]; then
|
pvm_check_file_exists_and_writable "$imagefile" || exit "$EXIT_FAILURE"
|
||||||
warning "%s: file exists. Continue? [y/N]" "$output"
|
pvm_prompt_clobber_file "$outfile" || exit "$EXIT_FAILURE"
|
||||||
read -p " " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
exit "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
rm -f "$output" || exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# mount the root filesystem
|
# mount the root filesystem
|
||||||
local workdir loopdev
|
local bootdir workdir loopdev
|
||||||
pvm_mount || exit
|
pvm_mount || exit "$EXIT_FAILURE" # assumes: $imagefile , sets: $loopdev $bootdir $workdir
|
||||||
|
|
||||||
# tar the root filesystem, excluding unneeded things
|
# tar the root filesystem, excluding unneeded things
|
||||||
# HACKING:
|
# HACKING:
|
||||||
@ -156,7 +80,7 @@ main() {
|
|||||||
#
|
#
|
||||||
# `tar -tf <tarball> | sort`
|
# `tar -tf <tarball> | sort`
|
||||||
msg "imploding tarball"
|
msg "imploding tarball"
|
||||||
sudo tar -c -f "$output" -C "$workdir" -X - . << EOF
|
sudo tar -c -f "$outfile" -C "$workdir" -X - . << EOF
|
||||||
./boot/lost+found
|
./boot/lost+found
|
||||||
./etc/.updated
|
./etc/.updated
|
||||||
./etc/pacman.d/gnupg
|
./etc/pacman.d/gnupg
|
||||||
@ -169,10 +93,15 @@ main() {
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# give the archive back to the user
|
# give the archive back to the user
|
||||||
sudo chown "$(id -u)":"$(id -g)" "$output"
|
sudo chown "$(id -u)":"$(id -g)" "$outfile"
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
pvm_umount
|
pvm_cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
if source /usr/lib/parabola-vmbootstrap/pvm-common.sh.inc 2> /dev/null || \
|
||||||
|
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"/pvm-common.sh.inc 2> /dev/null
|
||||||
|
then main "$@"
|
||||||
|
else echo "can not find pvm-common.sh.inc" && exit 1
|
||||||
|
fi
|
||||||
|
226
src/pvmboot.sh
226
src/pvmboot.sh
@ -19,8 +19,6 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# shellcheck source=/usr/lib/libretools/messages.sh
|
|
||||||
source "$(librelib messages)"
|
|
||||||
|
|
||||||
readonly DEF_KERNEL='linux-libre' # ASSERT: must be 'linux-libre', per 'parabola-base'
|
readonly DEF_KERNEL='linux-libre' # ASSERT: must be 'linux-libre', per 'parabola-base'
|
||||||
readonly DEF_RAM_MB=1000
|
readonly DEF_RAM_MB=1000
|
||||||
@ -29,14 +27,16 @@ Kernel=$DEF_KERNEL
|
|||||||
RedirectSerial=0
|
RedirectSerial=0
|
||||||
|
|
||||||
|
|
||||||
usage() {
|
usage()
|
||||||
|
{
|
||||||
print "USAGE:"
|
print "USAGE:"
|
||||||
print " pvmboot [-h] [-k <kernel>] [-r] <img> [qemu-args ...]"
|
print " pvmboot [-h] [-k <kernel>] [-r] <img> [qemu-args ...]"
|
||||||
echo
|
echo
|
||||||
prose "Determine the architecture of <img> and boot it using qemu. <img> is assumed
|
prose "Determine the architecture of <img> and boot it using qemu. <img> is assumed
|
||||||
to be a valid, raw-formatted parabola virtual machine image, ideally
|
to be a valid, raw-formatted parabola virtual machine image, ideally
|
||||||
created using pvmbootstrap. The started instances are assigned
|
created using pvmbootstrap. If the image was not created using pvmbootstrap,
|
||||||
${DEF_RAM_MB}MB of RAM and one SMP core."
|
the boot partition must be vfat or ext2, and the root partition must be ext4
|
||||||
|
The machine instance is assigned ${DEF_RAM_MB}MB of RAM and one SMP core."
|
||||||
echo
|
echo
|
||||||
prose "When a graphical desktop environment is available, start the machine
|
prose "When a graphical desktop environment is available, start the machine
|
||||||
normally, otherwise append -nographic to the qemu options. This behavior
|
normally, otherwise append -nographic to the qemu options. This behavior
|
||||||
@ -63,176 +63,120 @@ usage() {
|
|||||||
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
||||||
}
|
}
|
||||||
|
|
||||||
pvm_mount() {
|
|
||||||
if ! file "$imagefile" | grep -q ' DOS/MBR '; then
|
|
||||||
error "%s: does not seem to be a raw qemu image." "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg "mounting filesystems"
|
pvm_guess_qemu_cmd() # assumes: $arch , sets: $qemu_cmd
|
||||||
trap 'pvm_umount' INT TERM EXIT
|
{
|
||||||
|
|
||||||
workdir="$(mktemp -d -t pvm-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
|
||||||
loopdev="$(sudo losetup -fLP --show "$imagefile")" || return "$EXIT_FAILURE"
|
|
||||||
sudo mount "$loopdev"p1 "$workdir" || \
|
|
||||||
sudo mount "$loopdev"p2 "$workdir" || return "$EXIT_FAILURE"
|
|
||||||
}
|
|
||||||
|
|
||||||
pvm_umount() {
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
|
|
||||||
[ -n "$workdir" ] && (sudo umount "$workdir"; rmdir "$workdir")
|
|
||||||
[ -n "$loopdev" ] && sudo losetup -d "$loopdev"
|
|
||||||
unset workdir
|
|
||||||
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" "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# attempt to get kernel arch from elf header
|
|
||||||
arch="$(readelf -h "$kernel" 2>/dev/null | grep Machine | awk '{print $2}')"
|
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
PowerPC64) arch=ppc64 ; return "$EXIT_SUCCESS" ;;
|
armv7h ) qemu_cmd="qemu-system-arm" ;;
|
||||||
RISC-V ) arch=riscv64 ; return "$EXIT_SUCCESS" ;;
|
i686 ) qemu_cmd="qemu-system-i386" ;;
|
||||||
* ) arch="" ;;
|
ppc64le) qemu_cmd="qemu-system-ppc64" ;;
|
||||||
|
riscv64) qemu_cmd="qemu-system-riscv64" ;;
|
||||||
|
x86_64 ) qemu_cmd="qemu-system-x86_64" ;;
|
||||||
|
* ) error "unknown image arch: '%s'" "$arch" ; return "$EXIT_FAILURE" ;;
|
||||||
esac
|
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 "$EXIT_SUCCESS" ;;
|
|
||||||
i386:*) arch=x86_64 ; return "$EXIT_SUCCESS" ;;
|
|
||||||
* ) arch="" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# attempt to get kernel arch from file magic
|
|
||||||
arch="$(file "$kernel")"
|
|
||||||
case "$arch" in
|
|
||||||
*"ARM boot executable"*) arch=arm ; return "$EXIT_SUCCESS" ;;
|
|
||||||
* ) arch="" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# no more ideas; giving up.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pvm_native_arch() {
|
pvm_guess_qemu_args() # assumes: $qemu_args $imagefile $arch $bootdir , appends: $qemu_args
|
||||||
local arch
|
{
|
||||||
|
msg "configuring the virtual machine ($arch)"
|
||||||
|
|
||||||
case "$1" in
|
qemu_args+=(-m $DEF_RAM_MB )
|
||||||
arm*) arch=armv7l ;;
|
|
||||||
* ) arch="$1" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
setarch "$arch" /bin/true 2>/dev/null || return
|
# optional large qemu disk
|
||||||
}
|
qemu_args+=( $( [[ -w $DATA_IMG ]] && echo "-hdb $DATA_IMG" ) )
|
||||||
|
|
||||||
pvm_guess_qemu_args() {
|
|
||||||
# if we're not running on X / wayland, disable graphics
|
# if we're not running on X / wayland, disable graphics
|
||||||
if [ -z "$DISPLAY" ]; then qemu_args+=(-nographic);
|
if [ -z "$DISPLAY" ]; then qemu_args+=(-nographic);
|
||||||
elif (( ${RedirectSerial} )); then qemu_args+=(-serial "mon:stdio");
|
elif (( ${RedirectSerial} )); then qemu_args+=(-serial "mon:stdio");
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# find root filesystem partition
|
||||||
|
local root_part_n
|
||||||
|
pvm_find_root_part_n "$imagefile" || return "$EXIT_FAILURE" # sets: $root_part_n
|
||||||
|
|
||||||
# if we're running a supported arch, enable kvm
|
# if we're running a supported arch, enable kvm
|
||||||
if pvm_native_arch "$arch"; then qemu_args+=(-enable-kvm); fi
|
if pvm_native_arch "$arch"; then qemu_args+=(-enable-kvm); fi
|
||||||
|
|
||||||
# find root filesystem partition (necessary for arches without bootloader)
|
|
||||||
local root_loopdev_n=$(echo $(parted "$imagefile" print 2> /dev/null | grep ext4) | cut -d ' ' -f 1)
|
|
||||||
local root_loopdev="$loopdev"p$root_loopdev_n
|
|
||||||
local root_vdev=/dev/vda$root_loopdev_n
|
|
||||||
if [[ -b "$root_loopdev" ]]
|
|
||||||
then
|
|
||||||
msg "found root filesystem loop device: %s" "$root_loopdev"
|
|
||||||
else
|
|
||||||
error "%s: unable to determine root filesystem loop device" "$imagefile"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set arch-specific args
|
# set arch-specific args
|
||||||
local kernel_console
|
local kernel_tty
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
i386|x86_64|ppc64)
|
armv7h ) kernel_tty="console=tty0 console=ttyAMA0 " ;;
|
||||||
qemu_args+=(-m $DEF_RAM_MB -hda "$imagefile")
|
i686 ) kernel_tty=$( [[ -z "$DISPLAY" ]] && echo "console=ttyS0 " ) ;;
|
||||||
# unmount the unneeded virtual drive early
|
ppc64le) ;; # TODO:
|
||||||
pvm_umount ;;
|
riscv64) ;; # TODO:
|
||||||
arm)
|
x86_64 ) kernel_tty=$( [[ -z "$DISPLAY" ]] && echo "console=ttyS0 " ) ;;
|
||||||
kernel_console="console=tty0 console=ttyAMA0 "
|
esac
|
||||||
qemu_args+=(-machine virt
|
case "$arch" in
|
||||||
-m $DEF_RAM_MB
|
armv7h ) qemu_args+=(-machine virt
|
||||||
-kernel "$workdir"/vmlinuz-${Kernel}
|
-kernel "$bootdir"/vmlinuz-${Kernel}
|
||||||
-initrd "$workdir"/initramfs-${Kernel}.img
|
-initrd "$bootdir"/initramfs-${Kernel}.img
|
||||||
-append "${kernel_console}rw root=${root_vdev}"
|
-append "${kernel_tty}rw root=/dev/vda$root_part_n"
|
||||||
-drive "if=none,file=${imagefile},format=raw,id=hd"
|
-drive "if=none,file=${imagefile},format=raw,id=hd"
|
||||||
-device "virtio-blk-device,drive=hd"
|
-device "virtio-blk-device,drive=hd"
|
||||||
-netdev "user,id=mynet"
|
-netdev "user,id=mynet"
|
||||||
-device "virtio-net-device,netdev=mynet") ;;
|
-device "virtio-net-device,netdev=mynet") ;;
|
||||||
riscv64)
|
i686 ) qemu_args+=(-hda "$imagefile") ;;
|
||||||
kernel_console=$( [ -z "$DISPLAY" ] && echo "console=ttyS0 " )
|
ppc64le) qemu_args+=(-hda " $imagefile") ;;
|
||||||
qemu_args+=(-machine virt
|
riscv64) qemu_args+=(-machine virt
|
||||||
-m $DEF_RAM_MB
|
-kernel "$bootdir"/bbl
|
||||||
-kernel "$workdir"/bbl
|
-append "${kernel_tty}rw root=/dev/vda"
|
||||||
-append "${kernel_console}rw root=/dev/vda"
|
-drive "file=/dev/vda$root_part_n,format=raw,id=hd0"
|
||||||
-drive "file=${root_vdev},format=raw,id=hd0"
|
-device "virtio-blk-device,drive=hd0"
|
||||||
-device "virtio-blk-device,drive=hd0"
|
-object "rng-random,filename=/dev/urandom,id=rng0"
|
||||||
-object "rng-random,filename=/dev/urandom,id=rng0"
|
-device "virtio-rng-device,rng=rng0"
|
||||||
-device "virtio-rng-device,rng=rng0"
|
-netdev "user,id=usernet"
|
||||||
-netdev "user,id=usernet"
|
-device "virtio-net-device,netdev=usernet") ;;
|
||||||
-device "virtio-net-device,netdev=usernet") ;;
|
x86_64 ) qemu_args+=(-hda "$imagefile") ;;
|
||||||
*)
|
|
||||||
error "%s: unable to determine default qemu args" "$imagefile"
|
|
||||||
return "$EXIT_FAILURE" ;;
|
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() # ( [cli_options] imagefile qemu_args )
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
{
|
||||||
error "This program must be run as a regular user"
|
pvm_check_unprivileged # exits on failure
|
||||||
exit "$EXIT_NOPERMISSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# parse options
|
# parse options
|
||||||
while getopts 'hk:r' arg; do
|
while getopts 'hk:r' arg; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
h) usage; return "$EXIT_SUCCESS";;
|
h) usage; return "$EXIT_SUCCESS" ;;
|
||||||
k) Kernel="$OPTARG";;
|
k) Kernel="$OPTARG" ;;
|
||||||
r) RedirectSerial=1;;
|
r) RedirectSerial=1 ;;
|
||||||
*) error "invalid argument: %s\n" "$arg"; usage >&2; exit "$EXIT_INVALIDARGUMENT";;
|
*) error "invalid argument: %s\n" "$arg"; usage >&2; exit "$EXIT_INVALIDARGUMENT" ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
local shiftlen=$(( OPTIND - 1 ))
|
local shiftlen=$(( OPTIND - 1 )) ; shift $shiftlen ;
|
||||||
shift $shiftlen
|
local imagefile="$1" ; shift ;
|
||||||
local imagefile="$1"
|
local cli_args=$@
|
||||||
shift
|
[ ! -n "$imagefile" ] && error "no image file specified" && exit "$EXIT_FAILURE"
|
||||||
[ ! -n "$imagefile" ] && error "no image file specified" && exit "$EXIT_FAILURE"
|
[ ! -e "$imagefile" ] && error "image file not found: '%s'" "$imagefile" && exit "$EXIT_FAILURE"
|
||||||
[ ! -e "$imagefile" ] && error "image file not found: '%s'" "$imagefile" && exit "$EXIT_FAILURE"
|
[ ! -w "$imagefile" ] && error "image file not writable: %s" "$imagefile" && exit "$EXIT_FAILURE"
|
||||||
|
|
||||||
msg "initializing ...."
|
msg "initializing ...."
|
||||||
local workdir loopdev
|
local bootdir workdir loopdev
|
||||||
pvm_mount || exit
|
|
||||||
|
|
||||||
local arch
|
local arch
|
||||||
pvm_probe_arch || exit
|
local qemu_cmd
|
||||||
if [ -z "$arch" ]; then
|
|
||||||
error "image arch is unknown: '%s'" "$arch"
|
|
||||||
exit "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local qemu_args=()
|
local qemu_args=()
|
||||||
pvm_guess_qemu_args || exit
|
local was_error
|
||||||
qemu_args+=("$@")
|
pvm_mount || exit "$EXIT_FAILURE" # assumes: $imagefile , sets: $loopdev $bootdir $workdir
|
||||||
|
pvm_probe_arch || exit "$EXIT_FAILURE" # assumes: $bootdir $workdir $imagefile , sets: $arch
|
||||||
|
pvm_guess_qemu_cmd || exit "$EXIT_FAILURE" # assumes: $arch , sets: $qemu_cmd
|
||||||
|
pvm_guess_qemu_args || exit "$EXIT_FAILURE" # assumes: $qemu_args $imagefile $arch $bootdir , appends: $qemu_args
|
||||||
|
|
||||||
msg "booting VM ...."
|
# unmount the virtual disks early, for images with a bootloader
|
||||||
(set -x; qemu-system-"$arch" "${qemu_args[@]}")
|
[[ "$arch" =~ ^i686$|^x86_64$|^ppc64le$ ]] && pvm_cleanup
|
||||||
|
|
||||||
|
msg "booting the virtual machine ...."
|
||||||
|
(set -x; $qemu_cmd "${qemu_args[@]}" $cli_args) ; was_error=$? ;
|
||||||
|
|
||||||
# clean up the terminal, in case SeaBIOS did something weird
|
# clean up the terminal, in case SeaBIOS did something weird
|
||||||
echo -n "[?7h[0m"
|
echo -n "[?7h[0m"
|
||||||
pvm_umount
|
pvm_cleanup
|
||||||
|
|
||||||
|
(( ! $was_error )) && exit "$EXIT_SUCCESS" || exit "$EXIT_FAILURE"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
if source /usr/lib/parabola-vmbootstrap/pvm-common.sh.inc 2> /dev/null || \
|
||||||
|
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"/pvm-common.sh.inc 2> /dev/null
|
||||||
|
then main "$@"
|
||||||
|
else echo "can not find pvm-common.sh.inc" && exit 1
|
||||||
|
fi
|
||||||
|
@ -20,10 +20,6 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
# shellcheck source=/usr/lib/libretools/messages.sh
|
|
||||||
source "$(librelib messages)"
|
|
||||||
|
|
||||||
|
|
||||||
# defaults
|
# defaults
|
||||||
readonly PKG_SET_MIN='minimal'
|
readonly PKG_SET_MIN='minimal'
|
||||||
readonly PKG_SET_STD='standard'
|
readonly PKG_SET_STD='standard'
|
||||||
@ -34,16 +30,22 @@ readonly DEV_PKGS=('base' 'parabola-base' 'base-devel') ; readonly ROOT_MB_DEV=1
|
|||||||
readonly DEF_PKGS=(${STD_PKGS[@]} ) ; readonly DEF_MIN_MB=$ROOT_MB_STD ;
|
readonly DEF_PKGS=(${STD_PKGS[@]} ) ; readonly DEF_MIN_MB=$ROOT_MB_STD ;
|
||||||
readonly DEF_KERNEL='linux-libre' # ASSERT: must be 'linux-libre', per 'parabola-base'
|
readonly DEF_KERNEL='linux-libre' # ASSERT: must be 'linux-libre', per 'parabola-base'
|
||||||
readonly DEF_MIRROR=https://repo.parabola.nu
|
readonly DEF_MIRROR=https://repo.parabola.nu
|
||||||
readonly DEF_ROOT_MB=64000
|
readonly DEF_ROOT_MB=32000
|
||||||
readonly DEF_BOOT_MB=100
|
readonly DEF_BOOT_MB=100
|
||||||
readonly DEF_SWAP_MB=0
|
readonly DEF_SWAP_MB=0
|
||||||
|
readonly MANDATORY_PKGS_ALL=( )
|
||||||
|
readonly MANDATORY_PKGS_armv7h=( haveged net-tools )
|
||||||
|
readonly MANDATORY_PKGS_i686=( haveged net-tools grub )
|
||||||
|
readonly MANDATORY_PKGS_ppc64le=( haveged net-tools )
|
||||||
|
readonly MANDATORY_PKGS_riscv64=( )
|
||||||
|
readonly MANDATORY_PKGS_x86_64=( haveged net-tools grub )
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
readonly THIS_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
|
||||||
readonly GUEST_CACHED_PKGS=('ca-certificates-utils')
|
readonly GUEST_CACHED_PKGS=('ca-certificates-utils')
|
||||||
|
readonly PVM_HOOKS_SUCCESS_MSG="[hooks.sh] pre-init hooks successful"
|
||||||
|
|
||||||
# options
|
# options
|
||||||
BasePkgSet=$PKG_SET_STD
|
BasePkgSet=$DEF_PKG_SET
|
||||||
MinRootMb=$DEF_MIN_MB
|
MinRootMb=$DEF_MIN_MB
|
||||||
Hooks=()
|
Hooks=()
|
||||||
Kernels=()
|
Kernels=()
|
||||||
@ -57,7 +59,8 @@ SwapSizeMb=$DEF_SWAP_MB
|
|||||||
HasSwap=0
|
HasSwap=0
|
||||||
|
|
||||||
|
|
||||||
usage() {
|
usage()
|
||||||
|
{
|
||||||
print "USAGE:"
|
print "USAGE:"
|
||||||
print " pvmbootstrap [-b <base-set>] [-h] [-H <hook>] [-k <kernel>] [-M <mirror>]"
|
print " pvmbootstrap [-b <base-set>] [-h] [-H <hook>] [-k <kernel>] [-M <mirror>]"
|
||||||
print " [-O] [-p <package>] [-s <root_size>] [-S <swap_size>]"
|
print " [-O] [-p <package>] [-s <root_size>] [-S <swap_size>]"
|
||||||
@ -110,27 +113,26 @@ usage() {
|
|||||||
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
echo " <https://git.parabola.nu/parabola-vmbootstrap.git>"
|
||||||
}
|
}
|
||||||
|
|
||||||
pvm_native_arch() {
|
pvm_bootstrap() # assumes: $arch $imagefile $loopdev $workdir , traps: INT TERM RETURN
|
||||||
local arch=$( [[ "$1" =~ arm.* ]] && echo 'armv7l' || echo "$1" )
|
{
|
||||||
|
# prompt to clobber if the target output file already exists
|
||||||
|
pvm_check_no_mounts || return "$EXIT_FAILURE"
|
||||||
|
mkdir -p "$(dirname "$imagefile")" || return "$EXIT_FAILURE"
|
||||||
|
pvm_prompt_clobber_file "$imagefile" || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
setarch "$arch" /bin/true 2>/dev/null || return "$EXIT_FAILURE"
|
msg "starting build for %s image: %s" "$arch" "$imagefile"
|
||||||
}
|
|
||||||
|
|
||||||
pvm_bootstrap() {
|
|
||||||
msg "starting creation of %s image: %s" "$arch" "$imagefile"
|
|
||||||
|
|
||||||
# create the raw image file
|
# create the raw image file
|
||||||
local img_mb=$(( $BootSizeMb + $SwapSizeMb + $RootSizeMb ))
|
local img_mb=$(( $BootSizeMb + $SwapSizeMb + $RootSizeMb ))
|
||||||
qemu-img create -f raw "$imagefile" "${img_mb}M" || return "$EXIT_FAILURE"
|
qemu-img create -f raw "$imagefile" "${img_mb}M" || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
# prepare for cleanup
|
# prepare for cleanup
|
||||||
trap 'pvm_cleanup' INT TERM RETURN
|
trap 'pvm_bootstrap_cleanup' INT TERM RETURN
|
||||||
|
|
||||||
# mount the virtual disk
|
# mount the virtual disk
|
||||||
local workdir loopdev
|
local bootdir workdir loopdev
|
||||||
workdir="$(mktemp -d -t pvm-rootfs-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
pvm_setup_loopdev || return "$EXIT_FAILURE" # sets: $bootdir $workdir $loopdev
|
||||||
loopdev="$(sudo losetup -fLP --show "$imagefile")" || return "$EXIT_FAILURE"
|
sudo dd if=/dev/zero of="$loopdev" bs=1M count=8 || return "$EXIT_FAILURE"
|
||||||
sudo dd if=/dev/zero of="$loopdev" bs=1M count=8 || return "$EXIT_FAILURE"
|
|
||||||
|
|
||||||
# partition
|
# partition
|
||||||
local boot_begin="$( [[ "$arch" =~ i686|x86_64 ]] && echo 2 || echo 1 )MiB"
|
local boot_begin="$( [[ "$arch" =~ i686|x86_64 ]] && echo 2 || echo 1 )MiB"
|
||||||
@ -202,20 +204,19 @@ pvm_bootstrap() {
|
|||||||
|
|
||||||
# setup qemu-user-static, if necessary
|
# setup qemu-user-static, if necessary
|
||||||
if ! pvm_native_arch "$arch"; then
|
if ! pvm_native_arch "$arch"; then
|
||||||
# target arch can't execute natively, pacstrap is going to need help by qemu
|
|
||||||
local qemu_arch
|
local qemu_arch
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
armv7h) qemu_arch=arm ;;
|
armv7h) qemu_arch=arm ;;
|
||||||
* ) qemu_arch="$arch" ;;
|
* ) qemu_arch="$arch" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local qemu_user_static=$(sudo grep -l -F -e "interpreter /usr/bin/qemu-$qemu_arch-" \
|
local qemu_static=$(sudo grep -l -F -e "interpreter /usr/bin/qemu-$qemu_arch-" \
|
||||||
-r -- /proc/sys/fs/binfmt_misc 2>/dev/null | \
|
-r -- /proc/sys/fs/binfmt_misc 2>/dev/null | \
|
||||||
xargs -r sudo grep -xF 'enabled' )
|
xargs -r sudo grep -xF 'enabled' )
|
||||||
if [[ -n "$qemu_user_static" ]]; then
|
if [[ -n "$qemu_static" ]]; then
|
||||||
msg "found qemu-user-static for %s" "$arch"
|
msg "found qemu-user-static for arch: '%s'" "$qemu_arch"
|
||||||
else
|
else
|
||||||
error "missing qemu-user-static for %s" "$arch"
|
error "missing qemu-user-static for arch: '%s'" "$qemu_arch"
|
||||||
return "$EXIT_FAILURE"
|
return "$EXIT_FAILURE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -224,9 +225,8 @@ pvm_bootstrap() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# prepare pacstrap config
|
# prepare pacstrap config
|
||||||
local pacconf repos
|
local pacconf="$(mktemp -t pvm-pacconf-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
||||||
pacconf="$(mktemp -t pvm-pacconf-XXXXXXXXXX)" || return "$EXIT_FAILURE"
|
local repos=(libre core extra community pcr)
|
||||||
repos=(libre core extra community pcr)
|
|
||||||
(( $IsNonsystemd )) && repos=('nonsystemd' ${repos[@]})
|
(( $IsNonsystemd )) && repos=('nonsystemd' ${repos[@]})
|
||||||
echo -e "[options]\nArchitecture = $arch" > "$pacconf"
|
echo -e "[options]\nArchitecture = $arch" > "$pacconf"
|
||||||
for repo in ${repos[@]}; do echo "[$repo]" >> "$pacconf";
|
for repo in ${repos[@]}; do echo "[$repo]" >> "$pacconf";
|
||||||
@ -234,15 +234,17 @@ pvm_bootstrap() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# prepare package lists
|
# prepare package lists
|
||||||
local kernels=( ${Kernels[@]} )
|
local kernels=( ${Kernels[@]} )
|
||||||
local pkgs=( ${Pkgs[@]} ${Kernels[@]} ${OptPkgs[@]} )
|
local pkgs=( ${Pkgs[@]} ${Kernels[@]} ${OptPkgs[@]} ${MANDATORY_PKGS_ALL[@]} )
|
||||||
local pkgs_cached=( ${GUEST_CACHED_PKGS[@]} )
|
local pkgs_cached=( ${GUEST_CACHED_PKGS[@]} )
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
i686|x86_64) pkgs+=(grub) ;;
|
armv7h ) pkgs+=( ${MANDATORY_PKGS_armv7h[@]} ) ;;
|
||||||
riscv64 ) ;;
|
i686 ) pkgs+=( ${MANDATORY_PKGS_i686[@]} ) ;;
|
||||||
* ) pkgs+=(haveged net-tools) ;;
|
ppc64le) pkgs+=( ${MANDATORY_PKGS_ppc64le[@]} ) ;;
|
||||||
|
riscv64) pkgs+=( ${MANDATORY_PKGS_riscv64[@]} ) ;;
|
||||||
|
x86_64 ) pkgs+=( ${MANDATORY_PKGS_x86_64[@]} ) ;;
|
||||||
esac
|
esac
|
||||||
(( $IsNonsystemd )) && && pkgs+=(libelogind)
|
(( $IsNonsystemd )) && [[ "$BasePkgSet" == "$PKG_SET_MIN" ]] && pkgs+=(libelogind)
|
||||||
(( ! $IsNonsystemd )) && [[ "${Hooks[@]}" =~ hook-ethernet-dhcp.sh ]] && pkgs+=(dhcpcd)
|
(( ! $IsNonsystemd )) && [[ "${Hooks[@]}" =~ hook-ethernet-dhcp.sh ]] && pkgs+=(dhcpcd)
|
||||||
|
|
||||||
# minimize package lists
|
# minimize package lists
|
||||||
@ -254,6 +256,9 @@ pvm_bootstrap() {
|
|||||||
msg "installing packages into the work chroot"
|
msg "installing packages into the work chroot"
|
||||||
sudo pacstrap -GMc -C "$pacconf" "$workdir" "${pkgs[@]}" || return "$EXIT_FAILURE"
|
sudo pacstrap -GMc -C "$pacconf" "$workdir" "${pkgs[@]}" || return "$EXIT_FAILURE"
|
||||||
sudo pacstrap -GM -C "$pacconf" "$workdir" "${pkgs_cached[@]}" || return "$EXIT_FAILURE"
|
sudo pacstrap -GM -C "$pacconf" "$workdir" "${pkgs_cached[@]}" || return "$EXIT_FAILURE"
|
||||||
|
msg2 "creating a list of installed packages"
|
||||||
|
pacman -Sl -r "$workdir/" --config "$pacconf" | \
|
||||||
|
awk '/\[installed\]$/ {print $1 "/" $2 "-" $3}' > $(dirname $imagefile)/pkglist.txt
|
||||||
|
|
||||||
# create an fstab
|
# create an fstab
|
||||||
msg "generating /etc/fstab"
|
msg "generating /etc/fstab"
|
||||||
@ -270,13 +275,16 @@ pvm_bootstrap() {
|
|||||||
local hostname='parabola'
|
local hostname='parabola'
|
||||||
local lang='en_US.UTF-8'
|
local lang='en_US.UTF-8'
|
||||||
msg "configuring system envoronment"
|
msg "configuring system envoronment"
|
||||||
echo "/etc/hostname: " ; echo $hostname | sudo tee "$workdir"/etc/hostname ;
|
echo -n "/etc/hostname: " ; echo $hostname | sudo tee "$workdir"/etc/hostname ;
|
||||||
echo "/etc/locale.conf: " ; echo "LANG=$lang" | sudo tee "$workdir"/etc/locale.conf ;
|
echo -n "/etc/locale.conf: " ; echo "LANG=$lang" | sudo tee "$workdir"/etc/locale.conf ;
|
||||||
sudo sed -i "s/#${lang}/${lang}/" "$workdir"/etc/locale.gen
|
sudo sed -i "s/#${lang}/${lang}/" "$workdir"/etc/locale.gen
|
||||||
|
|
||||||
# install a boot loader
|
# install a boot loader
|
||||||
msg "installing boot loader"
|
msg "installing boot loader"
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
|
armv7h)
|
||||||
|
msg2 "(armv7h has no boot loader)"
|
||||||
|
;;
|
||||||
i686|x86_64)
|
i686|x86_64)
|
||||||
local grub_def_file="$workdir"/etc/default/grub
|
local grub_def_file="$workdir"/etc/default/grub
|
||||||
local grub_cfg_file=/boot/grub/grub.cfg
|
local grub_cfg_file=/boot/grub/grub.cfg
|
||||||
@ -292,26 +300,26 @@ pvm_bootstrap() {
|
|||||||
sudo arch-chroot "$workdir" grub-install "$loopdev" || return "$EXIT_FAILURE"
|
sudo arch-chroot "$workdir" grub-install "$loopdev" || return "$EXIT_FAILURE"
|
||||||
sudo arch-chroot "$workdir" grub-mkconfig -o $grub_cfg_file || return "$EXIT_FAILURE"
|
sudo arch-chroot "$workdir" grub-mkconfig -o $grub_cfg_file || return "$EXIT_FAILURE"
|
||||||
;;
|
;;
|
||||||
armv7h)
|
ppc64le)
|
||||||
echo "(armv7h has no boot loader)"
|
msg2 "(ppc64le has no boot loader)"
|
||||||
;;
|
;;
|
||||||
riscv64)
|
riscv64)
|
||||||
# FIXME: for the time being, use fedora bbl to boot
|
# FIXME: for the time being, use berkeley bootloader to boot
|
||||||
warning "(riscv64 requires a blob - downloading it now)"
|
if [[ -f /usr/lib/parabola-vmbootstrap/bbl ]]; then
|
||||||
local bbl_url=https://fedorapeople.org/groups/risc-v/disk-images/bbl
|
cp /usr/lib/parabola-vmbootstrap/bbl "$workdir"/boot/
|
||||||
sudo wget $bbl_url -O "$workdir"/boot/bbl || return "$EXIT_FAILURE"
|
else
|
||||||
;;
|
error "riscv64 requires the berkeley bootloader from the 'parabola-vmbootstrap' package"
|
||||||
ppc64le)
|
return "$EXIT_FAILURE"
|
||||||
# FIXME: what about ppc64le?
|
fi
|
||||||
echo "(ppc64le has no boot loader)"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# regenerate the initcpio(s), skipping the autodetect hook
|
# regenerate the initcpio(s), to skip the 'autodetect' hook
|
||||||
for kernel in ${Kernels[@]}
|
for kernel in ${Kernels[@]}
|
||||||
do
|
do
|
||||||
local preset_file="$workdir"/etc/mkinitcpio.d/${kernel}.preset
|
local preset_file="$workdir"/etc/mkinitcpio.d/${kernel}.preset
|
||||||
local default_options="default_options=\"-S autodetect\""
|
local default_options="default_options=\"-S autodetect\""
|
||||||
|
|
||||||
msg "regenerating initcpio for kernel: '${kernel}'"
|
msg "regenerating initcpio for kernel: '${kernel}'"
|
||||||
sudo cp "$preset_file"{,.backup} || return "$EXIT_FAILURE"
|
sudo cp "$preset_file"{,.backup} || return "$EXIT_FAILURE"
|
||||||
echo "$default_options" | sudo tee -a "$preset_file" > /dev/null || return "$EXIT_FAILURE"
|
echo "$default_options" | sudo tee -a "$preset_file" > /dev/null || return "$EXIT_FAILURE"
|
||||||
@ -326,19 +334,16 @@ pvm_bootstrap() {
|
|||||||
|
|
||||||
# push hooks into the image
|
# push hooks into the image
|
||||||
msg "preparing hooks"
|
msg "preparing hooks"
|
||||||
sudo mkdir -p "$workdir/root/hooks"
|
sudo mkdir -p "$workdir"/root/hooks
|
||||||
[ "${#Hooks[@]}" -eq 0 ] || sudo cp -v "${Hooks[@]}" "$workdir"/root/hooks/
|
[ "${#Hooks[@]}" -eq 0 ] || sudo cp -v "${Hooks[@]}" "$workdir"/root/hooks/
|
||||||
(( $IsNonsystemd )) && sudo rm "$workdir"/root/hooks/hook-ethernet-dhcp.sh # systemd-only hook
|
(( $IsNonsystemd )) && sudo rm "$workdir"/root/hooks/hook-ethernet-dhcp.sh # systemd-only hook
|
||||||
|
|
||||||
# create a master hook script
|
# create a master hook script
|
||||||
local hooks_success_msg="[hooks.sh] pre-init hooks successful"
|
msg2 "hooks.sh:"
|
||||||
echo "hooks.sh:"
|
|
||||||
sudo tee "$workdir"/root/hooks.sh << EOF
|
sudo tee "$workdir"/root/hooks.sh << EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
echo "[hooks.sh] boot successful - configuring ...."
|
echo "[hooks.sh] boot successful - configuring ...."
|
||||||
|
|
||||||
systemctl disable preinit.service
|
|
||||||
|
|
||||||
# generate the locale
|
# generate the locale
|
||||||
locale-gen
|
locale-gen
|
||||||
|
|
||||||
@ -355,19 +360,20 @@ for hook in /root/hooks/*; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# clean up after yourself
|
# clean up after yourself
|
||||||
|
systemctl disable preinit.service
|
||||||
|
rm -f /root/.bash_history
|
||||||
rm -rf /root/hooks
|
rm -rf /root/hooks
|
||||||
rm -f /root/hooks.sh
|
rm -f /root/hooks.sh
|
||||||
rm -f /usr/lib/systemd/system/preinit.service
|
rm -f /usr/lib/systemd/system/preinit.service
|
||||||
rm -f /var/cache/pacman/pkg/*
|
rm -f /var/cache/pacman/pkg/*
|
||||||
rm -f /root/.bash_history
|
|
||||||
|
|
||||||
# report success :)
|
# report success :)
|
||||||
echo "$hooks_success_msg - powering off"
|
echo "$PVM_HOOKS_SUCCESS_MSG - powering off"
|
||||||
[[ -e "/usr/lib/libretools/common.sh" ]] && rm -f /usr/lib/libretools/common.sh
|
[[ -e "/usr/lib/libretools/common.sh" ]] && rm -f /usr/lib/libretools/common.sh
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# create a pre-init service to run the hooks
|
# create a pre-init service to run the hooks
|
||||||
echo "preinit.service:"
|
msg2 "preinit.service:"
|
||||||
sudo tee "$workdir"/usr/lib/systemd/system/preinit.service << 'EOF'
|
sudo tee "$workdir"/usr/lib/systemd/system/preinit.service << 'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Oneshot VM Preinit
|
Description=Oneshot VM Preinit
|
||||||
@ -394,23 +400,18 @@ EOF
|
|||||||
sudo arch-chroot "$workdir" systemctl enable preinit.service || return "$EXIT_FAILURE"
|
sudo arch-chroot "$workdir" systemctl enable preinit.service || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
# unmount everything
|
# unmount everything
|
||||||
pvm_cleanup
|
pvm_bootstrap_cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
pvm_bootstrap_preinit() # assumes: $imagefile
|
||||||
|
{
|
||||||
|
pvm_check_no_mounts || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
# boot the machine to run the pre-init hooks
|
# boot the machine to run the pre-init hooks
|
||||||
local pvmboot_cmd
|
[[ "$(pvm_get_pvmboot_cmd)" ]] && msg "booting the VM to run the pre-init hooks" || \
|
||||||
local qemu_flags=(-no-reboot)
|
warning "unable to run pre-init hooks"
|
||||||
if [ -f "$THIS_DIR/pvmboot.sh" ]; then # in-tree
|
|
||||||
pvmboot_cmd=("$THIS_DIR/pvmboot.sh")
|
|
||||||
elif type -p pvmboot &>/dev/null; then # installed
|
|
||||||
pvmboot_cmd=('pvmboot')
|
|
||||||
else
|
|
||||||
error "pvmboot not available -- unable to run hooks"
|
|
||||||
return "$EXIT_FAILURE"
|
|
||||||
fi
|
|
||||||
pvmboot_cmd+=("$imagefile" "${qemu_flags[@]}")
|
|
||||||
exec 3>&1
|
exec 3>&1
|
||||||
msg "booting the machine to run the pre-init hooks"
|
pvm_boot "$imagefile" | tee /dev/fd/3 | grep -q -F "$PVM_HOOKS_SUCCESS_MSG"
|
||||||
DISPLAY='' "${pvmboot_cmd[@]}" | tee /dev/fd/3 | grep -q -F "$hooks_success_msg"
|
|
||||||
local res=$?
|
local res=$?
|
||||||
exec 3>&-
|
exec 3>&-
|
||||||
! (( $res )) || error "%s: failed to complete preinit hooks" "$imagefile"
|
! (( $res )) || error "%s: failed to complete preinit hooks" "$imagefile"
|
||||||
@ -418,28 +419,22 @@ EOF
|
|||||||
return $res
|
return $res
|
||||||
}
|
}
|
||||||
|
|
||||||
pvm_cleanup() {
|
pvm_bootstrap_cleanup() # sets: $pacconf , untraps: INT TERM RETURN
|
||||||
|
{
|
||||||
trap - INT TERM RETURN
|
trap - INT TERM RETURN
|
||||||
|
|
||||||
[ -n "${workdir}${loopdev}${pacconf}" ] && msg "cleaning up"
|
[[ "${workdir}${pacconf}" ]] && msg "cleaning up"
|
||||||
|
|
||||||
|
[[ -n "$workdir" ]] && sudo rm -f "$workdir"/usr/bin/qemu-*C
|
||||||
|
[[ -n "$pacconf" ]] && rm -f "$pacconf"
|
||||||
|
pvm_cleanup || return "$EXIT_FAILURE"
|
||||||
|
|
||||||
if [ -n "$workdir" ]; then
|
|
||||||
sudo rm -f "$workdir"/usr/bin/qemu-*C
|
|
||||||
sudo umount -R "$workdir" 2> /dev/null
|
|
||||||
rmdir "$workdir"
|
|
||||||
fi
|
|
||||||
if [ -n "$loopdev" ]; then sudo losetup -d "$loopdev"; fi;
|
|
||||||
if [ -n "$pacconf" ]; then rm -f "$pacconf"; fi;
|
|
||||||
unset workdir
|
|
||||||
unset loopdev
|
|
||||||
unset pacconf
|
unset pacconf
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() # ( [cli_options] imagefile arch )
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
{
|
||||||
error "This program must be run as a regular user"
|
pvm_check_unprivileged # exits on failure
|
||||||
exit "$EXIT_NOPERMISSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# parse options
|
# parse options
|
||||||
while getopts 'b:hH:k:M:Op:s:S:' arg; do
|
while getopts 'b:hH:k:M:Op:s:S:' arg; do
|
||||||
@ -450,28 +445,19 @@ main() {
|
|||||||
Pkgs=(${STD_PKGS[@]}) ; MinRootMb=$ROOT_MB_STD ;;
|
Pkgs=(${STD_PKGS[@]}) ; MinRootMb=$ROOT_MB_STD ;;
|
||||||
$PKG_SET_DEV) BasePkgSet=$OPTARG ; Kernels+=($DEF_KERNEL) ;
|
$PKG_SET_DEV) BasePkgSet=$OPTARG ; Kernels+=($DEF_KERNEL) ;
|
||||||
Pkgs=(${DEV_PKGS[@]}) ; MinRootMb=$ROOT_MB_DEV ;;
|
Pkgs=(${DEV_PKGS[@]}) ; MinRootMb=$ROOT_MB_DEV ;;
|
||||||
* ) warning "%s: invalid base set" "$OPTARG" ;;
|
* ) warning "invalid base set: %s" "$OPTARG" ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
h) usage; return "$EXIT_SUCCESS";;
|
h) usage; return "$EXIT_SUCCESS" ;;
|
||||||
H) if [ -e "$THIS_DIR/hooks/hook-$OPTARG.sh" ]; then # in-tree
|
H) Hooks+=( "$(pvm_get_hook $OPTARG)" ) ;;
|
||||||
Hooks+=("$THIS_DIR/hooks/hook-$OPTARG.sh")
|
k) Kernels+=($OPTARG) ;;
|
||||||
elif [ -e "/usr/lib/libretools/pvmbootstrap/hook-$OPTARG.sh" ]; then # installed
|
M) Mirror="$OPTARG" ;;
|
||||||
Hooks+=("/usr/lib/libretools/pvmbootstrap/hook-$OPTARG.sh")
|
O) IsNonsystemd=0 ;; # TODO:
|
||||||
elif [ -e "$OPTARG" ]; then
|
p) OptPkgs+=($OPTARG) ;;
|
||||||
Hooks+=("$OPTARG")
|
s) RootSizeMb="$(sed 's|[^0-9]||g' <<<$OPTARG)" ;;
|
||||||
else
|
S) SwapSizeMb="$(sed 's|[^0-9]||g' <<<$OPTARG)" ;;
|
||||||
warning "%s: hook does not exist" "$OPTARG"
|
*) error "invalid option: '%s'" "$arg" ; usage >&2 ; exit "$EXIT_INVALIDARGUMENT" ;;
|
||||||
fi ;;
|
|
||||||
k) Kernels+=($OPTARG);;
|
|
||||||
M) Mirror="$OPTARG";;
|
|
||||||
O) IsNonsystemd=0;; # TODO:
|
|
||||||
p) OptPkgs+=($OPTARG);;
|
|
||||||
s) RootSizeMb="$(sed 's|[^0-9]||g' <<<$OPTARG)";;
|
|
||||||
S) SwapSizeMb="$(sed 's|[^0-9]||g' <<<$OPTARG)";;
|
|
||||||
*) error "invalid argument: %s\n" "$arg"; usage >&2; exit "$EXIT_INVALIDARGUMENT";;
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
local shiftlen=$(( OPTIND - 1 ))
|
local shiftlen=$(( OPTIND - 1 ))
|
||||||
shift $shiftlen
|
shift $shiftlen
|
||||||
local imagefile="$1"
|
local imagefile="$1"
|
||||||
@ -484,32 +470,34 @@ main() {
|
|||||||
RootSizeMb=$(( $RootSizeMb + (${#Kernels[@]} * 75) ))
|
RootSizeMb=$(( $RootSizeMb + (${#Kernels[@]} * 75) ))
|
||||||
HasSwap=$( (( $SwapSizeMb > 0 )) && echo 1 || echo 0 )
|
HasSwap=$( (( $SwapSizeMb > 0 )) && echo 1 || echo 0 )
|
||||||
|
|
||||||
|
msg "making $arch image: $imagefile"
|
||||||
|
|
||||||
# determine if the target arch is supported
|
# determine if the target arch is supported
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
i686|x86_64|armv7h) ;;
|
i686|x86_64|armv7h) ;;
|
||||||
ppc64le|riscv64 ) warning "arch %s is experimental" "$arch" ;;
|
ppc64le|riscv64 ) warning "arch is experimental: %s" "$arch" ;;
|
||||||
* ) error "arch %s is unsupported" "$arch"
|
* ) error "arch is unsupported: %s" "$arch"
|
||||||
exit "$EXIT_INVALIDARGUMENT" ;;
|
exit "$EXIT_INVALIDARGUMENT" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# determine whether the target output file already exists
|
# create the virtual machine
|
||||||
if [ -e "$imagefile" ]; then
|
if pvm_bootstrap; then
|
||||||
warning "%s: file exists. Continue? [y/N]" "$imagefile"
|
if pvm_bootstrap_preinit; then
|
||||||
read -p " " -n 1 -r
|
msg "bootstrap complete for image: %s" "$imagefile"
|
||||||
echo
|
exit "$EXIT_SUCCESS"
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
else
|
||||||
|
error "bootstrap complete, but preinit failed for image: %s" "$imagefile"
|
||||||
exit "$EXIT_FAILURE"
|
exit "$EXIT_FAILURE"
|
||||||
fi
|
fi
|
||||||
rm -f "$imagefile" || exit
|
else
|
||||||
fi
|
|
||||||
|
|
||||||
# create the virtual machine
|
|
||||||
if ! pvm_bootstrap; then
|
|
||||||
error "bootstrap failed for image: %s" "$imagefile"
|
error "bootstrap failed for image: %s" "$imagefile"
|
||||||
exit "$EXIT_FAILURE"
|
exit "$EXIT_FAILURE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg "bootstrap complete for image: %s" "$imagefile"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
if source /usr/lib/parabola-vmbootstrap/pvm-common.sh.inc 2> /dev/null || \
|
||||||
|
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"/pvm-common.sh.inc 2> /dev/null
|
||||||
|
then main "$@"
|
||||||
|
else echo "can not find pvm-common.sh.inc" && exit 1
|
||||||
|
fi
|
||||||
|
Loading…
Reference in New Issue
Block a user