LINUX.ORG.RU

История изменений

Исправление mradermaxlol, (текущая версия) :

На данный момент выглядит вот так. Требуемое решение реализовано в функции mode_noloop.

#!/bin/sh -Eeu


opt_help() {
	echo "createimg - tool for creating bootable disk images."
	echo "Usage: $(basename "$0") [OPTIONS]"
	echo
	echo "Options:"
	echo "	-h	Show this help text."
	echo "	-l	Create image with losetup and mount (sudo required)."
	echo "	-n	Create image with dd and mtools/e2tools."
	echo "	-e	EFI partition size in megabytes."
	echo "	-d	Data partition size in megabytes."
	echo "	-k	Kernel image filename."
	echo "	-i	Initrd filename."
}


prepare_image() {
	# exit with error if rootfs OR kernel image (OR both) is not present
	# useful if default filenames are used
	if [ ! -e "${KERNEL_IMAGE}" ] || [ ! -e "${INITRD_IMAGE}" ]; then
		echo "Bootable files (kernel and/or initrd) not found!"
		exit 1;
	fi


	# remove leftover images;
	# create sparse disk image and write GPT to it; create partition images;
	# 2 megabytes are reserved for GPT data
	for img_file in img_full.img img_p1_EFI.img img_p2_data.img; do rm $img_file; done
	truncate -s $((IMG_EFI_SIZE + IMG_DATA_SIZE + 2))M img_full.img
	truncate -s "${IMG_EFI_SIZE}"M img_p1_EFI.img
	truncate -s "${IMG_DATA_SIZE}"M img_p2_data.img
	sgdisk -og -n 0:0:+"${IMG_EFI_SIZE}"M -t 1:ef00 -n 0:0:+"${IMG_DATA_SIZE}"M -t 2:8300 -s img_full.img
}


mode_loop() {
	# create loopdev & exit with error if loopdev node could not be created
	LOOPDEV=$(sudo losetup --show -Pf img_full.img)
	if [ ! -e "${LOOPDEV}" ]; then exit 1; fi
	
	
	# format disk image partitions
	sudo mkfs.fat -F32 "${LOOPDEV}p1"
	sudo mkfs.ext4 -qF "${LOOPDEV}p2"
	
	
	# create tmp directories & mount disk image partitions
	IMG_TMP=/tmp/br_img
	mkdir -p ${IMG_TMP}/boot ${IMG_TMP}/root ${IMG_TMP}/efi/boot
	sudo mount "${LOOPDEV}p1" ${IMG_TMP}/boot
	
	
	# populate disk image boot partition
	cp -R efi-part/* ${IMG_TMP}/efi/
	cp "${KERNEL_IMAGE}" ${IMG_TMP}/efi/boot/
	cp "${INITRD_IMAGE}" ${IMG_TMP}/efi/boot/initrd
	sudo cp -R ${IMG_TMP}/efi/* ${IMG_TMP}/boot/
	
	
	# unmount disk image & cleanup
	sudo umount ${IMG_TMP}/boot
	sudo rm -rf ${IMG_TMP}
	
	
	# create partition images using cat to inherit user permissions
	# "sudo cp" creates files as root
	sudo cat "${LOOPDEV}p1" > img_p1_EFI.img
	sudo cat "${LOOPDEV}p2" > img_p2_data.img
	
	
	# release disk image loopdev
	sudo losetup -d "${LOOPDEV}"
}


mode_noloop() {
	# format partition images
	mkfs.fat -F32 img_p1_EFI.img
	mkfs.ext4 -qF img_p2_data.img


	# populate disk image boot partition
	mcopy -si img_p1_EFI.img efi-part/* ::
	mmd -i img_p1_EFI.img ::boot
	mcopy -i img_p1_EFI.img "${KERNEL_IMAGE}" ::boot/bzImage
	mcopy -i img_p1_EFI.img "${INITRD_IMAGE}" ::boot/initrd


	# add partition images to the disk image
	# calculating offsets:
	# 1) paritions start at sector 2048 (everything before that is GPT data)
	# 2) sector N's offset is (N * 2^9) bytes away from the beginning
	#    this means that sector 2048 is
	#    2048 * 2^9 = 2^20 = 1048576 bytes away
	#    IT IS ASSUMED THAT 1 SECTOR = 512 BYTES!
	# 3) amount of sectors is (size(P) * 2^11)
	#    where size(P) is the partition P size in megabytes
	# 4) taking that into account, first sector of the next partition P + 1
	#    is calculated as ((size(P) + 1) * 2^11)
	# 5) offset (taking GPT data into account) for dd'ing partiiton P + 1
	#    is calculated as ((size(P) + 1) * 2^20)
	# 6) for compatibility with POSIX shells, ** operator can't be used in
	#    arithmetic expressions; however, as we only use powers of 2, we can
	#    replace $((2 ** N)) with $((2 << (N - 1)))
	dd if=img_p1_EFI.img of=img_full.img oflag=seek_bytes \
		seek=$((2 << 19)) conv=notrunc status=none
	dd if=img_p2_data.img of=img_full.img oflag=seek_bytes \
		seek=$(((IMG_EFI_SIZE + 1) * (2 << 19))) conv=notrunc status=none
}


# set default creation mode, partition sizes & filenames
IMG_MODE=none
IMG_EFI_SIZE=256
IMG_DATA_SIZE=32
KERNEL_IMAGE=bzImage
INITRD_IMAGE=rootfs.cpio


# handle commandline arguments
while getopts ":hlne:d:k:i:" arg; do
	case $arg in
		h)
			opt_help
			;;
		l)
			IMG_MODE=loop
			;;
		n)
			IMG_MODE=noloop
			;;
		e)
			# check if arg is an integer
			if [ -n "${OPTARG##*[!0-9]*}" ]; then
				IMG_EFI_SIZE=${OPTARG}
			else
				echo "EFI partition size must be integer!"
			fi
			;;
		d)
			# check if arg is an integer
			if [ -n "${OPTARG##*[!0-9]*}" ]; then
				IMG_DATA_SIZE=${OPTARG}
			else
				echo "Data partition size must be integer!"
			fi
			;;
		k)
			# check path existece
			if [ -e "${OPTARG}" ]; then
				KERNEL_IMAGE=${OPTARG}
			else
				echo "Kernel image not found!"
				exit 1;
			fi
			;;
		i)
			# check path existence
			if [ -e "${OPTARG}" ]; then
				INITRD_IMAGE=${OPTARG}
			else
				echo "Initrd image not found!"
				exit 1;
			fi
			;;
		?)
			echo "Unknown option: -${OPTARG}"
			exit 1
			;;
	esac
done


# create image in selected mode
case $IMG_MODE in
	loop)
		prepare_image
		mode_loop
		;;
	noloop)
		prepare_image
		mode_noloop
		;;
	?)
		echo "No proper image creation mode specified: ${IMG_MODE}"
		exit 1
		;;
esac

Исходная версия mradermaxlol, :

На данный момент выглядит вот так. Требуемое решение реализовано в функции mode_noloop.

#!/bin/sh -Eeu


opt_help() {
	echo "createimg - tool for creating bootable disk images."
	echo "Usage: $(basename "$0") [OPTIONS]"
	echo
	echo "Options:"
	echo "	-h	Show this help text."
	echo "	-l	Create image with losetup and mount (sudo required)."
	echo "	-n	Create image with dd and mtools/e2tools."
	echo "	-e	EFI partition size in megabytes."
	echo "	-d	Data partition size in megabytes."
	echo "	-k	Kernel image filename."
	echo "	-i	Initrd filename."
}


prepare_image() {
	# exit with error if rootfs OR kernel image (OR both) is not present
	# useful if default filenames are used
	if [ ! -e "${KERNEL_IMAGE}" ] || [ ! -e "${INITRD_IMAGE}" ]; then
		echo "Bootable files (kernel and/or initrd) not found!"
		exit 1;
	fi


	# remove leftover images;
	# create sparse disk image and write GPT to it; create partition images;
	# 2 megabytes are reserved for GPT data
	for img_file in img_full.img img_p1_EFI.img img_p2_data.img; do rm $img_file; done
	truncate -s $((IMG_EFI_SIZE + IMG_DATA_SIZE + 2))M img_full.img
	truncate -s "${IMG_EFI_SIZE}"M img_p1_EFI.img
	truncate -s "${IMG_DATA_SIZE}"M img_p2_data.img
	sgdisk -og -n 0:0:+"${IMG_EFI_SIZE}"M -t 1:ef00 -n 0:0:+"${IMG_DATA_SIZE}"M -t 2:8300 -s img_full.img
}


mode_loop() {
	# create loopdev & exit with error if loopdev node could not be created
	LOOPDEV=$(sudo losetup --show -Pf img_full.img)
	if [ ! -e "${LOOPDEV}" ]; then exit 1; fi
	
	
	# format disk image partitions
	sudo mkfs.fat -F32 "${LOOPDEV}p1"
	sudo mkfs.ext4 -qF "${LOOPDEV}p2"
	
	
	# create tmp directories & mount disk image partitions
	IMG_TMP=/tmp/br_img
	mkdir -p ${IMG_TMP}/boot ${IMG_TMP}/root ${IMG_TMP}/efi/boot
	sudo mount "${LOOPDEV}p1" ${IMG_TMP}/boot
	
	
	# populate disk image boot partition
	cp -R efi-part/* ${IMG_TMP}/efi/
	cp "${KERNEL_IMAGE}" ${IMG_TMP}/efi/boot/
	cp "${INITRD_IMAGE}" ${IMG_TMP}/efi/boot/initrd
	sudo cp -R ${IMG_TMP}/efi/* ${IMG_TMP}/boot/
	
	
	# unmount disk image & cleanup
	sudo umount ${IMG_TMP}/boot
	sudo rm -rf ${IMG_TMP}
	
	
	# create partition images using cat to inherit user permissions
	# "sudo cp" creates files as root
	sudo cat "${LOOPDEV}p1" > img_p1_EFI.img
	sudo cat "${LOOPDEV}p2" > img_p2_data.img
	
	
	# release disk image loopdev
	sudo losetup -d "${LOOPDEV}"
}


mode_noloop() {
	# format partition images
	mkfs.fat -F32 img_p1_EFI.img
	mkfs.ext4 -qF img_p2_data.img


	# populate disk image boot partition
	mcopy -si img_p1_EFI.img efi-part/* ::
	mmd -i img_p1_EFI.img ::boot
	mcopy -i img_p1_EFI.img "${KERNEL_IMAGE}" ::boot/bzImage
	mcopy -i img_p1_EFI.img "${INITRD_IMAGE}" ::boot/initrd


	# add partition images to the disk image
	# calculating offsets:
	# 1) paritions start at sector 2048 (everything before that is GPT data)
	# 2) sector N's offset is (N * 2^9) bytes away from the beginning
	#    this means that sector 2048 is
	#    2048 * 2^9 = 2^20 = 1048576 bytes away
	#    IT IS ASSUMED THAT 1 SECTOR = 512 BYTES!
	# 3) amount of sectors is (size(P) * 2^11)
	#    where size(P) is the partition P size in megabytes
	# 4) taking that into account, first sector of the next partition P + 1
	#    is calculated as ((size(P) + 1) * 2^11)
	# 5) offset (taking GPT data into account) for dd'ing partiiton P + 1
	#    is calculated as ((size(P) + 1) * 2^20)
	# 6) for compatibility with POSIX shells, ** operator can't be used in
	#    arithmetic expressions; however, as we only use powers of 2, we can
	#    replace $((2 ** N)) with $((2 << (N - 1)))
	dd if=img_p1_EFI.img of=img_full.img oflag=seek_bytes \
		seek=$((2 << 19)) conv=notrunc status=none
	dd if=img_p2_data.img of=img_full.img oflag=seek_bytes \
		seek=$(((IMG_EFI_SIZE + 1) * (2 << 19))) conv=notrunc status=none
}


# set default creation mode, partition sizes & filenames
IMG_MODE=none
IMG_EFI_SIZE=256
IMG_DATA_SIZE=32
KERNEL_IMAGE=bzImage
INITRD_IMAGE=rootfs.cpio


# handle commandline arguments
while getopts ":hlne:d:k:i:" arg; do
	case $arg in
		h)
			opt_help
			;;
		l)
			IMG_MODE=loop
			;;
		n)
			IMG_MODE=noloop
			;;
		e)
			# check if arg is an integer
			if [ -n "${OPTARG##*[!0-9]*}" ]; then
				IMG_EFI_SIZE=${OPTARG}
			else
				echo "EFI partition size must be integer!"
			fi
			;;
		d)
			# check if arg is an integer
			if [ -n "${OPTARG##*[!0-9]*}" ]; then
				IMG_DATA_SIZE=${OPTARG}
			else
				echo "Data partition size must be integer!"
			fi
			;;
		k)
			# check path existece
			if [ -e "${OPTARG}" ]; then
				KERNEL_IMAGE=${OPTARG}
			else
				echo "Kernel image not found!"
				exit 1;
			fi
			;;
		i)
			# check path existence
			if [ -e "${OPTARG}" ]; then
				INITRD_IMAGE=${OPTARG}
			else
				echo "Initrd image not found!"
				exit 1;
			fi
			;;
		?)
			echo "Unknown option: -${OPTARG}"
			exit 1
			;;
	esac
done


# create image in selected mode
case $IMG_MODE in
	loop)
		prepare_image
		mode_loop
		;;
	noloop)
		prepare_image
		mode_noloop
		;;
	?)
		echo "No proper image creation mode specified: ${IMG_MODE}"
		exit 1
		;;
esac