Created
September 18, 2017 03:38
-
-
Save anthonygclark/444f7c569c7b414c36c7c05714ea4a1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Creates a multi-partition QEMU disk image from our buildroot outputs and embeds grub2 | |
# | |
# TODO: Better error handling | |
# TODO: Better args (grub.cfg path is assumed) | |
# | |
DEBUG=1 | |
IMAGE_NAME="dhc.img" | |
IMAGE_SIZE="1G" # 100M used for /boot | |
function log_() | |
{ | |
echo "[$(basename "$0")] $*" | |
} | |
(( DEBUG )) && { | |
KERNEL="${1:-./initrd-buildroot-2017.08/output/images/bzImage}" | |
log_ "Debug: Using KERNEL = $KERNEL" | |
INITRD="${2:-./initrd-buildroot-2017.08/output/images/rootfs.cpio.gz}" | |
log_ "Debug: Using INITRD = $INITRD" | |
ROOTFS="${3:-./rootfs-buildroot-2017.08/output/images/rootfs.tar.bz2}" | |
log_ "Debug: Using ROOTFS = $ROOTFS" | |
} | |
[[ -e $KERNEL ]] || { | |
log_ "$KERNEL: File not found" | |
exit 1 | |
} | |
[[ -e $INITRD ]] || { | |
log_ "$INITRD: File not found" | |
exit 1 | |
} | |
[[ -e $ROOTFS ]] || { | |
log_ "$ROOTFS: File not found" | |
exit 1 | |
} | |
[[ -e ./grub.cfg ]] || { | |
log_ "./grub.cfg: File not found" | |
exit 1 | |
} | |
function atexit() | |
{ | |
[[ -d $MOUNT2 ]] && sudo umount "$MOUNT2" &> /dev/null | |
[[ -d $MOUNT1 ]] && sudo umount "$MOUNT1" &> /dev/null | |
sudo kpartx -d "$LOOPBACK" &> /dev/null | |
sudo losetup -d "$LOOPBACK" &> /dev/null | |
sudo qemu-nbd -d "$NBD" &> /dev/null | |
} | |
function error() | |
{ | |
log_ "Error: $*" | |
atexit | |
exit 1 | |
} | |
function check_commands() | |
{ | |
for comm in qemu-img qemu-nbd losetup kpartx parted mkfs.ext2 mkfs.ext4 grub-install ; | |
do | |
command -v "$comm" &> /dev/null || { | |
log_ "Command '$comm' is not available" | |
exit 1 | |
} | |
done | |
} | |
function find_next_nbd() | |
{ | |
for dev in /sys/class/block/nbd*; | |
do | |
local size | |
size="$(cat "$dev"/size)" | |
if (( size == 0 )); | |
then | |
printf "%s" "/dev/nbd${dev: -1}" | |
return | |
fi | |
done | |
error "No available nbd devices" | |
} | |
function find_next_loopback() | |
{ | |
sudo losetup -f &> /dev/null || error "No available loopback devices" | |
printf "%s" "$(sudo losetup -f)" | |
} | |
##### | |
if [[ -e "$IMAGE_NAME" ]] ; then | |
error "File '$IMAGE_NAME' already exists. Exiting to avoid overwriting!" | |
fi | |
# init | |
check_commands | |
sudo -v || exit | |
atexit | |
sudo modprobe nbd max_part=16 | |
# vars | |
NBD="$(find_next_nbd)" | |
LOOPBACK="$(find_next_loopback)" | |
LOOPBACK_N="${LOOPBACK: -1}" # the space before -1 is very important | |
MAPPER1="/dev/mapper/loop${LOOPBACK_N}p1" | |
MAPPER2="/dev/mapper/loop${LOOPBACK_N}p2" | |
(( DEBUG )) && { | |
log_ "Debug: NBD=$NBD" | |
log_ "Debug: LOOPBACK=$LOOPBACK" | |
log_ "Debug: LOOPBACK_N=$LOOPBACK_N" | |
log_ "Debug: MAPPER2=$MAPPER1" | |
log_ "Debug: MAPPER2=$MAPPER1" | |
} | |
export NBD | |
export LOOPBACK | |
export MAPPER1 | |
export MAPPER2 | |
##### | |
qemu-img create -f qcow2 "$IMAGE_NAME" "$IMAGE_SIZE" || error "create image" | |
log_ "[+] Created image" | |
sudo qemu-nbd -c "$NBD" "$IMAGE_NAME" || error "mount nbd" | |
log_ "[+] Bound to $NBD" | |
sudo parted --script "$NBD" \ | |
mklabel msdos \ | |
mkpart primary ext2 1M 100M \ | |
mkpart primary ext4 100M "$IMAGE_SIZE" || error "format" | |
log_ "[+] Partitioned via parted" | |
sleep 3 | |
sudo losetup "$LOOPBACK" "$NBD" || error "losetup" | |
log_ "[+] losetup on $LOOPBACK" | |
sleep 3 | |
sudo kpartx -a "$LOOPBACK" || error "kpartx" | |
sleep 3 | |
[[ -e "$MAPPER1" ]] || error "mapper 1 doesnt exist" | |
[[ -e "$MAPPER2" ]] || error "mapper 2 doesnt exist" | |
log_ "[+] kpartx" | |
MOUNT1=$(mktemp -d) | |
MOUNT2="$MOUNT1/boot" | |
export MOUNT1 | |
export MOUNT2 | |
log_ "[+] Created mount dirs ($MOUNT1) ($MOUNT2)" | |
log_ "[...] Starting format..." | |
sudo mkfs.ext2 "$MAPPER1" || error "mkfs.ext2" | |
sudo mkfs.ext4 "$MAPPER2" || error "mkfs.ext4" | |
log_ "[+] Formatted in ext2 + ext4..." | |
sudo mount "$MAPPER2" "$MOUNT1" || error "Failed to mount ext4 partition" | |
log_ "[+] Mounted $MAPPER2 to $MOUNT1" | |
sudo mkdir -p "$MOUNT2" # /boot not not exist | |
sudo mount "$MAPPER1" "$MOUNT2" || error "Failed to mount ext2 partition" | |
log_ "[+] Mounted $MAPPER1 to $MOUNT2" | |
log_ "[+] Mounted loopback devices" | |
sudo cp "$KERNEL" "$MOUNT2" || error "Failed to copy kernel" | |
log_ "[+] Copied kernel" | |
sudo cp "$INITRD" "$MOUNT2/initrd.cpio.gz" || error "Failed to copy initrd" | |
log_ "[+] Copied initrd" | |
sudo tar -xjf "$ROOTFS" -C "$MOUNT1" || error "Failed to extract rootfs" | |
log_ "[+] Copied rootfs" | |
sudo grub-install --target=i386-pc --boot-directory="$(readlink -f "$MOUNT2")" "$LOOPBACK" || error "Failed to install grub" | |
log_ "[+] Grub installed" | |
sudo cp ./grub.cfg "$MOUNT2/grub/grub.cfg" || error "Failed to write grub config" | |
sudo umount "$MOUNT2" || error "Failed to unmount loop2" | |
log_ "[+] Unmounted MOUNT2" | |
sudo umount "$MOUNT1" || error "Failed to unmount loop1" | |
log_ "[+] Unmounted MOUNT1" | |
rm -r "$MOUNT1" # remove this dir as we no longer need it | |
atexit | |
exit 0 |
At line 112:
LOOPBACK_N="${LOOPBACK: -1}" # the space before -1 is very important
Should be replaced with:
LOOPBACK_N="${LOOPBACK//[!0-9]/}"
... to support loop devices started from 10 and above.
Cutting only one digit doesn't work.
Excellent script, immensely helpful in resolving my issues building disk images.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
At line 120:
Numbers are swapped.
Great script btw.