История изменений
Исправление 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