Begin persistent storage implementation
All checks were successful
Aimee OS/aimee-os/pipeline/head This commit looks good
All checks were successful
Aimee OS/aimee-os/pipeline/head This commit looks good
Most of the logic in the `init-storage` script is the same as it was in Aimee OS v1 (Gentoo). The major difference is now we are initializing the data volume in the initramfs instead of in the real OS. This allows us to make all of `/etc` writable via OverlayFS, instead of having only certain sub-directories writable via bind-mounts. Buildroot doesn't really have any tools for building an initramfs, unfortunately. It does have a bit of infrastructure for running `dracut`, but I'd really rather avoid having that much complexity in the initramfs; all we need is to run the `init-storage` script and then switch root. Instead, the `mkinitramfs.sh` script, called in the post-build stage, creates the CPIO archive from files in the target directory. The only particularly interesting bit is how it resolves shared library dependencies, to make sure the appropriate resources are available for the requisite commands. I briefly considered building a statically-linked BusyBox just for the initramfs. Since it doesn't provide several important tools like `btrfs`/`mkfs.btrfs`, I had to implement the dynamic link resolution function anyway. It made sense, then, to copy Dash and the necessary Coreutils binaries themselves.
This commit is contained in:
@@ -9,5 +9,6 @@ cat > "${TARGET_DIR}"/boot/grub.cfg <<EOF
|
||||
menuentry "Aimee OS ${vers} (Buildroot ${br2_vers}) on \$dev" --class gnu-linux --id "id-\$partuuid" "\$dev" "\$partuuid" {
|
||||
set root="\$2"
|
||||
linux "/boot/${kernel_filename}" root=PARTUUID=\$3 ro \$rootflags
|
||||
initrd "/boot/initramfs.img.zst"
|
||||
}
|
||||
EOF
|
||||
|
||||
165
boot/initramfs/init-storage.sh
Executable file
165
boot/initramfs/init-storage.sh
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/bin/sh
|
||||
# vim: set sw=4 ts=4 sts=4 et :
|
||||
|
||||
SUBVOLUMES='
|
||||
/var
|
||||
/var/log
|
||||
/var/tmp
|
||||
/etc
|
||||
'
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${tmpdir}" ] && [ "${tmpdir}" != / ]; then
|
||||
if mountpoint -q "${tmpdir}"; then
|
||||
umount "${tmpdir}"
|
||||
fi
|
||||
rm -rf "${tmpdir}"
|
||||
unset tmpdir
|
||||
fi
|
||||
}
|
||||
|
||||
copy_vol() {
|
||||
dev="$1"
|
||||
vol=$2
|
||||
|
||||
printf 'Copying %s contents to data volume\n' "${vol}" >&2
|
||||
mount -o subvol="${vol#/}" "${dev}" "${tmpdir}" || exit
|
||||
cp -au${VERBOSE+v} /sysroot/${vol#/}/. "${tmpdir}" || exit
|
||||
umount "${tmpdir}"
|
||||
}
|
||||
|
||||
format_dev() {
|
||||
dev="$1"
|
||||
partno=$(partition_number "${dev}")
|
||||
if [ -n "${partno}" ]; then
|
||||
disk="$(get_disk "${dev}")"
|
||||
if [ -n "${disk}" ]; then
|
||||
printf 'Resizing partition %d on disk %s\n' \
|
||||
"${partno}" \
|
||||
"${disk}" \
|
||||
>&2
|
||||
resize_partition "${disk}" "${partno}"
|
||||
else
|
||||
printf 'Could not find disk for device %s\n' \
|
||||
"${dev}" \
|
||||
>&2
|
||||
fi
|
||||
fi
|
||||
|
||||
printf 'Creating BTRFS filesystem on %s\n' "${dev}" >&2
|
||||
mkfs.btrfs --quiet "${dev}" || exit
|
||||
|
||||
mount "${dev}" "${tmpdir}" || exit
|
||||
for vol in ${SUBVOLUMES}; do
|
||||
mkdir -p "${tmpdir}${vol%/*}" || exit
|
||||
btrfs subvolume create "${tmpdir}${vol}" || exit
|
||||
done
|
||||
relabel_all
|
||||
umount "${dev}" || exit
|
||||
}
|
||||
|
||||
get_disk() {
|
||||
_syspath=/sys/class/block/${1##*/}
|
||||
[ -d "${_syspath}" ] || return 1
|
||||
if [ ! -f "${_syspath}"/partition ]; then
|
||||
readlink -f "${1}"
|
||||
return $?
|
||||
fi
|
||||
_disk=$(readlink -f "${_syspath}"/..)
|
||||
if [ -n "${_disk}" ]; then
|
||||
printf '/dev/%s\n' "${_disk##*/}"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
has_fs() {
|
||||
dev="$1"
|
||||
fstype=$(blkid -o value -s TYPE "${dev}")
|
||||
[ -n "${fstype}" ]
|
||||
}
|
||||
|
||||
last_partition() {
|
||||
cat /sys/class/block/"${1##*/}"/*/partition \
|
||||
| sort -n \
|
||||
| tail -n1
|
||||
}
|
||||
|
||||
partition_number() {
|
||||
cat /sys/class/block/${1##*/}/partition
|
||||
}
|
||||
|
||||
relabel_all() {
|
||||
if [ ! -d /sys/fs/selinux ] || [ ! -f /etc/selinux/config ]; then
|
||||
return
|
||||
fi
|
||||
selinuxtype=$(. /etc/selinux/config && echo ${SELINUXTYPE})
|
||||
find "${tmpdir}" | \
|
||||
setfiles \
|
||||
-v \
|
||||
-F \
|
||||
-m \
|
||||
-r "${tmpdir}" \
|
||||
-s \
|
||||
/etc/selinux/${selinuxtype}/contexts/files/file_contexts
|
||||
}
|
||||
|
||||
resize_partition() {
|
||||
_disk="${1}"
|
||||
_part="${2}"
|
||||
_lastpart=$(last_partition "${_disk}")
|
||||
if [ "${_part}" -ne "${_lastpart}" ]; then
|
||||
printf 'Cannot resize %s, it is not the last partition on the disk\n' \
|
||||
"${_dev}" \
|
||||
>&2
|
||||
return 1
|
||||
fi
|
||||
_uuid=$(sfdisk --part-uuid "${_disk}" "${_part}") || return $?
|
||||
_type=$(sfdisk --part-type "${_disk}" "${_part}") || return $?
|
||||
_label=$(sfdisk --part-label "${_disk}" "${_part}") || return $?
|
||||
sfdisk --delete "${_disk}" "${_part}" || return $?
|
||||
printf 'type=%s, uuid=%s, name="%s"\n' \
|
||||
"${_type}" \
|
||||
"${_uuid}" \
|
||||
"${_label}" \
|
||||
| sfdisk -N "${_part}" "${_disk}" --quiet --force \
|
||||
|| return $?
|
||||
partx -u "${_disk}"
|
||||
}
|
||||
|
||||
setup_etc() {
|
||||
dev="$1"
|
||||
|
||||
echo 'Initializing /etc overlay' >&2
|
||||
mkdir -p /run/aimeeos/etc || return
|
||||
mount -o subvol=etc "${dev}" /run/aimeeos/etc || return
|
||||
mkdir -p /run/aimeeos/etc/rw /run/aimeeos/etc/work || return
|
||||
mount -t overlay \
|
||||
-o lowerdir=/sysroot/etc,upperdir=/run/aimeeos/etc/rw,workdir=/run/aimeeos/etc/work \
|
||||
overlay \
|
||||
/sysroot/etc
|
||||
}
|
||||
|
||||
rootdev=$(findfs "$1")
|
||||
datapart=$(findfs "${2:-PARTLABEL=aimeeos-data}")
|
||||
if [ -b "${datapart}" ]; then
|
||||
printf 'Found data partition: %s\n' "${datapart}" >&2
|
||||
else
|
||||
echo 'Could not identify data partition' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
trap cleanup INT TERM QUIT EXIT
|
||||
tmpdir=/run/storinit
|
||||
mkdir -p "${tmpdir}"
|
||||
|
||||
if ! has_fs "${datapart}"; then
|
||||
format_dev "${datapart}"
|
||||
fi
|
||||
|
||||
mkdir -p /sysroot
|
||||
mount -o ro "${rootdev}" /sysroot || exit
|
||||
|
||||
setup_etc "${datapart}"
|
||||
copy_vol "${datapart}" /var
|
||||
exit 0
|
||||
27
boot/initramfs/initramfs-init.sh
Executable file
27
boot/initramfs/initramfs-init.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p \
|
||||
/dev \
|
||||
/proc \
|
||||
/run \
|
||||
/sys \
|
||||
/sysroot \
|
||||
&& :
|
||||
|
||||
mount -t devtmpfs devtmpfs /dev
|
||||
mount -t proc proc /proc
|
||||
mount -t sysfs sysfs /sys
|
||||
mount -t tmpfs tmpfs /run
|
||||
|
||||
set -- $(cat /proc/cmdline)
|
||||
for arg; do
|
||||
case "${arg}" in
|
||||
root=*)
|
||||
root=${arg#root=}
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
init-storage "${root}"
|
||||
|
||||
exec switch_root /sysroot /sbin/init
|
||||
113
boot/mkinitramfs.sh
Executable file
113
boot/mkinitramfs.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $(id -u) != 0 ]; then
|
||||
exec "${HOST_DIR}"/bin/fakeroot "$0" "$@"
|
||||
fi
|
||||
|
||||
export PATH="${HOST_DIR}:${PATH}"
|
||||
|
||||
TARGET_DIR=$1
|
||||
WORKDIR=$(mktemp -d)
|
||||
OUTDIR="${WORKDIR}"/initramfs
|
||||
LIB_CACHE="${WORKDIR}"/libs.cache
|
||||
PKGDIR="${0%/*}"
|
||||
|
||||
trap 'rm -rf "${WORKDIR}"' INT QUIT TERM EXIT
|
||||
|
||||
cache_libs() {
|
||||
find \
|
||||
"${TARGET_DIR}"/usr/lib \
|
||||
"${TARGET_DIR}"/usr/lib64 \
|
||||
\( -type f -o -type l \) \
|
||||
-name '*.so*' \
|
||||
| sed "s@${TARGET_DIR}@@" \
|
||||
> "${LIB_CACHE}"
|
||||
}
|
||||
|
||||
bin_install() {
|
||||
for arg; do
|
||||
arg=${arg#/}
|
||||
[ -e "${OUTDIR}/${arg}" ] && continue
|
||||
mkdir -p "${OUTDIR}/${arg%/*}"
|
||||
cp -a "${TARGET_DIR}/${arg}" "${OUTDIR}/${arg}"
|
||||
if [ -h "${TARGET_DIR}/${arg}" ]; then
|
||||
bin_install "$(realpath --relative-to "${TARGET_DIR}" "${TARGET_DIR}/${arg}")"
|
||||
elif [ -f "${TARGET_DIR}/${arg}" ]; then
|
||||
readelf --dynamic "${TARGET_DIR}/${arg}" \
|
||||
| awk '$2=="(NEEDED)"{gsub(/\[|\]/,"",$5); print $5}' \
|
||||
| while IFS= read -r lib; do
|
||||
path="$(grep "${lib}"'$' "${LIB_CACHE}")"
|
||||
if [ -z "${path}" ]; then
|
||||
printf 'ERROR could not resolve shared library %s\n' "${lib}" >&2
|
||||
return 1
|
||||
fi
|
||||
bin_install "${path}"
|
||||
done
|
||||
elif [ ! -e "${TARGET_DIR}/${arg}" ]; then
|
||||
printf 'ERROR could not find /%s to copy\n' "${arg}" >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
mk_skel() {
|
||||
mkdir -p "${OUTDIR}"/dev
|
||||
mknod -m 0622 "${OUTDIR}"/dev/console c 5 1
|
||||
|
||||
mkdir -p \
|
||||
"${OUTDIR}"/usr \
|
||||
"${OUTDIR}"/usr/bin \
|
||||
"${OUTDIR}"/usr/sbin \
|
||||
"${OUTDIR}"/usr/lib
|
||||
ln -s usr/bin "${OUTDIR}"/bin
|
||||
ln -s usr/sbin "${OUTDIR}"/sbin
|
||||
ln -s usr/lib "${OUTDIR}"/lib
|
||||
if [ -h "${TARGET_DIR}"/usr/lib64 ]; then
|
||||
cp -P "${TARGET_DIR}"/usr/lib64 "${OUTDIR}"/usr
|
||||
fi
|
||||
if [ -h "${TARGET_DIR}"/lib64 ]; then
|
||||
cp -P "${TARGET_DIR}"/lib64 "${OUTDIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
rm -rf "${OUTDIR}"
|
||||
|
||||
mk_skel || exit
|
||||
cache_libs || exit
|
||||
|
||||
bin_install \
|
||||
/bin/cat \
|
||||
/bin/cp \
|
||||
/bin/ls \
|
||||
/bin/mkdir \
|
||||
/bin/mount \
|
||||
/bin/rm \
|
||||
/bin/sh \
|
||||
/bin/sort \
|
||||
/bin/tail \
|
||||
/bin/umount \
|
||||
/usr/bin/btrfs \
|
||||
/usr/bin/mkfs.btrfs \
|
||||
/usr/bin/mountpoint \
|
||||
/usr/bin/readlink \
|
||||
/usr/sbin/blkid \
|
||||
/usr/sbin/findfs \
|
||||
/usr/sbin/partx \
|
||||
/usr/sbin/sfdisk \
|
||||
/usr/sbin/switch_root \
|
||||
|| exit
|
||||
|
||||
if [ -e "${TARGET_DIR}"/usr/bin/setfiles ]; then
|
||||
bin_install /usr/bin/setfiles || exit
|
||||
fi
|
||||
|
||||
install "${PKGDIR}"/initramfs/initramfs-init.sh "${OUTDIR}"/init || exit
|
||||
install "${PKGDIR}"/initramfs/init-storage.sh "${OUTDIR}"/usr/bin/init-storage || exit
|
||||
|
||||
mkdir -p "${TARGET_DIR}"/boot
|
||||
|
||||
(cd "${OUTDIR}" && find . -mindepth 1 \
|
||||
| LC_ALL=C sort \
|
||||
| cpio --reproducible --quiet -o -H newc \
|
||||
| zstd \
|
||||
) > "${TARGET_DIR}"/boot/initramfs.img.zst
|
||||
Reference in New Issue
Block a user