Kleines Raspberry Pi OS Update, große Probleme: Änderungen in /boot und ihre Folgen

Als Video ansehen
Bereitgestellt über YouTube

Kleines Raspberry Pi OS Update, große Probleme: Änderungen in /boot und ihre Folgen

Eine kleine Aktualisierung verursacht gerade an einigen Stellen im Raspberry Pi OS 12 Probleme – dabei war sie als Übergangslösung für eine Umstellung gedacht. Vor allem config.txt und cmdline.txt sind betroffen. Einige Werkzeuge verwenden sie intern. Leider rechnen nicht alle damit, dass es die alten Pfade nicht mehr geben könnte. Im Raspberry Pi OS 12 aka Bookworm ist aber genau das passiert: /boot wurde nach /boot/firmware verschoben. Das irritiert nicht nur einige Nutzer, die sie für erweiterte Funktionen anpassen möchten.

Hier erfährst du, warum derzeit Skripte wie rpi-clone nicht mehr funktionieren und wir derzeit mit zwei verschiedenen Pfaden arbeiten müssen, um diese beiden Dateien zu bearbeiten. Außerdem demonstriere ich am quelloffenen rpi-clone Projekt, wie man bei OSS mit wenigen Anpassungen eine Lösung einbauen kann.

Was machen config.txt und cmdline.txt?

Von X86-PCs sind wir ein BIOS gewohnt, das inzwischen nahezu vollständig vom Nachfolger UEFI abgelöst wurde. In beiden Fällen geht es im Kern um eine Firmware, die beim Starten des Computers weitere Software startet. Für gewöhnlich ist das ein Bootloader, der wiederum ein Betriebssystem wie eine GNU/Linux-Distribution oder Microsoft Windows startet. Jedes BIOS/UEFI hat eine Konfigurationsoberfläche, um diverse Einstellungen vornehmen zu können. Dort lassen sich Hardware-Funktionen des Mainboards aktivieren oder deaktivieren. Darunter ist z.B. die Startreihenfolge der Medien, von denen das BIOS/UEFI versuchen soll, Bootloader und Betriebssystem zu starten.

Während das UEFI im X86-Bereich Standardisiert ist, haben wir bei Einplatinencomputern leider ein Chaos mit selbst entwickelter, oft Proprietärer Firmware. Beim Raspberry Pi existiert keine Oberfläche für dessen Einstellungen, wie bei BIOS und UEFI. Stattdessen können Einstellungen über die config.txt Datei vorgenommen werden.1 Beispielsweise lässt sich dort die Tonausgabe deaktivieren. Auch verschiedene GPIO-Schnittstellen kann man dort ein- oder ausschalten.

# Tonausgabe aktivieren
dtparam=audio=on
# I2C Bus auf den GPIO-Schnittstellen einschalten
dtparam=i2c_arm=on

Die Firmware übergibt an den Bootloader. Findet dieser entsprechend seiner Konfiguration ein Betriebssystem (z.B. auf der Speicherkarte oder angeschlossener USB-Geräte), wird vereinfacht erst der Linux-Kernel geladen, dann die restliche GNU/Linux-Distribution (z.B. Raspberry Pi OS). Wie der Name bereits vermuten lässt, ist der Kernel zentraler Bestandteil jedes Betriebssystems. Er kümmert sich um Prozesse und Dateien an unterster Stelle, d.H. mit direktem Zugriff auf die Hardware (z.B. eine Speicherkarte). Auch hier gibt es daher einige Einstellungen, die man als Parameter an den Kernel übermitteln kann. Sie werden beim Raspberry Pi in der cmdline.txt im Format name=wert festgelegt. Im Gegensatz zu config.txt allerdings alle in der gleichen Zeile, getrennt durch ein Leerzeichen.

console=serial0,115200 console=tty1 root=PARTUUID=7ce26686-02 rootfstype=ext4 ...

Im Auszug wird etwa eine serielle Konsole (zu Debug-Zwecken) festlegt und ein tty für die Bildschirmausgabe. TTY steht für teletypewriter, zu Deutsch Fernschreiber. Im Kern geht es um Ein- und Ausgabe auf der Konsole, die auch aus der Ferne (tele) stattfinden kann. Darüber hinaus ist das Wurzel-Dateisystem mit eindeutiger UUID der Partition angegeben. Wie man sehen kann, ist das nach dem Start in / eingehängt worden:

$ ls -lh /dev/disk/by-partuuid/7ce26686-02
lrwxrwxrwx 1 root root 15 Feb  7 00:22 /dev/disk/by-partuuid/7ce26686-02 -> ../../mmcblk0p2
$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
mmcblk0     179:0    0 59.5G  0 disk 
├─mmcblk0p1 179:1    0  512M  0 part /boot/firmware
└─mmcblk0p2 179:2    0   59G  0 part /

Es finden sich in der standardmäßig vorhandenen cmdline.txt noch weitere Parameter, die hier den Rahmen sprengen würden. Das Konzept dahinter ist nicht spezifisch für den Raspberry Pi: In jeder GNU/Linux-Distribution kann man Parameter für den Kernel setzen. Üblicherweise geschieht dies auf X86-Systemen über den Bootloader. Meist ist das Grub, dieser leitet den Inhalt der Variable GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub beim Start an Linux weiter.

Was genau wurde beim Raspberry Pi OS geändert?

Beide Dateien lagen dort bis Bookworm direkt in /boot. Unter den meisten GNU/Linux-Distributionen liegen dort einige Dateien, die notwendig sind, um Linux zu starten – oft auch die Kernel selbst. Mit dem Raspberry Pi OS 12 (Bookworm) hat sich das geändert: Die Dateien wurden in /boot/firmware verschoben.23 Dabei handelt es sich um ein für den Raspberry Pi spezifisches Verzeichnis.4

  • /boot/config.txt wurde zu /boot/firmware/config.txt
  • /boot/cmdline.txt wurde zu /boot/firmware/<code>cmdline.txt

Diese Änderung blieb lange Zeit unbemerkt, weil man als Übergangslösung symbolische Verknüpfungen (Symlinks) für beide Dateien erstellt hatte. Das ist eine Datei, die auf eine andere zeigt. Viele Programme folgen solchen symbolischen Verknüpfungen. Folgendes Beispiel legt eine Textdatei in meinem Heimverzeichnis an und erstellt /tmp/demo.txt als symbolische Verknüpfung auf diese Datei. Der Schreibvorgang mit echo fügt den Text in die originale Datei meines Heimverzeichnisses ein:

$ touch /home/u-labs/demo.txt
$ ln -s /home/u-labs/demo.txt /tmp/demo.txt
$ l /tmp/demo.txt
Permissions Size User   Group  Date Modified Name
lrwxrwxrwx     - u-labs u-labs  5 Feb 16:07   /tmp/demo.txt -> /home/u-labs/demo.txt

$ echo abc > /tmp/demo.txt
$ cat /home/u-labs/demo.txt
abc

Am 18.01.2024 wurde diese Übergangslösung jedoch im APT-Paket raspberrypi-sys-mods entfernt.5 Statt der symbolischen Verknüpfung auf die jeweilige Datei im firmware Unterverzeichnis enthalten beide einen Hinweis, man solle diese Datei nicht mehr bearbeiten und stattdessen den neuen Pfad verwenden:

$ cat /boot/config.txt 
DO NOT EDIT THIS FILE

The file you are looking for has moved to /boot/firmware/config.txt

Die aktualisierte Version 20240123 des Pakets wurde Ende Dezember 2023 verteilt. Wer alle Paketquellen und Pakete per sudo apt update && sudo apt upgrade aktualisiert hat, dem wurden die beiden symbolischen Verknüpfungen entfernt.

$ dpkg -l | grep raspberrypi-sys-mods
ii  raspberrypi-sys-mods                 20240123                            arm64        System tweaks for the Raspberry Pi

Das sind die Folgen

Und das hat Konsequenzen: Dadurch funktioniert beispielsweise rpi-clone nicht mehr: Seit dem aktualisierten Paket starten geklonte Laufwerke nicht mehr, sondern landen in einer BusyBox Shell. Bei rpi-clone handelt es sich um ein beliebtes Skript, um u.a. einen kompletten Klon der Karte anfertigen zu können – etwa, um von SD-Speicherkarte auf SSD zu migrieren. Im Gegensatz zum 1:1 Klonen mit dd weist das Skript den Partitionen auf dem Ziellaufwerk neue UUIDs zu. Sonst kann es zu Konflikten kommen, wenn beide Laufwerke verbunden sind. Außerdem bietet es erweiterte Optionen, die ansonsten ebenfalls manuelle Vorarbeit erforderlich machen. Beispielsweise das Kopieren auf Datenträger, die kleiner als die Partitionen sind (aber immer noch groß genug für den belegten Speicher). Seit der

Auch der Einrichtungsassistent von DietPi, welches auf dem Raspberry Pi OS basiert, lief durch diese Änderung auf Fehler.6 Der Aufwand einer Portierung von DietPi auf den neuen Raspberry Pi 5 ist u.a. dadurch gestiegen.7 Im Raspberry Pi Forum wurde und wird diese Änderung kontrovers diskutiert.8 Neben diesen Beispielen gibt es wohl eine größere Dunkelziffer an Programmen, die nun nicht mehr funktionieren, da sie automatisiert Änderungen an einer der beiden Dateien vornehmen. Unter Umständen sind eben so Anleitungen und Dokumentationen betroffen.

Warum wurde die symbolische Verknüpfung entfernt?

Aus Gründen der Abwärtskompatibilität schien die Verknüpfung ein sinnvoller Kompromiss zu sein. Einige fragen sich daher, warum man diese nicht schlichtweg hat bestehen lassen – dazu gibt es ein Ticket auf GitHub.9 Darin bestätigt der für die Entfernung verantwortliche Entwickler bereits zuvor geäußerte Vermutungen, dass manche Editoren die symbolische Verknüpfung nicht beachten und die Verknüpfung überschreiben, statt deren Ziel. Ich habe dies mit Vim und Nano getestet, beide haben in das Verknüpfungsziel geschrieben.

Anders sieht es dagegen beim beliebten GNU/Linux Werkzeug sed aus: Standardmäßig legt es beim Ersetzen in Dateien mit -i (--in-place) im Pfad der Verknüpfung die neue Datei an. Nur wer den Parameter --follow-symlinks kennt und benutzt, schreibt tatsächlich in das Verknüpfungsziel.

$ sed 's/a/X/' /tmp/demo.txt -i
$ cat demo.txt 
abc def ghi
$ cat /tmp/demo.txt
Xbc def ghi
$ l /tmp/demo.txt
Permissions Size User   Group  Date Modified Name
.rw-r--r--    12 u-labs u-labs  5 Feb 16:35   /tmp/demo.txt

Das wird schnell zum Problem, da sed als GNU-Werkzeug vorinstalliert ist – es kommt in vielen Skripten zum Einsatz. Insbesondere wenn das Skript keine vernünftige Fehlerbehandlung aufweist (wie bei etwa rpi-clone der Fall), führt das zu schwer auffindbaren Fehlern. Bei rpi-clone wiederum hat man mitgedacht und ruft sämtliche Pfade mit dem Werkzeug realpath auf. Dies gibt uns den echten Pfad zurück, bei Verknüpfungen also deren Ziel:

$ realpath /tmp/demo.txt
/home/u-labs/demo.txt

Daher hat es auf dem Raspberry Pi OS 12 auch mit der Verknüpfung funktioniert. Erst die Aktualisierung zur Entfernung des Symlinks machte es unbrauchbar. So gut die Idee einer Verknüpfung auch gemeint ist – es ist nicht von der Hand zu weisen, dass dies zu Verwirrung führen kann und in gewissen Konstellationen eine fiese Fehlerquelle ist. An dieser Stelle ist ein Ende mit Schrecken wohl besser, als ein Schrecken ohne Ende. Wenngleich man über die Entscheidung, die Dateien zu verschieben, sicher streiten kann.

Wir reparieren rpi-clone

Das originale Projekt von billw2 wird leider seit 2020 nicht mehr gepflegt.10 Doch das ist in der Open Source Gemeinschaft kein Beinbruch: Es gibt andere Personen, es als Abspaltung (Fork) selbst weiterführen. Der wohl verbreitetste stammt von Jeff Geerling. Er hat bereits in der Vergangenheit neue Funktionen, Fehlerkorrekturen und andere Änderungen eingebaut. Ich habe aus diesem Grunde seine Abspaltung als Grundlage genommen:

git clone https://github.com/geerlingguy/rpi-clone.git

Da ich die Codebasis nicht kenne, habe ich im Hauptskript (rpi-clone) schlicht nach cmdline gesucht – 11 Treffer. Auch cmdline liefert nur 25 Ergebnisse. Das ist überschaubar für eine händische Überprüfung. Zumal der Begriff an einigen Stellen in Kommentaren gefunden wurde. Die Wichtigsten, bei denen wir den Pfad ändern müssen, lauten:

cmdline_txt=$(realpath /boot/cmdline.txt)
# ...
cmdline_txt=${clone}$(realpath /boot/cmdline.txt)
# ...
cp $cmdline_txt /boot/cmdline.txt

Nun können wir allerdings nicht lediglich an diesen drei Stellen den Pfad um den Unterordner firmware ersetzen. Schließlich betrifft die Änderung nur Raspberry Pi OS 12 Bookworm. Die Vorgängerversion 11 nutzt weiterhin die bestehenden Pfade und ist noch unterstützt. Selbst bei Bookworm können wir nicht pauschal vom neuen Pfad ausgehen. Gerade zur jetzigen Zeit hat ggf. noch nicht jeder das frische Paket installiert. Daher ist eine Weiche nötig: Ich prüfe, ob in /boot/cmdline.txt der Hinweistext aus dem Paketupdate enthalten ist. In dem Fall müssen wir den neuen Pfad nehmen, ansonsten den alten.

# In the end of 2023, RPIOS moved cmdline.txt and config.txt from /boot to /boot/firmware:
# https://github.com/raspberrypi/documentation/issues/3089
# There was a symlink, but it got removed at the end of january 2024 and leaves a notice in /boot/cmdline.txst:
# https://github.com/RPi-Distro/raspberrypi-sys-mods/commit/c62cf1a12f4e422c855f7e2fcb39e9cadcb5459b
# This update has broken pi-clone: The cloned drive would boot into busybox.
# To fix this, get_cmdline_path() checks if /boot/cmdline.txt has moved, so it uses the new path on updated systems.
get_cmdline_path() {
       if [ "$(head -1 /boot/cmdline.txt)" = "DO NOT EDIT THIS FILE" ]; then
               echo "/boot/firmware/cmdline.txt"
       else
               echo "/boot/cmdline.txt"
       fi
}

Die obigen drei Aufrufe habe ich nun durch get_cmdline_path ersetzt:

- cmdline_txt=$(realpath /boot/cmdline.txt)
+ cmdline_txt=$(realpath $(get_cmdline_path))

- cmdline_txt=${clone}$(realpath /boot/cmdline.txt)
+ cmdline_txt=${clone}$(realpath $(get_cmdline_path))

- cp $cmdline_txt /boot/cmdline.txt
+ cp $cmdline_txt $(get_cmdline_path)

Mit dem neuen Skript erstellt startet das geklonte Abbild wieder wie das Original direkt in das Raspberry Pi OS, statt in BusyBox. Nun wäre im Sinne der OSS-Bewegung der Zeitpunkt, dem Quell-Repository diese Änderung zur Verfügung zu stellen: So profitieren alle die Geerlings Repository nutzen von den Änderungen, inklusive ihm selbst. Während ich das für diesen Beitrag vorbereite, stellte sich allerdings heraus: Er war schneller und hat kurz davor einige Änderungen (Commits) veröffentlicht. Darunter auch eine Korrektur für das Problem der verschobenen Boot-Partition.11

Somit ist die Übermittlung meines Fix nicht mehr nötig. Dies demonstriert die Macht der Open Source Community: Bereits wenige Tage nachdem das Problem bemerkt wird, arbeiten mehrere Personen an einer Lösung. Alleine hier sind es mindestens drei, da diese Code-Änderung nicht von Geerling selbst kam. Sondern von einem GNU/Linux-Nutzer aus Stuttgart.

Fazit

Kleine Änderung, große Wirkung – so könnte man die Problematik zusammen fassen. Dieser Beitrag soll ein Verständnis für das Problem schaffen und sowohl Betroffene als auch Entwickler in die richtige Richtung lotsen, nachdem die Ursache teils nur schwer auffindbar ist. Da nicht alle Nutzer ihre Software sofort aktualisieren, wird es in den nächsten Wochen und Monaten wohl sicher noch den einen oder anderen betreffen – bis alle Projekte entsprechende Weichen eingebaut sowie verteilt haben. Ich habe dies bei rpi-clone durchgeführt, da ich es für einen geplanten Beitrag zum übertragen von SSD-Karten auf M.2 SSDs am Raspberry Pi benötige.

Ein großer Vorteil von Quelloffener Software: Wir müssen nicht zuschauen oder sind gar aufgeschmissen, weil ein Projekt eingestellt wurde – wie es mit rpi-clone leider der Fall zu sein scheint. Stattdessen können wir per Fork unseren eigenen Zweig davon erstellen. Gerade bei vergleichsweise kleinen Änderungen wie in diesem Falle muss man kein Softwareentwickler mit 20 Jahren Erfahrung sein, um das Problem selbst lösen zu können. Bei proprietärer Software sind nun alle Nutzer darauf angewiesen, dass der Hersteller sie aktualisiert – sofern es ihn noch gibt & er die Unterstützung nicht längst eingestellt hat.

Quellen & weiterführende Informationen

  1. https://www.raspberrypi.com/documentation/computers/config_txt.html ↩︎
  2. https://github.com/raspberrypi/documentation/issues/3089 ↩︎
  3. https://9to5linux.com/raspberry-pi-os-is-now-based-on-debian-bookworm-supports-raspberry-pi-5-and-pipewire ↩︎
  4. https://askubuntu.com/a/1256823/650986 ↩︎
  5. https://github.com/RPi-Distro/raspberrypi-sys-mods/commit/c62cf1a12f4e422c855f7e2fcb39e9cadcb5459b ↩︎
  6. https://github.com/MichaIng/DietPi/issues/6747 ↩︎
  7. https://github.com/MichaIng/DietPi/issues/6676#issuecomment-1771124218 ↩︎
  8. https://forums.raspberrypi.com/viewtopic.php?t=364582 ↩︎
  9. https://github.com/RPi-Distro/raspberrypi-sys-mods/issues/88#issuecomment-1931626454 ↩︎
  10. https://github.com/billw2/rpi-clone ↩︎
  11. https://github.com/geerlingguy/rpi-clone/commit/63765e8e84cc978417a75bbb7e1a28746d4ca542 ↩︎

Leave a Reply