Im Rahmen einer Forschungsarbeit benoetigte ich FreeBSD-Systeme, die von einem USB-Stick aus booten koennen. Da ich schnell merkte, dass so etwas auch jenseits davon recht nuetzlich sein kann, habe ich es dann auch mit der gebuehrenden Systematik umgesetzt. Herausgekommen ist ein huebsches modulares System zur Erstellung von USB-Systemen fuer alles moegliche. Zum Beispiel als Thinclient-Ersatz: In einen alten PC wird ein USB-Stick als neues Bootmedium eingesteckt; von ihm wird gebootet. Anschliessend holt er automatisch eine IP-Adresse per DHCP und ruft per RDP einen vorgegebenen Windows-Server auf. Gleiches geht natuerlich auch fuer X: Wahlweise mit vorgegebenem Host oder Broadcast..

Das Booten so ueberhaupt

Wer von einem USB-Stick booten moechte, sollte zumindest ungefaehr wissen, was dabei passieren soll. Sollte zumindest. Also hier zumindest eine ganz grobe zusammenfassung, was beim Booten ablaeuft:

Daraus leiten sich einige der Anforderungen an ein per USB-gebootetes System ab:
Ach ja, und das USB-Stick-zusammenbauen soll so automatisiert wie moeglich vonstatten gehen. Je weniger Nutzerinteraktion, desto besser. Denn Nutzerinteraktion birgt immer die Gefahr von Fehlern. Natuerlich birgt sie die Gefahr um so schlimmerer Fehler, wenn man sie danach automatisiert wiederverwendet.

Die Umsetzung

Der Anfang ist eine FreeBSD-Installations-CD. Und zwar Disc1. Sie beinhaltet alles, was es braucht, um ein System zum Laufen zu bringen: Kernel und Welt, wie es in der FreeBSD-Terminologie heisst.
Und dann muss irgendwie der USB-Stick fertig werden. Damit er laeuft, braucht es also den Bootloader, nen Kernel und ein bisschen Welt (also das Userland). Und dann noch alles, was irgendwann mal laufen soll, also z.B. ein X oder so etwas.
Natuerlich koennte man auch alles gleich direkt auf dem USB-Stick anlegen. Aber es ist deutlich performanter, es zunaechst auf der Festplatte zu tun. Es geht in der Summe deutlich schneller, zunaechst Overhead zu installieren (manpages, infopages, headerfiles, ...) und diese anschliessend zu entfernen als sie nur auf den USB-Stick zu kopieren. Ganz zu schweigen von der Platzverschwendung. Auf einem USB-Stick ist man praktisch wieder in den fruehen Zweitausendern: Mit mehr als zehn Gigabytes Speicherplatz zu rechnen ist dekadent. Damit stehen die zentralen Schritte fest:

Ein paar Details

Hier soll nun nicht alles in allen Details beschrieben werden -- es sollen nur einige besonders interessante Stellen erlaeutert werden.

Datentraeger beim Booten wiederfinden
Waehrend des Bootprozesses ist es noch ein wenig Magie, die dafuer sorgt, dass der Kernel vom Datentraeger geladen wird. Dann ist der Kernel aber irgendwann geladen und alle Hardwaredevices (fuer die es Treiber gibt) sind erkannt worden. Nun muss der USB-Stick gemountet werden -- idealerweise nach /. Dabei stellt sich aber erstmal ein Problem: Was, wenn der USB-Stick nicht das Device ist, dass angeommen wird (also z.B. /dev/da0s1a)? Wenn z.B. schon ein anderer USB-Stick eingestoepselt war und der Boot-Stick stattdessen als /dev/da1s1a gefunden wurde? Die entscheidende Anregung gab miwi (http://miwi.bsdcrew.de) -- UFS-Labels. Ein Datentraeger mit UFS-Label wird nicht nur als einfaches Device erkannt, sondern bekommt auch einen Eintrag der Form /dev/ufs/somefunnyname -- ud das wiederunm unabhaengig davon, an welchem USB-Anschluss der Stoepsel steckt.

Startup und Autologin
Irgendwann ist das Betriebssystem dann ja gebootet. Dann kommt ueblicherweise die Login-Aufforderung. An diesem Punkt waere der Nutzer an der Reihe, etwas zu tun. Das genau soll aber bei einigen Anwendungen, z.B. als Thinclient-Ersatz, nicht passieren. Hier soll ja automatisch weitergemacht werden, bis der RDP-Login des Windows' angezeigt wird. Hierzu stellte sich Autologin als einfachste Variante heraus, vor allem im Vergleich zu einem Start per Cron mit @reboot-Eintrag. Der wesentliche Unterschied: Bei einem Start via Autologin sind Nutzereingaben moeglich. Das ist zwar nicht notwendig, aber hilfreich.
Autologin realisiert sich recht einfach:
In der /etc/ttys wird die Zeile

ttyv0   "/usr/libexec/getty Pc"         cons25  on  secure
durch
ttyv0   "/usr/libexec/getty autologin"          xterm   on  secure

ersetzt. Nun verhaelt das System sich beim Hochfahren so, als wenn sich nach dem Start der Root-Benutzer eingeloggt haette. Das weitere Vorgehen ist einfach: Beim Login wird die .login ausgefuehrt. Diese beinhaltet (fuer den RDP-Client) zwei Aufrufe:
/bin/sh /root/autonetwork
/bin/sh /root/rdp-starter
... und in diesen Shellskripten wird dann wie ueblich gebastelt. Erst wird (s.u.) eine Netzwerkverbindung gebastelt (toi toi toi) und schliesslich der grafische Spass angefangen.

Netzwerkerkennung
BSD verwendet als Kennzeichen fuer Netzwerkdevices Kuerzel, die auf dem Treiber und damit der Hardware aufbauen. bge-Devices enthalten einen Broadcom Gigabit Ethernet-Chip; ath-Devices einen Atheros-Wlan-Chipsatz. Hinzu kommt, dass sich ein Skript sowiso nicht darauf verlassen sollte, dass ein irgendwie definiertes "erstes" Device (Linux: eth0, Darwin: en0) auch das zu verwendende ist. Es wurden schon Maschinen mit mehreren Netzwerkinterfaces gesichtet, von denen nur ein nicht-erstes mit dem Internet verbunden war. Also gibt es hierfuer ein doch umfangreicheres Skript -- es tut nichts weiter als die Ausgabe von ifconfig nach Interfaces zu durchsuchen, dabei zu pruefen, ob diese verbunden sind (also status: active gemeldet wird) und schliesslich auf diesen Interfaces -- in zugegebenerweise recht wuesten Reihenfolge -- zu versuchen, per DHCP eine Adresse zu erhalten.
Hoffentlich klappt das.
Die Vergabe statischer IP-Adressen ist gegenwaertig nicht vorgesehen.
Dennoch war ebendiese Option ausschlaggebend dafuer, die Netzwerkkonfiguration nicht in den Configfiles zu erledigen: Diese Loesung erlaubt eine hoehere Flexibilitaet: Beispielsweise koennten hier auch SSH-Tunnel aufgebaut werden, die spaeter verwendet werden.

Netzwerk-Device-Erkennung
Jetzt geraet also mein USB-Stick in die Haende eines glaeubigen Linuxers. Er moechte es den Stick als Trafficshaper einsetzen. Dazu muss er aber wissen, welches Device welchem Hardwareanschluss entspricht. Vielleicht hat er sich sogar eth0 und eth1 drangeschrieben. Und dann kommt da mein BSD und liefert ihm vr0 und em0. Und was ist nun was?
Um hier Licht ins Dunkel zu bringen, kann ein kleines Helferlein gestartet werden, welches im wesentlichen die folgende Ausabe sekuendlich aktualisiert auf den Bildschirm wirft:

These Interfaces have been identified:
em0     wpi0    wlan0

The following Interfaces are currently identified as connectet
(i.e. there is some cable plugged in and connected to some other
 device):

em0

You may now plug and unplug your physical devices to identify them.
Hit Enter when you are done.
Und das Problem reduziert sich auf Stecker ein-und-ausstoepseln.

Dateien zum Download

...finden sich unter down/mkstick-20121004.tar und sind BSD-Lizensiert. Ueber Rueckmeldungen an ad001@uni-rostock.de freue ich mich natuerlich. Das Skript laeuft unter FreeBSD 8.0. Vielleicht auch anderswo. Ich habe nicht aktiv dagegengearbeitet, aber auch nicht aktiv drauf zu. Kurzum: Ob es auf Meier- Schmidt- oder Muellerix laeuft ist mir zimlich egal. Es ist ein Werkzeug fuer mich. Und ich benutze mein BSD :)

Optimierungspotential

Stichworte:


Impressum