From 89c748bf051c4330d0893ac1db95eb0ddba3ddfd Mon Sep 17 00:00:00 2001 From: Hangfan Li Date: Thu, 4 Sep 2025 16:59:29 +0800 Subject: [PATCH] just work (TM) --- Dockerfile | 12 +- Makefile | 28 ++- functions.mk | 104 +++++++-- .../24.03-lts-sp1/userspace/base/receipe.mk | 2 +- .../24.03-lts-sp2/bsp/spacemit-k1/board.mk | 0 .../40-kenel-preq/post.d/50-dracut/entry.sh | 0 .../post.d/50-u-boot-menu/entry.sh | 0 .../post.d/50-u-boot-menu/u-boot | 6 - .../24.03-lts-sp2/bsp/spacemit-k1/device.mk | 3 + .../xfce4/packages.d/99-extension.list | 1 + .../image-layout.conf | 17 +- .../packages.d/40-kenel-preq/packages.list | 0 .../post.d/50-dracut/50-spacemit_k1_fw.conf | 0 .../40-kenel-preq/post.d/50-dracut/entry.sh | 3 + .../40-kenel-preq/post.d/50-fstab/entry.sh | 6 + .../post.d/50-u-boot-menu/entry.sh | 12 + .../packages.d/60-kernel/packages.list | 0 .../bsp/spacemit-k1/extlinux/profile.mk | 1 + .../repos.d/bsp.repo | 0 receipes/openeuler/24.03-lts-sp2/release.mk | 1 + .../24.03-lts-sp2/userspace/base/receipe.mk | 2 +- .../24.03-lts-sp2/userspace/xfce4/receipe.mk | 2 +- tools/build_bsp.sh | 137 ++++++++++++ tools/build_rootfs.sh | 128 +---------- tools/fs_helper/ext4.sh | 28 +++ tools/fs_helper/vfat.sh | 23 ++ tools/image_creation_helper.sh | 97 +++++++++ tools/image_helper/partitioned_disk.sh | 43 ++++ tools/image_layout_helper.sh | 70 ++++++ tools/imgcat.sh | 137 ------------ tools/{ => partition_table_helper}/gptcfg.sh | 29 ++- tools/partition_table_helper/guid.sh | 206 ++++++++++++++++++ tools/receipe_helper.sh | 114 ++++++++++ 33 files changed, 907 insertions(+), 305 deletions(-) delete mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/board.mk delete mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh delete mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh delete mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/u-boot create mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/device.mk create mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/extensions/xfce4/packages.d/99-extension.list rename receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/{bootstd-extlinux => extlinux}/image-layout.conf (60%) rename receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/{bootstd-extlinux => extlinux}/packages.d/40-kenel-preq/packages.list (100%) rename receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/{bootstd-extlinux => extlinux}/packages.d/40-kenel-preq/post.d/50-dracut/50-spacemit_k1_fw.conf (100%) create mode 100755 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh create mode 100755 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-fstab/entry.sh create mode 100755 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh rename receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/{bootstd-extlinux => extlinux}/packages.d/60-kernel/packages.list (100%) create mode 100644 receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/profile.mk rename receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/{bootstd-extlinux => extlinux}/repos.d/bsp.repo (100%) create mode 100755 tools/build_bsp.sh create mode 100644 tools/fs_helper/ext4.sh create mode 100644 tools/fs_helper/vfat.sh create mode 100644 tools/image_creation_helper.sh create mode 100644 tools/image_helper/partitioned_disk.sh create mode 100644 tools/image_layout_helper.sh delete mode 100755 tools/imgcat.sh rename tools/{ => partition_table_helper}/gptcfg.sh (93%) create mode 100644 tools/partition_table_helper/guid.sh create mode 100644 tools/receipe_helper.sh diff --git a/Dockerfile b/Dockerfile index 88475b8..8deb9dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,10 +4,14 @@ RUN sed -i 's/metalink=/# metalink=/g' /etc/yum.repos.d/openEuler.repo && \ sed -i 's/repo.openeuler.org/mirror.isrc.ac.cn\/openeuler/g' /etc/yum.repos.d/openEuler.repo RUN yum install -y \ - tar \ - zstd \ - gzip \ - xz \ bzip2 \ + dosfstools \ findutils \ + gdisk \ + gzip \ + rsync \ + tar \ + util-linux \ + xz \ + zstd \ && yum clean all diff --git a/Makefile b/Makefile index 171a74d..b71ab96 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ CONTAINER_CMD ?= docker CONTAINER_IMAGE_TAG ?= imagebuilder-openeuler-24.03-lts define stack_include -$$(info Makefile "$$(lastword $$(MAKEFILE_STACK))" includes "$1") +#$$(info Makefile "$$(lastword $$(MAKEFILE_STACK))" includes "$1") MAKEFILE_STACK += $1 CURRENT_MAKEFILE := $$(lastword $$(MAKEFILE_STACK)) CURRENT_DIR := $$(dir $$(CURRENT_MAKEFILE)) @@ -48,10 +48,33 @@ $(eval $(call stack_include,$(CURRENT_DIR)receipes/receipes.mk)) .PHONY: all_rootfs all_rootfs: $(ROOTFS_TARGETS) +.PHONY: all_bsp +all_bsp: $(BSP_TARGETS) + +.PHONY: list_rootfs +list_rootfs: + @echo $(ROOTFS_TARGETS) + +.PHONY: list_bsp +list_bsp: + @echo $(BSP_TARGETS) + +.PHONY: list +list: + @echo "ROOTFS targets:" + @echo "$(ROOTFS_TARGETS)" | tr ' ' '\n' + @echo + @echo "BSP targets:" + @echo "$(BSP_TARGETS)" | tr ' ' '\n' + .PHONY: clean clean: rm -rf "$(WORK_DIR)" +.PHONY: clean_staging +clean_staging: + rm -rf "$(STAGING_DIR)" + .PHONY: container container: $(CONTAINER_CMD) build -t $(CONTAINER_IMAGE_TAG) $(ROOT_DIR) @@ -59,4 +82,5 @@ container: .PHONY: .test .test: - @echo $(MAKEFILE_STACK) + @echo $(ROOTFS_TARGETS) + @echo $(BSP_TARGETS) diff --git a/functions.mk b/functions.mk index e322718..b5db9eb 100644 --- a/functions.mk +++ b/functions.mk @@ -41,6 +41,8 @@ ifndef RELEASE_NAME $$(error RELEASE_NAME not provided) endif +$$(DISTRO_NAME)_$$(RELEASE_NAME)_RECEIPES := + undefine RELEASE_NAME endef @@ -53,7 +55,7 @@ endif # Cleanup and register new receipe undefine RECEIPE_NAME -undefine ROOTFS_COMPRESSION +undefine COMPRESSION undefine EXTENDS $$(eval $$(call stack_include,$1/receipe.mk)) @@ -63,16 +65,17 @@ ifndef RECEIPE_NAME $$(error RECEIPE_NAME not defined) endif # Check compression method -ifeq ($$(ROOTFS_COMPRESSION),zstd) -ROOTFS_COMPRESSION_SUFFIX := tar.zst -ROOTFS_COMPRESSION_CMD := tar --use-compress-program=zstd -cf "$$$$$$$${OUTPUT_ARCHIVE}" -C "$$$$$$$${ROOTFS_DIR}" . +ifeq ($$(COMPRESSION),zstd) +COMPRESSION_SUFFIX := tar.zst +COMPRESSION_CMD := tar --use-compress-program=zstd -cf "$$$$$$$${OUTPUT_ARCHIVE}" -C "$$$$$$$${ROOTFS_DIR}" . else $$(error Unsupported compression mode) endif # Define global references +$$(DISTRO_NAME)_$$(RELEASE_NAME)_RECEIPES := $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_RECEIPES) $$(RECEIPE_NAME) $$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_DIR := $1 -$$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT := $(DIST_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/$$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(RECEIPE_NAME)-rootfs.$$(ROOTFS_COMPRESSION_SUFFIX) +$$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT := $(DIST_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/$$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(RECEIPE_NAME)-rootfs.$$(COMPRESSION_SUFFIX) ROOTFS_TARGETS += $$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(RECEIPE_NAME)-rootfs # Populate workdir @@ -84,8 +87,6 @@ endif endef $$(foreach dep,$$(EXTENDS),$$(eval $$(call check_receipe_exist,$$(dep)))) undefine check_receipe_exist -# Directory timestamp is not reliable so always resync staging dir -.PHONY: $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/receipes/$$(RECEIPE_NAME) $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/receipes/$$(RECEIPE_NAME): $$(foreach depname,$$(EXTENDS),$$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(depname)_DIR)) $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_DIR) $$(dir_guard) rm -rf "$$@" @@ -96,11 +97,11 @@ $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/receipes/$$(RECEIPE_NAME): $$(fo .PHONY: $$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(RECEIPE_NAME)-rootfs $$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(RECEIPE_NAME)-rootfs: $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT) define GENERATE_TAR_TARGET -$$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT): $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/receipes/$$(RECEIPE_NAME) +$$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT): | $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/receipes/$$(RECEIPE_NAME) $$$$(dir_guard) $(CONTAINER_CMD) run --rm \ -v $(ROOT_DIR)/tools:/image-builder/tools:ro \ - -v $$$$+:/image-builder/receipe:ro \ + -v $$$$|:/image-builder/receipe:ro \ -v $$$$(dir $$$$@):/image-builder/output \ $(CONTAINER_IMAGE_TAG) \ /bin/sh -c ' \ @@ -109,7 +110,7 @@ $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(RECEIPE_NAME)_ARTIFACT): $(STAGING_DIR)/$ ./build_rootfs.sh -i /image-builder/receipe -o /tmp/rootfs -p $$(PACKAGE_MANAGER) && \ export OUTPUT_ARCHIVE=/image-builder/output/$$$$(notdir $$$$@) && \ export ROOTFS_DIR=/tmp/rootfs && \ - $$(ROOTFS_COMPRESSION_CMD)' + $$(COMPRESSION_CMD)' endef $$(eval $$(GENERATE_TAR_TARGET)) @@ -117,9 +118,86 @@ $$(eval $$(GENERATE_TAR_TARGET)) # Reset registers again undefine GENERATE_TAR_TARGET undefine EXTENDS -undefine ROOTFS_COMPRESSION_CMD -undefine ROOTFS_COMPRESSION_SUFFIX -undefine ROOTFS_COMPRESSION +undefine COMPRESSION_CMD +undefine COMPRESSION_SUFFIX +undefine COMPRESSION undefine RECEIPE_NAME endef + +######## +define add_device +ifndef RELEASE_NAME +$$(error Not within distro release section) +endif +ifdef DEVICE_NAME +$$(error Nested device section is not allowed! Currently in "$$(DISTRO_NAME) $$(RELEASE_NAME) $$(DEVICE_NAME)") +endif + +undefine DEVICE_NAME + +$$(eval $$(call stack_include,$1/device.mk)) + +ifndef DEVICE_NAME +$$(error DEVICE_NAME not provided) +endif + +undefine DEVICE_NAME +endef + + +######## +define add_device_profile +ifndef DEVICE_NAME +$$(error Not within device section) +endif +ifdef PROFILE_NAME +$$(error Nested profile section is not allowed! Currently in "$$(DISTRO_NAME) $$(RELEASE_NAME) $$(DEVICE_NAME)" $$(PROFILE_NAME)) +endif + +undefine PROFILE_NAME + +$$(eval $$(call stack_include,$1/profile.mk)) + +ifndef PROFILE_NAME +$$(error PROFILE_NAME not provided) +endif + +BSP_PROFILE_DIR := $1 + +define GENERATE_RECEIPE_PROFILE_MATRIX +BSP_TARGETS += $$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(1)-$$(DEVICE_NAME)-$$(PROFILE_NAME) +$$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(1)-$$(DEVICE_NAME)_PROFILES += $$(PROFILE_NAME) + +.PHONY: $$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(1)-$$(DEVICE_NAME)-$$(PROFILE_NAME) +$$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(1)-$$(DEVICE_NAME)-$$(PROFILE_NAME): $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/bsp/$$(PROFILE_NAME)/$$(1) $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(1)_ARTIFACT) + @mkdir -p $(DIST_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/$$(DEVICE_NAME) + $(CONTAINER_CMD) run --privileged --rm \ + -v $(ROOT_DIR)/tools:/image-builder/tools:ro \ + -v $$$$<:/image-builder/receipe:ro \ + -v $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(1)_ARTIFACT):/image-builder/$$(notdir $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(1)_ARTIFACT)):ro \ + -v $(DIST_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/$$(DEVICE_NAME):/image-builder/output \ + $(CONTAINER_IMAGE_TAG) \ + /bin/sh -c ' set -x && \ + cd /image-builder/tools && \ + LOG_LEVEL=DEBUG ./build_bsp.sh -i /image-builder/receipe -s /image-builder/$$(notdir $$($$(DISTRO_NAME)_$$(RELEASE_NAME)_$$(1)_ARTIFACT)) -o /image-builder/output/$$(DISTRO_NAME)-$$(RELEASE_NAME)-$$(1)-$$(DEVICE_NAME)-$$(PROFILE_NAME) -p $$(PACKAGE_MANAGER)' + +ifneq ($$$$(wildcard $$(BSP_PROFILE_DIR)/extensions/$$(1)/.),) +# corresponding extension exists +BSP_PROFILE_EXTENSION_DIR := $$(BSP_PROFILE_DIR)/extensions/$$(1) +endif + +.PHONY: $(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/bsp/$$(PROFILE_NAME)/$$(1) +$(STAGING_DIR)/$$(DISTRO_NAME)/$$(RELEASE_NAME)/bsp/$$(PROFILE_NAME)/$$(1): $$$$(BSP_PROFILE_DIR) $$$$(BSP_PROFILE_EXTENSION_DIR) + $$$$(dir_guard) + rm -rf "$$@" + @# Not preserving modification time, aka -t + rsync -rlpgoD --exclude profile.mk --exclude extensions $$$$(foreach dep,$$$$+,$$$$(dep)/) $$$$@ + +endef +$$(foreach receipe,$$($$(DISTRO_NAME)_$$(RELEASE_NAME)_RECEIPES),$$(eval $$(call GENERATE_RECEIPE_PROFILE_MATRIX,$$(receipe)))) + +undefine PROFILE_NAME +undefine BSP_PROFILE_DIR +undefine GENERATE_RECEIPE_PROFILE_MATRIX +endef diff --git a/receipes/openeuler/24.03-lts-sp1/userspace/base/receipe.mk b/receipes/openeuler/24.03-lts-sp1/userspace/base/receipe.mk index ea28953..32b1af8 100644 --- a/receipes/openeuler/24.03-lts-sp1/userspace/base/receipe.mk +++ b/receipes/openeuler/24.03-lts-sp1/userspace/base/receipe.mk @@ -1,2 +1,2 @@ RECEIPE_NAME := base -ROOTFS_COMPRESSION := zstd +COMPRESSION := zstd diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/board.mk b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/board.mk deleted file mode 100644 index e69de29..0000000 diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh deleted file mode 100644 index e69de29..0000000 diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh deleted file mode 100644 index e69de29..0000000 diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/u-boot b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/u-boot deleted file mode 100644 index 47e7670..0000000 --- a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/u-boot +++ /dev/null @@ -1,6 +0,0 @@ -U_BOOT_PROMPT="2" -U_BOOT_MENU_LABEL="OpenEuler GNU/Linux, kernel" -# tty enabled on both serial0 and fbdev -U_BOOT_PARAMETERS="rootwait rw earlycon=sbi console=tty0 console=ttyS0,115200 rd.multipath=0" -U_BOOT_ROOT= -U_BOOT_FDT_DIR="/dtb-" diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/device.mk b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/device.mk new file mode 100644 index 0000000..c2d350a --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/device.mk @@ -0,0 +1,3 @@ +DEVICE_NAME := SpacemiT-K1 + +$(foreach profile_dir,$(filter-out %.mk,$(wildcard $(CURRENT_DIR)*)),$(eval $(call add_device_profile,$(profile_dir)))) diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/extensions/xfce4/packages.d/99-extension.list b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/extensions/xfce4/packages.d/99-extension.list new file mode 100644 index 0000000..4a6bca2 --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/extensions/xfce4/packages.d/99-extension.list @@ -0,0 +1 @@ +linux-firmware diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/image-layout.conf b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/image-layout.conf similarity index 60% rename from receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/image-layout.conf rename to receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/image-layout.conf index 8a040f1..8a1308e 100644 --- a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/image-layout.conf +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/image-layout.conf @@ -1,23 +1,24 @@ -DISK_TABLE_TYPE=GUID +OUTPUT_FORMAT=partitioned_disk +PARTITION_TABLE_TYPE=GUID PARTITION_1_OFFSET=1MB -PARTITION_1_LENGTH=499MB +PARTITION_1_SIZE=499M PARTITION_1_NAME="oerv-boot" PARTITION_1_UUID= PARTITION_1_TYPE=bls_boot PARTITION_1_ATTRS=legacy_boot PARTITION_1_USAGE=MOUNTPOINT -PARTITION_1_MOUNTPONT="/boot" -PARTITION_1_FILESYSTEM=vfat +PARTITION_1_MOUNTPOINT="/boot" +PARTITION_1_FS=vfat PARTITION_1_FS_UUID= PARTITION_2_OFFSET= -PARTITION_2_LENGTH= +PARTITION_2_SIZE= PARTITION_2_NAME="oerv-root" PARTITION_2_UUID= PARTITION_2_TYPE=linux_root_riscv64 PARTITION_2_ATTRS= PARTITION_2_USAGE=MOUNTPOINT -PARTITION_2_MOUNTPONT="/" -PARTITION_1_FILESYSTEM=ext4 -PARTITION_1_FS_UUID= +PARTITION_2_MOUNTPOINT="/" +PARTITION_2_FS=ext4 +PARTITION_2_FS_UUID= diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/packages.list b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/packages.list similarity index 100% rename from receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/packages.list rename to receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/packages.list diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-dracut/50-spacemit_k1_fw.conf b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/50-spacemit_k1_fw.conf similarity index 100% rename from receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/40-kenel-preq/post.d/50-dracut/50-spacemit_k1_fw.conf rename to receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/50-spacemit_k1_fw.conf diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh new file mode 100755 index 0000000..dc003ce --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-dracut/entry.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +cp 50-spacemit_k1_fw.conf "${ROOTFS_DIR}/etc/dracut.conf.d/" diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-fstab/entry.sh b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-fstab/entry.sh new file mode 100755 index 0000000..96725e9 --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-fstab/entry.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +cat << EOF | column -t | tee "${ROOTFS_DIR}/etc/fstab" +UUID=$($get_fs_uuid_by_mountpoint /) / ext4 errors=remount-ro 0 1 +UUID=$($get_fs_uuid_by_mountpoint /boot) /boot vfat defaults 0 2 +EOF diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh new file mode 100755 index 0000000..4abe683 --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/40-kenel-preq/post.d/50-u-boot-menu/entry.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +. "${ROOTFS_DIR}/etc/os-release" + +cat << EOF | tee "${ROOTFS_DIR}/etc/default/u-boot" +U_BOOT_PROMPT="2" +U_BOOT_MENU_LABEL="${PRETTY_NAME}" +# tty enabled on both serial0 and fbdev +U_BOOT_PARAMETERS="rootwait rw earlycon=sbi console=tty0 console=ttyS0,115200 rd.multipath=0" +U_BOOT_ROOT=$($get_fs_uuid_by_mountpoint /) +U_BOOT_FDT_DIR="/dtb-" +EOF diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/60-kernel/packages.list b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/60-kernel/packages.list similarity index 100% rename from receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/packages.d/60-kernel/packages.list rename to receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/packages.d/60-kernel/packages.list diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/profile.mk b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/profile.mk new file mode 100644 index 0000000..185b51e --- /dev/null +++ b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/profile.mk @@ -0,0 +1 @@ +PROFILE_NAME := extlinux diff --git a/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/repos.d/bsp.repo b/receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/repos.d/bsp.repo similarity index 100% rename from receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/bootstd-extlinux/repos.d/bsp.repo rename to receipes/openeuler/24.03-lts-sp2/bsp/spacemit-k1/extlinux/repos.d/bsp.repo diff --git a/receipes/openeuler/24.03-lts-sp2/release.mk b/receipes/openeuler/24.03-lts-sp2/release.mk index ee75186..30eb3d2 100644 --- a/receipes/openeuler/24.03-lts-sp2/release.mk +++ b/receipes/openeuler/24.03-lts-sp2/release.mk @@ -1,3 +1,4 @@ RELEASE_NAME := 24.03-LTS-SP2 $(foreach receipe_dir,$(filter-out %.mk,$(wildcard $(CURRENT_DIR)userspace/*)),$(eval $(call add_receipe,$(receipe_dir)))) +$(foreach device_dir,$(filter-out %.mk,$(wildcard $(CURRENT_DIR)bsp/*)),$(eval $(call add_device,$(device_dir)))) diff --git a/receipes/openeuler/24.03-lts-sp2/userspace/base/receipe.mk b/receipes/openeuler/24.03-lts-sp2/userspace/base/receipe.mk index ea28953..32b1af8 100644 --- a/receipes/openeuler/24.03-lts-sp2/userspace/base/receipe.mk +++ b/receipes/openeuler/24.03-lts-sp2/userspace/base/receipe.mk @@ -1,2 +1,2 @@ RECEIPE_NAME := base -ROOTFS_COMPRESSION := zstd +COMPRESSION := zstd diff --git a/receipes/openeuler/24.03-lts-sp2/userspace/xfce4/receipe.mk b/receipes/openeuler/24.03-lts-sp2/userspace/xfce4/receipe.mk index 3b72960..9983d70 100644 --- a/receipes/openeuler/24.03-lts-sp2/userspace/xfce4/receipe.mk +++ b/receipes/openeuler/24.03-lts-sp2/userspace/xfce4/receipe.mk @@ -1,3 +1,3 @@ RECEIPE_NAME := xfce4 -ROOTFS_COMPRESSION := zstd +COMPRESSION := zstd EXTENDS := base diff --git a/tools/build_bsp.sh b/tools/build_bsp.sh new file mode 100755 index 0000000..f053030 --- /dev/null +++ b/tools/build_bsp.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env sh +# shellcheck shell=dash disable=SC2317 +# Unreachable Detection is disabled as the script relies on indirect call. + +set -o errexit +set -o nounset + +. ./logging.sh + +RECEIPE_DIR="" +ROOTFS_ARCHIVE="" +PACKAGE_MANAGER="" +OUTPUT_PREFIX="" + +ROOTFS_DIR="" + +. ./receipe_helper.sh +. ./fs_helper/vfat.sh +. ./fs_helper/ext4.sh +. ./partition_table_helper/guid.sh +. ./image_layout_helper.sh +. ./image_creation_helper.sh + +parse_image_layout() { + logi "Parsing image layout" + + # Introduce subshell for isolated env vars + image_layout_info="$(parse_image_layout_impl)" + logdraw "${image_layout_info}" +} + +create_image() { + logi "Creating image" + (eval "${image_layout_info}" && create_image_impl) +} + +generate_bsp() { + # Pre-process image layout for subsequent post-install scripts + parse_image_layout + + # Prepare pre-built rootfs + ROOTFS_DIR="$(mktemp -d)" + logi "Extracting pre-built rootfs to ${ROOTFS_DIR}" + tar -xf "${ROOTFS_ARCHIVE}" -C "${ROOTFS_DIR}" + + setup_repo + + SCRIPT_ENV_SETUP_CMD=" +export ROOTFS_DIR=${ROOTFS_DIR} && +$(echo "${image_layout_info}" | sed -E 's/^(.+)$/export \1 \&\& /') +export get_fs_uuid_by_mountpoint='${get_fs_uuid_by_mountpoint}' && +" + install_packages "${SCRIPT_ENV_SETUP_CMD}" + post_scripts "${SCRIPT_ENV_SETUP_CMD}" + create_image + + # Clean up + rm -rf "${ROOTFS_DIR}" +} + +print_usage() { + # Keep help message within 80 cols for special consoles. + cat << EOF + +Usage: $0 [-hp] [-i input [-i input [...]]] output + -h Print this help message. + -s rootfs Path to pre-built rootfs archive + -i receipe Path to BSP receipe directory + -p package_manager + Specify which package manager should be + used. + -o output Prefix for generated files +Environment Variables: + LOG_LEVEL Controls the log level of this script. + One of: DEBUG, INFO, WARN, ERROR + Defaults to: INFO +EOF +} + +main() { + # Handling args + while getopts "i:o:p:s:h" o; do + case "${o}" in + h) + print_usage + exit 0 + ;; + i) + RECEIPE_DIR=${OPTARG} + ;; + s) + ROOTFS_ARCHIVE=${OPTARG} + ;; + p) + PACKAGE_MANAGER=${OPTARG} + ;; + o) + OUTPUT_PREFIX=${OPTARG} + ;; + *) + exit 1 + ;; + esac + done + shift $((OPTIND-1)) + + logi "BSP Builder" + + # Validate inputs + if [ -z "${RECEIPE_DIR}" ]; then + loge "No receipe is specified!" + exit 1 + fi + if [ -z "${ROOTFS_ARCHIVE}" ]; then + loge "No output dir is specified!" + exit 1 + fi + if [ -z "${OUTPUT_PREFIX}" ]; then + loge "No output dir is specified!" + exit 1 + fi + if [ -z "${PACKAGE_MANAGER}" ]; then + loge "No package manager is specified!" + exit 1 + fi + + logi "Using receipe: ${RECEIPE_DIR}" + logi "- ROOTFS_ARCHIVE: ${ROOTFS_ARCHIVE}" + logi "- PACKAGE_MANAGER: ${PACKAGE_MANAGER}" + logi "- OUTPUT_PREFIX: ${OUTPUT_PREFIX}" + + generate_bsp + + exit 0 +} + +main "$@" diff --git a/tools/build_rootfs.sh b/tools/build_rootfs.sh index 3ef7229..af3595e 100755 --- a/tools/build_rootfs.sh +++ b/tools/build_rootfs.sh @@ -11,125 +11,15 @@ RECEIPE_DIR="" ROOTFS_DIR="" PACKAGE_MANAGER="" - -is_function() { - type "$1" 2>/dev/null | head -n 1 | grep 'function' > /dev/null -} - -setup_repo_yum() { - mkdir -p "${ROOTFS_DIR}/etc/yum.repos.d" - cp "${RECEIPE_DIR}"/repos.d/* "${ROOTFS_DIR}/etc/yum.repos.d" -} - -setup_repo() { - logi "Preconfiguring package repo..." - setup_repo_func="setup_repo_${PACKAGE_MANAGER}" - if ! is_function "${setup_repo_func}" ; then - loge "Package manager ${PACKAGE_MANAGER} not supported yet." - exit 1 - fi - "setup_repo_${PACKAGE_MANAGER}" -} - -execute_script_dir() { - script_dir="$1" - - find "${script_dir}" -maxdepth 1 -mindepth 1 -type d,l | sort | \ - while IFS= read -r line; do - logi "Executing scripts: ${line}" - bash -c " - cd ${line} && - export ROOTFS_DIR=${ROOTFS_DIR} && - ${line}/entry.sh - " - done -} - -install_package_cleanup_yum() { - yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" clean all -} - -install_package_cleanup() { - logi "Cleanup package installation" - install_package_cleanup_func="install_package_cleanup_${PACKAGE_MANAGER}" - if ! is_function "${install_package_cleanup_func}" ; then - loge "Package manager ${PACKAGE_MANAGER} not supported yet." - exit 1 - fi - "install_package_cleanup_${PACKAGE_MANAGER}" -} - -install_package_list_yum() { - # shellcheck shell=dash disable=SC2086 - yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" -y install $1 -} - -install_package_list() { - logi "Installing package list: $1" - install_package_list_func="install_package_list_${PACKAGE_MANAGER}" - if ! is_function "${install_package_list_func}" ; then - loge "Package manager ${PACKAGE_MANAGER} not supported yet." - exit 1 - fi - "install_package_list_${PACKAGE_MANAGER}" "$(tr '\n' ' ' < "$1")" -} - -install_package_group_yum() { - # shellcheck shell=dash disable=SC2086 - yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" -y groupinstall $1 -} - -install_package_group() { - logi "Installing package group: $1" - install_package_group_func="install_package_group_${PACKAGE_MANAGER}" - if ! is_function "${install_package_group_func}" ; then - loge "Package manager ${PACKAGE_MANAGER} not supported yet." - exit 1 - fi - "install_package_group_${PACKAGE_MANAGER}" "$(tr '\n' ' ' < "$1")" -} - -install_packages() { - logi "Install packages..." - find "${RECEIPE_DIR}"/packages.d/ -maxdepth 1 -mindepth 1 -type f,d,l | sort | \ - while IFS= read -r line; do - actualpath="$(readlink -f "${line}")" - if [ -d "${actualpath}" ]; then - if [ -f "${line}/packages.list" ]; then - install_package_list "${line}/packages.list" - elif [ -f "${line}/packages.group" ]; then - install_package_group "${line}/packages.group" - else - logw "No package list, ignoring ${line}" - continue - fi - if [ -d "${line}/post.d" ]; then - execute_script_dir "${line}/post.d" - fi - elif [ -f "${actualpath}" ]; then - if echo "${line}" | grep ".*.list" > /dev/null; then - install_package_list "${line}" - elif echo "${line}" | grep ".*.group" > /dev/null; then - install_package_group "${line}" - else - logw "Unsupported package list, ignoring ${line}" - fi - fi - done - install_package_cleanup -} - -post_scripts() { - if [ -d "$(readlink -f "${RECEIPE_DIR}/post.d")" ]; then - logi "Post configuring..." - execute_script_dir "${RECEIPE_DIR}/post.d" - fi -} +. ./receipe_helper.sh generate_rootfs() { + SCRIPT_ENV_SETUP_CMD=" +export ROOTFS_DIR=${ROOTFS_DIR} && +" setup_repo - install_packages - post_scripts + install_packages "${SCRIPT_ENV_SETUP_CMD}" + post_scripts "${SCRIPT_ENV_SETUP_CMD}" } print_usage() { @@ -176,7 +66,7 @@ main() { done shift $((OPTIND-1)) - logi "ImageBuilder" + logi "RootFS Builder" # Validate inputs if [ -z "${RECEIPE_DIR}" ]; then @@ -187,6 +77,10 @@ main() { loge "No output dir is specified!" exit 1 fi + if [ -z "${PACKAGE_MANAGER}" ]; then + loge "No package manager is specified!" + exit 1 + fi logi "Using receipe: ${RECEIPE_DIR}" logi "- ROOTFS_DIR: ${ROOTFS_DIR}" diff --git a/tools/fs_helper/ext4.sh b/tools/fs_helper/ext4.sh new file mode 100644 index 0000000..f575a68 --- /dev/null +++ b/tools/fs_helper/ext4.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env false + +filesystem_generate_uuid_ext4() { + uuidgen +} + +filesystem_validate_uuid_ext4() { + echo "${1}" | sed -n '/^[0-9a-fA-F]\{8\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{12\}$/!q1' +} + +filesystem_set_uuid_ext4() { + device="${1}" + uuid="${2}" + if ! filesystem_validate_uuid_vfat "${uuid}"; then + loge "Invalid vfat serial number: ${uuid}" + exit 1 + fi + tune2fs -U "${uuid}" "${device}" +} + +filesystem_make_fs_ext4() { + mkfs.ext4 "${1}" +} + +filesystem_shrink_ext4() { + e2fsck -y -f "${1}" + for i in $(seq 1 10); do resize2fs -M "${1}"; done +} diff --git a/tools/fs_helper/vfat.sh b/tools/fs_helper/vfat.sh new file mode 100644 index 0000000..00ee17e --- /dev/null +++ b/tools/fs_helper/vfat.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env false + +filesystem_generate_uuid_vfat() { + hexdump -vn4 -e'1/2 "%04X" 1 "-" 1/2 "%04X" 1 "\n"' /dev/urandom +} + +filesystem_validate_uuid_vfat() { + echo "${1}" | sed -n '/^[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}$/!q1' +} + +filesystem_set_uuid_vfat() { + device="${1}" + uuid="${2}" + if ! filesystem_validate_uuid_vfat "${uuid}"; then + loge "Invalid vfat serial number: ${uuid}" + exit 1 + fi + mlabel -N "$(echo "${uuid}" | tr -d '-')" -i "${device}" +} + +filesystem_make_fs_vfat() { + mkfs.vfat "${1}" +} diff --git a/tools/image_creation_helper.sh b/tools/image_creation_helper.sh new file mode 100644 index 0000000..83012fa --- /dev/null +++ b/tools/image_creation_helper.sh @@ -0,0 +1,97 @@ +. ./image_helper/partitioned_disk.sh + +prepare_fs_blocks() { + for fs_idx in ${MOUNTPOINT_SORTED_IDX}; do + fs_mountpoint="FILESYSTEM_${fs_idx}_MOUNTPOINT" + fs_mountpoint="${!fs_mountpoint}" + fs_format="FILESYSTEM_${fs_idx}_FORMAT" + fs_format="${!fs_format}" + fs_size="FILESYSTEM_${fs_idx}_CONTAINER_SIZE" + fs_size="${!fs_size}" + + if [ "${fs_size}" -eq 0 ]; then + # Flex-size partition + # Allocating block file based on real disk usage + real_usage_size="$(du -b -s "${ROOTFS_DIR}${fs_mountpoint}" | cut -f 1)" + # Round-up at least 512 MB + fs_size="$(( ((real_usage_size + 512 * 1024 * 1024) / 1024 / 1024 / 1024 + 1) * 1024 * 1024 * 1024))" + logi "Allocating ${fs_size}B for flex-size mountpoint \"${fs_mountpoint}\"" + else + # Make sure real usage does not exceed constraint + real_usage_size="$(du -b -s "${ROOTFS_DIR}${fs_mountpoint}" | cut -f 1)" + if [ "${real_usage_size}" -gt "${fs_size}" ]; then + loge "Filesystem usage (${real_usage_size}B) exceeds limitation (${fs_size}B)" + exit 1 + fi + logi "Allocating ${fs_size}B for mountpoint \"${fs_mountpoint}\"" + fi + fs_content="${FS_IMG_DIR}/$(echo "${fs_mountpoint}" | tr '/' ':').${fs_format}" + eval "FILESYSTEM_${fs_idx}_CONTENT=${fs_content}" + truncate -s "${fs_size}" "${fs_content}" + "filesystem_make_fs_${fs_format}" "${fs_content}" + + logi "Mounting \"${fs_mountpoint}\" at \"${ROOTFS_MNT}${fs_mountpoint}\"" + mkdir -p "${ROOTFS_MNT}${fs_mountpoint}" + mount "${fs_content}" "${ROOTFS_MNT}${fs_mountpoint}" + done +} + +post_fs_blocks() { + for fs_idx in $(echo "${MOUNTPOINT_SORTED_IDX}" | rev); do + fs_mountpoint="FILESYSTEM_${fs_idx}_MOUNTPOINT" + fs_mountpoint="${!fs_mountpoint}" + logi "Unmounting \"${fs_mountpoint}\" at \"${ROOTFS_MNT}${fs_mountpoint}\"" + umount "${ROOTFS_MNT}${fs_mountpoint}" + + # Shrink filesystem if flex-size + fs_size="FILESYSTEM_${fs_idx}_CONTAINER_SIZE" + fs_size="${!fs_size}" + fs_format="FILESYSTEM_${fs_idx}_FORMAT" + fs_format="${!fs_format}" + if [ "${fs_size}" -eq 0 ]; then + if ! is_function "filesystem_shrink_${fs_format}" ; then + loge "Shrinking ${fs_format} is not supported yet." + exit 1 + fi + fs_content="FILESYSTEM_${fs_idx}_CONTENT" + fs_content="${!fs_content}" + "filesystem_shrink_${fs_format}" "${fs_content}" + shrinked_size="$(du --apparent-size -b -s "${fs_content}" | cut -f 1)" + logi "Shrinking filesystem mounted at \"${fs_mountpoint}\" to ${shrinked_size}B" + fi + done +} + +create_fs_mountpoint_content() { + ROOTFS_MNT="${WORK_DIR}/mnt" + FS_IMG_DIR="${WORK_DIR}/content/fs" + + mkdir -p "${ROOTFS_MNT}" + mkdir -p "${FS_IMG_DIR}" + + # Create and mount the filesystem block + prepare_fs_blocks + # Restore plain rootfs onto structured mountpoint + logi "Copy files" + rsync -ah "${ROOTFS_DIR}/" "${ROOTFS_MNT}" + # Umount and shrink (if necessary) + post_fs_blocks + + rm -rf "${ROOTFS_MNT}" +} + +create_image_impl() { + if ! is_function "create_image_impl_${OUTPUT_FORMAT}"; then + loge "Image type \"${OUTPUT_FORMAT}\" not implemented" + exit 1 + fi + + WORK_DIR="$(mktemp -d)" + + # Dealing with fs mountpoint separately as it may operate over multiple segments + create_fs_mountpoint_content + + "create_image_impl_${OUTPUT_FORMAT}" + + rm -rf "${WORK_DIR}" +} diff --git a/tools/image_helper/partitioned_disk.sh b/tools/image_helper/partitioned_disk.sh new file mode 100644 index 0000000..ca625b3 --- /dev/null +++ b/tools/image_helper/partitioned_disk.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env false + +# A partitioned disk configuration must describe: +# - PARTITION_TABLE_TYPE +# - PARTITION_x_USAGE + +match_partition_content_MOUNTPOINT() { + fs_idx="PARTITION_${part_idx}_FILESYSTEM_IDX" + fs_idx="${!fs_idx}" + fs_content="FILESYSTEM_${fs_idx}_CONTENT" + fs_content="${!fs_content}" + eval "PARTITION_${part_idx}_CONTENT=${fs_content}" +} + +prepare_partition_content() { + for part_idx in $(seq 1 99); do + if eval "[ -z \"\${PARTITION_${part_idx}_USAGE+x}\" ]"; then + break + fi + part_usage="PARTITION_${part_idx}_USAGE" + part_usage="${!part_usage}" + + if ! is_function "match_partition_content_${part_usage}"; then + loge "Content matching for partition usage \"${part_usage}\" not implemented" + exit 1 + fi + "match_partition_content_${part_usage}" + + done +} + +create_image_impl_partitioned_disk() { + logi "Creating partitioned_disk image" + + prepare_partition_content + + disk_part_table="${PARTITION_TABLE_TYPE}" + if ! is_function "produce_image_${disk_part_table}" ; then + loge "Partition table ${disk_part_table} is not supported yet." + exit 1 + fi + "produce_image_${disk_part_table}" +} diff --git a/tools/image_layout_helper.sh b/tools/image_layout_helper.sh new file mode 100644 index 0000000..6afc73e --- /dev/null +++ b/tools/image_layout_helper.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env false + +parse_image_layout_impl_output_format_partitioned_disk() { + logi "Parsing partitioned_disk image" + if [ -z ${PARTITION_TABLE_TYPE+x} ]; then + loge "PARTITION_TABLE_TYPE not provided" + exit 1 + fi + echo "PARTITION_TABLE_TYPE=${PARTITION_TABLE_TYPE}" + if ! is_function "parse_image_layout_impl_partitioned_disk_table_${PARTITION_TABLE_TYPE}"; then + loge "PARTITION_TABLE_TYPE \"${PARTITION_TABLE_TYPE}\" not implemented" + exit 1 + fi + "parse_image_layout_impl_partitioned_disk_table_${PARTITION_TABLE_TYPE}" +} + +parse_image_layout_impl_sort_mountpoint() { + mountpoints="" + for fs_idx in $(seq 0 $(( IMAGE_LAYOUT_FILESYSTEM_COUNT - 1 ))); do + mountpoints+="$(eval echo \$\{FILESYSTEM_"${fs_idx}"_MOUNTPOINT\}) ${fs_idx} +" + done + mountpoints="$(echo "${mountpoints}" | sort)" + sorted_mountpoint_idx="$(echo "${mountpoints}" | rev | cut -d ' ' -f 1 | rev | tr '\n' ' ')" + echo "MOUNTPOINT_SORTED_IDX=\"${sorted_mountpoint_idx}\"" +} + +parse_image_layout_impl() { + # shellcheck shell=dash disable=SC1091 + . "${RECEIPE_DIR}/image-layout.conf" + + if [ -z ${OUTPUT_FORMAT+x} ]; then + loge "OUTPUT_FORMAT not provided" + exit 1 + fi + echo "OUTPUT_FORMAT=${OUTPUT_FORMAT}" + if ! is_function "parse_image_layout_impl_output_format_${OUTPUT_FORMAT}"; then + loge "OUTPUT_FORMAT \"${OUTPUT_FORMAT}\" not implemented" + exit 1 + fi + + # Collect number of FILESYSTEMs + IMAGE_LAYOUT_FILESYSTEM_COUNT=0 + + "parse_image_layout_impl_output_format_${OUTPUT_FORMAT}" + + parse_image_layout_impl_sort_mountpoint +} + +# shellcheck shell=dash disable=SC2016 +get_fs_uuid_by_mountpoint_impl=' +get_fs_uuid_by_mountpoint_impl() { + for part_idx in $(seq 1 99); do + if eval "[ -z \"\${PARTITION_${part_idx}_USAGE+x}\" ]"; then + echo "partition not found by mountpoint: ${1} 1>&2"; + exit 1; + fi; + fs_idx="PARTITION_${part_idx}_FILESYSTEM_IDX" && + fs_idx="${!fs_idx}" && + fs_mp="FILESYSTEM_${fs_idx}_MOUNTPOINT" && + fs_mp="${!fs_mp}" && + if [ "${fs_mp}" = "${1}" ]; then + fs_uuid="FILESYSTEM_${fs_idx}_UUID" && + echo "${!fs_uuid}" && + return; + fi; + done +;}; get_fs_uuid_by_mountpoint_impl' + +get_fs_uuid_by_mountpoint="eval ${get_fs_uuid_by_mountpoint_impl}" diff --git a/tools/imgcat.sh b/tools/imgcat.sh deleted file mode 100755 index 428c745..0000000 --- a/tools/imgcat.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env dash - -set -o errexit -set -o nounset - -. ./logging.sh - -INPUT_FILES="" -OUTPUT_FILE="" -ALIGNMENT_SECTOR_SIZE="" -ALIGNMENT_SECTOR_COUNT="" -ALIGNMENT_BYTES="" - -calc_parts_total_size() { - local total_aligned_blocks=0 - while IFS= read -r line; do - if [ -z "${line}" ]; then - continue - fi - ifile_aligned_blocks="$(du --apparent-size -B ${ALIGNMENT_BYTES} "${line}" | cut -f 1)" - logi "Input: ${ifile_aligned_blocks} blocks: ${line}" - total_aligned_blocks="$((total_aligned_blocks+ifile_aligned_blocks))" - done << EOF -$INPUT_FILES -EOF - echo "${total_aligned_blocks}" -} - -probe_alignment() { - local TEMP_FILE - TEMP_FILE="$(mktemp)" - truncate -s 1G "${TEMP_FILE}" - ALIGNMENT_SECTOR_SIZE="$(sgdisk -p "${TEMP_FILE}" | sed -rn 's/Sector size \(logical\): ([0-9]+) bytes/\1/p')" - ALIGNMENT_SECTOR_COUNT="$(sgdisk -p "${TEMP_FILE}" | sed -rn 's/Partitions will be aligned on ([0-9]+)-sector boundaries/\1/p')" - ALIGNMENT_BYTES="$((ALIGNMENT_SECTOR_SIZE*ALIGNMENT_SECTOR_COUNT))" - rm "${TEMP_FILE}" - logd "Probed alignment: ${ALIGNMENT_BYTES}B (${ALIGNMENT_SECTOR_SIZE}B*${ALIGNMENT_SECTOR_COUNT})" -} - -print_usage() { - # Keep help message within 80 cols for special consoles. - cat << EOF -Concatenate multiple partitions into a single GUID disk image. -This script only handles the image creation. -Usage: $0 [-hp] [-i input [-i input [...]]] output - -h Print this help message. - -p Print the alignment, in bytes - -i input Partition images to be included. - Multiple inputs are arranged as the specified order. - It is recommended to have input file size rounded according - to the alignment requirements, as the partition will always - be placed at alignment boundaries. - output The produced disk image. -Environment Variables: - LOG_LEVEL Controls the log level of this script. - One of: DEBUG, INFO, WARN, ERROR - Defaults to: INFO -EOF -} - -main() { - # Handling args - while getopts "i:hp" o; do - case "${o}" in - h) - print_usage - exit 0 - ;; - i) - INPUT_FILES="${INPUT_FILES}${OPTARG} -" - ;; - p) - probe_alignment - echo -n "${ALIGNMENT_BYTES}" - exit 0 - ;; - *) - exit 1 - ;; - esac - done - shift $((OPTIND-1)) - OUTPUT_FILE="${1:-}" - - # Validate inputs - if [ -z "${OUTPUT_FILE}" ]; then - loge "No output file is specified!" - exit 1 - fi - if [ -z "${INPUT_FILES}" ]; then - loge "No input file is specified!" - exit 1 - fi - - probe_alignment - logi "Using alignment: ${ALIGNMENT_SECTOR_COUNT} sectors @ ${ALIGNMENT_SECTOR_SIZE}B" - - local target_image_content_size - target_image_content_size="$(calc_parts_total_size)" - - # One block is reserved at both beginning and ending, for GPT tables. - # Final image size will be target_image_content_size+2 blocks - local final_image_blocks="$((target_image_content_size+2))" - local final_image_size_b="$((final_image_blocks*ALIGNMENT_BYTES))" - logi "Allocating output image (${final_image_blocks} blocks, ${final_image_size_b}B) at ${OUTPUT_FILE}" - truncate -s "${final_image_size_b}" "${OUTPUT_FILE}" - - logi "Writing GUID Partition Table" - 1>/dev/null sgdisk -Z "${OUTPUT_FILE}" - 1>/dev/null sgdisk -G "${OUTPUT_FILE}" - - local curr_part_idx - curr_part_idx=0 - local curr_part_start_sector - curr_part_start_sector="${ALIGNMENT_SECTOR_COUNT}" - while IFS= read -r line; do - if [ -z "${line}" ]; then - continue - fi - curr_part_idx="$((curr_part_idx+1))" - local curr_part_blocks - curr_part_blocks="$(du --apparent-size -B "${ALIGNMENT_BYTES}" "${line}" | cut -f 1)" - local curr_part_sectors="$((curr_part_blocks*ALIGNMENT_BYTES/ALIGNMENT_SECTOR_SIZE))" - logi "Create partition ${curr_part_idx}: ${curr_part_sectors} sectors @ ${curr_part_start_sector} sector" - 1>/dev/null sgdisk --new "${curr_part_idx}:${curr_part_start_sector}:+${curr_part_sectors}" "${OUTPUT_FILE}" - logi "Copy contents to part ${curr_part_idx} from ${line}" - 2>/dev/null dd if="${line}" of="${OUTPUT_FILE}" bs="${ALIGNMENT_SECTOR_SIZE}" seek="${curr_part_start_sector}" count="${curr_part_sectors}" conv=notrunc iflag=fullblock - curr_part_start_sector="$((curr_part_start_sector+curr_part_sectors))" - done << EOF -$INPUT_FILES -EOF - - exit 0 -} - -main "$@" diff --git a/tools/gptcfg.sh b/tools/partition_table_helper/gptcfg.sh similarity index 93% rename from tools/gptcfg.sh rename to tools/partition_table_helper/gptcfg.sh index aa39ec9..640d56f 100755 --- a/tools/gptcfg.sh +++ b/tools/partition_table_helper/gptcfg.sh @@ -1,5 +1,6 @@ -#!/usr/bin/env dash +#!/usr/bin/env sh # shellcheck shell=dash disable=SC2034 +# TODO: dynamically generate help message set -o errexit set -o nounset @@ -78,12 +79,12 @@ handle_set_uuid() { loge "part_id not specified." exit 2 fi - local partid; partid="$1"; shift 1 - local new_uuid; new_uuid="${1:-}" + partid="$1"; shift 1 + new_uuid="${1:-}" if [ -z "${new_uuid}" ]; then new_uuid="$(uuidgen)" fi - logd "Setting new UUID to part ${partid}: ${new_uuid}" + logd "Setting new UUID for part ${partid}: ${new_uuid}" 1>/dev/null sgdisk -u "${partid}:${new_uuid}" "${TARGET_FILE}" } @@ -92,26 +93,25 @@ handle_set_type() { loge "part_id not specified." exit 2 fi - local partid; partid="$1"; shift 1 + partid="$1"; shift 1 if [ $# -eq 0 ]; then loge "Type not specified." exit 2 fi - local parttype; parttype="$1"; shift 1 + parttype="$1"; shift 1 if ! printf '%s' "${TYPENAME}" | grep -E "^${parttype}$" > /dev/null; then loge "Unsupported type: ${parttype}" exit 2 fi - local typecode typecode="$(getvarbyname "TYPECODE_$(str_to_upper "${parttype}")")" - local supported_attrs="" + supported_attrs="" supported_attrs="$(getvarbyname "TYPECODE_$(str_to_upper "${parttype}")_ATTRS:-")" - local typeattrbits="" + typeattrbits="" while [ $# -ne 0 ]; do - local curr_attr="$1" + curr_attr="$1" shift 1 if ! printf '%s' "${supported_attrs}" | grep -E "^${curr_attr}$" > /dev/null; then loge "Usupported attribute for type ${parttype}: ${curr_attr}" @@ -120,13 +120,13 @@ handle_set_type() { typeattrbits="${typeattrbits}$(getvarbyname "TYPECODE_$(str_to_upper "${parttype}")_ATTRS_$(str_to_upper "${curr_attr}")") " done - logd "Set type code to ${typecode} for part ${partid}" + logd "Set type code for part ${partid}: ${typecode}" 1>/dev/null sgdisk -t "${partid}:${typecode}" "${TARGET_FILE}" printf '%s' "${typeattrbits}" | while read -r attrbit ; do if [ -z "${attrbit}" ]; then continue fi - logd "Set partition attribute bit ${attrbit} for part ${partid}" + logd "Set partition attribute bit for part ${partid}: ${attrbit}" 1>/dev/null sgdisk -A "${partid}:set:${attrbit}" "${TARGET_FILE}" done } @@ -136,13 +136,13 @@ handle_set_name() { loge "part_id not specified." exit 2 fi - local partid; partid="$1"; shift 1 + partid="$1"; shift 1 if [ $# -eq 0 ]; then loge "part name not specified." exit 2 fi - local partname; partname="$1"; shift 1 + partname="$1"; shift 1 1>/dev/null sgdisk -c "${partid}:${partname}" "${TARGET_FILE}" } @@ -229,7 +229,6 @@ main() { TARGET_FILE="$1" shift 1 - local arg_command if [ "$#" -eq 0 ]; then loge "No command specified." exit 1 diff --git a/tools/partition_table_helper/guid.sh b/tools/partition_table_helper/guid.sh new file mode 100644 index 0000000..0e37ab4 --- /dev/null +++ b/tools/partition_table_helper/guid.sh @@ -0,0 +1,206 @@ +# Assuming sector size is 512B +readonly GUID_TABLE_SECTOR_SIZE=512 +# Default alignment of the offset of each partition +readonly GUID_TABLE_ALIGNMENT="$(( 2048 * GUID_TABLE_SECTOR_SIZE ))" +# Reserved size for partition table header +readonly GUID_TABLE_RESV_SIZE="$(( 34 * GUID_TABLE_SECTOR_SIZE ))" + +parse_image_layout_impl_partitioned_disk_table_GUID_part_usage_MOUNTPOINT() { + logi "Parsing mountpoint usage" + + # PARTITION_xx_FS + part_fs="$(eval echo \$\{PARTITION_"${part_idx}"_FS:-\})" + if ! is_function "filesystem_validate_uuid_${part_fs}"; then + loge "File system \"${part_fs}\" not implemented" + exit 1 + fi + echo "FILESYSTEM_${IMAGE_LAYOUT_FILESYSTEM_COUNT}_FORMAT=${part_fs}" + + # PARTITION_xx_FS_UUID + part_fs_uuid="$(eval echo \$\{PARTITION_"${part_idx}"_FS_UUID:-\})" + if [ -n "${part_fs_uuid}" ]; then + if ! "filesystem_validate_uuid_${part_fs}" "${part_fs_uuid}"; then + loge "Inavlid ${part_fs} UUID: \"${part_fs_uuid}\"" + exit 1 + fi + fi + if [ -z "${part_fs_uuid}" ]; then + part_fs_uuid="$("filesystem_generate_uuid_${part_fs}")" + fi + echo "FILESYSTEM_${IMAGE_LAYOUT_FILESYSTEM_COUNT}_UUID=${part_fs_uuid}" + + # PARTITION_xx_MOUNTPOINT + part_mountpoint="$(eval echo \$\{PARTITION_"${part_idx}"_MOUNTPOINT:-\})" + if ! case "${part_mountpoint}" in (/*) pathchk -- "${part_mountpoint}";; (*) ! : ;; esac; then + loge "Invalid mountpoint: ${part_mountpoint}" + exit 1 + fi + echo "FILESYSTEM_${IMAGE_LAYOUT_FILESYSTEM_COUNT}_MOUNTPOINT=${part_mountpoint}" + eval "FILESYSTEM_${IMAGE_LAYOUT_FILESYSTEM_COUNT}_MOUNTPOINT=${part_mountpoint}" + + echo "FILESYSTEM_${IMAGE_LAYOUT_FILESYSTEM_COUNT}_CONTAINER_SIZE=${part_size_in_byte}" + + echo "PARTITION_${part_idx}_FILESYSTEM_IDX=${IMAGE_LAYOUT_FILESYSTEM_COUNT}" + IMAGE_LAYOUT_FILESYSTEM_COUNT="$(( IMAGE_LAYOUT_FILESYSTEM_COUNT + 1 ))" +} + +parse_image_layout_impl_partitioned_disk_table_GUID() { + logi "Parsing GUID table" + # reserve space for table header + curr_part_offset=${GUID_TABLE_RESV_SIZE} + curr_part_offset="(( ((curr_part_offset - 1) / GUID_TABLE_ALIGNMENT + 1) * GUID_TABLE_ALIGNMENT ))" + has_flex_size_part=false + for part_idx in $(seq 1 99); do + if eval "[ -z \"\${PARTITION_${part_idx}_USAGE+x}\" ]"; then + break + fi + logi "Parsing part ${part_idx}" + + if $has_flex_size_part; then + loge "No more partition is allowed after flex-size partition" + exit 1 + fi + + # PARTITION_xx_OFFSET + # Ensure current part offset alignment + part_offset_in_byte="$(eval echo \$\{PARTITION_"${part_idx}"_OFFSET:-0B\})" + part_offset_in_byte="$(numfmt --from iec "${part_offset_in_byte%B}")" + if [ "${part_offset_in_byte}" -ne 0 ]; then + # Ensure alignment first + aligned_part_offset="$(( ((part_offset_in_byte - 1) / GUID_TABLE_ALIGNMENT + 1) * GUID_TABLE_ALIGNMENT ))" + if [ "${aligned_part_offset}" -ne "${part_offset_in_byte}" ]; then + logw "Force aligning ${part_offset_in_byte} to ${aligned_part_offset}" + fi + # Then make sure it does not overlap + if [ "${aligned_part_offset}" -lt "${curr_part_offset}" ]; then + loge "Offset ${aligned_part_offset} overlaps with existing occupation ${curr_part_offset}" + exit 1 + fi + # Finally update curr_part_offset + curr_part_offset="${aligned_part_offset}" + fi + # if the optional offset is not provided then use calculated one instead + echo "PARTITION_${part_idx}_OFFSET=${curr_part_offset}" + + # PARTITION_xx_SIZE + # There's no special limitation about the partition size. But we only accept IEC scaling factor + part_size_in_byte="$(eval echo \$\{PARTITION_"${part_idx}"_SIZE:-0B\})" + part_size_in_byte="$(numfmt --from iec "${part_size_in_byte%B}")" + if [ "${part_size_in_byte}" -eq 0 ]; then + # no follow-up partition is allowed + has_flex_size_part=true + fi + echo "PARTITION_${part_idx}_SIZE=${part_size_in_byte}" + + # Then increase the part offset to next available position + curr_part_offset="$(( ((curr_part_offset + part_size_in_byte - 1) / GUID_TABLE_ALIGNMENT + 1) * GUID_TABLE_ALIGNMENT ))" + + # PARTITION_xx_NAME + echo "PARTITION_${part_idx}_NAME=$(eval echo \$\{PARTITION_"${part_idx}"_NAME:-\})" + + # PARTITION_xx_UUID + part_uuid="$(eval echo \$\{PARTITION_"${part_idx}"_UUID:-\})" + if [ -n "${part_uuid}" ]; then + if ! echo "${part_uuid}" | sed -n '/^[0-9a-fA-F]\{8\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{4\}-[0-9a-fA-F]\{12\}$/!q1'; then + loge "Inavlid part UUID: ${part_uuid}" + exit 1 + fi + fi + if [ -z "${part_uuid}" ]; then + part_uuid="$(uuidgen)" + fi + echo "PARTITION_${part_idx}_UUID=${part_uuid}" + + # PARTITION_xx_TYPE + echo "PARTITION_${part_idx}_TYPE=$(eval echo \$\{PARTITION_"${part_idx}"_TYPE:-\})" + # PARTITION_xx_ATTRS + echo "PARTITION_${part_idx}_ATTRS=$(eval echo \$\{PARTITION_"${part_idx}"_ATTRS:-\})" + + # PARTITION_xx_USAGE + part_usage="$(eval echo \$\{PARTITION_"${part_idx}"_USAGE:-\})" + if ! is_function "parse_image_layout_impl_partitioned_disk_table_GUID_part_usage_${part_usage}"; then + loge "PARTITION_USAGE \"${part_usage}\" not implemented" + exit 1 + fi + echo "PARTITION_${part_idx}_USAGE=${part_usage}" + "parse_image_layout_impl_partitioned_disk_table_GUID_part_usage_${part_usage}" + done +} + +produce_image_GUID() { + # Calculate the final image size + total_partition_count=0 + for part_idx in $(seq 1 99); do + if eval "[ -z \"\${PARTITION_${part_idx}_USAGE+x}\" ]"; then + break + fi + total_partition_count="$(( total_partition_count + 1 ))" + done + last_part_offset="PARTITION_${total_partition_count}_OFFSET" + last_part_offset="${!last_part_offset}" + last_part_size="PARTITION_${total_partition_count}_SIZE" + last_part_size="${!last_part_size}" + if [ "${last_part_size}" -eq 0 ]; then + last_part_fs_idx="PARTITION_${total_partition_count}_FILESYSTEM_IDX" + last_part_fs_idx="${!last_part_fs_idx}" + last_part_fs_mountpoint="FILESYSTEM_${last_part_fs_idx}_MOUNTPOINT" + last_part_fs_mountpoint="${!last_part_fs_mountpoint}" + last_part_fs_format="FILESYSTEM_${last_part_fs_idx}_FORMAT" + last_part_fs_format="${!last_part_fs_format}" + fs_img_file="$(echo "${last_part_fs_mountpoint}" | tr '/' ':').${last_part_fs_format}" + last_part_size="$(du --apparent-size -b -s "${FS_IMG_DIR}/${fs_img_file}" | cut -f 1)" + fi + curr_offset="$(( last_part_offset + last_part_size ))" + # Ensure the last partition owns the last usable sector + curr_offset="$(( ((curr_offset - 1) / GUID_TABLE_SECTOR_SIZE + 1) * GUID_TABLE_SECTOR_SIZE ))" + final_disk_size="$(( curr_offset + GUID_TABLE_RESV_SIZE ))" + final_disk_size="$(( ((final_disk_size - 1) / GUID_TABLE_SECTOR_SIZE + 1) * GUID_TABLE_SECTOR_SIZE ))" + + # Prepare the partition table + OUTPUT_IMAGE="${OUTPUT_PREFIX}.img" + rm -f "${OUTPUT_IMAGE}" + logi "Allocating ${final_disk_size}B for ${OUTPUT_IMAGE}" + truncate -s "${final_disk_size}" "${OUTPUT_IMAGE}" + sgdisk -Z "${OUTPUT_IMAGE}" >/dev/null 2>&1 + # sgdisk operates on files that may have different sector size with out target image + SECTOR_SIZE="$(sgdisk -p "${OUTPUT_IMAGE}" | sed -rn 's/Sector size \(logical\): ([0-9]+) bytes/\1/p')" + # Make sure our offset alignment satisfies sector size + if [ "$(( (GUID_TABLE_ALIGNMENT / SECTOR_SIZE) * SECTOR_SIZE ))" -ne "${GUID_TABLE_ALIGNMENT}" ]; then + loge "Unsupported alignment between GUID_TABLE_ALIGNMENT (${GUID_TABLE_ALIGNMENT}) and SECTOR_SIZE (${SECTOR_SIZE})" + exit 1 + fi + + for part_idx in $(seq 1 ${total_partition_count}); do + logi "Creating partition ${part_idx}" + curr_part_size="PARTITION_${part_idx}_SIZE" + curr_part_size="${!curr_part_size}" + if [ "${curr_part_size}" -eq 0 ]; then + # Must be the last partition + curr_part_size="${last_part_size}" + fi + curr_part_offset="PARTITION_${part_idx}_OFFSET" + curr_part_offset="${!curr_part_offset}" + sgdisk --new "${part_idx}:$(( curr_part_offset / SECTOR_SIZE )):+$(( curr_part_size / SECTOR_SIZE ))" "${OUTPUT_IMAGE}" >/dev/null 2>&1 + curr_part_uuid="PARTITION_${part_idx}_UUID" + curr_part_uuid="${!curr_part_uuid}" + ./partition_table_helper/gptcfg.sh "${OUTPUT_IMAGE}" set-uuid "${part_idx}" "${curr_part_uuid}" + curr_part_name="PARTITION_${part_idx}_NAME" + curr_part_name="${!curr_part_name}" + ./partition_table_helper/gptcfg.sh "${OUTPUT_IMAGE}" set-name "${part_idx}" "${curr_part_name}" + curr_part_type="PARTITION_${part_idx}_TYPE" + curr_part_type="${!curr_part_type}" + curr_part_attrs="PARTITION_${part_idx}_ATTRS" + curr_part_attrs="${!curr_part_attrs}" + ./partition_table_helper/gptcfg.sh "${OUTPUT_IMAGE}" set-type "${part_idx}" "${curr_part_type}" ${curr_part_attrs} + + # Filling contents + curr_part_content="PARTITION_${part_idx}_CONTENT" + curr_part_content="${!curr_part_content}" + dd conv=notrunc,sparse status=none \ + if="${curr_part_content}" \ + of="${OUTPUT_IMAGE}" \ + bs="${GUID_TABLE_SECTOR_SIZE}" \ + seek="$(( curr_part_offset / GUID_TABLE_SECTOR_SIZE ))" + done + logi "${OUTPUT_IMAGE} written." +} diff --git a/tools/receipe_helper.sh b/tools/receipe_helper.sh new file mode 100644 index 0000000..dd420c1 --- /dev/null +++ b/tools/receipe_helper.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env false + +is_function() { + type "$1" 2>/dev/null | head -n 1 | grep 'function' > /dev/null +} + +setup_repo_yum() { + mkdir -p "${ROOTFS_DIR}/etc/yum.repos.d" + cp "${RECEIPE_DIR}"/repos.d/* "${ROOTFS_DIR}/etc/yum.repos.d" +} + +setup_repo() { + logi "Preconfiguring package repo..." + setup_repo_func="setup_repo_${PACKAGE_MANAGER}" + if ! is_function "${setup_repo_func}" ; then + loge "Package manager ${PACKAGE_MANAGER} not supported yet." + exit 1 + fi + "setup_repo_${PACKAGE_MANAGER}" +} + +execute_script_dir() { + script_dir="$1" + + find "${script_dir}" -maxdepth 1 -mindepth 1 -type d,l | sort | \ + while IFS= read -r line; do + logi "Executing scripts: ${line}" + bash -c " +cd ${line} && +${2} +${line}/entry.sh" + done +} + +install_package_cleanup_yum() { + yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" clean all +} + +install_package_cleanup() { + logi "Cleanup package installation" + install_package_cleanup_func="install_package_cleanup_${PACKAGE_MANAGER}" + if ! is_function "${install_package_cleanup_func}" ; then + loge "Package manager ${PACKAGE_MANAGER} not supported yet." + exit 1 + fi + "install_package_cleanup_${PACKAGE_MANAGER}" +} + +install_package_list_yum() { + # shellcheck shell=dash disable=SC2086 + yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" -y install $1 +} + +install_package_list() { + logi "Installing package list: $1" + install_package_list_func="install_package_list_${PACKAGE_MANAGER}" + if ! is_function "${install_package_list_func}" ; then + loge "Package manager ${PACKAGE_MANAGER} not supported yet." + exit 1 + fi + "install_package_list_${PACKAGE_MANAGER}" "$(tr '\n' ' ' < "$1")" +} + +install_package_group_yum() { + # shellcheck shell=dash disable=SC2086 + yum --forcearch riscv64 --installroot="${ROOTFS_DIR}" -y groupinstall $1 +} + +install_package_group() { + logi "Installing package group: $1" + install_package_group_func="install_package_group_${PACKAGE_MANAGER}" + if ! is_function "${install_package_group_func}" ; then + loge "Package manager ${PACKAGE_MANAGER} not supported yet." + exit 1 + fi + "install_package_group_${PACKAGE_MANAGER}" "$(tr '\n' ' ' < "$1")" +} + +install_packages() { + logi "Install packages..." + find "${RECEIPE_DIR}"/packages.d/ -maxdepth 1 -mindepth 1 -type f,d,l | sort | \ + while IFS= read -r line; do + actualpath="$(readlink -f "${line}")" + if [ -d "${actualpath}" ]; then + if [ -f "${line}/packages.list" ]; then + install_package_list "${line}/packages.list" + elif [ -f "${line}/packages.group" ]; then + install_package_group "${line}/packages.group" + else + logw "No package list, ignoring ${line}" + continue + fi + if [ -d "${line}/post.d" ]; then + execute_script_dir "${line}/post.d" "${1}" + fi + elif [ -f "${actualpath}" ]; then + if echo "${line}" | grep ".*.list" > /dev/null; then + install_package_list "${line}" + elif echo "${line}" | grep ".*.group" > /dev/null; then + install_package_group "${line}" + else + logw "Unsupported package list, ignoring ${line}" + fi + fi + done + install_package_cleanup +} + +post_scripts() { + if [ -d "$(readlink -f "${RECEIPE_DIR}/post.d")" ]; then + logi "Post configuring..." + execute_script_dir "${RECEIPE_DIR}/post.d" "${1}" + fi +}