262 lines
8.6 KiB
Bash
Executable File
262 lines
8.6 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
|
|
metadata_target=${METADATA_OUT:-}
|
|
|
|
cleanup=0
|
|
if [ -n "${WORKDIR:-}" ]; then
|
|
workdir=$WORKDIR
|
|
mkdir -p "$workdir"
|
|
else
|
|
workdir=$(mktemp -d /tmp/fruix-phase8-bhyve-image.XXXXXX)
|
|
cleanup=1
|
|
fi
|
|
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
|
cleanup=0
|
|
fi
|
|
|
|
phase7_rootfs_dir=$workdir/phase7-rootfs
|
|
phase7_rootfs_log=$workdir/phase7-rootfs.log
|
|
phase7_rootfs_metadata=$workdir/phase7-rootfs-metadata.txt
|
|
image_rootfs=$workdir/image-rootfs
|
|
queue_file=$workdir/store-queue.txt
|
|
esp_stage=$workdir/esp-stage
|
|
esp_image_a=$workdir/esp-a.img
|
|
esp_image_b=$workdir/esp-b.img
|
|
root_image_a=$workdir/root-a.ufs
|
|
root_image_b=$workdir/root-b.ufs
|
|
disk_image_a=$workdir/fruix-bhyve-a.img
|
|
disk_image_b=$workdir/fruix-bhyve-b.img
|
|
root_makefs_a_log=$workdir/root-makefs-a.log
|
|
root_makefs_b_log=$workdir/root-makefs-b.log
|
|
esp_makefs_a_log=$workdir/esp-makefs-a.log
|
|
esp_makefs_b_log=$workdir/esp-makefs-b.log
|
|
mkimg_a_log=$workdir/mkimg-a.log
|
|
mkimg_b_log=$workdir/mkimg-b.log
|
|
gpart_log=$workdir/gpart-show.txt
|
|
metadata_file=$workdir/phase8-bhyve-image-metadata.txt
|
|
mnt_esp=$workdir/mnt-esp
|
|
mnt_root=$workdir/mnt-root
|
|
md_unit=
|
|
|
|
cleanup_workdir() {
|
|
if [ -n "$md_unit" ]; then
|
|
sudo umount "$mnt_esp" >/dev/null 2>&1 || true
|
|
sudo umount "$mnt_root" >/dev/null 2>&1 || true
|
|
sudo mdconfig -d -u "$md_unit" >/dev/null 2>&1 || true
|
|
fi
|
|
if [ "$cleanup" -eq 1 ]; then
|
|
rm -rf "$workdir" 2>/dev/null || sudo rm -rf "$workdir"
|
|
fi
|
|
}
|
|
trap cleanup_workdir EXIT INT TERM
|
|
|
|
copy_store_closure() {
|
|
closure_path=$1
|
|
stage_root=$2
|
|
|
|
: > "$queue_file"
|
|
printf '%s\n' "$closure_path" > "$queue_file"
|
|
|
|
while IFS= read -r item || [ -n "$item" ]; do
|
|
[ -n "$item" ] || continue
|
|
staged_item=$stage_root/frx/store/$(basename "$item")
|
|
if [ ! -e "$staged_item" ]; then
|
|
sudo cp -a "$item" "$staged_item"
|
|
if [ -f "$item/.references" ]; then
|
|
while IFS= read -r ref || [ -n "$ref" ]; do
|
|
[ -n "$ref" ] || continue
|
|
if [ ! -e "$stage_root/frx/store/$(basename "$ref")" ]; then
|
|
printf '%s\n' "$ref" >> "$queue_file"
|
|
fi
|
|
done < "$item/.references"
|
|
fi
|
|
fi
|
|
done < "$queue_file"
|
|
}
|
|
|
|
KEEP_WORKDIR=1 WORKDIR=$phase7_rootfs_dir METADATA_OUT=$phase7_rootfs_metadata \
|
|
"$repo_root/tests/system/run-phase7-rootfs.sh" >"$phase7_rootfs_log" 2>&1
|
|
|
|
rootfs=$phase7_rootfs_dir/rootfs
|
|
closure_path=$(readlink "$rootfs/run/current-system")
|
|
closure_base=$(basename "$closure_path")
|
|
|
|
sudo rm -rf "$image_rootfs"
|
|
sudo cp -a "$rootfs" "$image_rootfs"
|
|
sudo mkdir -p "$image_rootfs/frx/store"
|
|
copy_store_closure "$closure_path" "$image_rootfs"
|
|
|
|
rm -rf "$esp_stage"
|
|
mkdir -p "$esp_stage/EFI/BOOT"
|
|
sudo cp -f "$closure_path/boot/loader.efi" "$esp_stage/EFI/BOOT/BOOTX64.EFI"
|
|
|
|
sudo makefs -t ffs -T 0 -B little -s 256m \
|
|
-o label=fruix-root,version=2,bsize=32768,fsize=4096,density=16384 \
|
|
"$root_image_a" "$image_rootfs" >"$root_makefs_a_log" 2>&1
|
|
sudo makefs -t ffs -T 0 -B little -s 256m \
|
|
-o label=fruix-root,version=2,bsize=32768,fsize=4096,density=16384 \
|
|
"$root_image_b" "$image_rootfs" >"$root_makefs_b_log" 2>&1
|
|
makefs -t msdos -T 0 \
|
|
-o fat_type=32 \
|
|
-o sectors_per_cluster=1 \
|
|
-o volume_label=EFISYS \
|
|
-o volume_id=305419896 \
|
|
-s 64m "$esp_image_a" "$esp_stage" >"$esp_makefs_a_log" 2>&1
|
|
makefs -t msdos -T 0 \
|
|
-o fat_type=32 \
|
|
-o sectors_per_cluster=1 \
|
|
-o volume_label=EFISYS \
|
|
-o volume_id=305419896 \
|
|
-s 64m "$esp_image_b" "$esp_stage" >"$esp_makefs_b_log" 2>&1
|
|
mkimg -s gpt -f raw -t 0 \
|
|
-p efi/efiboot:="$esp_image_a" \
|
|
-p freebsd-ufs/fruix-root:="$root_image_a" \
|
|
-o "$disk_image_a" >"$mkimg_a_log" 2>&1
|
|
mkimg -s gpt -f raw -t 0 \
|
|
-p efi/efiboot:="$esp_image_b" \
|
|
-p freebsd-ufs/fruix-root:="$root_image_b" \
|
|
-o "$disk_image_b" >"$mkimg_b_log" 2>&1
|
|
|
|
raw_sha256_a=$(sha256 -q "$disk_image_a")
|
|
raw_sha256_b=$(sha256 -q "$disk_image_b")
|
|
[ "$raw_sha256_a" = "$raw_sha256_b" ] || {
|
|
echo "raw image reproducibility check failed" >&2
|
|
exit 1
|
|
}
|
|
|
|
md=$(sudo mdconfig -a -t vnode -f "$disk_image_a")
|
|
md_unit=${md#md}
|
|
sudo mkdir -p "$mnt_esp" "$mnt_root"
|
|
sudo gpart show -lp "/dev/$md" >"$gpart_log"
|
|
esp_fstype=$(sudo fstyp "/dev/${md}p1")
|
|
root_fstype=$(sudo fstyp "/dev/${md}p2")
|
|
[ "$esp_fstype" = msdosfs ] || { echo "unexpected ESP filesystem: $esp_fstype" >&2; exit 1; }
|
|
[ "$root_fstype" = ufs ] || { echo "unexpected root filesystem: $root_fstype" >&2; exit 1; }
|
|
sudo mount -t msdosfs "/dev/${md}p1" "$mnt_esp"
|
|
sudo mount -t ufs -o ro "/dev/${md}p2" "$mnt_root"
|
|
|
|
[ -f "$mnt_esp/EFI/BOOT/BOOTX64.EFI" ] || {
|
|
echo "missing EFI bootloader in mounted ESP" >&2
|
|
exit 1
|
|
}
|
|
run_current_system_target=$(readlink "$mnt_root/run/current-system")
|
|
activate_target=$(readlink "$mnt_root/activate")
|
|
bin_target=$(readlink "$mnt_root/bin")
|
|
boot_loader_target=$(readlink "$mnt_root/boot/loader")
|
|
boot_loader_conf_target=$(readlink "$mnt_root/boot/loader.conf")
|
|
rc_conf_target=$(readlink "$mnt_root/etc/rc.conf")
|
|
rc_script_target=$(readlink "$mnt_root/usr/local/etc/rc.d/fruix-shepherd")
|
|
[ "$run_current_system_target" = "/frx/store/$closure_base" ] || {
|
|
echo "unexpected /run/current-system target: $run_current_system_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$activate_target" = /run/current-system/activate ] || {
|
|
echo "unexpected /activate target: $activate_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$bin_target" = /run/current-system/profile/bin ] || {
|
|
echo "unexpected /bin target: $bin_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$boot_loader_target" = /run/current-system/boot/loader ] || {
|
|
echo "unexpected /boot/loader target: $boot_loader_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$boot_loader_conf_target" = /run/current-system/boot/loader.conf ] || {
|
|
echo "unexpected /boot/loader.conf target: $boot_loader_conf_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$rc_conf_target" = /run/current-system/etc/rc.conf ] || {
|
|
echo "unexpected /etc/rc.conf target: $rc_conf_target" >&2
|
|
exit 1
|
|
}
|
|
[ "$rc_script_target" = /run/current-system/usr/local/etc/rc.d/fruix-shepherd ] || {
|
|
echo "unexpected fruix_shepherd rc script target: $rc_script_target" >&2
|
|
exit 1
|
|
}
|
|
[ -d "$mnt_root/frx/store/$closure_base" ] || {
|
|
echo "closure missing from image store population" >&2
|
|
exit 1
|
|
}
|
|
loader_conf_image=$mnt_root/frx/store/$closure_base/boot/loader.conf
|
|
rc_conf_image=$mnt_root/frx/store/$closure_base/etc/rc.conf
|
|
rc_script_image=$mnt_root/frx/store/$closure_base/usr/local/etc/rc.d/fruix-shepherd
|
|
shepherd_config_image=$mnt_root/frx/store/$closure_base/shepherd/init.scm
|
|
activate_image=$mnt_root/frx/store/$closure_base/activate
|
|
for required in "$loader_conf_image" "$rc_conf_image" "$rc_script_image" "$shepherd_config_image" "$activate_image"; do
|
|
[ -f "$required" ] || {
|
|
echo "required image content missing: $required" >&2
|
|
exit 1
|
|
}
|
|
done
|
|
grep -F 'console="comconsole"' "$loader_conf_image" >/dev/null || {
|
|
echo "loader.conf is missing the serial console setting" >&2
|
|
exit 1
|
|
}
|
|
grep -F 'hostname="fruix-freebsd"' "$rc_conf_image" >/dev/null || {
|
|
echo "rc.conf is missing the expected hostname" >&2
|
|
exit 1
|
|
}
|
|
grep -F 'fruix_shepherd_enable="YES"' "$rc_conf_image" >/dev/null || {
|
|
echo "rc.conf does not enable fruix_shepherd" >&2
|
|
exit 1
|
|
}
|
|
grep -F '/var/lib/fruix/ready' "$shepherd_config_image" >/dev/null || {
|
|
echo "shepherd configuration does not contain the ready marker" >&2
|
|
exit 1
|
|
}
|
|
store_item_count=$(find "$mnt_root/frx/store" -mindepth 1 -maxdepth 1 | wc -l | awk '{print $1}')
|
|
image_size_bytes=$(stat -f %z "$disk_image_a")
|
|
|
|
cat >"$metadata_file" <<EOF
|
|
workdir=$workdir
|
|
phase7_rootfs_dir=$phase7_rootfs_dir
|
|
phase7_rootfs_log=$phase7_rootfs_log
|
|
phase7_rootfs_metadata=$phase7_rootfs_metadata
|
|
image_rootfs=$image_rootfs
|
|
closure_path=$closure_path
|
|
closure_base=$closure_base
|
|
esp_stage=$esp_stage
|
|
esp_image_a=$esp_image_a
|
|
esp_image_b=$esp_image_b
|
|
root_image_a=$root_image_a
|
|
root_image_b=$root_image_b
|
|
disk_image_a=$disk_image_a
|
|
disk_image_b=$disk_image_b
|
|
raw_sha256=$raw_sha256_a
|
|
image_size_bytes=$image_size_bytes
|
|
gpart_log=$gpart_log
|
|
esp_fstype=$esp_fstype
|
|
root_fstype=$root_fstype
|
|
run_current_system_target=$run_current_system_target
|
|
activate_target=$activate_target
|
|
bin_target=$bin_target
|
|
boot_loader_target=$boot_loader_target
|
|
boot_loader_conf_target=$boot_loader_conf_target
|
|
rc_conf_target=$rc_conf_target
|
|
rc_script_target=$rc_script_target
|
|
store_item_count=$store_item_count
|
|
boot_mode=uefi
|
|
image_format=raw
|
|
partition_scheme=gpt
|
|
root_partition_label=fruix-root
|
|
efi_partition_label=efiboot
|
|
serial_console=comconsole
|
|
EOF
|
|
|
|
if [ -n "$metadata_target" ]; then
|
|
mkdir -p "$(dirname "$metadata_target")"
|
|
cp "$metadata_file" "$metadata_target"
|
|
fi
|
|
|
|
printf 'PASS phase8-bhyve-image\n'
|
|
printf 'Work directory: %s\n' "$workdir"
|
|
printf 'Metadata file: %s\n' "$metadata_file"
|
|
if [ -n "$metadata_target" ]; then
|
|
printf 'Copied metadata to: %s\n' "$metadata_target"
|
|
fi
|
|
printf '%s\n' '--- metadata ---'
|
|
cat "$metadata_file"
|