I am trying to write a script that will unpack and repack a FreeBSD ISO such that I can then do an installation with it. The goal is an unattended installation.

I've got the following script written but it doesn't work. While the original ISO will boot in VirtualBox under UEFI mode, the newly created ISO won't.



iso_mnt=$(mktemp -d /tmp/freebsd-mnt-XXXXXX)
iso_wrk=$(mktemp -d /tmp/freebsd-wrk-XXXXXX)

vol_id=$(isoinfo -d -i "${src_iso}" | sed -n -e 's/^Volume id: \(.*\)$/\1/p')

md_name=$(mdconfig -a -t vnode -f "${src_iso}")
mount -t cd9660 "/dev/${md_name}" "${iso_mnt}"

cp -a -v "${iso_mnt}/" "${iso_wrk}"
cp "${inst_cfg}" "${iso_wrk}/etc/installerconfig"
mkisofs -J -R -no-emul-boot -V "${vol_id}" -b boot/cdboot -o "${dst_iso}" "${iso_wrk}"

umount "${iso_mnt}" # cd9660
mdconfig -d -u "${md_name}"

rm -rf "${iso_mnt}"
rm -rf "${iso_wrk}"

The created filesystem looks good. I've diff'ed the files of the original and custom ISOs and the only differences are the installerconfig file added and boot.catalog (which I understand mkisofs adds, but why? Could this be the problem?)

I've tried various combinations of options to mkisofs, including -R -U, -L -D -R, -J -R, but nothing makes a difference.

Additionally, the FreeBSD Handbook interestingly has the following commentary:

So, if /tmp/myboot holds a bootable FreeBSD system with the boot image in /tmp/myboot/boot/cdboot, this command would produce /tmp/bootable.iso:

mkisofs -R -no-emul-boot -b boot/cdboot -o /tmp/bootable.iso /tmp/myboot

This does not produce an ISO that boots under VirtualBox in UEFI mode.

Does anyone have an idea what's wrong?


The problem is not in the filesystem content but in the boot records and partitions:

$ xorriso -indev FreeBSD-12.0-RELEASE-amd64-bootonly.iso -report_el_torito plain -report_system_area plain
libisofs: WARNING : Found hidden El-Torito image. Its size could not be figured out, so image modify or boot image patching may lead to bad results.
libisofs: NOTE : Found hidden El-Torito image for EFI.
libisofs: NOTE : EFI image start and size: 20 * 2048 , 1600 * 512
Boot record  : El Torito , MBR protective-msdos-label cyl-align-off GPT
El Torito catalog  : 19  1
El Torito images   :   N  Pltf  B   Emul  Ld_seg  Hdpt  Ldsiz         LBA
El Torito boot img :   1  BIOS  y   none  0x0000  0x00      4         420
El Torito boot img :   2  UEFI  y   none  0x0000  0x00   1600          20
El Torito img blks :   1  1204
El Torito img blks :   2  400
System area options: 0x00000201
System area summary: MBR protective-msdos-label cyl-align-off GPT
ISO image size/512 : 675508
Partition offset   : 0
MBR heads per cyl  : 0
MBR secs per head  : 0
MBR partition table:   N Status  Type        Start       Blocks
MBR partition      :   1   0x00  0xee            1       676107
GPT                :   N  Info
GPT backup problems:      Not a GPT 1.0 header of 92 bytes for 128 bytes per entry
GPT disk GUID      :      7ce0bf52def9e8118c360cc47ad8b808
GPT entry array    :      2  2  separated
GPT lba range      :      3  676105  676107
GPT partition name :   1  
GPT partition GUID :   1  6de0bf52def9e8118c360cc47ad8b808
GPT type GUID      :   1  28732ac11ff8d211ba4b00a0c93ec93b
GPT partition flags:   1  0x0000000000000000
GPT start and size :   1  80  1600
GPT partition name :   2  
GPT partition GUID :   2  73e0bf52def9e8118c360cc47ad8b808
GPT type GUID      :   2  9d6bbd83417fdc11be0b001560b84f0f
GPT partition flags:   2  0x0000000000000000
GPT start and size :   2  3  29

Both, the BIOS boot image and the EFI System Partition are not files in the ISO but rather unnamed block areas.

If you don't go the way of appending a session by fixed growisofs or by

cp FreeBSD-12.0-RELEASE-amd64-bootonly.iso new.iso
xorriso -boot_image any keep \
        -dev new.iso \
        -map /path/to/your_installerconfig /etc/installerconfig
        [other -map commands for files or directory trees ...]

then you need to extract those areas

dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=512 skip=80 count=1600 \
dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=512 skip=1680 count=4816 \

(El Torito gives LBAs in blocks of 2048 but sizes in blocks of 512. 4 * 420 = 1680. The BIOS image size of 1204 blocks of 2048 bytes is estimated by the lowest filesystem object LBA that's above 420. Possibly it is smaller but any oversize should not harm.)

Then there is the MBR code for BIOS booting from USB stick:

dd if=FreeBSD-12.0-RELEASE-amd64-bootonly.iso bs=1 count=446 \

If you do not plan to boot by BIOS, then bios_boot.img and mbr_code.img are not needed.

Building a new ISO from unpacked and mainpulated tree $HOME/files_for_iso and the extracted image files

xorriso -as mkisofs \
        -o new.iso \
        -d -l -r \
        -V "12_0_RELEASE_AMD64_BO" \
        -G mbr_code.img \
        -b /bios_boot.img \
           -no-emul-boot -boot-load-size 4 \
        -eltorito-alt-boot \
        -append_partition 2 0xef efi_part.img \
        -e '--interval:appended_partition_2:all::' \
           -no-emul-boot \
        bios_boot.img $HOME/files_for_iso

This will yield no GPT but rather an MBR partition table with two partitions of type 0x83 for the ISO filesystem and 0xef for the EFI System Partition.

(Whether BIOS boots from USB stick would have to be tested. Many MBRs need info patched in to find the next stage of boot programs.)


Instead of unpacking and packing back the iso, it's much easier to add the extra file(s) by creating another cd9660 session on top of the standard image:

cp FreeBSD-12.0-RELEASE-amd64-bootonly.iso new.iso
volid=$(isoinfo -d -i new.iso | awk '/Volume id/{print$3}')
growisofs -M new.iso -d -l -r -V "$volid" -graft-points \
   /etc/installerconfig=/path/to/your_installerconfig \
   [other files ...]

This should "inherit" the bootimage from the previous session, and new files with the same path will override those already on the disc (but only if they are newer, when using the standard mkisofs/genisoimage).

Notice that unless the Volume Id of the new session is set to the same as the old (as above), the FreeBSD installer won't mount the cd automatically, but will prompt for a fs spec with mountroot>.

I've tested the above on qemu using the OVMF UEFI firmware from here, using the following command line:

qemu-system-x86_64 -enable-kvm -m 2G -serial none \
    -bios ovmf-x64/OVMF-pure-efi.fd -cdrom new.iso

If you really need to create a UEFI bootable cd from scratch, then you can find more info in FreeBSD's wiki (under "CD/DVD Boot under UEFI") and here.

FreeBSD's broken growisofs

Because of a bug, growisofs will crash on FreeBSD when used with a regular file instead of a device; to avoid that, you should apply this diff to growisofs.c (apply with patch -l):

--- growisofs.c~        2018-12-14 07:32:38.814189935 +0200
+++ growisofs.c 2018-12-14 07:32:43.602431986 +0200
@@ -3471,7 +3471,8 @@
 #if !(defined(__APPLE__) && defined(__MACH__))
-    CLOSEONEXEC(ioctl_fd);
+    if(ioctl_handle != INVALID_HANDLE)
+       CLOSEONEXEC(ioctl_fd);
  • Thanks, I just tried this but growisofs seems to not work. I'm getting a segmentation fault / core dump on FreeBSD and it flat doesn't work on macOS.
    – Roxy
    Dec 14 '18 at 3:04
  • I was able to get growisofs working on Linux and created the ISO, but it did stop when trying to mount as you said. In my case, the original scenario continued through to the installer just fine, so this doesn't seem like a workable solution.
    – Roxy
    Dec 14 '18 at 3:32
  • That case (from the 2nd comment) was likely caused by a non-matching volume_id -- the installer expect it to be the same as the original. I'll see what can be done with the bug in FreeBSD's growisofs.
    – mosvy
    Dec 14 '18 at 3:36
  • what versions of FreeBSD are you using / trying to install?
    – mosvy
    Dec 14 '18 at 3:41
  • I'm using the bootonly version of the FreeBSD 12 image. I installed it with pkg install dvd+rw-tools but maybe the ports version will work better?
    – Roxy
    Dec 14 '18 at 4:17

The problem with many documents on creating bootable ISOs is that they tend to assume non-UEFI boot by default.

Here's a good reference that has information on UEFI boot from CD/DVD media: https://dev.lovelyhq.com/libburnia/libisofs/raw/master/doc/boot_sectors.txt

So, it appears that if you want to use a separate El Torito boot image with UEFI (like you used to do with BIOS), you'll need to make sure the boot image gets embedded with a correct platform ID byte for UEFI. For x86 BIOS, the platform ID was 0. PowerPCs used 1; value 2 was designated for Macs; and UEFI specifies a value of 0xef, or 239 in decimal.

So it seems to me that you would have to have some way to specify the platform ID value: either directly, or by using some option to specify that the boot image is supposed to be an UEFI boot image. I suppose this Fedora document linked by mosvy does this by using option -e to specify the location of efiboot.img instead of using -b as with traditional BIOS boot images.

So, verify that your boot/cdboot is a valid UEFI boot image, and try using -e boot/cdboot in the mkisofs command line instead of -b boot/cdboot.

And here is a description of what the contents of a UEFI boot image might look like:

I happen to have a RHEL 8.0 beta 1 ISO image at hand, and I've just confirmed that it is in fact bootable using VirtualBox in UEFI mode. The UEFI boot image it uses is available in the main iso9660 filesystem of the images as images/efiboot.img, and it apparently contains just a FAT filesystem image, with no partitition table of any kind.

Within the filesystem of efiboot.img, there is just a directory \EFI\BOOT with the appropriate UEFI bootloaders: in this case, both BOOTX64.EFI and BOOTIA32.EFI, which appear to be Secure Boot shims, and corresponding versions of GRUB as grubx64.efi and grubia32.efi respectively, and any ancillary files required by those: the GRUB configuration file, the GRUB font file, and the MOKManager for the Secure Boot shim.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.