Files
Michael Crosby 74ace148de
Build containerization / containerization (push) Failing after 1s
Build containerization / Verify commit signatures (push) Has been cancelled
Linux build / Determine Swift version (push) Has been cancelled
Linux build / Linux compile check (push) Has been cancelled
Build vminitd and initfs inside the dev container (#810)
Signed-off-by: michael_crosby <michael_crosby@apple.com>
2026-07-24 11:04:06 -04:00

107 lines
3.5 KiB
Bash
Executable File

#!/bin/bash
# Copyright © 2026 Apple Inc. and the Containerization project authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Builds the guest init filesystem (initfs.ext4) — and optionally a rootfs
# tar.gz for OCI image creation — from the compiled vminitd/vmexec binaries.
#
# Runs INSIDE the Linux dev container (invoked by the root Makefile's `init`
# target via linux_run on macOS, or directly on Linux). A real loop mount is
# preferred; when loop devices aren't available (an unprivileged CI container,
# or a dev VM without loop support) it falls back to `mke2fs -d`, which
# populates the filesystem without mounting. Both paths yield an equivalent
# ext4, so the build works whether or not the container is privileged.
#
# The rootfs layout below MUST stay in sync with cctl's InitImage rootfs
# (Sources/cctl/RootfsCommand.swift): directories bin/ sbin/ dev/ sys/
# proc/self/ run/ tmp/ mnt/ var/, sbin/vminitd + sbin/vmexec at mode 0755, and
# a proc/self/exe -> sbin/vminitd symlink ("hack for swift init's booting").
set -euo pipefail
usage() {
echo "usage: $0 --vminitd PATH --vmexec PATH --ext4 OUT.ext4 [--tar OUT.tar.gz] [--size 512M]" >&2
exit 2
}
VMINITD=
VMEXEC=
EXT4=
TAR=
SIZE=512M
while [ $# -gt 0 ]; do
case "$1" in
--vminitd) VMINITD=$2; shift 2 ;;
--vmexec) VMEXEC=$2; shift 2 ;;
--ext4) EXT4=$2; shift 2 ;;
--tar) TAR=$2; shift 2 ;;
--size) SIZE=$2; shift 2 ;;
*) usage ;;
esac
done
[ -n "$VMINITD" ] && [ -n "$VMEXEC" ] && [ -n "$EXT4" ] || usage
[ -f "$VMINITD" ] || { echo "ERROR: vminitd not found: $VMINITD" >&2; exit 1; }
[ -f "$VMEXEC" ] || { echo "ERROR: vmexec not found: $VMEXEC" >&2; exit 1; }
umask 022
STAGING=$(mktemp -d)
MNT=
cleanup() {
if [ -n "$MNT" ]; then
mountpoint -q "$MNT" 2>/dev/null && umount "$MNT" 2>/dev/null || true
rmdir "$MNT" 2>/dev/null || true
fi
rm -rf "$STAGING"
}
trap cleanup EXIT
# Directory structure — keep in sync with RootfsCommand.directories.
for d in bin sbin dev sys proc/self run tmp mnt var; do
mkdir -p "$STAGING/$d"
done
install -m 0755 "$VMINITD" "$STAGING/sbin/vminitd"
install -m 0755 "$VMEXEC" "$STAGING/sbin/vmexec"
ln -sf sbin/vminitd "$STAGING/proc/self/exe"
mkdir -p "$(dirname "$EXT4")"
rm -f "$EXT4"
truncate -s "$SIZE" "$EXT4"
# Prefer a real loop mount; fall back to `mke2fs -d` when it isn't available.
if mkfs.ext4 -F -q "$EXT4" \
&& MNT=$(mktemp -d) \
&& mount -o loop "$EXT4" "$MNT" 2>/dev/null; then
echo "==> populating $EXT4 via loop mount"
cp -a "$STAGING"/. "$MNT"/
sync
umount "$MNT"
rmdir "$MNT"
MNT=
else
echo "==> loop mount unavailable; populating $EXT4 via mke2fs -d"
if [ -n "$MNT" ]; then rmdir "$MNT" 2>/dev/null || true; MNT=; fi
rm -f "$EXT4"
truncate -s "$SIZE" "$EXT4"
mkfs.ext4 -F -q -d "$STAGING" "$EXT4"
fi
echo "==> wrote initfs $EXT4"
if [ -n "$TAR" ]; then
mkdir -p "$(dirname "$TAR")"
rm -f "$TAR"
tar -czf "$TAR" -C "$STAGING" .
echo "==> wrote rootfs tar $TAR"
fi