# shellcheck shell=bash # Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. # See LICENSE.md for license information. # SPDX-License-Identifier: MIT # # Shared by the Haiku components (haikuGcc, haikuGcc2, haikuVm, haikuVm32), # the BeOS VM (installer/lib/beos.sh, which uses its BFS helpers and job # runner protocol) and the Be API ports' gates (scripts/lib/beGate.sh): the # Haiku R1/beta6 release they are all made from, getting files into and out # of its disk images and packages, and the job runner its VM images boot # into. Sourced, not executed. ARCH is a Haiku architecture: x86_64, or # x86_gcc2 (the 32-bit hybrid, gcc2h, whose primary compiler is gcc 2.95 # for BeOS compatibility). # # The job runner: a VM image's UserBootscript (written by haikuVmPrepare) # looks for a disk labeled HAIKU_JOB_VOLUME, mounts it, waits for the # desktop and the media services (the boot script runs before they are up, # and a program opening its sound before the media server has started gets # none), runs its job.sh there with the output going to job.log beside it, # then shuts the machine down, so QEMU exits. A boot without that disk is an # ordinary desktop. Lines on the first serial port mark the job's progress # (HAIKU_JOB_STARTED, HAIKU_JOB_FINISHED). # The anyboot images: a mirror listed on haiku-os.org/get-haiku/r1beta6, and # the SHA256 sums that page gives. HAIKU_ISO_BASE="https://mirrors.rit.edu/haiku/r1beta6" HAIKU_ISO_NAME_x86_64="haiku-r1beta6-x86_64-anyboot.iso" HAIKU_ISO_SHA256_x86_64="bb7743474fd175aea511be1799764ba054465285bbdf54c4722ca61d1fb4f5c9" HAIKU_ISO_NAME_x86_gcc2="haiku-r1beta6-x86_gcc2h-anyboot.iso" HAIKU_ISO_SHA256_x86_gcc2="5a55ad9429f1de9fb5ca5cbcd54de3733ff247cc7919ce5d690fb1271cb1dc76" # The release's packages (hrev59866_79, what the images were built from) in # Haiku's repository, and HaikuPorts' (the compiler's runtime), by the # checksums the repositories' indexes give. HAIKU_REVISION="r1~beta6_hrev59866_79" HAIKU_REPO_BASE="https://eu.hpkg.haiku-os.org/haiku/r1beta6" HAIKU_PORTS_BASE="https://eu.hpkg.haiku-os.org/haikuports/master" # The job runner's disk label and serial port lines, and the applications # it waits for: Deskbar, the media server and its add-on host. HAIKU_JOB_VOLUME="JoeyJob" HAIKU_JOB_WAIT_APPS="application/x-vnd.Be-TSKB application/x-vnd.Be.media-server application/x-vnd.Be.addon-host" HAIKU_JOB_STARTED="JOEY: job started" HAIKU_JOB_FINISHED="JOEY: job finished" # Seconds the runner waits for the job disk to appear while booting. HAIKU_JOB_WAIT_SECONDS=10 # Haiku's build-host tools (component haikuTools). HAIKU_TOOLS="${HAIKU_TOOLS:-${JOEY_OPT:-}/haikuTools/bin}" # haikuBfs IMAGE [OFFSET] -- run the bfs_shell commands on stdin against the # BFS volume in IMAGE (at byte OFFSET, for a partitioned disk), the volume # at /myfs and host files as :PATH. Its output is printed; returns 1 when a # command failed. sync is run before the volume is let go: bfs_shell's quit # reports the volume busy after a copy and would not write it otherwise. haikuBfs() { local image="$1" local offset="${2:-}" local out local errors out="$({ cat; printf 'sync\nquit\n'; } | "$HAIKU_TOOLS/bfs_shell" ${offset:+--start-offset "$offset"} "$image" 2>&1 || true)" printf '%s\n' "$out" errors="$(printf '%s\n' "$out" | grep -i -e 'error' | grep -v 'Unmounting FS failed: Device or resource busy' || true)" [ -z "$errors" ] } # haikuBfsNew IMAGE SIZE LABEL -- a new BFS volume of SIZE (truncate's # suffixes: 64M) in the file IMAGE. haikuBfsNew() { rm -f "$1" truncate -s "$2" "$1" "$HAIKU_TOOLS/bfs_shell" --initialize "$1" "$3" > /dev/null } # haikuBootOffset IMAGE -- the byte offset of an anyboot image's first # partition, its BFS system volume (from the MBR: entry 1, at byte 446, # holds its start sector, little-endian, at byte 8). haikuBootOffset() { local mbrEntry1=446 local entryStartLba=8 local sectorBytes=512 local b read -ra b <<< "$(od -An -tu1 -v -j $((mbrEntry1 + entryStartLba)) -N 4 "$1")" [ "${#b[@]}" -eq 4 ] || return 1 echo $(((b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24) * sectorBytes)) } # haikuIso ARCH -- download (once) and print the release's anyboot image. haikuIso() { local name="HAIKU_ISO_NAME_$1" local sum="HAIKU_ISO_SHA256_$1" fetchFile "$HAIKU_ISO_BASE/${!name}" "${!sum}" } # haikuIsoPackage ARCH FILE DEST -- copy the package FILE out of the # release image's /system/packages to DEST. haikuIsoPackage() { local iso iso="$(haikuIso "$1")" haikuBfs "$iso" "$(haikuBootOffset "$iso")" <<< "cp /myfs/system/packages/$2 :$3" > /dev/null || die "cannot copy $2 out of $iso" [ -s "$3" ] || die "$2 is not in $iso" } # haikuRepoPackage BASE ARCH PATH FILE SHA256 -- download (once) and print # a package from a Haiku repository: BASE/ARCH/PATH/packages/FILE. haikuRepoPackage() { fetchFile "$1/$2/$3/packages/$4" "$5" "$4" } # haikuSysroot DEST PACKAGE... -- the parts of the packages a cross compiler # needs (lib and develop) unpacked into DEST/boot/system, where a Haiku # compiler looks for them. haikuSysroot() { local dest="$1" local package shift mkdir -p "$dest/boot/system" for package in "$@"; do # A package with only one of the two warns about the other. "$HAIKU_TOOLS/package" extract -C "$dest/boot/system" "$package" lib develop 2> /dev/null || die "cannot unpack $package" done } # haikuVmPrepare ARCH IMAGE -- the release's anyboot image copied to IMAGE, # booting straight to the desktop (no first-boot prompt) and running the job # runner. haikuVmPrepare() { local iso local tmp iso="$(haikuIso "$1")" tmp="$(mktemp -d)" haikuJobRunner > "$tmp/UserBootscript" # The first-boot prompt (language and keymap, or the installer) comes # up while there are no locale settings. : > "$tmp/Locale settings" cp "$iso" "$2.part" haikuBfs "$2.part" "$(haikuBootOffset "$2.part")" > /dev/null < /dev/null 2>&1 tries=\$((tries + 1)) if [ \$tries -gt $HAIKU_JOB_WAIT_SECONDS ]; then exit 0 fi sleep 1 done for app in $HAIKU_JOB_WAIT_APPS; do waitfor -m \$app done echo "$HAIKU_JOB_STARTED" > \$serial cd /$HAIKU_JOB_VOLUME /bin/sh ./job.sh > job.log 2>&1 echo "$HAIKU_JOB_FINISHED \$?" > \$serial cd / sync shutdown -q EOF }