init
⎇
Raw
1#!/bin/sh
2# PID 1 of the build VM. It builds the context from the job disk with
3# buildah and writes the image to the "hf.image" port as a tar of a
4# containers-image dir: layout.
5# Every exit path reboots, and QEMU runs with -no-reboot, so it exits.
6
7finish() {
8 echo "$1"
9 sync
10 reboot -f
11}
12
13# crun cannot pivot_root out of the initramfs, so the rest runs on a tmpfs.
14if [ ! -e /.hf-tmpfs ]; then
15 mount -t tmpfs -o mode=0755 tmpfs /mnt
16 tar -c -C / --exclude=./mnt . | tar -x -C /mnt
17 touch /mnt/.hf-tmpfs
18 exec switch_root /mnt /init
19fi
20
21mount -t devtmpfs dev /dev
22exec </dev/null >/dev/console 2>&1
23mount -t proc proc /proc
24mount -t sysfs sys /sys
25mount -t cgroup2 cgroup2 /sys/fs/cgroup
26mkdir -p /dev/pts /dev/shm
27mount -t devpts devpts /dev/pts
28mount -t tmpfs tmpfs /dev/shm
29mount -t tmpfs tmpfs /tmp
30mount -t tmpfs tmpfs /run
31
32for ko in /lib/hf-modules/*.ko; do
33 insmod "$ko" || finish "hearthforge: cannot load $ko"
34done
35
36# QEMU user networking: fixed guest address, gateway and DNS.
37ip link set lo up
38ip link set eth0 up
39ip addr add 10.0.2.15/24 dev eth0
40ip route add default via 10.0.2.2
41echo "nameserver 10.0.2.3" > /etc/resolv.conf
42echo "127.0.0.1 localhost" > /etc/hosts
43
44job=
45scratch=
46for b in /sys/block/vd*; do
47 case $(cat "$b/serial" 2>/dev/null) in
48 hfjob) job=/dev/${b##*/} ;;
49 hfscratch) scratch=/dev/${b##*/} ;;
50 esac
51done
52[ -n "$job" ] && [ -n "$scratch" ] || finish "hearthforge: disks missing"
53mkfs.ext4 -q -F -E lazy_itable_init=1,lazy_journal_init=1 "$scratch" ||
54 finish "hearthforge: cannot format the scratch disk"
55mount -o noatime "$scratch" /var/lib/containers ||
56 finish "hearthforge: cannot mount the scratch disk"
57# The root is a RAM tmpfs. The job and buildah's layer staging in /var/tmp
58# go to the scratch disk instead.
59hf=/var/lib/containers/hf
60mkdir -p "$hf" /var/lib/containers/tmp
61mount --bind /var/lib/containers/tmp /var/tmp
62tar -x -f "$job" -C "$hf" || finish "hearthforge: cannot read the job"
63
64# The engine extracts the context under its own directory name.
65ctx=$(find "$hf/context" -mindepth 1 -maxdepth 1)
66[ -d "$ctx" ] || finish "hearthforge: the build context is not a single directory"
67
68out=
69for port in /sys/class/virtio-ports/*; do
70 [ "$(cat "$port/name" 2>/dev/null)" = hf.image ] && out=/dev/${port##*/}
71done
72[ -n "$out" ] || finish "hearthforge: image port missing"
73
74set --
75[ -f "$hf/job/file" ] && set -- "$@" -f "$ctx/$(cat "$hf/job/file")"
76[ -f "$hf/job/target" ] && set -- "$@" --target "$(cat "$hf/job/target")"
77for f in "$hf"/job/args/*; do
78 [ -f "$f" ] && set -- "$@" --build-arg "${f##*/}=$(cat "$f")"
79done
80for f in "$hf"/job/secrets/*; do
81 [ -f "$f" ] && set -- "$@" --secret "id=${f##*/},src=$f"
82done
83
84# Docker format keeps HEALTHCHECK, SHELL and ONBUILD, which OCI drops.
85# --layers gives one layer per instruction, like docker build.
86buildah build --format docker --layers --network host "$@" \
87 -t localhost/hf-build "$ctx" ||
88 finish "hearthforge: build failed"
89buildah push --quiet --format v2s2 --compression-format gzip \
90 localhost/hf-build dir:/var/lib/containers/hf-out ||
91 finish "hearthforge: cannot export the image"
92tar -c -f "$out" -C /var/lib/containers/hf-out . ||
93 finish "hearthforge: cannot write the image"
94finish "hearthforge: image written"
95