Es kann von Vorteil sein, während des Boot-Prozesses oder evtl. auch danach noch gewisse Schalter (engl. flags) abfragen zu können, ohne deswegen gleich auf /var/flash/debug.cfg zugreifen zu müssen. Dafür gibt es folgende Gründe:
Kein Problem ohne Lösung. Wir könnten innerhalb von rc.mini_fo selbst mknod verwenden, um debug.cfg temporär zugreifbar zu machen und nach Abfragen der gewünschten Information wieder aufräumen mit rm, damit später rc.S nicht irritiert wird beim erneuten Erzeugen des Nodes. Es gibt tatsächlich ein Paket (NFS-Root, verfügbar ab ds26-15.3), welches diese Technik verwendet, um auf AVM-Konfigurationsdaten aus dem TFFS zuzugreifen, zusätzlich aber auch noch Informationen von woanders einholt, und zwar aus dem sog. Bootloader Environment (Urlader-Umgebungsvariablen). Schon seit 15.0 greifen auch zwei (noch) undokumentierte Logging-Werkzeuge des DS-Mod, Inotify-Tools und Dmesg-Recording, auf diese Umgebungsvariablen zu, die beiden Letzteren sogar über ein kleines, funktional auf bestimmte Anwendungsfälle eingegrenztes Shell-API, das ich mir habe einfallen lassen. Dazu später mehr.
Der Urlader (engl. bootloader), je nach Version auch bekannt unter ADAM2 oder EVA, besitzt ein sog. Environment, also einen kleinen Speicherbereich für globale Einstellungen, welche absolut erforderlich sind, damit die Box überhaupt funktioniert. Das ist ja bekannt, aber zur Auffrischung nochmals die (mit “#“ anonymisierte) Ausgabe, generiert auf meiner 7170 mit Kernel 2.6:
$ cat /proc/sys/urlader/environment HWRevision 94.1.1.0 ProductID Fritz_Box_7170 SerialNumber 0000000000000000 annex B autoload yes bootloaderVersion 1.153 bootserport tty0 bluetooth ##:##:##:##:##:## cpufrequency 211968000 firstfreeaddress 0x946AE530 firmware_version 1und1 firmware_info 29.04.29 flashsize 0x00800000 maca ##:##:##:##:##:## macb ##:##:##:##:##:## macwlan ##:##:##:##:##:## macdsl ##:##:##:##:##:## memsize 0x02000000 modetty0 38400,n,8,1,hw modetty1 38400,n,8,1,hw mtd0 0x90000000,0x90000000 mtd1 0x90010000,0x90780000 mtd2 0x90000000,0x90010000 mtd3 0x90780000,0x907C0000 mtd4 0x907C0000,0x90800000 my_ipaddress 192.168.178.1 prompt AVM_Ar7 ptest reserved ##:##:##:##:##:## req_fullrate_freq 125000000 sysfrequency 125000000 urlader-version 1153 usb_board_mac ##:##:##:##:##:## usb_rndis_mac ##:##:##:##:##:## usb_device_id 0x3D00 usb_revision_id 0x0200 usb_device_name USB DSL Device usb_manufacturer_name AVM wlan_key ################ wlan_cal ####,####,####,####,####,####,####,####,####
Das Schöne an diesem Environment ist, daß es nicht nur lesbar, sondern auch (teilweise) beschreibbar ist. Das wird gern verwendet, um Anpassungen am Annex oder am Branding vorzunehmen, insbesondere bei OEM-Boxen, deren Besitzer gern eine vollwertige Fritz!Box daraus machen möchten, um die entsprechenden Original-FWs oder den DS-Mod darauf zu installieren, bzw. auch, um eine deutsche Box im Ausland lauffähig zu machen oder umgekehrt.
Es ist bei den allermeisten Werten im Environment absolut nicht ratsam, sie für andere Zwecke zu mißbrauchen, aber es gibt eine oben gar nicht sichtbare Variable, die dafür geschaffen wurde, dem Linux-Kernel Parameter für den Boot-Vorgang mitzugeben. Diese Parameter werden später weitergereicht an die Startskripten, aber auch gleichzeitig persistent gespeichert und sind somit ideal geeignet, um Werte von dort abzufragen.
Die Variable, von der hier die Rede ist, heißt kernel_args, faßt maximal 64 Zeichen an Informationen und sollte daher mit Bedacht verwendet werden. Man kann folgendermaßen etwas hinein schreiben:
echo "kernel_args tea=Darjeeling quality=FTGFOP1" > /proc/sys/urlader/environment
Damit würden wir ein eigens dafür entworfenes (leider fiktives) Startskript der Fritz!Box anweisen, beim Hochfahren der Box Tee zu kochen, und zwar Darjeeling der Qualitätsstufe FTGFOP1 (Finest Tippy Golden Flowery Orange Pekoe 1).
Wenn man sich jetzt das Environment nochmals anzeigen läßt, findet man plötzlich dort die Variable kernel_args vor:
$ cat /proc/sys/urlader/environment | grep kernel_args kernel_args tea=Darjeeling quality=FTGFOP1
Mit ein bißchen Zeichenketten-Manipulation können wir den Wert von kernel_args isolieren und dann weiter zerlegen in unsere beiden Schlüssel-Werte-Paare. Darauf will ich an dieser Stelle nicht weiter eingehen, das sind Grundlagen der Shell-Programmierung.
Jedoch wichtig zu wissen ist, wie man während des Boot-Vorgangs an diese Variable heran kommt. Die Antwort hängt davon ab, zu welchem Zeitpunkt man den Zugriff benötigt. Sofern das virtuelle Dateisystem unter /proc bereits zugreifbar, das sog. procfs also bereits ins Root-Dateisystem per mount eingehängt wurde, können wir so vorgehen wie oben gezeigt. Andernfalls müssen wir zunächst mittels
[ -e /proc/mounts ] || mount procprocfs selbst einhängen, falls es noch nicht da ist. Nach Benutzung loswerden können wir es entsprechend über
umount proc
Für einfache, auf Debugging oder Logging ausgerichtete Anwendungsfälle, die innerhalb von kernel_args auskommen mit den Werten
gibt es das Shell-Skript kernel_args, welches man mit
. /usr/bin/kernel_argsin ein laufendes Skript inkludieren und daraufhin auf verschiedene vorgefertigte Funktionen zur Manipulation von innerhalb der Bootloader-Variablen kernel_args gespeicherten Schlüssel-Werte-Paaren zugreifen kann. Das Skript ist in den enthaltenen Kommentarzeilen gut dokumentiert, daher hier nur eine kurze Auflistung der aktuell (ds26-15.2) verfügbaren Funktionen:
Gerade die letzten beiden Aufrufe ermöglichen ein hilfreiches Konstrukt beim Entwickeln von Startskripten: Man kann eine Variable z.B. auf 5 setzen und bei jedem Startvorgang um 1 vermindern, bis sie nach fünf Durchläufen auf „n“ (inaktiv) gesetzt wird. Abhängig davon könnte man den weiteren Verlauf eines Skripts beeinflussen, es also fortsetzen oder vorzeitig beenden. Sollte im weiteren Verlauf des Skripts also ein Fehler auftauchen, der den Startvorgang der Box torpediert, so daß man nicht mehr an sie heran kommt ohne Recover, wäre dieser Countdown eine praktische Hilfe, denn spätestens beim sechsten Anlauf würde ja die fehlerhafte Funktion nicht mehr aktiviert sein und die Box normal weiter gestartet werden. Wir retten uns hiermit also vor uns selbst und ziehen uns an den eigenen Haaren aus dem Sumpf!
Sobald wir andere Arten von Werten in kernel_args speichern wollen, z.B. etwas wie my_path=/usr/bin/my_script, versagt das API in der momentanen Version seinen Dienst, weil es ja nur die Werte „y“, „n“, positive Ganzzahl zuläßt. Aber oben steht ja, wie man auch damit umgehen kann durch Direktzugriff. Eines Tages erweitere ich vielleicht auch das API.
Root-Mounts: Dienste wie mini_fo zur virtuellen Überlagerung des Root-Dateisystems durch eine RAM-Disk oder einen externen Speicher, um Schreibzugriffe zu ermöglichen oder NFS-Root, also der vollständige Ersatz des Root-Dateisystems durch einen voll beschreibbaren und größenmäßig quasi unbegrenzten Netzwerk-Mount könnten von Schaltern im Bootloader Environment profitieren, weil man sie bei Bedarf ein- und ausschalten könnte. (Anm.: NFS-Root zum [De-]Aktivieren tatsächlich einen Eintrag in kernel_args, allerdings ohne API. Zusätzlich wird der zu mountende NFS-Pfad in einer anderen Bootloader-Variablen Namens nfsroot abgelegt, die der Linux-Kernel sowieso kennt und die wir quasi mißbrauchen.)
Debugging/Logging: Bei Bedarf zuschaltebare Funktionen, um Dateizugriffe beim Booten zu protokollieren, um z.B. festzustellen, welchen Binaries beim Starten nicht angerührt werden und die man deshalb via Downloader-CGI auslagern könnte, um Platz für mehr früher benötigte DS-Mod-Pakete zu schaffen, oder um das Kernel-Log in eine Datei zu sichern, bevor der Ringpuffer überläuft und der Anfang verloren geht, sind Beispiele für weitere sinnvolle Anwendungsbereiche von kernel_args, ob nun mit oder ohne API. Der Entwickler braucht keine Debug-Version seiner FW zu flashen, um etwas zu probieren, sondern er baut die notwendigen Dinge fest in seine FW ein, macht den Start aber abhängig von einem oder mehreren Schaltern (Berücksichtigung in den Init-Skripten). Sehr bequem!
Weitere Schweinereien überlasse ich Eurer geschätzten Phantasie.
Diskussionen zum Thema bitte unter http://www.ip-phone-forum.de/showthread.php?t=134976, wo zu Beginn noch die Rede davon ist, die Variable SerialNumber zu verwenden, um Werte dort zu speichern. Allerdings hat sich später herausgestellt, daß man diese Variable zwar dem Anschein nach ändern kann, die Änderungen aber einen Neustart der Box nicht überleben. Also bitte nicht verwirren lassen, „state of the art“ ist momentan kernel_args.