just work (TM)

This commit is contained in:
2025-09-04 16:59:29 +08:00
parent 7b5219bb0d
commit 89c748bf05
33 changed files with 907 additions and 305 deletions
+8 -4
View File
@@ -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
+26 -2
View File
@@ -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)
+91 -13
View File
@@ -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
@@ -1,2 +1,2 @@
RECEIPE_NAME := base
ROOTFS_COMPRESSION := zstd
COMPRESSION := zstd
@@ -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-"
@@ -0,0 +1,3 @@
DEVICE_NAME := SpacemiT-K1
$(foreach profile_dir,$(filter-out %.mk,$(wildcard $(CURRENT_DIR)*)),$(eval $(call add_device_profile,$(profile_dir))))
@@ -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=
@@ -0,0 +1,3 @@
#!/usr/bin/env sh
cp 50-spacemit_k1_fw.conf "${ROOTFS_DIR}/etc/dracut.conf.d/"
@@ -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
@@ -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
@@ -0,0 +1 @@
PROFILE_NAME := extlinux
@@ -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))))
@@ -1,2 +1,2 @@
RECEIPE_NAME := base
ROOTFS_COMPRESSION := zstd
COMPRESSION := zstd
@@ -1,3 +1,3 @@
RECEIPE_NAME := xfce4
ROOTFS_COMPRESSION := zstd
COMPRESSION := zstd
EXTENDS := base
+137
View File
@@ -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 "$@"
+11 -117
View File
@@ -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}"
+28
View File
@@ -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
}
+23
View File
@@ -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}"
}
+97
View File
@@ -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}"
}
+43
View File
@@ -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}"
}
+70
View File
@@ -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}"
-137
View File
@@ -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 "$@"
@@ -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
+206
View File
@@ -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."
}
+114
View File
@@ -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
}