IT security, FreeBSD, Linux, mail server hardening, post-quantum crypto, DNS, retro computing & hands-on hardware hacks. Privater Tech-Blog seit 2003.

Schlagwort: USB (Seite 1 von 3)

Commodore Floppy Disk Preservation: Firmware-Bug im xum1541 gefunden und gefixt

Commodore 1571 Laufwerk mit xum1541 (Teensy2) beim Auslesen einer 5,25-Zoll-Diskette unter Linux

In meinem Keller stehen Kisten voller alter 5,25-Zoll-Disketten. Commodore-Software aus den späten 80ern, Spiele, Tools, selbstgeschriebener Kram. Das Problem mit Floppy-Disks: die Magnetisierung lässt mit der Zeit nach. Alle paar Jahre sollte man die Daten einmal komplett lesen und zurückschreiben, sonst wird das Medium irgendwann unlesbar. Mein letztes Auffrischen ist eine Weile her, also war es mal wieder Zeit. Zugegeben, ich arbeite nur noch extrem selten mit meinem Commodore; aber wenn ich es mache, ist es immer eine kleine Zeitreise voller Nostalgie für mich. Die Geräusche, der Geruch, die Wartezeit. Hin und wieder tut es mir einfach gut, noch mal die alten Spiele zu spielen, mit den Tools zu arbeiten oder auch meine ersten eigenen Programme noch mal zu starten, in den Code zu schauen *kopfschütteln*…. Ich habe sogar noch alte Hausaufgaben auf Disketten 😀

Stapel aus Commodore 1571 Diskettenlaufwerken mit 5,25-Zoll-Disketten und dem 1570/1571 Handbuch

Was als routinemäßige Sicherungsaktion geplant war, wurde dann allerdings eine mehrtägige Debugging-Session. Inklusive eines Firmware-Bugs, der seit sechs Jahren im Code schlummerte.

Die Ausgangslage

Mein Setup: Zwei Commodore 1571 Laufwerke, angeschlossen über einen xum1541 USB-Adapter an einem Linux-Rechner. Der xum1541 sitzt auf einem TEENSY2-Board (ATmega32U4) und spricht über USB mit OpenCBM, einer Open-Source-Treibersammlung für Commodore-Laufwerke. Die Software-Seite hatte ich in einer vorherigen Session bereits verifiziert. Beide Laufwerke laufen bei fast perfekten 300,5 RPM, lesen und schreiben fehlerfrei auf beiden Seiten und liefern sogar bit-identische Images im Crosscheck.

Der Plan war simpel: Alle Disketten systematisch als 1:1-Image sichern, die physischen Medien durch Zurückschreiben auffrischen und nebenbei prüfen, ob die Inhalte bereits in Online-Archiven wie CSDB, Gamebase64 oder dem Internet Archive vorhanden sind.

Der xum1541 im gelben Gehäuse. Links das USB-Kabel zum Linux-Rechner, rechts das IEC-Kabel zur 1571:

xum1541 USB-Adapter im gelben 3D-gedruckten Gehäuse mit USB- und IEC-Kabel angeschlossen

Und ein Blick auf die Platine mit dem Teensy2-Board (ATmega32U4), in dem der Firmware-Bug steckte:

Geöffneter xum1541-Adapter mit Teensy2-Board (ATmega32U4) auf der Platine, USB-Anschluss und IEC-DIN-Buchse

Disk 001: Pirates! und das Kopierschutz-Problem

Die erste Disk war eine Pirates!-Kopie (Microprose, 1987), „imported by The Critters Inc 1221“. Mit d64copy ausgelesen, 683 Blocks, keine Fehler. Dann zurückgeschrieben und zur Verifikation nochmal gelesen. Checksummen stimmten nicht überein.

Die Analyse ergab: Das Original-D64 enthält drei Sektoren mit Error Code 5 (Data Block Checksum Error) auf Track 23 und 24. Das ist klassischer C64-Kopierschutz. Microprose nutzte absichtliche Lesefehler, um Raubkopien zu erkennen. Das Spiel prüft beim Start ob diese Fehler vorhanden sind, fehlen sie, verweigert es den Dienst.

d64copy arbeitet auf Sektor-Ebene und kann solche GCR-Level-Fehler nicht reproduzieren. Die Error-Info wird zwar im D64 gespeichert (Emulatoren wie VICE werten sie aus), aber auf der physischen Disk gehen die absichtlichen Fehler beim Zurückschreiben verloren. Für eine echte 1:1-Kopie inklusive Kopierschutz braucht man nibtools. Das arbeitet direkt auf GCR/Nibble-Ebene und liest die Rohdaten vom Laufwerk, inklusive aller Timing-Patterns und absichtlichen Fehler.

nibtools bauen und der erste Crash

nibtools liegt als Quellcode im OpenCBM-Quellbaum, muss aber separat gebaut werden. Ich habe den markusC64-v637 Branch von GitHub genommen. Build mit dem cc65 Cross-Compiler für den 6502-Floppy-Code und gcc für die Host-Tools ging glatt. Erster Versuch:

nibread -D8 image.nib

Ergebnis: LIBUSB_ERROR_PIPE. Der USB-Transfer bricht sofort ab, nachdem der Drive-Code hochgeladen ist. nibtools erkennt die 1571 korrekt und versucht SRQ-Burst-Transfers zu nutzen, ein schnelles serielles Protokoll das die CIA-UART der 1571 verwendet. Aber der Transfer scheitert schon beim Communication-Test.

Drei Schichten tief: der Firmware-Bug

Schicht 1: Bekannter SRQ-Bug in Firmware v7. Die xum1541-Firmware v7 hatte einen dokumentierten Bug: IEC_SRQ war als 0x80 definiert (Bit 7), aber die Lookup-Tabelle iec2hw_table hatte nur 16 Einträge (4 Bits). SRQ-Operationen griffen ins Leere. In v8 gefixt: IEC_SRQ auf 0x10 geändert, Tabelle auf 32 Einträge erweitert. Commit 3ef4fc0d von Spiro Trikaliotis, 2021.

Problem: Es gab kein fertiges v8-Hex für das TEENSY2-Board. Nur für ZOOMFLOPPY und PROMICRO. Die Boards haben unterschiedliche Mikrocontroller-Pin-Belegungen, also kann man die Firmware nicht einfach zwischen Boards tauschen. Lösung: AVR-Toolchain installiert (gcc-avr, avr-libc), v8 für TEENSY2 selbst gebaut und über den HalfKay-Bootloader geflasht.

teensy_loader_cli --mcu=atmega32u4 -w -v firmware.hex

Risikofrei, da der Bootloader in einem geschützten Flash-Bereich sitzt. Knopf am Teensy drücken, flashen, fertig.

Schicht 2: v8 geflasht, gleiches Problem. Auch mit v8 kommt LIBUSB_ERROR_PIPE. Die OpenCBM-Library musste ebenfalls neu gebaut werden, sie prüft die Firmware-Version und war noch auf v7 kompiliert. Neu gebaut, installiert. Immer noch Crash.

Schicht 3: Der eigentliche Bug. Also tiefer in den Quellcode. In board-teensy2.h, Funktion iec_srq_write():

// BUGGY — seit Commit 57bb6726 (April 2020)
PORTD = (((data >> 4) & IO_DATA) ^ IO_DATA) | IO_SRQ;

Das wurde 1:1 von der ZoomFloppy-Implementierung kopiert. Aber die Pin-Belegung ist bei den Boards unterschiedlich:

  • ZoomFloppy hat IO_DATA auf Port D, Bit 4 (PD4)
  • TEENSY2 hat IO_DATA auf Port F, Bit 0 (PF0)

Der Code schrieb auf den komplett falschen Port mit dem falschen Bit-Shift. Das erklärt warum der Communication-Test sofort fehlschlug. Die SRQ-Daten kamen nie auf den richtigen Pins an.

Der Fix, analog zur korrekten PROMICRO-Implementierung:

// FIXED
uint8_t port_base_data = (DDRF & IO_ATN) | IO_SRQ;
// ...
DDRF = (((data >> 7) & IO_DATA) ^ IO_DATA) | port_base_data;

Die Änderungen im Detail: PORTD wird zu DDRF (richtiger Port für die IEC-Leitungen beim TEENSY2), der Shift von data >> 4 auf data >> 7 (Bit 7 des Datenbytes auf Bit 0 des Ports, wo IO_DATA liegt), und der ATN-Zustand wird über port_base_data erhalten, was vorher nicht berücksichtigt war. Timing von 0,935 µs auf 0,80 µs angepasst, passend zur PROMICRO-Implementierung.

Firmware neu gebaut (8260 Bytes, 32 mehr als vorher), geflasht. nibread läuft sofort fehlerfrei durch alle 41 Tracks. Der Bug steckte seit April 2020 im Code. Jeder mit einem TEENSY2-basierten xum1541 hatte dieses Problem bei SRQ-Transfers.

Den Fix habe ich als Pull Request eingereicht, der am 26. März vom OpenCBM-Maintainer Spiro Trikaliotis gemerged wurde. Damit ist auch ein seit 2021 offenes Issue im nibtools-Repository endlich geschlossen. Dort hatten andere User auf macOS und Fedora mit Teensy-basierten Adaptern exakt die gleichen LIBUSB-Fehler gemeldet, ohne dass die Ursache gefunden wurde.

Die bittere Lektion mit Disk 001

Die erste Pirates!-Disk, der Import von The Critters Inc, war zu diesem Zeitpunkt bereits zerstört. Ich hatte sie vor dem Fix mit d64copy zurückgeschrieben. Das hat die GCR-Level-Kopierschutzmuster überschrieben. Das anschließend mit nibread erstellte NIB-Image zeigt nur noch die „reparierten“ Sektoren, nicht den originalen Kopierschutz. Disk und Images entsorgt.

Die Lektion ist simpel und ärgerlich zugleich: Nie zurückschreiben, bevor das NIB-Image existiert.

Der Workflow ab Disk 002

Ab der zweiten Disk lief der Prozess dann sauber:

  1. nibread -D8 — GCR-Rohdaten lesen, inklusive Kopierschutz
  2. d64copy — Sektor-Level-Image für Emulatoren
  3. nibwrite — 1:1 zurückschreiben aus dem NIB (erhält Kopierschutz)
  4. d64copy nochmal lesen + MD5-Vergleich zur Verifikation

Ergebnisse

DiskInhaltStatus
001Pirates! (The Critters Inc)Verloren — Kopierschutz vor dem Fix zerstört
002Ace of Aces, Light Force, Hacker + TrainersGesichert + aufgefrischt, Killer Track auf Track 1 erhalten
003Commando, The Last V8, Robin of the WoodVerloren — Medium physisch zu schwer beschädigt
004Warplay, Worldcup 86, Hyper OlympicsGesichert, Original-Disk defekt (T18/S15)
005Pirates! (The Red Lions Import, 2-Disk)Gesichert + aufgefrischt + verifiziert

Technische Eckdaten

Für die Leute die es genau wissen wollen:

  • Hardware: 2× Commodore 1571, xum1541 (TEENSY2, ATmega32U4), Linux-Host
  • Software: OpenCBM (from source), nibtools (markusC64-v637), VICE 3.7.1
  • RPM: Konstant 300,5 RPM (Nominal: 300). Die 1571 ist elektronisch geregelt, kein Trimmpoti
  • Kopierschutz-Typen: Error Code 5 (Checksum Errors) auf Pirates!, Killer Track (Track komplett mit Sync-Bytes) auf der Crocodile Soft Compilation
  • NIB-Format: ~336 KB pro Disk (41 Tracks × 8192 Bytes GCR-Rohdaten)
  • D64-Format: ~175 KB pro Disk (683 Sektoren × 256 Bytes + optional 683 Bytes Error-Info)

Fazit

Was als „schnell mal Disketten auffrischen“ geplant war, endete in einer Reise durch sechs Jahre alten Firmware-Code. Der Bug in iec_srq_write() war ein klassischer Copy-Paste-Fehler, der nie aufgefallen ist, weil kaum jemand nibtools mit einem TEENSY2-Board benutzt. SRQ-Burst-Transfers braucht man nur für nibtools, und die meisten Leute nutzen ohnehin einen ZoomFloppy-Adapter, wo der Code korrekt ist.

Der Verlust von Disk 001 ärgert mich immer noch. Aber die Lektion sitzt: Erst NIB, dann zurückschreiben. Und wenn ein Tool beim ersten Mal nicht funktioniert, lohnt es sich manchmal die Firmware aufzuschrauben, statt das Tool wegzulegen.

Der Blick ins Regal, wo das alles steht. Ja, es ist voll da unten:

Retro-Computing-Regal mit Commodore-Monitor, 1571 Laufwerk, C128 Tastatur, Diskettenstapeln und dem gelben xum1541-Adapter
Zweite Perspektive des Retro-Regals mit Commodore 1541-II, Disketten- und Kassettensammlung

Siehe auch: Commodore – PC Projekt (mein erster Versuch mit cbm4linux und einem XM1541-Kabel, anno 2009) und VC-64 Turbo Tape (1986).

Fragen? Einfach melden.

Voltcraft CM 2016: Endlich eine Linux-GUI für das Ladegerät

Seit bestimmt zehn Jahren steht hier ein Voltcraft Charge Manager CM 2016 auf dem Schreibtisch. Irgendwann bei Conrad gekauft, als die tatsächlich noch Geschäfte in der Innenstadt hatten. Damals mit zwei kleinen Kindern war der Akkuverbrauch enorm. Spielzeugautos, Taschenlampen, Fernbedienungen, irgendwas war immer leer. Einwegbatterien waren teurer als heute (zumindest in meiner Erinnerung), und so wurde das Ladegerät schnell zum wichtigsten Gerät im Haushalt.

Das CM 2016 hat sechs unabhängige Ladeschächte (vier für AA/AAA, zwei für 9V-Blöcke) und kann deutlich mehr als nur Laden. Es misst Kapazitäten, erkennt defekte Akkus, kann Lade-/Entladezyklen fahren und hält Akkus per Trickle-Charge am Leben. Wer seine Akkus ernsthaft pflegen will, braucht so ein Gerät. Damit halten die Zellen länger, man kann sie wiederaufbereiten und erkennt rechtzeitig, wann einer reif für die Tonne ist.

Voltcraft Charge Manager CM 2016 Frontansicht mit Display und eingelegtem Akku
Der Voltcraft Charge Manager CM 2016 mit eingelegtem Akku

In den letzten Jahren wurde es zugegebenermaßen weniger eingesetzt. Trotzdem laufen noch immer diverse Smarthome-Geräte und Notfall-Taschenlampen mit Akkus, und da ist ein ordentliches Ladegerät einfach Pflicht.

Das Problem: kein Linux, kein gar nichts

Das CM 2016 kommt mit einer Windows-Software. CM2016 Logger V2.10, eine .NET-Anwendung von 2013. Unter Linux funktioniert die selbstverständlich nicht. Es gibt ein paar Projekte, die das Gerät auf der Kommandozeile auslesen können, ein Java-Tool hier, ein Python-Script dort. Eine echte GUI für Linux oder FreeBSD? Fehlanzeige. Selbst als ich vor ein paar Tagen noch einmal gesucht habe: nichts. Eine kommerzielle Java-GUI existiert zwar, aber nur als 30-Tage-Trial.

Also habe ich mich selbst daran gesetzt.

Das Ergebnis: eine native GTK4-Anwendung

Das Ergebnis ist eine vollständige Desktop-Anwendung in Python mit GTK4 und libadwaita. Quelloffen, MIT-lizenziert, auf GitHub:

https://github.com/Kernel-Error/voltcraft-cm2016

Voltcraft CM 2016 GUI: Hauptfenster mit Datentabelle und Live-Aufzeichnung
Hauptfenster mit Datentabelle während einer Live-Aufzeichnung

Die App erkennt das CM 2016 automatisch per USB (Silicon Labs CP210x Chip) und zeigt alle sechs Schächte in Echtzeit an. Alle zwei Sekunden kommen neue Messdaten rein: Spannung, Strom, Kapazität, Laufzeit, Programmstatus.

Was die App kann

  • Echtzeit-Überwachung aller 6 Ladeschächte mit Autoscroll und Slot-Filterung
  • Spannungs- und Strom-Diagramme als Linien- oder Balkendiagramm mit Zeitfenster-Steuerung
  • Chart-Zoom per Maus-Drag, Scrollrad oder Tastatur, dazu Daten-Tooltips
  • Export als CSV oder Spreadsheet (.xlsx mit eingebetteten Diagrammen)
  • Druckfunktion für Messprotokolle im DIN A4 Querformat
  • Speichern und Laden von Aufzeichnungen (.cm2016 Dateien), inklusive Crash-Recovery über Temp-Dateien
  • Sleep-Inhibit: das System schläft nicht ein, solange aufgezeichnet wird
  • 7 Sprachen: Deutsch, Englisch, Französisch, Niederländisch, Italienisch, Spanisch, Polnisch
Voltcraft CM 2016 GUI: Spannungs- und Strom-Diagramme
Liniendiagramme für Spannung und Strom über die Zeit
Voltcraft CM 2016 GUI: Balkendiagramm
Balkendiagramm-Ansicht
Voltcraft CM 2016 GUI: Port-Auswahl Dialog
Port-Auswahl mit automatischer Geräteerkennung

Das Protokoll: nicht ganz so dokumentiert wie gedacht

Das CM 2016 sendet alle zwei Sekunden einen 127-Byte-Frame über die serielle Schnittstelle (19200 Baud, 8N1). Die ersten sieben Bytes sind immer CM2016 , dann folgen zehn Bytes Header und je 18 Bytes pro Ladeschacht.

Klingt einfach. Ist es auch, bis man die existierende Dokumentation mit echten Messdaten vergleicht. Dabei sind mir ein paar Dinge aufgefallen, die so nirgendwo korrekt dokumentiert waren:

  • Kapazitätsfelder sind 32-Bit Little-Endian, nicht 24-Bit wie es in mehreren Quellen steht. Charge-Capacity und Discharge-Capacity belegen jeweils vier Bytes.
  • Der dokumentierte Byte-Swap für Discharge-Capacity war falsch. Mehrere Referenzprojekte haben die Bytes in der falschen Reihenfolge gelesen, was zu absurden Kapazitätswerten geführt hat.
  • Die Header-Bytes 7-16 waren bisher größtenteils undokumentiert. Tatsächlich stecken da die Firmware-Version, die eingestellte Akku-Chemie (NiMH/NiZn), Temperaturdaten und ein Action-Counter drin. Alles Big-Endian, im Gegensatz zu den Slot-Daten, die Little-Endian sind.
  • Die Kapazitätsskalierung hängt vom Slot-Typ ab: Slots 1-4 (AA/AAA) teilen durch 100, die beiden 9V-Slots teilen durch 1000. Gleiches gilt für den Strom: AA/AAA-Slots durch 1000, 9V-Slots durch 10000.

Das alles musste mit dem echten Gerät verifiziert werden. Akku rein, verschiedene Programme durchlaufen lassen, Rohwerte mit dem Display vergleichen. Klassisches Reverse Engineering, nur eben mit Ladeströmen statt mit Netzwerkpaketen.

Technik unter der Haube

Die Anwendung nutzt GTK4 mit libadwaita für eine zeitgemäße GNOME-Oberfläche. Dark Mode funktioniert automatisch. Die Diagramme werden mit Cairo gerendert, Benachrichtigungen laufen über den libadwaita ToastOverlay. Für den seriellen Zugriff kommt pyserial zum Einsatz, die CP210x-Erkennung läuft über die USB Vendor/Product ID von Silicon Labs.

Der Spreadsheet-Export erzeugt .xlsx-Dateien mit eingebetteten Diagrammen über openpyxl. Die Druckfunktion generiert DIN A4 Querformat mit allen Slots und Diagrammen. Sessions lassen sich als .cm2016-Dateien speichern und wieder laden, und falls die Anwendung während einer Aufzeichnung abstürzt, gibt es eine automatische Recovery über Temp-Dateien.

Insgesamt 135 Unit-Tests decken Parser, Protokoll und die Export-Funktionen ab.

Installation

Die App braucht GTK 4.14+ und libadwaita 1.5+. Unter Debian/Ubuntu/Mint:

sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0 gir1.2-adw-1
git clone https://github.com/Kernel-Error/voltcraft-cm2016.git
cd voltcraft-cm2016
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install -e .

Unter Fedora:

sudo dnf install python3-gobject gtk4 libadwaita

Unter Arch:

sudo pacman -S python-gobject gtk4 libadwaita

Dann einfach cm2016 starten, USB-Kabel anschließen, fertig.

Ein .deb-Paket gibt es auf der GitHub Releases Seite. Ein Flatpak-Manifest liegt im Repository, die Einreichung bei Flathub ist eingereicht.

Falls jemand das gleiche Gerät hat und Fragen zur App oder zum Protokoll hat, einfach fragen.

Siehe auch: NB-2033-U: Reverse Engineering eines Fingerabdrucklesers für Linux

NEXT Biometrics NB-2033-U: Reverse Engineering eines Fingerabdrucklesers für Linux

Illustration eines USB-Fingerabdrucklesers mit Linux-Tux und USB-Protokollanalyse (Reverse Engineering NB-2033-U)

Im letzten Beitrag zum Thema hatte ich angekündigt, dass ich mir auch den NB-2033-U vornehmen will. Der steckt in einem zweiten Fujitsu Notebook hier, dem von meiner Tochter Maja. Gleicher Hersteller, gleiche Sensorfamilie, sollte ähnlich laufen wie beim NB-2020-U. Dachte ich.

Falsch gedacht.

Hersteller sagt: geht nicht

Ich hatte bei NEXT Biometrics nach Protokolldokumentation oder einem SDK für den NB-2033-U gefragt. Kevin Hung, Director FAE, antwortete freundlich aber eindeutig:

„Both 2020-U and 2033-U have different firmware and USB stack. The code flow (libusb) related to 2033-U and 2020-U is different. This could be the reason for 2033-U failure/unsupported in linux. As of now, it is not supported.“

Kein SDK, keine Doku, kein Support. Und 74 Einträge auf linux-hardware.org mit Status „failed“ für die USB ID 298d:2033. Weltweit kein Linux-Support für dieses Gerät.

Gut. Dann eben Reverse Engineering.

Erster Versuch: Windows-Treiber belauschen

Plan A war klassisch: Windows-Treiber in einer VM laufen lassen, USB-Traffic mitschneiden. VirtualBox installiert, USB-Passthrough konfiguriert, Windows gestartet. Der Fingerabdruckleser tauchte im Gerätemanager auf. Mit Code 31. Treiber konnte das Gerät nicht starten. Secure Boot hatte VirtualBox den Kernel-Treiber nicht signiert, und der USB-Passthrough war damit unbrauchbar.

Plan A verworfen.

Plan B: Das SDK direkt auf Linux

Das SDK von NEXT Biometrics (libNBBiometrics.so) unterstützt den NB-2033-U intern. Es kommuniziert direkt über libusb, ohne Kernel-Treiber. Das heißt: ich kann das SDK-Sample direkt auf dem Linux-Notebook laufen lassen und gleichzeitig den USB-Traffic mit usbmon mitschneiden.

Dafür musste Secure Boot deaktiviert werden. usbmon ist ein Kernel-Modul, und lockdown=integrity (von Secure Boot gesetzt) blockiert es auch für root. Secure Boot im BIOS aus, lockdown=none in GRUB, Neustart. Danach:

modprobe usbmon
cat /sys/kernel/debug/usb/usbmon/3u > /tmp/capture.txt &
./NBBSample

7654 Zeilen USB-Traffic. Das komplette Protokoll des NB-2033-U, aufgezeichnet während einer Enrollment-Session.

Was dabei rauskam

Das Protokoll ist komplett anders als beim NB-1010-U/NB-2020-U. Kevins Aussage stimmte. Hier die wesentlichen Unterschiede:

EigenschaftNB-1010-U / NB-2020-UNB-2033-U
Bulk IN EndpointEP 3 (0x83)EP 1 (0x81)
Kommandoformat[0x80][CMD][SEQ][0x00]...[CMD][0x00][LEN_LO][LEN_HI][PAYLOAD] (TLV)
Finger-ErkennungEinzelnes 0x38Zwei 0x0D Config + 0x38
Bildübertragung90 Chunks à 540 Bytes180 Chunks à 268 Bytes
InitEinmal 0x07Zweimal 0x07 nötig

Gleicher Sensor-Die (256×180 Pixel, 385 DPI, aktiv thermisch), aber ein komplett anderer USB-Stack. Der NB-2033-U nutzt ein TLV-Format (Type-Length-Value) statt des festen Kommandoschemas vom NB-1010-U. Jedes Kommando hat eine eigene Längenangabe, und die Antworten sind anders strukturiert.

Die Kommandos im Detail

Aus dem USB-Capture konnte ich sechs Kommandos identifizieren:

  • 0x07 — Init/Wake. Muss zweimal gesendet werden, sonst reagiert der Sensor nicht.
  • 0x0D — Sensor-Konfiguration. Wird zweimal vor jeder Finger-Erkennung gebraucht, um den „Enhanced“ Modus zu aktivieren.
  • 0x38 — Finger-Erkennung. Byte 4 der Antwort ist der Detect-Level. Schwellwert 40.
  • 0x12 — Capture starten. Liefert 180 Zeilen à 256 Pixel, 8-Bit Graustufen.
  • 0x13 — Geräteinformationen (Hersteller, Modell, Seriennummer).
  • 0xF7 — Firmware-Version.

Thermischer Sensor: Eigenheiten

Der Sensor misst Temperaturänderungen, nicht statischen Kontakt. Das klingt nach einem Detail, ist aber für die Treiber-Implementierung entscheidend. Finger auflegen erzeugt einen kurzen Spike im Detect-Wert (10 bis 50+). Finger bleibt liegen, und der Wert fällt zurück auf Basisniveau. Der Treiber muss also den Spike erkennen, nicht einen dauerhaften Zustand.

Dazu kommt: Nach dem Init gibt es transiente Spikes, die ungefähr 1,5 Sekunden brauchen, bis sie abklingen. Ohne Settle-Pause nach dem Init erkennt der Treiber Phantom-Finger.

Der Treiber

Rausgekommen ist nb2033.c, ein eigenständiger libfprint-Treiber mit rund 350 Zeilen. Kein proprietärer Code, keine SDK-Abhängigkeit. Das SDK diente nur als Referenz für die Capture-Analyse, der Treiber ist sauber von Grund auf geschrieben. Lizenz: LGPL 2.1+ wie alle libfprint-Treiber.

Die State Machine:

  1. Init (0x07 × 2) mit 1,5 Sekunden Settle-Pause
  2. Finger-Detect-Polling (0x0D + 0x0D + 0x38, Schwellwert 40)
  3. Pre-Capture Config (0x0D)
  4. Capture (0x12) mit 150 ms Pause, dann 180 Zeilen lesen
  5. Bild an libfprint übergeben

Test

Getestet auf Majas Fujitsu Notebook mit Linux Mint 22.3:

$ fprintd-enroll
Using device /net/reactivated/Fprint/Device/0
Enrolling right-index-finger finger.
Enroll result: enroll-stage-passed
[... 5/5 Stages ...]
Enroll result: enroll-completed
$ fprintd-verify
Using device /net/reactivated/Fprint/Device/0
Listing enrolled fingers:
 - #0: right-index-finger
Verify result: verify-match (true)

Richtiger Finger: Match. Falscher Finger: No Match. Enrollment sauber, Verifikation zuverlässig.

Upstream

Der Merge Request ist eingereicht: MR !574 bei libfprint. Fünf Dateien: der neue Treiber, meson.build, autosuspend.hwdb und die Allowlist. CI läuft durch. Der verwandte MR !569 für den NB-2020-U ist noch in Review.

Für die Wiki-Aktualisierung (das Gerät von der „unsupported“ Liste nehmen) gibt es Issue #134.

Fazit

Der Hersteller sagt „not supported“, 74 Linux-User melden „failed“, und trotzdem war das an einem Nachmittag erledigt. SDK auf Linux ausführen, USB-Traffic mitschneiden, Protokoll rekonstruieren, Treiber schreiben, testen, upstream einreichen. Alles mit Open-Source-Tools: usbmon, libusb, libfprint.

Das Ergebnis: Majas Notebook hat jetzt einen funktionierenden Fingerabdruckleser unter Linux. Und sobald der Merge Request durch ist, haben ihn alle anderen auch.

Wie immer: Bei Fragen, fragen.

Raspberry Pi als serieller Konsolenserver

Wir haben 2026. Alles wandert in die Cloud. Trotzdem will ich heute über serielle Konsolen schreiben. Klingt retro, ist es aber nicht. Wenn ein Switch sich verkonfiguriert hat und das Netzwerk weg ist, hilft kein Ansible und kein Dashboard in der Cloud. Dann hilft nur noch der serielle Konsolenport. Out-of-Band Management ist nicht tot. Es wurde nur teuer verpackt.

Kommerzielle Konsolenserver kosten gerne vierstellig. Oder man nimmt einen Raspberry Pi der noch herum liegt und auf eine neue Aufgabe wartet (ich habe hier ein paar Pi1 oder 2 herum liegen). Zusammen mit zwei USB Serial Adaptern hat man für unter 50 Euro einen Konsolenserver mit acht Ports. Das reicht für die meisten Setups locker aus.

Raspberry Pi als DIY-Konsolenserver mit USB-Serial-Adaptern zur Verwaltung serieller Konsolen von Netzwerkgeräten über SSH und ser2net

Wofür ein Konsolenserver

Der klassische Fall: Ein paar Switches im Rack, jedes Gerät hat einen seriellen Konsolenport. Im Normalbetrieb konfiguriert man über das Netzwerk. Aber wenn mal eine falsche Route das Management Interface unerreichbar macht oder ein VLAN Umbau schiefgeht, steht man vor dem Gerät und steckt ein Kabel rein. Wenn das im DC in Frankfurt ist, oder vielleicht irgendwo in China, dann kann das spannend werden.

Oder man hat vorgebaut.

Ein Konsolenserver hängt permanent an den seriellen Ports der Netzwerkgeräte. Man kommt per SSH auf den Konsolenserver und von dort auf die serielle Konsole des Zielgeräts. Ob das Netzwerk funktioniert oder nicht, spielt keine Rolle mehr. Öhm also ja, so grob. Der Pi sollte dann ja schon noch erreichbar sein. Aber man hat ja in einem entfernten DC auch eine Dailin Line oder ähnliches, richtig? Richtig?

Meme mit Anakin und Padmé: „Der Konsolenserver hängt an allen Switches – wir kommen immer auf die Konsole – der Raspi ist erreichbar über … die gleiche Strecke.“

Hardware

Ein Raspberry Pi. Es muss kein aktuelles Modell sein. Selbst ein alter Pi 2 reicht völlig aus. Das Ding muss ser2net laufen lassen und ein paar serielle Ports bedienen, dafür braucht man keinen Quad Core mit 8 GB RAM. Der Pi aus der Schublade bekommt endlich eine sinnvolle Aufgabe.

FTDI Quad Port USB Serial Adapter (Vendor 0403, Product 6011). Pro Adapter bekommt man vier serielle Ports. Mit zwei Adaptern hat man acht Ports. Die Dinger gibt es für kleines Geld.

RS232 Kabel zu den Console Ports der Netzwerkgeräte. Welcher Stecker passt, hängt vom Hersteller ab. RJ45 auf DB9, DB9 auf DB9, die üblichen Verdächtigen. Da muss man schauen was die eigenen Geräte mitbringen.

Stabile Gerätenamen mit udev

Das erste Problem nach dem Einstecken der USB Adapter: Linux vergibt die /dev/ttyUSBx Nummern nach Lust und Laune. Nach einem Reboot kann ttyUSB0 plötzlich ttyUSB4 sein. Wenn man wissen will welcher Port an welchem Gerät hängt, ist das unpraktisch.

Die Lösung sind udev Regeln. Jeder FTDI Adapter hat eine eigene Seriennummer. Die findet man so:

udevadm info -a -n /dev/ttyUSB0 | grep serial

Damit baut man sich Regeln die stabile Symlinks erzeugen. Datei /etc/udev/rules.d/99-serial-consoles.rules:

SUBSYSTEMS=="usb", ENV{.LOCAL_ifNum}="$attr{bInterfaceNumber}"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="FT000001", SYMLINK+="quad0-%E{.LOCAL_ifNum}"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", ATTRS{serial}=="FT000002", SYMLINK+="quad1-%E{.LOCAL_ifNum}"

FT000001 und FT000002 ersetzt man durch die echten Seriennummern der eigenen Adapter. Das Ergebnis sind stabile Symlinks: /dev/quad0-00 bis /dev/quad0-03 für den ersten Adapter, /dev/quad1-00 bis /dev/quad1-03 für den zweiten. Acht Ports, immer gleich benannt. Egal wie oft man den Pi neustartet.

ser2net

ser2net bildet die seriellen Ports auf TCP Ports ab. Man kann dann per Telnet auf einen bestimmten Port zugreifen und landet direkt auf der seriellen Konsole des zugehörigen Geräts. Installieren mit apt install ser2net, dann die Konfiguration in /etc/ser2net.conf:

localhost,2001:telnet:600:/dev/quad0-00:9600 8DATABITS NONE 1STOPBIT banner
localhost,2002:telnet:600:/dev/quad0-01:9600 8DATABITS NONE 1STOPBIT banner
localhost,2003:telnet:600:/dev/quad0-02:9600 8DATABITS NONE 1STOPBIT banner
localhost,2004:telnet:600:/dev/quad0-03:9600 8DATABITS NONE 1STOPBIT banner
localhost,2005:telnet:600:/dev/quad1-00:9600 8DATABITS NONE 1STOPBIT banner
localhost,2006:telnet:600:/dev/quad1-01:9600 8DATABITS NONE 1STOPBIT banner
localhost,2007:telnet:600:/dev/quad1-02:9600 8DATABITS NONE 1STOPBIT banner
localhost,2008:telnet:600:/dev/quad1-03:9600 8DATABITS NONE 1STOPBIT banner

9600 8N1 ist der Standard bei den meisten Netzwerkgeräten. Falls ein Gerät eine andere Baudrate braucht, passt man die entsprechende Zeile an. Der Timeout von 600 Sekunden trennt die Verbindung nach zehn Minuten Inaktivität. Das verhindert dass ein vergessenes Telnet die Konsole dauerhaft blockiert.

Direkter Zugriff mit minicom

Wer ser2net nicht nutzen will oder schnell direkt auf einen Port muss, nimmt minicom:

minicom -D /dev/quad0-00 -b 9600

minicom ist gut für schnelle Tests und Debugging. Für den Dauerbetrieb mit mehreren Ports gleichzeitig ist ser2net die bessere Wahl.

Warum localhost

ser2net ist im gezeigten Setup bewusst auf localhost gebunden. Man muss sich erst per SSH auf den Pi einloggen und dann telnet 127.0.0.1 200x aufrufen. Das ist Absicht.

Man könnte ser2net auch auf 0.0.0.0 binden und die Ports direkt aus dem Netz erreichen. Davon rate ich ab. Telnet ist unverschlüsselt. Auch in einem Management VLAN hat das nichts verloren.

Bessere Alternativen wenn man ohne SSH auf den Pi will:

  • ser2net ab Version 4.x unterstützt SSL/TLS. Damit hat man verschlüsselte Verbindungen direkt zu den Console Ports.
  • stunnel vor ser2net schalten. stunnel terminiert TLS und reicht die Verbindung an den lokalen ser2net weiter.
  • Wer nativen SSH Zugriff direkt auf die seriellen Ports braucht, sollte sich conserver anschauen. ser2net kann kein SSH.

Für die meisten Setups ist SSH auf den Pi und dann Telnet auf localhost der einfachste und sicherste Weg.

Absichern

Ein paar Dinge die man auf dem Pi noch machen sollte:

Den Default Benutzer pi löschen. Einen eigenen Benutzer anlegen. SSH Key Authentifizierung einrichten und Login per Passwort deaktivieren. Das ist nicht optional.

NTP konfigurieren. Timestamps in Logs sind nutzlos wenn die Uhrzeit nicht stimmt.

Syslog an einen zentralen Logserver weiterleiten. Wenn man serielle Konsolen mitschneidet, will man die Logs nicht nur lokal auf dem Pi haben.

Workflow

Der Alltag sieht dann so aus:

  1. SSH auf den Pi: ssh admin@10.0.0.50
  2. Telnet auf den gewünschten Port: telnet 127.0.0.1 2003
  3. Man landet auf der seriellen Konsole von Switch 3

Alternativ direkt mit minicom: minicom -D /dev/quad0-02 -b 9600

Zum Trennen: Ctrl-] und dann quit bei Telnet. Ctrl-A gefolgt von X bei minicom.

Fazit

Ein alter Raspberry Pi, zwei USB Adapter, ein paar Kabel. Mehr braucht man nicht für einen funktionierenden Konsolenserver mit acht Ports. Die Einrichtung dauert vielleicht eine Stunde. Danach läuft das Ding und man muss nie wieder ein Konsolenkabel quer durch den Serverraum schleppen.

Und der alte Pi aus der Schublade hat endlich wieder eine Aufgabe.

Ihr habt Fragen, Anmerkungen oder baut das Setup selbst nach? Meldet euch gerne über die Kontaktseite oder direkt per E-Mail.

Siehe auch: DHT22 am Raspberry Pi

NEXT Biometrics NB-2020-U Fingerabdruckleser unter Linux zum Laufen gebracht

In meinem Fujitsu Notebook steckt ein Fingerabdruckleser. Ein NEXT Biometrics NB-2020-U, USB ID 298d:2020. Unter Windows funktioniert er, unter Linux nicht. Kein Treiber, kein Support, nichts. Das Gerät taucht in lsusb auf, wird aber von keinem Treiber erkannt. Im libfprint Wiki steht es auf der Liste der nicht unterstützten Geräte. Dort steht es schon eine Weile.

Das hat mich gestört.

Picture of NB-2020-U

libfprint kennt den NB-1010-U. Das ist ein externer USB Fingerabdruckleser von NEXT Biometrics, der seit einiger Zeit einen funktionierenden Treiber hat. Der NB-2020-U ist die eingebettete Variante desselben Sensors, gedacht für den Einbau in Notebooks. Wenn man sich Teardown Reports ansieht, etwa von System Plus Consulting oder Yole Group, dann stellt man fest: Beide Geräte verwenden den identischen Sensor Die. Gleiche Technik, anderes Gehäuse.

Das war der erste Anhaltspunkt. Wenn die Hardware gleich ist, sollte auch das USB Protokoll gleich sein. Und wenn das Protokoll gleich ist, sollte der vorhandene Treiber funktionieren.

Bevor ich aber einfach auf Verdacht losprogrammiert habe, wollte ich es absichern. Ich habe NEXT Biometrics direkt angeschrieben. Kevin Hung, Director FAE bei NEXT Biometrics, hatte mir bereits 2022 auf eine Anfrage zu Linux Treibern geantwortet. Damals war sein Vorschlag, über Fujitsu zu gehen. Das führte ins Leere. Diesmal habe ich konkret angeboten, selbst einen libfprint Treiber zu schreiben, und um das SDK gebeten.

Kevin hat mir daraufhin das NBBiometrics ANF SDK 3.0.0.1384 zugeschickt. Ein komplettes SDK mit Headern, Bibliotheken, Beispielcode und Dokumentation. Das war sehr hilfreich, denn die Header bestätigen einiges. Das SDK nutzt eine einzige Shared Library libNBBiometrics.so für alle Gerätetypen. Der NB-1010-U hat den internen Gerätetyp 200, der NB-2020-U den Typ 202. Beide verwenden dasselbe Scanformat: 180×256 Pixel bei 385 DPI. Die USB Vendor ID ist bei beiden 0x298d, nur die Product ID unterscheidet sich: 0x1010 beim einen, 0x2020 beim anderen.

Wichtig: Das SDK ist proprietär. Für den eigentlichen Treiber habe ich keinen Code daraus verwendet. libfprint akzeptiert nur sauberen, eigenständig entwickelten Code. Das SDK diente ausschließlich als Referenz, um die Protokollkompatibilität zu bestätigen.

Also habe ich es einfach ausprobiert. Den bestehenden nb1010.c Treiber genommen, die USB Product ID 0x2020 zur id_table hinzugefügt und gebaut. Dann auf dem Fujitsu Notebook getestet.

Es funktionierte sofort.

Geräteerkennung, USB Interface Claim, die State Machine für die Fingererkennung, alles lief auf Anhieb. fprintd-enroll hat Fingerabdrücke aufgenommen, fprintd-verify hat sie korrekt verifiziert. Der bestehende Treibercode brauchte keinerlei Anpassungen. Null. Nur die PID in der Tabelle und den Gerätenamen.

Ein Blick auf die USB Deskriptoren bestätigt das Bild. Der NB-2020-U hat exakt dasselbe Endpoint Layout wie der NB-1010-U: Bulk OUT auf Endpoint 0x02, Bulk IN auf Endpoint 0x83. Dazu kommt ein Interrupt Endpoint auf 0x81, den der Treiber nicht verwendet. Die Kommunikation läuft identisch ab.

Der Patch selbst ist entsprechend klein. Drei Dateien, drei Zeilen rein, drei Zeilen raus:

  1. libfprint/drivers/nb1010.c: Die neue PID 0x2020 wird in die id_table eingetragen und der full_name auf "NextBiometrics NB-1010-U/NB-2020-U" erweitert.
  2. data/autosuspend.hwdb: Der Eintrag 298d:2020 wird von der Liste der nicht unterstützten Geräte in die Sektion des nb1010 Treibers verschoben.
  3. libfprint/fprint-list-udev-hwdb.c: Der Eintrag wird aus der Allowlist der nicht unterstützten Geräte entfernt, da er jetzt vom Treiber abgedeckt wird.

Den Merge Request habe ich bei libfprint upstream eingereicht: MR !569. Die CI Pipeline läuft durch, alle 124 Tests bestehen. Jetzt heißt es warten auf das Review durch die Maintainer.

Für alle, die denselben Fingerabdruckleser in ihrem Notebook haben: Sobald der Patch gemergt und in einer neuen libfprint Version enthalten ist, funktioniert der Sensor out of the box. Enrollment und Verifikation über fprintd laufen sauber. Wer nicht warten möchte, kann den Patch auch jetzt schon selbst auf ein aktuelles libfprint anwenden.

Im selben Fujitsu Notebook meiner Tochter steckt ein NB-2033-U, ein weiterer Fingerabdruckleser aus der gleichen Familie. Der verwendet allerdings ein komplett anderes Protokoll und ließ sich nicht einfach mit dem nb1010 Treiber ansprechen. Den habe ich per Reverse Engineering geknackt.

Telekom SmartHome: Firmware-Updates für HomeMatic-Geräte über die CCU2

Die QIVICON Home Base vom Telekom SmartHome kann keine Firmware-Updates auf die HomeMatic-Geräte von eQ-3 aufspielen. Bei den älteren HomeMatic-Geräten war das kein Problem, Updates waren selten und betrafen keine kritischen Funktionen. Bei den neueren HomeMatic IP Geräten sieht das anders aus. Die Firmware ändert sich regelmäßig, neue Funktionen kommen dazu und Bugs werden behoben. Ein Zwischenstecker fungiert zum Beispiel erst ab einem bestimmten Firmwarestand als Repeater im Mesh-Netzwerk.

Der Update-Weg über die CCU2

Zum Updaten gibt es zwei Möglichkeiten: Einen Funk-Konfigurationsstick für USB oder die CCU2 Zentrale von eQ-3. Ich habe mir die CCU2 besorgt. Der Ablauf pro Gerät sieht so aus:

1. Gerät vom Telekom SmartHome ablernen
2. Gerät an der CCU2 anlernen
3. Firmware-Update durchführen
4. Gerät von der CCU2 ablernen
5. Gerät am Telekom SmartHome wieder anlernen

Das ist aufwendig. Für jedes einzelne Gerät. Und bei den HomeMatic IP Geräten dauert ein Firmware-Update zwischen 8 und 42 Stunden. Die Firmware ist dabei knapp über 100 KB groß. Bei den älteren HomeMatic-Geräten ist das gleiche Update in fünf Minuten erledigt. Warum der Funkweg bei den IP-Geräten so langsam ist, erschließt sich mir nicht.

Warum nicht gleich die CCU2?

Das Telekom SmartHome hat einen Vorteil der schwer wiegt: Man kann Geräte verschiedener Hersteller miteinander kombinieren. HomeMatic, Philips Hue, Schellenberg Rolladen, DECT-Steckdosen. Das können die reinen eQ-3 Lösungen wie CCU2 mit Orbylon oder pocket control nicht in dem Umfang. Dafür nimmt man den umständlichen Firmware-Update-Prozess in Kauf.

Siehe auch: Telekom SmartHome im Test: Erfahrungen mit QIVICON und Home Base​

Fragen? Einfach melden.

ioping: Read- und Write-Latency schnell messen

Für ausführliche Storage-Benchmarks gibt es Tools wie bonnie++ oder fio. Wenn man nur schnell die Read- oder Write-Latency eines Dateisystems prüfen will, reicht ioping — ein einzelner Befehl, Ergebnis in Sekunden.

Installation

# FreeBSD
pkg install ioping

# Debian/Ubuntu
apt install ioping

Read-Latency messen

ioping -s 256k -T 120 -D -c 20 ./
256 KiB <<< ./ (zfs tanksmeer/usr/home): request=1 time=16.0 us (warmup)
256 KiB <<< ./ (zfs tanksmeer/usr/home): request=2 time=35.7 us
256 KiB <<< ./ (zfs tanksmeer/usr/home): request=3 time=45.8 us
...

--- ./ (zfs tanksmeer/usr/home) ioping statistics ---
19 requests completed in 853.7 us, 4.75 MiB read, 22.3 k iops, 5.43 GiB/s
generated 20 requests in 19.0 s, 5 MiB, 1 iops, 269.2 KiB/s
min/avg/max/mdev = 35.7 us / 44.9 us / 52.8 us / 3.85 us

Die Parameter im Detail:

  • -s 256k — Blockgröße pro Request (hier 256 KiB)
  • -T 120 — Timeout in Sekunden, Requests die länger brauchen werden ignoriert
  • -D — Direct I/O, umgeht den Kernel-Cache (misst die echte Disk-Latency)
  • -c 20 — Anzahl der Requests
  • ./ — Pfad zum Dateisystem das gemessen werden soll

Die Summary am Ende zeigt min/avg/max/mdev — genau wie bei ping. Hier: durchschnittlich 44,9 µs Read-Latency auf einem ZFS-Dataset.

Write-Latency messen

Für die Write-Latency kommt ein einziger Parameter dazu — -W:

ioping -s 256k -T 120 -D -W -c 20 ./
256 KiB >>> ./ (zfs tanksmeer/usr/home): request=1 time=27.0 us (warmup)
256 KiB >>> ./ (zfs tanksmeer/usr/home): request=2 time=54.4 us
256 KiB >>> ./ (zfs tanksmeer/usr/home): request=3 time=60.6 us
...

--- ./ (zfs tanksmeer/usr/home) ioping statistics ---
19 requests completed in 3.86 ms, 4.75 MiB written, 4.93 k iops, 1.20 GiB/s
generated 20 requests in 19.0 s, 5 MiB, 1 iops, 269.5 KiB/s
min/avg/max/mdev = 51.6 us / 202.9 us / 2.65 ms / 577.9 us

Write ist hier erwartungsgemäß langsamer — 202,9 µs im Schnitt gegenüber 44,9 µs beim Lesen. Die höhere Standardabweichung (577,9 µs vs. 3,85 µs) zeigt, dass einzelne Writes deutlich länger dauern können (hier ein Ausreißer mit 2,65 ms — vermutlich ein ZFS Transaction Group Commit).

Weitere nützliche Optionen

# Fortlaufend messen (wie ping ohne -c)
ioping -D ./

# Nur die Summary nach 10 Requests
ioping -D -c 10 -q ./

# Bestimmte Blockgröße (4k für Random I/O)
ioping -s 4k -D -c 20 ./

# Netzlaufwerk / NFS-Mount testen
ioping -D -c 20 /mnt/nfs-share/

Praktisch für einen schnellen Vergleich: Lokale SSD, NFS-Share und USB-Platte mit dem gleichen Befehl messen — die Unterschiede werden sofort sichtbar. Fragen? Einfach melden.

FreeBSD auf dem Desktop: Grundinstallation mit MATE

Nach der Grundinstallation von FreeBSD hängt man auf der Konsole. Kein Fenstermanager, kein Browser, keine grafische Oberfläche. Für Serverleute normal, für Desktopnutzer erstmal irritierend. Hier die Schritte von der nackten FreeBSD-Installation zu einem funktionierenden MATE-Desktop mit deutschem Layout.

Screenshot vom FreeBSD Desktop

Pakete installieren

Ein Einzeiler holt alles was man für den Anfang braucht. MATE als Desktop, Xorg als Display-Server, LightDM als Login-Manager und die üblichen Anwendungen:

pkg install xorg mate mate-desktop lightdm lightdm-gtk-greeter \
  firefox thunderbird pidgin vlc libreoffice gimp \
  de-aspell de-hunspell cups cups-pdf sudo

rc.conf anpassen

In der /etc/rc.conf die nötigen Dienste aktivieren:

# Deutsche Konsolenschriftarten
font8x8="iso15-8x8"
font8x14="iso15-8x14"
font8x16="iso15-8x16"

# D-Bus für den Desktop
dbus_enable="YES"

# Grafischer Login
lightdm_enable="YES"

# Drucken über CUPS
cupsd_enable="YES"
lpd_enable="NO"

# Temp-Verzeichnisse aufräumen
clear_tmp_enable="YES"
clean_tmp_X="YES"

# Erweiterte Device-Regeln aktivieren
devfs_system_ruleset="devfsrules_common"

Deutsche Locale

FreeBSD setzt Sprache und Zeichensatz über Login-Klassen. In der /etc/login.conf eine neue Klasse anlegen:

german|German Users Accounts:\
      :charset=UTF-8:\
      :lang=de_DE.UTF-8:\
      :tc=default:

Danach die Login-Datenbank neu bauen und dem Benutzer die Klasse zuweisen:

cap_mkdb /etc/login.conf

In vipw die Klasse german im fünften Feld eintragen:

kernel:*:1001:1001:german:0:0:Sebastian:/home/kernel:/usr/local/bin/fish

Xorg: Deutsches Tastaturlayout

Datei /usr/local/etc/X11/xorg.conf.d/keyboard-de-nodeadkeys.conf anlegen:

Section "InputClass"
    Identifier  "KeyboardDefaults"
    Driver      "keyboard"
    MatchIsKeyboard "on"
    Option      "XkbLayout" "de"
    Option      "XkbVariant" "nodeadkeys"
EndSection

Hardware-Berechtigungen

Normale Benutzer brauchen Zugriff auf Laufwerke, USB-Geräte und Soundkarten. Die /etc/devfs.rules regelt das. Wer das Thema im Detail verstehen will: Im Beitrag zu CD/DVD-Brenner-Berechtigungen unter FreeBSD ist das ausführlicher erklärt.

[devfsrules_common=7]
add path 'ada[0-9]\*'   mode 666
add path 'da[0-9]\*'    mode 666
add path 'cd[0-9]\*'    mode 666
add path 'pass[0-9]\*'  mode 666
add path 'xpt[0-9]\*'   mode 666
add path 'ugen[0-9]\*'  mode 666
add path 'usb/\*'       mode 666
add path 'video[0-9]\*' mode 666
add path 'mmcsd[0-9]\*' mode 666
add path 'lpt[0-9]\*'   mode 666
add path 'ulpt[0-9]\*'  mode 666

sudo und wheel-Gruppe

Den Benutzer in die Gruppe wheel aufnehmen und per visudo die sudo-Berechtigung setzen:

pw groupmod wheel -m kernel
# visudo
root   ALL=(ALL) ALL
kernel ALL=(ALL) ALL

loader.conf: Kernel-Module

In der /boot/loader.conf ein paar Module die auf einem Desktop sinnvoll sind:

# Neuer Grafik-Konsolentreiber
kern.vty=vt

# Kernel-Tuning
kern.ipc.shmseg=1024
kern.ipc.shmmni=1024
kern.maxproc=10000

# SD-Kartenleser
mmc_load="YES"
mmcsd_load="YES"
sdhci_load="YES"

# FUSE (Dateisysteme im Userspace, z.B. NTFS)
fuse_load="YES"

# CPU-Temperatursensoren (Intel)
coretemp_load="YES"

# tmpfs und asynchrone I/O
tmpfs_load="YES"
aio_load="YES"

# Unicode auf Wechselmedien
libiconv_load="YES"
libmchain_load="YES"
cd9660_iconv_load="YES"
msdosfs_iconv_load="YES"

# Sound
snd_driver_load="YES"

# Linux-Kompatibilität
linux_load="YES"

# ZFS ARC begrenzen (hier 2 GB, an RAM anpassen)
vfs.zfs.arc_max="2048M"

Die vfs.zfs.arc_max Einstellung ist wichtig. ZFS nutzt standardmäßig so viel RAM wie verfügbar für den Dateisystem-Cache. Auf einem Desktop mit 8 GB will man das begrenzen, damit für Anwendungen genug übrig bleibt.

Fertig

Nach einem Neustart sollte LightDM den grafischen Login zeigen. MATE als Session auswählen, anmelden, fertig. Firefox, Thunderbird, LibreOffice und der Rest sind installiert und startbereit.

FreeBSD auf dem Desktop ist nicht so komfortabel wie ein Ubuntu. Dafür hat man ein sauberes ZFS, ein durchdachtes System und eine Dokumentation die ihresgleichen sucht. Wer sich darauf einlässt, wird es mögen.

Fragen? Einfach melden.

FreeBSD: Verschlüsseltes ZFS-Backup auf USB-Platte mit geli

Ein Notebook mit Full-Disk-Encryption verdient auch ein verschlüsseltes Backup. Plan: ZFS-Snapshots per zfs send auf eine USB-Platte schieben, die komplett mit geli verschlüsselt ist. Schlüssel und Passphrase sicher aufbewahren — fertig.

Hinweis: Seit OpenZFS 2.0 (FreeBSD 13+) gibt es native ZFS-Verschlüsselung (zfs create -o encryption=aes-256-gcm). Damit entfällt geli als Zwischenschicht. Auf älteren Systemen oder wenn man die gesamte Platte unabhängig vom Dateisystem verschlüsseln will, bleibt geli die richtige Wahl.

USB-Platte verschlüsseln

Platte einstecken und per dmesg das Device identifizieren — in diesem Fall da0. Dann mit gpart eine neue GPT-Partitionstabelle anlegen und eine Partition erstellen.

geli braucht einen Schlüssel aus Zufallsdaten:

dd if=/dev/random of=./backup-key bs=256 count=1

Mit diesem Schlüssel die verschlüsselte Partition einrichten:

geli init -s 4096 -K ./backup-key -l 256 /dev/da0s1
Enter new passphrase:
Reenter new passphrase:

Metadata backup can be found in /var/backups/da0s1.eli and
can be restored with the following command:

    # geli restore /var/backups/da0s1.eli /dev/da0s1

Partition öffnen:

geli attach -k ./backup-key /dev/da0s1
Enter passphrase:

ZFS-Pool anlegen

Auf der geöffneten geli-Partition (da0s1.eli) den ZFS-Pool erstellen:

zpool create usb-backup /dev/da0s1.eli

zpool list
NAME         SIZE  ALLOC   FREE  CAP  HEALTH
zroot        460G   184G   276G  40%  ONLINE
usb-backup   928G   296K   928G   0%  ONLINE

Backup starten

Initiales Vollbackup per zfs send -R (rekursiv, alle Datasets und Snapshots):

zfs send -R zroot@auto-2015-05-23-21-00-00 | zfs recv -u usb-backup/notebook

Die Option -R sendet alles rekursiv. Die Option -u beim Empfänger verhindert, dass die Datasets auf der USB-Platte gemountet werden. Bei allen folgenden Backups muss nur noch die Differenz zwischen zwei Snapshots übertragen werden.

Platte sicher aushängen

Drei Schritte in der richtigen Reihenfolge:

  • Sync erzwingen — alle Daten sicher auf die Platte schreiben
  • ZFS-Pool exportieren
  • geli-Partition schließen
sync
zpool export usb-backup
geli detach /dev/da0s1

Wichtig: Den Schlüssel (backup-key) an einem dritten Ort aufbewahren — weder auf dem Notebook noch auf der Backup-Platte. Ohne Schlüssel und Passphrase sind die Daten nicht wiederherstellbar.

Mehr zu ZFS-Backups: Automatische ZFS-Snapshots und ZFS send/recv Fehler beheben. Fragen? Einfach melden.

FreeBSD: CD/DVD-Brenner funktioniert nicht als normaler Benutzer

Brennprogramme wie xfburn melden unter FreeBSD gerne, dass kein Laufwerk gefunden wurde oder die Berechtigungen nicht stimmen. Als root funktioniert es, als normaler Benutzer nicht. Das Problem sind nicht die Berechtigungen auf /dev/cd0, sondern auf dem zugehörigen SCSI-Passthrough-Device.

atapicam laden

Brennprogramme greifen über das CAM-Subsystem (Common Access Method) auf den Brenner zu. Dafür muss das Modul atapicam geladen sein. In der /boot/loader.conf:

atapicam_load="YES"
hw.ata.atapi_dma="1"

Die erste Zeile macht den ATA-Brenner als SCSI-Gerät sichtbar, die zweite aktiviert DMA für ATA-Geräte.

Das pass-Device finden

Mit camcontrol sieht man welches pass-Device zum Brenner gehört:

camcontrol devlist
# Ausgabe:
#            at scbus0 target 0 lun 0 (ada0,pass0)
#    at scbus1 target 0 lun 0 (cd0,pass1)

Der Brenner ist cd0 mit dem Passthrough-Device pass1. Ein Blick auf die Berechtigungen zeigt das Problem:

ls -la /dev/cd0
# crw-rw-rw-  1 root  operator  ... /dev/cd0

ls -la /dev/pass1
# crw-------  1 root  operator  ... /dev/pass1

/dev/cd0 ist für alle lesbar und schreibbar, aber /dev/pass1 ist nur für root zugänglich. Die Brennsoftware braucht aber genau dieses Device.

Berechtigungen dauerhaft setzen

Zum Testen reicht ein chmod 0666 /dev/pass1. Damit die Berechtigungen nach einem Neustart erhalten bleiben, den Eintrag in /etc/devfs.conf hinterlegen:

# /etc/devfs.conf
perm    /dev/cd0        0666
perm    /dev/pass1      0666

Die Device-Nummer von pass kann sich ändern, wenn USB-Geräte dazukommen oder die Boot-Reihenfolge wechselt. Im Zweifelsfall vorher mit camcontrol devlist prüfen.

Siehe auch: FreeBSD auf dem Desktop

Fragen? Einfach melden.

« Ältere Beiträge

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑