diff --git a/Makefile b/Makefile index 7806781..bd091d5 100644 --- a/Makefile +++ b/Makefile @@ -24,147 +24,15 @@ endif target_platforms: @echo $(platforms) -raspi_base_buster.yaml: raspi_master.yaml - cat raspi_master.yaml | \ - sed "s/__FIRMWARE_PKG__/raspi3-firmware/" | \ - sed "s/__RELEASE__/buster/" |\ - sed "s/__SECURITY_SUITE__/buster\/updates/" |\ - sed "s/__FIX_FIRMWARE_PKG_NAME__/sed -i s#raspi-firmware#raspi3-firmware# \$${ROOT?}\/etc\/systemd\/system\/rpi-reconfigure-raspi-firmware.service/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_1_buster.yaml: raspi_base_buster.yaml - cat raspi_base_buster.yaml | sed "s/__ARCH__/armel/" | \ - sed "s/__LINUX_IMAGE__/linux-image-rpi/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-rpi\\/bcm*rpi-*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - grep -v "__OTHER_APT_ENABLE__" |\ - sed "s/__HOST__/rpi1/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_2_buster.yaml: raspi_base_buster.yaml - cat raspi_base_buster.yaml | sed "s/__ARCH__/armhf/" | \ - sed "s/__LINUX_IMAGE__/linux-image-armmp/" | \ - grep -v "__EXTRA_PKGS__" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-armmp\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - sed "s/__OTHER_APT_ENABLE__//" |\ - sed "s/__HOST__/rpi2/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_3_buster.yaml: raspi_base_buster.yaml - cat raspi_base_buster.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211\/buster-backports/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__OTHER_APT_ENABLE__/# raspi 3 needs firmware-brcm80211 newer than buster's for wifi\n deb http:\/\/deb.debian.org\/debian\/ buster-backports main contrib non-free/" |\ - sed "s/__HOST__/rpi3/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_4_buster.yaml: raspi_base_buster.yaml - cat raspi_base_buster.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s#raspi3-firmware#raspi-firmware/buster-backports#" | \ - sed "s#apt-get update#echo 'APT::Default-Release \"buster\";' > /etc/apt/apt.conf\n apt-get update#" | \ - sed "s#\(RASPIROOT.*cmdline.txt\)#\1\n sed -i 's/cma=64M //' /boot/firmware/cmdline.txt#" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64\/buster-backports/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211\/buster-backports/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__OTHER_APT_ENABLE__/deb http:\/\/deb.debian.org\/debian\/ buster-backports main contrib non-free # raspi 4 needs a kernel and raspi-firmware newer than buster's/" |\ - sed "s/__HOST__/rpi4/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_base_bullseye.yaml: raspi_master.yaml - cat raspi_master.yaml | \ - sed "s/__RELEASE__/bullseye/" |\ - sed "s/__FIRMWARE_PKG__/raspi-firmware/" | \ - sed "/touch \/etc\/machine-id/d" | \ - grep -v "__OTHER_APT_ENABLE__" |\ - grep -v "__FIX_FIRMWARE_PKG_NAME__" |\ - sed "s/__SECURITY_SUITE__/bullseye-security/" > $@ - -raspi_1_bullseye.yaml: raspi_base_bullseye.yaml - cat raspi_base_bullseye.yaml | sed "s/__ARCH__/armel/" | \ - sed "s/__LINUX_IMAGE__/linux-image-rpi/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-rpi\\/bcm*rpi-*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - sed "s/__HOST__/rpi_1/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_2_bullseye.yaml: raspi_base_bullseye.yaml - cat raspi_base_bullseye.yaml | sed "s/__ARCH__/armhf/" | \ - sed "s/__LINUX_IMAGE__/linux-image-armmp/" | \ - grep -v "__EXTRA_PKGS__" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-armmp\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - sed "s/__HOST__/rpi_2/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_3_bullseye.yaml: raspi_base_bullseye.yaml - cat raspi_base_bullseye.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__HOST__/rpi_3/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_4_bullseye.yaml: raspi_base_bullseye.yaml - cat raspi_base_bullseye.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s#\(RASPIROOT.*cmdline.txt\)#\1\n sed -i 's/cma=64M //' /boot/firmware/cmdline.txt#" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__HOST__/rpi_4/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_base_bookworm.yaml: raspi_master.yaml - cat raspi_master.yaml | \ - sed "s/__RELEASE__/bookworm/" |\ - sed "s/__FIRMWARE_PKG__/raspi-firmware/" | \ - grep -v "__OTHER_APT_ENABLE__" |\ - grep -v "__FIX_FIRMWARE_PKG_NAME__" |\ - grep -v "__SECURITY_SUITE__" > $@ - -raspi_1_bookworm.yaml: raspi_base_bookworm.yaml - cat raspi_base_bookworm.yaml | sed "s/__ARCH__/armel/" | \ - sed "s/__LINUX_IMAGE__/linux-image-rpi/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-rpi\\/bcm*rpi-*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - sed "s/__HOST__/rpi_1/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_2_bookworm.yaml: raspi_base_bookworm.yaml - cat raspi_base_bookworm.yaml | sed "s/__ARCH__/armhf/" | \ - sed "s/__LINUX_IMAGE__/linux-image-armmp/" | \ - grep -v "__EXTRA_PKGS__" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-armmp\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyAMA0,115200/" |\ - sed "s/__HOST__/rpi_2/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_3_bookworm.yaml: raspi_base_bookworm.yaml - cat raspi_base_bookworm.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__HOST__/rpi_3/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ - -raspi_4_bookworm.yaml: raspi_base_bookworm.yaml - cat raspi_base_bookworm.yaml | sed "s/__ARCH__/arm64/" | \ - sed "s#\(RASPIROOT.*cmdline.txt\)#\1\n sed -i 's/cma=64M //' /boot/firmware/cmdline.txt#" | \ - sed "s/__LINUX_IMAGE__/linux-image-arm64/" | \ - sed "s/__EXTRA_PKGS__/- firmware-brcm80211/" | \ - sed "s/__DTB__/\\/usr\\/lib\\/linux-image-*-arm64\\/broadcom\\/bcm*rpi*.dtb/" |\ - sed "s/__SERIAL_CONSOLE__/ttyS1,115200/" |\ - sed "s/__HOST__/rpi_4/" |\ - grep -v '__EXTRA_SHELL_CMDS__' > $@ +# Generate targets based on all family * release combinations: +define dynamic_yaml_target = + raspi_$(1)_$(2).yaml: raspi_master.yaml generate-recipe.py + raspi_$(1)_$(2).yaml: + ./generate-recipe.py $(1) $(2) +endef +$(foreach release,$(BUILD_RELEASES), \ + $(foreach family,$(BUILD_FAMILIES), \ + $(eval $(call dynamic_yaml_target,$(family),$(release))))) %.img.sha256: %.img echo $@ diff --git a/generate-recipe.py b/generate-recipe.py new file mode 100755 index 0000000..a8f428f --- /dev/null +++ b/generate-recipe.py @@ -0,0 +1,172 @@ +#!/usr/bin/python3 + +import re +import sys + +# pylint: disable=invalid-name + +### Sanity/usage checks + +if len(sys.argv) != 3: + print("E: need 2 arguments", file=sys.stderr) + sys.exit(1) + +version = sys.argv[1] +if version not in ["1", "2", "3", "4"]: + print("E: unsupported version %s" % version, file=sys.stderr) + sys.exit(1) + +suite = sys.argv[2] +if suite not in ['buster', 'bullseye', 'bookworm']: + print("E: unsupported suite %s" % suite, file=sys.stderr) + sys.exit(1) +target_yaml = 'raspi_%s_%s.yaml' % (version, suite) + + +### Setting variables based on suite and version starts here + +# Arch, kernel, DTB: +if version == '1': + arch = 'armel' + linux = 'linux-image-rpi' + dtb = '/usr/lib/linux-image-*-rpi/bcm*rpi-*.dtb' +elif version == '2': + arch = 'armhf' + linux = 'linux-image-armmp' + dtb = '/usr/lib/linux-image-*-armmp/bcm*rpi*.dtb' +elif version in ['3', '4']: + arch = 'arm64' + linux = 'linux-image-arm64' + dtb = '/usr/lib/linux-image-*-arm64/broadcom/bcm*rpi*.dtb' + +# APT and default firmware (name + handling) +if suite == 'buster': + security_suite = '%s/updates' % suite + raspi_firmware = 'raspi3-firmware' + fix_firmware = True +else: + security_suite = '%s-security' % suite + raspi_firmware = 'raspi-firmware' + fix_firmware = False + +# Extra wireless firmware: +if version != '2': + wireless_firmware = 'firmware-brcm80211' +else: + wireless_firmware = '' + +# Pi 4 on buster requires some backports: +backports_enable = False +backports_suite = '%s-backports' % suite +if version == '4' and suite == 'buster': + backports_enable = "# raspi 4 needs kernel and firmware newer than buster's" + linux = '%s/%s' % (linux, backports_suite) + raspi_firmware = 'raspi-firmware/%s' % backports_suite + wireless_firmware = 'firmware-brcm80211/%s' % backports_suite + fix_firmware = False + +if version == '3' and suite == 'buster': + backports_enable = "# raspi 3 needs firmware-brcm80211 newer than buster's for wifi" + wireless_firmware = 'firmware-brcm80211/%s' % backports_suite + +# Serial console: +if version in ['1', '2']: + serial = 'ttyAMA0,115200' +elif version in ['3', '4']: + serial = 'ttyS1,115200' + +# CMA fixup: +extra_chroot_shell_cmds = [] +if version == '4': + extra_chroot_shell_cmds = [ + "sed -i 's/cma=64M //' /boot/firmware/cmdline.txt", + ] + +# XXX: The disparity between suite seems to be a bug, pick a naming +# and stick to it! +# +# Hostname: +if suite == 'buster': + hostname = 'rpi%s' % version +else: + hostname = 'rpi_%s' % version + +# Nothing yet! +extra_root_shell_cmds = [] + + +### The following prepares substitutions based on variables set earlier + +# Commands to fix the firmware name in the systemd unit: +if fix_firmware: + fix_firmware_cmds = ['sed -i s/raspi-firmware/raspi3-firmware/ ${ROOT?}/etc/systemd/system/rpi-reconfigure-raspi-firmware.service'] +else: + fix_firmware_cmds = [] + +# Enable backports with a reason, or add commented-out entry: +if backports_enable: + backports_stanza = """ +%s +deb http://deb.debian.org/debian/ %s main contrib non-free +""" % (backports_enable, backports_suite) +else: + backports_stanza = """ +# Backports are _not_ enabled by default. +# Enable them by uncommenting the following line: +# deb http://deb.debian.org/debian %s main contrib non-free +""" % backports_suite + +# Buster requires an existing, empty /etc/machine-id file: +if suite == 'buster': + touch_machine_id = 'touch /etc/machine-id' +else: + touch_machine_id = '' + + +### Write results: + +def align_replace(text, pattern, replacement): + """ + This helper lets us keep the indentation of the matched pattern + with the upcoming replacement, across multiple lines. Naive + implementation, please make it more pythonic! + """ + lines = text.splitlines() + for i, line in enumerate(lines): + m = re.match(r'^(\s+)%s' % pattern, line) + if m: + indent = m.group(1) + del lines[i] + for r in replacement: + lines.insert(i, '%s%s' % (indent, r)) + i = i + 1 + break + return '\n'. join(lines) + '\n' + + +with open('raspi_master.yaml', 'r') as in_file: + with open(target_yaml, 'w') as out_file: + in_text = in_file.read() + out_text = in_text \ + .replace('__RELEASE__', suite) \ + .replace('__ARCH__', arch) \ + .replace('__LINUX_IMAGE__', linux) \ + .replace('__DTB__', dtb) \ + .replace('__SECURITY_SUITE__', security_suite) \ + .replace('__RASPI_FIRMWARE__', raspi_firmware) \ + .replace('__WIRELESS_FIRMWARE__', wireless_firmware) \ + .replace('__SERIAL_CONSOLE__', serial) \ + .replace('__HOST__', hostname) \ + .replace('__TOUCH_MACHINE_ID__', touch_machine_id) + + out_text = align_replace(out_text, '__FIX_FIRMWARE_PKG_NAME__', fix_firmware_cmds) + out_text = align_replace(out_text, '__EXTRA_ROOT_SHELL_CMDS__', extra_root_shell_cmds) + out_text = align_replace(out_text, '__EXTRA_CHROOT_SHELL_CMDS__', extra_chroot_shell_cmds) + out_text = align_replace(out_text, '__BACKPORTS__', backports_stanza.splitlines()) + + # Try not to keep lines where the placeholder was replaced + # with nothing at all (including on a "list item" line): + filtered = [x for x in out_text.splitlines() + if not re.match(r'^\s+$', x) + and not re.match(r'^\s+-\s*$', x)] + out_file.write('\n'.join(filtered) + "\n") diff --git a/raspi_master.yaml b/raspi_master.yaml index 18e0474..95ffe8a 100644 --- a/raspi_master.yaml +++ b/raspi_master.yaml @@ -49,14 +49,11 @@ steps: unless: rootfs_unpacked - create-file: /etc/apt/sources.list - trailing-newline: '1' - contents: | + contents: |+ deb http://deb.debian.org/debian __RELEASE__ main contrib non-free deb http://security.debian.org/debian-security __SECURITY_SUITE__ main contrib non-free - # Backports are _not_ enabled by default. - # Enable them by uncommenting the following line: - # deb http://deb.debian.org/debian __RELEASE__-backports main contrib non-free - __OTHER_APT_ENABLE__ + __BACKPORTS__ + unless: rootfs_unpacked - copy-file: /etc/initramfs-tools/hooks/rpi-resizerootfs @@ -82,9 +79,9 @@ steps: - parted - ssh - wpasupplicant - - __FIRMWARE_PKG__ - __LINUX_IMAGE__ - __EXTRA_PKGS__ + - __RASPI_FIRMWARE__ + - __WIRELESS_FIRMWARE__ tag: / unless: rootfs_unpacked @@ -121,7 +118,7 @@ steps: ln -s /etc/systemd/system/rpi-generate-ssh-host-keys.service "${ROOT?}/etc/systemd/system/multi-user.target.requires/rpi-generate-ssh-host-keys.service" rm -f "${ROOT?}"/etc/ssh/ssh_host_*_key* - __EXTRA_SHELL_CMDS__ + __EXTRA_ROOT_SHELL_CMDS__ root-fs: / # Copy the relevant device tree files to the boot partition @@ -149,6 +146,8 @@ steps: sed -i 's#root=/dev/mmcblk0p2#root=LABEL=RASPIROOT#' /boot/firmware/cmdline.txt sed -i 's/^#ROOTPART=.*/ROOTPART=LABEL=RASPIROOT/' /etc/default/raspi-firmware + __EXTRA_CHROOT_SHELL_CMDS__ + # TODO(https://github.com/larswirzenius/vmdb2/issues/24): remove once vmdb # clears /etc/resolv.conf on its own. - shell: | @@ -169,4 +168,4 @@ steps: - chroot: / shell: | rm -f /etc/machine-id /var/lib/dbus/machine-id - touch /etc/machine-id + __TOUCH_MACHINE_ID__