11#! /bin/bash
2- # Boot from signed ISO
2+ # Boot from signed ISO file on USB media
3+ #
4+ # This script handles booting from ISO files stored on USB storage.
5+ # It works by mounting the ISO, detecting boot mechanisms supported by
6+ # the ISO's initrd, injecting appropriate kernel parameters, and
7+ # executing kexec to boot the OS.
8+ #
9+ # Detection approach:
10+ # 1. Mount the ISO as a loopback device
11+ # 2. Extract and scan the initrd for supported boot mechanisms
12+ # 3. Fall back to scanning *.cfg files if initrd detection yields nothing
13+ # 4. If no known boot-from-ISO mechanism is found, warn and guide user
14+ #
15+ # Supported boot mechanisms (detected in initrd or config):
16+ # - iso-scan/findiso: Dracut-based (Ubuntu, Debian Live, Tails, etc.)
17+ # - live-media: Dracut live-media parameter
18+ # - boot=live: Debian Live / Fedora Live
19+ # - boot=casper: Ubuntu Casper
20+ # - nixos: NixOS
21+ # - anaconda: Fedora/RHEL Anaconda (block device required)
22+ # - overlay: OverlayFS support
23+ # - toram: Load-to-RAM support
24+ #
25+ # If no mechanism is detected, the user is warned that the ISO may not
26+ # support booting from ISO file on USB, and is given alternative options:
27+ # - Write ISO directly to USB with dd
28+ # - Use Ventoy in USB emulation mode
29+ # - Boot from real DVD drive
30+ #
331set -e -o pipefail
432. /etc/functions.sh
533. /etc/gui_functions.sh
@@ -52,6 +80,18 @@ mount -t iso9660 -o loop $MOUNTED_ISO_PATH /boot ||
5280
5381DEV_UUID=$( blkid $DEV | tail -1 | tr " " " \n" | grep UUID | cut -d\" -f2)
5482
83+ # Scan an initrd for supported filesystems and boot mechanisms.
84+ # This function unpacks the initrd and searches for:
85+ # - Kernel modules (*.ko/*.ko.xz) -> supported filesystems
86+ # - Scripts and configs (*.sh, *.conf, init, scripts/*) -> boot mechanisms
87+ #
88+ # Supported filesystems detected: ext4, vfat, exfat, ntfs, btrfs, xfs
89+ # Supported boot mechanisms detected: iso-scan, live-media, boot-live,
90+ # casper, nixos, anaconda, overlay, toram, device
91+ #
92+ # Results are stored in global variables:
93+ # - supported_fses: Space-separated list of supported filesystem types
94+ # - supported_boot: Space-separated list of supported boot mechanisms
5595scan_initramfs () {
5696 local path=" $1 "
5797 local tmpdir=" "
@@ -82,20 +122,40 @@ scan_initramfs() {
82122 boot_content=$( strings " $path " 2> /dev/null) || true
83123 fi
84124
85- echo " $boot_content " | grep -qEi " iso.scan|findiso" &&
86- supported_boot=" ${supported_boot} iso-scan/findiso " || true
87- echo " $boot_content " | grep -qEi " live.media|live-media" &&
88- supported_boot=" ${supported_boot} live-media= " || true
89- echo " $boot_content " | grep -qEi " boot=live|rd.live.image|rd.live.squash" &&
90- supported_boot=" ${supported_boot} boot=live " || true
91- echo " $boot_content " | grep -qEi " boot.casper|casper" &&
92- supported_boot=" ${supported_boot} boot=casper " || true
93- echo " $boot_content " | grep -qEi " nixos" &&
94- supported_boot=" ${supported_boot} nixos " || true
95- echo " $boot_content " | grep -qEi " inst.stage2|inst.repo" &&
96- supported_boot=" ${supported_boot} anaconda " || true
125+ for pattern in " iso.scan|findiso" " live.media|live-media" " boot=live|rd.live.image|rd.live.squash" " boot.casper|casper" " nixos" " inst.stage2|inst.repo" " overlay|overlayfs" " toram" " CDLABEL|img_dev|check_dev" ; do
126+ case " $pattern " in
127+ iso.scan|findiso) label=" iso-scan" ;;
128+ live.media|live-media) label=" live-media" ;;
129+ boot=live|rd.live.image|rd.live.squash) label=" boot-live" ;;
130+ boot.casper|casper) label=" casper" ;;
131+ nixos) label=" nixos" ;;
132+ inst.stage2|inst.repo) label=" anaconda" ;;
133+ overlay|overlayfs) label=" overlay" ;;
134+ toram) label=" toram" ;;
135+ CDLABEL|img_dev|check_dev) label=" device" ;;
136+ esac
137+ echo " $boot_content " | grep -qEi " $pattern " &&
138+ supported_boot=" ${supported_boot}${label} " || true
139+ done
97140}
98141
142+ # Detect if the mounted ISO is an installer ISO (not a live/bootable ISO).
143+ # Installer ISOs (like Debian DVD installer) do not support booting from
144+ # ISO file on USB - they only work with physical CD/DVD or PXE boot.
145+ #
146+ # Detection checks for:
147+ # - /boot/install* directory (installer content)
148+ # - /boot/isolinux or /boot/grub (boot configs, but no live boot)
149+ # - /boot/install.amd/vmlinuz and initrd.gz (installer kernel/initrd)
150+ #
151+ # Detect boot mechanisms supported by the ISO's initrd.
152+ # This function:
153+ # 1. Parses all *.cfg files to find initrd paths
154+ # 2. For each initrd, calls scan_initramfs() to extract supported features
155+ # 3. Outputs two lines: "fs:..." and "boot:..." with detected support
156+ #
157+ # This is the primary detection method - scanning initrd content directly
158+ # provides the most accurate picture of what the ISO can do.
99159detect_initrd_boot_support () {
100160 local supported_fses=" "
101161 local supported_boot=" "
@@ -131,6 +191,13 @@ detect_initrd_boot_support() {
131191 return 0
132192}
133193
194+ # Fallback detection: scan *.cfg files for boot parameters.
195+ # This is used when initrd detection fails or yields no results.
196+ # It greps through boot config files (GRUB, syslinux, ISOLINUX) for
197+ # known boot parameters that indicate ISO-on-USB support.
198+ #
199+ # This method is less accurate than initrd scanning but can provide
200+ # hints when initrd extraction fails.
134201extract_boot_params_from_cfg () {
135202 for cfg in $( find /boot -name ' *.cfg' -type f 2> /dev/null) ; do
136203 [ -r " $cfg " ] || continue
@@ -141,22 +208,49 @@ extract_boot_params_from_cfg() {
141208 while IFS= read -r line; do
142209 case " $line " in
143210 * boot=live* | * rd.live.image* | * rd.live.squashimg=* )
144- boot_params=" ${boot_params} boot=live "
211+ if ! echo " $boot_params " | grep -q " boot-live" ; then
212+ boot_params=" ${boot_params} boot-live "
213+ fi
145214 ;;
146215 * iso-scan/filename=* | * findiso=* )
147- boot_params=" ${boot_params} iso-scan/findiso "
216+ if ! echo " $boot_params " | grep -q " iso-scan" ; then
217+ boot_params=" ${boot_params} iso-scan "
218+ fi
148219 ;;
149220 * live-media=* | * live.media=* )
150- boot_params=" ${boot_params} live-media= "
221+ if ! echo " $boot_params " | grep -q " live-media" ; then
222+ boot_params=" ${boot_params} live-media "
223+ fi
151224 ;;
152225 * boot=casper* | * casper* )
153- boot_params=" ${boot_params} boot=casper "
226+ if ! echo " $boot_params " | grep -q " casper" ; then
227+ boot_params=" ${boot_params} casper "
228+ fi
154229 ;;
155230 * inst.stage2=* | * inst.repo=* )
156- boot_params=" ${boot_params} anaconda "
231+ if ! echo " $boot_params " | grep -q " anaconda" ; then
232+ boot_params=" ${boot_params} anaconda "
233+ fi
157234 ;;
158235 * nixos* )
159- boot_params=" ${boot_params} nixos "
236+ if ! echo " $boot_params " | grep -q " nixos" ; then
237+ boot_params=" ${boot_params} nixos "
238+ fi
239+ ;;
240+ * overlay=* | * overlayfs* )
241+ if ! echo " $boot_params " | grep -q " overlay" ; then
242+ boot_params=" ${boot_params} overlay "
243+ fi
244+ ;;
245+ * toram* )
246+ if ! echo " $boot_params " | grep -q " toram" ; then
247+ boot_params=" ${boot_params} toram "
248+ fi
249+ ;;
250+ * CDLABEL=* | * img_dev=* | * check_dev* )
251+ if ! echo " $boot_params " | grep -q " device" ; then
252+ boot_params=" ${boot_params} device "
253+ fi
160254 ;;
161255 esac
162256 done < " $cfg "
@@ -165,6 +259,15 @@ extract_boot_params_from_cfg() {
165259 return 1
166260}
167261
262+ # ============================================================================
263+ # Main detection flow
264+ # ============================================================================
265+ # Step 1: Scan initrd for supported boot mechanisms
266+ # Step 2: If no boot method found, fall back to cfg file scanning
267+ # Step 3: Check USB filesystem compatibility
268+ # Step 4: If no known mechanism found, warn user with guidance
269+ # ============================================================================
270+
168271STATUS " Detecting USB filesystem and boot method support..."
169272SUPPORTED_FSES=" "
170273SUPPORTED_BOOT=" "
@@ -177,12 +280,16 @@ SUPPORTED_BOOT=$(echo "$tmp_support" | grep "^boot:" | sed 's/^boot://') || SUPP
177280DEBUG " SUPPORTED_FSES='$SUPPORTED_FSES '"
178281DEBUG " SUPPORTED_BOOT from initrd='$SUPPORTED_BOOT '"
179282
180- if [ -z " $SUPPORTED_BOOT " ]; then
181- DEBUG " No boot method in initrd, scanning *.cfg files..."
182- CFG_BOOT=$( extract_boot_params_from_cfg 2> /dev/null | grep " ^cfg:" | sed ' s/^cfg://' ) || CFG_BOOT=" "
183- DEBUG " CFG_BOOT='$CFG_BOOT '"
184- else
185- DEBUG " Boot method found in initrd, skipping cfg extraction"
283+ DEBUG " Scanning *.cfg files to augment initrd results..."
284+ CFG_BOOT=$( extract_boot_params_from_cfg 2> /dev/null | grep " ^cfg:" | sed ' s/^cfg://' ) || CFG_BOOT=" "
285+ DEBUG " CFG_BOOT='$CFG_BOOT '"
286+
287+ if [ -n " $SUPPORTED_BOOT " ] && [ -n " $CFG_BOOT " ]; then
288+ SUPPORTED_BOOT=" $SUPPORTED_BOOT $CFG_BOOT "
289+ DEBUG " Combined boot methods: $SUPPORTED_BOOT "
290+ elif [ -z " $SUPPORTED_BOOT " ] && [ -n " $CFG_BOOT " ]; then
291+ SUPPORTED_BOOT=" $CFG_BOOT "
292+ DEBUG " Using cfg boot methods: $SUPPORTED_BOOT "
186293fi
187294
188295if [ -n " $SUPPORTED_FSES " ]; then
197304
198305if [ -n " $SUPPORTED_BOOT " ]; then
199306 DETECTED_METHODS=" $SUPPORTED_BOOT "
200- DEBUG " Initrd supports boot methods: $DETECTED_METHODS "
201- elif [ -n " $CFG_BOOT " ]; then
202- DETECTED_METHODS=" $CFG_BOOT "
203- DEBUG " Boot config (*.cfg) indicates boot methods: $DETECTED_METHODS "
307+ DEBUG " Detected boot methods: $DETECTED_METHODS "
204308fi
205309
206310DEBUG " DETECTED_METHODS='$DETECTED_METHODS '"
207311if [ -z " $DETECTED_METHODS " ]; then
208312 WARN " ISO may not boot from USB file: no supported boot method detected"
209313 if [ -x /bin/whiptail ]; then
210- if ! whiptail_warning --title ' ISO BOOT COMPATIBILITY WARNING ' --yesno \
211- " ISO boot from USB file may not work.\n\nThis ISO does not appear to support booting from ISO file on USB stick .\n\nKnown compatible ISOs: Ubuntu, Debian Live, Tails, NixOS, Fedora Workstation, PureOS, Kicksecure .\n\nFor this ISO, try :\n- Use distribution USB creation tool (Ventoy, Rufus, etc )\n- Write ISO directly to USB with dd\n- Report to upstream that ISO should support USB file boot \n\nDo you want to try anyway? " \
314+ if ! whiptail_warning --title ' ISO BOOT NOT SUPPORTED ' --yesno \
315+ " This ISO does not support booting from ISO file on USB.\n\nThe initrd does not include boot-from-ISO mechanisms (no live-boot, casper, fromiso, iso-scan, anaconda, or nixos support detected) .\n\nTo use this ISO, write the hybrid image directly to a USB flash drive :\n\nLinux: sudo cp image.iso /dev/sdX (Be cautious!)\nWindows/Mac: Use Rufus, select DD mode (NOT ISO mode )\n\nWrite to whole-disk device (NOT a partition, e.g. /dev/sdX not /dev/sdX1),\nthen boot from USB device directly (not as ISO file). \n\nSee Debian wiki: https://wiki.debian.org/DebianInstall " \
212316 0 80; then
213- DIE " ISO boot cancelled - unsupported ISO on USB file"
317+ DIE " ISO boot cancelled - initrd does not support USB file boot "
214318 fi
215319 else
216- INPUT " ISO may not support USB file boot. Try anyway? [y/N]:" -n 1 response
217- [ " $response " != " y" ] && [ " $response " != " Y" ] && DIE " ISO boot cancelled - unsupported ISO on USB file"
320+ ERROR " ISO initrd has no boot-from-ISO support (no live-boot/casper/iso-scan)"
321+ ERROR " Write hybrid image to USB: Linux: cp iso /dev/sdX | Win/Mac: Rufus DD mode"
322+ INPUT " Try anyway? [y/N]:" -n 1 response
323+ [ " $response " != " y" ] && [ " $response " != " Y" ] && DIE " ISO boot cancelled"
218324 fi
219325fi
220326
221- ADD=" fromiso=/dev/disk/by-uuid/$DEV_UUID /$ISO_PATH img_dev=/dev/disk/by-uuid/$DEV_UUID iso-scan/filename=/${ISO_PATH} img_loop=$ISO_PATH iso=$DEV_UUID /$ISO_PATH live-media=/dev/disk/by-uuid/$DEV_UUID /$ISO_PATH live-media-path=casper"
327+ # ============================================================================
328+ # Boot parameter injection
329+ # ============================================================================
330+ # Inject all known boot-from-ISO parameters. The ISO's initrd will use
331+ # whichever parameters it understands and ignore the rest.
332+ #
333+ # Parameters injected (covering all major boot systems):
334+ # - findiso, fromiso, iso-scan/filename: Dracut standard
335+ # - img_dev, img_loop: additional Dracut variants
336+ # - iso: alternative parameter
337+ # - live-media, live-media-path: live-boot parameters
338+ # - boot=live, boot=casper: casper/live-boot parameters
339+ # ============================================================================
340+
341+ ISO_DEV=" /dev/disk/by-uuid/$DEV_UUID "
342+ ISO_PATH_ABS=" /$ISO_PATH "
343+
344+ base_params=" findiso=$ISO_DEV /$ISO_PATH fromiso=$ISO_DEV /$ISO_PATH iso-scan/filename=$ISO_PATH_ABS img_dev=$ISO_DEV img_loop=$ISO_PATH iso=$DEV_UUID /$ISO_PATH "
345+
346+ add_params=" "
347+ if echo " $DETECTED_METHODS " | grep -q " casper" ; then
348+ add_params=" $add_params boot=casper live-media-path=casper"
349+ fi
350+ if echo " $DETECTED_METHODS " | grep -q " boot-live" ; then
351+ add_params=" $add_params boot=live"
352+ fi
353+ if echo " $DETECTED_METHODS " | grep -q " live-media" ; then
354+ add_params=" $add_params live-media=$ISO_DEV /$ISO_PATH "
355+ fi
356+
357+ ADD=" $base_params $add_params "
358+ DEBUG " Injecting boot params: $ADD "
222359REMOVE=" "
223360
224361paramsdir=" /media/kexec_iso/$ISO_PATH "
0 commit comments