#!/bin/sh set -eu project_root=${PROJECT_ROOT:-$(pwd)} guix_source_dir=${GUIX_SOURCE_DIR:-"$HOME/repos/guix"} script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd) runner_scm=$script_dir/materialize-phase8-system-image.scm os_file=${OS_FILE:-$script_dir/phase7-minimal-operating-system.scm} guile_bin=${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile} guile_extra_prefix=${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install} shepherd_prefix=${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install} store_dir=${STORE_DIR:-/frx/store} disk_capacity=${DISK_CAPACITY:-} metadata_target=${METADATA_OUT:-} if [ ! -x "$guile_bin" ]; then echo "Guile binary is not executable: $guile_bin" >&2 exit 1 fi ensure_built() { if [ ! -d "$guile_extra_prefix/share/guile/site" ] || \ ! GUILE_LOAD_PATH="$guile_extra_prefix/share/guile/site/3.0${GUILE_LOAD_PATH:+:$GUILE_LOAD_PATH}" \ GUILE_LOAD_COMPILED_PATH="$guile_extra_prefix/lib/guile/3.0/site-ccache${GUILE_LOAD_COMPILED_PATH:+:$GUILE_LOAD_COMPILED_PATH}" \ GUILE_EXTENSIONS_PATH="$guile_extra_prefix/lib/guile/3.0/extensions${GUILE_EXTENSIONS_PATH:+:$GUILE_EXTENSIONS_PATH}" \ LD_LIBRARY_PATH="$guile_extra_prefix/lib:/tmp/guile-freebsd-validate-install/lib:/usr/local/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \ "$guile_bin" -c '(catch #t (lambda () (use-modules (fibers)) (display "ok") (newline)) (lambda _ (display "missing") (newline)))' | grep -qx ok; then METADATA_OUT= ENV_OUT= "$project_root/tests/shepherd/build-local-guile-fibers.sh" fi if [ ! -x "$shepherd_prefix/bin/shepherd" ] || [ ! -x "$shepherd_prefix/bin/herd" ]; then METADATA_OUT= ENV_OUT= GUILE_EXTRA_PREFIX="$guile_extra_prefix" "$project_root/tests/shepherd/build-local-shepherd.sh" fi } ensure_built guile_prefix=$(CDPATH= cd -- "$(dirname "$guile_bin")/.." && pwd) guile_lib_dir=$guile_prefix/lib cleanup=0 if [ -n "${WORKDIR:-}" ]; then workdir=$WORKDIR mkdir -p "$workdir" else workdir=$(mktemp -d /tmp/fruix-phase8-system-image.XXXXXX) cleanup=1 fi if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then cleanup=0 fi build_metadata=$workdir/phase8-system-image-build-metadata.txt metadata_file=$workdir/phase8-system-image-validation-metadata.txt gpart_log=$workdir/gpart-show.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 if [ -n "${GUILE_LOAD_PATH:-}" ]; then gui_load_path="$project_root/modules:$guix_source_dir:$GUILE_LOAD_PATH" else gui_load_path="$project_root/modules:$guix_source_dir" fi printf 'Using Guile: %s\n' "$guile_bin" printf 'Working directory: %s\n' "$workdir" printf 'Store directory: %s\n' "$store_dir" sudo env \ GUILE_AUTO_COMPILE=0 \ GUILE_LOAD_PATH="$gui_load_path" \ LD_LIBRARY_PATH="$guile_lib_dir${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \ WORKDIR="$workdir" \ OS_FILE="$os_file" \ STORE_DIR="$store_dir" \ DISK_CAPACITY="$disk_capacity" \ GUILE_PREFIX="$guile_prefix" \ GUILE_EXTRA_PREFIX="$guile_extra_prefix" \ SHEPHERD_PREFIX="$shepherd_prefix" \ METADATA_OUT="$build_metadata" \ "$guile_bin" -s "$runner_scm" image_store_path=$(sed -n 's/^image_store_path=//p' "$build_metadata") disk_image=$(sed -n 's/^disk_image=//p' "$build_metadata") closure_path=$(sed -n 's/^closure_path=//p' "$build_metadata") raw_sha256=$(sed -n 's/^raw_sha256=//p' "$build_metadata") image_size_bytes=$(sed -n 's/^image_size_bytes=//p' "$build_metadata") disk_capacity_reported=$(sed -n 's/^disk_capacity=//p' "$build_metadata") store_item_count=$(sed -n 's/^store_item_count=//p' "$build_metadata") closure_base=$(basename "$closure_path") case "$image_store_path" in /frx/store/*-fruix-bhyve-image-fruix-freebsd) : ;; *) echo "unexpected image store path: $image_store_path" >&2; exit 1 ;; esac case "$disk_image" in /frx/store/*-fruix-bhyve-image-fruix-freebsd/disk.img) : ;; *) echo "unexpected disk image path: $disk_image" >&2; exit 1 ;; esac md=$(sudo mdconfig -a -t vnode -f "$disk_image") 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 boot file in integrated image" >&2; exit 1; } run_current_system_target=$(readlink "$mnt_root/run/current-system") 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; } [ "$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 target: $rc_script_target" >&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 grep -F 'comconsole' "$loader_conf_image" >/dev/null || { echo "loader.conf is missing serial console config" >&2; exit 1; } grep -F 'hostname="fruix-freebsd"' "$rc_conf_image" >/dev/null || { echo "rc.conf is missing hostname" >&2; exit 1; } cat >"$metadata_file" <