#!/bin/sh set -eu project_root=${PROJECT_ROOT:-$(pwd)} script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd) fruix_cmd=$project_root/bin/fruix os_file=${OS_FILE:-$script_dir/phase7-minimal-operating-system.scm} system_name=${SYSTEM_NAME:-phase7-operating-system} store_dir=${STORE_DIR:-/frx/store} disk_capacity=${DISK_CAPACITY:-} root_size=${ROOT_SIZE:-} metadata_target=${METADATA_OUT:-} [ -x "$fruix_cmd" ] || { echo "fruix command is not executable: $fruix_cmd" >&2 exit 1 } 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 action_env() { sudo env \ HOME="$HOME" \ GUILE_AUTO_COMPILE=0 \ GUIX_SOURCE_DIR="${GUIX_SOURCE_DIR:-$HOME/repos/guix}" \ 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}" \ "$@" } printf 'Using fruix command: %s\n' "$fruix_cmd" printf 'Working directory: %s\n' "$workdir" printf 'Store directory: %s\n' "$store_dir" set -- "$fruix_cmd" system image "$os_file" --system "$system_name" --store "$store_dir" if [ -n "$disk_capacity" ]; then set -- "$@" --disk-capacity "$disk_capacity" fi if [ -n "$root_size" ]; then set -- "$@" --root-size "$root_size" fi action_env "$@" >"$build_metadata" 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") disk_capacity_reported=$(sed -n 's/^disk_capacity=//p' "$build_metadata") root_size_reported=$(sed -n 's/^root_size=//p' "$build_metadata") store_item_count=$(sed -n 's/^store_item_count=//p' "$build_metadata") host_base_store_count=$(sed -n 's/^host_base_store_count=//p' "$build_metadata") host_base_stores=$(sed -n 's/^host_base_stores=//p' "$build_metadata") native_base_store_count=$(sed -n 's/^native_base_store_count=//p' "$build_metadata") native_base_stores=$(sed -n 's/^native_base_stores=//p' "$build_metadata") fruix_runtime_store_count=$(sed -n 's/^fruix_runtime_store_count=//p' "$build_metadata") fruix_runtime_stores=$(sed -n 's/^fruix_runtime_stores=//p' "$build_metadata") freebsd_base_name=$(sed -n 's/^freebsd_base_name=//p' "$build_metadata") freebsd_base_version_label=$(sed -n 's/^freebsd_base_version_label=//p' "$build_metadata") freebsd_base_release=$(sed -n 's/^freebsd_base_release=//p' "$build_metadata") freebsd_base_branch=$(sed -n 's/^freebsd_base_branch=//p' "$build_metadata") freebsd_base_source_root=$(sed -n 's/^freebsd_base_source_root=//p' "$build_metadata") freebsd_base_target=$(sed -n 's/^freebsd_base_target=//p' "$build_metadata") freebsd_base_target_arch=$(sed -n 's/^freebsd_base_target_arch=//p' "$build_metadata") freebsd_base_kernconf=$(sed -n 's/^freebsd_base_kernconf=//p' "$build_metadata") freebsd_base_file=$(sed -n 's/^freebsd_base_file=//p' "$build_metadata") host_base_provenance_file=$(sed -n 's/^host_base_provenance_file=//p' "$build_metadata") store_layout_file=$(sed -n 's/^store_layout_file=//p' "$build_metadata") host_freebsd_version=$(sed -n 's/^host_freebsd_version=//p' "$build_metadata") host_uname=$(sed -n 's/^host_uname=//p' "$build_metadata") usr_src_git_revision=$(sed -n 's/^usr_src_git_revision=//p' "$build_metadata") usr_src_git_branch=$(sed -n 's/^usr_src_git_branch=//p' "$build_metadata") usr_src_newvers_sha256=$(sed -n 's/^usr_src_newvers_sha256=//p' "$build_metadata") raw_sha256=$(sha256 -q "$disk_image") image_size_bytes=$(stat -f '%z' "$disk_image") closure_base=$(basename "$closure_path") case "$image_store_path" in /frx/store/*-fruix-bhyve-image-*) : ;; *) echo "unexpected image store path: $image_store_path" >&2; exit 1 ;; esac case "$disk_image" in /frx/store/*-fruix-bhyve-image-*/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") if [ -L "$mnt_root/etc/login.conf" ]; then login_conf_kind=symlink; elif [ -f "$mnt_root/etc/login.conf" ]; then login_conf_kind=regular; else login_conf_kind=missing; fi if [ -L "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=symlink; elif [ -f "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=regular; else master_passwd_kind=missing; fi [ "$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; } [ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in the image" >&2; exit 1; } [ "$master_passwd_kind" = regular ] || { echo "/etc/master.passwd is not a regular file in the image" >&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 -E '^hostname=".+"$' "$rc_conf_image" >/dev/null || { echo "rc.conf is missing hostname" >&2; exit 1; } [ -f "$host_base_provenance_file" ] || { echo "missing host base provenance file: $host_base_provenance_file" >&2; exit 1; } [ -f "$store_layout_file" ] || { echo "missing store layout file: $store_layout_file" >&2; exit 1; } [ -n "$host_freebsd_version" ] || { echo "missing host freebsd version provenance" >&2; exit 1; } [ -n "$host_uname" ] || { echo "missing host uname provenance" >&2; exit 1; } cat >"$metadata_file" <