You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
9.9 KiB
Bash

#!/usr/bin/env bash
#
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
############## Setup #########################
function cleanup {
sync
kill_gpg_agent
stop_jails
unmount_folders
remove_memory_devices
for f in "${folders[@]}"; do
log "Deleting $f"
rm -rf "$f"
done
}
folders=()
jails=()
memorydevices=()
mountedfolders=()
gpgagents=()
for sig in EXIT INT QUIT HUP TERM; do
trap "set +e; cleanup" "$sig"
done
function die {
local status_code="$1"
shift
>&2 echo "${@}"
exit "$status_code"
}
function log {
>&2 echo "${@}"
}
############## Config Settings ###############
# These are below the Setup in case I end up creating things that need
# to be cleaned up
# Cache for local development to avoid stressing alpine servers
: ${NETIZEN_CACHE:="/tmp"}
: ${LOCAL_DEV:="false"}
: ${ALPINE_TARBALL:="alpine-minirootfs-3.15.0-x86_64.tar.gz"}
: ${ALPINE_SHA256:="ec7ec80a96500f13c189a6125f2dbe8600ef593b87fc4670fe959dc02db727a2"}
: ${ALPINE_SIGNATURE:="-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEBILYQCL1LfHE581DKTrNCQfZSVoFAmGeGqEACgkQKTrNCQfZ
SVp4Ww/+MzjBfj+33+0QxesuW/4ZGTShK6E+Hi7bXH04kparCEL77pdBnyYTfTjW
Myt2BdPPze6upbsTJjDezpoKkza47ODD5MwsT22Utm4+zJUcHVAUiRKkm57lUuF0
60DldhNj1K5sUrZgfPq+QIkJLsKZtUEoCx3lf1Ou0cRb+5P6nxnRNqqqpcwXaoJr
mhoH/YCH6f+HydbXRcHX9hwdAlCj3LnOn2m6kwppdl6sWSp7yUXkjn1grKN7bnzy
lzevA2aJJGc1S4qATYflaQcsWCcBJZ/Y1cAAl8OPLB+SYtmXbEJyluH5O7PsMGRg
Ni0XQvqvYT8RosleRLuJKu7dc2626cwHRZj6CJhfpjvFvPvwvnHWSjRrXYmcERpj
MWlyYbubF167mUb3qB2MlS58G6nsHmruejkLLe0+CJsNw7AGu2D/kB2MrJylLLvj
CV3aFJoqrsAbaUrAl9kmgE2UPjOaUl1lld+y/tnDmN4o0FsBCPLc+Zve29qkNP8P
AUeit46pKrAPEQpHFNE5bPZsZA6aR6SLRMPnVNQl57O8F+wAGe5gpvNeb24Q80PY
CB/YX6tY0dlY352Vd1kveO73YZuLzyuP35yKreFUQEyWlGYEgivkI9AZLX+LGS0f
QsATDB/JXW6pEivbW3r5v/iH0633JE2xMbI9rsP2nSrtXT5uMCw=
=Wb5G
-----END PGP SIGNATURE-----"}
: ${ALPINE_KEY:="-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
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
Mkc=
=FcYC
-----END PGP PUBLIC KEY BLOCK-----"}
############## Main Script ###################
function precheck {
# Checks to run before building the image
if [ $(id -u) -ne 0 ]; then
die 1 "Must run as root."
fi
if ! grep -q 'linux.ko' <<<"$(kldstat)"; then
die 1 "Need linux kernel module for building initramfs."
fi
for bin in gpg sha256 mkfs.ext4; do
if ! command -V "$bin" &> /dev/null; then
die 1 "Need $bin installed."
fi
done
}
function download_alpine {
if [ "$LOCAL_DEV" == "true" ] && [ -e "${NETIZEN_CACHE}/${ALPINE_TARBALL}" ]; then
# Cache for local development to avoid stressing alpine servers
fetch -o "${download_directory}/" "file://${NETIZEN_CACHE}/${ALPINE_TARBALL}"
else
fetch -o "${download_directory}/" "https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/${ALPINE_TARBALL}"
if [ "$LOCAL_DEV" == "true" ]; then
cp "${download_directory}/${ALPINE_TARBALL}" /tmp/
fi
fi
# Validate
sha256 -c "$ALPINE_SHA256" "${download_directory}/${ALPINE_TARBALL}"
local keyring="$work_directory/keyring"
local gpghome="$work_directory/gpghome"
(umask 077 && mkdir "$gpghome")
GNUPGHOME="$gpghome" gpg --no-default-keyring --keyring "$keyring" --trust-model always --import <<<"$ALPINE_KEY"
gpgagents+=("$gpghome")
GNUPGHOME="$gpghome" gpg --no-default-keyring --keyring "$keyring" --trust-model always --verify <(cat <<<"$ALPINE_SIGNATURE") "${download_directory}/${ALPINE_TARBALL}"
}
function make_chroot {
bsdtar -C "$chroot" -xpf "${download_directory}/${ALPINE_TARBALL}"
# Steal the DNS info from the host
(umask 022 && resolvconf -l > "${chroot}/etc/resolv.conf")
# Enter the jail
# install mkinitfs
jid=$(jail -c -i path="$chroot" ip4=inherit ip6=inherit host=inherit allow.raw_sockets=true persist)
jails+=("$jid")
jexec "$jid" apk add --no-cache mkinitfs docker linux-virt
jexec "$jid" apk add --no-cache --repository 'http://dl-cdn.alpinelinux.org/alpine/edge/testing' refind
module_name=$(jexec "$jid" ls /lib/modules/)
jexec "$jid" mkinitfs -c /etc/mkinitfs/mkinitfs.conf -b / "$module_name"
jexec "$jid" mkdir /boot/efi
jexec "$jid" cp -r /usr/share/refind /boot/efi/boot
jexec "$jid" cp /boot/efi/boot/refind_x64.efi /boot/efi/boot/bootx64.efi
(umask 022 && tee "${chroot}/boot/refind_linux.conf" <<EOF
"Boot normal" "rw root=vda2 console=ttyS0,115200"
EOF
)
# (umask 022 && tee "${chroot}/boot/refind_linux.conf" <<EOF
# "Boot normal" "rw root=PARTLABEL=DIB console=ttyS0,115200"
# EOF
# )
# Open shell to look/experiment
# jexec "$jid" /bin/sh
# Remove the resolv.conf file since it should get populated via dhcp
rm "${chroot}/etc/resolv.conf"
}
function make_image {
dd if=/dev/zero of="$image_file" bs=1 count=0 seek=10G
local image_device
# image_device=$(mdconfig -a -t vnode -f "$image_file")
image_device=$(mdconfig -f "$image_file")
memorydevices+=("$image_device")
efi_partition="${image_device}p1"
data_partition="${image_device}p2"
gpart create -s gpt "$image_device"
gpart add -t efi -l efi -a4k -s500m "$image_device"
newfs_msdos "${efi_partition}"
gpart add -t linux-data -l DIB -a4k "$image_device"
mkfs.ext4 "/dev/${data_partition}"
mount -t ext2fs "/dev/${data_partition}" "${mount_directory}"
mountedfolders+=("$mount_directory")
boot_directory="${mount_directory}/boot"
mkdir -p "$boot_directory"
mount_msdosfs "/dev/${efi_partition}" "${boot_directory}"
mountedfolders+=("$boot_directory")
}
function kill_gpg_agent {
for f in "${gpgagents[@]}"; do
log "Killing gpg-agent $f"
GNUPGHOME="$f" gpgconf --kill gpg-agent
done
gpgagents=()
}
function stop_jails {
for f in "${jails[@]}"; do
log "Stopping jail $f"
jail -r "$f"
done
jails=()
}
function unmount_folders {
for (( idx=${#mountedfolders[@]}-1 ; idx>=0 ; idx-- )) ; do
log "Unmounting folder ${mountedfolders[idx]}"
umount -f "${mountedfolders[idx]}"
done
mountedfolders=()
}
function remove_memory_devices {
for f in "${memorydevices[@]}"; do
log "Removing memory device $f"
mdconfig -d -u "$f"
done
memorydevices=()
}
function main {
precheck
mkdir "$DIR/work_directory"
work_directory="$DIR/work_directory"
# work_directory=$(mktemp -d -t dib)
folders+=("$work_directory")
download_directory="${work_directory}/downloads"
mkdir "$download_directory"
download_alpine
image_directory="${work_directory}/images"
mount_directory="${work_directory}/mount"
mkdir "$image_directory" "$mount_directory"
image_file="$image_directory/dib.img"
make_image
chroot="${mount_directory}"
# mkdir "$chroot"
log "Building chroot in $chroot"
make_chroot
kill_gpg_agent
stop_jails
unmount_folders
remove_memory_devices
log "Copying final image to $DIR"
cp "$image_file" "$DIR"
}
main