diff --git a/Config.in b/Config.in index 8632387..351303a 100644 --- a/Config.in +++ b/Config.in @@ -15,6 +15,7 @@ config AIMEEOS select BR2_PACKAGE_HOST_MTOOLS select BR2_TARGET_GRUB2 select BR2_PACKAGE_HOST_ZSTD + select BR2_PACKAGE_AIMEE_OS_UTILS help Enable all Aimee OS features. @@ -35,3 +36,5 @@ config AIMEEOS_DEFAULT_ROOTFLAGS string "Default kernel command line argumens" help Additional command line arguments to pass to the kernel by default. + +source "$BR2_EXTERNAL_AIMEEOS_PATH/package/aimee-os-utils/Config.in" diff --git a/boot/grub2/gen-grub-cfg.sh b/boot/grub2/gen-grub-cfg.sh index 37adca2..ca34682 100755 --- a/boot/grub2/gen-grub-cfg.sh +++ b/boot/grub2/gen-grub-cfg.sh @@ -9,5 +9,6 @@ cat > "${TARGET_DIR}"/boot/grub.cfg <&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 diff --git a/boot/initramfs/initramfs-init.sh b/boot/initramfs/initramfs-init.sh new file mode 100755 index 0000000..b45e7a4 --- /dev/null +++ b/boot/initramfs/initramfs-init.sh @@ -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 diff --git a/boot/mkinitramfs.sh b/boot/mkinitramfs.sh new file mode 100755 index 0000000..b12c5cc --- /dev/null +++ b/boot/mkinitramfs.sh @@ -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 diff --git a/external.mk b/external.mk index 834c04b..f33020b 100644 --- a/external.mk +++ b/external.mk @@ -1,3 +1,20 @@ +ifeq ($(AIMEEOS),y) + +# Disable the default fstab +SKELETON_INIT_SYSTEMD_ROOT_RO_OR_RW = +# Disable the default var.mount +SKELETON_INIT_SYSTEMD_ROOTFS_PRE_CMD_HOOKS = + +# Enable required kernel options for Aimee OS storage +define AIMEEOS_LINUX_CONFIG_FIXUPS +$(call KCONFIG_ENABLE_OPT,CONFIG_BTRFS_FS) +$(call KCONFIG_ENABLE_OPT,CONFIG_BLK_DEV_INITRD) +endef +LINUX_KCONFIG_FIXUP_CMDS += $(AIMEEOS_LINUX_CONFIG_FIXUPS) + +# Generate the initramfs image after building the target +BR2_ROOTFS_POST_BUILD_SCRIPT += $(BR2_EXTERNAL_AIMEEOS_PATH)/boot/mkinitramfs.sh + # Overwrite the grub.cfg provided by Buildroot with our own. define AIMEEOS_GRUB2_INSTALL_IMAGES_CMDS $(foreach tuple, $(GRUB2_TUPLES-y), \ @@ -27,3 +44,7 @@ define AIMEEOS_GEN_GRUB_CFG $(BR2_EXTERNAL_AIMEEOS_PATH)/boot/grub2/gen-grub-cfg.sh $(AIMEEOS_KERNEL_FILENAME) endef LINUX_TARGET_FINALIZE_HOOKS += AIMEEOS_GEN_GRUB_CFG + +endif + +include $(sort $(wildcard $(BR2_EXTERNAL_AIMEEOS_PATH)/package/*/*.mk)) diff --git a/package/aimee-os-utils/Config.in b/package/aimee-os-utils/Config.in new file mode 100644 index 0000000..2807f2b --- /dev/null +++ b/package/aimee-os-utils/Config.in @@ -0,0 +1,8 @@ +config BR2_PACKAGE_AIMEE_OS_UTILS + bool + select BR2_PACKAGE_BTRFS_PROGS + select BR2_PACKAGE_UTIL_LINUX + select BR2_PACKAGE_UTIL_LINUX_BINARIES + select BR2_PACKAGE_UTIL_LINUX_MOUNTPOINT + select BR2_PACKAGE_UTIL_LINUX_PARTX + select BR2_PACKAGE_UTIL_LINUX_SWITCH_ROOT diff --git a/package/aimee-os-utils/aimee-os-utils.mk b/package/aimee-os-utils/aimee-os-utils.mk new file mode 100644 index 0000000..7952bee --- /dev/null +++ b/package/aimee-os-utils/aimee-os-utils.mk @@ -0,0 +1,21 @@ +################################################################################ +# +# Aimee OS Utils +# +################################################################################ + +AIMEE_OS_UTILS_VERSION = 2.0 +AIMEE_OS_UTILS_LICENSE = GPL-3.0+ +AIMEE_OS_UTILS_DEPENDENCIES = \ + host-fakeroot \ + btrfs-progs \ + +AIMEE_OS_UTILS_SOURCE = + +define AIMEE_OS_UTILS_INSTALL_INIT_SYSTEMD + $(INSTALL) -D -m u=rw,go=r \ + $(AIMEE_OS_UTILS_PKGDIR)/var.mount \ + $(TARGET_DIR)/usr/lib/systemd/system/var.mount +endef + +$(eval $(generic-package)) diff --git a/package/aimee-os-utils/var.mount b/package/aimee-os-utils/var.mount new file mode 100644 index 0000000..17a27bc --- /dev/null +++ b/package/aimee-os-utils/var.mount @@ -0,0 +1,12 @@ +[Unit] +Description=/var +DefaultDependencies=no +Conflicts=umount.target +Before=local-fs.target umount.target +After=swap.target + +[Mount] +What=PARTLABEL=aimeeos-data +Where=/var +Type=btrfs +Options=subvol=var,nosuid,nodev,noexec