mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Replace bind mounts with typed mounts (mount -t proc, mount -t sysfs, mount -t efivarfs) for /proc, /sys, and efivars in chroot environments.
549 lines
19 KiB
Bash
Executable File
549 lines
19 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
|
|
echo "==== StartOS Image Build ===="
|
|
|
|
echo "Building for architecture: $IB_TARGET_ARCH"
|
|
|
|
SOURCE_DIR="$(realpath $(dirname "${BASH_SOURCE[0]}"))"
|
|
|
|
base_dir="$(pwd -P)"
|
|
prep_results_dir="$base_dir/images-prep"
|
|
RESULTS_DIR="$base_dir/results"
|
|
echo "Saving results in: $RESULTS_DIR"
|
|
|
|
DEB_PATH="$base_dir/$1"
|
|
|
|
VERSION="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/VERSION.txt)"
|
|
GIT_HASH="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/GIT_HASH.txt)"
|
|
if [[ "$GIT_HASH" =~ ^@ ]]; then
|
|
GIT_HASH="unknown"
|
|
else
|
|
GIT_HASH="$(echo -n "$GIT_HASH" | head -c 7)"
|
|
fi
|
|
IB_OS_ENV="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/ENVIRONMENT.txt)"
|
|
IB_TARGET_PLATFORM="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/PLATFORM.txt)"
|
|
|
|
VERSION_FULL="${VERSION}-${GIT_HASH}"
|
|
if [ -n "$IB_OS_ENV" ]; then
|
|
VERSION_FULL="$VERSION_FULL~${IB_OS_ENV}"
|
|
fi
|
|
|
|
IMAGE_BASENAME=startos-${VERSION_FULL}_${IB_TARGET_PLATFORM}
|
|
|
|
BOOTLOADERS=grub-efi
|
|
if [ "$IB_TARGET_PLATFORM" = "x86_64" ] || [ "$IB_TARGET_PLATFORM" = "x86_64-nonfree" ] || [ "$IB_TARGET_PLATFORM" = "x86_64-nvidia" ]; then
|
|
IB_TARGET_ARCH=amd64
|
|
QEMU_ARCH=x86_64
|
|
BOOTLOADERS=grub-efi,syslinux
|
|
elif [ "$IB_TARGET_PLATFORM" = "aarch64" ] || [ "$IB_TARGET_PLATFORM" = "aarch64-nonfree" ] || [ "$IB_TARGET_PLATFORM" = "aarch64-nvidia" ] || [ "$IB_TARGET_PLATFORM" = "raspberrypi" ] || [ "$IB_TARGET_PLATFORM" = "rockchip64" ]; then
|
|
IB_TARGET_ARCH=arm64
|
|
QEMU_ARCH=aarch64
|
|
elif [ "$IB_TARGET_PLATFORM" = "riscv64" ] || [ "$IB_TARGET_PLATFORM" = "riscv64-nonfree" ]; then
|
|
IB_TARGET_ARCH=riscv64
|
|
QEMU_ARCH=riscv64
|
|
else
|
|
IB_TARGET_ARCH="$IB_TARGET_PLATFORM"
|
|
QEMU_ARCH="$IB_TARGET_PLATFORM"
|
|
fi
|
|
|
|
QEMU_ARGS=()
|
|
if [ "$QEMU_ARCH" != $(uname -m) ]; then
|
|
QEMU_ARGS+=(--bootstrap-qemu-arch ${IB_TARGET_ARCH})
|
|
QEMU_ARGS+=(--bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static)
|
|
fi
|
|
|
|
mkdir -p $prep_results_dir
|
|
|
|
cd $prep_results_dir
|
|
|
|
NON_FREE=
|
|
if [[ "${IB_TARGET_PLATFORM}" =~ -nonfree$ ]] || [[ "${IB_TARGET_PLATFORM}" =~ -nvidia$ ]] || [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
NON_FREE=1
|
|
fi
|
|
NVIDIA=
|
|
if [[ "${IB_TARGET_PLATFORM}" =~ -nvidia$ ]]; then
|
|
NVIDIA=1
|
|
fi
|
|
IMAGE_TYPE=iso
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ] || [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
|
|
IMAGE_TYPE=img
|
|
fi
|
|
|
|
ARCHIVE_AREAS="main contrib"
|
|
if [ "$NON_FREE" = 1 ]; then
|
|
if [ "$IB_SUITE" = "bullseye" ]; then
|
|
ARCHIVE_AREAS="$ARCHIVE_AREAS non-free"
|
|
else
|
|
ARCHIVE_AREAS="$ARCHIVE_AREAS non-free non-free-firmware"
|
|
fi
|
|
fi
|
|
|
|
PLATFORM_CONFIG_EXTRAS=()
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
PLATFORM_CONFIG_EXTRAS+=( --firmware-binary false )
|
|
PLATFORM_CONFIG_EXTRAS+=( --firmware-chroot false )
|
|
RPI_KERNEL_VERSION=6.12.47+rpt
|
|
PLATFORM_CONFIG_EXTRAS+=( --linux-packages linux-image-$RPI_KERNEL_VERSION )
|
|
PLATFORM_CONFIG_EXTRAS+=( --linux-flavours "rpi-v8 rpi-2712" )
|
|
elif [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
|
|
PLATFORM_CONFIG_EXTRAS+=( --linux-flavours rockchip64 )
|
|
elif [ "${IB_TARGET_ARCH}" = "riscv64" ]; then
|
|
PLATFORM_CONFIG_EXTRAS+=( --uefi-secure-boot=disable )
|
|
fi
|
|
|
|
|
|
cat > /etc/wgetrc << EOF
|
|
retry_connrefused = on
|
|
tries = 100
|
|
EOF
|
|
lb config \
|
|
--iso-application "StartOS v${VERSION_FULL} ${IB_TARGET_ARCH}" \
|
|
--iso-volume "StartOS v${VERSION} ${IB_TARGET_ARCH}" \
|
|
--iso-preparer "START9 LABS; HTTPS://START9.COM" \
|
|
--iso-publisher "START9 LABS; HTTPS://START9.COM" \
|
|
--backports true \
|
|
--bootappend-live "boot=live noautologin console=tty0" \
|
|
--bootloaders $BOOTLOADERS \
|
|
--cache false \
|
|
--mirror-bootstrap "https://deb.debian.org/debian/" \
|
|
--mirror-chroot "https://deb.debian.org/debian/" \
|
|
--mirror-chroot-security "https://security.debian.org/debian-security" \
|
|
-d ${IB_SUITE} \
|
|
-a ${IB_TARGET_ARCH} \
|
|
${QEMU_ARGS[@]} \
|
|
--archive-areas "${ARCHIVE_AREAS}" \
|
|
${PLATFORM_CONFIG_EXTRAS[@]}
|
|
|
|
# Overlays
|
|
|
|
mkdir -p config/packages.chroot/
|
|
cp $RESULTS_DIR/$IMAGE_BASENAME.deb config/packages.chroot/
|
|
dpkg-name config/packages.chroot/*.deb
|
|
|
|
mkdir -p config/includes.chroot/etc
|
|
echo start > config/includes.chroot/etc/hostname
|
|
cat > config/includes.chroot/etc/hosts << EOT
|
|
127.0.0.1 localhost start
|
|
::1 localhost start ip6-localhost ip6-loopback
|
|
ff02::1 ip6-allnodes
|
|
ff02::2 ip6-allrouters
|
|
EOT
|
|
|
|
if [[ "${IB_OS_ENV}" =~ (^|-)dev($|-) ]]; then
|
|
mkdir -p config/includes.chroot/etc/ssh/sshd_config.d
|
|
echo "PasswordAuthentication yes" > config/includes.chroot/etc/ssh/sshd_config.d/dev-password-auth.conf
|
|
fi
|
|
|
|
# Installer marker file (used by installed GRUB to detect the live USB)
|
|
mkdir -p config/includes.binary
|
|
touch config/includes.binary/.startos-installer
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
mkdir -p config/includes.chroot
|
|
git clone --depth=1 --branch=stable https://github.com/raspberrypi/rpi-firmware.git config/includes.chroot/boot
|
|
rm -rf config/includes.chroot/boot/.git config/includes.chroot/boot/modules
|
|
rsync -rLp $SOURCE_DIR/raspberrypi/squashfs/ config/includes.chroot/
|
|
fi
|
|
|
|
# Bootloaders
|
|
|
|
rm -rf config/bootloaders
|
|
cp -r /usr/share/live/build/bootloaders config/bootloaders
|
|
|
|
cat > config/bootloaders/syslinux/syslinux.cfg << EOF
|
|
include menu.cfg
|
|
default vesamenu.c32
|
|
prompt 0
|
|
timeout 50
|
|
EOF
|
|
|
|
cat > config/bootloaders/isolinux/isolinux.cfg << EOF
|
|
include menu.cfg
|
|
default vesamenu.c32
|
|
prompt 0
|
|
timeout 50
|
|
EOF
|
|
|
|
# Extract splash.png from the deb package
|
|
dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xf - ./usr/lib/startos/splash.png > /tmp/splash.png
|
|
cp /tmp/splash.png config/bootloaders/syslinux_common/splash.png
|
|
cp /tmp/splash.png config/bootloaders/isolinux/splash.png
|
|
cp /tmp/splash.png config/bootloaders/grub-pc/splash.png
|
|
rm /tmp/splash.png
|
|
|
|
sed -i -e '2i set timeout=5' config/bootloaders/grub-pc/config.cfg
|
|
|
|
# Archives
|
|
|
|
mkdir -p config/archives
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
# Fetch the keyring package (not the old raspberrypi.gpg.key, which has
|
|
# SHA1-only binding signatures that sqv on Trixie rejects).
|
|
KEYRING_DEB=$(mktemp)
|
|
curl -fsSL -o "$KEYRING_DEB" https://archive.raspberrypi.com/debian/pool/main/r/raspberrypi-archive-keyring/raspberrypi-archive-keyring_2025.1+rpt1_all.deb
|
|
dpkg-deb -x "$KEYRING_DEB" "$KEYRING_DEB.d"
|
|
cp "$KEYRING_DEB.d/usr/share/keyrings/raspberrypi-archive-keyring.gpg" config/archives/raspi.key
|
|
rm -rf "$KEYRING_DEB" "$KEYRING_DEB.d"
|
|
echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/raspi.key.gpg] https://archive.raspberrypi.com/debian/ ${IB_SUITE} main" > config/archives/raspi.list
|
|
fi
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
|
|
curl -fsSL https://apt.armbian.com/armbian.key | gpg --dearmor -o config/archives/armbian.key
|
|
echo "deb https://apt.armbian.com/ ${IB_SUITE} main" > config/archives/armbian.list
|
|
fi
|
|
|
|
if [ "$NVIDIA" = 1 ]; then
|
|
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o config/archives/nvidia-container-toolkit.key
|
|
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
|
|
| sed 's#deb https://#deb [signed-by=/etc/apt/trusted.gpg.d/nvidia-container-toolkit.key.gpg] https://#g' \
|
|
> config/archives/nvidia-container-toolkit.list
|
|
fi
|
|
|
|
cat > config/archives/backports.pref <<-EOF
|
|
Package: linux-image-*
|
|
Pin: release n=${IB_SUITE}-backports
|
|
Pin-Priority: 500
|
|
|
|
Package: linux-headers-*
|
|
Pin: release n=${IB_SUITE}-backports
|
|
Pin-Priority: 500
|
|
|
|
Package: *nvidia*
|
|
Pin: release n=${IB_SUITE}-backports
|
|
Pin-Priority: 500
|
|
EOF
|
|
|
|
# Hooks
|
|
|
|
cat > config/hooks/normal/9000-install-startos.hook.chroot << EOF
|
|
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" != "raspberrypi" ]; then
|
|
/usr/lib/startos/scripts/enable-kiosk
|
|
fi
|
|
|
|
if [ "${NVIDIA}" = "1" ]; then
|
|
# install a specific NVIDIA driver version
|
|
|
|
# ---------------- configuration ----------------
|
|
NVIDIA_DRIVER_VERSION="\${NVIDIA_DRIVER_VERSION:-580.126.09}"
|
|
|
|
BASE_URL="https://download.nvidia.com/XFree86/Linux-${QEMU_ARCH}"
|
|
|
|
echo "[nvidia-hook] Using NVIDIA driver: \${NVIDIA_DRIVER_VERSION}" >&2
|
|
|
|
# ---------------- kernel version ----------------
|
|
|
|
# Determine target kernel version from newest /boot/vmlinuz-* in the chroot.
|
|
KVER="\$(
|
|
ls -1t /boot/vmlinuz-* 2>/dev/null \
|
|
| head -n1 \
|
|
| sed 's|.*/vmlinuz-||'
|
|
)"
|
|
|
|
if [ -z "\${KVER}" ]; then
|
|
echo "[nvidia-hook] ERROR: no /boot/vmlinuz-* found; cannot determine kernel version" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "[nvidia-hook] Target kernel version: \${KVER}" >&2
|
|
|
|
# Ensure kernel headers are present
|
|
TEMP_APT_DEPS=(build-essential pkg-config)
|
|
if [ ! -e "/lib/modules/\${KVER}/build" ]; then
|
|
TEMP_APT_DEPS+=(linux-headers-\${KVER})
|
|
fi
|
|
|
|
echo "[nvidia-hook] Installing build dependencies" >&2
|
|
|
|
/usr/lib/startos/scripts/install-equivs <<-EOF
|
|
Package: nvidia-depends
|
|
Version: \${NVIDIA_DRIVER_VERSION}
|
|
Section: unknown
|
|
Priority: optional
|
|
Depends: \${dep_list="\$(IFS=', '; echo "\${TEMP_APT_DEPS[*]}")"}
|
|
EOF
|
|
|
|
# ---------------- download and run installer ----------------
|
|
|
|
RUN_NAME="NVIDIA-Linux-${QEMU_ARCH}-\${NVIDIA_DRIVER_VERSION}.run"
|
|
RUN_PATH="/root/\${RUN_NAME}"
|
|
RUN_URL="\${BASE_URL}/\${NVIDIA_DRIVER_VERSION}/\${RUN_NAME}"
|
|
|
|
echo "[nvidia-hook] Downloading \${RUN_URL}" >&2
|
|
wget -O "\${RUN_PATH}" "\${RUN_URL}"
|
|
chmod +x "\${RUN_PATH}"
|
|
|
|
echo "[nvidia-hook] Running NVIDIA installer for kernel \${KVER}" >&2
|
|
|
|
if ! sh "\${RUN_PATH}" \
|
|
--silent \
|
|
--kernel-name="\${KVER}" \
|
|
--no-x-check \
|
|
--no-nouveau-check \
|
|
--no-runlevel-check; then
|
|
cat /var/log/nvidia-installer.log
|
|
exit 1
|
|
fi
|
|
|
|
# Rebuild module metadata
|
|
echo "[nvidia-hook] Running depmod for \${KVER}" >&2
|
|
depmod -a "\${KVER}"
|
|
|
|
echo "[nvidia-hook] NVIDIA \${NVIDIA_DRIVER_VERSION} installation complete for kernel \${KVER}" >&2
|
|
|
|
echo "[nvidia-hook] Removing .run installer..." >&2
|
|
rm -f "\${RUN_PATH}"
|
|
|
|
echo "[nvidia-hook] Blacklisting nouveau..." >&2
|
|
echo "blacklist nouveau" > /etc/modprobe.d/blacklist-nouveau.conf
|
|
echo "options nouveau modeset=0" >> /etc/modprobe.d/blacklist-nouveau.conf
|
|
|
|
echo "[nvidia-hook] Rebuilding initramfs..." >&2
|
|
update-initramfs -u -k "\${KVER}"
|
|
|
|
echo "[nvidia-hook] Removing build dependencies..." >&2
|
|
apt-get purge -y nvidia-depends
|
|
apt-get autoremove -y
|
|
echo "[nvidia-hook] Removed build dependencies." >&2
|
|
fi
|
|
|
|
# Install linux-kbuild for sign-file (Secure Boot module signing)
|
|
KVER_ALL="\$(ls -1t /boot/vmlinuz-* 2>/dev/null | head -n1 | sed 's|.*/vmlinuz-||')"
|
|
if [ -n "\${KVER_ALL}" ]; then
|
|
KBUILD_VER="\$(echo "\${KVER_ALL}" | grep -oP '^\d+\.\d+')"
|
|
if [ -n "\${KBUILD_VER}" ]; then
|
|
echo "[build] Installing linux-kbuild-\${KBUILD_VER} for Secure Boot support" >&2
|
|
apt-get install -y "linux-kbuild-\${KBUILD_VER}" || echo "[build] WARNING: linux-kbuild-\${KBUILD_VER} not available" >&2
|
|
fi
|
|
fi
|
|
|
|
cp /etc/resolv.conf /etc/resolv.conf.bak
|
|
|
|
if [ "${IB_SUITE}" = trixie ] && [ "${IB_TARGET_ARCH}" != riscv64 ]; then
|
|
echo 'deb https://deb.debian.org/debian/ bookworm main' > /etc/apt/sources.list.d/bookworm.list
|
|
apt-get update
|
|
apt-get install -y postgresql-15
|
|
rm /etc/apt/sources.list.d/bookworm.list
|
|
apt-get update
|
|
systemctl mask postgresql
|
|
fi
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
ln -sf /usr/bin/pi-beep /usr/local/bin/beep
|
|
sh /boot/firmware/config.sh > /boot/firmware/config.txt
|
|
mkinitramfs -c gzip -o /boot/initrd.img-${RPI_KERNEL_VERSION}-rpi-v8 ${RPI_KERNEL_VERSION}-rpi-v8
|
|
mkinitramfs -c gzip -o /boot/initrd.img-${RPI_KERNEL_VERSION}-rpi-2712 ${RPI_KERNEL_VERSION}-rpi-2712
|
|
cp /usr/lib/u-boot/rpi_arm64/u-boot.bin /boot/firmware/u-boot.bin
|
|
fi
|
|
|
|
useradd --shell /bin/bash -G startos -m start9
|
|
echo start9:embassy | chpasswd
|
|
usermod -aG sudo start9
|
|
usermod -aG systemd-journal start9
|
|
|
|
echo "start9 ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee "/etc/sudoers.d/010_start9-nopasswd"
|
|
|
|
if ! [[ "${IB_OS_ENV}" =~ (^|-)dev($|-) ]]; then
|
|
passwd -l start9
|
|
fi
|
|
|
|
mkdir -p /media/startos
|
|
chmod 750 /media/startos
|
|
chown root:startos /media/startos
|
|
|
|
EOF
|
|
|
|
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date '+%s')}"
|
|
|
|
if lb bootstrap; then
|
|
true
|
|
else
|
|
EXIT=$?
|
|
cat ./chroot/debootstrap/debootstrap.log
|
|
exit $EXIT
|
|
fi
|
|
lb chroot
|
|
lb installer
|
|
lb binary_chroot
|
|
lb chroot_prep install all mode-apt-install-binary mode-archives-chroot
|
|
mv chroot/chroot/etc/resolv.conf.bak chroot/chroot/etc/resolv.conf
|
|
lb binary_rootfs
|
|
|
|
cp $prep_results_dir/binary/live/filesystem.squashfs $RESULTS_DIR/$IMAGE_BASENAME.squashfs
|
|
|
|
if [ "${IMAGE_TYPE}" = iso ]; then
|
|
|
|
lb binary_manifest
|
|
lb binary_package-lists
|
|
lb binary_linux-image
|
|
lb binary_memtest
|
|
lb binary_grub-legacy
|
|
lb binary_grub-pc
|
|
lb binary_grub_cfg
|
|
lb binary_syslinux
|
|
lb binary_disk
|
|
lb binary_loadlin
|
|
lb binary_win32-loader
|
|
lb binary_includes
|
|
lb binary_grub-efi
|
|
lb binary_hooks
|
|
lb binary_checksums
|
|
find binary -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" -printf "%y %p\n" -exec touch '{}' -d@${SOURCE_DATE_EPOCH} --no-dereference ';' > binary.modified_timestamps
|
|
lb binary_iso
|
|
lb binary_onie
|
|
lb binary_netboot
|
|
lb binary_tar
|
|
lb binary_hdd
|
|
lb binary_zsync
|
|
lb chroot_prep remove all mode-archives-chroot
|
|
lb source
|
|
|
|
mv $prep_results_dir/live-image-${IB_TARGET_ARCH}.hybrid.iso $RESULTS_DIR/$IMAGE_BASENAME.iso
|
|
|
|
elif [ "${IMAGE_TYPE}" = img ]; then
|
|
|
|
SECTOR_LEN=512
|
|
FW_START=$((1024 * 1024)) # 1MiB (sector 2048) — Pi-specific
|
|
FW_LEN=$((128 * 1024 * 1024)) # 128MiB (Pi firmware + U-Boot + DTBs)
|
|
FW_END=$((FW_START + FW_LEN - 1))
|
|
ESP_START=$((FW_END + 1)) # 100MB EFI System Partition (matches os_install)
|
|
ESP_LEN=$((100 * 1024 * 1024))
|
|
ESP_END=$((ESP_START + ESP_LEN - 1))
|
|
BOOT_START=$((ESP_END + 1)) # 2GB /boot (matches os_install)
|
|
BOOT_LEN=$((2 * 1024 * 1024 * 1024))
|
|
BOOT_END=$((BOOT_START + BOOT_LEN - 1))
|
|
ROOT_START=$((BOOT_END + 1))
|
|
|
|
# Size root partition to fit the squashfs + 256MB overhead for btrfs
|
|
# metadata and config overlay, avoiding the need for btrfs resize
|
|
SQUASHFS_SIZE=$(stat -c %s $prep_results_dir/binary/live/filesystem.squashfs)
|
|
ROOT_LEN=$(( SQUASHFS_SIZE + 256 * 1024 * 1024 ))
|
|
# Align to sector boundary
|
|
ROOT_LEN=$(( (ROOT_LEN + SECTOR_LEN - 1) / SECTOR_LEN * SECTOR_LEN ))
|
|
|
|
# Total image: partitions + GPT backup header (34 sectors)
|
|
IMG_LEN=$((ROOT_START + ROOT_LEN + 34 * SECTOR_LEN))
|
|
|
|
# Fixed GPT partition UUIDs (deterministic, based on old MBR disk ID cb15ae4d)
|
|
FW_UUID=cb15ae4d-0001-4000-8000-000000000001
|
|
ESP_UUID=cb15ae4d-0002-4000-8000-000000000002
|
|
BOOT_UUID=cb15ae4d-0003-4000-8000-000000000003
|
|
ROOT_UUID=cb15ae4d-0004-4000-8000-000000000004
|
|
|
|
TARGET_NAME=$prep_results_dir/${IMAGE_BASENAME}.img
|
|
truncate -s $IMG_LEN $TARGET_NAME
|
|
|
|
sfdisk $TARGET_NAME <<-EOF
|
|
label: gpt
|
|
|
|
${TARGET_NAME}1 : start=$((FW_START / SECTOR_LEN)), size=$((FW_LEN / SECTOR_LEN)), type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=${FW_UUID}, name="firmware"
|
|
${TARGET_NAME}2 : start=$((ESP_START / SECTOR_LEN)), size=$((ESP_LEN / SECTOR_LEN)), type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=${ESP_UUID}, name="efi"
|
|
${TARGET_NAME}3 : start=$((BOOT_START / SECTOR_LEN)), size=$((BOOT_LEN / SECTOR_LEN)), type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=${BOOT_UUID}, name="boot"
|
|
${TARGET_NAME}4 : start=$((ROOT_START / SECTOR_LEN)), size=$((ROOT_LEN / SECTOR_LEN)), type=B921B045-1DF0-41C3-AF44-4C6F280D3FAE, uuid=${ROOT_UUID}, name="root"
|
|
EOF
|
|
|
|
# Create named loop device nodes (high minor numbers to avoid conflicts)
|
|
# and detach any stale ones from previous failed builds
|
|
FW_DEV=/dev/startos-loop-fw
|
|
ESP_DEV=/dev/startos-loop-esp
|
|
BOOT_DEV=/dev/startos-loop-boot
|
|
ROOT_DEV=/dev/startos-loop-root
|
|
for dev in $FW_DEV:200 $ESP_DEV:201 $BOOT_DEV:202 $ROOT_DEV:203; do
|
|
name=${dev%:*}
|
|
minor=${dev#*:}
|
|
[ -e $name ] || mknod $name b 7 $minor
|
|
losetup -d $name 2>/dev/null || true
|
|
done
|
|
|
|
losetup $FW_DEV --offset $FW_START --sizelimit $FW_LEN $TARGET_NAME
|
|
losetup $ESP_DEV --offset $ESP_START --sizelimit $ESP_LEN $TARGET_NAME
|
|
losetup $BOOT_DEV --offset $BOOT_START --sizelimit $BOOT_LEN $TARGET_NAME
|
|
losetup $ROOT_DEV --offset $ROOT_START --sizelimit $ROOT_LEN $TARGET_NAME
|
|
|
|
mkfs.vfat -F32 -n firmware $FW_DEV
|
|
mkfs.vfat -F32 -n efi $ESP_DEV
|
|
mkfs.vfat -F32 -n boot $BOOT_DEV
|
|
mkfs.btrfs -f -L rootfs $ROOT_DEV
|
|
|
|
TMPDIR=$(mktemp -d)
|
|
|
|
# Extract boot files from squashfs to staging area
|
|
BOOT_STAGING=$(mktemp -d)
|
|
unsquashfs -n -f -d $BOOT_STAGING $prep_results_dir/binary/live/filesystem.squashfs boot
|
|
|
|
# Mount partitions (nested: firmware and efi inside boot)
|
|
mkdir -p $TMPDIR/boot $TMPDIR/root
|
|
mount $BOOT_DEV $TMPDIR/boot
|
|
mkdir -p $TMPDIR/boot/firmware $TMPDIR/boot/efi
|
|
mount $FW_DEV $TMPDIR/boot/firmware
|
|
mount $ESP_DEV $TMPDIR/boot/efi
|
|
mount $ROOT_DEV $TMPDIR/root
|
|
|
|
# Copy boot files — nested mounts route firmware/* to the firmware partition
|
|
cp -a $BOOT_STAGING/boot/. $TMPDIR/boot/
|
|
rm -rf $BOOT_STAGING
|
|
|
|
mkdir $TMPDIR/root/images $TMPDIR/root/config
|
|
B3SUM=$(b3sum $prep_results_dir/binary/live/filesystem.squashfs | head -c 16)
|
|
cp $prep_results_dir/binary/live/filesystem.squashfs $TMPDIR/root/images/$B3SUM.rootfs
|
|
ln -rsf $TMPDIR/root/images/$B3SUM.rootfs $TMPDIR/root/config/current.rootfs
|
|
|
|
mkdir -p $TMPDIR/next $TMPDIR/lower $TMPDIR/root/config/work $TMPDIR/root/config/overlay
|
|
mount $TMPDIR/root/config/current.rootfs $TMPDIR/lower
|
|
|
|
mount -t overlay -o lowerdir=$TMPDIR/lower,workdir=$TMPDIR/root/config/work,upperdir=$TMPDIR/root/config/overlay overlay $TMPDIR/next
|
|
|
|
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
|
|
rsync -a $SOURCE_DIR/raspberrypi/img/ $TMPDIR/next/
|
|
|
|
# Install GRUB: ESP at /boot/efi (Part 2), /boot (Part 3)
|
|
mkdir -p $TMPDIR/next/boot \
|
|
$TMPDIR/next/dev $TMPDIR/next/proc $TMPDIR/next/sys $TMPDIR/next/media/startos/root
|
|
mount --rbind $TMPDIR/boot $TMPDIR/next/boot
|
|
mount --bind /dev $TMPDIR/next/dev
|
|
mount -t proc proc $TMPDIR/next/proc
|
|
mount -t sysfs sysfs $TMPDIR/next/sys
|
|
mount --bind $TMPDIR/root $TMPDIR/next/media/startos/root
|
|
|
|
chroot $TMPDIR/next grub-install --target=arm64-efi --removable --efi-directory=/boot/efi --boot-directory=/boot --no-nvram
|
|
chroot $TMPDIR/next update-grub
|
|
|
|
umount $TMPDIR/next/media/startos/root
|
|
umount $TMPDIR/next/sys
|
|
umount $TMPDIR/next/proc
|
|
umount $TMPDIR/next/dev
|
|
umount -l $TMPDIR/next/boot
|
|
|
|
# Fix root= in grub.cfg: update-grub sees loop devices, but the
|
|
# real device uses a fixed GPT PARTUUID for root (Part 4).
|
|
sed -i "s|root=[^ ]*|root=PARTUUID=${ROOT_UUID}|g" $TMPDIR/boot/grub/grub.cfg
|
|
|
|
# Inject first-boot resize script into GRUB config
|
|
sed -i 's| boot=startos| boot=startos init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/grub/grub.cfg
|
|
fi
|
|
|
|
umount $TMPDIR/next
|
|
umount $TMPDIR/lower
|
|
|
|
umount $TMPDIR/boot/firmware
|
|
umount $TMPDIR/boot/efi
|
|
umount $TMPDIR/boot
|
|
umount $TMPDIR/root
|
|
|
|
losetup -d $ROOT_DEV
|
|
losetup -d $BOOT_DEV
|
|
losetup -d $ESP_DEV
|
|
losetup -d $FW_DEV
|
|
|
|
mv $TARGET_NAME $RESULTS_DIR/$IMAGE_BASENAME.img
|
|
|
|
fi
|
|
|
|
chown $IB_UID:$IB_UID $RESULTS_DIR/$IMAGE_BASENAME.*
|