201 lines
7.4 KiB
Bash
201 lines
7.4 KiB
Bash
# 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 labelled 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's start sector).
|
|
haikuBootOffset() {
|
|
python3 - "$1" <<'PY'
|
|
import struct
|
|
import sys
|
|
|
|
MBR_ENTRY_1 = 446
|
|
ENTRY_START_LBA = 8
|
|
SECTOR_BYTES = 512
|
|
|
|
with open(sys.argv[1], 'rb') as image:
|
|
mbr = image.read(SECTOR_BYTES)
|
|
print(struct.unpack_from('<I', mbr, MBR_ENTRY_1 + ENTRY_START_LBA)[0] * SECTOR_BYTES)
|
|
PY
|
|
}
|
|
|
|
|
|
# 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 <<EOF || die "cannot write the job runner into $2"
|
|
cp :$tmp/UserBootscript /myfs/home/config/settings/boot/UserBootscript
|
|
cp ":$tmp/Locale settings" "/myfs/home/config/settings/Locale settings"
|
|
EOF
|
|
rm -rf "$tmp"
|
|
mv "$2.part" "$2"
|
|
}
|
|
|
|
|
|
# haikuVmPin ARCH -- what a VM image component is rebuilt for: the release
|
|
# image and the job runner.
|
|
haikuVmPin() {
|
|
local sum="HAIKU_ISO_SHA256_$1"
|
|
printf '%s:%s\n' "${!sum}" "$(haikuJobRunner | sha256sum | cut -d' ' -f1)"
|
|
}
|
|
|
|
|
|
# haikuVmVerify IMAGE -- the job runner is on the image's system volume.
|
|
haikuVmVerify() {
|
|
local runner
|
|
runner="$(haikuBfs "$1" "$(haikuBootOffset "$1")" <<< "cat /myfs/home/config/settings/boot/UserBootscript" || true)"
|
|
[[ "$runner" == *"$HAIKU_JOB_VOLUME"* ]]
|
|
}
|
|
|
|
|
|
# haikuJobRunner -- the UserBootscript the VM images run at every boot.
|
|
haikuJobRunner() {
|
|
cat <<EOF
|
|
#!/bin/sh
|
|
# JoeyLib's job runner (installer/lib/haiku.sh): a disk labelled
|
|
# $HAIKU_JOB_VOLUME holding job.sh is mounted, job.sh is run there (its output
|
|
# in job.log) and the machine shuts down. Without one, an ordinary boot.
|
|
serial=/dev/ports/pc_serial0
|
|
tries=0
|
|
while [ ! -f /$HAIKU_JOB_VOLUME/job.sh ]; do
|
|
mountvolume $HAIKU_JOB_VOLUME > /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
|
|
}
|