From 821ea84ea7969525228e1da02a0abea1feb19637 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sat, 30 Aug 2025 11:15:32 -0500 Subject: [PATCH] Implement system-update feature The `system-update` and `install-update` scripts are the same as from Aimee OS v1, with references to Gentoo replaced, of course. We need some additional kernel features in order to mount the firmware partition and update the GRUB environment file, and of course the `grub-editenv` tool itself. We also need `wget` for now, since that's how the tool downloads the specified update file from the network. Eventually, `system-update` will be replaced by a much more robust tool, with package URL discovery, signature verification, etc. The shell script will do for now while development is still proceeding rapidly. --- ci/Jenkinsfile | 1 + external.mk | 7 ++ package/aimee-os-utils/Config.in | 2 + package/aimee-os-utils/aimee-os-utils.mk | 7 ++ package/aimee-os-utils/system-update.sh | 135 +++++++++++++++++++++++ update/install-update.sh | 101 +++++++++++++++++ update/make-package.sh | 17 +++ 7 files changed, 270 insertions(+) create mode 100755 package/aimee-os-utils/system-update.sh create mode 100755 update/install-update.sh create mode 100755 update/make-package.sh diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile index 569efe0..69a618b 100644 --- a/ci/Jenkinsfile +++ b/ci/Jenkinsfile @@ -65,6 +65,7 @@ pipeline { 'firmware.img.zst', 'rootfs.squashfs', 'sdcard.img.zst', + 'update.tar.zst', ].join(',')) } } diff --git a/external.mk b/external.mk index cc4edfd..ab860c0 100644 --- a/external.mk +++ b/external.mk @@ -12,7 +12,12 @@ define AIMEEOS_LINUX_CONFIG_FIXUPS $(call KCONFIG_ENABLE_OPT,CONFIG_BLK_DEV_INITRD) $(call KCONFIG_ENABLE_OPT,CONFIG_BTRFS_FS) $(call KCONFIG_ENABLE_OPT,CONFIG_EFI) +$(call KCONFIG_ENABLE_OPT,CONFIG_MSDOS_FS) +$(call KCONFIG_ENABLE_OPT,CONFIG_NLS_CODEPAGE_437) +$(call KCONFIG_ENABLE_OPT,CONFIG_NLS_ISO8859_1) +$(call KCONFIG_ENABLE_OPT,CONFIG_NLS_UTF8) $(call KCONFIG_ENABLE_OPT,CONFIG_SQUASHFS) +$(call KCONFIG_ENABLE_OPT,CONFIG_VFAT_FS) endef LINUX_KCONFIG_FIXUP_CMDS += $(AIMEEOS_LINUX_CONFIG_FIXUPS) @@ -71,6 +76,8 @@ $(BR2_EXTERNAL_AIMEEOS_PATH)/boot/grub2/gen-grub-cfg.sh $(AIMEEOS_KERNEL_FILENAM endef LINUX_TARGET_FINALIZE_HOOKS += AIMEEOS_GEN_GRUB_CFG +BR2_ROOTFS_POST_IMAGE_SCRIPT += $(BR2_EXTERNAL_AIMEEOS_PATH)/update/make-package.sh + 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 index 2807f2b..04027ff 100644 --- a/package/aimee-os-utils/Config.in +++ b/package/aimee-os-utils/Config.in @@ -6,3 +6,5 @@ config BR2_PACKAGE_AIMEE_OS_UTILS select BR2_PACKAGE_UTIL_LINUX_MOUNTPOINT select BR2_PACKAGE_UTIL_LINUX_PARTX select BR2_PACKAGE_UTIL_LINUX_SWITCH_ROOT + select BR2_PACKAGE_WGET + select BR2_TARGET_GRUB2_INSTALL_TOOLS diff --git a/package/aimee-os-utils/aimee-os-utils.mk b/package/aimee-os-utils/aimee-os-utils.mk index 7952bee..28dde14 100644 --- a/package/aimee-os-utils/aimee-os-utils.mk +++ b/package/aimee-os-utils/aimee-os-utils.mk @@ -12,6 +12,13 @@ AIMEE_OS_UTILS_DEPENDENCIES = \ AIMEE_OS_UTILS_SOURCE = +define AIMEE_OS_UTILS_INSTALL_TARGET_CMDS +$(INSTALL) -D -m u=rwx,go=rx \ + $(AIMEE_OS_UTILS_PKGDIR)/system-update.sh \ + $(TARGET_DIR)/usr/sbin/system-update +mkdir -p $(TARGET_DIR)/boot/efi +endef + define AIMEE_OS_UTILS_INSTALL_INIT_SYSTEMD $(INSTALL) -D -m u=rw,go=r \ $(AIMEE_OS_UTILS_PKGDIR)/var.mount \ diff --git a/package/aimee-os-utils/system-update.sh b/package/aimee-os-utils/system-update.sh new file mode 100755 index 0000000..5e9c798 --- /dev/null +++ b/package/aimee-os-utils/system-update.sh @@ -0,0 +1,135 @@ +#!/bin/sh +# vim: set sw=4 ts=4 sts=4 et : + +cleanup() { + cd / + if [ -n "${workdir}" ] && [ "${workdir}" != / ]; then + rm -rf "${workdir}" + fi + unset workdir +} + +die() { + rc=$? + if [ $rc -eq 0 ]; then + rc=1 + fi + error "$@" + exit $rc +} + +error() { + if [ $# -eq 1 ]; then + echo "$1" >&2 + elif [ $# -gt 1 ]; then + printf "$@" >&2 + fi +} + +extract_update() { + zstd -dc update.tar.zstd | tar -x \ + || die 'Could not extract update source' + sha256sum -c digests \ + || die 'Invalid update source: checksum mismatch' +} + +fetch_update() { + wget -O update.tar.zstd "$1" +} + +get_root() { + set -- $(cat /proc/cmdline) + while [ $# -gt 0 ]; do + case "$1" in + root=*) + _root=${1#root=} + ;; + esac + shift + done + echo $(findfs "${_root}") +} + +get_partlabel() { + blkid -o value -s PARTLABEL "$1" +} + +help() { + usage +} + +info() { + if [ $# -eq 1 ]; then + echo "$1" >&2 + elif [ $# -gt 1 ]; then + printf "$@" >&2 + fi +} + +usage() { + printf 'usage: %s source_url\n' "${0##*/}" +} + +while [ $# -gt 0 ]; do + case "$1" in + --help) + help + exit 0 + ;; + *) + if [ -z "${source_url}" ]; then + source_url="$1" + else + usage >&2 + exit 2 + fi + ;; + esac + shift +done + +if [ -z "${source_url}" ]; then + usage >&2 + exit 2 +fi + +root=$(get_root) +partlabel=$(get_partlabel "${root}") + +case "${partlabel}" in +rootfs-a) + newpartlabel=rootfs-b + ;; +rootfs-b) + newpartlabel=rootfs-a + ;; +*) + die \ + 'Unsupported system configuration: invalid rootfs partition label: %s\n' \ + "${partlabel}" >&2 +esac +newroot=$(findfs PARTLABEL="${newpartlabel}") +if [ -z "${newroot}" ]; then + die 'Could not find partition with label %s\n' "${partlabel}" +fi +info 'Current rootfs: %s (%s)\n' "${partlabel}" "${root}" +info 'New rootfs: %s (%s)\n' "${newpartlabel}" "${newroot}" + +trap cleanup INT TERM QUIT EXIT +workdir=$(mktemp -d) +cd "${workdir}" + +fetch_update "${source_url}" || die 'Failed to fetch update source' +extract_update || die 'Failed to extact update source' +./install "${newroot}" || die 'Error installing system update' + +printf 'Do you want to reboot now? [y/N] ' +read confirm +case "${confirm}" in +[yY]|[yY][eE][sS]) + systemctl reboot + ;; +*) + info 'A reboot is required to complete the update' + ;; +esac diff --git a/update/install-update.sh b/update/install-update.sh new file mode 100755 index 0000000..bc01dd8 --- /dev/null +++ b/update/install-update.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# vim: set sw=4 ts=4 sts=4 et : + +EFIMOUNT=/boot/efi +GRUBENV=${EFIMOUNT}/EFI/BOOT/grubenv + +die() { + rc=$? + if [ $rc -eq 0 ]; then + rc=1 + fi + error "$@" + exit $rc +} + +error() { + printf 'ERROR: ' + info "$@" +} + +get_partuuid() { + blkid -o value -s PARTUUID "$1" +} + +info() { + if [ $# -eq 1 ]; then + echo "$1" >&2 + elif [ $# -gt 1 ]; then + printf "$@" >&2 + fi +} + +set_default_boot() { + _rc=0 + mkdir -p newroot || return + mount -oro "$1" newroot || return + _partuuid=$(get_partuuid "$1") + _id=id-${_partuuid} + printf 'Setting default boot entry to %s\n' "${_id}" + grub-editenv "${GRUBENV}" set "default=${_id}" || rc=$? + umount newroot + return $rc +} + +warn() { + printf 'WARNING: ' + info "$@" +} + +write_firmware() { + _rc=0 + _esp=$(findfs PARTLABEL='EFI System Partition') + if [ -z "${_esp}" ]; then + error 'Could not identify EFI System Partition' + return 1 + fi + if ! mountpoint -q "${EFIMOUNT}"; then + mount -o ro "${_esp}" "${EFIMOUNT}" \ + || warn 'Failed to mount EFI System Partition' + fi + if [ -f "${GRUBENV}" ]; then + info 'Saving current GRUB environment ...' + cp "${GRUBENV}" grubenv \ + || warn 'Failed to save GRUB environment' + fi + if mountpoint -q "${EFIMOUNT}"; then + umount "${EFIMOUNT}" || return + fi + info 'Writing firmware image to EFI System Partition (%s) ...\n' "${_esp}" + dd if=firmware.img of="${_esp}" bs=1M || _rc=$? + if [ $_rc -eq 0 ]; then + mount -orw "${_esp}" "${EFIMOUNT}" || rc=$? + fi + if [ $_rc -eq 0 ]; then + if [ -f grubenv ]; then + printf 'Restoring GRUB environment ...\n' + cp grubenv "${GRUBENV}" || _rc=$? + fi + fi + return $_rc +} + +write_rootfs() { + printf 'Writing rootfs image to %s ...\n' "$1" + dd if=rootfs.squashfs of="$1" bs=1M +} + +rc=0 +newroot="$1" + +write_rootfs "${newroot}" || die 'Failed to write new rootfs image to disk' +write_firmware || die 'Failed to write new firmware image to disk' +if ! set_default_boot "${newroot}"; then + rc=$? + error 'Failed to set default boot option' +fi + +if [ $rc -eq 0 ]; then + info 'Successfully installed update' +fi +exit $rc diff --git a/update/make-package.sh b/update/make-package.sh new file mode 100755 index 0000000..de0879a --- /dev/null +++ b/update/make-package.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# vim: set sw=4 ts=4 sts=4 et : + +UPDATE_PACKAGE=update.tar.zstd +SRCDIR=$(realpath "${0%/*}") + +cd "${BINARIES_DIR}" +printf 'Creating %s/%s\n' "${BINARIES_DIR}" "${UPDATE_PACKAGE}" >&2 +sha256sum firmware.img > digests || exit +sha256sum rootfs.squashfs >> digests || exit +cp -u "${SRCDIR}"/install-update.sh install || exit +tar -c --zstd -f "${UPDATE_PACKAGE}" \ + digests \ + firmware.img \ + rootfs.squashfs \ + install \ + || exit