Silvio,

Thanks, changing "mcopy -b" to "mcopy" fixed things for me.

For the record, I attach the full scripts;
Debian 12 (4.0.33-1+really4.0.32-1) fails with -b;
Debian 11 (mtools=4.0.26-1) works with -b.
#!/usr/bin/python3
import argparse
import pathlib
import subprocess
import tempfile

__author__ = "Trent W. Buck"
__copyright__ = "Copyright © 2020 Trent W. Buck"
__license__ = "expat"

__doc__ = """ build the simplest Debian Live image that can boot

This uses mmdebstrap to do the heavy lifting;
it can run entirely without root privileges.
It emits a USB key disk image that contains a bootable EFI ESP,
which in turn includes a bootloader (refind), kernel, ramdisk, and filesystem.squashfs.

NOTE: this is the simplest config possible.
      It lacks CRITICAL SECURITY AND DATA LOSS packages, such as amd64-microcode and smartd.
"""

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('output_file', nargs='?', default=pathlib.Path('filesystem.img'), type=pathlib.Path)
parser.add_argument('--boot-test', action='store_true')
args = parser.parse_args()


filesystem_img_size = '256M'    # big enough to include filesystem.squashfs + about 64M of bootloader, kernel, and ramdisk.
esp_offset = 1024 * 1024        # 1MiB
esp_label = 'UEFI-ESP'          # max 8 bytes for FAT32
live_media_path = 'debian-live'

with tempfile.TemporaryDirectory(prefix='debian-live-bullseye-amd64-minimal.') as td:
    td = pathlib.Path(td)
    subprocess.check_call(
        ['mmdebstrap',
         '--mode=unshare',
         '--variant=apt',
         '--aptopt=Acquire::http::Proxy "http://localhost:3142";',
         '--aptopt=Acquire::https::Proxy "DIRECT"',
         '--dpkgopt=force-unsafe-io',
         '--include=linux-image-amd64 init initramfs-tools live-boot netbase',
         '--include=dbus',          # https://bugs.debian.org/814758
         '--include=live-config iproute2 keyboard-configuration locales sudo user-setup',
         '--include=ifupdown isc-dhcp-client',  # live-config doesn't support systemd-networkd yet.

         # Do the **BARE MINIMUM** to make a USB key that can boot on X86_64 UEFI.
         # We use mtools so we do not ever need root privileges.
         # We can't use mkfs.vfat, as that needs kpartx or losetup (i.e. root).
         # We can't use mkfs.udf, as that needs mount (i.e. root).
         # We can't use "refind-install --usedefault" as that runs mount(8) (i.e. root).
         # We don't use genisoimage because
         # 1) ISO9660 must die;
         # 2) incomplete UDF 1.5+ support;
         # 3) resulting filesystem can't be tweaked after flashing (e.g. debian-live/site.dir/etc/systemd/network/up.network).
         #
         # We use refind because 1) I hate grub; and 2) I like refind.
         # If you want aarch64 or ia32 you need to install their BOOTxxx.EFI files.
         # If you want kernel+initrd on something other than FAT, you need refind/drivers_xxx/xxx_xxx.EFI.
         #
         # FIXME: with qemu in UEFI mode (OVMF), I get dumped into startup.nsh (UEFI REPL).
         #        From there, I can manually type in "FS0:\EFI\BOOT\BOOTX64.EFI" to start refind, tho.
         #        So WTF is its problem?  Does it not support fallback bootloader?
         '--include=refind parted mtools',
         '--essential-hook=echo refind refind/install_to_esp boolean false | chroot $1 debconf-set-selections',
         '--customize-hook=echo refind refind/install_to_esp boolean true  | chroot $1 debconf-set-selections',
         '--customize-hook=chroot $1 mkdir -p /boot/USB /boot/EFI/BOOT',
         '--customize-hook=chroot $1 cp /usr/share/refind/refind/refind_x64.efi /boot/EFI/BOOT/BOOTX64.EFI',
         f'--customize-hook=chroot $1 truncate --size={filesystem_img_size} /boot/USB/filesystem.img',
         f'--customize-hook=chroot $1 parted --script --align=optimal /boot/USB/filesystem.img  mklabel gpt  mkpart {esp_label} {esp_offset}b 100%  set 1 esp on',
         f'--customize-hook=chroot $1 mformat -i /boot/USB/filesystem.img@@{esp_offset} -F -v {esp_label}',
         f'--customize-hook=chroot $1 mmd     -i /boot/USB/filesystem.img@@{esp_offset} ::{live_media_path}',
         f"""--customize-hook=echo '"Boot with default options" "boot=live live-media-path={live_media_path}"' >$1/boot/refind_linux.conf""",
         # NOTE: find sidesteps the "glob expands before chroot applies" problem.
         f"""--customize-hook=chroot $1 find -O3 /boot/ -xdev -mindepth 1 -maxdepth 1 -regextype posix-egrep -iregex '.*/(EFI|refind_linux.conf|vmlinuz.*|initrd.img.*)' -exec mcopy -vsbpm -i /boot/USB/filesystem.img@@{esp_offset} {{}} :: ';'""",
         # FIXME: copy-out doesn't handle sparseness, so is REALLY slow (about 50 seconds).
         # Therefore instead leave it in the squashfs, and extract it later.
         #  f'--customize-hook=copy-out /boot/USB/filesystem.img /tmp/',
         #  f'--customize-hook=chroot $1 rm /boot/USB/filesystem.img',

         'bullseye',
         td / 'filesystem.squashfs'
         ])

    with args.output_file.open('wb') as f:
        subprocess.check_call(
            ['rdsquashfs',
             '--cat=boot/USB/filesystem.img',
             td / 'filesystem.squashfs'],
            stdout=f)
    subprocess.check_call([
        'mcopy',
        '-i', f'{args.output_file}@@{esp_offset}',
        td / 'filesystem.squashfs', f'::{live_media_path}/filesystem.squashfs'])

# Fuck it, also show how to do a basic qemu boot.
if args.boot_test:
    subprocess.check_call([
        'kvm', '-m', '2G',
        '--drive', f'if=virtio,format=raw,readonly=on,media=disk,file={args.output_file}',
        '--drive', 'if=pflash,format=raw,unit=0,readonly=on,file=/usr/share/ovmf/OVMF.fd'])
#!/usr/bin/python3
import argparse
import pathlib
import subprocess
import tempfile

__author__ = "Trent W. Buck"
__copyright__ = "Copyright © 2020 Trent W. Buck"
__license__ = "expat"

__doc__ = """ build the simplest Debian Live image that can boot

This uses mmdebstrap to do the heavy lifting;
it can run entirely without root privileges.
It emits a USB key disk image that contains a bootable EFI ESP,
which in turn includes a bootloader (refind), kernel, ramdisk, and filesystem.squashfs.

NOTE: this is the simplest config possible.
      It lacks CRITICAL SECURITY AND DATA LOSS packages, such as amd64-microcode and smartd.
"""

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('output_file', nargs='?', default=pathlib.Path('filesystem.img'), type=pathlib.Path)
parser.add_argument('--boot-test', action='store_true')
args = parser.parse_args()


filesystem_img_size = '512M'    # big enough to include filesystem.squashfs + about 64M of bootloader, kernel, and ramdisk.
esp_offset = 1024 * 1024        # 1MiB
esp_label = 'UEFI-ESP'          # max 8 bytes for FAT32
live_media_path = 'debian-live'

with tempfile.TemporaryDirectory(prefix='debian-live-bullseye-amd64-minimal.') as td:
    td = pathlib.Path(td)
    subprocess.check_call(
        ['mmdebstrap',
         '--mode=unshare',
         '--variant=apt',
         '--aptopt=Acquire::http::Proxy "http://localhost:3142";',
         '--aptopt=Acquire::https::Proxy "DIRECT"',
         '--dpkgopt=force-unsafe-io',
         '--include=linux-image-amd64 init initramfs-tools live-boot netbase',
         '--include=dbus-broker',  # https://bugs.debian.org/814758
         '--include=live-config iproute2 keyboard-configuration locales sudo user-setup',
         '--include=ifupdown isc-dhcp-client',  # live-config doesn't support systemd-networkd yet.

         # Do the **BARE MINIMUM** to make a USB key that can boot on X86_64 UEFI.
         # We use mtools so we do not ever need root privileges.
         # We can't use mkfs.vfat, as that needs kpartx or losetup (i.e. root).
         # We can't use mkfs.udf, as that needs mount (i.e. root).
         # We can't use "refind-install --usedefault" as that runs mount(8) (i.e. root).
         # We don't use genisoimage because
         # 1) ISO9660 must die;
         # 2) incomplete UDF 1.5+ support;
         # 3) resulting filesystem can't be tweaked after flashing (e.g. debian-live/site.dir/etc/systemd/network/up.network).
         #
         # We use refind because 1) I hate grub; and 2) I like refind.
         # If you want aarch64 or ia32 you need to install their BOOTxxx.EFI files.
         # If you want kernel+initrd on something other than FAT, you need refind/drivers_xxx/xxx_xxx.EFI.
         #
         # FIXME: with qemu in UEFI mode (OVMF), I get dumped into startup.nsh (UEFI REPL).
         #        From there, I can manually type in "FS0:\EFI\BOOT\BOOTX64.EFI" to start refind, tho.
         #        So WTF is its problem?  Does it not support fallback bootloader?
         '--include=refind parted mtools',
         '--essential-hook=echo refind refind/install_to_esp boolean false | chroot $1 debconf-set-selections',
         '--customize-hook=echo refind refind/install_to_esp boolean true  | chroot $1 debconf-set-selections',
         '--customize-hook=chroot $1 mkdir -p /boot/USB /boot/EFI/BOOT',
         '--customize-hook=chroot $1 cp /usr/share/refind/refind/refind_x64.efi /boot/EFI/BOOT/BOOTX64.EFI',
         f'--customize-hook=chroot $1 truncate --size={filesystem_img_size} /boot/USB/filesystem.img',
         f'--customize-hook=chroot $1 parted --script --align=optimal /boot/USB/filesystem.img  mklabel gpt  mkpart {esp_label} {esp_offset}b 100%  set 1 esp on',
         f'--customize-hook=chroot $1 mformat -i /boot/USB/filesystem.img@@{esp_offset} -F -v {esp_label}',
         f'--customize-hook=chroot $1 mmd     -i /boot/USB/filesystem.img@@{esp_offset} ::{live_media_path}',
         f"""--customize-hook=echo '"Boot with default options" "boot=live live-media-path={live_media_path}"' >$1/boot/refind_linux.conf""",
         # NOTE: find sidesteps the "glob expands before chroot applies" problem.
         # FIXME: had to remove the "-b" option due to https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=990486#15
         f"""--customize-hook=chroot $1 find -O3 /boot/ -xdev -mindepth 1 -maxdepth 1 -regextype posix-egrep -iregex '.*/(EFI|refind_linux.conf|vmlinuz.*|initrd.img.*)' -exec mcopy -vspm -i /boot/USB/filesystem.img@@{esp_offset} {{}} :: ';'""",
         # FIXME: copy-out doesn't handle sparseness, so is REALLY slow (about 50 seconds).
         # Therefore instead leave it in the squashfs, and extract it later.
         #  f'--customize-hook=copy-out /boot/USB/filesystem.img /tmp/',
         #  f'--customize-hook=chroot $1 rm /boot/USB/filesystem.img',

         'bookworm',
         td / 'filesystem.squashfs'
         ])

    with args.output_file.open('wb') as f:
        subprocess.check_call(
            ['rdsquashfs',
             '--cat=boot/USB/filesystem.img',
             td / 'filesystem.squashfs'],
            stdout=f)
    subprocess.check_call([
        'mcopy',
        '-i', f'{args.output_file}@@{esp_offset}',
        td / 'filesystem.squashfs', f'::{live_media_path}/filesystem.squashfs'])

# Fuck it, also show how to do a basic qemu boot.
if args.boot_test:
    subprocess.check_call([
        'kvm', '-m', '2G',
        '--drive', f'if=virtio,format=raw,readonly=on,media=disk,file={args.output_file}',
        '--drive', 'if=pflash,format=raw,unit=0,readonly=on,file=/usr/share/ovmf/OVMF.fd'])

Reply via email to