Created
December 8, 2025 20:46
-
-
Save bketelsen/9346ca3310b59605084a98015308a7be to your computer and use it in GitHub Desktop.
bootable img to iso
This file contains hidden or 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 | |
| set -e | |
| # This script converts a raw image with 512 byte sectors to an iso with 2048 byte sectors. The conversion | |
| # allows for booting of the resulting iso as a (virtual) CDROM. | |
| if [ "$#" -ne 1 ]; then | |
| echo "Usage: $0 <input img>" | |
| exit 1 | |
| fi | |
| if [ $EUID -ne 0 ]; then | |
| echo "This script must be run as root" | |
| exit 1 | |
| fi | |
| SRC=$1 | |
| DST="${SRC//.img/.iso}" | |
| cp "$SRC" "$DST" | |
| truncate --size +1MiB "$DST" | |
| sgdisk -Z "$DST" | |
| SRCLOOPDEV=$(losetup --find --show --partscan "$SRC") | |
| # Check actual space used on partition 3 (btrfs) | |
| echo "" | |
| echo "Checking space usage on partition 3 (btrfs)..." | |
| MOUNT_TEMP=$(mktemp -d) | |
| mount -o ro "${SRCLOOPDEV}p3" "$MOUNT_TEMP" | |
| # Get btrfs filesystem usage | |
| echo "Btrfs filesystem information:" | |
| btrfs filesystem show "$MOUNT_TEMP" || true | |
| btrfs filesystem usage "$MOUNT_TEMP" || true | |
| # Get actual used space in bytes | |
| USED_BYTES=$(btrfs filesystem usage -b "$MOUNT_TEMP" | grep "Used:" | head -1 | awk '{print $2}') | |
| # Alternative if the above doesn't work | |
| if [ -z "$USED_BYTES" ]; then | |
| USED_BYTES=$(df -B1 "$MOUNT_TEMP" | tail -1 | awk '{print $3}') | |
| fi | |
| # Add 20% overhead for filesystem metadata and safety margin | |
| USED_MB=$((USED_BYTES / 1024 / 1024)) | |
| OVERHEAD_MB=$((USED_MB / 5)) | |
| TOTAL_MB=$((USED_MB + OVERHEAD_MB + 512)) # Add extra 512MB for safety | |
| echo "" | |
| echo "Space analysis for partition 3:" | |
| echo " Used space: ${USED_MB} MiB" | |
| echo " Overhead (20%): ${OVERHEAD_MB} MiB" | |
| echo " Total allocated: ${TOTAL_MB} MiB" | |
| umount "$MOUNT_TEMP" | |
| rmdir "$MOUNT_TEMP" | |
| DSTLOOPDEV=$(losetup --sector-size 2048 --find --show "$DST") | |
| PART1GUID=$(sgdisk -i 1 "$SRC" | grep "Partition unique GUID:" | sed -e "s/Partition unique GUID: //") | |
| PART2GUID=$(sgdisk -i 2 "$SRC" | grep "Partition unique GUID:" | sed -e "s/Partition unique GUID: //") | |
| PART3GUID=$(sgdisk -i 3 "$SRC" | grep "Partition unique GUID:" | sed -e "s/Partition unique GUID: //") | |
| echo "PART1GUID: $PART1GUID" | |
| echo "PART2GUID: $PART2GUID" | |
| echo "PART3GUID: $PART3GUID" | |
| PART1NAME=$(sgdisk -i 1 "$SRC" | grep "Partition name:" | sed -e "s/Partition name: '//" | sed -e "s/'//") | |
| PART2NAME=$(sgdisk -i 2 "$SRC" | grep "Partition name:" | sed -e "s/Partition name: '//" | sed -e "s/'//") | |
| PART3NAME=$(sgdisk -i 3 "$SRC" | grep "Partition name:" | sed -e "s/Partition name: '//" | sed -e "s/'//") | |
| echo "PART1NAME: $PART1NAME" | |
| echo "PART2NAME: $PART2NAME" | |
| echo "PART3NAME: $PART3NAME" | |
| sgdisk -n 1::+100MiB -u "1:$PART1GUID" -t 1:21686148-6449-6E6F-744E-656564454649 -c 1:"$PART1NAME" "$DSTLOOPDEV" | |
| sgdisk -n 2::+512MiB -u "2:$PART2GUID" -t 2:c12a7328-f81f-11d2-ba4b-00a0c93ec93b -c 2:"$PART2NAME" "$DSTLOOPDEV" | |
| # Use calculated size for partition 3 instead of filling all remaining space | |
| sgdisk -n 3::+${TOTAL_MB}MiB -u "3:$PART3GUID" -t 3:4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 -c 3:"$PART3NAME" "$DSTLOOPDEV" | |
| # sgdisk -n ::+16KiB -u "3:$PART3GUID" -t 3:E7BB33FB-06CF-4E81-8273-E543B413E2E2 -c "3:$PART3NAME" "$DSTLOOPDEV" | |
| # sgdisk -n 4::+100MiB -u "4:$PART4GUID" -t 4:77FF5F63-E7B6-4633-ACF4-1565B864C0E6 -c "4:$PART4NAME" "$DSTLOOPDEV" | |
| # sgdisk -n 5::+1024MiB -u "5:$PART5GUID" -t 5:8484680C-9521-48C6-9C11-B0720656F69E -c "5:$PART5NAME" "$DSTLOOPDEV" | |
| partprobe "$DSTLOOPDEV" | |
| echo "" | |
| echo "Copying partitions..." | |
| echo "Copying partition 1 (BIOS boot)..." | |
| dd if="${SRCLOOPDEV}p1" of="${DSTLOOPDEV}p1" status=progress | |
| echo "Copying partition 2 (EFI)..." | |
| dd if="${SRCLOOPDEV}p2" of="${DSTLOOPDEV}p2" status=progress | |
| echo "Copying partition 3 (Root btrfs) - using filesystem-aware copy..." | |
| # Create btrfs filesystem on the smaller partition | |
| mkfs.btrfs -f "${DSTLOOPDEV}p3" | |
| # Mount both filesystems | |
| SRC_MOUNT=$(mktemp -d) | |
| DST_MOUNT=$(mktemp -d) | |
| mount -o ro "${SRCLOOPDEV}p3" "$SRC_MOUNT" | |
| mount "${DSTLOOPDEV}p3" "$DST_MOUNT" | |
| # Copy files preserving all attributes and using compression | |
| echo "Copying files from source to destination (this may take a while)..." | |
| rsync -aAXHv --info=progress2 "$SRC_MOUNT/" "$DST_MOUNT/" | |
| # Sync and unmount | |
| sync | |
| umount "$SRC_MOUNT" | |
| umount "$DST_MOUNT" | |
| rmdir "$SRC_MOUNT" | |
| rmdir "$DST_MOUNT" | |
| echo "" | |
| echo "Final ISO size optimization..." | |
| # Truncate the ISO to actual used size plus small buffer | |
| ISO_END=$(sgdisk -E "$DSTLOOPDEV") | |
| ISO_SECTOR_SIZE=2048 | |
| ISO_SIZE_BYTES=$((ISO_END * ISO_SECTOR_SIZE)) | |
| ISO_SIZE_MB=$((ISO_SIZE_BYTES / 1024 / 1024)) | |
| echo "ISO will be ${ISO_SIZE_MB} MiB (compared to original source image)" | |
| losetup -d "$SRCLOOPDEV" | |
| losetup -d "$DSTLOOPDEV" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment